/* ============================================================
   HOME — landing page (all projects) + Crew Directory database
   · LandingPage: first screen, every production visible
   · PeopleDB: living org-wide crew database — names, contacts,
     abilities, projects, rates. Editable, searchable, persistent.
   ============================================================ */

/* ---------- owned productions (mutable + persisted) ---------- */
const OWNED_SEED = [
  { code: 'CS', pid: 'crimson', name: 'Crimson Skies', type: 'Commercial Campaign', client: 'Aether Aviation Co.',
    status: 'In Production', tone: 'proflow', meta: 'Day 1 of 4 · Jun 22–25, 2026', bg: '#5B0952', fg: '#F7A8CF', open: true, owner: true },
];
/* ---------- remote / invited productions (static — leave as is) ---------- */
const REMOTE_PROJECTS = [
  { code: 'GH', name: 'Glass Harbor', type: 'Documentary', client: 'Harbor Trust',
    status: 'In Post', tone: 'amber', meta: 'Edit week 2 of 6', bg: '#16323A', fg: '#F9A06E',
    remote: true, owner: 'Tideline Studios · Lisbon', presence: '2 online in Lisbon',
    dates: 'Jun 2 – Jul 18, 2026', leads: [{ name: 'Lars Holt', role: 'Showrunner', color: '#F9A06E' }, { name: 'Mara Silva', role: 'Editor', color: '#16323A' }] },
  { code: 'AR', name: 'Atlas Run', type: 'Feature Film', client: 'Meridian Pictures',
    status: 'In Production', tone: 'proflow', meta: 'Shoot day 6 of 32', bg: '#200248', fg: '#9FC1E8',
    remote: true, owner: 'Meridian Pictures · Los Angeles', presence: '4 online in LA · 1 here',
    dates: 'May 18 – Aug 1, 2026', leads: [{ name: 'Elena Fischer', role: 'Line Producer', color: '#9FC1E8' }] },
];

/* owned-projects store — persisted, so created/deleted productions stick */
const PROJ_KEY = 'silverlines.projects.v1';
let ownCache = null; const ownSubs = new Set();
/* the Crimson demo is always present and always flagged demo:true, so every
   account sees it as a labeled sandbox and it can never be permanently deleted. */
function ownNormalize(arr) {
  let list = Array.isArray(arr) ? arr.map(p => ({ ...p })) : [];
  const ci = list.findIndex(p => p && p.pid === 'crimson');
  if (ci >= 0) list[ci] = { ...list[ci], demo: true, owner: true, open: true };
  else list.unshift({ ...OWNED_SEED[0], demo: true });
  return list;
}
function ownLoad() {
  if (ownCache) return ownCache;
  let base = null;
  const s = window.SLStore.get(PROJ_KEY); if (Array.isArray(s)) base = s;
  ownCache = ownNormalize(base || OWNED_SEED.map(p => ({ ...p })));
  return ownCache;
}
function ownSave(next) {
  ownCache = typeof next === 'function' ? next(ownLoad()) : next;
  window.SLStore.set(PROJ_KEY, ownCache);
  ownSubs.forEach(fn => fn());
}
function useOwnedProjects() {
  const [, force] = useState(0);
  useEffect(() => { const fn = () => force(n => n + 1); ownSubs.add(fn); return () => ownSubs.delete(fn); }, []);
  return [ownLoad(), ownSave];
}
const PRODUCTION_TYPES = ['Commercial', 'Music Video', 'Film', 'Documentary', 'Series', 'Other'];
const NEW_PALETTE = [['#1F2A3D', '#9FC1E8'], ['#200248', '#F7A8CF'], ['#16323A', '#F9A06E'], ['#3A1630', '#F7A8CF'], ['#0E2A24', '#22D48A']];
function makeNewProject(list, opts) {
  opts = opts || {};
  const name = (opts.name || '').trim() || 'Untitled Production';
  const initials = (name.split(/\s+/).filter(Boolean).map(w => w[0]).join('').slice(0, 2).toUpperCase()) || 'PR';
  const codeTag = ((name.replace(/[^A-Za-z0-9]/g, '').slice(0, 4).toUpperCase()) || 'PROD') + '-' + new Date().getFullYear();
  const c = NEW_PALETTE[list.filter(p => !p.demo).length % NEW_PALETTE.length];
  return { code: initials, pid: 'prod-' + Date.now(), name, type: opts.type || 'New project',
    client: (opts.client || '').trim() || 'No client yet', codeTag,
    status: 'In Development', tone: 'electric', meta: 'New — start from zero',
    bg: c[0], fg: c[1], open: true, blank: true, owner: true, demo: false, createdAt: Date.now() };
}
/* wipe a production's data (true reset) — keeps workspace-level/global keys */
function wipeProject(pid) {
  try {
    /* workspace-level keys to preserve — single source of truth is index.html's SL_GLOBAL_KEYS */
    const KEEP = window.SL_GLOBAL_KEYS || ['silverlines.project', 'silverlines.autoopen', 'silverlines.lang', 'silverlines.people.v1', 'silverlines.settings.v1', 'producer.theme', 'silverlines.projects.v1', 'silverlines.account.v1'];
    /* use RAW localStorage removal so this works regardless of the active
       per-project proxy (e.g. resetting the demo while inside a real production) */
    const rm = (window.__lsRaw && window.__lsRaw.remove) ? window.__lsRaw.remove : (k => localStorage.removeItem(k));
    Object.keys(localStorage).forEach(k => {
      if (pid === 'crimson') { if ((/^silverlines\./.test(k) || /^producer\./.test(k)) && KEEP.indexOf(k) < 0 && k[0] !== '@') rm(k); }
      else { if (k.indexOf('@' + pid + '.') === 0) rm(k); }
    });
  } catch (e) {}
}

/* ---------- production registry API (shared with the in-app switcher/settings) ---------- */
window.slProductions = () => ownLoad();
window.slAddProduction = function (opts) {
  const list = ownLoad();
  const nonDemo = list.filter(p => !p.demo).length;
  if (window.planGate && !window.planGate.createProduction(nonDemo)) return null; // plan limit reached
  const p = makeNewProject(list, opts);
  ownSave(l => [...l, p]);
  return p;
};
window.slRenameProduction = function (pid, name) {
  if (name == null) return;
  name = String(name);
  if (!name.trim()) return;                 // block blank, but keep internal/typed spaces
  ownSave(l => l.map(x => x.pid === pid ? { ...x, name } : x));
  if (pid === window.PROJ_ID && window.projectMetaRefresh) window.projectMetaRefresh();
};
/* opens the global New-Production modal (mounted once in App) from anywhere */
window.createProduction = function () { try { window.dispatchEvent(new CustomEvent('sl-new-production')); } catch (e) {} };
/* reset the shared demo to its seed data (works from any project context) */
window.slResetDemo = function () { wipeProject('crimson'); };

/* ---------- new production: name it up front (replaces the 'Untitled' hardcode) ---------- */
function NewProductionModal({ open, onClose, onCreate }) {
  const [name, setName] = useState('');
  const [client, setClient] = useState('');
  const [type, setType] = useState(PRODUCTION_TYPES[0]);
  useEffect(() => { if (open) { setName(''); setClient(''); setType(PRODUCTION_TYPES[0]); } }, [open]);
  if (!open) return null;
  const nonDemo = (window.slProductions ? window.slProductions().filter(p => !p.demo).length : 0);
  const gated = !!(window.planGate && !window.planGate.createProduction(nonDemo));
  const ok = name.trim().length > 0;
  const submit = () => { if (ok && !gated) onCreate({ name: name.trim(), client: client.trim(), type }); };
  return (
    <div data-no-i18n="true" className="fixed inset-0 z-[70] flex items-center justify-center p-4" onClick={onClose}>
      <div className="absolute inset-0 bg-black/70 backdrop-blur-sm"></div>
      <div onClick={e => e.stopPropagation()} className="fade-up relative w-full max-w-[440px] overflow-hidden rounded-2xl border border-line bg-ink-850">
        {gated ? (
          <div className="p-6 text-center">
            <span className="mx-auto flex h-12 w-12 items-center justify-center rounded-2xl bg-proflow/12 text-proflow-soft"><Icon name="Sparkles" size={22} /></span>
            <h3 className="mt-3 font-display text-[20px] leading-tight text-head">Upgrade to add productions</h3>
            <p className="mx-auto mt-2 max-w-[320px] text-[12.5px] leading-relaxed text-zinc-400">Your Free plan includes one active production. Upgrade to <span className="font-700 text-zinc-200">Producer</span> — CHF&nbsp;19/seat/mo — for unlimited productions and clean PDF exports.</p>
            <div className="mt-5 flex gap-2">
              <button onClick={onClose} className="flex-1 rounded-xl border border-line bg-ink-900 py-2.5 text-[13px] font-700 text-zinc-200 hover:border-ink-600">Maybe later</button>
              <button onClick={() => { window.toast('Upgrades open when billing goes live — you’re on the beta plan for now', 'Sparkles'); onClose(); }}
                className="flex flex-1 items-center justify-center gap-1.5 rounded-xl bg-cta py-2.5 text-[13px] font-700 text-cta-ink hover:bg-cta-hover"><Icon name="ArrowUpRight" size={14} /> See Producer</button>
            </div>
          </div>
        ) : (
          <React.Fragment>
            <div className="flex items-start gap-3 border-b border-line p-5">
              <span className="flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-electric/12 text-electric-soft"><Icon name="FolderPlus" size={20} /></span>
              <div className="min-w-0">
                <h3 className="font-display text-[19px] leading-tight text-head">New production</h3>
                <p className="mt-1 text-[12.5px] leading-relaxed text-zinc-400">Give it a name — you can rename it any time from the project menu or Settings.</p>
              </div>
              <button onClick={onClose} className="ml-auto flex h-7 w-7 shrink-0 items-center justify-center rounded-lg bg-ink-800 text-zinc-400 hover:text-white"><Icon name="X" size={15} /></button>
            </div>
            <div className="space-y-3 p-5">
              <div>
                <label className="mb-1.5 block font-mono text-[10px] uppercase tracking-[0.14em] text-zinc-500">Production name</label>
                <input autoFocus value={name} onChange={e => setName(e.target.value)}
                  onKeyDown={e => { if (e.key === 'Enter' && ok) submit(); if (e.key === 'Escape') onClose(); }}
                  placeholder="e.g. Nordwind — Winter Campaign"
                  className="w-full rounded-xl border border-line bg-ink-900 px-3 py-2.5 text-[13px] text-zinc-100 outline-none focus:border-electric/60 placeholder:text-zinc-600" />
              </div>
              <div>
                <label className="mb-1.5 block font-mono text-[10px] uppercase tracking-[0.14em] text-zinc-500">Client <span className="text-zinc-600">· optional</span></label>
                <input value={client} onChange={e => setClient(e.target.value)}
                  onKeyDown={e => { if (e.key === 'Enter' && ok) submit(); }}
                  placeholder="Who's it for?"
                  className="w-full rounded-xl border border-line bg-ink-900 px-3 py-2.5 text-[13px] text-zinc-100 outline-none focus:border-electric/60 placeholder:text-zinc-600" />
              </div>
              <div>
                <label className="mb-1.5 block font-mono text-[10px] uppercase tracking-[0.14em] text-zinc-500">Type</label>
                <div className="flex flex-wrap gap-1.5">
                  {PRODUCTION_TYPES.map(t => (
                    <button key={t} onClick={() => setType(t)}
                      className={cx('rounded-lg border px-2.5 py-1.5 font-display text-[12px] transition-colors',
                        type === t ? 'border-electric/60 bg-electric/10 text-electric-soft' : 'border-line bg-ink-900 text-zinc-400 hover:text-zinc-200')}>{t}</button>
                  ))}
                </div>
              </div>
              <div className="flex gap-2 pt-1">
                <button onClick={onClose} className="flex-1 rounded-xl border border-line bg-ink-900 py-2.5 text-[13px] font-700 text-zinc-200 hover:border-ink-600">Cancel</button>
                <button onClick={submit} disabled={!ok}
                  className={cx('flex flex-1 items-center justify-center gap-1.5 rounded-xl py-2.5 text-[13px] font-700 transition-colors',
                    ok ? 'bg-cta text-cta-ink hover:bg-cta-hover' : 'cursor-not-allowed bg-ink-700 text-zinc-600')}>
                  <Icon name="ArrowRight" size={14} /> Create &amp; open
                </button>
              </div>
            </div>
          </React.Fragment>
        )}
      </div>
    </div>
  );
}
window.NewProductionModal = NewProductionModal;

/* opens the global Account overlay (mounted once in App) from anywhere */
window.openAccount = function () { try { window.dispatchEvent(new CustomEvent('sl-open-account')); } catch (e) {} };

/* ---------- account / base settings: your identity + the defaults every new
     production inherits. Per-production overrides (currency, shoot dates) still
     live inside a production's own Settings. Opened from the dashboard avatar. ---------- */
function AccountModal({ open, onClose }) {
  const [s, set] = useSettings();
  const acct = window.useAccount ? window.useAccount() : { name: 'Producer', email: '', company: '', role: 'Producer', color: '#22D48A' };
  const { theme, setTheme } = useContext(AccessContext);
  const [lng, setLng] = useState(() => (window.getLang && window.getLang()) || 'en');
  const [confirmReset, setConfirmReset] = useState(false);
  const mobileUrl = useMemo(() => { try { return new URL('mobile.html', location.href).href; } catch (e) { return 'mobile.html'; } }, []);
  useEffect(() => { document.documentElement.style.setProperty('--grain-op', s.grain ? '' : '0'); }, [s.grain]);
  useEffect(() => { document.documentElement.classList.toggle('reduce-motion', !s.motion); }, [s.motion]);
  useEffect(() => { if (!open) setConfirmReset(false); }, [open]);
  useEffect(() => {
    if (!open) return;
    const onKey = e => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [open]);
  if (!open) return null;

  const saveProfile = patch => { set(patch); if (window.Auth) window.Auth.updateProfile(patch); };
  const setLang = v => { setLng(v); window.setLang && window.setLang(v); };
  const CUR = window.CURRENCIES || {};
  const curDefault = (s.currency && CUR[s.currency]) ? s.currency : 'USD';
  const setDefaultCurrency = code => { set({ currency: code }); try { window.dispatchEvent(new CustomEvent('sl-currency')); } catch (e) {} };
  const acctColor = acct.color || '#22D48A';

  return (
    <div className="fixed inset-0 z-[70] flex items-start justify-center overflow-y-auto p-4 sm:p-6" onClick={onClose}>
      <div className="absolute inset-0 bg-black/70 backdrop-blur-sm"></div>
      <div onClick={e => e.stopPropagation()} className="fade-up relative my-auto w-full max-w-[640px] overflow-hidden rounded-2xl border border-line bg-ink-850">
        {/* header */}
        <div className="sticky top-0 z-10 flex items-center gap-3 border-b border-line bg-ink-850/95 px-5 py-4 backdrop-blur">
          <Avatar name={acct.name} color={acctColor} size={36} />
          <div className="min-w-0 flex-1">
            <h3 className="font-display text-[17px] leading-tight text-head">Account</h3>
            <p className="truncate text-[12px] text-zinc-500">These preferences apply to your whole account.</p>
          </div>
          <button onClick={onClose} aria-label="Close" className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-ink-800 text-zinc-400 hover:text-white"><Icon name="X" size={16} /></button>
        </div>

        <div className="space-y-4 p-5">
          {/* identity */}
          <Panel>
            <h3 className="mb-3 font-display text-[15px] text-head">Profile</h3>
            <div className="flex items-center gap-3">
              <Avatar name={acct.name} color={acctColor} size={52} />
              <div className="min-w-0 flex-1">
                <div className="text-[15px] font-700 text-head"><Edit value={acct.name} onChange={v => saveProfile({ name: v })} className="text-[15px] font-700" /></div>
                <div className="text-[12px] text-zinc-500"><Edit value={acct.role} onChange={v => saveProfile({ role: v })} className="text-[12px]" /></div>
              </div>
              <Chip tone="mint">Owner</Chip>
            </div>
            <div className="mt-4 space-y-2">
              <div className="flex items-center gap-3 rounded-xl border border-line bg-ink-900 px-3 py-2.5 text-[13px] text-zinc-200">
                <Icon name="Building2" size={15} className="shrink-0 text-zinc-500" /><Edit value={acct.company} onChange={v => saveProfile({ company: v })} className="min-w-0 flex-1 truncate text-[13px]" placeholder="Company" /></div>
              <div className="flex items-center gap-3 rounded-xl border border-line bg-ink-900 px-3 py-2.5 text-[13px] text-zinc-200">
                <Icon name="Mail" size={15} className="shrink-0 text-zinc-500" /><Edit value={acct.email} onChange={v => saveProfile({ email: v })} className="min-w-0 flex-1 truncate text-[13px]" placeholder="Email" /></div>
              <div className="flex items-center gap-3 rounded-xl border border-line bg-ink-900 px-3 py-2.5 text-[13px] text-zinc-200">
                <Icon name="Phone" size={15} className="shrink-0 text-zinc-500" /><Edit value={s.phone} onChange={v => set({ phone: v })} className="min-w-0 flex-1 font-mono text-[13px]" placeholder="Phone" /></div>
            </div>
          </Panel>

          {/* appearance & language */}
          <Panel>
            <h3 className="mb-1 font-display text-[15px] text-head">Appearance &amp; language</h3>
            <SettingRow icon={theme === 'day' ? 'Sun' : 'Moon'} label="Theme" sub="Night for the edit bay, Day for set">
              <Seg value={theme} options={[['night', 'Night'], ['day', 'Day']]} onChange={setTheme} />
            </SettingRow>
            <SettingRow icon="Languages" label="Language" sub="English · Français · Deutsch">
              <div data-no-i18n="true"><Seg value={lng} options={[['en', 'EN'], ['fr', 'FR'], ['de', 'DE']]} onChange={setLang} /></div>
            </SettingRow>
            <SettingRow icon="Sparkle" label="Film grain" sub="Subtle texture on backgrounds">
              <Switch on={s.grain} onChange={v => set({ grain: v })} />
            </SettingRow>
            <SettingRow icon="Wind" label="Motion" sub="Fades, pulses and transitions">
              <Switch on={s.motion} onChange={v => set({ motion: v })} />
            </SettingRow>
          </Panel>

          {/* notifications */}
          <Panel>
            <h3 className="mb-1 font-display text-[15px] text-head">Notifications</h3>
            <SettingRow icon="ClipboardList" label="Call sheet published" sub="When a day’s sheet goes out">
              <Switch on={s.notifCallsheet} onChange={v => set({ notifCallsheet: v })} />
            </SettingRow>
            <SettingRow icon="UploadCloud" label="Uploads complete" sub="Rushes and transfers landing">
              <Switch on={s.notifUploads} onChange={v => set({ notifUploads: v })} />
            </SettingRow>
            <SettingRow icon="CircleDollarSign" label="Purchase suggestions" sub="Art department asks for approval">
              <Switch on={s.notifPurchase} onChange={v => set({ notifPurchase: v })} />
            </SettingRow>
            <SettingRow icon="MessageSquare" label="Review comments" sub="Client and team notes on cuts">
              <Switch on={s.notifComments} onChange={v => set({ notifComments: v })} />
            </SettingRow>
          </Panel>

          {/* defaults for new productions */}
          <Panel>
            <h3 className="mb-1 font-display text-[15px] text-head">Defaults for new productions</h3>
            <p className="mb-1 px-1 text-[11.5px] leading-relaxed text-zinc-500">New productions inherit these — override them per production.</p>
            <SettingRow icon="CircleDollarSign" label="Default currency" sub="Starting currency for a new production">
              <select value={curDefault} onChange={e => setDefaultCurrency(e.target.value)} data-no-i18n="true"
                className="shrink-0 rounded-lg border border-line bg-ink-900 px-2.5 py-1.5 font-display text-[12px] text-zinc-200 outline-none focus:border-electric/60">
                {Object.keys(CUR).map(k => <option key={k} value={k}>{k} · {CUR[k].sym.trim()}</option>)}
              </select>
            </SettingRow>
            <SettingRow icon="Ruler" label="Floor plan units" sub="Lengths on the lighting plan">
              <Seg value={s.units} options={[['ft', 'Feet'], ['m', 'Meters']]} onChange={v => set({ units: v })} />
            </SettingRow>
            <SettingRow icon="Clock" label="Time format" sub="Call times and schedules">
              <Seg value={s.clock} options={[['24h', '24 hr'], ['12h', '12 hr']]} onChange={v => set({ clock: v })} />
            </SettingRow>
            <SettingRow icon="Hourglass" label="Link expiry" sub="Default for new share links">
              <Seg value={s.expiry} options={[['24h', '24 hr'], ['7d', '7 days'], ['never', 'Never']]} onChange={v => set({ expiry: v })} />
            </SettingRow>
          </Panel>

          {/* security & devices */}
          <Panel>
            <h3 className="mb-1 font-display text-[15px] text-head">Security &amp; devices</h3>
            <SettingRow icon="KeyRound" label="Password-protect new links" sub="Applies to share links by default">
              <Switch on={s.pwDefault} onChange={v => set({ pwDefault: v })} />
            </SettingRow>
            <SettingRow icon="ShieldCheck" label="Two-factor authentication" sub={s.twoFA ? 'Enabled for ' + (acct.email || 'your account') : 'Protect sign-in with a code'}>
              <Switch on={s.twoFA} onChange={v => { set({ twoFA: v }); if (v) window.toast('Two-factor enabled for ' + (acct.email || 'your account'), 'ShieldCheck'); }} />
            </SettingRow>
            <SettingRow icon="RotateCcwKey" label="Reset password" sub="Password reset activates with the backend email flow.">
              <button onClick={() => window.toast('Password reset activates with the backend email flow.', 'RotateCcwKey')}
                className="shrink-0 rounded-lg border border-line px-3 py-1.5 text-[12px] font-600 text-zinc-400 transition-colors hover:border-ink-600 hover:text-zinc-200">Reset password</button>
            </SettingRow>

            {/* connect your phone — real QR, honest about sync */}
            <div className="mt-2 rounded-xl border border-line bg-ink-900 p-4">
              <div className="flex items-center gap-2"><Icon name="QrCode" size={16} className="text-proflow-soft" /><span className="font-display text-[13.5px] font-600 text-zinc-100">Connect your phone</span></div>
              <div className="mt-3 flex flex-col items-center gap-3 sm:flex-row sm:items-start">
                <div className="mx-auto rounded-xl bg-white p-2.5 sm:mx-0"><QrCode value={mobileUrl} size={148} /></div>
                <div className="min-w-0 flex-1">
                  <p className="text-[12px] leading-relaxed text-zinc-400">Scan to open the mobile producer view.</p>
                  <p className="mt-1.5 text-[11px] leading-relaxed text-zinc-500">Live sync between your phone and this Mac turns on with the backend.</p>
                  <div className="mt-2 truncate rounded-lg border border-line bg-ink-950 px-2.5 py-1.5 font-mono text-[11px] text-zinc-400" title={mobileUrl}>{mobileUrl}</div>
                </div>
              </div>
            </div>

            <div className="mt-4 flex flex-wrap items-center gap-2">
              <button onClick={() => { if (window.Auth) window.Auth.signOut(); onClose(); }}
                className="flex items-center gap-2 rounded-xl border border-line px-3.5 py-2.5 text-[12.5px] font-600 text-zinc-300 transition-colors hover:border-ink-600">
                <Icon name="LogOut" size={14} /> Sign out</button>
              {confirmReset ? (
                <div className="flex flex-1 flex-wrap items-center gap-2 rounded-xl border border-[#FF4D6D]/30 bg-[#FF4D6D]/10 px-3 py-2">
                  <span className="flex-1 text-[11.5px] leading-snug text-[#FF4D6D]">This erases the account and all local data on this device.</span>
                  <button onClick={() => setConfirmReset(false)} className="rounded-lg border border-line bg-ink-900 px-2.5 py-1.5 text-[11.5px] font-600 text-zinc-300 hover:border-ink-600">Cancel</button>
                  <button onClick={() => { if (window.Auth) window.Auth.reset(); }} className="rounded-lg bg-[#FF4D6D] px-2.5 py-1.5 text-[11.5px] font-700 text-white">Reset this device</button>
                </div>
              ) : (
                <button onClick={() => setConfirmReset(true)}
                  className="flex items-center gap-2 rounded-xl border border-[#FF4D6D]/30 bg-[#FF4D6D]/10 px-3.5 py-2.5 text-[12.5px] font-600 text-[#FF4D6D] transition-colors hover:bg-[#FF4D6D]/15">
                  <Icon name="Trash2" size={14} /> Reset this device</button>
              )}
            </div>
          </Panel>
        </div>
      </div>
    </div>
  );
}
window.AccountModal = AccountModal;

/* ---------- crew database seed — everyone who's been on a call sheet ---------- */
const CREW_DB_SEED = [
  { id: 'dahlia', name: 'Dahlia Mercer', role: 'Director', dept: 'Direction', color: '#F57F45', phone: '+1 310 555 0148', email: 'dahlia@crimsonskies.co', rate: '$2,400/day', abilities: ['Commercials', 'Aerial units', 'Cast direction'], projects: ['CRSK', 'NTDE'] },
  { id: 'idris', name: 'Idris Vance', role: 'Director of Photography', dept: 'Camera', color: '#BD2555', phone: '+1 310 555 0192', email: 'idris@lensworks.co', rate: '$1,800/day', abilities: ['Anamorphic', 'Steadicam', 'Low light'], projects: ['CRSK', 'GLHB'] },
  { id: 'noor', name: 'Noor Haddad', role: 'Producer', dept: 'Production', color: '#22D48A', phone: '+1 213 555 0177', email: 'noor@silverlines.app', rate: '$1,500/day', abilities: ['Budgeting', 'Permits', 'Vendor network'], projects: ['CRSK', 'NTDE', 'GLHB'] },
  { id: 'suki', name: 'Suki Tanaka', role: '1st AD', dept: 'Production', color: '#F43F3E', phone: '+1 323 555 0163', email: 'suki@silverlines.app', rate: '$950/day', abilities: ['Scheduling', 'Stunt coordination'], projects: ['CRSK', 'NTDE'] },
  { id: 'theo', name: 'Theo Nkemelu', role: 'Gaffer', dept: 'Lighting', color: '#F9A06E', phone: '+1 818 555 0124', email: 'theo@gridlight.co', rate: '$850/day', abilities: ['HMI rigs', 'Generators', 'Night exteriors'], projects: ['CRSK'] },
  { id: 'russ', name: 'Russ Calderon', role: 'Key Grip', dept: 'Grip', color: '#9aa0aa', phone: '+1 818 555 0167', email: 'russ@gripworks.la', rate: '$800/day', abilities: ['Cranes', 'Dolly track', 'Car rigs'], projects: ['CRSK', 'GLHB'] },
  { id: 'mia', name: 'Mia Sorenson', role: '1st AC', dept: 'Camera', color: '#a698be', phone: '+1 310 555 0139', email: 'mia@lensworks.co', rate: '$700/day', abilities: ['Focus pulling', 'DIT backup'], projects: ['CRSK', 'NTDE'] },
  { id: 'pia', name: 'Pia Lindqvist', role: 'Sound Mixer', dept: 'Sound', color: '#FFB020', phone: '+1 213 555 0151', email: 'pia@fieldaudio.co', rate: '$750/day', abilities: ['Boom op', '96kHz field', 'Timecode sync'], projects: ['CRSK'] },
  { id: 'ravi', name: 'Ravi Anand', role: 'Production Designer', dept: 'Art', color: '#5B0952', phone: '+1 626 555 0140', email: 'ravi@setpiece.co', rate: '$1,100/day', abilities: ['Period sets', 'Props fabrication'], projects: ['CRSK', 'GLHB'] },
  { id: 'juno', name: 'Juno Park', role: 'Costume Designer', dept: 'Wardrobe', color: '#92ad8c', phone: '+1 323 555 0185', email: 'juno@stitchroom.co', rate: '$700/day', abilities: ['Flight suits', 'Quick changes'], projects: ['CRSK', 'NTDE'] },
  { id: 'coraline', name: 'Coraline Bisset', role: 'Key MUA', dept: 'HMU', color: '#FF5D92', phone: '+1 310 555 0173', email: 'coraline@facecraft.co', rate: '$650/day', abilities: ['SFX makeup', 'Hair', 'Sweat & grime continuity'], projects: ['CRSK', 'GLHB'] },
  { id: 'lena', name: 'Lena Frost', role: 'Lead Talent', dept: 'Cast', color: '#F7A8CF', phone: '+1 310 555 0199', email: 'lena@frosttalent.co', rate: 'Agency', abilities: ['Stunt driving', 'Licensed pilot'], projects: ['CRSK'] },
];

/* ---------- project roster + status flags (shared with Cast & Crew) ---------- */
function readPeopleDB() {
  const s = window.SLStore.get('silverlines.people.v1'); if (Array.isArray(s) && s.length) return s;
  return CREW_DB_SEED;
}
function useRoster() {
  const [roster, setR] = useState(() => {
    return window.SLStore.get('silverlines.roster.v1', []);
  });
  const save = l => { window.SLStore.set('silverlines.roster.v1', l); return l; };
  const add = id => setR(l => save(l.includes(id) ? l : [...l, id]));
  const remove = (id, label) => setR(l => {
    const next = l.filter(x => x !== id);
    if (next.length !== l.length) window.pushUndo && window.pushUndo(label || 'Removed from the project', () => setR(save(l)));
    return save(next);
  });
  return { roster, add, remove };
}
const FLAG_OPTS = [
  { label: 'Preselected', tone: 'proflow' },
  { label: 'Waiting on quote', tone: 'amber' },
  { label: 'Waiting on answer', tone: 'electric' },
  { label: 'Approved', tone: 'mint' },
  { label: 'Rejected', tone: 'red' },
  { label: 'On hold', tone: 'neutral' },
];
const FLAG_TONES = {
  amber: 'border-amber/40 bg-amber/10 text-amber',
  electric: 'border-electric/40 bg-electric/10 text-electric-soft',
  mint: 'border-mint/40 bg-mint/10 text-mint',
  red: 'border-[#FF4D6D]/40 bg-[#FF4D6D]/10 text-[#FF4D6D]',
  neutral: 'border-line bg-ink-800 text-zinc-400',
  proflow: 'border-proflow/40 bg-proflow/10 text-proflow-soft',
};
function useFlags() {
  const [flags, setF] = useState(() => {
    return window.SLStore.get('silverlines.flags.v1', {});
  });
  const setFlag = (id, flag, name) => {
    setF(o => {
      const n = { ...o };
      if (flag) n[id] = flag; else delete n[id];
      window.SLStore.set('silverlines.flags.v1', n);
      return n;
    });
    if (flag) {
      const icon = flag.label === 'Approved' ? 'UserCheck' : flag.label === 'Rejected' ? 'UserX' : 'Flag';
      window.notify && window.notify(`${name || 'Crew member'} marked ${flag.label}`, icon, 'crewdb');
    }
  };
  return { flags, setFlag };
}
function FlagPicker({ id, name, flag, setFlag }) {
  const [open, setOpen] = useState(false);
  const [custom, setCustom] = useState('');
  const commit = () => { const t = custom.trim(); if (t) { setFlag(id, { label: t, tone: 'proflow' }, name); setCustom(''); setOpen(false); } };
  return (
    <div className="relative" onClick={e => e.stopPropagation()}>
      <button onClick={() => setOpen(o => !o)} title={flag ? flag.label : 'Set status — waiting, approved, rejected, anything'}
        className={cx('flex items-center gap-1 whitespace-nowrap rounded-full border px-2 py-[3px] text-[9.5px] font-700 transition-colors',
          flag ? FLAG_TONES[flag.tone] || FLAG_TONES.proflow : 'border-dashed border-ink-600 text-zinc-500 hover:border-zinc-500 hover:text-zinc-300')}>
        <Icon name="Flag" size={8} />{flag ? flag.label : 'Set status'}
        <Icon name="ChevronDown" size={8} />
      </button>
      {open && (
        <React.Fragment>
          <div className="fixed inset-0 z-30" onClick={() => setOpen(false)}></div>
          <div className="fade-up absolute left-0 z-40 mt-1.5 w-[195px] rounded-xl border border-line bg-ink-850 p-1.5 shadow-2xl">
            {FLAG_OPTS.map(o => (
              <button key={o.label} onClick={() => { setFlag(id, o, name); setOpen(false); }}
                className="flex w-full items-center gap-2 rounded-lg px-2.5 py-2 text-left text-[12px] font-600 text-zinc-300 transition-colors hover:bg-ink-800">
                <span className={cx('h-2 w-2 rounded-full', { amber: 'bg-amber', electric: 'bg-electric', mint: 'bg-mint', red: 'bg-[#FF4D6D]', neutral: 'bg-zinc-500', proflow: 'bg-proflow' }[o.tone])}></span>
                <span className="flex-1">{o.label}</span>
                {flag && flag.label === o.label && <Icon name="Check" size={12} className="text-mint" />}
              </button>
            ))}
            <div className="mt-1 flex items-center gap-1.5 border-t border-line px-1 pt-1.5">
              <input value={custom} onChange={e => setCustom(e.target.value)} onKeyDown={e => e.key === 'Enter' && commit()}
                placeholder="Custom flag…" className="min-w-0 flex-1 rounded-md bg-ink-900 px-2 py-1.5 text-[11.5px] text-zinc-200 outline-none placeholder:text-zinc-600" />
              <button onClick={commit} className="shrink-0 text-[11px] font-700 text-electric-soft hover:text-electric">Set</button>
            </div>
            {flag && (
              <button onClick={() => { setFlag(id, null, name); setOpen(false); }}
                className="mt-1 flex w-full items-center gap-2 rounded-lg px-2.5 py-1.5 text-left text-[11.5px] font-600 text-zinc-500 transition-colors hover:bg-ink-800 hover:text-[#FF4D6D]">
                <Icon name="X" size={11} /> Clear flag
              </button>
            )}
          </div>
        </React.Fragment>
      )}
    </div>
  );
}
window.FlagPicker = FlagPicker;

function usePeopleDB() {
  const [people, setPeople] = useState(() => {
    const s = window.SLStore.get('silverlines.people.v1'); if (Array.isArray(s) && s.length) return s;
    return CREW_DB_SEED;
  });
  const save = list => { window.SLStore.set('silverlines.people.v1', list); return list; };
  const patch = (id, p) => setPeople(l => save(l.map(x => x.id === id ? { ...x, ...p } : x)));
  const add = () => {
    const id = 'p-' + Date.now();
    const colors = ['#F57F45', '#BD2555', '#22D48A', '#FFB020', '#F7A8CF', '#9aa0aa'];
    setPeople(l => save([{ id, name: 'New crew member', role: 'Role', dept: 'Production', color: colors[l.length % colors.length], phone: '+1 ', email: 'name@crew.co', rate: '$—/day', abilities: [], projects: ['CRSK'] }, ...l]));
    window.toast('Added — click any field to edit', 'UserPlus');
  };
  const del = id => {
    const prev = people; const person = people.find(x => x.id === id) || {};
    setPeople(l => save(l.filter(x => x.id !== id)));
    window.pushUndo && window.pushUndo(`Removed ${person.name || 'crew member'} from the database`, () => setPeople(save(prev)));
  };
  const addMany = rows => {
    const colors = ['#F57F45', '#BD2555', '#22D48A', '#FFB020', '#F7A8CF', '#9aa0aa', '#5ab3c9', '#c08bf0'];
    /* skip duplicates — against the existing DB and within the batch — by name,
       then email/phone, so re-importing contacts doesn't pile up copies */
    const seen = new Set(people.map(p => (p.name || '').trim().toLowerCase()).filter(Boolean));
    const seenC = new Set(people.map(p => (p.email || '').toLowerCase() + '|' + (p.phone || '').replace(/\s/g, '')).filter(k => k.length > 1));
    const added = [];
    rows.forEach((r, i) => {
      const name = (r.name || '').trim(); if (!name) return;
      const key = name.toLowerCase();
      const ckey = (r.email || '').toLowerCase() + '|' + (r.phone || '').replace(/\s/g, '');
      if (seen.has(key) || (ckey.length > 1 && seenC.has(ckey))) return;
      seen.add(key); if (ckey.length > 1) seenC.add(ckey);
      added.push({ id: 'c-' + Date.now() + '-' + i, name, role: r.role || 'Crew', dept: r.dept || 'Crew', color: colors[added.length % colors.length], phone: r.phone || '—', email: r.email || '—', rate: '$—/day', abilities: [], projects: [], imported: true });
    });
    if (added.length) setPeople(l => save([...added, ...l]));
    return added.length;
  };
  return { people, patch, add, addMany, del };
}

/* ---------- narrow-viewport detector (desktop vs phone surface) ---------- */
function useNarrow(bp = 760) {
  const [n, setN] = useState(typeof window !== 'undefined' ? window.innerWidth < bp : false);
  useEffect(() => { const on = () => setN(window.innerWidth < bp); window.addEventListener('resize', on); return () => window.removeEventListener('resize', on); }, []);
  return n;
}

/* ---------- per-project crew assignments (any production, not just CRSK) ---------- */
function useAssignments() {
  const [map, setMap] = useState(() => window.SLStore.get('silverlines.assign.v1', {}));
  /* per-(production,person) post metadata layered on the v1 membership map, so one
     person can hold a different post on each production they're on. Keyed by the
     same production code as v1: { [code]: { [personId]: {post, dept, rate, status} } } */
  const [meta, setMeta] = useState(() => window.SLStore.get('silverlines.assignmeta.v1', {}));
  const save = m => { window.SLStore.set('silverlines.assign.v1', m); return m; };
  const saveMeta = m => { window.SLStore.set('silverlines.assignmeta.v1', m); return m; };
  const toggle = (code, id) => setMap(m => { const list = m[code] || []; const nl = list.includes(id) ? list.filter(x => x !== id) : [...list, id]; return save({ ...m, [code]: nl }); });
  const has = (code, id) => (map[code] || []).includes(id);
  const postOf = (code, id) => (meta[code] || {})[id] || null;
  const setPost = (code, id, patch) => setMeta(mm => { const c = { ...(mm[code] || {}) }; c[id] = { ...(c[id] || {}), ...patch }; return saveMeta({ ...mm, [code]: c }); });
  return { map, meta, toggle, has, postOf, setPost };
}

/* ---------- popover: assign a person to any production ---------- */
function ProjectAssignMenu({ p, isOn, onToggle, count, projects }) {
  const [open, setOpen] = useState(false);
  return (
    <div className="relative" onClick={e => e.stopPropagation()}>
      <button onClick={() => setOpen(o => !o)} title="Add to a production"
        className="flex h-7 items-center gap-1 whitespace-nowrap rounded-lg bg-cta px-2 text-[10px] font-700 text-cta-ink transition-colors hover:bg-cta-hover">
        <Icon name="Plus" size={10} /> Assign{count ? ` · ${count}` : ''} <Icon name="ChevronDown" size={9} />
      </button>
      {open && (
        <React.Fragment>
          <div className="fixed inset-0 z-30" onClick={() => setOpen(false)}></div>
          <div className="fade-up absolute right-0 z-40 mt-1.5 w-[244px] rounded-xl border border-line bg-ink-850 p-1.5 shadow-2xl">
            <div className="px-2 py-1.5 text-[10px] font-700 uppercase tracking-[0.12em] text-zinc-600">Add to production</div>
            {(projects || []).map(pr => {
              const on = isOn(pr);
              return (
                <button key={pr.code} onClick={() => onToggle(pr)}
                  className="flex w-full items-center gap-2.5 rounded-lg px-2 py-2 text-left transition-colors hover:bg-ink-800">
                  <span className="flex h-7 w-7 shrink-0 items-center justify-center rounded-md font-display text-[10px]" style={{ background: pr.bg, color: pr.fg }}>{pr.code}</span>
                  <span className="min-w-0 flex-1">
                    <span className="flex items-center gap-1 truncate text-[12px] font-600 text-zinc-200">{pr.name}{pr.remote && <Icon name="Globe2" size={9} className="text-[#F9A06E]" />}</span>
                    <span className="block truncate text-[10px] text-zinc-500">{pr.remote ? `Remote · ${pr.owner}` : pr.type}</span>
                  </span>
                  <span className={cx('flex h-4.5 w-4.5 shrink-0 items-center justify-center rounded-[5px] border', on ? 'border-mint bg-mint text-ink-950' : 'border-zinc-600 text-transparent')} style={{ height: 18, width: 18 }}><Icon name="Check" size={11} sw={3} /></span>
                </button>
              );
            })}
          </div>
        </React.Fragment>
      )}
    </div>
  );
}

/* ---------- phone contact import (mobile surface) ---------- */
const PHONE_CONTACTS = [
  { name: 'Marcus Reyes', role: 'Gaffer', dept: 'Lighting', phone: '+1 213 555 0182', email: 'marcus.reyes@gmail.com' },
  { name: 'Yuki Tanaka', role: '1st AC', dept: 'Camera', phone: '+81 90 5555 0147', email: 'yuki.t@icloud.com' },
  { name: 'Elena Fischer', role: 'Producer', dept: 'Production', phone: '+41 79 555 0119', email: 'elena@fischerfilms.ch' },
  { name: 'Tomás Vidal', role: 'Key Grip', dept: 'Grip', phone: '+34 612 555 077', email: 'tvidal@proton.me' },
  { name: 'Amara Okafor', role: 'Makeup Artist', dept: 'HMU', phone: '+44 7700 555041', email: 'amara.okafor@gmail.com' },
  { name: 'Sven Bauer', role: 'Sound Mixer', dept: 'Sound', phone: '+49 151 5550 332', email: 'sven@bauaudio.de' },
];
function PhoneContacts({ open, onClose, onImport }) {
  const [granted, setGranted] = useState(false);
  const [sel, setSel] = useState([]);
  useEffect(() => { if (open) { setGranted(false); setSel(PHONE_CONTACTS.map((_, i) => i)); } }, [open]);
  if (!open) return null;
  const toggle = i => setSel(s => s.includes(i) ? s.filter(x => x !== i) : [...s, i]);
  const doImport = () => { onImport(sel.map(i => PHONE_CONTACTS[i])); onClose(); };
  return (
    <div className="fixed inset-0 z-50 flex items-end justify-center p-0 sm:items-center sm:p-4" onClick={onClose}>
      <div className="absolute inset-0 bg-black/70 backdrop-blur-sm"></div>
      <div onClick={e => e.stopPropagation()} className="fade-up relative w-full max-w-[420px] overflow-hidden rounded-t-3xl border border-line bg-ink-850 sm:rounded-3xl">
        <div className="flex items-center justify-between border-b border-line px-4 py-3">
          <div className="flex items-center gap-2"><Icon name="Smartphone" size={15} className="text-mint" /><span className="font-display text-[14px] text-head">Phone Contacts</span></div>
          <button onClick={onClose} className="flex h-7 w-7 items-center justify-center rounded-lg bg-ink-700 text-zinc-300 hover:text-white"><Icon name="X" size={14} /></button>
        </div>
        {!granted ? (
          <div className="p-6 text-center">
            <span className="mx-auto flex h-14 w-14 items-center justify-center rounded-2xl bg-ink-800 text-mint"><Icon name="ContactRound" size={26} /></span>
            <div className="mt-4 font-display text-[17px] leading-tight text-head">“Silverlines” would like to access your Contacts</div>
            <p className="mt-2 text-[12.5px] leading-relaxed text-zinc-500">Pull crew straight from your phone — no typing. They’re saved to your studio database.</p>
            <div className="mt-5 grid grid-cols-2 gap-2">
              <button onClick={onClose} className="rounded-xl border border-line bg-ink-900 py-2.5 text-[13px] font-600 text-zinc-300 hover:border-ink-600">Don’t Allow</button>
              <button onClick={() => setGranted(true)} className="rounded-xl bg-cta py-2.5 text-[13px] font-700 text-cta-ink hover:bg-cta-hover">Allow</button>
            </div>
          </div>
        ) : (
          <React.Fragment>
            <div className="flex items-center justify-between px-4 pt-3 text-[11px] text-zinc-500">
              <span className="font-mono">{PHONE_CONTACTS.length} on this device</span>
              <button onClick={() => setSel(sel.length === PHONE_CONTACTS.length ? [] : PHONE_CONTACTS.map((_, i) => i))} className="font-600 text-electric-soft hover:text-electric">{sel.length === PHONE_CONTACTS.length ? 'Deselect all' : 'Select all'}</button>
            </div>
            <div className="max-h-[46vh] overflow-y-auto p-2">
              {PHONE_CONTACTS.map((c, i) => {
                const on = sel.includes(i);
                return (
                  <button key={i} onClick={() => toggle(i)} className="flex w-full items-center gap-3 rounded-xl px-2.5 py-2 text-left transition-colors hover:bg-ink-800">
                    <Avatar name={c.name} color="#2B303D" size={36} />
                    <div className="min-w-0 flex-1">
                      <div className="truncate text-[13.5px] font-600 text-zinc-100">{c.name}</div>
                      <div className="truncate font-mono text-[11px] text-zinc-500">{c.phone}</div>
                    </div>
                    <span className={cx('flex h-5 w-5 shrink-0 items-center justify-center rounded-full border', on ? 'border-mint bg-mint text-ink-950' : 'border-zinc-600 text-transparent')}><Icon name="Check" size={12} sw={3} /></span>
                  </button>
                );
              })}
            </div>
            <div className="border-t border-line p-3">
              <button onClick={doImport} disabled={!sel.length}
                className={cx('flex w-full items-center justify-center gap-2 rounded-xl py-3 font-display text-[14px] transition-colors', sel.length ? 'bg-cta text-cta-ink hover:bg-cta-hover' : 'bg-ink-700 text-zinc-600')}>
                <Icon name="Download" size={15} /> Add {sel.length} to crew
              </button>
            </div>
          </React.Fragment>
        )}
      </div>
    </div>
  );
}

/* ---------- ability tags: removable + inline add ---------- */
function AbilityChips({ list, onChange }) {
  const [adding, setAdding] = useState(false);
  const [v, setV] = useState('');
  const commit = () => { const t = v.trim(); if (t) onChange([...list, t]); setV(''); setAdding(false); };
  return (
    <div className="flex flex-wrap items-center gap-1.5">
      {list.map((a, i) => (
        <span key={i} className="group/ab inline-flex items-center gap-1 rounded-full border border-line bg-ink-800 px-2 py-0.5 text-[10.5px] font-600 text-zinc-300">
          {a}
          <button onClick={() => onChange(list.filter((_, k) => k !== i))} className="hidden text-zinc-600 hover:text-[#FF4D6D] group-hover/ab:inline"><Icon name="X" size={9} /></button>
        </span>
      ))}
      {adding
        ? <input autoFocus value={v} onChange={e => setV(e.target.value)} onBlur={commit}
            onKeyDown={e => { if (e.key === 'Enter') commit(); if (e.key === 'Escape') { setV(''); setAdding(false); } }}
            placeholder="ability…" className="w-20 rounded-full border border-electric/50 bg-ink-900 px-2 py-0.5 text-[10.5px] text-zinc-200 outline-none" />
        : <button onClick={() => setAdding(true)} title="Add ability"
            className="inline-flex h-[19px] w-[19px] items-center justify-center rounded-full border border-dashed border-ink-600 text-zinc-600 transition-colors hover:border-electric/50 hover:text-electric-soft">
            <Icon name="Plus" size={10} />
          </button>}
    </div>
  );
}

function PersonRow({ p, mobile, onPatch, onDelete, inProject, isCore, onToggleProject, flag, onFlag, crsk, assigned = [], isOn, onAssignToggle, projects, postOf, onOpen }) {
  const onCRSK = isCore || inProject;
  /* bubble counts CRSK by live standing: approved/on = green, flagged-pending = amber, rejected/off = not counted */
  const base = (p.projects || []).filter(c => c !== 'CRSK');
  const counted = crsk.state === 'on' || crsk.state === 'pending';
  const projList = counted ? [...base, 'CRSK'] : base;
  const bubbleTitle = `On ${projList.length} production${projList.length === 1 ? '' : 's'}: ${projList.join(', ') || '—'}`
    + (crsk.state === 'pending' ? ` · CRSK pending (${crsk.label})` : '')
    + (crsk.state === 'off' ? ` · off CRSK (${crsk.label})` : '');
  return (
    <div className={cx('group rounded-xl border border-line bg-ink-900 p-3 transition-colors hover:border-ink-600',
      mobile ? 'flex flex-col gap-2.5' : 'grid grid-cols-12 items-center gap-3')}>
      {/* who */}
      <div className={cx('flex min-w-0 items-center gap-2.5', !mobile && 'col-span-3')}>
        <div className="relative shrink-0">
          <Avatar name={p.name} color={p.color} size={34} />
          {projList.length > 0 && (
            <span title={bubbleTitle}
              className={cx('absolute -bottom-1 -right-1 flex h-[15px] w-[15px] items-center justify-center rounded-full border-2 border-ink-900 font-mono text-[8px] font-700 text-ink-950',
                crsk.state === 'pending' ? 'bg-amber' : 'bg-mint')}>
              {projList.length}
            </span>
          )}
        </div>
        <div className="min-w-0 flex-1">
          <div className="truncate text-[13px] font-700 text-head"><Edit value={p.name} onChange={v => onPatch({ name: v })} className="text-[13px] font-700" /></div>
          <div className="truncate text-[11px] text-zinc-500"><Edit value={p.role} onChange={v => onPatch({ role: v })} className="text-[11px]" /></div>
          {onFlag && (
            <div className="mt-1" onClick={e => e.stopPropagation()}>
              <FlagPicker id={p.id} name={p.name} flag={flag} setFlag={onFlag} />
            </div>
          )}
        </div>
      </div>
      {/* dept + history */}
      <div className={cx(!mobile && 'col-span-2')}>
        <Chip tone="neutral">{p.dept}</Chip>
        <div className="mt-1 font-mono text-[9.5px] tracking-wide text-zinc-600">{projList.join(' · ') || '—'}</div>
        {assigned.length > 0 && (
          <div className="mt-1.5 flex flex-wrap gap-1">
            {assigned.map(pr => {
              const meta = postOf ? postOf(pr.code, p.id) : null;
              return (
              <span key={pr.code} className="group/pj inline-flex items-center gap-1 rounded-md border px-1.5 py-0.5 text-[9.5px] font-700"
                style={{ borderColor: pr.remote ? '#F57F4566' : 'rgb(var(--line))', color: pr.remote ? '#F9A06E' : 'rgb(var(--z300))', background: pr.remote ? 'rgba(245,127,69,0.10)' : 'rgb(var(--ink-800))' }}
                title={(pr.remote ? `Remote · ${pr.owner}` : pr.name) + (meta && meta.post ? ` · ${meta.post}` : '')}>
                {pr.remote && <Icon name="Globe2" size={8} />}{pr.code}{meta && meta.post ? ' · ' + meta.post : ''}
                {onAssignToggle && <button onClick={e => { e.stopPropagation(); onAssignToggle(pr); }} className="text-zinc-500 hover:text-[#FF4D6D]"><Icon name="X" size={8} /></button>}
              </span>
              );
            })}
          </div>
        )}
      </div>
      {/* contact */}
      <div className={cx('min-w-0 space-y-0.5', !mobile && 'col-span-3')}>
        <div className="truncate font-mono text-[11px] text-zinc-300"><Edit value={p.phone} onChange={v => onPatch({ phone: v })} className="font-mono text-[11px]" /></div>
        <div className="truncate text-[11px] text-zinc-500"><Edit value={p.email} onChange={v => onPatch({ email: v })} className="text-[11px]" /></div>
        <div className="truncate font-mono text-[10px] text-zinc-600"><Edit value={p.rate} onChange={v => onPatch({ rate: v })} className="font-mono text-[10px]" /></div>
      </div>
      {/* abilities */}
      <div className={cx('min-w-0', !mobile && 'col-span-3')}>
        <AbilityChips list={p.abilities || []} onChange={abilities => onPatch({ abilities })} />
      </div>
      {/* actions — no project status here; the green bubble counts productions */}
      <div className={cx('flex items-center justify-end gap-1.5', !mobile && 'col-span-1')}>
        {onOpen && <button onClick={onOpen} title="Open full profile"
          className="flex h-7 w-7 items-center justify-center rounded-lg bg-ink-700 text-zinc-400 transition-colors hover:bg-electric/20 hover:text-electric-soft"><Icon name="PanelRightOpen" size={13} /></button>}
        {onAssignToggle && <ProjectAssignMenu p={p} isOn={isOn} onToggle={onAssignToggle} count={assigned.length} projects={projects} />}
        <a href={`tel:${(p.phone || '').replace(/\s/g, '')}`} title="Call"
          className="flex h-7 w-7 items-center justify-center rounded-lg bg-ink-700 text-zinc-400 transition-colors hover:bg-cta hover:text-cta-ink"><Icon name="Phone" size={12} /></a>
        <a href={`mailto:${p.email}`} title="Email"
          className="flex h-7 w-7 items-center justify-center rounded-lg bg-ink-700 text-zinc-400 transition-colors hover:bg-cta hover:text-cta-ink"><Icon name="Mail" size={12} /></a>
        <button onClick={onDelete} title="Remove from database"
          className="flex h-7 w-7 items-center justify-center rounded-lg bg-ink-700 text-zinc-500 opacity-0 transition-all hover:text-[#FF4D6D] group-hover:opacity-100"><Icon name="Trash2" size={12} /></button>
      </div>
    </div>
  );
}

/* full contact card + per-production posts. One person can be on many
   productions, each with a different post (job title) on that show. */
function PersonDrawer({ person, onClose, onPatch, allProjects, isOn, onToggle, postOf, setPost }) {
  const diets = window.SL_DIETS || [
    { id:'vegetarian', label:'Vegetarian' }, { id:'vegan', label:'Vegan' }, { id:'lactose-free', label:'Lactose intolerant' },
    { id:'gluten-free', label:'Gluten-free' }, { id:'nut-free', label:'Nut allergy' }, { id:'halal', label:'Halal' },
  ];
  useEffect(() => {
    const onKey = e => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onKey); return () => window.removeEventListener('keydown', onKey);
  }, []);
  if (!person) return null;
  const p = person;
  const emg = p.emergency || {};
  const onDiets = p.diet || [];
  const toggleDiet = id => onPatch({ diet: onDiets.includes(id) ? onDiets.filter(d => d !== id) : [...onDiets, id] });
  const Field = ({ icon, label, value, onChange, mono, placeholder }) => (
    <div className="flex items-center gap-3 rounded-xl border border-line bg-ink-900 px-3 py-2.5 text-[13px] text-zinc-200">
      <Icon name={icon} size={15} className="shrink-0 text-zinc-500" />
      <div className="min-w-0 flex-1">
        <div className="text-[9.5px] uppercase tracking-[0.1em] text-zinc-600">{label}</div>
        <Edit value={value || ''} onChange={onChange} placeholder={placeholder || label} className={cx('min-w-0 text-[13px]', mono && 'font-mono')} />
      </div>
    </div>
  );
  return (
    <div className="fixed inset-0 z-[70] flex items-start justify-center overflow-y-auto p-4 sm:p-6" onClick={onClose}>
      <div className="absolute inset-0 bg-black/70 backdrop-blur-sm"></div>
      <div onClick={e => e.stopPropagation()} className="fade-up relative my-auto w-full max-w-[680px] overflow-hidden rounded-2xl border border-line bg-ink-850">
        <div className="sticky top-0 z-10 flex items-center gap-3 border-b border-line bg-ink-850/95 px-5 py-4 backdrop-blur">
          <Avatar name={p.name} color={p.color} size={40} />
          <div className="min-w-0 flex-1">
            <div className="text-[16px] font-700 text-head"><Edit value={p.name} onChange={v => onPatch({ name: v })} className="text-[16px] font-700" /></div>
            <div className="text-[12px] text-zinc-500"><Edit value={p.role} onChange={v => onPatch({ role: v })} className="text-[12px]" /> · <Edit value={p.dept} onChange={v => onPatch({ dept: v })} className="text-[12px]" /></div>
          </div>
          <button onClick={onClose} aria-label="Close" className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-ink-800 text-zinc-400 hover:text-white"><Icon name="X" size={16} /></button>
        </div>
        <div className="space-y-4 p-5">
          {/* contact */}
          <Panel>
            <h3 className="mb-2 font-display text-[14px] text-head">Contact</h3>
            <div className="grid gap-2 sm:grid-cols-2">
              {Field({ icon:'Phone', label:'Phone', value:p.phone, onChange:v => onPatch({ phone: v }), mono:true })}
              {Field({ icon:'Mail', label:'Email', value:p.email, onChange:v => onPatch({ email: v }) })}
              {Field({ icon:'MapPin', label:'City', value:p.city, onChange:v => onPatch({ city: v }) })}
              {Field({ icon:'Flag', label:'Country', value:p.country, onChange:v => onPatch({ country: v }) })}
              {Field({ icon:'Globe', label:'Website', value:p.website, onChange:v => onPatch({ website: v }) })}
              {Field({ icon:'Briefcase', label:'Agency', value:p.agency, onChange:v => onPatch({ agency: v }) })}
            </div>
          </Panel>
          {/* productions + per-production post */}
          <Panel>
            <h3 className="mb-1 font-display text-[14px] text-head">Productions &amp; posts</h3>
            <p className="mb-2 text-[11.5px] text-zinc-500">On multiple productions at once — set a different post on each.</p>
            <div className="space-y-2">
              {allProjects.map(pr => {
                const on = isOn(pr);
                const meta = postOf(pr.code, p.id) || {};
                return (
                  <div key={pr.pid || pr.code} className={cx('rounded-xl border px-3 py-2.5 transition-colors', on ? 'border-electric/40 bg-electric/[0.05]' : 'border-line bg-ink-900')}>
                    <div className="flex items-center gap-2.5">
                      <span className="flex h-6 w-9 shrink-0 items-center justify-center rounded-md bg-ink-700 font-mono text-[10px] font-700 text-zinc-300">{pr.code}</span>
                      <div className="min-w-0 flex-1"><div className="truncate text-[13px] font-600 text-zinc-100">{pr.name}</div></div>
                      <Switch on={on} onChange={() => onToggle(pr)} />
                    </div>
                    {on && (
                      <div className="mt-2 grid gap-2 pl-11 sm:grid-cols-2">
                        <div className="flex items-center gap-2 rounded-lg border border-line bg-ink-950 px-2.5 py-1.5">
                          <Icon name="BriefcaseBusiness" size={13} className="shrink-0 text-zinc-500" />
                          <Edit value={meta.post || ''} onChange={v => setPost(pr.code, p.id, { post: v })} placeholder={'Post on this show (e.g. ' + p.role + ')'} className="min-w-0 flex-1 text-[12px]" />
                        </div>
                        <div className="flex items-center gap-2 rounded-lg border border-line bg-ink-950 px-2.5 py-1.5">
                          <Icon name="DollarSign" size={13} className="shrink-0 text-zinc-500" />
                          <Edit value={meta.rate || ''} onChange={v => setPost(pr.code, p.id, { rate: v })} placeholder="Rate on this show" className="min-w-0 flex-1 font-mono text-[12px]" />
                        </div>
                      </div>
                    )}
                  </div>
                );
              })}
            </div>
          </Panel>
          {/* logistics */}
          <Panel>
            <h3 className="mb-2 font-display text-[14px] text-head">Logistics</h3>
            <div className="grid gap-2 sm:grid-cols-2">
              {Field({ icon:'DollarSign', label:'Default rate', value:p.rate, onChange:v => onPatch({ rate: v }), mono:true })}
              {Field({ icon:'IdCard', label:"Driver's license", value:p.license, onChange:v => onPatch({ license: v }) })}
              {Field({ icon:'UserRound', label:'Emergency contact', value:emg.name, onChange:v => onPatch({ emergency: { ...emg, name: v } }) })}
              {Field({ icon:'PhoneCall', label:'Emergency phone', value:emg.phone, onChange:v => onPatch({ emergency: { ...emg, phone: v } }), mono:true })}
            </div>
          </Panel>
          {/* dietary */}
          <Panel>
            <h3 className="mb-1 font-display text-[14px] text-head">Dietary &amp; allergies</h3>
            <p className="mb-2 text-[11.5px] text-zinc-500">Flows into catering for every production they're on.</p>
            <div className="flex flex-wrap gap-1.5">
              {diets.map(d => (
                <button key={d.id} onClick={() => toggleDiet(d.id)}
                  className={cx('rounded-full border px-2.5 py-1 text-[11.5px] font-600 transition-colors', onDiets.includes(d.id) ? 'border-mint/50 bg-mint/12 text-mint' : 'border-line text-zinc-500 hover:text-zinc-300')}>{d.label}</button>
              ))}
            </div>
          </Panel>
          {/* notes */}
          <Panel>
            <h3 className="mb-1 font-display text-[14px] text-head">Notes</h3>
            <div className="text-[12.5px] text-zinc-300"><Edit value={p.notes || ''} onChange={v => onPatch({ notes: v })} placeholder="Anything worth remembering — availability, preferences, history…" multiline className="text-[12.5px]" /></div>
          </Panel>
        </div>
      </div>
    </div>
  );
}

function PeopleDB({ mobile, inProject }) {
  const { people, patch, add, addMany, del } = usePeopleDB();
  const { roster, add: rosterAdd, remove: rosterRemove } = useRoster();
  const { flags, setFlag } = useFlags();
  const assign = useAssignments();
  const [owned] = useOwnedProjects();
  const allProjects = [...owned, ...REMOTE_PROJECTS];
  const narrow = useNarrow();
  const [contacts, setContacts] = useState(false);
  const [drawerId, setDrawerId] = useState(null);
  const [q, setQ] = useState('');
  const [dept, setDept] = useState('All');
  const isCore = p => PEOPLE.some(x => x.name === p.name);
  /* live CRSK standing: flags override membership for the count bubble */
  const crskOf = p => {
    const f = flags[p.id];
    const member = isCore(p) || roster.includes(p.id);
    if (f && f.label === 'Rejected') return { state: 'off', label: f.label };
    if (f && f.label === 'Approved') return { state: 'on', label: f.label };
    if (member) return f ? { state: 'pending', label: f.label } : { state: 'on', label: null };
    if (f) return { state: 'pending', label: f.label };
    return { state: 'none', label: null };
  };
  const toggleProject = p => {
    if (roster.includes(p.id)) {
      rosterRemove(p.id, `Removed ${p.name} from the project`);
      window.toast(`${p.name} removed from Crimson Skies`, 'UserMinus');
      window.notify && window.notify(`${p.name} removed from Crimson Skies`, 'UserMinus', 'crewdb');
    } else {
      rosterAdd(p.id);
      window.toast(`${p.name} added to Crimson Skies — see Pre-Production → Cast & Crew`, 'UserPlus');
      window.notify && window.notify(`${p.name} added to Crimson Skies`, 'UserPlus', 'preprod');
    }
  };
  /* membership across ANY production — crimson uses the live roster, others a per-project map */
  const isOnProject = (pr, person) => pr.pid === 'crimson' ? (isCore(person) || roster.includes(person.id)) : assign.has(pr.code, person.id);
  const liveProjects = person => allProjects.filter(pr => isOnProject(pr, person));
  const onProjectToggle = (pr, person) => {
    if (pr.pid === 'crimson') { toggleProject(person); return; }
    const was = assign.has(pr.code, person.id);
    assign.toggle(pr.code, person.id);
    window.toast(`${person.name} ${was ? 'removed from' : 'added to'} ${pr.name}`, was ? 'UserMinus' : 'UserPlus');
    window.notify && window.notify(`${person.name} ${was ? 'removed from' : 'added to'} ${pr.name}`, was ? 'UserMinus' : 'UserPlus', 'crewdb');
  };
  const depts = ['All', ...Array.from(new Set(people.map(p => p.dept)))];
  const ql = q.trim().toLowerCase();
  const shown = people.filter(p =>
    (dept === 'All' || p.dept === dept) &&
    (!ql || (p.name + ' ' + p.role + ' ' + (p.abilities || []).join(' ')).toLowerCase().includes(ql)));
  return (
    <div>
      <div className="mb-4 flex flex-wrap items-center gap-2">
        <div className="flex min-w-[200px] flex-1 items-center gap-2 rounded-xl border border-line bg-ink-900 px-3 py-2">
          <Icon name="Search" size={14} className="shrink-0 text-zinc-500" />
          <input value={q} onChange={e => setQ(e.target.value)} placeholder="Search names, roles, abilities…"
            className="min-w-0 flex-1 bg-transparent text-[12.5px] text-zinc-200 outline-none placeholder:text-zinc-600" />
        </div>
        <button onClick={() => setContacts(true)} title="Import from your phone contacts"
          className="flex shrink-0 items-center gap-1.5 rounded-xl border border-line bg-ink-900 px-3 py-2 text-[12.5px] font-700 text-zinc-200 transition-colors hover:border-ink-600">
          <Icon name="Smartphone" size={14} /> {narrow ? 'Contacts' : 'Import from Contacts'}
        </button>
        <button onClick={add} className="flex shrink-0 items-center gap-1.5 rounded-xl bg-cta px-3.5 py-2 text-[12.5px] font-700 text-cta-ink hover:bg-cta-hover">
          <Icon name="UserPlus" size={14} /> {narrow ? 'Add' : 'Add person'}
        </button>
      </div>
      <div className="mb-4 flex flex-wrap items-center gap-1.5">
        {depts.map(d => (
          <button key={d} onClick={() => setDept(d)}
            className={cx('rounded-full border px-2.5 py-1 font-display text-[11px] transition-colors',
              dept === d ? 'border-electric/40 bg-electric/10 text-electric-soft' : 'border-line text-zinc-500 hover:text-zinc-300')}>{d}</button>
        ))}
        <span className="ml-auto font-mono text-[10.5px] text-zinc-600">{shown.length} of {people.length} people</span>
      </div>
      <div className="space-y-2">
        {shown.map(p => (
          <PersonRow key={p.id} p={p} mobile={mobile} onPatch={v => patch(p.id, v)} onDelete={() => del(p.id)}
            isCore={isCore(p)} inProject={roster.includes(p.id)} onToggleProject={() => toggleProject(p)}
            assigned={liveProjects(p)} isOn={pr => isOnProject(pr, p)} onAssignToggle={pr => onProjectToggle(pr, p)} projects={allProjects}
            postOf={assign.postOf} onOpen={() => setDrawerId(p.id)}
            crsk={crskOf(p)} flag={inProject ? flags[p.id] : null} onFlag={inProject ? setFlag : null} />
        ))}
        {shown.length === 0 && (
          <div className="scan flex h-[110px] items-center justify-center rounded-xl border border-line text-[12px] text-zinc-500">No one matches — try another search</div>
        )}
      </div>
      <p className="mt-3 text-[11px] text-zinc-600">{inProject
        ? 'Statuses set here (preselected, approved, rejected…) follow the person onto Cast & Crew — one flag, everywhere.'
        : 'This database lives at the workspace level — every production can pull from it. Assign anyone to any project, or import straight from your phone.'}</p>
      <PhoneContacts open={contacts} onClose={() => setContacts(false)}
        onImport={rows => { const n = addMany(rows); if (n) { window.toast(`${n} contact${n > 1 ? 's' : ''} added from your phone`, 'Smartphone'); window.notify && window.notify(`${n} contact${n > 1 ? 's' : ''} imported from phone`, 'Smartphone', 'crewdb'); } }} />
      {drawerId && <PersonDrawer person={people.find(x => x.id === drawerId)} onClose={() => setDrawerId(null)}
        onPatch={v => patch(drawerId, v)} allProjects={allProjects}
        isOn={pr => isOnProject(pr, people.find(x => x.id === drawerId))}
        onToggle={pr => onProjectToggle(pr, people.find(x => x.id === drawerId))}
        postOf={assign.postOf} setPost={assign.setPost} />}
    </div>
  );
}
window.PeopleDB = PeopleDB;

/* ---------- Tools wrapper for in-project access ---------- */
function CrewDBModule({ mobile }) {
  return (
    <div className="fade-up">
      <SectionTitle kicker="Crew & Departments" icon="BookUser" title="Crew Directory"
        action={<Chip tone="proflow"><Icon name="Database" size={12} /> Workspace database</Chip>} />
      <Panel><PeopleDB mobile={mobile} inProject={true} /></Panel>
    </div>
  );
}
window.CrewDBModule = CrewDBModule;

/* ============================================================
   LANDING PAGE — all productions, plus the people database
   ============================================================ */
/* ---------- production schedule + responsible-people derivation ---------- */
function projDates(p) {
  if (p.dates) return p.dates;
  if (p.pid === 'crimson') return 'Jun 22 – 25, 2026';
  if (p.blank) return 'Not scheduled yet';
  return p.meta || '—';
}
function projProgress(p) {
  if (p.remote) return p.meta || p.presence || '';
  if (p.pid === 'crimson') return 'Day 1 of 4 · prep wraps tonight';
  if (p.blank) return 'Empty — start from zero';
  return p.meta || '';
}
function projLeads(p) {
  if (p.leads) return p.leads;
  if (p.pid === 'crimson') return [
    { name: 'Noor Haddad', role: 'Producer', color: '#22D48A' },
    { name: 'Dahlia Mercer', role: 'Director', color: '#F57F45' },
  ];
  return [];
}

/* ---------- production ROW (replaces card) ---------- */
function ProjectRow({ p, onOpen, onDelete, onRename }) {
  const open = () => p.open ? onOpen(p.pid) : window.toast(`${p.name} — ${p.remote ? 'remote production · view-only in this walkthrough' : 'view only in this walkthrough'}`, 'Info');
  const leads = projLeads(p);
  const canRename = onRename && p.owner && !p.remote && !p.demo;
  return (
    <div role="button" tabIndex={0} onClick={open}
      onKeyDown={e => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); open(); } }}
      className="group relative cursor-pointer overflow-hidden rounded-2xl border border-line bg-ink-850 px-4 py-3.5 transition-colors hover:border-ink-600"
      style={p.remote ? { borderLeftWidth: '3px', borderLeftColor: '#F57F45' } : undefined}>
      <div className="grid grid-cols-1 items-center gap-y-3 sm:grid-cols-12 sm:gap-4">
        {/* identity */}
        <div className="flex min-w-0 items-center gap-3 sm:col-span-4">
          <span className="flex h-12 w-12 shrink-0 items-center justify-center rounded-xl font-display text-[16px]" style={{ background: p.bg, color: p.fg }}>{p.code}</span>
          <div className="min-w-0">
            {canRename ? (
              <div className="truncate font-display text-[18px] leading-tight text-head"
                onClick={e => e.stopPropagation()} onKeyDown={e => e.stopPropagation()}>
                <Edit value={p.name} onChange={v => onRename(p, v)} className="font-display text-[18px] leading-tight" placeholder="Name this production" />
              </div>
            ) : (
              <div className="truncate font-display text-[18px] leading-tight text-head">{p.name}</div>
            )}
            <div className="mt-0.5 truncate text-[12px] text-zinc-500">{p.type} · {p.client}</div>
          </div>
        </div>
        {/* status */}
        <div className="flex items-center gap-1.5 sm:col-span-2">
          {p.demo && <span className="inline-flex items-center gap-1 rounded-full bg-amber/15 px-2 py-0.5 text-[9.5px] font-700 uppercase tracking-wide text-amber"><Icon name="FlaskConical" size={10} />Demo</span>}
          {p.remote && <span className="inline-flex items-center gap-1 rounded-full bg-[#F57F45]/15 px-2 py-0.5 text-[9.5px] font-700 uppercase tracking-wide text-[#F9A06E]"><Icon name="Globe2" size={10} />Remote</span>}
          <Chip tone={p.tone}>{p.status}</Chip>
        </div>
        {/* schedule */}
        <div className="min-w-0 sm:col-span-3">
          <div className="flex items-center gap-1.5 text-zinc-300"><Icon name="CalendarDays" size={13} className="shrink-0 text-zinc-500" /><span className="truncate font-mono text-[11.5px]">{projDates(p)}</span></div>
          <div className="mt-1 flex items-center gap-1.5 font-mono text-[10.5px] tracking-wide text-zinc-600"><Icon name={p.remote ? 'Activity' : 'Clock3'} size={11} className="shrink-0" /><span className="truncate">{projProgress(p)}</span></div>
        </div>
        {/* responsible people */}
        <div className="min-w-0 sm:col-span-2">
          {leads.length ? (
            <div className="flex items-center gap-2">
              <div className="flex -space-x-1.5">{leads.map(l => <Avatar key={l.name} name={l.name} color={l.color} size={24} ring />)}</div>
              <div className="min-w-0 leading-tight">
                <div className="truncate text-[11.5px] font-600 text-zinc-200">{leads[0].name}</div>
                <div className="truncate text-[10px] text-zinc-500">{leads.length > 1 ? `${leads[0].role} · +${leads.length - 1}` : leads[0].role}</div>
              </div>
            </div>
          ) : <span className="flex items-center gap-1.5 font-mono text-[10.5px] text-zinc-600"><Icon name="UserPlus" size={12} />Unassigned</span>}
        </div>
        {/* action */}
        <div className="flex items-center justify-end gap-2 sm:col-span-1">
          {onDelete && p.demo && (
            <button onClick={e => { e.stopPropagation(); onDelete(p); }} title="Reset the demo to its original data"
              className="flex h-7 w-7 items-center justify-center rounded-lg border border-line bg-ink-900/80 text-zinc-500 opacity-0 transition-all hover:border-amber/50 hover:text-amber group-hover:opacity-100"><Icon name="RefreshCcw" size={13} /></button>
          )}
          {onDelete && p.owner && !p.remote && !p.demo && (
            <button onClick={e => { e.stopPropagation(); onDelete(p); }} title="Delete this production (owner)"
              className="flex h-7 w-7 items-center justify-center rounded-lg border border-line bg-ink-900/80 text-zinc-500 opacity-0 transition-all hover:border-[#FF4D6D]/50 hover:text-[#FF4D6D] group-hover:opacity-100"><Icon name="Trash2" size={13} /></button>
          )}
          <span className={cx('flex items-center gap-1 whitespace-nowrap font-display text-[12px] transition-colors', p.open ? 'text-electric-soft group-hover:text-electric' : p.remote ? 'text-[#F9A06E]' : 'text-zinc-600')}>{p.open ? 'Open' : 'View'} <Icon name="ArrowRight" size={13} /></span>
        </div>
      </div>
    </div>
  );
}

function ProjectCard({ p, onOpen, onDelete }) {
  const open = () => p.open ? onOpen(p.pid) : window.toast(`${p.name} — ${p.remote ? 'remote production · view-only in this walkthrough' : 'view only in this walkthrough'}`, 'Info');
  return (
    <div role="button" tabIndex={0} onClick={open}
      onKeyDown={e => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); open(); } }}
      className="group relative cursor-pointer overflow-hidden rounded-2xl border border-line bg-ink-850 p-5 text-left transition-colors hover:border-ink-600"
      style={p.remote ? { borderLeftWidth: '3px', borderLeftColor: '#F57F45' } : undefined}>
      <div className="flex items-start justify-between gap-3">
        <span className="flex h-11 w-11 items-center justify-center rounded-xl font-display text-[15px]" style={{ background: p.bg, color: p.fg }}>{p.code}</span>
        <div className="flex items-center gap-1.5">
          {p.remote && <span className="inline-flex items-center gap-1 rounded-full bg-[#F57F45]/15 px-2 py-0.5 text-[9.5px] font-700 uppercase tracking-wide text-[#F9A06E]"><Icon name="Globe2" size={10} />Remote</span>}
          <Chip tone={p.tone}>{p.status}</Chip>
          {onDelete && p.owner && !p.remote && (
            <button onClick={e => { e.stopPropagation(); onDelete(p); }} title="Delete this production (owner)"
              className="flex h-7 w-7 items-center justify-center rounded-lg border border-line bg-ink-900/80 text-zinc-500 opacity-0 backdrop-blur-sm transition-all hover:border-[#FF4D6D]/50 hover:text-[#FF4D6D] group-hover:opacity-100">
              <Icon name="Trash2" size={13} />
            </button>
          )}
        </div>
      </div>
      <div className="mt-4 font-display text-[24px] leading-tight text-head">{p.name}</div>
      <div className="mt-0.5 text-[12.5px] text-zinc-500">{p.type} · {p.client}</div>
      <div className="mt-3 flex items-center gap-1.5 font-mono text-[10.5px] tracking-wide text-zinc-600">
        {p.remote && <Icon name="Globe2" size={11} className="text-[#F9A06E]" />}{p.remote ? `Invited by ${p.owner}` : p.meta}
      </div>
      <div className="mt-4 flex items-center justify-between border-t border-line pt-3.5">
        {p.remote && p.presence
          ? <div className="flex items-center gap-1.5 font-mono text-[10px] text-mint"><span className="h-1.5 w-1.5 rounded-full bg-mint proflow-pulse"></span>{p.presence}</div>
          : <div className="flex -space-x-1.5">
              {(p.blank ? [] : PEOPLE.slice(0, 4)).map(x => <Avatar key={x.name} name={x.name} color={x.color} size={22} ring />)}
              {p.blank && <span className="font-mono text-[10px] text-zinc-600">No crew yet</span>}
            </div>}
        <span className={cx('flex items-center gap-1 font-display text-[12px] transition-colors',
          p.open ? 'text-electric-soft group-hover:text-electric' : p.remote ? 'text-[#F9A06E]' : 'text-zinc-600')}>
          {p.open ? 'Open' : 'View'} <Icon name="ArrowRight" size={13} />
        </span>
      </div>
    </div>
  );
}

/* ---------- delete confirmation — must type "reset" ---------- */
function DeleteProjectModal({ project, onClose, onConfirm }) {
  const [val, setVal] = useState('');
  useEffect(() => { setVal(''); }, [project]);
  if (!project) return null;
  const demo = !!project.demo;
  const accent = demo ? 'amber' : '#FF4D6D';
  const ok = val.trim().toLowerCase() === 'reset';
  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center p-4" onClick={onClose}>
      <div className="absolute inset-0 bg-black/70 backdrop-blur-sm"></div>
      <div onClick={e => e.stopPropagation()} className={cx('fade-up relative w-full max-w-[420px] overflow-hidden rounded-2xl border bg-ink-850', demo ? 'border-amber/30' : 'border-[#FF4D6D]/30')}>
        <div className="flex items-start gap-3 border-b border-line p-5">
          <span className={cx('flex h-11 w-11 shrink-0 items-center justify-center rounded-xl', demo ? 'bg-amber/12 text-amber' : 'bg-[#FF4D6D]/12 text-[#FF4D6D]')}><Icon name={demo ? 'RefreshCcw' : 'TriangleAlert'} size={20} /></span>
          <div className="min-w-0">
            {demo ? (
              <React.Fragment>
                <h3 className="font-display text-[19px] leading-tight text-head">Reset the demo?</h3>
                <p className="mt-1 text-[12.5px] leading-relaxed text-zinc-400">This restores Crimson Skies to its original sample data — any edits you made to the demo are cleared. Your own productions and account are untouched.</p>
              </React.Fragment>
            ) : (
              <React.Fragment>
                <h3 className="font-display text-[19px] leading-tight text-head">Delete “{project.name}”?</h3>
                <p className="mt-1 text-[12.5px] leading-relaxed text-zinc-400">This permanently wipes the production and all its data — storyboard, shot list, breakdown and call sheets. This can’t be undone.</p>
              </React.Fragment>
            )}
          </div>
          <button onClick={onClose} className="ml-auto flex h-7 w-7 shrink-0 items-center justify-center rounded-lg bg-ink-800 text-zinc-400 hover:text-white"><Icon name="X" size={15} /></button>
        </div>
        <div className="p-5">
          <label className="mb-1.5 block text-[12px] font-600 text-zinc-300">Type <span className={cx('rounded bg-ink-900 px-1.5 py-0.5 font-mono text-[12px]', demo ? 'text-amber' : 'text-[#FF6B6B]')}>reset</span> to confirm</label>
          <input autoFocus value={val} onChange={e => setVal(e.target.value)}
            onKeyDown={e => { if (e.key === 'Enter' && ok) onConfirm(project); if (e.key === 'Escape') onClose(); }}
            placeholder="reset"
            className={cx('w-full rounded-xl border bg-ink-900 px-3 py-2.5 text-[13px] text-zinc-100 outline-none transition-colors placeholder:text-zinc-600',
              ok ? (demo ? 'border-amber/60' : 'border-[#FF4D6D]/60') : 'border-line focus:border-zinc-600')} />
          <div className="mt-4 flex gap-2">
            <button onClick={onClose} className="flex-1 rounded-xl border border-line bg-ink-900 py-2.5 text-[13px] font-700 text-zinc-200 hover:border-ink-600">Cancel</button>
            <button onClick={() => ok && onConfirm(project)} disabled={!ok}
              className={cx('flex flex-1 items-center justify-center gap-1.5 rounded-xl py-2.5 text-[13px] font-700 transition-colors',
                ok ? (demo ? 'bg-amber text-ink-950 hover:opacity-90' : 'bg-[#FF4D6D] text-white hover:bg-[#e0345a]') : 'cursor-not-allowed bg-ink-700 text-zinc-600')}>
              <Icon name={demo ? 'RefreshCcw' : 'Trash2'} size={14} /> {demo ? 'Reset demo' : 'Delete production'}
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}

/* section header for Mine vs Remote */
function HomeSection({ icon, title, count, sub, color }) {
  return (
    <div className="mb-3 flex items-center gap-2.5">
      <span className="flex h-8 w-8 items-center justify-center rounded-lg border border-line bg-ink-850" style={{ color }}><Icon name={icon} size={16} /></span>
      <div>
        <div className="flex items-center gap-2 font-display text-[18px] text-head">{title}<span className="font-mono text-[11px] text-zinc-600">{count}</span></div>
        <div className="text-[11.5px] text-zinc-500">{sub}</div>
      </div>
    </div>
  );
}

function LandingPage({ onOpen }) {
  const { theme, setTheme } = useContext(AccessContext);
  const acct = window.useAccount ? window.useAccount() : null;
  const [tab, setTab] = useState('projects');
  const [owned, setOwned] = useOwnedProjects();
  const [del, setDel] = useState(null);
  const demoRows = owned.filter(p => p.demo);
  const mine = owned.filter(p => !p.demo);
  const newProduction = () => { window.createProduction && window.createProduction(); };
  const rename = (p, v) => {
    if (window.slRenameProduction) window.slRenameProduction(p.pid, v);
    else setOwned(l => l.map(x => x.pid === p.pid ? { ...x, name: v } : x));
  };
  const confirmDelete = (p) => {
    wipeProject(p.pid);
    if (p.demo) { window.toast('Demo reset to Crimson Skies', 'RefreshCcw'); }
    else {
      /* if we're deleting the production that's currently open, reset the active
         pointer so the next boot can't land on a dangling "Untitled" ghost */
      if (p.pid === window.PROJ_ID) { try { localStorage.setItem('silverlines.project', 'crimson'); localStorage.removeItem('silverlines.autoopen'); } catch (e) {} }
      setOwned(l => l.filter(x => x.pid !== p.pid)); window.toast(`${p.name} deleted`, 'Trash2');
    }
    setDel(null);
  };
  const [lng, setLng] = useState(() => (window.getLang && window.getLang()) || 'en');
  const cycleLang = () => { const nx = { en: 'fr', fr: 'de', de: 'en' }[lng] || 'en'; setLng(nx); window.setLang && window.setLang(nx); };
  const day = theme === 'day';
  return (
    <div className="grain relative min-h-screen overflow-y-auto bg-ink-950" style={{ height: '100vh' }}>
      <div className="relative z-10">
        <header className="mx-auto flex max-w-[1180px] items-center justify-between px-7 py-5">
          <Logo />
          <div className="flex items-center gap-2.5">
            <button onClick={cycleLang} data-no-i18n="true" title="Language — English / Français / Deutsch"
              className="flex h-9 items-center gap-1.5 rounded-lg border border-line bg-ink-900 px-2.5 text-[11px] font-700 uppercase tracking-wide text-zinc-400 transition-colors hover:text-zinc-200">
              <Icon name="Globe" size={14} />{lng}
            </button>
            <button onClick={() => setTheme(day ? 'night' : 'day')}
              className="flex h-9 w-9 items-center justify-center rounded-lg border border-line bg-ink-900 text-zinc-400 hover:text-zinc-200">
              <Icon name={day ? 'Sun' : 'Moon'} size={15} />
            </button>
            {acct && acct.company ? <span className="hidden truncate text-[12px] font-600 text-zinc-400 sm:block">{acct.company}</span> : null}
            <button onClick={() => window.openAccount && window.openAccount()} aria-label="Account settings" title="Account settings"
              className="rounded-full ring-2 ring-transparent transition-all hover:ring-electric/50 focus:outline-none focus-visible:ring-electric/70">
              <Avatar name={acct ? acct.name : 'Producer'} color={acct ? acct.color : '#22D48A'} size={32} />
            </button>
          </div>
        </header>

        <main className="mx-auto max-w-[1180px] px-7 pb-16 pt-8">
          <div className="text-[11px] font-600 uppercase tracking-[0.2em] text-proflow-soft">Silverlines · Production OS</div>
          <h1 className="mt-2 font-display text-[44px] leading-none text-head">
            {tab === 'projects' ? 'Your productions.' : 'Your people.'}
          </h1>
          <p className="mt-2 max-w-[480px] text-[14px] leading-relaxed text-zinc-400">
            {tab === 'projects'
              ? 'The productions you own and the ones you’ve been invited onto — all in one place, synced live.'
              : 'Everyone who has ever been on a call sheet, and what they are great at. Pull from here on every new project.'}
          </p>

          <div className="mt-6 inline-flex rounded-xl border border-line bg-ink-850 p-1">
            {[['projects', 'Clapperboard', 'Projects'], ['people', 'BookUser', 'People']].map(([id, ic, l]) => (
              <button key={id} onClick={() => setTab(id)}
                className={cx('flex items-center gap-2 rounded-lg px-4 py-2 font-display text-[12.5px] transition-colors',
                  tab === id ? 'bg-ink-700 text-head' : 'text-zinc-400 hover:text-zinc-200')}>
                <Icon name={ic} size={14} />{l}
              </button>
            ))}
          </div>

          {tab === 'projects' && (
            <div className="fade-up mt-7 space-y-9">
              <section>
                <HomeSection icon="FlaskConical" title="Demo production" count={demoRows.length}
                  sub="Explore Silverlines with the Crimson Skies sample — edit freely, reset any time." color="rgb(var(--amber))" />
                <div className="space-y-3">
                  {demoRows.map(p => <ProjectRow key={p.pid} p={p} onOpen={onOpen} onDelete={setDel} />)}
                </div>
              </section>

              <section>
                <HomeSection icon="FolderOpen" title="My Productions" count={mine.length}
                  sub="Productions your company owns and runs." color="rgb(var(--proflow))" />
                <div className="space-y-3">
                  {mine.map(p => <ProjectRow key={p.pid || p.code} p={p} onOpen={onOpen} onDelete={setDel} onRename={rename} />)}
                  {mine.length === 0 ? (
                    <EmptyState icon="Clapperboard" title="Create your first production"
                      sub="Your workspace is empty. Spin up a real production — schedule, budget, call sheets and crew, all yours."
                      action={<button onClick={newProduction} className="mt-1 inline-flex items-center gap-2 rounded-xl bg-cta px-4 py-2.5 font-display text-[13px] text-cta-ink transition-colors hover:bg-cta-hover"><Icon name="Plus" size={15} /> New production</button>} />
                  ) : (
                    <button onClick={newProduction}
                      className="flex w-full items-center gap-3 rounded-2xl border border-dashed border-ink-600 px-4 py-3.5 text-left text-zinc-500 transition-colors hover:border-electric/50 hover:text-electric-soft">
                      <span className="flex h-12 w-12 shrink-0 items-center justify-center rounded-xl border border-dashed border-ink-600"><Icon name="Plus" size={20} /></span>
                      <div><div className="font-display text-[14px]">New production</div><div className="font-mono text-[10px] text-zinc-600">Name it · start from zero</div></div>
                    </button>
                  )}
                </div>
              </section>

              <section>
                <HomeSection icon="Globe2" title="Remote / Invited" count={REMOTE_PROJECTS.length}
                  sub="Preview — live invites arrive with the beta backend." color="#F57F45" />
                <div className="space-y-3">
                  {REMOTE_PROJECTS.map(p => <ProjectRow key={p.code} p={p} onOpen={onOpen} />)}
                  <button onClick={() => window.toast('Invite links go live with the beta backend', 'Mailbox')}
                    className="flex w-full items-center gap-3 rounded-2xl border border-dashed border-ink-600 px-4 py-3.5 text-left text-zinc-500 transition-colors hover:border-[#F57F45]/50 hover:text-[#F9A06E]">
                    <span className="flex h-12 w-12 shrink-0 items-center justify-center rounded-xl border border-dashed border-ink-600"><Icon name="Mailbox" size={20} /></span>
                    <div><div className="font-display text-[14px]">Join with an invite</div><div className="font-mono text-[10px] text-zinc-600">Paste a link or 6-digit code</div></div>
                  </button>
                </div>
              </section>
            </div>
          )}
          {tab === 'people' && (
            <div className="fade-up mt-6 rounded-2xl border border-line bg-ink-850 p-5">
              <PeopleDB mobile={false} />
            </div>
          )}

          {/* ---------- legal disclaimer ---------- */}
          <footer className="mt-14 border-t border-line pt-6">
            <div className="flex items-start gap-2.5">
              <Icon name="ShieldCheck" size={14} className="mt-0.5 shrink-0 text-zinc-600" />
              <p className="max-w-[820px] text-[11px] leading-relaxed text-zinc-600">
                <span className="font-600 text-zinc-500">Confidential &amp; proprietary.</span> Silverlines Production OS and every record it holds — schedules, crew and contact data, scripts, breakdowns, budgets, call sheets and media — are confidential and provided solely for authorized members of each production. Do not copy, distribute, or share access outside the assigned team. Crew and talent personal data is processed under our Data Processing Agreement and applicable privacy law; rights to scripts, footage and creative materials remain with their respective owners. Use of this workspace constitutes acceptance of the Silverlines Terms of Service.
              </p>
            </div>
            <div className="mt-3 flex flex-wrap items-center gap-x-3 gap-y-1 font-mono text-[10px] text-zinc-700">
              <span>© 2026 Silverlines</span><span>·</span>
              <button onClick={() => window.toast('Terms of Service — opens in your browser', 'FileText')} className="hover:text-zinc-400">Terms</button><span>·</span>
              <button onClick={() => window.toast('Privacy Policy — opens in your browser', 'FileText')} className="hover:text-zinc-400">Privacy</button><span>·</span>
              <button onClick={() => window.toast('Data Processing Agreement — opens in your browser', 'FileText')} className="hover:text-zinc-400">Data Processing</button><span>·</span>
              <span>Silverlines OS v1.0</span>
            </div>
          </footer>
        </main>
      </div>
      <DeleteProjectModal project={del} onClose={() => setDel(null)} onConfirm={confirmDelete} />
    </div>
  );
}
window.LandingPage = LandingPage;
