// React loaded from CDN as global
const { useState, useCallback, useMemo, useEffect } = React;

class ErrorBoundary extends React.Component {
  constructor(props) { super(props); this.state = { error: null, info: null }; }
  componentDidCatch(error, info) { this.setState({ error, info }); }
  render() {
    if (this.state.error) {
      return (
        <div style={{padding:20,background:"#fff",fontFamily:"monospace"}}>
          <h2 style={{color:"red"}}>Error: {this.state.error.message}</h2>
          <pre style={{fontSize:11,color:"#333",whiteSpace:"pre-wrap"}}>
            {this.state.info?.componentStack}
          </pre>
        </div>
      );
    }
    return this.props.children;
  }
}




// ─── KOIOS DESIGN TOKENS ─────────────────────────────────────────────────────
const K = {
  bg:"#f0f4f8", surface:"#ffffff", surfaceAlt:"#f7f9fc", border:"#dce3ed",
  navy:"#0d1f3c", blue:"#1a4a8a", blueMid:"#2563b0", blueLight:"#e8f0fb", blueAccent:"#0ea5e9",
  text:"#0d1f3c", textMid:"#4a5c74", textDim:"#8a9bb0",
  red:"#991b1b", redLight:"#fef2f2",
  amber:"#78350f", amberLight:"#fffbeb",
  green:"#14532d", greenLight:"#f0fdf4",
  class:{
    UNCLASSIFIED:["#14532d","#f0fdf4","#bbf7d0"],
    RESTRICTED:  ["#78350f","#fffbeb","#fde68a"],
    CONFIDENTIAL:["#1a4a8a","#e8f0fb","#bfdbfe"],
    SECRET:      ["#991b1b","#fef2f2","#fecaca"],
    "TOP SECRET":["#4c1d95","#f5f3ff","#ddd6fe"],
  },
};

// ─── URN GENERATOR ───────────────────────────────────────────────────────────
const URN_PREFIXES = {
  person:"PER",organisation:"ORG",information:"INF",statement:"STM",
  source:"SRC",material:"MAT",intelligence:"INT",event:"EVT",
  communication:"COM",investigation:"INV",incident:"INC",
  address:"ADR",assessment:"ASS",case:"CAS",decision:"DEC",
  outcome:"OUT",staff:"STF",equipment:"EQP",
};
const urnCounters = {};

// Seed urnCounters from existing localStorage records to avoid collisions
(function() {
  try {
    const raw = localStorage.getItem("koios_v2");
    if (!raw) return;
    const data = JSON.parse(raw);
    if (!data.records) return;
    Object.entries(data.records).forEach(function(entry) {
      const reg = entry[0];
      const recs = entry[1];
      recs.forEach(function(r) {
        if (!r.urn) return;
        const parts = r.urn.split("-");
        const num = parseInt(parts[parts.length-1], 10);
        if (!isNaN(num)) {
          urnCounters[reg] = Math.max(urnCounters[reg]||0, num);
        }
      });
    });
  } catch(e) {}
})();;
const makeURN = reg => {
  urnCounters[reg] = (urnCounters[reg]||0)+1;
  return `AW-${URN_PREFIXES[reg]||"REC"}-${String(urnCounters[reg]).padStart(4,"0")}`;
};




// ─── LIST VALUES ─────────────────────────────────────────────────────────────
const DEFAULT_L = {
  person_type:["Command Responsibility","Corporate / Business Entity","Subject","Witness","Victim","Associate","Suspect","Person of Interest","Expert"],
  person_subtype:["— Military / Command —","Supreme Commander-in-Chief","Theatre Commander","Unit Commander","Political Leader","Field Commander","Intelligence Officer","Financier","— Corporate / Business —","Director","Ultimate Beneficial Owner (UBO)","Registered Shareholder","Beneficial Shareholder","Company Secretary","Chief Executive Officer (CEO)","Chief Financial Officer (CFO)","Chief Operating Officer (COO)","Chairman","Non-Executive Director","Nominee Director","Nominee Shareholder","Authorised Signatory","Power of Attorney","Trustee","Settlor","Beneficiary","Sole Trader","Partner","Liquidator","Administrator","— Other —","Legal Representative","Accountant","Auditor"],
  title:["Mr","Mrs","Ms","Miss","Dr","Prof","Brig. Gen.","Gen.","Col.","Maj.","Capt.","Lt.","Cdr."],
  sex:["Male","Female","Non-binary","Unknown","Not stated"],
  org_type:["Company","Government Body","Military Unit","Intelligence Agency","NGO","Criminal Organisation","Political Party","Militia","Financial Institution","Media Organisation","Law Firm","Accountancy Firm","Trust","Foundation","Shell Company","Other"],
  org_status:["Active","Dissolved","Sanctioned","Dormant","In Administration","Liquidation","Unknown"],
  comm_type:["Telephone Number","Mobile Number","Email Address","Website Address","Social Media Profile","Messaging App","Fax Number","Encrypted Channel"],
  source_type:["Human Intelligence (HUMINT)","Open Source (OSINT)","Technical Intelligence","Partner Agency","Official Record"],
  source_category:["Registered Source","Unregistered Source","Confidential Source","Open Source"],
  contact_method:["Phone","In Person","Secure Messaging","Email","Dead Drop","Intermediary","Other"],
  mat_type:["Document","Photograph","Video/Audio Recording","Digital Device","Satellite Imagery","Financial Record","Open Source Material","Forensic Sample","i2 Chart","Email","Social Media Post"],
  mat_status:["Seized","Secured","Submitted","In Analysis","Released","Destroyed"],
  movement_reason:["Seized","Transferred","Submitted to Lab","Returned","Released","Destroyed","Secured","Other"],
  intel_type:["Threat Intelligence","Financial Intelligence","Human Intelligence","Technical Intelligence","Open Source Intelligence","Counter Intelligence"],
  source_eval:["A - Always Reliable","B - Mostly Reliable","C - Sometimes Reliable","D - Unreliable","E - Untested Source"],
  intel_assessment:["1 - Known to be true","2 - Known personally, not corroborated","3 - Not known personally, corroborated","4 - Cannot be judged","5 - Suspected to be false"],
  handling_code:["1 - May be disseminated","2 - Restrict dissemination","3 - Restrict + protect source","4 - Highest restrictions apply"],
  draft_status:["Draft","Submitted","Approved","Rejected","Disseminated"],
  event_type:["Incidents","Intelligence","Action","Meeting","Court Hearing","Arrest","Timeline","Surveillance"],
  stmt_type:["Witness Statement","Victim Statement","Expert Statement","Suspect Interview","Voluntary Interview","ABE Interview"],
  info_type:["Findings Report","Information Request","Intelligence Report","Briefing Note","Referral","Response","Memorandum"],
  info_subtype:["Internal","External","Restricted","Privileged"],
  info_status:["Draft","For Review","Approved","Disseminated","Archived"],
  inv_type:["War Crimes","Financial Crime","Organised Crime","Counter Terrorism","Human Rights","Fraud","Cybercrime","Other"],
  inv_status:["Open","Suspended","Closed","Archived"],
  inc_type:["Starvation Crimes","Torture","Unlawful Killing","Forced Displacement","Sexual Violence","Destruction of Property","Siege / Blockade","Chemical Weapons","Enforced Disappearance","Unlawful Detention"],
  inc_status:["Started","In Progress","Complete","Referred","No Further Action"],
  how_reported:["Intelligence","Open Source","Witness Report","Partner Agency","Anonymous","Judicial Referral"],
  priority:["Critical","High","Medium","Low"],
  mol:["Joint Criminal Enterprise (JCE)","Command Responsibility","Aiding and Abetting","Direct Perpetration","Ordering","Planning","Instigation"],
  address_type:["Home Address","Business Address","Last Known Address","Crime Scene","Meeting Location","Safe House","Border Crossing","Other"],
  assessment_type:["Risk Assessment","Threat Assessment","Intelligence Assessment","Legal Assessment","Source Assessment","Operational Assessment"],
  case_type:["Criminal","Civil","Financial","Human Rights","War Crimes","Counter Terrorism"],
  case_status:["Open","Active","Under Review","Closed","Referred","Archived"],
  case_priority:["Critical","High","Medium","Low"],
  decision_type:["Operational Decision","Legal Decision","Tasking Decision","Referral Decision","Closure Decision"],
  outcome_type:["Arrest","Prosecution","Conviction","Referral","No Further Action","Asset Seizure","Deportation","Extradition"],
  staff_type:["Investigator","Analyst","Manager","Legal","Technical","Administrative","Contractor"],
  staff_clearance:["UNCLASSIFIED","RESTRICTED","CONFIDENTIAL","SECRET","TOP SECRET"],
  equipment_type:["Vehicle","Aircraft","Vessel","Electronic Device","Surveillance Equipment","Communications Equipment","Weapon","Other"],
  equipment_colour:["Black","White","Silver","Grey","Blue","Red","Green","Yellow","Brown","Orange","Other"],
  class_lvl:["UNCLASSIFIED","RESTRICTED","CONFIDENTIAL","SECRET","TOP SECRET"],
  review_per:["1 Week","2 Weeks","1 Month","3 Months","6 Months","1 Year","2 Years","3 Years","5 Years","10 Years"],
  task_type:["Action","Review","Research","Interview","Surveillance","Tasking","Other"],
  task_status:["Pending","In Progress","Complete","Cancelled"],
  note_type:["Email","Phone Call","Meeting","Action","Intelligence","Observation","Other"],
  file_type:["Open Source","Confidential","Material","Intelligence Report","Legal Document","Photograph","Video","Audio","Other"],
  link_type:["Subject","Witness","Associate","Owner","Member","Director","Commander","Subordinate","Contact","Location","Related","Command Responsibility","Financer","Intermediary","Timeline","Suspect","Victim"],
};

// Dynamic L — reads customised lists if available
const L = new Proxy({}, { get(_, key) { return (window._koiosL || DEFAULT_L)[key] || DEFAULT_L[key]; } });


// ─── HELPERS ─────────────────────────────────────────────────────────────────
const fmtDate = d => d ? new Date(d).toLocaleDateString("en-GB",{day:"2-digit",month:"short",year:"numeric"}) : "—";
const fmtDateTime = d => {
  if(!d) return "—";
  const dt = new Date(d);
  return dt.toLocaleDateString("en-GB",{day:"2-digit",month:"short",year:"numeric"}) +
    (d.includes("T") && !d.endsWith("T00:00") ? " " + dt.toLocaleTimeString("en-GB",{hour:"2-digit",minute:"2-digit"}) : "");
};
const today = new Date().toISOString().split("T")[0];
const isOverdue = d => d && d < today;
const calcAge = dob => dob ? Math.floor((Date.now()-new Date(dob))/(365.25*24*60*60*1000)) : "";
const buildFullAddress = f => [f.address_line1,f.address_line2,f.city,f.county,f.postcode,f.country].filter(Boolean).join(", ");
const autoStmtTitle = f => {
  const name = f.given_by_name?.trim();
  const date = f.date_taken;
  if(!name&&!date) return "";
  const parts=["Statement given by"];
  if(name) parts.push(name);
  if(date) parts.push(`on ${new Date(date).toLocaleDateString("en-GB",{day:"2-digit",month:"long",year:"numeric"})}`);
  return parts.join(" ");
};

// ─── COLOUR MAPS & ICON MAPS ─────────────────────────────────────────────────
const STATUS_COLOR = {
  Seized:        { fg:K.red,     bg:K.redLight,   border:"#fecaca" },
  Secured:       { fg:K.green,   bg:K.greenLight, border:"#bbf7d0" },
  Submitted:     { fg:K.blue,    bg:K.blueLight,  border:"#bfdbfe" },
  "In Analysis": { fg:K.amber,   bg:K.amberLight, border:"#fde68a" },
  Released:      { fg:K.textMid, bg:"#f1f5f9",    border:"#cbd5e1" },
  Destroyed:     { fg:"#fff",    bg:"#374151",    border:"#374151" },
};

const INV_STATUS_COLOR = {
  Open:      { fg:K.green,  bg:K.greenLight,  border:"#bbf7d0" },
  Suspended: { fg:K.amber,  bg:K.amberLight,  border:"#fde68a" },
  Closed:    { fg:K.red,    bg:K.redLight,    border:"#fecaca" },
  Archived:  { fg:K.textDim,bg:"#f1f5f9",    border:"#e2e8f0" },
};

const INC_STATUS_COLOR = {
  Started:           { fg:K.blue,    bg:K.blueLight,   border:"#bfdbfe" },
  "In Progress":     { fg:K.amber,   bg:K.amberLight,  border:"#fde68a" },
  Complete:          { fg:K.green,   bg:K.greenLight,  border:"#bbf7d0" },
  Referred:          { fg:"#7c3aed", bg:"#f5f3ff",     border:"#ddd6fe" },
  "No Further Action":{ fg:K.textDim,bg:"#f1f5f9",    border:"#e2e8f0" },
};

const CASE_STATUS_COLOR = {
  Open:          { fg:K.green,   bg:K.greenLight,  border:"#bbf7d0" },
  Active:        { fg:K.blue,    bg:K.blueLight,   border:"#bfdbfe" },
  "Under Review":{ fg:K.amber,   bg:K.amberLight,  border:"#fde68a" },
  Closed:        { fg:K.red,     bg:K.redLight,    border:"#fecaca" },
  Referred:      { fg:"#7c3aed", bg:"#f5f3ff",     border:"#ddd6fe" },
  Archived:      { fg:K.textDim, bg:"#f1f5f9",     border:"#e2e8f0" },
};

const PRIORITY_COLOR = {
  Critical: { fg:"#fff",   bg:K.red,       border:K.red     },
  High:     { fg:K.red,   bg:K.redLight,  border:"#fecaca" },
  Medium:   { fg:K.amber, bg:K.amberLight,border:"#fde68a" },
  Low:      { fg:K.green, bg:K.greenLight,border:"#bbf7d0" },
};

const CAT_COLOR = {
  "Registered Source":   { fg:K.green,  bg:K.greenLight,  border:"#bbf7d0" },
  "Unregistered Source": { fg:K.amber,  bg:K.amberLight,  border:"#fde68a" },
  "Confidential Source": { fg:K.red,    bg:K.redLight,    border:"#fecaca" },
  "Open Source":         { fg:K.blue,   bg:K.blueLight,   border:"#bfdbfe" },
};

const TYPE_ICON = {
  "Incidents":"▲","Intelligence":"◆","Action":"⚡","Meeting":"👥",
  "Court Hearing":"⚖","Arrest":"🔒","Timeline":"◷","Surveillance":"👁",
  "Document":"📄","Photograph":"🖼","Video/Audio Recording":"🎬",
  "Digital Device":"💻","Satellite Imagery":"🛰","Financial Record":"💰",
  "Open Source Material":"🌐","Forensic Sample":"🔬","i2 Chart":"🔗",
  "Email":"✉","Social Media Post":"📱",
  "Telephone Number":"📞","Mobile Number":"📱","Email Address":"✉",
  "Website Address":"🌐","Social Media Profile":"💬","Messaging App":"🔒",
  "Fax Number":"📠","Encrypted Channel":"🛡",
  "Witness Statement":"👁","Victim Statement":"❤","Expert Statement":"🎓",
  "Suspect Interview":"⚖","Voluntary Interview":"🗣","ABE Interview":"🛡",
};

const TYPE_COLOR = {
  "Incidents":    K.red,
  "Intelligence": K.blue,
  "Action":       K.green,
  "Meeting":      "#5b21b6",
  "Court Hearing":"#0369a1",
  "Arrest":       K.red,
  "Timeline":     K.amber,
  "Surveillance": "#0f766e",
  "Telephone Number": "#0369a1",
  "Mobile Number":    "#0891b2",
  "Email Address":    "#7c3aed",
  "Website Address":  "#059669",
  "Social Media Profile": "#db2777",
  "Messaging App":    "#d97706",
  "Fax Number":       K.textMid,
  "Encrypted Channel":"#b91c1c",
};

const GRADE_COLOR = {
  A:K.green, B:"#15803d", C:K.amber, D:K.red, E:K.textDim,
  1:K.green, 2:"#15803d", 3:K.amber, 4:K.textDim, 5:K.red,
};

const DRAFT_COLOR = {
  Draft:        { fg:K.textMid,  bg:"#f1f5f9",   border:"#cbd5e1" },
  Submitted:    { fg:K.amber,    bg:K.amberLight, border:"#fde68a" },
  Approved:     { fg:K.green,    bg:K.greenLight, border:"#bbf7d0" },
  Rejected:     { fg:K.red,      bg:K.redLight,   border:"#fecaca" },
  Disseminated: { fg:K.blue,     bg:K.blueLight,  border:"#bfdbfe" },
};


// ─── BASE UI ─────────────────────────────────────────────────────────────────
const inp = {
  width:"100%", padding:"8px 11px",
  border:`1px solid ${K.border}`, borderRadius:"4px",
  fontSize:"13px", color:K.text, background:K.surface,
  outline:"none", boxSizing:"border-box", fontFamily:"inherit",
  transition:"border-color 0.15s",
};

function Field({ label, required, hint, children }) {
  return (
    <div style={{ marginBottom:"16px" }}>
      <label style={{ display:"block", fontSize:"11px", fontWeight:"700",
        color:K.textMid, marginBottom:"5px", letterSpacing:"0.5px", textTransform:"uppercase" }}>
        {label}
        {required && <span style={{ color:K.red, marginLeft:"3px" }}>*</span>}
        {hint && <span style={{ fontWeight:"400", color:K.textDim, marginLeft:"6px", textTransform:"none", letterSpacing:0 }}>({hint})</span>}
      </label>
      {children}
    </div>
  );
}

function Input({ value, onChange, placeholder, type="text", disabled, onBlur }) {
  const [focused, setFocused] = useState(false);
  return (
    <input type={type} value={value||""} onChange={e=>onChange(e.target.value)}
      placeholder={placeholder} disabled={disabled} onBlur={onBlur}
      onFocus={()=>setFocused(true)}
      style={{ ...inp,
        background: disabled ? K.surfaceAlt : K.surface,
        borderColor: focused ? K.blueMid : K.border,
        color: disabled ? K.textDim : K.text,
        cursor: disabled ? "default" : "text",
      }}
      onBlur={e=>{setFocused(false);onBlur&&onBlur(e);}}
    />
  );
}

function Textarea({ value, onChange, rows=4, placeholder }) {
  const [focused, setFocused] = useState(false);
  return (
    <textarea value={value||""} onChange={e=>onChange(e.target.value)}
      rows={rows} placeholder={placeholder}
      onFocus={()=>setFocused(true)} onBlur={()=>setFocused(false)}
      style={{ ...inp, resize:"vertical", lineHeight:"1.5",
        borderColor: focused ? K.blueMid : K.border }}
    />
  );
}

function Select({ value, onChange, options, placeholder="Select…" }) {
  const [focused, setFocused] = useState(false);
  return (
    <select value={value||""} onChange={e=>onChange(e.target.value)}
      onFocus={()=>setFocused(true)} onBlur={()=>setFocused(false)}
      style={{ ...inp, color: value ? K.text : K.textDim,
        borderColor: focused ? K.blueMid : K.border,
        appearance:"auto" }}>
      <option value="">{placeholder}</option>
      {options.map(o => <option key={o} value={o}>{o}</option>)}
    </select>
  );
}

function Checkbox({ label, checked, onChange }) {
  return (
    <label style={{ display:"flex", alignItems:"center", gap:"9px", cursor:"pointer", fontSize:"13px", color:K.text }}>
      <input type="checkbox" checked={!!checked} onChange={e=>onChange(e.target.checked)}
        style={{ width:"16px", height:"16px", accentColor:K.blueMid, cursor:"pointer" }}/>
      {label}
    </label>
  );
}

function Btn({ children, onClick, variant="default", small, disabled, full, title }) {
  const [hov, setHov] = useState(false);
  const styles = {
    primary:  { bg:K.blue,     border:K.blue,    color:"#fff" },
    danger:   { bg:K.red,      border:K.red,     color:"#fff" },
    default:  { bg:K.surface,  border:K.border,  color:K.text },
    ghost:    { bg:"transparent", border:"transparent", color:K.blueMid },
  };
  const s = styles[variant] || styles.default;
  return (
    <button onClick={onClick} disabled={disabled} title={title}
      onMouseEnter={()=>setHov(true)} onMouseLeave={()=>setHov(false)}
      style={{
        padding: small ? "5px 12px" : "8px 18px",
        background: hov && !disabled ? (variant==="primary"?K.blueMid:variant==="danger"?"#b91c1c":K.surfaceAlt) : s.bg,
        border: `1px solid ${s.border}`,
        color: s.color, borderRadius:"4px",
        fontSize: small ? "11px" : "12px",
        fontWeight:"600", cursor: disabled?"not-allowed":"pointer",
        fontFamily:"inherit", opacity: disabled?0.5:1,
        whiteSpace:"nowrap", transition:"background 0.12s",
        width: full?"100%":"auto",
      }}>
      {children}
    </button>
  );
}

// ─── CLASSIFICATION BADGE ─────────────────────────────────────────────────────
function ClassBadge({ v }) {
  const [fg, bg, border] = K.class[v] || ["#333","#eee","#ccc"];
  return (
    <span style={{ padding:"3px 10px", background:bg, color:fg,
      border:`1px solid ${border}`, borderRadius:"3px",
      fontSize:"10px", fontWeight:"800", letterSpacing:"1.2px", fontFamily:"monospace" }}>
      {v}
    </span>
  );
}

// ─── TAG PILL ─────────────────────────────────────────────────────────────────
// ─── STATUS / TYPE / GRADE BADGES ────────────────────────────────────────────
function StatusBadge({ v, colorMap }) {
  const map = colorMap || {};
  const s = map[v] || { fg:K.textDim, bg:"#f1f5f9", border:"#e2e8f0" };
  return <span style={{ padding:"4px 12px", background:s.bg, color:s.fg,
    border:`1px solid ${s.border}`, borderRadius:"12px", fontSize:"11px", fontWeight:"700" }}>{v||"—"}</span>;
}

function DraftBadge({ v }) {
  const map = {
    Draft:        { fg:K.textMid,  bg:"#f1f5f9",   border:"#cbd5e1" },
    Submitted:    { fg:K.amber,    bg:K.amberLight, border:"#fde68a" },
    Approved:     { fg:K.green,    bg:K.greenLight, border:"#bbf7d0" },
    Rejected:     { fg:K.red,      bg:K.redLight,   border:"#fecaca" },
    Disseminated: { fg:K.blue,     bg:K.blueLight,  border:"#bfdbfe" },
  };
  const s = map[v] || map.Draft;
  return <span style={{ padding:"4px 14px", background:s.bg, color:s.fg,
    border:`1px solid ${s.border}`, borderRadius:"12px", fontSize:"12px", fontWeight:"700" }}>{v||"Draft"}</span>;
}

function PriorityBadge({ v }) {
  const map = {
    Critical: { fg:"#fff",   bg:K.red,       border:K.red     },
    High:     { fg:K.red,   bg:K.redLight,  border:"#fecaca" },
    Medium:   { fg:K.amber, bg:K.amberLight,border:"#fde68a" },
    Low:      { fg:K.green, bg:K.greenLight,border:"#bbf7d0" },
  };
  const s = map[v] || { fg:K.textDim, bg:"#f1f5f9", border:"#e2e8f0" };
  return <span style={{ padding:"3px 10px", background:s.bg, color:s.fg,
    border:`1px solid ${s.border}`, borderRadius:"4px", fontSize:"11px", fontWeight:"800",
    letterSpacing:"0.5px" }}>{v||"—"}</span>;
}

function CatBadge({ v }) {
  const map = {
    "Registered Source":   { fg:K.green,  bg:K.greenLight,  border:"#bbf7d0" },
    "Unregistered Source": { fg:K.amber,  bg:K.amberLight,  border:"#fde68a" },
    "Confidential Source": { fg:K.red,    bg:K.redLight,    border:"#fecaca" },
    "Open Source":         { fg:K.blue,   bg:K.blueLight,   border:"#bfdbfe" },
  };
  const s = map[v] || { fg:K.textDim, bg:"#f1f5f9", border:"#e2e8f0" };
  return <span style={{ padding:"3px 10px", background:s.bg, color:s.fg,
    border:`1px solid ${s.border}`, borderRadius:"12px", fontSize:"11px", fontWeight:"700" }}>{v}</span>;
}

function GradePill({ label, value }) {
  const gradeColor = { A:K.green,B:"#15803d",C:K.amber,D:K.red,E:K.textDim,
    1:K.green,2:"#15803d",3:K.amber,4:K.textDim,5:K.red };
  const col = gradeColor[value] || K.textDim;
  return (
    <div style={{ display:"flex", flexDirection:"column", alignItems:"center", gap:"2px" }}>
      <div style={{ fontSize:"10px", fontWeight:"700", color:K.textMid }}>{label}</div>
      <div style={{ width:"36px", height:"36px", borderRadius:"50%",
        background:`${col}18`, border:`2px solid ${col}`,
        display:"flex", alignItems:"center", justifyContent:"center",
        fontSize:"16px", fontWeight:"800", color:col, fontFamily:"monospace" }}>
        {value||"—"}
      </div>
    </div>
  );
}

function TypeBadge({ v }) {
  const typeColor = {
    "Incidents":K.red,"Intelligence":K.blue,"Action":K.green,
    "Meeting":"#5b21b6","Court Hearing":"#0369a1","Arrest":K.red,
    "Timeline":K.amber,"Surveillance":"#0f766e",
  };
  const typeIcon = {
    "Incidents":"▲","Intelligence":"◆","Action":"⚡","Meeting":"👥",
    "Court Hearing":"⚖","Arrest":"🔒","Timeline":"◷","Surveillance":"👁",
  };
  const col = typeColor[v] || K.blue;
  return <span style={{ display:"inline-flex", alignItems:"center", gap:"5px",
    padding:"3px 10px", background:`${col}15`, color:col,
    border:`1px solid ${col}44`, borderRadius:"12px", fontSize:"11px", fontWeight:"700" }}>
    {typeIcon[v]||"◷"} {v}
  </span>;
}

// SH = SectionHeader shorthand used in phase3 forms
function SH({ title, action, onAction }) {
  return (
    <div style={{ display:"flex", justifyContent:"space-between", alignItems:"center",
      padding:"10px 0", borderBottom:`2px solid ${K.blueLight}`,
      marginBottom:"16px", marginTop:"28px" }}>
      <span style={{ fontSize:"11px", fontWeight:"800", color:K.blue,
        letterSpacing:"2px", textTransform:"uppercase" }}>{title}</span>
      {action&&<button onClick={onAction} style={{ background:"none", border:"none",
        color:K.blueMid, fontSize:"11px", cursor:"pointer", fontWeight:"700",
        fontFamily:"inherit" }}>+ {action}</button>}
    </div>
  );
}


function TagPill({ label, onRemove }) {
  return (
    <span style={{ display:"inline-flex", alignItems:"center", gap:"5px",
      padding:"3px 9px", background:K.blueLight, color:K.blue,
      borderRadius:"20px", fontSize:"11px", fontWeight:"600", border:`1px solid #bfdbfe` }}>
      {label}
      {onRemove && (
        <span onClick={onRemove} style={{ cursor:"pointer", opacity:0.6, lineHeight:1 }}>×</span>
      )}
    </span>
  );
}

// ─── SECTION HEADER ───────────────────────────────────────────────────────────
function SectionHeader({ title, action, onAction }) {
  return (
    <div style={{ display:"flex", justifyContent:"space-between", alignItems:"center",
      padding:"10px 0", borderBottom:`2px solid ${K.blueLight}`,
      marginBottom:"16px", marginTop:"28px" }}>
      <span style={{ fontSize:"11px", fontWeight:"800", color:K.blue,
        letterSpacing:"2px", textTransform:"uppercase" }}>{title}</span>
      {action && (
        <button onClick={onAction} style={{ background:"none", border:"none",
          color:K.blueMid, fontSize:"11px", cursor:"pointer", fontWeight:"700",
          letterSpacing:"0.5px", fontFamily:"inherit" }}>
          + {action}
        </button>
      )}
    </div>
  );
}

// ─── TAGS INPUT ───────────────────────────────────────────────────────────────
function TagsInput({ tags, setTags }) {
  const [input, setInput] = useState("");
  const add = () => {
    const t = input.trim();
    if (t && !tags.includes(t)) setTags([...tags, t]);
    setInput("");
  };
  return (
    <div style={{ display:"flex", alignItems:"center", gap:"8px", flexWrap:"wrap", marginBottom:"20px" }}>
      <span style={{ fontSize:"11px", color:K.textDim, fontWeight:"600" }}>TAGS</span>
      <div style={{ position:"relative" }}>
        <input value={input} onChange={e=>setInput(e.target.value)}
          onKeyDown={e=>{ if(e.key==="Enter"){e.preventDefault();add();} }}
          placeholder="Add tag…"
          style={{ padding:"4px 10px", border:`1px solid ${K.border}`,
            borderRadius:"20px", fontSize:"11px", outline:"none",
            width:"120px", fontFamily:"inherit", color:K.text }} />
      </div>
      {tags.map(t => <TagPill key={t} label={t} onRemove={() => setTags(tags.filter(x=>x!==t))} />)}
    </div>
  );
}

// ─── TASKS SECTION ────────────────────────────────────────────────────────────
function TasksSection({ tasks, setTasks }) {
  const [adding, setAdding] = useState(false);
  const [form, setForm] = useState({ title:"", task_type:"Action", status:"Pending", due_date:"", allocated_to:"", description:"" });
  const sf = k => v => setForm(p => ({...p,[k]:v}));

  const add = () => {
    if (!(form.title||"").trim()) return;
    setTasks([...tasks, {...form, id:Date.now()}]);
    setForm({ title:"", task_type:"Action", status:"Pending", due_date:"", allocated_to:"", description:"" });
    setAdding(false);
  };

  const statusColor = { Pending:K.amber, "In Progress":K.blueMid, Complete:K.green, Cancelled:K.textDim };

  return (
    <div>
      <SectionHeader title="Tasks" action="Add Task" onAction={() => setAdding(true)} />
      {adding && (
        <div style={{ background:K.surfaceAlt, border:`1px solid ${K.border}`, borderRadius:"6px", padding:"16px", marginBottom:"14px" }}>
          <div style={{ display:"grid", gridTemplateColumns:"2fr 1fr 1fr", gap:"12px", marginBottom:"12px" }}>
            <Field label="Task Title" required><Input value={form.title} onChange={sf("title")} placeholder="What needs to be done?"/></Field>
            <Field label="Type"><Select value={form.task_type} onChange={sf("task_type")} options={L.task_type}/></Field>
            <Field label="Status"><Select value={form.status} onChange={sf("status")} options={L.task_status}/></Field>
          </div>
          <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:"12px", marginBottom:"12px" }}>
            <Field label="Due Date"><Input type="date" value={form.due_date} onChange={sf("due_date")}/></Field>
            <Field label="Allocated To"><Input value={form.allocated_to} onChange={sf("allocated_to")} placeholder="Name or team"/></Field>
          </div>
          <Field label="Description"><Textarea value={form.description} onChange={sf("description")} rows={2} placeholder="Additional context…"/></Field>
          <div style={{ display:"flex", gap:"8px" }}><Btn variant="primary" small onClick={add}>Save Task</Btn><Btn small onClick={() => setAdding(false)}>Cancel</Btn></div>
        </div>
      )}
      {tasks.length === 0 && !adding && (
        <p style={{ fontSize:"12px", color:K.textDim, margin:"8px 0" }}>No tasks assigned.</p>
      )}
      {tasks.length > 0 && (
        <div style={{ border:`1px solid ${K.border}`, borderRadius:"6px", overflow:"hidden" }}>
          <table style={{ width:"100%", borderCollapse:"collapse", fontSize:"12px" }}>
            <thead>
              <tr style={{ background:K.surfaceAlt }}>
                {["Due","Allocated To","Status","Type","Title",""].map(h => (
                  <th key={h} style={{ padding:"8px 12px", textAlign:"left", fontWeight:"700",
                    fontSize:"10px", color:K.textMid, letterSpacing:"0.8px",
                    borderBottom:`1px solid ${K.border}` }}>{h}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {tasks.map((t, i) => (
                <tr key={t.id} style={{ borderBottom:`1px solid ${K.border}`, background:i%2?K.surfaceAlt:K.surface }}>
                  <td style={{ padding:"9px 12px", color:isOverdue(t.due_date)?K.red:K.textMid, fontWeight:isOverdue(t.due_date)?"700":"400" }}>
                    {t.due_date||"—"}{isOverdue(t.due_date)&&" ⚠"}
                  </td>
                  <td style={{ padding:"9px 12px" }}>{t.allocated_to||"—"}</td>
                  <td style={{ padding:"9px 12px" }}>
                    <span style={{ color:statusColor[t.status]||K.textDim, fontWeight:"700", fontSize:"11px" }}>{t.status}</span>
                  </td>
                  <td style={{ padding:"9px 12px", color:K.textMid }}>{t.task_type}</td>
                  <td style={{ padding:"9px 12px", fontWeight:"600", color:K.text }}>{t.title}</td>
                  <td style={{ padding:"9px 12px" }}>
                    <button onClick={() => setTasks(tasks.filter(x=>x.id!==t.id))}
                      style={{ background:"none", border:"none", color:K.textDim, cursor:"pointer", fontSize:"11px" }}>
                      Remove
                    </button>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}

// ─── INVESTIGATOR NOTES ───────────────────────────────────────────────────────
function NotesSection({ notes, setNotes }) {
  const [adding, setAdding] = useState(false);
  const [form, setForm] = useState({ type:"Email", date:"", details:"" });
  const sf = k => v => setForm(p=>({...p,[k]:v}));

  const add = () => {
    if (!(form.details||"").trim()) return;
    setNotes([...notes, {...form, id:Date.now(), entered_by:"Mark Watson"}]);
    setForm({ type:"Email", date:"", details:"" });
    setAdding(false);
  };

  return (
    <div>
      <SectionHeader title="Investigator Notes" action="Add Note" onAction={() => setAdding(true)} />
      {adding && (
        <div style={{ background:K.surfaceAlt, border:`1px solid ${K.border}`, borderRadius:"6px", padding:"16px", marginBottom:"14px" }}>
          <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:"12px", marginBottom:"12px" }}>
            <Field label="Type"><Select value={form.type} onChange={sf("type")} options={L.note_type}/></Field>
            <Field label="Date / Time"><Input type="datetime-local" value={form.date} onChange={sf("date")}/></Field>
          </div>
          <Field label="Details" required><Textarea value={form.details} onChange={sf("details")} rows={3} placeholder="Enter note details…"/></Field>
          <div style={{ display:"flex", gap:"8px" }}><Btn variant="primary" small onClick={add}>Save Note</Btn><Btn small onClick={() => setAdding(false)}>Cancel</Btn></div>
        </div>
      )}
      {notes.length === 0 && !adding && <p style={{ fontSize:"12px", color:K.textDim, margin:"8px 0" }}>No notes recorded.</p>}
      {notes.length > 0 && (
        <div style={{ border:`1px solid ${K.border}`, borderRadius:"6px", overflow:"hidden" }}>
          <table style={{ width:"100%", borderCollapse:"collapse", fontSize:"12px" }}>
            <thead>
              <tr style={{ background:K.surfaceAlt }}>
                {["Entered By","Type","Date / Time","Details"].map(h=>(
                  <th key={h} style={{ padding:"8px 12px", textAlign:"left", fontWeight:"700",
                    fontSize:"10px", color:K.textMid, letterSpacing:"0.8px", borderBottom:`1px solid ${K.border}` }}>{h}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {notes.map((n, i) => (
                <tr key={n.id} style={{ borderBottom:`1px solid ${K.border}`, background:i%2?K.surfaceAlt:K.surface, verticalAlign:"top" }}>
                  <td style={{ padding:"9px 12px", whiteSpace:"nowrap" }}>{n.entered_by}</td>
                  <td style={{ padding:"9px 12px", whiteSpace:"nowrap" }}>{n.type}</td>
                  <td style={{ padding:"9px 12px", whiteSpace:"nowrap", color:K.textMid, fontSize:"11px" }}>{n.date}</td>
                  <td style={{ padding:"9px 12px", lineHeight:"1.5" }}>{n.details}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}

// ─── FILES SECTION ────────────────────────────────────────────────────────────

// ─── FILE TEXT EXTRACTION ─────────────────────────────────────────────────────

// Load pdf.js from CDN (deferred — only when needed)
let _pdfJsLoaded = false;
let _pdfJsLoading = false;
let _pdfJsCallbacks = [];

function loadPdfJs() {
  return new Promise(function(resolve) {
    if (_pdfJsLoaded && window.pdfjsLib) { resolve(true); return; }
    _pdfJsCallbacks.push(resolve);
    if (_pdfJsLoading) return;
    _pdfJsLoading = true;
    const script = document.createElement("script");
    script.src = "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js";
    script.onload = function() {
      window.pdfjsLib.GlobalWorkerOptions.workerSrc =
        "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js";
      _pdfJsLoaded = true; _pdfJsLoading = false;
      _pdfJsCallbacks.forEach(function(cb) { cb(true); });
      _pdfJsCallbacks = [];
    };
    script.onerror = function() {
      _pdfJsLoading = false;
      _pdfJsCallbacks.forEach(function(cb) { cb(false); });
      _pdfJsCallbacks = [];
    };
    document.head.appendChild(script);
  });
}

async function extractPdfText(dataUrl) {
  const loaded = await loadPdfJs();
  if (!loaded || !window.pdfjsLib) {
    return { status:"error", searchable:false, text:"", note:"pdf.js failed to load." };
  }
  try {
    // Convert base64 dataUrl to Uint8Array
    const base64 = dataUrl.split(",")[1];
    const binary = atob(base64);
    const bytes = new Uint8Array(binary.length);
    for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);

    const pdf = await window.pdfjsLib.getDocument({ data: bytes }).promise;
    let fullText = "";
    for (let p = 1; p <= pdf.numPages; p++) {
      const page = await pdf.getPage(p);
      const tc = await page.getTextContent();
      const pageText = tc.items.map(function(item) { return item.str; }).join(" ");
      fullText += pageText + " ";
    }
    fullText = fullText.trim();
    if (!fullText || fullText.length < 20) {
      return {
        status: "no_text_layer",
        searchable: false,
        text: "",
        note: "No text layer found — this appears to be a scanned PDF. OCR requires Azure AI Document Intelligence.",
      };
    }
    return {
      status: "extracted",
      searchable: true,
      text: fullText.substring(0, 50000), // cap at 50k chars
      note: pdf.numPages + " page" + (pdf.numPages!==1?"s":"") + " · " + fullText.length + " chars extracted",
    };
  } catch(err) {
    return { status:"error", searchable:false, text:"", note:"Extraction error: "+err.message };
  }
}

async function extractFileText(file) {
  const ext = (file.name||"").split(".").pop().toLowerCase();
  const cat = ext;

  // Plain text files — read directly
  if (["txt","csv","md","log","xml","json","html","htm"].includes(ext)) {
    return new Promise(function(resolve) {
      const reader = new FileReader();
      reader.onload = function(ev) {
        const text = (ev.target.result||"").substring(0, 50000);
        resolve({
          status: "plain_text",
          searchable: true,
          text: text,
          note: text.length + " chars",
        });
      };
      reader.onerror = function() {
        resolve({ status:"error", searchable:false, text:"", note:"Could not read file." });
      };
      reader.readAsText(file);
    });
  }

  // PDF — attempt text extraction via pdf.js
  if (ext === "pdf") {
    return new Promise(function(resolve) {
      const reader = new FileReader();
      reader.onload = async function(ev) {
        const result = await extractPdfText(ev.target.result);
        resolve(result);
      };
      reader.onerror = function() {
        resolve({ status:"error", searchable:false, text:"", note:"Could not read PDF." });
      };
      reader.readAsDataURL(file);
    });
  }

  // Images — flag for Azure OCR
  if (["jpg","jpeg","png","gif","webp","bmp","tiff","tif"].includes(ext)) {
    return {
      status: "ocr_pending",
      searchable: false,
      text: "",
      note: "Image text requires Azure AI Document Intelligence for OCR.",
    };
  }

  // Word documents — flag for Azure extraction
  if (["doc","docx","odt","rtf"].includes(ext)) {
    return {
      status: "ocr_pending",
      searchable: false,
      text: "",
      note: "Word document text extraction requires Azure AI Document Intelligence.",
    };
  }

  // Spreadsheets
  if (["xls","xlsx","ods"].includes(ext)) {
    return {
      status: "ocr_pending",
      searchable: false,
      text: "",
      note: "Spreadsheet text extraction requires Azure AI Document Intelligence.",
    };
  }

  // Everything else
  return {
    status: "not_applicable",
    searchable: false,
    text: "",
    note: "Text extraction not supported for this file type.",
  };
}

function FilesSection({ files: filesProp, setFiles, onSetProfile }) {
  const files = Array.isArray(filesProp) ? filesProp : [];
  const [adding, setAdding] = React.useState(false);
  const [form, setForm] = React.useState({ title:"", type:"Document", description:"" });
  const sf = k => v => setForm(p => ({...p,[k]:v}));

  // File type detection
  const getFileCategory = (name) => {
    if (!name) return "other";
    const ext = name.split(".").pop().toLowerCase();
    if (["jpg","jpeg","png","gif","webp","bmp","svg","tiff"].includes(ext)) return "image";
    if (["mp4","mov","avi","mkv","wmv","webm","flv"].includes(ext)) return "video";
    if (["mp3","wav","m4a","ogg","aac","flac"].includes(ext)) return "audio";
    if (["pdf"].includes(ext)) return "pdf";
    if (["doc","docx","odt","rtf","txt"].includes(ext)) return "document";
    if (["xls","xlsx","csv","ods"].includes(ext)) return "spreadsheet";
    if (["ppt","pptx","odp"].includes(ext)) return "presentation";
    if (["zip","rar","7z","tar","gz"].includes(ext)) return "archive";
    return "other";
  };

  const FILE_ICONS = {
    image:"🖼", video:"🎬", audio:"🎵", pdf:"📕",
    document:"📝", spreadsheet:"📊", presentation:"📑",
    archive:"🗜", other:"📎",
  };

  const FILE_WARN = {
    video: "Video stored as reference only — file content requires Azure Blob Storage.",
    audio: "Audio stored as reference only — file content requires Azure Blob Storage.",
    archive: "Archive stored as reference only — file content requires Azure Blob Storage.",
  };

  // Max size for base64 storage: 2MB (prevents localStorage overflow)
  const MAX_INLINE_BYTES = 2 * 1024 * 1024;

  const handleDrop = (id, e) => {
    const file = e.target.files[0];
    if (!file) return;
    const cat = getFileCategory(file.name);
    const isStorable = ["image","pdf","document","spreadsheet","presentation"].includes(cat);

    if (!isStorable) {
      // Non-storable: record metadata only
      setFiles(prev => prev.map(f => f.id===id ? {
        ...f,
        title: f.title || file.name,
        file_name: file.name,
        file_size: file.size,
        file_category: cat,
        file_type_ext: file.name.split(".").pop().toLowerCase(),
        _dataUrl: null,
        _storage: "reference_only",
        _storage_note: "File content not stored — connect Azure Blob Storage to attach files of this type.",
        ocr_status: "not_applicable",
        text_searchable: false,
        ocr_note: "File content not stored locally.",
      } : f));
      return;
    }

    if (file.size > MAX_INLINE_BYTES) {
      setFiles(prev => prev.map(f => f.id===id ? {
        ...f,
        title: f.title || file.name,
        file_name: file.name,
        file_size: file.size,
        file_category: cat,
        file_type_ext: file.name.split(".").pop().toLowerCase(),
        _dataUrl: null,
        _storage: "reference_only",
        _storage_note: "File exceeds 2MB inline limit — connect Azure Blob Storage for large files.",
        ocr_status: "not_applicable",
        text_searchable: false,
        ocr_note: "File too large for inline storage.",
      } : f));
      alert("File is larger than 2MB. Filename recorded but content not stored. Azure Blob Storage required for large files.");
      return;
    }

    // Storable and within size: read as base64
    // Set processing status immediately
    setFiles(prev => prev.map(f => f.id===id ? {
      ...f, ocr_status:"processing"
    } : f));
    const reader = new FileReader();
    reader.onload = ev => {
      setFiles(prev => prev.map(f => f.id===id ? {
        ...f,
        title: f.title || file.name,
        file_name: file.name,
        file_size: file.size,
        file_category: cat,
        file_type_ext: file.name.split(".").pop().toLowerCase(),
        _dataUrl: ev.target.result,
        _storage: "inline_base64",
      } : f));
      // Extract text after dataUrl is set
      extractFileText(file).then(function(result) {
        setFiles(prev => prev.map(f => f.id===id ? {
          ...f,
          ocr_status: result.status,
          text_searchable: result.searchable,
          extracted_text: result.text,
          ocr_note: result.note,
        } : f));
      });
    };
    reader.readAsDataURL(file);
  };

  const toggleProfile = (id) => {
    const file = files.find(f => f.id===id);
    if (!file) return;
    if (file.file_category && file.file_category !== "image") {
      alert("Only images can be set as profile photo.");
      return;
    }
    setFiles(prev => prev.map(f => ({...f, is_profile: f.id===id ? !f.is_profile : false})));
    if (onSetProfile && file._dataUrl) onSetProfile(file.is_profile ? null : file._dataUrl);
  };

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

  const add = () => {
    if (!(form.title||"").trim()) { alert("File title is required."); return; }
    setFiles([...files, {
      ...form,
      id: Date.now(),
      urn: "ATT-" + String(files.length+1).padStart(3,"0"),
      is_profile: false,
      _dataUrl: null,
      _storage: "metadata_only",
      file_category: "other",
    }]);
    setForm({ title:"", type:"Document", description:"" });
    setAdding(false);
  };

  return (
    <div>
      <SectionHeader title="Files & Attachments" action="Add Entry" onAction={() => setAdding(true)}/>

      {/* Storage notice */}
      <div style={{background:"#fffbeb",border:"1px solid #fcd34d",borderRadius:"6px",
        padding:"10px 14px",marginBottom:"14px",fontSize:"11px",color:"#78350f",
        display:"flex",alignItems:"flex-start",gap:"8px"}}>
        <span style={{fontSize:"14px",flexShrink:0}}>💡</span>
        <div>
          <strong>Current storage:</strong> Images and documents under 2MB are stored inline in the browser.
          Videos, audio, archives, and files over 2MB are recorded as references only — file content
          will be stored in <strong>Azure Blob Storage</strong> once connected.
          Images under 2MB can be set as a profile photo.
        </div>
      </div>

      {adding && (
        <div style={{background:K.surfaceAlt,border:"1px solid "+K.border,
          borderRadius:"6px",padding:"16px",marginBottom:"14px"}}>
          <div style={{display:"grid",gridTemplateColumns:"2fr 1fr",gap:"12px",marginBottom:"12px"}}>
            <Field label="Title" required>
              <Input value={form.title} onChange={sf("title")} placeholder="File name or description"/>
            </Field>
            <Field label="Type">
              <Select value={form.type} onChange={sf("type")} options={L.file_type}/>
            </Field>
          </div>
          <Field label="Description">
            <Input value={form.description} onChange={sf("description")} placeholder="Optional notes about this file"/>
          </Field>
          <div style={{display:"flex",gap:"8px",marginTop:"12px"}}>
            <Btn variant="primary" small onClick={add}>Add Entry</Btn>
            <Btn small onClick={()=>setAdding(false)}>Cancel</Btn>
          </div>
        </div>
      )}

      {files.length === 0 && !adding && (
        <p style={{fontSize:"12px",color:K.textDim,margin:"8px 0"}}>No files attached.</p>
      )}

      {files.length > 0 && (
        <div style={{display:"flex",flexDirection:"column",gap:"8px",marginBottom:"8px"}}>
          {files.map((f, i) => {
            const cat = f.file_category || getFileCategory(f.file_name||f.title||"");
            const icon = FILE_ICONS[cat] || "📎";
            const warn = FILE_WARN[cat];
            const isRef = f._storage === "reference_only";
            const hasData = !!f._dataUrl;
            return (
              <div key={f.id} style={{border:"1px solid "+K.border,borderRadius:"6px",
                background:K.surface,padding:"12px 14px"}}>
                <div style={{display:"flex",alignItems:"flex-start",gap:"12px"}}>
                  {/* Thumbnail or icon */}
                  <div style={{width:"40px",height:"40px",flexShrink:0,borderRadius:"4px",
                    background:K.surfaceAlt,border:"1px solid "+K.border,
                    display:"flex",alignItems:"center",justifyContent:"center",overflow:"hidden"}}>
                    {hasData && cat==="image"
                      ? <img src={f._dataUrl} alt="" style={{width:"100%",height:"100%",objectFit:"cover"}}/>
                      : <span style={{fontSize:"20px"}}>{icon}</span>}
                  </div>

                  {/* Info */}
                  <div style={{flex:1,minWidth:0}}>
                    <div style={{display:"flex",alignItems:"center",gap:"8px",flexWrap:"wrap"}}>
                      <span style={{fontWeight:"700",color:K.text,fontSize:"13px"}}>
                        {f.title||f.file_name||"Untitled"}
                      </span>
                      <span style={{fontFamily:"monospace",fontSize:"10px",color:K.textDim}}>{f.urn}</span>
                      {f.file_type_ext && (
                        <span style={{padding:"1px 6px",background:K.surfaceAlt,border:"1px solid "+K.border,
                          borderRadius:"3px",fontSize:"10px",fontWeight:"700",
                          color:K.textMid,textTransform:"uppercase"}}>.{f.file_type_ext}</span>
                      )}
                      {f.file_size && (
                        <span style={{fontSize:"10px",color:K.textDim}}>{formatSize(f.file_size)}</span>
                      )}
                    </div>
                    {f.description && (
                      <div style={{fontSize:"11px",color:K.textMid,marginTop:"2px"}}>{f.description}</div>
                    )}
                    {/* Storage status */}
                    <div style={{display:"flex",alignItems:"center",gap:"6px",marginTop:"4px"}}>
                      {hasData && (
                        <span style={{fontSize:"10px",padding:"1px 6px",borderRadius:"3px",
                          background:"#dcfce7",color:"#166534",fontWeight:"700"}}>
                          ✓ Stored inline
                        </span>
                      )}
                      {isRef && (
                        <span style={{fontSize:"10px",padding:"1px 6px",borderRadius:"3px",
                          background:"#fef3c7",color:"#78350f",fontWeight:"700"}}>
                          ⚠ Reference only
                        </span>
                      )}
                      {f._storage==="metadata_only" && !hasData && !isRef && (
                        <span style={{fontSize:"10px",padding:"1px 6px",borderRadius:"3px",
                          background:K.surfaceAlt,color:K.textDim,fontWeight:"700"}}>
                          Awaiting upload
                        </span>
                      )}
                      {warn && (
                        <span style={{fontSize:"10px",color:K.textDim}}>· {warn}</span>
                      )}
                    </div>
                    {/* OCR / text extraction status */}
                    <div style={{display:"flex",alignItems:"center",gap:"6px",marginTop:"3px"}}>
                      {f.ocr_status==="extracted" && (
                        <span style={{fontSize:"10px",padding:"1px 6px",borderRadius:"3px",
                          background:"#dcfce7",color:"#166534",fontWeight:"700",cursor:"default"}}
                          title={f.extracted_text ? "Extracted: "+f.extracted_text.substring(0,200)+"..." : ""}>
                          🔍 Text searchable ({f.extracted_text ? Math.round(f.extracted_text.length/5)+" words est." : ""})
                        </span>
                      )}
                      {f.ocr_status==="no_text_layer" && (
                        <span style={{fontSize:"10px",padding:"1px 6px",borderRadius:"3px",
                          background:"#fef3c7",color:"#78350f",fontWeight:"700"}}
                          title="Scanned PDF — no text layer detected">
                          ⚠ Scanned PDF — OCR pending (Azure AI required)
                        </span>
                      )}
                      {f.ocr_status==="ocr_pending" && (
                        <span style={{fontSize:"10px",padding:"1px 6px",borderRadius:"3px",
                          background:"#fef3c7",color:"#78350f",fontWeight:"700"}}>
                          ⚠ OCR pending — requires Azure AI Document Intelligence
                        </span>
                      )}
                      {f.ocr_status==="plain_text" && (
                        <span style={{fontSize:"10px",padding:"1px 6px",borderRadius:"3px",
                          background:"#dcfce7",color:"#166534",fontWeight:"700"}}>
                          🔍 Plain text — fully searchable
                        </span>
                      )}
                      {f.ocr_status==="processing" && (
                        <span style={{fontSize:"10px",padding:"1px 6px",borderRadius:"3px",
                          background:"#dbeafe",color:"#1e40af",fontWeight:"700"}}>
                          ⏳ Extracting text...
                        </span>
                      )}
                      {f.ocr_status==="error" && (
                        <span style={{fontSize:"10px",padding:"1px 6px",borderRadius:"3px",
                          background:"#fef2f2",color:K.red,fontWeight:"700"}}
                          title={f.ocr_note||""}>
                          ✗ Extraction failed
                        </span>
                      )}
                      {f.ocr_note && !["extracted","no_text_layer","ocr_pending","plain_text","processing","error"].includes(f.ocr_status) && (
                        <span style={{fontSize:"10px",color:K.textDim}}>{f.ocr_note}</span>
                      )}
                    </div>
                  </div>

                  {/* Actions */}
                  <div style={{display:"flex",flexDirection:"column",gap:"6px",flexShrink:0,alignItems:"flex-end"}}>
                    {/* Upload button */}
                    <label style={{cursor:"pointer"}}>
                      <span style={{padding:"4px 10px",border:"1px solid "+K.border,
                        borderRadius:"4px",fontSize:"11px",fontWeight:"700",
                        color:K.blue,background:K.surface,cursor:"pointer",
                        display:"inline-block"}}>
                        {hasData ? "Replace" : "Upload"}
                      </span>
                      <input type="file" style={{display:"none"}}
                        onChange={(e)=>handleDrop(f.id,e)}/>
                    </label>
                    {/* View/download if stored */}
                    {hasData && (
                      <a href={f._dataUrl} download={f.file_name||f.title}
                        style={{padding:"4px 10px",border:"1px solid "+K.border,
                          borderRadius:"4px",fontSize:"11px",fontWeight:"700",
                          color:K.text,background:K.surface,textDecoration:"none",
                          display:"inline-block"}}>
                        Download
                      </a>
                    )}
                    {/* Profile pic toggle for images */}
                    {(cat==="image"||(!f.file_category&&hasData)) && (
                      <label style={{display:"flex",alignItems:"center",gap:"4px",
                        cursor:"pointer",fontSize:"10px",color:f.is_profile?K.blue:K.textDim}}>
                        <input type="checkbox" checked={!!f.is_profile}
                          onChange={()=>toggleProfile(f.id)}
                          style={{accentColor:K.blueMid,cursor:"pointer"}}/>
                        Profile pic
                      </label>
                    )}
                    {/* Remove */}
                    <button onClick={()=>setFiles(files.filter(x=>x.id!==f.id))}
                      style={{background:"none",border:"none",color:K.textDim,
                        cursor:"pointer",fontSize:"11px",fontWeight:"700",
                        fontFamily:"inherit",padding:"2px 4px"}}
                      onMouseEnter={e=>e.currentTarget.style.color=K.red}
                      onMouseLeave={e=>e.currentTarget.style.color=K.textDim}>
                      Remove
                    </button>
                  </div>
                </div>
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}

function RecordPicker({ reg, allRecords, value, onChange }) {
  const [query, setQuery] = useState("");
  const [open, setOpen] = useState(false);
  const ref = useState(null);

  const records = allRecords[reg] || [];

  const filtered = useMemo(() => {
    const q = query.toLowerCase();
    return records.filter(r => {
      const label = getRecordLabel(reg, r).toLowerCase();
      return !q || label.includes(q) || r.urn?.toLowerCase().includes(q);
    }).slice(0, 10); // cap at 10 for usability
  }, [records, query, reg]);

  const handleSelect = (record) => {
    onChange({
      to_id: record.id,
      to_label: `${record.urn} — ${getRecordLabel(reg, record)}`,
    });
    setQuery("");
    setOpen(false);
  };

  const handleClear = () => {
    onChange({ to_id: "", to_label: "" });
    setQuery("");
  };

  // Display the selected label or the search box
  if (value.to_label && !open) {
    return (
      <div style={{ display:"flex", alignItems:"center", gap:"8px",
        padding:"8px 11px", border:`2px solid ${K.blue}`, borderRadius:"4px",
        background:K.blueLight, cursor:"pointer" }}
        onClick={() => setOpen(true)}>
        <span style={{ flex:1, fontSize:"13px", fontWeight:"600", color:K.blue }}>{value.to_label}</span>
        <button onClick={e => { e.stopPropagation(); handleClear(); }}
          style={{ background:"none", border:"none", color:K.textDim, cursor:"pointer",
            fontSize:"14px", lineHeight:1, padding:"0 2px" }}>×</button>
      </div>
    );
  }

  return (
    <div style={{ position:"relative" }}>
      <input
        autoFocus={open}
        value={query}
        onChange={e => { setQuery(e.target.value); setOpen(true); }}
        onFocus={() => setOpen(true)}
        placeholder={records.length === 0
          ? `No ${reg} records available`
          : `Search ${records.length} ${reg} record${records.length !== 1 ? "s" : ""}…`}
        style={{ ...{width:"100%",padding:"8px 11px",border:`1px solid ${K.border}`,
          borderRadius:"4px",fontSize:"13px",color:K.text,background:K.surface,
          outline:"none",boxSizing:"border-box",fontFamily:"inherit"},
          borderColor: open ? K.blueMid : K.border }}
      />
      {open && (
        <div style={{ position:"absolute", top:"calc(100% + 4px)", left:0, right:0,
          background:K.surface, border:`1px solid ${K.border}`, borderRadius:"6px",
          boxShadow:"0 4px 16px rgba(0,0,0,0.12)", zIndex:200, maxHeight:"240px",
          overflowY:"auto" }}>
          {filtered.length === 0 ? (
            <div style={{ padding:"14px 16px", fontSize:"12px", color:K.textDim, textAlign:"center" }}>
              {records.length === 0
                ? `No ${reg} records exist yet`
                : `No results for "${query}"`}
            </div>
          ) : (
            filtered.map((record, i) => (
              <div key={record.id}
                onClick={() => handleSelect(record)}
                style={{ padding:"10px 14px", cursor:"pointer", borderBottom: i < filtered.length-1 ? `1px solid ${K.border}` : "none",
                  display:"flex", alignItems:"center", gap:"10px",
                  background: K.surface, transition:"background 0.1s" }}
                onMouseEnter={e => e.currentTarget.style.background = K.blueLight}
                onMouseLeave={e => e.currentTarget.style.background = K.surface}>
                <span style={{ fontFamily:"monospace", fontSize:"11px", color:K.blue,
                  fontWeight:"700", whiteSpace:"nowrap" }}>{record.urn}</span>
                <span style={{ fontSize:"13px", color:K.text, fontWeight:"600" }}>
                  {getRecordLabel(reg, record)}
                </span>
                {record.type && (
                  <span style={{ fontSize:"10px", color:K.textDim, marginLeft:"auto" }}>{record.type}</span>
                )}
              </div>
            ))
          )}
          {records.length > 10 && filtered.length === 10 && (
            <div style={{ padding:"8px 14px", fontSize:"11px", color:K.textDim,
              borderTop:`1px solid ${K.border}`, textAlign:"center" }}>
              Showing first 10 — type to filter
            </div>
          )}
        </div>
      )}
      {open && (
        <div style={{ position:"fixed", inset:0, zIndex:199 }}
          onClick={() => setOpen(false)}/>
      )}
    </div>
  );
}

// ─── LINKS SECTION ────────────────────────────────────────────────────────────
function LinksSection({ links, setLinks, allRecords }) {
  const [adding, setAdding] = useState(false);
  const [form, setForm] = useState({
    to_register:"organisation", to_id:"", to_label:"", link_type:"Subject", reason:""
  });
  const sf = k => v => setForm(p => ({...p,[k]:v}));
  const allRegs = ["person","organisation","communication","source","material","intelligence","event","statement","information","investigation","incident","address","assessment","case","decision","outcome","staff","equipment"];

  // When register changes, reset the picked record
  const handleRegChange = v => setForm(p => ({...p, to_register:v, to_id:"", to_label:""}));

  const add = () => {
    if (!(form.to_label||"").trim()) return;
    setLinks([...links, {...form, id:Date.now()}]);
    setForm({ to_register:"organisation", to_id:"", to_label:"", link_type:"Subject", reason:"" });
    setAdding(false);
  };

  const grouped = useMemo(() => {
    const g = {};
    links.forEach(l => { (g[l.to_register] = g[l.to_register]||[]).push(l); });
    return g;
  }, [links]);

  return (
    <div>
      <SectionHeader title="Universal Links" action="Add Link" onAction={() => setAdding(true)} />
      {adding && (
        <div style={{ background:K.surfaceAlt, border:`1px solid ${K.border}`, borderRadius:"6px", padding:"16px", marginBottom:"14px" }}>
          <div style={{ display:"grid", gridTemplateColumns:"160px 1fr 180px", gap:"12px", marginBottom:"12px" }}>
            <Field label="Register">
              <select value={form.to_register} onChange={e => handleRegChange(e.target.value)}
                style={{ width:"100%", padding:"8px 11px", border:`1px solid ${K.border}`,
                  borderRadius:"4px", fontSize:"13px", color:K.text, background:K.surface,
                  outline:"none", fontFamily:"inherit" }}>
                {allRegs.map(r => <option key={r} value={r}>{r.charAt(0).toUpperCase()+r.slice(1)}</option>)}
              </select>
            </Field>
            <Field label="Record" hint="type to search">
              <RecordPicker
                reg={form.to_register}
                allRecords={allRecords || {}}
                value={{ to_id:form.to_id, to_label:form.to_label }}
                onChange={v => setForm(p => ({...p, ...v}))}
              />
            </Field>
            <Field label="Link Type">
              <Select value={form.link_type} onChange={sf("link_type")} options={L.link_type}/>
            </Field>
          </div>
          <Field label="Reason / Description">
            <Input value={form.reason} onChange={sf("reason")} placeholder="Why is this link relevant?"/>
          </Field>
          <div style={{ display:"flex", gap:"8px", alignItems:"center" }}>
            <Btn variant="primary" small onClick={add} disabled={!form.to_label}>Add Link</Btn>
            <Btn small onClick={() => { setAdding(false); setForm({to_register:"organisation",to_id:"",to_label:"",link_type:"Subject",reason:""}); }}>Cancel</Btn>
            {!form.to_label && <span style={{ fontSize:"11px", color:K.textDim }}>Select a record to continue</span>}
          </div>
        </div>
      )}
      {links.length === 0 && !adding && <p style={{ fontSize:"12px", color:K.textDim, margin:"8px 0" }}>No links recorded.</p>}
      {Object.entries(grouped).map(([reg, regLinks]) => (
        <div key={reg} style={{ marginBottom:"12px" }}>
          <div style={{ fontSize:"10px", fontWeight:"700", color:K.textMid, letterSpacing:"1.5px",
            textTransform:"uppercase", marginBottom:"6px", paddingBottom:"4px", borderBottom:`1px solid ${K.border}` }}>
            {reg}s ({regLinks.length})
          </div>
          <div style={{ border:`1px solid ${K.border}`, borderRadius:"6px", overflow:"hidden" }}>
            <table style={{ width:"100%", borderCollapse:"collapse", fontSize:"12px" }}>
              <thead>
                <tr style={{ background:K.surfaceAlt }}>
                  {["URN — Record","Link Type","Reason",""].map(h=>(
                    <th key={h} style={{ padding:"7px 12px", textAlign:"left", fontWeight:"700",
                      fontSize:"10px", color:K.textMid, borderBottom:`1px solid ${K.border}` }}>{h}</th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {regLinks.map((l, i) => (
                  <tr key={l.id} style={{ borderBottom:`1px solid ${K.border}`, background:i%2?K.surfaceAlt:K.surface }}>
                    <td style={{ padding:"8px 12px", color:K.blue, fontWeight:"600" }}>{l.to_label||l.to_id}</td>
                    <td style={{ padding:"8px 12px" }}>
                      <span style={{ padding:"2px 8px", background:K.blueLight, color:K.blue,
                        borderRadius:"3px", fontSize:"11px", fontWeight:"600" }}>{l.link_type}</span>
                    </td>
                    <td style={{ padding:"8px 12px", color:K.textMid }}>{l.reason}</td>
                    <td style={{ padding:"8px 12px" }}>
                      <button onClick={() => setLinks(links.filter(x=>x.id!==l.id))}
                        style={{ background:"none", border:"none", color:K.textDim, cursor:"pointer", fontSize:"11px" }}>
                        Remove
                      </button>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      ))}
    </div>
  );
}

// ─── RECORD PROPERTIES PANEL ──────────────────────────────────────────────────
function RecordProps({ record }) {
  const [open, setOpen] = useState(false);
  return (
    <div style={{ border:`1px solid ${K.border}`, borderRadius:"6px", marginBottom:"16px", overflow:"hidden" }}>
      <button onClick={() => setOpen(!open)} style={{ width:"100%", padding:"9px 14px",
        background:K.surfaceAlt, border:"none", cursor:"pointer",
        display:"flex", justifyContent:"space-between", alignItems:"center",
        fontFamily:"inherit" }}>
        <span style={{ fontSize:"11px", fontWeight:"700", color:K.blue, letterSpacing:"1.5px" }}>
          RECORD PROPERTIES
        </span>
        <span style={{ color:K.textDim, fontSize:"13px" }}>{open?"▲":"▼"}</span>
      </button>
      {open && (
        <div style={{ padding:"12px 16px", fontSize:"12px", color:K.textMid, background:K.surface,
          display:"grid", gridTemplateColumns:"1fr 1fr", gap:"6px" }}>
          <div><strong>URN:</strong> {record?.urn||"Will be assigned on save"}</div>
          <div><strong>Created:</strong> {fmtDate(today)} by Mark Watson</div>
          <div><strong>Classification:</strong> <ClassBadge v={record?.classification||"CONFIDENTIAL"}/></div>
          <div><strong>Last Updated:</strong> {fmtDate(today)}</div>

      {record?._prev && (
        <div style={{marginTop:"10px",paddingTop:"10px",borderTop:`1px solid ${K.border}`}}>
          <div style={{fontSize:"10px",fontWeight:"800",color:K.amber,
            letterSpacing:"1.5px",marginBottom:"8px"}}>PREVIOUS VERSION</div>
          <div style={{fontSize:"11px",color:K.textMid,lineHeight:"1.8"}}>
            <div><strong>Saved:</strong> {record._prev._saved_at ? new Date(record._prev._saved_at).toLocaleString("en-GB") : "—"}</div>
            <div><strong>By:</strong> {record._prev._saved_by||"—"}</div>
            {record._prev.title && record.title !== record._prev.title && (
              <div style={{marginTop:"6px",padding:"6px 8px",background:K.amberLight,
                borderRadius:"4px",fontSize:"11px"}}>
                <strong>Title changed from:</strong> {record._prev.title}
              </div>
            )}
            {record._prev.status && record.status !== record._prev.status && (
              <div style={{marginTop:"4px",padding:"6px 8px",background:K.amberLight,
                borderRadius:"4px",fontSize:"11px"}}>
                <strong>Status changed from:</strong> {record._prev.status}
              </div>
            )}
            {record._prev.classification && record.classification !== record._prev.classification && (
              <div style={{marginTop:"4px",padding:"6px 8px",background:K.amberLight,
                borderRadius:"4px",fontSize:"11px"}}>
                <strong>Classification changed from:</strong> {record._prev.classification}
              </div>
            )}
          </div>
        </div>
      )}
        </div>
      )}
    </div>
  );
}

// ─── SEED DATA ───────────────────────────────────────────────────────────────
const SEED_PERSON = [
  {
    id: "p1", urn: "AW-PER-0001", classification: "CONFIDENTIAL",
    type: "Command Responsibility", subtype: "Supreme Commander-in-Chief",
    title: "Mr", surname: "AL-ASSAD", forenames: "Bashar",
    dob: "1965-09-11", pob: "Damascus, Syria", sex: "Male",
    nationality: "Syrian", occupation: "Former Syrian President",
    reason_for_nominal: "Central role in orchestrating widespread human rights abuses and alleged war crimes.",
    notes: "Implicated in chemical weapons use, indiscriminate bombing, torture and enforced disappearances.",
    review_period: "5 Years", review_date: "2030-05-21",
    tags: ["Syria","High Value Target"],
    tasks: [{id:1, title:"Verify current location", task_type:"Research", status:"Pending", due_date:"2026-06-01", allocated_to:"Mark Watson", description:"Confirm current whereabouts via open source"}],
    inv_notes: [{id:1, entered_by:"Mark Watson", type:"Meeting", date:"2025-10-05T10:00", details:"Discussed investigation scope with GRC Foundation. Confirmed subject as primary target."}],
    files: [{id:1, urn:1, title:"Profile photograph", type:"Open Source", description:"Open source image"}],
    links: [{to_register:"organisation", to_id:"o1", link_type:"Commander", reason:"Supreme commander of Syrian Armed Forces"}],
  },
  {
    id: "p2", urn: "AW-PER-0002", classification: "CONFIDENTIAL",
    type: "Command Responsibility", subtype: "Theatre Commander",
    title: "Mr", surname: "AL-ASSAD", forenames: "Maher Hafiz",
    dob: "1967-12-08", nationality: "Syrian", occupation: "Commander 4th Armoured Division",
    reason_for_nominal: "Leader of Syria's 4th Armoured Division, responsible for documented IHL violations.",
    notes: "", review_period: "3 Years", review_date: "2027-01-01",
    tags: ["Syria","4th Division"], tasks: [], inv_notes: [], files: [], links: [],
  },
  {
    id: "p3", urn: "AW-PER-0003", classification: "CONFIDENTIAL",
    type: "Witness", subtype: "",
    title: "Mr", surname: "FAYYAD", forenames: "Mohammad",
    dob: "1985-03-15", nationality: "Syrian", occupation: "Civilian",
    reason_for_nominal: "Witness to starvation conditions in Yarmouk camp 2013–2015.",
    notes: "", review_period: "1 Year", review_date: "2026-11-12",
    tags: ["Yarmouk","Witness"], tasks: [], inv_notes: [], files: [], links: [],
  },
];

const SEED_ORG = [
  {
    id:"o1", urn:"AW-ORG-0001", classification:"CONFIDENTIAL",
    type:"Military Unit", name:"4TH ARMOURED DIVISION",
    status:"Active", date_inc:"",
    registered_country:"Syria", also_known_as:"4th Division; Tiger Forces",
    reg_number:"", last_accounts:"",
    reg_address:"Damascus, Syrian Arab Republic",
    telephone:"", fax:"", email:"", website:"",
    reason_for_nominal:"Elite Syrian Army division commanded by Maher al-Assad, implicated in multiple IHL violations.",
    source:"Open Source / Intelligence", civil_litigation:"",
    notes:"Responsible for numerous documented war crimes including starvation sieges and unlawful killings.",
    review_period:"1 Year", review_date:"2026-01-01",
    tags:["Syria","Military"], tasks:[], inv_notes:[], files:[], links:[],
    logo_url:null,
  },
  {
    id:"o2", urn:"AW-ORG-0002", classification:"CONFIDENTIAL",
    type:"Company", name:"SYRIATEL",
    status:"Active", date_inc:"2000-01-01",
    registered_country:"Syria", also_known_as:"SyriaTel Mobile Telecom",
    reg_number:"SY-COM-00412", last_accounts:"2023-12-31",
    reg_address:"Mazzeh District, Damascus, Syrian Arab Republic",
    telephone:"+963 11 2223344", fax:"", email:"info@syriatel.sy", website:"www.syriatel.sy",
    reason_for_nominal:"Telecoms company controlled by Rami Makhlouf, used for regime financial flows.",
    source:"Corporate Registry / Open Source", civil_litigation:"",
    notes:"60.9% beneficial ownership held by Rami Makhlouf via Investcomm (BVI).",
    review_period:"2 Years", review_date:"2027-01-01",
    tags:["Syria","Financial","Telecoms"], tasks:[], inv_notes:[], files:[], links:[],
    logo_url:null,
  },
  {
    id:"o3", urn:"AW-ORG-0003", classification:"CONFIDENTIAL",
    type:"NGO", name:"GLOBAL RIGHTS COMPLIANCE FOUNDATION",
    status:"Active", date_inc:"2015-03-10",
    registered_country:"Netherlands", also_known_as:"GRC Foundation; GRC",
    reg_number:"NL-NGO-71204", last_accounts:"2024-12-31",
    reg_address:"Bezuidenhoutseweg 67, 2594 AC The Hague, Netherlands",
    telephone:"+31 70 302 0000", fax:"", email:"info@globalrightscompliance.com", website:"www.globalrightscompliance.com",
    reason_for_nominal:"Partner organisation on BLUE TITAN investigation.",
    source:"Partner", civil_litigation:"",
    notes:"",
    review_period:"1 Year", review_date:"2026-01-01",
    tags:["Partner"], tasks:[], inv_notes:[], files:[], links:[],
    logo_url:null,
  },
];

const SEED_INF = [
  {
    id:"inf1", urn:"AW-INF-0001", classification:"CONFIDENTIAL",
    type:"Findings Report", subtype:"Internal",
    title:"RUMIS: MPI VOLNA — Financial Network Analysis",
    date_reported:"2024-03-24", date_occurred:"2024-03-01", date_until:"2024-03-24",
    source_text:"ArcticWind internal analysis; Europol OS-12 Financial Crime Team",
    information_body:"Analysis of the MPI VOLNA financial network reveals a complex web of offshore entities controlled through nominee structures in the British Virgin Islands and UAE. The network is used to move funds derived from sanctions evasion and weapons procurement on behalf of the Assad regime.\n\nKey findings:\n1. VOLNA LLC (BVI) acts as the primary holding entity\n2. Funds flow through three UAE-registered intermediaries before reaching destination accounts in Lebanon\n3. Beneficial ownership traced back to Rami Makhlouf via Investcomm (BVI)\n4. Total estimated flows: USD 340m between 2020–2024",
    provenance:"Intelligence gathered from open source financial databases, corporate registry searches, and partner agency intelligence sharing (Europol EFECC).",
    status:"For Review",
    review_period:"1 Month", review_date:"2025-04-25",
    tags:["MPI VOLNA","Financial","Sanctions"],
    tasks:[
      {id:1,title:"Legal review of draft report",task_type:"Review",status:"Pending",due_date:"2026-01-15",allocated_to:"Lucy Myles",description:"Review before submission to Europol."},
    ],
    inv_notes:[
      {id:1,entered_by:"Mark Watson",type:"Email",date:"2025-05-07T10:29",details:"Follow-up email sent to Lucy Myles (lucilla.myles@europol.europa.eu) to include the original i2 chart."},
      {id:2,entered_by:"Mark Watson",type:"Email",date:"2025-04-01T19:04",details:"EUROPOL Head of Team informs report received and shared with OS-12 Financial Crime Team."},
    ],
    files:[
      {id:1,urn:1597,title:"MPI Volna_belotti Shared.anb",type:"Material",description:"i2 chart shared via email",is_profile:false,_dataUrl:null},
      {id:2,urn:316,title:"MPI VOLNA LLC Investigation Report",type:"Material",description:"Full investigation report",is_profile:false,_dataUrl:null},
      {id:3,urn:315,title:"MPI VOLNA Report Cover Page",type:"Material",description:"",is_profile:false,_dataUrl:null},
      {id:4,urn:314,title:"MPI VOLNA Link Chart",type:"Material",description:"Network link chart",is_profile:false,_dataUrl:null},
    ],
    links:[],
  },
  {
    id:"inf2", urn:"AW-INF-0002", classification:"CONFIDENTIAL",
    type:"Briefing Note", subtype:"Internal",
    title:"BLUE TITAN: Summary of Evidence to Date",
    date_reported:"2025-11-01", date_occurred:"2013-01-01", date_until:"2015-12-31",
    source_text:"ArcticWind / GRC Foundation joint investigation",
    information_body:"Executive briefing note summarising the current state of evidence in Operation BLUE TITAN. Three witness statements have been secured, two documentary exhibits confirmed, and OSINT corroborates the blockade timeline.",
    provenance:"Compiled from witness statements, material evidence, and open source intelligence gathered during the investigation.",
    status:"Approved",
    review_period:"3 Months", review_date:"2026-02-01",
    tags:["BLUE TITAN","Syria","Starvation"],
    tasks:[], inv_notes:[], files:[], links:[],
  },
  {
    id:"inf3", urn:"AW-INF-0003", classification:"SECRET",
    type:"Information Request", subtype:"External",
    title:"MLA Request — Syrian Financial Records (ICC Referral)",
    date_reported:"2025-09-15", date_occurred:"", date_until:"",
    source_text:"ICC Office of the Prosecutor",
    information_body:"Mutual Legal Assistance request submitted to the Syrian National Commission for the provision of financial records relating to the 4th Armoured Division procurement accounts 2010–2024.",
    provenance:"Formal MLA request via ICC OTP channels.",
    status:"Draft",
    review_period:"6 Months", review_date:"2026-03-15",
    tags:["MLA","ICC","Financial"],
    tasks:[], inv_notes:[], files:[], links:[],
  },
];

const SEED_STMT = [
  {
    id:"st1", urn:"AW-STM-0001", classification:"CONFIDENTIAL",
    type:"Witness Statement",
    title:"Statement given by Mohammad FAYYAD on 12 November 2025",
    description:"Witness account of starvation conditions in Yarmouk camp, Damascus, during the siege period 2013–2015. Witness was resident throughout the siege and provides first-hand testimony of food blockades and civilian deaths.",
    given_by_name:"Mohammad FAYYAD",
    statement_number:"WS-2025-029",
    date_taken:"2025-11-12", time_taken:"14:00",
    where_taken:"Secure Interview Room, London",
    taken_by_name:"Mark Watson",
    produced_exhibits:[
      {id:1, exhibit_ref:"MF/1", description:"Photograph of food queue at UNRWA distribution point, taken by witness in February 2014"},
      {id:2, exhibit_ref:"MF/2", description:"Handwritten diary entries from January–March 2014 recording daily ration amounts"},
    ],
    referenced_material:[
      {id:1, material_urn:"AW-MAT-0001", description:"GREEN Network: Bashar al-Assad Transfer Order — referenced by witness at page 4 of statement"},
    ],
    review_period:"1 Year", review_date:"2026-11-12",
    tags:["Yarmouk","Starvation","BLUE TITAN"],
    tasks:[],
    inv_notes:[
      {id:1,entered_by:"Mark Watson",type:"Email",date:"2025-11-13T09:00",details:"Follow-up email sent to confirm receipt of signed statement. Awaiting return copy."},
      {id:2,entered_by:"Mark Watson",type:"Meeting",date:"2025-11-12T14:00",details:"Witness was cooperative throughout. Appeared credible and consistent. No significant inconsistencies noted."},
    ],
    files:[
      {id:1,urn:1,title:"WS-2025-029 Signed Statement",type:"Legal Document",description:"Signed original",_dataUrl:null},
      {id:2,urn:2,title:"MF-1 Exhibit Photograph",type:"Photograph",description:"UNRWA food queue Feb 2014",_dataUrl:null},
    ],
    links:[{id:1,to_register:"incident",to_id:"inc1",to_label:"AW-INC-0028 — BLUE TITAN",link_type:"Witness",reason:"Witness statement concerning starvation crimes"}],
  },
  {
    id:"st2", urn:"AW-STM-0002", classification:"CONFIDENTIAL",
    type:"Witness Statement",
    title:"Statement given by Ahmad Ali AL-SOLH on 11 October 2025",
    description:"Witness account describing enforcement of the food blockade by armed groups at checkpoints surrounding Yarmouk camp.",
    given_by_name:"Ahmad Ali AL-SOLH",
    statement_number:"WS-2025-027",
    date_taken:"2025-10-11", time_taken:"11:00",
    where_taken:"Secure Interview Room, The Hague",
    taken_by_name:"Mark Watson",
    produced_exhibits:[],
    referenced_material:[],
    review_period:"1 Year", review_date:"2026-10-11",
    tags:["Yarmouk","Starvation","BLUE TITAN"],
    tasks:[], inv_notes:[], files:[], links:[],
  },
  {
    id:"st3", urn:"AW-STM-0003", classification:"CONFIDENTIAL",
    type:"Witness Statement",
    title:"Statement given by Khaled SALAMEH on 21 October 2025",
    description:"Witness describes systematic denial of medical supplies in addition to food, and names specific checkpoint commanders responsible.",
    given_by_name:"Khaled SALAMEH",
    statement_number:"WS-2025-026",
    date_taken:"2025-10-21", time_taken:"15:30",
    where_taken:"Secure Interview Room, London",
    taken_by_name:"Elise Baranowski",
    produced_exhibits:[],
    referenced_material:[],
    review_period:"1 Year", review_date:"2026-10-21",
    tags:["Yarmouk","Medical","BLUE TITAN"],
    tasks:[], inv_notes:[], files:[], links:[],
  },
];

const SEED_SRC = [
  {
    id:"src1", urn:"AW-SRC-0001", classification:"SECRET",
    type:"Human Intelligence (HUMINT)", category:"Confidential Source",
    reference:"SPARROW-2",
    title:"", surname:"[REDACTED]", forenames:"SPARROW-2",
    dob:"", pob:"", sex:"Male",
    height_imp:"", height_met:"", ethnicity:"", self_defined_ethnicity:"",
    pnc_id:"", religion:"", self_defined_disability:"",
    deceased:false, date_of_death:"",
    further_details:"Military defector with direct knowledge of 4th Armoured Division operational planning and command structure.",
    nationality:"Syrian", occupation:"Former Military Officer",
    reason_for_nominal:"Primary HUMINT source for intelligence on 4th Division movements and command chain during the BLUE TITAN investigation period.",
    source:"Intelligence referral", notes:"Source assessed as reliable. Three intelligence items corroborated to date.",
    contact_preference:"In person only. Contact via secure intermediary. Do not attempt direct contact.",
    specialist_skills:"Military logistics; Command structure knowledge; Syrian Army order of battle",
    aliases:[{id:1,alias:"SPARROW-2",type:"Codename"},{id:2,alias:"[REDACTED]",type:"True Name"}],
    record_of_contact:[
      {id:1,date:"2024-03-22",method:"In Person",location:"Undisclosed",officer:"Mark Watson",summary:"Debriefing on 4th Division movements in northern sector March 2024. Source confirmed troop positions. Intelligence graded B/2/3.",duration:"90 mins"},
      {id:2,date:"2024-01-15",method:"Secure Messaging",location:"Remote",officer:"Mark Watson",summary:"Initial contact and tasking. Source agreed to provide information on divisional structure.",duration:"30 mins"},
    ],
    review_period:"6 Months", review_date:"2025-06-22",
    tags:["Syria","Military","BLUE TITAN"],
    tasks:[], inv_notes:[], files:[], links:[],
  },
  {
    id:"src2", urn:"AW-SRC-0002", classification:"CONFIDENTIAL",
    type:"Partner Agency", category:"Registered Source",
    reference:"EUROPOL-OS12",
    title:"", surname:"MYLES", forenames:"Lucy",
    dob:"", pob:"", sex:"Female",
    height_imp:"", height_met:"", ethnicity:"", self_defined_ethnicity:"",
    pnc_id:"", religion:"", self_defined_disability:"",
    deceased:false, date_of_death:"",
    further_details:"",
    nationality:"British", occupation:"Europol Financial Crime Analyst — OS-12 Team",
    reason_for_nominal:"Official partner source at Europol providing financial intelligence on MPI VOLNA network.",
    source:"Formal MOU", notes:"Europol liaison for Operation BLUE TITAN. Formal information sharing agreement in place.",
    contact_preference:"Email or phone during business hours (CET). Formal requests via MOU channel.",
    specialist_skills:"Financial crime analysis; Sanctions evasion; Corporate structures",
    aliases:[],
    record_of_contact:[
      {id:1,date:"2025-05-07",method:"Email",location:"Remote",officer:"Mark Watson",summary:"Sent follow-up regarding MPI VOLNA i2 chart. Europol confirmed receipt and sharing with relevant authority.",duration:""},
    ],
    review_period:"1 Year", review_date:"2026-01-01",
    tags:["Europol","Financial","Partner"],
    tasks:[], inv_notes:[], files:[], links:[],
  },
];

const SEED_MAT = [
  {
    id:"m1", urn:"AW-MAT-0001", classification:"CONFIDENTIAL",
    type:"Document", title:"GREEN Network: Bashar al-Assad Transfer Order",
    description:"Transfer order (N13) signed by Bashar al-Assad on 9 April 2024, directing movement of funds through the GREEN network shell company structure.",
    is_exhibit:true,
    when_found:"2024-04-15T09:00",
    found_by_name:"Mark Watson",
    where_found:"Digital — open source financial database",
    status:"Secured",
    current_location:"KOIOS Secure Document Store — London",
    seal_number:"AW-SEAL-001",
    av_reviews:[],
    movements:[
      {id:1,date:"2024-04-15",from_location:"Open source database",to_location:"KOIOS Secure Document Store — London",reason:"Secured",officer:"Mark Watson",notes:"Downloaded and hash-verified. SHA-256 recorded."},
    ],
    review_period:"3 Years", review_date:"2027-01-01",
    tags:["Documentary Evidence","GREEN Network","Assad"],
    tasks:[], inv_notes:[], files:[], links:[{id:1,to_register:"person",to_label:"AW-PER-0001 — Bashar AL-ASSAD",link_type:"Subject",reason:"Document signed by subject"}],
  },
  {
    id:"m2", urn:"AW-MAT-0002", classification:"CONFIDENTIAL",
    type:"Video/Audio Recording", title:"Yarmouk survivor testimony — audio recording",
    description:"Audio recording of witness FALCON-7 describing conditions in Yarmouk camp during the siege period January–March 2014. Duration: 47 minutes.",
    is_exhibit:true,
    when_found:"2025-10-14T11:00",
    found_by_name:"Mark Watson",
    where_found:"Secure Interview Room, London",
    status:"In Analysis",
    current_location:"Digital forensics lab — ArcticWind London",
    seal_number:"AW-SEAL-002",
    av_reviews:[
      {id:1,reviewed_by:"Mark Watson",date:"2025-10-16",duration_reviewed:"00:47:00",summary:"Recording is clear throughout. Witness describes systematic food blockade in detail. No inconsistencies with written statement. Key testimony at 12:30–18:45 mark.",quality:"Good"},
    ],
    movements:[
      {id:1,date:"2025-10-14",from_location:"Secure Interview Room",to_location:"Digital forensics lab",reason:"Submitted to Lab",officer:"Mark Watson",notes:"Original recording on encrypted USB. Chain of custody form signed."},
    ],
    review_period:"3 Years", review_date:"2027-03-18",
    tags:["Yarmouk","Audio","Witness"],
    tasks:[], inv_notes:[], files:[], links:[],
  },
  {
    id:"m3", urn:"AW-MAT-0003", classification:"SECRET",
    type:"Satellite Imagery",
    title:"Al-Rashid District — pre/post bombardment imagery",
    description:"Satellite imagery showing civilian settlement before and after bombardment. Two images — January 2014 (before) and April 2014 (after). Source: commercial satellite provider.",
    is_exhibit:false,
    when_found:"2025-09-01T00:00",
    found_by_name:"Elise Baranowski",
    where_found:"Commercial satellite imagery provider",
    status:"Secured",
    current_location:"KOIOS Secure Document Store — London",
    seal_number:"",
    av_reviews:[],
    movements:[],
    review_period:"5 Years", review_date:"2029-03-15",
    tags:["Satellite","Al-Rashid","Bombardment"],
    tasks:[], inv_notes:[], files:[], links:[],
  },
];

const SEED_INT = [
  {
    id:"i1", urn:"AW-INT-0001", classification:"CONFIDENTIAL",
    type:"Human Intelligence",
    investigation_ref:"AW-INV-0001",
    title:"SPARROW-2: 4th Division movements confirmed — northern sector",
    date_occurred:"2024-03-22T00:00", date_until:"2024-03-22T23:59",
    source_ref:"AW-SRC-0001 — SPARROW-2",
    entries:[
      {id:1, s:"B", i:"2", h:"3", content:"4th Armoured Division confirmed active in northern sector during the period 20–22 March 2024. Source had direct observation of troop movements consistent with intelligence from previous reporting cycle.", confidential:false},
      {id:2, s:"B", i:"3", h:"3", content:"Source reports that orders for the northern deployment were issued from divisional HQ in Damascus on 18 March 2024.", confidential:false},
    ],
    show_confidential:false,
    source_eval:"B", intel_assessment:"2", handling_code:"3",
    confidence_level:"Medium",
    pii:false,
    summary:"Source SPARROW-2 confirms 4th Armoured Division active in northern sector during the BLUE TITAN incident window. Two intelligence entries, overall graded B/2/3. Corroborates satellite imagery AW-MAT-0003.",
    draft_status:"Approved",
    review_period:"3 Months", review_date:"2024-06-22",
    tags:["4th Division","Syria","BLUE TITAN"],
    tasks:[], inv_notes:[], files:[], links:[
      {id:1,to_register:"person",to_label:"AW-PER-0001 — Bashar AL-ASSAD",link_type:"Subject",reason:"Intelligence concerns this subject"},
      {id:2,to_register:"material",to_label:"AW-MAT-0003 — Al-Rashid satellite imagery",link_type:"Related",reason:"Satellite imagery corroborates this intelligence"},
    ],
  },
  {
    id:"i2", urn:"AW-INT-0002", classification:"SECRET",
    type:"Open Source Intelligence",
    investigation_ref:"AW-INV-0001",
    title:"Yarmouk food convoy blockades confirmed — open source",
    date_occurred:"2024-02-01T00:00", date_until:"2024-03-31T23:59",
    source_ref:"UNRWA reports / BBC / Al-Jazeera",
    entries:[
      {id:1, s:"A", i:"1", h:"1", content:"Multiple open source reports including UNRWA situation reports, BBC and Al-Jazeera coverage confirm systematic blocking of food convoys to Yarmouk camp between February and March 2024. UNRWA reported 19 convoy attempts blocked in this period.", confidential:false},
    ],
    show_confidential:false,
    source_eval:"A", intel_assessment:"1", handling_code:"1",
    confidence_level:"High",
    pii:false,
    summary:"Open source intelligence confirming systematic blockade of food convoys to Yarmouk camp. Graded A/1/1 — corroborated by multiple independent reliable sources.",
    draft_status:"Disseminated",
    review_period:"6 Months", review_date:"2024-08-15",
    tags:["Yarmouk","Starvation","OSINT","BLUE TITAN"],
    tasks:[], inv_notes:[], files:[], links:[],
  },
  {
    id:"i3", urn:"AW-INT-0003", classification:"CONFIDENTIAL",
    type:"Financial Intelligence",
    investigation_ref:"AW-INV-0001",
    title:"MPI VOLNA — beneficial ownership traced to Makhlouf",
    date_occurred:"2024-03-01T00:00", date_until:"2024-03-24T23:59",
    source_ref:"Europol OS-12 / ArcticWind financial analysis",
    entries:[
      {id:1, s:"B", i:"2", h:"2", content:"Beneficial ownership of VOLNA LLC (BVI) traced through three UAE intermediaries to Rami Makhlouf via Investcomm (BVI). Corporate registry and financial flow analysis.", confidential:false},
      {id:2, s:"C", i:"3", h:"3", content:"Source within UAE financial sector indicates accounts are still active as of March 2024. Not independently corroborated.", confidential:true},
    ],
    show_confidential:false,
    source_eval:"B", intel_assessment:"2", handling_code:"2",
    confidence_level:"Medium-High",
    pii:false,
    summary:"Financial intelligence tracing MPI VOLNA LLC beneficial ownership to Rami Makhlouf. Second entry contains sensitive source material — marked confidential.",
    draft_status:"Approved",
    review_period:"3 Months", review_date:"2024-06-24",
    tags:["MPI VOLNA","Financial","Makhlouf"],
    tasks:[], inv_notes:[], files:[], links:[],
  },
];

const SEED_EVT = [
  {
    id:"e1", urn:"AW-EVT-0001", classification:"CONFIDENTIAL",
    type:"Timeline",
    date_of_occurrence:"2013-07-01T00:00",
    officer:"Mark Watson", subject:"BLUE TITAN — Yarmouk Siege Timeline",
    title:"July 2013: Yarmouk camp population estimated at 160,000 — siege begins",
    notes:"Following the outbreak of the Syrian Civil War, armed groups took control of Yarmouk camp in December 2012. By July 2013, the population had swelled to an estimated 160,000 civilians. Syrian government forces and allied militias imposed a blockade preventing food, medicine and other supplies from entering the camp. This marks the effective start of the starvation siege.",
    team:"ArcticWind / GRC Foundation",
    location_text:"Yarmouk Camp, Damascus, Syrian Arab Republic",
    review_period:"5 Years", review_date:"2030-01-01",
    tags:["Yarmouk","Timeline","Starvation","BLUE TITAN"],
    tasks:[], inv_notes:[], files:[], links:[
      {id:1,to_register:"incident",to_label:"AW-INC-0001 — BLUE TITAN",link_type:"Timeline",reason:"Timeline event for BLUE TITAN investigation"},
    ],
  },
  {
    id:"e2", urn:"AW-EVT-0002", classification:"CONFIDENTIAL",
    type:"Timeline",
    date_of_occurrence:"2014-01-18T00:00",
    officer:"Mark Watson", subject:"BLUE TITAN — Food Convoy",
    title:"18 January 2014: First UNRWA food convoy enters Yarmouk — 6.5 tonnes",
    notes:"After months of negotiations, the first UNRWA food convoy was permitted to enter Yarmouk camp on 18 January 2014. The convoy carried 6.5 tonnes of food, estimated to be sufficient for only a fraction of the population. Subsequent convoys were irregularly permitted and frequently blocked, creating a pattern of deliberate deprivation.",
    team:"ArcticWind / GRC Foundation",
    location_text:"Yarmouk Camp checkpoint, Damascus, Syrian Arab Republic",
    review_period:"5 Years", review_date:"2030-01-01",
    tags:["Yarmouk","Timeline","UNRWA","BLUE TITAN"],
    tasks:[], inv_notes:[], files:[], links:[
      {id:1,to_register:"incident",to_label:"AW-INC-0001 — BLUE TITAN",link_type:"Timeline",reason:"Timeline event for BLUE TITAN investigation"},
    ],
  },
  {
    id:"e3", urn:"AW-EVT-0003", classification:"CONFIDENTIAL",
    type:"Meeting",
    date_of_occurrence:"2025-10-05T10:00",
    officer:"Mark Watson", subject:"BLUE TITAN — Operational Planning",
    title:"GRC Foundation — ArcticWind operational planning meeting, The Hague",
    notes:"Initial meeting with Global Rights Compliance Foundation to discuss scope and methodology for Operation BLUE TITAN. Agreed investigation structure, evidence standards, and information sharing protocols. Data sharing platform to be established by 24 October 2025.",
    team:"ArcticWind",
    location_text:"GRC Foundation offices, The Hague, Netherlands",
    review_period:"1 Year", review_date:"2026-10-05",
    tags:["BLUE TITAN","GRC","Planning"],
    tasks:[
      {id:1,title:"Establish shared document platform",task_type:"Action",status:"Complete",due_date:"2025-10-24",allocated_to:"Mark Watson",description:"Set up secure data sharing between ArcticWind and GRC Foundation."},
    ],
    inv_notes:[], files:[], links:[
      {id:1,to_register:"organisation",to_label:"AW-ORG-0003 — Global Rights Compliance Foundation",link_type:"Related",reason:"Meeting with partner organisation"},
    ],
  },
  {
    id:"e4", urn:"AW-EVT-0004", classification:"CONFIDENTIAL",
    type:"Intelligence",
    date_of_occurrence:"2024-03-22T09:00",
    officer:"Mark Watson", subject:"4th Division — SPARROW-2 debrief",
    title:"SPARROW-2 debrief — 4th Division northern sector movements confirmed",
    notes:"Source SPARROW-2 debriefed at undisclosed location. Confirmed 4th Armoured Division active in northern sector 20–22 March 2024. Orders issued from divisional HQ on 18 March. Intelligence product AW-INT-0001 produced from this debrief.",
    team:"ArcticWind",
    location_text:"Undisclosed",
    review_period:"6 Months", review_date:"2024-09-22",
    tags:["SPARROW-2","4th Division","Intelligence","BLUE TITAN"],
    tasks:[], inv_notes:[], files:[], links:[
      {id:1,to_register:"source",to_label:"AW-SRC-0001 — SPARROW-2",link_type:"Contact",reason:"Source debriefed at this event"},
      {id:2,to_register:"intelligence",to_label:"AW-INT-0001 — 4th Division movements",link_type:"Related",reason:"Intelligence product from this debrief"},
    ],
  },
  {
    id:"e5", urn:"AW-EVT-0005", classification:"CONFIDENTIAL",
    type:"Court Hearing",
    date_of_occurrence:"2026-03-15T09:30",
    officer:"Mark Watson", subject:"ICC — Preliminary hearing",
    title:"ICC OTP — preliminary admissibility hearing, The Hague",
    notes:"Preliminary hearing before the International Criminal Court Office of the Prosecutor regarding admissibility of evidence gathered under Operation BLUE TITAN. ArcticWind represented by legal counsel.",
    team:"ArcticWind Legal",
    location_text:"International Criminal Court, The Hague, Netherlands",
    review_period:"1 Year", review_date:"2027-03-15",
    tags:["ICC","Legal","BLUE TITAN"],
    tasks:[], inv_notes:[], files:[], links:[],
  },
];

const SEED_COM = [
  {
    id:"c1", urn:"AW-COM-0001", classification:"CONFIDENTIAL",
    type:"Website Address",
    number_address:"www.yonastar.com",
    service_provider:"",
    reason_for_nominal:"Website linked to VOLNA LLC shell company network. Created 13 January 2014 by Bassam NAQAWEH. Registered to PO Box 123902, Dubai, UAE.",
    source:"Open source corporate registry / OSINT",
    notes:"Domain registered through a UAE intermediary. Whois data partially redacted. Site appears dormant since 2022 but domain remains active.",
    primary_person_ref:"",
    review_period:"1 Year", review_date:"2026-01-01",
    tags:["MPI VOLNA","Financial","UAE"],
    tasks:[], inv_notes:[], files:[], links:[
      {id:1,to_register:"organisation",to_label:"AW-ORG-0002 — SYRIATEL",link_type:"Related",reason:"Website linked to associated network"},
    ],
  },
  {
    id:"c2", urn:"AW-COM-0002", classification:"CONFIDENTIAL",
    type:"Mobile Number",
    number_address:"+963 11 912 3456",
    service_provider:"Syriatel",
    reason_for_nominal:"Mobile number attributed to Maher al-Assad, used during the period 2013–2015.",
    source:"Intelligence / SIGINT referral",
    notes:"Number active on Syriatel network. Last active signal: March 2024. Associated IMEI recorded separately.",
    primary_person_ref:"AW-PER-0002 — Maher AL-ASSAD",
    review_period:"6 Months", review_date:"2026-06-01",
    tags:["Syria","4th Division"],
    tasks:[], inv_notes:[], files:[], links:[
      {id:1,to_register:"person",to_label:"AW-PER-0002 — Maher AL-ASSAD",link_type:"Subject",reason:"Number attributed to this subject"},
    ],
  },
  {
    id:"c3", urn:"AW-COM-0003", classification:"CONFIDENTIAL",
    type:"Email Address",
    number_address:"info@globalrightscompliance.com",
    service_provider:"Google Workspace",
    reason_for_nominal:"Official email address for Global Rights Compliance Foundation — partner organisation.",
    source:"Open source / partner MOU",
    notes:"Official contact email. Formal communications should use the MOU secure channel.",
    primary_person_ref:"",
    review_period:"2 Years", review_date:"2027-01-01",
    tags:["GRC","Partner"],
    tasks:[], inv_notes:[], files:[], links:[
      {id:1,to_register:"organisation",to_label:"AW-ORG-0003 — Global Rights Compliance Foundation",link_type:"Contact",reason:"Official contact address for partner organisation"},
    ],
  },
  {
    id:"c4", urn:"AW-COM-0004", classification:"SECRET",
    type:"Encrypted Channel",
    number_address:"Signal: SPARROW-2-HANDLER",
    service_provider:"Signal",
    reason_for_nominal:"Secure communication channel for contact with source SPARROW-2.",
    source:"Handler established",
    notes:"Channel established January 2024. Safety number verified. Do not use for any other communications.",
    primary_person_ref:"AW-SRC-0001 — SPARROW-2",
    review_period:"6 Months", review_date:"2025-12-01",
    tags:["Source","SPARROW-2","Secure"],
    tasks:[], inv_notes:[], files:[], links:[
      {id:1,to_register:"source",to_label:"AW-SRC-0001 — SPARROW-2",link_type:"Contact",reason:"Secure channel for this source"},
    ],
  },
];

const INV_SEED = [
  {
    id:"inv1", urn:"AW-INV-0001", classification:"CONFIDENTIAL",
    type:"War Crimes", status:"Open",
    title:"Operation BLUE TITAN — Syrian Starvation Crimes",
    summary:"Comprehensive all-source investigation into starvation crimes committed in Syrian camps under the Assad regime 2013–2015, conducted in partnership with Global Rights Compliance Foundation. The investigation focuses on the systematic siege of Yarmouk camp and the use of starvation as a weapon of war, constituting a potential crime against humanity under Article 7 of the Rome Statute.",
    start_date:"2025-01-10", close_date:"",
    lead_investigator:"Mark Watson",
    investigation_team:"Mark Watson; Lucy Myles (Europol); Elise Baranowski",
    share_internally:true, restricted_search:false,
    review_period:"1 Year", review_date:"2026-01-10",
    tags:["Syria","Starvation","War Crimes","Yarmouk"],
    tasks:[
      {id:1,title:"Review draft findings report",task_type:"Review",status:"Pending",due_date:"2026-01-15",allocated_to:"Lucy Myles",description:"Legal review before submission to Europol."},
      {id:2,title:"Identify additional witnesses",task_type:"Research",status:"Pending",due_date:"2026-02-15",allocated_to:"Mark Watson",description:"Target minimum 5 further witness statements."},
      {id:3,title:"Establish data sharing platform",task_type:"Action",status:"Complete",due_date:"2025-10-24",allocated_to:"Mark Watson",description:""},
    ],
    inv_notes:[
      {id:1,entered_by:"Mark Watson",type:"Meeting",date:"2025-10-05T10:00",details:"Initial planning meeting with GRC Foundation, The Hague. Investigation scope and methodology agreed."},
    ],
    files:[], links:[
      {id:1,to_register:"incident",to_label:"AW-INC-0001 — BLUE TITAN",link_type:"Related",reason:"Primary incident under investigation"},
      {id:2,to_register:"person",to_label:"AW-PER-0001 — Bashar AL-ASSAD",link_type:"Subject",reason:"Primary subject of investigation"},
      {id:3,to_register:"organisation",to_label:"AW-ORG-0003 — GRC Foundation",link_type:"Related",reason:"Partner organisation"},
    ],
  },
];

const INC_SEED = [
  {
    id:"inc1", urn:"AW-INC-0001", classification:"CONFIDENTIAL",
    type:"Starvation Crimes",
    title:"BLUE TITAN",
    how_reported:"Intelligence", date_reported:"2025-10-11",
    taken_by:"Mark Watson", date_occurred:"2013-07-01",
    reported_by:"Global Rights Compliance Foundation",
    location_text:"Yarmouk Camp, Damascus, Syrian Arab Republic",
    notes:"ArcticWind will partner with the Global Rights Compliance Foundation to conduct a comprehensive all-source investigation into starvation crimes committed in Syrian camps under the Assad regime. The siege of Yarmouk camp from 2013–2015 resulted in widespread civilian deaths from starvation and denial of medical care. An estimated 160,000 civilians were trapped at the height of the siege.",
    assigned_to:"Mark Watson",
    case_priority:"Critical",
    status:"In Progress",
    date_completed:"",
    modes_of_liability:"Joint Criminal Enterprise (JCE)",
    methods_duration:"All-source investigation using witness testimony, documentary evidence, satellite imagery, OSINT and intelligence. Estimated duration 24 months.",
    type_of_info:"Witness statements; Documentary evidence of command orders; Satellite imagery; Financial records; Intelligence reports",
    necessity_legitimacy:"Investigation is necessary to ensure accountability for alleged crimes against humanity. Conducted under formal MOU with GRC Foundation. ICC referral pathway identified.",
    exclusivity:"No other organisation is conducting a comparable investigation with equivalent resource and legal standing.",
    data_storage:"All data stored on encrypted KOIOS system. Azure cloud storage with geo-redundancy. Access controls enforced by role.",
    legal_risk:"Medium. Risk of subject becoming aware of investigation. Witness protection measures in place.",
    data_breach_plan:"Incident response plan in place. DPO notified within 72 hours of any breach. Subjects notified where legally required.",
    dsar_response:"DSARs from subjects will be assessed by legal counsel. Exemptions under law enforcement processing likely to apply.",
    authorisation_statement:"I authorise the conduct of this investigation under the terms of the MOU between ArcticWind and Global Rights Compliance Foundation, dated 10 January 2025.",
    authorising_officer:"Mark Watson",
    authorising_position:"Director, ArcticWind",
    review_period:"3 Years", review_date:"2028-10-11",
    tags:["Starvation","Syria","Yarmouk","War Crimes"],
    tasks:[
      {id:1,title:"Establish data sharing platform",task_type:"Action",status:"Complete",due_date:"2025-10-24",allocated_to:"Mark Watson",description:""},
      {id:2,title:"Identify additional witnesses",task_type:"Research",status:"Pending",due_date:"2026-02-15",allocated_to:"Mark Watson",description:"Target minimum 5 further witness statements."},
    ],
    inv_notes:[], files:[], links:[
      {id:1,to_register:"person",to_label:"AW-PER-0001 — Bashar AL-ASSAD",link_type:"Command Responsibility",reason:"Supreme commander of forces conducting starvation strategy"},
      {id:2,to_register:"person",to_label:"AW-PER-0002 — Maher AL-ASSAD",link_type:"Command Responsibility",reason:"Operational commander of 4th Armoured Division"},
      {id:3,to_register:"organisation",to_label:"AW-ORG-0001 — 4th Armoured Division",link_type:"Subject",reason:"Military unit executing blockade"},
      {id:4,to_register:"statement",to_label:"AW-STM-0001 — Mohammad FAYYAD",link_type:"Witness",reason:"Witness statement"},
      {id:5,to_register:"statement",to_label:"AW-STM-0002 — Ahmad AL-SOLH",link_type:"Witness",reason:"Witness statement"},
    ],
  },
];

const SEEDS = {
  address:[
    {id:"a1",urn:"AW-ADR-0001",classification:"CONFIDENTIAL",type:"Business Address",
     address_line1:"4th Armoured Division HQ",address_line2:"Mazzeh Military Base",
     city:"Damascus",county:"",postcode:"",country:"Syrian Arab Republic",
     latitude:"33.4973",longitude:"36.2257",
     reason_for_nominal:"HQ of 4th Armoured Division — command centre for BLUE TITAN subject organisation.",
     source:"Open source / satellite imagery",notes:"",
     review_period:"1 Year",review_date:"2026-01-01",
     tags:["Syria","4th Division"],tasks:[],inv_notes:[],files:[],links:[
       {id:1,to_register:"organisation",to_label:"AW-ORG-0001 — 4th Armoured Division",link_type:"Location",reason:"HQ of this organisation"},
     ]},
    {id:"a2",urn:"AW-ADR-0002",classification:"CONFIDENTIAL",type:"Business Address",
     address_line1:"Bezuidenhoutseweg 67",address_line2:"",
     city:"The Hague",county:"South Holland",postcode:"2594 AC",country:"Netherlands",
     latitude:"52.0799",longitude:"4.3113",
     reason_for_nominal:"GRC Foundation registered office — partner organisation.",
     source:"Open source / corporate registry",notes:"",
     review_period:"2 Years",review_date:"2027-01-01",
     tags:["GRC","Partner"],tasks:[],inv_notes:[],files:[],links:[]},
  ],
  assessment:[
    {id:"as1",urn:"AW-ASS-0001",classification:"CONFIDENTIAL",type:"Legal Assessment",
     title:"BLUE TITAN — Rome Statute Article 7 Admissibility Assessment",
     description:"Legal assessment of admissibility of evidence gathered under BLUE TITAN for ICC proceedings under Article 7 of the Rome Statute (Crimes Against Humanity).",
     assessment_date:"2025-12-01",assessed_by:"Legal Counsel — ArcticWind",
     outcome:"Evidence meets the threshold for admissibility. Witness testimony corroborated by documentary and satellite evidence. Command responsibility chain established to requisite standard. Recommend referral to ICC OTP.",
     source:"Internal legal review",notes:"",
     review_period:"6 Months",review_date:"2026-06-01",
     tags:["ICC","Legal","BLUE TITAN"],tasks:[],inv_notes:[],files:[],links:[]},
  ],
  case:[
    {id:"c1",urn:"AW-CAS-0001",classification:"CONFIDENTIAL",type:"War Crimes",
     status:"Active",priority:"Critical",
     title:"Assad Regime — Starvation as Weapon of War",
     summary:"Case file for the use of starvation as a method of warfare against the civilian population of Yarmouk camp, Damascus, 2013–2015.",
     start_date:"2025-01-10",close_date:"",lead_investigator:"Mark Watson",
     notes:"Case linked to Operation BLUE TITAN investigation. ICC referral pathway active.",
     review_period:"1 Year",review_date:"2026-01-10",
     tags:["War Crimes","Syria","ICC"],tasks:[],inv_notes:[],files:[],links:[
       {id:1,to_register:"investigation",to_label:"AW-INV-0001 — Operation BLUE TITAN",link_type:"Related",reason:"Primary investigation for this case"},
     ]},
  ],
  decision:[
    {id:"d1",urn:"AW-DEC-0001",classification:"CONFIDENTIAL",type:"Operational Decision",
     title:"Decision to partner with GRC Foundation on BLUE TITAN",
     description:"Decision to formalise the partnership between ArcticWind and Global Rights Compliance Foundation for the conduct of Operation BLUE TITAN.",
     decision_date:"2025-01-10",decided_by:"Mark Watson",
     rationale:"GRC Foundation brings specialist expertise in IHL documentation and established ICC relationships. Partnership strengthens legal standing of evidence gathered. MOU executed 10 January 2025.",
     notes:"",
     review_period:"1 Year",review_date:"2026-01-10",
     tags:["BLUE TITAN","GRC"],tasks:[],inv_notes:[],files:[],links:[]},
    {id:"d2",urn:"AW-DEC-0002",classification:"CONFIDENTIAL",type:"Legal Decision",
     title:"Decision to pursue ICC referral pathway",
     description:"Decision to pursue referral of BLUE TITAN evidence to the ICC Office of the Prosecutor rather than domestic jurisdiction.",
     decision_date:"2025-12-01",decided_by:"Mark Watson / Legal Counsel",
     rationale:"ICC jurisdiction established. Syrian domestic courts not independent. Third-state universal jurisdiction complex. ICC OTP referral is the appropriate and most effective route to accountability.",
     notes:"",
     review_period:"6 Months",review_date:"2026-06-01",
     tags:["ICC","Legal","BLUE TITAN"],tasks:[],inv_notes:[],files:[],links:[]},
  ],
  outcome:[
    {id:"o1",urn:"AW-OUT-0001",classification:"CONFIDENTIAL",type:"Referral",
     title:"BLUE TITAN — ICC OTP Referral (anticipated)",
     description:"Anticipated referral of BLUE TITAN evidence package to the ICC Office of the Prosecutor, targeting Q2 2026.",
     notes:"Subject to completion of evidence review and legal sign-off.",
     review_period:"6 Months",review_date:"2026-06-01",
     tags:["ICC","BLUE TITAN"],tasks:[],inv_notes:[],files:[],links:[]},
  ],
  staff:[
    {id:"sf1",urn:"AW-STF-0001",classification:"CONFIDENTIAL",type:"Investigator",
     title:"Mr",surname:"Watson",forenames:"Mark",
     dob:"",pob:"",sex:"Male",
     nationality:"British",occupation:"Director",
     clearance:"TOP SECRET",department:"Investigations",
     reason_for_nominal:"Lead investigator and Director of ArcticWind.",
     source:"Internal",notes:"Lead on BLUE TITAN and all current investigations.",further_details:"",
     review_period:"1 Year",review_date:"2026-01-01",
     tags:["ArcticWind","Senior"],tasks:[],inv_notes:[],files:[],links:[]},
    {id:"sf2",urn:"AW-STF-0002",classification:"CONFIDENTIAL",type:"Analyst",
     title:"Ms",surname:"Baranowski",forenames:"Elise",
     dob:"",pob:"",sex:"Female",
     nationality:"British",occupation:"Intelligence Analyst",
     clearance:"CONFIDENTIAL",department:"Intelligence",
     reason_for_nominal:"Intelligence analyst supporting BLUE TITAN.",
     source:"Internal",notes:"",further_details:"",
     review_period:"1 Year",review_date:"2026-01-01",
     tags:["ArcticWind"],tasks:[],inv_notes:[],files:[],links:[]},
  ],
  equipment:[
    {id:"eq1",urn:"AW-EQP-0001",classification:"CONFIDENTIAL",type:"Electronic Device",
     registration:"",make:"Apple",model:"MacBook Pro 16\"",colour:"Silver",
     serial_number:"C02XL0LDJG5J",
     further_details:"Primary investigation workstation. Full-disk encryption enabled. Remote wipe configured.",
     reason_for_nominal:"Primary device used in BLUE TITAN investigation. Chain of custody relevant if evidence challenged.",
     source:"ArcticWind asset",notes:"",
     review_period:"1 Year",review_date:"2026-01-01",
     tags:["ArcticWind","IT"],tasks:[],inv_notes:[],files:[],links:[]},
  ],
};


const INITIAL_RECORDS = {
  person: SEED_PERSON,
  organisation: SEED_ORG,
  information: SEED_INF,
  statement: SEED_STMT,
  source: SEED_SRC,
  material: SEED_MAT,
  intelligence: SEED_INT,
  event: SEED_EVT,
  communication: SEED_COM,
  investigation: INV_SEED,
  incident: INC_SEED,
  address: SEEDS.address,
  assessment: SEEDS.assessment,
  case: SEEDS.case,
  decision: SEEDS.decision,
  outcome: SEEDS.outcome,
  staff: SEEDS.staff,
  equipment: SEEDS.equipment,
};

// ══════════════════════════════════════════════════════════════════

// PERSON REGISTER
// ══════════════════════════════════════════════════════════════════


// ─── PERSON FORM ──────────────────────────────────────────────────────────────
function PersonForm({ record, onSave, onCancel, allRecords={}, onOpenRecord, readOnly=false, onDelete, onDuplicate }) {
  const isNew = !record?.id;
  const [f, setF] = useState(record || {
    classification: "CONFIDENTIAL",
    tags: [], tasks: [], inv_notes: [], files: [], links: [],
    deceased: false,
    photo_url: null,
  });
  const fileInputRef = useState(null);
  const handlePhotoUpload = (e) => {
    const file = e.target.files[0];
    if (!file) return;
    const reader = new FileReader();
    reader.onload = (ev) => setF(p => ({...p, photo_url: ev.target.result}));
    reader.readAsDataURL(file);
  };
  const handleSetProfileFromFile = (fileId) => {
    const file = (f.files||[]).find(x => x.id === fileId);
    if (file && file._dataUrl) setF(p => ({...p, photo_url: file._dataUrl}));
  };
  const s = k => v => setF(p => ({...p, [k]:v}));

  const fullName = [f.title, f.forenames, f.surname].filter(Boolean).join(" ");
  const age = calcAge(f.dob);

  const handleSave = () => {
    if (!f.surname?.trim()) { alert("Surname is required."); return; }
    const saved = { ...f, id:f.id||Date.now(), urn:f.urn||makeURN() };
    onSave(saved);
  };

  return (
    <div style={{ maxWidth:"900px", margin:"0 auto" }}>
      {/* Record header */}
      <div style={{ display:"flex", justifyContent:"space-between", alignItems:"flex-start",
        marginBottom:"24px", paddingBottom:"18px", borderBottom:`1px solid ${K.border}` }}>
        <div>
          <div style={{ fontSize:"11px", fontWeight:"700", color:K.textDim,
            letterSpacing:"2px", textTransform:"uppercase", marginBottom:"4px" }}>
            PERSON REGISTER
            {!isNew && <span style={{ marginLeft:"10px", fontFamily:"monospace",
              color:K.blue, fontWeight:"800" }}>{f.urn}</span>}
          </div>
          <h1 style={{ margin:0, fontSize:"22px", fontWeight:"800", color:K.navy,
            fontFamily:"'Georgia','Times New Roman',serif" }}>
            {isNew ? "Add New Person" : fullName||"Unnamed Person"}
          </h1>
          {!isNew && f.type && (
            <div style={{ marginTop:"4px", fontSize:"12px", color:K.textMid }}>
              {f.type}{f.subtype ? ` · ${f.subtype}` : ""}
            </div>
          )}
        </div>
        <div style={{ display:"flex", flexDirection:"column", alignItems:"flex-end", gap:"8px" }}>
          <div style={{ display:"flex", alignItems:"center", gap:"8px" }}>
            <span style={{ fontSize:"11px", color:K.textMid, fontWeight:"600" }}>Classification</span>
            <select value={f.classification} onChange={e=>s("classification")(e.target.value)}
              style={{ padding:"5px 9px", border:`1px solid ${K.border}`, borderRadius:"4px",
                fontSize:"11px", fontWeight:"800", color:K.blue, fontFamily:"monospace",
                background:K.surface, cursor:"pointer" }}>
              {L.class_lvl.map(c => <option key={c} value={c}>{c}</option>)}
            </select>
          </div>
          <ClassBadge v={f.classification}/>
        </div>
      </div>

      {/* Tags + Photo box side by side */}
      <div style={{ display:"flex", gap:"24px", alignItems:"flex-start", marginBottom:"8px" }}>
        {/* Left: tags */}
        <div style={{ flex:1 }}>
          <TagsInput tags={f.tags||[]} setTags={s("tags")} />
        </div>
        {/* Right: photo box */}
        <div style={{ flexShrink:0, width:"140px", display:"flex", flexDirection:"column", alignItems:"center", gap:"8px" }}>
          <div style={{ width:"130px", height:"155px", border:`2px solid ${K.border}`,
            borderRadius:"6px", overflow:"hidden", background:K.surfaceAlt,
            display:"flex", alignItems:"center", justifyContent:"center", position:"relative", cursor:"pointer" }}
            onClick={() => document.getElementById("photo-upload-input").click()}>
            {f.photo_url
              ? <img src={f.photo_url} alt="Profile" style={{ width:"100%", height:"100%", objectFit:"cover" }}/>
              : <img src="/mnt/user-data/uploads/Unknown_Person.png" alt="No photo"
                  style={{ width:"100%", height:"100%", objectFit:"cover", opacity:0.5 }}
                  onError={e => { e.target.style.display="none"; e.target.parentNode.innerHTML += "<div style='font-size:11px;color:#8a9bb0;text-align:center;padding:10px'>No photo<br/>Click to upload</div>"; }}/>
            }
            <div style={{ position:"absolute", bottom:0, left:0, right:0,
              background:"rgba(13,31,60,0.65)", color:"#fff",
              fontSize:"10px", textAlign:"center", padding:"4px", fontWeight:"600" }}>
              {f.photo_url ? "Click to change" : "Click to upload"}
            </div>
          </div>
          <input id="photo-upload-input" type="file" accept="image/*"
            style={{ display:"none" }} onChange={handlePhotoUpload}/>
          {f.photo_url && (
            <button onClick={() => setF(p=>({...p, photo_url:null}))}
              style={{ background:"none", border:"none", color:K.textDim,
                fontSize:"10px", cursor:"pointer", fontFamily:"inherit" }}>
              ✕ Remove photo
            </button>
          )}
          <div style={{ fontSize:"9px", color:K.textDim, textAlign:"center", lineHeight:"1.4" }}>
            Profile picture<br/>JPG, PNG accepted
          </div>
        </div>
      </div>

      {/* ── DETAILS ── */}
      <SectionHeader title="Details"/>

      <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:"16px" }}>
        <Field label="Type">
          <Select value={f.type} onChange={s("type")} options={L.person_type}/>
        </Field>
        <Field label="Subtype">
          <select value={f.subtype||""} onChange={e=>s("subtype")(e.target.value)}
            style={{...inp, color:f.subtype?K.text:K.textDim}}>
            <option value="">Select…</option>
            {L.person_subtype.map(o => o.startsWith("—")
              ? <option key={o} value="" disabled style={{color:K.textDim,fontWeight:"700",background:"#f0f4f8"}}>{o}</option>
              : <option key={o} value={o}>{o}</option>
            )}
          </select>
        </Field>
      </div>

      <div style={{ display:"grid", gridTemplateColumns:"100px 1fr 1fr", gap:"12px" }}>
        <Field label="Title">
          <Select value={f.title} onChange={s("title")} options={L.title}/>
        </Field>
        <Field label="Surname" required>
          <Input value={f.surname} onChange={v => s("surname")(v.toUpperCase())} placeholder="FAMILY NAME"/>
        </Field>
        <Field label="Forename(s)">
          <Input value={f.forenames} onChange={s("forenames")} placeholder="Given names"/>
        </Field>
      </div>

      <Field label="Also Known As" hint="aliases, alternative names, maiden name">
        <Input value={f.also_known_as} onChange={s("also_known_as")} placeholder="e.g. Abu Hafez, Maher Assad, née Smith — separate with semicolons"/>
      </Field>

      <div style={{ display:"grid", gridTemplateColumns:"1fr 80px 1fr 1fr", gap:"12px" }}>
        <Field label="Date of Birth">
          <Input type="date" value={f.dob} onChange={s("dob")}/>
        </Field>
        <Field label="Age" hint="auto">
          <Input value={age||""} onChange={()=>{}} disabled/>
        </Field>
        <Field label="Place of Birth">
          <Input value={f.pob} onChange={s("pob")} placeholder="City, Country"/>
        </Field>
        <Field label="Sex">
          <Select value={f.sex} onChange={s("sex")} options={L.sex}/>
        </Field>
      </div>

      <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:"16px" }}>
        <Field label="Nationality">
          <Input value={f.nationality} onChange={s("nationality")} placeholder="e.g. British, Syrian"/>
        </Field>
        <Field label="Occupation">
          <Input value={f.occupation} onChange={s("occupation")} placeholder="Job title or role"/>
        </Field>
      </div>

      {/* Deceased toggle */}
      <div style={{ marginBottom:"16px" }}>
        <Checkbox label="Deceased" checked={f.deceased} onChange={s("deceased")}/>
        {f.deceased && (
          <div style={{ marginTop:"10px", maxWidth:"200px" }}>
            <Field label="Date of Death">
              <Input type="date" value={f.date_of_death} onChange={s("date_of_death")}/>
            </Field>
          </div>
        )}
      </div>

      <Field label="Further Details">
        <Textarea value={f.further_details} onChange={s("further_details")} rows={3}
          placeholder="Any additional biographical or descriptive information…"/>
      </Field>

      <Field label="Reason for Nominal" hint="Why is this person in the system?">
        <Input value={f.reason_for_nominal} onChange={s("reason_for_nominal")}
          placeholder="Brief explanation of investigative relevance"/>
      </Field>

      <Field label="Source">
        <Input value={f.source} onChange={s("source")} placeholder="Where did this information come from?"/>
      </Field>

      <Field label="Notes">
        <Textarea value={f.notes} onChange={s("notes")} rows={5}
          placeholder="Free-text notes, observations, intelligence…"/>
      </Field>

      {/* Review */}
      <div style={{ display:"grid", gridTemplateColumns:"200px auto 160px", gap:"12px", alignItems:"end", marginBottom:"20px" }}>
        <Field label="Review After (Period)">
          <Select value={f.review_period} onChange={s("review_period")} options={L.review_per}/>
        </Field>
        <div style={{ paddingBottom:"1px", color:K.textMid, fontSize:"12px", paddingTop:"32px" }}>on date</div>
        <Field label="Review Date">
          <Input type="date" value={f.review_date} onChange={s("review_date")}/>
        </Field>
      </div>

      {/* Record Properties */}
      <RecordProps record={f}/>

      {/* ── SAVE BAR ── */}
      <div style={{ borderTop:`1px solid ${K.border}`, paddingTop:"16px", marginBottom:"8px",
        display:"flex", gap:"10px", alignItems:"center", flexWrap:"wrap" }}>
        <Btn variant="primary" onClick={handleSave}>Save Record</Btn>
        <Btn onClick={() => { const saved={...f,id:f.id||Date.now(),urn:f.urn||makeURN()};onSave(saved); }}>
          Save & Continue
        </Btn>
        <Btn onClick={onCancel}>Cancel</Btn>
        {!isNew && (
          <>
            <div style={{ flex:1 }}/>
            <span style={{ fontSize:"11px", color:K.textDim }}>Export:</span>
            <Btn small onClick={() => alert("i2 ANB export — connects to backend API")}>i2 ANB</Btn>
            <Btn small variant="primary" onClick={() => alert("PDF report — opens print dialog")}>PDF</Btn>
          </>
        )}
      </div>

      {/* ── SHARED SECTIONS ── */}
      <TasksSection tasks={f.tasks||[]} setTasks={s("tasks")}/>
      <NotesSection notes={f.inv_notes||[]} setNotes={s("inv_notes")}/>
      <FilesSection files={f.files||[]} setFiles={s("files")}
        onSetProfile={(url) => setF(p => ({...p, photo_url: url}))}/>
      <LinksSection links={f.links||[]} setLinks={s("links")} allRecords={allRecords} onOpenRecord={onOpenRecord}/>
    </div>
  );
}

// ─── REGISTER LIST VIEW ───────────────────────────────────────────────────────
// ─── PERSON BULK IMPORT ──────────────────────────────────────────────────────

const PERSON_IMPORT_FIELDS = [
  { key:"surname",      label:"Surname",       required:true,  hint:"SURNAME (uppercase recommended)" },
  { key:"forenames",    label:"Forenames",     required:false, hint:"First / given names" },
  { key:"title",        label:"Title",         required:false, hint:"Mr, Mrs, Dr etc." },
  { key:"type",         label:"Type",          required:false, hint:"e.g. Subject, Witness, Suspect" },
  { key:"date_of_birth",label:"Date of Birth", required:false, hint:"YYYY-MM-DD" },
  { key:"nationality",  label:"Nationality",   required:false, hint:"e.g. Syrian" },
  { key:"passport_number",label:"Passport No.",required:false, hint:"" },
  { key:"sex",          label:"Sex",           required:false, hint:"Male, Female, Unknown" },
  { key:"classification",label:"Classification",required:false,hint:"UNCLASSIFIED, RESTRICTED, CONFIDENTIAL" },
  { key:"description",  label:"Description",   required:false, hint:"Free text" },
  { key:"tags",         label:"Tags",          required:false, hint:"Comma-separated e.g. Syria,BLUE TITAN" },
];

function parseCSV(text) {
  const lines = text.trim().split(/\r?\n/);
  if (lines.length < 2) return { headers:[], rows:[] };
  const headers = lines[0].split(",").map(h => { const t=h.trim(); return (t[0]==="\u0022"&&t[t.length-1]==="\u0022")?t.slice(1,-1):t; });
  const rows = lines.slice(1).map(line => {
    // Handle quoted fields with commas inside
    const fields = [];
    let inQ = false, cur = "";
    for (let i = 0; i < line.length; i++) {
      const c = line[i];
      if (c === '"') { inQ = !inQ; }
      else if (c === "," && !inQ) { fields.push(cur.trim()); cur = ""; }
      else { cur += c; }
    }
    fields.push(cur.trim());
    const row = {};
    headers.forEach((h, i) => { const raw=(fields[i]||"").trim(); row[h]=(raw[0]==='"'&&raw[raw.length-1]==='"')?raw.slice(1,-1):raw; });
    return row;
  }).filter(r => Object.values(r).some(v => v.trim()));
  return { headers, rows };
}

function PersonImportModal({ onClose, onImport, existingRecords }) {
  const [step, setStep] = React.useState("upload"); // upload | map | preview | done
  const [csvData, setCsvData] = React.useState(null);  // { headers, rows }
  const [mapping, setMapping] = React.useState({});    // koios_field -> csv_column
  const [preview, setPreview] = React.useState([]);
  const [importing, setImporting] = React.useState(false);
  const [results, setResults] = React.useState(null);  // { imported, skipped, errors }
  const [dupAction, setDupAction] = React.useState("skip"); // skip | import
  const [templatePreview, setTemplatePreview] = React.useState(null);

  // Step 1: file upload
  const handleFile = (e) => {
    const file = e.target.files[0];
    if (!file) return;
    const reader = new FileReader();
    reader.onload = (ev) => {
      const parsed = parseCSV(ev.target.result);
      if (parsed.rows.length === 0) {
        alert("No data rows found. Check the file has a header row and at least one data row.");
        return;
      }
      setCsvData(parsed);
      // Auto-map: try to match CSV headers to KOIOS fields by similarity
      const autoMap = {};
      PERSON_IMPORT_FIELDS.forEach(f => {
        const match = parsed.headers.find(h => {
          const hLow = h.toLowerCase().replace(/[^a-z]/g,"");
          const fLow = f.key.toLowerCase().replace(/[^a-z]/g,"");
          const fLabel = f.label.toLowerCase().replace(/[^a-z]/g,"");
          return hLow === fLow || hLow === fLabel ||
            hLow.includes(fLow) || fLow.includes(hLow) ||
            hLow.includes(fLabel) || fLabel.includes(hLow);
        });
        if (match) autoMap[f.key] = match;
      });
      setMapping(autoMap);
      setStep("map");
    };
    reader.readAsText(file);
    e.target.value = "";
  };

  // Download template CSV
  const downloadTemplate = () => {
    const headers = PERSON_IMPORT_FIELDS.map(f => f.key).join(",");
    const example = '"AL-ASSAD","Bashar Hafez","","Subject","1965-09-11","Syrian","P12345678","Male","CONFIDENTIAL","President of Syria","Syria,BLUE TITAN"';
    const csv = headers + "\n" + example;
    if (navigator.clipboard && navigator.clipboard.writeText) {
      navigator.clipboard.writeText(csv).then(function() {
        alert("Template CSV copied to clipboard!\n\nPaste into a text editor, save as .csv, fill in your data, then upload here.");
      }).catch(function() { setTemplatePreview(csv); });
    } else { setTemplatePreview(csv); }
  };

  // Step 2: build preview from mapping
  const buildPreview = () => {
    const rows = csvData.rows.map(row => {
      const rec = { classification:"CONFIDENTIAL", type:"Subject",
        tags:[], tasks:[], inv_notes:[], files:[], links:[] };
      PERSON_IMPORT_FIELDS.forEach(f => {
        const col = mapping[f.key];
        if (col && row[col] !== undefined) {
          if (f.key === "tags") {
            rec.tags = row[col] ? row[col].split(",").map(t=>t.trim()).filter(Boolean) : [];
          } else if (f.key === "surname" || f.key === "forenames") {
            rec[f.key] = (row[col]||"").toUpperCase();
          } else {
            rec[f.key] = row[col] || "";
          }
        }
      });
      // Fill defaults
      if (!rec.classification) rec.classification = "CONFIDENTIAL";
      if (!rec.type) rec.type = "Subject";
      // Check for duplicate
      const isDup = existingRecords.some(e =>
        e.surname && rec.surname &&
        e.surname.toUpperCase() === rec.surname.toUpperCase() &&
        (e.forenames||"").toUpperCase() === (rec.forenames||"").toUpperCase()
      );
      return { ...rec, _isDup: isDup, _valid: !!(rec.surname||"").trim() };
    });
    setPreview(rows);
    setStep("preview");
  };

  // Step 3: run import
  const runImport = () => {
    setImporting(true);
    let imported = 0, skipped = 0, errors = 0;
    const toImport = preview.filter(r => {
      if (!r._valid) { errors++; return false; }
      if (r._isDup && dupAction === "skip") { skipped++; return false; }
      return true;
    });
    // Find true max URN from existing records to avoid collisions
    const existingMax = (existingRecords||[]).reduce(function(max, r) {
      if (!r.urn) return max;
      const parts = r.urn.split("-");
      const num = parseInt(parts[parts.length-1], 10);
      return isNaN(num) ? max : Math.max(max, num);
    }, 0);
    const newRecords = toImport.map((r, i) => {
      const clean = {...r};
      delete clean._isDup; delete clean._valid;
      // Ensure array fields are arrays (not objects)
      clean.files = Array.isArray(clean.files) ? clean.files : [];
      clean.tasks = Array.isArray(clean.tasks) ? clean.tasks : [];
      clean.inv_notes = Array.isArray(clean.inv_notes) ? clean.inv_notes : [];
      clean.links = Array.isArray(clean.links) ? clean.links : [];
      clean.tags = Array.isArray(clean.tags) ? clean.tags : [];
      const num = existingMax + i + 1;
      const urn = "AW-" + (URN_PREFIXES["person"]||"PER") + "-" + String(num).padStart(4,"0");
      return { ...clean, id: Date.now() + i, urn: urn };
    });
    imported = newRecords.length;
    setResults({ imported, skipped, errors, records: newRecords });
    setImporting(false);
    setStep("done");
    onImport(newRecords);
  };

  const MODAL_STYLE = {
    position:"fixed", inset:0, zIndex:500,
    background:"rgba(0,0,0,0.5)", display:"flex",
    alignItems:"center", justifyContent:"center", padding:"20px",
  };
  const PANEL_STYLE = {
    background:K.surface, borderRadius:"10px", width:"100%",
    maxWidth:"860px", maxHeight:"90vh", overflow:"hidden",
    display:"flex", flexDirection:"column",
    boxShadow:"0 20px 60px rgba(0,0,0,0.3)",
  };

  return (
    <div style={MODAL_STYLE} onClick={e=>{if(e.target===e.currentTarget)onClose();}}>
      <div style={PANEL_STYLE}>

        {/* Modal header */}
        <div style={{padding:"20px 24px",borderBottom:"1px solid "+K.border,
          display:"flex",alignItems:"center",justifyContent:"space-between",
          background:K.navy,borderRadius:"10px 10px 0 0"}}>
          <div>
            <div style={{fontSize:"16px",fontWeight:"800",color:"#fff",letterSpacing:"1px"}}>
              ⬆ Bulk Import — Person Register
            </div>
            <div style={{fontSize:"11px",color:"rgba(255,255,255,0.5)",marginTop:"2px"}}>
              {step==="upload"?"Step 1 of 3: Upload CSV":
               step==="map"?"Step 2 of 3: Map Columns":
               step==="preview"?"Step 3 of 3: Review & Import":"Import Complete"}
            </div>
          </div>
          <button onClick={onClose}
            style={{background:"none",border:"none",color:"rgba(255,255,255,0.6)",
              cursor:"pointer",fontSize:"20px",lineHeight:1,padding:"4px"}}>✕</button>
        </div>

        {/* Progress bar */}
        <div style={{height:"3px",background:K.border}}>
          <div style={{height:"3px",background:K.blue,transition:"width 0.3s",
            width:step==="upload"?"33%":step==="map"?"66%":step==="preview"?"100%":"100%"}}/>
        </div>

        <div style={{overflowY:"auto",flex:1,padding:"24px"}}>

          {/* ── STEP 1: UPLOAD ── */}
          {step==="upload" && (
            <div>
              <div style={{background:"#f0f7ff",border:"1px solid "+K.blueMid,
                borderRadius:"8px",padding:"20px",marginBottom:"24px",fontSize:"13px",
                color:K.textMid,lineHeight:"1.7"}}>
                <strong style={{color:K.navy}}>How to import:</strong><br/>
                1. Download the template CSV below<br/>
                2. Fill in your data (one person per row — works with sanctions list exports)<br/>
                3. Save as CSV and upload here<br/>
                4. Map columns and review before importing
              </div>

              <div style={{display:"flex",gap:"16px",marginBottom:"24px"}}>
                <button onClick={downloadTemplate}
                  style={{padding:"10px 20px",background:K.surfaceAlt,
                    border:"1px solid "+K.border,borderRadius:"5px",
                    fontSize:"13px",fontWeight:"700",cursor:"pointer",
                    fontFamily:"inherit",color:K.text,display:"flex",
                    alignItems:"center",gap:"6px"}}>
                  📋 Copy Template CSV
                </button>
              </div>
              {templatePreview && (
                <div style={{marginBottom:"16px"}}>
                  <div style={{fontSize:"11px",color:K.blue,fontWeight:"700",marginBottom:"6px"}}>
                    Template copied — or select all below and copy manually:
                  </div>
                  <pre style={{background:"#f7f9fc",border:"1px solid "+K.border,borderRadius:"4px",
                    padding:"10px",fontSize:"10px",fontFamily:"monospace",overflowX:"auto",
                    whiteSpace:"pre",margin:0,maxHeight:"120px",overflowY:"auto"}}>
                    {templatePreview}
                  </pre>
                </div>
              )}

              <div style={{border:"2px dashed "+K.border,borderRadius:"8px",
                padding:"40px",textAlign:"center",background:K.surfaceAlt}}>
                <div style={{fontSize:"32px",marginBottom:"12px"}}>📄</div>
                <div style={{fontSize:"14px",fontWeight:"700",color:K.text,marginBottom:"6px"}}>
                  Drop your CSV file here
                </div>
                <div style={{fontSize:"12px",color:K.textDim,marginBottom:"16px"}}>
                  .csv format · UTF-8 encoding · First row must be headers
                </div>
                <label style={{cursor:"pointer"}} onClick={function(e){
                    e.currentTarget.querySelector('input[type="file"]').click();
                  }}>
                  <span style={{padding:"10px 24px",background:K.blue,color:"#fff",
                    borderRadius:"5px",fontSize:"13px",fontWeight:"700",cursor:"pointer",pointerEvents:"none"}}>
                    Choose File
                  </span>
                  <input type="file" accept=".csv,.txt,.CSV" style={{display:"none",position:"absolute"}} onChange={handleFile}/>
                </label>
              </div>

              {/* Show KOIOS field reference */}
              <div style={{marginTop:"20px"}}>
                <div style={{fontSize:"11px",fontWeight:"800",color:K.textMid,
                  letterSpacing:"1.5px",marginBottom:"10px"}}>AVAILABLE FIELDS</div>
                <div style={{display:"grid",gridTemplateColumns:"repeat(3,1fr)",gap:"6px"}}>
                  {PERSON_IMPORT_FIELDS.map(f => (
                    <div key={f.key} style={{padding:"8px 10px",background:K.surfaceAlt,
                      border:"1px solid "+K.border,borderRadius:"4px",fontSize:"11px"}}>
                      <div style={{fontWeight:"700",color:K.text,fontFamily:"monospace"}}>{f.key}</div>
                      {f.required && <span style={{fontSize:"10px",color:K.red}}>required</span>}
                      {f.hint && <div style={{color:K.textDim,marginTop:"1px"}}>{f.hint}</div>}
                    </div>
                  ))}
                </div>
              </div>
            </div>
          )}

          {/* ── STEP 2: MAP COLUMNS ── */}
          {step==="map" && csvData && (
            <div>
              <div style={{display:"flex",justifyContent:"space-between",
                alignItems:"center",marginBottom:"16px"}}>
                <div>
                  <div style={{fontSize:"14px",fontWeight:"700",color:K.text}}>
                    {csvData.rows.length} rows detected · {csvData.headers.length} columns
                  </div>
                  <div style={{fontSize:"12px",color:K.textDim,marginTop:"2px"}}>
                    Match your CSV columns to KOIOS fields. Auto-matched where possible.
                  </div>
                </div>
                <Btn small onClick={()=>setStep("upload")}>← Back</Btn>
              </div>

              <div style={{background:K.surfaceAlt,border:"1px solid "+K.border,
                borderRadius:"8px",padding:"16px",marginBottom:"20px"}}>
                <table style={{width:"100%",borderCollapse:"collapse",fontSize:"12px"}}>
                  <thead>
                    <tr style={{borderBottom:"2px solid "+K.border}}>
                      <th style={{padding:"8px 12px",textAlign:"left",fontWeight:"800",
                        color:K.textMid,fontSize:"10px",letterSpacing:"1px"}}>KOIOS FIELD</th>
                      <th style={{padding:"8px 12px",textAlign:"left",fontWeight:"800",
                        color:K.textMid,fontSize:"10px",letterSpacing:"1px"}}>YOUR CSV COLUMN</th>
                      <th style={{padding:"8px 12px",textAlign:"left",fontWeight:"800",
                        color:K.textMid,fontSize:"10px",letterSpacing:"1px"}}>SAMPLE VALUE</th>
                    </tr>
                  </thead>
                  <tbody>
                    {PERSON_IMPORT_FIELDS.map(f => {
                      const mapped = mapping[f.key];
                      const sample = mapped && csvData.rows[0] ? csvData.rows[0][mapped] : "";
                      return (
                        <tr key={f.key} style={{borderBottom:"1px solid "+K.border}}>
                          <td style={{padding:"8px 12px"}}>
                            <div style={{fontFamily:"monospace",fontWeight:"700",color:K.navy,fontSize:"12px"}}>
                              {f.key}
                            </div>
                            {f.required && <span style={{fontSize:"10px",color:K.red,fontWeight:"700"}}>required</span>}
                          </td>
                          <td style={{padding:"8px 12px"}}>
                            <select value={mapped||""}
                              onChange={e=>setMapping(p=>({...p,[f.key]:e.target.value||undefined}))}
                              style={{padding:"5px 8px",border:"1px solid "+(mapped?K.blue:K.border),
                                borderRadius:"4px",fontSize:"12px",color:K.text,
                                background:mapped?"#f0f7ff":K.surface,
                                outline:"none",fontFamily:"inherit",width:"100%"}}>
                              <option value="">— not mapped —</option>
                              {csvData.headers.map(h => <option key={h} value={h}>{h}</option>)}
                            </select>
                          </td>
                          <td style={{padding:"8px 12px",fontFamily:"monospace",
                            fontSize:"11px",color:K.textMid,maxWidth:"160px",
                            overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>
                            {sample||<span style={{color:K.border}}>—</span>}
                          </td>
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              </div>

              <div style={{display:"flex",alignItems:"center",gap:"12px",
                padding:"14px 16px",background:K.surfaceAlt,border:"1px solid "+K.border,
                borderRadius:"6px",marginBottom:"20px"}}>
                <span style={{fontSize:"12px",fontWeight:"700",color:K.text}}>
                  Duplicate handling:
                </span>
                <label style={{display:"flex",alignItems:"center",gap:"6px",cursor:"pointer",fontSize:"12px"}}>
                  <input type="radio" name="dup" value="skip" checked={dupAction==="skip"}
                    onChange={()=>setDupAction("skip")}/>
                  Skip if same name already exists
                </label>
                <label style={{display:"flex",alignItems:"center",gap:"6px",cursor:"pointer",fontSize:"12px"}}>
                  <input type="radio" name="dup" value="import" checked={dupAction==="import"}
                    onChange={()=>setDupAction("import")}/>
                  Import anyway
                </label>
              </div>

              <div style={{display:"flex",gap:"10px"}}>
                <Btn variant="primary" onClick={buildPreview}
                  disabled={!PERSON_IMPORT_FIELDS.filter(f=>f.required).every(f=>mapping[f.key])}>
                  Preview Import →
                </Btn>
                <Btn onClick={()=>setStep("upload")}>← Back</Btn>
                {!PERSON_IMPORT_FIELDS.filter(f=>f.required).every(f=>mapping[f.key]) && (
                  <span style={{fontSize:"11px",color:K.red,alignSelf:"center"}}>
                    Map the required "surname" field to continue
                  </span>
                )}
              </div>
            </div>
          )}

          {/* ── STEP 3: PREVIEW ── */}
          {step==="preview" && (
            <div>
              <div style={{display:"flex",justifyContent:"space-between",
                alignItems:"center",marginBottom:"16px"}}>
                <div>
                  <div style={{fontSize:"14px",fontWeight:"700",color:K.text}}>
                    {preview.filter(r=>r._valid&&(!r._isDup||dupAction==="import")).length} records ready to import
                    {preview.filter(r=>r._isDup&&dupAction==="skip").length > 0 &&
                      <span style={{color:K.amber,marginLeft:"8px"}}>
                        · {preview.filter(r=>r._isDup&&dupAction==="skip").length} duplicates will be skipped
                      </span>}
                    {preview.filter(r=>!r._valid).length > 0 &&
                      <span style={{color:K.red,marginLeft:"8px"}}>
                        · {preview.filter(r=>!r._valid).length} invalid (no surname)
                      </span>}
                  </div>
                  <div style={{fontSize:"12px",color:K.textDim,marginTop:"2px"}}>
                    Review before confirming. Surnames will be uppercased automatically.
                  </div>
                </div>
                <Btn small onClick={()=>setStep("map")}>← Back</Btn>
              </div>

              <div style={{border:"1px solid "+K.border,borderRadius:"8px",
                overflow:"hidden",marginBottom:"20px",maxHeight:"360px",overflowY:"auto"}}>
                <table style={{width:"100%",borderCollapse:"collapse",fontSize:"12px"}}>
                  <thead style={{position:"sticky",top:0}}>
                    <tr style={{background:K.surfaceAlt}}>
                      {["Status","Surname","Forenames","Type","DOB","Nationality","Classification"].map(h=>(
                        <th key={h} style={{padding:"9px 12px",textAlign:"left",fontSize:"10px",
                          fontWeight:"800",color:K.textMid,letterSpacing:"1px",
                          borderBottom:"1px solid "+K.border,whiteSpace:"nowrap"}}>{h}</th>
                      ))}
                    </tr>
                  </thead>
                  <tbody>
                    {preview.map((r, i) => {
                      const willSkip = r._isDup && dupAction==="skip";
                      const invalid = !r._valid;
                      const bg = invalid?"#fef2f2":willSkip?"#fffbeb":i%2?K.surfaceAlt:K.surface;
                      return (
                        <tr key={i} style={{borderBottom:"1px solid "+K.border,background:bg,
                          opacity:willSkip||invalid?0.6:1}}>
                          <td style={{padding:"8px 12px",whiteSpace:"nowrap"}}>
                            {invalid
                              ? <span style={{color:K.red,fontWeight:"700",fontSize:"10px"}}>✗ INVALID</span>
                              : willSkip
                              ? <span style={{color:K.amber,fontWeight:"700",fontSize:"10px"}}>⚠ SKIP DUP</span>
                              : <span style={{color:K.green,fontWeight:"700",fontSize:"10px"}}>✓ IMPORT</span>}
                          </td>
                          <td style={{padding:"8px 12px",fontWeight:"700",color:K.navy}}>{r.surname||"—"}</td>
                          <td style={{padding:"8px 12px",color:K.text}}>{r.forenames||"—"}</td>
                          <td style={{padding:"8px 12px",color:K.textMid}}>{r.type||"—"}</td>
                          <td style={{padding:"8px 12px",color:K.textMid,whiteSpace:"nowrap"}}>{r.date_of_birth||"—"}</td>
                          <td style={{padding:"8px 12px",color:K.textMid}}>{r.nationality||"—"}</td>
                          <td style={{padding:"8px 12px"}}><ClassBadge v={r.classification}/></td>
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              </div>

              <div style={{display:"flex",gap:"10px",alignItems:"center"}}>
                <Btn variant="primary" onClick={runImport} disabled={importing||
                  preview.filter(r=>r._valid&&(!r._isDup||dupAction==="import")).length===0}>
                  {importing?"Importing...":"✓ Confirm Import"}
                </Btn>
                <Btn onClick={()=>setStep("map")}>← Back</Btn>
              </div>
            </div>
          )}

          {/* ── DONE ── */}
          {step==="done" && results && (
            <div style={{textAlign:"center",padding:"20px"}}>
              <div style={{fontSize:"48px",marginBottom:"16px"}}>✅</div>
              <div style={{fontSize:"20px",fontWeight:"800",color:K.navy,marginBottom:"8px"}}>
                Import Complete
              </div>
              <div style={{display:"flex",justifyContent:"center",gap:"24px",marginBottom:"24px"}}>
                <div style={{padding:"16px 24px",background:"#dcfce7",borderRadius:"8px"}}>
                  <div style={{fontSize:"28px",fontWeight:"800",color:K.green}}>{results.imported}</div>
                  <div style={{fontSize:"12px",color:K.green,fontWeight:"700"}}>Imported</div>
                </div>
                {results.skipped > 0 && (
                  <div style={{padding:"16px 24px",background:"#fef3c7",borderRadius:"8px"}}>
                    <div style={{fontSize:"28px",fontWeight:"800",color:K.amber}}>{results.skipped}</div>
                    <div style={{fontSize:"12px",color:K.amber,fontWeight:"700"}}>Skipped (duplicates)</div>
                  </div>
                )}
                {results.errors > 0 && (
                  <div style={{padding:"16px 24px",background:"#fef2f2",borderRadius:"8px"}}>
                    <div style={{fontSize:"28px",fontWeight:"800",color:K.red}}>{results.errors}</div>
                    <div style={{fontSize:"12px",color:K.red,fontWeight:"700"}}>Invalid (skipped)</div>
                  </div>
                )}
              </div>
              <Btn variant="primary" onClick={onClose}>Close</Btn>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

// ─── REPORT EXPORT ───────────────────────────────────────────────────────────

function ExportModal({ records, allRecords, register, onClose }) {
  const regRecords = records || [];

  // Filter state
  const [filterClass,  setFilterClass]  = React.useState("");
  const [filterType,   setFilterType]   = React.useState("");
  const [filterTag,    setFilterTag]    = React.useState("");
  const [filterSearch, setFilterSearch] = React.useState("");
  const [selected,     setSelected]     = React.useState(new Set());
  const [format,       setFormat]       = React.useState("csv"); // csv | doc
  const [htmlPreview,  setHtmlPreview]  = React.useState(null);
  const [csvPreview,   setCsvPreview]   = React.useState(null);

  const isPerson = register === "person";
  const isOrg    = register === "organisation";

  // Derive filter options
  const types = [...new Set(regRecords.map(r=>r.type).filter(Boolean))].sort();
  const allTags = [...new Set(regRecords.flatMap(r=>r.tags||[]))].sort();

  // Apply filters
  const filtered = React.useMemo(() => {
    const q = filterSearch.toLowerCase();
    return regRecords.filter(r => {
      if (r._redacted) return false;
      const name = isPerson
        ? [r.forenames, r.surname].filter(Boolean).join(" ").toLowerCase()
        : (r.name||"").toLowerCase();
      const matchSearch = !q || name.includes(q) || (r.urn||"").toLowerCase().includes(q) ||
        (r.reason_for_nominal||"").toLowerCase().includes(q);
      const matchClass = !filterClass || r.classification === filterClass;
      const matchType  = !filterType  || r.type === filterType;
      const matchTag   = !filterTag   || (r.tags||[]).includes(filterTag);
      return matchSearch && matchClass && matchType && matchTag;
    });
  }, [regRecords, filterSearch, filterClass, filterType, filterTag]);

  // Toggle selection
  const toggleAll = () => {
    if (selected.size === filtered.length)
      setSelected(new Set());
    else
      setSelected(new Set(filtered.map(r=>r.id)));
  };
  const toggleOne = (id) => {
    const s = new Set(selected);
    s.has(id) ? s.delete(id) : s.add(id);
    setSelected(s);
  };

  // Get linked records for a person/org
  const getLinked = (record) => {
    const linked = { organisations:[], communications:[], addresses:[] };
    if (!record.links || !allRecords) return linked;
    record.links.forEach(link => {
      const regRecs = allRecords[link.to_register] || [];
      const target = regRecs.find(r => r.id === link.to_id || r.urn === link.to_id);
      if (!target) return;
      if (link.to_register === "organisation")   linked.organisations.push({...target, link_type:link.link_type});
      if (link.to_register === "communication")  linked.communications.push({...target, link_type:link.link_type});
      if (link.to_register === "address")        linked.addresses.push({...target, link_type:link.link_type});
    });
    return linked;
  };

  // ── CSV EXPORT ──
  const exportCSV = () => {
    const toExport = filtered.filter(r => selected.size === 0 || selected.has(r.id));
    if (!toExport.length) { alert("No records to export."); return; }

    const headers = isPerson
      ? ["URN","Classification","Type","Subtype","Title","Surname","Forenames","AKA",
         "DOB","POB","Sex","Nationality","Occupation","Reason for Nominal",
         "Notes","Further Details","Tags","Linked Organisations","Linked Communications","Linked Addresses"]
      : ["URN","Classification","Type","Status","Name","AKA","Registered Country",
         "Registered Number","Incorporation Date","Registered Address","Telephone","Email","Website",
         "Reason for Nominal","Notes","Tags","Linked Persons","Linked Addresses"];

    const escape = v => '"' + String(v||"").replace(/"/g,'""') + '"';

    const rows = toExport.map(r => {
      const linked = getLinked(r);
      if (isPerson) {
        return [
          r.urn, r.classification, r.type, r.subtype||"",
          r.title||"", r.surname||"", r.forenames||"", r.aka||"",
          r.dob||"", r.pob||"", r.sex||"", r.nationality||"", r.occupation||"",
          r.reason_for_nominal||"", r.notes||"", r.further_details||"",
          (r.tags||[]).join("; "),
          linked.organisations.map(o=>o.name||o.urn).join("; "),
          linked.communications.map(c=>c.number_address||c.urn).join("; "),
          linked.addresses.map(a=>[a.address_line1,a.city,a.country].filter(Boolean).join(", ")||a.urn).join("; "),
        ].map(escape).join(",");
      } else {
        const linkedPersons = (allRecords?.person||[]).filter(p =>
          (p.links||[]).some(l => l.to_register==="organisation" && (l.to_id===r.id||l.to_id===r.urn))
        );
        return [
          r.urn, r.classification, r.type||"", r.status||"", r.name||"", r.aka||"",
          r.registered_country||"", r.registration_number||"", r.date_inc||"",
          r.registered_address||"", r.telephone||"", r.email||"", r.website||"",
          r.reason_for_nominal||"", r.notes||"",
          (r.tags||[]).join("; "),
          linkedPersons.map(p=>[p.forenames,p.surname].filter(Boolean).join(" ")||p.urn).join("; "),
          linked.addresses.map(a=>[a.address_line1,a.city].filter(Boolean).join(", ")||a.urn).join("; "),
        ].map(escape).join(",");
      }
    });

    const csv = [headers.map(h=>'"'+h+'"').join(","), ...rows].join("\n");
    // Copy to clipboard — works in all sandbox environments
    if (navigator.clipboard && navigator.clipboard.writeText) {
      navigator.clipboard.writeText(csv).then(function() {
        alert("CSV copied to clipboard! Paste into Excel or a .csv file, then use Word mail merge.");
      }).catch(function() {
        setCsvPreview(csv);
      });
    } else {
      setCsvPreview(csv);
    }
  };

  // ── DOCX-STYLE HTML EXPORT (printable / paste into Word) ──
  const exportDoc = () => {
    const toExport = filtered.filter(r => selected.size === 0 || selected.has(r.id));
    if (!toExport.length) { alert("No records to export."); return; }

    const fmtDate = d => d ? new Date(d).toLocaleDateString("en-GB",{day:"2-digit",month:"long",year:"numeric"}) : "—";
    const val = v => v || "—";

    const profiles = toExport.map((r, idx) => {
      const linked = getLinked(r);
      const name = isPerson
        ? [r.title, r.forenames, r.surname].filter(Boolean).join(" ")
        : (r.name || r.urn);

      const linkedOrgsHtml = linked.organisations.length
        ? "<tr><td>Linked Organisations</td><td>" + linked.organisations.map(o =>
            (o.name||o.urn) + (o.link_type ? " <em>("+o.link_type+")</em>" : "")
          ).join("<br>") + "</td></tr>" : "";

      const linkedCommsHtml = linked.communications.length
        ? "<tr><td>Communications</td><td>" + linked.communications.map(c =>
            (c.number_address||c.urn) + " [" + (c.type||"") + "]" + (c.link_type ? " <em>("+c.link_type+")</em>" : "")
          ).join("<br>") + "</td></tr>" : "";

      const linkedAddrsHtml = linked.addresses.length
        ? "<tr><td>Addresses</td><td>" + linked.addresses.map(a =>
            [a.address_line1, a.address_line2, a.city, a.country].filter(Boolean).join(", ") || a.urn
          ).join("<br>") + "</td></tr>" : "";

      const personRows = isPerson ? `
        <tr><td>URN</td><td><strong>${val(r.urn)}</strong></td></tr>
        <tr><td>Classification</td><td>${val(r.classification)}</td></tr>
        <tr><td>Type</td><td>${val(r.type)}${r.subtype?" / "+r.subtype:""}</td></tr>
        <tr><td>Date of Birth</td><td>${fmtDate(r.dob)}</td></tr>
        <tr><td>Place of Birth</td><td>${val(r.pob)}</td></tr>
        <tr><td>Sex</td><td>${val(r.sex)}</td></tr>
        <tr><td>Nationality</td><td>${val(r.nationality)}</td></tr>
        <tr><td>Occupation</td><td>${val(r.occupation)}</td></tr>
        <tr><td>Also Known As</td><td>${val(r.aka)}</td></tr>
        ${r.tags&&r.tags.length?"<tr><td>Tags</td><td>"+r.tags.join(", ")+"</td></tr>":""}
        <tr><td colspan='2' style='padding-top:12px;font-weight:700;color:#0d1f3c;background:#f0f7ff'>REASON FOR NOMINAL</td></tr>
        <tr><td colspan='2' style='padding:10px 14px'>${val(r.reason_for_nominal)}</td></tr>
        ${linkedOrgsHtml}${linkedCommsHtml}${linkedAddrsHtml}
        ${r.further_details?"<tr><td>Further Details</td><td>"+r.further_details+"</td></tr>":""}
        ${r.notes?"<tr><td colspan='2' style='padding-top:12px;font-weight:700;color:#0d1f3c;background:#f0f7ff'>NOTES</td></tr><tr><td colspan='2' style='padding:10px 14px'>"+r.notes+"</td></tr>":""}
      ` : `
        <tr><td>URN</td><td><strong>${val(r.urn)}</strong></td></tr>
        <tr><td>Classification</td><td>${val(r.classification)}</td></tr>
        <tr><td>Type</td><td>${val(r.type)}</td></tr>
        <tr><td>Status</td><td>${val(r.status)}</td></tr>
        <tr><td>Registered Country</td><td>${val(r.registered_country)}</td></tr>
        <tr><td>Registration Number</td><td>${val(r.registration_number)}</td></tr>
        <tr><td>Date of Incorporation</td><td>${fmtDate(r.date_inc)}</td></tr>
        <tr><td>Registered Address</td><td>${val(r.registered_address)}</td></tr>
        <tr><td>Telephone</td><td>${val(r.telephone)}</td></tr>
        <tr><td>Email</td><td>${val(r.email)}</td></tr>
        <tr><td>Website</td><td>${val(r.website)}</td></tr>
        ${r.tags&&r.tags.length?"<tr><td>Tags</td><td>"+r.tags.join(", ")+"</td></tr>":""}
        <tr><td colspan='2' style='padding-top:12px;font-weight:700;color:#0d1f3c;background:#f0f7ff'>REASON FOR NOMINAL</td></tr>
        <tr><td colspan='2' style='padding:10px 14px'>${val(r.reason_for_nominal)}</td></tr>
        ${linkedAddrsHtml}
        ${r.notes?"<tr><td colspan='2' style='padding-top:12px;font-weight:700;color:#0d1f3c;background:#f0f7ff'>NOTES</td></tr><tr><td colspan='2' style='padding:10px 14px'>"+r.notes+"</td></tr>":""}
      `;

      return `
        <div class="profile" style="page-break-after:always">
          <div class="profile-header">
            <div class="annex-ref">ANNEX ${String.fromCharCode(64+idx+1)}</div>
            <h2>${name}</h2>
            <div class="class-badge">${r.classification||"UNCLASSIFIED"}</div>
          </div>
          <table class="profile-table"><tbody>${personRows}</tbody></table>
        </div>`;
    }).join("\n");

    const html = `<!DOCTYPE html>
<html><head><meta charset="utf-8">
<title>KOIOS ${isPerson?"Person":"Organisation"} Profiles — ${new Date().toLocaleDateString("en-GB")}</title>
<style>
  body { font-family:"Palatino Linotype",Georgia,serif; max-width:800px; margin:40px auto; padding:0 20px; color:#0d1f3c; font-size:13px; }
  h1 { font-size:22px; border-bottom:3px solid #0d1f3c; padding-bottom:10px; margin-bottom:6px; }
  .meta { font-size:11px; color:#4a5c74; margin-bottom:30px; }
  .profile { margin-bottom:40px; }
  .profile-header { display:flex; align-items:baseline; gap:16px; border-bottom:2px solid #1a4a8a; padding-bottom:10px; margin-bottom:16px; }
  .annex-ref { font-size:10px; font-weight:800; color:#1a4a8a; letter-spacing:2px; white-space:nowrap; }
  h2 { margin:0; font-size:20px; font-weight:800; }
  .class-badge { font-size:10px; font-weight:800; padding:3px 10px; border:1px solid #1a4a8a; color:#1a4a8a; letter-spacing:1px; margin-left:auto; white-space:nowrap; }
  .profile-table { width:100%; border-collapse:collapse; font-size:12px; }
  .profile-table td { padding:7px 12px; border-bottom:1px solid #dce3ed; vertical-align:top; }
  .profile-table td:first-child { font-weight:700; width:160px; color:#4a5c74; white-space:nowrap; }
  .footer { margin-top:40px; padding-top:16px; border-top:1px solid #dce3ed; font-size:10px; color:#8a9bb0; text-align:center; }
  @media print { .profile { page-break-after:always; } body { margin:20px; } }
</style></head>
<body>
  <h1>KOIOS — ${isPerson?"Person of Interest":"Organisation"} Profiles</h1>
  <div class="meta">
    Generated: ${new Date().toLocaleString("en-GB")} &nbsp;·&nbsp;
    Records: ${toExport.length} &nbsp;·&nbsp;
    Classification: ${[...new Set(toExport.map(r=>r.classification))].join(", ")}
  </div>
  ${profiles}
  <div class="footer">KOIOS Investigation Management System · ArcticWind · All sessions logged</div>
</body></html>`;

    setHtmlPreview(html);
  };

  const toExportCount = selected.size > 0 ? selected.size : filtered.length;

  const MS = {position:"fixed",inset:0,zIndex:500,background:"rgba(0,0,0,0.5)",
    display:"flex",alignItems:"center",justifyContent:"center",padding:"20px"};
  const PS = {background:"white",borderRadius:"10px",width:"100%",maxWidth:"860px",
    maxHeight:"90vh",overflow:"hidden",display:"flex",flexDirection:"column",
    boxShadow:"0 20px 60px rgba(0,0,0,0.3)"};

  return (
    <div style={MS} onClick={e=>{if(e.target===e.currentTarget)onClose();}}>
      <div style={PS}>
        {/* Header */}
        <div style={{padding:"20px 24px",borderBottom:"1px solid "+K.border,display:"flex",
          alignItems:"center",justifyContent:"space-between",background:K.navy,borderRadius:"10px 10px 0 0"}}>
          <div>
            <div style={{fontSize:"16px",fontWeight:"800",color:"#fff",letterSpacing:"1px"}}>
              📄 Export {isPerson?"Person":"Organisation"} Profiles
            </div>
            <div style={{fontSize:"11px",color:"rgba(255,255,255,0.5)",marginTop:"2px"}}>
              Filter, select and export for analytical reports
            </div>
          </div>
          <button onClick={onClose}
            style={{background:"none",border:"none",color:"rgba(255,255,255,0.6)",
              cursor:"pointer",fontSize:"20px",padding:"4px"}}>✕</button>
        </div>

        <div style={{overflowY:"auto",flex:1,padding:"20px 24px"}}>
          {/* Filters */}
          <div style={{display:"flex",gap:"10px",marginBottom:"16px",flexWrap:"wrap",
            padding:"14px",background:K.surfaceAlt,borderRadius:"8px",border:"1px solid "+K.border}}>
            <input value={filterSearch} onChange={e=>setFilterSearch(e.target.value)}
              placeholder="Search name / URN..."
              style={{padding:"7px 11px",border:"1px solid "+K.border,borderRadius:"4px",
                fontSize:"12px",color:K.text,background:K.surface,outline:"none",
                fontFamily:"inherit",flex:1,minWidth:"160px"}}/>
            <Select value={filterClass} onChange={setFilterClass}
              options={["UNCLASSIFIED","RESTRICTED","CONFIDENTIAL"]} placeholder="All Classifications"/>
            {types.length>0 && <Select value={filterType} onChange={setFilterType}
              options={types} placeholder="All Types"/>}
            {allTags.length>0 && <Select value={filterTag} onChange={setFilterTag}
              options={allTags} placeholder="All Tags"/>}
            {(filterSearch||filterClass||filterType||filterTag) &&
              <Btn small onClick={()=>{setFilterSearch("");setFilterClass("");setFilterType("");setFilterTag("");}}>
                Clear
              </Btn>}
          </div>

          {/* Format selector */}
          <div style={{display:"flex",gap:"10px",marginBottom:"16px"}}>
            {[["csv","📊 CSV (Mail Merge)"],["doc","📄 HTML Profile Document"]].map(([f,label])=>(
              <label key={f} style={{display:"flex",alignItems:"center",gap:"8px",
                padding:"10px 16px",border:"2px solid "+(format===f?K.blue:K.border),
                borderRadius:"6px",cursor:"pointer",flex:1,
                background:format===f?K.blueLight:K.surface}}>
                <input type="radio" name="fmt" value={f} checked={format===f}
                  onChange={()=>setFormat(f)} style={{accentColor:K.blue}}/>
                <div>
                  <div style={{fontSize:"13px",fontWeight:"700",color:format===f?K.blue:K.text}}>{label}</div>
                  <div style={{fontSize:"10px",color:K.textDim}}>
                    {f==="csv"?"All fields as columns — use with Word mail merge":"Formatted profiles — paste directly into analytical report"}
                  </div>
                </div>
              </label>
            ))}
          </div>

          {/* Record list */}
          <div style={{border:"1px solid "+K.border,borderRadius:"8px",overflow:"hidden",marginBottom:"16px"}}>
            <div style={{background:K.surfaceAlt,padding:"8px 14px",display:"flex",
              alignItems:"center",gap:"10px",borderBottom:"1px solid "+K.border}}>
              <input type="checkbox"
                checked={selected.size>0 && selected.size===filtered.length}
                onChange={toggleAll}
                style={{width:"15px",height:"15px",cursor:"pointer",accentColor:K.blue}}/>
              <span style={{fontSize:"11px",fontWeight:"700",color:K.textMid}}>
                {filtered.length} record{filtered.length!==1?"s":""} shown
                {selected.size>0&&" · "+selected.size+" selected"}
              </span>
              {selected.size>0 &&
                <span style={{fontSize:"11px",color:K.blue,cursor:"pointer",marginLeft:"auto"}}
                  onClick={()=>setSelected(new Set())}>Clear selection</span>}
            </div>
            <div style={{maxHeight:"280px",overflowY:"auto"}}>
              {filtered.length===0 ? (
                <div style={{padding:"32px",textAlign:"center",color:K.textDim,fontSize:"13px"}}>
                  No records match the filters.
                </div>
              ) : filtered.map((r,i)=>{
                const name = isPerson
                  ? [r.forenames,r.surname].filter(Boolean).join(" ")||r.urn
                  : (r.name||r.urn);
                const isChecked = selected.size===0 || selected.has(r.id);
                return (
                  <div key={r.id} style={{display:"flex",alignItems:"center",gap:"10px",
                    padding:"9px 14px",borderBottom:"1px solid "+K.border,
                    background:selected.has(r.id)?K.blueLight:i%2?K.surfaceAlt:K.surface,
                    cursor:"pointer"}}
                    onClick={()=>toggleOne(r.id)}>
                    <input type="checkbox" checked={selected.has(r.id)}
                      onChange={()=>toggleOne(r.id)}
                      onClick={e=>e.stopPropagation()}
                      style={{width:"15px",height:"15px",cursor:"pointer",accentColor:K.blue}}/>
                    <span style={{fontFamily:"monospace",fontSize:"11px",color:K.blue,
                      fontWeight:"700",minWidth:"110px"}}>{r.urn}</span>
                    <span style={{flex:1,fontSize:"12px",fontWeight:"600",color:K.text}}>{name}</span>
                    {r.type&&<span style={{fontSize:"11px",color:K.textMid}}>{r.type}</span>}
                    <ClassBadge v={r.classification}/>
                  </div>
                );
              })}
            </div>
          </div>
        </div>

        {/* Footer */}
        {/* HTML Preview */}
        {htmlPreview && (
          <div style={{borderTop:"1px solid "+K.border}}>
            <div style={{padding:"10px 16px",background:"#f0f7ff",display:"flex",
              alignItems:"center",justifyContent:"space-between",gap:"12px"}}>
              <span style={{fontSize:"12px",color:K.blue,fontWeight:"700"}}>
                ✓ Profile document ready — select all and copy into Word, or print to PDF
              </span>
              <div style={{display:"flex",gap:"8px"}}>
                <Btn small onClick={()=>{
                  const el = document.getElementById("koios-html-preview");
                  if(el){ const sel=window.getSelection(); const r=document.createRange();
                    r.selectNodeContents(el); sel.removeAllRanges(); sel.addRange(r); }
                }}>Select All</Btn>
                <Btn small onClick={()=>window.print()}>Print / Save PDF</Btn>
                <Btn small onClick={()=>setHtmlPreview(null)}>✕ Close</Btn>
              </div>
            </div>
            <div id="koios-html-preview"
              style={{maxHeight:"400px",overflowY:"auto",padding:"20px",
                background:"white",borderTop:"1px solid "+K.border}}
              dangerouslySetInnerHTML={{__html:htmlPreview}}/>
          </div>
        )}

        {/* CSV Preview */}
        {csvPreview && (
          <div style={{borderTop:"1px solid "+K.border}}>
            <div style={{padding:"10px 16px",background:"#f0f7ff",display:"flex",
              alignItems:"center",justifyContent:"space-between",gap:"12px"}}>
              <span style={{fontSize:"12px",color:K.blue,fontWeight:"700"}}>
                ✓ CSV ready — select all and copy, then paste into Excel and save as .csv
              </span>
              <div style={{display:"flex",gap:"8px"}}>
                <Btn small onClick={()=>{
                  const el=document.getElementById("koios-csv-preview");
                  if(el){ const sel=window.getSelection(); const r=document.createRange();
                    r.selectNodeContents(el); sel.removeAllRanges(); sel.addRange(r);
                    try{document.execCommand("copy");alert("Copied!");}catch(e){}
                  }
                }}>Copy All</Btn>
                <Btn small onClick={()=>setCsvPreview(null)}>✕ Close</Btn>
              </div>
            </div>
            <pre id="koios-csv-preview"
              style={{maxHeight:"300px",overflowY:"auto",padding:"16px",
                background:"#f7f9fc",margin:0,fontSize:"11px",
                fontFamily:"monospace",whiteSpace:"pre",overflowX:"auto",
                borderTop:"1px solid "+K.border}}>
              {csvPreview}
            </pre>
          </div>
        )}

        <div style={{padding:"16px 24px",borderTop:"1px solid "+K.border,
          display:"flex",alignItems:"center",justifyContent:"space-between",
          background:K.surfaceAlt}}>
          <span style={{fontSize:"12px",color:K.textMid}}>
            Exporting <strong>{toExportCount}</strong> record{toExportCount!==1?"s":""} as{" "}
            <strong>{format==="csv"?"CSV (mail merge)":"HTML profile document"}</strong>
          </span>
          <div style={{display:"flex",gap:"8px"}}>
            <Btn onClick={onClose}>Cancel</Btn>
            <Btn variant="primary" onClick={format==="csv"?exportCSV:exportDoc}
              disabled={filtered.length===0}>
              ⬇ Export {toExportCount} Record{toExportCount!==1?"s":""}
            </Btn>
          </div>
        </div>
      </div>
    </div>
  );
}

function PersonList({ records, onNew, onEdit, perms={}, onBulkSave, onDelete, allRecords={} }) {
  const [showImport, setShowImport] = useState(false);
  const [showExport, setShowExport] = useState(false);
  const [search, setSearch] = useState("");
  const [filterClass, setFilterClass] = useState("");
  const [filterType, setFilterType] = useState("");
  const [sortBy, setSortBy] = useState("surname");

  const filtered = useMemo(() => {
    return records
      .filter(r => {
        const name = [r.forenames, r.surname].filter(Boolean).join(" ").toLowerCase();
        const q = search.toLowerCase();
        const matchSearch = !q || name.includes(q) || r.urn?.toLowerCase().includes(q) ||
          r.nationality?.toLowerCase().includes(q) || (r.tags||[]).some(t=>t.toLowerCase().includes(q));
        const matchClass = !filterClass || r.classification === filterClass;
        const matchType = !filterType || r.type === filterType;
        return matchSearch && matchClass && matchType;
      })
      .sort((a, b) => {
        if (sortBy === "surname") return (a.surname||"").localeCompare(b.surname||"");
        if (sortBy === "urn") return (a.urn||"").localeCompare(b.urn||"");
        if (sortBy === "review") return (a.review_date||"").localeCompare(b.review_date||"");
        return 0;
      });
  }, [records, search, filterClass, filterType, sortBy]);

  return (
    <div>
      {/* List header */}
      <div style={{ display:"flex", justifyContent:"space-between", alignItems:"center", marginBottom:"20px" }}>
        <div>
          <h2 style={{ margin:0, fontSize:"20px", fontWeight:"800", color:K.navy,
            fontFamily:"'Georgia','Times New Roman',serif" }}>
            Person Register
          </h2>
          <div style={{ fontSize:"12px", color:K.textDim, marginTop:"3px" }}>
            {filtered.length} of {records.length} record{records.length!==1?"s":""}
          </div>
        </div>
        <div style={{display:"flex",gap:"8px"}}>
          <Btn small onClick={()=>setShowExport(true)}>📄 Export</Btn>
          {perms.canCreate && <Btn small onClick={()=>setShowImport(true)}>⬆ Bulk Import</Btn>}
          {perms.canCreate && <Btn variant="primary" onClick={onNew}>+ Add Person</Btn>}
        </div>
        {showImport && (
          <PersonImportModal existingRecords={records}
            onClose={()=>setShowImport(false)}
            onImport={function(recs){if(onBulkSave)onBulkSave(recs);setShowImport(false);}}/>
        )}
        {showExport && (
          <ExportModal records={records} allRecords={allRecords}
            register="person" onClose={()=>setShowExport(false)}/>
        )}
      </div>


      {/* Filters */}
      <div style={{ display:"flex", gap:"10px", marginBottom:"16px", flexWrap:"wrap" }}>
        <div style={{ flex:1, minWidth:"200px" }}>
          <input value={search} onChange={e=>setSearch(e.target.value)}
            placeholder="Search name, URN, nationality, tags…"
            style={{ ...inp, paddingLeft:"14px" }}/>
        </div>
        <div style={{ width:"180px" }}>
          <Select value={filterType} onChange={setFilterType} options={L.person_type} placeholder="All Types"/>
        </div>
        <div style={{ width:"170px" }}>
          <Select value={filterClass} onChange={setFilterClass} options={L.class_lvl} placeholder="All Classifications"/>
        </div>
        <div style={{ width:"150px" }}>
          <Select value={sortBy} onChange={setSortBy} options={["surname","urn","review"]} placeholder="Sort by…"/>
        </div>
      </div>

      {/* Table */}
      <div style={{ border:`1px solid ${K.border}`, borderRadius:"8px", overflow:"hidden",
        boxShadow:"0 1px 3px rgba(0,0,0,0.06)" }}>
        <table style={{ width:"100%", borderCollapse:"collapse", fontSize:"12px" }}>
          <thead>
            <tr style={{ background:K.navy }}>
              {["URN","Name","Type","Nationality","Classification","Tags","Review",""].map(h => (
                <th key={h} style={{ padding:"11px 14px", textAlign:"left", fontWeight:"700",
                  fontSize:"10px", color:"rgba(255,255,255,0.7)", letterSpacing:"1px" }}>{h}</th>
              ))}
            </tr>
          </thead>
          <tbody>
            {filtered.length === 0 && (
              <tr><td colSpan={8} style={{ padding:"32px", textAlign:"center", color:K.textDim }}>
                No records found matching your search.
              </td></tr>
            )}
            {filtered.map((r, i) => {
              const name = [r.forenames, r.surname].filter(Boolean).join(" ");
              const overdue = isOverdue(r.review_date);
              return (
                <tr key={r.id} onClick={() => onEdit(r)} style={{
                  borderBottom:`1px solid ${K.border}`,
                  cursor:"pointer", transition:"background 0.1s",
                  background: i%2 ? K.surfaceAlt : K.surface,
                }} onMouseEnter={e=>e.currentTarget.style.background=K.blueLight}
                   onMouseLeave={e=>e.currentTarget.style.background=i%2?K.surfaceAlt:K.surface}>
                  <td style={{ padding:"11px 14px", fontFamily:"monospace", fontSize:"11px",
                    color:K.blue, fontWeight:"700" }}>{r.urn}</td>
                  <td style={{ padding:"11px 14px", fontWeight:"700", color:K.text }}>
                    {name}
                    {r.deceased && <span style={{ marginLeft:"6px", fontSize:"10px",
                      color:K.textDim, background:K.surfaceAlt, padding:"1px 5px", borderRadius:"2px" }}>✝</span>}
                  </td>
                  <td style={{ padding:"11px 14px", color:K.textMid }}>
                    {r.type||"—"}
                    {r.subtype && <div style={{ fontSize:"10px", color:K.textDim }}>{r.subtype}</div>}
                  </td>
                  <td style={{ padding:"11px 14px", color:K.textMid }}>{r.nationality||"—"}</td>
                  <td style={{ padding:"11px 14px" }}><ClassBadge v={r.classification}/></td>
                  <td style={{ padding:"11px 14px" }}>
                    <div style={{ display:"flex", gap:"4px", flexWrap:"wrap" }}>
                      {(r.tags||[]).map(t => <TagPill key={t} label={t}/>)}
                    </div>
                  </td>
                  <td style={{ padding:"11px 14px",
                    color: overdue ? K.red : K.textMid,
                    fontWeight: overdue ? "700" : "400",
                    fontSize:"11px" }}>
                    {fmtDate(r.review_date)}{overdue && " ⚠"}
                  </td>
                  <td style={{ padding:"11px 14px" }}>
                    <span style={{ color:K.blueMid, fontWeight:"700", fontSize:"11px" }}>Open →</span>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
        {filtered.length > 0 && (
          <div style={{ padding:"8px 14px", background:K.surfaceAlt, fontSize:"11px",
            color:K.textDim, borderTop:`1px solid ${K.border}`, textAlign:"right" }}>
            {filtered.length} record{filtered.length!==1?"s":""}
          </div>
        )}
      </div>
    </div>
  );
}

// ══════════════════════════════════════════════════════════════════

// ORG REGISTER
// ══════════════════════════════════════════════════════════════════
// ─── ORGANISATION FORM ────────────────────────────────────────────────────────
function OrgForm({ record, onSave, onCancel, onOpenRecord, readOnly=false, onDelete, onDuplicate }) {
  const isNew = !record?.id;
  const [f, setF] = useState(record || {
    classification:"CONFIDENTIAL", tags:[], tasks:[], inv_notes:[], files:[], links:[],
    logo_url:null, status:"Active",
  });
  const s = k => v => setF(p=>({...p,[k]:v}));

  const handleLogoUpload = (e) => {
    const file = e.target.files[0]; if(!file)return;
    const reader = new FileReader();
    reader.onload = ev => setF(p=>({...p,logo_url:ev.target.result}));
    reader.readAsDataURL(file);
  };

  const handleSave = () => {
    if(!f.name?.trim()){alert("Organisation Name is required.");return;}
    onSave({...f, id:f.id||Date.now(), urn:f.urn||makeURN()});
  };

  // Status colour
  const statusColor = {
    Active:K.green, Dissolved:K.textDim, Sanctioned:K.red,
    Dormant:K.amber, "In Administration":K.amber, Liquidation:K.red, Unknown:K.textDim,
  };

  return (
    <div style={{maxWidth:"900px",margin:"0 auto"}}>
      {/* Header */}
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:"24px",paddingBottom:"18px",borderBottom:`1px solid ${K.border}`}}>
        <div>
          <div style={{fontSize:"11px",fontWeight:"700",color:K.textDim,letterSpacing:"2px",textTransform:"uppercase",marginBottom:"4px"}}>
            ORGANISATION REGISTER
            {!isNew&&<span style={{marginLeft:"10px",fontFamily:"monospace",color:K.blue,fontWeight:"800"}}>{f.urn}</span>}
          </div>
          <h1 style={{margin:0,fontSize:"22px",fontWeight:"800",color:K.navy,fontFamily:"'Georgia','Times New Roman',serif"}}>
            {isNew?"Add New Organisation":f.name||"Unnamed Organisation"}
          </h1>
          {!isNew&&f.type&&<div style={{marginTop:"4px",fontSize:"12px",color:K.textMid}}>
            {f.type}
            {f.status&&<span style={{marginLeft:"10px",fontWeight:"700",color:statusColor[f.status]||K.textMid}}>● {f.status}</span>}
          </div>}
        </div>
        <div style={{display:"flex",flexDirection:"column",alignItems:"flex-end",gap:"8px"}}>
          <div style={{display:"flex",alignItems:"center",gap:"8px"}}>
            <span style={{fontSize:"11px",color:K.textMid,fontWeight:"600"}}>Classification</span>
            <select value={f.classification} onChange={e=>s("classification")(e.target.value)}
              style={{padding:"5px 9px",border:`1px solid ${K.border}`,borderRadius:"4px",fontSize:"11px",fontWeight:"800",color:K.blue,fontFamily:"monospace",background:K.surface,cursor:"pointer"}}>
              {L.class_lvl.map(c=><option key={c} value={c}>{c}</option>)}
            </select>
          </div>
          <ClassBadge v={f.classification}/>
        </div>
      </div>

      {/* Tags + Logo box */}
      <div style={{display:"flex",gap:"24px",alignItems:"flex-start",marginBottom:"8px"}}>
        <div style={{flex:1}}>
          <TagsInput tags={f.tags||[]} setTags={s("tags")}/>
        </div>
        {/* Logo box */}
        <div style={{flexShrink:0,width:"140px",display:"flex",flexDirection:"column",alignItems:"center",gap:"8px"}}>
          <div style={{width:"130px",height:"130px",border:`2px solid ${K.border}`,borderRadius:"6px",
            overflow:"hidden",background:K.surfaceAlt,display:"flex",alignItems:"center",
            justifyContent:"center",position:"relative",cursor:"pointer"}}
            onClick={()=>document.getElementById("logo-upload-input").click()}>
            {f.logo_url
              ? <img src={f.logo_url} alt="Logo" style={{width:"100%",height:"100%",objectFit:"contain",padding:"8px"}}/>
              : <div style={{textAlign:"center",padding:"12px"}}>
                  <div style={{fontSize:"32px",marginBottom:"6px",opacity:0.3}}>🏢</div>
                  <div style={{fontSize:"10px",color:K.textDim,lineHeight:"1.4"}}>Click to upload logo</div>
                </div>
            }
            <div style={{position:"absolute",bottom:0,left:0,right:0,background:"rgba(13,31,60,0.65)",
              color:"#fff",fontSize:"10px",textAlign:"center",padding:"4px",fontWeight:"600"}}>
              {f.logo_url?"Click to change":"Upload logo"}
            </div>
          </div>
          <input id="logo-upload-input" type="file" accept="image/*"
            style={{display:"none"}} onChange={handleLogoUpload}/>
          {f.logo_url&&<button onClick={()=>setF(p=>({...p,logo_url:null}))}
            style={{background:"none",border:"none",color:K.textDim,fontSize:"10px",cursor:"pointer",fontFamily:"inherit"}}>
            ✕ Remove logo
          </button>}
          <div style={{fontSize:"9px",color:K.textDim,textAlign:"center",lineHeight:"1.4"}}>
            Organisation logo<br/>JPG, PNG accepted
          </div>
        </div>
      </div>

      {/* ── DETAILS ── */}
      <SectionHeader title="Details"/>

      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"16px"}}>
        <Field label="Type">
          <Select value={f.type} onChange={s("type")} options={L.org_type}/>
        </Field>
        <Field label="Status">
          <select value={f.status||""} onChange={e=>s("status")(e.target.value)}
            style={{...inp,color:f.status?(statusColor[f.status]||K.text):K.textDim,fontWeight:f.status?"700":"400"}}>
            <option value="">Select…</option>
            {L.org_status.map(o=><option key={o} value={o} style={{color:K.text,fontWeight:"400"}}>{o}</option>)}
          </select>
        </Field>
      </div>

      <Field label="Name" required hint="Full legal registered name">
        <Input value={f.name} onChange={v=>s("name")(v.toUpperCase())} placeholder="FULL LEGAL NAME"/>
      </Field>

      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"16px"}}>
        <Field label="Also Known As" hint="aliases, trading names — semicolon separated">
          <Input value={f.also_known_as} onChange={s("also_known_as")} placeholder="e.g. Trading Name; Abbreviation; Former Name"/>
        </Field>
        <Field label="Registered Country">
          <Input value={f.registered_country} onChange={s("registered_country")} placeholder="Country of incorporation"/>
        </Field>
      </div>

      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"16px"}}>
        <Field label="Registered Number" hint="Company / charity number">
          <Input value={f.reg_number} onChange={s("reg_number")} placeholder="e.g. 12345678"/>
        </Field>
        <Field label="Date of Incorporation">
          <Input type="date" value={f.date_inc} onChange={s("date_inc")}/>
        </Field>
      </div>

      <Field label="Last Accounts Filed">
        <Input type="date" value={f.last_accounts} onChange={s("last_accounts")}/>
      </Field>

      {/* ── REGISTERED OFFICE ── */}
      <SectionHeader title="Registered Office"/>

      <Field label="Registered Address">
        <Textarea value={f.reg_address} onChange={s("reg_address")} rows={3}
          placeholder="Full registered address including postcode and country"/>
      </Field>

      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:"12px"}}>
        <Field label="Telephone">
          <Input value={f.telephone} onChange={s("telephone")} placeholder="+44 20 7000 0000"/>
        </Field>
        <Field label="Fax">
          <Input value={f.fax} onChange={s("fax")} placeholder="+44 20 7000 0001"/>
        </Field>
        <Field label="Email">
          <Input type="email" value={f.email} onChange={s("email")} placeholder="contact@organisation.com"/>
        </Field>
      </div>

      <Field label="Website">
        <Input value={f.website} onChange={s("website")} placeholder="www.organisation.com"/>
      </Field>

      {/* ── INVESTIGATION DETAILS ── */}
      <SectionHeader title="Investigation Details"/>

      <Field label="Reason for Nominal" hint="Why is this organisation in the system?">
        <Textarea value={f.reason_for_nominal} onChange={s("reason_for_nominal")} rows={3}
          placeholder="Brief explanation of investigative relevance"/>
      </Field>

      <Field label="Source">
        <Input value={f.source} onChange={s("source")} placeholder="Where did this information come from?"/>
      </Field>

      <Field label="Civil Litigation">
        <Textarea value={f.civil_litigation} onChange={s("civil_litigation")} rows={3}
          placeholder="Any known civil litigation, regulatory action or legal proceedings…"/>
      </Field>

      <Field label="Notes">
        <Textarea value={f.notes} onChange={s("notes")} rows={5}
          placeholder="Free-text notes, observations, intelligence…"/>
      </Field>

      {/* Review */}
      <div style={{display:"grid",gridTemplateColumns:"200px auto 160px",gap:"12px",alignItems:"end",marginBottom:"20px"}}>
        <Field label="Review After (Period)">
          <Select value={f.review_period} onChange={s("review_period")} options={L.review_per}/>
        </Field>
        <div style={{paddingBottom:"1px",color:K.textMid,fontSize:"12px",paddingTop:"32px"}}>on date</div>
        <Field label="Review Date">
          <Input type="date" value={f.review_date} onChange={s("review_date")}/>
        </Field>
      </div>

      <RecordProps record={f}/>

      {/* Save bar */}
      <div style={{borderTop:`1px solid ${K.border}`,paddingTop:"16px",marginBottom:"8px",display:"flex",gap:"10px",alignItems:"center",flexWrap:"wrap"}}>
        <Btn variant="primary" onClick={handleSave}>Save Record</Btn>
        <Btn onClick={()=>onSave({...f,id:f.id||Date.now(),urn:f.urn||makeURN()})}>Save & Continue</Btn>
        <Btn onClick={onCancel}>Cancel</Btn>
        {!isNew&&<>
          <div style={{flex:1}}/>
          <span style={{fontSize:"11px",color:K.textDim}}>Export:</span>
          <Btn small onClick={()=>alert("i2 ANB export")}>i2 ANB</Btn>
          <Btn small variant="primary" onClick={()=>alert("PDF report")}>PDF</Btn>
        </>}
      </div>

      <TasksSection tasks={f.tasks||[]} setTasks={s("tasks")}/>
      <NotesSection notes={f.inv_notes||[]} setNotes={s("inv_notes")}/>
      <FilesSection files={f.files||[]} setFiles={s("files")}
        onSetLogo={url=>setF(p=>({...p,logo_url:url}))}/>
      <LinksSection links={f.links||[]} setLinks={s("links")} onOpenRecord={onOpenRecord}/>
    </div>
  );
}

// ─── LIST VIEW ────────────────────────────────────────────────────────────────

// ─── ORG BULK IMPORT ─────────────────────────────────────────────────────────
const ORG_IMPORT_FIELDS = [
  {key:"name",            label:"Name",             required:true,  hint:"Organisation name"},
  {key:"type",            label:"Type",             required:false, hint:"e.g. Company, Military Unit, NGO"},
  {key:"status",          label:"Status",           required:false, hint:"Active, Dissolved, Sanctioned etc."},
  {key:"registration_number",label:"Reg. Number",   required:false, hint:"Company/registration number"},
  {key:"registered_country", label:"Country",       required:false, hint:"Country of registration"},
  {key:"date_inc",        label:"Date Incorporated",required:false, hint:"YYYY-MM-DD"},
  {key:"classification",  label:"Classification",   required:false, hint:"UNCLASSIFIED, RESTRICTED, CONFIDENTIAL"},
  {key:"description",     label:"Description",      required:false, hint:"Free text"},
  {key:"tags",            label:"Tags",             required:false, hint:"Comma-separated"},
];

function OrgImportModal({ onClose, onImport, existingRecords }) {
  const [step, setStep]       = React.useState("upload");
  const [csvData, setCsvData] = React.useState(null);
  const [mapping, setMapping] = React.useState({});
  const [preview, setPreview] = React.useState([]);
  const [dupAction,setDupAction]=React.useState("skip");
  const [orgTemplatePreview,setOrgTemplatePreview]=React.useState(null);
  const [results, setResults] = React.useState(null);

  const handleFile = (e) => {
    const file = e.target.files[0]; if(!file) return;
    const reader = new FileReader();
    reader.onload = (ev) => {
      const parsed = parseCSV(ev.target.result);
      if(parsed.rows.length===0){alert("No data rows found.");return;}
      setCsvData(parsed);
      const autoMap = {};
      ORG_IMPORT_FIELDS.forEach(f => {
        const match = parsed.headers.find(h => {
          const hL=h.toLowerCase().replace(/[^a-z]/g,"");
          const fL=f.key.toLowerCase().replace(/[^a-z]/g,"");
          const lL=f.label.toLowerCase().replace(/[^a-z]/g,"");
          return hL===fL||hL===lL||hL.includes(fL)||fL.includes(hL);
        });
        if(match) autoMap[f.key]=match;
      });
      setMapping(autoMap); setStep("map");
    };
    reader.readAsText(file); e.target.value="";
  };

  const downloadTemplate = () => {
    const headers = ORG_IMPORT_FIELDS.map(f=>f.key).join(",");
    const example = '"4TH ARMOURED DIVISION","Military Unit","Active","","Syrian Arab Republic","","CONFIDENTIAL","4th Armoured Division of the Syrian Army","Syria,BLUE TITAN"';
    const csv = headers + "\n" + example;
    if (navigator.clipboard && navigator.clipboard.writeText) {
      navigator.clipboard.writeText(csv).then(function() {
        alert("Template CSV copied to clipboard!\n\nPaste into a text editor, save as .csv, fill in your data, then upload here.");
      }).catch(function() { setOrgTemplatePreview(csv); });
    } else { setOrgTemplatePreview(csv); }
  };

  const buildPreview = () => {
    const rows = csvData.rows.map(row => {
      const rec = {classification:"CONFIDENTIAL",tags:[],tasks:[],inv_notes:[],files:[],links:[]};
      ORG_IMPORT_FIELDS.forEach(f => {
        const col=mapping[f.key];
        if(col&&row[col]!==undefined){
          if(f.key==="tags") rec.tags=row[col]?row[col].split(",").map(t=>t.trim()).filter(Boolean):[];
          else rec[f.key]=row[col]||"";
        }
      });
      if(!rec.classification) rec.classification="CONFIDENTIAL";
      const isDup = existingRecords.some(e=>e.name&&rec.name&&e.name.toUpperCase()===rec.name.toUpperCase());
      return {...rec,_isDup:isDup,_valid:!!(rec.name||"").trim()};
    });
    setPreview(rows); setStep("preview");
  };

  const runImport = () => {
    let imported=0,skipped=0,errors=0;
    const toImport = preview.filter(r=>{
      if(!r._valid){errors++;return false;}
      if(r._isDup&&dupAction==="skip"){skipped++;return false;}
      return true;
    });
    const existingMax = (existingRecords||[]).reduce(function(max,r) {
      if(!r.urn) return max;
      const parts=r.urn.split("-"); const num=parseInt(parts[parts.length-1],10);
      return isNaN(num)?max:Math.max(max,num);
    }, 0);
    const newRecords = toImport.map((r,i)=>{
      const clean={...r}; delete clean._isDup; delete clean._valid;
      clean.files=Array.isArray(clean.files)?clean.files:[];
      clean.tasks=Array.isArray(clean.tasks)?clean.tasks:[];
      clean.inv_notes=Array.isArray(clean.inv_notes)?clean.inv_notes:[];
      clean.links=Array.isArray(clean.links)?clean.links:[];
      clean.tags=Array.isArray(clean.tags)?clean.tags:[];
      const num=existingMax+i+1;
      const urn="AW-"+(URN_PREFIXES["organisation"]||"ORG")+"-"+String(num).padStart(4,"0");
      return{...clean,id:Date.now()+i,urn:urn};
    });
    imported=newRecords.length;
    setResults({imported,skipped,errors});
    setStep("done"); onImport(newRecords);
  };

  const MS={position:"fixed",inset:0,zIndex:500,background:"rgba(0,0,0,0.5)",display:"flex",alignItems:"center",justifyContent:"center",padding:"20px"};
  const PS={background:K.surface,borderRadius:"10px",width:"100%",maxWidth:"820px",maxHeight:"90vh",overflow:"hidden",display:"flex",flexDirection:"column",boxShadow:"0 20px 60px rgba(0,0,0,0.3)"};

  return (
    <div style={MS} onClick={e=>{if(e.target===e.currentTarget)onClose();}}>
      <div style={PS}>
        <div style={{padding:"20px 24px",borderBottom:"1px solid "+K.border,display:"flex",alignItems:"center",justifyContent:"space-between",background:K.navy,borderRadius:"10px 10px 0 0"}}>
          <div>
            <div style={{fontSize:"16px",fontWeight:"800",color:"#fff",letterSpacing:"1px"}}>⬆ Bulk Import — Organisation Register</div>
            <div style={{fontSize:"11px",color:"rgba(255,255,255,0.5)",marginTop:"2px"}}>
              {step==="upload"?"Step 1 of 3: Upload CSV":step==="map"?"Step 2 of 3: Map Columns":step==="preview"?"Step 3 of 3: Review & Import":"Import Complete"}
            </div>
          </div>
          <button onClick={onClose} style={{background:"none",border:"none",color:"rgba(255,255,255,0.6)",cursor:"pointer",fontSize:"20px",padding:"4px"}}>✕</button>
        </div>
        <div style={{height:"3px",background:K.border}}>
          <div style={{height:"3px",background:K.blue,transition:"width 0.3s",width:step==="upload"?"33%":step==="map"?"66%":"100%"}}/>
        </div>
        <div style={{overflowY:"auto",flex:1,padding:"24px"}}>

          {step==="upload"&&(
            <div>
              <div style={{background:"#f0f7ff",border:"1px solid "+K.blueMid,borderRadius:"8px",padding:"16px",marginBottom:"20px",fontSize:"13px",color:K.textMid,lineHeight:"1.7"}}>
                <strong style={{color:K.navy}}>How to import:</strong> Download the template, fill in your data (one organisation per row), save as CSV and upload here.
              </div>
              <button onClick={downloadTemplate} style={{padding:"10px 20px",background:K.surfaceAlt,border:"1px solid "+K.border,borderRadius:"5px",fontSize:"13px",fontWeight:"700",cursor:"pointer",fontFamily:"inherit",marginBottom:"10px"}}>📋 Copy Template CSV</button>
              {orgTemplatePreview && (
                <div style={{marginBottom:"16px"}}>
                  <div style={{fontSize:"11px",color:K.blue,fontWeight:"700",marginBottom:"6px"}}>Select all and copy manually:</div>
                  <pre style={{background:"#f7f9fc",border:"1px solid "+K.border,borderRadius:"4px",
                    padding:"10px",fontSize:"10px",fontFamily:"monospace",overflowX:"auto",
                    whiteSpace:"pre",margin:0,maxHeight:"120px",overflowY:"auto"}}>
                    {orgTemplatePreview}
                  </pre>
                </div>
              )}
              <div style={{border:"2px dashed "+K.border,borderRadius:"8px",padding:"40px",textAlign:"center",background:K.surfaceAlt}}>
                <div style={{fontSize:"32px",marginBottom:"12px"}}>🏢</div>
                <div style={{fontSize:"14px",fontWeight:"700",color:K.text,marginBottom:"6px"}}>Drop your CSV file here</div>
                <div style={{fontSize:"12px",color:K.textDim,marginBottom:"16px"}}>.csv format · First row must be headers</div>
                <label style={{cursor:"pointer"}} onClick={function(e){
                    e.currentTarget.querySelector('input[type="file"]').click();
                  }}>
                  <span style={{padding:"10px 24px",background:K.blue,color:"#fff",borderRadius:"5px",fontSize:"13px",fontWeight:"700",pointerEvents:"none"}}>Choose File</span>
                  <input type="file" accept=".csv,.txt,.CSV" style={{display:"none",position:"absolute"}} onChange={handleFile}/>
                </label>
              </div>
            </div>
          )}

          {step==="map"&&csvData&&(
            <div>
              <div style={{fontSize:"13px",color:K.textMid,marginBottom:"16px"}}>{csvData.rows.length} rows · {csvData.headers.length} columns detected. Match your columns to KOIOS fields.</div>
              <table style={{width:"100%",borderCollapse:"collapse",fontSize:"12px",marginBottom:"20px"}}>
                <thead><tr style={{borderBottom:"2px solid "+K.border}}>
                  {["KOIOS Field","Your CSV Column","Sample"].map(h=><th key={h} style={{padding:"8px 12px",textAlign:"left",fontWeight:"800",color:K.textMid,fontSize:"10px",letterSpacing:"1px"}}>{h}</th>)}
                </tr></thead>
                <tbody>
                  {ORG_IMPORT_FIELDS.map(f=>{
                    const mapped=mapping[f.key];
                    const sample=mapped&&csvData.rows[0]?csvData.rows[0][mapped]:"";
                    return(
                      <tr key={f.key} style={{borderBottom:"1px solid "+K.border}}>
                        <td style={{padding:"8px 12px"}}>
                          <div style={{fontFamily:"monospace",fontWeight:"700",color:K.navy}}>{f.key}</div>
                          {f.required&&<span style={{fontSize:"10px",color:K.red,fontWeight:"700"}}>required</span>}
                        </td>
                        <td style={{padding:"8px 12px"}}>
                          <select value={mapped||""} onChange={e=>setMapping(p=>({...p,[f.key]:e.target.value||undefined}))}
                            style={{padding:"5px 8px",border:"1px solid "+(mapped?K.blue:K.border),borderRadius:"4px",fontSize:"12px",color:K.text,background:mapped?"#f0f7ff":K.surface,outline:"none",fontFamily:"inherit",width:"100%"}}>
                            <option value="">— not mapped —</option>
                            {csvData.headers.map(h=><option key={h} value={h}>{h}</option>)}
                          </select>
                        </td>
                        <td style={{padding:"8px 12px",fontFamily:"monospace",fontSize:"11px",color:K.textMid,maxWidth:"140px",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>{sample||"—"}</td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
              <div style={{display:"flex",alignItems:"center",gap:"12px",padding:"12px 14px",background:K.surfaceAlt,border:"1px solid "+K.border,borderRadius:"6px",marginBottom:"16px"}}>
                <span style={{fontSize:"12px",fontWeight:"700"}}>Duplicates:</span>
                <label style={{display:"flex",alignItems:"center",gap:"5px",cursor:"pointer",fontSize:"12px"}}><input type="radio" name="orgdup" value="skip" checked={dupAction==="skip"} onChange={()=>setDupAction("skip")}/>Skip same name</label>
                <label style={{display:"flex",alignItems:"center",gap:"5px",cursor:"pointer",fontSize:"12px"}}><input type="radio" name="orgdup" value="import" checked={dupAction==="import"} onChange={()=>setDupAction("import")}/>Import anyway</label>
              </div>
              <div style={{display:"flex",gap:"10px"}}>
                <Btn variant="primary" onClick={buildPreview} disabled={!ORG_IMPORT_FIELDS.filter(f=>f.required).every(f=>mapping[f.key])}>Preview Import →</Btn>
                <Btn onClick={()=>setStep("upload")}>← Back</Btn>
              </div>
            </div>
          )}

          {step==="preview"&&(
            <div>
              <div style={{fontSize:"14px",fontWeight:"700",color:K.text,marginBottom:"4px"}}>
                {preview.filter(r=>r._valid&&(!r._isDup||dupAction==="import")).length} ready to import
                {preview.filter(r=>r._isDup&&dupAction==="skip").length>0&&<span style={{color:K.amber,marginLeft:"8px"}}>· {preview.filter(r=>r._isDup&&dupAction==="skip").length} duplicates skipped</span>}
                {preview.filter(r=>!r._valid).length>0&&<span style={{color:K.red,marginLeft:"8px"}}>· {preview.filter(r=>!r._valid).length} invalid</span>}
              </div>
              <div style={{border:"1px solid "+K.border,borderRadius:"8px",overflow:"hidden",marginBottom:"16px",maxHeight:"360px",overflowY:"auto"}}>
                <table style={{width:"100%",borderCollapse:"collapse",fontSize:"12px"}}>
                  <thead style={{position:"sticky",top:0}}><tr style={{background:K.surfaceAlt}}>
                    {["Status","Name","Type","Country","Classification"].map(h=><th key={h} style={{padding:"9px 12px",textAlign:"left",fontSize:"10px",fontWeight:"800",color:K.textMid,letterSpacing:"1px",borderBottom:"1px solid "+K.border,whiteSpace:"nowrap"}}>{h}</th>)}
                  </tr></thead>
                  <tbody>
                    {preview.map((r,i)=>{
                      const willSkip=r._isDup&&dupAction==="skip";
                      const invalid=!r._valid;
                      return(
                        <tr key={i} style={{borderBottom:"1px solid "+K.border,background:invalid?"#fef2f2":willSkip?"#fffbeb":i%2?K.surfaceAlt:K.surface,opacity:willSkip||invalid?0.6:1}}>
                          <td style={{padding:"8px 12px",whiteSpace:"nowrap"}}>
                            {invalid?<span style={{color:K.red,fontWeight:"700",fontSize:"10px"}}>✗ INVALID</span>:willSkip?<span style={{color:K.amber,fontWeight:"700",fontSize:"10px"}}>⚠ SKIP</span>:<span style={{color:K.green,fontWeight:"700",fontSize:"10px"}}>✓ IMPORT</span>}
                          </td>
                          <td style={{padding:"8px 12px",fontWeight:"700",color:K.navy}}>{r.name||"—"}</td>
                          <td style={{padding:"8px 12px",color:K.textMid}}>{r.type||"—"}</td>
                          <td style={{padding:"8px 12px",color:K.textMid}}>{r.registered_country||"—"}</td>
                          <td style={{padding:"8px 12px"}}><ClassBadge v={r.classification}/></td>
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              </div>
              <div style={{display:"flex",gap:"10px"}}>
                <Btn variant="primary" onClick={runImport} disabled={preview.filter(r=>r._valid&&(!r._isDup||dupAction==="import")).length===0}>✓ Confirm Import</Btn>
                <Btn onClick={()=>setStep("map")}>← Back</Btn>
              </div>
            </div>
          )}

          {step==="done"&&results&&(
            <div style={{textAlign:"center",padding:"20px"}}>
              <div style={{fontSize:"48px",marginBottom:"16px"}}>✅</div>
              <div style={{fontSize:"20px",fontWeight:"800",color:K.navy,marginBottom:"16px"}}>Import Complete</div>
              <div style={{display:"flex",justifyContent:"center",gap:"20px",marginBottom:"24px"}}>
                <div style={{padding:"16px 24px",background:"#dcfce7",borderRadius:"8px"}}><div style={{fontSize:"28px",fontWeight:"800",color:K.green}}>{results.imported}</div><div style={{fontSize:"12px",color:K.green,fontWeight:"700"}}>Imported</div></div>
                {results.skipped>0&&<div style={{padding:"16px 24px",background:"#fef3c7",borderRadius:"8px"}}><div style={{fontSize:"28px",fontWeight:"800",color:K.amber}}>{results.skipped}</div><div style={{fontSize:"12px",color:K.amber,fontWeight:"700"}}>Skipped</div></div>}
                {results.errors>0&&<div style={{padding:"16px 24px",background:"#fef2f2",borderRadius:"8px"}}><div style={{fontSize:"28px",fontWeight:"800",color:K.red}}>{results.errors}</div><div style={{fontSize:"12px",color:K.red,fontWeight:"700"}}>Invalid</div></div>}
              </div>
              <Btn variant="primary" onClick={onClose}>Close</Btn>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

function OrgList({ records, onNew, onEdit, perms={}, onBulkSave, onDelete, allRecords={} }) {
  const [showOrgImport, setShowOrgImport] = useState(false);
  const [showOrgExport, setShowOrgExport] = useState(false);
  const [search, setSearch] = useState("");
  const [filterType, setFilterType] = useState("");
  const [filterClass, setFilterClass] = useState("");
  const [filterStatus, setFilterStatus] = useState("");

  const filtered = useMemo(()=>records.filter(r=>{
    const q=search.toLowerCase();
    const matchSearch=!q||r.name?.toLowerCase().includes(q)||r.urn?.toLowerCase().includes(q)||
      r.registered_country?.toLowerCase().includes(q)||r.reg_number?.toLowerCase().includes(q)||
      (r.also_known_as||"").toLowerCase().includes(q)||(r.tags||[]).some(t=>t.toLowerCase().includes(q));
    return matchSearch&&(!filterType||r.type===filterType)&&
      (!filterClass||r.classification===filterClass)&&(!filterStatus||r.status===filterStatus);
  }),[records,search,filterType,filterClass,filterStatus]);

  const statusColor={Active:K.green,Dissolved:K.textDim,Sanctioned:K.red,Dormant:K.amber,"In Administration":K.amber,Liquidation:K.red,Unknown:K.textDim};

  return <div>
    <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"20px"}}>
      <div>
        <h2 style={{margin:0,fontSize:"20px",fontWeight:"800",color:K.navy,fontFamily:"'Georgia','Times New Roman',serif"}}>Organisation Register</h2>
        <div style={{fontSize:"12px",color:K.textDim,marginTop:"3px"}}>{filtered.length} of {records.length} record{records.length!==1?"s":""}</div>
      </div>
      <div style={{display:"flex",gap:"8px"}}>
          <Btn small onClick={()=>setShowOrgExport(true)}>📄 Export</Btn>
          {perms.canCreate && <Btn small onClick={()=>setShowOrgImport(true)}>⬆ Bulk Import</Btn>}
          <Btn variant="primary" onClick={onNew}>+ Add Organisation</Btn>
        </div>
    </div>
    {showOrgImport && (
      <OrgImportModal existingRecords={records}
        onClose={()=>setShowOrgImport(false)}
        onImport={function(recs){if(onBulkSave)onBulkSave(recs);setShowOrgImport(false);}}/>
    )}
    {showOrgExport && (
      <ExportModal records={records} allRecords={allRecords}
        register="organisation" onClose={()=>setShowOrgExport(false)}/>
    )}

    {/* Filters */}
    <div style={{display:"flex",gap:"10px",marginBottom:"16px",flexWrap:"wrap"}}>
      <div style={{flex:1,minWidth:"200px"}}>
        <input value={search} onChange={e=>setSearch(e.target.value)}
          placeholder="Search name, URN, country, reg number, tags…"
          style={{...inp}}/>
      </div>
      <div style={{width:"180px"}}><Select value={filterType} onChange={setFilterType} options={L.org_type} placeholder="All Types"/></div>
      <div style={{width:"150px"}}><Select value={filterStatus} onChange={setFilterStatus} options={L.org_status} placeholder="All Statuses"/></div>
      <div style={{width:"170px"}}><Select value={filterClass} onChange={setFilterClass} options={L.class_lvl} placeholder="All Classifications"/></div>
    </div>

    {/* Table */}
    <div style={{border:`1px solid ${K.border}`,borderRadius:"8px",overflow:"hidden",boxShadow:"0 1px 3px rgba(0,0,0,0.06)"}}>
      <table style={{width:"100%",borderCollapse:"collapse",fontSize:"12px"}}>
        <thead>
          <tr style={{background:K.navy}}>
            {["Logo","URN","Name","Type","Country","Status","Classification","Tags","Review",""].map(h=>(
              <th key={h} style={{padding:"11px 14px",textAlign:"left",fontWeight:"700",fontSize:"10px",color:"rgba(255,255,255,0.7)",letterSpacing:"1px"}}>{h}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {filtered.length===0&&<tr><td colSpan={10} style={{padding:"32px",textAlign:"center",color:K.textDim}}>No records found matching your search.</td></tr>}
          {filtered.map((r,i)=>(
            <tr key={r.id} onClick={()=>onEdit(r)}
              style={{borderBottom:`1px solid ${K.border}`,cursor:"pointer",background:i%2?K.surfaceAlt:K.surface}}
              onMouseEnter={e=>e.currentTarget.style.background=K.blueLight}
              onMouseLeave={e=>e.currentTarget.style.background=i%2?K.surfaceAlt:K.surface}>
              <td style={{padding:"9px 14px"}}>
                {r.logo_url
                  ? <img src={r.logo_url} alt="" style={{width:"32px",height:"32px",objectFit:"contain",borderRadius:"3px",border:`1px solid ${K.border}`}}/>
                  : <div style={{width:"32px",height:"32px",background:K.surfaceAlt,borderRadius:"3px",border:`1px solid ${K.border}`,display:"flex",alignItems:"center",justifyContent:"center",fontSize:"14px",color:K.textDim}}>🏢</div>
                }
              </td>
              <td style={{padding:"9px 14px",fontFamily:"monospace",fontSize:"11px",color:K.blue,fontWeight:"700"}}>{r.urn}</td>
              <td style={{padding:"9px 14px"}}>
                <div style={{fontWeight:"700",color:K.text}}>{r.name}</div>
                {r.also_known_as&&<div style={{fontSize:"10px",color:K.textDim,marginTop:"1px"}}>aka {r.also_known_as.split(";")[0].trim()}</div>}
              </td>
              <td style={{padding:"9px 14px",color:K.textMid}}>{r.type||"—"}</td>
              <td style={{padding:"9px 14px",color:K.textMid}}>{r.registered_country||"—"}</td>
              <td style={{padding:"9px 14px"}}>
                <span style={{color:statusColor[r.status]||K.textDim,fontWeight:"700",fontSize:"11px"}}>● {r.status||"—"}</span>
              </td>
              <td style={{padding:"9px 14px"}}><ClassBadge v={r.classification}/></td>
              <td style={{padding:"9px 14px"}}>
                <div style={{display:"flex",gap:"4px",flexWrap:"wrap"}}>
                  {(r.tags||[]).map(t=><TagPill key={t} label={t}/>)}
                </div>
              </td>
              <td style={{padding:"9px 14px",color:isOverdue(r.review_date)?K.red:K.textMid,fontWeight:isOverdue(r.review_date)?"700":"400",fontSize:"11px"}}>
                {fmtDate(r.review_date)}{isOverdue(r.review_date)&&" ⚠"}
              </td>
              <td style={{padding:"9px 14px"}}><span style={{color:K.blueMid,fontWeight:"700",fontSize:"11px"}}>Open →</span></td>
            </tr>
          ))}
        </tbody>
      </table>
      {filtered.length>0&&<div style={{padding:"8px 14px",background:K.surfaceAlt,fontSize:"11px",color:K.textDim,borderTop:`1px solid ${K.border}`,textAlign:"right"}}>{filtered.length} record{filtered.length!==1?"s":""}</div>}
    </div>
  </div>;
}

// ══════════════════════════════════════════════════════════════════

// INFO REGISTER
// ══════════════════════════════════════════════════════════════════
// ─── INFORMATION FORM ─────────────────────────────────────────────────────────
function InfoForm({ record, onSave, onCancel, onOpenRecord, readOnly=false, onDelete, onDuplicate }) {
  const isNew = !record?.id;
  const [f, setF] = useState(record || {
    classification:"CONFIDENTIAL", status:"Draft",
    tags:[], tasks:[], inv_notes:[], files:[], links:[],
  });
  const s = k => v => setF(p=>({...p,[k]:v}));

  const handleSave = () => {
    if(!f.title?.trim()){alert("Title is required.");return;}
    onSave({...f, id:f.id||Date.now(), urn:f.urn||makeURN()});
  };

  const typeIcon = TYPE_ICON[f.type] || "📄";
  const sc = STATUS_COLOR[f.status] || STATUS_COLOR["Draft"];

  return (
    <div style={{maxWidth:"900px",margin:"0 auto"}}>

      {/* Header */}
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",
        marginBottom:"24px",paddingBottom:"18px",borderBottom:`1px solid ${K.border}`}}>
        <div>
          <div style={{fontSize:"11px",fontWeight:"700",color:K.textDim,letterSpacing:"2px",
            textTransform:"uppercase",marginBottom:"4px",display:"flex",alignItems:"center",gap:"10px"}}>
            <span>INFORMATION REGISTER</span>
            {!isNew&&<span style={{fontFamily:"monospace",color:K.blue,fontWeight:"800"}}>{f.urn}</span>}
          </div>
          <h1 style={{margin:0,fontSize:"22px",fontWeight:"800",color:K.navy,
            fontFamily:"'Georgia','Times New Roman',serif",display:"flex",alignItems:"center",gap:"10px"}}>
            <span style={{fontSize:"20px"}}>{typeIcon}</span>
            {isNew?"Add New Information Record":f.title||"Untitled"}
          </h1>
          {!isNew&&<div style={{marginTop:"8px",display:"flex",alignItems:"center",gap:"10px",flexWrap:"wrap"}}>
            {f.type&&<span style={{fontSize:"12px",color:K.textMid}}>{f.type}</span>}
            {f.subtype&&<><span style={{color:K.textDim}}>·</span><span style={{fontSize:"12px",color:K.textMid}}>{f.subtype}</span></>}
            <StatusBadge v={f.status||"Draft"}/>
          </div>}
        </div>
        <div style={{display:"flex",flexDirection:"column",alignItems:"flex-end",gap:"8px"}}>
          <div style={{display:"flex",alignItems:"center",gap:"8px"}}>
            <span style={{fontSize:"11px",color:K.textMid,fontWeight:"600"}}>Classification</span>
            <select value={f.classification} onChange={e=>s("classification")(e.target.value)}
              style={{padding:"5px 9px",border:`1px solid ${K.border}`,borderRadius:"4px",
                fontSize:"11px",fontWeight:"800",color:K.blue,fontFamily:"monospace",
                background:K.surface,cursor:"pointer"}}>
              {L.class_lvl.map(c=><option key={c} value={c}>{c}</option>)}
            </select>
          </div>
          <ClassBadge v={f.classification}/>
        </div>
      </div>

      <TagsInput tags={f.tags||[]} setTags={s("tags")}/>

      {/* ── DETAILS ── */}
      <SectionHeader title="Details"/>

      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:"14px"}}>
        <Field label="Type">
          <Select value={f.type} onChange={s("type")} options={L.info_type}/>
        </Field>
        <Field label="Subtype">
          <Select value={f.subtype} onChange={s("subtype")} options={L.info_subtype}/>
        </Field>
        <Field label="Status">
          {/* Inline status selector with colour */}
          <select value={f.status||""} onChange={e=>s("status")(e.target.value)}
            style={{...inp,
              color:STATUS_COLOR[f.status]?.fg||K.textDim,
              background:STATUS_COLOR[f.status]?.bg||K.surface,
              borderColor:STATUS_COLOR[f.status]?.border||K.border,
              fontWeight:"700"}}>
            <option value="">Select…</option>
            {L.info_status.map(o=><option key={o} value={o} style={{color:K.text,background:K.surface,fontWeight:"400"}}>{o}</option>)}
          </select>
        </Field>
      </div>

      <Field label="Title" required>
        <Input value={f.title} onChange={s("title")} placeholder="Descriptive title for this information record"/>
      </Field>

      {/* Date row */}
      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:"14px"}}>
        <Field label="Date Reported">
          <Input type="date" value={f.date_reported} onChange={s("date_reported")}/>
        </Field>
        <Field label="Date Occurred" hint="start of period">
          <Input type="date" value={f.date_occurred} onChange={s("date_occurred")}/>
        </Field>
        <Field label="Until" hint="end of period">
          <Input type="date" value={f.date_until} onChange={s("date_until")}/>
        </Field>
      </div>

      <Field label="Source" hint="free text description of source">
        <Input value={f.source_text} onChange={s("source_text")}
          placeholder="e.g. Open source, Partner agency, Internal analysis"/>
      </Field>

      {/* ── CONTENT ── */}
      <SectionHeader title="Content"/>

      <Field label="Information" hint="main body — supports long-form content">
        <Textarea value={f.information_body} onChange={s("information_body")} rows={12}
          placeholder="Enter the full information content here…&#10;&#10;This field supports long-form text including findings, summaries, analysis, and intelligence reports."/>
      </Field>

      <Field label="Provenance" hint="how was this information obtained?">
        <Textarea value={f.provenance} onChange={s("provenance")} rows={3}
          placeholder="Describe how this information was gathered, verified, or received…"/>
      </Field>

      {/* Review */}
      <div style={{display:"grid",gridTemplateColumns:"200px auto 160px",gap:"12px",alignItems:"end",marginBottom:"20px"}}>
        <Field label="Review After (Period)">
          <Select value={f.review_period} onChange={s("review_period")} options={L.review_per}/>
        </Field>
        <div style={{paddingBottom:"1px",color:K.textMid,fontSize:"12px",paddingTop:"32px"}}>on date</div>
        <Field label="Review Date">
          <Input type="date" value={f.review_date} onChange={s("review_date")}/>
        </Field>
      </div>

      <RecordProps record={f}/>

      {/* Save bar */}
      <div style={{borderTop:`1px solid ${K.border}`,paddingTop:"16px",marginBottom:"8px",
        display:"flex",gap:"10px",alignItems:"center",flexWrap:"wrap"}}>
        <Btn variant="primary" onClick={handleSave}>Save Record</Btn>
        <Btn onClick={()=>onSave({...f,id:f.id||Date.now(),urn:f.urn||makeURN()})}>Save & Continue</Btn>
        <Btn onClick={onCancel}>Cancel</Btn>
        {!isNew&&<>
          <div style={{flex:1}}/>
          <span style={{fontSize:"11px",color:K.textDim}}>Export:</span>
          <Btn small onClick={()=>alert("i2 ANB export")}>i2 ANB</Btn>
          <Btn small variant="primary" onClick={()=>alert("PDF report")}>PDF</Btn>
        </>}
      </div>

      <TasksSection tasks={f.tasks||[]} setTasks={s("tasks")}/>
      <NotesSection notes={f.inv_notes||[]} setNotes={s("inv_notes")}/>
      <FilesSection files={f.files||[]} setFiles={s("files")}/>
      <LinksSection links={f.links||[]} setLinks={s("links")} onOpenRecord={onOpenRecord}/>
    </div>
  );
}

// ─── LIST VIEW ────────────────────────────────────────────────────────────────
function InfoList({ records, onNew, onEdit , onDelete }) {
  const [search, setSearch] = useState("");
  const [filterType, setFilterType] = useState("");
  const [filterStatus, setFilterStatus] = useState("");
  const [filterClass, setFilterClass] = useState("");

  const filtered = useMemo(()=>records.filter(r=>{
    const q=search.toLowerCase();
    const matchSearch=!q||r.title?.toLowerCase().includes(q)||r.urn?.toLowerCase().includes(q)||
      r.source_text?.toLowerCase().includes(q)||(r.tags||[]).some(t=>t.toLowerCase().includes(q))||
      r.information_body?.toLowerCase().includes(q);
    return matchSearch&&(!filterType||r.type===filterType)&&
      (!filterStatus||r.status===filterStatus)&&(!filterClass||r.classification===filterClass);
  }),[records,search,filterType,filterStatus,filterClass]);

  return <div>
    <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"20px"}}>
      <div>
        <h2 style={{margin:0,fontSize:"20px",fontWeight:"800",color:K.navy,fontFamily:"'Georgia','Times New Roman',serif"}}>Information Register</h2>
        <div style={{fontSize:"12px",color:K.textDim,marginTop:"3px"}}>{filtered.length} of {records.length} record{records.length!==1?"s":""}</div>
      </div>
      <Btn variant="primary" onClick={onNew}>+ Add Information</Btn>
    </div>

    {/* Filters */}
    <div style={{display:"flex",gap:"10px",marginBottom:"16px",flexWrap:"wrap"}}>
      <div style={{flex:1,minWidth:"220px"}}>
        <input value={search} onChange={e=>setSearch(e.target.value)}
          placeholder="Search title, URN, source, content, tags…" style={{...inp}}/>
      </div>
      <div style={{width:"180px"}}><Select value={filterType} onChange={setFilterType} options={L.info_type} placeholder="All Types"/></div>
      <div style={{width:"160px"}}><Select value={filterStatus} onChange={setFilterStatus} options={L.info_status} placeholder="All Statuses"/></div>
      <div style={{width:"170px"}}><Select value={filterClass} onChange={setFilterClass} options={L.class_lvl} placeholder="All Classifications"/></div>
    </div>

    {/* Table */}
    <div style={{border:`1px solid ${K.border}`,borderRadius:"8px",overflow:"hidden",boxShadow:"0 1px 3px rgba(0,0,0,0.06)"}}>
      <table style={{width:"100%",borderCollapse:"collapse",fontSize:"12px"}}>
        <thead>
          <tr style={{background:K.navy}}>
            {["URN","Title","Type","Subtype","Status","Date Reported","Classification","Tags","Review",""].map(h=>(
              <th key={h} style={{padding:"11px 14px",textAlign:"left",fontWeight:"700",fontSize:"10px",color:"rgba(255,255,255,0.7)",letterSpacing:"1px"}}>{h}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {filtered.length===0&&<tr><td colSpan={10} style={{padding:"32px",textAlign:"center",color:K.textDim}}>No records found.</td></tr>}
          {filtered.map((r,i)=>(
            <tr key={r.id} onClick={()=>onEdit(r)}
              style={{borderBottom:`1px solid ${K.border}`,cursor:"pointer",background:i%2?K.surfaceAlt:K.surface}}
              onMouseEnter={e=>e.currentTarget.style.background=K.blueLight}
              onMouseLeave={e=>e.currentTarget.style.background=i%2?K.surfaceAlt:K.surface}>
              <td style={{padding:"11px 14px",fontFamily:"monospace",fontSize:"11px",color:K.blue,fontWeight:"700",whiteSpace:"nowrap"}}>{r.urn}</td>
              <td style={{padding:"11px 14px"}}>
                <div style={{display:"flex",alignItems:"center",gap:"6px"}}>
                  <span style={{fontSize:"14px"}}>{TYPE_ICON[r.type]||"📄"}</span>
                  <div>
                    <div style={{fontWeight:"700",color:K.text}}>{r.title}</div>
                    {r.source_text&&<div style={{fontSize:"10px",color:K.textDim,marginTop:"1px"}}>Source: {r.source_text.substring(0,40)}{r.source_text.length>40?"…":""}</div>}
                  </div>
                </div>
              </td>
              <td style={{padding:"11px 14px",color:K.textMid,whiteSpace:"nowrap"}}>{r.type||"—"}</td>
              <td style={{padding:"11px 14px",color:K.textDim,fontSize:"11px"}}>{r.subtype||"—"}</td>
              <td style={{padding:"11px 14px",whiteSpace:"nowrap"}}><StatusBadge v={r.status||"Draft"}/></td>
              <td style={{padding:"11px 14px",color:K.textMid,fontSize:"11px",whiteSpace:"nowrap"}}>{fmtDate(r.date_reported)}</td>
              <td style={{padding:"11px 14px"}}><ClassBadge v={r.classification}/></td>
              <td style={{padding:"11px 14px"}}>
                <div style={{display:"flex",gap:"4px",flexWrap:"wrap"}}>
                  {(r.tags||[]).map(t=><TagPill key={t} label={t}/>)}
                </div>
              </td>
              <td style={{padding:"11px 14px",color:isOverdue(r.review_date)?K.red:K.textMid,
                fontWeight:isOverdue(r.review_date)?"700":"400",fontSize:"11px",whiteSpace:"nowrap"}}>
                {fmtDate(r.review_date)}{isOverdue(r.review_date)&&" ⚠"}
              </td>
              <td style={{padding:"11px 14px",whiteSpace:"nowrap"}}><span style={{color:K.blueMid,fontWeight:"700",fontSize:"11px"}}>Open →</span></td>
            </tr>
          ))}
        </tbody>
      </table>
      {filtered.length>0&&<div style={{padding:"8px 14px",background:K.surfaceAlt,fontSize:"11px",color:K.textDim,borderTop:`1px solid ${K.border}`,textAlign:"right"}}>{filtered.length} record{filtered.length!==1?"s":""}</div>}
    </div>
  </div>;
}

// ══════════════════════════════════════════════════════════════════

// INTEL REGISTER
// ══════════════════════════════════════════════════════════════════
// ─── INTELLIGENCE ENTRIES TABLE ───────────────────────────────────────────────
function EntriesTable({ entries, setEntries, showConfidential }) {
  const addEntry = () => setEntries([...entries,{id:Date.now(),s:"",i:"",h:"",content:"",confidential:false}]);
  const upd = (id,key,val) => setEntries(entries.map(e=>e.id===id?{...e,[key]:val}:e));
  const remove = id => setEntries(entries.filter(e=>e.id!==id));

  const sGradeOpts = ["A","B","C","D","E"];
  const iGradeOpts = ["1","2","3","4","5"];
  const hGradeOpts = ["1","2","3","4"];

  const gradeSelect = (val, opts, onChange, col) => (
    <select value={val||""} onChange={e=>onChange(e.target.value)}
      style={{ width:"46px", padding:"5px 2px", border:`1px solid ${K.border}`,
        borderRadius:"4px", fontSize:"13px", fontWeight:"700", textAlign:"center",
        color:col||K.textDim, background:K.surface, cursor:"pointer", fontFamily:"monospace" }}>
      <option value=""></option>
      {opts.map(o=><option key={o} value={o} style={{color:GRADE_COLOR[o]||K.text}}>{o}</option>)}
    </select>
  );

  return (
    <div>
      <SectionHeader title="Intelligence Entries" action="Add Entry" onAction={addEntry}/>
      <p style={{fontSize:"11px",color:K.textDim,marginTop:"-10px",marginBottom:"12px"}}>
        Each row is a discrete piece of intelligence with its own S/I/H grading.
        Mark entries as Confidential to restrict display — use Show Confidential toggle to reveal.
      </p>
      {entries.length===0&&(
        <div style={{padding:"20px",textAlign:"center",color:K.textDim,border:`1px dashed ${K.border}`,borderRadius:"6px",marginBottom:"10px"}}>
          No intelligence entries. Click <strong>+ Add Entry</strong> to begin.
        </div>
      )}
      {entries.map((e,i)=>{
        const isConfHidden = e.confidential && !showConfidential;
        return (
          <div key={e.id} style={{border:`1px solid ${e.confidential?K.red+"44":K.border}`,
            borderRadius:"6px",marginBottom:"10px",overflow:"hidden",
            background:e.confidential?K.redLight:"transparent"}}>
            {/* Entry header */}
            <div style={{padding:"8px 12px",background:e.confidential?"#fef2f2":K.surfaceAlt,
              borderBottom:`1px solid ${e.confidential?K.red+"22":K.border}`,
              display:"flex",alignItems:"center",gap:"12px"}}>
              <span style={{fontSize:"11px",fontWeight:"700",color:K.textDim}}>Entry {i+1}</span>
              {/* S grade */}
              <div style={{display:"flex",alignItems:"center",gap:"4px"}}>
                <span style={{fontSize:"10px",fontWeight:"700",color:K.textMid}}>S</span>
                {gradeSelect(e.s, sGradeOpts, v=>upd(e.id,"s",v), GRADE_COLOR[e.s])}
              </div>
              {/* I grade */}
              <div style={{display:"flex",alignItems:"center",gap:"4px"}}>
                <span style={{fontSize:"10px",fontWeight:"700",color:K.textMid}}>I</span>
                {gradeSelect(e.i, iGradeOpts, v=>upd(e.id,"i",v), GRADE_COLOR[e.i])}
              </div>
              {/* H grade */}
              <div style={{display:"flex",alignItems:"center",gap:"4px"}}>
                <span style={{fontSize:"10px",fontWeight:"700",color:K.textMid}}>H</span>
                {gradeSelect(e.h, hGradeOpts, v=>upd(e.id,"h",v), GRADE_COLOR[e.h])}
              </div>
              {/* Grade summary */}
              {(e.s||e.i||e.h)&&(
                <span style={{padding:"2px 10px",background:K.navy,color:"#fff",
                  borderRadius:"3px",fontFamily:"monospace",fontSize:"12px",fontWeight:"700"}}>
                  {e.s||"·"}/{e.i||"·"}/{e.h||"·"}
                </span>
              )}
              <div style={{marginLeft:"auto",display:"flex",alignItems:"center",gap:"10px"}}>
                <label style={{display:"flex",alignItems:"center",gap:"5px",cursor:"pointer",fontSize:"11px",
                  color:e.confidential?K.red:K.textMid,fontWeight:e.confidential?"700":"400"}}>
                  <input type="checkbox" checked={!!e.confidential} onChange={ev=>upd(e.id,"confidential",ev.target.checked)}
                    style={{accentColor:K.red,cursor:"pointer"}}/>
                  🔒 Confidential
                </label>
                <button onClick={()=>remove(e.id)}
                  style={{background:"none",border:"none",color:K.textDim,cursor:"pointer",fontSize:"12px"}}>✕</button>
              </div>
            </div>
            {/* Entry content */}
            <div style={{padding:"10px 12px"}}>
              {isConfHidden
                ? <div style={{padding:"12px",textAlign:"center",color:K.red,fontSize:"12px",fontStyle:"italic"}}>
                    🔒 Confidential entry — enable "Show Confidential" to view
                  </div>
                : <textarea value={e.content||""} onChange={ev=>upd(e.id,"content",ev.target.value)}
                    rows={3} placeholder="Enter intelligence content for this entry…"
                    style={{...inp,resize:"vertical",lineHeight:"1.6",
                      background:e.confidential?"#fef9f9":K.surface,
                      borderColor:e.confidential?K.red+"44":K.border}}/>
              }
            </div>
          </div>
        );
      })}
    </div>
  );
}

// ─── OVERALL GRADING ──────────────────────────────────────────────────────────
function OverallGrading({ f, s }) {
  return (
    <div>
      <SectionHeader title="Overall Grading (5×5×5)"/>
      <p style={{fontSize:"11px",color:K.textDim,marginTop:"-10px",marginBottom:"16px"}}>
        Set the overall S/I/H grade for the intelligence report as a whole.
      </p>
      {/* Visual grade display */}
      <div style={{display:"flex",gap:"24px",alignItems:"center",marginBottom:"16px",
        padding:"16px",background:K.surfaceAlt,borderRadius:"6px",border:`1px solid ${K.border}`}}>
        <GradePill label="S — Source" value={f.source_eval?.split(" ")[0]}/>
        <div style={{fontSize:"20px",color:K.border}}>/</div>
        <GradePill label="I — Intelligence" value={f.intel_assessment?.split(" ")[0]}/>
        <div style={{fontSize:"20px",color:K.border}}>/</div>
        <GradePill label="H — Handling" value={f.handling_code?.split(" ")[0]}/>
        {f.source_eval&&f.intel_assessment&&f.handling_code&&(
          <div style={{marginLeft:"auto",padding:"10px 18px",background:K.navy,color:"#fff",
            borderRadius:"6px",fontFamily:"monospace",fontSize:"18px",fontWeight:"800"}}>
            {f.source_eval.split(" ")[0]}/{f.intel_assessment.split(" ")[0]}/{f.handling_code.split(" ")[0]}
          </div>
        )}
      </div>
      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:"14px"}}>
        <Field label="Source Evaluation (S)">
          <select value={f.source_eval||""} onChange={e=>s("source_eval")(e.target.value)}
            style={{...inp,color:f.source_eval?GRADE_COLOR[f.source_eval[0]]||K.text:K.textDim,fontWeight:f.source_eval?"700":"400"}}>
            <option value="">Select…</option>
            {L.source_eval.map(o=><option key={o} value={o} style={{color:K.text,fontWeight:"400"}}>{o}</option>)}
          </select>
        </Field>
        <Field label="Intelligence Assessment (I)">
          <select value={f.intel_assessment||""} onChange={e=>s("intel_assessment")(e.target.value)}
            style={{...inp,color:f.intel_assessment?GRADE_COLOR[f.intel_assessment[0]]||K.text:K.textDim,fontWeight:f.intel_assessment?"700":"400"}}>
            <option value="">Select…</option>
            {L.intel_assessment.map(o=><option key={o} value={o} style={{color:K.text,fontWeight:"400"}}>{o}</option>)}
          </select>
        </Field>
        <Field label="Handling Code (H)">
          <select value={f.handling_code||""} onChange={e=>s("handling_code")(e.target.value)}
            style={{...inp,color:f.handling_code?GRADE_COLOR[f.handling_code[0]]||K.text:K.textDim,fontWeight:f.handling_code?"700":"400"}}>
            <option value="">Select…</option>
            {L.handling_code.map(o=><option key={o} value={o} style={{color:K.text,fontWeight:"400"}}>{o}</option>)}
          </select>
        </Field>
      </div>
      <Field label="Confidence Level" hint="free text">
        <Input value={f.confidence_level} onChange={s("confidence_level")} placeholder="e.g. High, Medium, Low"/>
      </Field>
    </div>
  );
}

// ─── SHARED SECTIONS ──────────────────────────────────────────────────────────
// ─── INTELLIGENCE FORM ────────────────────────────────────────────────────────
function IntelForm({ record, onSave, onCancel, onOpenRecord, readOnly=false, onDelete, onDuplicate }) {
  const isNew = !record?.id;
  const [f, setF] = useState(record || {
    classification:"CONFIDENTIAL", draft_status:"Draft",
    tags:[], tasks:[], inv_notes:[], files:[], links:[],
    entries:[], show_confidential:false, pii:false,
  });
  const s = k => v => setF(p=>({...p,[k]:v}));

  const handleSave = () => {
    if(!f.title?.trim()){alert("Title is required.");return;}
    if(!f.draft_status){alert("Draft Status is required.");return;}
    onSave({...f, id:f.id||Date.now(), urn:f.urn||makeURN()});
  };

  const dc = DRAFT_COLOR[f.draft_status]||DRAFT_COLOR.Draft;
  const confCount = (f.entries||[]).filter(e=>e.confidential).length;

  return (
    <div style={{maxWidth:"900px",margin:"0 auto"}}>

      {/* Header */}
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",
        marginBottom:"24px",paddingBottom:"18px",borderBottom:`1px solid ${K.border}`}}>
        <div>
          <div style={{fontSize:"11px",fontWeight:"700",color:K.textDim,letterSpacing:"2px",
            textTransform:"uppercase",marginBottom:"6px",display:"flex",alignItems:"center",gap:"10px",flexWrap:"wrap"}}>
            <span>INTELLIGENCE REGISTER</span>
            {!isNew&&<span style={{fontFamily:"monospace",color:K.blue,fontWeight:"800"}}>{f.urn}</span>}
            <DraftBadge v={f.draft_status}/>

          </div>
          <h1 style={{margin:0,fontSize:"22px",fontWeight:"800",color:K.navy,fontFamily:"'Georgia','Times New Roman',serif"}}>
            {isNew?"Add New Intelligence Record":f.title||"Untitled"}
          </h1>
          {!isNew&&<div style={{marginTop:"6px",display:"flex",alignItems:"center",gap:"10px",flexWrap:"wrap"}}>
            {f.type&&<span style={{fontSize:"12px",color:K.textMid}}>{f.type}</span>}
            {f.source_eval&&f.intel_assessment&&f.handling_code&&(
              <span style={{padding:"3px 12px",background:K.navy,color:"#fff",borderRadius:"4px",
                fontFamily:"monospace",fontSize:"13px",fontWeight:"800"}}>
                {f.source_eval.split(" ")[0]}/{f.intel_assessment.split(" ")[0]}/{f.handling_code.split(" ")[0]}
              </span>
            )}
            {confCount>0&&(
              <span style={{fontSize:"11px",color:K.red,fontWeight:"600"}}>
                🔒 {confCount} confidential entr{confCount===1?"y":"ies"}
              </span>
            )}
          </div>}
        </div>
        <div style={{display:"flex",flexDirection:"column",alignItems:"flex-end",gap:"8px"}}>
          <div style={{display:"flex",alignItems:"center",gap:"8px"}}>
            <span style={{fontSize:"11px",color:K.textMid,fontWeight:"600"}}>Classification</span>
            <select value={f.classification} onChange={e=>s("classification")(e.target.value)}
              style={{padding:"5px 9px",border:`1px solid ${K.border}`,borderRadius:"4px",
                fontSize:"11px",fontWeight:"800",color:K.blue,fontFamily:"monospace",background:K.surface,cursor:"pointer"}}>
              {L.class_lvl.map(c=><option key={c} value={c}>{c}</option>)}
            </select>
          </div>
          <ClassBadge v={f.classification}/>
        </div>
      </div>

      <TagsInput tags={f.tags||[]} setTags={s("tags")}/>

      {/* ── DETAILS ── */}
      <SectionHeader title="Details"/>

      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"16px"}}>
        <Field label="Type">
          <Select value={f.type} onChange={s("type")} options={L.intel_type}/>
        </Field>
        <Field label="Draft Status" required>
          <select value={f.draft_status||""} onChange={e=>s("draft_status")(e.target.value)}
            style={{...inp, color:dc.fg, background:dc.bg, borderColor:dc.border, fontWeight:"700"}}>
            {L.draft_status.map(o=><option key={o} value={o} style={{color:K.text,background:K.surface,fontWeight:"400"}}>{o}</option>)}
          </select>
        </Field>
      </div>

      <Field label="Title" required>
        <Input value={f.title} onChange={s("title")} placeholder="Descriptive title for this intelligence record"/>
      </Field>

      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"14px"}}>
        <Field label="Date Occurred" hint="start of intelligence period">
          <Input type="datetime-local" value={f.date_occurred} onChange={s("date_occurred")}/>
        </Field>
        <Field label="Until" hint="end of intelligence period">
          <Input type="datetime-local" value={f.date_until} onChange={s("date_until")}/>
        </Field>
      </div>

      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"14px"}}>
        <Field label="Source" hint="link to Source register via Universal Links">
          <Input value={f.source_ref} onChange={s("source_ref")} placeholder="e.g. AW-SRC-0001 — SPARROW-2"/>
        </Field>
        <Field label="Investigation" hint="link to Investigation register via Universal Links">
          <Input value={f.investigation_ref} onChange={s("investigation_ref")} placeholder="e.g. AW-INV-0001"/>
        </Field>
      </div>

      {/* Show confidential toggle */}
      {(f.entries||[]).some(e=>e.confidential)&&(
        <div style={{padding:"10px 14px",background:K.redLight,border:`1px solid ${K.red}33`,
          borderRadius:"6px",marginBottom:"16px",display:"flex",alignItems:"center",justifyContent:"space-between"}}>
          <span style={{fontSize:"12px",color:K.red,fontWeight:"600"}}>
            🔒 This record contains {confCount} confidential entr{confCount===1?"y":"ies"}
          </span>
          <label style={{display:"flex",alignItems:"center",gap:"8px",cursor:"pointer",fontSize:"12px",color:K.red,fontWeight:"600"}}>
            <input type="checkbox" checked={!!f.show_confidential} onChange={e=>s("show_confidential")(e.target.checked)}
              style={{accentColor:K.red,cursor:"pointer"}}/>
            Show Confidential Text
          </label>
        </div>
      )}

      {/* Intelligence Entries */}
      <EntriesTable
        entries={f.entries||[]}
        setEntries={s("entries")}
        showConfidential={f.show_confidential}/>

      {/* Overall Grading */}
      <OverallGrading f={f} s={s}/>

      {/* Summary */}
      <SectionHeader title="Summary"/>
      <Field label="Summary">
        <Textarea value={f.summary} onChange={s("summary")} rows={5}
          placeholder="Overall summary of this intelligence record — key findings, context, corroboration…"/>
      </Field>

      {/* Review */}
      <div style={{display:"grid",gridTemplateColumns:"200px auto 160px",gap:"12px",alignItems:"end",marginBottom:"20px"}}>
        <Field label="Review After (Period)">
          <Select value={f.review_period} onChange={s("review_period")} options={L.review_per}/>
        </Field>
        <div style={{paddingBottom:"1px",color:K.textMid,fontSize:"12px",paddingTop:"32px"}}>on date</div>
        <Field label="Review Date">
          <Input type="date" value={f.review_date} onChange={s("review_date")}/>
        </Field>
      </div>

      <RecordProps record={f}/>

      {/* Save bar */}
      <div style={{borderTop:`1px solid ${K.border}`,paddingTop:"16px",marginBottom:"8px",
        display:"flex",gap:"10px",alignItems:"center",flexWrap:"wrap"}}>
        <Btn variant="primary" onClick={handleSave}>Save Record</Btn>
        <Btn onClick={()=>onSave({...f,id:f.id||Date.now(),urn:f.urn||makeURN()})}>Save & Continue</Btn>
        <Btn onClick={onCancel}>Cancel</Btn>
        {!isNew&&<>
          <div style={{flex:1}}/>
          <span style={{fontSize:"11px",color:K.textDim}}>Export:</span>
          <Btn small onClick={()=>alert("i2 ANB export")}>i2 ANB</Btn>
          <Btn small variant="primary" onClick={()=>alert("PDF report")}>PDF</Btn>
        </>}
      </div>

      <TasksSection tasks={f.tasks||[]} setTasks={s("tasks")}/>
      <NotesSection notes={f.inv_notes||[]} setNotes={s("inv_notes")}/>
      <FilesSection files={f.files||[]} setFiles={s("files")}/>
      <LinksSection links={f.links||[]} setLinks={s("links")} onOpenRecord={onOpenRecord}/>
    </div>
  );
}

// ─── LIST VIEW ────────────────────────────────────────────────────────────────
function IntelList({ records, onNew, onEdit , onDelete }) {
  const [search, setSearch] = useState("");
  const [filterType, setFilterType] = useState("");
  const [filterStatus, setFilterStatus] = useState("");
  const [filterClass, setFilterClass] = useState("");

  const filtered = useMemo(()=>records.filter(r=>{
    const q=search.toLowerCase();
    const matchSearch=!q||r.title?.toLowerCase().includes(q)||r.urn?.toLowerCase().includes(q)||
      r.summary?.toLowerCase().includes(q)||
      (r.tags||[]).some(t=>t.toLowerCase().includes(q));
    return matchSearch&&(!filterType||r.type===filterType)&&
      (!filterStatus||r.draft_status===filterStatus)&&(!filterClass||r.classification===filterClass);
  }),[records,search,filterType,filterStatus,filterClass]);

  return <div>
    <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"20px"}}>
      <div>
        <h2 style={{margin:0,fontSize:"20px",fontWeight:"800",color:K.navy,fontFamily:"'Georgia','Times New Roman',serif"}}>Intelligence Register</h2>
        <div style={{fontSize:"12px",color:K.textDim,marginTop:"3px"}}>{filtered.length} of {records.length} record{records.length!==1?"s":""}</div>
      </div>
      <Btn variant="primary" onClick={onNew}>+ Add Intelligence</Btn>
    </div>

    <div style={{display:"flex",gap:"10px",marginBottom:"16px",flexWrap:"wrap"}}>
      <div style={{flex:1,minWidth:"220px"}}>
        <input value={search} onChange={e=>setSearch(e.target.value)}
          placeholder="Search title, URN, summary, external ref, tags…" style={{...inp}}/>
      </div>
      <div style={{width:"200px"}}><Select value={filterType} onChange={setFilterType} options={L.intel_type} placeholder="All Types"/></div>
      <div style={{width:"180px"}}><Select value={filterStatus} onChange={setFilterStatus} options={L.draft_status} placeholder="All Statuses"/></div>
      <div style={{width:"170px"}}><Select value={filterClass} onChange={setFilterClass} options={L.class_lvl} placeholder="All Classifications"/></div>
    </div>

    <div style={{border:`1px solid ${K.border}`,borderRadius:"8px",overflow:"hidden",boxShadow:"0 1px 3px rgba(0,0,0,0.06)"}}>
      <table style={{width:"100%",borderCollapse:"collapse",fontSize:"12px"}}>
        <thead>
          <tr style={{background:K.navy}}>
            {["URN","Title","Type","Grade","Status","Date","Classification","Tags","Review",""].map(h=>(
              <th key={h} style={{padding:"11px 14px",textAlign:"left",fontWeight:"700",fontSize:"10px",color:"rgba(255,255,255,0.7)",letterSpacing:"1px"}}>{h}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {filtered.length===0&&<tr><td colSpan={10} style={{padding:"32px",textAlign:"center",color:K.textDim}}>No records found.</td></tr>}
          {filtered.map((r,i)=>{
            const grade = [r.source_eval?.split(" ")[0],r.intel_assessment?.split(" ")[0],r.handling_code?.split(" ")[0]].filter(Boolean).join("/");
            const confCount=(r.entries||[]).filter(e=>e.confidential).length;
            return (
              <tr key={r.id} onClick={()=>onEdit(r)}
                style={{borderBottom:`1px solid ${K.border}`,cursor:"pointer",background:i%2?K.surfaceAlt:K.surface}}
                onMouseEnter={e=>e.currentTarget.style.background=K.blueLight}
                onMouseLeave={e=>e.currentTarget.style.background=i%2?K.surfaceAlt:K.surface}>
                <td style={{padding:"11px 14px",fontFamily:"monospace",fontSize:"11px",color:K.blue,fontWeight:"700",whiteSpace:"nowrap"}}>{r.urn}</td>
                <td style={{padding:"11px 14px"}}>
                  <div style={{fontWeight:"700",color:K.text,maxWidth:"220px",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>{r.title}</div>
                  <div style={{display:"flex",gap:"6px",marginTop:"2px",alignItems:"center"}}>

                    {confCount>0&&<span style={{fontSize:"10px",color:K.red,fontWeight:"600"}}>🔒 {confCount}</span>}

                  </div>
                </td>
                <td style={{padding:"11px 14px",color:K.textMid,whiteSpace:"nowrap",fontSize:"11px"}}>{r.type||"—"}</td>
                <td style={{padding:"11px 14px"}}>
                  {grade
                    ? <span style={{padding:"3px 10px",background:K.navy,color:"#fff",borderRadius:"4px",fontFamily:"monospace",fontSize:"12px",fontWeight:"800",whiteSpace:"nowrap"}}>{grade}</span>
                    : <span style={{color:K.textDim}}>—</span>}
                </td>
                <td style={{padding:"11px 14px",whiteSpace:"nowrap"}}><DraftBadge v={r.draft_status}/></td>
                <td style={{padding:"11px 14px",color:K.textMid,fontSize:"11px",whiteSpace:"nowrap"}}>{fmtDate(r.date_occurred?.split("T")[0])}</td>
                <td style={{padding:"11px 14px"}}><ClassBadge v={r.classification}/></td>
                <td style={{padding:"11px 14px"}}>
                  <div style={{display:"flex",gap:"4px",flexWrap:"wrap"}}>
                    {(r.tags||[]).map(t=><TagPill key={t} label={t}/>)}
                  </div>
                </td>
                <td style={{padding:"11px 14px",color:isOverdue(r.review_date)?K.red:K.textMid,
                  fontWeight:isOverdue(r.review_date)?"700":"400",fontSize:"11px",whiteSpace:"nowrap"}}>
                  {fmtDate(r.review_date)}{isOverdue(r.review_date)&&" ⚠"}
                </td>
                <td style={{padding:"11px 14px",whiteSpace:"nowrap"}}><span style={{color:K.blueMid,fontWeight:"700",fontSize:"11px"}}>Open →</span></td>
              </tr>
            );
          })}
        </tbody>
      </table>
      {filtered.length>0&&<div style={{padding:"8px 14px",background:K.surfaceAlt,fontSize:"11px",color:K.textDim,borderTop:`1px solid ${K.border}`,textAlign:"right"}}>{filtered.length} record{filtered.length!==1?"s":""}</div>}
    </div>
  </div>;
}

// ══════════════════════════════════════════════════════════════════

// EVENT REGISTER
// ══════════════════════════════════════════════════════════════════
// ─── EVENT FORM ───────────────────────────────────────────────────────────────
function EventForm({ record, onSave, onCancel, onOpenRecord, readOnly=false, onDelete, onDuplicate }) {
  const isNew = !record?.id;
  const [f, setF] = useState(record || {
    classification:"CONFIDENTIAL",
    tags:[], tasks:[], inv_notes:[], files:[], links:[],
  });
  const s = k => v => setF(p=>({...p,[k]:v}));

  const handleSave = () => {
    if(!f.title?.trim()){alert("Title is required.");return;}
    onSave({...f, id:f.id||Date.now(), urn:f.urn||makeURN()});
  };

  const typeCol = TYPE_COLOR[f.type]||K.blue;

  return (
    <div style={{maxWidth:"900px",margin:"0 auto"}}>

      {/* Header */}
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",
        marginBottom:"24px",paddingBottom:"18px",borderBottom:`1px solid ${K.border}`}}>
        <div>
          <div style={{fontSize:"11px",fontWeight:"700",color:K.textDim,letterSpacing:"2px",
            textTransform:"uppercase",marginBottom:"4px",display:"flex",alignItems:"center",gap:"10px"}}>
            <span>EVENT REGISTER</span>
            {!isNew&&<span style={{fontFamily:"monospace",color:K.blue,fontWeight:"800"}}>{f.urn}</span>}
          </div>
          <h1 style={{margin:0,fontSize:"22px",fontWeight:"800",color:K.navy,
            fontFamily:"'Georgia','Times New Roman',serif"}}>
            {isNew?"Add New Event":f.title||"Untitled Event"}
          </h1>
          {!isNew&&<div style={{marginTop:"8px",display:"flex",alignItems:"center",gap:"10px",flexWrap:"wrap"}}>
            {f.type&&<TypeBadge v={f.type}/>}
            {f.date_of_occurrence&&<span style={{fontSize:"12px",color:K.textMid}}>
              {fmtDateTime(f.date_of_occurrence)}
            </span>}
            {f.location_text&&<span style={{fontSize:"12px",color:K.textDim}}>📍 {f.location_text}</span>}
          </div>}
        </div>
        <div style={{display:"flex",flexDirection:"column",alignItems:"flex-end",gap:"8px"}}>
          <div style={{display:"flex",alignItems:"center",gap:"8px"}}>
            <span style={{fontSize:"11px",color:K.textMid,fontWeight:"600"}}>Classification</span>
            <select value={f.classification} onChange={e=>s("classification")(e.target.value)}
              style={{padding:"5px 9px",border:`1px solid ${K.border}`,borderRadius:"4px",
                fontSize:"11px",fontWeight:"800",color:K.blue,fontFamily:"monospace",background:K.surface,cursor:"pointer"}}>
              {L.class_lvl.map(c=><option key={c} value={c}>{c}</option>)}
            </select>
          </div>
          <ClassBadge v={f.classification}/>
        </div>
      </div>

      <TagsInput tags={f.tags||[]} setTags={s("tags")}/>

      {/* ── DETAILS ── */}
      <SectionHeader title="Details"/>

      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"16px"}}>
        <Field label="Type">
          <Select value={f.type} onChange={s("type")} options={L.event_type}/>
        </Field>
        <Field label="Date of Occurrence">
          <Input type="datetime-local" value={f.date_of_occurrence} onChange={s("date_of_occurrence")}/>
        </Field>
      </div>

      <Field label="Title" required>
        <Input value={f.title} onChange={s("title")} placeholder="Descriptive title for this event"/>
      </Field>

      <Field label="Subject" hint="brief subject line">
        <Input value={f.subject} onChange={s("subject")} placeholder="Short subject or reference"/>
      </Field>

      <Field label="Notes" hint="full narrative — supports long entries">
        <Textarea value={f.notes} onChange={s("notes")} rows={8}
          placeholder="Full narrative description of the event — what happened, who was involved, what was the outcome…"/>
      </Field>

      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"16px"}}>
        <Field label="Officer" hint="responsible officer">
          <Input value={f.officer} onChange={s("officer")} placeholder="Officer or investigator name"/>
        </Field>
        <Field label="Team">
          <Input value={f.team} onChange={s("team")} placeholder="Team or unit responsible"/>
        </Field>
      </div>

      <Field label="Location" hint="link to Address register via Universal Links">
        <Input value={f.location_text} onChange={s("location_text")}
          placeholder="Free text location or address"/>
      </Field>

      {/* Review */}
      <div style={{display:"grid",gridTemplateColumns:"200px auto 160px",gap:"12px",alignItems:"end",marginBottom:"20px"}}>
        <Field label="Review After (Period)">
          <Select value={f.review_period} onChange={s("review_period")} options={L.review_per}/>
        </Field>
        <div style={{paddingBottom:"1px",color:K.textMid,fontSize:"12px",paddingTop:"32px"}}>on date</div>
        <Field label="Review Date">
          <Input type="date" value={f.review_date} onChange={s("review_date")}/>
        </Field>
      </div>

      <RecordProps record={f}/>

      {/* Save bar */}
      <div style={{borderTop:`1px solid ${K.border}`,paddingTop:"16px",marginBottom:"8px",
        display:"flex",gap:"10px",alignItems:"center",flexWrap:"wrap"}}>
        <Btn variant="primary" onClick={handleSave}>Save Record</Btn>
        <Btn onClick={()=>onSave({...f,id:f.id||Date.now(),urn:f.urn||makeURN()})}>Save & Continue</Btn>
        <Btn onClick={onCancel}>Cancel</Btn>
        {!isNew&&<>
          <div style={{flex:1}}/>
          <span style={{fontSize:"11px",color:K.textDim}}>Export:</span>
          <Btn small onClick={()=>alert("i2 ANB export")}>i2 ANB</Btn>
          <Btn small variant="primary" onClick={()=>alert("PDF report")}>PDF</Btn>
        </>}
      </div>

      <TasksSection tasks={f.tasks||[]} setTasks={s("tasks")}/>
      <NotesSection notes={f.inv_notes||[]} setNotes={s("inv_notes")}/>
      <FilesSection files={f.files||[]} setFiles={s("files")}/>
      <LinksSection links={f.links||[]} setLinks={s("links")} onOpenRecord={onOpenRecord}/>
    </div>
  );
}

// ─── LIST VIEW ────────────────────────────────────────────────────────────────
function EventList({ records, onNew, onEdit , onDelete }) {
  const [search, setSearch] = useState("");
  const [filterType, setFilterType] = useState("");
  const [filterClass, setFilterClass] = useState("");
  const [sortOrder, setSortOrder] = useState("asc"); // chronological by default

  const filtered = useMemo(()=>{
    return records
      .filter(r=>{
        const q=search.toLowerCase();
        const matchSearch=!q||r.title?.toLowerCase().includes(q)||r.urn?.toLowerCase().includes(q)||
          r.subject?.toLowerCase().includes(q)||r.notes?.toLowerCase().includes(q)||
          r.location_text?.toLowerCase().includes(q)||(r.tags||[]).some(t=>t.toLowerCase().includes(q));
        return matchSearch&&(!filterType||r.type===filterType)&&(!filterClass||r.classification===filterClass);
      })
      .sort((a,b)=>{
        const da=a.date_of_occurrence||"";
        const db=b.date_of_occurrence||"";
        return sortOrder==="asc"?da.localeCompare(db):db.localeCompare(da);
      });
  },[records,search,filterType,filterClass,sortOrder]);

  // Group by year for timeline view
  const timelineGroups = useMemo(()=>{
    if(filterType && filterType!=="Timeline") return null;
    const groups={};
    filtered.forEach(r=>{
      if(!r.date_of_occurrence) return;
      const yr=new Date(r.date_of_occurrence).getFullYear();
      (groups[yr]=groups[yr]||[]).push(r);
    });
    return Object.keys(groups).length>0?groups:null;
  },[filtered,filterType]);

  const showTimeline = !search && (!filterType || filterType==="Timeline") && timelineGroups;

  return <div>
    <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"20px"}}>
      <div>
        <h2 style={{margin:0,fontSize:"20px",fontWeight:"800",color:K.navy,fontFamily:"'Georgia','Times New Roman',serif"}}>Event Register</h2>
        <div style={{fontSize:"12px",color:K.textDim,marginTop:"3px"}}>{filtered.length} of {records.length} record{records.length!==1?"s":""}</div>
      </div>
      <Btn variant="primary" onClick={onNew}>+ Add Event</Btn>
    </div>

    <div style={{display:"flex",gap:"10px",marginBottom:"16px",flexWrap:"wrap"}}>
      <div style={{flex:1,minWidth:"220px"}}>
        <input value={search} onChange={e=>setSearch(e.target.value)}
          placeholder="Search title, subject, notes, location, tags…" style={{...inp}}/>
      </div>
      <div style={{width:"180px"}}><Select value={filterType} onChange={setFilterType} options={L.event_type} placeholder="All Types"/></div>
      <div style={{width:"170px"}}><Select value={filterClass} onChange={setFilterClass} options={L.class_lvl} placeholder="All Classifications"/></div>
      <button onClick={()=>setSortOrder(o=>o==="asc"?"desc":"asc")}
        style={{padding:"8px 14px",border:`1px solid ${K.border}`,borderRadius:"4px",
          background:K.surface,fontSize:"12px",cursor:"pointer",fontFamily:"inherit",
          color:K.textMid,fontWeight:"600",whiteSpace:"nowrap"}}>
        {sortOrder==="asc"?"↑ Oldest first":"↓ Newest first"}
      </button>
    </div>

    {/* Timeline view */}
    {showTimeline&&(
      <div style={{marginBottom:"24px"}}>
        <div style={{fontSize:"11px",fontWeight:"700",color:K.blue,letterSpacing:"2px",
          marginBottom:"16px",textTransform:"uppercase"}}>TIMELINE VIEW</div>
        <div style={{position:"relative",paddingLeft:"24px"}}>
          <div style={{position:"absolute",left:"8px",top:"0",bottom:"0",width:"2px",background:K.border}}/>
          {Object.keys(timelineGroups).sort((a,b)=>sortOrder==="asc"?a-b:b-a).map(yr=>(
            <div key={yr} style={{marginBottom:"24px"}}>
              <div style={{position:"relative",marginBottom:"12px"}}>
                <div style={{position:"absolute",left:"-20px",top:"50%",transform:"translateY(-50%)",
                  width:"14px",height:"14px",borderRadius:"50%",background:K.blue,border:`3px solid ${K.surface}`}}/>
                <div style={{fontSize:"13px",fontWeight:"800",color:K.blue,letterSpacing:"1px"}}>{yr}</div>
              </div>
              {timelineGroups[yr].map(r=>{
                const col=TYPE_COLOR[r.type]||K.blue;
                return(
                  <div key={r.id} onClick={()=>onEdit(r)}
                    style={{position:"relative",marginBottom:"8px",marginLeft:"12px",cursor:"pointer"}}>
                    <div style={{position:"absolute",left:"-20px",top:"14px",
                      width:"8px",height:"8px",borderRadius:"50%",background:col,border:`2px solid ${K.surface}`}}/>
                    <div style={{border:`1px solid ${K.border}`,borderLeft:`3px solid ${col}`,
                      borderRadius:"4px",padding:"10px 14px",background:K.surface,
                      transition:"background 0.1s"}}
                      onMouseEnter={e=>e.currentTarget.style.background=K.blueLight}
                      onMouseLeave={e=>e.currentTarget.style.background=K.surface}>
                      <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",gap:"12px"}}>
                        <div style={{flex:1}}>
                          <div style={{fontSize:"11px",color:col,fontWeight:"700",marginBottom:"2px"}}>
                            {fmtDateTime(r.date_of_occurrence)} · {TYPE_ICON[r.type]} {r.type}
                          </div>
                          <div style={{fontSize:"13px",fontWeight:"700",color:K.text}}>{r.title}</div>
                          {r.location_text&&<div style={{fontSize:"11px",color:K.textDim,marginTop:"2px"}}>📍 {r.location_text}</div>}
                        </div>
                        <div style={{display:"flex",gap:"6px",alignItems:"center",flexShrink:0}}>
                          <ClassBadge v={r.classification}/>
                          <span style={{color:K.blueMid,fontWeight:"700",fontSize:"11px"}}>→</span>
                        </div>
                      </div>
                    </div>
                  </div>
                );
              })}
            </div>
          ))}
        </div>
      </div>
    )}

    {/* Table view */}
    {!showTimeline&&<div style={{border:`1px solid ${K.border}`,borderRadius:"8px",overflow:"hidden",boxShadow:"0 1px 3px rgba(0,0,0,0.06)"}}>
      <table style={{width:"100%",borderCollapse:"collapse",fontSize:"12px"}}>
        <thead>
          <tr style={{background:K.navy}}>
            {["URN","Date","Title","Type","Officer","Location","Classification","Tags","Review",""].map(h=>(
              <th key={h} style={{padding:"11px 14px",textAlign:"left",fontWeight:"700",fontSize:"10px",color:"rgba(255,255,255,0.7)",letterSpacing:"1px"}}>{h}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {filtered.length===0&&<tr><td colSpan={10} style={{padding:"32px",textAlign:"center",color:K.textDim}}>No records found.</td></tr>}
          {filtered.map((r,i)=>{
            const col=TYPE_COLOR[r.type]||K.blue;
            return(
              <tr key={r.id} onClick={()=>onEdit(r)}
                style={{borderBottom:`1px solid ${K.border}`,cursor:"pointer",background:i%2?K.surfaceAlt:K.surface}}
                onMouseEnter={e=>e.currentTarget.style.background=K.blueLight}
                onMouseLeave={e=>e.currentTarget.style.background=i%2?K.surfaceAlt:K.surface}>
                <td style={{padding:"11px 14px",fontFamily:"monospace",fontSize:"11px",color:K.blue,fontWeight:"700",whiteSpace:"nowrap"}}>{r.urn}</td>
                <td style={{padding:"11px 14px",color:K.textMid,fontSize:"11px",whiteSpace:"nowrap"}}>{fmtDateTime(r.date_of_occurrence)}</td>
                <td style={{padding:"11px 14px"}}>
                  <div style={{fontWeight:"700",color:K.text,maxWidth:"240px",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>{r.title}</div>
                  {r.subject&&<div style={{fontSize:"10px",color:K.textDim,marginTop:"1px"}}>{r.subject}</div>}
                </td>
                <td style={{padding:"11px 14px",whiteSpace:"nowrap"}}>
                  <span style={{display:"inline-flex",alignItems:"center",gap:"4px",
                    padding:"2px 8px",background:`${col}15`,color:col,
                    border:`1px solid ${col}44`,borderRadius:"10px",fontSize:"11px",fontWeight:"600"}}>
                    {TYPE_ICON[r.type]||"◷"} {r.type||"—"}
                  </span>
                </td>
                <td style={{padding:"11px 14px",color:K.textMid,fontSize:"11px"}}>{r.officer||"—"}</td>
                <td style={{padding:"11px 14px",color:K.textMid,fontSize:"11px",maxWidth:"140px",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>{r.location_text||"—"}</td>
                <td style={{padding:"11px 14px"}}><ClassBadge v={r.classification}/></td>
                <td style={{padding:"11px 14px"}}>
                  <div style={{display:"flex",gap:"4px",flexWrap:"wrap"}}>
                    {(r.tags||[]).map(t=><TagPill key={t} label={t}/>)}
                  </div>
                </td>
                <td style={{padding:"11px 14px",color:isOverdue(r.review_date)?K.red:K.textMid,
                  fontWeight:isOverdue(r.review_date)?"700":"400",fontSize:"11px",whiteSpace:"nowrap"}}>
                  {fmtDate(r.review_date)}{isOverdue(r.review_date)&&" ⚠"}
                </td>
                <td style={{padding:"11px 14px",whiteSpace:"nowrap"}}><span style={{color:K.blueMid,fontWeight:"700",fontSize:"11px"}}>Open →</span></td>
              </tr>
            );
          })}
        </tbody>
      </table>
      {filtered.length>0&&<div style={{padding:"8px 14px",background:K.surfaceAlt,fontSize:"11px",color:K.textDim,borderTop:`1px solid ${K.border}`,textAlign:"right"}}>{filtered.length} record{filtered.length!==1?"s":""}</div>}
    </div>}
  </div>;
}

// ══════════════════════════════════════════════════════════════════

// COMM REGISTER
// ══════════════════════════════════════════════════════════════════
// ─── COMMUNICATION FORM ───────────────────────────────────────────────────────
function CommForm({ record, onSave, onCancel, onOpenRecord, readOnly=false, onDelete, onDuplicate }) {
  const isNew = !record?.id;
  const [f, setF] = useState(record || {
    classification:"CONFIDENTIAL",
    tags:[], tasks:[], inv_notes:[], files:[], links:[],
  });
  const s = k => v => setF(p=>({...p,[k]:v}));

  const handleSave = () => {
    if(!f.number_address?.trim()){alert("Number / Address is required.");return;}
    onSave({...f, id:f.id||Date.now(), urn:f.urn||makeURN()});
  };

  const typeCol = TYPE_COLOR[f.type]||K.blue;
  const typeIcon = TYPE_ICON[f.type]||"📡";

  return (
    <div style={{maxWidth:"900px",margin:"0 auto"}}>

      {/* Header */}
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",
        marginBottom:"24px",paddingBottom:"18px",borderBottom:`1px solid ${K.border}`}}>
        <div>
          <div style={{fontSize:"11px",fontWeight:"700",color:K.textDim,letterSpacing:"2px",
            textTransform:"uppercase",marginBottom:"4px",display:"flex",alignItems:"center",gap:"10px"}}>
            <span>COMMUNICATION REGISTER</span>
            {!isNew&&<span style={{fontFamily:"monospace",color:K.blue,fontWeight:"800"}}>{f.urn}</span>}
          </div>
          <h1 style={{margin:0,fontSize:"22px",fontWeight:"800",color:K.navy,
            fontFamily:"'Georgia','Times New Roman',serif",display:"flex",alignItems:"center",gap:"12px"}}>
            {f.type&&<span style={{fontSize:"24px"}}>{typeIcon}</span>}
            {isNew?"Add New Communication":f.number_address||"Untitled"}
          </h1>
          {!isNew&&<div style={{marginTop:"8px",display:"flex",alignItems:"center",gap:"10px",flexWrap:"wrap"}}>
            {f.type&&<span style={{padding:"3px 10px",background:`${typeCol}15`,color:typeCol,
              border:`1px solid ${typeCol}44`,borderRadius:"12px",fontSize:"11px",fontWeight:"700"}}>{f.type}</span>}
            {f.service_provider&&<span style={{fontSize:"12px",color:K.textMid}}>via {f.service_provider}</span>}
          </div>}
        </div>
        <div style={{display:"flex",flexDirection:"column",alignItems:"flex-end",gap:"8px"}}>
          <div style={{display:"flex",alignItems:"center",gap:"8px"}}>
            <span style={{fontSize:"11px",color:K.textMid,fontWeight:"600"}}>Classification</span>
            <select value={f.classification} onChange={e=>s("classification")(e.target.value)}
              style={{padding:"5px 9px",border:`1px solid ${K.border}`,borderRadius:"4px",
                fontSize:"11px",fontWeight:"800",color:K.blue,fontFamily:"monospace",background:K.surface,cursor:"pointer"}}>
              {L.class_lvl.map(c=><option key={c} value={c}>{c}</option>)}
            </select>
          </div>
          <ClassBadge v={f.classification}/>
        </div>
      </div>

      <TagsInput tags={f.tags||[]} setTags={s("tags")}/>

      {/* ── DETAILS ── */}
      <SectionHeader title="Details"/>

      <Field label="Type">
        <Select value={f.type} onChange={s("type")} options={L.comm_type}/>
      </Field>

      {/* Number / Address — the key field, given prominent display */}
      <Field label="Number / Address" required hint="the actual value — phone number, email, URL, handle">
        <div style={{position:"relative"}}>
          {f.type&&<div style={{position:"absolute",left:"11px",top:"50%",transform:"translateY(-50%)",
            fontSize:"16px",pointerEvents:"none",zIndex:1}}>{typeIcon}</div>}
          <input value={f.number_address||""} onChange={e=>s("number_address")(e.target.value)}
            placeholder={
              f.type==="Telephone Number"||f.type==="Mobile Number"||f.type==="Fax Number" ? "+44 7700 900000" :
              f.type==="Email Address" ? "name@domain.com" :
              f.type==="Website Address" ? "www.example.com" :
              f.type==="Social Media Profile" ? "@username or profile URL" :
              f.type==="Messaging App" ? "Username or handle" :
              f.type==="Encrypted Channel" ? "Signal / Wire handle" :
              "Enter value…"
            }
            style={{...inp, paddingLeft:f.type?"38px":"11px",
              fontSize:"15px", fontWeight:"600", fontFamily:"monospace",
              borderColor:`${typeCol}66`, borderWidth:"2px"}}/>
        </div>
      </Field>

      <Field label="Service Provider" hint="e.g. Vodafone, Gmail, Meta, Signal">
        <Input value={f.service_provider} onChange={s("service_provider")}
          placeholder="Network or service provider"/>
      </Field>

      <Field label="Reason for Nominal" hint="why is this communication address in the system?">
        <Input value={f.reason_for_nominal} onChange={s("reason_for_nominal")}
          placeholder="Brief explanation of investigative relevance"/>
      </Field>

      <Field label="Primary Person / Organisation" hint="link to Person or Organisation register via Universal Links">
        <Input value={f.primary_person_ref} onChange={s("primary_person_ref")}
          placeholder="e.g. AW-PER-0001 — Bashar AL-ASSAD"/>
      </Field>

      <Field label="Source" hint="how was this communication address obtained?">
        <Input value={f.source} onChange={s("source")}
          placeholder="e.g. Open source, Intelligence, Warrant, Partner agency"/>
      </Field>

      <Field label="Notes">
        <Textarea value={f.notes} onChange={s("notes")} rows={4}
          placeholder="Additional notes — attribution confidence, last active date, associated accounts…"/>
      </Field>

      {/* Review */}
      <div style={{display:"grid",gridTemplateColumns:"200px auto 160px",gap:"12px",alignItems:"end",marginBottom:"20px"}}>
        <Field label="Review After (Period)">
          <Select value={f.review_period} onChange={s("review_period")} options={L.review_per}/>
        </Field>
        <div style={{paddingBottom:"1px",color:K.textMid,fontSize:"12px",paddingTop:"32px"}}>on date</div>
        <Field label="Review Date">
          <Input type="date" value={f.review_date} onChange={s("review_date")}/>
        </Field>
      </div>

      <RecordProps record={f}/>

      {/* Save bar */}
      <div style={{borderTop:`1px solid ${K.border}`,paddingTop:"16px",marginBottom:"8px",
        display:"flex",gap:"10px",alignItems:"center",flexWrap:"wrap"}}>
        <Btn variant="primary" onClick={handleSave}>Save Record</Btn>
        <Btn onClick={()=>onSave({...f,id:f.id||Date.now(),urn:f.urn||makeURN()})}>Save & Continue</Btn>
        <Btn onClick={onCancel}>Cancel</Btn>
        {!isNew&&<>
          <div style={{flex:1}}/>
          <span style={{fontSize:"11px",color:K.textDim}}>Export:</span>
          <Btn small onClick={()=>alert("i2 ANB export")}>i2 ANB</Btn>
          <Btn small variant="primary" onClick={()=>alert("PDF report")}>PDF</Btn>
        </>}
      </div>

      <TasksSection tasks={f.tasks||[]} setTasks={s("tasks")}/>
      <NotesSection notes={f.inv_notes||[]} setNotes={s("inv_notes")}/>
      <FilesSection files={f.files||[]} setFiles={s("files")}/>
      <LinksSection links={f.links||[]} setLinks={s("links")} onOpenRecord={onOpenRecord}/>
    </div>
  );
}

// ─── LIST VIEW ────────────────────────────────────────────────────────────────
function CommList({ records, onNew, onEdit , onDelete }) {
  const [search, setSearch] = useState("");
  const [filterType, setFilterType] = useState("");
  const [filterClass, setFilterClass] = useState("");

  const filtered = useMemo(()=>records.filter(r=>{
    const q=search.toLowerCase();
    const matchSearch=!q||r.number_address?.toLowerCase().includes(q)||r.urn?.toLowerCase().includes(q)||
      r.service_provider?.toLowerCase().includes(q)||r.reason_for_nominal?.toLowerCase().includes(q)||
      (r.tags||[]).some(t=>t.toLowerCase().includes(q));
    return matchSearch&&(!filterType||r.type===filterType)&&(!filterClass||r.classification===filterClass);
  }),[records,search,filterType,filterClass]);

  return <div>
    <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"20px"}}>
      <div>
        <h2 style={{margin:0,fontSize:"20px",fontWeight:"800",color:K.navy,fontFamily:"'Georgia','Times New Roman',serif"}}>Communication Register</h2>
        <div style={{fontSize:"12px",color:K.textDim,marginTop:"3px"}}>{filtered.length} of {records.length} record{records.length!==1?"s":""}</div>
      </div>
      <Btn variant="primary" onClick={onNew}>+ Add Communication</Btn>
    </div>

    <div style={{display:"flex",gap:"10px",marginBottom:"16px",flexWrap:"wrap"}}>
      <div style={{flex:1,minWidth:"220px"}}>
        <input value={search} onChange={e=>setSearch(e.target.value)}
          placeholder="Search number, address, provider, reason, tags…" style={{...inp}}/>
      </div>
      <div style={{width:"200px"}}><Select value={filterType} onChange={setFilterType} options={L.comm_type} placeholder="All Types"/></div>
      <div style={{width:"170px"}}><Select value={filterClass} onChange={setFilterClass} options={L.class_lvl} placeholder="All Classifications"/></div>
    </div>

    <div style={{border:`1px solid ${K.border}`,borderRadius:"8px",overflow:"hidden",boxShadow:"0 1px 3px rgba(0,0,0,0.06)"}}>
      <table style={{width:"100%",borderCollapse:"collapse",fontSize:"12px"}}>
        <thead>
          <tr style={{background:K.navy}}>
            {["URN","Type","Number / Address","Service Provider","Reason for Nominal","Classification","Tags","Review",""].map(h=>(
              <th key={h} style={{padding:"11px 14px",textAlign:"left",fontWeight:"700",fontSize:"10px",color:"rgba(255,255,255,0.7)",letterSpacing:"1px"}}>{h}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {filtered.length===0&&<tr><td colSpan={9} style={{padding:"32px",textAlign:"center",color:K.textDim}}>No records found.</td></tr>}
          {filtered.map((r,i)=>{
            const col = TYPE_COLOR[r.type]||K.blue;
            return (
              <tr key={r.id} onClick={()=>onEdit(r)}
                style={{borderBottom:`1px solid ${K.border}`,cursor:"pointer",background:i%2?K.surfaceAlt:K.surface}}
                onMouseEnter={e=>e.currentTarget.style.background=K.blueLight}
                onMouseLeave={e=>e.currentTarget.style.background=i%2?K.surfaceAlt:K.surface}>
                <td style={{padding:"11px 14px",fontFamily:"monospace",fontSize:"11px",color:K.blue,fontWeight:"700",whiteSpace:"nowrap"}}>{r.urn}</td>
                <td style={{padding:"11px 14px",whiteSpace:"nowrap"}}>
                  <span style={{display:"inline-flex",alignItems:"center",gap:"5px",
                    padding:"3px 9px",background:`${col}15`,color:col,
                    border:`1px solid ${col}44`,borderRadius:"10px",fontSize:"11px",fontWeight:"600"}}>
                    {TYPE_ICON[r.type]||"📡"} {r.type||"—"}
                  </span>
                </td>
                <td style={{padding:"11px 14px"}}>
                  <span style={{fontWeight:"700",color:K.text,fontFamily:"monospace",fontSize:"13px"}}>{r.number_address}</span>
                </td>
                <td style={{padding:"11px 14px",color:K.textMid,fontSize:"11px"}}>{r.service_provider||"—"}</td>
                <td style={{padding:"11px 14px",color:K.textMid,fontSize:"11px",maxWidth:"200px",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>{r.reason_for_nominal||"—"}</td>
                <td style={{padding:"11px 14px"}}><ClassBadge v={r.classification}/></td>
                <td style={{padding:"11px 14px"}}>
                  <div style={{display:"flex",gap:"4px",flexWrap:"wrap"}}>
                    {(r.tags||[]).map(t=><TagPill key={t} label={t}/>)}
                  </div>
                </td>
                <td style={{padding:"11px 14px",color:isOverdue(r.review_date)?K.red:K.textMid,
                  fontWeight:isOverdue(r.review_date)?"700":"400",fontSize:"11px",whiteSpace:"nowrap"}}>
                  {fmtDate(r.review_date)}{isOverdue(r.review_date)&&" ⚠"}
                </td>
                <td style={{padding:"11px 14px",whiteSpace:"nowrap"}}><span style={{color:K.blueMid,fontWeight:"700",fontSize:"11px"}}>Open →</span></td>
              </tr>
            );
          })}
        </tbody>
      </table>
      {filtered.length>0&&<div style={{padding:"8px 14px",background:K.surfaceAlt,fontSize:"11px",color:K.textDim,borderTop:`1px solid ${K.border}`,textAlign:"right"}}>{filtered.length} record{filtered.length!==1?"s":""}</div>}
    </div>
  </div>;
}

// ══════════════════════════════════════════════════════════════════

// INV_INC REGISTER
// ══════════════════════════════════════════════════════════════════
// ─── INVESTIGATION FORM ───────────────────────────────────────────────────────
function InvForm({ record, onSave, onCancel, onOpenRecord, readOnly=false, onDelete, onDuplicate }) {
  const isNew = !record?.id;
  const [f, setF] = useState(record || {
    classification:"CONFIDENTIAL", status:"Open",
    share_internally:true, restricted_search:false,
    tags:[], tasks:[], inv_notes:[], files:[], links:[],
  });
  const s = k => v => setF(p=>({...p,[k]:v}));

  const handleSave = () => {
    if(!f.title?.trim()){alert("Title is required.");return;}
    if(!f.status){alert("Status is required.");return;}
    onSave({...f, id:f.id||Date.now(), urn:f.urn||makeInvURN()});
  };

  const sc = INV_STATUS_COLOR[f.status]||INV_STATUS_COLOR.Open;

  return (
    <div style={{maxWidth:"900px",margin:"0 auto"}}>
      {/* Header */}
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",
        marginBottom:"24px",paddingBottom:"18px",borderBottom:`1px solid ${K.border}`}}>
        <div>
          <div style={{fontSize:"11px",fontWeight:"700",color:K.textDim,letterSpacing:"2px",
            textTransform:"uppercase",marginBottom:"4px",display:"flex",alignItems:"center",gap:"10px"}}>
            <span>INVESTIGATION REGISTER</span>
            {!isNew&&<span style={{fontFamily:"monospace",color:K.blue,fontWeight:"800"}}>{f.urn}</span>}
            <StatusBadge v={f.status} colorMap={INV_STATUS_COLOR}/>
          </div>
          <h1 style={{margin:0,fontSize:"22px",fontWeight:"800",color:K.navy,fontFamily:"'Georgia','Times New Roman',serif"}}>
            {isNew?"Add New Investigation":f.title||"Untitled Investigation"}
          </h1>
          {!isNew&&f.type&&<div style={{marginTop:"4px",fontSize:"12px",color:K.textMid}}>{f.type}</div>}
        </div>
        <div style={{display:"flex",flexDirection:"column",alignItems:"flex-end",gap:"8px"}}>
          <div style={{display:"flex",alignItems:"center",gap:"8px"}}>
            <span style={{fontSize:"11px",color:K.textMid,fontWeight:"600"}}>Classification</span>
            <select value={f.classification} onChange={e=>s("classification")(e.target.value)}
              style={{padding:"5px 9px",border:`1px solid ${K.border}`,borderRadius:"4px",
                fontSize:"11px",fontWeight:"800",color:K.blue,fontFamily:"monospace",background:K.surface,cursor:"pointer"}}>
              {L.class_lvl.map(c=><option key={c} value={c}>{c}</option>)}
            </select>
          </div>
          <ClassBadge v={f.classification}/>
        </div>
      </div>

      <TagsInput tags={f.tags||[]} setTags={s("tags")}/>
      <SectionHeader title="Details"/>

      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"16px"}}>
        <Field label="Type"><Select value={f.type} onChange={s("type")} options={L.inv_type}/></Field>
        <Field label="Status" required>
          <select value={f.status||""} onChange={e=>s("status")(e.target.value)}
            style={{...inp, color:sc.fg, background:sc.bg, borderColor:sc.border, fontWeight:"700"}}>
            {L.inv_status.map(o=><option key={o} value={o} style={{color:K.text,background:K.surface,fontWeight:"400"}}>{o}</option>)}
          </select>
        </Field>
      </div>

      <Field label="Title" required>
        <Input value={f.title} onChange={s("title")} placeholder="Full investigation title e.g. Operation BLUE TITAN"/>
      </Field>

      <Field label="Summary">
        <Textarea value={f.summary} onChange={s("summary")} rows={5}
          placeholder="Overview of the investigation — scope, objectives, methodology…"/>
      </Field>

      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"16px"}}>
        <Field label="Start Date"><Input type="date" value={f.start_date} onChange={s("start_date")}/></Field>
        <Field label="Close Date"><Input type="date" value={f.close_date} onChange={s("close_date")}/></Field>
      </div>

      <Field label="Lead Investigator" hint="link to Staff register via Universal Links">
        <Input value={f.lead_investigator} onChange={s("lead_investigator")} placeholder="Name of lead investigator"/>
      </Field>

      <Field label="Investigation Team" hint="semicolon-separated names or link to Staff via Universal Links">
        <Input value={f.investigation_team} onChange={s("investigation_team")}
          placeholder="e.g. Mark Watson; Lucy Myles; Elise Baranowski"/>
      </Field>

      <SectionHeader title="Access Controls"/>
      <div style={{padding:"14px 16px",border:`1px solid ${K.border}`,borderRadius:"6px",marginBottom:"16px",
        background:K.surfaceAlt,display:"flex",gap:"32px"}}>
        <div>
          <Checkbox label="Share Internally" checked={f.share_internally} onChange={s("share_internally")}/>
          <p style={{margin:"4px 0 0 25px",fontSize:"11px",color:K.textDim}}>Visible to all authenticated KOIOS users</p>
        </div>
        <div>
          <Checkbox label="Restricted Search" checked={f.restricted_search} onChange={s("restricted_search")}/>
          <p style={{margin:"4px 0 0 25px",fontSize:"11px",color:K.textDim}}>Excluded from Global Search for non-team members</p>
        </div>
      </div>

      <div style={{display:"grid",gridTemplateColumns:"200px auto 160px",gap:"12px",alignItems:"end",marginBottom:"20px"}}>
        <Field label="Review After (Period)"><Select value={f.review_period} onChange={s("review_period")} options={L.review_per}/></Field>
        <div style={{paddingBottom:"1px",color:K.textMid,fontSize:"12px",paddingTop:"32px"}}>on date</div>
        <Field label="Review Date"><Input type="date" value={f.review_date} onChange={s("review_date")}/></Field>
      </div>

      <RecordProps record={f}/>

      <div style={{borderTop:`1px solid ${K.border}`,paddingTop:"16px",marginBottom:"8px",display:"flex",gap:"10px",flexWrap:"wrap"}}>
        <Btn variant="primary" onClick={handleSave}>Save Record</Btn>
        <Btn onClick={()=>onSave({...f,id:f.id||Date.now(),urn:f.urn||makeInvURN()})}>Save & Continue</Btn>
        <Btn onClick={onCancel}>Cancel</Btn>
        {!isNew&&<><div style={{flex:1}}/><span style={{fontSize:"11px",color:K.textDim}}>Export:</span><Btn small>i2 ANB</Btn><Btn small variant="primary">PDF</Btn></>}
      </div>

      <TasksSection tasks={f.tasks||[]} setTasks={s("tasks")}/>
      <NotesSection notes={f.inv_notes||[]} setNotes={s("inv_notes")}/>
      <FilesSection files={f.files||[]} setFiles={s("files")}/>
      <LinksSection links={f.links||[]} setLinks={s("links")} onOpenRecord={onOpenRecord}/>
    </div>
  );
}

// ─── INCIDENT FORM ────────────────────────────────────────────────────────────
function IncForm({ record, onSave, onCancel, onOpenRecord, readOnly=false, onDelete, onDuplicate }) {
  const isNew = !record?.id;
  const [f, setF] = useState(record || {
    classification:"CONFIDENTIAL",
    tags:[], tasks:[], inv_notes:[], files:[], links:[],
  });
  const s = k => v => setF(p=>({...p,[k]:v}));
  const [authOpen, setAuthOpen] = useState(false);

  const handleSave = () => {
    if(!f.title?.trim()){alert("Title is required.");return;}
    onSave({...f, id:f.id||Date.now(), urn:f.urn||makeIncURN()});
  };

  const sc = INC_STATUS_COLOR[f.status];
  const pc = PRIORITY_COLOR[f.case_priority];

  return (
    <div style={{maxWidth:"900px",margin:"0 auto"}}>
      {/* Header */}
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",
        marginBottom:"24px",paddingBottom:"18px",borderBottom:`1px solid ${K.border}`}}>
        <div>
          <div style={{fontSize:"11px",fontWeight:"700",color:K.textDim,letterSpacing:"2px",
            textTransform:"uppercase",marginBottom:"4px",display:"flex",alignItems:"center",gap:"10px",flexWrap:"wrap"}}>
            <span>INCIDENT REGISTER</span>
            {!isNew&&<span style={{fontFamily:"monospace",color:K.blue,fontWeight:"800"}}>{f.urn}</span>}
            {f.status&&<StatusBadge v={f.status} colorMap={INC_STATUS_COLOR}/>}
            {f.case_priority&&<PriorityBadge v={f.case_priority}/>}
          </div>
          <h1 style={{margin:0,fontSize:"22px",fontWeight:"800",color:K.navy,fontFamily:"'Georgia','Times New Roman',serif"}}>
            {isNew?"Add New Incident":f.title||"Untitled Incident"}
          </h1>
          {!isNew&&<div style={{marginTop:"4px",fontSize:"12px",color:K.textMid,display:"flex",gap:"10px",flexWrap:"wrap"}}>
            {f.type&&<span>{f.type}</span>}
            {f.location_text&&<span style={{color:K.textDim}}>📍 {f.location_text}</span>}
          </div>}
        </div>
        <div style={{display:"flex",flexDirection:"column",alignItems:"flex-end",gap:"8px"}}>
          <div style={{display:"flex",alignItems:"center",gap:"8px"}}>
            <span style={{fontSize:"11px",color:K.textMid,fontWeight:"600"}}>Classification</span>
            <select value={f.classification} onChange={e=>s("classification")(e.target.value)}
              style={{padding:"5px 9px",border:`1px solid ${K.border}`,borderRadius:"4px",
                fontSize:"11px",fontWeight:"800",color:K.blue,fontFamily:"monospace",background:K.surface,cursor:"pointer"}}>
              {L.class_lvl.map(c=><option key={c} value={c}>{c}</option>)}
            </select>
          </div>
          <ClassBadge v={f.classification}/>
        </div>
      </div>

      <TagsInput tags={f.tags||[]} setTags={s("tags")}/>
      <SectionHeader title="Details"/>

      <Field label="Type"><Select value={f.type} onChange={s("type")} options={L.inc_type}/></Field>
      <Field label="Title" required hint="operation or incident codename">
        <Input value={f.title} onChange={s("title")} placeholder="e.g. BLUE TITAN or descriptive incident title"/>
      </Field>

      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"16px"}}>
        <Field label="How Reported"><Select value={f.how_reported} onChange={s("how_reported")} options={L.how_reported}/></Field>
        <Field label="Date Reported"><Input type="date" value={f.date_reported} onChange={s("date_reported")}/></Field>
      </div>

      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"16px"}}>
        <Field label="Date Occurred"><Input type="date" value={f.date_occurred} onChange={s("date_occurred")}/></Field>
        <Field label="Reported By"><Input value={f.reported_by} onChange={s("reported_by")} placeholder="Reporting organisation or person"/></Field>
      </div>

      <Field label="Location" hint="link to Address register via Universal Links">
        <Input value={f.location_text} onChange={s("location_text")} placeholder="Free text location"/>
      </Field>

      <Field label="Notes" hint="main incident narrative">
        <Textarea value={f.notes} onChange={s("notes")} rows={6}
          placeholder="Full narrative description of the incident — what happened, context, scope, impact…"/>
      </Field>

      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:"14px"}}>
        <Field label="Assigned To" hint="link to Staff via Universal Links">
          <Input value={f.assigned_to} onChange={s("assigned_to")} placeholder="Assigned officer"/>
        </Field>
        <Field label="Case Priority">
          <select value={f.case_priority||""} onChange={e=>s("case_priority")(e.target.value)}
            style={{...inp, color:pc?.fg||K.textDim, background:pc?.bg||K.surface,
              borderColor:pc?.border||K.border, fontWeight:f.case_priority?"700":"400"}}>
            <option value="" style={{color:K.text,background:K.surface,fontWeight:"400"}}>Select…</option>
            {L.priority.map(o=><option key={o} value={o} style={{color:K.text,background:K.surface,fontWeight:"400"}}>{o}</option>)}
          </select>
        </Field>
        <Field label="Status">
          <select value={f.status||""} onChange={e=>s("status")(e.target.value)}
            style={{...inp, color:sc?.fg||K.textDim, background:sc?.bg||K.surface,
              borderColor:sc?.border||K.border, fontWeight:f.status?"700":"400"}}>
            <option value="" style={{color:K.text,background:K.surface,fontWeight:"400"}}>Select…</option>
            {L.inc_status.map(o=><option key={o} value={o} style={{color:K.text,background:K.surface,fontWeight:"400"}}>{o}</option>)}
          </select>
        </Field>
      </div>

      <Field label="Date Completed">
        <Input type="date" value={f.date_completed} onChange={s("date_completed")}/>
      </Field>

      {/* Modes of Liability — prominent */}
      <Field label="Modes of Liability" hint="legal basis for criminal responsibility">
        <select value={f.modes_of_liability||""} onChange={e=>s("modes_of_liability")(e.target.value)}
          style={{...inp, fontWeight:f.modes_of_liability?"700":"400",
            borderColor:f.modes_of_liability?K.navy:K.border}}>
          <option value="">Select…</option>
          {L.mol.map(o=><option key={o} value={o}>{o}</option>)}
        </select>
        {f.modes_of_liability&&(
          <div style={{marginTop:"6px",padding:"8px 12px",background:K.navy+"0d",
            border:`1px solid ${K.navy}22`,borderRadius:"4px",fontSize:"12px",color:K.navy,fontWeight:"600"}}>
            ⚖ {f.modes_of_liability}
          </div>
        )}
      </Field>

      {/* Taken By */}
      <Field label="Taken By" hint="officer who logged this incident">
        <Input value={f.taken_by} onChange={s("taken_by")} placeholder="Officer name"/>
      </Field>

      {/* Authorisation — collapsible */}
      <div style={{border:`1px solid ${K.border}`,borderRadius:"6px",marginBottom:"16px",marginTop:"28px",overflow:"hidden"}}>
        <button onClick={()=>setAuthOpen(!authOpen)} style={{width:"100%",padding:"12px 16px",
          background:authOpen?K.navy:K.surfaceAlt,border:"none",cursor:"pointer",
          display:"flex",justifyContent:"space-between",alignItems:"center",fontFamily:"inherit"}}>
          <span style={{fontSize:"11px",fontWeight:"800",color:authOpen?"#fff":K.blue,letterSpacing:"2px"}}>
            INVESTIGATION AUTHORITY & LEGAL BASIS
          </span>
          <span style={{color:authOpen?"#fff":K.textDim,fontSize:"13px"}}>{authOpen?"▲":"▼"}</span>
        </button>
        {authOpen&&(
          <div style={{padding:"20px"}}>
            <p style={{fontSize:"11px",color:K.textDim,marginTop:0,marginBottom:"16px"}}>
              This section documents the legal basis for the investigation. All fields should be completed before commencing covert or intrusive methods.
            </p>
            <Field label="Methods and Duration of Investigation">
              <Textarea value={f.methods_duration} onChange={s("methods_duration")} rows={3}
                placeholder="Describe the investigative methods to be used and estimated duration…"/>
            </Field>
            <Field label="Type of Information Required">
              <Textarea value={f.type_of_info} onChange={s("type_of_info")} rows={3}
                placeholder="What categories of information are required?"/>
            </Field>
            <Field label="Necessity and Legitimacy">
              <Textarea value={f.necessity_legitimacy} onChange={s("necessity_legitimacy")} rows={3}
                placeholder="Why is this investigation necessary and proportionate?"/>
            </Field>
            <Field label="Exclusivity of Methods">
              <Textarea value={f.exclusivity} onChange={s("exclusivity")} rows={2}
                placeholder="Why are the proposed methods the least intrusive available?"/>
            </Field>
            <Field label="Data Storage & Security Measures">
              <Textarea value={f.data_storage} onChange={s("data_storage")} rows={2}
                placeholder="How will data be stored and secured?"/>
            </Field>
            <Field label="Legal Risk Assessment">
              <Textarea value={f.legal_risk} onChange={s("legal_risk")} rows={2}
                placeholder="Identify any legal risks and how they will be managed…"/>
            </Field>
            <Field label="Data Breach Plan">
              <Textarea value={f.data_breach_plan} onChange={s("data_breach_plan")} rows={2}
                placeholder="What is the response plan in the event of a data breach?"/>
            </Field>
            <Field label="Response to DSARs">
              <Textarea value={f.dsar_response} onChange={s("dsar_response")} rows={2}
                placeholder="How will Data Subject Access Requests be handled?"/>
            </Field>
            <Field label="Authorisation Statement">
              <Textarea value={f.authorisation_statement} onChange={s("authorisation_statement")} rows={3}
                placeholder="I authorise the conduct of this investigation…"/>
            </Field>
            <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"16px"}}>
              <Field label="Authorising Officer">
                <Input value={f.authorising_officer} onChange={s("authorising_officer")} placeholder="Full name"/>
              </Field>
              <Field label="Position / Title">
                <Input value={f.authorising_position} onChange={s("authorising_position")} placeholder="Job title"/>
              </Field>
            </div>
          </div>
        )}
      </div>

      <div style={{display:"grid",gridTemplateColumns:"200px auto 160px",gap:"12px",alignItems:"end",marginBottom:"20px"}}>
        <Field label="Review After (Period)"><Select value={f.review_period} onChange={s("review_period")} options={L.review_per}/></Field>
        <div style={{paddingBottom:"1px",color:K.textMid,fontSize:"12px",paddingTop:"32px"}}>on date</div>
        <Field label="Review Date"><Input type="date" value={f.review_date} onChange={s("review_date")}/></Field>
      </div>

      <RecordProps record={f}/>

      <div style={{borderTop:`1px solid ${K.border}`,paddingTop:"16px",marginBottom:"8px",display:"flex",gap:"10px",flexWrap:"wrap"}}>
        <Btn variant="primary" onClick={handleSave}>Save Record</Btn>
        <Btn onClick={()=>onSave({...f,id:f.id||Date.now(),urn:f.urn||makeIncURN()})}>Save & Continue</Btn>
        <Btn onClick={onCancel}>Cancel</Btn>
        {!isNew&&<><div style={{flex:1}}/><span style={{fontSize:"11px",color:K.textDim}}>Export:</span><Btn small>i2 ANB</Btn><Btn small variant="primary">PDF</Btn></>}
      </div>

      <TasksSection tasks={f.tasks||[]} setTasks={s("tasks")}/>
      <NotesSection notes={f.inv_notes||[]} setNotes={s("inv_notes")}/>
      <FilesSection files={f.files||[]} setFiles={s("files")}/>
      <LinksSection links={f.links||[]} setLinks={s("links")} onOpenRecord={onOpenRecord}/>
    </div>
  );
}

// ─── LIST VIEWS ───────────────────────────────────────────────────────────────
function InvList({ records, onNew, onEdit , onDelete }) {
  const [search, setSearch] = useState("");
  const [filterStatus, setFilterStatus] = useState("");
  const [filterType, setFilterType] = useState("");

  const filtered = useMemo(()=>records.filter(r=>{
    const q=search.toLowerCase();
    const match=!q||r.title?.toLowerCase().includes(q)||r.urn?.toLowerCase().includes(q)||
      r.summary?.toLowerCase().includes(q)||(r.tags||[]).some(t=>t.toLowerCase().includes(q));
    return match&&(!filterStatus||r.status===filterStatus)&&(!filterType||r.type===filterType);
  }),[records,search,filterStatus,filterType]);

  return <div>
    <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"20px"}}>
      <div>
        <h2 style={{margin:0,fontSize:"20px",fontWeight:"800",color:K.navy,fontFamily:"'Georgia','Times New Roman',serif"}}>Investigation Register</h2>
        <div style={{fontSize:"12px",color:K.textDim,marginTop:"3px"}}>{filtered.length} of {records.length} record{records.length!==1?"s":""}</div>
      </div>
      <Btn variant="primary" onClick={onNew}>+ Add Investigation</Btn>
    </div>
    <div style={{display:"flex",gap:"10px",marginBottom:"16px",flexWrap:"wrap"}}>
      <div style={{flex:1,minWidth:"220px"}}><input value={search} onChange={e=>setSearch(e.target.value)} placeholder="Search title, URN, summary, tags…" style={{...inp}}/></div>
      <div style={{width:"180px"}}><Select value={filterStatus} onChange={setFilterStatus} options={L.inv_status} placeholder="All Statuses"/></div>
      <div style={{width:"180px"}}><Select value={filterType} onChange={setFilterType} options={L.inv_type} placeholder="All Types"/></div>
    </div>
    <div style={{border:`1px solid ${K.border}`,borderRadius:"8px",overflow:"hidden",boxShadow:"0 1px 3px rgba(0,0,0,0.06)"}}>
      <table style={{width:"100%",borderCollapse:"collapse",fontSize:"12px"}}>
        <thead><tr style={{background:K.navy}}>
          {["URN","Title","Type","Status","Lead","Start Date","Classification","Tags","Review",""].map(h=>(
            <th key={h} style={{padding:"11px 14px",textAlign:"left",fontWeight:"700",fontSize:"10px",color:"rgba(255,255,255,0.7)",letterSpacing:"1px"}}>{h}</th>
          ))}
        </tr></thead>
        <tbody>
          {filtered.length===0&&<tr><td colSpan={10} style={{padding:"32px",textAlign:"center",color:K.textDim}}>No records found.</td></tr>}
          {filtered.map((r,i)=>(
            <tr key={r.id} onClick={()=>onEdit(r)}
              style={{borderBottom:`1px solid ${K.border}`,cursor:"pointer",background:i%2?K.surfaceAlt:K.surface}}
              onMouseEnter={e=>e.currentTarget.style.background=K.blueLight}
              onMouseLeave={e=>e.currentTarget.style.background=i%2?K.surfaceAlt:K.surface}>
              <td style={{padding:"11px 14px",fontFamily:"monospace",fontSize:"11px",color:K.blue,fontWeight:"700",whiteSpace:"nowrap"}}>{r.urn}</td>
              <td style={{padding:"11px 14px"}}>
                <div style={{fontWeight:"700",color:K.text,maxWidth:"220px",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>{r.title}</div>
                {r.summary&&<div style={{fontSize:"10px",color:K.textDim,marginTop:"1px",maxWidth:"220px",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>{r.summary}</div>}
              </td>
              <td style={{padding:"11px 14px",color:K.textMid,fontSize:"11px",whiteSpace:"nowrap"}}>{r.type||"—"}</td>
              <td style={{padding:"11px 14px",whiteSpace:"nowrap"}}><StatusBadge v={r.status} colorMap={INV_STATUS_COLOR}/></td>
              <td style={{padding:"11px 14px",color:K.textMid,fontSize:"11px",whiteSpace:"nowrap"}}>{r.lead_investigator||"—"}</td>
              <td style={{padding:"11px 14px",color:K.textMid,fontSize:"11px",whiteSpace:"nowrap"}}>{fmtDate(r.start_date)}</td>
              <td style={{padding:"11px 14px"}}><ClassBadge v={r.classification}/></td>
              <td style={{padding:"11px 14px"}}><div style={{display:"flex",gap:"4px",flexWrap:"wrap"}}>{(r.tags||[]).map(t=><TagPill key={t} label={t}/>)}</div></td>
              <td style={{padding:"11px 14px",color:isOverdue(r.review_date)?K.red:K.textMid,fontWeight:isOverdue(r.review_date)?"700":"400",fontSize:"11px",whiteSpace:"nowrap"}}>{fmtDate(r.review_date)}{isOverdue(r.review_date)&&" ⚠"}</td>
              <td style={{padding:"11px 14px",whiteSpace:"nowrap"}}><span style={{color:K.blueMid,fontWeight:"700",fontSize:"11px"}}>Open →</span></td>
            </tr>
          ))}
        </tbody>
      </table>
      {filtered.length>0&&<div style={{padding:"8px 14px",background:K.surfaceAlt,fontSize:"11px",color:K.textDim,borderTop:`1px solid ${K.border}`,textAlign:"right"}}>{filtered.length} record{filtered.length!==1?"s":""}</div>}
    </div>
  </div>;
}

function IncList({ records, onNew, onEdit , onDelete }) {
  const [search, setSearch] = useState("");
  const [filterStatus, setFilterStatus] = useState("");
  const [filterPriority, setFilterPriority] = useState("");
  const [filterType, setFilterType] = useState("");

  const filtered = useMemo(()=>records.filter(r=>{
    const q=search.toLowerCase();
    const match=!q||r.title?.toLowerCase().includes(q)||r.urn?.toLowerCase().includes(q)||
      r.notes?.toLowerCase().includes(q)||(r.tags||[]).some(t=>t.toLowerCase().includes(q));
    return match&&(!filterStatus||r.status===filterStatus)&&
      (!filterPriority||r.case_priority===filterPriority)&&(!filterType||r.type===filterType);
  }),[records,search,filterStatus,filterPriority,filterType]);

  return <div>
    <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"20px"}}>
      <div>
        <h2 style={{margin:0,fontSize:"20px",fontWeight:"800",color:K.navy,fontFamily:"'Georgia','Times New Roman',serif"}}>Incident Register</h2>
        <div style={{fontSize:"12px",color:K.textDim,marginTop:"3px"}}>{filtered.length} of {records.length} record{records.length!==1?"s":""}</div>
      </div>
      <Btn variant="primary" onClick={onNew}>+ Add Incident</Btn>
    </div>
    <div style={{display:"flex",gap:"10px",marginBottom:"16px",flexWrap:"wrap"}}>
      <div style={{flex:1,minWidth:"220px"}}><input value={search} onChange={e=>setSearch(e.target.value)} placeholder="Search title, URN, notes, tags…" style={{...inp}}/></div>
      <div style={{width:"160px"}}><Select value={filterType} onChange={setFilterType} options={L.inc_type} placeholder="All Types"/></div>
      <div style={{width:"160px"}}><Select value={filterStatus} onChange={setFilterStatus} options={L.inc_status} placeholder="All Statuses"/></div>
      <div style={{width:"140px"}}><Select value={filterPriority} onChange={setFilterPriority} options={L.priority} placeholder="All Priorities"/></div>
    </div>
    <div style={{border:`1px solid ${K.border}`,borderRadius:"8px",overflow:"hidden",boxShadow:"0 1px 3px rgba(0,0,0,0.06)"}}>
      <table style={{width:"100%",borderCollapse:"collapse",fontSize:"12px"}}>
        <thead><tr style={{background:K.navy}}>
          {["URN","Title","Type","Priority","Status","Date Occurred","Location","Classification","Tags","Review",""].map(h=>(
            <th key={h} style={{padding:"11px 14px",textAlign:"left",fontWeight:"700",fontSize:"10px",color:"rgba(255,255,255,0.7)",letterSpacing:"1px"}}>{h}</th>
          ))}
        </tr></thead>
        <tbody>
          {filtered.length===0&&<tr><td colSpan={11} style={{padding:"32px",textAlign:"center",color:K.textDim}}>No records found.</td></tr>}
          {filtered.map((r,i)=>(
            <tr key={r.id} onClick={()=>onEdit(r)}
              style={{borderBottom:`1px solid ${K.border}`,cursor:"pointer",background:i%2?K.surfaceAlt:K.surface}}
              onMouseEnter={e=>e.currentTarget.style.background=K.blueLight}
              onMouseLeave={e=>e.currentTarget.style.background=i%2?K.surfaceAlt:K.surface}>
              <td style={{padding:"11px 14px",fontFamily:"monospace",fontSize:"11px",color:K.blue,fontWeight:"700",whiteSpace:"nowrap"}}>{r.urn}</td>
              <td style={{padding:"11px 14px"}}>
                <div style={{fontWeight:"700",color:K.text}}>{r.title}</div>
                {r.modes_of_liability&&<div style={{fontSize:"10px",color:K.textDim,marginTop:"1px"}}>⚖ {r.modes_of_liability}</div>}
              </td>
              <td style={{padding:"11px 14px",color:K.textMid,fontSize:"11px",whiteSpace:"nowrap"}}>{r.type||"—"}</td>
              <td style={{padding:"11px 14px",whiteSpace:"nowrap"}}>{r.case_priority&&<PriorityBadge v={r.case_priority}/>}</td>
              <td style={{padding:"11px 14px",whiteSpace:"nowrap"}}>{r.status&&<StatusBadge v={r.status} colorMap={INC_STATUS_COLOR}/>}</td>
              <td style={{padding:"11px 14px",color:K.textMid,fontSize:"11px",whiteSpace:"nowrap"}}>{fmtDate(r.date_occurred)}</td>
              <td style={{padding:"11px 14px",color:K.textMid,fontSize:"11px",maxWidth:"140px",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>{r.location_text||"—"}</td>
              <td style={{padding:"11px 14px"}}><ClassBadge v={r.classification}/></td>
              <td style={{padding:"11px 14px"}}><div style={{display:"flex",gap:"4px",flexWrap:"wrap"}}>{(r.tags||[]).map(t=><TagPill key={t} label={t}/>)}</div></td>
              <td style={{padding:"11px 14px",color:isOverdue(r.review_date)?K.red:K.textMid,fontWeight:isOverdue(r.review_date)?"700":"400",fontSize:"11px",whiteSpace:"nowrap"}}>{fmtDate(r.review_date)}{isOverdue(r.review_date)&&" ⚠"}</td>
              <td style={{padding:"11px 14px",whiteSpace:"nowrap"}}><span style={{color:K.blueMid,fontWeight:"700",fontSize:"11px"}}>Open →</span></td>
            </tr>
          ))}
        </tbody>
      </table>
      {filtered.length>0&&<div style={{padding:"8px 14px",background:K.surfaceAlt,fontSize:"11px",color:K.textDim,borderTop:`1px solid ${K.border}`,textAlign:"right"}}>{filtered.length} record{filtered.length!==1?"s":""}</div>}
    </div>
  </div>;
}

// ══════════════════════════════════════════════════════════════════



// ─── GENERIC REGISTER LIST ───────────────────────────────────────────────────
function RegisterList({ label, icon, records, onNew, onEdit, onDelete, onDuplicate, perms={},
  searchFields=["title","urn","description","type","status"], emptyMsg="" }) {
  const [search, setSearch] = React.useState("");
  const [filterType, setFilterType] = React.useState("");
  const [filterStatus, setFilterStatus] = React.useState("");
  const types    = [...new Set((records||[]).map(r=>r.type).filter(Boolean))].sort();
  const statuses = [...new Set((records||[]).map(r=>r.status).filter(Boolean))].sort();
  const filtered = React.useMemo(() => {
    const q = search.toLowerCase();
    return (records||[]).filter(r => {
      const matchSearch = !q || searchFields.some(f=>String(r[f]||"").toLowerCase().includes(q))||
        (r.tags||[]).some(t=>t.toLowerCase().includes(q));
      return matchSearch&&(!filterType||r.type===filterType)&&(!filterStatus||r.status===filterStatus);
    });
  }, [records, search, filterType, filterStatus]);
  return (
    <div>
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"20px"}}>
        <div>
          <h1 style={{margin:0,fontSize:"22px",fontWeight:"800",color:K.navy,fontFamily:"Georgia,serif"}}>{icon} {label} Register</h1>
          <div style={{fontSize:"12px",color:K.textDim,marginTop:"3px"}}>{filtered.length} of {(records||[]).length} record{(records||[]).length!==1?"s":""}</div>
        </div>
        {perms.canCreate && <Btn variant="primary" onClick={onNew}>+ New {label}</Btn>}
      </div>
      <div style={{display:"flex",gap:"10px",marginBottom:"16px",flexWrap:"wrap"}}>
        <input value={search} onChange={e=>setSearch(e.target.value)}
          placeholder={"Search "+label.toLowerCase()+"..."}
          style={{padding:"7px 11px",border:"1px solid "+K.border,borderRadius:"4px",fontSize:"12px",
            color:K.text,background:K.surface,outline:"none",fontFamily:"inherit",width:"220px"}}/>
        {types.length>0&&<Select value={filterType} onChange={setFilterType} options={types} placeholder="All Types"/>}
        {statuses.length>0&&<Select value={filterStatus} onChange={setFilterStatus} options={statuses} placeholder="All Statuses"/>}
        {(search||filterType||filterStatus)&&<Btn small onClick={()=>{setSearch("");setFilterType("");setFilterStatus("");}}>Clear</Btn>}
      </div>
      {filtered.length===0?(
        <div style={{background:K.surface,border:"1px solid "+K.border,borderRadius:"8px",padding:"60px",textAlign:"center"}}>
          <div style={{fontSize:"36px",marginBottom:"12px"}}>{icon}</div>
          <div style={{fontSize:"14px",color:K.textDim}}>{search||filterType||filterStatus?"No records match your filters.":(emptyMsg||"No "+label.toLowerCase()+" records yet.")}</div>
          {perms.canCreate&&!search&&!filterType&&!filterStatus&&<div style={{marginTop:"16px"}}><Btn variant="primary" onClick={onNew}>+ Add First {label}</Btn></div>}
        </div>
      ):(
        <div style={{background:K.surface,border:"1px solid "+K.border,borderRadius:"8px",overflow:"hidden"}}>
          <table style={{width:"100%",borderCollapse:"collapse",fontSize:"12px"}}>
            <thead><tr style={{background:K.surfaceAlt}}>
              {["URN","Title / Name","Type","Status","Classification",""].map(h=>(
                <th key={h} style={{padding:"10px 14px",textAlign:"left",fontSize:"10px",fontWeight:"800",
                  color:K.textMid,letterSpacing:"1px",borderBottom:"1px solid "+K.border,whiteSpace:"nowrap"}}>{h}</th>
              ))}
            </tr></thead>
            <tbody>
              {filtered.map((r,i)=>(
                <tr key={r.id||i} style={{borderBottom:"1px solid "+K.border,
                  background:i%2?K.surfaceAlt:K.surface,cursor:"pointer"}}
                  onClick={()=>onEdit(r)}
                  onMouseEnter={e=>e.currentTarget.style.background=K.blueLight}
                  onMouseLeave={e=>e.currentTarget.style.background=i%2?K.surfaceAlt:K.surface}>
                  <td style={{padding:"10px 14px",fontFamily:"monospace",fontSize:"11px",color:K.blue,fontWeight:"700",whiteSpace:"nowrap"}}>{r.urn||"—"}</td>
                  <td style={{padding:"10px 14px"}}>
                    <div style={{fontWeight:"700",color:K.text}}>{r.title||r.name||[r.forenames,r.surname].filter(Boolean).join(" ")||r.number_address||"—"}</div>
                    {(r.date_of_occurrence||r.date_taken)&&<div style={{fontSize:"10px",color:K.textDim}}>{r.date_of_occurrence||r.date_taken}</div>}
                    {r.tags&&r.tags.length>0&&<div style={{marginTop:"3px",display:"flex",gap:"4px",flexWrap:"wrap"}}>{r.tags.slice(0,3).map(t=><span key={t} style={{padding:"1px 6px",background:K.blueLight,color:K.blue,borderRadius:"3px",fontSize:"10px"}}>{t}</span>)}</div>}
                  </td>
                  <td style={{padding:"10px 14px",color:K.textMid,whiteSpace:"nowrap"}}>{r.type||"—"}</td>
                  <td style={{padding:"10px 14px"}}>{r.status&&<span style={{padding:"2px 8px",borderRadius:"10px",fontSize:"11px",fontWeight:"700",background:K.surfaceAlt,color:K.textMid}}>{r.status}</span>}</td>
                  <td style={{padding:"10px 14px"}}><ClassBadge v={r.classification}/></td>
                  <td style={{padding:"10px 14px",whiteSpace:"nowrap",display:"flex",gap:"6px"}}>
                  <Btn small onClick={e=>{e.stopPropagation();onEdit(r);}}>Open</Btn>
                  {onDuplicate && !r._redacted && <Btn small onClick={e=>{e.stopPropagation();onDuplicate(r);}}>⧉</Btn>}
                  {onDelete && !r._redacted && <Btn small variant="danger" onClick={e=>{e.stopPropagation();onDelete(r);}}>Delete</Btn>}
                </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}
function StatementList({records,onNew,onEdit,perms={},onDelete,onDuplicate}) {
  return <RegisterList label="Statement" icon="📋" records={records} onNew={onNew} onEdit={onEdit} onDelete={onDelete} onDuplicate={onDuplicate} perms={perms} searchFields={["title","urn","given_by_name","type"]} emptyMsg="No statements recorded."/>;
}
function SourceList({records,onNew,onEdit,perms={},onDelete,onDuplicate}) {
  return <RegisterList label="Source" icon="🔒" records={records} onNew={onNew} onEdit={onEdit} onDelete={onDelete} onDuplicate={onDuplicate} perms={perms} searchFields={["urn","reference","type","category","handler_reference"]} emptyMsg="No sources recorded."/>;
}
function AddressList({records,onNew,onEdit,perms={},onDelete,onDuplicate}) {
  return <RegisterList label="Address" icon="📍" records={records} onNew={onNew} onEdit={onEdit} onDelete={onDelete} onDuplicate={onDuplicate} perms={perms} searchFields={["urn","address_line1","city","country","type"]} emptyMsg="No addresses recorded."/>;
}
function AssessmentList({records,onNew,onEdit,perms={},onDelete,onDuplicate}) {
  return <RegisterList label="Assessment" icon="📊" records={records} onNew={onNew} onEdit={onEdit} onDelete={onDelete} onDuplicate={onDuplicate} perms={perms} searchFields={["urn","title","type","assessed_by"]} emptyMsg="No assessments recorded."/>;
}
function CaseList({records,onNew,onEdit,perms={},onDelete,onDuplicate}) {
  return <RegisterList label="Case" icon="⚖" records={records} onNew={onNew} onEdit={onEdit} onDelete={onDelete} onDuplicate={onDuplicate} perms={perms} searchFields={["urn","title","type","lead_investigator"]} emptyMsg="No cases recorded."/>;
}
function DecisionList({records,onNew,onEdit,perms={},onDelete,onDuplicate}) {
  return <RegisterList label="Decision" icon="✔" records={records} onNew={onNew} onEdit={onEdit} onDelete={onDelete} onDuplicate={onDuplicate} perms={perms} searchFields={["urn","title","type","decided_by"]} emptyMsg="No decisions recorded."/>;
}
function OutcomeList({records,onNew,onEdit,perms={},onDelete,onDuplicate}) {
  return <RegisterList label="Outcome" icon="🏁" records={records} onNew={onNew} onEdit={onEdit} onDelete={onDelete} onDuplicate={onDuplicate} perms={perms} searchFields={["urn","title","type","jurisdiction"]} emptyMsg="No outcomes recorded."/>;
}
function StaffList({records,onNew,onEdit,perms={},onDelete,onDuplicate}) {
  return <RegisterList label="Staff" icon="👥" records={records} onNew={onNew} onEdit={onEdit} onDelete={onDelete} onDuplicate={onDuplicate} perms={perms} searchFields={["urn","surname","forenames","role","department"]} emptyMsg="No staff records."/>;
}
function EquipmentList({records,onNew,onEdit,perms={},onDelete,onDuplicate}) {
  return <RegisterList label="Equipment" icon="🔧" records={records} onNew={onNew} onEdit={onEdit} onDelete={onDelete} onDuplicate={onDuplicate} perms={perms} searchFields={["urn","make","model","registration","serial_number"]} emptyMsg="No equipment records."/>;
}
function StubList({label,records,onNew,onEdit}){return(<div><h2 style={{color:K.navy}}>{label}</h2>{records.map(r=><div key={r.id} onClick={()=>onEdit(r)} style={{padding:10,border:`1px solid ${K.border}`,borderRadius:4,marginBottom:6,cursor:"pointer"}}>{r.urn||r.id}</div>)}<button onClick={onNew} style={{marginTop:8,padding:"8px 16px",background:K.blue,color:"#fff",border:"none",borderRadius:4,cursor:"pointer"}}>+</button></div>);}
function ProducedExhibits({ exhibits, setExhibits }) {
  const [adding, setAdding] = useState(false);
  const [form, setForm] = useState({ exhibit_ref:"", description:"" });
  const sf = k => v => setForm(p=>({...p,[k]:v}));
  const add = () => {
    if(!(form.exhibit_ref||"").trim()&&!(form.description||"").trim()) return;
    setExhibits([...exhibits,{...form,id:Date.now()}]);
    setForm({exhibit_ref:"",description:""});
    setAdding(false);
  };
  return <div>
    <SectionHeader title="Produced Exhibits" action="Add Exhibit" onAction={()=>setAdding(true)}/>
    <p style={{fontSize:"11px",color:K.textDim,marginTop:"-10px",marginBottom:"12px"}}>
      Physical items or documents produced by the witness during the taking of this statement.
    </p>
    {adding&&<div style={{background:K.surfaceAlt,border:`1px solid ${K.border}`,borderRadius:"6px",padding:"16px",marginBottom:"14px"}}>
      <div style={{display:"grid",gridTemplateColumns:"150px 1fr",gap:"12px",marginBottom:"8px"}}>
        <Field label="Exhibit Reference" required>
          <Input value={form.exhibit_ref} onChange={sf("exhibit_ref")} placeholder="e.g. MF/1"/>
        </Field>
        <Field label="Description">
          <Input value={form.description} onChange={sf("description")} placeholder="Brief description of the exhibit…"/>
        </Field>
      </div>
      <div style={{display:"flex",gap:"8px"}}><Btn variant="primary" small onClick={add}>Add</Btn><Btn small onClick={()=>setAdding(false)}>Cancel</Btn></div>
    </div>}
    {exhibits.length===0&&!adding&&<p style={{fontSize:"12px",color:K.textDim,margin:"8px 0"}}>No exhibits produced.</p>}
    {exhibits.length>0&&<div style={{border:`1px solid ${K.border}`,borderRadius:"6px",overflow:"hidden"}}>
      <table style={{width:"100%",borderCollapse:"collapse",fontSize:"12px"}}>
        <thead><tr style={{background:K.surfaceAlt}}>
          {["Exhibit Ref","Description",""].map(h=>(
            <th key={h} style={{padding:"8px 12px",textAlign:"left",fontWeight:"700",fontSize:"10px",color:K.textMid,letterSpacing:"0.8px",borderBottom:`1px solid ${K.border}`}}>{h}</th>
          ))}
        </tr></thead>
        <tbody>{exhibits.map((e,i)=>(
          <tr key={e.id} style={{borderBottom:`1px solid ${K.border}`,background:i%2?K.surfaceAlt:K.surface}}>
            <td style={{padding:"9px 12px",fontWeight:"800",color:K.blue,fontFamily:"monospace",whiteSpace:"nowrap"}}>{e.exhibit_ref}</td>
            <td style={{padding:"9px 12px"}}>{e.description}</td>
            <td style={{padding:"9px 12px"}}><button onClick={()=>setExhibits(exhibits.filter(x=>x.id!==e.id))} style={{background:"none",border:"none",color:K.textDim,cursor:"pointer",fontSize:"11px"}}>Remove</button></td>
          </tr>
        ))}</tbody>
      </table>
    </div>}
  </div>;
}

// ─── REFERENCED MATERIAL ──────────────────────────────────────────────────────
function ReferencedMaterial({ refs, setRefs }) {
  const [adding, setAdding] = useState(false);
  const [form, setForm] = useState({ material_urn:"", description:"" });
  const sf = k => v => setForm(p=>({...p,[k]:v}));
  const add = () => {
    if(!(form.material_urn||"").trim()&&!(form.description||"").trim()) return;
    setRefs([...refs,{...form,id:Date.now()}]);
    setForm({material_urn:"",description:""});
    setAdding(false);
  };
  return <div>
    <SectionHeader title="Referenced Material" action="Add Reference" onAction={()=>setAdding(true)}/>
    <p style={{fontSize:"11px",color:K.textDim,marginTop:"-10px",marginBottom:"12px"}}>
      Material records from the KOIOS Material register referenced within this statement.
    </p>
    {adding&&<div style={{background:K.surfaceAlt,border:`1px solid ${K.border}`,borderRadius:"6px",padding:"16px",marginBottom:"14px"}}>
      <div style={{display:"grid",gridTemplateColumns:"200px 1fr",gap:"12px",marginBottom:"8px"}}>
        <Field label="Material URN">
          <Input value={form.material_urn} onChange={sf("material_urn")} placeholder="e.g. AW-MAT-0001"/>
        </Field>
        <Field label="Context / Description">
          <Input value={form.description} onChange={sf("description")} placeholder="Where and how it is referenced in the statement…"/>
        </Field>
      </div>
      <div style={{display:"flex",gap:"8px"}}><Btn variant="primary" small onClick={add}>Add</Btn><Btn small onClick={()=>setAdding(false)}>Cancel</Btn></div>
    </div>}
    {refs.length===0&&!adding&&<p style={{fontSize:"12px",color:K.textDim,margin:"8px 0"}}>No material referenced.</p>}
    {refs.length>0&&<div style={{border:`1px solid ${K.border}`,borderRadius:"6px",overflow:"hidden"}}>
      <table style={{width:"100%",borderCollapse:"collapse",fontSize:"12px"}}>
        <thead><tr style={{background:K.surfaceAlt}}>
          {["Material URN","Context / Description",""].map(h=>(
            <th key={h} style={{padding:"8px 12px",textAlign:"left",fontWeight:"700",fontSize:"10px",color:K.textMid,letterSpacing:"0.8px",borderBottom:`1px solid ${K.border}`}}>{h}</th>
          ))}
        </tr></thead>
        <tbody>{refs.map((r,i)=>(
          <tr key={r.id} style={{borderBottom:`1px solid ${K.border}`,background:i%2?K.surfaceAlt:K.surface}}>
            <td style={{padding:"9px 12px",fontWeight:"700",color:K.blue,fontFamily:"monospace",whiteSpace:"nowrap"}}>{r.material_urn}</td>
            <td style={{padding:"9px 12px",color:K.textMid}}>{r.description}</td>
            <td style={{padding:"9px 12px"}}><button onClick={()=>setRefs(refs.filter(x=>x.id!==r.id))} style={{background:"none",border:"none",color:K.textDim,cursor:"pointer",fontSize:"11px"}}>Remove</button></td>
          </tr>
        ))}</tbody>
      </table>
    </div>}
  </div>;
}

// ─── SHARED SECTIONS ──────────────────────────────────────────────────────────
function AliasesSection({ aliases, setAliases }) {
  const [adding, setAdding] = useState(false);
  const [form, setForm] = useState({ alias:"", type:"Alias" });
  const sf = k => v => setForm(p=>({...p,[k]:v}));
  const aliasTypes = ["Codename","True Name","Alias","Maiden Name","Former Name","Nickname","Other"];
  const add = () => {
    if(!(form.alias||"").trim()) return;
    setAliases([...aliases,{...form,id:Date.now()}]);
    setForm({alias:"",type:"Alias"});
    setAdding(false);
  };
  return <div>
    <SectionHeader title="Other Names / Aliases" action="Add Name" onAction={()=>setAdding(true)}/>
    {adding&&<div style={{background:K.surfaceAlt,border:`1px solid ${K.border}`,borderRadius:"6px",padding:"16px",marginBottom:"14px"}}>
      <div style={{display:"grid",gridTemplateColumns:"1fr 160px",gap:"12px",marginBottom:"8px"}}>
        <Field label="Name / Alias"><Input value={form.alias} onChange={sf("alias")} placeholder="e.g. SPARROW-2 or [REDACTED]"/></Field>
        <Field label="Type"><Select value={form.type} onChange={sf("type")} options={aliasTypes}/></Field>
      </div>
      <div style={{display:"flex",gap:"8px"}}><Btn variant="primary" small onClick={add}>Add</Btn><Btn small onClick={()=>setAdding(false)}>Cancel</Btn></div>
    </div>}
    {aliases.length===0&&!adding&&<p style={{fontSize:"12px",color:K.textDim,margin:"8px 0"}}>No other names recorded.</p>}
    {aliases.length>0&&<div style={{border:`1px solid ${K.border}`,borderRadius:"6px",overflow:"hidden"}}>
      <table style={{width:"100%",borderCollapse:"collapse",fontSize:"12px"}}>
        <thead><tr style={{background:K.surfaceAlt}}>
          {["Name / Alias","Type",""].map(h=>(
            <th key={h} style={{padding:"8px 12px",textAlign:"left",fontWeight:"700",fontSize:"10px",color:K.textMid,letterSpacing:"0.8px",borderBottom:`1px solid ${K.border}`}}>{h}</th>
          ))}
        </tr></thead>
        <tbody>{aliases.map((a,i)=>(
          <tr key={a.id} style={{borderBottom:`1px solid ${K.border}`,background:i%2?K.surfaceAlt:K.surface}}>
            <td style={{padding:"9px 12px",fontWeight:"700",color:a.alias==="[REDACTED]"?K.textDim:K.text,fontStyle:a.alias==="[REDACTED]"?"italic":"normal"}}>{a.alias}</td>
            <td style={{padding:"9px 12px"}}><span style={{padding:"2px 8px",background:K.blueLight,color:K.blue,borderRadius:"3px",fontSize:"11px",fontWeight:"600"}}>{a.type}</span></td>
            <td style={{padding:"9px 12px"}}><button onClick={()=>setAliases(aliases.filter(x=>x.id!==a.id))} style={{background:"none",border:"none",color:K.textDim,cursor:"pointer",fontSize:"11px"}}>Remove</button></td>
          </tr>
        ))}</tbody>
      </table>
    </div>}
  </div>;
}

// ─── RECORD OF CONTACT ────────────────────────────────────────────────────────
function RecordOfContact({ contacts, setContacts }) {
  const [adding, setAdding] = useState(false);
  const [form, setForm] = useState({ date:"", method:"In Person", location:"", officer:"", summary:"", duration:"" });
  const sf = k => v => setForm(p=>({...p,[k]:v}));
  const add = () => {
    if(!form.date&&!form.summary) return;
    setContacts([...contacts,{...form,id:Date.now()}]);
    setForm({date:"",method:"In Person",location:"",officer:"",summary:"",duration:""});
    setAdding(false);
  };
  return <div>
    <SectionHeader title="Record of Contact" action="Add Contact" onAction={()=>setAdding(true)} warning/>
    <p style={{fontSize:"11px",color:K.textDim,marginTop:"-10px",marginBottom:"12px"}}>
      Every contact with this source must be recorded here. This section is treated as immutable once saved.
    </p>
    {adding&&<div style={{background:"#fef9f9",border:`1px solid ${K.red}33`,borderRadius:"6px",padding:"16px",marginBottom:"14px"}}>
      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:"12px",marginBottom:"12px"}}>
        <Field label="Date" required><Input type="date" value={form.date} onChange={sf("date")}/></Field>
        <Field label="Method"><Select value={form.method} onChange={sf("method")} options={L.contact_method}/></Field>
        <Field label="Duration"><Input value={form.duration} onChange={sf("duration")} placeholder="e.g. 90 mins"/></Field>
      </div>
      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"12px",marginBottom:"12px"}}>
        <Field label="Location"><Input value={form.location} onChange={sf("location")} placeholder="Undisclosed / location name"/></Field>
        <Field label="Officer"><Input value={form.officer} onChange={sf("officer")} placeholder="Handler name"/></Field>
      </div>
      <Field label="Summary" required><Textarea value={form.summary} onChange={sf("summary")} rows={3} placeholder="Summary of information obtained and any tasking…"/></Field>
      <div style={{display:"flex",gap:"8px"}}><Btn variant="primary" small onClick={add}>Save Contact Record</Btn><Btn small onClick={()=>setAdding(false)}>Cancel</Btn></div>
    </div>}
    {contacts.length===0&&!adding&&<p style={{fontSize:"12px",color:K.textDim,margin:"8px 0"}}>No contacts recorded.</p>}
    {contacts.length>0&&contacts.map((c,i)=>(
      <div key={c.id} style={{border:`1px solid ${K.border}`,borderRadius:"6px",marginBottom:"10px",overflow:"hidden"}}>
        <div style={{padding:"10px 14px",background:K.surfaceAlt,display:"flex",justifyContent:"space-between",alignItems:"center",borderBottom:`1px solid ${K.border}`}}>
          <div style={{display:"flex",alignItems:"center",gap:"12px"}}>
            <span style={{fontWeight:"700",color:K.navy,fontSize:"12px"}}>{fmtDate(c.date)}</span>
            <span style={{padding:"2px 8px",background:K.blueLight,color:K.blue,borderRadius:"3px",fontSize:"11px",fontWeight:"600"}}>{c.method}</span>
            {c.location&&<span style={{fontSize:"11px",color:K.textMid}}>📍 {c.location}</span>}
            {c.duration&&<span style={{fontSize:"11px",color:K.textDim}}>⏱ {c.duration}</span>}
            {c.officer&&<span style={{fontSize:"11px",color:K.textMid}}>👤 {c.officer}</span>}
          </div>
          <button onClick={()=>setContacts(contacts.filter(x=>x.id!==c.id))} style={{background:"none",border:"none",color:K.textDim,cursor:"pointer",fontSize:"11px"}}>Remove</button>
        </div>
        <div style={{padding:"10px 14px",fontSize:"12px",color:K.textMid,lineHeight:"1.6"}}>{c.summary}</div>
      </div>
    ))}
  </div>;
}

// ─── SHARED SECTIONS ──────────────────────────────────────────────────────────
function StatementForm({ record, onSave, onCancel }) {
  const isNew = !record?.id;
  const [f, setF] = useState(record || {
    classification:"CONFIDENTIAL",
    tags:[], tasks:[], inv_notes:[], files:[], links:[],
    produced_exhibits:[], referenced_material:[],
  });
  const s = k => v => setF(p=>({...p,[k]:v}));

  // Auto-generate title preview
  const autoTitle = (f) => {
    const name = f.given_by_name?.trim();
    const date = f.date_taken;
    if (!name && !date) return "";
    const parts = ["Statement given by"];
    if (name) parts.push(name);
    if (date) parts.push(`on ${new Date(date).toLocaleDateString("en-GB",{day:"2-digit",month:"long",year:"numeric"})}`);
    return parts.join(" ");
  };
  const generatedTitle = autoTitle(f);
  const displayTitle = f.title || generatedTitle;

  const handleSave = () => {
    if(!f.date_taken){alert("Date Taken is required.");return;}
    // Auto-fill title if blank
    const saved = {
      ...f,
      title: f.title?.trim() || generatedTitle,
      id:f.id||Date.now(),
      urn:f.urn||makeURN(),
    };
    onSave(saved);
  };

  const typeIcon = TYPE_ICON[f.type] || "📋";

  return (
    <div style={{maxWidth:"900px",margin:"0 auto"}}>

      {/* Header */}
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",
        marginBottom:"24px",paddingBottom:"18px",borderBottom:`1px solid ${K.border}`}}>
        <div>
          <div style={{fontSize:"11px",fontWeight:"700",color:K.textDim,letterSpacing:"2px",
            textTransform:"uppercase",marginBottom:"4px",display:"flex",alignItems:"center",gap:"10px"}}>
            <span>STATEMENT REGISTER</span>
            {!isNew&&<span style={{fontFamily:"monospace",color:K.blue,fontWeight:"800"}}>{f.urn}</span>}
            {f.statement_number&&<span style={{padding:"2px 10px",background:K.blueLight,color:K.blue,
              borderRadius:"3px",fontFamily:"monospace",fontWeight:"800",fontSize:"11px"}}>{f.statement_number}</span>}
          </div>
          <h1 style={{margin:0,fontSize:"20px",fontWeight:"800",color:K.navy,
            fontFamily:"'Georgia','Times New Roman',serif",display:"flex",alignItems:"center",gap:"10px"}}>
            <span style={{fontSize:"20px"}}>{typeIcon}</span>
            {isNew?"Add New Statement":displayTitle||"Untitled Statement"}
          </h1>
          {!isNew&&f.type&&<div style={{marginTop:"4px",fontSize:"12px",color:K.textMid}}>
            {f.type}
            {f.given_by_name&&<span style={{marginLeft:"8px",color:K.textDim}}>· Given by <strong style={{color:K.text}}>{f.given_by_name}</strong></span>}
          </div>}
        </div>
        <div style={{display:"flex",flexDirection:"column",alignItems:"flex-end",gap:"8px"}}>
          <div style={{display:"flex",alignItems:"center",gap:"8px"}}>
            <span style={{fontSize:"11px",color:K.textMid,fontWeight:"600"}}>Classification</span>
            <select value={f.classification} onChange={e=>s("classification")(e.target.value)}
              style={{padding:"5px 9px",border:`1px solid ${K.border}`,borderRadius:"4px",
                fontSize:"11px",fontWeight:"800",color:K.blue,fontFamily:"monospace",background:K.surface,cursor:"pointer"}}>
              {L.class_lvl.map(c=><option key={c} value={c}>{c}</option>)}
            </select>
          </div>
          <ClassBadge v={f.classification}/>
        </div>
      </div>

      <TagsInput tags={f.tags||[]} setTags={s("tags")}/>

      {/* ── DETAILS ── */}
      <SectionHeader title="Details"/>

      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"16px"}}>
        <Field label="Type">
          <Select value={f.type} onChange={s("type")} options={L.stmt_type}/>
        </Field>
        <Field label="Statement Number" hint="e.g. WS-2025-029">
          <Input value={f.statement_number} onChange={s("statement_number")} placeholder="WS-YYYY-NNN"/>
        </Field>
      </div>

      {/* Title with auto-generate hint */}
      <Field label="Title" hint="leave blank to auto-generate from name and date">
        <Input value={f.title} onChange={s("title")} placeholder={generatedTitle||"e.g. Statement given by John SMITH on 01 January 2026"}/>
        {!f.title && generatedTitle && (
          <div style={{marginTop:"5px",fontSize:"11px",color:K.textDim}}>
            Will be saved as: <em style={{color:K.textMid}}>{generatedTitle}</em>
          </div>
        )}
      </Field>

      <Field label="Description" hint="brief summary of content">
        <Textarea value={f.description} onChange={s("description")} rows={3}
          placeholder="Brief description of what this statement covers…"/>
      </Field>

      {/* ── TAKING DETAILS ── */}
      <SectionHeader title="Taking Details"/>

      <Field label="Given By" required hint="name of the person who gave this statement">
        <Input value={f.given_by_name} onChange={v=>s("given_by_name")(v.toUpperCase())}
          placeholder="FULL NAME — link to Person register via Universal Links"/>
      </Field>

      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:"14px"}}>
        <Field label="Date Taken" required>
          <Input type="date" value={f.date_taken} onChange={s("date_taken")}/>
        </Field>
        <Field label="Time Taken">
          <Input type="time" value={f.time_taken} onChange={s("time_taken")}/>
        </Field>
        <Field label="Taken By" hint="officer who took the statement">
          <Input value={f.taken_by_name} onChange={s("taken_by_name")} placeholder="Officer name"/>
        </Field>
      </div>

      <Field label="Where Taken">
        <Input value={f.where_taken} onChange={s("where_taken")}
          placeholder="e.g. Secure Interview Room, London — link to Address register via Universal Links"/>
      </Field>

      {/* Review */}
      <div style={{display:"grid",gridTemplateColumns:"200px auto 160px",gap:"12px",alignItems:"end",marginBottom:"20px"}}>
        <Field label="Review After (Period)">
          <Select value={f.review_period} onChange={s("review_period")} options={L.review_per}/>
        </Field>
        <div style={{paddingBottom:"1px",color:K.textMid,fontSize:"12px",paddingTop:"32px"}}>on date</div>
        <Field label="Review Date">
          <Input type="date" value={f.review_date} onChange={s("review_date")}/>
        </Field>
      </div>

      <RecordProps record={f}/>

      {/* Save bar */}
      <div style={{borderTop:`1px solid ${K.border}`,paddingTop:"16px",marginBottom:"8px",
        display:"flex",gap:"10px",alignItems:"center",flexWrap:"wrap"}}>
        <Btn variant="primary" onClick={handleSave}>Save Record</Btn>
        <Btn onClick={()=>{const saved={...f,title:f.title?.trim()||generatedTitle,id:f.id||Date.now(),urn:f.urn||makeURN()};onSave(saved);}}>Save & Continue</Btn>
        <Btn onClick={onCancel}>Cancel</Btn>
        {!isNew&&<>
          <div style={{flex:1}}/>
          <span style={{fontSize:"11px",color:K.textDim}}>Export:</span>
          <Btn small onClick={()=>alert("i2 ANB export")}>i2 ANB</Btn>
          <Btn small variant="primary" onClick={()=>alert("PDF report")}>PDF</Btn>
        </>}
      </div>

      <ProducedExhibits exhibits={f.produced_exhibits||[]} setExhibits={s("produced_exhibits")}/>
      <ReferencedMaterial refs={f.referenced_material||[]} setRefs={s("referenced_material")}/>
      <TasksSection tasks={f.tasks||[]} setTasks={s("tasks")}/>
      <NotesSection notes={f.inv_notes||[]} setNotes={s("inv_notes")}/>
      <FilesSection files={f.files||[]} setFiles={s("files")}/>
      <LinksSection links={f.links||[]} setLinks={s("links")}/>
    </div>
  );
}

function SourceForm({ record, onSave, onCancel }) {
  const isNew = !record?.id;
  const [f, setF] = useState(record || {
    classification:"SECRET",
    tags:[], tasks:[], inv_notes:[], files:[], links:[],
    aliases:[], record_of_contact:[],
    deceased:false,
  });
  const s = k => v => setF(p=>({...p,[k]:v}));
  const age = calcAge(f.dob);

  const handleSave = () => {
    if(!f.type){alert("Type is required.");return;}
    if(!f.category){alert("Category is required.");return;}
    onSave({...f, id:f.id||Date.now(), urn:f.urn||makeURN()});
  };

  const displayName = [f.title, f.forenames, f.surname].filter(Boolean).join(" ") || f.reference || "New Source";

  return (
    <div style={{maxWidth:"900px",margin:"0 auto"}}>

      {/* Security warning banner */}
      <div style={{background:K.redLight,border:`1px solid ${K.red}44`,borderRadius:"6px",
        padding:"10px 16px",marginBottom:"20px",display:"flex",alignItems:"center",gap:"10px"}}>
        <span style={{fontSize:"18px"}}>🔒</span>
        <div style={{fontSize:"12px",color:K.red}}>
          <strong>Sensitive Record.</strong> Source records contain information that could identify confidential informants.
          Access is logged. Handle in accordance with your source protection policy.
        </div>
      </div>

      {/* Header */}
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",
        marginBottom:"24px",paddingBottom:"18px",borderBottom:`1px solid ${K.border}`}}>
        <div>
          <div style={{fontSize:"11px",fontWeight:"700",color:K.textDim,letterSpacing:"2px",
            textTransform:"uppercase",marginBottom:"4px",display:"flex",alignItems:"center",gap:"10px"}}>
            <span>SOURCE REGISTER</span>
            {!isNew&&<span style={{fontFamily:"monospace",color:K.blue,fontWeight:"800"}}>{f.urn}</span>}
            {f.reference&&<span style={{padding:"2px 10px",background:K.redLight,color:K.red,
              borderRadius:"3px",fontFamily:"monospace",fontWeight:"800",fontSize:"11px",border:`1px solid ${K.red}44`}}>{f.reference}</span>}
          </div>
          <h1 style={{margin:0,fontSize:"22px",fontWeight:"800",color:K.navy,fontFamily:"'Georgia','Times New Roman',serif"}}>
            {isNew?"Add New Source":displayName}
          </h1>
          {!isNew&&<div style={{marginTop:"8px",display:"flex",alignItems:"center",gap:"10px",flexWrap:"wrap"}}>
            {f.type&&<span style={{fontSize:"12px",color:K.textMid}}>{f.type}</span>}
            {f.category&&<CatBadge v={f.category}/>}
          </div>}
        </div>
        <div style={{display:"flex",flexDirection:"column",alignItems:"flex-end",gap:"8px"}}>
          <div style={{display:"flex",alignItems:"center",gap:"8px"}}>
            <span style={{fontSize:"11px",color:K.textMid,fontWeight:"600"}}>Classification</span>
            <select value={f.classification} onChange={e=>s("classification")(e.target.value)}
              style={{padding:"5px 9px",border:`1px solid ${K.border}`,borderRadius:"4px",
                fontSize:"11px",fontWeight:"800",color:K.red,fontFamily:"monospace",background:K.surface,cursor:"pointer"}}>
              {L.class_lvl.map(c=><option key={c} value={c}>{c}</option>)}
            </select>
          </div>
          <ClassBadge v={f.classification}/>
        </div>
      </div>

      <TagsInput tags={f.tags||[]} setTags={s("tags")}/>

      {/* ── SOURCE CLASSIFICATION ── */}
      <SectionHeader title="Source Classification"/>

      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"16px"}}>
        <Field label="Type" required>
          <Select value={f.type} onChange={s("type")} options={L.source_type}/>
        </Field>
        <Field label="Category" required>
          <select value={f.category||""} onChange={e=>s("category")(e.target.value)}
            style={{...inp,
              color:CAT_COLOR[f.category]?.fg||K.textDim,
              background:CAT_COLOR[f.category]?.bg||K.surface,
              borderColor:CAT_COLOR[f.category]?.border||K.border,
              fontWeight:f.category?"700":"400"}}>
            <option value="" style={{color:K.text,background:K.surface,fontWeight:"400"}}>Select…</option>
            {L.source_category.map(o=><option key={o} value={o} style={{color:K.text,background:K.surface,fontWeight:"400"}}>{o}</option>)}
          </select>
        </Field>
      </div>

      <Field label="Handler Reference / Codename" hint="e.g. SPARROW-2, SRC-001">
        <Input value={f.reference} onChange={s("reference")} placeholder="Handler-assigned code or codename"/>
      </Field>

      {/* ── PERSONAL DETAILS ── */}
      <SectionHeader title="Personal Details" />

      <div style={{display:"grid",gridTemplateColumns:"100px 1fr 1fr",gap:"12px"}}>
        <Field label="Title">
          <Select value={f.title} onChange={s("title")} options={L.title}/>
        </Field>
        <Field label="Surname" hint="use [REDACTED] if identity protected">
          <div style={{display:"flex",gap:"8px"}}>
            <Input value={f.surname} onChange={v=>s("surname")(v.toUpperCase())}
              placeholder="SURNAME or [REDACTED]"/>
            <button onClick={()=>s("surname")("[REDACTED]")}
              style={{padding:"8px 12px",background:K.amberLight,border:`1px solid ${K.amber}44`,
                borderRadius:"4px",color:K.amber,fontSize:"11px",fontWeight:"700",
                cursor:"pointer",fontFamily:"inherit",whiteSpace:"nowrap"}}>
              Redact
            </button>
          </div>
        </Field>
        <Field label="Forename(s)" hint="codename acceptable">
          <Input value={f.forenames} onChange={s("forenames")} placeholder="Given names or codename"/>
        </Field>
      </div>

      <div style={{display:"grid",gridTemplateColumns:"1fr 80px 1fr 1fr",gap:"12px"}}>
        <Field label="Date of Birth">
          <Input type="date" value={f.dob} onChange={s("dob")}/>
        </Field>
        <Field label="Age" hint="auto">
          <Input value={age||""} onChange={()=>{}} disabled/>
        </Field>
        <Field label="Place of Birth">
          <Input value={f.pob} onChange={s("pob")} placeholder="City, Country"/>
        </Field>
        <Field label="Sex">
          <Select value={f.sex} onChange={s("sex")} options={L.sex}/>
        </Field>
      </div>



      <div style={{marginBottom:"16px"}}>
        <Checkbox label="Deceased" checked={f.deceased} onChange={s("deceased")}/>
        {f.deceased&&<div style={{marginTop:"10px",maxWidth:"200px"}}>
          <Field label="Date of Death"><Input type="date" value={f.date_of_death} onChange={s("date_of_death")}/></Field>
        </div>}
      </div>

      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"16px"}}>
        <Field label="Nationality">
          <Input value={f.nationality} onChange={s("nationality")} placeholder="e.g. Syrian"/>
        </Field>
        <Field label="Occupation">
          <Input value={f.occupation} onChange={s("occupation")} placeholder="Current or last known occupation"/>
        </Field>
      </div>

      <Field label="Further Details">
        <Textarea value={f.further_details} onChange={s("further_details")} rows={3}
          placeholder="Additional biographical or descriptive details…"/>
      </Field>

      {/* ── SOURCE DETAILS ── */}
      <SectionHeader title="Source Details"/>

      <Field label="Reason for Nominal">
        <Textarea value={f.reason_for_nominal} onChange={s("reason_for_nominal")} rows={3}
          placeholder="Why is this source registered? What is their value to the investigation?"/>
      </Field>

      <Field label="Source" hint="how was this source identified?">
        <Input value={f.source} onChange={s("source")} placeholder="e.g. Intelligence referral, Walk-in, Partner agency"/>
      </Field>

      <Field label="Contact Preference">
        <Textarea value={f.contact_preference} onChange={s("contact_preference")} rows={3}
          placeholder="How and when to contact this source. Include any security considerations…"/>
      </Field>

      <Field label="Specialist Skills / Knowledge" hint="semicolon-separated">
        <Textarea value={f.specialist_skills} onChange={s("specialist_skills")} rows={2}
          placeholder="e.g. Military logistics; Syrian Army order of battle; Financial networks"/>
      </Field>

      <Field label="Notes">
        <Textarea value={f.notes} onChange={s("notes")} rows={4}
          placeholder="General notes, reliability assessment, handling considerations…"/>
      </Field>

      {/* Review */}
      <div style={{display:"grid",gridTemplateColumns:"200px auto 160px",gap:"12px",alignItems:"end",marginBottom:"20px"}}>
        <Field label="Review After (Period)">
          <Select value={f.review_period} onChange={s("review_period")} options={L.review_per}/>
        </Field>
        <div style={{paddingBottom:"1px",color:K.textMid,fontSize:"12px",paddingTop:"32px"}}>on date</div>
        <Field label="Review Date">
          <Input type="date" value={f.review_date} onChange={s("review_date")}/>
        </Field>
      </div>

      <RecordProps record={f}/>

      {/* Save bar */}
      <div style={{borderTop:`1px solid ${K.border}`,paddingTop:"16px",marginBottom:"8px",
        display:"flex",gap:"10px",alignItems:"center",flexWrap:"wrap"}}>
        <Btn variant="primary" onClick={handleSave}>Save Record</Btn>
        <Btn onClick={()=>onSave({...f,id:f.id||Date.now(),urn:f.urn||makeURN()})}>Save & Continue</Btn>
        <Btn onClick={onCancel}>Cancel</Btn>
        {!isNew&&<>
          <div style={{flex:1}}/>
          <span style={{fontSize:"11px",color:K.textDim}}>Export:</span>
          <Btn small onClick={()=>alert("i2 ANB export")}>i2 ANB</Btn>
          <Btn small variant="primary" onClick={()=>alert("PDF report")}>PDF</Btn>
        </>}
      </div>

      <AliasesSection aliases={f.aliases||[]} setAliases={s("aliases")}/>
      <RecordOfContact contacts={f.record_of_contact||[]} setContacts={s("record_of_contact")}/>
      <TasksSection tasks={f.tasks||[]} setTasks={s("tasks")}/>
      <NotesSection notes={f.inv_notes||[]} setNotes={s("inv_notes")}/>
      <FilesSection files={f.files||[]} setFiles={s("files")}/>
      <LinksSection links={f.links||[]} setLinks={s("links")}/>
    </div>
  );
}

function MaterialList({ records, onNew, onEdit, perms={}, onDelete, onDuplicate }) {
  const [search, setSearch] = React.useState("");
  const [filterType, setFilterType] = React.useState("");
  const [filterStatus, setFilterStatus] = React.useState("");

  const filtered = React.useMemo(() => {
    const q = search.toLowerCase();
    return (records||[]).filter(r => {
      const matchSearch = !q ||
        (r.title||"").toLowerCase().includes(q) ||
        (r.urn||"").toLowerCase().includes(q) ||
        (r.exhibit_ref||"").toLowerCase().includes(q) ||
        (r.source_url||"").toLowerCase().includes(q) ||
        (r.description||"").toLowerCase().includes(q) ||
        (r.tags||[]).some(t => t.toLowerCase().includes(q));
      return matchSearch &&
        (!filterType   || r.type === filterType) &&
        (!filterStatus || r.status === filterStatus);
    });
  }, [records, search, filterType, filterStatus]);

  return (
    <div>
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"20px"}}>
        <h1 style={{margin:0,fontSize:"22px",fontWeight:"800",color:K.navy,fontFamily:"Georgia,serif"}}>
          📦 Material Register
        </h1>
        {perms.canCreate && <Btn variant="primary" onClick={onNew}>+ New Material</Btn>}
      </div>

      <div style={{display:"flex",gap:"10px",marginBottom:"16px",flexWrap:"wrap"}}>
        <input value={search} onChange={e=>setSearch(e.target.value)}
          placeholder="Search material..."
          style={{padding:"7px 11px",border:"1px solid "+K.border,borderRadius:"4px",
            fontSize:"12px",color:K.text,background:K.surface,outline:"none",
            fontFamily:"inherit",width:"220px"}}/>
        <Select value={filterType} onChange={setFilterType} options={L.mat_type} placeholder="All Types"/>
        <Select value={filterStatus} onChange={setFilterStatus} options={L.mat_status} placeholder="All Statuses"/>
        {(search||filterType||filterStatus) &&
          <Btn small onClick={()=>{setSearch("");setFilterType("");setFilterStatus("");}}>Clear</Btn>}
        <span style={{marginLeft:"auto",fontSize:"11px",color:K.textDim,alignSelf:"center"}}>
          {filtered.length} of {(records||[]).length} records
        </span>
      </div>

      {filtered.length === 0 ? (
        <div style={{background:K.surface,border:"1px solid "+K.border,borderRadius:"8px",
          padding:"60px",textAlign:"center"}}>
          <div style={{fontSize:"40px",marginBottom:"12px"}}>📦</div>
          <div style={{fontSize:"14px",color:K.textDim}}>No material records found.</div>
          {perms.canCreate && <div style={{marginTop:"16px"}}><Btn variant="primary" onClick={onNew}>+ Add First Record</Btn></div>}
        </div>
      ) : (
        <div style={{background:K.surface,border:"1px solid "+K.border,borderRadius:"8px",overflow:"hidden"}}>
          <table style={{width:"100%",borderCollapse:"collapse",fontSize:"12px"}}>
            <thead>
              <tr style={{background:K.surfaceAlt}}>
                {["URN","Title","Type","Status","Exhibit Ref","Classification",""].map(h => (
                  <th key={h} style={{padding:"10px 14px",textAlign:"left",fontSize:"10px",
                    fontWeight:"800",color:K.textMid,letterSpacing:"1px",
                    borderBottom:"1px solid "+K.border,whiteSpace:"nowrap"}}>{h}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {filtered.map((r, i) => (
                <tr key={r.id} style={{borderBottom:"1px solid "+K.border,
                  background:i%2?K.surfaceAlt:K.surface,cursor:"pointer"}}
                  onClick={()=>onEdit(r)}
                  onMouseEnter={e=>e.currentTarget.style.background=K.blueLight}
                  onMouseLeave={e=>e.currentTarget.style.background=i%2?K.surfaceAlt:K.surface}>
                  <td style={{padding:"10px 14px",fontFamily:"monospace",fontSize:"11px",
                    color:K.blue,fontWeight:"700",whiteSpace:"nowrap"}}>{r.urn}</td>
                  <td style={{padding:"10px 14px"}}>
                    <div style={{fontWeight:"700",color:K.text}}>{r.title||"—"}</div>
                    {r.exhibit_number && <div style={{fontSize:"10px",color:K.textMid}}>Exhibit {r.exhibit_number}</div>}
                    {r.is_web_capture && <div style={{fontSize:"10px",color:K.blue,marginTop:"2px"}}>🌐 Web Capture</div>}
                  </td>
                  <td style={{padding:"10px 14px",color:K.textMid,whiteSpace:"nowrap"}}>{r.type||"—"}</td>
                  <td style={{padding:"10px 14px"}}>
                    {r.status && <span style={{padding:"2px 8px",borderRadius:"10px",fontSize:"11px",
                      fontWeight:"700",background:K.surfaceAlt,color:K.textMid}}>{r.status}</span>}
                  </td>
                  <td style={{padding:"10px 14px",fontFamily:"monospace",fontSize:"11px",
                    color:K.textMid}}>{r.exhibit_ref||"—"}</td>
                  <td style={{padding:"10px 14px"}}><ClassBadge v={r.classification}/></td>
                  <td style={{padding:"10px 14px"}}>
                    <Btn small onClick={e=>{e.stopPropagation();onEdit(r);}}>Open</Btn>
                  {onDelete && !r._redacted && <Btn small variant="danger" onClick={e=>{e.stopPropagation();onDelete(r);}}>Delete</Btn>}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}

function MaterialForm({ record, onSave, onCancel, allRecords={}, onOpenRecord, readOnly=false, onDelete, onDuplicate }) {
  const isNew = !record?.id;
  const [f, setF] = React.useState(record || {
    classification:"CONFIDENTIAL",
    type:"Open Source Material",
    title:"", description:"", status:"Secured",
    exhibit_number:"", exhibit_ref:"", seized_from:"", seized_by:"",
    date_seized:"", date_submitted:"", storage_location:"",
    is_exhibit:false,
    // Web capture fields
    is_web_capture:false,
    source_url:"", capture_tool:"", capture_operator:"",
    capture_timestamp:"", sha256_hash:"", hash_algorithm:"SHA-256",
    capture_notes:"",
    // Chain of custody
    movements:[],
    tags:[], tasks:[], inv_notes:[], files:[], links:[],
  });
  const s = k => v => setF(p => ({...p, [k]:v}));

  const handleSave = () => {
    if (!(f.title||"").trim()) { alert("Title is required."); return; }
    if (onSave) onSave({...f, id:f.id||Date.now(), urn:f.urn||makeURN("material")});
  };

  // Chain of custody movement
  const [movForm, setMovForm] = React.useState({date:"",from_location:"",to_location:"",reason:"",officer:""});
  const addMovement = () => {
    if (!(movForm.reason||"").trim()) return;
    setF(p => ({...p, movements:[...(p.movements||[]),{...movForm,id:Date.now()}]}));
    setMovForm({date:"",from_location:"",to_location:"",reason:"",officer:""});
  };

  // Web capture: generate a hash from URL + timestamp + operator
  const [captureLoading, setCaptureLoading] = React.useState(false);
  const runCapture = async () => {
    if (!(f.source_url||"").trim()) { alert("Enter a URL first."); return; }
    setCaptureLoading(true);
    const ts = new Date().toISOString();
    // Generate SHA-256 hash of URL + timestamp (deterministic evidence of when recorded)
    const msgBuffer = new TextEncoder().encode(f.source_url + "|" + ts + "|" + (f.capture_operator||""));
    let hashHex = "";
    try {
      const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer);
      hashHex = Array.from(new Uint8Array(hashBuffer)).map(b => b.toString(16).padStart(2,"0")).join("");
    } catch(e) {
      hashHex = "SHA-256 unavailable in this environment";
    }
    setF(p => ({...p,
      capture_timestamp: ts,
      sha256_hash: hashHex,
      hash_algorithm: "SHA-256",
      is_web_capture: true,
      title: p.title || ("Web Capture: " + f.source_url.replace("https://","").replace("http://","").substring(0,60)),
    }));
    setCaptureLoading(false);
  };

  // Download evidence package (ZIP-like: JSON manifest + HTML certificate)
  const downloadEvidencePackage = () => {
    if (!f.sha256_hash) { alert("Run capture first to generate hash."); return; }
    const manifest = {
      koios_urn: f.urn || "(unsaved)",
      evidence_type: "Web Capture",
      url: f.source_url,
      title: f.title,
      capture_timestamp: f.capture_timestamp,
      hash_algorithm: f.hash_algorithm || "SHA-256",
      sha256_hash: f.sha256_hash,
      capture_tool: f.capture_tool,
      capture_operator: f.capture_operator,
      capture_notes: f.capture_notes,
      exhibit_ref: f.exhibit_ref,
      classification: f.classification,
      exported: new Date().toISOString(),
      system: "KOIOS Investigation Management System",
      organisation: "ArcticWind",
    };

    const cert = `<!DOCTYPE html>
<html><head><meta charset="utf-8">
<title>KOIOS Web Evidence Certificate — ${f.urn||"UNSAVED"}</title>
<style>
  body{font-family:"Palatino Linotype",Georgia,serif;max-width:800px;margin:40px auto;padding:0 20px;color:#0d1f3c;}
  h1{font-size:28px;border-bottom:3px solid #0d1f3c;padding-bottom:12px;}
  .badge{display:inline-block;padding:4px 14px;border:2px solid #1a4a8a;color:#1a4a8a;font-weight:800;letter-spacing:2px;font-size:12px;margin-bottom:20px;}
  table{width:100%;border-collapse:collapse;margin:20px 0;}
  td{padding:10px 14px;border-bottom:1px solid #dce3ed;font-size:13px;}
  td:first-child{font-weight:700;width:200px;color:#4a5c74;}
  .hash{font-family:monospace;font-size:11px;word-break:break-all;background:#f7f9fc;padding:10px;border:1px solid #dce3ed;border-radius:4px;margin:10px 0;}
  .footer{margin-top:40px;font-size:10px;color:#8a9bb0;text-align:center;border-top:1px solid #dce3ed;padding-top:16px;}
  @media print{body{margin:20px;}}
</style></head>
<body>
  <div class="badge">${manifest.classification}</div>
  <h1>🔐 Web Evidence Certificate</h1>
  <p>This certificate records the preservation of online material as evidence. The SHA-256 hash below provides cryptographic proof of the URL and capture time recorded by the KOIOS system.</p>
  <table>
    <tr><td>KOIOS URN</td><td>${manifest.koios_urn}</td></tr>
    <tr><td>URL Captured</td><td style="word-break:break-all">${manifest.url}</td></tr>
    <tr><td>Title</td><td>${manifest.title}</td></tr>
    <tr><td>Capture Timestamp</td><td><strong>${manifest.capture_timestamp}</strong> (UTC)</td></tr>
    <tr><td>Capture Tool</td><td>${manifest.capture_tool||"KOIOS IMS (URL + timestamp hash)"}</td></tr>
    <tr><td>Capture Operator</td><td>${manifest.capture_operator||"Not recorded"}</td></tr>
    <tr><td>Exhibit Reference</td><td>${manifest.exhibit_ref||"Not assigned"}</td></tr>
    <tr><td>Classification</td><td>${manifest.classification}</td></tr>
    <tr><td>Exported</td><td>${manifest.exported}</td></tr>
  </table>
  <h2>SHA-256 Hash</h2>
  <p>Hash of: <code>${manifest.url} | ${manifest.capture_timestamp} | ${manifest.capture_operator||""}</code></p>
  <div class="hash">${manifest.sha256_hash}</div>
  <p style="font-size:12px;color:#4a5c74;">To verify: compute SHA-256 of the string <em>URL|timestamp|operator</em> (pipe-separated, exact values above) and compare with the hash recorded above.</p>
  ${manifest.capture_notes ? "<h2>Notes</h2><p>"+manifest.capture_notes+"</p>" : ""}
  <div class="footer">
    KOIOS Investigation Management System · ArcticWind · All sessions logged<br>
    This document was generated on ${manifest.exported}
  </div>
</body></html>`;

    // Download manifest JSON
    const jsonBlob = new Blob([JSON.stringify(manifest, null, 2)], {type:"application/json"});
    const jsonUrl = URL.createObjectURL(jsonBlob);
    const a1 = document.createElement("a");
    a1.href = jsonUrl;
    a1.download = (f.urn||"KOIOS") + "_evidence_manifest.json";
    a1.click();
    URL.revokeObjectURL(jsonUrl);

    // Download certificate HTML (printable to PDF)
    setTimeout(() => {
      const certBlob = new Blob([cert], {type:"text/html"});
      const certUrl = URL.createObjectURL(certBlob);
      const a2 = document.createElement("a");
      a2.href = certUrl;
      a2.download = (f.urn||"KOIOS") + "_evidence_certificate.html";
      a2.click();
      URL.revokeObjectURL(certUrl);
    }, 500);
  };

  return (
    <div style={{maxWidth:"900px",margin:"0 auto"}}>
      {/* Header */}
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",
        marginBottom:"24px",paddingBottom:"18px",borderBottom:"2px solid "+K.blueLight}}>
        <div>
          <div style={{fontSize:"11px",fontWeight:"700",color:K.blue,letterSpacing:"2px",marginBottom:"4px"}}>
            📦 {isNew?"NEW MATERIAL":"MATERIAL"} · {f.urn||"Will be assigned"}
            {f.is_web_capture && <span style={{marginLeft:"8px",padding:"2px 8px",background:K.blueLight,
              color:K.blue,borderRadius:"3px",fontSize:"10px"}}>🌐 WEB CAPTURE</span>}
          </div>
          <div style={{fontSize:"20px",fontWeight:"800",color:K.navy,fontFamily:"Georgia,serif"}}>
            {f.title||"Title not set"}
          </div>
          <div style={{display:"flex",gap:"8px",marginTop:"6px"}}>
            <ClassBadge v={f.classification}/>
            {f.is_exhibit && <span style={{padding:"3px 10px",background:"#fef3c7",color:"#78350f",
              border:"1px solid #fcd34d",borderRadius:"10px",fontSize:"11px",fontWeight:"700"}}>
              EXHIBIT
            </span>}
          </div>
        </div>
        <div style={{display:"flex",gap:"8px",flexWrap:"wrap",justifyContent:"flex-end"}}>
          {!isNew && f.sha256_hash && (
            <Btn onClick={downloadEvidencePackage}>⬇ Evidence Package</Btn>
          )}
          {!readOnly && <Btn variant="primary" onClick={handleSave}>Save Record</Btn>}
          <Btn onClick={onCancel}>Cancel</Btn>
          {!isNew && onDuplicate && <Btn onClick={()=>onDuplicate(f)}>⧉ Duplicate</Btn>}
          {!isNew && onDelete && (
            <Btn variant="danger" onClick={()=>onDelete(f)} style={{marginLeft:"4px"}}>Delete</Btn>
          )}
        </div>
      </div>

      {/* Core fields */}
      <SectionHeader title="Material Details"/>
      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"16px",marginBottom:"20px"}}>
        <Field label="Classification">
          <Select value={f.classification} onChange={s("classification")} options={L.class_lvl}/>
        </Field>
        <Field label="Material Type">
          <Select value={f.type} onChange={s("type")} options={L.mat_type}/>
        </Field>
        <Field label="Title" style={{gridColumn:"span 2"}}>
          <Input value={f.title} onChange={s("title")} placeholder="Descriptive title for this material"/>
        </Field>
        <Field label="Status">
          <Select value={f.status} onChange={s("status")} options={L.mat_status}/>
        </Field>
        <Field label="Storage Location">
          <Input value={f.storage_location} onChange={s("storage_location")} placeholder="e.g. Evidence Room A, Shelf 3"/>
        </Field>
        <Field label="Exhibit Number">
          <Input value={f.exhibit_number} onChange={s("exhibit_number")} placeholder="e.g. MG/11/001"/>
        </Field>
        <Field label="Exhibit Reference">
          <Input value={f.exhibit_ref} onChange={s("exhibit_ref")} placeholder="e.g. AW-EX-001"/>
        </Field>
        <Field label="Seized From">
          <Input value={f.seized_from} onChange={s("seized_from")} placeholder="Person / location"/>
        </Field>
        <Field label="Seized By">
          <Input value={f.seized_by} onChange={s("seized_by")} placeholder="Officer name"/>
        </Field>
        <Field label="Date Seized">
          <Input type="date" value={f.date_seized} onChange={s("date_seized")}/>
        </Field>
        <Field label="Date Submitted">
          <Input type="date" value={f.date_submitted} onChange={s("date_submitted")}/>
        </Field>
      </div>
      <div style={{display:"flex",alignItems:"center",gap:"10px",marginBottom:"20px"}}>
        <input type="checkbox" id="is_exhibit" checked={!!f.is_exhibit}
          onChange={e=>setF(p=>({...p,is_exhibit:e.target.checked}))}
          style={{width:"16px",height:"16px",cursor:"pointer"}}/>
        <label htmlFor="is_exhibit" style={{fontSize:"13px",fontWeight:"600",cursor:"pointer"}}>
          Mark as Exhibit
        </label>
      </div>
      <Field label="Description">
        <Textarea value={f.description} onChange={s("description")} rows={3}
          placeholder="Describe the material and its evidential significance"/>
      </Field>

      {/* ── WEB EVIDENCE CAPTURE ── */}
      <SectionHeader title="Web Evidence Capture"/>
      <div style={{background:"#f0f7ff",border:"1px solid "+K.blueMid,borderRadius:"8px",padding:"20px",marginBottom:"20px"}}>
        <div style={{fontSize:"12px",color:K.textMid,marginBottom:"16px",lineHeight:"1.6"}}>
          Use this section to record the preservation of online material as evidence.
          Enter the URL and operator name, then click <strong>Record Capture</strong> to generate
          a SHA-256 hash of the URL and precise timestamp. Download the evidence package after saving.
          <br/>
          <span style={{color:K.amber,fontWeight:"700"}}>⚠ For full page archival use Hunchly or Magnet — record their output hash here.</span>
        </div>

        <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"16px",marginBottom:"16px"}}>
          <Field label="Source URL" style={{gridColumn:"span 2"}} hint="Full URL including https://">
            <Input value={f.source_url} onChange={s("source_url")} placeholder="https://example.com/page"/>
          </Field>
          <Field label="Capture Tool" hint="e.g. Hunchly, Magnet, KOIOS">
            <Input value={f.capture_tool} onChange={s("capture_tool")} placeholder="Tool used for capture"/>
          </Field>
          <Field label="Capture Operator" hint="Officer who performed capture">
            <Input value={f.capture_operator} onChange={s("capture_operator")} placeholder="Officer name"/>
          </Field>
        </div>

        {/* Hash fields — editable so Hunchly/Magnet hashes can be pasted in */}
        <div style={{display:"grid",gridTemplateColumns:"120px 1fr",gap:"16px",marginBottom:"16px"}}>
          <Field label="Algorithm">
            <Select value={f.hash_algorithm||"SHA-256"} onChange={s("hash_algorithm")}
              options={["SHA-256","SHA-512","MD5","SHA-1"]}/>
          </Field>
          <Field label="Hash Value" hint="Paste hash from capture tool, or generate below">
            <Input value={f.sha256_hash} onChange={s("sha256_hash")}
              placeholder="e.g. a3f2c1... (paste from Hunchly/Magnet or generate below)"
              style={{fontFamily:"monospace",fontSize:"11px"}}/>
          </Field>
        </div>

        <Field label="Capture Timestamp (UTC)" hint="ISO 8601 — auto-filled on generate, or enter manually">
          <Input value={f.capture_timestamp} onChange={s("capture_timestamp")}
            placeholder="e.g. 2025-11-15T14:32:00.000Z"/>
        </Field>

        <Field label="Capture Notes">
          <Textarea value={f.capture_notes} onChange={s("capture_notes")} rows={2}
            placeholder="Any observations at time of capture (page state, login required, content warnings etc.)"/>
        </Field>

        {/* Generate button */}
        <div style={{display:"flex",gap:"10px",marginTop:"16px",alignItems:"center",flexWrap:"wrap"}}>
          <button onClick={runCapture} disabled={captureLoading||!(f.source_url||"").trim()||readOnly}
            style={{padding:"10px 20px",background:captureLoading||!(f.source_url||"").trim()||readOnly ? K.surfaceAlt : K.blue,
              color:captureLoading||!(f.source_url||"").trim()||readOnly ? K.textDim : "#fff",
              border:"none",borderRadius:"5px",fontSize:"13px",fontWeight:"700",
              cursor:captureLoading||!(f.source_url||"").trim()||readOnly ? "not-allowed" : "pointer",
              fontFamily:"inherit"}}>
            {captureLoading ? "Generating..." : "🔐 Record Capture (Generate Hash)"}
          </button>
          {f.sha256_hash && !isNew && (
            <button onClick={downloadEvidencePackage}
              style={{padding:"10px 20px",background:K.green,color:"#fff",
                border:"none",borderRadius:"5px",fontSize:"13px",fontWeight:"700",
                cursor:"pointer",fontFamily:"inherit"}}>
              ⬇ Download Evidence Package
            </button>
          )}
          {f.sha256_hash && (
            <span style={{fontSize:"11px",color:K.green,fontWeight:"700"}}>
              ✓ Hash recorded at {f.capture_timestamp ? new Date(f.capture_timestamp).toLocaleString("en-GB") : ""}
            </span>
          )}
        </div>

        {/* Hash display */}
        {f.sha256_hash && (
          <div style={{marginTop:"16px",padding:"12px 16px",background:K.surface,
            border:"1px solid "+K.border,borderRadius:"6px"}}>
            <div style={{fontSize:"10px",fontWeight:"800",color:K.textMid,
              letterSpacing:"1.5px",marginBottom:"6px"}}>{f.hash_algorithm||"SHA-256"} HASH</div>
            <div style={{fontFamily:"monospace",fontSize:"12px",color:K.navy,
              wordBreak:"break-all",lineHeight:"1.6"}}>{f.sha256_hash}</div>
            <div style={{fontSize:"10px",color:K.textDim,marginTop:"6px"}}>
              Hash of: {f.source_url} | {f.capture_timestamp} | {f.capture_operator||""}
            </div>
          </div>
        )}
      </div>

      {/* Chain of custody */}
      <SectionHeader title="Chain of Custody"/>
      <div style={{marginBottom:"20px"}}>
        {(f.movements||[]).length === 0 && (
          <p style={{fontSize:"12px",color:K.textDim,margin:"8px 0 12px"}}>No movements recorded.</p>
        )}
        {(f.movements||[]).map((m, i) => (
          <div key={m.id} style={{display:"flex",gap:"0",marginBottom:"6px",alignItems:"stretch"}}>
            <div style={{width:"4px",background:K.blue,borderRadius:"2px",marginRight:"12px",flexShrink:0}}/>
            <div style={{flex:1,padding:"10px 14px",background:K.surfaceAlt,
              border:"1px solid "+K.border,borderRadius:"6px",fontSize:"12px"}}>
              <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start"}}>
                <div>
                  <span style={{fontWeight:"700",color:K.text}}>{m.reason}</span>
                  {m.from_location && <span style={{color:K.textMid}}> · From: {m.from_location}</span>}
                  {m.to_location && <span style={{color:K.textMid}}> → {m.to_location}</span>}
                </div>
                <div style={{display:"flex",gap:"8px",alignItems:"center"}}>
                  <span style={{color:K.textDim,fontSize:"11px",whiteSpace:"nowrap"}}>
                    {m.date} {m.officer && "· "+m.officer}
                  </span>
                  {!readOnly && (
                    <button onClick={()=>setF(p=>({...p,movements:p.movements.filter(x=>x.id!==m.id)}))}
                      style={{background:"none",border:"none",color:K.textDim,cursor:"pointer",fontSize:"11px"}}>✕</button>
                  )}
                </div>
              </div>
            </div>
          </div>
        ))}
        {!readOnly && (
          <div style={{background:K.surfaceAlt,border:"1px solid "+K.border,
            borderRadius:"6px",padding:"14px",marginTop:"10px"}}>
            <div style={{fontSize:"11px",fontWeight:"700",color:K.textMid,
              marginBottom:"10px",letterSpacing:"1px"}}>ADD MOVEMENT</div>
            <div style={{display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:"10px",marginBottom:"10px"}}>
              <Field label="Date"><Input type="date" value={movForm.date} onChange={v=>setMovForm(p=>({...p,date:v}))}/></Field>
              <Field label="From Location"><Input value={movForm.from_location} onChange={v=>setMovForm(p=>({...p,from_location:v}))}/></Field>
              <Field label="To Location"><Input value={movForm.to_location} onChange={v=>setMovForm(p=>({...p,to_location:v}))}/></Field>
              <Field label="Reason">
                <Select value={movForm.reason} onChange={v=>setMovForm(p=>({...p,reason:v}))} options={L.movement_reason}/>
              </Field>
              <Field label="Officer"><Input value={movForm.officer} onChange={v=>setMovForm(p=>({...p,officer:v}))}/></Field>
            </div>
            <div style={{display:"flex",gap:"8px"}}>
              <Btn variant="primary" small onClick={addMovement} disabled={!movForm.reason}>Add Movement</Btn>
            </div>
          </div>
        )}
      </div>

      <Field label="Tags"><TagsInput tags={f.tags||[]} setTags={s("tags")}/></Field>
      <TasksSection tasks={f.tasks||[]} setTasks={s("tasks")}/>
      <NotesSection notes={f.inv_notes||[]} setNotes={s("inv_notes")}/>
      <FilesSection files={f.files||[]} setFiles={s("files")}/>
      <LinksSection links={f.links||[]} setLinks={s("links")} allRecords={allRecords} onOpenRecord={onOpenRecord}/>
      <RecordProps record={f}/>
    </div>
  );
}
function AddressForm({ record, onSave, onCancel, allRecords={}, onOpenRecord, readOnly=false, onDelete, onDuplicate }) {
  const isNew = !record?.id;
  const [f, setF] = React.useState(record || {
    classification:"CONFIDENTIAL", type:"", address_line1:"", address_line2:"",
    city:"", county:"", postcode:"", country:"", latitude:"", longitude:"",
    reason_for_nominal:"", tags:[], tasks:[], inv_notes:[], files:[], links:[],
  });
  const s = k => v => setF(p => ({...p, [k]:v}));
  const handleSave = () => {
    if(!(f.address_line1||"").trim()){alert("Address Line 1 is required.");return;}
    if(onSave) onSave({...f, id:f.id||Date.now(), urn:f.urn||makeURN("address")});
  };
  return (
    <div style={{maxWidth:"900px",margin:"0 auto"}}>
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:"24px",paddingBottom:"18px",borderBottom:`2px solid ${K.blueLight}`}}>
        <div>
          <div style={{fontSize:"11px",fontWeight:"700",color:K.blue,letterSpacing:"2px",marginBottom:"4px"}}>📍 {isNew?"NEW ADDRESS":"ADDRESS"} · {f.urn||"Will be assigned"}</div>
          <ClassBadge v={f.classification}/>
        </div>
        <div style={{display:"flex",gap:"8px"}}>
          {!readOnly&&<Btn variant="primary" onClick={handleSave}>Save Record</Btn>}
          <Btn onClick={onCancel}>Cancel</Btn>
          {!isNew&&onDuplicate&&<Btn onClick={()=>onDuplicate(f)}>⧉ Duplicate</Btn>}
          {!isNew&&onDelete&&<Btn variant="danger" onClick={()=>onDelete(f)} style={{marginLeft:"auto"}}>Delete</Btn>}
        </div>
      </div>
      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"16px",marginBottom:"20px"}}>
        <Field label="Classification"><Select value={f.classification} onChange={s("classification")} options={L.class_lvl}/></Field>
        <Field label="Address Type"><Select value={f.type} onChange={s("type")} options={L.address_type}/></Field>
        <Field label="Address Line 1"><Input value={f.address_line1} onChange={s("address_line1")} placeholder="Street address"/></Field>
        <Field label="Address Line 2"><Input value={f.address_line2} onChange={s("address_line2")} placeholder="Area / district"/></Field>
        <Field label="City / Town"><Input value={f.city} onChange={s("city")}/></Field>
        <Field label="County / State"><Input value={f.county} onChange={s("county")}/></Field>
        <Field label="Postcode / ZIP"><Input value={f.postcode} onChange={s("postcode")}/></Field>
        <Field label="Country"><Input value={f.country} onChange={s("country")}/></Field>
        <Field label="Latitude"><Input value={f.latitude} onChange={s("latitude")} placeholder="e.g. 33.4973"/></Field>
        <Field label="Longitude"><Input value={f.longitude} onChange={s("longitude")} placeholder="e.g. 36.2257"/></Field>
      </div>
      <Field label="Reason for Nominal"><Textarea value={f.reason_for_nominal} onChange={s("reason_for_nominal")} rows={3}/></Field>
      <Field label="Tags"><TagsInput tags={f.tags||[]} setTags={s("tags")}/></Field>
      <TasksSection tasks={f.tasks||[]} setTasks={s("tasks")}/>
      <NotesSection notes={f.inv_notes||[]} setNotes={s("inv_notes")}/>
      <FilesSection files={f.files||[]} setFiles={s("files")}/>
      <LinksSection links={f.links||[]} setLinks={s("links")} allRecords={allRecords} onOpenRecord={onOpenRecord}/>
      <RecordProps record={f}/>
    </div>
  );
}
function AssessmentForm({ record, onSave, onCancel, allRecords={}, onOpenRecord, readOnly=false, onDelete, onDuplicate }) {
  const isNew = !record?.id;
  const [f, setF] = React.useState(record || {
    classification:"CONFIDENTIAL", type:"", title:"", assessment_date:"",
    assessed_by:"", summary:"", findings:"", recommendations:"", risk_level:"",
    tags:[], tasks:[], inv_notes:[], files:[], links:[],
  });
  const s = k => v => setF(p => ({...p, [k]:v}));
  const handleSave = () => {
    if(!(f.title||"").trim()){alert("Title is required.");return;}
    if(onSave) onSave({...f, id:f.id||Date.now(), urn:f.urn||makeURN("assessment")});
  };
  return (
    <div style={{maxWidth:"900px",margin:"0 auto"}}>
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:"24px",paddingBottom:"18px",borderBottom:`2px solid ${K.blueLight}`}}>
        <div>
          <div style={{fontSize:"11px",fontWeight:"700",color:K.blue,letterSpacing:"2px",marginBottom:"4px"}}>📊 {isNew?"NEW ASSESSMENT":"ASSESSMENT"} · {f.urn||"Will be assigned"}</div>
          <ClassBadge v={f.classification}/>
        </div>
        <div style={{display:"flex",gap:"8px"}}>
          {!readOnly&&<Btn variant="primary" onClick={handleSave}>Save Record</Btn>}
          <Btn onClick={onCancel}>Cancel</Btn>
          {!isNew&&onDuplicate&&<Btn onClick={()=>onDuplicate(f)}>⧉ Duplicate</Btn>}
          {!isNew&&onDelete&&<Btn variant="danger" onClick={()=>onDelete(f)} style={{marginLeft:"auto"}}>Delete</Btn>}
        </div>
      </div>
      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"16px",marginBottom:"20px"}}>
        <Field label="Classification"><Select value={f.classification} onChange={s("classification")} options={L.class_lvl}/></Field>
        <Field label="Assessment Type"><Select value={f.type} onChange={s("type")} options={L.assessment_type}/></Field>
        <Field label="Title" style={{gridColumn:"span 2"}}><Input value={f.title} onChange={s("title")} placeholder="Assessment title"/></Field>
        <Field label="Assessment Date"><Input type="date" value={f.assessment_date} onChange={s("assessment_date")}/></Field>
        <Field label="Assessed By"><Input value={f.assessed_by} onChange={s("assessed_by")}/></Field>
        <Field label="Risk Level"><Select value={f.risk_level} onChange={s("risk_level")} options={["Critical","High","Medium","Low","Not Applicable"]} placeholder="Select level"/></Field>
      </div>
      <Field label="Summary"><Textarea value={f.summary} onChange={s("summary")} rows={3}/></Field>
      <Field label="Findings"><Textarea value={f.findings} onChange={s("findings")} rows={4}/></Field>
      <Field label="Recommendations"><Textarea value={f.recommendations} onChange={s("recommendations")} rows={3}/></Field>
      <Field label="Tags"><TagsInput tags={f.tags||[]} setTags={s("tags")}/></Field>
      <TasksSection tasks={f.tasks||[]} setTasks={s("tasks")}/>
      <NotesSection notes={f.inv_notes||[]} setNotes={s("inv_notes")}/>
      <FilesSection files={f.files||[]} setFiles={s("files")}/>
      <LinksSection links={f.links||[]} setLinks={s("links")} allRecords={allRecords} onOpenRecord={onOpenRecord}/>
      <RecordProps record={f}/>
    </div>
  );
}
function CaseForm({ record, onSave, onCancel, allRecords={}, onOpenRecord, readOnly=false, onDelete, onDuplicate }) {
  const isNew = !record?.id;
  const [f, setF] = React.useState(record || {
    classification:"CONFIDENTIAL", type:"", title:"", status:"Open", priority:"High",
    date_opened:"", date_closed:"", lead_investigator:"", case_officer:"",
    jurisdiction:"", description:"", tags:[], tasks:[], inv_notes:[], files:[], links:[],
  });
  const s = k => v => setF(p => ({...p, [k]:v}));
  const handleSave = () => {
    if(!(f.title||"").trim()){alert("Title is required.");return;}
    if(onSave) onSave({...f, id:f.id||Date.now(), urn:f.urn||makeURN("case")});
  };
  const STATUS_C = {Open:"#166534",Active:"#1a4a8a","Under Review":"#78350f",Closed:"#374151",Referred:"#6b21a8",Archived:"#94a3b8"};
  return (
    <div style={{maxWidth:"900px",margin:"0 auto"}}>
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:"24px",paddingBottom:"18px",borderBottom:`2px solid ${K.blueLight}`}}>
        <div>
          <div style={{fontSize:"11px",fontWeight:"700",color:K.blue,letterSpacing:"2px",marginBottom:"4px"}}>⚖ {isNew?"NEW CASE":"CASE"} · {f.urn||"Will be assigned"}</div>
          <div style={{display:"flex",gap:"8px",alignItems:"center"}}>
            <ClassBadge v={f.classification}/>
            {f.status&&<span style={{padding:"3px 10px",borderRadius:"10px",fontSize:"11px",fontWeight:"700",background:(STATUS_C[f.status]||K.textDim)+"18",color:STATUS_C[f.status]||K.textDim}}>{f.status}</span>}
            {f.priority&&<span style={{padding:"3px 10px",borderRadius:"4px",fontSize:"11px",fontWeight:"800",background:K.surfaceAlt}}>{f.priority}</span>}
          </div>
        </div>
        <div style={{display:"flex",gap:"8px",flexWrap:"wrap"}}>
          {!readOnly&&<Btn variant="primary" onClick={handleSave}>Save Record</Btn>}
          <Btn onClick={onCancel}>Cancel</Btn>
          {!isNew&&onDuplicate&&<Btn onClick={()=>onDuplicate(f)}>⧉ Duplicate</Btn>}
          {!isNew&&onDelete&&<Btn variant="danger" onClick={()=>onDelete(f)} style={{marginLeft:"auto"}}>Delete</Btn>}
        </div>
      </div>
      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"16px",marginBottom:"20px"}}>
        <Field label="Classification"><Select value={f.classification} onChange={s("classification")} options={L.class_lvl}/></Field>
        <Field label="Case Type"><Select value={f.type} onChange={s("type")} options={L.case_type}/></Field>
        <Field label="Title" style={{gridColumn:"span 2"}}><Input value={f.title} onChange={s("title")} placeholder="Case title"/></Field>
        <Field label="Status"><Select value={f.status} onChange={s("status")} options={L.case_status}/></Field>
        <Field label="Priority"><Select value={f.priority} onChange={s("priority")} options={L.case_priority}/></Field>
        <Field label="Date Opened"><Input type="date" value={f.date_opened} onChange={s("date_opened")}/></Field>
        <Field label="Date Closed"><Input type="date" value={f.date_closed} onChange={s("date_closed")}/></Field>
        <Field label="Lead Investigator"><Input value={f.lead_investigator} onChange={s("lead_investigator")}/></Field>
        <Field label="Case Officer"><Input value={f.case_officer} onChange={s("case_officer")}/></Field>
        <Field label="Jurisdiction"><Input value={f.jurisdiction} onChange={s("jurisdiction")} placeholder="e.g. ICC, UK, US Federal"/></Field>
      </div>
      <Field label="Description"><Textarea value={f.description} onChange={s("description")} rows={4} placeholder="Case overview and background"/></Field>
      <Field label="Tags"><TagsInput tags={f.tags||[]} setTags={s("tags")}/></Field>
      <TasksSection tasks={f.tasks||[]} setTasks={s("tasks")}/>
      <NotesSection notes={f.inv_notes||[]} setNotes={s("inv_notes")}/>
      <FilesSection files={f.files||[]} setFiles={s("files")}/>
      <LinksSection links={f.links||[]} setLinks={s("links")} allRecords={allRecords} onOpenRecord={onOpenRecord}/>
      <RecordProps record={f}/>
    </div>
  );
}
function DecisionForm({ record, onSave, onCancel, allRecords={}, onOpenRecord, readOnly=false, onDelete, onDuplicate }) {
  const isNew = !record?.id;
  const [f, setF] = React.useState(record || {
    classification:"CONFIDENTIAL", type:"", title:"", decision_date:"",
    decided_by:"", rationale:"", outcome_summary:"", authority_level:"",
    tags:[], tasks:[], inv_notes:[], files:[], links:[],
  });
  const s = k => v => setF(p => ({...p, [k]:v}));
  const handleSave = () => {
    if(!(f.title||"").trim()){alert("Title is required.");return;}
    if(onSave) onSave({...f, id:f.id||Date.now(), urn:f.urn||makeURN("decision")});
  };
  return (
    <div style={{maxWidth:"900px",margin:"0 auto"}}>
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:"24px",paddingBottom:"18px",borderBottom:`2px solid ${K.blueLight}`}}>
        <div>
          <div style={{fontSize:"11px",fontWeight:"700",color:K.blue,letterSpacing:"2px",marginBottom:"4px"}}>✔ {isNew?"NEW DECISION":"DECISION"} · {f.urn||"Will be assigned"}</div>
          <ClassBadge v={f.classification}/>
        </div>
        <div style={{display:"flex",gap:"8px"}}>
          {!readOnly&&<Btn variant="primary" onClick={handleSave}>Save Record</Btn>}
          <Btn onClick={onCancel}>Cancel</Btn>
          {!isNew&&onDuplicate&&<Btn onClick={()=>onDuplicate(f)}>⧉ Duplicate</Btn>}
          {!isNew&&onDelete&&<Btn variant="danger" onClick={()=>onDelete(f)} style={{marginLeft:"auto"}}>Delete</Btn>}
        </div>
      </div>
      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"16px",marginBottom:"20px"}}>
        <Field label="Classification"><Select value={f.classification} onChange={s("classification")} options={L.class_lvl}/></Field>
        <Field label="Decision Type"><Select value={f.type} onChange={s("type")} options={L.decision_type}/></Field>
        <Field label="Title" style={{gridColumn:"span 2"}}><Input value={f.title} onChange={s("title")} placeholder="Decision title"/></Field>
        <Field label="Decision Date"><Input type="date" value={f.decision_date} onChange={s("decision_date")}/></Field>
        <Field label="Decided By"><Input value={f.decided_by} onChange={s("decided_by")}/></Field>
        <Field label="Authority Level"><Input value={f.authority_level} onChange={s("authority_level")} placeholder="e.g. Senior Investigating Officer"/></Field>
      </div>
      <Field label="Rationale"><Textarea value={f.rationale} onChange={s("rationale")} rows={4}/></Field>
      <Field label="Outcome Summary"><Textarea value={f.outcome_summary} onChange={s("outcome_summary")} rows={3}/></Field>
      <Field label="Tags"><TagsInput tags={f.tags||[]} setTags={s("tags")}/></Field>
      <TasksSection tasks={f.tasks||[]} setTasks={s("tasks")}/>
      <NotesSection notes={f.inv_notes||[]} setNotes={s("inv_notes")}/>
      <FilesSection files={f.files||[]} setFiles={s("files")}/>
      <LinksSection links={f.links||[]} setLinks={s("links")} allRecords={allRecords} onOpenRecord={onOpenRecord}/>
      <RecordProps record={f}/>
    </div>
  );
}
function OutcomeForm({ record, onSave, onCancel, allRecords={}, onOpenRecord, readOnly=false, onDelete, onDuplicate }) {
  const isNew = !record?.id;
  const [f, setF] = React.useState(record || {
    classification:"CONFIDENTIAL", type:"", title:"", outcome_date:"",
    description:"", impact:"", sentence:"", jurisdiction:"",
    tags:[], tasks:[], inv_notes:[], files:[], links:[],
  });
  const s = k => v => setF(p => ({...p, [k]:v}));
  const handleSave = () => {
    if(!(f.title||"").trim()){alert("Title is required.");return;}
    if(onSave) onSave({...f, id:f.id||Date.now(), urn:f.urn||makeURN("outcome")});
  };
  return (
    <div style={{maxWidth:"900px",margin:"0 auto"}}>
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:"24px",paddingBottom:"18px",borderBottom:`2px solid ${K.blueLight}`}}>
        <div>
          <div style={{fontSize:"11px",fontWeight:"700",color:K.blue,letterSpacing:"2px",marginBottom:"4px"}}>🏁 {isNew?"NEW OUTCOME":"OUTCOME"} · {f.urn||"Will be assigned"}</div>
          <ClassBadge v={f.classification}/>
        </div>
        <div style={{display:"flex",gap:"8px"}}>
          {!readOnly&&<Btn variant="primary" onClick={handleSave}>Save Record</Btn>}
          <Btn onClick={onCancel}>Cancel</Btn>
          {!isNew&&onDuplicate&&<Btn onClick={()=>onDuplicate(f)}>⧉ Duplicate</Btn>}
          {!isNew&&onDelete&&<Btn variant="danger" onClick={()=>onDelete(f)} style={{marginLeft:"auto"}}>Delete</Btn>}
        </div>
      </div>
      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"16px",marginBottom:"20px"}}>
        <Field label="Classification"><Select value={f.classification} onChange={s("classification")} options={L.class_lvl}/></Field>
        <Field label="Outcome Type"><Select value={f.type} onChange={s("type")} options={L.outcome_type}/></Field>
        <Field label="Title" style={{gridColumn:"span 2"}}><Input value={f.title} onChange={s("title")} placeholder="Outcome title"/></Field>
        <Field label="Outcome Date"><Input type="date" value={f.outcome_date} onChange={s("outcome_date")}/></Field>
        <Field label="Jurisdiction"><Input value={f.jurisdiction} onChange={s("jurisdiction")} placeholder="e.g. ICC, UK Crown Court"/></Field>
        <Field label="Sentence / Penalty"><Input value={f.sentence} onChange={s("sentence")} placeholder="e.g. 25 years imprisonment"/></Field>
      </div>
      <Field label="Description"><Textarea value={f.description} onChange={s("description")} rows={3}/></Field>
      <Field label="Impact Assessment"><Textarea value={f.impact} onChange={s("impact")} rows={3}/></Field>
      <Field label="Tags"><TagsInput tags={f.tags||[]} setTags={s("tags")}/></Field>
      <TasksSection tasks={f.tasks||[]} setTasks={s("tasks")}/>
      <NotesSection notes={f.inv_notes||[]} setNotes={s("inv_notes")}/>
      <FilesSection files={f.files||[]} setFiles={s("files")}/>
      <LinksSection links={f.links||[]} setLinks={s("links")} allRecords={allRecords} onOpenRecord={onOpenRecord}/>
      <RecordProps record={f}/>
    </div>
  );
}
function StaffForm({ record, onSave, onCancel, allRecords={}, onOpenRecord, readOnly=false, onDelete, onDuplicate }) {
  const isNew = !record?.id;
  const [f, setF] = React.useState(record || {
    classification:"CONFIDENTIAL", type:"", title:"", forenames:"", surname:"",
    role:"", department:"", clearance:"CONFIDENTIAL", email:"", phone:"",
    date_joined:"", date_left:"", active:true,
    tags:[], tasks:[], inv_notes:[], files:[], links:[],
  });
  const s = k => v => setF(p => ({...p, [k]:v}));
  const handleSave = () => {
    if(!(f.surname||"").trim()){alert("Surname is required.");return;}
    if(onSave) onSave({...f, id:f.id||Date.now(), urn:f.urn||makeURN("staff")});
  };
  return (
    <div style={{maxWidth:"900px",margin:"0 auto"}}>
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:"24px",paddingBottom:"18px",borderBottom:`2px solid ${K.blueLight}`}}>
        <div>
          <div style={{fontSize:"11px",fontWeight:"700",color:K.blue,letterSpacing:"2px",marginBottom:"4px"}}>👥 {isNew?"NEW STAFF RECORD":"STAFF"} · {f.urn||"Will be assigned"}</div>
          <div style={{fontSize:"20px",fontWeight:"800",color:K.navy,fontFamily:"Georgia,serif"}}>
            {[f.title,f.forenames,f.surname].filter(Boolean).join(" ")||"Name not set"}
          </div>
          <div style={{display:"flex",gap:"8px",marginTop:"6px"}}>
            <ClassBadge v={f.classification}/>
            {f.clearance&&<ClassBadge v={f.clearance}/>}
          </div>
        </div>
        <div style={{display:"flex",gap:"8px",flexWrap:"wrap"}}>
          {!readOnly&&<Btn variant="primary" onClick={handleSave}>Save Record</Btn>}
          <Btn onClick={onCancel}>Cancel</Btn>
          {!isNew&&onDuplicate&&<Btn onClick={()=>onDuplicate(f)}>⧉ Duplicate</Btn>}
          {!isNew&&onDelete&&<Btn variant="danger" onClick={()=>onDelete(f)} style={{marginLeft:"auto"}}>Delete</Btn>}
        </div>
      </div>
      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"16px",marginBottom:"20px"}}>
        <Field label="Classification"><Select value={f.classification} onChange={s("classification")} options={L.class_lvl}/></Field>
        <Field label="Staff Type"><Select value={f.type} onChange={s("type")} options={L.staff_type}/></Field>
        <Field label="Title"><Select value={f.title} onChange={s("title")} options={L.title} placeholder="Select title"/></Field>
        <Field label="Clearance"><Select value={f.clearance} onChange={s("clearance")} options={L.staff_clearance}/></Field>
        <Field label="Forenames"><Input value={f.forenames} onChange={s("forenames")}/></Field>
        <Field label="Surname" required><Input value={f.surname} onChange={v=>setF(p=>({...p,surname:v.toUpperCase()}))} placeholder="SURNAME"/></Field>
        <Field label="Role / Position"><Input value={f.role} onChange={s("role")} placeholder="e.g. Senior Investigator"/></Field>
        <Field label="Department"><Input value={f.department} onChange={s("department")}/></Field>
        <Field label="Email"><Input value={f.email} onChange={s("email")} type="email"/></Field>
        <Field label="Phone"><Input value={f.phone} onChange={s("phone")}/></Field>
        <Field label="Date Joined"><Input type="date" value={f.date_joined} onChange={s("date_joined")}/></Field>
        <Field label="Date Left"><Input type="date" value={f.date_left} onChange={s("date_left")}/></Field>
      </div>
      <Field label="Tags"><TagsInput tags={f.tags||[]} setTags={s("tags")}/></Field>
      <TasksSection tasks={f.tasks||[]} setTasks={s("tasks")}/>
      <NotesSection notes={f.inv_notes||[]} setNotes={s("inv_notes")}/>
      <FilesSection files={f.files||[]} setFiles={s("files")}/>
      <LinksSection links={f.links||[]} setLinks={s("links")} allRecords={allRecords} onOpenRecord={onOpenRecord}/>
      <RecordProps record={f}/>
    </div>
  );
}
function EquipmentForm({ record, onSave, onCancel, allRecords={}, onOpenRecord, readOnly=false, onDelete, onDuplicate }) {
  const isNew = !record?.id;
  const [f, setF] = React.useState(record || {
    classification:"CONFIDENTIAL", type:"", make:"", model:"", colour:"",
    registration:"", serial_number:"", condition:"", assigned_to:"",
    date_acquired:"", date_disposed:"", description:"",
    tags:[], tasks:[], inv_notes:[], files:[], links:[],
  });
  const s = k => v => setF(p => ({...p, [k]:v}));
  const handleSave = () => {
    if(!(f.type||"").trim()){alert("Equipment Type is required.");return;}
    if(onSave) onSave({...f, id:f.id||Date.now(), urn:f.urn||makeURN("equipment")});
  };
  return (
    <div style={{maxWidth:"900px",margin:"0 auto"}}>
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:"24px",paddingBottom:"18px",borderBottom:`2px solid ${K.blueLight}`}}>
        <div>
          <div style={{fontSize:"11px",fontWeight:"700",color:K.blue,letterSpacing:"2px",marginBottom:"4px"}}>🔧 {isNew?"NEW EQUIPMENT":"EQUIPMENT"} · {f.urn||"Will be assigned"}</div>
          <div style={{fontSize:"20px",fontWeight:"800",color:K.navy,fontFamily:"Georgia,serif"}}>
            {[f.make,f.model].filter(Boolean).join(" ")||"Equipment not named"}
          </div>
          <ClassBadge v={f.classification}/>
        </div>
        <div style={{display:"flex",gap:"8px"}}>
          {!readOnly&&<Btn variant="primary" onClick={handleSave}>Save Record</Btn>}
          <Btn onClick={onCancel}>Cancel</Btn>
          {!isNew&&onDuplicate&&<Btn onClick={()=>onDuplicate(f)}>⧉ Duplicate</Btn>}
          {!isNew&&onDelete&&<Btn variant="danger" onClick={()=>onDelete(f)} style={{marginLeft:"auto"}}>Delete</Btn>}
        </div>
      </div>
      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"16px",marginBottom:"20px"}}>
        <Field label="Classification"><Select value={f.classification} onChange={s("classification")} options={L.class_lvl}/></Field>
        <Field label="Equipment Type"><Select value={f.type} onChange={s("type")} options={L.equipment_type}/></Field>
        <Field label="Make"><Input value={f.make} onChange={s("make")} placeholder="e.g. Toyota"/></Field>
        <Field label="Model"><Input value={f.model} onChange={s("model")} placeholder="e.g. Land Cruiser"/></Field>
        <Field label="Colour"><Select value={f.colour} onChange={s("colour")} options={L.equipment_colour} placeholder="Select colour"/></Field>
        <Field label="Registration / Plate"><Input value={f.registration} onChange={s("registration")}/></Field>
        <Field label="Serial Number"><Input value={f.serial_number} onChange={s("serial_number")}/></Field>
        <Field label="Condition"><Select value={f.condition} onChange={s("condition")} options={["Operational","Serviceable","Unserviceable","Seized","Destroyed","Unknown"]} placeholder="Select condition"/></Field>
        <Field label="Assigned To"><Input value={f.assigned_to} onChange={s("assigned_to")} placeholder="Person or unit"/></Field>
        <Field label="Date Acquired"><Input type="date" value={f.date_acquired} onChange={s("date_acquired")}/></Field>
        <Field label="Date Disposed"><Input type="date" value={f.date_disposed} onChange={s("date_disposed")}/></Field>
      </div>
      <Field label="Description / Notes"><Textarea value={f.description} onChange={s("description")} rows={3}/></Field>
      <Field label="Tags"><TagsInput tags={f.tags||[]} setTags={s("tags")}/></Field>
      <TasksSection tasks={f.tasks||[]} setTasks={s("tasks")}/>
      <NotesSection notes={f.inv_notes||[]} setNotes={s("inv_notes")}/>
      <FilesSection files={f.files||[]} setFiles={s("files")}/>
      <LinksSection links={f.links||[]} setLinks={s("links")} allRecords={allRecords} onOpenRecord={onOpenRecord}/>
      <RecordProps record={f}/>
    </div>
  );
}
function StubForm({ label,record,onSave,onCancel, onOpenRecord, readOnly=false, onDelete, onDuplicate }){const[f,setF]=useState(record||{});return(<div><h2>{label}</h2><button onClick={()=>onSave({...f,id:f.id||Date.now()})}>Save</button><button onClick={onCancel}>Cancel</button></div>);}
function GenericList({label,records,onNew,onEdit}){return <StubList label={label} records={records} onNew={onNew} onEdit={onEdit}/>;}


// ─── RELATIONSHIP GRAPH ──────────────────────────────────────────────────────

const REG_COLORS = {
  person:"#1a4a8a",organisation:"#0ea5e9",information:"#8b5cf6",
  statement:"#f59e0b",source:"#dc2626",material:"#64748b",
  intelligence:"#7c3aed",event:"#0891b2",communication:"#059669",
  investigation:"#1d4ed8",incident:"#b91c1c",address:"#a16207",
  assessment:"#0f766e",case:"#7e22ce",decision:"#15803d",
  outcome:"#b45309",staff:"#1e40af",equipment:"#374151",
};
const REG_ICONS = {
  person:"👤",organisation:"🏢",information:"📄",statement:"📋",
  source:"🔒",material:"📦",intelligence:"◆",event:"◷",
  communication:"📱",investigation:"🔍",incident:"🚨",address:"📍",
  assessment:"📊",case:"⚖",decision:"✔",outcome:"🏁",
  staff:"👥",equipment:"🔧",
};

function getNodeLabel(reg, record) {
  if (!record) return "Unknown";
  if (reg==="person"||reg==="source"||reg==="staff")
    return [record.forenames, record.surname].filter(Boolean).join(" ") || record.urn || "—";
  if (reg==="organisation") return record.name || record.urn || "—";
  if (reg==="communication") return record.number_address || record.urn || "—";
  if (reg==="address") return [record.address_line1, record.city].filter(Boolean).join(", ") || record.urn || "—";
  if (reg==="equipment") return [record.make, record.model].filter(Boolean).join(" ") || record.urn || "—";
  return record.title || record.name || record.urn || "—";
}

function buildGraphData(records, filterReg, filterId) {
  const nodes = new Map(); // id -> node
  const edges = [];

  const addNode = (reg, record) => {
    const id = reg + ":" + record.id;
    if (!nodes.has(id)) {
      nodes.set(id, {
        id, reg, record,
        label: getNodeLabel(reg, record),
        urn: record.urn || "—",
        color: REG_COLORS[reg] || "#64748b",
        icon: REG_ICONS[reg] || "◆",
        linkCount: 0,
      });
    }
    return id;
  };

  // Start from all records that have links, or filter to one record's network
  const allRecs = [];
  Object.entries(records).forEach(([reg, recs]) => {
    recs.forEach(r => {
      if ((r.links||[]).length > 0) allRecs.push({reg, record:r});
    });
  });

  // If filtered, do BFS from the seed node
  let seedRecs = allRecs;
  if (filterReg && filterId) {
    const visited = new Set();
    const queue = [{reg:filterReg, id:filterId}];
    while (queue.length > 0) {
      const {reg, id} = queue.shift();
      const key = reg+":"+id;
      if (visited.has(key)) continue;
      visited.add(key);
      const rec = (records[reg]||[]).find(r=>r.id===id||r.urn===id);
      if (!rec) continue;
      (rec.links||[]).forEach(link => {
        const targetRecs = records[link.to_register]||[];
        const target = targetRecs.find(r=>r.id===link.to_id||r.urn===link.to_id||r.urn===link.to_label.split(" — ")[0]);
        if (target && !visited.has(link.to_register+":"+target.id)) {
          queue.push({reg:link.to_register, id:target.id});
        }
      });
      seedRecs = allRecs; // reset - we'll filter below
    }
    // Only include records in the visited set
    seedRecs = [];
    visited.forEach(key => {
      const [r, id] = key.split(":");
      const rec = (records[r]||[]).find(rc=>rc.id==id);
      if (rec) seedRecs.push({reg:r, record:rec});
    });
  }

  // Build nodes and edges
  seedRecs.forEach(({reg, record}) => {
    const srcId = addNode(reg, record);
    (record.links||[]).forEach(link => {
      const targetRecs = records[link.to_register]||[];
      const target = targetRecs.find(r =>
        r.id===link.to_id || r.urn===link.to_id ||
        (link.to_label && r.urn===link.to_label.split(" — ")[0])
      );
      if (target) {
        const tgtId = addNode(link.to_register, target);
        const edgeId = [srcId, tgtId].sort().join("--");
        if (!edges.find(e=>e.id===edgeId)) {
          edges.push({id:edgeId, source:srcId, target:tgtId, type:link.link_type||""});
          nodes.get(srcId).linkCount++;
          nodes.get(tgtId).linkCount++;
        }
      }
    });
  });

  return {nodes:[...nodes.values()], edges};
}

function RelationshipGraph({ records, onOpenRecord }) {
  const svgRef = React.useRef(null);
  const simRef = React.useRef(null);
  const [filterReg, setFilterReg] = React.useState("");
  const [filterId, setFilterId]   = React.useState("");
  const [selected, setSelected]   = React.useState(null);
  const [graphData, setGraphData] = React.useState({nodes:[],edges:[]});
  const [zoom, setZoom]           = React.useState(1);
  const [pan, setPan]             = React.useState({x:0,y:0});
  const [dragging, setDragging]   = React.useState(null);

  // Build graph data when filter changes
  React.useEffect(() => {
    const data = buildGraphData(records, filterReg, filterId);
    setGraphData(data);
    setSelected(null);
  }, [records, filterReg, filterId]);

  // D3 force simulation
  React.useEffect(() => {
    if (!window.d3 || graphData.nodes.length === 0) return;
    const d3 = window.d3;
    const width = 800, height = 560;

    // Clone nodes/edges for d3 (it mutates them)
    const nodes = graphData.nodes.map(n => ({...n, x: width/2+(Math.random()-0.5)*200, y: height/2+(Math.random()-0.5)*200}));
    const edges = graphData.edges.map(e => ({...e,
      source: nodes.find(n=>n.id===e.source),
      target: nodes.find(n=>n.id===e.target),
    })).filter(e=>e.source&&e.target);

    if (simRef.current) simRef.current.stop();

    simRef.current = d3.forceSimulation(nodes)
      .force("link", d3.forceLink(edges).id(d=>d.id).distance(120).strength(0.8))
      .force("charge", d3.forceManyBody().strength(-300))
      .force("center", d3.forceCenter(width/2, height/2))
      .force("collision", d3.forceCollide().radius(40))
      .on("tick", () => {
        if (!svgRef.current) return;
        const svg = svgRef.current;

        // Update edge positions
        svg.querySelectorAll(".graph-edge").forEach(el => {
          const eid = el.getAttribute("data-id");
          const edge = edges.find(e=>e.id===eid);
          if (!edge||!edge.source||!edge.target) return;
          el.setAttribute("x1", edge.source.x);
          el.setAttribute("y1", edge.source.y);
          el.setAttribute("x2", edge.target.x);
          el.setAttribute("y2", edge.target.y);
        });

        // Update node positions
        svg.querySelectorAll(".graph-node-g").forEach(el => {
          const nid = el.getAttribute("data-id");
          const node = nodes.find(n=>n.id===nid);
          if (!node) return;
          el.setAttribute("transform", `translate(${node.x},${node.y})`);
        });
      });

    // Store node positions for drag
    svgRef.current._nodes = nodes;
    svgRef.current._edges = edges;

    return () => { if (simRef.current) simRef.current.stop(); };
  }, [graphData]);

  const nodeRadius = (node) => Math.max(20, Math.min(36, 20 + node.linkCount * 3));

  // All investigation/incident records for the filter dropdown
  const filterOptions = [
    ...Object.entries(records).flatMap(([reg, recs]) =>
      recs.filter(r=>(r.links||[]).length>0).map(r=>({
        value: reg+":"+r.id,
        label: `${REG_ICONS[reg]||"◆"} ${getNodeLabel(reg,r)} (${r.urn})`
      }))
    )
  ];

  const totalLinks = graphData.edges.length;
  const totalNodes = graphData.nodes.length;

  return (
    <div>
      {/* Header */}
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:"20px"}}>
        <div>
          <h1 style={{margin:0,fontSize:"22px",fontWeight:"800",color:K.navy,fontFamily:"Georgia,serif"}}>
            🕸 Relationship Graph
          </h1>
          <div style={{fontSize:"12px",color:K.textMid,marginTop:"4px"}}>
            {totalNodes} nodes · {totalLinks} connections
            {filterReg && " · filtered view"}
          </div>
        </div>
        <div style={{display:"flex",gap:"10px",alignItems:"center"}}>
          <select value={filterReg ? filterReg+":"+filterId : ""}
            onChange={e=>{
              if(!e.target.value){setFilterReg("");setFilterId("");}
              else{const[r,id]=e.target.value.split(":");setFilterReg(r);setFilterId(id);}
            }}
            style={{padding:"7px 11px",border:"1px solid "+K.border,borderRadius:"4px",
              fontSize:"12px",color:K.text,background:K.surface,outline:"none",
              fontFamily:"inherit",maxWidth:"280px"}}>
            <option value="">Show all linked records</option>
            {filterOptions.map(o=><option key={o.value} value={o.value}>{o.label}</option>)}
          </select>
          {(filterReg||filterId) && <Btn small onClick={()=>{setFilterReg("");setFilterId("");}}>Show All</Btn>}
        </div>
      </div>

      {/* Legend */}
      <div style={{display:"flex",gap:"8px",flexWrap:"wrap",marginBottom:"16px"}}>
        {Object.entries(REG_COLORS).filter(([reg])=>
          graphData.nodes.some(n=>n.reg===reg)
        ).map(([reg,color])=>(
          <div key={reg} style={{display:"flex",alignItems:"center",gap:"4px",
            padding:"3px 8px",background:color+"18",borderRadius:"4px",fontSize:"11px"}}>
            <div style={{width:"8px",height:"8px",borderRadius:"50%",background:color,flexShrink:0}}/>
            <span style={{color,fontWeight:"700",textTransform:"capitalize"}}>{reg}</span>
          </div>
        ))}
      </div>

      {graphData.nodes.length === 0 ? (
        <div style={{background:K.surface,border:"1px solid "+K.border,borderRadius:"8px",
          padding:"80px",textAlign:"center"}}>
          <div style={{fontSize:"48px",marginBottom:"16px"}}>🕸</div>
          <div style={{fontSize:"16px",fontWeight:"700",color:K.text,marginBottom:"8px"}}>
            No linked records found
          </div>
          <div style={{fontSize:"13px",color:K.textMid}}>
            Add Universal Links to records to see them appear here.
          </div>
        </div>
      ) : (
        <div style={{display:"grid",gridTemplateColumns:"1fr 280px",gap:"16px"}}>
          {/* SVG Graph */}
          <div style={{background:K.surface,border:"1px solid "+K.border,
            borderRadius:"8px",overflow:"hidden",position:"relative"}}>

            {/* Zoom controls */}
            <div style={{position:"absolute",top:"12px",right:"12px",zIndex:10,
              display:"flex",flexDirection:"column",gap:"4px"}}>
              {[["＋",0.2],["－",-0.2],["⟳",0]].map(([label,delta])=>(
                <button key={label} onClick={()=>{
                  if(delta===0){setZoom(1);setPan({x:0,y:0});}
                  else setZoom(z=>Math.max(0.3,Math.min(2.5,z+delta)));
                }}
                  style={{width:"28px",height:"28px",background:K.surface,
                    border:"1px solid "+K.border,borderRadius:"4px",cursor:"pointer",
                    fontSize:"14px",fontWeight:"700",color:K.text,
                    display:"flex",alignItems:"center",justifyContent:"center"}}>
                  {label}
                </button>
              ))}
            </div>

            <svg ref={svgRef} width="100%" viewBox="0 0 800 560"
              style={{display:"block",cursor:dragging?"grabbing":"grab"}}
              onMouseMove={e=>{
                if(!dragging) return;
                const {nodeId, startX, startY, origX, origY} = dragging;
                const rect = e.currentTarget.getBoundingClientRect();
                const scaleX = 800/rect.width, scaleY = 560/rect.height;
                const dx = (e.clientX - startX)*scaleX/zoom;
                const dy = (e.clientY - startY)*scaleY/zoom;
                if(nodeId && svgRef.current._nodes) {
                  const node = svgRef.current._nodes.find(n=>n.id===nodeId);
                  if(node){node.x=origX+dx;node.y=origY+dy;node.fx=node.x;node.fy=node.y;}
                  if(simRef.current) simRef.current.alpha(0.3).restart();
                }
              }}
              onMouseUp={()=>{
                if(dragging?.nodeId && svgRef.current._nodes){
                  const node = svgRef.current._nodes.find(n=>n.id===dragging.nodeId);
                  if(node){node.fx=null;node.fy=null;}
                }
                setDragging(null);
              }}
              onMouseLeave={()=>setDragging(null)}>

              <g transform={`translate(${pan.x},${pan.y}) scale(${zoom})`}>
                {/* Edges */}
                {graphData.edges.map(e=>(
                  <line key={e.id} className="graph-edge" data-id={e.id}
                    stroke="#cbd5e1" strokeWidth="1.5" strokeOpacity="0.6"
                    x1="400" y1="280" x2="400" y2="280"/>
                ))}

                {/* Edge labels */}
                {graphData.edges.map(e=>{
                  const src = svgRef.current?._nodes?.find(n=>n.id===e.source);
                  const tgt = svgRef.current?._nodes?.find(n=>n.id===e.target);
                  if(!src||!tgt||!e.type) return null;
                  return null; // skip labels for now - too cluttered
                })}

                {/* Nodes */}
                {graphData.nodes.map(node=>{
                  const r = nodeRadius(node);
                  const isSelected = selected?.id === node.id;
                  return (
                    <g key={node.id} className="graph-node-g" data-id={node.id}
                      transform="translate(400,280)"
                      style={{cursor:"pointer"}}
                      onMouseDown={e=>{
                        e.stopPropagation();
                        const rect = svgRef.current.getBoundingClientRect();
                        const nd = svgRef.current._nodes?.find(n=>n.id===node.id);
                        setDragging({nodeId:node.id,startX:e.clientX,startY:e.clientY,
                          origX:nd?.x||400,origY:nd?.y||280});
                      }}
                      onClick={e=>{e.stopPropagation();setSelected(node);}}>
                      {/* Shadow */}
                      <circle cx="2" cy="2" r={r} fill="rgba(0,0,0,0.1)"/>
                      {/* Node circle */}
                      <circle r={r}
                        fill={node.color+"22"}
                        stroke={node.color}
                        strokeWidth={isSelected?3:1.5}/>
                      {/* Icon */}
                      <text textAnchor="middle" dominantBaseline="middle"
                        y={-4} fontSize={r>28?16:13} style={{userSelect:"none",pointerEvents:"none"}}>
                        {node.icon}
                      </text>
                      {/* URN */}
                      <text textAnchor="middle" dominantBaseline="middle"
                        y={r>28?8:6} fontSize="7"
                        fill={node.color} fontWeight="700" fontFamily="monospace"
                        style={{userSelect:"none",pointerEvents:"none"}}>
                        {node.urn.length>12?node.urn.substring(0,12)+"…":node.urn}
                      </text>
                      {/* Label below node */}
                      <text textAnchor="middle" y={r+14} fontSize="10"
                        fill={K.text} fontFamily="inherit" fontWeight="600"
                        style={{userSelect:"none",pointerEvents:"none"}}>
                        {node.label.length>18?node.label.substring(0,18)+"…":node.label}
                      </text>
                    </g>
                  );
                })}
              </g>
            </svg>
          </div>

          {/* Detail panel */}
          <div style={{display:"flex",flexDirection:"column",gap:"12px"}}>
            {selected ? (
              <div style={{background:K.surface,border:"1px solid "+K.border,
                borderRadius:"8px",padding:"16px"}}>
                <div style={{display:"flex",alignItems:"center",gap:"8px",marginBottom:"12px"}}>
                  <div style={{width:"36px",height:"36px",borderRadius:"50%",
                    background:selected.color+"22",border:"2px solid "+selected.color,
                    display:"flex",alignItems:"center",justifyContent:"center",
                    fontSize:"18px",flexShrink:0}}>{selected.icon}</div>
                  <div>
                    <div style={{fontWeight:"800",color:K.navy,fontSize:"14px"}}>{selected.label}</div>
                    <div style={{fontFamily:"monospace",fontSize:"11px",color:selected.color,fontWeight:"700"}}>{selected.urn}</div>
                  </div>
                </div>
                <div style={{fontSize:"11px",color:K.textMid,marginBottom:"6px",
                  textTransform:"capitalize",fontWeight:"700"}}>{selected.reg}</div>
                {selected.record.classification && (
                  <div style={{marginBottom:"10px"}}><ClassBadge v={selected.record.classification}/></div>
                )}
                {selected.record.type && (
                  <div style={{fontSize:"12px",color:K.textMid,marginBottom:"4px"}}>
                    <strong>Type:</strong> {selected.record.type}
                  </div>
                )}
                {selected.record.status && (
                  <div style={{fontSize:"12px",color:K.textMid,marginBottom:"4px"}}>
                    <strong>Status:</strong> {selected.record.status}
                  </div>
                )}
                {selected.record.description && (
                  <div style={{fontSize:"12px",color:K.textMid,marginBottom:"8px",
                    lineHeight:"1.5",borderTop:"1px solid "+K.border,paddingTop:"8px",marginTop:"8px"}}>
                    {selected.record.description.substring(0,150)}{selected.record.description.length>150?"…":""}
                  </div>
                )}
                <div style={{fontSize:"11px",color:K.textDim,marginBottom:"10px"}}>
                  {selected.linkCount} connection{selected.linkCount!==1?"s":""}
                </div>
                <div style={{display:"flex",flexDirection:"column",gap:"6px"}}>
                  <Btn variant="primary" onClick={()=>onOpenRecord&&onOpenRecord(selected.reg,selected.record)}>
                    Open Record ↗
                  </Btn>
                  <Btn onClick={()=>{setFilterReg(selected.reg);setFilterId(selected.record.id);}}>
                    Focus Graph Here
                  </Btn>
                </div>
              </div>
            ) : (
              <div style={{background:K.surface,border:"1px solid "+K.border,
                borderRadius:"8px",padding:"20px",textAlign:"center",color:K.textDim}}>
                <div style={{fontSize:"32px",marginBottom:"8px"}}>👆</div>
                <div style={{fontSize:"12px"}}>Click any node to see details</div>
              </div>
            )}

            {/* Node list */}
            <div style={{background:K.surface,border:"1px solid "+K.border,
              borderRadius:"8px",padding:"12px",maxHeight:"300px",overflowY:"auto"}}>
              <div style={{fontSize:"10px",fontWeight:"800",color:K.textMid,
                letterSpacing:"1.5px",marginBottom:"8px"}}>ALL NODES ({totalNodes})</div>
              {graphData.nodes.sort((a,b)=>b.linkCount-a.linkCount).map(node=>(
                <div key={node.id}
                  onClick={()=>setSelected(node)}
                  style={{display:"flex",alignItems:"center",gap:"8px",
                    padding:"6px 8px",borderRadius:"4px",cursor:"pointer",
                    background:selected?.id===node.id?K.blueLight:"transparent"}}
                  onMouseEnter={e=>e.currentTarget.style.background=K.blueLight}
                  onMouseLeave={e=>e.currentTarget.style.background=selected?.id===node.id?K.blueLight:"transparent"}>
                  <div style={{width:"8px",height:"8px",borderRadius:"50%",
                    background:node.color,flexShrink:0}}/>
                  <div style={{flex:1,minWidth:0}}>
                    <div style={{fontSize:"11px",fontWeight:"700",color:K.text,
                      overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>
                      {node.label}
                    </div>
                    <div style={{fontSize:"10px",color:K.textDim,fontFamily:"monospace"}}>{node.urn}</div>
                  </div>
                  <div style={{fontSize:"10px",color:node.color,fontWeight:"700",flexShrink:0}}>
                    {node.linkCount}
                  </div>
                </div>
              ))}
            </div>
          </div>
        </div>
      )}
    </div>
  );
}


// ─── RBAC ─────────────────────────────────────────────────────────────────────
const CLEARANCE_RANK = {"UNCLASSIFIED":0,"RESTRICTED":1,"CONFIDENTIAL":2,"SECRET":3,"TOP SECRET":4};
const ROLE_PERMS = {
  superadmin:  {canCreate:true, canEdit:true, canDelete:true},
  analyst:     {canCreate:true, canEdit:true, canDelete:false},
  investigator:{canCreate:true, canEdit:true, canDelete:false},
  viewer:      {canCreate:false,canEdit:false,canDelete:false},
};
const canViewRecord = (user, record) => {
  if (!record || !record.classification) return true;
  return (CLEARANCE_RANK[user.clearance]||0) >= (CLEARANCE_RANK[record.classification]||0);
};
const userPerms = (user) => ROLE_PERMS[user && user.role] || ROLE_PERMS.viewer;

// ─── AUDIT LOG ────────────────────────────────────────────────────────────────
const AUDIT_ICON  = {login:"🔑",logout:"🚪",create:"➕",edit:"✏",delete:"🗑",view:"👁",rbac_block:"🔒"};
const AUDIT_COLOR = {login:"#0ea5e9",logout:"#64748b",create:"#10b981",edit:"#f59e0b",delete:"#ef4444",view:"#8b5cf6",rbac_block:"#dc2626"};
const AUDIT_LABEL = {login:"Login",logout:"Logout",create:"Created",edit:"Edited",delete:"Deleted",view:"Viewed",rbac_block:"Access Denied"};

function makeAuditEntry(user, action, reg, urn, detail) {
  return {
    id: Date.now() + Math.random(),
    ts: new Date().toISOString(),
    user_name: user ? user.name : "System",
    user_role: user ? user.role : "",
    action: action,
    reg: reg || "",
    urn: urn || "",
    detail: detail || "",
  };
}

function AuditLogView({ auditLog, onClear, user }) {
  const [filter, setFilter] = useState("");
  const perms = userPerms(user);
  const fmtTS = function(ts) {
    const d = new Date(ts);
    return d.toLocaleDateString("en-GB",{day:"2-digit",month:"short",year:"numeric"})
      + " " + d.toLocaleTimeString("en-GB",{hour:"2-digit",minute:"2-digit"});
  };
  const shown = auditLog.filter(function(e) {
    if (!filter) return true;
    const q = filter.toLowerCase();
    return e.action.includes(q) || e.user_name.toLowerCase().includes(q) || (e.urn||"").toLowerCase().includes(q);
  }).slice().reverse();

  return (
    <div>
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"24px"}}>
        <div>
          <h1 style={{margin:0,fontSize:"22px",fontWeight:"800",color:K.navy,fontFamily:"Georgia,serif"}}>
            📋 Audit Log
          </h1>
          <div style={{fontSize:"12px",color:K.textMid,marginTop:"4px"}}>
            {auditLog.length} events recorded
          </div>
        </div>
        <div style={{display:"flex",gap:"8px"}}>
          <input value={filter} onChange={function(e){setFilter(e.target.value);}}
            placeholder="Filter events..."
            style={{padding:"7px 11px",border:"1px solid "+K.border,borderRadius:"4px",fontSize:"12px",
              color:K.text,background:K.surface,outline:"none",fontFamily:"inherit",width:"180px"}}/>
          {perms.canDelete && auditLog.length > 0 && (
            <Btn onClick={function(){if(window.confirm("Clear audit log?")) onClear();}}>Clear</Btn>
          )}
        </div>
      </div>
      {shown.length === 0 ? (
        <div style={{background:K.surface,border:"1px solid "+K.border,borderRadius:"8px",
          padding:"40px",textAlign:"center",color:K.textDim,fontSize:"13px"}}>
          No audit events recorded yet.
        </div>
      ) : (
        <div style={{background:K.surface,border:"1px solid "+K.border,borderRadius:"8px",overflow:"hidden"}}>
          <table style={{width:"100%",borderCollapse:"collapse",fontSize:"12px"}}>
            <thead>
              <tr style={{background:K.surfaceAlt}}>
                {["Timestamp","User","Action","Register","URN / Record","Detail"].map(function(h) {
                  return (
                    <th key={h} style={{padding:"10px 14px",textAlign:"left",fontSize:"10px",
                      fontWeight:"800",color:K.textMid,letterSpacing:"1px",
                      borderBottom:"1px solid "+K.border,whiteSpace:"nowrap"}}>{h}</th>
                  );
                })}
              </tr>
            </thead>
            <tbody>
              {shown.map(function(e, i) {
                const color = AUDIT_COLOR[e.action] || K.textMid;
                return (
                  <tr key={e.id} style={{borderBottom:"1px solid "+K.border,
                    background:i%2 ? K.surfaceAlt : K.surface}}>
                    <td style={{padding:"8px 14px",fontFamily:"monospace",fontSize:"11px",
                      color:K.textMid,whiteSpace:"nowrap"}}>{fmtTS(e.ts)}</td>
                    <td style={{padding:"8px 14px",whiteSpace:"nowrap"}}>
                      <div style={{fontWeight:"700",color:K.text}}>{e.user_name}</div>
                      <div style={{fontSize:"10px",color:K.textMid}}>{ROLE_LABEL[e.user_role]||e.user_role}</div>
                    </td>
                    <td style={{padding:"8px 14px",whiteSpace:"nowrap"}}>
                      <span style={{display:"inline-flex",alignItems:"center",gap:"5px",
                        padding:"2px 8px",borderRadius:"4px",
                        background:color+"22",color:color,
                        fontSize:"11px",fontWeight:"700"}}>
                        {AUDIT_ICON[e.action]} {AUDIT_LABEL[e.action]||e.action}
                      </span>
                    </td>
                    <td style={{padding:"8px 14px",color:K.textMid,fontSize:"11px",
                      textTransform:"capitalize"}}>{e.reg||"—"}</td>
                    <td style={{padding:"8px 14px",fontFamily:"monospace",fontSize:"11px",
                      color:K.blue,fontWeight:"700"}}>{e.urn||"—"}</td>
                    <td style={{padding:"8px 14px",color:K.textMid,fontSize:"11px",
                      maxWidth:"200px",overflow:"hidden",textOverflow:"ellipsis",
                      whiteSpace:"nowrap"}}>{e.detail||""}</td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}

// ─── WATCHLIST ────────────────────────────────────────────────────────────────
const WL_PC = {
  Critical:{fg:"#991b1b",bg:"#fee2e2",border:"#fca5a5"},
  High:    {fg:"#92400e",bg:"#fef3c7",border:"#fcd34d"},
  Medium:  {fg:"#1e40af",bg:"#dbeafe",border:"#93c5fd"},
  Low:     {fg:"#374151",bg:"#f3f4f6",border:"#d1d5db"},
};
const WL_CATS = ["Person","Location","Financial","Vehicle","Digital","Keyword","URN","Other"];
const WL_PRIS = ["Critical","High","Medium","Low"];
const WL_FIELDS = ["title","name","surname","forenames","description","number_address",
  "address_line1","city","country","registration_number","passport_number",
  "make","model","registration","serial_number","handler_reference","reference"];

function scanRecordsForKeyword(keyword, records) {
  const kw = keyword.toLowerCase().trim();
  if (!kw) return [];
  const hits = [];
  Object.entries(records).forEach(function(entry) {
    const reg = entry[0];
    const recs = entry[1];
    recs.forEach(function(record) {
      const matched = [];
      WL_FIELDS.forEach(function(field) {
        if (record[field] && String(record[field]).toLowerCase().includes(kw))
          matched.push(field.replace(/_/g," "));
      });
      (record.tags||[]).forEach(function(t) {
        if (String(t).toLowerCase().includes(kw)) matched.push("tag");
      });
      (record.inv_notes||[]).forEach(function(n) {
        if ((n.details||"").toLowerCase().includes(kw)) matched.push("note");
      });
      if ((record.urn||"").toLowerCase().includes(kw)) matched.push("urn");
      // Search extracted text from file attachments
      (record.files||[]).forEach(function(file) {
        if (file.extracted_text && file.extracted_text.toLowerCase().includes(kw)) {
          matched.push("file: "+(file.title||file.file_name||"attachment"));
        }
      });
      if (matched.length > 0) {
        hits.push({reg:reg, record:record, fields:[...new Set(matched)]});
      }
    });
  });
  return hits;
}

function WatchlistView({ watchlist, setWatchlist, records, onOpenRecord, user }) {
  const [adding, setAdding] = useState(false);
  const [expanded, setExpanded] = useState(null);
  const [form, setForm] = useState({keyword:"",category:"Keyword",priority:"Medium",notes:"",active:true});

  const allHits = useMemo(function() {
    const out = {};
    watchlist.filter(function(w){return w.active;}).forEach(function(w) {
      out[w.id] = scanRecordsForKeyword(w.keyword, records);
    });
    return out;
  }, [watchlist, records]);

  const totalHits = Object.values(allHits).reduce(function(a,b){return a+b.length;}, 0);

  function addItem() {
    if (!(form.keyword||"").trim()) return;
    setWatchlist(function(prev) {
      return [...prev, Object.assign({}, form, {
        id: Date.now(),
        keyword: (form.keyword||"").trim(),
        added_by: user.name,
        date_added: new Date().toISOString().split("T")[0],
      })];
    });
    setForm({keyword:"",category:"Keyword",priority:"Medium",notes:"",active:true});
    setAdding(false);
  }

  return (
    <div>
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:"24px"}}>
        <div>
          <h1 style={{margin:0,fontSize:"22px",fontWeight:"800",color:K.navy,fontFamily:"Georgia,serif"}}>
            🎯 Keyword Watchlist
          </h1>
          <div style={{fontSize:"12px",color:K.textMid,marginTop:"4px"}}>
            {watchlist.length} keyword{watchlist.length !== 1 ? "s" : ""} · {watchlist.filter(function(w){return w.active;}).length} active · <span style={{color:totalHits>0?K.red:K.green,fontWeight:"700"}}>{totalHits} hit{totalHits !== 1 ? "s" : ""}</span>
          </div>
        </div>
        <Btn variant="primary" onClick={function(){setAdding(!adding);}}>
          {adding ? "← Cancel" : "+ Add Keyword"}
        </Btn>
      </div>

      {adding && (
        <div style={{background:K.surfaceAlt,border:"1px solid "+K.border,borderRadius:"8px",padding:"20px",marginBottom:"20px"}}>
          <div style={{display:"grid",gridTemplateColumns:"2fr 1fr 1fr",gap:"12px",marginBottom:"12px"}}>
            <Field label="Keyword / Term">
              <Input value={form.keyword} onChange={function(v){setForm(function(p){return Object.assign({},p,{keyword:v});});}} placeholder="name, number, place, URN..."/>
            </Field>
            <Field label="Category">
              <Select value={form.category} onChange={function(v){setForm(function(p){return Object.assign({},p,{category:v});});}} options={WL_CATS}/>
            </Field>
            <Field label="Priority">
              <Select value={form.priority} onChange={function(v){setForm(function(p){return Object.assign({},p,{priority:v});});}} options={WL_PRIS}/>
            </Field>
          </div>
          <Field label="Notes">
            <Input value={form.notes} onChange={function(v){setForm(function(p){return Object.assign({},p,{notes:v});});}} placeholder="Why is this term being watched?"/>
          </Field>
          <div style={{display:"flex",gap:"8px",marginTop:"12px"}}>
            <Btn variant="primary" onClick={addItem} disabled={!(form.keyword||"").trim()}>Add to Watchlist</Btn>
            <Btn onClick={function(){setAdding(false);}}>Cancel</Btn>
          </div>
        </div>
      )}

      {watchlist.length === 0 ? (
        <div style={{background:K.surface,border:"1px solid "+K.border,borderRadius:"8px",padding:"60px",textAlign:"center"}}>
          <div style={{fontSize:"40px",marginBottom:"12px"}}>🎯</div>
          <div style={{fontSize:"16px",fontWeight:"700",color:K.text,marginBottom:"8px"}}>No keywords being watched</div>
          <div style={{fontSize:"13px",color:K.textMid,marginBottom:"16px"}}>Add keywords to automatically scan all records for matches</div>
          <Btn variant="primary" onClick={function(){setAdding(true);}}>+ Add First Keyword</Btn>
        </div>
      ) : (
        <div style={{background:K.surface,border:"1px solid "+K.border,borderRadius:"8px",overflow:"hidden"}}>
          <table style={{width:"100%",borderCollapse:"collapse",fontSize:"12px"}}>
            <thead>
              <tr style={{background:K.surfaceAlt}}>
                {["Keyword","Category","Priority","Hits","Added","Active",""].map(function(h) {
                  return (
                    <th key={h} style={{padding:"10px 14px",textAlign:"left",fontSize:"10px",
                      fontWeight:"800",color:K.textMid,letterSpacing:"1px",
                      borderBottom:"1px solid "+K.border,whiteSpace:"nowrap"}}>{h}</th>
                  );
                })}
              </tr>
            </thead>
            <tbody>
              {watchlist.map(function(w, idx) {
                const hits = allHits[w.id] || [];
                const pc = WL_PC[w.priority] || WL_PC.Medium;
                const isExp = expanded === w.id;
                return (
                  <React.Fragment key={w.id}>
                    <tr style={{borderBottom:"1px solid "+K.border,
                      background:isExp ? K.blueLight : (idx%2 ? K.surfaceAlt : K.surface),
                      opacity:w.active ? 1 : 0.5}}>
                      <td style={{padding:"10px 14px"}}>
                        <div style={{fontWeight:"800",fontFamily:"monospace",fontSize:"13px",color:K.navy}}>{w.keyword}</div>
                        {w.notes && <div style={{fontSize:"11px",color:K.textMid,marginTop:"2px"}}>{w.notes}</div>}
                      </td>
                      <td style={{padding:"10px 14px"}}>
                        <span style={{padding:"2px 8px",borderRadius:"3px",background:"#e0e7ff",color:"#3730a3",fontSize:"11px",fontWeight:"700"}}>{w.category}</span>
                      </td>
                      <td style={{padding:"10px 14px"}}>
                        <span style={{padding:"2px 8px",borderRadius:"4px",background:pc.bg,color:pc.fg,border:"1px solid "+pc.border,fontSize:"11px",fontWeight:"800"}}>{w.priority}</span>
                      </td>
                      <td style={{padding:"10px 14px"}}>
                        {hits.length > 0 ? (
                          <button onClick={function(){setExpanded(isExp ? null : w.id);}}
                            style={{background:"none",border:"none",cursor:"pointer",padding:0}}>
                            <span style={{padding:"3px 10px",background:pc.bg,color:pc.fg,
                              border:"1px solid "+pc.border,borderRadius:"10px",fontSize:"11px",fontWeight:"800"}}>
                              {hits.length} hit{hits.length !== 1 ? "s" : ""}
                            </span>
                            <span style={{fontSize:"10px",color:K.blue,marginLeft:"4px"}}>{isExp ? "▲" : "▼"}</span>
                          </button>
                        ) : <span style={{fontSize:"11px",color:K.textDim}}>—</span>}
                      </td>
                      <td style={{padding:"10px 14px",color:K.textMid,fontSize:"11px",whiteSpace:"nowrap"}}>{w.date_added||""}</td>
                      <td style={{padding:"10px 14px"}}>
                        <button onClick={function(){setWatchlist(function(prev){return prev.map(function(x){return x.id===w.id ? Object.assign({},x,{active:!x.active}) : x;});});}}
                          style={{padding:"3px 10px",borderRadius:"10px",cursor:"pointer",fontSize:"10px",
                            fontWeight:"700",border:"1px solid",fontFamily:"inherit",
                            background:w.active ? "#dcfce7" : "#f3f4f6",
                            color:w.active ? "#166534" : K.textDim,
                            borderColor:w.active ? "#86efac" : K.border}}>
                          {w.active ? "Active" : "Paused"}
                        </button>
                      </td>
                      <td style={{padding:"10px 14px"}}>
                        <button onClick={function(){setWatchlist(function(prev){return prev.filter(function(x){return x.id!==w.id;});});if(expanded===w.id)setExpanded(null);}}
                          style={{background:"none",border:"none",color:K.textDim,cursor:"pointer",fontSize:"12px"}}
                          onMouseEnter={function(e){e.currentTarget.style.color=K.red;}}
                          onMouseLeave={function(e){e.currentTarget.style.color=K.textDim;}}>✕</button>
                      </td>
                    </tr>
                    {isExp && hits.length > 0 && (
                      <tr>
                        <td colSpan={7} style={{padding:0,borderBottom:"1px solid "+K.border}}>
                          <div style={{background:"#f0f7ff",borderLeft:"4px solid "+K.blue,padding:"12px 16px"}}>
                            <div style={{fontSize:"10px",fontWeight:"800",color:K.blue,letterSpacing:"1.5px",marginBottom:"10px"}}>
                              MATCHES FOR "{w.keyword}" — {hits.length} RECORD{hits.length !== 1 ? "S" : ""}
                            </div>
                            <div style={{display:"flex",flexDirection:"column",gap:"6px"}}>
                              {hits.map(function(hit, hi) {
                                const meta = REGISTER_META[hit.reg] || {label:hit.reg,icon:"◆"};
                                return (
                                  <div key={hi}
                                    onClick={onOpenRecord ? function(){onOpenRecord(hit.reg, hit.record);} : undefined}
                                    style={{display:"flex",alignItems:"center",gap:"12px",padding:"8px 12px",
                                      background:K.surface,borderRadius:"5px",border:"1px solid "+K.border,
                                      cursor:onOpenRecord ? "pointer" : "default"}}
                                    onMouseEnter={function(e){if(onOpenRecord)e.currentTarget.style.background=K.blueLight;}}
                                    onMouseLeave={function(e){if(onOpenRecord)e.currentTarget.style.background=K.surface;}}>
                                    <span style={{fontSize:"14px"}}>{meta.icon}</span>
                                    <span style={{fontFamily:"monospace",fontSize:"11px",color:K.blue,fontWeight:"700",whiteSpace:"nowrap",minWidth:"100px"}}>{hit.record.urn}</span>
                                    <div style={{flex:1,minWidth:0}}>
                                      <div style={{fontSize:"12px",fontWeight:"700",color:K.text,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>
                                        {hit.record.title || hit.record.name || [hit.record.forenames,hit.record.surname].filter(Boolean).join(" ") || hit.record.urn}
                                      </div>
                                      <div style={{fontSize:"10px",color:K.textMid}}>
                                        {meta.label} · matched in: <span style={{fontWeight:"700",color:K.navy}}>{hit.fields.join(", ")}</span>
                                      </div>
                                    </div>
                                    {hit.record.classification && <ClassBadge v={hit.record.classification}/>}
                                    {onOpenRecord && <span style={{fontSize:"11px",color:K.blue,opacity:0.6}}>↗</span>}
                                  </div>
                                );
                              })}
                            </div>
                          </div>
                        </td>
                      </tr>
                    )}
                  </React.Fragment>
                );
              })}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}

// ─── USERS ───────────────────────────────────────────────────────────────────
const DEFAULT_USERS = [
  { id:"u1", username:"mark.watson",   password:"koios2025", name:"Mark Watson",   role:"superadmin",   clearance:"CONFIDENTIAL", initials:"MW", colour:"#0ea5e9", active:true },
  { id:"u2", username:"jolene.watson", password:"koios2025", name:"Jolene Watson", role:"analyst",      clearance:"CONFIDENTIAL", initials:"JW", colour:"#8b5cf6", active:true },
  { id:"u3", username:"jordan.winn",   password:"koios2025", name:"Jordan Winn",   role:"investigator", clearance:"CONFIDENTIAL", initials:"JW", colour:"#10b981", active:true },
];
const ROLE_LABEL = { superadmin:"Super Admin", analyst:"Analyst", investigator:"Investigator", viewer:"Viewer" };


// ─── LOGIN SCREEN ────────────────────────────────────────────────────────────
function LoginScreen({ onLogin }) {
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(false);

  const handleLogin = () => {
    setLoading(true); setError("");
    setTimeout(() => {
      const user = (window._koiosUsers||DEFAULT_USERS).find(u => u.active!==false && u.username === username.toLowerCase().trim() && u.password === password);
      if (user) { onLogin(user); }
      else { setError("Invalid username or password."); setLoading(false); }
    }, 600);
  };

  return (
    <div style={{ minHeight:"100vh", background:"#0d1f3c",
      display:"flex", alignItems:"center", justifyContent:"center",
      fontFamily:"'Palatino Linotype','Book Antiqua',Palatino,Georgia,serif" }}>
      <div style={{ width:"380px" }}>
        {/* Logo */}
        <div style={{ textAlign:"center", marginBottom:"40px" }}>
          <img src="/mnt/user-data/uploads/koios_logo_icon_only.png" alt="KOIOS"
            style={{ width:"60px", height:"60px", objectFit:"contain",
              filter:"brightness(0) invert(1)", opacity:0.9, marginBottom:"16px",
              display:"block", margin:"0 auto 16px" }}
            onError={e=>e.target.style.display="none"}/>
          <div style={{ fontSize:"28px", fontWeight:"800", color:"#fff",
            letterSpacing:"6px", marginBottom:"4px" }}>KOIOS</div>
          <div style={{ fontSize:"11px", color:"rgba(255,255,255,0.4)",
            letterSpacing:"3px" }}>INVESTIGATION MANAGEMENT SYSTEM</div>
          <div style={{ fontSize:"11px", color:"rgba(255,255,255,0.25)",
            letterSpacing:"2px", marginTop:"4px" }}>ARCTICWIND</div>
        </div>

        {/* Card */}
        <div style={{ background:"rgba(255,255,255,0.06)", borderRadius:"10px",
          padding:"32px", border:"1px solid rgba(255,255,255,0.12)",
          backdropFilter:"blur(10px)" }}>
          <div style={{ marginBottom:"20px" }}>
            <label style={{ display:"block", fontSize:"11px", fontWeight:"700",
              color:"rgba(255,255,255,0.5)", letterSpacing:"1.5px",
              textTransform:"uppercase", marginBottom:"8px" }}>Username</label>
            <input value={username} onChange={e=>setUsername(e.target.value)}
              onKeyDown={e=>e.key==="Enter"&&handleLogin()}
              placeholder="your.name"
              style={{ width:"100%", padding:"11px 14px",
                background:"rgba(255,255,255,0.08)",
                border:"1px solid rgba(255,255,255,0.15)", borderRadius:"5px",
                color:"#fff", fontSize:"14px", outline:"none",
                boxSizing:"border-box", fontFamily:"inherit",
                letterSpacing:"0.5px" }}/>
          </div>
          <div style={{ marginBottom:"24px" }}>
            <label style={{ display:"block", fontSize:"11px", fontWeight:"700",
              color:"rgba(255,255,255,0.5)", letterSpacing:"1.5px",
              textTransform:"uppercase", marginBottom:"8px" }}>Password</label>
            <input type="password" value={password} onChange={e=>setPassword(e.target.value)}
              onKeyDown={e=>e.key==="Enter"&&handleLogin()}
              placeholder="••••••••"
              style={{ width:"100%", padding:"11px 14px",
                background:"rgba(255,255,255,0.08)",
                border:"1px solid rgba(255,255,255,0.15)", borderRadius:"5px",
                color:"#fff", fontSize:"14px", outline:"none",
                boxSizing:"border-box", fontFamily:"inherit" }}/>
          </div>
          {error && <div style={{ padding:"10px 14px", background:"rgba(153,27,27,0.3)",
            border:"1px solid rgba(239,68,68,0.4)", borderRadius:"5px",
            color:"#fca5a5", fontSize:"12px", marginBottom:"16px" }}>{error}</div>}
          <button onClick={handleLogin} disabled={loading||!username||!password}
            style={{ width:"100%", padding:"13px",
              background: loading||!username||!password ? "rgba(255,255,255,0.1)" : "#1a4a8a",
              border:"none", borderRadius:"5px",
              color: loading||!username||!password ? "rgba(255,255,255,0.3)" : "#fff",
              fontSize:"13px", fontWeight:"700", cursor: loading||!username||!password ? "not-allowed":"pointer",
              letterSpacing:"1px", fontFamily:"inherit", transition:"background 0.2s" }}>
            {loading ? "Authenticating…" : "SIGN IN"}
          </button>
        </div>
        <div style={{ textAlign:"center", marginTop:"20px",
          fontSize:"10px", color:"rgba(255,255,255,0.2)", letterSpacing:"1px" }}>
          ALL SESSIONS LOGGED · AUTHORISED ACCESS ONLY
        </div>
      </div>
    </div>
  );
}


// ─── DASHBOARD ───────────────────────────────────────────────────────────────
function Dashboard({ records, user, onNavigate, watchlist, onResetData, onExport, onImport }) {
  const counts = Object.fromEntries(Object.entries(records).map(([k,v])=>[k,v.length]));
  const totalRecords = Object.values(counts).reduce((a,b)=>a+b,0);

  // Tasks due/overdue
  const allTasks = Object.values(records).flatMap(recs =>
    recs.flatMap(r => (r.tasks||[]).map(t=>({...t, _reg:r.urn})))
  );
  const pendingTasks = allTasks.filter(t=>t.status==="Pending"||t.status==="In Progress");
  const overdueTasks = pendingTasks.filter(t=>isOverdue(t.due_date));

  // Review dates overdue
  const overdueReviews = Object.values(records).flatMap(recs =>
    recs.filter(r=>isOverdue(r.review_date))
  );

  // Open investigations
  const openInvs = records.investigation?.filter(r=>r.status==="Open")||[];

  const statCards = [
    { label:"Total Records",    value:totalRecords,             icon:"🗂",  color:K.blue,  action:null },
    { label:"Open Investigations", value:openInvs.length,       icon:"🔍",  color:K.green, action:"investigation" },
    { label:"Tasks Pending",    value:pendingTasks.length,      icon:"✅",  color:K.amber, action:null },
    { label:"Watchlist Hits", value:watchlist.filter(function(w){return w.active;}).reduce(function(a,w){return a+scanRecordsForKeyword(w.keyword,records).length;},0), icon:"🎯", color:K.red, action:"watchlist" },
    { label:"Overdue Reviews",  value:overdueReviews.length,    icon:"⚠",   color:overdueReviews.length>0?K.red:K.textDim, action:null },
  ];

  const regCards = [
    {id:"person",       label:"Persons",        icon:"👤"},
    {id:"organisation", label:"Organisations",  icon:"🏢"},
    {id:"incident",     label:"Incidents",      icon:"🚨"},
    {id:"statement",    label:"Statements",     icon:"📋"},
    {id:"source",       label:"Sources",        icon:"🔒"},
    {id:"material",     label:"Material",       icon:"📦"},
    {id:"intelligence", label:"Intelligence",   icon:"◆"},
    {id:"event",        label:"Events",         icon:"◷"},
    {id:"communication",label:"Comms",          icon:"📱"},
    {id:"information",  label:"Information",    icon:"📄"},
    {id:"investigation",label:"Investigations", icon:"🔍"},
    {id:"address",      label:"Addresses",      icon:"📍"},
  ];

  return (
    <div>
      {/* Welcome */}
      <div style={{ marginBottom:"28px" }}>
        <h1 style={{ margin:0, fontSize:"24px", fontWeight:"800", color:K.navy,
          fontFamily:"'Georgia','Times New Roman',serif" }}>
          Welcome back, {user.name.split(" ")[0]}
        </h1>
        <div style={{ fontSize:"13px", color:K.textMid, marginTop:"4px" }}>
          {new Date().toLocaleDateString("en-GB",{weekday:"long",day:"numeric",month:"long",year:"numeric"})}
          {" · "}<span style={{ fontFamily:"monospace", color:K.blue, fontWeight:"700" }}>{user.clearance}</span>
          {" · "}{ROLE_LABEL[user.role]}
        </div>
      </div>

      {/* Stat cards */}
      <div style={{ display:"grid", gridTemplateColumns:"repeat(4,1fr)", gap:"16px", marginBottom:"28px" }}>
        {statCards.map(c => (
          <div key={c.label} onClick={c.action?()=>onNavigate(c.action):undefined}
            style={{ background:K.surface, border:`1px solid ${K.border}`, borderRadius:"8px",
              padding:"20px", cursor:c.action?"pointer":"default",
              borderLeft:`4px solid ${c.color}`,
              boxShadow:"0 1px 3px rgba(0,0,0,0.06)", transition:"transform 0.1s" }}
            onMouseEnter={e=>{if(c.action)e.currentTarget.style.transform="translateY(-1px)";}}
            onMouseLeave={e=>e.currentTarget.style.transform="translateY(0)"}>
            <div style={{ fontSize:"24px", marginBottom:"8px" }}>{c.icon}</div>
            <div style={{ fontSize:"28px", fontWeight:"800", color:c.color, lineHeight:1 }}>{c.value}</div>
            <div style={{ fontSize:"12px", color:K.textMid, marginTop:"4px", fontWeight:"600" }}>{c.label}</div>
          </div>
        ))}
      </div>

      <div style={{ display:"grid", gridTemplateColumns:"2fr 1fr", gap:"20px" }}>
        {/* Register quick-access */}
        <div style={{ background:K.surface, border:`1px solid ${K.border}`,
          borderRadius:"8px", padding:"20px", boxShadow:"0 1px 3px rgba(0,0,0,0.06)" }}>
          <div style={{ fontSize:"11px", fontWeight:"800", color:K.blue,
            letterSpacing:"2px", marginBottom:"16px" }}>REGISTERS</div>
          <div style={{ display:"grid", gridTemplateColumns:"repeat(3,1fr)", gap:"10px" }}>
            {regCards.map(r => (
              <div key={r.id} onClick={()=>onNavigate(r.id)}
                style={{ padding:"12px", border:`1px solid ${K.border}`, borderRadius:"6px",
                  cursor:"pointer", display:"flex", flexDirection:"column", gap:"6px",
                  background:K.surfaceAlt, transition:"all 0.1s" }}
                onMouseEnter={e=>{e.currentTarget.style.background=K.blueLight;e.currentTarget.style.borderColor=K.blueMid;}}
                onMouseLeave={e=>{e.currentTarget.style.background=K.surfaceAlt;e.currentTarget.style.borderColor=K.border;}}>
                <span style={{ fontSize:"18px" }}>{r.icon}</span>
                <span style={{ fontSize:"12px", fontWeight:"700", color:K.text }}>{r.label}</span>
                <span style={{ fontSize:"20px", fontWeight:"800", color:K.blue, lineHeight:1 }}>{counts[r.id]||0}</span>
              </div>
            ))}
          </div>
        </div>

        {/* Tasks + overdue reviews */}
        <div style={{ display:"flex", flexDirection:"column", gap:"16px" }}>
          {/* Open investigations */}
          <div style={{ background:K.surface, border:`1px solid ${K.border}`,
            borderRadius:"8px", padding:"16px", boxShadow:"0 1px 3px rgba(0,0,0,0.06)" }}>
            <div style={{ fontSize:"11px", fontWeight:"800", color:K.blue,
              letterSpacing:"2px", marginBottom:"12px" }}>OPEN INVESTIGATIONS</div>
            {openInvs.length===0
              ? <p style={{ fontSize:"12px", color:K.textDim, margin:0 }}>None.</p>
              : openInvs.map(inv => (
                <div key={inv.id} onClick={()=>onNavigate("investigation")}
                  style={{ padding:"8px 10px", borderRadius:"5px", marginBottom:"6px",
                    background:K.greenLight, border:"1px solid #bbf7d0",
                    cursor:"pointer", fontSize:"12px" }}>
                  <div style={{ fontWeight:"700", color:K.green }}>{inv.urn}</div>
                  <div style={{ color:K.text, marginTop:"1px" }}>{inv.title}</div>
                </div>
              ))}
          </div>

          {/* Overdue reviews */}
          {overdueReviews.length > 0 && (
            <div style={{ background:K.surface, border:`1px solid ${K.red}`, borderLeft:`4px solid ${K.red}`,
              borderRadius:"8px", padding:"16px", boxShadow:"0 1px 3px rgba(0,0,0,0.06)", flex:1 }}>
              <div style={{ fontSize:"11px", fontWeight:"800", color:K.red,
                letterSpacing:"2px", marginBottom:"12px" }}>
                ⚠ OVERDUE REVIEWS ({overdueReviews.length})
              </div>
              <div style={{ display:"flex", flexDirection:"column", gap:"6px" }}>
                {overdueReviews.slice(0,6).map(r => (
                  <div key={r.id} style={{ display:"flex", justifyContent:"space-between",
                    alignItems:"center", padding:"6px 10px", background:K.redLight,
                    borderRadius:"5px", fontSize:"12px" }}>
                    <div>
                      <span style={{ fontFamily:"monospace", fontSize:"11px",
                        color:K.red, fontWeight:"700", marginRight:"8px" }}>{r.urn}</span>
                      <span style={{ color:K.text, fontWeight:"600" }}>
                        {r.title||r.name||[r.forenames,r.surname].filter(Boolean).join(" ")||"—"}
                      </span>
                    </div>
                    <div style={{ fontSize:"10px", color:K.red, whiteSpace:"nowrap", marginLeft:"8px" }}>
                      Due: {r.review_date}
                    </div>
                  </div>
                ))}
                {overdueReviews.length > 6 && (
                  <div style={{ fontSize:"11px", color:K.textDim, textAlign:"center", padding:"4px" }}>
                    +{overdueReviews.length - 6} more overdue
                  </div>
                )}
              </div>
            </div>
          )}
          {/* Overdue tasks */}
          <div style={{ background:K.surface, border:`1px solid ${K.border}`,
            borderRadius:"8px", padding:"16px", boxShadow:"0 1px 3px rgba(0,0,0,0.06)", flex:1 }}>
            <div style={{ fontSize:"11px", fontWeight:"800", color:K.blue,
              letterSpacing:"2px", marginBottom:"12px" }}>
              OVERDUE TASKS {overdueTasks.length>0&&<span style={{ color:K.red }}>({overdueTasks.length})</span>}
            </div>
            {overdueTasks.length===0
              ? <p style={{ fontSize:"12px", color:K.textDim, margin:0 }}>No overdue tasks. ✓</p>
              : overdueTasks.slice(0,5).map(t => (
                <div key={t.id} style={{ padding:"8px 10px", borderRadius:"5px",
                  marginBottom:"6px", background:K.redLight, border:"1px solid #fecaca",
                  fontSize:"12px" }}>
                  <div style={{ fontWeight:"700", color:K.red }}>{t.due_date} ⚠</div>
                  <div style={{ color:K.text }}>{t.title}</div>
                  {t.allocated_to&&<div style={{ color:K.textMid, fontSize:"11px" }}>→ {t.allocated_to}</div>}
                </div>
              ))}
            {overdueTasks.length>5&&<div style={{ fontSize:"11px", color:K.textDim, marginTop:"4px" }}>+{overdueTasks.length-5} more</div>}
          </div>
        </div>
      </div>
      <div style={{marginTop:"20px",padding:"12px 16px",background:K.surfaceAlt,border:"1px solid "+K.border,borderRadius:"8px",display:"flex",alignItems:"center",gap:"10px",flexWrap:"wrap"}}>
        <span style={{fontSize:"11px",color:K.textDim,flex:1}}>💾 Data saves automatically to this browser</span>
        <Btn small onClick={onExport}>⬇ Export</Btn>
        <label style={{cursor:"pointer"}}>
          <span style={{padding:"4px 10px",border:"1px solid "+K.border,borderRadius:"4px",fontSize:"12px",color:K.text,background:K.surface}}>⬆ Import</span>
          <input type="file" accept=".json" style={{display:"none"}} onChange={onImport}/>
        </label>
        {onResetData && <Btn small onClick={onResetData}>↺ Reset</Btn>}
      </div>
    </div>
  );
}


// ─── NAVIGATION HEADER ───────────────────────────────────────────────────────
const ALL_REGISTERS = [
  {id:"dashboard",    label:"Dashboard",     icon:"⌂",  group:"main"},
  {id:"person",       label:"Person",        icon:"👤", group:"registers"},
  {id:"organisation", label:"Organisation",  icon:"🏢", group:"registers"},
  {id:"information",  label:"Information",   icon:"📄", group:"registers"},
  {id:"statement",    label:"Statement",     icon:"📋", group:"registers"},
  {id:"source",       label:"Source",        icon:"🔒", group:"registers"},
  {id:"material",     label:"Material",      icon:"📦", group:"registers"},
  {id:"intelligence", label:"Intelligence",  icon:"◆",  group:"registers"},
  {id:"event",        label:"Event",         icon:"◷",  group:"registers"},
  {id:"communication",label:"Communication", icon:"📱", group:"registers"},
  {id:"investigation",label:"Investigation", icon:"🔍", group:"registers"},
  {id:"incident",     label:"Incident",      icon:"🚨", group:"registers"},
  {id:"address",      label:"Address",       icon:"📍", group:"registers"},
  {id:"assessment",   label:"Assessment",    icon:"📊", group:"registers"},
  {id:"case",         label:"Case",          icon:"⚖",  group:"registers"},
  {id:"decision",     label:"Decision",      icon:"✔",  group:"registers"},
  {id:"outcome",      label:"Outcome",       icon:"🏁", group:"registers"},
  {id:"staff",        label:"Staff",         icon:"👥", group:"registers"},
  {id:"equipment",    label:"Equipment",     icon:"🔧", group:"registers"},
  {id:"watchlist",    label:"Watchlist",     icon:"🎯", group:"tools"},
  {id:"auditlog",     label:"Audit Log",     icon:"📋", group:"tools"},
  {id:"graph",        label:"Graph",          icon:"🕸", group:"tools"},
  {id:"usermgmt",     label:"Users",          icon:"⚙", group:"tools"},
  {id:"listsmgr",     label:"Lists",          icon:"📋", group:"tools"},
];

function Header({ user, activeReg, onNavigate, onLogout, editingTitle }) {
  const [menuOpen, setMenuOpen] = useState(false);
  const [searchVal, setSearchVal] = useState("");

  const regItem = ALL_REGISTERS.find(r=>r.id===activeReg);

  return (
    <header style={{ background:K.navy, position:"sticky", top:0, zIndex:100,
      boxShadow:"0 2px 8px rgba(0,0,0,0.3)" }}>
      {/* Top bar */}
      <div style={{ display:"flex", alignItems:"center", padding:"0 24px",
        gap:"16px", height:"52px" }}>
        {/* Logo */}
        <div style={{ display:"flex", alignItems:"center", gap:"10px",
          paddingRight:"18px", borderRight:"1px solid rgba(255,255,255,0.15)",
          cursor:"pointer" }} onClick={()=>onNavigate("dashboard")}>
          <img src="/mnt/user-data/uploads/koios_logo_icon_only.png" alt="KOIOS"
            style={{ width:"28px", height:"28px", objectFit:"contain",
              filter:"brightness(0) invert(1)", opacity:0.9 }}
            onError={e=>e.target.style.display="none"}/>
          <div>
            <div style={{ fontSize:"15px", fontWeight:"800", color:"#fff",
              letterSpacing:"3px", lineHeight:1 }}>KOIOS</div>
            <div style={{ fontSize:"8px", color:"rgba(255,255,255,0.4)",
              letterSpacing:"2px", marginTop:"2px" }}>INVESTIGATION MANAGEMENT</div>
          </div>
        </div>

        {/* Breadcrumb */}
        <div style={{ display:"flex", alignItems:"center", gap:"6px", flex:1 }}>
          <span style={{ fontSize:"12px", color:"rgba(255,255,255,0.4)" }}>
            {activeReg==="dashboard"?"Home":"Registers"}
          </span>
          {activeReg!=="dashboard"&&<>
            <span style={{ color:"rgba(255,255,255,0.25)" }}>›</span>
            <span style={{ fontSize:"12px", color:"rgba(255,255,255,0.8)", fontWeight:"600" }}>
              {regItem?.label}
            </span>
          </>}
          {editingTitle&&<>
            <span style={{ color:"rgba(255,255,255,0.25)" }}>›</span>
            <span style={{ fontSize:"12px", color:"#60a5fa", fontWeight:"600" }}>
              {editingTitle.substring(0,45)}{editingTitle.length>45?"…":""}
            </span>
          </>}
        </div>

        {/* Quick search */}
        <div style={{ position:"relative" }}>
          <input value={searchVal} onChange={e=>setSearchVal(e.target.value)}
            placeholder="Quick search…"
            style={{ padding:"6px 12px 6px 30px",
              background:"rgba(255,255,255,0.1)",
              border:"1px solid rgba(255,255,255,0.2)", borderRadius:"4px",
              color:"#fff", fontSize:"12px", width:"180px", outline:"none",
              fontFamily:"inherit" }}/>
          <span style={{ position:"absolute", left:"9px", top:"50%",
            transform:"translateY(-50%)", fontSize:"12px", opacity:0.5 }}>🔍</span>
        </div>

        {/* User */}
        <div style={{ display:"flex", alignItems:"center", gap:"8px",
          paddingLeft:"16px", borderLeft:"1px solid rgba(255,255,255,0.15)",
          cursor:"pointer" }} onClick={()=>setMenuOpen(!menuOpen)}>
          <div style={{ width:"28px", height:"28px", borderRadius:"50%",
            background:user.colour, display:"flex", alignItems:"center",
            justifyContent:"center", color:"#fff", fontSize:"11px", fontWeight:"800" }}>
            {user.initials}
          </div>
          <div style={{ fontSize:"11px" }}>
            <div style={{ color:"#fff", fontWeight:"600" }}>{user.name}</div>
            <div style={{ fontSize:"9px", color:"rgba(255,255,255,0.4)" }}>
              {ROLE_LABEL[user.role]} · {user.clearance}
            </div>
          </div>
          <span style={{ color:"rgba(255,255,255,0.4)", fontSize:"10px" }}>▼</span>
        </div>
        {menuOpen&&(
          <div style={{ position:"absolute", top:"52px", right:"16px",
            background:K.surface, border:`1px solid ${K.border}`, borderRadius:"6px",
            boxShadow:"0 4px 16px rgba(0,0,0,0.15)", zIndex:200, minWidth:"160px" }}>
            <div style={{ padding:"10px 16px", fontSize:"12px", color:K.textMid,
              borderBottom:`1px solid ${K.border}` }}>
              Signed in as <strong style={{ color:K.text }}>{user.name}</strong>
            </div>
            <button onClick={onLogout}
              style={{ width:"100%", padding:"10px 16px", background:"none",
                border:"none", cursor:"pointer", textAlign:"left",
                fontSize:"12px", color:K.red, fontWeight:"600", fontFamily:"inherit" }}>
              Sign Out
            </button>
          </div>
        )}
      </div>

      {/* Register tab bar */}
      <div style={{ display:"flex", padding:"0 24px",
        borderTop:"1px solid rgba(255,255,255,0.08)", overflowX:"auto" }}>
        {ALL_REGISTERS.filter(r=>r.id!=="dashboard").map(r=>(
          <div key={r.id} onClick={()=>onNavigate(r.id)}
            style={{ padding:"8px 14px", fontSize:"11px", fontWeight:"600",
              cursor:"pointer", whiteSpace:"nowrap", letterSpacing:"0.3px",
              color: activeReg===r.id ? "#fff" : "rgba(255,255,255,0.4)",
              borderBottom: activeReg===r.id ? "2px solid #60a5fa" : "2px solid transparent",
              transition:"color 0.1s" }}>
            {r.label}
          </div>
        ))}
      </div>
    </header>
  );
}


// ─── REGISTER ROUTER ─────────────────────────────────────────────────────────
// Phase3 register config
const PHASE3_CFG = {
  address:{label:"Address",Form:AddressForm,
    columns:[
      {key:"type",label:"Type",style:{color:K.textMid,whiteSpace:"nowrap"}},
      {key:"_addr",label:"Address",render:r=><div><div style={{fontWeight:"700"}}>{[r.address_line1,r.city].filter(Boolean).join(", ")||"—"}</div><div style={{fontSize:"10px",color:K.textDim}}>{r.country||""}</div></div>},
      {key:"_coords",label:"Coordinates",render:r=>r.latitude&&r.longitude?<span style={{fontFamily:"monospace",fontSize:"11px",color:K.textMid}}>{r.latitude}, {r.longitude}</span>:<span style={{color:K.textDim}}>—</span>},
    ]},
  assessment:{label:"Assessment",Form:AssessmentForm,
    columns:[
      {key:"type",label:"Type",style:{color:K.textMid,whiteSpace:"nowrap"}},
      {key:"title",label:"Title",render:r=><div><div style={{fontWeight:"700"}}>{r.title}</div></div>},
      {key:"assessment_date",label:"Date",render:r=><span style={{color:K.textMid,fontSize:"11px"}}>{fmtDate(r.assessment_date)}</span>},
      {key:"assessed_by",label:"Assessed By",style:{color:K.textMid,fontSize:"11px"}},
    ]},
  case:{label:"Case",Form:CaseForm,
    columns:[
      {key:"type",label:"Type",style:{color:K.textMid,whiteSpace:"nowrap"}},
      {key:"title",label:"Title",render:r=><div style={{fontWeight:"700"}}>{r.title}</div>},
      {key:"status",label:"Status",render:r=>{const s=CASE_STATUS_COLOR[r.status]||{fg:K.textDim,bg:"#f1f5f9",border:"#e2e8f0"};return r.status?<span style={{padding:"3px 10px",background:s.bg,color:s.fg,border:`1px solid ${s.border}`,borderRadius:"10px",fontSize:"11px",fontWeight:"700"}}>{r.status}</span>:<span style={{color:K.textDim}}>—</span>;}},
      {key:"priority",label:"Priority",render:r=>{const p=PRIORITY_COLOR[r.priority];return r.priority?<span style={{padding:"2px 8px",background:p.bg,color:p.fg,border:`1px solid ${p.border}`,borderRadius:"4px",fontSize:"11px",fontWeight:"800"}}>{r.priority}</span>:<span style={{color:K.textDim}}>—</span>;}},
    ]},
  decision:{label:"Decision",Form:DecisionForm,
    columns:[
      {key:"type",label:"Type",style:{color:K.textMid,whiteSpace:"nowrap"}},
      {key:"title",label:"Title",render:r=><div><div style={{fontWeight:"700"}}>{r.title}</div></div>},
      {key:"decision_date",label:"Date",render:r=><span style={{color:K.textMid,fontSize:"11px"}}>{fmtDate(r.decision_date)}</span>},
      {key:"decided_by",label:"Decided By",style:{color:K.textMid,fontSize:"11px"}},
    ]},
  outcome:{label:"Outcome",Form:OutcomeForm,
    columns:[
      {key:"type",label:"Type",style:{color:K.textMid,whiteSpace:"nowrap"}},
      {key:"title",label:"Title",render:r=><div><div style={{fontWeight:"700"}}>{r.title}</div></div>},
    ]},
  staff:{label:"Staff",Form:StaffForm,
    columns:[
      {key:"type",label:"Type",style:{color:K.textMid,whiteSpace:"nowrap"}},
      {key:"_name",label:"Name",render:r=><div><div style={{fontWeight:"700"}}>{[r.title,r.forenames,r.surname].filter(Boolean).join(" ")||"—"}</div><div style={{fontSize:"10px",color:K.textDim}}>{r.department||""}</div></div>},
      {key:"clearance",label:"Clearance",render:r=>r.clearance?<ClassBadge v={r.clearance}/>:<span style={{color:K.textDim}}>—</span>},
    ]},
  equipment:{label:"Equipment",Form:EquipmentForm,
    columns:[
      {key:"type",label:"Type",style:{color:K.textMid,whiteSpace:"nowrap"}},
      {key:"_desc",label:"Description",render:r=><div><div style={{fontWeight:"700"}}>{[r.make,r.model].filter(Boolean).join(" ")||"—"}</div><div style={{fontSize:"10px",color:K.textDim}}>{[r.colour,r.registration].filter(Boolean).join(" · ")||""}</div></div>},
      {key:"serial_number",label:"Serial Number",style:{fontFamily:"monospace",fontSize:"11px",color:K.textMid}},
    ]},
};


// ─── MAIN APP ────────────────────────────────────────────────────────────────
export default function App() {
  const [user, setUser]           = useState(null);
  // localStorage boot
  const _boot = (function() {
    try {
      const raw = localStorage.getItem("koios_v2");
      return raw ? JSON.parse(raw) : null;
    } catch(e) { return null; }
  })();
  const [records,  setRecords]  = useState((_boot && _boot.records)  || INITIAL_RECORDS);
  const [appL,     setAppL]     = useState((_boot && _boot.appL)     || DEFAULT_L);
  // L is available module-wide via window._koiosL (set above)
  const [auditLog, setAuditLog] = useState((_boot && _boot.auditLog) || []);
  const [appUsers, setAppUsers] = useState((_boot && _boot.appUsers) || DEFAULT_USERS);
  const [watchlist,setWatchlist]= useState((_boot && _boot.watchlist) || [
    {id:1,keyword:"AL-ASSAD",  category:"Person",  priority:"Critical",active:true,notes:"Primary subjects",added_by:"Mark Watson",date_added:"2025-11-01"},
    {id:2,keyword:"Yarmouk",   category:"Location",priority:"Critical",active:true,notes:"Camp location",   added_by:"Mark Watson",date_added:"2025-11-01"},
    {id:3,keyword:"4TH ARMOUR",category:"Keyword", priority:"High",   active:true,notes:"Unit responsible", added_by:"Lucy Myles",  date_added:"2025-11-03"},
    {id:4,keyword:"SPARROW",   category:"Keyword", priority:"High",   active:true,notes:"Source reference", added_by:"Mark Watson",date_added:"2025-11-05"},
    {id:5,keyword:"starvation",category:"Keyword", priority:"Medium", active:true,notes:"Mode of liability",added_by:"Elise Baranowski",date_added:"2025-11-08"},
  ]);
  const [activeReg, setActiveReg] = useState("dashboard");
  const [view, setView]           = useState("list");   // "list" | "form"
  const [editing, setEditing]     = useState(null);
  const [saved, setSaved]         = useState(null);

  // ── Sync users and L to window ───────────────────────────────────────────────
  useEffect(function() { window._koiosUsers = appUsers; }, [appUsers]);
  useEffect(function() { window._koiosL = appL; }, [appL]);

  // ── Session timeout (30 min inactivity) ─────────────────────────────────────
  const lastActivity = React.useRef(Date.now());
  const [timeoutWarning, setTimeoutWarning] = React.useState(false);
  const TIMEOUT_MS = 30 * 60 * 1000;   // 30 minutes
  const WARNING_MS = 28 * 60 * 1000;   // warn at 28 min

  useEffect(function() {
    if (!user) return;
    const bump = function() { lastActivity.current = Date.now(); setTimeoutWarning(false); };
    window.addEventListener("mousemove", bump);
    window.addEventListener("keydown", bump);
    window.addEventListener("click", bump);
    const interval = setInterval(function() {
      const idle = Date.now() - lastActivity.current;
      if (idle >= TIMEOUT_MS) {
        setAuditLog(function(prev) {
          return [...prev, makeAuditEntry(user, "logout", "", "", "Auto-logout: session timeout")];
        });
        setUser(null); setActiveReg("dashboard"); setView("list"); setEditing(null);
        setTimeoutWarning(false);
      } else if (idle >= WARNING_MS) {
        setTimeoutWarning(true);
      }
    }, 30000);
    return function() {
      window.removeEventListener("mousemove", bump);
      window.removeEventListener("keydown", bump);
      window.removeEventListener("click", bump);
      clearInterval(interval);
    };
  }, [user]);

  // ── Load D3 ──────────────────────────────────────────────────────────────────
  React.useEffect(function() {
    if (window.d3) return;
    const script = document.createElement("script");
    script.src = "https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js";
    script.onload = function() { console.log("D3 loaded"); };
    document.head.appendChild(script);
  }, []);

  // ── Persist to localStorage ─────────────────────────────────────────────────
  useEffect(function() {
    try {
      localStorage.setItem("koios_v2", JSON.stringify({records:records,auditLog:auditLog,watchlist:watchlist,appUsers:appUsers,appL:appL}));
    } catch(e) { /* storage full */ }
  }, [records, auditLog, watchlist]);

  // ── Navigation ──────────────────────────────────────────────────────────────
  const navigate = useCallback(function(reg, record) {
    setActiveReg(reg);
    if (record) { setEditing(record); setView("form"); }
    else { setView("list"); setEditing(null); }
  }, []);

  const openNew = useCallback(() => {
    setEditing(null); setView("form");
  }, []);

  const openEdit = useCallback(function(record) {
    if (record && record._redacted) {
      alert("Access Denied: Insufficient clearance to view this record.");
      return;
    }
    setEditing(record); setView("form");
    if (record && record.id) {
      setAuditLog(function(prev) {
        return [...prev, makeAuditEntry(user, "view", activeReg, record.urn||"", "Viewed record")];
      });
    }
  }, [user, activeReg]);

  const handleCancel = useCallback(() => {
    setView("list"); setEditing(null);
  }, []);

  const handleBulkSave = useCallback(function(reg, newRecords) {
    setRecords(function(prev) {
      return Object.assign({}, prev, {[reg]: [...(prev[reg]||[]), ...newRecords]});
    });
    setAuditLog(function(prev) {
      return [...prev, makeAuditEntry(user, "create", reg, "",
        "Bulk import: "+newRecords.length+" "+reg+" records added")];
    });
  }, [user]);

  const handleDuplicate = useCallback(function(reg, record) {
    const duped = Object.assign({}, record, {
      id: Date.now(),
      urn: makeURN(reg),
      title: record.title ? "COPY — " + record.title : undefined,
      name:  record.name  ? "COPY — " + record.name  : undefined,
      surname: record.surname ? record.surname : undefined,
      forenames: record.forenames ? record.forenames + " (COPY)" : undefined,
    });
    // Clean undefined values
    Object.keys(duped).forEach(k => duped[k] === undefined && delete duped[k]);
    setRecords(function(prev) {
      return Object.assign({}, prev, {[reg]: [...(prev[reg]||[]), duped]});
    });
    setAuditLog(function(prev) {
      return [...prev, makeAuditEntry(user, "create", reg, duped.urn,
        "Duplicated from " + (record.urn||""))];
    });
    setEditing(duped);
    setView("form");
  }, [user]);

  const handleDelete = useCallback(function(reg, record) {
    if (!window.confirm("Delete " + record.urn + "?\n\nThis cannot be undone.")) return;
    setRecords(function(prev) {
      return Object.assign({}, prev, {
        [reg]: (prev[reg]||[]).filter(function(r){ return r.id !== record.id; })
      });
    });
    setAuditLog(function(prev) {
      return [...prev, makeAuditEntry(user, "delete", reg, record.urn||"", "Deleted "+reg+" record")];
    });
    setView("list"); setEditing(null);
  }, [user]);

  // ── Save ────────────────────────────────────────────────────────────────────
  const handleSave = useCallback(function(reg, record) {
    const saved_record = { ...record, id: record.id||Date.now(), urn: record.urn||makeURN(reg) };
    // Store previous version for history
    const existing = (records[reg]||[]).find(r => r.id === saved_record.id);
    if (existing) {
      saved_record._prev = {
        _saved_at: existing._saved_at || new Date().toISOString(),
        _saved_by: existing._saved_by || (user ? user.name : "Unknown"),
        ...Object.fromEntries(
          Object.entries(existing).filter(([k]) => !k.startsWith('_'))
        ),
      };
    }
    saved_record._saved_at = new Date().toISOString();
    saved_record._saved_by = user ? user.name : "Unknown";
    setRecords(prev => {
      const existing = prev[reg]||[];
      const idx = existing.findIndex(r=>r.id===saved_record.id);
      const updated = idx>=0
        ? existing.map((r,i)=>i===idx?saved_record:r)
        : [...existing, saved_record];
      return {...prev, [reg]: updated};
    });
    const isNew = !record.id || !(records[reg]||[]).find(function(r){return r.id===record.id;});
    setAuditLog(function(prev) {
      return [...prev, makeAuditEntry(user, isNew?"create":"edit", reg, saved_record.urn, (isNew?"Created ":"Edited ")+reg+" record")];
    });
    setSaved(saved_record.urn);
    setView("list"); setEditing(null);
    setTimeout(function(){setSaved(null);}, 3000);
  }, [user, records]);

  // ── Login / Logout ──────────────────────────────────────────────────────────
  if (!user) return <LoginScreen onLogin={function(u) {
    setUser(u);
    setAuditLog(function(prev) {
      return [...prev, makeAuditEntry(u, "login", "", "", "Signed in as "+u.name)];
    });
  }}/>;

  // ── Editing title for breadcrumb ────────────────────────────────────────────
  const editingTitle = editing
    ? (editing.title || editing.surname || editing.name || editing.number_address || editing.urn || "New Record")
    : null;

  // ── Common props shared into every Form/List ─────────────────────────────────
  const sharedProps = { allRecords: records };

  // ── Render register ──────────────────────────────────────────────────────────
  const renderRegister = () => {
    const reg = activeReg;
    const perms = userPerms(user);
    const onOpenRecord = function(targetReg, targetRecord) {
      if (!canViewRecord(user, targetRecord)) {
        setAuditLog(function(prev) {
          return [...prev, makeAuditEntry(user, "rbac_block", targetReg, targetRecord.urn||"",
            "Blocked: "+targetRecord.classification+" above "+user.clearance)];
        });
        alert("Access Denied: This record is classified "+targetRecord.classification+". Your clearance is "+user.clearance+".");
        return;
      }
      navigate(targetReg, targetRecord);
    };
    const regRecords = (records[reg]||[]).map(function(r) {
      if (canViewRecord(user, r)) return r;
      return Object.assign({}, r, {
        _redacted: true,
        title: "["+r.classification+" — Access Restricted]",
        name:  "["+r.classification+" — Access Restricted]",
        surname: "[RESTRICTED]", forenames: "",
        description: "", number_address: "[RESTRICTED]",
      });
    });
    const onSave = (record) => handleSave(reg, record);
    const onDelete = function(record) { handleDelete(reg, record); };
    const onBulkSave = function(recs) { handleBulkSave(reg, recs); };
    const onDuplicate = function(record) { handleDuplicate(reg, record); };

    // Dashboard
    if (reg==="dashboard") return <Dashboard records={records} user={user} onNavigate={navigate}
        watchlist={watchlist}
        onExport={function() {
          const data = JSON.stringify({records,watchlist,auditLog,exported:new Date().toISOString(),version:"KOIOS-1.0"},null,2);
          const blob = new Blob([data],{type:"application/json"});
          const url = URL.createObjectURL(blob);
          const a = document.createElement("a");
          a.href=url; a.download="koios-"+new Date().toISOString().split("T")[0]+".json"; a.click();
          URL.revokeObjectURL(url);
        }}
        onImport={function(e) {
          const file = e.target.files[0]; if(!file) return;
          const reader = new FileReader();
          reader.onload = function(ev) {
            try {
              const data = JSON.parse(ev.target.result);
              if(!data.records){alert("Invalid KOIOS file.");return;}
              if(!window.confirm("Import will replace all current data. Continue?")) return;
              setRecords(data.records);
              if(data.watchlist) setWatchlist(data.watchlist);
              if(data.auditLog) setAuditLog(data.auditLog);
              alert("Imported successfully.");
            } catch(err){ alert("Import failed: "+err.message); }
          };
          reader.readAsText(file); e.target.value="";
        }}
        onResetData={function(){
          if(window.confirm("Reset all data to demo defaults?")) {
            setRecords(INITIAL_RECORDS);
            setAuditLog([]);
          }
        }}/>;

    // Person
    if (reg==="person") return view==="list"
      ? <PersonList records={regRecords} onNew={perms.canCreate ? openNew : undefined} onEdit={openEdit} perms={perms} onBulkSave={onBulkSave}/>
      : <PersonForm record={editing} onSave={onSave} onCancel={handleCancel} allRecords={records} onOpenRecord={onOpenRecord} readOnly={!perms.canEdit} onDelete={perms.canDelete ? onDelete : undefined}/>;

    // Organisation
    if (reg==="organisation") return view==="list"
      ? <OrgList records={regRecords} onNew={perms.canCreate ? openNew : undefined} onEdit={openEdit} perms={perms} onDelete={perms.canDelete?onDelete:undefined} onDuplicate={perms.canCreate?onDuplicate:undefined} onBulkSave={onBulkSave} allRecords={records}/>
      : <OrgForm record={editing} onSave={onSave} onCancel={handleCancel} allRecords={records} onOpenRecord={onOpenRecord} readOnly={!perms.canEdit} onDelete={perms.canDelete ? onDelete : undefined}/>;

    // Information
    if (reg==="information") return view==="list"
      ? <InfoList records={regRecords} onNew={perms.canCreate ? openNew : undefined} onEdit={openEdit} perms={perms} onDelete={perms.canDelete?onDelete:undefined} onDuplicate={perms.canCreate?onDuplicate:undefined}/>
      : <InfoForm record={editing} onSave={onSave} onCancel={handleCancel} allRecords={records} onOpenRecord={onOpenRecord} readOnly={!perms.canEdit} onDelete={perms.canDelete ? onDelete : undefined}/>;

    // Statement
    if (reg==="statement") return view==="list"
      ? <StatementList records={regRecords} onNew={perms.canCreate ? openNew : undefined} onEdit={openEdit} perms={perms} onDelete={perms.canDelete?onDelete:undefined} onDuplicate={perms.canCreate?onDuplicate:undefined}/>
      : <StatementForm record={editing} onSave={onSave} onCancel={handleCancel} allRecords={records} onOpenRecord={onOpenRecord} readOnly={!perms.canEdit} onDelete={perms.canDelete ? onDelete : undefined}/>;

    // Source
    if (reg==="source") return view==="list"
      ? <SourceList records={regRecords} onNew={perms.canCreate ? openNew : undefined} onEdit={openEdit} perms={perms} onDelete={perms.canDelete?onDelete:undefined} onDuplicate={perms.canCreate?onDuplicate:undefined}/>
      : <SourceForm record={editing} onSave={onSave} onCancel={handleCancel} allRecords={records} onOpenRecord={onOpenRecord} readOnly={!perms.canEdit} onDelete={perms.canDelete ? onDelete : undefined}/>;

    // Material
    if (reg==="material") return view==="list"
      ? <MaterialList records={regRecords} onNew={perms.canCreate ? openNew : undefined} onEdit={openEdit} perms={perms} onDelete={perms.canDelete?onDelete:undefined} onDuplicate={perms.canCreate?onDuplicate:undefined}/>
      : <MaterialForm record={editing} onSave={onSave} onCancel={handleCancel} allRecords={records} onOpenRecord={onOpenRecord} readOnly={!perms.canEdit} onDelete={perms.canDelete ? onDelete : undefined}/>;

    // Intelligence
    if (reg==="intelligence") return view==="list"
      ? <IntelList records={regRecords} onNew={perms.canCreate ? openNew : undefined} onEdit={openEdit} perms={perms} onDelete={perms.canDelete?onDelete:undefined} onDuplicate={perms.canCreate?onDuplicate:undefined}/>
      : <IntelForm record={editing} onSave={onSave} onCancel={handleCancel} allRecords={records} onOpenRecord={onOpenRecord} readOnly={!perms.canEdit} onDelete={perms.canDelete ? onDelete : undefined}/>;

    // Event
    if (reg==="event") return view==="list"
      ? <EventList records={regRecords} onNew={perms.canCreate ? openNew : undefined} onEdit={openEdit} perms={perms} onDelete={perms.canDelete?onDelete:undefined} onDuplicate={perms.canCreate?onDuplicate:undefined}/>
      : <EventForm record={editing} onSave={onSave} onCancel={handleCancel} allRecords={records} onOpenRecord={onOpenRecord} readOnly={!perms.canEdit} onDelete={perms.canDelete ? onDelete : undefined}/>;

    // Communication
    if (reg==="communication") return view==="list"
      ? <CommList records={regRecords} onNew={perms.canCreate ? openNew : undefined} onEdit={openEdit} perms={perms} onDelete={perms.canDelete?onDelete:undefined} onDuplicate={perms.canCreate?onDuplicate:undefined}/>
      : <CommForm record={editing} onSave={onSave} onCancel={handleCancel} allRecords={records} onOpenRecord={onOpenRecord} readOnly={!perms.canEdit} onDelete={perms.canDelete ? onDelete : undefined}/>;

    // Investigation
    if (reg==="investigation") return view==="list"
      ? <InvList records={regRecords} onNew={perms.canCreate ? openNew : undefined} onEdit={openEdit} perms={perms} onDelete={perms.canDelete?onDelete:undefined} onDuplicate={perms.canCreate?onDuplicate:undefined}/>
      : <InvForm record={editing} onSave={onSave} onCancel={handleCancel} allRecords={records} onOpenRecord={onOpenRecord} readOnly={!perms.canEdit} onDelete={perms.canDelete ? onDelete : undefined}/>;

    // Incident
    if (reg==="incident") return view==="list"
      ? <IncList records={regRecords} onNew={perms.canCreate ? openNew : undefined} onEdit={openEdit} perms={perms} onDelete={perms.canDelete?onDelete:undefined} onDuplicate={perms.canCreate?onDuplicate:undefined}/>
      : <IncForm record={editing} onSave={onSave} onCancel={handleCancel} allRecords={records} onOpenRecord={onOpenRecord} readOnly={!perms.canEdit} onDelete={perms.canDelete ? onDelete : undefined}/>;

    // Lists Manager (superadmin only)
    if (reg === "listsmgr") {
      if (user.role !== "superadmin") return (
        <div style={{textAlign:"center",padding:"60px",color:K.textDim}}>
          <div style={{fontSize:"32px",marginBottom:"12px"}}>🔒</div>
          <div style={{fontSize:"14px",fontWeight:"700"}}>Access Denied</div>
          <div style={{fontSize:"12px",marginTop:"6px"}}>Lists management requires Super Admin role.</div>
        </div>
      );
      return <ListsManager appL={appL} setAppL={setAppL} defaultL={DEFAULT_L}/>;
    }

    // User Management (superadmin only)
    if (reg === "usermgmt") {
      if (user.role !== "superadmin") return (
        <div style={{textAlign:"center",padding:"60px",color:K.textDim}}>
          <div style={{fontSize:"32px",marginBottom:"12px"}}>🔒</div>
          <div style={{fontSize:"14px",fontWeight:"700"}}>Access Denied</div>
          <div style={{fontSize:"12px",marginTop:"6px"}}>User management requires Super Admin role.</div>
        </div>
      );
      return <UserManagement appUsers={appUsers} setAppUsers={setAppUsers} currentUser={user}/>;
    }

    // Relationship Graph
    if (reg === "graph") return (
      <RelationshipGraph records={records} onOpenRecord={onOpenRecord}/>
    );

    // Watchlist
    if (reg === "watchlist") return (
      <WatchlistView
        watchlist={watchlist}
        setWatchlist={setWatchlist}
        records={records}
        onOpenRecord={onOpenRecord}
        user={user}
      />
    );

    // Audit Log
    if (reg === "auditlog") return (
      <AuditLogView
        auditLog={auditLog}
        onClear={function(){setAuditLog([]);}}
        user={user}
      />
    );

    // Phase 3 registers
    const P3_MAP = {
      address:    {List:AddressList,    Form:AddressForm},
      assessment: {List:AssessmentList, Form:AssessmentForm},
      case:       {List:CaseList,       Form:CaseForm},
      decision:   {List:DecisionList,   Form:DecisionForm},
      outcome:    {List:OutcomeList,    Form:OutcomeForm},
      staff:      {List:StaffList,      Form:StaffForm},
      equipment:  {List:EquipmentList,  Form:EquipmentForm},
    };
    if (P3_MAP[reg]) {
      const {List: P3List, Form: P3Form} = P3_MAP[reg];
      return view==="list"
        ? <P3List records={regRecords} onNew={perms.canCreate?openNew:undefined} onEdit={openEdit} perms={perms} onDelete={perms.canDelete?onDelete:undefined} onDuplicate={perms.canCreate?onDuplicate:undefined}/>
        : <P3Form record={editing} onSave={perms.canEdit?onSave:null} onCancel={handleCancel}
            allRecords={records} onOpenRecord={onOpenRecord}
            readOnly={!perms.canEdit} onDelete={perms.canDelete?onDelete:undefined} onDuplicate={perms.canCreate?onDuplicate:undefined}/>;
    }

    return <div style={{padding:"40px",color:K.textDim}}>Register not found: {reg}</div>;
  };

  return (
    <ErrorBoundary>
    <div style={{ minHeight:"100vh", background:K.bg,
      fontFamily:"'Palatino Linotype','Book Antiqua',Palatino,Georgia,serif",
      color:K.text }}>

      {timeoutWarning && (
        <div style={{position:"fixed",top:0,left:0,right:0,zIndex:1000,
          background:"#fef3c7",borderBottom:"2px solid #fcd34d",
          padding:"10px 24px",display:"flex",alignItems:"center",
          justifyContent:"space-between",fontSize:"12px",color:"#78350f"}}>
          <span>⚠ Your session will expire in 2 minutes due to inactivity.</span>
          <button onClick={()=>{lastActivity.current=Date.now();setTimeoutWarning(false);}}
            style={{padding:"4px 12px",background:"#78350f",color:"#fff",
              border:"none",borderRadius:"4px",cursor:"pointer",
              fontSize:"11px",fontWeight:"700",fontFamily:"inherit"}}>
            Stay Logged In
          </button>
        </div>
      )}
      <Header user={user} activeReg={activeReg} onNavigate={navigate}
        onLogout={function() {
          setAuditLog(function(prev) {
            return [...prev, makeAuditEntry(user, "logout", "", "", "Signed out")];
          });
          setUser(null); setActiveReg("dashboard"); setView("list"); setEditing(null);
        }}
        editingTitle={view==="form"?editingTitle:null}/>

      {/* Save toast */}
      {saved&&(
        <div style={{ position:"fixed", bottom:"24px", right:"24px", zIndex:999,
          background:K.navy, color:"#fff", padding:"12px 20px", borderRadius:"6px",
          fontSize:"13px", fontWeight:"600", boxShadow:"0 4px 16px rgba(0,0,0,0.3)",
          borderLeft:"4px solid #4ade80", display:"flex", alignItems:"center", gap:"10px" }}>
          <span style={{ color:"#4ade80", fontSize:"16px" }}>✓</span>
          Record saved: <span style={{ fontFamily:"monospace", color:"#60a5fa" }}>{saved}</span>
        </div>
      )}

      <main key={`${activeReg}-${view}`} style={{ padding:"28px 32px", maxWidth:"1200px", margin:"0 auto" }}>
        {renderRegister()}
      </main>

      <footer style={{ padding:"16px 32px", textAlign:"center", fontSize:"10px",
        color:K.textDim, borderTop:`1px solid ${K.border}`, marginTop:"40px" }}>
        KOIOS Investigation Management System · ArcticWind · All sessions logged
      </footer>
    </div>
    </ErrorBoundary>
  );
}

// ─── USER MANAGEMENT ─────────────────────────────────────────────────────────

const ROLE_OPTIONS = ["superadmin","analyst","investigator","viewer"];
const CLEARANCE_OPTIONS = ["UNCLASSIFIED","RESTRICTED","CONFIDENTIAL"];
const AVATAR_COLOURS = ["#0ea5e9","#8b5cf6","#10b981","#f59e0b","#dc2626","#1a4a8a","#059669","#7c3aed"];

function UserManagement({ appUsers, setAppUsers, currentUser }) {
  const [editing, setEditing] = React.useState(null); // null | "new" | user object
  const [form, setForm] = React.useState({});
  const [pwVisible, setPwVisible] = React.useState(false);
  const s = k => v => setForm(p => ({...p, [k]:v}));

  const openNew = () => {
    setForm({ id:"u"+Date.now(), username:"", password:"koios2025",
      name:"", role:"viewer", clearance:"RESTRICTED",
      initials:"", colour:AVATAR_COLOURS[appUsers.length % AVATAR_COLOURS.length],
      active:true });
    setEditing("new");
  };

  const openEdit = (u) => { setForm({...u}); setEditing(u); };

  const handleSave = () => {
    if (!(form.username||"").trim()) { alert("Username is required."); return; }
    if (!(form.name||"").trim())     { alert("Full name is required."); return; }
    if (!(form.password||"").trim()) { alert("Password is required."); return; }
    if (editing === "new") {
      if (appUsers.find(u => u.username === (form.username||"").trim())) {
        alert("Username already exists."); return;
      }
      setAppUsers(prev => [...prev, {...form, username:form.username.toLowerCase().trim()}]);
    } else {
      setAppUsers(prev => prev.map(u => u.id === form.id ? {...form, username:form.username.toLowerCase().trim()} : u));
    }
    setEditing(null);
  };

  const toggleActive = (u) => {
    if (u.id === currentUser.id) { alert("You cannot deactivate your own account."); return; }
    setAppUsers(prev => prev.map(x => x.id === u.id ? {...x, active:!x.active} : x));
  };

  const initials = (name) => name.split(" ").map(w=>w[0]).join("").toUpperCase().substring(0,2);

  return (
    <div>
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:"24px"}}>
        <div>
          <h1 style={{margin:0,fontSize:"22px",fontWeight:"800",color:K.navy,fontFamily:"Georgia,serif"}}>
            ⚙ User Management
          </h1>
          <div style={{fontSize:"12px",color:K.textMid,marginTop:"4px"}}>
            {appUsers.length} user{appUsers.length!==1?"s":""} · {appUsers.filter(u=>u.active!==false).length} active
          </div>
        </div>
        <Btn variant="primary" onClick={openNew}>+ Add User</Btn>
      </div>

      {editing && (
        <div style={{background:K.surfaceAlt,border:"1px solid "+K.border,borderRadius:"8px",
          padding:"20px",marginBottom:"20px"}}>
          <div style={{fontSize:"13px",fontWeight:"800",color:K.navy,marginBottom:"16px"}}>
            {editing==="new" ? "New User" : "Edit User"}
          </div>
          <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"14px",marginBottom:"14px"}}>
            <Field label="Full Name" required>
              <Input value={form.name} onChange={v=>{s("name")(v);s("initials")(initials(v));}} placeholder="First Last"/>
            </Field>
            <Field label="Username" required>
              <Input value={form.username} onChange={s("username")} placeholder="first.last"/>
            </Field>
            <Field label="Password" required>
              <div style={{position:"relative"}}>
                <input type={pwVisible?"text":"password"} value={form.password}
                  onChange={e=>s("password")(e.target.value)}
                  style={{width:"100%",padding:"8px 32px 8px 11px",border:"1px solid "+K.border,
                    borderRadius:"4px",fontSize:"13px",color:K.text,background:K.surface,
                    outline:"none",fontFamily:"inherit",boxSizing:"border-box"}}/>
                <button onClick={()=>setPwVisible(v=>!v)}
                  style={{position:"absolute",right:"8px",top:"50%",transform:"translateY(-50%)",
                    background:"none",border:"none",cursor:"pointer",fontSize:"12px",color:K.textDim}}>
                  {pwVisible?"Hide":"Show"}
                </button>
              </div>
            </Field>
            <Field label="Initials">
              <Input value={form.initials} onChange={s("initials")} placeholder="MW"/>
            </Field>
            <Field label="Role">
              <Select value={form.role} onChange={s("role")} options={ROLE_OPTIONS}/>
            </Field>
            <Field label="Clearance">
              <Select value={form.clearance} onChange={s("clearance")} options={CLEARANCE_OPTIONS}/>
            </Field>
            <Field label="Avatar Colour">
              <div style={{display:"flex",gap:"6px",flexWrap:"wrap",paddingTop:"4px"}}>
                {AVATAR_COLOURS.map(c=>(
                  <div key={c} onClick={()=>s("colour")(c)}
                    style={{width:"24px",height:"24px",borderRadius:"50%",background:c,
                      cursor:"pointer",border:form.colour===c?"3px solid "+K.navy:"3px solid transparent"}}>
                  </div>
                ))}
              </div>
            </Field>
          </div>
          <div style={{display:"flex",gap:"8px"}}>
            <Btn variant="primary" onClick={handleSave}>Save User</Btn>
            <Btn onClick={()=>setEditing(null)}>Cancel</Btn>
          </div>
        </div>
      )}

      <div style={{background:K.surface,border:"1px solid "+K.border,borderRadius:"8px",overflow:"hidden"}}>
        <table style={{width:"100%",borderCollapse:"collapse",fontSize:"12px"}}>
          <thead>
            <tr style={{background:K.surfaceAlt}}>
              {["User","Username","Role","Clearance","Status",""].map(h=>(
                <th key={h} style={{padding:"10px 16px",textAlign:"left",fontSize:"10px",
                  fontWeight:"800",color:K.textMid,letterSpacing:"1px",
                  borderBottom:"1px solid "+K.border}}>{h}</th>
              ))}
            </tr>
          </thead>
          <tbody>
            {appUsers.map((u,i)=>(
              <tr key={u.id} style={{borderBottom:"1px solid "+K.border,
                background:i%2?K.surfaceAlt:K.surface,
                opacity:u.active===false?0.5:1}}>
                <td style={{padding:"12px 16px"}}>
                  <div style={{display:"flex",alignItems:"center",gap:"10px"}}>
                    <div style={{width:"32px",height:"32px",borderRadius:"50%",
                      background:u.colour||K.blue,display:"flex",alignItems:"center",
                      justifyContent:"center",color:"#fff",fontSize:"11px",
                      fontWeight:"800",flexShrink:0}}>
                      {u.initials||initials(u.name)}
                    </div>
                    <div>
                      <div style={{fontWeight:"700",color:K.text}}>{u.name}</div>
                      {u.id===currentUser.id&&<div style={{fontSize:"10px",color:K.blue,fontWeight:"700"}}>You</div>}
                    </div>
                  </div>
                </td>
                <td style={{padding:"12px 16px",fontFamily:"monospace",fontSize:"11px",color:K.textMid}}>{u.username}</td>
                <td style={{padding:"12px 16px"}}>
                  <span style={{padding:"2px 8px",borderRadius:"10px",fontSize:"11px",fontWeight:"700",
                    background:K.blueLight,color:K.blue}}>{ROLE_LABEL[u.role]||u.role}</span>
                </td>
                <td style={{padding:"12px 16px"}}><ClassBadge v={u.clearance}/></td>
                <td style={{padding:"12px 16px"}}>
                  <span style={{padding:"2px 8px",borderRadius:"10px",fontSize:"11px",fontWeight:"700",
                    background:u.active!==false?"#dcfce7":"#f3f4f6",
                    color:u.active!==false?"#166534":K.textDim}}>
                    {u.active!==false?"Active":"Inactive"}
                  </span>
                </td>
                <td style={{padding:"12px 16px"}}>
                  <div style={{display:"flex",gap:"6px"}}>
                    <Btn small onClick={()=>openEdit(u)}>Edit</Btn>
                    {u.id!==currentUser.id&&(
                      <Btn small onClick={()=>toggleActive(u)}>
                        {u.active!==false?"Deactivate":"Reactivate"}
                      </Btn>
                    )}
                  </div>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}

// ─── LISTS MANAGER ───────────────────────────────────────────────────────────

const LIST_LABELS = {
  person_type:"Person Type", person_subtype:"Person Subtype", title:"Title/Salutation",
  sex:"Sex", org_type:"Organisation Type", org_status:"Organisation Status",
  comm_type:"Communication Type", source_type:"Source Type", source_category:"Source Category",
  contact_method:"Contact Method", mat_type:"Material Type", mat_status:"Material Status",
  movement_reason:"Movement Reason", intel_type:"Intelligence Type", source_eval:"Source Evaluation",
  intel_assessment:"Intelligence Assessment", handling_code:"Handling Code",
  draft_status:"Draft Status", event_type:"Event Type", stmt_type:"Statement Type",
  info_type:"Information Type", info_subtype:"Information Subtype", info_status:"Information Status",
  inv_type:"Investigation Type", inv_status:"Investigation Status",
  inc_type:"Incident Type", inc_status:"Incident Status", how_reported:"How Reported",
  priority:"Priority", mol:"Mode of Liability", address_type:"Address Type",
  assessment_type:"Assessment Type", case_type:"Case Type", case_status:"Case Status",
  case_priority:"Case Priority", decision_type:"Decision Type", outcome_type:"Outcome Type",
  staff_type:"Staff Type", staff_clearance:"Staff Clearance", equipment_type:"Equipment Type",
  equipment_colour:"Equipment Colour", class_lvl:"Classification Level",
  review_per:"Review Period", task_type:"Task Type", task_status:"Task Status",
  note_type:"Note Type", file_type:"File Type", link_type:"Link Type",
};

const LIST_GROUPS = {
  "Person Register":    ["person_type","person_subtype","title","sex"],
  "Organisation":       ["org_type","org_status"],
  "Communication":      ["comm_type","contact_method"],
  "Source":             ["source_type","source_category","source_eval","contact_method"],
  "Material":           ["mat_type","mat_status","movement_reason"],
  "Intelligence":       ["intel_type","intel_assessment","handling_code","draft_status"],
  "Event":              ["event_type"],
  "Statement":          ["stmt_type"],
  "Information":        ["info_type","info_subtype","info_status"],
  "Investigation":      ["inv_type","inv_status"],
  "Incident":           ["inc_type","inc_status","how_reported","mol"],
  "Phase 3 Registers":  ["address_type","assessment_type","case_type","case_status","case_priority","decision_type","outcome_type","staff_type","staff_clearance","equipment_type","equipment_colour"],
  "Shared / System":    ["class_lvl","priority","review_per","task_type","task_status","note_type","file_type","link_type"],
};

function ListsManager({ appL, setAppL, defaultL }) {
  const [activeGroup, setActiveGroup] = React.useState(Object.keys(LIST_GROUPS)[0]);
  const [activeList, setActiveList]   = React.useState(LIST_GROUPS[Object.keys(LIST_GROUPS)[0]][0]);
  const [newOption, setNewOption]     = React.useState("");
  const [editIdx, setEditIdx]         = React.useState(null);
  const [editVal, setEditVal]         = React.useState("");
  const [confirm, setConfirm]         = React.useState(null);

  const currentOptions = appL[activeList] || [];

  const addOption = () => {
    const val = newOption.trim();
    if (!val) return;
    if (currentOptions.includes(val)) { alert("That option already exists."); return; }
    setAppL(prev => ({...prev, [activeList]: [...(prev[activeList]||[]), val]}));
    setNewOption("");
  };

  const removeOption = (idx) => {
    setAppL(prev => ({...prev, [activeList]: prev[activeList].filter((_,i)=>i!==idx)}));
    setConfirm(null);
  };

  const saveEdit = (idx) => {
    const val = editVal.trim();
    if (!val) return;
    setAppL(prev => {
      const opts = [...(prev[activeList]||[])];
      opts[idx] = val;
      return {...prev, [activeList]: opts};
    });
    setEditIdx(null); setEditVal("");
  };

  const moveOption = (idx, dir) => {
    setAppL(prev => {
      const opts = [...(prev[activeList]||[])];
      const to = idx + dir;
      if (to < 0 || to >= opts.length) return prev;
      [opts[idx], opts[to]] = [opts[to], opts[idx]];
      return {...prev, [activeList]: opts};
    });
  };

  const resetList = () => {
    if (!window.confirm("Reset this list to default options? Any custom changes will be lost.")) return;
    setAppL(prev => ({...prev, [activeList]: defaultL[activeList]||[]}));
  };

  const resetAll = () => {
    if (!window.confirm("Reset ALL lists to defaults? All customisations will be lost.")) return;
    setAppL(defaultL);
  };

  return (
    <div>
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:"24px"}}>
        <div>
          <h1 style={{margin:0,fontSize:"22px",fontWeight:"800",color:K.navy,fontFamily:"Georgia,serif"}}>
            📋 Lists & Lookups
          </h1>
          <div style={{fontSize:"12px",color:K.textMid,marginTop:"4px"}}>
            {Object.keys(appL).length} lists · customise dropdown options across all registers
          </div>
        </div>
        <Btn small onClick={resetAll}>↺ Reset All to Defaults</Btn>
      </div>

      <div style={{display:"grid",gridTemplateColumns:"220px 1fr",gap:"16px"}}>

        {/* Left: group + list selector */}
        <div style={{background:K.surface,border:"1px solid "+K.border,borderRadius:"8px",overflow:"hidden"}}>
          {Object.entries(LIST_GROUPS).map(([group, keys]) => (
            <div key={group}>
              <div style={{padding:"8px 12px",fontSize:"10px",fontWeight:"800",
                color:K.textMid,letterSpacing:"1.5px",background:K.surfaceAlt,
                borderBottom:"1px solid "+K.border}}>
                {group.toUpperCase()}
              </div>
              {keys.map(key => (
                <div key={key}
                  onClick={()=>{setActiveGroup(group);setActiveList(key);setEditIdx(null);setNewOption("");}}
                  style={{padding:"8px 14px",cursor:"pointer",fontSize:"12px",
                    fontWeight:activeList===key?"700":"400",
                    color:activeList===key?K.blue:K.text,
                    background:activeList===key?K.blueLight:"transparent",
                    borderBottom:"1px solid "+K.border}}>
                  {LIST_LABELS[key]||key}
                  <span style={{float:"right",fontSize:"10px",color:K.textDim}}>
                    {(appL[key]||[]).length}
                  </span>
                </div>
              ))}
            </div>
          ))}
        </div>

        {/* Right: options editor */}
        <div>
          <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",
            marginBottom:"14px"}}>
            <div>
              <div style={{fontSize:"15px",fontWeight:"800",color:K.navy}}>
                {LIST_LABELS[activeList]||activeList}
              </div>
              <div style={{fontSize:"11px",color:K.textDim,marginTop:"2px"}}>
                {currentOptions.length} option{currentOptions.length!==1?"s":""}
              </div>
            </div>
            <Btn small onClick={resetList}>↺ Reset to Default</Btn>
          </div>

          {/* Add new option */}
          <div style={{display:"flex",gap:"8px",marginBottom:"16px"}}>
            <input
              value={newOption}
              onChange={e=>setNewOption(e.target.value)}
              onKeyDown={e=>e.key==="Enter"&&addOption()}
              placeholder={"Add new option to "+( LIST_LABELS[activeList]||activeList)+"..."}
              style={{flex:1,padding:"8px 12px",border:"1px solid "+K.border,
                borderRadius:"4px",fontSize:"13px",color:K.text,
                background:K.surface,outline:"none",fontFamily:"inherit"}}/>
            <Btn variant="primary" onClick={addOption} disabled={!newOption.trim()}>
              + Add
            </Btn>
          </div>

          {/* Options list */}
          <div style={{background:K.surface,border:"1px solid "+K.border,
            borderRadius:"8px",overflow:"hidden"}}>
            {currentOptions.length === 0 ? (
              <div style={{padding:"32px",textAlign:"center",color:K.textDim,fontSize:"13px"}}>
                No options. Add one above.
              </div>
            ) : (
              currentOptions.map((opt, idx) => (
                <div key={idx} style={{display:"flex",alignItems:"center",gap:"8px",
                  padding:"10px 14px",borderBottom:idx<currentOptions.length-1?"1px solid "+K.border:"none",
                  background:editIdx===idx?K.blueLight:idx%2?K.surfaceAlt:K.surface}}>

                  {/* Reorder buttons */}
                  <div style={{display:"flex",flexDirection:"column",gap:"1px"}}>
                    <button onClick={()=>moveOption(idx,-1)} disabled={idx===0}
                      style={{background:"none",border:"none",cursor:idx===0?"not-allowed":"pointer",
                        fontSize:"10px",color:idx===0?K.border:K.textDim,lineHeight:1,padding:"1px 3px"}}>▲</button>
                    <button onClick={()=>moveOption(idx,1)} disabled={idx===currentOptions.length-1}
                      style={{background:"none",border:"none",cursor:idx===currentOptions.length-1?"not-allowed":"pointer",
                        fontSize:"10px",color:idx===currentOptions.length-1?K.border:K.textDim,lineHeight:1,padding:"1px 3px"}}>▼</button>
                  </div>

                  {/* Option value (editable) */}
                  {editIdx===idx ? (
                    <input value={editVal} onChange={e=>setEditVal(e.target.value)}
                      onKeyDown={e=>{if(e.key==="Enter")saveEdit(idx);if(e.key==="Escape"){setEditIdx(null);}}}
                      autoFocus
                      style={{flex:1,padding:"5px 8px",border:"1px solid "+K.blue,
                        borderRadius:"4px",fontSize:"13px",color:K.text,
                        background:K.surface,outline:"none",fontFamily:"inherit"}}/>
                  ) : (
                    <span style={{flex:1,fontSize:"13px",color:K.text}}>{opt}</span>
                  )}

                  {/* Actions */}
                  <div style={{display:"flex",gap:"6px",flexShrink:0}}>
                    {editIdx===idx ? (
                      <>
                        <Btn small variant="primary" onClick={()=>saveEdit(idx)}>Save</Btn>
                        <Btn small onClick={()=>setEditIdx(null)}>Cancel</Btn>
                      </>
                    ) : (
                      <>
                        <Btn small onClick={()=>{setEditIdx(idx);setEditVal(opt);}}>Edit</Btn>
                        {confirm===idx ? (
                          <>
                            <Btn small variant="danger" onClick={()=>removeOption(idx)}>Confirm</Btn>
                            <Btn small onClick={()=>setConfirm(null)}>Cancel</Btn>
                          </>
                        ) : (
                          <Btn small onClick={()=>setConfirm(idx)}>Remove</Btn>
                        )}
                      </>
                    )}
                  </div>
                </div>
              ))
            )}
          </div>

          <div style={{marginTop:"12px",padding:"10px 14px",background:"#fffbeb",
            border:"1px solid #fcd34d",borderRadius:"6px",fontSize:"11px",color:"#78350f"}}>
            💡 Changes take effect immediately across all registers. Existing records keep their
            saved values even if an option is removed from the list.
          </div>
        </div>
      </div>
    </div>
  );
}

// Mount KOIOS to the DOM
const _koiosRoot = document.getElementById("root");
if (_koiosRoot) {
  ReactDOM.createRoot(_koiosRoot).render(React.createElement(App));
}
