const { useState, useRef, useEffect, useCallback } = React;

// ═══════════════════════════════════════════════════════
// DESIGN TOKENS (from studio.config.js)
// ═══════════════════════════════════════════════════════
const _cfg = typeof STUDIO_CONFIG !== 'undefined' ? STUDIO_CONFIG : {};
const _theme = _cfg.theme || {};
const _dark = _theme.dark || {};

const ORANGE = _theme.primary || "#3B82F6";
const BG = _dark.bg || "#0c0c0d";
const SURFACE = _dark.surface || "#141416";
const SURFACE2 = _dark.surface2 || "#1a1a1e";
const BORDER = _dark.border || "#1e1e22";
const TEXT = _dark.text || "#d8d5d0";
const SUBTEXT = _dark.subtext || "#888";
const MUTED = _dark.muted || "#444";
const font = _theme.fontFamily || "'Manrope', sans-serif";
const APP_NAME = _cfg.appName || "AI Studio";
const TAGLINE = _cfg.tagline || "Your AI-powered toolkit";
const LOGO_URL = _cfg.logoUrl || "/public/logo.svg";

// Light mode tokens
const _light = _theme.light || {};
const LIGHT = {
  bg: _light.bg || "#f5f5f5", surface: _light.surface || "#ffffff", surface2: _light.surface2 || "#f0f0f0",
  border: _light.border || "#e0e0e0", text: _light.text || "#1a1a1a", subtext: _light.subtext || "#666",
  muted: _light.muted || "#999", inputBg: _light.inputBg || "#f7f7f7",
};

// Theme context — shared across components
const ThemeContext = React.createContext({ mode: 'dark', toggle: () => {} });
function useTheme() { return React.useContext(ThemeContext); }

// Get current token value based on theme mode
function t(darkVal, lightVal) {
  // This is a static helper for inline use — components that need reactive theme should use useTheme()
  return darkVal; // default; actual switching happens via the themed() wrapper
}

// Markdown renderer for chat messages — uses CSS vars for theme support
function renderMarkdown(text) {
  if (!text) return '';
  // Escape HTML first
  let html = text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
  // Code blocks
  html = html.replace(/```(\w*)\n?([\s\S]*?)```/g, (_, lang, code) =>
    `<pre style="background:var(--surface2,#1a1a1e);border:1px solid var(--border,#1e1e22);border-radius:8px;padding:12px 16px;overflow-x:auto;font-size:13px;line-height:1.5;margin:8px 0"><code>${code.trim()}</code></pre>`);
  // Inline code
  html = html.replace(/`([^`]+)`/g, '<code style="background:var(--surface2,#1a1a1e);padding:2px 6px;border-radius:4px;font-size:13px">$1</code>');
  // Bold
  html = html.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
  // Italic
  html = html.replace(/\*(.+?)\*/g, '<em>$1</em>');
  // Headers
  html = html.replace(/^### (.+)$/gm, '<h3 style="font-size:15px;font-weight:700;margin:12px 0 6px">$1</h3>');
  html = html.replace(/^## (.+)$/gm, '<h2 style="font-size:17px;font-weight:700;margin:14px 0 6px">$1</h2>');
  html = html.replace(/^# (.+)$/gm, '<h1 style="font-size:20px;font-weight:800;margin:16px 0 8px">$1</h1>');
  // Blockquote
  html = html.replace(/^&gt; (.+)$/gm, '<blockquote style="border-left:3px solid var(--muted,#444);padding-left:12px;color:var(--subtext,#888);margin:8px 0">$1</blockquote>');
  // Horizontal rule
  html = html.replace(/^---$/gm, '<hr style="border:none;border-top:1px solid var(--border,#1e1e22);margin:12px 0">');
  // Unordered lists
  html = html.replace(/(^[-*] .+$(\n|$))+/gm, (block) => {
    const items = block.trim().split('\n').map(l => `<li style="margin:2px 0">${l.replace(/^[-*] /, '')}</li>`).join('');
    return `<ul style="padding-left:20px;margin:8px 0">${items}</ul>`;
  });
  // Ordered lists
  html = html.replace(/(^\d+\. .+$(\n|$))+/gm, (block) => {
    const items = block.trim().split('\n').map(l => `<li style="margin:2px 0">${l.replace(/^\d+\. /, '')}</li>`).join('');
    return `<ol style="padding-left:20px;margin:8px 0">${items}</ol>`;
  });
  // Links
  html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank" rel="noopener" style="color:#3B82F6">$1</a>');
  // Paragraphs
  html = html.replace(/\n\n/g, '</p><p>');
  html = html.replace(/\n/g, '<br>');
  return html;
}

// ═══════════════════════════════════════════════════════
// NAV ITEMS
// ═══════════════════════════════════════════════════════
const navItems = [
  { id: "dashboard", icon: "⊞", label: "Dashboard" },
  { id: "tools", icon: "🧰", label: "My Tools" },
  { id: "training", icon: "📚", label: "Training" },
  { id: "settings", icon: "⚙️", label: "Settings" },
];

// ═══════════════════════════════════════════════════════
// TOAST UTILITY
// ═══════════════════════════════════════════════════════
function showToast(message, type = 'info') {
  const container = document.getElementById('toast-container');
  const colors = { success: '#22c55e', error: '#ef4444', info: ORANGE };
  const toast = document.createElement('div');
  toast.className = 'toast';
  toast.style.cssText = `background:var(--surface,${SURFACE});border:1px solid var(--border,${BORDER});border-left:3px solid ${colors[type] || ORANGE};color:var(--text,${TEXT});`;
  toast.textContent = message;
  container.appendChild(toast);
  setTimeout(() => toast.remove(), 4000);
}

// ═══════════════════════════════════════════════════════
// SHARED COMPONENTS
// ═══════════════════════════════════════════════════════

function Logo() {
  const [imgFailed, setImgFailed] = React.useState(false);
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
      {!imgFailed
        ? <img src={LOGO_URL} alt={APP_NAME} onError={() => setImgFailed(true)} style={{ height: 52, maxWidth: 180, width: "auto", borderRadius: 10, objectFit: "contain" }} />
        : <div style={{ fontWeight: 800, fontSize: 16, letterSpacing: "-0.4px", color: TEXT }}>{APP_NAME}</div>
      }
    </div>
  );
}

function LogoSmall() {
  const th = useTheme();
  const [imgFailed, setImgFailed] = React.useState(false);
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 9 }}>
      {!imgFailed
        ? <img src={LOGO_URL} alt={APP_NAME} onError={() => setImgFailed(true)} style={{ height: 44, maxWidth: 160, width: "auto", borderRadius: 8, objectFit: "contain" }} />
        : <div style={{ fontWeight: 800, fontSize: 14, letterSpacing: "-0.4px", color: th.text }}>{APP_NAME}</div>
      }
    </div>
  );
}

function Input({ label, type = "text", placeholder, value, onChange, name }) {
  const [focused, setFocused] = useState(false);
  const [showPassword, setShowPassword] = useState(false);
  const th = useTheme();
  const isPassword = type === "password";
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
      <label style={{ fontSize: 12, fontWeight: 600, color: th.subtext, letterSpacing: "0.3px", textTransform: "uppercase" }}>{label}</label>
      <div style={{ position: "relative" }}>
        <input
          type={isPassword && showPassword ? "text" : type} name={name} placeholder={placeholder} value={value} onChange={onChange}
          onFocus={() => setFocused(true)} onBlur={() => setFocused(false)}
          style={{
            width: "100%", boxSizing: "border-box",
            background: th.inputBg || th.bg, border: `1px solid ${focused ? ORANGE : th.border}`,
            borderRadius: 10, padding: isPassword ? "11px 42px 11px 14px" : "11px 14px", fontSize: 14, color: th.text,
            outline: "none", fontFamily: font, transition: "border 0.2s"
          }}
        />
        {isPassword && (
          <button type="button" onClick={() => setShowPassword(!showPassword)} style={{
            position: "absolute", right: 12, top: "50%", transform: "translateY(-50%)",
            background: "none", border: "none", cursor: "pointer", padding: 0, color: th.muted, fontSize: 16, lineHeight: 1
          }} tabIndex={-1}>
            {showPassword ? "🙈" : "👁"}
          </button>
        )}
      </div>
    </div>
  );
}

function Btn({ children, onClick, variant = "primary", fullWidth, disabled, style: s = {} }) {
  const [hovered, setHovered] = useState(false);
  const th = useTheme();
  const base = {
    border: "none", borderRadius: 10, padding: "12px 20px", fontSize: 14,
    fontWeight: 700, cursor: disabled ? "not-allowed" : "pointer", fontFamily: font, transition: "all 0.2s",
    width: fullWidth ? "100%" : "auto", letterSpacing: "-0.2px", opacity: disabled ? 0.5 : 1, ...s
  };
  const variants = {
    primary: { background: hovered && !disabled ? "#bf4e22" : ORANGE, color: "#fff" },
    ghost: { background: "transparent", color: th.subtext, border: `1px solid ${th.border}` },
    outline: { background: "transparent", color: th.text, border: `1px solid ${th.border}` },
  };
  return (
    <button onClick={!disabled ? onClick : undefined} onMouseEnter={() => setHovered(true)} onMouseLeave={() => setHovered(false)} style={{ ...base, ...variants[variant] }}>
      {children}
    </button>
  );
}

function ToolCard({ tool, onClick, isFavorite, onToggleFavorite }) {
  const [hovered, setHovered] = useState(false);
  const th = useTheme();
  return (
    <div onMouseEnter={() => setHovered(true)} onMouseLeave={() => setHovered(false)}
      style={{
        background: hovered ? th.surface2 : th.surface, border: `1px solid ${hovered ? (tool.color || ORANGE) + "55" : th.border}`,
        borderRadius: 14, padding: 22, transition: "all 0.2s", display: "flex", flexDirection: "column", gap: 14
      }}>
      <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between" }}>
        <div style={{ width: 42, height: 42, borderRadius: 12, background: (tool.color || ORANGE) + "18", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 20 }}>{tool.emoji}</div>
        {tool.tag && <span style={{ fontSize: 10, fontWeight: 700, color: tool.color || ORANGE, background: (tool.color || ORANGE) + "18", padding: "3px 9px", borderRadius: 20, letterSpacing: "0.4px", textTransform: "uppercase" }}>{tool.tag}</span>}
      </div>
      <div style={{ flex: 1 }}>
        <div style={{ fontWeight: 800, fontSize: 15, color: th.text, letterSpacing: "-0.3px" }}>{tool.name}</div>
        <div style={{ fontSize: 11, color: tool.color || ORANGE, fontWeight: 600, marginTop: 2 }}>{tool.role}</div>
        <p style={{ fontSize: 13, color: th.subtext, margin: "8px 0 0", lineHeight: 1.55, whiteSpace: "pre-wrap" }}>{tool.description || tool.desc}</p>
      </div>
      <div style={{ display: "flex", gap: 8, marginTop: 4 }}>
        <button onClick={() => onClick(tool)}
          style={{
            flex: 1, padding: "9px 0", borderRadius: 10, border: "none", cursor: "pointer",
            background: tool.color || ORANGE, color: "#fff", fontSize: 13, fontWeight: 700,
            fontFamily: "inherit", transition: "opacity 0.15s"
          }}
          onMouseEnter={e => e.target.style.opacity = "0.85"}
          onMouseLeave={e => e.target.style.opacity = "1"}
        >Use Tool</button>
        {onToggleFavorite && (
          <button onClick={() => onToggleFavorite(tool.id)}
            style={{
              flex: 1, padding: "9px 0", borderRadius: 10, cursor: "pointer",
              background: isFavorite ? "#f5a623" + "18" : th.surface2,
              border: `1px solid ${isFavorite ? "#f5a623" + "44" : th.border}`,
              color: isFavorite ? "#f5a623" : th.subtext, fontSize: 13, fontWeight: 700,
              fontFamily: "inherit", transition: "all 0.15s", display: "flex", alignItems: "center", justifyContent: "center", gap: 6
            }}
          >{isFavorite ? "\u2605" : "\u2606"} {isFavorite ? "Pinned" : "Pin to Sidebar"}</button>
        )}
      </div>
    </div>
  );
}

// ═══════════════════════════════════════════════════════
// AUTH SCREENS
// ═══════════════════════════════════════════════════════

function LoginScreen({ onNavigate, onAuth }) {
  const [email, setEmail] = useState("");
  const [pass, setPass] = useState("");
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(false);

  const handleSubmit = async () => {
    if (!email.trim() || !pass) return;
    setError(""); setLoading(true);
    try {
      const res = await fetch('/api/auth/login', {
        method: 'POST', credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email: email.trim(), password: pass }),
      });
      const data = await res.json();
      if (!res.ok) { setError(data.error || 'Login failed'); setLoading(false); return; }
      onAuth();
    } catch { setError('Something went wrong. Please try again.'); setLoading(false); }
  };

  return (
    <div style={{ minHeight: "100vh", background: BG, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", fontFamily: font, padding: 24 }}>
      <div style={{ width: "100%", maxWidth: 420 }}>
        <div style={{ textAlign: "center", marginBottom: 36 }}>
          <div style={{ display: "flex", justifyContent: "center" }}><Logo /></div>
          <p style={{ color: SUBTEXT, fontSize: 14, marginTop: 12 }}>{TAGLINE}</p>
        </div>
        <div style={{ background: SURFACE, border: `1px solid ${BORDER}`, borderRadius: 16, padding: 32, display: "flex", flexDirection: "column", gap: 20 }}>
          <div>
            <h2 style={{ margin: 0, fontSize: 20, fontWeight: 800, color: TEXT, letterSpacing: "-0.5px" }}>Welcome back</h2>
            <p style={{ margin: "6px 0 0", fontSize: 13, color: SUBTEXT }}>Sign in to your {APP_NAME}</p>
          </div>
          <Input label="Email" type="email" placeholder="you@example.com" value={email} onChange={e => setEmail(e.target.value)} />
          <Input label="Password" type="password" placeholder="••••••••" value={pass} onChange={e => setPass(e.target.value)} />
          <div style={{ textAlign: "right", marginTop: -12 }}>
            <span onClick={() => onNavigate("forgot")} style={{ fontSize: 12, color: ORANGE, cursor: "pointer", fontWeight: 600 }}>Forgot password?</span>
          </div>
          {error && <div style={{ color: "#ef4444", fontSize: 13 }}>{error}</div>}
          <Btn fullWidth onClick={handleSubmit} disabled={loading}>{loading ? 'Signing in...' : 'Sign In'}</Btn>
          <div style={{ textAlign: "center", fontSize: 13, color: SUBTEXT }}>
            Don't have an account?{" "}
            <span onClick={() => onNavigate("signup")} style={{ color: ORANGE, fontWeight: 700, cursor: "pointer" }}>Sign up</span>
          </div>
        </div>
        <div style={{ textAlign: "center", marginTop: 20 }}>
          <span onClick={() => onNavigate("pricing")} style={{ fontSize: 12, color: MUTED, cursor: "pointer" }}>View pricing →</span>
        </div>
      </div>
    </div>
  );
}

function SignupScreen({ onNavigate, onAuth }) {
  const [name, setName] = useState("");
  const [email, setEmail] = useState("");
  const [pass, setPass] = useState("");
  const [agreed, setAgreed] = useState(false);
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(false);

  const handleSubmit = async () => {
    if (!name.trim() || !email.trim() || !pass) return;
    if (!agreed) { setError('Please agree to the Terms of Service and Privacy Policy'); return; }
    setError(""); setLoading(true);
    try {
      const res = await fetch('/api/auth/signup', {
        method: 'POST', credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email: email.trim(), password: pass, fullName: name.trim() }),
      });
      const data = await res.json();
      if (!res.ok) { setError(data.error || 'Signup failed'); setLoading(false); return; }
      showToast('Account created! Check your email to verify.', 'success');
      onAuth();
    } catch { setError('Something went wrong. Please try again.'); setLoading(false); }
  };

  return (
    <div style={{ minHeight: "100vh", background: BG, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", fontFamily: font, padding: 24 }}>
      <div style={{ width: "100%", maxWidth: 420 }}>
        <div style={{ textAlign: "center", marginBottom: 36 }}><div style={{ display: "flex", justifyContent: "center" }}><Logo /></div></div>
        <div style={{ background: SURFACE, border: `1px solid ${BORDER}`, borderRadius: 16, padding: 32, display: "flex", flexDirection: "column", gap: 20 }}>
          <div>
            <h2 style={{ margin: 0, fontSize: 20, fontWeight: 800, color: TEXT, letterSpacing: "-0.5px" }}>Create your account</h2>
            <p style={{ margin: "6px 0 0", fontSize: 13, color: SUBTEXT }}>Join {APP_NAME} and start building</p>
          </div>
          <Input label="Full Name" placeholder="Your name" value={name} onChange={e => setName(e.target.value)} />
          <Input label="Email" type="email" placeholder="you@example.com" value={email} onChange={e => setEmail(e.target.value)} />
          <Input label="Password" type="password" placeholder="Min. 8 characters" value={pass} onChange={e => setPass(e.target.value)} />
          <div style={{ display: "flex", alignItems: "flex-start", gap: 8, fontSize: 13, color: SUBTEXT }}>
            <input type="checkbox" checked={agreed} onChange={e => setAgreed(e.target.checked)} style={{ marginTop: 2, accentColor: ORANGE }} />
            <label>I agree to the <a href="/terms" target="_blank" rel="noopener" style={{ color: ORANGE, textDecoration: "none", fontWeight: 600 }}>Terms of Service</a> and <a href="/privacy" target="_blank" rel="noopener" style={{ color: ORANGE, textDecoration: "none", fontWeight: 600 }}>Privacy Policy</a></label>
          </div>
          {error && <div style={{ color: "#ef4444", fontSize: 13 }}>{error}</div>}
          <Btn fullWidth onClick={handleSubmit} disabled={loading || !agreed}>{loading ? 'Creating account...' : 'Create Account'}</Btn>
          <div style={{ textAlign: "center", fontSize: 13, color: SUBTEXT }}>
            Already have an account?{" "}
            <span onClick={() => onNavigate("login")} style={{ color: ORANGE, fontWeight: 700, cursor: "pointer" }}>Sign in</span>
          </div>
        </div>
      </div>
    </div>
  );
}

function ForgotScreen({ onNavigate }) {
  const [email, setEmail] = useState("");
  const [sent, setSent] = useState(false);
  const [loading, setLoading] = useState(false);

  const handleSubmit = async () => {
    if (!email.trim()) return;
    setLoading(true);
    try {
      await fetch('/api/auth/forgot', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email: email.trim() }),
      });
      setSent(true);
    } catch {}
    setLoading(false);
  };

  return (
    <div style={{ minHeight: "100vh", background: BG, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", fontFamily: font, padding: 24 }}>
      <div style={{ width: "100%", maxWidth: 420 }}>
        <div style={{ textAlign: "center", marginBottom: 36 }}><div style={{ display: "flex", justifyContent: "center" }}><Logo /></div></div>
        <div style={{ background: SURFACE, border: `1px solid ${BORDER}`, borderRadius: 16, padding: 32, display: "flex", flexDirection: "column", gap: 20 }}>
          {!sent ? <>
            <div>
              <h2 style={{ margin: 0, fontSize: 20, fontWeight: 800, color: TEXT, letterSpacing: "-0.5px" }}>Reset password</h2>
              <p style={{ margin: "6px 0 0", fontSize: 13, color: SUBTEXT }}>We'll send a reset link to your email</p>
            </div>
            <Input label="Email" type="email" placeholder="you@example.com" value={email} onChange={e => setEmail(e.target.value)} />
            <Btn fullWidth onClick={handleSubmit} disabled={loading}>{loading ? 'Sending...' : 'Send Reset Link'}</Btn>
          </> : <>
            <div style={{ textAlign: "center", padding: "12px 0" }}>
              <div style={{ fontSize: 40, marginBottom: 12 }}>📬</div>
              <h3 style={{ margin: 0, fontSize: 18, fontWeight: 800, color: TEXT }}>Check your inbox</h3>
              <p style={{ fontSize: 13, color: SUBTEXT, marginTop: 8 }}>We sent a reset link to <strong style={{ color: TEXT }}>{email || "your email"}</strong></p>
            </div>
          </>}
          <div style={{ textAlign: "center" }}>
            <span onClick={() => onNavigate("login")} style={{ fontSize: 13, color: ORANGE, fontWeight: 600, cursor: "pointer" }}>← Back to sign in</span>
          </div>
        </div>
      </div>
    </div>
  );
}

function ResetPasswordScreen({ token, onNavigate }) {
  const [pass, setPass] = useState("");
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(false);

  const handleSubmit = async () => {
    if (!pass || pass.length < 8) { setError("Password must be at least 8 characters"); return; }
    setError(""); setLoading(true);
    try {
      const res = await fetch('/api/auth/reset', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ token, password: pass }),
      });
      const data = await res.json();
      if (res.ok) { showToast('Password reset! You can now sign in.', 'success'); window.history.replaceState({}, '', '/'); onNavigate("login"); }
      else { setError(data.error || 'Reset failed'); }
    } catch { setError('Something went wrong.'); }
    setLoading(false);
  };

  return (
    <div style={{ minHeight: "100vh", background: BG, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", fontFamily: font, padding: 24 }}>
      <div style={{ width: "100%", maxWidth: 420 }}>
        <div style={{ textAlign: "center", marginBottom: 36 }}><div style={{ display: "flex", justifyContent: "center" }}><Logo /></div></div>
        <div style={{ background: SURFACE, border: `1px solid ${BORDER}`, borderRadius: 16, padding: 32, display: "flex", flexDirection: "column", gap: 20 }}>
          <div>
            <h2 style={{ margin: 0, fontSize: 20, fontWeight: 800, color: TEXT, letterSpacing: "-0.5px" }}>Set new password</h2>
            <p style={{ margin: "6px 0 0", fontSize: 13, color: SUBTEXT }}>Enter your new password below</p>
          </div>
          <Input label="New Password" type="password" placeholder="Min. 8 characters" value={pass} onChange={e => setPass(e.target.value)} />
          {error && <div style={{ color: "#ef4444", fontSize: 13 }}>{error}</div>}
          <Btn fullWidth onClick={handleSubmit} disabled={loading}>{loading ? 'Resetting...' : 'Reset Password'}</Btn>
          <div style={{ textAlign: "center" }}>
            <span onClick={() => onNavigate("login")} style={{ fontSize: 13, color: ORANGE, fontWeight: 600, cursor: "pointer" }}>← Back to sign in</span>
          </div>
        </div>
      </div>
    </div>
  );
}

function PricingScreen({ onNavigate }) {
  const [annual, setAnnual] = useState(false);
  const plans = _cfg.plans || [];
  return (
    <div style={{ minHeight: "100vh", background: BG, fontFamily: font, padding: "48px 24px" }}>
      <div style={{ maxWidth: 900, margin: "0 auto" }}>
        <div style={{ textAlign: "center", marginBottom: 48 }}>
          <div style={{ display: "flex", justifyContent: "center", marginBottom: 28 }}><Logo /></div>
          <h1 style={{ fontSize: 36, fontWeight: 800, color: TEXT, margin: 0, letterSpacing: "-1px" }}>Your tools.<br /><span style={{ color: ORANGE }}>Infinite leverage.</span></h1>
          <p style={{ color: SUBTEXT, fontSize: 15, marginTop: 14 }}>Pick the plan that fits where you are right now.</p>
          <div style={{ display: "inline-flex", alignItems: "center", gap: 10, marginTop: 20, background: SURFACE, border: `1px solid ${BORDER}`, borderRadius: 10, padding: "8px 14px" }}>
            <span style={{ fontSize: 13, color: annual ? SUBTEXT : TEXT, fontWeight: 600, cursor: "pointer" }} onClick={() => setAnnual(false)}>Monthly</span>
            <div onClick={() => setAnnual(a => !a)} style={{ width: 40, height: 22, borderRadius: 11, background: annual ? ORANGE : "#2a2a2e", cursor: "pointer", position: "relative", transition: "background 0.2s" }}>
              <div style={{ width: 16, height: 16, borderRadius: "50%", background: "#fff", position: "absolute", top: 3, left: annual ? 21 : 3, transition: "left 0.2s" }} />
            </div>
            <span style={{ fontSize: 13, color: annual ? TEXT : SUBTEXT, fontWeight: 600, cursor: "pointer" }} onClick={() => setAnnual(true)}>Annual <span style={{ color: ORANGE }}>-20%</span></span>
          </div>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))", gap: 20, maxWidth: 680, margin: "0 auto" }}>
          {plans.map(p => {
            const price = annual ? Math.round(p.price * 0.8) : p.price;
            const planColor = ORANGE;
            return (
              <div key={p.id} style={{ background: SURFACE, border: `1px solid ${planColor}`, borderRadius: 16, padding: 28, display: "flex", flexDirection: "column", gap: 20, position: "relative" }}>
                {p.badge && <div style={{ position: "absolute", top: -12, left: "50%", transform: "translateX(-50%)", background: planColor, color: "#fff", fontSize: 11, fontWeight: 700, padding: "4px 12px", borderRadius: 20, whiteSpace: "nowrap" }}>{p.badge}</div>}
                <div>
                  <div style={{ fontSize: 13, fontWeight: 700, color: planColor, textTransform: "uppercase", letterSpacing: "0.5px" }}>{p.name}</div>
                  <div style={{ display: "flex", alignItems: "flex-end", gap: 4, marginTop: 8 }}>
                    <span style={{ fontSize: 38, fontWeight: 800, color: TEXT, letterSpacing: "-2px" }}>${price}</span>
                    <span style={{ fontSize: 13, color: SUBTEXT, marginBottom: 8 }}>/ {annual ? "mo, billed annually" : p.period || "mo"}</span>
                  </div>
                </div>
                <div style={{ flex: 1 }}>
                  <div style={{ fontSize: 11, fontWeight: 700, color: SUBTEXT, textTransform: "uppercase", letterSpacing: "0.5px", marginBottom: 10 }}>Includes</div>
                  {(p.features || []).map(t => (
                    <div key={t} style={{ display: "flex", alignItems: "flex-start", gap: 8, marginBottom: 8 }}>
                      <span style={{ color: planColor, fontSize: 14, marginTop: 1 }}>✓</span>
                      <span style={{ fontSize: 13, color: TEXT, lineHeight: 1.4 }}>{t}</span>
                    </div>
                  ))}
                </div>
                <Btn fullWidth onClick={() => onNavigate("signup")} variant="outline" style={{ borderColor: planColor, color: planColor }}>Join {p.name}</Btn>
              </div>
            );
          })}
        </div>
        <div style={{ textAlign: "center", marginTop: 40 }}>
          <p style={{ fontSize: 13, color: MUTED }}>Cancel anytime.</p>
          <span onClick={() => onNavigate("login")} style={{ fontSize: 13, color: ORANGE, fontWeight: 600, cursor: "pointer" }}>Already have an account? Sign in →</span>
        </div>
      </div>
    </div>
  );
}

// ═══════════════════════════════════════════════════════
// SIDEBAR
// ═══════════════════════════════════════════════════════

function Sidebar({ active, onNav, collapsed, onCollapse, onLogout, user, plugins, theme, onToggleTheme, pinnedChats, onOpenPinnedChat }) {
  const th = useTheme();
  const userPlan = user?.plan || 'free';
  const [onlineUsers, setOnlineUsers] = React.useState([]);
  React.useEffect(() => {
    const load = () => fetch('/api/online', { credentials: 'include' }).then(r => r.ok ? r.json() : null).then(d => { if (d?.online) setOnlineUsers(d.online); }).catch(() => {});
    load();
    const t = setInterval(load, 60000);
    return () => clearInterval(t);
  }, []);
  const plans = _cfg.plans || [];
  const currentPlan = plans.find(p => p.id === userPlan);
  const upgradePlan = plans.find(p => p.id !== userPlan && p.price > (currentPlan?.price || 0));

  const handleNav = (id) => { onNav(id); };

  return (
    <div style={{
      width: collapsed ? 60 : 220, background: th.surface, borderRight: `1px solid ${th.border}`,
      display: "flex", flexDirection: "column", padding: collapsed ? "20px 10px" : "20px 14px",
      gap: 4, transition: "width 0.2s", flexShrink: 0, height: "100vh", position: "relative"
    }}>
      {/* Collapse toggle */}
      <div onClick={onCollapse} style={{
        position: "absolute", top: 22, right: -10, width: 20, height: 20, background: th.surface2,
        border: `1px solid ${th.border}`, borderRadius: "50%", display: "flex", alignItems: "center",
        justifyContent: "center", cursor: "pointer", fontSize: 10, color: th.subtext, zIndex: 10
      }}>
        {collapsed ? "›" : "‹"}
      </div>

      <div style={{ marginBottom: 24, paddingLeft: collapsed ? 0 : 4, display: "flex", justifyContent: collapsed ? "center" : "flex-start" }}>
        {collapsed
          ? <img src={LOGO_URL} alt="" onError={e => e.target.style.display='none'} style={{ width: 36, height: 36, borderRadius: 8, objectFit: "contain" }} />
          : <LogoSmall />}
      </div>

      <div style={{ flex: 1, overflowY: 'auto', minHeight: 0, display: 'flex', flexDirection: 'column', gap: 4 }}>
      {navItems.map(n => (
        <div key={n.id} onClick={() => handleNav(n.id)}
          style={{
            display: "flex", alignItems: "center", gap: 10,
            padding: collapsed ? "10px 0" : "10px 12px", borderRadius: 10, cursor: "pointer",
            background: active === n.id ? ORANGE + "18" : "transparent",
            color: active === n.id ? ORANGE : th.subtext,
            fontWeight: active === n.id ? 700 : 500, fontSize: 13,
            transition: "all 0.15s", justifyContent: collapsed ? "center" : "flex-start"
          }}>
          <span style={{ fontSize: 16 }}>{n.icon}</span>
          {!collapsed && <span>{n.label}</span>}
        </div>
      ))}

      {user?.role === 'admin' && (
        <div onClick={() => handleNav("admin")}
          style={{
            display: "flex", alignItems: "center", gap: 10,
            padding: collapsed ? "10px 0" : "10px 12px", borderRadius: 10, cursor: "pointer",
            background: active === "admin" ? ORANGE + "18" : "transparent",
            color: active === "admin" ? ORANGE : th.subtext,
            fontWeight: active === "admin" ? 700 : 500, fontSize: 13,
            transition: "all 0.15s", justifyContent: collapsed ? "center" : "flex-start"
          }}>
          <span style={{ fontSize: 16 }}>🛠️</span>
          {!collapsed && <span>Admin</span>}
        </div>
      )}

      {/* Tool quick-access — only show favorited plugins */}
      {(() => {
        const sidebarPlugins = user?.favorite_plugins
          ? plugins.filter(p => user.favorite_plugins.includes(p.id))
          : [];
        const hasFavs = sidebarPlugins.length > 0;
        return (
          <>
            {hasFavs && !collapsed && <div style={{ fontSize: 10, fontWeight: 700, color: th.muted, textTransform: "uppercase", letterSpacing: "0.5px", padding: "16px 12px 6px" }}>Tools</div>}
            {hasFavs && collapsed && <div style={{ height: 1, background: th.border, margin: "8px 0" }} />}
            {hasFavs ? sidebarPlugins.map(p => (
              <div key={p.id} onClick={() => handleNav("chat-" + p.id)}
                style={{
                  display: "flex", alignItems: "center", gap: 10,
                  padding: collapsed ? "8px 0" : "8px 12px", borderRadius: 8, cursor: "pointer",
                  background: active === "chat-" + p.id ? th.surface2 : "transparent",
                  transition: "all 0.15s", justifyContent: collapsed ? "center" : "flex-start"
                }}>
                <span style={{ fontSize: 15, flexShrink: 0 }}>{p.emoji}</span>
                {!collapsed && <span style={{ fontSize: 12, color: active === "chat-" + p.id ? th.text : th.subtext, fontWeight: active === "chat-" + p.id ? 600 : 400 }}>{p.name}</span>}
              </div>
            )) : !collapsed && (
              <div style={{ padding: "16px 12px", fontSize: 11, color: th.muted, lineHeight: 1.5 }}>
                Star tools in My Tools to pin them here
              </div>
            )}
          </>
        );
      })()}

      {/* Pinned chats */}
      {pinnedChats && pinnedChats.length > 0 && (
        <>
          {!collapsed && <div style={{ fontSize: 10, fontWeight: 700, color: th.muted, textTransform: "uppercase", letterSpacing: "0.5px", padding: "12px 12px 6px" }}>Pinned Chats</div>}
          {collapsed && <div style={{ height: 1, background: th.border, margin: "8px 0" }} />}
          {pinnedChats.map(c => {
            const toolForChat = plugins.find(p => p.id === c.plugin_id);
            return (
              <div key={c.id} onClick={() => onOpenPinnedChat && onOpenPinnedChat(c)}
                style={{
                  display: "flex", alignItems: "center", gap: 10,
                  padding: collapsed ? "8px 0" : "7px 12px", borderRadius: 8, cursor: "pointer",
                  background: "transparent", transition: "all 0.15s", justifyContent: collapsed ? "center" : "flex-start"
                }}>
                <span style={{ fontSize: 13, flexShrink: 0 }}>{toolForChat?.emoji || "💬"}</span>
                {!collapsed && <span style={{ fontSize: 11, color: th.subtext, fontWeight: 400, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{c.title || "Chat"}</span>}
              </div>
            );
          })}
        </>
      )}
      </div>

      {/* Plan card — free plan only (upsell); hidden for paid subscribers and admins */}
      {user?.role !== 'admin' && userPlan === 'free' && (
      <div style={{ background: ORANGE + "18", border: `1px solid ${ORANGE}33`, borderRadius: 10, padding: collapsed ? "10px 6px" : "12px 14px", cursor: "pointer" }} onClick={() => { if (upgradePlan) onNav("settings"); }}>
        {collapsed
          ? <div style={{ textAlign: "center", fontSize: 16 }}>⚡</div>
          : <>
            <div style={{ fontSize: 10, fontWeight: 700, color: ORANGE, textTransform: "uppercase", letterSpacing: "0.5px" }}>Your Plan</div>
            <div style={{ fontSize: 13, fontWeight: 800, color: th.text, marginTop: 4, textTransform: "capitalize" }}>{userPlan}</div>
            {currentPlan && <div style={{ fontSize: 11, color: th.subtext, marginTop: 2 }}>${currentPlan.price}/{currentPlan.period}</div>}
            {upgradePlan && <div style={{ fontSize: 11, color: ORANGE, marginTop: 8, fontWeight: 600 }}>Upgrade to {upgradePlan.name} →</div>}
          </>}
      </div>
      )}

      {/* Who's Online */}
      {onlineUsers.length > 0 && (
        <div style={{ marginTop: 8, padding: collapsed ? "6px 0" : "7px 10px", borderRadius: 8, background: th.surface2, display: "flex", alignItems: "center", gap: 6, justifyContent: collapsed ? "center" : "flex-start" }}>
          <span style={{ width: 7, height: 7, borderRadius: "50%", background: "#22c55e", display: "inline-block", flexShrink: 0 }} />
          {!collapsed && <span style={{ fontSize: 11, fontWeight: 700, color: th.subtext }}>{onlineUsers.length} online</span>}
        </div>
      )}

      {/* Theme toggle slider */}
      <div onClick={onToggleTheme} style={{
        display: "flex", alignItems: "center", justifyContent: collapsed ? "center" : "flex-start", gap: 10,
        cursor: "pointer", marginTop: 8, padding: collapsed ? "4px 0" : "4px 4px",
      }}>
        <div style={{
          width: 44, height: 24, borderRadius: 12, position: "relative",
          background: theme === 'dark' ? th.surface2 : ORANGE + "30",
          border: `1px solid ${theme === 'dark' ? th.border : ORANGE + "55"}`,
          transition: "all 0.25s ease", flexShrink: 0,
        }}>
          <div style={{
            width: 18, height: 18, borderRadius: "50%", position: "absolute", top: 2,
            left: theme === 'dark' ? 2 : 22,
            background: theme === 'dark' ? th.subtext : ORANGE,
            transition: "all 0.25s ease",
            display: "flex", alignItems: "center", justifyContent: "center", fontSize: 10,
          }}>
            {theme === 'dark' ? '🌙' : '☀️'}
          </div>
        </div>
        {!collapsed && <span style={{ fontSize: 12, fontWeight: 600, color: th.subtext }}>{theme === 'dark' ? 'Light Mode' : 'Dark Mode'}</span>}
      </div>

      {/* User */}
      <div onClick={onLogout} style={{ display: "flex", alignItems: "center", gap: 8, marginTop: 8, padding: collapsed ? "0" : "0 4px", justifyContent: collapsed ? "center" : "flex-start", cursor: "pointer" }}>
        <div style={{ width: 28, height: 28, borderRadius: "50%", background: th.mode === 'light' ? "#e0e0e0" : "#2a2a2e", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 13, color: th.text }}>{(user?.full_name || user?.email || "?")[0].toUpperCase()}</div>
        {!collapsed && <div>
          <div style={{ fontSize: 12, fontWeight: 700, color: th.text }}>{user?.full_name || user?.email || ""}</div>
          <div style={{ fontSize: 10, color: th.subtext }}>Sign out</div>
        </div>}
      </div>
    </div>
  );
}

// ═══════════════════════════════════════════════════════
// DASHBOARD HOME
// ═══════════════════════════════════════════════════════

// Milestone definitions (must match server)
const MILESTONE_DEFS = [
  { id: 'first-message', emoji: '🌱', name: 'First Message', description: 'Sent your first message' },
  { id: 'chatterbox', emoji: '💬', name: 'Chatterbox', description: 'Sent 50 messages' },
  { id: 'power-user', emoji: '🔥', name: 'Power User', description: 'Sent 100 messages' },
  { id: 'super-user', emoji: '⚡', name: 'Super User', description: 'Sent 500 messages' },
  { id: 'legend', emoji: '🏆', name: 'Legend', description: 'Sent 1,000 messages' },
  { id: 'explorer', emoji: '🧭', name: 'Explorer', description: 'Used 3 different tools' },
  { id: 'trailblazer', emoji: '🌍', name: 'Trailblazer', description: 'Used every available tool' },
  { id: 'consistent', emoji: '📅', name: 'Consistent', description: '7-day activity streak' },
  { id: 'on-fire', emoji: '🔥', name: 'On Fire', description: '30-day activity streak' },
];

function DashboardHome({ onOpenTool, user, plugins, theme }) {
  const th = useTheme();
  const isAdmin = user?.role === 'admin';
  const [adminStats, setAdminStats] = useState(null);
  const [personalStats, setPersonalStats] = useState(null);
  const [leaderboard, setLeaderboard] = useState(null);
  const hour = new Date().getHours();
  const greeting = hour < 12 ? "Good morning" : hour < 17 ? "Good afternoon" : "Good evening";
  const firstName = (user?.full_name || user?.email || "").split(" ")[0] || "";

  // Fetch admin stats for dashboard BANs
  useEffect(() => {
    if (!isAdmin) return;
    (async () => {
      try {
        const res = await fetch('/api/admin/usage?days=30', { credentials: 'include' });
        const data = await res.json();
        if (res.ok) setAdminStats(data);
      } catch {}
    })();
  }, [isAdmin]);

  // Fetch gamification data
  useEffect(() => {
    (async () => {
      try {
        const [statsRes, lbRes] = await Promise.all([
          fetch('/api/stats/me', { credentials: 'include' }),
          fetch('/api/leaderboard', { credentials: 'include' }),
        ]);
        if (statsRes.ok) setPersonalStats(await statsRes.json());
        if (lbRes.ok) setLeaderboard(await lbRes.json());
      } catch {}
    })();
  }, []);

  // Skeleton while plugins load
  if (!plugins || plugins.length === 0) {
    return (
      <div style={{ padding: "32px 32px", maxWidth: 900 }}>
        <div className="skeleton" style={{ width: 300, height: 32, marginBottom: 8 }} />
        <div className="skeleton" style={{ width: 200, height: 16, marginBottom: 32 }} />
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(150px, 1fr))", gap: 14, marginBottom: 36 }}>
          {[1,2,3,4].map(i => <div key={i} className="skeleton" style={{ height: 90, borderRadius: 12 }} />)}
        </div>
        <div className="skeleton" style={{ width: 120, height: 20, marginBottom: 16 }} />
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(240px, 1fr))", gap: 14 }}>
          {[1,2,3].map(i => <div key={i} className="skeleton" style={{ height: 160, borderRadius: 14 }} />)}
        </div>
      </div>
    );
  }

  // Dynamic stats
  const planLimits = { free: (_cfg.rateLimits?.freeTrialMessages) || 10 };
  if (_cfg.plans) _cfg.plans.forEach(p => { planLimits[p.id] = p.monthlyMessageLimit; });
  const limit = planLimits[user?.plan] || 10;
  const used = user?.messages_used || 0;
  const remaining = Math.max(limit - used, 0);

  // Upsell plan
  const plans = _cfg.plans || [];
  const upgradePlan = plans.find(p => p.price > (plans.find(pp => pp.id === user?.plan)?.price || 0));

  return (
    <div style={{ padding: "32px 32px", maxWidth: 900 }}>
      <div style={{ marginBottom: 32 }}>
        <h1 style={{ margin: 0, fontSize: 24, fontWeight: 800, color: th.text, letterSpacing: "-0.6px" }}>{greeting}, {firstName} 👋</h1>
        <p style={{ margin: "8px 0 0", fontSize: 14, color: th.subtext }}>What are we building today?</p>
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(150px, 1fr))", gap: 14, marginBottom: 36 }}>
        {(isAdmin ? [
          { label: "Total Users", value: adminStats ? String(adminStats.totalUsers || 0) : "—", icon: "👥" },
          { label: "Active (30d)", value: adminStats ? String(adminStats.activeUsers || 0) : "—", icon: "📊" },
          { label: "Messages (30d)", value: adminStats ? (adminStats.totals?.total_messages || 0).toLocaleString() : "—", icon: "💬" },
          { label: "Est. API Cost", value: adminStats ? "$" + (adminStats.byPlugin || []).reduce((sum, r) => { const p = (_cfg.apiPricing || {})[r.model] || { inputPer1k: 0.003, outputPer1k: 0.015, cacheWritePer1k: 0.00375, cacheReadPer1k: 0.0003 }; return sum + (r.input_tokens / 1000) * p.inputPer1k + (r.output_tokens / 1000) * p.outputPer1k + ((r.cache_creation_input_tokens || 0) / 1000) * (p.cacheWritePer1k || 0.00375) + ((r.cache_read_input_tokens || 0) / 1000) * (p.cacheReadPer1k || 0.0003); }, 0).toFixed(2) : "—", icon: "💰" },
        ] : [
          { label: "Messages Remaining", value: String(remaining), icon: "💬" },
          { label: "Messages Used", value: String(used), icon: "📊" },
          { label: "Tools Available", value: `${plugins.length}`, icon: "🧰" },
          { label: "Current Plan", value: (user?.plan || "free").charAt(0).toUpperCase() + (user?.plan || "free").slice(1), icon: "⚡" },
        ]).map(s => (
          <div key={s.label} style={{ background: th.surface, border: `1px solid ${th.border}`, borderRadius: 12, padding: "16px 18px" }}>
            <div style={{ fontSize: 20, marginBottom: 8 }}>{s.icon}</div>
            <div style={{ fontSize: 22, fontWeight: 800, color: th.text, letterSpacing: "-0.5px" }}>{s.value}</div>
            <div style={{ fontSize: 11, color: th.subtext, marginTop: 3 }}>{s.label}</div>
          </div>
        ))}
      </div>
      {/* Personal Stats */}
      {personalStats && (
        <div style={{ marginBottom: 28 }}>
          <h2 style={{ margin: "0 0 12px", fontSize: 16, fontWeight: 800, color: th.text, letterSpacing: "-0.4px" }}>Your Activity</h2>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(130px, 1fr))", gap: 12 }}>
            <div style={{ background: th.surface, border: `1px solid ${th.border}`, borderRadius: 12, padding: "14px 16px" }}>
              <div style={{ fontSize: 20, marginBottom: 6 }}>{personalStats.streak > 0 ? '🔥' : '📅'}</div>
              <div style={{ fontSize: 22, fontWeight: 800, color: th.text }}>{personalStats.streak}</div>
              <div style={{ fontSize: 11, color: th.subtext, marginTop: 2 }}>Day Streak</div>
            </div>
            <div style={{ background: th.surface, border: `1px solid ${th.border}`, borderRadius: 12, padding: "14px 16px" }}>
              <div style={{ fontSize: 20, marginBottom: 6 }}>💬</div>
              <div style={{ fontSize: 22, fontWeight: 800, color: th.text }}>{personalStats.messagesThisWeek}</div>
              <div style={{ fontSize: 11, color: th.subtext, marginTop: 2 }}>This Week</div>
            </div>
            <div style={{ background: th.surface, border: `1px solid ${th.border}`, borderRadius: 12, padding: "14px 16px" }}>
              <div style={{ fontSize: 20, marginBottom: 6 }}>📊</div>
              <div style={{ fontSize: 22, fontWeight: 800, color: th.text }}>{personalStats.messagesThisMonth}</div>
              <div style={{ fontSize: 11, color: th.subtext, marginTop: 2 }}>This Month</div>
            </div>
            <div style={{ background: th.surface, border: `1px solid ${th.border}`, borderRadius: 12, padding: "14px 16px" }}>
              <div style={{ fontSize: 20, marginBottom: 6 }}>🧭</div>
              <div style={{ fontSize: 22, fontWeight: 800, color: th.text }}>{personalStats.toolsExplored}/{personalStats.totalTools}</div>
              <div style={{ fontSize: 11, color: th.subtext, marginTop: 2 }}>Tools Explored</div>
              {personalStats.totalTools > 0 && (
                <div style={{ height: 4, background: th.surface2, borderRadius: 2, marginTop: 6, overflow: "hidden" }}>
                  <div style={{ height: "100%", width: `${Math.min((personalStats.toolsExplored / personalStats.totalTools) * 100, 100)}%`, background: ORANGE, borderRadius: 2, transition: "width 0.5s" }} />
                </div>
              )}
            </div>
          </div>
        </div>
      )}

      {/* Leaderboard */}
      {leaderboard && (
        <div style={{ marginBottom: 28 }}>
          <h2 style={{ margin: "0 0 12px", fontSize: 16, fontWeight: 800, color: th.text, letterSpacing: "-0.4px" }}>This Week's Leaderboard</h2>
          {!(leaderboard.topUsers?.length > 0 || leaderboard.topTools?.length > 0) && (
            <div style={{ background: th.surface, border: `1px solid ${th.border}`, borderRadius: 14, padding: "28px 20px", textAlign: "center", color: th.subtext, fontSize: 13 }}>
              No activity yet this week — check back soon!
            </div>
          )}
          {(leaderboard.topUsers?.length > 0 || leaderboard.topTools?.length > 0) && (
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14 }}>
            {/* Top Users */}
            {leaderboard.topUsers?.length > 0 && (
              <div style={{ background: th.surface, border: `1px solid ${th.border}`, borderRadius: 14, padding: 20 }}>
                <div style={{ fontSize: 13, fontWeight: 700, color: th.subtext, marginBottom: 12, textTransform: "uppercase", letterSpacing: "0.3px" }}>🏆 Top Users</div>
                {leaderboard.topUsers.map((u, i) => (
                  <div key={i} style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "8px 0", borderBottom: i < leaderboard.topUsers.length - 1 ? `1px solid ${th.border}` : "none" }}>
                    <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
                      <span style={{ fontSize: 14, fontWeight: 800, color: i === 0 ? "#f59e0b" : i === 1 ? "#94a3b8" : i === 2 ? "#cd7c32" : th.muted, width: 20, textAlign: "center" }}>{i + 1}</span>
                      <span style={{ fontSize: 13, fontWeight: 600, color: th.text }}>{u.displayName}</span>
                    </div>
                    <span style={{ fontSize: 12, fontWeight: 700, color: ORANGE }}>{u.messageCount}</span>
                  </div>
                ))}
              </div>
            )}
            {/* Popular Tools — This Week */}
            {leaderboard.topTools?.length > 0 && (
              <div style={{ background: th.surface, border: `1px solid ${th.border}`, borderRadius: 14, padding: 20 }}>
                <div style={{ fontSize: 13, fontWeight: 700, color: th.subtext, marginBottom: 12, textTransform: "uppercase", letterSpacing: "0.3px" }}>🔧 Popular Tools <span style={{ fontWeight: 400, textTransform: "none" }}>(This Week)</span></div>
                {leaderboard.topTools.map((t, i) => {
                  const plugin = plugins.find(p => p.id === t.pluginId);
                  return (
                    <div key={i} style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "8px 0", borderBottom: i < leaderboard.topTools.length - 1 ? `1px solid ${th.border}` : "none" }}>
                      <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
                        <span style={{ fontSize: 16 }}>{plugin?.emoji || '🔧'}</span>
                        <span style={{ fontSize: 13, fontWeight: 600, color: th.text }}>{plugin?.name || t.pluginId}</span>
                      </div>
                      <span style={{ fontSize: 12, fontWeight: 700, color: ORANGE }}>{t.messageCount}</span>
                    </div>
                  );
                })}
              </div>
            )}
          </div>
          )}
          {/* All Time row */}
          {(leaderboard.topUsersAllTime?.length > 0 || leaderboard.topToolsAllTime?.length > 0) && (
            <div style={{ marginTop: 20 }}>
              <h2 style={{ margin: "0 0 12px", fontSize: 16, fontWeight: 800, color: th.text, letterSpacing: "-0.4px" }}>All Time Leaderboard</h2>
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14 }}>
                {leaderboard.topUsersAllTime?.length > 0 && (
                  <div style={{ background: th.surface, border: `1px solid ${th.border}`, borderRadius: 14, padding: 20 }}>
                    <div style={{ fontSize: 13, fontWeight: 700, color: th.subtext, marginBottom: 12, textTransform: "uppercase", letterSpacing: "0.3px" }}>🏆 Top Users</div>
                    {leaderboard.topUsersAllTime.map((u, i) => (
                      <div key={i} style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "8px 0", borderBottom: i < leaderboard.topUsersAllTime.length - 1 ? `1px solid ${th.border}` : "none" }}>
                        <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
                          <span style={{ fontSize: 14, fontWeight: 800, color: i === 0 ? "#f59e0b" : i === 1 ? "#94a3b8" : i === 2 ? "#cd7c32" : th.muted, width: 20, textAlign: "center" }}>{i + 1}</span>
                          <span style={{ fontSize: 13, fontWeight: 600, color: th.text }}>{u.displayName}</span>
                        </div>
                        <span style={{ fontSize: 12, fontWeight: 700, color: ORANGE }}>{u.messageCount}</span>
                      </div>
                    ))}
                  </div>
                )}
                {leaderboard.topToolsAllTime?.length > 0 && (
                  <div style={{ background: th.surface, border: `1px solid ${th.border}`, borderRadius: 14, padding: 20 }}>
                    <div style={{ fontSize: 13, fontWeight: 700, color: th.subtext, marginBottom: 12, textTransform: "uppercase", letterSpacing: "0.3px" }}>🔧 Popular Tools</div>
                    {leaderboard.topToolsAllTime.map((t, i) => {
                      const plugin = plugins.find(p => p.id === t.pluginId);
                      return (
                        <div key={i} style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "8px 0", borderBottom: i < leaderboard.topToolsAllTime.length - 1 ? `1px solid ${th.border}` : "none" }}>
                          <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
                            <span style={{ fontSize: 16 }}>{plugin?.emoji || '🔧'}</span>
                            <span style={{ fontSize: 13, fontWeight: 600, color: th.text }}>{plugin?.name || t.pluginId}</span>
                          </div>
                          <span style={{ fontSize: 12, fontWeight: 700, color: ORANGE }}>{t.messageCount}</span>
                        </div>
                      );
                    })}
                  </div>
                )}
              </div>
            </div>
          )}
        </div>
      )}

      {/* Milestones */}
      {personalStats?.milestones !== undefined && (
        <div style={{ marginBottom: 28 }}>
          <h2 style={{ margin: "0 0 12px", fontSize: 16, fontWeight: 800, color: th.text, letterSpacing: "-0.4px" }}>Milestones</h2>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(100px, 1fr))", gap: 10 }}>
            {MILESTONE_DEFS.map(m => {
              const earned = personalStats.milestones.find(e => e.id === m.id);
              return (
                <div key={m.id} style={{
                  background: earned ? th.surface : th.bg,
                  border: `1px solid ${earned ? ORANGE + '44' : th.border}`,
                  borderRadius: 10, padding: "12px 10px", textAlign: "center",
                  opacity: earned ? 1 : 0.35,
                  transition: "all 0.3s ease",
                }}>
                  <div style={{ fontSize: 22 }}>{m.emoji}</div>
                  <div style={{ fontSize: 11, fontWeight: 700, color: th.text, marginTop: 4 }}>{m.name}</div>
                  <div style={{ fontSize: 9, color: th.subtext, marginTop: 2 }}>{m.description}</div>
                  {earned && <div style={{ fontSize: 9, color: ORANGE, marginTop: 3, fontWeight: 600 }}>{new Date(earned.earnedAt).toLocaleDateString()}</div>}
                </div>
              );
            })}
          </div>
        </div>
      )}

      {upgradePlan && !isAdmin && (
        <div style={{ background: th.mode === 'light' ? "linear-gradient(135deg, #f0ecf8, #ece8f4)" : "linear-gradient(135deg, #1a1020, #120f1a)", border: `1px solid ${th.mode === 'light' ? "#7c5cbf33" : "#7c5cbf44"}`, borderRadius: 14, padding: "24px 28px", display: "flex", alignItems: "center", justifyContent: "space-between", flexWrap: "wrap", gap: 16 }}>
          <div>
            <div style={{ fontSize: 11, fontWeight: 700, color: "#7c5cbf", textTransform: "uppercase", letterSpacing: "0.5px" }}>⚡ {upgradePlan.name}</div>
            <div style={{ fontSize: 16, fontWeight: 800, color: th.text, marginTop: 6, letterSpacing: "-0.4px" }}>Want to level up?</div>
            <div style={{ fontSize: 13, color: th.subtext, marginTop: 4 }}>{(upgradePlan.features || []).slice(-2).join(" + ")}. ${upgradePlan.price}/{upgradePlan.period}.</div>
          </div>
          <button onClick={() => startCheckout(upgradePlan.id)} style={{ background: "#7c5cbf", border: "none", borderRadius: 10, padding: "11px 20px", fontSize: 13, fontWeight: 700, color: "#fff", cursor: "pointer", fontFamily: font, whiteSpace: "nowrap" }}>Join {upgradePlan.name}</button>
        </div>
      )}
    </div>
  );
}

// ═══════════════════════════════════════════════════════
// TOOLS PAGE
// ═══════════════════════════════════════════════════════

function ToolsPage({ onOpenTool, plugins, user, onToggleFavorite }) {
  const th = useTheme();
  return (
    <div style={{ padding: "32px 32px", maxWidth: 900 }}>
      <h1 style={{ margin: "0 0 6px", fontSize: 24, fontWeight: 800, color: th.text, letterSpacing: "-0.6px" }}>Your Tools</h1>
      <p style={{ margin: "0 0 28px", fontSize: 14, color: th.subtext }}>{TAGLINE}</p>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(240px, 1fr))", gap: 14 }}>
        {plugins.map(t => <ToolCard key={t.id} tool={t} onClick={onOpenTool} isFavorite={user?.favorite_plugins?.includes(t.id) || false} onToggleFavorite={onToggleFavorite} />)}
      </div>
    </div>
  );
}

// ═══════════════════════════════════════════════════════
// USAGE RING — circular progress indicator
// ═══════════════════════════════════════════════════════

function UsageRing({ user, size = 36 }) {
  const _cfg = typeof STUDIO_CONFIG !== 'undefined' ? STUDIO_CONFIG : {};
  const planLimits = { free: (_cfg.rateLimits?.freeTrialMessages) || 10 };
  if (_cfg.plans) _cfg.plans.forEach(p => { planLimits[p.id] = p.monthlyMessageLimit; });

  const limit = planLimits[user?.plan] || 10;
  const used = user?.messages_used || 0;
  const remaining = Math.max(limit - used, 0);
  const pct = Math.min(used / limit, 1);

  // Color: green when >50% remaining, amber 20-50%, red <20%
  const remainingPct = 1 - pct;
  const ringColor = remainingPct > 0.5 ? '#22c55e' : remainingPct > 0.2 ? '#f59e0b' : '#ef4444';

  const r = (size - 4) / 2;
  const circumference = 2 * Math.PI * r;
  const offset = circumference * (1 - pct);

  return (
    <div style={{ display: "flex", alignItems: "center", gap: 8, cursor: "default" }} title={`${remaining} of ${limit} messages remaining`}>
      <svg width={size} height={size} style={{ transform: "rotate(-90deg)" }}>
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke="currentColor" strokeWidth={3} opacity={0.12} />
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke={ringColor} strokeWidth={3}
          strokeDasharray={circumference} strokeDashoffset={offset}
          strokeLinecap="round" style={{ transition: "stroke-dashoffset 0.6s ease, stroke 0.3s ease" }} />
      </svg>
      <div style={{ fontSize: 11, fontWeight: 600, color: ringColor, whiteSpace: "nowrap", lineHeight: 1.2 }}>
        <div>{remaining} left</div>
        <div style={{ fontSize: 10, opacity: 0.7, fontWeight: 500 }}>{used}/{limit}</div>
      </div>
    </div>
  );
}

// ═══════════════════════════════════════════════════════
// CHAT VIEW
// ═══════════════════════════════════════════════════════

function ChatView({ tool, theme, user, onMessageSent, initialConversationId, onConversationLoaded, onPinnedChange, onConversationChange }) {
  const th = useTheme();
  const [messages, setMessages] = useState([{ role: "assistant", content: tool.greeting || `Hi! I'm ${tool.name}. How can I help?` }]);
  const [inputValue, setInputValue] = useState("");
  const [isLoading, setIsLoading] = useState(false);
  const [conversationId, setConversationId] = useState(null);
  const [conversations, setConversations] = useState([]);
  const [showHistory, setShowHistory] = useState(false);
  const [historyLoading, setHistoryLoading] = useState(false);
  const [usageCapModal, setUsageCapModal] = useState(null);
  const [pendingImages, setPendingImages] = useState([]);
  const retryRef = useRef({ count: 0, lastText: "" });
  const messagesEndRef = useRef(null);
  const inputRef = useRef(null);
  const fileInputRef = useRef(null);
  const chatAreaRef = useRef(null);
  const [dragOver, setDragOver] = useState(false);

  useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: "auto" }); }, [messages]);
  useEffect(() => { inputRef.current?.focus(); }, [tool.id]);

  // Auto-load pinned conversation
  useEffect(() => {
    if (initialConversationId) {
      loadConversation(initialConversationId);
      if (onConversationLoaded) onConversationLoaded();
    }
  }, [initialConversationId]);

  // Persist active conversation so refresh can resume it
  useEffect(() => {
    if (onConversationChange) onConversationChange(conversationId);
  }, [conversationId]);

  // Reset when tool changes
  useEffect(() => {
    setMessages([{ role: "assistant", content: tool.greeting || `Hi! I'm ${tool.name}. How can I help?` }]);
    setConversationId(null);
    setPendingImages([]);
    retryRef.current = { count: 0, lastText: "" };
  }, [tool.id]);

  // --- Image handling utilities ---
  const MAX_IMAGE_DIM = 1568;
  const MAX_IMAGES = 3;
  const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];

  const resizeAndEncode = (file) => new Promise((resolve, reject) => {
    if (!ALLOWED_TYPES.includes(file.type)) { reject(new Error('Unsupported image type')); return; }
    if (file.size > 20 * 1024 * 1024) { reject(new Error('Image too large (max 20MB)')); return; }
    const reader = new FileReader();
    reader.onload = () => {
      const img = new Image();
      img.onload = () => {
        let { width, height } = img;
        // Downscale to stay within Anthropic's optimal bounds:
        // - Max 1568px on long edge
        // - Max ~1.15 megapixels total (avoids server-side downscale penalty)
        const MAX_MEGAPIXELS = 1150000;
        if (width > MAX_IMAGE_DIM || height > MAX_IMAGE_DIM) {
          const scale = MAX_IMAGE_DIM / Math.max(width, height);
          width = Math.round(width * scale);
          height = Math.round(height * scale);
        }
        if (width * height > MAX_MEGAPIXELS) {
          const scale = Math.sqrt(MAX_MEGAPIXELS / (width * height));
          width = Math.round(width * scale);
          height = Math.round(height * scale);
        }
        const canvas = document.createElement('canvas');
        canvas.width = width;
        canvas.height = height;
        const ctx = canvas.getContext('2d');
        ctx.imageSmoothingEnabled = true;
        ctx.imageSmoothingQuality = 'high';
        ctx.drawImage(img, 0, 0, width, height);
        // Keep PNG for screenshots (lossless text), high-quality JPEG for photos
        const outputType = (file.type === 'image/png' || file.type === 'image/webp') ? file.type : 'image/jpeg';
        const dataUrl = canvas.toDataURL(outputType, 0.95);
        const base64 = dataUrl.split(',')[1];
        resolve({ base64, mediaType: outputType, preview: dataUrl });
      };
      img.onerror = () => reject(new Error('Failed to load image'));
      img.src = reader.result;
    };
    reader.onerror = () => reject(new Error('Failed to read file'));
    reader.readAsDataURL(file);
  });

  const addImages = async (files) => {
    const remaining = MAX_IMAGES - pendingImages.length;
    if (remaining <= 0) { showToast(`Maximum ${MAX_IMAGES} images per message`, 'info'); return; }
    const toProcess = Array.from(files).slice(0, remaining);
    for (const file of toProcess) {
      try {
        const img = await resizeAndEncode(file);
        setPendingImages(prev => [...prev, img]);
      } catch (err) {
        showToast(err.message, 'error');
      }
    }
  };

  const removeImage = (idx) => {
    setPendingImages(prev => prev.filter((_, i) => i !== idx));
  };

  // Paste handler for images
  const handlePaste = (e) => {
    const items = Array.from(e.clipboardData?.items || []);
    const imageItems = items.filter(item => item.type.startsWith('image/'));
    if (imageItems.length > 0) {
      e.preventDefault();
      const files = imageItems.map(item => item.getAsFile()).filter(Boolean);
      addImages(files);
    }
  };

  // Drag-drop handlers
  const handleDragOver = (e) => { e.preventDefault(); setDragOver(true); };
  const handleDragLeave = (e) => { e.preventDefault(); setDragOver(false); };
  const handleDrop = (e) => {
    e.preventDefault();
    setDragOver(false);
    const files = Array.from(e.dataTransfer.files).filter(f => f.type.startsWith('image/'));
    if (files.length > 0) addImages(files);
  };

  // Load conversation history
  const loadConversations = async () => {
    setHistoryLoading(true);
    try {
      const res = await fetch(`/api/conversations?plugin_id=${tool.id}`, { credentials: 'include' });
      if (res.ok) { const data = await res.json(); setConversations(data.conversations || []); }
    } catch {}
    setHistoryLoading(false);
  };

  const loadConversation = async (convoId) => {
    try {
      const res = await fetch(`/api/conversations/${convoId}`, { credentials: 'include' });
      if (res.ok) {
        const data = await res.json();
        setConversationId(convoId);
        setMessages(data.messages || []);
        setShowHistory(false);
      }
    } catch { showToast('Could not load conversation', 'error'); }
  };

  const deleteConversation = async (convoId) => {
    if (!confirm('Delete this conversation?')) return;
    try {
      await fetch(`/api/conversations/${convoId}`, { method: 'DELETE', credentials: 'include' });
      setConversations(prev => prev.filter(c => c.id !== convoId));
      if (conversationId === convoId) clearChat();
    } catch {}
  };

  const [editingConvoId, setEditingConvoId] = useState(null);
  const [editingTitle, setEditingTitle] = useState("");

  const renameConversation = async (convoId, newTitle) => {
    try {
      await fetch(`/api/conversations/${convoId}`, { method: 'PATCH', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title: newTitle }) });
      setConversations(prev => prev.map(c => c.id === convoId ? { ...c, title: newTitle } : c));
      if (onPinnedChange) onPinnedChange();
    } catch {}
    setEditingConvoId(null);
  };

  const togglePinConversation = async (convoId) => {
    const convo = conversations.find(c => c.id === convoId);
    const newPinned = convo?.pinned ? 0 : 1;
    try {
      await fetch(`/api/conversations/${convoId}`, { method: 'PATCH', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ pinned: !!newPinned }) });
      setConversations(prev => prev.map(c => c.id === convoId ? { ...c, pinned: newPinned } : c));
      // Refresh sidebar pinned chats
      if (onPinnedChange) onPinnedChange();
    } catch {}
  };

  const toggleHistory = () => {
    if (!showHistory) loadConversations();
    setShowHistory(v => !v);
  };

  const copyMessage = (content) => {
    navigator.clipboard.writeText(content).then(() => showToast('Copied!', 'success')).catch(() => {});
  };

  const MAX_RETRIES = 3;

  const sendMessage = async (textOverride) => {
    const text = textOverride || inputValue.trim();
    if (!text || isLoading) return;
    if (!textOverride) { setInputValue(""); if (inputRef.current) inputRef.current.style.height = "auto"; }

    // Capture and clear pending images
    const imagesToSend = textOverride ? [] : [...pendingImages];
    if (!textOverride) setPendingImages([]);

    // Store images in message state for rendering during this session
    const userMsg = { role: "user", content: text };
    if (imagesToSend.length > 0) {
      userMsg.images = imagesToSend.map(img => img.preview);
    }

    const updated = [...messages, userMsg];
    setMessages(updated);
    setIsLoading(true);
    retryRef.current.lastText = text;

    try {
      const response = await fetch('/api/chat', {
        method: 'POST', credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          pluginId: tool.id,
          conversationId,
          message: text,
          ...(imagesToSend.length > 0 ? { images: imagesToSend.map(img => ({ base64: img.base64, mediaType: img.mediaType })) } : {}),
        }),
      });

      if (!response.ok) {
        const err = await response.json().catch(() => ({}));
        if (response.status === 403) {
          setUsageCapModal(err.error || 'You\'ve hit your message limit for this month. Upgrade your plan to keep going.');
        } else {
          showToast(err.error || 'Something went wrong.', 'error');
        }
        setIsLoading(false);
        retryRef.current.count = 0;
        return;
      }

      retryRef.current.count = 0;
      const newConvoId = response.headers.get('X-Conversation-Id');
      if (newConvoId) setConversationId(newConvoId);
      const wasCompacted = response.headers.get('X-Compacted') === 'true';
      if (wasCompacted) {
        setMessages(prev => [...prev, { role: 'compaction', content: 'Conversation summarized to maintain speed and quality' }]);
      }

      // Stream the response
      setIsLoading(false);
      setMessages(prev => [...prev, { role: "assistant", content: "" }]);

      const reader = response.body.getReader();
      const decoder = new TextDecoder();
      let assistantContent = '';
      let sseBuffer = '';

      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        const chunk = decoder.decode(value, { stream: true });
        sseBuffer += chunk;
        const lines = sseBuffer.split('\n');
        sseBuffer = lines.pop() || ''; // Keep last potentially incomplete line
        for (const line of lines) {
          if (!line.startsWith('data: ')) continue;
          const data = line.slice(6);
          if (data === '[DONE]') continue;
          try {
            const event = JSON.parse(data);
            if (event.type === 'content_block_delta' && event.delta?.text) {
              assistantContent += event.delta.text;
              setMessages(prev => {
                const newMsgs = [...prev];
                newMsgs[newMsgs.length - 1] = { role: "assistant", content: assistantContent };
                return newMsgs;
              });
            }
          } catch {}
        }
      }
      onMessageSent?.();
    } catch {
      setIsLoading(false);
      // Auto-retry with exponential backoff
      if (retryRef.current.count < MAX_RETRIES) {
        retryRef.current.count++;
        const delay = Math.pow(2, retryRef.current.count) * 1000;
        showToast(`Connection lost. Retrying in ${delay / 1000}s...`, 'info');
        // Remove the failed user message
        setMessages(prev => prev.slice(0, -1));
        setTimeout(() => sendMessage(text), delay);
      } else {
        setMessages(prev => [...prev, { role: "assistant", content: "Could not connect. Please check your connection and try again." }]);
        retryRef.current.count = 0;
      }
    }
  };

  const clearChat = () => {
    setMessages([{ role: "assistant", content: tool.greeting || `Hi! I'm ${tool.name}. How can I help?` }]);
    setConversationId(null);
    retryRef.current = { count: 0, lastText: "" };
  };

  const handleKeyDown = (e) => {
    if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); sendMessage(); }
  };

  const toolColor = tool.color || ORANGE;
  const getTimeAgo = (ts) => {
    if (!ts) return '';
    const diff = Date.now() - new Date(ts).getTime();
    const mins = Math.floor(diff / 60000);
    if (mins < 60) return `${mins}m ago`;
    const hrs = Math.floor(mins / 60);
    if (hrs < 24) return `${hrs}h ago`;
    return `${Math.floor(hrs / 24)}d ago`;
  };

  return (
    <div style={{ display: "flex", height: "100vh" }}>
      {/* Conversation history sidebar */}
      {showHistory && (
        <div style={{ width: 260, borderRight: `1px solid ${th.border}`, background: th.surface, display: "flex", flexDirection: "column", flexShrink: 0 }}>
          <div style={{ padding: "16px", borderBottom: `1px solid ${th.border}`, display: "flex", alignItems: "center", justifyContent: "space-between" }}>
            <span style={{ fontSize: 13, fontWeight: 700, color: th.text }}>History</span>
            <button onClick={() => { clearChat(); setShowHistory(false); }} style={{ background: ORANGE, border: "none", borderRadius: 6, color: "#fff", padding: "4px 10px", fontSize: 11, fontWeight: 700, cursor: "pointer", fontFamily: font }}>+ New</button>
          </div>
          <div style={{ flex: 1, overflowY: "auto" }}>
            {historyLoading ? (
              <div style={{ padding: 16 }}>
                <div style={{ height: 14, background: th.surface2, borderRadius: 4, marginBottom: 12, animation: "pulse 1.5s infinite" }} />
                <div style={{ height: 14, background: th.surface2, borderRadius: 4, width: "60%", animation: "pulse 1.5s infinite" }} />
              </div>
            ) : conversations.length === 0 ? (
              <div style={{ padding: 16, color: th.muted, fontSize: 13 }}>No conversations yet</div>
            ) : conversations.map(c => (
              <div key={c.id} onClick={() => editingConvoId !== c.id && loadConversation(c.id)}
                style={{
                  padding: "10px 12px", cursor: editingConvoId === c.id ? "default" : "pointer", borderBottom: `1px solid ${th.border}`,
                  background: c.id === conversationId ? ORANGE + "18" : "transparent",
                  transition: "background 0.15s"
                }}>
                {editingConvoId === c.id ? (
                  <input autoFocus value={editingTitle}
                    onChange={e => setEditingTitle(e.target.value)}
                    onKeyDown={e => { if (e.key === 'Enter') renameConversation(c.id, editingTitle); if (e.key === 'Escape') setEditingConvoId(null); }}
                    onBlur={() => renameConversation(c.id, editingTitle)}
                    style={{ width: "100%", background: th.inputBg, border: `1px solid ${ORANGE}44`, borderRadius: 6, padding: "5px 8px", fontSize: 12, color: th.text, fontFamily: font, outline: "none" }}
                  />
                ) : (
                  <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
                    {c.pinned ? <span style={{ fontSize: 11, flexShrink: 0 }} title="Pinned">{"📌"}</span> : null}
                    <div style={{ fontSize: 13, fontWeight: 600, color: th.text, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", flex: 1 }}>
                      {c.title || 'New conversation'}
                    </div>
                  </div>
                )}
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: 5 }}>
                  <span style={{ fontSize: 11, color: th.muted }}>{getTimeAgo(c.updated_at)}</span>
                  <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
                    <span onClick={(e) => { e.stopPropagation(); togglePinConversation(c.id); }} style={{ fontSize: 12, color: c.pinned ? ORANGE : th.muted, cursor: "pointer", opacity: 0.7 }} title={c.pinned ? "Unpin" : "Pin"}>{"📌"}</span>
                    <span onClick={(e) => { e.stopPropagation(); setEditingConvoId(c.id); setEditingTitle(c.title || ''); }} style={{ fontSize: 11, color: th.muted, cursor: "pointer" }} title="Rename">{"✏️"}</span>
                    <span onClick={(e) => { e.stopPropagation(); deleteConversation(c.id); }} style={{ fontSize: 11, color: th.muted, cursor: "pointer" }} title="Delete">{"✕"}</span>
                  </div>
                </div>
              </div>
            ))}
          </div>
        </div>
      )}

      {/* Main chat area */}
      <div ref={chatAreaRef} onDragOver={handleDragOver} onDragLeave={handleDragLeave} onDrop={handleDrop} style={{ display: "flex", flexDirection: "column", flex: 1, position: "relative" }}>
        {/* Drag overlay */}
        {dragOver && (
          <div style={{ position: "absolute", inset: 0, background: "rgba(214, 88, 40, 0.08)", border: "2px dashed " + ORANGE, borderRadius: 12, zIndex: 10, display: "flex", alignItems: "center", justifyContent: "center", pointerEvents: "none" }}>
            <div style={{ fontSize: 16, fontWeight: 700, color: ORANGE }}>Drop image here</div>
          </div>
        )}
        {/* Header */}
        <div style={{ padding: "16px 24px", borderBottom: `1px solid ${th.border}`, display: "flex", alignItems: "center", justifyContent: "space-between", flexShrink: 0 }}>
          <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
            <button onClick={toggleHistory} title="Conversation history" style={{ background: showHistory ? ORANGE + "18" : ORANGE + "0D", border: `1px solid ${ORANGE}44`, borderRadius: 8, color: ORANGE, padding: "8px 16px", fontSize: 13, cursor: "pointer", fontFamily: font, fontWeight: 700, display: "flex", alignItems: "center", gap: 6 }}>{"📋 History"}</button>
            <div style={{ width: 38, height: 38, borderRadius: 10, background: toolColor + "20", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 20 }}>{tool.emoji}</div>
            <div>
              <div style={{ fontWeight: 700, fontSize: 15, color: th.text }}>{tool.name}</div>
              <div style={{ fontSize: 11, color: toolColor, fontWeight: 600 }}>{tool.role}</div>
            </div>
          </div>
          <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
            {user?.role !== 'admin' && <UsageRing user={user} />}
            <button onClick={clearChat} style={{ background: th.surface2, border: `1px solid ${th.border}`, borderRadius: 8, color: th.subtext, padding: "7px 14px", fontSize: 12, cursor: "pointer", fontFamily: font, fontWeight: 600 }}>
              New Chat
            </button>
          </div>
        </div>

        {/* Messages */}
        <div style={{ flex: 1, overflowY: "auto", padding: "24px 24px 8px" }}>
          {messages.map((msg, idx) => {
            if (msg.role === 'compaction') {
              return (
                <div key={idx} className="compaction-notice">
                  🧠 {msg.content}
                </div>
              );
            }
            const isUser = msg.role === "user";
            return (
              <div key={idx} style={{ display: "flex", justifyContent: isUser ? "flex-end" : "flex-start", marginBottom: 16, paddingLeft: isUser ? 60 : 0, paddingRight: isUser ? 0 : 60, position: "relative" }}
                className="chat-msg-row">
                {!isUser && (
                  <div style={{ width: 30, height: 30, borderRadius: 8, background: toolColor + "20", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 15, marginRight: 10, flexShrink: 0, marginTop: 2 }}>
                    {tool.emoji}
                  </div>
                )}
                <div style={{ position: "relative", maxWidth: "85%" }}>
                  <div style={{
                    background: isUser ? (th.mode === 'light' ? "#e8e5e0" : th.surface2) : (th.mode === 'light' ? th.surface : "transparent"),
                    border: isUser ? "none" : `1px solid ${th.border}`,
                    borderRadius: isUser ? "14px 14px 4px 14px" : "14px 14px 14px 4px",
                    padding: "12px 16px", color: th.text, fontSize: 14, lineHeight: 1.65,
                    wordBreak: "break-word", whiteSpace: isUser ? "pre-wrap" : "normal"
                  }}>
                    {isUser ? (
                      <>
                        {/* Render images if present (in-session only) */}
                        {msg.images && msg.images.length > 0 && (
                          <div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginBottom: 8 }}>
                            {msg.images.map((src, i) => (
                              <img key={i} src={src} alt="Shared image" style={{ maxWidth: 200, maxHeight: 200, borderRadius: 8, objectFit: "cover" }} />
                            ))}
                          </div>
                        )}
                        {/* Render placeholder for images loaded from DB */}
                        {!msg.images && /^\[\d+ images? shared\]/.test(msg.content) ? (
                          <div>
                            <div style={{ fontSize: 12, color: th.muted, marginBottom: 4, display: "flex", alignItems: "center", gap: 4 }}>
                              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
                              {msg.content.split('\n')[0]}
                            </div>
                            {msg.content.split('\n').slice(1).join('\n')}
                          </div>
                        ) : msg.content}
                      </>
                    ) : (
                      <div dangerouslySetInnerHTML={{ __html: renderMarkdown(msg.content) }} />
                    )}
                  </div>
                  {/* Copy button on assistant messages */}
                  {!isUser && msg.content && (
                    <button onClick={() => copyMessage(msg.content)}
                      className="copy-btn-hover"
                      style={{
                        position: "absolute", top: 8, right: 8,
                        background: th.surface2, border: `1px solid ${th.border}`, borderRadius: 6,
                        padding: "3px 8px", cursor: "pointer", color: th.subtext,
                        fontSize: 11, fontFamily: font, opacity: 0, transition: "opacity 0.15s"
                      }}>
                      Copy
                    </button>
                  )}
                </div>
              </div>
            );
          })}
          {isLoading && (
            <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 16 }}>
              <div style={{ width: 30, height: 30, borderRadius: 8, background: toolColor + "20", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 15 }}>{tool.emoji}</div>
              <div style={{ display: "flex", gap: 4 }}>
                {[0, 1, 2].map(i => (
                  <div key={i} style={{ width: 6, height: 6, borderRadius: "50%", background: th.muted, animation: `pulse 1.2s ease-in-out ${i * 0.2}s infinite` }} />
                ))}
              </div>
            </div>
          )}
          <div ref={messagesEndRef} />
        </div>

        {/* Input */}
        <div style={{ padding: "16px 24px 20px", borderTop: `1px solid ${th.border}`, flexShrink: 0 }}>
          {/* Image preview strip */}
          {pendingImages.length > 0 && (
            <div style={{ display: "flex", gap: 8, marginBottom: 10, flexWrap: "wrap" }}>
              {pendingImages.map((img, idx) => (
                <div key={idx} style={{ position: "relative", width: 64, height: 64 }}>
                  <img src={img.preview} alt="Upload preview" style={{ width: 64, height: 64, objectFit: "cover", borderRadius: 8, border: `1px solid ${th.border}` }} />
                  <button onClick={() => removeImage(idx)} style={{
                    position: "absolute", top: -6, right: -6, width: 20, height: 20, borderRadius: "50%",
                    background: th.mode === 'light' ? "#666" : "#555", border: "none", color: "#fff", fontSize: 12,
                    cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", lineHeight: 1
                  }}>×</button>
                </div>
              ))}
              {pendingImages.length > 0 && (
                <div style={{ fontSize: 11, color: th.muted, alignSelf: "flex-end", paddingBottom: 4 }}>
                  {pendingImages.length} image{pendingImages.length > 1 ? 's' : ''} · counts as {pendingImages.length * 5} messages
                </div>
              )}
            </div>
          )}
          <div style={{ display: "flex", alignItems: "flex-end", gap: 10, background: th.surface, border: `1px solid ${th.border}`, borderRadius: 12, padding: "10px 14px" }}>
            {/* Hidden file input */}
            <input ref={fileInputRef} type="file" accept="image/jpeg,image/png,image/gif,image/webp" multiple style={{ display: "none" }}
              onChange={e => { if (e.target.files.length) addImages(e.target.files); e.target.value = ''; }} />
            {/* Image upload button */}
            <button onClick={() => fileInputRef.current?.click()} title="Upload image" style={{
              background: "transparent", border: "none", cursor: "pointer", padding: 4, display: "flex", alignItems: "center", justifyContent: "center",
              color: pendingImages.length >= MAX_IMAGES ? th.muted : th.subtext, flexShrink: 0, transition: "color 0.15s"
            }} disabled={pendingImages.length >= MAX_IMAGES}>
              <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                <rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/>
              </svg>
            </button>
            <textarea
              ref={inputRef}
              value={inputValue}
              onChange={e => setInputValue(e.target.value)}
              onKeyDown={handleKeyDown}
              onPaste={handlePaste}
              placeholder={`Message ${tool.name}...`}
              rows={1}
              style={{ flex: 1, background: "transparent", border: "none", outline: "none", color: th.text, fontFamily: font, fontSize: 14, lineHeight: 1.5, resize: "none", maxHeight: 120, minHeight: 24 }}
              onInput={e => { e.target.style.height = "auto"; e.target.style.height = e.target.scrollHeight + "px"; }}
            />
            <button
              onClick={() => sendMessage()}
              disabled={!inputValue.trim() || isLoading}
              style={{
                background: inputValue.trim() && !isLoading ? toolColor : (th.mode === 'light' ? "#ccc" : "#333"),
                border: "none", borderRadius: 8, width: 36, height: 36,
                cursor: inputValue.trim() && !isLoading ? "pointer" : "not-allowed",
                display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0, transition: "all 0.15s"
              }}>
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
                <path d="M22 2L11 13" /><path d="M22 2L15 22L11 13L2 9L22 2Z" />
              </svg>
            </button>
          </div>
          <div style={{ fontSize: 11, color: th.muted, textAlign: "center", marginTop: 8 }}>
            Powered by Claude · {APP_NAME}
          </div>
        </div>
      </div>

      {/* Usage cap modal */}
      {usageCapModal && (
        <div onClick={() => setUsageCapModal(null)} style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.7)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 100 }}>
          <div onClick={e => e.stopPropagation()} style={{ background: th.surface, border: `1px solid ${th.border}`, borderRadius: 16, padding: 32, maxWidth: 420, width: "90%", textAlign: "center" }}>
            <div style={{ fontSize: 40, marginBottom: 12 }}>⚡</div>
            <h3 style={{ margin: "0 0 8px", fontSize: 18, fontWeight: 800, color: th.text }}>Message Limit Reached</h3>
            <p style={{ fontSize: 14, color: SUBTEXT, marginBottom: 24, lineHeight: 1.5 }}>{usageCapModal}</p>
            <Btn fullWidth onClick={() => { setUsageCapModal(null); openUpgradeModal(); }}>Upgrade Plan</Btn>
            <div style={{ marginTop: 12 }}>
              <span onClick={() => setUsageCapModal(null)} style={{ fontSize: 13, color: MUTED, cursor: "pointer" }}>Close</span>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

// ═══════════════════════════════════════════════════════
// SETTINGS PAGE
// ═══════════════════════════════════════════════════════

function SettingsPage({ user, onUpdate }) {
  const th = useTheme();
  const [fullName, setFullName] = useState(user?.full_name || "");
  const [displayName, setDisplayName] = useState(user?.display_name || "");
  const [currentPass, setCurrentPass] = useState("");
  const [newPass, setNewPass] = useState("");
  const [saving, setSaving] = useState(false);
  const [showEmailChange, setShowEmailChange] = useState(false);
  const [newEmail, setNewEmail] = useState("");
  const [emailSending, setEmailSending] = useState(false);

  const planLimits = { free: (_cfg.rateLimits?.freeTrialMessages) || 10 };
  if (_cfg.plans) _cfg.plans.forEach(p => { planLimits[p.id] = p.monthlyMessageLimit; });
  const limit = planLimits[user?.plan] || 10;
  const used = user?.messages_used || 0;
  const pct = Math.min((used / limit) * 100, 100);

  const handleSaveProfile = async () => {
    setSaving(true);
    try {
      const res = await fetch('/api/auth/me', {
        method: 'PATCH', credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ fullName: fullName.trim(), displayName: displayName.trim() || null }),
      });
      if (res.ok) { showToast('Profile updated!', 'success'); onUpdate(); }
      else { const d = await res.json(); showToast(d.error || 'Update failed', 'error'); }
    } catch { showToast('Something went wrong.', 'error'); }
    setSaving(false);
  };

  const handleChangePassword = async () => {
    if (!currentPass || !newPass || newPass.length < 8) { showToast('Password must be at least 8 characters', 'error'); return; }
    setSaving(true);
    try {
      const res = await fetch('/api/auth/me', {
        method: 'PATCH', credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ currentPassword: currentPass, newPassword: newPass }),
      });
      if (res.ok) { showToast('Password updated!', 'success'); setCurrentPass(""); setNewPass(""); }
      else { const d = await res.json(); showToast(d.error || 'Update failed', 'error'); }
    } catch { showToast('Something went wrong.', 'error'); }
    setSaving(false);
  };

  const handleChangeEmail = async () => {
    if (!newEmail || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(newEmail)) { showToast('Please enter a valid email address', 'error'); return; }
    if (newEmail.toLowerCase() === user?.email?.toLowerCase()) { showToast('That\'s already your current email', 'error'); return; }
    setEmailSending(true);
    try {
      const res = await fetch('/api/auth/change-email', {
        method: 'POST', credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ newEmail: newEmail.trim() }),
      });
      const d = await res.json();
      if (res.ok) { showToast('Verification email sent! Check your new inbox.', 'success'); setShowEmailChange(false); setNewEmail(""); }
      else { showToast(d.error || 'Failed to send verification email', 'error'); }
    } catch { showToast('Something went wrong.', 'error'); }
    setEmailSending(false);
  };

  return (
    <div style={{ padding: "32px 32px", maxWidth: 560 }}>
      <h1 style={{ margin: "0 0 28px", fontSize: 24, fontWeight: 800, color: th.text, letterSpacing: "-0.6px" }}>Settings</h1>

      {/* Profile */}
      <div style={{ background: th.surface, border: `1px solid ${th.border}`, borderRadius: 14, padding: 24, marginBottom: 16 }}>
        <h3 style={{ margin: "0 0 16px", fontSize: 15, fontWeight: 700, color: th.text }}>Profile</h3>
        <Input label="Full Name" value={fullName} onChange={e => setFullName(e.target.value)} />
        <div style={{ marginTop: 16 }}>
          <Input label="Display Name" placeholder="Shown on leaderboard (optional)" value={displayName} onChange={e => setDisplayName(e.target.value)} />
          <div style={{ fontSize: 11, color: th.subtext, marginTop: 4 }}>How others see you on the leaderboard. Leave blank to use your first name + last initial.</div>
        </div>
        <div style={{ marginTop: 16 }}>
          <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
            <label style={{ fontSize: 12, fontWeight: 600, color: th.subtext, letterSpacing: "0.3px", textTransform: "uppercase" }}>Email</label>
            <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
              <div style={{ flex: 1, background: th.inputBg || th.bg, border: `1px solid ${th.border}`, borderRadius: 10, padding: "11px 14px", fontSize: 14, color: th.muted }}>{user?.email}</div>
              <button onClick={() => setShowEmailChange(!showEmailChange)} style={{ background: "none", border: `1px solid ${th.border}`, borderRadius: 8, color: th.subtext, padding: "10px 12px", fontSize: 12, cursor: "pointer", fontFamily: _cfg.theme?.fontFamily || "sans-serif", fontWeight: 600, whiteSpace: "nowrap" }}>Change</button>
            </div>
          </div>
          {showEmailChange && (
            <div style={{ marginTop: 12, display: "flex", gap: 8, alignItems: "flex-end" }}>
              <div style={{ flex: 1 }}>
                <Input label="New Email" type="email" placeholder="Enter new email address" value={newEmail} onChange={e => setNewEmail(e.target.value)} />
              </div>
              <Btn onClick={handleChangeEmail} disabled={emailSending} style={{ padding: "10px 14px", fontSize: 12, marginBottom: 0 }}>{emailSending ? "Sending..." : "Send Verification"}</Btn>
            </div>
          )}
        </div>
        <div style={{ marginTop: 16 }}>
          <Btn onClick={handleSaveProfile} disabled={saving} style={{ padding: "8px 16px", fontSize: 13 }}>Save Changes</Btn>
        </div>
      </div>

      {/* Password */}
      <div style={{ background: th.surface, border: `1px solid ${th.border}`, borderRadius: 14, padding: 24, marginBottom: 16 }}>
        <h3 style={{ margin: "0 0 16px", fontSize: 15, fontWeight: 700, color: th.text }}>Change Password</h3>
        <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
          <Input label="Current Password" type="password" placeholder="Enter current password" value={currentPass} onChange={e => setCurrentPass(e.target.value)} />
          <Input label="New Password" type="password" placeholder="Min. 8 characters" value={newPass} onChange={e => setNewPass(e.target.value)} />
        </div>
        <div style={{ marginTop: 16 }}>
          <Btn onClick={handleChangePassword} disabled={saving} style={{ padding: "8px 16px", fontSize: 13 }}>Update Password</Btn>
        </div>
      </div>

      {/* Subscription — hidden for admins */}
      {user?.role !== 'admin' && (
      <div style={{ background: th.surface, border: `1px solid ${th.border}`, borderRadius: 14, padding: 24, marginBottom: 16 }}>
        <h3 style={{ margin: "0 0 16px", fontSize: 15, fontWeight: 700, color: th.text }}>Subscription</h3>
        <div style={{ display: "flex", justifyContent: "space-between", padding: "10px 0", borderBottom: `1px solid ${th.border}` }}>
          <span style={{ fontSize: 14, color: th.text }}>Plan</span>
          <span style={{ fontSize: 14, color: th.subtext, textTransform: "capitalize" }}>{user?.plan || 'free'}</span>
        </div>
        <div style={{ display: "flex", justifyContent: "space-between", padding: "10px 0" }}>
          <span style={{ fontSize: 14, color: th.text }}>Messages Used</span>
          <span style={{ fontSize: 14, color: th.subtext }}>{used} / {limit}</span>
        </div>
        <div style={{ height: 6, background: th.surface2, borderRadius: 3, marginTop: 8, overflow: "hidden" }}>
          <div style={{ height: "100%", width: `${pct}%`, background: pct > 90 ? "#ef4444" : pct > 70 ? "#f59e0b" : ORANGE, borderRadius: 3, transition: "width 0.5s" }} />
        </div>
        <div style={{ marginTop: 16 }}>
          {user?.plan !== 'free' ? (
            <Btn variant="ghost" onClick={openBillingPortal} style={{ padding: "8px 16px", fontSize: 13 }}>Manage Billing</Btn>
          ) : (
            <Btn onClick={openUpgradeModal} style={{ padding: "8px 16px", fontSize: 13 }}>Upgrade Plan</Btn>
          )}
        </div>
      </div>
      )}

      {/* Support */}
      {_cfg.support?.enabled && (
        <div style={{ background: th.surface, border: `1px solid ${th.border}`, borderRadius: 14, padding: 24 }}>
          <h3 style={{ margin: "0 0 8px", fontSize: 15, fontWeight: 700, color: th.text }}>Support</h3>
          <p style={{ fontSize: 13, color: th.subtext, marginBottom: 16 }}>Need help? Submit a support request.</p>
          <a href={_cfg.support.url} target="_blank" rel="noopener noreferrer" style={{ textDecoration: "none" }}>
            <Btn variant="ghost" style={{ padding: "8px 16px", fontSize: 13 }}>Contact Support</Btn>
          </a>
        </div>
      )}
    </div>
  );
}

// ═══════════════════════════════════════════════════════
// PLUGINS EDITOR (Admin)
// ═══════════════════════════════════════════════════════

function toKebabCase(str) {
  return str.toLowerCase().replace(/[^a-z0-9\s-]/g, '').trim().replace(/\s+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '').slice(0, 63);
}

function PluginsEditor({ plugins, onPluginsChange }) {
  // Theme-aware overrides (shadow module-level dark-only constants)
  const th = useTheme();
  const SURFACE = th.surface, SURFACE2 = th.surface2, BORDER = th.border;
  const TEXT = th.text, SUBTEXT = th.subtext, MUTED = th.muted;
  const INPUT_BG = th.inputBg;

  const [editing, setEditing] = useState(null); // plugin id being edited
  const [creatingNew, setCreatingNew] = useState(false);
  const [form, setForm] = useState({});
  const [systemPrompt, setSystemPrompt] = useState("");
  const [knowledge, setKnowledge] = useState("");
  const [loadingPrompt, setLoadingPrompt] = useState(false);
  const [saving, setSaving] = useState(false);
  const [newPluginId, setNewPluginId] = useState("");
  const [idManuallyEdited, setIdManuallyEdited] = useState(false);

  // Auto-generate plugin ID from name
  useEffect(() => {
    if (creatingNew && !idManuallyEdited && form.name) {
      setNewPluginId(toKebabCase(form.name));
    }
  }, [form.name, creatingNew, idManuallyEdited]);

  const resetNewForm = () => {
    setForm({});
    setSystemPrompt('');
    setKnowledge('');
    setNewPluginId('');
    setIdManuallyEdited(false);
  };

  const openEditor = async (plugin) => {
    setEditing(plugin.id);
    setForm({
      name: plugin.name || "",
      emoji: plugin.emoji || "",
      description: plugin.description || "",
      greeting: plugin.greeting || "",
      role: plugin.role || "",
      color: plugin.color || '#6366f1',
      tag: plugin.tag || '',
      model: plugin.model || 'claude-sonnet-4-6',
      maxTokens: plugin.maxTokens || 4000,
    });
    setSystemPrompt("");
    setKnowledge("");
    setLoadingPrompt(true);

    try {
      const res = await fetch(`/api/admin/plugins/${plugin.id}`, { credentials: 'include' });
      if (res.ok) {
        const data = await res.json();
        if (data.override) {
          setForm(prev => ({
            ...prev,
            name: data.override.name || prev.name,
            emoji: data.override.emoji || prev.emoji,
            description: data.override.description || prev.description,
            greeting: data.override.greeting || prev.greeting,
            role: data.override.role || prev.role,
            color: data.override.color || prev.color,
            tag: data.override.tag !== undefined ? data.override.tag : prev.tag,
            model: data.override.model || prev.model,
            maxTokens: data.override.maxTokens || prev.maxTokens,
          }));
        }
        if (data.systemPrompt) setSystemPrompt(data.systemPrompt);
        else {
          // No override — load from disk (skipped gracefully for dynamic plugins)
          const diskRes = await fetch(`/plugins/${plugin.id}/system-prompt.md`);
          if (diskRes.ok) setSystemPrompt(await diskRes.text());
        }
        if (data.knowledge) setKnowledge(data.knowledge);
        else {
          // No override — try loading from disk
          const diskRes = await fetch(`/plugins/${plugin.id}/knowledge.md`);
          if (diskRes.ok) setKnowledge(await diskRes.text());
        }
      }
    } catch { showToast('Failed to load plugin details', 'error'); }
    setLoadingPrompt(false);
  };

  const savePlugin = async () => {
    const plugin = plugins.find(p => p.id === editing);
    const isDynamic = plugin?._dynamic === true;
    setSaving(true);
    try {
      const overrideBody = { name: form.name, emoji: form.emoji, description: form.description, greeting: form.greeting, role: form.role };
      // Preserve dynamic-only fields so they survive a save
      if (isDynamic) {
        Object.assign(overrideBody, { color: form.color, tag: form.tag, model: form.model, maxTokens: form.maxTokens, _dynamic: true });
      }
      const res = await fetch(`/api/admin/plugins/${editing}`, {
        method: 'PUT', credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ override: overrideBody, systemPrompt, knowledge: knowledge || null }),
      });
      if (res.ok) { showToast('Plugin saved — changes apply immediately', 'success'); setEditing(null); }
      else { const d = await res.json().catch(() => ({})); showToast(d.error || 'Save failed', 'error'); }
    } catch { showToast('Something went wrong', 'error'); }
    setSaving(false);
  };

  const resetPlugin = async () => {
    const plugin = plugins.find(p => p.id === editing);
    const isDynamic = plugin?._dynamic === true;
    const confirmMsg = isDynamic
      ? 'Delete this plugin? This cannot be undone — the plugin will be permanently removed.'
      : 'Reset this plugin to its default settings? This removes all admin overrides.';
    if (!confirm(confirmMsg)) return;
    try {
      const res = await fetch(`/api/admin/plugins/${editing}`, { method: 'DELETE', credentials: 'include' });
      if (res.ok) {
        showToast(isDynamic ? 'Plugin deleted' : 'Plugin reset to defaults', 'success');
        setEditing(null);
        if (isDynamic && onPluginsChange) await onPluginsChange();
      } else showToast(isDynamic ? 'Delete failed' : 'Reset failed', 'error');
    } catch { showToast('Something went wrong', 'error'); }
  };

  const createPlugin = async () => {
    if (!newPluginId || !/^[a-z0-9][a-z0-9-]{0,62}$/.test(newPluginId)) {
      showToast('Invalid plugin ID — use lowercase letters, numbers, and hyphens only', 'error');
      return;
    }
    const required = ['name', 'emoji', 'role', 'description', 'greeting'];
    for (const f of required) {
      if (!form[f]?.trim()) { showToast(`${f.charAt(0).toUpperCase() + f.slice(1)} is required`, 'error'); return; }
    }
    if (!systemPrompt.trim()) { showToast('System prompt is required', 'error'); return; }

    setSaving(true);
    try {
      const res = await fetch('/api/admin/plugins', {
        method: 'POST', credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          id: newPluginId,
          manifest: {
            name: form.name, emoji: form.emoji, role: form.role,
            description: form.description, color: form.color || '#6366f1',
            tag: form.tag || '', greeting: form.greeting,
            model: form.model || 'claude-sonnet-4-6',
            maxTokens: parseInt(form.maxTokens) || 4000,
          },
          systemPrompt,
          knowledge: knowledge || '',
        }),
      });
      if (res.ok) {
        showToast('Plugin created — it now appears in your studio!', 'success');
        setCreatingNew(false);
        resetNewForm();
        if (onPluginsChange) await onPluginsChange();
      } else {
        const d = await res.json().catch(() => ({}));
        showToast(d.error || 'Failed to create plugin', 'error');
      }
    } catch { showToast('Something went wrong', 'error'); }
    setSaving(false);
  };

  const fieldStyle = { background: INPUT_BG, border: `1px solid ${BORDER}`, borderRadius: 10, padding: "9px 14px", fontSize: 13, color: TEXT, outline: "none", fontFamily: font, width: "100%" };
  const labelStyle = { fontSize: 12, fontWeight: 600, color: SUBTEXT, marginBottom: 6, display: "block" };

  // New plugin creation form
  if (creatingNew) {
    const tokenCount = Math.round(knowledge.length / 4);
    return (
      <div>
        <button onClick={() => { setCreatingNew(false); resetNewForm(); }} style={{ background: "none", border: "none", color: SUBTEXT, fontSize: 13, cursor: "pointer", fontFamily: font, marginBottom: 16, padding: 0 }}>← Back to plugins</button>
        <h2 style={{ margin: "0 0 24px", fontSize: 20, fontWeight: 800, color: TEXT }}>New Plugin</h2>

        {/* Plugin ID */}
        <div style={{ marginBottom: 20, background: SURFACE2, border: `1px solid ${BORDER}`, borderRadius: 10, padding: 16 }}>
          <label style={labelStyle}>Plugin ID <span style={{ fontWeight: 400, color: MUTED }}>(auto-generated, editable)</span></label>
          <input
            value={newPluginId}
            onChange={e => { setNewPluginId(e.target.value.toLowerCase().replace(/[^a-z0-9-]/g, '')); setIdManuallyEdited(true); }}
            placeholder="my-plugin-name"
            style={fieldStyle}
          />
          <div style={{ fontSize: 11, color: MUTED, marginTop: 6 }}>Lowercase letters, numbers, and hyphens only. Cannot be changed after creation.</div>
        </div>

        {/* Name + Emoji + Role + Tag */}
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16, marginBottom: 20 }}>
          <div>
            <label style={labelStyle}>Name *</label>
            <input value={form.name || ''} onChange={e => setForm({ ...form, name: e.target.value })} placeholder="e.g. Alex" style={fieldStyle} />
          </div>
          <div>
            <label style={labelStyle}>Emoji *</label>
            <input value={form.emoji || ''} onChange={e => setForm({ ...form, emoji: e.target.value })} placeholder="e.g. 🤖" style={fieldStyle} />
          </div>
          <div>
            <label style={labelStyle}>Role / Subtitle *</label>
            <input value={form.role || ''} onChange={e => setForm({ ...form, role: e.target.value })} placeholder="e.g. Content Writer" style={fieldStyle} />
          </div>
          <div>
            <label style={labelStyle}>Tag <span style={{ fontWeight: 400, color: MUTED }}>(optional)</span></label>
            <input value={form.tag || ''} onChange={e => setForm({ ...form, tag: e.target.value })} placeholder="e.g. Writing" style={fieldStyle} />
          </div>
        </div>

        {/* Greeting */}
        <div style={{ marginBottom: 20 }}>
          <label style={labelStyle}>Greeting Message *</label>
          <textarea value={form.greeting || ''} onChange={e => setForm({ ...form, greeting: e.target.value })} rows={3} placeholder="Hey! I'm here to help you..." style={{ ...fieldStyle, resize: "vertical" }} />
        </div>

        {/* Description */}
        <div style={{ marginBottom: 20 }}>
          <label style={labelStyle}>Description *</label>
          <textarea value={form.description || ''} onChange={e => setForm({ ...form, description: e.target.value })} rows={2} placeholder="One-sentence summary of what this assistant does." style={{ ...fieldStyle, resize: "vertical" }} />
        </div>

        {/* Color + Model + maxTokens */}
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 16, marginBottom: 20 }}>
          <div>
            <label style={labelStyle}>Color <span style={{ fontWeight: 400, color: MUTED }}>(hex)</span></label>
            <input value={form.color || '#6366f1'} onChange={e => setForm({ ...form, color: e.target.value })} placeholder="#6366f1" style={fieldStyle} />
          </div>
          <div>
            <label style={labelStyle}>Model</label>
            <select value={form.model || 'claude-sonnet-4-6'} onChange={e => setForm({ ...form, model: e.target.value })} style={{ ...fieldStyle, appearance: "none" }}>
              <option value="claude-sonnet-4-6">Sonnet (default)</option>
              <option value="claude-opus-4-6">Opus (5x cost)</option>
              <option value="claude-haiku-4-5-20251001">Haiku (fast/cheap)</option>
            </select>
          </div>
          <div>
            <label style={labelStyle}>Max Tokens</label>
            <input type="number" value={form.maxTokens || 4000} onChange={e => setForm({ ...form, maxTokens: e.target.value })} min={500} max={8000} style={fieldStyle} />
          </div>
        </div>

        {/* System Prompt */}
        <div style={{ marginBottom: 24 }}>
          <label style={labelStyle}>System Prompt *</label>
          <div style={{ fontSize: 13, color: SUBTEXT, marginBottom: 8 }}>Behavioral instructions — personality, rules, and how the assistant should respond.</div>
          <textarea value={systemPrompt} onChange={e => setSystemPrompt(e.target.value)} rows={18} placeholder="You are a helpful assistant..." style={{ ...fieldStyle, resize: "vertical", lineHeight: 1.6, fontSize: 12, fontFamily: "'Menlo', 'Monaco', 'Courier New', monospace" }} />
        </div>

        {/* Knowledge Base */}
        <div style={{ marginBottom: 24 }}>
          <label style={labelStyle}>Knowledge Base <span style={{ fontWeight: 400, color: MUTED }}>(optional)</span></label>
          <textarea value={knowledge} onChange={e => setKnowledge(e.target.value)} rows={8} placeholder="Paste reference material here — frameworks, key concepts, processes, terminology, etc." style={{ ...fieldStyle, resize: "vertical", lineHeight: 1.6, fontSize: 12, fontFamily: "'Menlo', 'Monaco', 'Courier New', monospace" }} />
          <div style={{ fontSize: 12, color: SUBTEXT, marginTop: 6 }}>
            ~{tokenCount.toLocaleString()} tokens
            {tokenCount >= 10000 && tokenCount < 16000 && <span style={{ color: "#d97706" }}> — Large knowledge base, this will increase API cost per message</span>}
            {tokenCount >= 16000 && <span style={{ color: "#dc2626" }}> — Knowledge base too large. Please distill to key frameworks and reference material.</span>}
          </div>
        </div>

        {/* Actions */}
        <div style={{ display: "flex", gap: 12, alignItems: "center" }}>
          <button onClick={createPlugin} disabled={saving || tokenCount >= 16000} style={{ background: ORANGE, border: "none", borderRadius: 10, padding: "10px 24px", fontSize: 13, fontWeight: 700, color: "#fff", cursor: "pointer", fontFamily: font, opacity: (saving || tokenCount >= 16000) ? 0.6 : 1 }}>
            {saving ? "Creating..." : "Create Plugin"}
          </button>
          <button onClick={() => { setCreatingNew(false); resetNewForm(); }} style={{ background: "none", border: "none", padding: "10px 12px", fontSize: 13, color: MUTED, cursor: "pointer", fontFamily: font }}>Cancel</button>
        </div>
      </div>
    );
  }

  // Editor view
  if (editing) {
    const plugin = plugins.find(p => p.id === editing);
    return (
      <div>
        <button onClick={() => setEditing(null)} style={{ background: "none", border: "none", color: SUBTEXT, fontSize: 13, cursor: "pointer", fontFamily: font, marginBottom: 16, padding: 0 }}>← Back to plugins</button>
        <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 24 }}>
          <span style={{ fontSize: 28 }}>{form.emoji || plugin?.emoji}</span>
          <h2 style={{ margin: 0, fontSize: 20, fontWeight: 800, color: TEXT }}>{form.name || plugin?.name}</h2>
        </div>

        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16, marginBottom: 20 }}>
          <div>
            <label style={labelStyle}>Name</label>
            <input value={form.name} onChange={e => setForm({ ...form, name: e.target.value })} style={fieldStyle} />
          </div>
          <div>
            <label style={labelStyle}>Emoji</label>
            <input value={form.emoji} onChange={e => setForm({ ...form, emoji: e.target.value })} style={fieldStyle} />
          </div>
          <div>
            <label style={labelStyle}>Role / Subtitle</label>
            <input value={form.role} onChange={e => setForm({ ...form, role: e.target.value })} style={fieldStyle} />
          </div>
          <div>
            <label style={labelStyle}>Greeting Message</label>
            <textarea value={form.greeting} onChange={e => setForm({ ...form, greeting: e.target.value })} rows={3} style={{ ...fieldStyle, resize: "vertical" }} />
          </div>
        </div>

        <div style={{ marginBottom: 20 }}>
          <label style={labelStyle}>Description</label>
          <textarea value={form.description} onChange={e => setForm({ ...form, description: e.target.value })} rows={2} style={{ ...fieldStyle, resize: "vertical" }} />
        </div>

        <div style={{ marginBottom: 24 }}>
          <label style={labelStyle}>System Prompt</label>
          <div style={{ fontSize: 13, color: SUBTEXT, marginBottom: 8 }}>Behavioral instructions — personality, rules, and how the assistant should respond. Changes apply immediately.</div>
          {loadingPrompt ? (
            <div style={{ padding: 24, textAlign: "center", color: SUBTEXT }}>Loading prompt...</div>
          ) : (
            <textarea
              value={systemPrompt}
              onChange={e => setSystemPrompt(e.target.value)}
              rows={18}
              style={{ ...fieldStyle, resize: "vertical", lineHeight: 1.6, fontSize: 12, fontFamily: "'Menlo', 'Monaco', 'Courier New', monospace" }}
            />
          )}
        </div>

        <div style={{ marginBottom: 24 }}>
          <label style={labelStyle}>Knowledge Base</label>
          <div style={{ fontSize: 13, color: SUBTEXT, marginBottom: 8, lineHeight: 1.6 }}>
            <strong style={{ color: TEXT }}>What to paste:</strong> Reference material your assistant needs to answer questions — frameworks, processes, terminology, SOPs, brand guides, etc. Plain text or markdown formatting both work.
            <br /><br />
            <strong style={{ color: TEXT }}>Size limit:</strong> ~25 pages of text maximum (~16,000 tokens). This is plenty for most reference material.
            <br /><br />
            <strong style={{ color: TEXT }}>If your source material is short (under 25 pages):</strong> You can copy-paste directly from Google Docs, Word, Notion, or any text source. No conversion needed.
            <br /><br />
            <strong style={{ color: TEXT }}>If your source material is long (books, full courses, 50+ pages):</strong> Do NOT paste the entire document. Instead, distill it down to the key frameworks, definitions, step-by-step processes, and reference points your assistant actually needs. Think of it as a cheat sheet, not the full textbook.
            <br /><br />
            <span style={{ fontSize: 12, color: MUTED }}>
              Tip: If you have a PDF or Word doc you'd like to convert to clean text first, use{" "}
              <a href="https://pandoc.org/try/" target="_blank" rel="noopener" style={{ color: ORANGE }}>this free converter →</a>
            </span>
          </div>
          {loadingPrompt ? (
            <div style={{ padding: 24, textAlign: "center", color: SUBTEXT }}>Loading...</div>
          ) : (
            <>
              <textarea
                value={knowledge}
                onChange={e => setKnowledge(e.target.value)}
                rows={12}
                placeholder="Paste your reference material here — frameworks, key concepts, processes, terminology, etc. Leave empty if this assistant doesn't need a knowledge base."
                style={{ ...fieldStyle, resize: "vertical", lineHeight: 1.6, fontSize: 12, fontFamily: "'Menlo', 'Monaco', 'Courier New', monospace" }}
              />
              <div style={{ fontSize: 12, color: SUBTEXT, marginTop: 6 }}>
                ~{Math.round(knowledge.length / 4).toLocaleString()} tokens
                {Math.round(knowledge.length / 4) >= 10000 && Math.round(knowledge.length / 4) < 16000 && (
                  <span style={{ color: "#d97706" }}> — Large knowledge base, this will increase API cost per message</span>
                )}
                {Math.round(knowledge.length / 4) >= 16000 && (
                  <span style={{ color: "#dc2626" }}> — Knowledge base too large. Please distill to key frameworks and reference material.</span>
                )}
              </div>
            </>
          )}
        </div>

        <div style={{ display: "flex", gap: 12, alignItems: "center" }}>
          <button onClick={savePlugin} disabled={saving || Math.round(knowledge.length / 4) >= 16000} style={{ background: ORANGE, border: "none", borderRadius: 10, padding: "10px 24px", fontSize: 13, fontWeight: 700, color: "#fff", cursor: "pointer", fontFamily: font, opacity: (saving || Math.round(knowledge.length / 4) >= 16000) ? 0.6 : 1 }}>{saving ? "Saving..." : "Save Changes"}</button>
          {plugin?._dynamic
            ? <button onClick={resetPlugin} style={{ background: "none", border: "1px solid #dc2626", borderRadius: 10, padding: "10px 18px", fontSize: 13, fontWeight: 600, color: "#dc2626", cursor: "pointer", fontFamily: font }}>Delete Plugin</button>
            : <button onClick={resetPlugin} style={{ background: "none", border: `1px solid ${BORDER}`, borderRadius: 10, padding: "10px 18px", fontSize: 13, fontWeight: 600, color: SUBTEXT, cursor: "pointer", fontFamily: font }}>Reset to Default</button>
          }
          <button onClick={() => setEditing(null)} style={{ background: "none", border: "none", padding: "10px 12px", fontSize: 13, color: MUTED, cursor: "pointer", fontFamily: font }}>Cancel</button>
        </div>
      </div>
    );
  }

  // Plugin cards grid
  return (
    <div>
      <div style={{ display: "flex", justifyContent: "flex-end", marginBottom: 16 }}>
        <button onClick={() => { resetNewForm(); setCreatingNew(true); }} style={{ background: ORANGE, border: "none", borderRadius: 10, padding: "10px 20px", fontSize: 13, fontWeight: 700, color: "#fff", cursor: "pointer", fontFamily: font }}>+ Add Plugin</button>
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))", gap: 16 }}>
        {plugins.map(p => (
          <div key={p.id} onClick={() => openEditor(p)} style={{ background: SURFACE, border: `1px solid ${BORDER}`, borderRadius: 14, padding: 20, cursor: "pointer", transition: "border-color 0.15s" }}
            onMouseEnter={e => e.currentTarget.style.borderColor = ORANGE}
            onMouseLeave={e => e.currentTarget.style.borderColor = BORDER}
          >
            <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 8 }}>
              <span style={{ fontSize: 24 }}>{p.emoji}</span>
              <div>
                <div style={{ fontWeight: 700, fontSize: 14, color: TEXT }}>{p.name}</div>
                <div style={{ fontSize: 12, color: SUBTEXT }}>{p.role}</div>
              </div>
            </div>
            <div style={{ fontSize: 13, color: SUBTEXT, marginBottom: 12 }}>{p.description}</div>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
              <div style={{ fontSize: 11, color: ORANGE, fontWeight: 600 }}>Click to edit →</div>
              {p._dynamic && <div style={{ fontSize: 10, color: MUTED, background: SURFACE2, border: `1px solid ${BORDER}`, borderRadius: 4, padding: "2px 6px" }}>admin-created</div>}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

// ═══════════════════════════════════════════════════════
// TRAINING — Video Utilities
// ═══════════════════════════════════════════════════════

function generateVideoEmbed(url) {
  const wrap = src => `<div class="video-embed" contenteditable="false"><iframe src="${src}" frameborder="0" allowfullscreen></iframe></div>`;
  const yt = url.match(/(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([a-zA-Z0-9_-]{11})/);
  if (yt) return wrap(`https://www.youtube.com/embed/${yt[1]}`);
  const loom = url.match(/loom\.com\/(?:share|embed)\/([a-zA-Z0-9]+)/);
  if (loom) return wrap(`https://www.loom.com/embed/${loom[1]}`);
  const vimeo = url.match(/vimeo\.com\/(\d+)/);
  if (vimeo) return wrap(`https://player.vimeo.com/video/${vimeo[1]}`);
  const tella = url.match(/tella\.tv\/video\/([a-zA-Z0-9_-]+)/);
  if (tella) return wrap(`https://www.tella.tv/video/${tella[1]}/embed`);
  return null;
}

function hoistVideos(html) {
  if (!html) return html;
  const embeds = [];
  const rest = html.replace(/<div class="video-embed"[^>]*>[\s\S]*?<\/iframe><\/div>/g, match => {
    embeds.push(match);
    return '';
  });
  return embeds.join('') + rest;
}

// ═══════════════════════════════════════════════════════
// TRAINING — Rich Text Editor
// ═══════════════════════════════════════════════════════

function RichTextEditor({ value, onChange }) {
  const editorRef = useRef(null);
  const th = useTheme();

  useEffect(() => {
    if (editorRef.current) editorRef.current.innerHTML = value || '';
  }, []);

  function handleInput() {
    if (editorRef.current) onChange(editorRef.current.innerHTML);
  }

  function fmt(command) {
    if (!editorRef.current) return;
    editorRef.current.focus();
    document.execCommand(command, false, null);
    if (editorRef.current) onChange(editorRef.current.innerHTML);
  }

  function insertVideo() {
    const url = prompt('Paste video URL\n\nSupported: YouTube, Loom, Vimeo, Tella');
    if (!url) return;
    const html = generateVideoEmbed(url.trim());
    if (!html) { alert('Unrecognized video URL. Paste a link from YouTube, Loom, Vimeo, or Tella.'); return; }
    const el = editorRef.current;
    if (!el) return;
    el.focus();
    document.execCommand('insertHTML', false, '<p><br></p>' + html + '<p><br></p>');
    const lastP = el.lastElementChild;
    if (lastP && lastP.tagName === 'P') {
      const range = document.createRange();
      const sel = window.getSelection();
      range.setStart(lastP, 0);
      range.collapse(true);
      sel.removeAllRanges();
      sel.addRange(range);
    }
    onChange(el.innerHTML);
  }

  const btnStyle = {
    padding: '4px 10px', fontSize: 13, border: `1px solid ${th.border}`,
    borderRadius: 5, background: th.surface, color: th.text,
    cursor: 'pointer', lineHeight: 1.4, fontFamily: font
  };

  return (
    <div style={{ border: `1px solid ${th.border}`, borderRadius: 14, overflow: 'hidden' }}>
      <div style={{ display: 'flex', gap: 4, padding: '8px 12px', borderBottom: `1px solid ${th.border}`, background: th.surface2, flexWrap: 'wrap', alignItems: 'center' }}>
        <button type="button" onMouseDown={e => { e.preventDefault(); fmt('bold'); }} style={{ ...btnStyle, fontWeight: 700 }} title="Bold">B</button>
        <button type="button" onMouseDown={e => { e.preventDefault(); fmt('italic'); }} style={{ ...btnStyle, fontStyle: 'italic' }} title="Italic">I</button>
        <button type="button" onMouseDown={e => { e.preventDefault(); fmt('underline'); }} style={{ ...btnStyle, textDecoration: 'underline' }} title="Underline">U</button>
        <div style={{ width: 1, height: 18, background: th.border, margin: '0 4px', flexShrink: 0 }} />
        <button type="button" onMouseDown={e => { e.preventDefault(); fmt('insertUnorderedList'); }} style={btnStyle} title="Bullet list">• List</button>
        <button type="button" onMouseDown={e => { e.preventDefault(); insertVideo(); }} style={btnStyle} title="Embed video">📹 Add Video</button>
      </div>
      <div
        ref={editorRef}
        contentEditable={true}
        suppressContentEditableWarning={true}
        onInput={handleInput}
        style={{ minHeight: 320, padding: 16, paddingBottom: 48, outline: 'none', fontSize: 14, lineHeight: 1.75, color: th.text, background: th.bg }}
      />
    </div>
  );
}

// ═══════════════════════════════════════════════════════
// TRAINING PAGE
// ═══════════════════════════════════════════════════════

function TrainingPage({ user, theme }) {
  const th = useTheme();
  const [modules, setModules] = useState(null);
  const [expanded, setExpanded] = useState({});
  const [activeLesson, setActiveLesson] = useState(null);
  const [editingLessonId, setEditingLessonId] = useState(null);
  const [lessonDraft, setLessonDraft] = useState('');
  const [editingTitleId, setEditingTitleId] = useState(null);
  const [titleDraft, setTitleDraft] = useState('');
  const [saving, setSaving] = useState(false);
  const [loadingLessonId, setLoadingLessonId] = useState(null);
  const isAdmin = user?.role === 'admin';

  useEffect(() => {
    fetch('/api/curriculum/modules', { credentials: 'include' })
      .then(r => r.json())
      .then(data => setModules(data.modules || []))
      .catch(() => setModules([]));
  }, []);

  // ── Admin actions ──

  async function createModule() {
    const title = prompt('Module title (e.g. "Getting Started"):');
    if (!title?.trim()) return;
    try {
      const res = await fetch('/api/curriculum/admin/modules', {
        method: 'POST', credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ title }),
      });
      const mod = await res.json();
      if (!res.ok) { showToast(mod.error || 'Failed', 'error'); return; }
      setModules(prev => [...(prev || []), { ...mod, lessons: [] }]);
      showToast('Module created!', 'success');
    } catch { showToast('Something went wrong', 'error'); }
  }

  async function saveModuleTitle(moduleId) {
    if (!titleDraft.trim()) return;
    try {
      const res = await fetch(`/api/curriculum/admin/modules/${moduleId}`, {
        method: 'PUT', credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ title: titleDraft }),
      });
      if (!res.ok) { showToast('Failed to save', 'error'); return; }
      setModules(prev => (prev || []).map(m => m.id === moduleId ? { ...m, title: titleDraft } : m));
      setEditingTitleId(null);
      showToast('Saved!', 'success');
    } catch { showToast('Something went wrong', 'error'); }
  }

  async function toggleModulePublished(mod) {
    const pub = !mod.published;
    try {
      const res = await fetch(`/api/curriculum/admin/modules/${mod.id}`, {
        method: 'PUT', credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ published: pub }),
      });
      if (!res.ok) { showToast('Failed', 'error'); return; }
      setModules(prev => (prev || []).map(m => m.id === mod.id ? { ...m, published: pub } : m));
      showToast(pub ? 'Module published!' : 'Module set to draft.', 'success');
    } catch { showToast('Something went wrong', 'error'); }
  }

  async function deleteModule(moduleId) {
    if (!confirm('Delete this module and all its lessons?')) return;
    try {
      const res = await fetch(`/api/curriculum/admin/modules/${moduleId}`, { method: 'DELETE', credentials: 'include' });
      if (!res.ok) { showToast('Failed', 'error'); return; }
      setModules(prev => (prev || []).filter(m => m.id !== moduleId));
      showToast('Module deleted.', 'success');
    } catch { showToast('Something went wrong', 'error'); }
  }

  async function addLesson(moduleId) {
    const title = prompt('Lesson title:');
    if (!title?.trim()) return;
    try {
      const res = await fetch(`/api/curriculum/admin/modules/${moduleId}/lessons`, {
        method: 'POST', credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ title }),
      });
      const lesson = await res.json();
      if (!res.ok) { showToast(lesson.error || 'Failed', 'error'); return; }
      setModules(prev => (prev || []).map(m => m.id === moduleId ? { ...m, lessons: [...m.lessons, lesson] } : m));
      showToast('Lesson added!', 'success');
    } catch { showToast('Something went wrong', 'error'); }
  }

  async function saveLessonTitle(lesson) {
    if (!titleDraft.trim()) return;
    try {
      const res = await fetch(`/api/curriculum/admin/lessons/${lesson.id}`, {
        method: 'PUT', credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ title: titleDraft }),
      });
      if (!res.ok) { showToast('Failed to save', 'error'); return; }
      setModules(prev => (prev || []).map(m => m.id === lesson.module_id
        ? { ...m, lessons: m.lessons.map(l => l.id === lesson.id ? { ...l, title: titleDraft } : l) }
        : m));
      setEditingTitleId(null);
      showToast('Saved!', 'success');
    } catch { showToast('Something went wrong', 'error'); }
  }

  async function toggleLessonPublished(lesson) {
    const pub = !lesson.published;
    try {
      const res = await fetch(`/api/curriculum/admin/lessons/${lesson.id}`, {
        method: 'PUT', credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ published: pub }),
      });
      if (!res.ok) { showToast('Failed', 'error'); return; }
      setModules(prev => (prev || []).map(m => m.id === lesson.module_id
        ? { ...m, lessons: m.lessons.map(l => l.id === lesson.id ? { ...l, published: pub } : l) }
        : m));
      if (activeLesson?.id === lesson.id) setActiveLesson(prev => prev ? { ...prev, published: pub } : prev);
      showToast(pub ? 'Published!' : 'Set to draft.', 'success');
    } catch { showToast('Something went wrong', 'error'); }
  }

  async function deleteLesson(lesson) {
    if (!confirm(`Delete lesson "${lesson.title}"?`)) return;
    try {
      const res = await fetch(`/api/curriculum/admin/lessons/${lesson.id}`, { method: 'DELETE', credentials: 'include' });
      if (!res.ok) { showToast('Failed', 'error'); return; }
      setModules(prev => (prev || []).map(m => m.id === lesson.module_id
        ? { ...m, lessons: m.lessons.filter(l => l.id !== lesson.id) }
        : m));
      showToast('Lesson deleted.', 'success');
    } catch { showToast('Something went wrong', 'error'); }
  }

  async function openLesson(lesson) {
    setLoadingLessonId(lesson.id);
    try {
      const res = await fetch(`/api/curriculum/modules/${lesson.module_id}/lessons/${lesson.id}`, { credentials: 'include' });
      const data = await res.json();
      if (res.ok) setActiveLesson(data.lesson);
      else showToast(data.error || 'Failed to load lesson', 'error');
    } catch { showToast('Something went wrong', 'error'); }
    finally { setLoadingLessonId(null); }
  }

  function startEditingLesson(lesson) {
    setEditingLessonId(lesson.id);
    setLessonDraft(lesson.content || '');
  }

  async function saveLessonContent(published) {
    setSaving(true);
    try {
      const res = await fetch(`/api/curriculum/admin/lessons/${editingLessonId}`, {
        method: 'PUT', credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ content: lessonDraft, published }),
      });
      if (!res.ok) { showToast('Failed to save', 'error'); return; }
      const updated = { ...activeLesson, content: lessonDraft, published };
      setActiveLesson(updated);
      setModules(prev => (prev || []).map(m => ({
        ...m,
        lessons: m.lessons.map(l => l.id === editingLessonId ? { ...l, published } : l),
      })));
      setEditingLessonId(null);
      showToast(published ? 'Saved & published!' : 'Saved as draft.', 'success');
    } catch { showToast('Something went wrong', 'error'); }
    finally { setSaving(false); }
  }

  // ── Shared styles ──

  const btnPrimary = {
    background: ORANGE, color: '#fff', border: 'none', borderRadius: 8,
    padding: '8px 16px', fontSize: 13, fontWeight: 600, cursor: 'pointer', fontFamily: font
  };
  const btnSecondary = {
    background: 'none', color: th.subtext, border: `1px solid ${th.border}`, borderRadius: 8,
    padding: '8px 16px', fontSize: 13, fontWeight: 600, cursor: 'pointer', fontFamily: font
  };
  const btnGhost = {
    background: 'none', border: 'none', padding: '4px 8px', fontSize: 12,
    cursor: 'pointer', fontFamily: font, fontWeight: 600
  };
  const draftBadge = {
    fontSize: 11, color: '#92400e', background: '#fef3c7', padding: '2px 7px',
    borderRadius: 10, fontWeight: 600, flexShrink: 0
  };
  const publishedBadge = {
    fontSize: 12, padding: '3px 9px', borderRadius: 20, fontWeight: 600,
    background: '#dcfce7', color: '#166534'
  };

  // ── Lesson detail view ──

  if (activeLesson) {
    const lessonMod = (modules || []).find(m => m.id === activeLesson.module_id);
    const isEditing = editingLessonId === activeLesson.id;

    return (
      <div style={{ padding: '40px 48px', width: '100%', overflowY: 'auto', flex: 1, boxSizing: 'border-box' }}>
        <button onClick={() => { setActiveLesson(null); setEditingLessonId(null); }} style={{ ...btnSecondary, marginBottom: 20 }}>
          ← Back to Training
        </button>

        <div style={{ fontSize: 13, color: th.subtext, marginBottom: 6 }}>{lessonMod?.title || ''}</div>
        <h2 style={{ fontSize: 28, fontWeight: 800, marginBottom: 20, letterSpacing: '-0.03em', color: th.text }}>{activeLesson.title}</h2>

        {isEditing ? (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
            <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8, flexWrap: 'wrap' }}>
              <button onClick={() => setEditingLessonId(null)} disabled={saving} style={btnSecondary}>Cancel</button>
              <button onClick={() => saveLessonContent(false)} disabled={saving} style={btnSecondary}>{saving ? 'Saving...' : 'Save as Draft'}</button>
              <button onClick={() => saveLessonContent(true)} disabled={saving} style={btnPrimary}>{saving ? 'Publishing...' : 'Save & Publish'}</button>
            </div>
            <RichTextEditor value={lessonDraft} onChange={setLessonDraft} />
          </div>
        ) : (
          <div>
            {isAdmin && (
              <div style={{ display: 'flex', gap: 8, marginBottom: 20, alignItems: 'center', flexWrap: 'wrap' }}>
                <button onClick={() => startEditingLesson(activeLesson)} style={btnSecondary}>✏️ Edit Lesson</button>
                <button onClick={() => toggleLessonPublished(activeLesson)} style={{ ...btnGhost, color: th.subtext }}>{activeLesson.published ? 'Unpublish' : 'Publish'}</button>
                <span style={activeLesson.published ? publishedBadge : draftBadge}>
                  {activeLesson.published ? '✓ Published' : 'Draft'}
                </span>
              </div>
            )}
            {activeLesson.content
              ? <div className="content-view" dangerouslySetInnerHTML={{ __html: hoistVideos(activeLesson.content) }} />
              : <div style={{ color: th.subtext, fontSize: 14, fontStyle: 'italic', marginTop: 20 }}>
                  {isAdmin ? 'No content yet — click "✏️ Edit Lesson" to add text or a video.' : 'Content coming soon.'}
                </div>
            }
          </div>
        )}
      </div>
    );
  }

  // ── Modules list view ──

  return (
    <div style={{ padding: '40px 48px', width: '100%', overflowY: 'auto', flex: 1, boxSizing: 'border-box' }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 24, flexWrap: 'wrap', gap: 12 }}>
        <h2 style={{ fontSize: 28, fontWeight: 800, letterSpacing: '-0.03em', color: th.text, margin: 0 }}>Training</h2>
        {isAdmin && <button onClick={createModule} style={btnPrimary}>+ Add Module</button>}
      </div>

      {!modules
        ? <div style={{ color: th.subtext, padding: '48px 0', textAlign: 'center' }}>Loading...</div>
        : modules.length === 0
          ? <div style={{ color: th.subtext, fontStyle: 'italic', padding: '20px 0' }}>
              {isAdmin ? 'No training content yet — click "+ Add Module" to get started.' : 'No training content available yet.'}
            </div>
          : <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
              {modules.map(mod => {
                const isExpanded = !!expanded[mod.id];
                return (
                  <div key={mod.id} style={{
                    background: `linear-gradient(135deg, ${th.surface} 0%, ${th.surface2} 100%)`,
                    border: `1px solid ${isExpanded ? ORANGE + '44' : th.border}`,
                    borderRadius: 14, overflow: 'hidden', transition: 'all 0.2s ease',
                    boxShadow: isExpanded ? `0 0 0 2px ${ORANGE}26, 0 4px 12px rgba(0,0,0,0.15)` : '0 1px 3px rgba(0,0,0,0.2)'
                  }}>
                    {/* Module header */}
                    <div
                      onClick={() => setExpanded(prev => ({ ...prev, [mod.id]: !prev[mod.id] }))}
                      style={{
                        display: 'flex', alignItems: 'center', padding: '16px 20px', cursor: 'pointer',
                        gap: 12, userSelect: 'none'
                      }}
                    >
                      {editingTitleId === `mod-${mod.id}` ? (
                        <div style={{ display: 'flex', gap: 8, flex: 1 }} onClick={e => e.stopPropagation()}>
                          <input
                            value={titleDraft}
                            onChange={e => setTitleDraft(e.target.value)}
                            onKeyDown={e => { if (e.key === 'Enter') saveModuleTitle(mod.id); if (e.key === 'Escape') setEditingTitleId(null); }}
                            autoFocus
                            style={{
                              flex: 1, fontSize: 14, background: th.inputBg || th.bg, border: `1px solid ${th.border}`,
                              borderRadius: 8, padding: '6px 10px', color: th.text, outline: 'none', fontFamily: font
                            }}
                          />
                          <button onClick={e => { e.stopPropagation(); saveModuleTitle(mod.id); }} style={btnPrimary}>Save</button>
                          <button onClick={e => { e.stopPropagation(); setEditingTitleId(null); }} style={btnSecondary}>Cancel</button>
                        </div>
                      ) : (
                        <div style={{ flex: 1, fontSize: 17, fontWeight: 700, letterSpacing: '-0.02em', color: th.text }}>{mod.title}</div>
                      )}
                      <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexShrink: 0 }}>
                        {!mod.published && isAdmin && <span style={draftBadge}>Draft</span>}
                        <span style={{ fontSize: 12, color: th.subtext, transition: 'transform 0.15s', transform: isExpanded ? 'rotate(90deg)' : 'rotate(0deg)', display: 'inline-block' }}>▶</span>
                      </div>
                    </div>

                    {/* Expanded content */}
                    {isExpanded && (
                      <div style={{ padding: '0 20px 16px', display: 'flex', flexDirection: 'column', gap: 4 }}>
                        {mod.lessons.length === 0
                          ? <div style={{ color: th.subtext, fontSize: 13, padding: '8px 4px', fontStyle: 'italic' }}>
                              {isAdmin ? 'No lessons yet — click "+ Add Lesson" below.' : 'No lessons yet.'}
                            </div>
                          : mod.lessons.map(lesson => (
                              <div key={lesson.id} style={{
                                display: 'flex', alignItems: 'center', gap: 8, padding: '10px 12px',
                                borderRadius: 10, cursor: 'pointer', transition: 'background 0.1s',
                                background: 'transparent',
                              }}
                              onMouseEnter={e => e.currentTarget.style.background = th.surface2}
                              onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
                              >
                                {editingTitleId === `lesson-${lesson.id}` ? (
                                  <div style={{ display: 'flex', gap: 8, flex: 1 }} onClick={e => e.stopPropagation()}>
                                    <input
                                      value={titleDraft}
                                      onChange={e => setTitleDraft(e.target.value)}
                                      onKeyDown={e => { if (e.key === 'Enter') saveLessonTitle(lesson); if (e.key === 'Escape') setEditingTitleId(null); }}
                                      autoFocus
                                      style={{
                                        flex: 1, fontSize: 13, background: th.inputBg || th.bg, border: `1px solid ${th.border}`,
                                        borderRadius: 8, padding: '5px 10px', color: th.text, outline: 'none', fontFamily: font
                                      }}
                                    />
                                    <button onClick={e => { e.stopPropagation(); saveLessonTitle(lesson); }} style={{ ...btnPrimary, padding: '5px 12px' }}>Save</button>
                                    <button onClick={e => { e.stopPropagation(); setEditingTitleId(null); }} style={{ ...btnSecondary, padding: '5px 12px' }}>✕</button>
                                  </div>
                                ) : (
                                  <>
                                    <span
                                      style={{ flex: 1, fontSize: 14, fontWeight: 500, color: th.text }}
                                      onClick={e => { e.stopPropagation(); if (loadingLessonId !== lesson.id) openLesson(lesson); }}
                                    >
                                      {loadingLessonId === lesson.id ? 'Loading...' : lesson.title}
                                    </span>
                                    {!lesson.published && isAdmin && <span style={draftBadge}>Draft</span>}
                                    {isAdmin ? (
                                      <div style={{ display: 'flex', gap: 4, flexShrink: 0, alignItems: 'center' }} onClick={e => e.stopPropagation()}>
                                        <button onClick={() => toggleLessonPublished(lesson)} style={{ ...btnGhost, color: lesson.published ? th.subtext : ORANGE }} title={lesson.published ? 'Unpublish' : 'Publish'}>
                                          {lesson.published ? 'Unpublish' : 'Publish'}
                                        </button>
                                        <button onClick={() => { setEditingTitleId(`lesson-${lesson.id}`); setTitleDraft(lesson.title); }} style={{ ...btnGhost, color: th.subtext }} title="Rename">✎</button>
                                        <button onClick={() => deleteLesson(lesson)} style={{ ...btnGhost, color: '#ef4444' }} title="Delete">✕</button>
                                      </div>
                                    ) : (
                                      <span style={{ color: th.subtext, fontSize: 14 }}>→</span>
                                    )}
                                  </>
                                )}
                              </div>
                            ))
                        }

                        {/* Admin footer: add lesson + module actions */}
                        {isAdmin && (
                          <div style={{ display: 'flex', gap: 8, padding: '10px 4px', borderTop: `1px dashed ${th.border}`, marginTop: 4, flexWrap: 'wrap', alignItems: 'center' }}
                            onClick={e => e.stopPropagation()}
                          >
                            <button onClick={() => addLesson(mod.id)} style={btnSecondary}>+ Add Lesson</button>
                            <button onClick={() => { setEditingTitleId(`mod-${mod.id}`); setTitleDraft(mod.title); }} style={{ ...btnGhost, color: th.subtext }}>✎ Rename</button>
                            <button onClick={() => toggleModulePublished(mod)} style={{ ...btnGhost, color: mod.published ? th.subtext : ORANGE }}>
                              {mod.published ? 'Unpublish' : 'Publish'}
                            </button>
                            <button onClick={() => deleteModule(mod.id)} style={{ ...btnGhost, color: '#ef4444', marginLeft: 'auto' }}>Delete</button>
                          </div>
                        )}
                      </div>
                    )}
                  </div>
                );
              })}
            </div>
      }
    </div>
  );
}

// ═══════════════════════════════════════════════════════
// ADMIN PANEL
// ═══════════════════════════════════════════════════════

function AdminPanel({ plugins, theme, onPluginsChange }) {
  // Theme-aware overrides (shadow module-level dark-only constants)
  const th = useTheme();
  const SURFACE = th.surface, SURFACE2 = th.surface2, BORDER = th.border;
  const TEXT = th.text, SUBTEXT = th.subtext, MUTED = th.muted;
  const INPUT_BG = th.inputBg;

  const [tab, setTab] = useState("plugins");
  const [users, setUsers] = useState([]);
  const [usersTotal, setUsersTotal] = useState(0);
  const [usersPage, setUsersPage] = useState(1);
  const [search, setSearch] = useState("");
  const [loading, setLoading] = useState(false);
  const [analytics, setAnalytics] = useState(null);
  const [revenue, setRevenue] = useState(null);
  const [days, setDays] = useState(30);
  const [demoMode, setDemoMode] = useState(false);
  const [rateLimits, setRateLimits] = useState(null);
  const [errors, setErrors] = useState([]);
  const [rateStats, setRateStats] = useState(null);
  const [tierOverride, setTierOverride] = useState(null);

  const TIER_LIMITS = {
    1: { cap: 100, rpm: 50, inputTPM: 40000, outputTPM: 8000 },
    2: { cap: 500, rpm: 1000, inputTPM: 400000, outputTPM: 80000 },
    3: { cap: 1000, rpm: 2000, inputTPM: 800000, outputTPM: 160000 },
    4: { cap: 200000, rpm: 4000, inputTPM: 2000000, outputTPM: 400000 },
  };

  useEffect(() => { if (tab === "users") loadUsers(); if (tab === "analytics") { loadAnalytics(); } if (tab === "errors") { loadErrors(); loadRateLimits(); loadRateStats(); loadTierOverride(); } if (tab === "financial") { loadRevenue(); loadAnalytics(); } }, [tab, usersPage, days]);

  const loadUsers = async () => {
    setLoading(true);
    try {
      const params = new URLSearchParams({ page: usersPage, limit: 50 });
      if (search) params.set('search', search);
      const res = await fetch(`/api/admin/users?${params}`, { credentials: 'include' });
      const data = await res.json();
      if (res.ok) { setUsers(data.users || []); setUsersTotal(data.total || 0); }
    } catch { showToast('Failed to load users', 'error'); }
    setLoading(false);
  };

  const loadAnalytics = async () => {
    setLoading(true);
    try {
      const res = await fetch(`/api/admin/usage?days=${days}`, { credentials: 'include' });
      const data = await res.json();
      if (res.ok) setAnalytics(data);
      else setAnalytics(null);
    } catch { setAnalytics(null); }
    setLoading(false);
  };

  const loadRevenue = async () => {
    try {
      const res = await fetch(`/api/admin/revenue?days=${days}`, { credentials: 'include' });
      const data = await res.json();
      if (res.ok && !data.error) setRevenue(data);
      else setRevenue({ error: data.error || 'Could not load revenue data' });
    } catch { setRevenue({ error: 'Could not connect to payment provider' }); }
  };

  const loadRateLimits = async () => {
    try {
      const res = await fetch('/api/admin/ratelimits', { credentials: 'include' });
      const data = await res.json();
      if (res.ok) setRateLimits(data);
    } catch { /* Non-critical */ }
  };

  const loadErrors = async () => {
    try {
      const res = await fetch(`/api/admin/errors?days=${days}`, { credentials: 'include' });
      const data = await res.json();
      if (res.ok) setErrors(data.errors || []);
      else setErrors([]);
    } catch { setErrors([]); }
  };

  const loadRateStats = async () => {
    try {
      const res = await fetch(`/api/admin/ratestats?days=${days}`, { credentials: 'include' });
      const data = await res.json();
      if (res.ok) setRateStats(data);
    } catch { /* Non-critical */ }
  };

  const loadTierOverride = async () => {
    try {
      const res = await fetch('/api/admin/tier', { credentials: 'include' });
      const data = await res.json();
      if (res.ok) setTierOverride(data.tier);
    } catch { /* Non-critical */ }
  };

  const saveTierOverrideHandler = async (tier) => {
    setTierOverride(tier);
    try {
      await fetch('/api/admin/tier', {
        method: 'PUT', credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ tier }),
      });
      loadRateLimits(); // Refresh to get updated spend cap
    } catch { showToast('Failed to save tier', 'error'); }
  };

  const updateUser = async (userId, updates) => {
    try {
      const res = await fetch(`/api/admin/users/${userId}`, {
        method: 'PATCH', credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(updates),
      });
      const data = await res.json();
      if (res.ok) {
        if (data.tempPassword) showToast(`Temp password: ${data.tempPassword}`, 'success');
        else showToast('User updated', 'success');
        loadUsers();
      } else { showToast(data.error || 'Update failed', 'error'); }
    } catch { showToast('Something went wrong', 'error'); }
  };

  const totalPages = Math.ceil(usersTotal / 50);
  const tabStyle = (t) => ({
    background: "none", border: "none", padding: "10px 20px", fontSize: 14, fontWeight: 600,
    color: tab === t ? ORANGE : SUBTEXT, cursor: "pointer", borderBottom: tab === t ? `2px solid ${ORANGE}` : "2px solid transparent",
    fontFamily: font, transition: "all 0.15s", marginBottom: -1
  });

  return (
    <div style={{ padding: "32px 32px", maxWidth: 1000 }}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 24 }}>
        <h1 style={{ margin: 0, fontSize: 24, fontWeight: 800, color: TEXT, letterSpacing: "-0.6px" }}>Admin Panel</h1>
        <button onClick={() => setDemoMode(d => !d)} style={{
          background: demoMode ? ORANGE + "18" : SURFACE2, border: `1px solid ${demoMode ? ORANGE + "44" : BORDER}`,
          borderRadius: 10, padding: "9px 18px", fontSize: 13, fontWeight: 600, cursor: "pointer",
          color: demoMode ? ORANGE : SUBTEXT, fontFamily: font, transition: "all 0.15s"
        }}>
          {demoMode ? '👁️ Show Private Info' : '🙈 Hide Private Info'}
        </button>
      </div>

      <div style={{ display: "flex", gap: 4, borderBottom: `1px solid ${BORDER}`, marginBottom: 24 }}>
        <button style={tabStyle("plugins")} onClick={() => setTab("plugins")}>Plugins</button>
        <button style={tabStyle("users")} onClick={() => setTab("users")}>Users</button>
        <button style={tabStyle("analytics")} onClick={() => setTab("analytics")}>Analytics</button>
        <button style={tabStyle("financial")} onClick={() => setTab("financial")}>Financial</button>
        <button style={tabStyle("errors")} onClick={() => setTab("errors")}>Errors</button>
      </div>

      {tab === "users" && (
        <div>
          <div style={{ display: "flex", alignItems: "center", gap: 16, marginBottom: 16 }}>
            <input
              placeholder="Search users..." value={search}
              onChange={e => { setSearch(e.target.value); setUsersPage(1); }}
              onKeyDown={e => { if (e.key === 'Enter') loadUsers(); }}
              style={{ background: INPUT_BG, border: `1px solid ${BORDER}`, borderRadius: 10, padding: "9px 14px", fontSize: 13, color: TEXT, outline: "none", fontFamily: font, flex: 1, maxWidth: 300 }}
            />
            <span style={{ fontSize: 13, color: SUBTEXT }}>{usersTotal} users</span>
            <button onClick={loadUsers} style={{ background: "none", border: `1px solid ${BORDER}`, borderRadius: 8, color: SUBTEXT, padding: "7px 12px", fontSize: 13, cursor: "pointer", fontFamily: font }}>↻</button>
          </div>
          {loading ? <div style={{ padding: 48, textAlign: "center", color: SUBTEXT }}>Loading...</div> : (
            <div style={{ overflowX: "auto", border: `1px solid ${BORDER}`, borderRadius: 14, background: SURFACE }}>
              <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 13 }}>
                <thead>
                  <tr>
                    {["User", "Plan", "Role", "Stripe", "Total Msgs", "Joined", "Actions"].map(h => (
                      <th key={h} style={{ textAlign: "left", padding: "12px 16px", fontWeight: 600, fontSize: 11, textTransform: "uppercase", letterSpacing: "0.03em", color: MUTED, borderBottom: `1px solid ${BORDER}` }}>{h}</th>
                    ))}
                  </tr>
                </thead>
                <tbody>
                  {users.map(u => (
                    <tr key={u.id} style={{ borderBottom: `1px solid ${BORDER}` }}>
                      <td style={{ padding: "12px 16px" }}>
                        <div style={{ fontWeight: 600 }}>{demoMode ? '••••••' : (u.full_name || "No name")}</div>
                        {u.display_name && <div style={{ fontSize: 11, color: MUTED }}>{demoMode ? '••••' : `@${u.display_name}`}</div>}
                        <div style={{ fontSize: 12, color: SUBTEXT }} className={demoMode ? 'blurred' : ''}>{u.email}</div>
                      </td>
                      <td style={{ padding: "12px 16px" }}>
                        <span style={{ background: u.role === 'admin' ? '#3b82f6' : u.is_test_account ? '#8b5cf6' : u.plan === 'free' ? MUTED : ORANGE, color: "#fff", padding: "2px 10px", borderRadius: 12, fontSize: 11, fontWeight: 700, textTransform: "capitalize" }}>{u.role === 'admin' ? 'Admin' : u.is_test_account ? 'Test' : u.plan}</span>
                      </td>
                      <td style={{ padding: "12px 16px", fontSize: 13 }} className={demoMode ? 'blurred' : ''}>{u.role === 'admin' ? <strong>admin</strong> : 'user'}</td>
                      <td style={{ padding: "12px 16px", fontSize: 12 }}>
                        {u.stripe_status === 'active' ? <span style={{ color: "#22c55e", fontWeight: 600 }}>active</span>
                          : u.stripe_status === 'past_due' ? <span style={{ color: "#f59e0b", fontWeight: 600 }}>past due</span>
                          : u.stripe_status === 'canceled' ? <span style={{ color: "#ef4444" }}>canceled</span>
                          : <span style={{ color: MUTED }}>—</span>}
                      </td>
                      <td style={{ padding: "12px 16px", fontSize: 13 }}>{u.messages_used || 0}</td>
                      <td style={{ padding: "12px 16px", fontSize: 12, color: SUBTEXT }}>{u.created_at ? new Date(u.created_at).toLocaleDateString() : ""}</td>
                      <td style={{ padding: "12px 16px" }}>
                        <select
                          defaultValue="" onChange={e => {
                            const v = e.target.value; e.target.value = "";
                            if (v.startsWith('plan:')) updateUser(u.id, { plan: v.split(':')[1] });
                            if (v.startsWith('role:')) updateUser(u.id, { role: v.split(':')[1] });
                            if (v === 'toggleTest') updateUser(u.id, { isTestAccount: !u.is_test_account });
                            if (v === 'resetPassword' && confirm('Reset password?')) updateUser(u.id, { resetPassword: true });
                            if (v === 'resetUsage' && confirm('Reset usage?')) updateUser(u.id, { resetUsage: true });
                            if (v === 'deactivate' && confirm('Deactivate this user? Sets plan to free and cancels subscription.')) updateUser(u.id, { plan: 'free', deactivate: true });
                          }}
                          style={{ background: SURFACE2, border: `1px solid ${BORDER}`, borderRadius: 6, color: TEXT, fontSize: 12, padding: "4px 8px", cursor: "pointer", fontFamily: font }}
                        >
                          <option value="">Actions</option>
                          <option value="plan:free">Set Free</option>
                          <option value="plan:maker">Set Maker</option>
                          <option value={`role:${u.role === 'admin' ? 'user' : 'admin'}`}>{u.role === 'admin' ? 'Remove Admin' : 'Make Admin'}</option>
                          <option value="toggleTest">{u.is_test_account ? 'Remove Test Account' : 'Set Test Account'}</option>
                          <option value="resetPassword">Reset Password</option>
                          <option value="resetUsage">Reset Usage</option>
                          <option value="deactivate">Deactivate</option>
                        </select>
                      </td>
                    </tr>
                  ))}
                  {users.length === 0 && <tr><td colSpan={7} style={{ padding: 24, textAlign: "center", color: SUBTEXT }}>No users found</td></tr>}
                </tbody>
              </table>
            </div>
          )}
          {totalPages > 1 && (
            <div style={{ display: "flex", alignItems: "center", justifyContent: "center", gap: 16, marginTop: 16 }}>
              <Btn variant="ghost" disabled={usersPage <= 1} onClick={() => setUsersPage(p => p - 1)} style={{ padding: "6px 12px", fontSize: 13 }}>« Prev</Btn>
              <span style={{ fontSize: 13, color: SUBTEXT }}>Page {usersPage} of {totalPages}</span>
              <Btn variant="ghost" disabled={usersPage >= totalPages} onClick={() => setUsersPage(p => p + 1)} style={{ padding: "6px 12px", fontSize: 13 }}>Next »</Btn>
            </div>
          )}
        </div>
      )}

      {tab === "plugins" && <PluginsEditor plugins={plugins} onPluginsChange={onPluginsChange} />}

      {tab === "analytics" && (
        <div>
          <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 20 }}>
            <span style={{ fontSize: 13, color: SUBTEXT }}>Period:</span>
            <select value={days} onChange={e => setDays(parseInt(e.target.value))} style={{ background: SURFACE2, border: `1px solid ${BORDER}`, borderRadius: 6, color: TEXT, fontSize: 12, padding: "4px 8px", fontFamily: font }}>
              <option value={7}>7 days</option>
              <option value={30}>30 days</option>
              <option value={90}>90 days</option>
            </select>
          </div>
          {loading ? <div style={{ padding: 48, textAlign: "center", color: SUBTEXT }}>Loading...</div> : analytics ? (
            <div>
              {/* Usage stat cards */}
              <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 14, marginBottom: 24 }}>
                {[
                  { label: "Total Users", value: analytics.totalUsers || 0 },
                  { label: `Active (${days}d)`, value: analytics.activeUsers || 0 },
                  { label: `Messages (${days}d)`, value: (analytics.totals?.total_messages || 0).toLocaleString() },
                ].map(s => (
                  <div key={s.label} style={{ background: SURFACE, border: `1px solid ${BORDER}`, borderRadius: 12, padding: 20, textAlign: "center" }}>
                    <div style={{ fontSize: 28, fontWeight: 800, color: TEXT }}>{s.value}</div>
                    <div style={{ fontSize: 12, color: SUBTEXT, marginTop: 4 }}>{s.label}</div>
                  </div>
                ))}
              </div>

              {/* Daily activity bar chart */}
              {analytics.byDay && analytics.byDay.length > 0 && (() => {
                const maxMsg = Math.max(...analytics.byDay.map(d => d.messages), 1);
                const totalMsgs = analytics.byDay.reduce((s, d) => s + d.messages, 0);
                return (
                  <div style={{ background: SURFACE, border: `1px solid ${BORDER}`, borderRadius: 14, padding: 24, marginBottom: 24 }}>
                    <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", marginBottom: 16 }}>
                      <h3 style={{ fontSize: 14, fontWeight: 700, color: TEXT, margin: 0 }}>Daily Activity</h3>
                      <span style={{ fontSize: 13, color: SUBTEXT, fontWeight: 600 }}>{totalMsgs.toLocaleString()} messages</span>
                    </div>
                    {/* Y-axis max label */}
                    <div style={{ display: "flex", alignItems: "flex-start", gap: 8 }}>
                      <div style={{ fontSize: 10, color: MUTED, minWidth: 28, textAlign: "right", paddingTop: 2 }}>{maxMsg}</div>
                      <div style={{ flex: 1 }}>
                        <div style={{ display: "flex", alignItems: "flex-end", gap: 3, height: 140 }}>
                          {analytics.byDay.map((d, i) => {
                            const pct = (d.messages / maxMsg) * 100;
                            return (
                              <div key={i} className="chart-bar-wrap" style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", height: "100%", justifyContent: "flex-end", position: "relative", cursor: "default" }}>
                                {/* Count label above bar */}
                                {pct > 15 && <div style={{ fontSize: 9, color: SUBTEXT, fontWeight: 600, marginBottom: 2, opacity: 0.8 }}>{d.messages}</div>}
                                <div style={{
                                  width: "100%", minWidth: 4, maxWidth: 20,
                                  height: `${pct}%`,
                                  background: ORANGE, borderRadius: "3px 3px 0 0",
                                  transition: "height 0.3s ease",
                                  minHeight: 2,
                                }} />
                                {/* Hover tooltip */}
                                <div className="chart-tooltip" style={{
                                  position: "absolute", bottom: "calc(100% + 4px)", left: "50%", transform: "translateX(-50%)",
                                  background: TEXT, color: SURFACE, padding: "4px 8px", borderRadius: 6, fontSize: 11, fontWeight: 600,
                                  whiteSpace: "nowrap", pointerEvents: "none", opacity: 0, transition: "opacity 0.15s", zIndex: 10,
                                }}>
                                  {d.date}: {d.messages}
                                </div>
                              </div>
                            );
                          })}
                        </div>
                        <div style={{ display: "flex", justifyContent: "space-between", marginTop: 8 }}>
                          <span style={{ fontSize: 11, color: MUTED }}>{analytics.byDay[0]?.date}</span>
                          <span style={{ fontSize: 11, color: MUTED }}>{analytics.byDay[analytics.byDay.length - 1]?.date}</span>
                        </div>
                      </div>
                    </div>
                  </div>
                );
              })()}

              {/* Top users */}
              {analytics.topUsers && analytics.topUsers.length > 0 && (
                <div className={demoMode ? 'blurred' : ''} style={{ background: SURFACE, border: `1px solid ${BORDER}`, borderRadius: 14, padding: 24, marginBottom: 24 }}>
                  <h3 style={{ fontSize: 14, fontWeight: 700, color: TEXT, marginBottom: 16 }}>Top Users <span style={{ fontWeight: 400, fontSize: 12, color: SUBTEXT }}>(last {days} days)</span></h3>
                  <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 13 }}>
                    <thead>
                      <tr>
                        {["User", "Plan", "Messages", "Tokens Used"].map(h => (
                          <th key={h} style={{ textAlign: "left", padding: "8px 12px", fontWeight: 600, fontSize: 11, textTransform: "uppercase", letterSpacing: "0.03em", color: MUTED, borderBottom: `1px solid ${BORDER}` }}>{h}</th>
                        ))}
                      </tr>
                    </thead>
                    <tbody>
                      {analytics.topUsers.map((u, i) => (
                        <tr key={i} style={{ borderBottom: `1px solid ${BORDER}` }}>
                          <td style={{ padding: "10px 12px" }}>
                            <div style={{ fontWeight: 600 }}>{u.full_name}</div>
                            <div style={{ fontSize: 12, color: SUBTEXT }}>{u.email}</div>
                          </td>
                          <td style={{ padding: "10px 12px" }}>
                            <span style={{ background: u.plan === 'free' ? MUTED : ORANGE, color: "#fff", padding: "2px 10px", borderRadius: 12, fontSize: 11, fontWeight: 700, textTransform: "capitalize" }}>{u.plan}</span>
                          </td>
                          <td style={{ padding: "10px 12px" }}>{u.messages.toLocaleString()}</td>
                          <td style={{ padding: "10px 12px", color: SUBTEXT }}>{((u.input_tokens + u.output_tokens) / 1000).toFixed(0)}k</td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              )}

            </div>
          ) : <div style={{ padding: 48, textAlign: "center", color: SUBTEXT }}>No data available</div>}
        </div>
      )}

      {tab === "errors" && (
        <div>
          {/* Spend cap warning banner */}
          {rateLimits && rateLimits.spendPct > 80 && (
            <div style={{
              background: rateLimits.spendPct > 95 ? "#ef444418" : "#f59e0b18",
              border: `1px solid ${rateLimits.spendPct > 95 ? "#ef444444" : "#f59e0b44"}`,
              borderRadius: 12, padding: "14px 20px", marginBottom: 16, display: "flex", alignItems: "center", gap: 12
            }}>
              <span style={{ fontSize: 20 }}>{rateLimits.spendPct > 95 ? "🚨" : "⚠️"}</span>
              <div>
                <div style={{ fontWeight: 700, fontSize: 14, color: rateLimits.spendPct > 95 ? "#ef4444" : "#f59e0b" }}>
                  {rateLimits.spendPct > 95 ? "Monthly spend limit almost reached!" : "Approaching monthly spend limit"}
                </div>
                <div style={{ fontSize: 13, color: SUBTEXT, marginTop: 2 }}>
                  ${rateLimits.monthlySpend.toFixed(2)} / ${rateLimits.spendCap} (Tier {rateLimits.effectiveTier || "1"} cap).
                  {rateLimits.spendPct > 95 ? " All AI tools will stop working when the cap is hit." : " Consider upgrading your Anthropic tier."}
                </div>
              </div>
            </div>
          )}

          {/* Tier selector card */}
          <div style={{ background: SURFACE, border: `1px solid ${BORDER}`, borderRadius: 14, padding: 24, marginBottom: 16 }}>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 12 }}>
              <h3 style={{ margin: 0, fontSize: 14, fontWeight: 700, color: TEXT }}>Anthropic Tier</h3>
              <select
                value={tierOverride ?? rateLimits?.effectiveTier ?? 1}
                onChange={e => saveTierOverrideHandler(parseInt(e.target.value))}
                style={{ background: SURFACE2, border: `1px solid ${BORDER}`, borderRadius: 8, color: TEXT, fontSize: 13, padding: "6px 12px", fontFamily: font, fontWeight: 600 }}
              >
                <option value={1}>Tier 1</option>
                <option value={2}>Tier 2</option>
                <option value={3}>Tier 3</option>
                <option value={4}>Tier 4</option>
              </select>
            </div>
            <div style={{ fontSize: 12, color: SUBTEXT, lineHeight: 1.5, marginBottom: 16 }}>
              Find your tier at{" "}
              <a href="https://platform.claude.com/settings/limits" target="_blank" rel="noopener" style={{ color: ORANGE, textDecoration: "none", fontWeight: 600 }}>platform.claude.com/settings/limits</a>
              {" "}&mdash; it's shown next to the "Rate Limits" heading.
              {rateLimits?.detectedTier && rateLimits.detectedTier !== (tierOverride ?? rateLimits.effectiveTier) && (
                <span style={{ display: "block", marginTop: 4, color: MUTED }}>Auto-detected from API: Tier {rateLimits.detectedTier}</span>
              )}
            </div>
            {/* Tier limits reference */}
            {(() => {
              const t = tierOverride ?? rateLimits?.effectiveTier ?? 1;
              const limits = TIER_LIMITS[t];
              return (
                <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 12 }}>
                  <div style={{ textAlign: "center" }}>
                    <div style={{ fontSize: 20, fontWeight: 800, color: TEXT }}>${limits.cap.toLocaleString()}</div>
                    <div style={{ fontSize: 11, color: SUBTEXT }}>Monthly Cap</div>
                  </div>
                  <div style={{ textAlign: "center" }}>
                    <div style={{ fontSize: 20, fontWeight: 800, color: TEXT }}>{limits.rpm.toLocaleString()}</div>
                    <div style={{ fontSize: 11, color: SUBTEXT }}>RPM Limit</div>
                  </div>
                  <div style={{ textAlign: "center" }}>
                    <div style={{ fontSize: 20, fontWeight: 800, color: TEXT }}>{(limits.inputTPM / 1000).toFixed(0)}k</div>
                    <div style={{ fontSize: 11, color: SUBTEXT }}>Input TPM</div>
                  </div>
                  <div style={{ textAlign: "center" }}>
                    <div style={{ fontSize: 20, fontWeight: 800, color: TEXT }}>{(limits.outputTPM / 1000).toFixed(0)}k</div>
                    <div style={{ fontSize: 11, color: SUBTEXT }}>Output TPM</div>
                  </div>
                </div>
              );
            })()}
          </div>

          {/* API Status — compact */}
          {rateLimits && (
            <div style={{ background: SURFACE, border: `1px solid ${BORDER}`, borderRadius: 14, padding: "18px 24px", marginBottom: 16 }}>
              <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
                <div style={{ display: "flex", alignItems: "center", gap: 16 }}>
                  <h3 style={{ margin: 0, fontSize: 14, fontWeight: 700, color: TEXT }}>API Status</h3>
                  {rateLimits.effectiveTier && <span style={{ background: ORANGE + "18", color: ORANGE, padding: "2px 10px", borderRadius: 10, fontSize: 11, fontWeight: 700 }}>Tier {rateLimits.effectiveTier}</span>}
                </div>
                <div style={{ display: "flex", alignItems: "center", gap: 20 }}>
                  <div style={{ textAlign: "right" }}>
                    <span style={{ fontSize: 18, fontWeight: 800, color: TEXT }}>${rateLimits.monthlySpend.toFixed(2)}</span>
                    <span style={{ fontSize: 11, color: MUTED, marginLeft: 4 }}>/ ${rateLimits.spendCap} cap</span>
                  </div>
                  {rateLimits.count429 > 0 && (
                    <div style={{ textAlign: "right" }}>
                      <span style={{ fontSize: 14, fontWeight: 700, color: "#ef4444" }}>{rateLimits.count429}</span>
                      <span style={{ fontSize: 11, color: SUBTEXT, marginLeft: 4 }}>429s (24h)</span>
                    </div>
                  )}
                </div>
              </div>
              {rateLimits.effectiveTier && rateLimits.effectiveTier < 4 && (() => {
                const nextTier = rateLimits.effectiveTier + 1;
                const depositNeeded = { 2: 40, 3: 200, 4: 400 }[nextTier];
                return (
                  <div style={{ fontSize: 12, color: SUBTEXT, marginTop: 10, lineHeight: 1.5 }}>
                    * To reduce rate limit errors, deposit <strong style={{ color: TEXT }}>${depositNeeded}</strong> on your{" "}
                    <a href="https://console.anthropic.com/settings/billing" target="_blank" rel="noopener" style={{ color: ORANGE, textDecoration: "none", fontWeight: 600 }}>Anthropic account</a>{" "}
                    to advance to <strong style={{ color: TEXT }}>Tier {nextTier}</strong>. You advance immediately — no spending required.
                  </div>
                );
              })()}
            </div>
          )}

          {/* Rate stats: avg/peak RPM and TPM */}
          {rateStats && (() => {
            const t = tierOverride ?? rateLimits?.effectiveTier ?? 1;
            const limits = TIER_LIMITS[t];
            const pctColor = (val, limit) => val >= limit * 0.95 ? "#ef4444" : val >= limit * 0.8 ? "#f59e0b" : TEXT;
            return (
              <div style={{ background: SURFACE, border: `1px solid ${BORDER}`, borderRadius: 14, padding: 24, marginBottom: 16 }}>
                <h3 style={{ margin: "0 0 16px", fontSize: 14, fontWeight: 700, color: TEXT }}>Rate Usage ({days}d)</h3>
                <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 16 }}>
                  {[
                    { label: "RPM", avg: rateStats.avgRPM, peak: rateStats.peakRPM, limit: limits.rpm, peakTime: rateStats.peakRPMMinute },
                    { label: "Input TPM", avg: rateStats.avgInputTPM, peak: rateStats.peakInputTPM, limit: limits.inputTPM, peakTime: rateStats.peakTPMMinute, fmt: v => (v / 1000).toFixed(1) + "k" },
                    { label: "Output TPM", avg: rateStats.avgOutputTPM, peak: rateStats.peakOutputTPM, limit: limits.outputTPM, peakTime: rateStats.peakTPMMinute, fmt: v => (v / 1000).toFixed(1) + "k" },
                  ].map(m => (
                    <div key={m.label} style={{ background: SURFACE2, borderRadius: 10, padding: 16 }}>
                      <div style={{ fontSize: 11, fontWeight: 700, color: SUBTEXT, textTransform: "uppercase", letterSpacing: "0.03em", marginBottom: 10 }}>{m.label}</div>
                      <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 6 }}>
                        <div>
                          <div style={{ fontSize: 11, color: MUTED }}>Average</div>
                          <div style={{ fontSize: 18, fontWeight: 800, color: TEXT }}>{m.fmt ? m.fmt(m.avg) : m.avg}</div>
                        </div>
                        <div style={{ textAlign: "right" }}>
                          <div style={{ fontSize: 11, color: MUTED }}>Peak</div>
                          <div style={{ fontSize: 18, fontWeight: 800, color: pctColor(m.peak, m.limit) }}>{m.fmt ? m.fmt(m.peak) : m.peak}</div>
                        </div>
                      </div>
                      <div style={{ fontSize: 11, color: MUTED }}>Limit: {m.fmt ? m.fmt(m.limit) : m.limit}/min</div>
                      {m.peakTime && <div style={{ fontSize: 10, color: MUTED, marginTop: 2 }}>Peak at: {m.peakTime}</div>}
                    </div>
                  ))}
                </div>
              </div>
            );
          })()}

          {/* Error log */}
          <h3 style={{ fontSize: 14, fontWeight: 700, color: TEXT, marginBottom: 12 }}>Error Log</h3>
          {errors.length === 0 ? (
            <div style={{ padding: 48, textAlign: "center", background: SURFACE, border: `1px solid ${BORDER}`, borderRadius: 14 }}>
              <div style={{ fontSize: 36, marginBottom: 12 }}>✅</div>
              <div style={{ fontSize: 14, fontWeight: 700, color: TEXT, marginBottom: 4 }}>No errors in the last {days} days</div>
              <div style={{ fontSize: 13, color: SUBTEXT }}>All systems running smoothly.</div>
            </div>
          ) : (
            <div style={{ overflowX: "auto", border: `1px solid ${BORDER}`, borderRadius: 14, background: SURFACE }}>
              <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 13 }}>
                <thead>
                  <tr>
                    {["Time", "User", "Tool", "Error Type", "Message"].map(h => (
                      <th key={h} style={{ textAlign: "left", padding: "12px 16px", fontWeight: 600, fontSize: 11, textTransform: "uppercase", letterSpacing: "0.03em", color: MUTED, borderBottom: `1px solid ${BORDER}` }}>{h}</th>
                    ))}
                  </tr>
                </thead>
                <tbody>
                  {errors.map(e => (
                    <tr key={e.id} style={{ borderBottom: `1px solid ${BORDER}` }}>
                      <td style={{ padding: "12px 16px", fontSize: 12, color: SUBTEXT, whiteSpace: "nowrap" }}>
                        {e.created_at ? new Date(e.created_at).toLocaleString() : "—"}
                      </td>
                      <td style={{ padding: "12px 16px" }}>
                        <div style={{ fontWeight: 600, fontSize: 13 }}>{e.full_name || "Unknown"}</div>
                        <div style={{ fontSize: 11, color: SUBTEXT }}>{e.email || ""}</div>
                      </td>
                      <td style={{ padding: "12px 16px", fontSize: 13, color: SUBTEXT }}>{e.plugin_id || "—"}</td>
                      <td style={{ padding: "12px 16px" }}>
                        <span style={{
                          padding: "3px 10px", borderRadius: 12, fontSize: 11, fontWeight: 700,
                          background: e.error_type === 'rate_limit' ? "#f59e0b22" : e.error_type === 'api_error' ? "#ef444422" : "#6366f122",
                          color: e.error_type === 'rate_limit' ? "#f59e0b" : e.error_type === 'api_error' ? "#ef4444" : "#6366f1",
                        }}>
                          {e.error_type === 'rate_limit' ? 'Rate Limit' : e.error_type === 'api_error' ? 'API Error' : e.error_type === 'stream_error' ? 'Stream Error' : e.error_type}
                        </span>
                      </td>
                      <td style={{ padding: "12px 16px", fontSize: 12, color: SUBTEXT, maxWidth: 300, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                        {e.error_message || "—"}
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          )}
        </div>
      )}

      {/* Financial tab */}
      {tab === "financial" && (
        <div>
          <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 20 }}>
            <span style={{ fontSize: 13, color: SUBTEXT }}>Period:</span>
            <select value={days} onChange={e => setDays(parseInt(e.target.value))} style={{ background: SURFACE2, border: `1px solid ${BORDER}`, borderRadius: 6, color: TEXT, fontSize: 12, padding: "4px 8px", fontFamily: font }}>
              <option value={7}>7 days</option>
              <option value={30}>30 days</option>
              <option value={90}>90 days</option>
            </select>
          </div>

          {loading ? <div style={{ padding: 48, textAlign: "center", color: SUBTEXT }}>Loading...</div> : (
            <div>
              {/* API Cost section — always show when analytics available */}
              {analytics && (
                <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 14, marginBottom: 14 }}>
                  {(() => {
                    const apiCost = (analytics.byPlugin || []).reduce((sum, r) => {
                      const p = (_cfg.apiPricing || {})[r.model] || { inputPer1k: 0.003, outputPer1k: 0.015, cacheWritePer1k: 0.00375, cacheReadPer1k: 0.0003 };
                      return sum + (r.input_tokens / 1000) * p.inputPer1k + (r.output_tokens / 1000) * p.outputPer1k
                        + ((r.cache_creation_input_tokens || 0) / 1000) * (p.cacheWritePer1k || 0.00375)
                        + ((r.cache_read_input_tokens || 0) / 1000) * (p.cacheReadPer1k || 0.0003);
                    }, 0);
                    const hasRevenue = revenue && !revenue.error;
                    const netRev = hasRevenue ? revenue.netRevenue / 100 : 0;
                    const profit = netRev - apiCost;
                    const margin = netRev > 0 ? ((profit / netRev) * 100).toFixed(0) : 0;
                    const cards = [
                      { label: `Est. API Cost (${days}d)`, value: "$" + apiCost.toFixed(2), color: "#f59e0b" },
                    ];
                    if (hasRevenue) {
                      cards.push(
                        { label: `Profit (${days}d)`, value: "$" + profit.toFixed(0), color: profit >= 0 ? "#22c55e" : "#ef4444" },
                        { label: "Margin", value: margin + "%", color: parseInt(margin) >= 50 ? "#22c55e" : "#f59e0b" },
                      );
                    }
                    return cards.map(s => (
                      <div key={s.label} style={{ background: SURFACE, border: `1px solid ${BORDER}`, borderRadius: 12, padding: 20, textAlign: "center" }}>
                        <div style={{ fontSize: 28, fontWeight: 800, color: s.color || TEXT }}>{s.value}</div>
                        <div style={{ fontSize: 12, color: SUBTEXT, marginTop: 4 }}>{s.label}</div>
                      </div>
                    ));
                  })()}
                </div>
              )}

              {/* Revenue section — Stripe data or connect prompt */}
              {revenue && !revenue.error ? (
                <div>
                  {/* Revenue hero BANs */}
                  <div className={demoMode ? 'blurred' : ''} style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 14, marginBottom: 14 }}>
                    {[
                      { label: "MRR", value: "$" + (revenue.mrr / 100).toLocaleString(undefined, { minimumFractionDigits: 0 }), color: "#22c55e" },
                      { label: `Revenue (${days}d)`, value: "$" + (revenue.netRevenue / 100).toLocaleString(undefined, { minimumFractionDigits: 0 }), color: "#22c55e" },
                      { label: "Active Subs", value: revenue.activeSubscriptions },
                      { label: `New Subs (${days}d)`, value: revenue.newSubscriptions },
                    ].map(s => (
                      <div key={s.label} style={{ background: SURFACE, border: `1px solid ${BORDER}`, borderRadius: 12, padding: 20, textAlign: "center" }}>
                        <div style={{ fontSize: 28, fontWeight: 800, color: s.color || TEXT }}>{s.value}</div>
                        <div style={{ fontSize: 12, color: SUBTEXT, marginTop: 4 }}>{s.label}</div>
                      </div>
                    ))}
                  </div>

                  {/* Refunds + Gross Revenue */}
                  <div className={demoMode ? 'blurred' : ''} style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 14, marginBottom: 24 }}>
                    {[
                      { label: `Refunds (${days}d)`, value: "$" + (revenue.refunded / 100).toFixed(0) },
                      { label: "Gross Revenue", value: "$" + (revenue.totalRevenue / 100).toLocaleString(undefined, { minimumFractionDigits: 0 }) },
                    ].map(s => (
                      <div key={s.label} style={{ background: SURFACE, border: `1px solid ${BORDER}`, borderRadius: 12, padding: 20, textAlign: "center" }}>
                        <div style={{ fontSize: 28, fontWeight: 800, color: s.color || TEXT }}>{s.value}</div>
                        <div style={{ fontSize: 12, color: SUBTEXT, marginTop: 4 }}>{s.label}</div>
                      </div>
                    ))}
                  </div>

                  {/* Recent transactions */}
                  {revenue.transactions && revenue.transactions.length > 0 && (
                    <div className={demoMode ? 'blurred' : ''} style={{ background: SURFACE, border: `1px solid ${BORDER}`, borderRadius: 14, padding: 24 }}>
                      <h3 style={{ fontSize: 14, fontWeight: 700, color: TEXT, marginBottom: 16 }}>Recent Transactions</h3>
                      <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 13 }}>
                        <thead>
                          <tr>
                            {["Customer", "Amount", "Description", "Date", "Status"].map(h => (
                              <th key={h} style={{ textAlign: "left", padding: "8px 12px", fontWeight: 600, fontSize: 11, textTransform: "uppercase", letterSpacing: "0.03em", color: MUTED, borderBottom: `1px solid ${BORDER}` }}>{h}</th>
                            ))}
                          </tr>
                        </thead>
                        <tbody>
                          {revenue.transactions.map(tx => (
                            <tr key={tx.id} style={{ borderBottom: `1px solid ${BORDER}` }}>
                              <td style={{ padding: "10px 12px" }}>
                                <div style={{ fontWeight: 600 }}>{tx.customer_name || "\u2014"}</div>
                                <div style={{ fontSize: 12, color: SUBTEXT }}>{tx.customer_email || ""}</div>
                              </td>
                              <td style={{ padding: "10px 12px", fontWeight: 700, color: tx.refunded ? "#ef4444" : "#22c55e" }}>
                                {tx.refunded ? "\u2212" : ""}${(tx.amount / 100).toLocaleString(undefined, { minimumFractionDigits: 2 })}
                              </td>
                              <td style={{ padding: "10px 12px", color: SUBTEXT }}>{tx.description}</td>
                              <td style={{ padding: "10px 12px", fontSize: 12, color: SUBTEXT }}>{new Date(tx.created * 1000).toLocaleDateString()}</td>
                              <td style={{ padding: "10px 12px" }}>
                                {tx.refunded
                                  ? <span style={{ background: "#ef444433", color: "#ef4444", padding: "2px 10px", borderRadius: 12, fontSize: 11, fontWeight: 700 }}>Refunded</span>
                                  : <span style={{ background: "#22c55e33", color: "#22c55e", padding: "2px 10px", borderRadius: 12, fontSize: 11, fontWeight: 700 }}>Paid</span>
                                }
                              </td>
                            </tr>
                          ))}
                        </tbody>
                      </table>
                    </div>
                  )}
                </div>
              ) : (
                <div>
                  {/* Blurred placeholder BANs — hint at what's behind Stripe connection */}
                  <div style={{ position: "relative", marginBottom: 14 }}>
                    <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 14, filter: "blur(6px)", opacity: 0.45, pointerEvents: "none", userSelect: "none" }}>
                      {[
                        { label: "MRR", value: "$—", color: "#22c55e" },
                        { label: `Revenue (${days}d)`, value: "$—", color: "#22c55e" },
                        { label: "Active Subs", value: "—" },
                        { label: `New Subs (${days}d)`, value: "—" },
                      ].map(s => (
                        <div key={s.label} style={{ background: SURFACE, border: `1px solid ${BORDER}`, borderRadius: 12, padding: 20, textAlign: "center" }}>
                          <div style={{ fontSize: 28, fontWeight: 800, color: s.color || TEXT }}>{s.value}</div>
                          <div style={{ fontSize: 12, color: SUBTEXT, marginTop: 4 }}>{s.label}</div>
                        </div>
                      ))}
                    </div>
                  </div>
                  <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 14, filter: "blur(6px)", opacity: 0.45, pointerEvents: "none", userSelect: "none", marginBottom: 24 }}>
                    {[
                      { label: `Profit (${days}d)`, value: "$—" },
                      { label: "Margin", value: "—%" },
                      { label: `Refunds (${days}d)`, value: "$0" },
                      { label: "Gross Revenue", value: "$—" },
                    ].map(s => (
                      <div key={s.label} style={{ background: SURFACE, border: `1px solid ${BORDER}`, borderRadius: 12, padding: 20, textAlign: "center" }}>
                        <div style={{ fontSize: 28, fontWeight: 800, color: TEXT }}>{s.value}</div>
                        <div style={{ fontSize: 12, color: SUBTEXT, marginTop: 4 }}>{s.label}</div>
                      </div>
                    ))}
                  </div>
                  {/* Connect Stripe CTA */}
                  <div style={{ background: SURFACE, border: `1px solid ${BORDER}`, borderRadius: 14, padding: "32px 24px", textAlign: "center" }}>
                    <div style={{ fontSize: 32, marginBottom: 10 }}>💳</div>
                    <div style={{ fontSize: 15, fontWeight: 700, color: TEXT, marginBottom: 6 }}>Connect Stripe to unlock revenue data</div>
                    <div style={{ fontSize: 13, color: SUBTEXT, lineHeight: 1.6, maxWidth: 440, margin: "0 auto" }}>
                      Set your <code style={{ background: SURFACE2, padding: "2px 6px", borderRadius: 4, fontSize: 12 }}>STRIPE_SECRET_KEY</code> and <code style={{ background: SURFACE2, padding: "2px 6px", borderRadius: 4, fontSize: 12 }}>STRIPE_WEBHOOK_SECRET</code> in Wrangler secrets to see MRR, transactions, and profit margins.
                    </div>
                  </div>
                </div>
              )}
            </div>
          )}
        </div>
      )}
    </div>
  );
}

// ═══════════════════════════════════════════════════════
// STRIPE HELPERS
// ═══════════════════════════════════════════════════════

async function startCheckout(planId) {
  if (!planId) return;
  try {
    const res = await fetch('/api/stripe/checkout', {
      method: 'POST', credentials: 'include',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ planId }),
    });
    const data = await res.json();
    if (data.url) window.location.href = data.url;
    else showToast('Could not start checkout.', 'error');
  } catch { showToast('Payment could not be processed.', 'error'); }
}

async function openBillingPortal() {
  try {
    const res = await fetch('/api/stripe/portal', { method: 'POST', credentials: 'include' });
    const data = await res.json();
    if (data.url) window.location.href = data.url;
    else showToast('Could not open billing portal.', 'error');
  } catch { showToast('Something went wrong.', 'error'); }
}

// ═══════════════════════════════════════════════════════
// PLAN SELECTION MODAL (upgrade from anywhere)
// ═══════════════════════════════════════════════════════

function openUpgradeModal() {
  const plans = _cfg.plans || [];
  if (plans.length === 0) return;
  const overlay = document.createElement('div');
  overlay.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,0.7);display:flex;align-items:center;justify-content:center;z-index:100;cursor:pointer;';
  overlay.addEventListener('click', (e) => { if (e.target === overlay) overlay.remove(); });
  const modal = document.createElement('div');
  modal.style.cssText = `background:${SURFACE};border:1px solid ${BORDER};border-radius:16px;padding:32px;max-width:560px;width:90%;cursor:default;`;
  modal.innerHTML = `<h3 style="margin:0 0 20px;font-size:20px;font-weight:800;color:${TEXT};text-align:center;font-family:${font}">Choose a Plan</h3>` +
    plans.map(p => {
      const planColor = ORANGE;
      return `<div style="background:${SURFACE2};border:1px solid ${BORDER};border-radius:12px;padding:20px;margin-bottom:12px;cursor:pointer;transition:border-color 0.15s;" onmouseover="this.style.borderColor='${planColor}'" onmouseout="this.style.borderColor='${BORDER}'" onclick="document.querySelector('.upgrade-overlay')?.remove();(${startCheckout.toString()})('${p.id}')">
        <div style="display:flex;justify-content:space-between;align-items:center;">
          <div><div style="font-weight:700;font-size:15px;color:${TEXT};font-family:${font}">${p.name}${p.badge ? ` <span style="font-size:10px;background:${planColor};color:#fff;padding:2px 8px;border-radius:10px;margin-left:6px">${p.badge}</span>` : ''}</div>
          <div style="font-size:13px;color:${SUBTEXT};margin-top:4px;font-family:${font}">${(p.features || []).join(' · ')}</div></div>
          <div style="font-size:22px;font-weight:800;color:${TEXT};font-family:${font}">$${p.price}<span style="font-size:12px;color:${SUBTEXT}">/${p.period || 'mo'}</span></div>
        </div></div>`;
    }).join('') +
    `<button style="width:100%;background:none;border:1px solid ${BORDER};border-radius:10px;padding:10px;color:${SUBTEXT};font-size:13px;cursor:pointer;font-family:${font};margin-top:4px" onclick="this.closest('.upgrade-overlay').remove()">Cancel</button>`;
  overlay.className = 'upgrade-overlay';
  overlay.appendChild(modal);
  document.body.appendChild(overlay);
}

// ═══════════════════════════════════════════════════════
// MAIN APP — ROUTES EVERYTHING
// ═══════════════════════════════════════════════════════

function App() {
  const [screen, setScreen] = useState("loading");
  const [user, setUser] = useState(null);
  const [plugins, setPlugins] = useState([]);
  const [nav, setNav] = useState(() => {
    const hash = window.location.hash.slice(1); // e.g. "#tools" → "tools"
    return hash || localStorage.getItem('lastNav') || 'dashboard';
  });
  const [collapsed, setCollapsed] = useState(false);
  const [resetToken, setResetToken] = useState(null);
  const [theme, setTheme] = useState(localStorage.getItem('theme') || 'dark');
  const [showWelcome, setShowWelcome] = useState(false);
  const [pinnedChats, setPinnedChats] = useState([]);
  const [pendingConvoId, setPendingConvoId] = useState(() => {
    const lastNav = localStorage.getItem('lastNav') || '';
    return lastNav.startsWith('chat-') ? (localStorage.getItem('lastConvoId') || null) : null;
  });

  // Apply theme to document
  const applyTheme = useCallback((mode) => {
    document.documentElement.setAttribute('data-theme', mode);
    localStorage.setItem('theme', mode);
    const tokens = mode === 'light' ? LIGHT : _dark;
    const root = document.documentElement.style;
    if (tokens) {
      root.setProperty('--bg', tokens.bg || BG);
      root.setProperty('--surface', tokens.surface || SURFACE);
      root.setProperty('--surface2', tokens.surface2 || SURFACE2);
      root.setProperty('--border', tokens.border || BORDER);
      root.setProperty('--text', tokens.text || TEXT);
      root.setProperty('--subtext', tokens.subtext || SUBTEXT);
      root.setProperty('--muted', tokens.muted || MUTED);
    }
    root.setProperty('--primary', ORANGE);
    root.setProperty('--font', font);
  }, []);

  useEffect(() => { applyTheme(theme); }, [theme, applyTheme]);

  const toggleTheme = () => {
    const newTheme = theme === 'dark' ? 'light' : 'dark';
    setTheme(newTheme);
    if (user) {
      fetch('/api/auth/me', {
        method: 'PATCH', credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ themePreference: newTheme }),
      }).catch(() => {});
    }
  };

  // Load user + plugins
  const loadPlugins = async () => {
    try {
      const res = await fetch('/api/plugins', { credentials: 'include' });
      if (res.ok) {
        const data = await res.json();
        setPlugins(data.plugins || []);
      }
    } catch {}
  };

  const loadApp = async () => {
    try {
      const [userRes, pluginsRes] = await Promise.all([
        fetch('/api/auth/me', { credentials: 'include' }),
        fetch('/api/plugins', { credentials: 'include' }),
      ]);
      if (!userRes.ok) { setScreen("login"); return; }
      const userData = await userRes.json();
      setUser(userData.user);
      const pluginsData = await pluginsRes.json();
      setPlugins(pluginsData.plugins || []);
      setScreen("app");
      // Load pinned chats (non-blocking)
      fetch('/api/conversations/pinned', { credentials: 'include' })
        .then(r => r.ok ? r.json() : { conversations: [] })
        .then(d => setPinnedChats(d.conversations || []))
        .catch(() => {});
    } catch { setScreen("login"); }
  };

  // Init: check session
  useEffect(() => {
    const params = new URLSearchParams(window.location.search);

    // Reset password
    if (params.get('reset')) {
      setResetToken(params.get('reset'));
      setScreen("reset");
      return;
    }

    // Verified email
    if (params.get('verified')) {
      showToast('Email verified successfully!', 'success');
      window.history.replaceState({}, '', '/');
    }

    // Check auth
    (async () => {
      try {
        const res = await fetch('/api/auth/verify', { credentials: 'include' });
        const data = await res.json();
        if (data.authenticated) { await loadApp(); }
        else { setScreen("login"); }
      } catch { setScreen("login"); }
    })();
  }, []);

  const handleAuth = () => loadApp();

  const handleLogout = async () => {
    await fetch('/api/auth/logout', { method: 'POST', credentials: 'include' });
    setUser(null); setPlugins([]); setScreen("login");
  };

  const openToolChat = (tool) => setNav("chat-" + tool.id);
  const activeChatTool = nav.startsWith("chat-") ? plugins.find(t => t.id === nav.replace("chat-", "")) : null;

  // Sync nav to browser history so back/forward buttons work within the app
  React.useEffect(() => {
    localStorage.setItem('lastNav', nav);
    const currentHash = window.location.hash.slice(1);
    if (currentHash !== nav) {
      window.history.pushState({ nav }, '', `#${nav}`);
    }
  }, [nav]);

  // Handle browser back/forward buttons
  useEffect(() => {
    const onPopState = (e) => {
      const navTarget = e.state?.nav || window.location.hash.slice(1) || 'dashboard';
      setNav(navTarget);
    };
    window.addEventListener('popstate', onPopState);
    return () => window.removeEventListener('popstate', onPopState);
  }, []);

  const toggleFavorite = async (pluginId) => {
    const currentFavs = user?.favorite_plugins || [];
    const isFav = currentFavs.includes(pluginId);
    const newFavs = isFav ? currentFavs.filter(id => id !== pluginId) : [...currentFavs, pluginId];
    const favValue = newFavs.length > 0 ? newFavs : null;
    setUser(prev => ({ ...prev, favorite_plugins: favValue }));
    try {
      await fetch('/api/favorites', { method: 'PUT', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ favorites: newFavs }) });
    } catch {
      setUser(prev => ({ ...prev, favorite_plugins: currentFavs.length > 0 ? currentFavs : null }));
    }
  };

  // Update page title
  useEffect(() => { document.title = APP_NAME; }, []);

  // Check for first-time welcome
  useEffect(() => {
    if (screen === 'app' && !localStorage.getItem('welcomed')) {
      setShowWelcome(true);
    }
  }, [screen]);

  // Loading
  if (screen === "loading") {
    return (
      <div style={{ minHeight: "100vh", background: BG, display: "flex", alignItems: "center", justifyContent: "center", fontFamily: font }}>
        <div style={{ color: SUBTEXT, fontSize: 14 }}>Loading...</div>
      </div>
    );
  }

  // Auth screens
  if (screen === "login") return <LoginScreen onNavigate={setScreen} onAuth={handleAuth} />;
  if (screen === "signup") return <SignupScreen onNavigate={setScreen} onAuth={handleAuth} />;
  if (screen === "forgot") return <ForgotScreen onNavigate={setScreen} />;
  if (screen === "reset") return <ResetPasswordScreen token={resetToken} onNavigate={setScreen} />;
  if (screen === "pricing") return <PricingScreen onNavigate={setScreen} />;

  const dismissWelcome = () => {
    setShowWelcome(false);
    localStorage.setItem('welcomed', '1');
  };

  // Resend email verification
  const resendVerification = async () => {
    try {
      const res = await fetch('/api/auth/resend-verify', { method: 'POST', credentials: 'include' });
      if (res.ok) showToast('Verification email sent!', 'success');
      else showToast('Could not send verification email.', 'error');
    } catch { showToast('Could not send verification email.', 'error'); }
  };

  // Main app
  const th = theme; // shorthand
  const bg = th === 'light' ? LIGHT.bg : BG;
  const surface = th === 'light' ? LIGHT.surface : SURFACE;
  const surface2 = th === 'light' ? LIGHT.surface2 : SURFACE2;
  const border = th === 'light' ? LIGHT.border : BORDER;
  const text = th === 'light' ? LIGHT.text : TEXT;
  const subtext = th === 'light' ? LIGHT.subtext : SUBTEXT;
  const muted = th === 'light' ? LIGHT.muted : MUTED;
  const inputBg = th === 'light' ? (LIGHT.inputBg || "#f7f7f7") : "#0f0f11";

  return (
    <ThemeContext.Provider value={{ mode: theme, toggle: toggleTheme, bg, surface, surface2, border, text, subtext, muted, inputBg }}>
      <div style={{ display: "flex", height: "100vh", background: bg, fontFamily: font, color: text, overflow: "hidden" }}>
        <div>
          <Sidebar
            active={activeChatTool ? "chat-" + activeChatTool.id : nav}
            onNav={(id) => { if (id.startsWith("chat-")) { const t = plugins.find(t => t.id === id.replace("chat-", "")); if (t) openToolChat(t); } else { setNav(id); } }}
            collapsed={collapsed}
            onCollapse={() => setCollapsed(c => !c)}
            onLogout={handleLogout}
            user={user}
            plugins={plugins}
            theme={theme}
            onToggleTheme={toggleTheme}
            pinnedChats={pinnedChats}
            onOpenPinnedChat={(c) => { setPendingConvoId(c.id); setNav("chat-" + c.plugin_id); }}
          />
        </div>

        <div style={{ flex: 1, overflowY: activeChatTool ? "hidden" : "auto", display: "flex", flexDirection: "column" }}>
          {/* Email verification banner */}
          {user && !user.email_verified && (
            <div style={{ background: ORANGE, color: "#fff", textAlign: "center", padding: "10px 20px", fontSize: 13, fontWeight: 500, flexShrink: 0 }}>
              Please verify your email.{" "}
              <span onClick={resendVerification} style={{ color: "#fff", textDecoration: "underline", fontWeight: 700, cursor: "pointer" }}>Resend verification</span>
            </div>
          )}

          {activeChatTool
            ? <ChatView key={activeChatTool.id} tool={activeChatTool} theme={theme} user={user} onMessageSent={() => setUser(prev => ({ ...prev, messages_used: (prev.messages_used || 0) + 1 }))} initialConversationId={pendingConvoId} onConversationLoaded={() => setPendingConvoId(null)} onConversationChange={(id) => { if (id) localStorage.setItem('lastConvoId', id); else localStorage.removeItem('lastConvoId'); }} onPinnedChange={() => fetch('/api/conversations/pinned', { credentials: 'include' }).then(r => r.ok ? r.json() : { conversations: [] }).then(d => setPinnedChats(d.conversations || [])).catch(() => {})} />
            : nav === "dashboard" ? <DashboardHome onOpenTool={openToolChat} user={user} plugins={plugins} theme={theme} />
            : nav === "tools" ? <ToolsPage onOpenTool={openToolChat} plugins={plugins} user={user} onToggleFavorite={toggleFavorite} />
            : nav === "settings" ? <SettingsPage user={user} onUpdate={loadApp} theme={theme} />
            : nav === "training" ? <TrainingPage user={user} theme={theme} />
            : nav === "admin" && user?.role === 'admin' ? <AdminPanel plugins={plugins} theme={theme} onPluginsChange={loadPlugins} />
            : <DashboardHome onOpenTool={openToolChat} user={user} plugins={plugins} theme={theme} />
          }
        </div>

        {/* Welcome overlay */}
        {showWelcome && (
          <div onClick={dismissWelcome} style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.7)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 100, cursor: "pointer" }}>
            <div onClick={e => e.stopPropagation()} style={{ background: surface, border: `1px solid ${border}`, borderRadius: 16, padding: 48, maxWidth: 480, width: "90%", textAlign: "center" }}>
              <div style={{ fontSize: 40, marginBottom: 16 }}>👋</div>
              <h2 style={{ margin: "0 0 12px", fontSize: 22, fontWeight: 800, color: text }}>{APP_NAME}</h2>
              <p style={{ fontSize: 14, color: subtext, marginBottom: 24, lineHeight: 1.6 }}>Here are your AI tools. Click any tool to get started.</p>
              <Btn onClick={dismissWelcome} fullWidth>Let's Go</Btn>
            </div>
          </div>
        )}
      </div>
    </ThemeContext.Provider>
  );
}

// ═══════════════════════════════════════════════════════
// RENDER
// ═══════════════════════════════════════════════════════

ReactDOM.createRoot(document.getElementById('app')).render(React.createElement(App));
