const { useState, useEffect, useRef, useCallback, useMemo } = React;

const API = window.location.origin + '/api';
const getHeaders = () => {
  const token = sessionStorage.getItem('crm_token');
  return { 'Content-Type': 'application/json', ...(token ? { 'Authorization': 'Bearer ' + token } : {}) };
};
const load = async () => {
  try {
    const r = await fetch(API + '/data', { headers: getHeaders() });
    if (r.status === 401) { window.location.reload(); return null; }
    const j = await r.json(); return j.data;
  } catch { return null; }
};
const persist = async (d) => {
  try {
    const clean = {...d, clients: d.clients.map(c => ({...c, files: (c.files||[]).map(f => {const {data, ...rest} = f; return rest;})}))};
    await fetch(API + '/data', {method:'POST', headers: getHeaders(), body: JSON.stringify(clean)});
  } catch(e) { console.error('Save failed:', e); }
};

const DEFAULT_COLUMNS = [
  { id: "facility", label: "Facility Name", type: "text", removable: false },
  { id: "groupOwner", label: "Group / Owner", type: "text", removable: true },
  { id: "address", label: "Address", type: "text", removable: true, hideFromTable: true },
  { id: "initialContact", label: "Initial Contact", type: "date", removable: true, isStage: true },
  { id: "referredBy", label: "Referred By", type: "text", removable: true, hideFromTable: true },
  { id: "pitchDate", label: "Pitch Date", type: "date", removable: true, isStage: true },
  { id: "projectionsDate", label: "Projections Date", type: "date", removable: true, isStage: true },
  { id: "baaDate", label: "BAA Date", type: "date", removable: true, isStage: true },
  { id: "contractSent", label: "Contract Sent", type: "date", removable: true, isStage: true },
  { id: "contractSigned", label: "Contract Signed", type: "date", removable: true, isStage: true },
  { id: "notes", label: "Notes", type: "textarea", removable: true },
];

const DEFAULT_ROLES = ["Administrator", "DON", "HR Contact", "BOM", "IT"];
const makeField = (label, value="") => ({ id: crypto.randomUUID(), label, value });
const makeContact = (role, fields=null, notes="") => ({
  id: crypto.randomUUID(), role, notes,
  fields: fields || [makeField("Name"), makeField("Phone"), makeField("Email")]
});
const makeClient = (columns) => {
  const c = { id: crypto.randomUUID(), archived: false, contacts: DEFAULT_ROLES.map(r => makeContact(r)) };
  columns.forEach(col => { c[col.id] = ""; });
  return c;
};

const mkClient = (facility, groupOwner, address) => ({
  id: crypto.randomUUID(), archived: false, facility, groupOwner, address,
  initialContact:"", referredBy:"", pitchDate:"", projectionsDate:"", baaDate:"", contractSent:"", contractSigned:"", notes:"",
  contacts: DEFAULT_ROLES.map(r => makeContact(r))
});

const SEED_DATA = () => ({
  columns: DEFAULT_COLUMNS,
  groups: [
    { id: crypto.randomUUID(), name: "CNC (David Norsworthy)", contactName: "David Norsworthy", address: "", phone: "", email: "", notes: "" },
    { id: crypto.randomUUID(), name: "Sunshine Terrace", contactName: "", address: "", phone: "", email: "", notes: "" },
    { id: crypto.randomUUID(), name: "Traditions Healthcare (Todd Bramall)", contactName: "Todd Bramall", address: "", phone: "", email: "", notes: "" },
    { id: crypto.randomUUID(), name: "Legacy Health (Molly & Jay Frances)", contactName: "Molly & Jay Frances", address: "", phone: "", email: "", notes: "" },
    { id: crypto.randomUUID(), name: "Continuum Group (Amy Lubsen)", contactName: "Amy Lubsen", address: "", phone: "", email: "", notes: "" },
    { id: crypto.randomUUID(), name: "Spanish Fork Rehab and Nursing", contactName: "", address: "", phone: "", email: "", notes: "" },
  ],
  clients: [
    mkClient("CNC Arkansas Facility", "CNC (David Norsworthy)", "AR"),
    mkClient("Sunshine Terrace Skilled Nursing & Rehabilitation", "Sunshine Terrace", "345 N 200 W, Logan, UT"),
    mkClient("San Rafael Health and Rehabilitation", "Traditions Healthcare (Todd Bramall)", "Ferron, UT"),
    mkClient("Millard County Care and Rehabilitation", "Traditions Healthcare (Todd Bramall)", "Delta, UT"),
    mkClient("Seasons Healthcare and Rehabilitation", "Traditions Healthcare (Todd Bramall)", "St. George, UT"),
    mkClient("Brighton Cornerstone", "Legacy Health (Molly & Jay Frances)", "55 East North Street, Madisonville, KY"),
    mkClient("Pioneer Trace Nursing", "Legacy Health (Molly & Jay Frances)", "115 Pioneer Trace, Flemingsburg, KY"),
    mkClient("Willowbrook Healthcare", "Legacy Health (Molly & Jay Frances)", "2323 Concrete Road, Carlisle, KY"),
    mkClient("Barnegat Rehab and Nursing Center", "Continuum Group (Amy Lubsen)", "859 West Bay Ave, Barnegat, NJ"),
    mkClient("Bloomingdale Rehab and Nursing Center", "Continuum Group (Amy Lubsen)", "255 Union Ave, Bloomingdale, NJ"),
    mkClient("Galloway Nursing and Rehabilitation", "Continuum Group (Amy Lubsen)", "66 West Jimmie Leeds Road, Galloway Township, NJ"),
    mkClient("Spanish Fork Rehab and Nursing", "Spanish Fork Rehab and Nursing", "UT"),
  ]
});

function CRM() {
  const [data, setData] = useState(null);
  const [view, setView] = useState("table");
  const [activeClient, setActiveClient] = useState(null);
  const [search, setSearch] = useState("");
  const [showArchived, setShowArchived] = useState(false);
  const [sortCol, setSortCol] = useState(null);
  const [sortDir, setSortDir] = useState("asc");
  const [colModal, setColModal] = useState(false);
  const [newColName, setNewColName] = useState("");
  const [newColType, setNewColType] = useState("text");
  const [dragCol, setDragCol] = useState(null);
  const [dragOver, setDragOver] = useState(null);
  const [editingNote, setEditingNote] = useState(null);
  const [noteVal, setNoteVal] = useState("");
  const [deleteConfirm, setDeleteConfirm] = useState(null);
  const noteRef = useRef(null);
  const tableRef = useRef(null);

  useEffect(() => {
    load().then(d => {
      if (d?.columns && d?.clients) {
        if (!d.groups) d.groups = [];
        setData(d);
      } else { const seed = SEED_DATA(); setData(seed); persist(seed); }
    });
  }, []);

  const updateData = useCallback((fn) => {
    setData(prev => { const next = fn(prev); persist(next); return next; });
  }, []);

  const addColumn = () => {
    if (!newColName.trim()) return;
    const id = "c_" + Date.now();
    updateData(d => ({
      ...d,
      columns: [...d.columns, { id, label: newColName.trim(), type: newColType, removable: true, isStage: newColType === "date" }],
      clients: d.clients.map(c => ({ ...c, [id]: "" }))
    }));
    setNewColName(""); setNewColType("text"); setColModal(false);
  };

  const removeColumn = (colId) => {
    updateData(d => ({
      ...d,
      columns: d.columns.filter(c => c.id !== colId),
      clients: d.clients.map(c => { const n = { ...c }; delete n[colId]; return n; })
    }));
  };

  const handleColDrop = (idx) => {
    if (dragCol === null || dragCol === idx) { setDragCol(null); setDragOver(null); return; }
    updateData(d => {
      const cols = [...d.columns];
      const [moved] = cols.splice(dragCol, 1);
      cols.splice(idx, 0, moved);
      return { ...d, columns: cols };
    });
    setDragCol(null); setDragOver(null);
  };

  // ─── Pipeline stage management ───
  const [stageModal, setStageModal] = useState(false);
  const [newStageName, setNewStageName] = useState("");

  const addStage = () => {
    if (!newStageName.trim()) return;
    const id = "stage_" + Date.now();
    // Insert before the notes column (or at end if no notes)
    updateData(d => {
      const notesIdx = d.columns.findIndex(c => c.id === "notes");
      const newCol = { id, label: newStageName.trim(), type: "date", removable: true, isStage: true };
      const cols = [...d.columns];
      if (notesIdx >= 0) cols.splice(notesIdx, 0, newCol);
      else cols.push(newCol);
      return { ...d, columns: cols, clients: d.clients.map(c => ({ ...c, [id]: "" })) };
    });
    setNewStageName("");
    setStageModal(false);
  };

  const renameStage = (colId, newLabel) => {
    updateData(d => ({
      ...d,
      columns: d.columns.map(c => c.id === colId ? { ...c, label: newLabel } : c)
    }));
  };

  const deleteStage = (colId) => {
    updateData(d => ({
      ...d,
      columns: d.columns.filter(c => c.id !== colId),
      clients: d.clients.map(c => {
        const n = { ...c };
        delete n[colId];
        // Also remove files associated with this stage
        if (n.files) n.files = n.files.filter(f => f.stageId !== colId);
        return n;
      })
    }));
  };

  const moveStage = (colId, direction) => {
    updateData(d => {
      const cols = [...d.columns];
      const idx = cols.findIndex(c => c.id === colId);
      if (idx < 0) return d;
      // Find next/prev stage column (skip non-stage columns)
      let targetIdx = idx;
      if (direction === "up") {
        for (let i = idx - 1; i >= 0; i--) {
          if (cols[i].isStage) { targetIdx = i; break; }
        }
      } else {
        for (let i = idx + 1; i < cols.length; i++) {
          if (cols[i].isStage) { targetIdx = i; break; }
        }
      }
      if (targetIdx === idx) return d;
      const [moved] = cols.splice(idx, 1);
      cols.splice(targetIdx, 0, moved);
      return { ...d, columns: cols };
    });
  };

  const addClient = () => {
    updateData(d => ({ ...d, clients: [...d.clients, makeClient(d.columns)] }));
    setTimeout(() => tableRef.current?.scrollTo({ top: tableRef.current.scrollHeight, behavior: "smooth" }), 80);
  };

  const updateField = (clientId, key, value) => {
    if (key === "facility") {
      const oldClient = data.clients.find(c => c.id === clientId);
      if (oldClient && oldClient.facility && oldClient.facility !== value) {
        fetch(API + '/rename-folder', {method:'POST', headers: getHeaders(), body: JSON.stringify({oldName: oldClient.facility, newName: value})}).catch(()=>{});
      }
    }
    updateData(d => ({ ...d, clients: d.clients.map(c => c.id === clientId ? { ...c, [key]: value } : c) }));
  };

  const archiveClient = (clientId) => {
    updateData(d => ({ ...d, clients: d.clients.map(c => c.id === clientId ? { ...c, archived: !c.archived } : c) }));
  };

  const deleteClient = (clientId) => {
    updateData(d => ({ ...d, clients: d.clients.filter(c => c.id !== clientId) }));
    setDeleteConfirm(null);
    if (activeClient === clientId) { setView("table"); setActiveClient(null); }
  };

  const updateContact = (clientId, contactId, field, value) => {
    updateData(d => ({
      ...d,
      clients: d.clients.map(c => c.id === clientId ? {
        ...c, contacts: c.contacts.map(ct => ct.id === contactId ? { ...ct, [field]: value } : ct)
      } : c)
    }));
  };

  const updateContactField = (clientId, contactId, fieldId, key, value) => {
    updateData(d => ({
      ...d,
      clients: d.clients.map(c => c.id === clientId ? {
        ...c, contacts: c.contacts.map(ct => ct.id === contactId ? {
          ...ct, fields: ct.fields.map(f => f.id === fieldId ? { ...f, [key]: value } : f)
        } : ct)
      } : c)
    }));
  };

  const addContactField = (clientId, contactId) => {
    updateData(d => ({
      ...d,
      clients: d.clients.map(c => c.id === clientId ? {
        ...c, contacts: c.contacts.map(ct => ct.id === contactId ? {
          ...ct, fields: [...(ct.fields || []), makeField("New Field")]
        } : ct)
      } : c)
    }));
  };

  const removeContactField = (clientId, contactId, fieldId) => {
    updateData(d => ({
      ...d,
      clients: d.clients.map(c => c.id === clientId ? {
        ...c, contacts: c.contacts.map(ct => ct.id === contactId ? {
          ...ct, fields: (ct.fields || []).filter(f => f.id !== fieldId)
        } : ct)
      } : c)
    }));
  };

  const reorderContactFields = (clientId, contactId, fromIdx, toIdx) => {
    if (fromIdx === toIdx) return;
    updateData(d => ({
      ...d,
      clients: d.clients.map(c => c.id === clientId ? {
        ...c, contacts: c.contacts.map(ct => {
          if (ct.id !== contactId) return ct;
          const fields = [...(ct.fields || [])];
          const [moved] = fields.splice(fromIdx, 1);
          fields.splice(toIdx, 0, moved);
          return { ...ct, fields };
        })
      } : c)
    }));
  };

  const [dragFieldInfo, setDragFieldInfo] = useState(null);
  const [dragFieldOver, setDragFieldOver] = useState(null);
  const [fileDragOver, setFileDragOver] = useState(null);

  const uploadFileToServer = async (file, facility, storedName) => {
    const token = sessionStorage.getItem('crm_token');
    const formData = new FormData();
    formData.append('facility', facility);
    formData.append('storedName', storedName);
    formData.append('file', file);
    try {
      const r = await fetch(API + '/upload', {method:'POST', headers: token ? {'Authorization':'Bearer '+token} : {}, body: formData});
      const j = await r.json();
      return j.path || null;
    } catch(e) { console.error('Upload failed:', e); return null; }
  };

  const downloadFile = (f) => {
    const a = document.createElement("a");
    a.href = f.serverPath || f.data || '#';
    a.download = f.storedName;
    a.target = "_blank";
    a.click();
  };

  const removeFile = (clientId, fileId) => {
    const client = data.clients.find(c => c.id === clientId);
    const file = client?.files?.find(f => f.id === fileId);
    if (file && client) {
      fetch(API + '/delete-file', {method:'POST', headers: getHeaders(), body: JSON.stringify({facility: client.facility, storedName: file.storedName})}).catch(()=>{});
    }
    updateData(d => ({
      ...d,
      clients: d.clients.map(c => c.id === clientId ? {
        ...c, files: (c.files || []).filter(f => f.id !== fileId)
      } : c)
    }));
  };

  const formatSize = (bytes) => {
    if (bytes < 1024) return bytes + " B";
    if (bytes < 1048576) return (bytes / 1024).toFixed(1) + " KB";
    return (bytes / 1048576).toFixed(1) + " MB";
  };

  const addContact = (clientId) => {
    updateData(d => ({
      ...d,
      clients: d.clients.map(c => c.id === clientId ? { ...c, contacts: [...(c.contacts || []), makeContact("New Contact")] } : c)
    }));
  };

  const removeContact = (clientId, contactId) => {
    updateData(d => ({
      ...d,
      clients: d.clients.map(c => c.id === clientId ? { ...c, contacts: (c.contacts || []).filter(ct => ct.id !== contactId) } : c)
    }));
  };

  const exportCSV = () => {
    if (!data) return;
    const h = data.columns.map(c => c.label);
    const rows = data.clients.filter(c => !c.archived).map(r => data.columns.map(c => `"${(r[c.id] || "").replace(/"/g, '""')}"`));
    const csv = [h.join(","), ...rows.map(r => r.join(","))].join("\n");
    const b = new Blob([csv], { type: "text/csv" });
    const a = document.createElement("a"); a.href = URL.createObjectURL(b);
    a.download = `crm-${new Date().toISOString().slice(0, 10)}.csv`; a.click();
  };

  const stageColumns = useMemo(() => data ? data.columns.filter(c => c.isStage) : [], [data]);
  const tableColumns = useMemo(() => data ? data.columns.filter(c => !c.hideFromTable) : [], [data]);

  const getStageCount = (client) => {
    let n = 0;
    for (const sc of stageColumns) { if (client[sc.id]) n++; else break; }
    return n;
  };

  const filtered = useMemo(() => {
    if (!data) return [];
    let list = data.clients.filter(c => showArchived ? c.archived : !c.archived);
    if (search) {
      const q = search.toLowerCase();
      list = list.filter(r => {
        // Search columns
        if (data.columns.some(col => (r[col.id] || "").toLowerCase().includes(q))) return true;
        // Search contacts: role, notes, and all dynamic fields
        if ((r.contacts || []).some(ct =>
          (ct.role || "").toLowerCase().includes(q) ||
          (ct.notes || "").toLowerCase().includes(q) ||
          (ct.fields || []).some(f =>
            (f.label || "").toLowerCase().includes(q) ||
            (f.value || "").toLowerCase().includes(q)
          )
        )) return true;
        return false;
      });
    }
    if (sortCol) {
      list = [...list].sort((a, b) => {
        const va = (a[sortCol] || "").toLowerCase(), vb = (b[sortCol] || "").toLowerCase();
        return sortDir === "asc" ? va.localeCompare(vb) : vb.localeCompare(va);
      });
    }
    return list;
  }, [data, search, sortCol, sortDir, showArchived, stageColumns]);

  if (!data) return <div style={S.loadWrap}><div style={S.spinner}/><p style={{color:"#6b7a90",marginTop:14,fontFamily:"var(--ff)"}}>Loading…</p></div>;

  // ─── Group helpers ───
  const groups = data.groups || [];
  const updateGroup = (groupId, field, value) => {
    updateData(d => ({ ...d, groups: (d.groups||[]).map(g => g.id === groupId ? { ...g, [field]: value } : g) }));
  };
  const addGroup = (name) => {
    const g = { id: crypto.randomUUID(), name: name || "New Group", contactName: "", address: "", phone: "", email: "", notes: "" };
    updateData(d => ({ ...d, groups: [...(d.groups||[]), g] }));
  };
  const deleteGroup = (groupId) => {
    updateData(d => ({ ...d, groups: (d.groups||[]).filter(g => g.id !== groupId) }));
  };
  const getGroupFacilities = (groupName) => data.clients.filter(c => c.groupOwner === groupName && !c.archived);

  // ═══════════════ GROUPS PAGE ═══════════════
  if (view === "groups") {
    return (
      <div style={S.app}><Fonts/>
        <button style={S.backBtn} onClick={() => setView("table")}>
          <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"><polyline points="15 18 9 12 15 6"/></svg>
          All Clients
        </button>
        <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:20,flexWrap:"wrap",gap:12}}>
          <div>
            <h1 style={S.title}>Group / Owner Directory</h1>
            <p style={S.subtitle}>Andrea's Client Pipeline</p>
          </div>
          <button style={S.btnPri} onClick={()=>addGroup("")}>
            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
            Add Group
          </button>
        </div>

        <div style={{display:"flex",flexDirection:"column",gap:16}}>
          {groups.map(g => {
            const facilities = getGroupFacilities(g.name);
            return (
              <div key={g.id} style={S.card}>
                <div style={{...S.cardHead,padding:"12px 16px"}}>
                  <input style={{...S.roleIn,fontSize:16,fontWeight:700}} value={g.name} onChange={e=>{
                    const oldName = g.name;
                    const newName = e.target.value;
                    // Update group name and all clients that reference it
                    updateData(d => ({
                      ...d,
                      groups: (d.groups||[]).map(gr => gr.id === g.id ? { ...gr, name: newName } : gr),
                      clients: d.clients.map(c => c.groupOwner === oldName ? { ...c, groupOwner: newName } : c)
                    }));
                  }} placeholder="Group / Owner Name"/>
                  <button style={{...S.xBtn,fontSize:16}} onClick={()=>deleteGroup(g.id)} title="Remove group">✕</button>
                </div>
                <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:0}}>
                  {/* Left: Contact info */}
                  <div style={{padding:16,borderRight:"1px solid var(--border)",display:"flex",flexDirection:"column",gap:10}}>
                    <div>
                      <label style={S.fLabel}>Contact Name</label>
                      <input style={S.fIn} value={g.contactName||""} onChange={e=>updateGroup(g.id,"contactName",e.target.value)} placeholder="Primary contact for group"/>
                    </div>
                    <div>
                      <label style={S.fLabel}>Address</label>
                      <input style={S.fIn} value={g.address||""} onChange={e=>updateGroup(g.id,"address",e.target.value)} placeholder="Address"/>
                    </div>
                    <div>
                      <label style={S.fLabel}>Phone</label>
                      <input style={S.fIn} value={g.phone||""} onChange={e=>updateGroup(g.id,"phone",e.target.value)} placeholder="Phone"/>
                    </div>
                    <div>
                      <label style={S.fLabel}>Email</label>
                      <input style={S.fIn} value={g.email||""} onChange={e=>updateGroup(g.id,"email",e.target.value)} placeholder="Email"/>
                    </div>
                    <div>
                      <label style={S.fLabel}>Notes</label>
                      <DateStampedNotes value={g.notes||""} onChange={v=>updateGroup(g.id,"notes",v)} placeholder="Add a note…" minHeight={60}/>
                    </div>
                  </div>
                  {/* Right: Facilities owned */}
                  <div style={{padding:16}}>
                    <label style={S.fLabel}>Facilities Owned ({facilities.length})</label>
                    {facilities.length > 0 ? (
                      <div style={{display:"flex",flexDirection:"column",gap:6,marginTop:6}}>
                        {facilities.map(f => (
                          <button key={f.id} style={{...S.matchCard,cursor:"pointer",textAlign:"left",border:"1px solid var(--border)"}} onClick={()=>{setActiveClient(f.id);setView("client");}}>
                            <span style={{fontSize:14,fontWeight:600,color:"var(--accent)"}}>{f.facility}</span>
                            <span style={{fontSize:12,color:"var(--text3)"}}>{f.address||"No address"}</span>
                          </button>
                        ))}
                      </div>
                    ) : (
                      <p style={{fontSize:13,color:"var(--text3)",marginTop:8}}>No facilities linked to this group yet. Set a client's "Group / Owner" field to "{g.name}" to link it here.</p>
                    )}
                  </div>
                </div>
              </div>
            );
          })}
          {groups.length === 0 && (
            <div style={S.empty}>
              <p style={{color:"var(--text3)",fontSize:14}}>No groups yet</p>
              <p style={{color:"var(--text3)",fontSize:12}}>Click "Add Group" to start tracking ownership groups</p>
            </div>
          )}
        </div>
      </div>
    );
  }

  // ═══════════════ CLIENT DETAIL PAGE ═══════════════
  if (view === "client" && activeClient) {
    const client = data.clients.find(c => c.id === activeClient);
    if (!client) { setView("table"); return null; }

    return (
      <div style={S.app}><Fonts/>
        <button style={S.backBtn} onClick={() => { setView("table"); setActiveClient(null); }}>
          <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"><polyline points="15 18 9 12 15 6"/></svg>
          All Clients
        </button>

        <div style={S.clientHeader}>
          <div style={{flex:1}}>
            <input style={S.clientTitle} value={client.facility||""} onChange={e=>updateField(client.id,"facility",e.target.value)} placeholder="Facility Name"/>
            <input style={S.clientSub} value={client.address||""} onChange={e=>updateField(client.id,"address",e.target.value)} placeholder="Address"/>
          </div>
          <button style={{...S.btnSm, background: client.archived?"#dcfce7":"#fef3c7", color: client.archived?"#16a34a":"#b45309", border: client.archived?"1px solid #86efac":"1px solid #fcd34d"}}
            onClick={()=>archiveClient(client.id)}>
            {client.archived ? "Reactivate" : "Archive Client"}
          </button>
        </div>

        <div style={S.clientGrid}>
          {/* LEFT — Contacts + Notes */}
          <div style={S.leftCol}>
            <div style={S.sectionBar}>
              <h3 style={S.secTitle}>Contacts</h3>
              <button style={S.addSmBtn} onClick={()=>addContact(client.id)}>+ Add Contact</button>
            </div>
            {(client.contacts||[]).map(ct=>(
              <div key={ct.id} style={S.card}>
                <div style={S.cardHead}>
                  <input style={S.roleIn} value={ct.role} onChange={e=>updateContact(client.id,ct.id,"role",e.target.value)} placeholder="Role Title"/>
                  <button style={S.xBtn} onClick={()=>removeContact(client.id,ct.id)}>✕</button>
                </div>
                <div style={S.cardSplit}>
                  {/* Left: fields */}
                  <div style={S.cardFields}>
                    {(ct.fields||[]).map((f,fi)=>(
                      <div key={f.id}
                        style={{...S.dynRow, opacity: dragFieldInfo?.contactId===ct.id && dragFieldInfo?.idx===fi ? 0.4 : 1, borderTop: dragFieldOver?.contactId===ct.id && dragFieldOver?.idx===fi ? "2px solid #3b82f6" : "2px solid transparent"}}
                        draggable
                        onDragStart={()=>setDragFieldInfo({contactId:ct.id,idx:fi})}
                        onDragOver={e=>{e.preventDefault();setDragFieldOver({contactId:ct.id,idx:fi});}}
                        onDrop={()=>{if(dragFieldInfo && dragFieldInfo.contactId===ct.id){reorderContactFields(client.id,ct.id,dragFieldInfo.idx,fi);}setDragFieldInfo(null);setDragFieldOver(null);}}
                        onDragEnd={()=>{setDragFieldInfo(null);setDragFieldOver(null);}}
                      >
                        <div style={S.dynLabelWrap}>
                          <svg width="8" height="8" viewBox="0 0 10 10" fill="#b0a898" style={{opacity:.5,flexShrink:0,cursor:"grab",marginRight:3}}><circle cx="2" cy="2" r="1"/><circle cx="2" cy="5" r="1"/><circle cx="2" cy="8" r="1"/><circle cx="6" cy="2" r="1"/><circle cx="6" cy="5" r="1"/><circle cx="6" cy="8" r="1"/></svg>
                          <input style={S.dynLabel} value={f.label} onChange={e=>updateContactField(client.id,ct.id,f.id,"label",e.target.value)} title="Click to rename this field"/>
                          <button style={S.dynX} onClick={()=>removeContactField(client.id,ct.id,f.id)} title="Remove field">✕</button>
                        </div>
                        <input style={{...S.fIn,marginLeft:11}} value={f.value} onChange={e=>updateContactField(client.id,ct.id,f.id,"value",e.target.value)} placeholder={f.label}/>
                      </div>
                    ))}
                    <button style={S.addFieldBtn} onClick={()=>addContactField(client.id,ct.id)}>+ Add Field</button>
                  </div>
                  {/* Right: notes */}
                  <div style={S.cardNotes}>
                    <label style={S.fLabel}>Notes</label>
                    <textarea style={{...S.fTa,minHeight:80,flex:1}} value={ct.notes||""} onChange={e=>updateContact(client.id,ct.id,"notes",e.target.value)} placeholder="Notes about this contact…" rows={4}/>
                  </div>
                </div>
              </div>
            ))}

            {/* General notes */}
            <div style={{...S.card, marginTop: 8}}>
              <div style={S.cardHead}><span style={{color:"var(--accent)",fontSize:14,fontWeight:600}}>General Notes</span></div>
              <div style={{padding:14}}>
                <DateStampedNotes value={client.notes||""} onChange={v=>updateField(client.id,"notes",v)} placeholder="Add a note…" minHeight={100}/>
              </div>
            </div>
          </div>

          {/* RIGHT — Pipeline */}
          <div style={S.rightCol}>
            <div style={S.sectionBar}>
              <h3 style={S.secTitle}>Pipeline Stages</h3>
              <button style={S.addSmBtn} onClick={()=>setStageModal(true)}>+ Add Stage</button>
            </div>
            <div style={S.pipeBox}>
              {stageColumns.map((sc,i)=>{
                const val = client[sc.id]||"";
                const filled = !!val;
                const stageFiles = (client.files||[]).filter(f=>f.stageId===sc.id);
                const toggleDate = () => {
                  if (filled) { updateField(client.id, sc.id, ""); }
                  else { updateField(client.id, sc.id, new Date().toISOString().slice(0,10)); }
                };
                const isDropTarget = fileDragOver===sc.id;
                const handleFileDrop = async (e) => {
                  e.preventDefault(); e.stopPropagation(); setFileDragOver(null);
                  const files = Array.from(e.dataTransfer?.files||[]);
                  if(!files.length) return;
                  const today = new Date().toISOString().slice(0,10);
                  const stageSlug = sc.label.replace(/[^a-zA-Z0-9]+/g,"_").replace(/_$/,"");
                  const newFiles = [];
                  for(const file of files){
                    const storedName = `${today}_${stageSlug}_${file.name}`;
                    const serverPath = await uploadFileToServer(file, client.facility, storedName);
                    newFiles.push({ id: crypto.randomUUID(), stageId: sc.id, originalName: file.name, storedName, size: file.size, type: file.type, date: today, serverPath });
                  }
                  updateData(d=>({...d,clients:d.clients.map(c=>c.id===client.id?{...c,files:[...(c.files||[]),...newFiles]}:c)}));
                };
                return (
                  <div key={sc.id}
                    style={{...S.pipeRow, background: isDropTarget?"rgba(59,130,246,.08)":"transparent", borderRadius:8, padding:"8px 6px", margin:"0 -6px", transition:"background .15s"}}
                    onDragOver={e=>{e.preventDefault();setFileDragOver(sc.id);}}
                    onDragLeave={()=>setFileDragOver(null)}
                    onDrop={handleFileDrop}
                  >
                    <div style={S.pipeTrack}>
                      <div
                        style={{...S.pipeDot, background: filled?"#16a34a":"var(--card)", boxShadow: filled?"0 0 12px rgba(52,211,153,0.35)":"none", cursor:"pointer", border: filled?"2px solid #16a34a":"2px solid var(--border2)"}}
                        onClick={toggleDate}
                        title={filled ? "Click to clear date" : "Click to set today's date"}
                      >
                        {filled && <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#ffffff" strokeWidth="3.5" strokeLinecap="round"><polyline points="20 6 9 17 4 12"/></svg>}
                      </div>
                      {i<stageColumns.length-1 && <div style={{...S.pipeLine, background: filled?"#16a34a":"var(--border)"}}/>}
                    </div>
                    <div style={{flex:1}}>
                      <div style={{display:"flex",alignItems:"center",gap:6,marginBottom:4}}>
                        <input
                          style={{...S.stageNameIn, color: filled?"var(--text)":"var(--text3)"}}
                          value={sc.label}
                          onChange={e=>renameStage(sc.id,e.target.value)}
                          title="Click to rename stage"
                        />
                        <div style={S.stageControls}>
                          {i>0 && <button style={S.stageCtrlBtn} onClick={()=>moveStage(sc.id,"up")} title="Move up">▲</button>}
                          {i<stageColumns.length-1 && <button style={S.stageCtrlBtn} onClick={()=>moveStage(sc.id,"down")} title="Move down">▼</button>}
                          <button style={{...S.stageCtrlBtn,color:"var(--red)"}} onClick={()=>deleteStage(sc.id)} title="Delete stage">✕</button>
                        </div>
                      </div>
                      <input type="date" style={{...S.pipeDateIn, borderColor: filled?"rgba(22,163,74,0.3)":"var(--border)"}} value={val} onChange={e=>updateField(client.id,sc.id,e.target.value)}/>
                      {stageFiles.length>0 && (
                        <div style={{marginTop:6,display:"flex",flexDirection:"column",gap:3}}>
                          {stageFiles.map(f=>(
                            <div key={f.id} style={S.fileRow}>
                              <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="#8a7f72" strokeWidth="2" style={{flexShrink:0}}><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
                              <button style={S.fileLink} onClick={()=>downloadFile(f)} title={f.storedName}>{f.storedName}</button>
                              <span style={{fontSize:10,color:"var(--text3)",flexShrink:0}}>{formatSize(f.size)}</span>
                              <button style={S.fileX} onClick={()=>removeFile(client.id,f.id)} title="Remove file">✕</button>
                            </div>
                          ))}
                        </div>
                      )}
                      <div style={{...S.dropHint, borderColor: isDropTarget?"#3b82f6":"var(--border)", color: isDropTarget?"var(--accent)":"var(--text3)"}}>
                        <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
                        Drop files here
                      </div>
                    </div>
                  </div>
                );
              })}

              {/* Non-stage fields (like referredBy) */}
              <div style={{marginTop:20,borderTop:"1px solid var(--border)",paddingTop:16}}>
                <h4 style={{...S.secTitle,fontSize:11,marginBottom:10}}>Other Fields</h4>
                {data.columns.filter(c=>!c.isStage && c.id!=="facility" && c.id!=="address" && c.id!=="notes" && c.type!=="textarea").map(col=>(
                  <div key={col.id} style={{marginBottom:10}}>
                    <label style={S.fLabel}>{col.label}</label>
                    <input type={col.type==="date"?"date":"text"} style={S.fIn} value={client[col.id]||""} onChange={e=>updateField(client.id,col.id,e.target.value)} placeholder={col.label}/>
                  </div>
                ))}
              </div>
            </div>
          </div>
        </div>

        {/* Add Stage Modal */}
        {stageModal && (
          <div style={S.ov} onClick={()=>setStageModal(false)}>
            <div style={S.mod} onClick={e=>e.stopPropagation()}>
              <div style={S.modH}><h3 style={S.modT}>Add Pipeline Stage</h3><button style={S.modX} onClick={()=>setStageModal(false)}>✕</button></div>
              <div style={{padding:18}}>
                <label style={S.fLabel}>Stage Name</label>
                <input style={{...S.fIn,marginTop:4}} value={newStageName} onChange={e=>setNewStageName(e.target.value)} placeholder="e.g. Site Visit, Credentialing…" autoFocus
                  onKeyDown={e=>{if(e.key==="Enter") addStage();}}
                />
                <p style={{fontSize:11,color:"var(--text3)",marginTop:8}}>New stages are added to the pipeline for all clients and appear as date columns in the consolidated table.</p>
              </div>
              <div style={S.modF}><button style={{...S.btnPri,opacity:newStageName.trim()?"1":"0.4"}} onClick={addStage}>Add Stage</button></div>
            </div>
          </div>
        )}
      </div>
    );
  }

  // ═══════════════ TABLE VIEW ═══════════════
  return (
    <div style={S.app}><Fonts/>
      <div style={S.header}>
        <div>
          <h1 style={S.title}>Client Relations Tracker</h1>
          <p style={S.subtitle}>Andrea's Client Pipeline</p>
        </div>
        <div style={S.stats}>
          <Stat n={data.clients.filter(c=>!c.archived).length} l="Active" c="#60a5fa"/>
          <Stat n={data.clients.filter(c=>c.contractSigned&&!c.archived).length} l="Signed" c="#34d399"/>
          <Stat n={data.clients.filter(c=>c.archived).length} l="Archived" c="#f87171"/>
        </div>
      </div>

      <div style={S.toolbar}>
        <div style={S.searchWrap}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#8a7f72" strokeWidth="2" style={{position:"absolute",left:10,top:9}}><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
          <input style={S.searchIn} placeholder="Search clients & contacts…" value={search} onChange={e=>setSearch(e.target.value)}/>
        </div>
        <div style={{display:"flex",gap:7,flexWrap:"wrap"}}>
          <button style={{...S.btnSec,background:showArchived?"#dcfce7":"var(--card)",color:showArchived?"#16a34a":"var(--text2)"}} onClick={()=>setShowArchived(!showArchived)}>
            {showArchived?"Show Active":"Archived"}
          </button>
          <button style={S.btnSec} onClick={()=>setView("groups")}>
            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
            Groups
          </button>
          <button style={S.btnSec} onClick={()=>setColModal(true)}>
            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><rect x="3" y="3" width="7" height="18" rx="1"/><line x1="17" y1="8" x2="17" y2="16"/><line x1="13" y1="12" x2="21" y2="12"/></svg>
            Column
          </button>
          <button style={S.btnSec} onClick={exportCSV}>Export</button>
          <button style={S.btnPri} onClick={addClient}>
            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
            Add Client
          </button>
        </div>
      </div>

      {filtered.length === 0 ? (
        <div style={S.empty}>
          <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="#b0a898" strokeWidth="1.5"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>
          <p style={{color:"var(--text3)",margin:"10px 0 2px",fontSize:14}}>{showArchived?"No archived clients":"No clients yet"}</p>
          <p style={{color:"var(--text3)",fontSize:11,margin:0}}>Click "Add Client" to start</p>
        </div>
      ) : (
        <div style={S.tableWrap} ref={tableRef}>
          <table style={S.table}>
            <thead><tr>
              <th style={{...S.th,width:32,minWidth:32}}>#</th>
              <th style={{...S.th,width:52,minWidth:52}}>Stage</th>
              {tableColumns.map((col,ci)=>(
                <th key={col.id} style={{...S.th, minWidth:col.type==="textarea"?180:col.type==="date"?115:130, cursor:"grab", background:dragOver===ci?"#dbeafe":"var(--bg2)", transition:"background .15s"}}
                  draggable onDragStart={()=>setDragCol(ci)} onDragOver={e=>{e.preventDefault();setDragOver(ci);}} onDrop={()=>handleColDrop(ci)} onDragEnd={()=>{setDragCol(null);setDragOver(null);}}>
                  <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",gap:3}}>
                    <span style={{cursor:"pointer",display:"flex",alignItems:"center",gap:3}} onClick={()=>{
                      if(sortCol===col.id) setSortDir(d=>d==="asc"?"desc":"asc");
                      else{setSortCol(col.id);setSortDir("asc");}
                    }}>
                      <svg width="7" height="7" viewBox="0 0 10 10" fill="#b0a898" style={{opacity:.6,flexShrink:0}}><circle cx="2" cy="2" r="1"/><circle cx="2" cy="5" r="1"/><circle cx="2" cy="8" r="1"/><circle cx="6" cy="2" r="1"/><circle cx="6" cy="5" r="1"/><circle cx="6" cy="8" r="1"/></svg>
                      {col.label}
                      {sortCol===col.id && <span style={{fontSize:8,opacity:.5}}>{sortDir==="asc"?"▲":"▼"}</span>}
                    </span>
                    {col.removable && <button style={S.colX} onClick={e=>{e.stopPropagation();removeColumn(col.id);}} title="Remove">✕</button>}
                  </div>
                </th>
              ))}
              <th style={{...S.th,width:85,minWidth:85}}></th>
            </tr></thead>
            <tbody>
              {filtered.map((row,idx)=>{
                const stage = getStageCount(row);
                const total = stageColumns.length;
                // Find matching contacts when searching
                const matchedContacts = search ? (row.contacts||[]).filter(ct => {
                  const q = search.toLowerCase();
                  return (ct.role||"").toLowerCase().includes(q) ||
                    (ct.notes||"").toLowerCase().includes(q) ||
                    (ct.fields||[]).some(f => (f.label||"").toLowerCase().includes(q) || (f.value||"").toLowerCase().includes(q));
                }) : [];
                return (
                  <React.Fragment key={row.id}>
                  <tr style={S.tr}>
                    <td style={{...S.td,color:"var(--text3)",fontSize:10,textAlign:"center"}}>{idx+1}</td>
                    <td style={S.td}>
                      <div style={{display:"flex",gap:2,alignItems:"center"}}>
                        {stageColumns.map((_,i)=>(
                          <div key={i} style={{width:5,height:5,borderRadius:"50%",background:i<stage?(stage===total?"#16a34a":"#2563eb"):"var(--border)"}}/>
                        ))}
                      </div>
                    </td>
                    {tableColumns.map(col=>(
                      <td key={col.id} style={S.td}>
                        {col.type==="textarea" ? (
                          <button style={S.noteBtn} onClick={()=>{setEditingNote({cid:row.id,col:col.id});setNoteVal(row[col.id]||"");setTimeout(()=>noteRef.current?.focus(),60);}}>
                            {row[col.id]?<span style={S.notePrev}>{row[col.id].slice(0,30)}{row[col.id].length>30?"…":""}</span>:<span style={{color:"var(--text3)",fontSize:10}}>+ note</span>}
                          </button>
                        ) : col.id==="facility" ? (
                          <button style={S.facBtn} onClick={()=>{setActiveClient(row.id);setView("client");}}>
                            {row.facility||<span style={{color:"var(--text3)",fontStyle:"italic"}}>Unnamed</span>}
                          </button>
                        ) : col.type==="date" ? (
                          <input type="date" style={S.dateIn} value={row[col.id]||""} onChange={e=>updateField(row.id,col.id,e.target.value)}/>
                        ) : (
                          <input type="text" style={S.cellIn} value={row[col.id]||""} onChange={e=>updateField(row.id,col.id,e.target.value)} placeholder="—"/>
                        )}
                      </td>
                    ))}
                    <td style={S.td}>
                      <div style={{display:"flex",gap:3,alignItems:"center"}}>
                        <button style={S.actBtn} onClick={()=>{setActiveClient(row.id);setView("client");}} title="Open">
                          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M15 3h6v6"/><path d="M10 14 21 3"/><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/></svg>
                        </button>
                        <button style={{...S.actBtn,color:row.archived?"#6ee7b7":"#a78bfa"}} onClick={()=>archiveClient(row.id)} title={row.archived?"Reactivate":"Archive"}>
                          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><rect x="2" y="4" width="20" height="5" rx="1"/><path d="M4 9v9a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9"/><path d="M10 13h4"/></svg>
                        </button>
                        {deleteConfirm===row.id ? (
                          <><button style={{...S.actBtn,color:"#f87171",fontWeight:700}} onClick={()=>deleteClient(row.id)}>✓</button>
                          <button style={S.actBtn} onClick={()=>setDeleteConfirm(null)}>✕</button></>
                        ) : (
                          <button style={{...S.actBtn,color:"var(--text3)"}} onClick={()=>setDeleteConfirm(row.id)} title="Delete">
                            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
                          </button>
                        )}
                      </div>
                    </td>
                  </tr>
                  {matchedContacts.length > 0 && (
                    <tr style={{background:"var(--bg)"}}>
                      <td colSpan={tableColumns.length + 3} style={{...S.td, padding:"6px 12px 8px 44px", borderBottom:"2px solid var(--border)"}}>
                        <div style={{display:"flex",gap:6,alignItems:"center",marginBottom:4}}>
                          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="var(--accent)" strokeWidth="2"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>
                          <span style={{fontSize:11,fontWeight:700,color:"var(--accent)",textTransform:"uppercase",letterSpacing:".5px",fontFamily:"var(--mono)"}}>Matching Contacts</span>
                        </div>
                        <div style={{display:"flex",flexWrap:"wrap",gap:8}}>
                          {matchedContacts.map(ct=>{
                            const nameField = (ct.fields||[]).find(f=>f.label.toLowerCase()==="name");
                            const phoneField = (ct.fields||[]).find(f=>f.label.toLowerCase().includes("phone"));
                            const emailField = (ct.fields||[]).find(f=>f.label.toLowerCase()==="email");
                            return (
                              <div key={ct.id} style={S.matchCard}>
                                <span style={{fontSize:11,fontWeight:700,color:"var(--accent)"}}>{ct.role}</span>
                                {nameField?.value && <span style={{fontSize:13,fontWeight:600,color:"var(--text)"}}>{nameField.value}</span>}
                                {phoneField?.value && <span style={{fontSize:12,color:"var(--text2)"}}>{phoneField.value}</span>}
                                {emailField?.value && <span style={{fontSize:11,color:"var(--text3)"}}>{emailField.value}</span>}
                              </div>
                            );
                          })}
                        </div>
                      </td>
                    </tr>
                  )}
                  </React.Fragment>
                );
              })}
            </tbody>
          </table>
        </div>
      )}

      <p style={S.foot}>Drag headers to reorder columns • Click facility name to open detail page • Auto-saves</p>

      {/* Note Modal */}
      {editingNote && (
        <div style={S.ov} onClick={()=>{updateField(editingNote.cid,editingNote.col,noteVal);setEditingNote(null);}}>
          <div style={S.mod} onClick={e=>e.stopPropagation()}>
            <div style={S.modH}><h3 style={S.modT}>Notes</h3><button style={S.modX} onClick={()=>{updateField(editingNote.cid,editingNote.col,noteVal);setEditingNote(null);}}>✕</button></div>
            <div style={{padding:16}}>
              <DateStampedNotes value={noteVal} onChange={v=>setNoteVal(v)} placeholder="Add a note…" minHeight={150}/>
            </div>
            <div style={S.modF}><button style={S.btnPri} onClick={()=>{updateField(editingNote.cid,editingNote.col,noteVal);setEditingNote(null);}}>Save</button></div>
          </div>
        </div>
      )}

      {/* Add Column Modal */}
      {colModal && (
        <div style={S.ov} onClick={()=>setColModal(false)}>
          <div style={S.mod} onClick={e=>e.stopPropagation()}>
            <div style={S.modH}><h3 style={S.modT}>Add Column</h3><button style={S.modX} onClick={()=>setColModal(false)}>✕</button></div>
            <div style={{padding:18,display:"flex",flexDirection:"column",gap:14}}>
              <div>
                <label style={S.fLabel}>Column Name</label>
                <input style={{...S.fIn,marginTop:4}} value={newColName} onChange={e=>setNewColName(e.target.value)} placeholder="e.g. Follow-up Date" autoFocus/>
              </div>
              <div>
                <label style={S.fLabel}>Type</label>
                <div style={{display:"flex",gap:6,marginTop:5}}>
                  {[["text","Text"],["date","Date (Stage)"],["textarea","Notes"]].map(([v,l])=>(
                    <button key={v} style={{...S.btnSec,background:newColType===v?"#dbeafe":"var(--card)",borderColor:newColType===v?"#3b82f6":"var(--border)",color:newColType===v?"#1d4ed8":"var(--text2)"}}
                      onClick={()=>setNewColType(v)}>{l}</button>
                  ))}
                </div>
                {newColType==="date" && <p style={{fontSize:10,color:"var(--text3)",marginTop:5}}>Date columns become pipeline stages on client pages</p>}
              </div>
            </div>
            <div style={S.modF}><button style={{...S.btnPri,opacity:newColName.trim()?"1":"0.4"}} onClick={addColumn}>Add Column</button></div>
          </div>
        </div>
      )}
    </div>
  );
}

function Fonts(){return <link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet"/>;}
function Stat({n,l,c}){return <div style={S.statBox}><span style={{...S.statN,color:c}}>{n}</span><span style={S.statL}>{l}</span></div>;}
function Row({label,children}){return <div style={{marginBottom:8}}><label style={S.fLabel}>{label}</label>{children}</div>;}

function DateStampedNotes({value, onChange, placeholder, minHeight}) {
  const [newEntry, setNewEntry] = useState("");
  const today = () => new Date().toISOString().slice(0,10);
  const addEntry = () => {
    if (!newEntry.trim()) return;
    const stamp = today() + " — " + newEntry.trim();
    const updated = value ? stamp + "\n" + value : stamp;
    onChange(updated);
    setNewEntry("");
  };
  return (
    <div style={{display:"flex",flexDirection:"column",gap:6}}>
      <div style={{display:"flex",gap:6}}>
        <input
          style={{flex:1,background:"var(--bg)",border:"1px solid var(--border)",borderRadius:5,padding:"7px 10px",color:"var(--text)",fontSize:13,fontFamily:"var(--ff)"}}
          value={newEntry}
          onChange={e=>setNewEntry(e.target.value)}
          onKeyDown={e=>{if(e.key==="Enter") addEntry();}}
          placeholder={placeholder || "Add a note…"}
        />
        <button
          style={{background:"linear-gradient(135deg,#2563eb,#1d4ed8)",color:"#fff",border:"none",borderRadius:5,padding:"6px 12px",fontSize:12,fontWeight:600,cursor:"pointer",fontFamily:"var(--ff)",opacity:newEntry.trim()?"1":"0.4"}}
          onClick={addEntry}
          disabled={!newEntry.trim()}
        >Add</button>
      </div>
      <textarea
        style={{background:"var(--bg)",border:"1px solid var(--border)",borderRadius:5,padding:"7px 10px",color:"var(--text)",fontSize:13,fontFamily:"var(--ff)",resize:"vertical",lineHeight:1.6,width:"100%",boxSizing:"border-box",minHeight:minHeight||80}}
        value={value||""}
        onChange={e=>onChange(e.target.value)}
        placeholder="Notes will appear here with dates…"
      />
    </div>
  );
}
if(typeof document!=="undefined"){const e=document.createElement("style");e.textContent=`
:root{--ff:'DM Sans',sans-serif;--mono:'JetBrains Mono',monospace;--bg:#f5f0e8;--bg2:#ebe5d9;--bg3:#e0d9cc;--card:#ffffff;--border:#d5cfc3;--border2:#c8c0b2;--text:#1a1a1a;--text2:#4a4540;--text3:#7a7168;--accent:#2563eb;--accent2:#1d4ed8;--green:#16a34a;--red:#dc2626}
*{box-sizing:border-box}
@keyframes spin{to{transform:rotate(360deg)}}
input:focus,textarea:focus{border-color:var(--accent) !important;outline:none}
tr:hover td{background:rgba(37,99,235,.04)}
button:hover{filter:brightness(1.05)}
::-webkit-scrollbar{width:6px;height:6px}
::-webkit-scrollbar-track{background:var(--bg2)}
::-webkit-scrollbar-thumb{background:var(--border2);border-radius:3px}
@media(max-width:800px){
  .client-grid{grid-template-columns:1fr !important}
}
`;document.head.appendChild(e);}

const S = {
  app:{fontFamily:"var(--ff)",background:"var(--bg)",minHeight:"100vh",color:"var(--text)",padding:"24px 20px"},
  loadWrap:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",height:"100vh",background:"var(--bg)"},
  spinner:{width:28,height:28,border:"3px solid var(--border)",borderTopColor:"var(--accent)",borderRadius:"50%",animation:"spin .7s linear infinite"},

  header:{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:20,flexWrap:"wrap",gap:14},
  title:{fontSize:24,fontWeight:700,margin:0,color:"var(--text)",letterSpacing:"-.4px"},
  subtitle:{fontSize:12,color:"var(--text3)",margin:"4px 0 0",fontFamily:"var(--mono)",textTransform:"uppercase",letterSpacing:"1.5px"},
  stats:{display:"flex",gap:10},
  statBox:{background:"var(--card)",border:"1px solid var(--border)",borderRadius:8,padding:"10px 18px",display:"flex",flexDirection:"column",alignItems:"center",minWidth:70,boxShadow:"0 1px 3px rgba(0,0,0,.06)"},
  statN:{fontSize:22,fontWeight:700,fontFamily:"var(--mono)"},
  statL:{fontSize:10,color:"var(--text3)",textTransform:"uppercase",letterSpacing:"1px",marginTop:2},

  toolbar:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:14,flexWrap:"wrap",gap:10},
  searchWrap:{position:"relative"},
  searchIn:{background:"var(--card)",border:"1px solid var(--border)",borderRadius:7,padding:"8px 12px 8px 34px",color:"var(--text)",fontSize:14,width:220,fontFamily:"var(--ff)"},

  btnPri:{background:"linear-gradient(135deg,#2563eb,#1d4ed8)",color:"#fff",border:"none",borderRadius:7,padding:"8px 16px",fontSize:13,fontWeight:600,cursor:"pointer",display:"flex",alignItems:"center",gap:6,fontFamily:"var(--ff)",boxShadow:"0 2px 8px rgba(37,99,235,.25)"},
  btnSec:{background:"var(--card)",color:"var(--text2)",border:"1px solid var(--border)",borderRadius:7,padding:"8px 14px",fontSize:13,fontWeight:500,cursor:"pointer",display:"flex",alignItems:"center",gap:5,fontFamily:"var(--ff)",boxShadow:"0 1px 2px rgba(0,0,0,.04)"},
  btnSm:{borderRadius:7,padding:"6px 14px",fontSize:12,fontWeight:600,cursor:"pointer",fontFamily:"var(--ff)"},
  addSmBtn:{background:"transparent",border:"1px dashed var(--border2)",borderRadius:6,padding:"4px 12px",fontSize:12,color:"var(--accent)",cursor:"pointer",fontFamily:"var(--ff)"},

  tableWrap:{overflowX:"auto",overflowY:"auto",maxHeight:"calc(100vh - 200px)",borderRadius:8,border:"1px solid var(--border)",background:"var(--card)",boxShadow:"0 1px 4px rgba(0,0,0,.06)"},
  table:{width:"100%",borderCollapse:"separate",borderSpacing:0,minWidth:1300},
  th:{position:"sticky",top:0,background:"var(--bg2)",borderBottom:"2px solid var(--border)",padding:"10px 8px",textAlign:"left",fontSize:11,fontWeight:700,color:"var(--text)",textTransform:"uppercase",letterSpacing:".7px",whiteSpace:"nowrap",zIndex:2,fontFamily:"var(--mono)",userSelect:"none"},
  tr:{},
  td:{padding:"4px 6px",borderBottom:"1px solid var(--border)",verticalAlign:"middle"},

  cellIn:{background:"transparent",border:"1px solid transparent",borderRadius:5,padding:"6px 8px",color:"var(--text)",fontSize:14,width:"100%",fontFamily:"var(--ff)"},
  dateIn:{background:"transparent",border:"1px solid transparent",borderRadius:5,padding:"5px 6px",color:"var(--text)",fontSize:13,width:"100%",fontFamily:"var(--mono)",colorScheme:"light"},
  noteBtn:{background:"var(--bg)",border:"1px solid var(--border)",borderRadius:5,padding:"5px 8px",cursor:"pointer",width:"100%",textAlign:"left",color:"var(--text)"},
  notePrev:{fontSize:12,color:"var(--text3)",lineHeight:1.3},
  facBtn:{background:"transparent",border:"none",color:"var(--accent)",cursor:"pointer",fontSize:14,fontWeight:600,fontFamily:"var(--ff)",padding:"4px 0",textDecoration:"underline",textDecorationColor:"rgba(37,99,235,.25)",textAlign:"left",width:"100%"},

  actBtn:{background:"transparent",border:"none",color:"var(--text3)",cursor:"pointer",padding:4,borderRadius:4,display:"flex",alignItems:"center"},
  colX:{background:"transparent",border:"none",color:"var(--text3)",fontSize:10,cursor:"pointer",padding:"0 3px",opacity:.6},

  empty:{textAlign:"center",padding:"50px 24px",background:"var(--card)",borderRadius:8,border:"1px dashed var(--border)"},
  foot:{textAlign:"center",fontSize:11,color:"var(--text3)",marginTop:14,fontFamily:"var(--mono)"},

  // Modals
  ov:{position:"fixed",inset:0,background:"rgba(0,0,0,.35)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:100,backdropFilter:"blur(3px)"},
  mod:{background:"var(--card)",border:"1px solid var(--border)",borderRadius:12,width:"92%",maxWidth:480,boxShadow:"0 16px 48px rgba(0,0,0,.15)"},
  modH:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"14px 18px",borderBottom:"1px solid var(--border)"},
  modT:{margin:0,fontSize:15,fontWeight:700,color:"var(--text)"},
  modX:{background:"transparent",border:"none",color:"var(--text3)",fontSize:16,cursor:"pointer"},
  modTa:{width:"100%",minHeight:160,background:"var(--bg)",border:"none",color:"var(--text)",fontSize:14,padding:18,resize:"vertical",fontFamily:"var(--ff)",lineHeight:1.6,boxSizing:"border-box"},
  modF:{padding:"12px 18px",borderTop:"1px solid var(--border)",display:"flex",justifyContent:"flex-end"},

  // Client page
  backBtn:{background:"transparent",border:"none",color:"var(--accent)",cursor:"pointer",display:"flex",alignItems:"center",gap:6,fontSize:14,fontWeight:500,fontFamily:"var(--ff)",padding:"4px 0",marginBottom:16},
  clientHeader:{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:24,flexWrap:"wrap",gap:12},
  clientTitle:{background:"transparent",border:"1px solid transparent",fontSize:26,fontWeight:700,color:"var(--text)",fontFamily:"var(--ff)",padding:"4px 8px",borderRadius:6,width:"100%"},
  clientSub:{background:"transparent",border:"1px solid transparent",fontSize:14,color:"var(--text3)",fontFamily:"var(--ff)",padding:"3px 8px",borderRadius:5,width:"100%",marginTop:4},

  clientGrid:{display:"grid",gridTemplateColumns:"1fr 400px",gap:24,alignItems:"start"},
  leftCol:{display:"flex",flexDirection:"column",gap:14},
  rightCol:{position:"sticky",top:20,display:"flex",flexDirection:"column",gap:14},

  sectionBar:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:10},
  secTitle:{fontSize:16,fontWeight:700,color:"var(--text)",textTransform:"uppercase",letterSpacing:"1px",fontFamily:"var(--mono)",margin:"0 0 0"},

  card:{background:"var(--card)",border:"1px solid var(--border)",borderRadius:9,overflow:"hidden",boxShadow:"0 1px 3px rgba(0,0,0,.05)"},
  cardHead:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"10px 14px",borderBottom:"1px solid var(--border)",background:"var(--bg2)"},
  cardSplit:{display:"grid",gridTemplateColumns:"1fr 1fr",gap:0},
  cardFields:{padding:14,display:"flex",flexDirection:"column",gap:7,borderRight:"1px solid var(--border)"},
  cardNotes:{padding:14,display:"flex",flexDirection:"column"},
  roleIn:{background:"transparent",border:"none",color:"var(--accent)",fontSize:14,fontWeight:700,fontFamily:"var(--ff)",padding:0,width:"85%"},
  xBtn:{background:"transparent",border:"none",color:"var(--text3)",fontSize:14,cursor:"pointer",padding:2},

  dynRow:{marginBottom:3},
  dynLabelWrap:{display:"flex",alignItems:"center",gap:3,marginBottom:3},
  dynLabel:{background:"transparent",border:"none",fontSize:10,fontWeight:700,color:"var(--text2)",textTransform:"uppercase",letterSpacing:".7px",fontFamily:"var(--mono)",padding:0,width:"100%",cursor:"text"},
  dynX:{background:"transparent",border:"none",color:"var(--text3)",fontSize:10,cursor:"pointer",padding:"0 3px",opacity:.5,flexShrink:0},
  addFieldBtn:{background:"transparent",border:"1px dashed var(--border2)",borderRadius:5,padding:"4px 10px",fontSize:11,color:"var(--accent)",cursor:"pointer",fontFamily:"var(--ff)",alignSelf:"flex-start",marginTop:5},

  fLabel:{fontSize:10,fontWeight:700,color:"var(--text2)",textTransform:"uppercase",letterSpacing:".7px",fontFamily:"var(--mono)",display:"block",marginBottom:4},
  fIn:{background:"var(--bg)",border:"1px solid var(--border)",borderRadius:5,padding:"7px 10px",color:"var(--text)",fontSize:14,fontFamily:"var(--ff)",width:"100%",boxSizing:"border-box"},
  fTa:{background:"var(--bg)",border:"1px solid var(--border)",borderRadius:5,padding:"7px 10px",color:"var(--text)",fontSize:14,fontFamily:"var(--ff)",resize:"vertical",lineHeight:1.5,width:"100%",boxSizing:"border-box"},

  pipeBox:{background:"var(--card)",border:"1px solid var(--border)",borderRadius:9,padding:22,boxShadow:"0 1px 3px rgba(0,0,0,.05)"},
  pipeRow:{display:"flex",gap:14,minHeight:60},
  pipeTrack:{display:"flex",flexDirection:"column",alignItems:"center",width:26,flexShrink:0,paddingTop:2},
  pipeDot:{width:24,height:24,borderRadius:"50%",display:"flex",alignItems:"center",justifyContent:"center",flexShrink:0,transition:"all .2s"},
  pipeLine:{width:2,flex:1,marginTop:3,marginBottom:3,borderRadius:1,transition:"background .2s"},
  pipeDateIn:{background:"var(--bg)",border:"1px solid var(--border)",borderRadius:5,padding:"6px 9px",color:"var(--text)",fontSize:13,fontFamily:"var(--mono)",colorScheme:"light",width:"100%",marginTop:3,boxSizing:"border-box"},
  stageNameIn:{background:"transparent",border:"1px solid transparent",borderRadius:4,padding:"2px 4px",fontSize:16,fontWeight:700,fontFamily:"var(--ff)",flex:1,minWidth:0},
  stageControls:{display:"flex",gap:2,alignItems:"center",flexShrink:0,opacity:.4,transition:"opacity .15s"},
  stageCtrlBtn:{background:"transparent",border:"1px solid var(--border)",borderRadius:4,padding:"1px 5px",fontSize:10,color:"var(--text3)",cursor:"pointer",fontFamily:"var(--mono)",lineHeight:1.2},

  dropHint:{display:"flex",alignItems:"center",gap:6,fontSize:12,marginTop:6,padding:"6px 10px",border:"1px dashed var(--border)",borderRadius:5,transition:"all .15s",fontFamily:"var(--ff)",color:"var(--text3)"},
  fileRow:{display:"flex",alignItems:"center",gap:6,padding:"4px 8px",background:"var(--bg)",borderRadius:5,fontSize:12},
  fileLink:{background:"transparent",border:"none",color:"var(--accent)",cursor:"pointer",fontSize:11,fontFamily:"var(--mono)",padding:0,textAlign:"left",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",flex:1},
  fileX:{background:"transparent",border:"none",color:"var(--text3)",fontSize:11,cursor:"pointer",padding:"0 3px",flexShrink:0},

  matchCard:{background:"var(--card)",border:"1px solid var(--border)",borderRadius:6,padding:"6px 10px",display:"flex",flexDirection:"column",gap:1,minWidth:160},
};
