// Modals: Share, Watermark, Login, NewCollection

function Modal({ children, onClose, width = 520 }) {
  return (
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0, zIndex: 200,
      background: 'rgba(5,5,7,0.75)', backdropFilter: 'blur(8px)',
      display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 20,
      animation: 'fade-in 160ms',
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        width: '100%', maxWidth: width, maxHeight: '88vh', overflowY: 'auto',
        background: 'var(--bg-1)', border: '1px solid var(--line-2)',
        borderRadius: 10, padding: 22,
        boxShadow: '0 32px 80px rgba(0,0,0,0.8)',
        animation: 'fade-up 180ms ease',
      }}>{children}</div>
    </div>
  );
}

function ShareModal({ onClose, shares, collections, onCreate, onRevoke }) {
  const [label, setLabel] = React.useState('Client Preview');
  const [filter, setFilter] = React.useState('picks');
  const [collection, setCollection] = React.useState('');
  const [expiry, setExpiry] = React.useState('7d');
  const [watermark, setWatermark] = React.useState(true);
  const [download, setDownload] = React.useState(true);
  const [pinProtect, setPinProtect] = React.useState(false);
  const [created, setCreated] = React.useState(null);
  const [creating, setCreating] = React.useState(false);
  const [qrTarget, setQrTarget] = React.useState(null); // { url, label }

  const handleCreate = async () => {
    setCreating(true);
    const share = await onCreate({ label, filter: filter === 'collection' ? `collection:${collection}` : filter, expires: expiry, watermark, download, pinProtect });
    setCreating(false);
    if (share) setCreated(share);
  };

  const copyUrl = (token) => {
    const url = `${window.location.origin}/share/${token}`;
    navigator.clipboard.writeText(url).catch(() => {});
  };

  return (
    <Modal onClose={onClose} width={560}>
      <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', marginBottom: 18 }}>
        <div>
          <div className="mono" style={{ fontSize: 9.5, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: 0.14 }}>Client Delivery</div>
          <div className="serif" style={{ fontSize: 28, letterSpacing: -0.5, color: 'var(--ink-0)', marginTop: 2 }}>Share gallery</div>
        </div>
        <Btn size="sm" onClick={onClose} icon={<IconX size={13}/>}/>
      </div>

      {!created ? (
        <>
          <Field label="Label">
            <input value={label} onChange={e => setLabel(e.target.value)} style={inputS}/>
          </Field>
          <Field label="Include">
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 6 }}>
              {[
                { v: 'all', l: 'All photos' }, { v: 'picks', l: 'Picks only' },
                { v: 'rated3', l: 'Rated 3★+' }, { v: 'collection', l: 'A collection…' },
              ].map(o => (
                <button key={o.v} onClick={() => setFilter(o.v)} style={radioBtnS(filter === o.v)}>
                  <span style={{ width: 12, height: 12, borderRadius: '50%', border: `1.5px solid ${filter===o.v?'var(--accent)':'var(--line-3)'}`, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                    {filter === o.v && <span style={{ width: 6, height: 6, borderRadius: '50%', background: 'var(--accent)' }}/>}
                  </span>
                  {o.l}
                </button>
              ))}
            </div>
          </Field>
          {filter === 'collection' && (
            <Field label="Collection">
              <select value={collection} onChange={e => setCollection(e.target.value)} style={inputS}>
                <option value="">— select —</option>
                {collections.map(c => <option key={c.name} value={c.name}>{c.name} ({c.count || (c.files && c.files.length) || 0})</option>)}
              </select>
            </Field>
          )}
          <Field label="Expires">
            <div style={{ display: 'flex', gap: 4 }}>
              {[{v:'1d',l:'24h'},{v:'7d',l:'7 days'},{v:'30d',l:'30 days'},{v:'never',l:'Never'}].map(o => (
                <button key={o.v} onClick={() => setExpiry(o.v)} style={segS(expiry === o.v)}>{o.l}</button>
              ))}
            </div>
          </Field>
          <Field label="Options">
            <Toggle checked={watermark} onChange={setWatermark} label="Apply watermark to downloads"/>
            <Toggle checked={download} onChange={setDownload} label="Allow downloads"/>
            <Toggle checked={pinProtect} onChange={setPinProtect} label="Require PIN code"/>
          </Field>
          <div style={{ display: 'flex', gap: 6, marginTop: 20 }}>
            <Btn variant="accent" size="lg" onClick={handleCreate} disabled={creating} style={{ flex: 1 }}>
              <IconLink size={14} stroke="#1a1200"/> {creating ? 'Creating…' : 'Create share link'}
            </Btn>
            <Btn variant="outline" size="lg" onClick={onClose}>Cancel</Btn>
          </div>
        </>
      ) : (
        <>
          <div style={{ padding: 18, background: 'var(--bg-2)', borderRadius: 8, border: '1px solid var(--line-2)', marginBottom: 16 }}>
            <div className="mono" style={{ fontSize: 9.5, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: 0.1, marginBottom: 6 }}>Share URL</div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <code className="mono" style={{ flex: 1, fontSize: 12, color: 'var(--ink-0)', background: 'var(--bg-3)', padding: '8px 10px', borderRadius: 4, border: '1px solid var(--line-2)', overflow: 'auto' }}>
                {window.location.origin}/share/{created.token}
              </code>
              <Btn variant="accent" icon={<IconCopy size={13}/>} onClick={() => copyUrl(created.token)}>Copy</Btn>
              <Btn variant="outline" icon={
                <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                  <rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/>
                  <rect x="14" y="14" width="7" height="7"/>
                </svg>
              } onClick={() => setQrTarget({ token: created.token, url: `${window.location.origin}/share/${created.token}`, label: created.label || 'Share' })}>QR</Btn>
            </div>
            <div style={{ display: 'flex', gap: 16, marginTop: 10, fontSize: 11, color: 'var(--ink-2)' }}>
              <span><span style={{ color: 'var(--ink-3)' }}>Filter:</span> <span className="mono">{created.filter}</span></span>
              <span><span style={{ color: 'var(--ink-3)' }}>Expires:</span> <span className="mono">{created.expires ? new Date(created.expires).toLocaleDateString() : 'never'}</span></span>
            </div>
          </div>
          <Btn variant="outline" size="lg" onClick={() => setCreated(null)} style={{ width: '100%' }}>Create another</Btn>
        </>
      )}

      {shares.length > 0 && (
        <div style={{ marginTop: 24, borderTop: '1px solid var(--line-1)', paddingTop: 18 }}>
          <div className="mono" style={{ fontSize: 9.5, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: 0.12, marginBottom: 10 }}>Active links · {shares.length}</div>
          {shares.map(s => (
            <ShareLinkRow key={s.token} share={s} onRevoke={onRevoke} copyUrl={copyUrl} onQR={() => setQrTarget({ token: s.token, url: `${window.location.origin}/share/${s.token}`, label: s.label || 'Share' })}/>
          ))}
        </div>
      )}
      {qrTarget && <QRModal token={qrTarget.token} url={qrTarget.url} label={qrTarget.label} onClose={() => setQrTarget(null)}/>}
    </Modal>
  );
}

function relDate(ts) {
  const diff = ts - Date.now();
  const d = Math.round(diff / 86400000);
  if (d < 0) return `${-d}d ago`;
  if (d < 1) return 'today';
  return `${d}d`;
}

function WatermarkModal({ onClose, config, onSave }) {
  const [text, setText] = React.useState(config.text || '© STUDIO 2026');
  const [opacity, setOpacity] = React.useState(config.opacity || 65);
  const [position, setPosition] = React.useState(config.position || 'bottom-right');
  const [size, setSize] = React.useState(config.size || 'medium');
  const [saving, setSaving] = React.useState(false);

  const handleSave = async () => {
    setSaving(true);
    await onSave({ text, opacity, position, size });
    setSaving(false);
    onClose();
  };

  return (
    <Modal onClose={onClose} width={640}>
      <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', marginBottom: 18 }}>
        <div>
          <div className="mono" style={{ fontSize: 9.5, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: 0.14 }}>Delivery protection</div>
          <div className="serif" style={{ fontSize: 28, letterSpacing: -0.5, color: 'var(--ink-0)', marginTop: 2 }}>Watermark</div>
        </div>
        <Btn size="sm" onClick={onClose} icon={<IconX size={13}/>}/>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: '1fr 240px', gap: 20 }}>
        <div>
          <Field label="Watermark text">
            <input value={text} onChange={e => setText(e.target.value)} placeholder="e.g. © Studio 2026" style={inputS}/>
          </Field>
          <Field label={`Opacity · ${opacity}%`}>
            <input type="range" min="10" max="100" value={opacity} onChange={e => setOpacity(+e.target.value)} style={{ width: '100%', accentColor: 'var(--accent)' }}/>
          </Field>
          <Field label="Position">
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 4 }}>
              {['top-left','top-center','top-right','center-left','center','center-right','bottom-left','bottom-center','bottom-right'].map(p => (
                <button key={p} onClick={() => setPosition(p)} style={{
                  height: 28, background: position === p ? 'var(--accent-soft)' : 'var(--bg-2)',
                  border: `1px solid ${position === p ? 'var(--accent)' : 'var(--line-1)'}`,
                  borderRadius: 4, cursor: 'pointer', position: 'relative',
                }}>
                  <span style={{
                    position: 'absolute',
                    top: p.startsWith('top') ? 3 : p.startsWith('center') ? '50%' : 'auto',
                    bottom: p.startsWith('bottom') ? 3 : 'auto',
                    left: p.endsWith('left') ? 4 : (p.includes('center') && !p.startsWith('center')) ? '50%' : 'auto',
                    right: p.endsWith('right') ? 4 : 'auto',
                    transform: p.startsWith('center') ? 'translateY(-50%)' : (p.includes('center') && !p.startsWith('center')) ? 'translateX(-50%)' : 'none',
                    width: 4, height: 4, borderRadius: 1, background: position === p ? 'var(--accent)' : 'var(--ink-3)',
                  }}/>
                </button>
              ))}
            </div>
          </Field>
          <Field label="Size">
            <div style={{ display: 'flex', gap: 4 }}>
              {['small','medium','large'].map(s => (
                <button key={s} onClick={() => setSize(s)} style={segS(size === s)}>{s}</button>
              ))}
            </div>
          </Field>
        </div>

        {/* Preview */}
        <div>
          <div className="mono" style={{ fontSize: 9, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: 0.14, marginBottom: 6 }}>Preview</div>
          <div style={{
            position: 'relative', width: '100%', aspectRatio: '4/5', borderRadius: 6, overflow: 'hidden',
            background: '#222',
          }}>
            <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(135deg, #333 0%, #1a1a1a 100%)' }}/>
            <span style={{
              position: 'absolute',
              top: position.startsWith('top') ? 12 : position.startsWith('center') ? '50%' : 'auto',
              bottom: position.startsWith('bottom') ? 12 : 'auto',
              left: position.endsWith('left') ? 12 : (position.includes('center') && !position.startsWith('center')) ? '50%' : 'auto',
              right: position.endsWith('right') ? 12 : 'auto',
              transform: [
                position.startsWith('center') ? 'translateY(-50%)' : '',
                (position.includes('center') && !position.startsWith('center')) ? 'translateX(-50%)' : ''
              ].filter(Boolean).join(' ') || 'none',
              color: '#fff', opacity: opacity/100,
              fontSize: size === 'small' ? 10 : size === 'medium' ? 14 : 18,
              fontWeight: 700, letterSpacing: 0.12, textTransform: 'uppercase',
              fontFamily: 'var(--mono)',
              textShadow: '0 1px 4px rgba(0,0,0,0.8)',
            }}>{text || '© STUDIO'}</span>
          </div>
        </div>
      </div>

      <div style={{ display: 'flex', gap: 6, marginTop: 20 }}>
        <Btn variant="accent" size="lg" onClick={handleSave} disabled={saving} style={{ flex: 1 }}>
          {saving ? 'Saving…' : 'Save watermark'}
        </Btn>
        <Btn variant="outline" size="lg" onClick={onClose}>Cancel</Btn>
      </div>
    </Modal>
  );
}

function Toggle({ checked, onChange, label }) {
  return (
    <label style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '6px 0', cursor: 'pointer' }}>
      <button onClick={() => onChange(!checked)} style={{
        width: 28, height: 16, borderRadius: 99,
        background: checked ? 'var(--accent)' : 'var(--bg-3)',
        border: `1px solid ${checked ? 'var(--accent)' : 'var(--line-2)'}`,
        position: 'relative', cursor: 'pointer', padding: 0, transition: 'background 160ms',
      }}>
        <span style={{
          position: 'absolute', top: 1, left: checked ? 13 : 1,
          width: 12, height: 12, borderRadius: '50%',
          background: checked ? '#1a1200' : 'var(--ink-1)',
          transition: 'left 160ms',
        }}/>
      </button>
      <span style={{ fontSize: 12, color: 'var(--ink-1)' }}>{label}</span>
    </label>
  );
}

function Field({ label, children }) {
  return (
    <div style={{ marginBottom: 14 }}>
      <div className="mono" style={{ fontSize: 9.5, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: 0.12, marginBottom: 6 }}>{label}</div>
      {children}
    </div>
  );
}

const inputS = {
  width: '100%', background: 'var(--bg-2)', border: '1px solid var(--line-2)',
  borderRadius: 6, padding: '8px 10px', fontSize: 12.5, color: 'var(--ink-0)',
  outline: 'none', fontFamily: 'inherit',
};
const radioBtnS = (active) => ({
  display: 'flex', alignItems: 'center', gap: 8, padding: '8px 10px',
  background: active ? 'var(--accent-soft)' : 'var(--bg-2)',
  border: `1px solid ${active ? 'var(--accent-dim)' : 'var(--line-1)'}`,
  borderRadius: 6, cursor: 'pointer', color: 'var(--ink-1)', fontSize: 12,
  textAlign: 'left',
});
const segS = (active) => ({
  flex: 1, padding: '6px 8px', fontSize: 11.5,
  background: active ? 'var(--bg-4)' : 'var(--bg-2)',
  color: active ? 'var(--ink-0)' : 'var(--ink-2)',
  border: `1px solid ${active ? 'var(--line-3)' : 'var(--line-1)'}`,
  borderRadius: 4, cursor: 'pointer', textTransform: 'capitalize',
});

function NewCollectionModal({ onClose, onCreate }) {
  const [name, setName] = React.useState('');
  const [creating, setCreating] = React.useState(false);
  const handle = async () => {
    if (!name.trim()) return;
    setCreating(true);
    await onCreate(name.trim());
    setCreating(false);
    onClose();
  };
  return (
    <Modal onClose={onClose} width={400}>
      <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', marginBottom: 14 }}>
        <div className="serif" style={{ fontSize: 22, color: 'var(--ink-0)', letterSpacing: -0.3 }}>New collection</div>
        <Btn size="sm" onClick={onClose} icon={<IconX size={13}/>}/>
      </div>
      <Field label="Name">
        <input autoFocus value={name} onChange={e => setName(e.target.value)}
          onKeyDown={e => { if (e.key === 'Enter') handle(); }}
          placeholder="e.g. Retouch Queue" style={inputS}/>
      </Field>
      <div style={{ display: 'flex', gap: 6, marginTop: 14 }}>
        <Btn variant="accent" onClick={handle} disabled={creating} style={{ flex: 1 }}>
          {creating ? 'Creating…' : 'Create'}
        </Btn>
        <Btn variant="outline" onClick={onClose}>Cancel</Btn>
      </div>
    </Modal>
  );
}

function LoginScreen({ onLogin, theme, setTheme }) {
  const [tab, setTab]         = React.useState('login'); // 'login' | 'register'
  const [user, setUser]       = React.useState('');
  const [pw, setPw]           = React.useState('');
  const [pw2, setPw2]         = React.useState('');
  const [name, setName]       = React.useState('');
  const [email, setEmail]     = React.useState('');
  const [err, setErr]         = React.useState('');
  const [errType, setErrType] = React.useState('error'); // 'error' | 'expired' | 'suspended'
  const [loading, setLoading] = React.useState(false);
  const [pending, setPending] = React.useState(false); // registration submitted

  const switchTab = (t) => { setTab(t); setErr(''); setErrType('error'); setUser(''); setPw(''); setPw2(''); setName(''); setEmail(''); };

  const submitLogin = async (e) => {
    e.preventDefault();
    if (!user.trim() || !pw.length) { setErr('Please fill in all fields.'); setErrType('error'); return; }
    setLoading(true);
    const result = await onLogin(user.trim(), pw);
    setLoading(false);
    if (!result.ok) {
      const msg = result.message || 'Incorrect username or password.';
      setErr(msg);
      if (msg.toLowerCase().includes('expired')) setErrType('expired');
      else if (msg.toLowerCase().includes('suspended')) setErrType('suspended');
      else setErrType('error');
    }
  };

  const submitRegister = async (e) => {
    e.preventDefault();
    if (!user.trim() || !name.trim() || !email.trim() || !pw.length) { setErr('Please fill in all fields.'); return; }
    if (!/\S+@\S+\.\S+/.test(email.trim())) { setErr('Please enter a valid email address.'); return; }
    if (pw !== pw2) { setErr('Passwords do not match.'); return; }
    if (pw.length < 6) { setErr('Password must be at least 6 characters.'); return; }
    if (!/^[a-z0-9_-]+$/.test(user.trim())) { setErr('Username: only letters, numbers, hyphens, underscores.'); return; }
    setLoading(true);
    try {
      const r = await fetch('/auth/register', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ username: user.trim(), password: pw, display_name: name.trim(), email: email.trim() }),
      });
      const data = await r.json().catch(() => ({}));
      if (r.ok) {
        setPending(true);
      } else {
        setErr(data.detail || 'Registration failed. Please try again.');
      }
    } catch {
      setErr('Network error. Please try again.');
    }
    setLoading(false);
  };

  const cardStyle = {
    width: 400, padding: '40px 36px',
    background: 'var(--bg-1)', border: '1px solid var(--line-2)',
    borderRadius: 12, boxShadow: '0 24px 80px rgba(0,0,0,0.5)',
  };

  const logo = (
    <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 28 }}>
      <div style={{ width: 30, height: 30, borderRadius: 6, background: 'var(--accent)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#1a1200' }}>
        <IconCamera size={16}/>
      </div>
      <div>
        <div className="mono" style={{ fontSize: 9.5, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: 0.14 }}>Studio</div>
        <div style={{ fontSize: 13, color: 'var(--ink-0)', fontWeight: 600, letterSpacing: -0.1 }}>Dashboard</div>
      </div>
    </div>
  );

  const footer = (
    <div style={{ marginTop: 22, paddingTop: 18, borderTop: '1px solid var(--line-1)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', fontSize: 10.5, color: 'var(--ink-3)' }}>
      <span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
        <span style={{ width: 6, height: 6, borderRadius: '50%', background: '#88ddaa', animation: 'pulse-dot 2s infinite' }}/>
        Studio online
      </span>
      <button onClick={() => setTheme(theme === 'graphite' ? 'darkroom' : 'graphite')}
        style={{ background: 'none', border: 'none', color: 'var(--ink-3)', fontFamily: 'var(--mono)', fontSize: 9.5, textTransform: 'uppercase', letterSpacing: 0.14, cursor: 'pointer' }}>
        {theme === 'graphite' ? 'Graphite' : 'Darkroom'}
      </button>
    </div>
  );

  const tabBar = (
    <div style={{ display: 'flex', gap: 0, marginBottom: 24, background: 'var(--bg-0)', borderRadius: 7, padding: 3 }}>
      {['login','register'].map(t => (
        <button key={t} onClick={() => switchTab(t)} style={{
          flex: 1, height: 30, borderRadius: 5, border: 'none', cursor: 'pointer',
          fontFamily: 'inherit', fontSize: 12, fontWeight: 500,
          background: tab === t ? 'var(--bg-2)' : 'transparent',
          color: tab === t ? 'var(--ink-0)' : 'var(--ink-3)',
          transition: 'all 0.15s',
        }}>
          {t === 'login' ? 'Sign In' : 'Request Access'}
        </button>
      ))}
    </div>
  );

  const wrap = (child) => (
    <div style={{ position: 'fixed', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'var(--bg-0)', backgroundImage: 'radial-gradient(ellipse at 30% 20%, rgba(244,185,66,0.06), transparent 60%), radial-gradient(ellipse at 70% 80%, rgba(112,165,255,0.04), transparent 60%)' }}>
      <div style={cardStyle}>{logo}{child}{footer}</div>
    </div>
  );

  // ── Pending approval screen ───────────────────────────────────────────────
  if (pending) return wrap(
    <>
      <div style={{ textAlign: 'center', padding: '12px 0 24px' }}>
        <div style={{ width: 52, height: 52, borderRadius: '50%', background: 'rgba(244,185,66,0.12)', border: '1px solid rgba(244,185,66,0.3)', display: 'flex', alignItems: 'center', justifyContent: 'center', margin: '0 auto 16px', fontSize: 22 }}>⏳</div>
        <div style={{ fontSize: 18, fontWeight: 600, color: 'var(--ink-0)', marginBottom: 8 }}>Request sent!</div>
        <div style={{ fontSize: 12.5, color: 'var(--ink-2)', lineHeight: 1.6 }}>
          Your account is awaiting admin approval.<br/>You'll receive an email at <strong>{email}</strong> once it's approved.
        </div>
      </div>
      <button onClick={() => { setPending(false); switchTab('login'); }} style={{
        width: '100%', height: 36, borderRadius: 6, border: '1px solid var(--line-1)',
        background: 'transparent', color: 'var(--ink-1)', fontFamily: 'inherit', fontSize: 13, cursor: 'pointer',
      }}>Back to sign in</button>
    </>
  );

  // ── Login form ────────────────────────────────────────────────────────────
  if (tab === 'login') return wrap(
    <>
      {tabBar}
      <div className="serif" style={{ fontSize: 28, lineHeight: 1.1, letterSpacing: -0.5, color: 'var(--ink-0)', marginBottom: 6 }}>Welcome back.</div>
      <div style={{ fontSize: 12.5, color: 'var(--ink-2)', marginBottom: 22 }}>Sign in to your studio.</div>
      <form onSubmit={submitLogin}>
        <Field label="Username">
          <input autoFocus type="text" value={user} onChange={e => { setUser(e.target.value); setErr(''); }}
            placeholder="your-username" style={inputS} autoCapitalize="none" autoCorrect="off"/>
        </Field>
        <Field label="Password">
          <input type="password" value={pw} onChange={e => { setPw(e.target.value); setErr(''); }}
            placeholder="••••••••" style={inputS}/>
        </Field>
        {err && (
          <div style={{
            marginBottom: 12, padding: '10px 14px', borderRadius: 7,
            background: errType === 'expired'   ? 'rgba(244,185,66,0.10)' :
                        errType === 'suspended' ? 'rgba(229,72,77,0.10)'  : 'rgba(229,72,77,0.08)',
            border: `1px solid ${errType === 'expired' ? 'rgba(244,185,66,0.35)' : 'rgba(229,72,77,0.3)'}`,
            display: 'flex', alignItems: 'flex-start', gap: 9,
          }}>
            <span style={{ fontSize: 15, marginTop: 1 }}>
              {errType === 'expired' ? '⏳' : errType === 'suspended' ? '🔒' : '⚠️'}
            </span>
            <div>
              <div style={{ fontSize: 12, fontWeight: 600, marginBottom: 2,
                color: errType === 'expired' ? '#f4b942' : '#e5484d' }}>
                {errType === 'expired' ? 'Account Expired' : errType === 'suspended' ? 'Account Suspended' : 'Sign In Failed'}
              </div>
              <div style={{ fontSize: 11.5, color: 'var(--ink-2)', lineHeight: 1.5 }}>{err}</div>
            </div>
          </div>
        )}
        <button type="submit" disabled={loading} style={{
          width: '100%', marginTop: 8, height: 36, borderRadius: 6,
          background: 'var(--accent)', color: '#1a1200', border: 'none',
          fontWeight: 600, fontSize: 13, cursor: loading ? 'wait' : 'pointer', fontFamily: 'inherit',
        }}>{loading ? 'Entering…' : 'Enter studio'}</button>
      </form>
    </>
  );

  // ── Register form ─────────────────────────────────────────────────────────
  return wrap(
    <>
      {tabBar}
      <div className="serif" style={{ fontSize: 28, lineHeight: 1.1, letterSpacing: -0.5, color: 'var(--ink-0)', marginBottom: 6 }}>Join the studio.</div>
      <div style={{ fontSize: 12.5, color: 'var(--ink-2)', marginBottom: 22 }}>Your request will be reviewed by the admin.</div>
      <form onSubmit={submitRegister}>
        <Field label="Display Name">
          <input autoFocus type="text" value={name} onChange={e => { setName(e.target.value); setErr(''); }}
            placeholder="Your full name" style={inputS}/>
        </Field>
        <Field label="Email">
          <input type="email" value={email} onChange={e => { setEmail(e.target.value); setErr(''); }}
            placeholder="you@example.com" style={inputS} autoCapitalize="none" autoCorrect="off"/>
        </Field>
        <Field label="Username">
          <input type="text" value={user} onChange={e => { setUser(e.target.value.toLowerCase().replace(/[^a-z0-9_-]/g,'')); setErr(''); }}
            placeholder="choose-a-username" style={inputS} autoCapitalize="none" autoCorrect="off"/>
        </Field>
        <Field label="Password">
          <input type="password" value={pw} onChange={e => { setPw(e.target.value); setErr(''); }}
            placeholder="••••••••" style={inputS}/>
        </Field>
        <Field label="Confirm Password">
          <input type="password" value={pw2} onChange={e => { setPw2(e.target.value); setErr(''); }}
            placeholder="••••••••" style={inputS}/>
        </Field>
        {err && <div style={{ fontSize: 11, color: 'var(--reject)', marginBottom: 10 }}>{err}</div>}
        <button type="submit" disabled={loading} style={{
          width: '100%', marginTop: 8, height: 36, borderRadius: 6,
          background: 'var(--accent)', color: '#1a1200', border: 'none',
          fontWeight: 600, fontSize: 13, cursor: loading ? 'wait' : 'pointer', fontFamily: 'inherit',
        }}>{loading ? 'Sending request…' : 'Request access'}</button>
      </form>
    </>
  );
}

// ── Welcome / onboarding modal ────────────────────────────────────────────────
function WelcomeModal({ displayName, onClose }) {
  const steps = [
    { icon: '📷', title: 'Upload via FTP', desc: 'Connect your camera using the FTP config from Settings → FTP Config.' },
    { icon: '⭐', title: 'Rate & cull', desc: 'Use 1–5 keys to rate, P to pick, X to reject. Arrow keys navigate.' },
    { icon: '🖼️', title: 'Set your profile photo', desc: 'Click your initials in the sidebar footer to upload a profile photo.' },
    { icon: '🔗', title: 'Share with clients', desc: 'Use the Share button to generate a client gallery link.' },
    { icon: '💧', title: 'Add a watermark', desc: 'Go to Watermark in the sidebar to protect your proofs.' },
  ];
  return (
    <div style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.7)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 9000 }}>
      <div style={{ width: 460, background: 'var(--bg-1)', border: '1px solid var(--line-2)', borderRadius: 14, padding: '36px 36px 28px', boxShadow: '0 24px 80px rgba(0,0,0,0.5)' }}>
        <div style={{ marginBottom: 24 }}>
          <div style={{ fontSize: 22, fontWeight: 700, color: 'var(--ink-0)', marginBottom: 6 }}>
            Welcome, {displayName}! 👋
          </div>
          <div style={{ fontSize: 13, color: 'var(--ink-2)' }}>Here's how to get started with your studio.</div>
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 14, marginBottom: 28 }}>
          {steps.map((s, i) => (
            <div key={i} style={{ display: 'flex', gap: 14, alignItems: 'flex-start' }}>
              <div style={{ width: 36, height: 36, borderRadius: 8, background: 'var(--bg-2)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 18, flexShrink: 0 }}>{s.icon}</div>
              <div>
                <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--ink-0)', marginBottom: 2 }}>{s.title}</div>
                <div style={{ fontSize: 12, color: 'var(--ink-3)', lineHeight: 1.5 }}>{s.desc}</div>
              </div>
            </div>
          ))}
        </div>
        <button onClick={onClose} style={{
          width: '100%', height: 36, borderRadius: 6,
          background: 'var(--accent)', color: '#1a1200', border: 'none',
          fontWeight: 600, fontSize: 13, cursor: 'pointer', fontFamily: 'inherit',
        }}>Start shooting 🚀</button>
      </div>
    </div>
  );
}

// ── Profile photo modal ───────────────────────────────────────────────────────
function ProfilePhotoModal({ onClose, onSaved }) {
  const [preview, setPreview] = React.useState(null);
  const [file, setFile]       = React.useState(null);
  const [saving, setSaving]   = React.useState(false);
  const [err, setErr]         = React.useState('');

  const pick = (e) => {
    const f = e.target.files[0];
    if (!f) return;
    if (!f.type.startsWith('image/')) { setErr('Please select an image file.'); return; }
    setFile(f);
    setErr('');
    const reader = new FileReader();
    reader.onload = ev => setPreview(ev.target.result);
    reader.readAsDataURL(f);
  };

  const save = async () => {
    if (!file) return;
    setSaving(true);
    const fd = new FormData();
    fd.append('photo', file);
    try {
      const r = await fetch('/api/profile/photo', { method: 'POST', body: fd });
      if (r.ok) { onSaved && onSaved(); onClose(); }
      else { const d = await r.json().catch(() => ({})); setErr(d.detail || 'Upload failed.'); }
    } catch { setErr('Network error.'); }
    setSaving(false);
  };

  return (
    <div style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.7)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 9000 }}>
      <div style={{ width: 360, background: 'var(--bg-1)', border: '1px solid var(--line-2)', borderRadius: 12, padding: '28px 28px 22px', boxShadow: '0 24px 80px rgba(0,0,0,0.5)' }}>
        <div style={{ fontSize: 15, fontWeight: 600, color: 'var(--ink-0)', marginBottom: 20 }}>Profile Photo</div>
        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 16, marginBottom: 20 }}>
          <div style={{ width: 100, height: 100, borderRadius: '50%', background: 'var(--bg-2)', border: '2px solid var(--line-1)', overflow: 'hidden', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            {preview
              ? <img src={preview} style={{ width: '100%', height: '100%', objectFit: 'cover' }}/>
              : <span style={{ fontSize: 32, color: 'var(--ink-3)' }}>📷</span>}
          </div>
          <label style={{ cursor: 'pointer', background: 'var(--bg-2)', border: '1px solid var(--line-1)', borderRadius: 6, padding: '7px 16px', fontSize: 12, color: 'var(--ink-1)' }}>
            Choose photo
            <input type="file" accept="image/*" onChange={pick} style={{ display: 'none' }}/>
          </label>
        </div>
        {err && <div style={{ fontSize: 11, color: 'var(--reject)', marginBottom: 12, textAlign: 'center' }}>{err}</div>}
        <div style={{ display: 'flex', gap: 10, justifyContent: 'flex-end' }}>
          <button onClick={onClose} style={{ height: 32, padding: '0 14px', borderRadius: 6, border: '1px solid var(--line-1)', background: 'transparent', color: 'var(--ink-2)', fontSize: 12, cursor: 'pointer', fontFamily: 'inherit' }}>Cancel</button>
          <button onClick={save} disabled={!file || saving} style={{ height: 32, padding: '0 14px', borderRadius: 6, border: 'none', background: 'var(--accent)', color: '#1a1200', fontSize: 12, fontWeight: 600, cursor: file && !saving ? 'pointer' : 'not-allowed', opacity: file && !saving ? 1 : 0.5, fontFamily: 'inherit' }}>
            {saving ? 'Saving…' : 'Save'}
          </button>
        </div>
      </div>
    </div>
  );
}

// ── Share link row with inline client review ──────────────────────────────────
function ShareLinkRow({ share: s, onRevoke, copyUrl, onQR }) {
  const [open, setOpen]         = React.useState(false);
  const [review, setReview]     = React.useState(null);  // {approvals, liked}
  const [loading, setLoading]   = React.useState(false);

  const loadReview = async () => {
    if (review) { setOpen(o => !o); return; }
    setLoading(true);
    try {
      const r = await fetch(`/api/share/${s.token}/approvals`);
      if (r.ok) setReview(await r.json());
    } catch {}
    setLoading(false);
    setOpen(true);
  };

  const approvals    = review ? review.approvals || {} : {};
  const liked        = review ? review.liked || []   : [];
  const approved     = Object.entries(approvals).filter(([,v]) => v.status === 'approved');
  const changes      = Object.entries(approvals).filter(([,v]) => v.status === 'changes');
  const totalReviewed = approved.length + changes.length;

  // Summary pill colour
  const hasFeedback = totalReviewed > 0 || liked.length > 0;

  return (
    <div style={{ borderBottom: '1px solid var(--line-1)' }}>
      {/* Main row */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '10px 0' }}>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 12.5, color: 'var(--ink-0)', fontWeight: 500 }}>{s.label}</div>
          <div className="mono" style={{ fontSize: 10.5, color: 'var(--ink-3)', marginTop: 2 }}>
            /share/{s.token} · {s.filter}
          </div>
        </div>
        {/* Quick review summary */}
        {hasFeedback && review && (
          <div style={{ display: 'flex', gap: 5 }}>
            {liked.length > 0 && (
              <span style={{ fontSize: 10, padding: '2px 7px', borderRadius: 20, background: 'rgba(244,185,66,0.15)', color: 'var(--accent)', fontWeight: 700 }}>
                ★ {liked.length}
              </span>
            )}
            {approved.length > 0 && (
              <span style={{ fontSize: 10, padding: '2px 7px', borderRadius: 20, background: 'rgba(136,221,170,0.15)', color: '#88ddaa', fontWeight: 700 }}>
                ✓ {approved.length}
              </span>
            )}
            {changes.length > 0 && (
              <span style={{ fontSize: 10, padding: '2px 7px', borderRadius: 20, background: 'rgba(244,164,66,0.15)', color: '#f4a442', fontWeight: 700 }}>
                ✗ {changes.length}
              </span>
            )}
          </div>
        )}
        <Pill color={s.expires && s.expires < Date.now() ? 'reject' : 'neutral'}>
          {s.expires ? `expires ${relDate(s.expires)}` : 'no expiry'}
        </Pill>
        <button onClick={loadReview}
          style={{ height: 26, padding: '0 10px', borderRadius: 5, border: '1px solid var(--line-2)', background: open ? 'var(--bg-3)' : 'transparent', color: 'var(--ink-2)', fontSize: 11, cursor: 'pointer', fontFamily: 'inherit', whiteSpace: 'nowrap' }}>
          {loading ? '…' : open ? 'Hide review' : 'Client review'}
        </button>
        <Btn size="sm" icon={<IconCopy size={12}/>} onClick={() => copyUrl(s.token)}/>
        <Btn size="sm" onClick={onQR} title="Show QR code" icon={
          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/>
            <rect x="14" y="14" width="7" height="7"/>
          </svg>
        }/>
        <Btn size="sm" variant="danger" onClick={() => onRevoke(s.token)} icon={<IconTrash size={12}/>}/>
      </div>

      {/* Review panel */}
      {open && review && (
        <div style={{ marginBottom: 14, background: 'var(--bg-0)', borderRadius: 8, border: '1px solid var(--line-1)', overflow: 'hidden' }}>
          {totalReviewed === 0 && liked.length === 0 ? (
            <div style={{ padding: '18px 16px', fontSize: 12, color: 'var(--ink-3)', textAlign: 'center' }}>
              Client hasn't reviewed any photos yet.
            </div>
          ) : (
            <>
              {/* Changes requested */}
              {changes.length > 0 && (
                <div style={{ borderBottom: liked.length > 0 || approved.length > 0 ? '1px solid var(--line-1)' : 'none' }}>
                  <div style={{ padding: '10px 14px 6px', fontSize: 9.5, fontWeight: 700, color: '#f4a442', textTransform: 'uppercase', letterSpacing: 0.12, fontFamily: 'var(--mono)' }}>
                    Changes requested · {changes.length}
                  </div>
                  {changes.map(([fname, data]) => (
                    <div key={fname} style={{ display: 'flex', alignItems: 'flex-start', gap: 10, padding: '8px 14px', borderTop: '1px solid var(--line-1)' }}>
                      <img src={`/thumbs/${s.token.split('').slice(0,0).join('')}` /* placeholder */}
                        onError={e => { e.target.style.display='none'; }}
                        style={{ width: 42, height: 42, objectFit: 'cover', borderRadius: 4, flexShrink: 0, background: 'var(--bg-2)' }}
                        alt=""/>
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div className="mono" style={{ fontSize: 10.5, color: 'var(--ink-1)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{fname}</div>
                        {data.note ? (
                          <div style={{ fontSize: 12, color: 'var(--ink-2)', marginTop: 3, fontStyle: 'italic' }}>"{data.note}"</div>
                        ) : (
                          <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 3 }}>No note left</div>
                        )}
                      </div>
                      <span style={{ fontSize: 10, padding: '2px 7px', borderRadius: 20, background: 'rgba(244,164,66,0.15)', color: '#f4a442', fontWeight: 700, flexShrink: 0 }}>✗ Changes</span>
                    </div>
                  ))}
                </div>
              )}

              {/* Approved */}
              {approved.length > 0 && (
                <div style={{ borderBottom: liked.length > 0 ? '1px solid var(--line-1)' : 'none' }}>
                  <div style={{ padding: '10px 14px 6px', fontSize: 9.5, fontWeight: 700, color: '#88ddaa', textTransform: 'uppercase', letterSpacing: 0.12, fontFamily: 'var(--mono)' }}>
                    Approved · {approved.length}
                  </div>
                  <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, padding: '6px 14px 12px' }}>
                    {approved.map(([fname]) => (
                      <div key={fname} title={fname} style={{ fontSize: 10.5, padding: '3px 9px', borderRadius: 20, background: 'rgba(136,221,170,0.12)', color: '#88ddaa', fontFamily: 'var(--mono)', border: '1px solid rgba(136,221,170,0.2)' }}>
                        ✓ {fname.length > 22 ? fname.slice(0,10)+'…'+fname.slice(-8) : fname}
                      </div>
                    ))}
                  </div>
                </div>
              )}

              {/* Favorites */}
              {liked.length > 0 && (
                <div>
                  <div style={{ padding: '10px 14px 6px', fontSize: 9.5, fontWeight: 700, color: 'var(--accent)', textTransform: 'uppercase', letterSpacing: 0.12, fontFamily: 'var(--mono)' }}>
                    Favorited · {liked.length}
                  </div>
                  <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, padding: '6px 14px 12px' }}>
                    {liked.map(fname => (
                      <div key={fname} title={fname} style={{ fontSize: 10.5, padding: '3px 9px', borderRadius: 20, background: 'rgba(244,185,66,0.12)', color: 'var(--accent)', fontFamily: 'var(--mono)', border: '1px solid rgba(244,185,66,0.2)' }}>
                        ★ {fname.length > 22 ? fname.slice(0,10)+'…'+fname.slice(-8) : fname}
                      </div>
                    ))}
                  </div>
                </div>
              )}
            </>
          )}
        </div>
      )}
    </div>
  );
}

// ── Branding modal ────────────────────────────────────────────────────────────
function BrandingModal({ onClose, onSaved }) {
  const [studioName, setStudioName] = React.useState('');
  const [tagline, setTagline]       = React.useState('');
  const [logoFile, setLogoFile]     = React.useState(null);
  const [logoPreview, setLogoPreview] = React.useState(null);
  const [hasLogo, setHasLogo]       = React.useState(false);
  const [saving, setSaving]         = React.useState(false);
  const [err, setErr]               = React.useState('');

  React.useEffect(() => {
    fetch('/api/branding')
      .then(r => r.ok ? r.json() : null)
      .then(d => {
        if (d) {
          setStudioName(d.studio_name || '');
          setTagline(d.tagline || '');
          setHasLogo(!!d.has_logo);
          if (d.has_logo) setLogoPreview(`/api/branding/logo?t=${Date.now()}`);
        }
      })
      .catch(() => {});
  }, []);

  const pickLogo = (e) => {
    const f = e.target.files[0];
    if (!f) return;
    if (f.size > 2 * 1024 * 1024) { setErr('Logo must be under 2 MB'); return; }
    setLogoFile(f);
    setErr('');
    const reader = new FileReader();
    reader.onload = ev => setLogoPreview(ev.target.result);
    reader.readAsDataURL(f);
  };

  const removeLogo = async () => {
    await fetch('/api/branding/logo', { method: 'DELETE' });
    setLogoFile(null);
    setLogoPreview(null);
    setHasLogo(false);
  };

  const save = async () => {
    setSaving(true); setErr('');
    try {
      // Save text settings
      const r = await fetch('/api/branding', {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ studio_name: studioName, tagline }),
      });
      if (!r.ok) throw new Error('Failed to save branding');
      // Upload logo if new one picked
      if (logoFile) {
        const fd = new FormData();
        fd.append('logo', logoFile);
        const r2 = await fetch('/api/branding/logo', { method: 'POST', body: fd });
        if (!r2.ok) throw new Error('Failed to upload logo');
        setHasLogo(true);
        setLogoFile(null);
      }
      onSaved && onSaved();
      onClose();
    } catch (ex) {
      setErr(ex.message || 'Something went wrong');
    } finally {
      setSaving(false);
    }
  };

  const hdr = { fontSize: 10, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: 0.12, marginBottom: 6 };

  return (
    <Modal onClose={onClose} width={480}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 20 }}>
        <div style={{ fontSize: 15, fontWeight: 700, color: 'var(--ink-0)' }}>Studio Branding</div>
        <button onClick={onClose} style={{ background: 'none', border: 'none', color: 'var(--ink-3)', cursor: 'pointer', display: 'flex' }}><IconX size={16}/></button>
      </div>

      {/* Logo upload */}
      <div style={{ marginBottom: 20 }}>
        <div style={hdr}>Studio Logo</div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
          <div style={{
            width: 160, height: 64, borderRadius: 8, border: '1px solid var(--line-1)',
            background: 'var(--bg-0)', display: 'flex', alignItems: 'center', justifyContent: 'center',
            overflow: 'hidden', flexShrink: 0,
          }}>
            {logoPreview
              ? <img src={logoPreview} style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }} alt="logo"/>
              : <span style={{ fontSize: 11, color: 'var(--ink-3)' }}>No logo</span>}
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
            <label style={{ cursor: 'pointer', background: 'var(--bg-2)', border: '1px solid var(--line-1)', borderRadius: 6, padding: '6px 14px', fontSize: 12, color: 'var(--ink-1)', display: 'inline-block' }}>
              {hasLogo || logoPreview ? 'Replace logo' : 'Upload logo'}
              <input type="file" accept="image/*" onChange={pickLogo} style={{ display: 'none' }}/>
            </label>
            {(hasLogo || logoPreview) && (
              <button onClick={removeLogo} style={{ background: 'none', border: 'none', color: 'var(--reject)', fontSize: 11, cursor: 'pointer', textAlign: 'left', padding: 0 }}>Remove logo</button>
            )}
            <div style={{ fontSize: 10.5, color: 'var(--ink-3)', lineHeight: 1.4 }}>PNG or JPEG, max 2 MB.<br/>Transparent background looks best.</div>
          </div>
        </div>
      </div>

      {/* Studio name */}
      <div style={{ marginBottom: 14 }}>
        <div style={hdr}>Studio Name</div>
        <input
          value={studioName} onChange={e => setStudioName(e.target.value)}
          placeholder="Your Studio Name"
          style={{ ...inputS, width: '100%' }}
          maxLength={80}
        />
        <div style={{ fontSize: 10, color: 'var(--ink-3)', marginTop: 4 }}>Shown in client gallery header when no logo is set</div>
      </div>

      {/* Tagline */}
      <div style={{ marginBottom: 20 }}>
        <div style={hdr}>Tagline</div>
        <input
          value={tagline} onChange={e => setTagline(e.target.value)}
          placeholder="A short line about your studio"
          style={{ ...inputS, width: '100%' }}
          maxLength={120}
        />
      </div>

      {/* Preview */}
      {(logoPreview || studioName || tagline) && (
        <div style={{ marginBottom: 20, padding: '14px 18px', background: 'var(--bg-0)', borderRadius: 8, border: '1px solid var(--line-1)' }}>
          <div style={{ fontSize: 9.5, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: 0.12, marginBottom: 10 }}>Preview on client gallery</div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
            {logoPreview && (
              <img src={logoPreview} style={{ height: 36, maxWidth: 120, objectFit: 'contain' }} alt="logo"/>
            )}
            <div>
              {studioName && <div style={{ fontSize: 16, fontWeight: 700, color: 'var(--ink-0)', letterSpacing: -0.2 }}>{studioName}</div>}
              {tagline    && <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 2 }}>{tagline}</div>}
            </div>
          </div>
        </div>
      )}

      {err && <div style={{ fontSize: 11, color: 'var(--reject)', marginBottom: 12 }}>{err}</div>}
      <div style={{ display: 'flex', gap: 10, justifyContent: 'flex-end' }}>
        <button onClick={onClose} style={{ height: 32, padding: '0 14px', borderRadius: 6, border: '1px solid var(--line-1)', background: 'transparent', color: 'var(--ink-2)', fontSize: 12, cursor: 'pointer', fontFamily: 'inherit' }}>Cancel</button>
        <button onClick={save} disabled={saving} style={{ height: 32, padding: '0 14px', borderRadius: 6, border: 'none', background: 'var(--accent)', color: '#1a1200', fontSize: 12, fontWeight: 600, cursor: saving ? 'not-allowed' : 'pointer', opacity: saving ? 0.6 : 1, fontFamily: 'inherit' }}>
          {saving ? 'Saving…' : 'Save branding'}
        </button>
      </div>
    </Modal>
  );
}

// ── Event Modal ───────────────────────────────────────────────────────────────
function EventModal({ onClose, onCreate }) {
  const today = new Date().toISOString().slice(0, 10);
  const [name, setName]         = React.useState('');
  const [date, setDate]         = React.useState(today);
  const [activate, setActivate] = React.useState(true);
  const [creating, setCreating] = React.useState(false);

  const handle = async () => {
    if (!name.trim()) return;
    setCreating(true);
    await onCreate({ name: name.trim(), date, activate });
    setCreating(false);
  };

  return (
    <Modal onClose={onClose} width={440}>
      <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', marginBottom: 20 }}>
        <div>
          <div className="mono" style={{ fontSize: 9.5, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: 0.14 }}>Studio</div>
          <div className="serif" style={{ fontSize: 28, letterSpacing: -0.5, color: 'var(--ink-0)', marginTop: 2 }}>New event</div>
        </div>
        <Btn size="sm" onClick={onClose} icon={<IconX size={13}/>}/>
      </div>

      <Field label="Event name">
        <input autoFocus value={name}
          onChange={e => setName(e.target.value)}
          onKeyDown={e => { if (e.key === 'Enter') handle(); }}
          placeholder="e.g. Smith Wedding — Ceremony"
          style={inputS}/>
      </Field>

      <Field label="Date">
        <input type="date" value={date} onChange={e => setDate(e.target.value)} style={inputS}/>
      </Field>

      <div style={{ marginTop: 6, padding: '12px 14px', background: 'var(--bg-2)', borderRadius: 8, border: '1px solid var(--line-1)' }}>
        <Toggle checked={activate} onChange={setActivate}
          label="Set as live — new photos from camera go here"/>
        {activate && (
          <div style={{ marginTop: 6, fontSize: 11, color: 'var(--ink-3)', paddingLeft: 38, lineHeight: 1.5 }}>
            Any previous live event will be paused. You can switch events at any time from the sidebar.
          </div>
        )}
      </div>

      <div style={{ display: 'flex', gap: 6, marginTop: 20 }}>
        <Btn variant="accent" size="lg" onClick={handle}
          disabled={creating || !name.trim()} style={{ flex: 1 }}>
          {creating ? 'Creating…' : 'Create event'}
        </Btn>
        <Btn variant="outline" size="lg" onClick={onClose}>Cancel</Btn>
      </div>
    </Modal>
  );
}

// ── QR Code Modal ─────────────────────────────────────────────────────────────
function QRModal({ token, url, label, onClose }) {
  const imgSrc = `/api/share/${token}/qr`;
  const [loaded, setLoaded] = React.useState(false);
  const [err, setErr]       = React.useState(false);

  const handlePrint = () => {
    const win = window.open('', '_blank', 'width=420,height=560');
    if (!win) return;
    win.document.write(`<!DOCTYPE html><html><head><title>QR — ${label}</title>
      <style>
        body{margin:0;display:flex;flex-direction:column;align-items:center;justify-content:center;
             min-height:100vh;font-family:-apple-system,sans-serif;background:#fff;color:#111;}
        img{display:block;width:260px;height:260px;}
        h2{font-size:16px;margin:18px 0 6px;font-weight:600;text-align:center;}
        p{font-size:11px;color:#666;word-break:break-all;max-width:280px;text-align:center;margin:0 0 20px;}
        .btn{padding:9px 22px;border:1px solid #ccc;border-radius:6px;cursor:pointer;font-size:13px;background:#f5f5f5;}
        @media print{.btn{display:none;}}
      </style></head><body>
      <img src="${window.location.origin}${imgSrc}"/>
      <h2>${label}</h2><p>${url}</p>
      <button class="btn" onclick="window.print()">Print</button>
    </body></html>`);
    win.document.close(); win.focus();
  };

  return (
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0, zIndex: 500,
      background: 'rgba(5,5,7,0.75)', backdropFilter: 'blur(8px)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      animation: 'fade-in 160ms',
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        background: 'var(--bg-1)', border: '1px solid var(--line-2)', borderRadius: 14,
        padding: '28px 28px 22px', display: 'flex', flexDirection: 'column', alignItems: 'center',
        boxShadow: '0 32px 80px rgba(0,0,0,0.7)', animation: 'fade-up 180ms ease',
      }}>
        <div style={{ width: '100%', display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 20 }}>
          <div>
            <div className="mono" style={{ fontSize: 9.5, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: 0.14 }}>Share QR Code</div>
            <div className="serif" style={{ fontSize: 22, letterSpacing: -0.4, color: 'var(--ink-0)', marginTop: 2 }}>{label}</div>
          </div>
          <Btn size="sm" onClick={onClose} icon={<IconX size={13}/>}/>
        </div>

        <div style={{ padding: 14, background: '#ffffff', borderRadius: 10, border: '1px solid var(--line-2)', width: 268, height: 268, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          {err ? (
            <div style={{ textAlign: 'center', color: '#888', fontSize: 12 }}>
              <div style={{ fontSize: 24, marginBottom: 8 }}>⚠</div>
              QR generation failed.<br/>Check server logs.
            </div>
          ) : (
            <>
              {!loaded && <div style={{ color: '#ccc', fontSize: 11 }}>Generating…</div>}
              <img src={imgSrc} width={240} height={240}
                style={{ display: loaded ? 'block' : 'none', borderRadius: 4 }}
                onLoad={() => setLoaded(true)}
                onError={() => setErr(true)}
                alt="QR code"/>
            </>
          )}
        </div>

        <div className="mono" style={{ marginTop: 14, fontSize: 10.5, color: 'var(--ink-3)', maxWidth: 270, textAlign: 'center', wordBreak: 'break-all', lineHeight: 1.55 }}>{url}</div>

        <div style={{ display: 'flex', gap: 8, marginTop: 18 }}>
          <Btn variant="accent" size="lg" onClick={handlePrint} disabled={!loaded} icon={
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
              <polyline points="6 9 6 2 18 2 18 9"/><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"/>
              <rect x="6" y="14" width="12" height="8"/>
            </svg>
          }>Print / Save</Btn>
          <Btn variant="outline" size="lg" onClick={() => navigator.clipboard.writeText(url).catch(()=>{})}>Copy URL</Btn>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { Modal, ShareModal, WatermarkModal, NewCollectionModal, LoginScreen, WelcomeModal, ProfilePhotoModal, BrandingModal, Toggle, Field, inputS, QRModal, EventModal });
