// ---------- Overlays: Toast, Modal, Sheet, CommandPalette, Notifications, NewProject ----------

// Toast system — global event bus
const ToastEvents = {
  emit: (toast) => window.dispatchEvent(new CustomEvent("hd-toast", { detail: toast })),
};

const Toaster = () => {
  const [toasts, setToasts] = React.useState([]);
  React.useEffect(() => {
    const handler = (e) => {
      const t = { id: Date.now() + Math.random(), ...e.detail };
      setToasts(prev => [...prev, t]);
      setTimeout(() => {
        setToasts(prev => prev.filter(x => x.id !== t.id));
      }, t.duration || 3600);
    };
    window.addEventListener("hd-toast", handler);
    return () => window.removeEventListener("hd-toast", handler);
  }, []);
  return (
    <div style={{
      position: "fixed", bottom: 20, right: 20, zIndex: 100,
      display: "flex", flexDirection: "column-reverse", gap: 10,
      pointerEvents: "none",
    }}>
      {toasts.map(t => <Toast key={t.id} toast={t} onClose={() => setToasts(p => p.filter(x => x.id !== t.id))} />)}
    </div>
  );
};

const Toast = ({ toast, onClose }) => {
  const tones = {
    success: { fg: "#86EFAC", bg: "rgba(34,197,94,0.10)", bd: "rgba(34,197,94,0.30)", icon: "CheckCircle" },
    info:    { fg: "#9CC1FF", bg: "rgba(29,78,216,0.12)", bd: "rgba(29,78,216,0.32)", icon: "Sparkle" },
    error:   { fg: "#FCA5A5", bg: "rgba(239,68,68,0.10)", bd: "rgba(239,68,68,0.30)", icon: "X" },
    upload:  { fg: "#7CE3D2", bg: "rgba(20,184,166,0.10)", bd: "rgba(20,184,166,0.30)", icon: "Upload" },
  }[toast.kind || "info"];
  const IconComp = window.Icon[tones.icon];
  return (
    <div className="hd-fadeUp" style={{
      pointerEvents: "auto",
      background: "var(--charcoal)",
      border: `1px solid ${tones.bd}`,
      borderRadius: 12,
      padding: "12px 14px",
      minWidth: 280, maxWidth: 380,
      display: "flex", alignItems: "flex-start", gap: 12,
      boxShadow: "0 20px 40px -16px rgba(0,0,0,0.5)",
      color: "var(--white)",
    }}>
      <div style={{
        width: 28, height: 28, borderRadius: 8,
        background: tones.bg, border: `1px solid ${tones.bd}`, color: tones.fg,
        display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0,
      }}><IconComp size={14} /></div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 13, fontWeight: 500 }}>{toast.title}</div>
        {toast.body && <div style={{ fontSize: 12, color: "var(--warm-gray)", marginTop: 3, lineHeight: 1.5 }}>{toast.body}</div>}
      </div>
      <button onClick={onClose} style={{
        background: "transparent", border: "none", color: "var(--warm-gray)",
        padding: 2, cursor: "pointer", flexShrink: 0,
      }}><window.Icon.X size={12} /></button>
    </div>
  );
};

// Backdrop helper
const Backdrop = ({ onClick, children, align = "center" }) => (
  <div
    onClick={onClick}
    style={{
      position: "fixed", inset: 0, zIndex: 60,
      background: "rgba(0,0,0,0.55)",
      backdropFilter: "blur(4px)",
      display: "flex",
      alignItems: align === "center" ? "center" : "flex-start",
      justifyContent: "center",
      padding: align === "center" ? 24 : "10vh 24px 24px",
      overflowY: "auto",
    }}
  >
    <div onClick={(e) => e.stopPropagation()} style={{ width: "100%", maxWidth: 560 }}>
      {children}
    </div>
  </div>
);

// Modal
const Modal = ({ title, eyebrow, onClose, children, footer, maxWidth = 560 }) => (
  <Backdrop onClick={onClose}>
    <div style={{
      maxWidth, margin: "0 auto",
      background: "var(--charcoal)",
      border: "1px solid rgba(255,255,255,0.08)",
      borderRadius: 14,
      boxShadow: "0 40px 80px -20px rgba(0,0,0,0.6)",
      overflow: "hidden",
    }}>
      <div style={{ padding: "18px 20px", borderBottom: "1px solid rgba(255,255,255,0.05)", display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 12 }}>
        <div>
          {eyebrow && <div className="micro" style={{ color: "var(--warm-gray)", marginBottom: 4 }}>{eyebrow}</div>}
          <div style={{ fontSize: 16, fontWeight: 600, color: "var(--white)" }}>{title}</div>
        </div>
        <button onClick={onClose} aria-label="Close" style={{
          width: 32, height: 32, borderRadius: 8,
          background: "transparent", border: "1px solid rgba(255,255,255,0.08)",
          color: "var(--warm-gray)", cursor: "pointer",
          display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0,
        }}><window.Icon.X size={14} /></button>
      </div>
      <div style={{ padding: 20 }}>{children}</div>
      {footer && (
        <div style={{ padding: "14px 20px", borderTop: "1px solid rgba(255,255,255,0.05)", display: "flex", justifyContent: "flex-end", gap: 8, background: "rgba(255,255,255,0.015)" }}>
          {footer}
        </div>
      )}
    </div>
  </Backdrop>
);

// Right-anchored sheet
const Sheet = ({ title, eyebrow, onClose, children, width = 400 }) => (
  <div
    onClick={onClose}
    style={{
      position: "fixed", inset: 0, zIndex: 60,
      background: "rgba(0,0,0,0.45)",
      backdropFilter: "blur(3px)",
      animation: "hd-fadeIn 200ms ease both",
    }}
  >
    <div
      onClick={(e) => e.stopPropagation()}
      style={{
        position: "absolute", right: 0, top: 0, bottom: 0,
        width, maxWidth: "100vw",
        background: "var(--charcoal)",
        borderLeft: "1px solid rgba(255,255,255,0.08)",
        boxShadow: "-40px 0 80px -20px rgba(0,0,0,0.5)",
        display: "flex", flexDirection: "column",
        animation: "hd-slideIn 320ms cubic-bezier(.16,1,.3,1) both",
      }}
    >
      <div style={{ padding: "18px 20px", borderBottom: "1px solid rgba(255,255,255,0.05)", display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 12 }}>
        <div>
          {eyebrow && <div className="micro" style={{ color: "var(--warm-gray)", marginBottom: 4 }}>{eyebrow}</div>}
          <div style={{ fontSize: 15, fontWeight: 600, color: "var(--white)" }}>{title}</div>
        </div>
        <button onClick={onClose} aria-label="Close" style={{
          width: 32, height: 32, borderRadius: 8,
          background: "transparent", border: "1px solid rgba(255,255,255,0.08)",
          color: "var(--warm-gray)", cursor: "pointer",
          display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0,
        }}><window.Icon.X size={14} /></button>
      </div>
      <div style={{ flex: 1, overflow: "auto" }}>{children}</div>
    </div>
  </div>
);

// Add sheet slide-in animation
const overlayStyleEl = document.createElement("style");
overlayStyleEl.textContent = `
@keyframes hd-slideIn { from { transform: translateX(100%); } to { transform: translateX(0); } }
`;
document.head.appendChild(overlayStyleEl);

// ---------- Command Palette ----------
const CommandPalette = ({ onClose, onNavigate, onOpenProject }) => {
  const [q, setQ] = React.useState("");
  const inputRef = React.useRef(null);
  React.useEffect(() => { setTimeout(() => inputRef.current?.focus(), 50); }, []);

  const navCommands = [
    { id: "dashboard", label: "Go to Dashboard", icon: "Home", group: "Navigate", action: () => onNavigate("dashboard") },
    { id: "projects",  label: "Go to Projects",  icon: "Folder", group: "Navigate", action: () => onNavigate("projects") },
    { id: "clients",   label: "Go to Clients",   icon: "Users", group: "Navigate", action: () => onNavigate("clients") },
    { id: "uploads",   label: "Go to Uploads",   icon: "Upload", group: "Navigate", action: () => onNavigate("uploads") },
    { id: "inbox",     label: "Go to Inbox",     icon: "Inbox", group: "Navigate", action: () => onNavigate("inbox") },
    { id: "calendar",  label: "Go to Calendar",  icon: "Calendar", group: "Navigate", action: () => onNavigate("calendar") },
    { id: "settings",  label: "Go to Settings",  icon: "Settings", group: "Navigate", action: () => onNavigate("settings") },
    { id: "portal",    label: "Preview client portal", icon: "Eye", group: "Navigate", action: () => onNavigate("portal") },
  ];
  const actionCommands = [
    { id: "new-project", label: "New project…", icon: "Plus", group: "Actions", action: () => window.dispatchEvent(new CustomEvent("hd-open-new-project")) },
    { id: "upload",      label: "Upload assets…", icon: "Upload", group: "Actions", action: () => ToastEvents.emit({ title: "Upload sheet", body: "Drag a file to begin (demo).", kind: "info" }) },
    { id: "invite",      label: "Invite a client reviewer…", icon: "Send", group: "Actions", action: () => ToastEvents.emit({ title: "Invitation sent", body: "Demo only — wires to /invitations in Phase 2.", kind: "success" }) },
    { id: "approve",     label: "Mark a draft approved…", icon: "Check", group: "Actions", action: () => ToastEvents.emit({ title: "Approve flow", body: "Pick a project to mark its current draft approved.", kind: "info" }) },
  ];
  const projectCommands = HD.projects.map(p => ({
    id: `p-${p.id}`, label: p.name, sub: p.client, icon: "Film", group: "Projects",
    action: () => onOpenProject(p.id),
  }));
  const clientCommands = HD.clients.map(c => ({
    id: `c-${c.id}`, label: c.name, sub: c.org, icon: "Users", group: "Clients",
    action: () => onNavigate("clients"),
  }));

  const all = [...navCommands, ...actionCommands, ...projectCommands, ...clientCommands];
  const lower = q.toLowerCase();
  const filtered = q
    ? all.filter(c => c.label.toLowerCase().includes(lower) || (c.sub || "").toLowerCase().includes(lower))
    : all;

  const groups = {};
  filtered.forEach(c => {
    if (!groups[c.group]) groups[c.group] = [];
    groups[c.group].push(c);
  });

  const [hoverId, setHoverId] = React.useState(filtered[0]?.id || null);

  React.useEffect(() => {
    setHoverId(filtered[0]?.id || null);
  }, [q]);

  const runCommand = (cmd) => {
    cmd.action();
    onClose();
  };

  const onKey = (e) => {
    if (e.key === "Escape") { onClose(); return; }
    if (e.key === "Enter") {
      const sel = filtered.find(c => c.id === hoverId) || filtered[0];
      if (sel) runCommand(sel);
      return;
    }
    if (e.key === "ArrowDown" || e.key === "ArrowUp") {
      e.preventDefault();
      const idx = filtered.findIndex(c => c.id === hoverId);
      const next = e.key === "ArrowDown"
        ? filtered[Math.min(filtered.length - 1, idx + 1)]
        : filtered[Math.max(0, idx - 1)];
      if (next) setHoverId(next.id);
    }
  };

  return (
    <Backdrop onClick={onClose} align="top">
      <div style={{
        maxWidth: 580, margin: "0 auto",
        background: "var(--charcoal)",
        border: "1px solid rgba(255,255,255,0.08)",
        borderRadius: 14,
        boxShadow: "0 40px 80px -20px rgba(0,0,0,0.6)",
        overflow: "hidden",
      }}>
        <div style={{ display: "flex", alignItems: "center", gap: 12, padding: "14px 18px", borderBottom: "1px solid rgba(255,255,255,0.05)" }}>
          <window.Icon.Search size={16} color="var(--warm-gray)" />
          <input
            ref={inputRef}
            value={q}
            onChange={(e) => setQ(e.target.value)}
            onKeyDown={onKey}
            placeholder="Search projects, clients, or jump to anywhere…"
            style={{
              flex: 1, background: "transparent", border: "none", outline: "none",
              color: "var(--white)", fontSize: 14, fontFamily: "var(--sans)",
            }}
          />
          <Kbd>ESC</Kbd>
        </div>
        <div style={{ maxHeight: 440, overflow: "auto", padding: "8px 0" }}>
          {filtered.length === 0 ? (
            <div style={{ padding: "32px 20px", textAlign: "center", color: "var(--warm-gray)", fontSize: 13 }}>
              Nothing matches "{q}".
            </div>
          ) : (
            Object.keys(groups).map(g => (
              <div key={g}>
                <div className="micro" style={{ color: "var(--warm-gray)", padding: "12px 18px 6px", fontSize: 9.5 }}>{g.toUpperCase()}</div>
                {groups[g].map(c => {
                  const IconComp = window.Icon[c.icon];
                  return (
                    <button
                      key={c.id}
                      onClick={() => runCommand(c)}
                      onMouseEnter={() => setHoverId(c.id)}
                      style={{
                        display: "flex", alignItems: "center", gap: 12, width: "100%",
                        padding: "10px 18px", textAlign: "left",
                        background: hoverId === c.id ? "rgba(29,78,216,0.10)" : "transparent",
                        border: "none", cursor: "pointer",
                        color: "var(--white)", fontFamily: "var(--sans)",
                      }}
                    >
                      <div style={{
                        width: 28, height: 28, borderRadius: 7,
                        background: "rgba(255,255,255,0.04)", border: "1px solid rgba(255,255,255,0.06)",
                        color: hoverId === c.id ? "var(--harbor-2)" : "var(--warm-gray)",
                        display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0,
                      }}><IconComp size={13} /></div>
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div style={{ fontSize: 13, fontWeight: 500, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{c.label}</div>
                        {c.sub && <div style={{ fontSize: 11, color: "var(--warm-gray)", marginTop: 2, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{c.sub}</div>}
                      </div>
                      {hoverId === c.id && <window.Icon.Arrow size={12} color="var(--warm-gray)" />}
                    </button>
                  );
                })}
              </div>
            ))
          )}
        </div>
        <div style={{ padding: "10px 18px", borderTop: "1px solid rgba(255,255,255,0.05)", display: "flex", alignItems: "center", justifyContent: "space-between", fontSize: 11, color: "var(--warm-gray)" }}>
          <div style={{ display: "flex", gap: 12 }}>
            <span style={{ display: "inline-flex", alignItems: "center", gap: 4 }}><Kbd>↑</Kbd><Kbd>↓</Kbd> navigate</span>
            <span style={{ display: "inline-flex", alignItems: "center", gap: 4 }}><Kbd>↵</Kbd> select</span>
          </div>
          <span>{filtered.length} result{filtered.length === 1 ? "" : "s"}</span>
        </div>
      </div>
    </Backdrop>
  );
};

// ---------- Notifications Sheet ----------
const NotificationsSheet = ({ onClose, onOpenProject }) => {
  const [items, setItems] = React.useState([
    { id: 1, who: "Roy Bahnam", what: "left 3 timecoded comments on Cambridge Listing — Cut 03", at: "10 min ago", icon: "Message", accent: "harbor", unread: true, projectId: "sarkis-cambridge" },
    { id: 2, who: "Lucius Firmin", what: "approved Founder Story — Color pass v2", at: "1h ago", icon: "CheckCircle", accent: "amber", unread: true, projectId: "lucius-fashion" },
    { id: 3, who: "Bluehill Nutrition", what: "uploaded 4 new assets to product launch intake", at: "3h ago", icon: "Upload", accent: "teal", unread: true, projectId: "bluehill-launch" },
    { id: 4, who: "OOO Creators", what: "downloaded final delivery for Episode 14", at: "Yesterday", icon: "Download", accent: "lavender", unread: false, projectId: "ooo-retainer" },
    { id: 5, who: "Maren K.", what: "marked deliverable Square cut as ready on Cambridge", at: "Yesterday", icon: "Check", accent: "harbor", unread: false, projectId: "sarkis-cambridge" },
    { id: 6, who: "Theo R.", what: "started color pass on Beacon Hill Luxury", at: "2 days ago", icon: "Sparkle", accent: "steel", unread: false, projectId: "sarkis-luxury" },
  ]);

  const markAllRead = () => setItems(prev => prev.map(i => ({ ...i, unread: false })));
  const unreadCount = items.filter(i => i.unread).length;

  return (
    <Sheet
      onClose={onClose}
      eyebrow="ALL CHANNELS"
      title={`Notifications${unreadCount ? ` · ${unreadCount} new` : ""}`}
      width={400}
    >
      <div style={{ padding: "10px 16px", display: "flex", justifyContent: "space-between", alignItems: "center", borderBottom: "1px solid rgba(255,255,255,0.04)" }}>
        <div style={{ display: "flex", gap: 4, padding: 3, background: "rgba(255,255,255,0.03)", border: "1px solid rgba(255,255,255,0.05)", borderRadius: 7 }}>
          <button style={{ padding: "4px 10px", borderRadius: 5, background: "rgba(255,255,255,0.06)", color: "var(--white)", border: "none", fontSize: 11.5, fontFamily: "var(--sans)", cursor: "pointer" }}>All</button>
          <button style={{ padding: "4px 10px", borderRadius: 5, background: "transparent", color: "var(--warm-gray)", border: "none", fontSize: 11.5, fontFamily: "var(--sans)", cursor: "pointer" }}>Mentions</button>
        </div>
        <button onClick={markAllRead} style={{
          background: "transparent", border: "none", color: "var(--harbor-2)",
          fontSize: 11.5, cursor: "pointer", fontFamily: "var(--sans)",
        }}>Mark all read</button>
      </div>
      <div>
        {items.map((n, i) => {
          const tone = STATUS_TONES[n.accent];
          const IconComp = window.Icon[n.icon];
          return (
            <button
              key={n.id}
              onClick={() => { onOpenProject(n.projectId); onClose(); }}
              style={{
                display: "flex", alignItems: "flex-start", gap: 12,
                width: "100%", padding: "14px 16px",
                background: "transparent", border: "none",
                borderBottom: i === items.length - 1 ? "none" : "1px solid rgba(255,255,255,0.04)",
                cursor: "pointer", textAlign: "left",
                position: "relative",
                color: "var(--white)", fontFamily: "var(--sans)",
                transition: "background 120ms ease",
              }}
              onMouseEnter={(e) => (e.currentTarget.style.background = "rgba(255,255,255,0.025)")}
              onMouseLeave={(e) => (e.currentTarget.style.background = "transparent")}
            >
              {n.unread && <span style={{ position: "absolute", left: 5, top: 22, width: 5, height: 5, borderRadius: 99, background: "var(--harbor-2)" }} />}
              <div style={{
                width: 32, height: 32, borderRadius: 8,
                background: tone.bg, border: `1px solid ${tone.bd}`, color: tone.fg,
                display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0,
              }}><IconComp size={14} /></div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 12.5, lineHeight: 1.5 }}>
                  <span style={{ fontWeight: 500 }}>{n.who}</span>
                  <span style={{ color: "var(--warm-gray)" }}> {n.what}</span>
                </div>
                <div style={{ fontSize: 11, color: "var(--warm-gray)", marginTop: 4 }}>{n.at}</div>
              </div>
            </button>
          );
        })}
      </div>
      <div style={{ padding: 16, borderTop: "1px solid rgba(255,255,255,0.05)", textAlign: "center" }}>
        <button style={{
          background: "transparent", border: "none", color: "var(--warm-gray)",
          fontSize: 12, cursor: "pointer", fontFamily: "var(--sans)",
        }}>Notification settings</button>
      </div>
    </Sheet>
  );
};

// ---------- New Project Modal ----------
const NewProjectModal = ({ onClose }) => {
  const [name, setName] = React.useState("");
  const [client, setClient] = React.useState(HD.clients[0].id);
  const [template, setTemplate] = React.useState("listing");
  const [due, setDue] = React.useState("");
  const templates = [
    { id: "listing", label: "Listing film", body: "Single-take exterior, slow-paced interiors, finishing." },
    { id: "youtube", label: "YouTube long-form", body: "Interview selects, B-roll, color, sound, captions." },
    { id: "launch",  label: "Launch suite", body: "Hero film + 9:16 cutdowns + stills package." },
    { id: "podcast", label: "Podcast episode", body: "Episode audio + transcript review + clip cuts." },
    { id: "retainer", label: "Retainer episode", body: "Weekly cadence with shared brief and asset pool." },
    { id: "custom",  label: "Custom", body: "Start blank — configure surfaces yourself." },
  ];
  const onCreate = () => {
    ToastEvents.emit({
      kind: "success",
      title: "Project created",
      body: `${name || "Untitled project"} is live — share the portal link with your client.`,
    });
    onClose();
  };
  return (
    <Modal
      eyebrow="NEW PROJECT"
      title="Kick off a HarborDock portal"
      onClose={onClose}
      maxWidth={620}
      footer={<>
        <Button variant="ghost" size="md" onClick={onClose}>Cancel</Button>
        <Button variant="primary" size="md" onClick={onCreate} icon={<window.Icon.Plus size={13} />}>Create project</Button>
      </>}
    >
      <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
        <FormRow label="Project name" hint="Visible to your client.">
          <input
            value={name}
            onChange={(e) => setName(e.target.value)}
            placeholder="93 Third St. Cambridge Listing Video"
            style={{
              width: "100%", background: "rgba(255,255,255,0.025)",
              border: "1px solid rgba(255,255,255,0.08)", borderRadius: 8,
              padding: "10px 12px", color: "var(--white)", fontSize: 13,
              fontFamily: "var(--sans)", outline: "none",
            }}
          />
        </FormRow>

        <FormRow label="Client">
          <div style={{ position: "relative" }}>
            <select
              value={client}
              onChange={(e) => setClient(e.target.value)}
              style={{
                width: "100%", background: "rgba(255,255,255,0.025)",
                border: "1px solid rgba(255,255,255,0.08)", borderRadius: 8,
                padding: "10px 12px", color: "var(--white)", fontSize: 13,
                fontFamily: "var(--sans)", outline: "none", appearance: "none",
              }}
            >
              {HD.clients.map(c => <option key={c.id} value={c.id} style={{ background: "var(--charcoal)" }}>{c.name}</option>)}
            </select>
            <window.Icon.ChevronD size={12} color="var(--warm-gray)" style={{ position: "absolute", right: 12, top: "50%", transform: "translateY(-50%)", pointerEvents: "none" }} />
          </div>
        </FormRow>

        <FormRow label="Template" hint="Sets the default surfaces and revision rounds.">
          <div className="md-2col" style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 8 }}>
            {templates.map(t => (
              <button
                key={t.id}
                onClick={() => setTemplate(t.id)}
                style={{
                  padding: 10, borderRadius: 8, cursor: "pointer", textAlign: "left",
                  background: template === t.id ? "rgba(29,78,216,0.10)" : "rgba(255,255,255,0.025)",
                  border: template === t.id ? "1px solid rgba(29,78,216,0.32)" : "1px solid rgba(255,255,255,0.06)",
                  fontFamily: "var(--sans)", color: "var(--white)",
                }}
              >
                <div style={{ fontSize: 12, fontWeight: 500, color: template === t.id ? "#9CC1FF" : "var(--white)" }}>{t.label}</div>
                <div style={{ fontSize: 10.5, color: "var(--warm-gray)", marginTop: 4, lineHeight: 1.4 }}>{t.body}</div>
              </button>
            ))}
          </div>
        </FormRow>

        <FormRow label="Due date">
          <input
            value={due}
            onChange={(e) => setDue(e.target.value)}
            placeholder="e.g. May 24"
            style={{
              width: "100%", background: "rgba(255,255,255,0.025)",
              border: "1px solid rgba(255,255,255,0.08)", borderRadius: 8,
              padding: "10px 12px", color: "var(--white)", fontSize: 13,
              fontFamily: "var(--sans)", outline: "none",
            }}
          />
        </FormRow>
      </div>
    </Modal>
  );
};

const FormRow = ({ label, hint, children }) => (
  <div>
    <label style={{ display: "block", marginBottom: 6 }}>
      <span style={{ fontSize: 12, fontWeight: 500, color: "var(--white)" }}>{label}</span>
      {hint && <span style={{ marginLeft: 8, fontSize: 11, color: "var(--warm-gray)" }}>{hint}</span>}
    </label>
    {children}
  </div>
);

// ---------- Share Portal Modal ----------
// Generates a secret, copyable, no-login link to a client portal.
const SharePortalModal = ({ onClose, clientId, onPreviewPortal }) => {
  const initial = HD.portalAccess[clientId] || HD.portalAccess.sarkis;
  const client = HD.clients.find(c => c.id === clientId) || HD.clients[0];

  const [enabled, setEnabled] = React.useState(initial.enabled !== false);
  const [requirePasscode, setRequirePasscode] = React.useState(initial.requirePasscode || false);
  const [passcode, setPasscode] = React.useState(initial.passcode || "");
  const [allowDownloads, setAllowDownloads] = React.useState(initial.allowDownloads !== false);
  const [allowComments, setAllowComments] = React.useState(initial.allowComments !== false);
  const [expiry, setExpiry] = React.useState(initial.expiresAt || "");

  const url = `https://harbor.dk/p/${initial.token}`;
  const [copied, setCopied] = React.useState(false);
  const copyLink = async () => {
    try {
      await navigator.clipboard.writeText(url);
      setCopied(true);
      ToastEvents.emit({ kind: "success", title: "Portal link copied", body: "Send it to your client — they don't need an account." });
      setTimeout(() => setCopied(false), 2200);
    } catch {
      ToastEvents.emit({ kind: "info", title: "Copy failed", body: "Select the URL manually." });
    }
  };

  const regenerate = () => {
    ToastEvents.emit({ kind: "info", title: "New link generated", body: "The old link is dead — anyone holding it will get a 404." });
  };

  return (
    <Modal
      onClose={onClose}
      eyebrow="SHARE CLIENT PORTAL"
      title={`${client.name.split(" / ")[0]} · public access`}
      maxWidth={620}
      footer={
        <>
          <Button variant="ghost" size="md" onClick={onClose}>Close</Button>
          <Button variant="ghost" size="md" icon={<window.Icon.Eye size={12} />} onClick={() => { onClose(); onPreviewPortal?.(clientId); }}>Preview as client</Button>
          <Button variant="primary" size="md" icon={<window.Icon.Copy size={12} />} onClick={copyLink}>{copied ? "Copied!" : "Copy link"}</Button>
        </>
      }
    >
      <div style={{ display: "flex", flexDirection: "column", gap: 20 }}>
        {/* Link block */}
        <div>
          <div className="micro" style={{ color: "var(--warm-gray)", marginBottom: 8 }}>SECURE LINK</div>
          <div style={{
            display: "flex", alignItems: "center", gap: 8,
            padding: "10px 12px", background: "rgba(255,255,255,0.025)",
            border: "1px solid rgba(255,255,255,0.08)", borderRadius: 10,
          }}>
            <window.Icon.Link size={14} color="var(--warm-gray)" />
            <span className="mono" style={{
              flex: 1, minWidth: 0, fontSize: 12, color: "var(--white)",
              whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis",
            }}>{url}</span>
            <button onClick={copyLink} style={{
              background: "transparent", border: "1px solid rgba(255,255,255,0.10)",
              color: "var(--white)", padding: "4px 8px", borderRadius: 6,
              fontSize: 11, cursor: "pointer", fontFamily: "var(--sans)",
              display: "inline-flex", alignItems: "center", gap: 4,
            }}>{copied ? <><window.Icon.Check size={11} stroke={3} /> Copied</> : <><window.Icon.Copy size={11} /> Copy</>}</button>
          </div>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: 8, gap: 12 }}>
            <div style={{ fontSize: 11, color: "var(--warm-gray)" }}>
              Anyone with this link can view the portal{requirePasscode ? ", after entering the passcode" : ""}.
              No account required.
            </div>
            <button onClick={regenerate} style={{
              background: "transparent", border: "none", color: "var(--harbor-2)",
              fontSize: 11.5, cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 4,
              fontFamily: "var(--sans)", flexShrink: 0,
            }}><window.Icon.Refresh size={11} /> Regenerate</button>
          </div>
        </div>

        <Divider />

        {/* Master toggle */}
        <ShareToggle
          icon="Globe"
          title="Portal is live"
          body={enabled ? "Anyone with the link (and passcode) can view." : "Link returns a 404. Existing reviewers will see a paused screen."}
          on={enabled}
          onChange={setEnabled}
        />

        {/* Security row */}
        <div>
          <div className="micro" style={{ color: "var(--warm-gray)", marginBottom: 10 }}>SECURITY</div>
          <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
            <ShareToggle
              icon="Lock"
              title="Require 4-digit passcode"
              body="Reviewers enter a passcode after opening the link."
              on={requirePasscode}
              onChange={setRequirePasscode}
              inline={requirePasscode ? (
                <input
                  value={passcode}
                  onChange={(e) => setPasscode(e.target.value.replace(/\D/g, "").slice(0, 4))}
                  maxLength={4} inputMode="numeric"
                  placeholder="0000"
                  className="mono"
                  style={{
                    width: 80, padding: "6px 10px",
                    background: "rgba(255,255,255,0.05)", border: "1px solid rgba(255,255,255,0.10)",
                    color: "var(--white)", borderRadius: 6, fontSize: 14,
                    letterSpacing: "0.18em", textAlign: "center", outline: "none",
                  }}
                />
              ) : null}
            />
            <ShareToggle
              icon="Clock"
              title="Link expires"
              body={expiry ? `Link will stop working after ${expiry}.` : "Link works until you disable it."}
              on={!!expiry}
              onChange={(v) => setExpiry(v ? "Jun 30, 2026" : "")}
              inline={expiry ? (
                <input
                  value={expiry}
                  onChange={(e) => setExpiry(e.target.value)}
                  placeholder="Jun 30, 2026"
                  style={{
                    width: 130, padding: "6px 10px",
                    background: "rgba(255,255,255,0.05)", border: "1px solid rgba(255,255,255,0.10)",
                    color: "var(--white)", borderRadius: 6, fontSize: 12, outline: "none",
                    fontFamily: "var(--sans)",
                  }}
                />
              ) : null}
            />
          </div>
        </div>

        {/* Capabilities */}
        <div>
          <div className="micro" style={{ color: "var(--warm-gray)", marginBottom: 10 }}>WHAT CAN THE CLIENT DO?</div>
          <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
            <ShareToggle icon="Download" title="Allow downloads" body="Reviewers can download delivered assets from the asset library." on={allowDownloads} onChange={setAllowDownloads} />
            <ShareToggle icon="Message" title="Allow comments + messaging" body="Reviewers can leave frame-accurate comments and message the studio." on={allowComments} onChange={setAllowComments} />
          </div>
        </div>

        {/* Visits */}
        <div style={{
          padding: "12px 14px", borderRadius: 10,
          background: "rgba(255,255,255,0.025)", border: "1px solid rgba(255,255,255,0.06)",
          display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12,
        }}>
          <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
            <window.Icon.Eye size={14} color="var(--warm-gray)" />
            <div>
              <div style={{ fontSize: 12.5, color: "var(--white)" }}><strong>{initial.visits}</strong> views · last opened {initial.lastViewed}</div>
              <div style={{ fontSize: 11, color: "var(--warm-gray)", marginTop: 2 }}>Audit log captures IP, device, and pages viewed.</div>
            </div>
          </div>
          <button style={{
            background: "transparent", border: "none", color: "var(--harbor-2)",
            fontSize: 11.5, cursor: "pointer", fontFamily: "var(--sans)",
          }}>View audit log</button>
        </div>
      </div>
    </Modal>
  );
};

const ShareToggle = ({ icon, title, body, on, onChange, inline }) => {
  const IconComp = window.Icon[icon] || window.Icon.Settings;
  return (
    <div style={{
      display: "flex", alignItems: "center", gap: 12,
      padding: "12px 14px",
      background: on ? "rgba(29,78,216,0.07)" : "rgba(255,255,255,0.025)",
      border: on ? "1px solid rgba(29,78,216,0.24)" : "1px solid rgba(255,255,255,0.06)",
      borderRadius: 10,
    }}>
      <div style={{
        width: 34, height: 34, borderRadius: 8,
        background: on ? "rgba(29,78,216,0.16)" : "rgba(255,255,255,0.04)",
        color: on ? "#9CC1FF" : "var(--warm-gray)",
        display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0,
      }}><IconComp size={15} /></div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 12.5, color: "var(--white)", fontWeight: 500 }}>{title}</div>
        <div style={{ fontSize: 11.5, color: "var(--warm-gray)", marginTop: 2 }}>{body}</div>
      </div>
      {inline}
      <button
        onClick={() => onChange(!on)}
        style={{
          width: 36, height: 20, borderRadius: 99,
          background: on ? "var(--harbor)" : "rgba(255,255,255,0.12)",
          position: "relative", cursor: "pointer",
          border: "none", padding: 0, flexShrink: 0, transition: "background 160ms ease",
        }}
        aria-label={`Toggle ${title}`}
      >
        <span style={{
          position: "absolute", top: 2, left: on ? 18 : 2,
          width: 16, height: 16, borderRadius: 99, background: "white",
          transition: "left 160ms cubic-bezier(.16,1,.3,1)",
          boxShadow: "0 2px 4px rgba(0,0,0,0.2)",
        }} />
      </button>
    </div>
  );
};

Object.assign(window, {
  ToastEvents, Toaster, Modal, Sheet, Backdrop,
  CommandPalette, NotificationsSheet, NewProjectModal, SharePortalModal,
});
