// app.jsx — Root app: auth pages, routing, global state
const { useState, useEffect, useCallback, useRef } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "accentColor": "#06B6D4" }/*EDITMODE-END*/;

const CLERK_PLAN_KEY = 'rosteath';

const CLERK_APPEARANCE = {
  variables: {
    colorPrimary: '#06B6D4',
    colorBackground: '#000000',
    colorText: '#F1F2F7',
    colorTextSecondary: '#5C5E72',
    colorInputBackground: '#111111',
    colorInputText: '#F1F2F7',
    colorNeutral: '#5C5E72',
    colorDanger: '#F87171',
    borderRadius: '10px',
    fontFamily: 'Inter, sans-serif',
    fontSize: '14px',
  },
  elements: {
    card: { boxShadow: 'none', background: 'transparent', border: 'none', padding: 0 },
    rootBox: { width: '100%' },
    // hide clerk's built-in header — we render our own above the mount div
    cardHeader: { display: 'none' },
    formButtonPrimary: {
      background: 'linear-gradient(135deg, #0891B2 0%, #06B6D4 100%)',
      boxShadow: '0 4px 20px rgba(6,182,212,0.35)',
      fontFamily: 'Inter, sans-serif',
      fontWeight: 600,
      letterSpacing: '-0.01em',
      transition: 'all 0.2s ease',
    },
    socialButtonsBlockButton: {
      background: '#111',
      border: '1px solid rgba(255,255,255,0.1)',
      color: '#F1F2F7',
      fontFamily: 'Inter, sans-serif',
      fontWeight: 500,
      transition: 'all 0.2s ease',
    },
    dividerLine: { background: 'rgba(255,255,255,0.07)' },
    dividerText: { color: '#3A3A50', fontSize: '12px' },
    formFieldLabel: { color: 'rgba(255,255,255,0.45)', fontFamily: 'Inter, sans-serif', fontSize: '13px', fontWeight: 500, letterSpacing: '-0.005em', textTransform: 'none' },
    formFieldInput: {
      background: '#111',
      border: '1px solid rgba(255,255,255,0.09)',
      color: '#F1F2F7',
      fontFamily: 'Inter, sans-serif',
      fontSize: '14px',
    },
    footerActionLink: { color: '#22D3EE', fontWeight: 600 },
    footerActionText: { color: '#3A3A50' },
    footer: { borderTop: '1px solid rgba(255,255,255,0.06)', paddingTop: '16px', marginTop: '8px' },
    identityPreviewText: { color: '#F1F2F7' },
    identityPreviewEditButtonIcon: { color: '#9496A8' },
    alert: { background: 'rgba(248,113,113,0.07)', border: '1px solid rgba(248,113,113,0.18)', borderRadius: '8px' },
    alertText: { color: '#F87171', fontSize: '13px' },
  },
};

function clerkUserToApp(u) {
  const hasClerkPlan = u.has?.({ plan: CLERK_PLAN_KEY }) ?? false;
  const hasMetaPlan  = u.publicMetadata?.plan === 'Pro';
  return {
    username: u.username || u.firstName || (u.emailAddresses[0]?.emailAddress || '').split('@')[0],
    email: u.emailAddresses[0]?.emailAddress || '',
    plan: (hasClerkPlan || hasMetaPlan) ? 'Pro' : 'Free',
    id: u.id,
    createdAt: u.createdAt,
  };
}

// ─── TOAST HOOK ───────────────────────────────────────────────────────────────
function useToasts() {
  const [toasts, setToasts] = useState([]);
  const nextId = useRef(1);
  const add = useCallback(({ type = 'info', msg }) => {
    const id = nextId.current++;
    setToasts(prev => [...prev, { id, type, msg, out: false }]);
    setTimeout(() => {
      setToasts(prev => prev.map(t => t.id === id ? { ...t, out: true } : t));
      setTimeout(() => setToasts(prev => prev.filter(t => t.id !== id)), 280);
    }, 3200);
  }, []);
  const remove = useCallback((id) => {
    setToasts(prev => prev.map(t => t.id === id ? { ...t, out: true } : t));
    setTimeout(() => setToasts(prev => prev.filter(t => t.id !== id)), 280);
  }, []);
  return [toasts, add, remove];
}

// ─── AUTH ASIDE — animated live-feed panel ───────────────────────────────────
const FEED_MEMBERS = [
  { name: 'xShadowReaper',    initStatus: 'online',   game: null },
  { name: 'FrostClan_Leader', initStatus: 'in-game',  game: 'Arsenal' },
  { name: 'Phantom_Wolf',     initStatus: 'offline',  game: null },
  { name: 'VelocityX99',     initStatus: 'online',   game: null },
  { name: 'DarkMatter_X',    initStatus: 'in-game',  game: 'Da Hood' },
  { name: 'NightOwl99',      initStatus: 'offline',  game: null },
];
const GAMES = ['Arsenal', 'Da Hood', 'Bloxburg', 'Brookhaven', 'Adopt Me'];
const STATUSES = ['online', 'in-game', 'offline'];

const StatusChip = ({ status, game }) => {
  const cfg = {
    'online':  { color: '#34D399', bg: 'rgba(52,211,153,0.1)',  label: 'Online' },
    'in-game': { color: '#22D3EE', bg: 'rgba(34,211,238,0.1)',  label: game || 'In Game' },
    'offline': { color: '#3F3F52', bg: 'rgba(255,255,255,0.04)', label: 'Offline' },
  }[status] || {};
  return (
    <span style={{ display:'inline-flex', alignItems:'center', gap:5, padding:'3px 8px', borderRadius:20, background:cfg.bg, fontSize:11, fontWeight:500, color:cfg.color, letterSpacing:'0.01em', whiteSpace:'nowrap' }}>
      <span style={{ width:5, height:5, borderRadius:'50%', background:cfg.color, flexShrink:0,
        animation: status !== 'offline' ? 'auth-dot-pulse 2s ease-in-out infinite' : 'none' }} />
      {cfg.label}
    </span>
  );
};

const AuthAside = ({ mode }) => {
  const [members, setMembers] = useState(FEED_MEMBERS.map(m => ({ ...m, status: m.initStatus })));
  const [feed, setFeed]       = useState([]);
  const feedRef = useRef([]);

  useEffect(() => {
    const tick = setInterval(() => {
      const idx = Math.floor(Math.random() * members.length);
      const next = STATUSES[Math.floor(Math.random() * STATUSES.length)];
      const game = next === 'in-game' ? GAMES[Math.floor(Math.random() * GAMES.length)] : null;
      setMembers(prev => prev.map((m, i) => i === idx ? { ...m, status: next, game } : m));
      const name = FEED_MEMBERS[idx].name;
      const event = next === 'online' ? 'came online' : next === 'in-game' ? `joined ${game}` : 'went offline';
      const entry = { id: Date.now(), name, event, status: next };
      feedRef.current = [entry, ...feedRef.current.slice(0, 3)];
      setFeed([...feedRef.current]);
    }, 2200);
    return () => clearInterval(tick);
  }, []);

  return (
    <div style={{
      flex: '0 0 48%', position: 'relative', overflow: 'hidden',
      borderLeft: '1px solid rgba(255,255,255,0.05)',
      background: 'linear-gradient(155deg, #050F11 0%, #020809 60%, #040D10 100%)',
      display: 'flex', flexDirection: 'column', justifyContent: 'center',
      padding: '56px clamp(32px,4vw,56px)',
    }}>
      <style>{`
        @keyframes auth-dot-pulse { 0%,100%{opacity:1;transform:scale(1)} 50%{opacity:0.4;transform:scale(0.7)} }
        @keyframes auth-feed-in   { from{opacity:0;transform:translateY(-8px)} to{opacity:1;transform:translateY(0)} }
        @keyframes auth-glow-breathe { 0%,100%{opacity:0.7} 50%{opacity:1} }
        @keyframes auth-ring-spin { from{transform:translateY(-50%) rotate(0deg)} to{transform:translateY(-50%) rotate(360deg)} }
        @keyframes auth-scan { 0%{transform:translateY(-100%)} 100%{transform:translateY(400%)} }
      `}</style>

      {/* bg glows */}
      <div style={{ position:'absolute', top:'8%', right:'-12%', width:480, height:480, background:'radial-gradient(ellipse, rgba(6,182,212,0.13) 0%, transparent 65%)', pointerEvents:'none', animation:'auth-glow-breathe 6s ease-in-out infinite' }} />
      <div style={{ position:'absolute', bottom:'-8%', left:'-8%', width:360, height:360, background:'radial-gradient(ellipse, rgba(14,116,144,0.1) 0%, transparent 65%)', pointerEvents:'none' }} />

      {/* dot grid */}
      <div style={{ position:'absolute', inset:0, backgroundImage:'radial-gradient(rgba(255,255,255,0.04) 1px, transparent 1px)', backgroundSize:'28px 28px', pointerEvents:'none', maskImage:'radial-gradient(ellipse 90% 80% at 60% 50%, black 10%, transparent 100%)' }} />

      {/* spinning ring */}
      <div style={{ position:'absolute', top:'50%', right:'-18%', width:560, height:560, borderRadius:'50%', border:'1px solid rgba(34,211,238,0.07)', pointerEvents:'none', animation:'auth-ring-spin 40s linear infinite', transformOrigin:'center center' }}>
        <div style={{ position:'absolute', top:8, left:'50%', width:5, height:5, borderRadius:'50%', background:'rgba(34,211,238,0.5)', transform:'translateX(-50%)', boxShadow:'0 0 8px rgba(34,211,238,0.8)' }} />
      </div>
      <div style={{ position:'absolute', top:'50%', right:'-8%', width:380, height:380, borderRadius:'50%', border:'1px solid rgba(34,211,238,0.04)', pointerEvents:'none' }} />

      {/* scan line */}
      <div style={{ position:'absolute', left:0, right:0, height:1, background:'linear-gradient(90deg, transparent 0%, rgba(6,182,212,0.15) 40%, rgba(6,182,212,0.3) 50%, rgba(6,182,212,0.15) 60%, transparent 100%)', animation:'auth-scan 8s linear infinite', pointerEvents:'none' }} />

      <div style={{ position:'relative', zIndex:1, maxWidth:400 }}>
        {/* Logo lockup */}
        <div style={{ display:'flex', alignItems:'center', gap:14, marginBottom:40, animation:'fadein 0.6s var(--ease-out-expo) both' }}>
          <div style={{ position:'relative' }}>
            <div style={{ position:'absolute', inset:-6, borderRadius:16, background:'radial-gradient(ellipse, rgba(6,182,212,0.2) 0%, transparent 70%)', animation:'auth-glow-breathe 3s ease-in-out infinite' }} />
            <LogoMark size={44} />
          </div>
          <div>
            <div style={{ fontSize:20, fontWeight:800, letterSpacing:'-0.04em', color:'#F1F2F7', lineHeight:1 }}>RoStealth</div>
            <div style={{ fontSize:11, color:'rgba(6,182,212,0.7)', letterSpacing:'0.1em', textTransform:'uppercase', fontWeight:500, marginTop:3 }}>Community Intelligence</div>
          </div>
        </div>

        {/* Headline */}
        <div style={{ marginBottom:32, animation:'fadein 0.6s var(--ease-out-expo) 80ms both' }}>
          <h2 style={{ fontSize:'clamp(22px,2.4vw,30px)', fontWeight:700, letterSpacing:'-0.035em', color:'#F1F2F7', lineHeight:1.18, marginBottom:10 }}>
            {mode === 'login'
              ? <>Your board is<br /><span style={{ background:'linear-gradient(90deg,#22D3EE,#2DD4BF)', WebkitBackgroundClip:'text', WebkitTextFillColor:'transparent' }}>live & waiting.</span></>
              : <>Know exactly<br /><span style={{ background:'linear-gradient(90deg,#22D3EE,#2DD4BF)', WebkitBackgroundClip:'text', WebkitTextFillColor:'transparent' }}>who's online now.</span></>}
          </h2>
          <p style={{ fontSize:14, color:'rgba(255,255,255,0.38)', lineHeight:1.65, maxWidth:310 }}>
            {mode === 'login'
              ? 'Real-time status for every member, right where you left off.'
              : 'Track your entire Roblox community with zero bots or passwords.'}
          </p>
        </div>

        {/* Live feed card */}
        <div style={{ background:'rgba(255,255,255,0.03)', border:'1px solid rgba(255,255,255,0.07)', borderRadius:12, overflow:'hidden', marginBottom:28, animation:'fadein 0.6s var(--ease-out-expo) 160ms both' }}>
          {/* card header */}
          <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', padding:'10px 14px', borderBottom:'1px solid rgba(255,255,255,0.05)' }}>
            <div style={{ display:'flex', alignItems:'center', gap:7 }}>
              <span style={{ width:6, height:6, borderRadius:'50%', background:'#34D399', animation:'auth-dot-pulse 2s ease-in-out infinite' }} />
              <span style={{ fontSize:11, fontWeight:600, color:'rgba(255,255,255,0.5)', letterSpacing:'0.08em', textTransform:'uppercase' }}>Live Feed</span>
            </div>
            <span style={{ fontSize:10, color:'rgba(255,255,255,0.2)', fontFamily:'var(--mono)' }}>
              {members.filter(m => m.status !== 'offline').length}/{members.length} online
            </span>
          </div>
          {/* members */}
          <div style={{ padding:'4px 0' }}>
            {members.slice(0, 5).map((m, i) => (
              <div key={m.name} style={{ display:'flex', alignItems:'center', justifyContent:'space-between', padding:'7px 14px', animation:`fadein 0.4s var(--ease-out-expo) ${i*50+200}ms both` }}>
                <div style={{ display:'flex', alignItems:'center', gap:9 }}>
                  <div style={{ width:24, height:24, borderRadius:6, background:`hsl(${(m.name.charCodeAt(0)*47)%360},25%,18%)`, border:'1px solid rgba(255,255,255,0.08)', display:'flex', alignItems:'center', justifyContent:'center', fontSize:10, fontWeight:700, color:'rgba(255,255,255,0.5)', flexShrink:0 }}>
                    {m.name[0]}
                  </div>
                  <span style={{ fontSize:12.5, fontWeight:500, color: m.status === 'offline' ? 'rgba(255,255,255,0.25)' : 'rgba(255,255,255,0.75)', fontFamily:'var(--mono)', letterSpacing:'-0.01em' }}>
                    {m.name.length > 14 ? m.name.slice(0,14)+'…' : m.name}
                  </span>
                </div>
                <StatusChip status={m.status} game={m.game} />
              </div>
            ))}
          </div>
          {/* live events */}
          {feed.length > 0 && (
            <div style={{ borderTop:'1px solid rgba(255,255,255,0.05)', padding:'8px 14px', display:'flex', flexDirection:'column', gap:4 }}>
              {feed.slice(0,2).map((f, i) => (
                <div key={f.id} style={{ fontSize:11, color:'rgba(255,255,255,0.3)', animation:'auth-feed-in 0.3s var(--ease-out-expo) both', display:'flex', gap:5 }}>
                  <span style={{ color: f.status === 'online' ? '#34D399' : f.status === 'in-game' ? '#22D3EE' : 'rgba(255,255,255,0.2)', fontWeight:600, fontFamily:'var(--mono)' }}>{f.name.split('_')[0]}</span>
                  <span>{f.event}</span>
                </div>
              ))}
            </div>
          )}
        </div>

        {/* stats strip */}
        <div style={{ display:'flex', gap:0, animation:'fadein 0.6s var(--ease-out-expo) 280ms both' }}>
          {[['2,300+','owners'],['12K+','tracked'],['30s','refresh']].map(([v,l], i) => (
            <div key={l} style={{ flex:1, padding:'0 0 0 20px', borderLeft: i > 0 ? '1px solid rgba(255,255,255,0.07)' : 'none' }}>
              <div style={{ fontSize:17, fontWeight:700, color:'#F1F2F7', letterSpacing:'-0.03em', lineHeight:1 }}>{v}</div>
              <div style={{ fontSize:11, color:'rgba(255,255,255,0.25)', marginTop:4, letterSpacing:'0.02em' }}>{l}</div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
};

// ─── AUTH SHELL (split: form left, brand right) ──────────────────────────────
const AuthShell = ({ mode = 'login', title, altText, altLabel, onAlt, onBack, children, legal }) => (
  <div style={{ display:'flex', minHeight:'100vh', background:'var(--bg0)' }}>
    {/* LEFT — form */}
    <div style={{ flex:1, position:'relative', display:'flex', flexDirection:'column', justifyContent:'center', alignItems:'center', padding:'48px 32px', overflow:'hidden' }}>
      {/* faint glow behind form */}
      <div style={{ position:'absolute', top:'-10%', left:'-10%', width:480, height:480, background:'radial-gradient(ellipse at center, rgba(6,182,212,0.07) 0%, transparent 65%)', pointerEvents:'none' }} />

      {onBack && (
        <button onClick={onBack} style={{ position:'absolute', top:24, left:24, zIndex:2, display:'flex', alignItems:'center', gap:7, background:'none', border:'none', cursor:'pointer', color:'var(--t3)', fontSize:13.5, fontFamily:'var(--font)', fontWeight:500, transition:'color 0.15s' }}
          onMouseEnter={e=>e.currentTarget.style.color='var(--t1)'} onMouseLeave={e=>e.currentTarget.style.color='var(--t3)'}>
          <span style={{ fontSize:16 }}>‹</span> Back to site
        </button>
      )}

      <div style={{ position:'relative', zIndex:1, width:'100%', maxWidth:380, animation:'auth-panel-in 0.42s var(--ease-out-expo) both' }}>
        {/* logo */}
        <div style={{ display:'flex', alignItems:'center', gap:11, marginBottom:32 }}>
          <LogoMark size={32} />
          <span style={{ fontSize:17, fontWeight:700, letterSpacing:'-0.03em', color:'var(--t1)' }}>RoStealth</span>
        </div>

        <h1 style={{ fontSize:27, fontWeight:700, letterSpacing:'-0.035em', color:'var(--t1)', marginBottom:8 }}>{title}</h1>
        <p style={{ fontSize:14, color:'var(--t3)', marginBottom:28 }}>
          {altText}{' '}
          <button onClick={onAlt} style={{ background:'none', border:'none', color:'var(--p4)', cursor:'pointer', fontSize:14, fontFamily:'var(--font)', fontWeight:600, padding:0, transition:'color 0.15s' }}
            onMouseEnter={e=>e.currentTarget.style.color='var(--p3)'} onMouseLeave={e=>e.currentTarget.style.color='var(--p4)'}>{altLabel}</button>
        </p>

        {children}

        {legal && <p style={{ marginTop:22, fontSize:11.5, color:'var(--t4)', lineHeight:1.7 }}>{legal}</p>}
      </div>
    </div>

    {/* RIGHT — brand showcase */}
    <AuthAside mode={mode} />
  </div>
);

// ─── AUTH ERROR + SUBMIT ─────────────────────────────────────────────────────
const AuthError = ({ msg }) => (
  <div style={{ display:'flex', alignItems:'center', gap:8, padding:'10px 13px', background:'var(--red-dim)', border:'1px solid rgba(248,113,113,0.22)', borderRadius:10, fontSize:13, color:'var(--red)', animation:'fadein-up 0.2s var(--ease-out-expo) both' }}>
    <svg width="14" height="14" viewBox="0 0 14 14" fill="none" style={{ flexShrink:0 }}><circle cx="7" cy="7" r="5.5" stroke="currentColor" strokeWidth="1.3"/><path d="M7 4.5v3M7 9.5v.2" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/></svg>
    {msg}
  </div>
);

const AuthSubmit = ({ loading, idle, busy }) => (
  <button type="submit" disabled={loading} style={{
    width:'100%', padding:'12px', borderRadius:10, border:'none',
    cursor:loading?'not-allowed':'pointer',
    background: loading ? 'var(--bg4)' : 'var(--p5)',
    color:'#fff', fontFamily:'var(--font)', fontSize:14.5, fontWeight:600, letterSpacing:'-0.01em',
    display:'flex', alignItems:'center', justifyContent:'center', gap:8,
    boxShadow: loading ? 'none' : '0 0 0 1px rgba(255,255,255,0.1) inset, 0 4px 18px rgba(6,182,212,0.4)',
    transition:'all 0.2s var(--ease-out-expo)', marginTop:4, opacity: loading?0.7:1,
  }}
    onMouseEnter={e=>{ if(!loading){ e.currentTarget.style.filter='brightness(1.1)'; e.currentTarget.style.boxShadow='0 0 0 1px rgba(255,255,255,0.1) inset, 0 6px 26px rgba(6,182,212,0.55)'; }}}
    onMouseLeave={e=>{ e.currentTarget.style.filter='none'; e.currentTarget.style.boxShadow=loading?'none':'0 0 0 1px rgba(255,255,255,0.1) inset, 0 4px 18px rgba(6,182,212,0.4)'; }}>
    {loading ? <><span style={{ animation:'spin 0.75s linear infinite', display:'inline-block' }}>&#8635;</span> {busy}</> : idle}
  </button>
);

// ─── FIELD ───────────────────────────────────────────────────────────────────
const AuthField = ({ label, value, onChange, placeholder, type = 'text', icon, autoFocus, onKeyDown, hint }) => {
  const [focus, setFocus] = useState(false);
  const [show, setShow]   = useState(false);
  const inputType = type === 'password' ? (show ? 'text' : 'password') : type;
  return (
    <div>
      <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:7 }}>
        <label style={{ fontSize:13.5, fontWeight:600, color:'var(--t1)', letterSpacing:'-0.005em' }}>{label}</label>
        {hint && <span style={{ fontSize:13, color:'var(--p4)', cursor:'pointer' }}>{hint}</span>}
      </div>
      <div style={{ position:'relative' }}>
        {icon && (
          <span style={{ position:'absolute', left:12, top:'50%', transform:'translateY(-50%)', color:focus?'var(--p4)':'var(--t4)', pointerEvents:'none', transition:'color 0.18s', display:'flex' }}>
            {icon}
          </span>
        )}
        <input
          autoFocus={autoFocus}
          type={inputType}
          value={value}
          onChange={e => onChange(e.target.value)}
          placeholder={placeholder}
          onKeyDown={onKeyDown}
          onFocus={() => setFocus(true)}
          onBlur={() => setFocus(false)}
          style={{
            width:'100%',
            padding: icon ? '10px 38px 10px 34px' : '10px 38px 10px 12px',
            background: focus ? 'var(--bg3)' : 'var(--bg2)',
            border:`1.5px solid ${focus ? 'var(--p5)' : 'var(--border)'}`,
            borderRadius:10, color:'var(--t1)', fontSize:14,
            fontFamily:'var(--font)', outline:'none',
            boxShadow: focus ? '0 0 0 3px rgba(6,182,212,0.14)' : 'none',
            transition:'all 0.2s var(--ease-out-expo)',
          }}
        />
        {type === 'password' && (
          <button type="button" onClick={() => setShow(s => !s)} style={{ position:'absolute', right:11, top:'50%', transform:'translateY(-50%)', background:'none', border:'none', color:'var(--t4)', cursor:'pointer', padding:2, display:'flex', transition:'color 0.15s' }}
            onMouseEnter={e => e.currentTarget.style.color='var(--t2)'}
            onMouseLeave={e => e.currentTarget.style.color='var(--t4)'}>
            {show
              ? <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M1 1l12 12M5.5 5.7A2 2 0 0 0 8.3 8.4M2 4.5C3.2 3 5 2 7 2s3.8 1 5 2.5M3.5 8.5C4.5 10 5.7 11 7 11s2.5-1 3.5-2.5" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round"/></svg>
              : <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M1 7s2.5-4.5 6-4.5S13 7 13 7s-2.5 4.5-6 4.5S1 7 1 7z" stroke="currentColor" strokeWidth="1.3"/><circle cx="7" cy="7" r="1.8" stroke="currentColor" strokeWidth="1.3"/></svg>
            }
          </button>
        )}
      </div>
    </div>
  );
};

// ─── LOGIN PAGE ───────────────────────────────────────────────────────────────
const LoginPage = ({ onAuth, onGoRegister, onBack }) => {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  const [loading, setLoading]   = useState(false);
  const [error, setError]       = useState('');
  const [shake, setShake]       = useState(false);

  const triggerError = (msg) => {
    setError(msg);
    setShake(true);
    setTimeout(() => setShake(false), 500);
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    if (!username.trim() || !password) { triggerError('Please fill in all fields.'); return; }
    if (username === 'admin' && password === 'admin') {
      onAuth({ username:'admin', email:'admin@rostealth.site', plan:'Pro', id:1 }); return;
    }
    setLoading(true); setError('');
    await new Promise(r => setTimeout(r, 850));
    onAuth({ username:username.trim(), email:`${username.trim()}@example.com`, plan:'Pro', id:Date.now() });
  };

  return (
    <AuthShell
      mode="login"
      title="Welcome back"
      altText="Don't have an account?"
      altLabel="Create one"
      onAlt={onGoRegister}
      onBack={onBack}
      legal="Public Roblox data only. Not affiliated with Roblox Corporation."
    >
      <form onSubmit={handleSubmit} style={{ display:'flex', flexDirection:'column', gap:16, animation:shake?'shake 0.38s var(--ease-out-expo)':'none' }}>
        <AuthField label="Username" value={username} onChange={setUsername} placeholder="Your RoStealth username" icon={<Icon.User />} autoFocus />
        <AuthField label="Password" value={password} onChange={setPassword} placeholder="Your password" type="password" hint="Forgot?" />
        {error && <AuthError msg={error} />}
        <AuthSubmit loading={loading} idle="Log in" busy="Signing in…" />
      </form>
    </AuthShell>
  );
};

// ─── SIGNUP PAGE ──────────────────────────────────────────────────────────────
const SignupPage = ({ onAuth, onGoLogin, onBack }) => {
  const [username, setUsername] = useState('');
  const [email, setEmail]       = useState('');
  const [password, setPassword] = useState('');
  const [loading, setLoading]   = useState(false);
  const [error, setError]       = useState('');
  const [shake, setShake]       = useState(false);

  const triggerError = (msg) => {
    setError(msg); setShake(true);
    setTimeout(() => setShake(false), 500);
  };

  const pwStrength = password.length === 0 ? 0 : password.length < 6 ? 1 : password.length < 10 ? 2 : 3;
  const strengthLabel = ['', 'Weak', 'Fair', 'Strong'];
  const strengthColor = ['', 'var(--red)', 'var(--amber)', 'var(--green)'];

  const handleSubmit = async (e) => {
    e.preventDefault();
    if (!username.trim()) { triggerError('Please enter a username.'); return; }
    if (!email.trim() || !email.includes('@')) { triggerError('Enter a valid email address.'); return; }
    if (!password || password.length < 6) { triggerError('Password must be at least 6 characters.'); return; }
    setLoading(true); setError('');
    await new Promise(r => setTimeout(r, 950));
    onAuth({ username:username.trim(), email:email.trim(), plan:'Pro', id:Date.now() });
  };

  return (
    <AuthShell
      mode="signup"
      title="Create your account"
      altText="Already have an account?"
      altLabel="Log in"
      onAlt={onGoLogin}
      onBack={onBack}
      legal={<>By continuing you agree to our <span style={{ color:'var(--t3)', cursor:'pointer', borderBottom:'1px solid var(--border)' }}>Terms of Service</span>. Public data only.</>}
    >
      <form onSubmit={handleSubmit} style={{ display:'flex', flexDirection:'column', gap:16, animation:shake?'shake 0.38s var(--ease-out-expo)':'none' }}>
        <AuthField label="Username" value={username} onChange={setUsername} placeholder="Your username" icon={<Icon.User />} autoFocus />
        <AuthField label="Email" value={email} onChange={setEmail} placeholder="you@example.com" type="email" icon={
          <svg width="13" height="13" viewBox="0 0 14 14" fill="none"><rect x="1" y="3" width="12" height="9" rx="1.5" stroke="currentColor" strokeWidth="1.2"/><path d="M1 4l6 4.5L13 4" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round"/></svg>
        } />
        <div>
          <AuthField label="Password" value={password} onChange={setPassword} placeholder="At least 6 characters" type="password" />
          {password.length > 0 && (
            <div style={{ marginTop:9, display:'flex', alignItems:'center', gap:10 }}>
              <div style={{ flex:1, height:3, background:'var(--bg4)', display:'flex', gap:3, overflow:'hidden', borderRadius:2 }}>
                {[1,2,3].map(i => (
                  <div key={i} style={{ flex:1, height:'100%', borderRadius:2, background: pwStrength >= i ? strengthColor[pwStrength] : 'transparent', transition:'background 0.3s' }}/>
                ))}
              </div>
              <span style={{ fontSize:11, color:strengthColor[pwStrength], fontWeight:600, flexShrink:0 }}>{strengthLabel[pwStrength]}</span>
            </div>
          )}
        </div>
        {error && <AuthError msg={error} />}
        <AuthSubmit loading={loading} idle="Create account" busy="Creating…" />
      </form>
    </AuthShell>
  );
};

// ─── CLERK AUTH PAGES ────────────────────────────────────────────────────────
const ClerkAuthLeft = ({ onBack, mode, children }) => {
  const copy = mode === 'signup'
    ? { title: 'Create your account', sub: 'Start tracking your Roblox community in minutes.' }
    : { title: 'Welcome back', sub: 'Sign in to pick up right where you left off.' };

  return (
    <div style={{ flex:1, position:'relative', display:'flex', flexDirection:'column', justifyContent:'center', alignItems:'center', padding:'56px clamp(28px,5vw,72px)', overflow:'hidden', background:'#000' }}>
      <style>{`
        @keyframes clerk-row-in { from{opacity:0;transform:translateX(-10px)} to{opacity:1;transform:translateX(0)} }
        .clerk-left-row { animation: clerk-row-in 0.4s var(--ease-out-expo) both; }
        /* suppress Clerk's built-in card header — we render our own */
        .cl-header, .cl-card-header, [class*='cl-headerTitle'], [class*='cl-headerSubtitle'], [class*='cl-header__'] { display: none !important; }
        /* hide Clerk's "Secured by Clerk" badge */
        .cl-footerPages, [class*='cl-poweredBy'], [class*='cl-internal-1fvshox'], [class*='cl-internal-1s6kazl'], [class*='cl-internal-c1j7z4'], [class*='cl-internal-1m27caj'], a[href*='clerk.com'][target='_blank'] { display: none !important; }
      `}</style>

      {/* ambient glow — top left only, very faint */}
      <div style={{ position:'absolute', top:-60, left:-60, width:400, height:400, background:'radial-gradient(ellipse at top left, rgba(6,182,212,0.08) 0%, transparent 60%)', pointerEvents:'none' }} />

      {/* back */}
      {onBack && (
        <button onClick={onBack} style={{ position:'absolute', top:24, left:24, zIndex:2, display:'flex', alignItems:'center', gap:5, background:'none', border:'none', cursor:'pointer', color:'rgba(255,255,255,0.2)', fontSize:12.5, fontFamily:'var(--font)', fontWeight:500, transition:'color 0.2s', letterSpacing:'0.01em' }}
          onMouseEnter={e=>e.currentTarget.style.color='rgba(255,255,255,0.55)'} onMouseLeave={e=>e.currentTarget.style.color='rgba(255,255,255,0.2)'}>
          <svg width="13" height="13" viewBox="0 0 13 13" fill="none"><path d="M8 2L3.5 6.5 8 11" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/></svg>
          Back
        </button>
      )}

      <div style={{ position:'relative', zIndex:1, width:'100%', maxWidth:400 }}>
        {/* logo — fades in first */}
        <div className="clerk-left-row" style={{ animationDelay:'0ms', display:'flex', alignItems:'center', gap:9, marginBottom:40 }}>
          <LogoMark size={28} />
          <span style={{ fontSize:14.5, fontWeight:700, letterSpacing:'-0.03em', color:'rgba(255,255,255,0.8)' }}>RoStealth</span>
        </div>

        {/* custom heading */}
        <div className="clerk-left-row" style={{ animationDelay:'60ms', marginBottom:24 }}>
          <h1 style={{ fontSize:26, fontWeight:700, letterSpacing:'-0.04em', color:'#F1F2F7', lineHeight:1.15, marginBottom:7 }}>{copy.title}</h1>
          <p style={{ fontSize:13.5, color:'rgba(255,255,255,0.3)', lineHeight:1.6, letterSpacing:'-0.005em' }}>{copy.sub}</p>
        </div>

        {/* clerk form mount — its own card header is hidden via appearance */}
        <div className="clerk-left-row" style={{ animationDelay:'120ms' }}>
          {children}
        </div>
      </div>

      {/* bottom legal */}
      <p style={{ position:'absolute', bottom:20, fontSize:11, color:'rgba(255,255,255,0.12)', letterSpacing:'0.01em', textAlign:'center' }}>
        Public Roblox data only · Not affiliated with Roblox Corporation
      </p>
    </div>
  );
};

const ClerkSignInPage = ({ onBack }) => {
  const ref = useRef(null);
  useEffect(() => {
    if (!ref.current || !window.clerk) return;
    window.clerk.mountSignIn(ref.current, { appearance: CLERK_APPEARANCE });
    return () => { try { if (ref.current) window.clerk.unmountSignIn(ref.current); } catch(e) {} };
  }, []);
  return (
    <div style={{ display:'flex', minHeight:'100vh' }}>
      <ClerkAuthLeft onBack={onBack} mode="login"><div ref={ref} /></ClerkAuthLeft>
      <AuthAside mode="login" />
    </div>
  );
};

const ClerkSignUpPage = ({ onBack }) => {
  const ref = useRef(null);
  useEffect(() => {
    if (!ref.current || !window.clerk) return;
    window.clerk.mountSignUp(ref.current, { appearance: CLERK_APPEARANCE });
    return () => { try { if (ref.current) window.clerk.unmountSignUp(ref.current); } catch(e) {} };
  }, []);
  return (
    <div style={{ display:'flex', minHeight:'100vh' }}>
      <ClerkAuthLeft onBack={onBack} mode="signup"><div ref={ref} /></ClerkAuthLeft>
      <AuthAside mode="signup" />
    </div>
  );
};

// ─── APP LAYOUT ───────────────────────────────────────────────────────────────
const AppLayout = ({ user, setUser, page, setPage, children, alertCount, alerts, onClearAlerts, onCmdK }) => {
  const [collapsed, setCollapsed] = useState(false);
  return (
    <div style={{ display:'flex', height:'100vh', overflow:'hidden' }}>
      <Sidebar page={page} setPage={setPage} collapsed={collapsed} user={user} alertCount={alertCount} />
      <div style={{ flex:1, display:'flex', flexDirection:'column', overflow:'hidden' }}>
        <TopBar page={page} collapsed={collapsed} setCollapsed={setCollapsed} onLogout={() => setUser(null)} user={user} alertCount={alertCount} alerts={alerts} onClearAlerts={onClearAlerts} onCmdK={onCmdK} />
        <main style={{ flex:1, overflowY:'auto' }}>{children}</main>
      </div>
    </div>
  );
};

// ─── ROOT APP ─────────────────────────────────────────────────────────────────
const App = () => {
  const [t, setTweak]  = useTweaks(TWEAK_DEFAULTS);
  const [user, setUser]                 = useState(null);
  const [clerkLoaded, setClerkLoaded]   = useState(false);
  const [needsOnboard, setNeedsOnboard] = useState(false);
  const path = window.location.pathname.replace(/\/$/, '');
  const [authView, setAuthView] = useState(
    path === '/terms' ? 'terms' : path === '/privacy' ? 'privacy' : null
  );

  const navTo = (view) => {
    const url = view === 'terms' ? '/terms' : view === 'privacy' ? '/privacy' : '/';
    window.history.pushState({}, '', url);
    setAuthView(view);
  };
  const [page, setPage]                 = useState('dashboard');
  const [trackedUsers, setTrackedUsers] = useState([]);
  const [alertRules, setAlertRules]     = useState([]);
  const [firedAlerts, setFiredAlerts]   = useState([]);
  const [syncAge, setSyncAge]           = useState(0);
  const [refreshing, setRefreshing]     = useState(false);
  const [cmdkOpen, setCmdkOpen]     = useState(false);
  const [drawerUser, setDrawerUser] = useState(null);
  const [drawerOpen, setDrawerOpen] = useState(false);
  const [toasts, addToast, removeToast] = useToasts();

  const API_BASE = 'https://api.rostealth.site';
  const apiGet = useCallback(async (path) => {
    const token = await window.clerk?.session?.getToken();
    const res = await fetch(API_BASE + path, { headers: token ? { Authorization: `Bearer ${token}` } : {} });
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    return res.json();
  }, []);

  const loadAll = useCallback(async () => {
    if (!window.clerk?.user) return;
    setRefreshing(true);
    try {
      const [users, rules, fired] = await Promise.all([
        apiGet('/api/users'),
        apiGet('/api/alerts'),
        apiGet('/api/alerts/fired'),
      ]);
      setTrackedUsers(users || []);
      setAlertRules(rules || []);
      setFiredAlerts(fired || []);
      setSyncAge(0);
    } catch (err) {
      console.warn('[RoStealth] data load failed:', err.message);
    } finally {
      setRefreshing(false);
    }
  }, [apiGet]);

  // poll every 30s, age counter every 1s
  useEffect(() => {
    if (!user) return;
    loadAll();
    const poll = setInterval(loadAll, 30000);
    const ticker = setInterval(() => setSyncAge(a => a + 1), 1000);
    return () => { clearInterval(poll); clearInterval(ticker); };
  }, [user, loadAll]);

  // global Cmd+K
  useEffect(() => {
    const h = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key === 'k') { e.preventDefault(); setCmdkOpen(v => !v); }
      if (e.key === 'Escape') setCmdkOpen(false);
    };
    window.addEventListener('keydown', h);
    return () => window.removeEventListener('keydown', h);
  }, []);

  const openUser = useCallback((u) => { setDrawerUser(u); setDrawerOpen(true); }, []);

  // Initialize Clerk
  useEffect(() => {
    if (!window.Clerk) {
      console.error('[RoStealth] Clerk SDK not loaded — check CDN script in index.html');
      setClerkLoaded(true);
      return;
    }
    const clerk = window.Clerk;
    window.clerk = clerk;
    clerk.load().then(() => {
      setClerkLoaded(true);
      if (clerk.user) {
        setUser(clerkUserToApp(clerk.user));
      }
      clerk.addListener(({ user: clerkUser }) => {
        if (clerkUser) {
          setUser(prev => {
            if (!prev) {
              const isNew = clerkUser.createdAt && (Date.now() - new Date(clerkUser.createdAt).getTime() < 90000);
              setNeedsOnboard(isNew);
              setAuthView(null);
            }
            return clerkUserToApp(clerkUser);
          });
        } else {
          setUser(null);
          setPage('dashboard');
          setAuthView(null);
        }
      });
    }).catch(err => {
      console.error('[RoStealth] Clerk load failed:', err);
      setClerkLoaded(true);
    });
  }, []);

  const handleOnboardComplete = () => {
    setNeedsOnboard(false);
    setPage('dashboard');
    addToast({ type:'success', msg:'Welcome to RoStealth! Your pass is now active.' });
    loadAll();
  };

  const handleLogout = () => {
    if (window.clerk) window.clerk.signOut();
  };

  const accentCSS = `:root { --p6:${t.accentColor}; --p5:${t.accentColor}; --p4:${t.accentColor}cc; --p3:${t.accentColor}99; --p-dim:${t.accentColor}18; --border-bright:${t.accentColor}55; }`;

  // ── clerk loading ──
  if (!clerkLoaded) {
    return (
      <div style={{ height:'100vh', display:'flex', alignItems:'center', justifyContent:'center', background:'var(--bg0)' }}>
        <LogoMark size={48} />
      </div>
    );
  }

  // ── onboarding ──
  if (user && needsOnboard) {
    return (
      <>
        <Onboarding user={user} onComplete={handleOnboardComplete} />
        <style>{accentCSS}</style>
      </>
    );
  }

  // ── auth pages (full screen, no modal) ──
  if (!user) {
    if (authView === 'login') {
      return (
        <>
          <ClerkSignInPage onGoRegister={() => setAuthView('register')} onBack={() => setAuthView(null)} />
          <style>{accentCSS}</style>
        </>
      );
    }
    if (authView === 'register') {
      return (
        <>
          <ClerkSignUpPage onGoLogin={() => setAuthView('login')} onBack={() => setAuthView(null)} />
          <style>{accentCSS}</style>
        </>
      );
    }
    if (authView === 'terms') {
      return <><TermsPage onBack={() => navTo(null)} /><style>{accentCSS}</style></>;
    }
    if (authView === 'privacy') {
      return <><PrivacyPage onBack={() => navTo(null)} /><style>{accentCSS}</style></>;
    }
    return (
      <div>
        <LandingPage onLogin={() => setAuthView('login')} onSignup={() => setAuthView('register')} onTerms={() => navTo('terms')} onPrivacy={() => navTo('privacy')} />
        <TweaksPanel>
          <TweakSection label="Accent" />
          <TweakColor label="Accent color" value={t.accentColor} options={['#06B6D4','#22D3EE','#14B8A6','#3B82F6','#2DD4BF']} onChange={v => setTweak('accentColor', v)} />
        </TweaksPanel>
        <style>{accentCSS}</style>
      </div>
    );
  }

  // ── subscription gate ──
  if (user.plan !== 'Pro') {
    const handleGateComplete = async () => {
      if (window.clerk?.user) {
        await window.clerk.user.reload();
        setUser(clerkUserToApp(window.clerk.user));
      }
      setPage('dashboard');
    };
    return (
      <div style={{ height:'100%' }}>
        <FreeGateFlow user={user} onComplete={handleGateComplete} />
        <style>{accentCSS}</style>
      </div>
    );
  }

  // ── dashboard ──
  const pageProps = { user, setPage, trackedUsers, setTrackedUsers, onOpenUser:openUser, addToast };
  const renderPage = () => {
    switch (page) {
      case 'dashboard': return <DashboardPage {...pageProps} firedAlerts={firedAlerts} onRefresh={loadAll} refreshing={refreshing} syncAge={syncAge} />;
      case 'tracking':  return <TrackingPage  {...pageProps} />;
      case 'analytics': return <AnalyticsPage {...pageProps} />;
      case 'alerts':    return <AlertsPage    {...pageProps} alertRules={alertRules} setAlertRules={setAlertRules} firedAlerts={firedAlerts} />;
      case 'settings':  return <SettingsPage  user={user} addToast={addToast} />;
      case 'admin':     return <AdminPage     user={user} />;
      case 'pricing':   return <FullPricingPage user={user} />;
      default:          return <DashboardPage {...pageProps} firedAlerts={firedAlerts} onRefresh={loadAll} refreshing={refreshing} syncAge={syncAge} />;
    }
  };

  return (
    <div style={{ height:'100%' }}>
      <AppLayout user={user} setUser={handleLogout} page={page} setPage={setPage}
        alertCount={firedAlerts.length}
        alerts={firedAlerts} onClearAlerts={() => setFiredAlerts([])} onCmdK={() => setCmdkOpen(true)}>
        {renderPage()}
      </AppLayout>
      <UserDrawer user={drawerUser} open={drawerOpen} onClose={() => setDrawerOpen(false)}
        onFlag={(id) => setTrackedUsers(prev => prev.map(u => u.id===id ? { ...u, flagged:!u.flagged } : u))}
        onRemove={(id) => { setTrackedUsers(prev => prev.filter(u => u.id!==id)); setDrawerOpen(false); }}
        addToast={addToast} />
      <CmdKModal open={cmdkOpen} onClose={() => setCmdkOpen(false)} trackedUsers={trackedUsers}
        setPage={(p) => { setPage(p); setCmdkOpen(false); }}
        onOpenUser={(u) => { openUser(u); setCmdkOpen(false); }} />
      <ToastContainer toasts={toasts} removeToast={removeToast} />
      <TweaksPanel>
        <TweakSection label="Accent" />
        <TweakColor label="Accent color" value={t.accentColor} options={['#06B6D4','#22D3EE','#14B8A6','#3B82F6','#2DD4BF']} onChange={v => setTweak('accentColor', v)} />
      </TweaksPanel>
      <style>{accentCSS}</style>
    </div>
  );
};

const appRoot = ReactDOM.createRoot(document.getElementById('root'));
appRoot.render(<App />);
