const { useState, useEffect, useCallback } = React;

const REPORT_ID = () => window.FINR_AUTH?.SITE_REPORT_ID || 'lekha';

// GATED_SCRIPTS (runtime/registry.js) lists what to fetch and in what order;
// finrLoadGatedAssets (runtime/load-gated.js) fetches + evaluates each one,
// isolating every file's top-level const/let in its own function scope so
// tab-*.jsx files that each redeclare `const { useState } = React` (and, in
// several, a private `const TickerLink`) don't collide as sibling scripts.
// Both are PUBLIC (asset-gate.js) and load before this file.

function finrClearLocalAccess() {
  localStorage.removeItem('micrositeAccess');
  for (const name of ['lekha_session', 'lekha_access', 'lekha_google_id']) {
    document.cookie = `${name}=; Path=/; Max-Age=0; SameSite=Lax`;
  }
}

function useFinrAccess() {
  const [accessInfo, setAccessInfo] = useState({ valid: false, expiresAt: null, email: null, checked: false, denied: false });

  useEffect(() => {
    if (typeof window === 'undefined') return;
    if (window.FINR_AUTH?.isLocalDev?.()) {
      setAccessInfo({ valid: true, expiresAt: null, email: 'local-dev', checked: true, denied: false });
      return;
    }

    let cancelled = false;
    const reportId = REPORT_ID();

    const grant = (email, denied = false) => {
      if (cancelled) return;
      setAccessInfo({
        valid: !denied,
        expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000,
        email,
        checked: true,
        denied,
      });
    };

    // Portal tokens are cookie-only (server never honors ?token=) and are
    // never persisted client-side; a valid lekha_access cookie is verified
    // server-side on every gated request.
    const checkSession = async () => {
      try {
        const res = await fetch('/api/auth/me', { credentials: 'same-origin' });
        if (!res.ok) {
          if (!cancelled) setAccessInfo((prev) => ({ ...prev, checked: true }));
          return;
        }
        const data = await res.json();
        const user = data.user;
        if (user && window.FINR_AUTH.userHasSiteAccess(user, reportId)) {
          grant(user.email);
          return;
        }
        if (user) {
          grant(user.email, true);
          return;
        }
      } catch {
        // static preview / no worker
      }
      if (!cancelled) setAccessInfo((prev) => ({ ...prev, checked: true }));
    };

    checkSession();
    return () => { cancelled = true; };
  }, []);

  const refreshSession = useCallback(async () => {
    const reportId = REPORT_ID();
    try {
      const res = await fetch('/api/auth/me', { credentials: 'same-origin' });
      if (!res.ok) return;
      const data = await res.json();
      const user = data.user;
      if (user && window.FINR_AUTH.userHasSiteAccess(user, reportId)) {
        setAccessInfo({ valid: true, expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000, email: user.email, checked: true, denied: false });
      } else if (user) {
        setAccessInfo({ valid: false, expiresAt: null, email: user.email, checked: true, denied: true });
      }
    } catch {}
  }, []);

  // A 401 on a gated asset mid-session (expired/forged token, revoked
  // access) must fall back to the login screen, not a blank/dead page.
  const forceLogout = useCallback(() => {
    finrClearLocalAccess();
    setAccessInfo({ valid: false, expiresAt: null, email: null, checked: true, denied: false });
  }, []);

  return { accessInfo, refreshSession, forceLogout };
}

async function finrSignOut() {
  try {
    await fetch('/api/auth/logout', { method: 'POST', credentials: 'include' });
  } catch {}
  finrClearLocalAccess();
  if (window.google?.accounts?.id) {
    try { window.google.accounts.id.disableAutoSelect(); } catch {}
  }
  window.location.reload();
}

function FinrAccessGate({ onAccessGranted }) {
  const [config, setConfig] = useState({ googleClientId: '', ready: false });
  const [tab, setTab] = useState('google');
  const [emailMode, setEmailMode] = useState('login');
  const [emailStep, setEmailStep] = useState('email');
  const [email, setEmail] = useState('');
  const [name, setName] = useState('');
  const [code, setCode] = useState('');
  const [error, setError] = useState(null);
  const [status, setStatus] = useState(null);
  const [busy, setBusy] = useState(false);
  const [scriptReady, setScriptReady] = useState(false);

  const isLocal = window.FINR_AUTH?.isLocalDev?.();

  useEffect(() => {
    fetch('/api/config', { credentials: 'same-origin' })
      .then((r) => (r.ok ? r.json() : null))
      .then((d) => {
        if (d) setConfig({ googleClientId: d.googleClientId || '', ready: true });
        else setConfig((c) => ({ ...c, ready: true }));
      })
      .catch(() => setConfig((c) => ({ ...c, ready: true })));
  }, []);

  useEffect(() => {
    if (isLocal || !config.googleClientId) return;
    if (window.google) { setScriptReady(true); return; }
    const script = document.createElement('script');
    script.src = 'https://accounts.google.com/gsi/client';
    script.async = true;
    script.defer = true;
    script.onload = () => setScriptReady(true);
    document.head.appendChild(script);
  }, [isLocal, config.googleClientId]);

  const handleGoogleCredential = useCallback(async (credential) => {
    setBusy(true);
    setError(null);
    try {
      const res = await fetch('/api/auth/google', {
        method: 'POST',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ credential }),
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.error || 'Google sign-in failed');
      const reportId = REPORT_ID();
      if (!window.FINR_AUTH.userHasSiteAccess(data.user, reportId)) {
        setError(`Signed in as ${data.user.email}, but you do not have access yet.`);
        return;
      }
      onAccessGranted({ email: data.user.email });
    } catch (e) {
      setError(e.message || 'Google sign-in failed');
    } finally {
      setBusy(false);
    }
  }, [onAccessGranted]);

  useEffect(() => {
    if (isLocal || !scriptReady || !config.googleClientId) return;
    if (window.__gsiFinrInitialized) return;
    window.__gsiFinrInitialized = true;
    try {
      window.google.accounts.id.initialize({
        client_id: config.googleClientId,
        callback: (response) => handleGoogleCredential(response.credential),
      });
      const el = document.getElementById('finr-google-btn');
      if (el) window.google.accounts.id.renderButton(el, { theme: 'outline', size: 'large', text: 'signin_with' });
    } catch {
      setError('Google Sign-In failed to initialize.');
    }
  }, [isLocal, scriptReady, config.googleClientId, handleGoogleCredential]);

  const sendOtp = async (e) => {
    e.preventDefault();
    setBusy(true);
    setError(null);
    setStatus(null);
    try {
      const res = await fetch('/api/auth/otp/send', {
        method: 'POST',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email: email.trim(), purpose: emailMode }),
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.error || 'Failed to send code');
      setEmailStep('otp');
      setStatus(data.message || 'Verification code sent to your email.');
    } catch (err) {
      setError(err.message || 'Failed to send code');
    } finally {
      setBusy(false);
    }
  };

  const verifyOtp = async (e) => {
    e.preventDefault();
    setBusy(true);
    setError(null);
    try {
      const res = await fetch('/api/auth/otp/verify', {
        method: 'POST',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          email: email.trim(),
          code: code.trim(),
          purpose: emailMode,
          name: emailMode === 'register' ? name.trim() : undefined,
        }),
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.error || 'Invalid code');
      const reportId = REPORT_ID();
      if (!window.FINR_AUTH.userHasSiteAccess(data.user, reportId)) {
        setError(`Signed in as ${data.user.email}, but you do not have access yet.`);
        return;
      }
      onAccessGranted({ email: data.user.email });
    } catch (err) {
      setError(err.message || 'Invalid code');
    } finally {
      setBusy(false);
    }
  };

  const gateStyle = {
    minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center',
    padding: 24, background: 'var(--bg)', color: 'var(--text)',
  };
  const cardStyle = {
    maxWidth: 480, width: '100%', background: 'var(--surface)', border: '1px solid var(--border)',
    borderRadius: 'var(--r-card)', padding: 32, boxShadow: 'var(--shadow-card)',
  };

  return (
    <div style={gateStyle}>
      <div style={cardStyle}>
        <p style={{ fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'var(--text-dim)', marginBottom: 8 }}>
          lekha.shiv.io — restricted access
        </p>
        <h1 style={{ fontFamily: 'var(--font-display)', fontSize: 24, fontWeight: 700, color: 'var(--primary)', marginBottom: 8 }}>
          Lekha
        </h1>
        <p style={{ fontFamily: 'var(--font-body)', fontSize: 14, color: 'var(--text-muted)', lineHeight: 1.6, marginBottom: 24 }}>
          Institutional AI / semiconductor supply-chain research dashboard. Sign in with an approved account, or use the magic link from your invite email.
        </p>

        <div style={{ display: 'flex', border: '1px solid var(--border)', borderRadius: 'var(--r-sm)', overflow: 'hidden', marginBottom: 20 }}>
          {['google', 'email'].map((t) => (
            <button key={t} type="button" onClick={() => setTab(t)}
              style={{
                flex: 1, padding: '10px 0', border: 'none', cursor: 'pointer',
                fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '0.12em', textTransform: 'uppercase',
                background: tab === t ? 'var(--kahalgaon-blue)' : 'var(--bg)',
                color: tab === t ? '#fff' : 'var(--text-muted)',
              }}>
              {t === 'google' ? 'Google' : 'Email OTP'}
            </button>
          ))}
        </div>

        {tab === 'google' && !isLocal && (
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 12, marginBottom: 16 }}>
            {!config.ready ? (
              <p style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--text-dim)' }}>Loading sign-in…</p>
            ) : (
              <>
                <div id="finr-google-btn" />
                {busy && <p style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--text-dim)' }}>Signing in…</p>}
              </>
            )}
          </div>
        )}

        {tab === 'google' && isLocal && (
          <p style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--text-dim)', marginBottom: 16 }}>
            Local dev: auth gate is bypassed automatically.
          </p>
        )}

        {tab === 'email' && (
          <div style={{ marginBottom: 16 }}>
            <div style={{ display: 'flex', gap: 8, marginBottom: 16 }}>
              {['login', 'register'].map((m) => (
                <button key={m} type="button"
                  onClick={() => { setEmailMode(m); setEmailStep('email'); setCode(''); setError(null); setStatus(null); }}
                  style={{
                    flex: 1, padding: '8px 0', border: '1px solid var(--border-mid)', borderRadius: 'var(--r-pill)',
                    background: emailMode === m ? 'var(--surface-alt)' : 'transparent', cursor: 'pointer',
                    fontFamily: 'var(--font-mono)', fontSize: 10, textTransform: 'uppercase', color: 'var(--text-muted)',
                  }}>
                  {m}
                </button>
              ))}
            </div>
            {emailStep === 'email' ? (
              <form onSubmit={sendOtp}>
                {emailMode === 'register' && (
                  <input type="text" placeholder="Your name" value={name} onChange={(e) => setName(e.target.value)}
                    style={{ width: '100%', marginBottom: 10, padding: '10px 12px', border: '1px solid var(--border)', borderRadius: 'var(--r-sm)', fontFamily: 'var(--font-body)', fontSize: 14 }} />
                )}
                <input type="email" required placeholder="Email address" value={email} onChange={(e) => setEmail(e.target.value)}
                  style={{ width: '100%', marginBottom: 12, padding: '10px 12px', border: '1px solid var(--border)', borderRadius: 'var(--r-sm)', fontFamily: 'var(--font-body)', fontSize: 14 }} />
                <button type="submit" disabled={busy}
                  style={{ width: '100%', padding: '10px 0', border: 'none', borderRadius: 'var(--r-sm)', cursor: 'pointer',
                    background: 'var(--kahalgaon-blue)', color: '#fff', fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '0.1em', textTransform: 'uppercase' }}>
                  {busy ? 'Sending…' : 'Send code'}
                </button>
              </form>
            ) : (
              <form onSubmit={verifyOtp}>
                <input type="text" inputMode="numeric" required placeholder="6-digit code" value={code} onChange={(e) => setCode(e.target.value)}
                  style={{ width: '100%', marginBottom: 12, padding: '10px 12px', border: '1px solid var(--border)', borderRadius: 'var(--r-sm)', fontFamily: 'var(--font-mono)', fontSize: 18, letterSpacing: '0.3em', textAlign: 'center' }} />
                <button type="submit" disabled={busy}
                  style={{ width: '100%', padding: '10px 0', border: 'none', borderRadius: 'var(--r-sm)', cursor: 'pointer',
                    background: 'var(--kahalgaon-blue)', color: '#fff', fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '0.1em', textTransform: 'uppercase' }}>
                  {busy ? 'Verifying…' : 'Verify & sign in'}
                </button>
                <button type="button" onClick={() => { setEmailStep('email'); setCode(''); }}
                  style={{ width: '100%', marginTop: 8, padding: '8px 0', border: 'none', background: 'transparent', cursor: 'pointer',
                    fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--text-dim)' }}>
                  Use a different email
                </button>
              </form>
            )}
          </div>
        )}

        {status && <p style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--paddy-green)', marginBottom: 12 }}>{status}</p>}
        {error && <p style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--mithila-vermillion)', background: 'rgba(192,57,43,0.08)', border: '1px solid rgba(192,57,43,0.2)', borderRadius: 'var(--r-sm)', padding: 12, marginBottom: 12 }}>{error}</p>}
      </div>
    </div>
  );
}

function FinrStatusScreen({ children }) {
  return (
    <div style={{
      minHeight: '100vh', display: 'flex', flexDirection: 'column', alignItems: 'center',
      justifyContent: 'center', gap: 12, padding: 24, background: 'var(--bg)', color: 'var(--text)',
      fontFamily: 'var(--font-mono)', fontSize: 13, textAlign: 'center',
    }}>
      {children}
    </div>
  );
}

// Phase 2 overrides: merge accepted refresh sections over the static
// REPORT/INDIA_REPORT before any tab renders. Static file stays the base;
// D1 overrides win per (market, section). Called only after the gated data
// scripts have evaluated (global REPORT bindings exist).
async function finrApplyResearchOverrides() {
  try {
    const res = await fetch('/api/refresh/overrides', { credentials: 'same-origin' });
    if (!res.ok) return;
    const data = await res.json();
    for (const o of data.overrides || []) {
      let content;
      try { content = JSON.parse(o.content_json); } catch { continue; }
      const R = o.market === 'india'
        ? (typeof INDIA_REPORT !== 'undefined' ? INDIA_REPORT : null)
        : (typeof REPORT !== 'undefined' ? REPORT : null);
      if (!R) continue;
      switch (o.section) {
        case 'rotation':
          if (o.market === 'india') R.rotationPlaybook = content;
          else {
            if (content && content.macroRotation) R.macroRotation = content.macroRotation;
            if (content && content.capitalRecycling) R.capitalRecycling = content.capitalRecycling;
            if (content && content.sectorSequence) R.sectorSequence = content.sectorSequence;
          }
          break;
        case 'macro':
          if (o.market === 'india') {
            if (content && content.macroContext) R.macroContext = content.macroContext;
            if (content && content.criticalGaps) R.criticalGaps = content.criticalGaps;
          } else {
            if (content && content.metadata) R.metadata = content.metadata;
            if (content && content.tldr) R.tldr = content.tldr;
          }
          break;
        case 'presets':
          if (o.market === 'india') window.INDIA_PRESETS = content;
          else window.PRESET_QUERIES = content;
          break;
        default:
          if (o.section in R) R[o.section] = content;
      }
    }
  } catch {
    // overrides are an enhancement; static base always renders
  }
}

function FinrAuthShell({ children }) {
  const { accessInfo, refreshSession, forceLogout } = useFinrAccess();
  const [assetsReady, setAssetsReady] = useState(false);
  const [assetsError, setAssetsError] = useState(null);
  const [progress, setProgress] = useState({ loaded: 0, total: window.GATED_SCRIPTS.length });
  const [retryKey, setRetryKey] = useState(0);

  useEffect(() => {
    if (!accessInfo.valid) return;
    let cancelled = false;
    const onProgress = (loaded, total) => { if (!cancelled) setProgress({ loaded, total }); };
    window.finrLoadGatedAssets(window.GATED_SCRIPTS, { onProgress })
      .then(() => finrApplyResearchOverrides())
      .then(() => { if (!cancelled) setAssetsReady(true); })
      .catch((err) => {
        if (cancelled) return;
        if (err?.status === 401) {
          forceLogout();
          return;
        }
        setAssetsError(err);
      });
    return () => { cancelled = true; };
  }, [accessInfo.valid, retryKey, forceLogout]);

  if (!accessInfo.checked) {
    return <FinrStatusScreen>Checking access…</FinrStatusScreen>;
  }

  if (accessInfo.denied || !accessInfo.valid) {
    return (
      <FinrAccessGate onAccessGranted={() => refreshSession()} />
    );
  }

  if (assetsError) {
    return (
      <FinrStatusScreen>
        <p style={{ color: 'var(--mithila-vermillion)', maxWidth: 420 }}>
          Failed to load {assetsError.src || 'report data'}: {assetsError.message || 'unknown error'}
        </p>
        <div style={{ display: 'flex', gap: 12 }}>
          <button type="button"
            onClick={() => { setAssetsError(null); window.finrResetGatedAssets(); setProgress({ loaded: 0, total: window.GATED_SCRIPTS.length }); setRetryKey((k) => k + 1); }}
            style={{ padding: '8px 16px', border: '1px solid var(--border-mid)', borderRadius: 'var(--r-pill)', background: 'var(--kahalgaon-blue)', color: '#fff', cursor: 'pointer', fontFamily: 'var(--font-mono)', fontSize: 11, textTransform: 'uppercase' }}>
            Retry
          </button>
          <button type="button" onClick={finrSignOut}
            style={{ padding: '8px 16px', border: '1px solid var(--border-mid)', borderRadius: 'var(--r-pill)', background: 'transparent', color: 'var(--text-muted)', cursor: 'pointer', fontFamily: 'var(--font-mono)', fontSize: 11, textTransform: 'uppercase' }}>
            Sign out
          </button>
        </div>
      </FinrStatusScreen>
    );
  }

  if (!assetsReady) {
    return <FinrStatusScreen>Loading Lekha… {progress.loaded}/{progress.total}</FinrStatusScreen>;
  }

  return children;
}

function useFinrSession() {
  const [session, setSession] = useState({ user: null, checked: false });

  useEffect(() => {
    if (window.FINR_AUTH?.isLocalDev?.()) {
      setSession({ user: { email: 'local-dev', isAdmin: true }, checked: true });
      return;
    }
    fetch('/api/auth/me', { credentials: 'same-origin' })
      .then((r) => (r.ok ? r.json() : { user: null }))
      .then((d) => setSession({ user: d.user || null, checked: true }))
      .catch(() => setSession({ user: null, checked: true }));
  }, []);

  return session;
}

function SessionIdentity() {
  const { user } = useFinrSession();

  if (window.FINR_AUTH?.isLocalDev?.()) return null;
  const email = user?.email;
  if (!email) return null;

  const initial = email.trim().charAt(0).toUpperCase();
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 8 }} title={`Signed in as ${email}`}>
      <div style={{ width: 28, height: 28, borderRadius: '50%', background: 'var(--kahalgaon-blue)', color: '#fff',
        display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'var(--font-mono)', fontSize: 12, fontWeight: 700 }}>{initial}</div>
      <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--text-muted)', maxWidth: 140, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{email}</span>
      <button type="button" onClick={finrSignOut} title="Sign out"
        style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--text-dim)', background: 'transparent',
          border: '1px solid var(--border-mid)', borderRadius: 'var(--r-pill)', padding: '3px 9px', cursor: 'pointer' }}>
        Sign out
      </button>
    </div>
  );
}

function TabAdmin() {
  const [users, setUsers] = useState([]);
  const [email, setEmail] = useState('');
  const [name, setName] = useState('');
  const [busy, setBusy] = useState(false);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [status, setStatus] = useState(null);

  const load = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const res = await fetch('/api/admin/users', { credentials: 'same-origin' });
      if (!res.ok) throw new Error('Failed to load users');
      const data = await res.json();
      setUsers(data.users || []);
    } catch (e) {
      setError(e.message || 'Failed to load users');
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    if (window.FINR_AUTH?.isLocalDev?.()) {
      setUsers([]);
      setLoading(false);
      return;
    }
    load();
  }, [load]);

  const grant = async (e) => {
    e.preventDefault();
    setBusy(true);
    setError(null);
    setStatus(null);
    try {
      const res = await fetch('/api/admin/users', {
        method: 'POST',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email: email.trim(), name: name.trim() || undefined }),
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.error || 'Grant failed');
      setStatus(data.inviteEmailSent ? `Access granted; invite sent to ${email.trim()}.` : `Access granted for ${email.trim()}.`);
      setEmail('');
      setName('');
      await load();
    } catch (err) {
      setError(err.message || 'Grant failed');
    } finally {
      setBusy(false);
    }
  };

  const revoke = async (userId, userEmail) => {
    if (!confirm(`Revoke access for ${userEmail}?`)) return;
    setBusy(true);
    setError(null);
    try {
      const res = await fetch(`/api/admin/users/${userId}`, { method: 'DELETE', credentials: 'include' });
      if (!res.ok) throw new Error('Revoke failed');
      await load();
    } catch (err) {
      setError(err.message || 'Revoke failed');
    } finally {
      setBusy(false);
    }
  };

  const grantedCount = users.filter((u) => u.hasAccess).length;

  return (
    <div className="tab-content" style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: 16 }}>
        <div className="stat-box">
          <div className="label">Total users</div>
          <div className="value" style={{ fontSize: 28, marginTop: 4 }}>{users.length}</div>
        </div>
        <div className="stat-box">
          <div className="label">With access</div>
          <div className="value" style={{ fontSize: 28, marginTop: 4, color: 'var(--paddy-green)' }}>{grantedCount}</div>
        </div>
        <div className="stat-box">
          <div className="label">Pending</div>
          <div className="value" style={{ fontSize: 28, marginTop: 4, color: 'var(--text-muted)' }}>{users.length - grantedCount}</div>
        </div>
      </div>

      <div className="card" style={{ padding: 24 }}>
        <div className="section-title" style={{ marginBottom: 8 }}>Grant access</div>
        <p style={{ fontFamily: 'var(--font-body)', fontSize: 13, color: 'var(--text-muted)', marginBottom: 16 }}>
          Add a user by email. An invite is sent automatically when Resend is configured.
        </p>
        <form onSubmit={grant} style={{ display: 'flex', flexWrap: 'wrap', gap: 10, marginBottom: 12 }}>
          <input type="email" required placeholder="user@firm.com" value={email} onChange={(e) => setEmail(e.target.value)}
            style={{ flex: '1 1 220px', padding: '10px 12px', border: '1px solid var(--border)', borderRadius: 'var(--r-sm)', fontSize: 14 }} />
          <input type="text" placeholder="Name (optional)" value={name} onChange={(e) => setName(e.target.value)}
            style={{ flex: '1 1 160px', padding: '10px 12px', border: '1px solid var(--border)', borderRadius: 'var(--r-sm)', fontSize: 14 }} />
          <button type="submit" disabled={busy}
            style={{ padding: '10px 20px', cursor: 'pointer', border: 'none', borderRadius: 'var(--r-sm)', background: 'var(--kahalgaon-blue)', color: '#fff', fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '0.08em', textTransform: 'uppercase' }}>
            {busy ? 'Working…' : 'Grant access'}
          </button>
        </form>
        {status && <p style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--paddy-green)', marginBottom: 8 }}>{status}</p>}
        {error && <p style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--mithila-vermillion)', marginBottom: 8 }}>{error}</p>}
      </div>

      <div className="card" style={{ padding: 0, overflow: 'hidden' }}>
        <div style={{ padding: '16px 20px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <div className="section-title" style={{ margin: 0 }}>Users</div>
          <button type="button" onClick={load} disabled={busy || loading}
            style={{ fontFamily: 'var(--font-mono)', fontSize: 10, border: '1px solid var(--border-mid)', background: 'var(--bg)', padding: '6px 12px', borderRadius: 'var(--r-pill)', cursor: 'pointer' }}>
            Refresh
          </button>
        </div>
        {loading ? (
          <p style={{ padding: 24, fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--text-dim)' }}>Loading users…</p>
        ) : (
          <table className="data-table">
            <thead><tr><th>Email</th><th>Name</th><th>Verified</th><th>Access</th><th></th></tr></thead>
            <tbody>
              {users.length === 0 ? (
                <tr><td colSpan={5} style={{ textAlign: 'center', color: 'var(--text-dim)', padding: 24 }}>No users yet</td></tr>
              ) : users.map((u) => (
                <tr key={u.id}>
                  <td style={{ fontFamily: 'var(--font-mono)', fontSize: 12 }}>{u.email}</td>
                  <td>{u.name || '—'}</td>
                  <td>{u.emailVerified ? <span className="badge badge-high">yes</span> : <span className="badge badge-low">no</span>}</td>
                  <td>{u.hasAccess ? <span className="badge badge-high">granted</span> : <span className="badge badge-low">none</span>}</td>
                  <td>
                    {u.hasAccess && !u.isAdmin && (
                      <button type="button" disabled={busy} onClick={() => revoke(u.id, u.email)}
                        style={{ fontFamily: 'var(--font-mono)', fontSize: 10, border: '1px solid var(--border-mid)', background: 'transparent', padding: '4px 10px', borderRadius: 'var(--r-pill)', cursor: 'pointer', color: 'var(--mithila-vermillion)' }}>
                        Revoke
                      </button>
                    )}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </div>
    </div>
  );
}

Object.assign(window, { useFinrAccess, useFinrSession, FinrAccessGate, FinrAuthShell, SessionIdentity, TabAdmin, finrSignOut });