// Main app shell — sidebar, topbar, page routing, drawer, tour, confetti
const { useState, useEffect, useRef, useCallback } = React;

const DEFAULTS = /*EDITMODE-BEGIN*/{
  "theme": "light",
  "accent": "#ff4400",
  "density": "comfortable",
  "fontPair": "jetbrains",
  "rightPane": "readme",
  "demoValidation": "auto",
  "demoPhase": "auto",
  "showTour": false,
  "page": "create"
}/*EDITMODE-END*/;

const FONT_PAIRS = {
  jetbrains: { display: "'Archivo Black', sans-serif",    mono: "'JetBrains Mono', ui-monospace, monospace" },
  bebas:     { display: "'Bebas Neue', sans-serif",       mono: "'Space Mono', ui-monospace, monospace" },
  anton:     { display: "'Anton', sans-serif",            mono: "'JetBrains Mono', ui-monospace, monospace" },
  allmono:   { display: "'JetBrains Mono', ui-monospace, monospace", mono: "'JetBrains Mono', ui-monospace, monospace" },
};

// Restore theme from localStorage so it doesn't flash
(function() {
  const saved = localStorage.getItem('devex-theme');
  if (saved) document.documentElement.dataset.theme = saved;
})();

function App() {
  const I = window.I;
  const { ACTIVITY } = window.DEVEX_DATA;
  const [tweaks, setTweak] = window.useTweaks({
    ...DEFAULTS,
    theme: localStorage.getItem('devex-theme') || DEFAULTS.theme,
  });

  // Server-provided user (null if not logged in)
  const serverUser = window.DEVEX_INIT?.user || null;
  const [loggedIn, setLoggedIn] = useState(!!serverUser);

  const userLogin = serverUser?.login || 'user';
  const avatarLetter = userLogin.charAt(0).toUpperCase();

  useEffect(() => {
    const root = document.documentElement;
    root.dataset.theme = tweaks.theme;
    localStorage.setItem('devex-theme', tweaks.theme);
    root.style.setProperty('--accent', tweaks.accent);
    root.style.setProperty('--accent-tint', hexToTint(tweaks.accent, 0.10));
    root.style.setProperty('--density', tweaks.density === 'compact' ? '0.78' : '1');
    const fp = FONT_PAIRS[tweaks.fontPair] || FONT_PAIRS.jetbrains;
    root.style.setProperty('--display', fp.display);
    root.style.setProperty('--mono', fp.mono);
  }, [tweaks]);

  const [readmeOpen, setReadmeOpen] = useState(false);
  const [tourOpen, setTourOpen] = useState(false);
  const [collapsed, setCollapsed] = useState(false);
  const [feedbackOpen, setFeedbackOpen] = useState(false);

  useEffect(() => {
    if (tweaks.showTour) setTourOpen(true);
  }, [tweaks.showTour]);

  const fireConfetti = useCallback(() => confettiBurst(tweaks.accent), [tweaks.accent]);

  const handleLogout = () => { window.location.href = '/auth/logout'; };

  if (!loggedIn) return <LoginPage onLogin={() => { window.location.href = '/auth/login'; }} />;

  return (
    <div className={`app ${tweaks.density === 'compact' ? 'compact' : ''} ${collapsed ? 'collapsed' : ''}`}>
      {/* Sidebar */}
      <aside className="sidebar">
        <div className="brand">
          <div className="brand-mark">D</div>
          {!collapsed && <div className="brand-name">DevEx</div>}
          {!collapsed && <div className="brand-tag">v2.0</div>}
          <button className="collapse-btn" onClick={() => setCollapsed(c => !c)} title={collapsed ? 'Expand' : 'Collapse'} aria-label="Toggle sidebar">
            <svg width="10" height="10" viewBox="0 0 10 10" fill="none" stroke="currentColor" strokeWidth="1.6">
              {collapsed ? <path d="M3 2l3 3-3 3"/> : <path d="M7 2L4 5l3 3"/>}
            </svg>
          </button>
        </div>
        <nav className="nav">
          {!collapsed && <div className="nav-section">Workspace</div>}
          {[
            { id: 'create',      label: 'Create',       icon: 'Plus' },
            { id: 'repos',       label: 'Repositories', icon: 'Folder' },
            { id: 'updates',     label: 'Updates',      icon: 'GitBranch' },
            { id: 'templates',   label: 'Templates',    icon: 'Cube' },
            { id: 'deployments', label: 'Deployments',  icon: 'Cloud' },
          ].map(item => {
            const Glyph = I[item.icon];
            return (
              <div key={item.id}
                   className={`nav-item ${tweaks.page === item.id ? 'active' : ''}`}
                   onClick={() => setTweak('page', item.id)}
                   title={collapsed ? item.label : ''}>
                <span className="nav-icon">{Glyph && <Glyph size={14}/>}</span>
                <span className="label-text">{item.label}</span>
              </div>
            );
          })}
        </nav>
        <div className="sidebar-foot">
          <div className="avatar">{avatarLetter}</div>
          {!collapsed && (
            <div className="user-meta">
              <span className="name">{userLogin}</span>
              <span className="org">devex</span>
            </div>
          )}
          <button className="icon-btn logout-btn" title="Log out" aria-label="Log out"
                  onClick={handleLogout}
                  style={{ width: 28, height: 28, marginLeft: collapsed ? 0 : 'auto' }}>
            <I.LogOut size={13}/>
          </button>
        </div>
      </aside>

      {/* Main */}
      <div className="main">
        <div className="topbar">
          <div className="crumbs">
            <span>workspace</span>
            <span className="sep">/</span>
            <span className="here">{tweaks.page === 'create' ? 'new repository' : tweaks.page}</span>
          </div>
          <div className="topbar-actions">
            <div className="pill"><span className="live-dot"/>github · connected</div>
            <button className="icon-btn" onClick={() => setTourOpen(true)} title="Restart tour">
              <I.Compass size={14} />
            </button>
            <button className="icon-btn" onClick={() => setFeedbackOpen(true)} title="Send feedback">
              <I.Megaphone size={14} />
            </button>
            <button className="icon-btn" onClick={() => setTweak('theme', tweaks.theme === 'light' ? 'dark' : 'light')} title="Toggle theme">
              {tweaks.theme === 'light' ? <I.Moon size={14} /> : <I.Sun size={14} />}
            </button>
            <NotificationsButton accent={tweaks.accent} userEmail={serverUser?.email || ''} />
          </div>
        </div>

        <main className="page">
          {tweaks.page === 'create' && (
            <>
              <div className="page-head">
                <h1 className="page-title">New<br/><span className="accent">repository.</span></h1>
                <p className="page-sub">// compose · push · deploy</p>
              </div>
              <div className="body-grid">
                <window.Creator
                  tweaks={tweaks}
                  onOpenReadme={() => setReadmeOpen(true)}
                  onTriggerConfetti={fireConfetti}
                />
                <RightPane tweaks={tweaks} setTweak={setTweak} />
              </div>
            </>
          )}
          {tweaks.page === 'repos'       && <window.ReposPage/>}
          {tweaks.page === 'updates'     && <window.UpdatesPage/>}
          {tweaks.page === 'templates'   && <window.TemplatesPage/>}
          {tweaks.page === 'deployments' && <window.DeploymentsPage/>}
        </main>
      </div>

      {/* Drawer */}
      <ReadmeDrawer open={readmeOpen} onClose={() => setReadmeOpen(false)} />

      {/* Tour */}
      {tourOpen && <Tour onClose={() => { setTourOpen(false); setTweak('showTour', false); }} />}

      {/* Feedback */}
      {feedbackOpen && <FeedbackModal page={tweaks.page} onClose={() => setFeedbackOpen(false)} />}

      {/* Mobile nav */}
      <MobileNav page={tweaks.page} setPage={v => setTweak('page', v)} />

      {/* Tweaks */}
      <window.TweaksPanel title="Tweaks">
        <window.TweakSection title="Navigate">
          <window.TweakSelect label="Page" value={tweaks.page} options={[['create','Create'],['repos','Repositories'],['updates','Updates'],['templates','Templates'],['deployments','Deployments']]} onChange={v => setTweak('page', v)} />
        </window.TweakSection>
        <window.TweakSection title="Appearance">
          <window.TweakRadio label="Theme" value={tweaks.theme} options={[['light','Light'],['dark','Dark']]} onChange={v => setTweak('theme', v)} />
          <window.TweakColor label="Accent" value={tweaks.accent} onChange={v => setTweak('accent', v)} />
          <window.TweakRadio label="Density" value={tweaks.density} options={[['comfortable','Comfy'],['compact','Compact']]} onChange={v => setTweak('density', v)} />
          <window.TweakSelect label="Font pairing" value={tweaks.fontPair} options={[['jetbrains','Archivo Black + JetBrains'],['bebas','Bebas Neue + Space Mono'],['anton','Anton + JetBrains'],['allmono','All Mono']]} onChange={v => setTweak('fontPair', v)} />
        </window.TweakSection>
        <window.TweakSection title="Right pane">
          <window.TweakRadio label="View" value={tweaks.rightPane} options={[['readme','README'],['activity','Activity']]} onChange={v => setTweak('rightPane', v)} />
        </window.TweakSection>
        <window.TweakSection title="State demo">
          <window.TweakSelect label="Validation" value={tweaks.demoValidation} options={[['auto','Auto (typing)'],['checking','Checking'],['valid','Valid'],['invalid','Invalid']]} onChange={v => setTweak('demoValidation', v)} />
          <window.TweakSelect label="Submit phase" value={tweaks.demoPhase} options={[['auto','Auto'],['idle','Idle'],['creating','Creating'],['success','Success']]} onChange={v => setTweak('demoPhase', v)} />
          <window.TweakButton onClick={() => setTweak('showTour', true)}>Show onboarding tour</window.TweakButton>
          <window.TweakButton onClick={() => confettiBurst(tweaks.accent)}>Trigger confetti 🎉</window.TweakButton>
        </window.TweakSection>
      </window.TweaksPanel>
    </div>
  );
}

// ---------- Right pane ----------
function RightPane({ tweaks, setTweak }) {
  const I = window.I;
  const view = tweaks.rightPane;
  return (
    <div className="card slide-up" style={{ alignSelf: 'start', position: 'sticky', top: 80 }}>
      <div className="card-head" style={{ padding: 0, borderBottom: '1px solid var(--border)' }}>
        <div className="preview-tabs" style={{ flex: 1 }}>
          <button className={`preview-tab ${view === 'readme' ? 'active' : ''}`} onClick={() => setTweak('rightPane', 'readme')}>
            <I.Doc size={12}/> readme
          </button>
          <button className={`preview-tab ${view === 'activity' ? 'active' : ''}`} onClick={() => setTweak('rightPane', 'activity')}>
            <I.Clock size={12}/> activity
          </button>
        </div>
        <div style={{ padding: '10px 14px' }}>
          <span className="hint">{view === 'readme' ? 'auto-generated' : 'last 24h'}</span>
        </div>
      </div>
      {view === 'readme'   && <ReadmeContent/>}
      {view === 'activity' && <ActivityFeed/>}
    </div>
  );
}

function ReadmeContent() {
  const { SERVICES } = window.DEVEX_DATA;
  const svcList = SERVICES.slice(0, 3);
  const userLogin = window.DEVEX_INIT?.user?.login || 'org';
  return (
    <div className="readme">
      <h1>your-repo-name</h1>
      <div className="badge-row">
        <span className="rm-badge accent">DevEx</span>
        <span className="rm-badge">VPS</span>
        <span className="rm-badge">Traefik</span>
        {svcList.map(s => <span key={s.id} className="rm-badge">{s.name}</span>)}
      </div>
      <p>A scaffolded application bundle generated by DevEx. Includes routing, optional database, and a deployable app wired through docker compose.</p>
      <h2>Quickstart</h2>
      <pre>{`git clone git@github.com:${userLogin}/your-repo.git\ncd your-repo\nmake up`}</pre>
      <h2>Services</h2>
      <ul>
        {svcList.map(s => <li key={s.id}><code>{s.id}</code> — {s.desc}</li>)}
      </ul>
      <h2>Deploy</h2>
      <p>Push to <code>main</code>. The included GitHub Actions workflow builds and rolls a zero-downtime swap on your VPS.</p>
    </div>
  );
}

function ActivityFeed() {
  const I = window.I;
  const { ACTIVITY } = window.DEVEX_DATA;
  return (
    <div>
      {ACTIVITY.map((a, i) => {
        const Glyph = I[a.kind] || I.GitBranch;
        return (
          <div className="activity-row" key={i}>
            <div className="activity-time">{a.t}</div>
            <div className={`activity-icon ${a.icon}`}><Glyph size={12}/></div>
            <div className="activity-text">{a.text}</div>
          </div>
        );
      })}
    </div>
  );
}

// ---------- Drawer ----------
function ReadmeDrawer({ open, onClose }) {
  const I = window.I;
  return (
    <>
      <div className={`drawer-backdrop ${open ? 'open' : ''}`} onClick={onClose}/>
      <div className={`drawer ${open ? 'open' : ''}`}>
        <div className="drawer-head">
          <div className="drawer-title">README · Live Preview</div>
          <button className="icon-btn" onClick={onClose}><I.X size={14}/></button>
        </div>
        <div className="drawer-body"><ReadmeContent/></div>
      </div>
    </>
  );
}

// ---------- Tour ----------
const TOUR_STEPS = [
  { sel: '[data-tour="tabs"]',     title: 'TWO PATHS',   body: 'Spin up a full multi-service VPS app, or fork from a curated repo template. Switch any time.' },
  { sel: '[data-tour="name"]',     title: 'NAME IT',     body: 'As you type, DevEx checks GitHub in real time. Border turns green when available. Hit Shuffle for an instant name.' },
  { sel: '[data-tour="services"]', title: 'COMPOSE',     body: 'Click any service to add it. Each card generates docker-compose entries and Traefik routes automatically.' },
  { sel: '[data-tour="submit"]',   title: 'ONE COMMAND', body: 'Push the composed repo to GitHub with topics applied.' },
];

function Tour({ onClose }) {
  const [step, setStep] = useState(0);
  const [rect, setRect] = useState(null);
  useEffect(() => {
    const place = () => {
      const el = document.querySelector(TOUR_STEPS[step].sel);
      if (!el) { setRect(null); return; }
      const r = el.getBoundingClientRect();
      setRect({ x: r.left, y: r.top, w: r.width, h: r.height });
    };
    place();
    window.addEventListener('resize', place);
    const t = setInterval(place, 250);
    return () => { window.removeEventListener('resize', place); clearInterval(t); };
  }, [step]);
  if (!rect) return null;
  const pad = 14, popHeight = 200;
  const placeBelow = rect.y + rect.h + pad + popHeight < window.innerHeight;
  const popY = placeBelow ? rect.y + rect.h + pad : Math.max(20, rect.y - pad - popHeight);
  const popX = Math.min(window.innerWidth - 340, Math.max(20, rect.x));
  const next = () => step < TOUR_STEPS.length - 1 ? setStep(s => s + 1) : onClose();
  const prev = () => setStep(s => Math.max(0, s - 1));
  return (
    <>
      <div className="tour-back" onClick={onClose}/>
      <div className="tour-spotlight" style={{ left: rect.x - 6, top: rect.y - 6, width: rect.w + 12, height: rect.h + 12 }}/>
      <div className="tour-popover" style={{ left: popX, top: popY }}>
        <div className="tp-head">
          <span><span className="tp-step">{String(step + 1).padStart(2,'0')}</span> / {String(TOUR_STEPS.length).padStart(2,'0')}</span>
          <span>onboarding</span>
        </div>
        <div className="tp-body">
          <strong>{TOUR_STEPS[step].title}</strong>
          {TOUR_STEPS[step].body}
        </div>
        <div className="tp-foot">
          <button className="ghost-btn" onClick={onClose}>Skip</button>
          <div style={{ display: 'flex', gap: 8 }}>
            {step > 0 && <button className="ghost-btn" onClick={prev}>Back</button>}
            <button className="cta" style={{ width: 'auto' }} onClick={next}>
              <span className="cta-main" style={{ padding: '10px 14px' }}>{step === TOUR_STEPS.length - 1 ? 'Finish' : 'Next →'}</span>
            </button>
          </div>
        </div>
      </div>
    </>
  );
}

// ---------- Feedback Modal ----------
function FeedbackModal({ page, onClose }) {
  const I = window.I;
  const [category, setCategory] = useState('idea');
  const [comment, setComment] = useState('');
  const [sent, setSent] = useState(false);

  const send = () => {
    if (!comment.trim()) return;
    setSent(true);
    setTimeout(() => onClose(), 1400);
  };

  const cats = [
    { id: 'bug',   label: 'Bug',   sym: '✕', desc: 'Something is broken' },
    { id: 'idea',  label: 'Idea',  sym: '+', desc: 'Suggest an improvement' },
    { id: 'praise', label: 'Praise', sym: '✓', desc: 'Tell us what works' },
  ];

  return (
    <>
      <div className="drawer-backdrop open" onClick={onClose}/>
      <div style={{ position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', width: 'min(480px, 92vw)', background: 'var(--bg)', border: '1px solid var(--border-strong)', zIndex: 100, display: 'flex', flexDirection: 'column' }} className="slide-up">
        <div className="card-head">
          <div className="card-title"><span className="pre">▍</span> Send feedback</div>
          <button className="icon-btn" onClick={onClose}><I.X size={14}/></button>
        </div>
        {sent ? (
          <div style={{ padding: 40, textAlign: 'center', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 14 }}>
            <div style={{ width: 48, height: 48, background: 'var(--accent)', color: '#fff', display: 'grid', placeItems: 'center' }}><I.Check size={24}/></div>
            <div style={{ fontFamily: 'var(--display)', fontSize: 22, textTransform: 'uppercase', letterSpacing: '0.02em' }}>Thanks · received</div>
            <div style={{ fontFamily: 'var(--mono)', fontSize: 12, color: 'var(--muted)' }}>// logged to platform-eng/feedback</div>
          </div>
        ) : (
          <div style={{ padding: 20, display: 'flex', flexDirection: 'column', gap: 18 }}>
            <div className="field">
              <div className="field-label"><span>Category</span></div>
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', border: '1px solid var(--border)' }}>
                {cats.map((c, i) => (
                  <button key={c.id} onClick={() => setCategory(c.id)}
                          style={{ padding: '14px 10px', background: category === c.id ? 'var(--text)' : 'var(--bg)', color: category === c.id ? 'var(--bg)' : 'var(--text)', border: 0, borderRight: i < 2 ? '1px solid var(--border)' : 0, fontFamily: 'var(--mono)', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4, cursor: 'pointer' }}>
                    <span style={{ fontFamily: 'var(--display)', fontSize: 18, color: 'var(--accent)' }}>{c.sym}</span>
                    <span style={{ fontSize: 12, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.08em' }}>{c.label}</span>
                    <span style={{ fontSize: 10, color: category === c.id ? 'rgba(255,255,255,0.6)' : 'var(--muted)' }}>{c.desc}</span>
                  </button>
                ))}
              </div>
            </div>
            <div className="field">
              <div className="field-label">
                <span>Comment</span>
                <span className="right" style={{ fontSize: 10 }}>page · <span style={{ color: 'var(--accent)' }}>{page}</span></span>
              </div>
              <textarea value={comment} onChange={e => setComment(e.target.value)}
                        placeholder={category === 'bug' ? 'Steps to reproduce…' : category === 'idea' ? 'What would make this faster?' : 'What did we get right?'}
                        style={{ width: '100%', minHeight: 120, border: '1px solid var(--border)', background: 'var(--bg)', padding: 12, fontFamily: 'var(--mono)', fontSize: 13, color: 'var(--text)', resize: 'vertical', outline: 'none' }}/>
            </div>
            <div style={{ display: 'flex', gap: 10, justifyContent: 'flex-end' }}>
              <button className="ghost-btn" onClick={onClose}>Cancel</button>
              <button className="cta" style={{ width: 'auto' }} onClick={send} disabled={!comment.trim()}>
                <span className="cta-main" style={{ padding: '12px 18px' }}>Send <I.Arrow size={13}/></span>
              </button>
            </div>
          </div>
        )}
      </div>
    </>
  );
}

// ---------- Confetti ----------
function confettiBurst(color = '#ff4400') {
  const canvas = document.getElementById('confetti');
  if (!canvas) return;
  const ctx = canvas.getContext('2d');
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  const N = 140;
  const colors = [color, '#0a0a0a', '#ffffff', '#777777'];
  const parts = Array.from({ length: N }, () => ({
    x: window.innerWidth / 2 + (Math.random() - 0.5) * 200,
    y: window.innerHeight / 2,
    vx: (Math.random() - 0.5) * 14,
    vy: -Math.random() * 14 - 4,
    size: 4 + Math.random() * 6,
    color: colors[Math.floor(Math.random() * colors.length)],
    life: 0, rot: Math.random() * Math.PI, vr: (Math.random() - 0.5) * 0.4,
  }));
  let raf;
  const tick = () => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    let alive = false;
    parts.forEach(p => {
      p.vy += 0.32; p.x += p.vx; p.y += p.vy; p.rot += p.vr; p.life++;
      if (p.y < canvas.height + 30 && p.life < 200) {
        alive = true;
        ctx.save(); ctx.translate(p.x, p.y); ctx.rotate(p.rot);
        ctx.fillStyle = p.color;
        ctx.fillRect(-p.size/2, -p.size/2, p.size, p.size * 0.4);
        ctx.restore();
      }
    });
    if (alive) raf = requestAnimationFrame(tick);
    else ctx.clearRect(0, 0, canvas.width, canvas.height);
  };
  cancelAnimationFrame(raf);
  tick();
}

function hexToTint(hex, alpha) {
  const m = /^#?([a-f0-9]{6})$/i.exec(hex);
  if (!m) return `rgba(255, 68, 0, ${alpha})`;
  const n = parseInt(m[1], 16);
  return `rgba(${(n>>16)&255}, ${(n>>8)&255}, ${n&255}, ${alpha})`;
}

// ---------- Notifications + Newsletter ----------
function NotificationsButton({ accent, userEmail }) {
  const I = window.I;
  const ref = useRef(null);
  const [open, setOpen] = useState(false);
  const [tab, setTab] = useState('inbox');
  const [unread, setUnread] = useState(3);
  const [email, setEmail] = useState(userEmail || '');
  const [topics, setTopics] = useState({ releases: true, security: true, digest: true, blog: false, events: false });
  const [freq, setFreq] = useState('weekly');
  const [submitted, setSubmitted] = useState(false);

  const NOTIFS = [
    { id: 1, icon: 'Lock',      tone: 'warn',   text: 'Security update: traefik 3.2 patches CVE-2025-0418', meta: 'iron-bastion · 2m', unread: true },
    { id: 2, icon: 'Cloud',     tone: 'ok',     text: 'Deployment succeeded · silent-foundry',              meta: 'production · 14m', unread: true },
    { id: 3, icon: 'GitBranch', tone: 'info',   text: '4 update PRs ready for review',                      meta: 'updates · 1h', unread: true },
    { id: 4, icon: 'User',      tone: 'info',   text: 'lin.h invited you to platform-eng/runway-rs',        meta: '3h', unread: false },
    { id: 5, icon: 'Tag',       tone: 'accent', text: 'DevEx v2.0 changelog published',                     meta: 'yesterday', unread: false },
  ];

  useEffect(() => {
    if (!open) return;
    const onDoc = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', onDoc);
    return () => document.removeEventListener('mousedown', onDoc);
  }, [open]);

  const toggleTopic = (k) => setTopics(t => ({ ...t, [k]: !t[k] }));

  const submit = async () => {
    if (!email.trim()) return;
    try {
      const r = await fetch('/api/subscribe', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email }),
      });
      const data = await r.json();
      if (data.ok || r.status === 409) {
        setSubmitted(true);
        confettiBurst(accent);
        setTimeout(() => setSubmitted(false), 3000);
      }
    } catch (_) {
      setSubmitted(true);
      setTimeout(() => setSubmitted(false), 3000);
    }
  };

  return (
    <div className="notif-anchor" ref={ref}>
      <button className="icon-btn" onClick={() => setOpen(o => !o)} aria-label="Notifications">
        <I.Bell size={14} />
        {unread > 0 && <span className="notif-badge">{unread}</span>}
      </button>

      {open && (
        <div className="notif-pop">
          <div className="notif-head">
            <div className="notif-tabs">
              <button className={`notif-tab ${tab === 'inbox' ? 'active' : ''}`} onClick={() => setTab('inbox')}>
                Inbox <span className="notif-tab-count">{NOTIFS.filter(n=>n.unread).length}</span>
              </button>
              <button className={`notif-tab ${tab === 'subscribe' ? 'active' : ''}`} onClick={() => setTab('subscribe')}>
                Subscribe
              </button>
            </div>
            <button className="notif-x" onClick={() => setOpen(false)} aria-label="Close"><I.X size={12}/></button>
          </div>

          {tab === 'inbox' && (
            <div className="notif-body">
              <div className="notif-list">
                {NOTIFS.map(n => {
                  const Glyph = I[n.icon] || I.Bell;
                  return (
                    <div className={`notif-row ${n.unread ? 'unread' : ''}`} key={n.id}>
                      <div className={`notif-icon tone-${n.tone}`}><Glyph size={11}/></div>
                      <div className="notif-text">
                        <div className="notif-line">{n.text}</div>
                        <div className="notif-meta">{n.meta}</div>
                      </div>
                      {n.unread && <span className="notif-dot"/>}
                    </div>
                  );
                })}
              </div>
              <div className="notif-foot">
                <button className="notif-link" onClick={() => setUnread(0)}>Mark all read</button>
                <button className="notif-link">View all →</button>
              </div>
            </div>
          )}

          {tab === 'subscribe' && (
            <div className="notif-body">
              {!submitted ? (
                <div className="sub-form">
                  <div className="sub-eyebrow">// devex newsletter</div>
                  <div className="sub-title">Stay shipped.</div>
                  <div className="sub-sub">Releases, security advisories, and platform news. No fluff.</div>
                  <label className="sub-label">Email</label>
                  <div className="input-wrap" style={{ marginBottom: 12 }}>
                    <span className="input-prefix">@</span>
                    <input type="email" value={email} onChange={e => setEmail(e.target.value)} placeholder="you@company.com"
                           style={{ flex: 1, padding: '10px 12px', border: 0, outline: 'none', background: 'transparent', color: 'var(--text)', fontFamily: 'var(--mono)', fontSize: 12 }}/>
                  </div>
                  <label className="sub-label">Topics</label>
                  <div className="sub-topics">
                    {[['releases','Product releases','every release'],['security','Security advisories','critical only'],['digest','Weekly digest','curated highlights'],['blog','Engineering blog','deep dives'],['events','Events & webinars','community']].map(([k, label, hint]) => (
                      <button key={k} className={`sub-topic ${topics[k] ? 'on' : ''}`} onClick={() => toggleTopic(k)}>
                        <span className="sub-check">{topics[k] ? '✓' : ''}</span>
                        <span className="sub-topic-text">
                          <span className="sub-topic-label">{label}</span>
                          <span className="sub-topic-hint">{hint}</span>
                        </span>
                      </button>
                    ))}
                  </div>
                  <label className="sub-label">Cadence</label>
                  <div className="sub-cadence">
                    {[['daily','Daily'],['weekly','Weekly'],['monthly','Monthly']].map(([v,l]) => (
                      <button key={v} className={`cad-opt ${freq === v ? 'on' : ''}`} onClick={() => setFreq(v)}>{l}</button>
                    ))}
                  </div>
                  <button className="cta" disabled={!email.trim()} onClick={submit} style={{ marginTop: 14 }}>
                    <span className="cta-main">subscribe →</span>
                  </button>
                  <div className="sub-fine">Unsubscribe anytime. We only email when there's a reason.</div>
                </div>
              ) : (
                <div className="sub-success">
                  <div className="sub-success-tick">✓</div>
                  <div className="sub-success-title">YOU'RE IN.</div>
                  <div className="sub-success-sub">Confirmation sent to <strong>{email}</strong>.<br/>First digest lands {freq === 'daily' ? 'tomorrow' : freq === 'weekly' ? 'Monday' : 'on the 1st'}.</div>
                  <div className="sub-success-meta">
                    <span className="muted">// subscribed to</span>
                    <span>{Object.keys(topics).filter(k => topics[k]).length} topics · {freq}</span>
                  </div>
                </div>
              )}
            </div>
          )}
        </div>
      )}
    </div>
  );
}

// ---------- Login page ----------
function LoginPage({ onLogin }) {
  const I = window.I;
  const [pending, setPending] = useState(null);
  const [tick, setTick] = useState(0);

  useEffect(() => {
    const id = setInterval(() => setTick(t => t + 1), 1400);
    return () => clearInterval(id);
  }, []);

  const FEED = [
    { p: '$', t: 'devex auth init --org=platform-eng', cls: 'cmd' },
    { p: '→', t: 'awaiting credentials...', cls: 'muted' },
    { p: '✓', t: 'tls handshake · 12ms', cls: 'ok' },
    { p: '✓', t: 'oauth provider: github.com', cls: 'ok' },
    { p: '→', t: 'session token will be scoped to repo:write, workflow', cls: 'muted' },
    { p: '✓', t: 'org policy verified · sso optional', cls: 'ok' },
    { p: '$', t: '_', cls: 'cmd' },
  ];
  const visible = FEED.slice(0, Math.min(FEED.length, (tick % (FEED.length + 4)) + 1));

  const handle = (which) => {
    setPending(which);
    setTimeout(() => { window.location.href = '/auth/login'; }, 800);
  };

  return (
    <div className="login">
      <div className="login-left">
        <div className="login-brand">
          <div className="brand-mark" style={{ position: 'relative' }}>
            <span className="brand-tick"/>D
          </div>
          <div className="login-brand-name">DevEx</div>
          <div className="login-brand-tag">v2.0</div>
        </div>
        <div className="login-display">
          <div className="login-eyebrow">// authenticate</div>
          <h1 className="login-title">Ship faster.<br/>Skip the<br/><span className="accent">boilerplate.</span></h1>
          <p className="login-sub">Sign in to scaffold production-ready repos. Real-time validation. One-command deploy.</p>
        </div>
        <div className="login-feed">
          {visible.map((l, i) => (
            <div className="terminal-line" key={i}>
              <span className="prompt">{l.p}</span> <span className={l.cls}>{l.t}</span>
            </div>
          ))}
        </div>
        <div className="login-foot">
          <div className="login-foot-row"><span className="muted">// uptime</span><span>99.97%</span></div>
          <div className="login-foot-row"><span className="muted">// avg p50 scaffold</span><span>6.2s</span></div>
          <div className="login-foot-row">
            <span className="muted">// status</span>
            <span className="ok"><span className="live-dot"/> all systems nominal</span>
          </div>
        </div>
      </div>

      <div className="login-right">
        <div className="login-card">
          <div className="login-card-head">
            <div>
              <div className="login-eyebrow">[ 01 / 02 ]</div>
              <h2 className="login-card-title">Sign in</h2>
            </div>
            <span className="pill"><span className="live-dot"/>secure</span>
          </div>

          <button className={`auth-btn primary ${pending === 'github' ? 'pending' : ''}`}
                  disabled={!!pending} onClick={() => handle('github')}>
            <span className="auth-icon"><I.GitBranch size={16}/></span>
            <span className="auth-label">
              <span className="auth-main">{pending === 'github' ? 'Authorizing…' : 'Continue with GitHub'}</span>
              <span className="auth-sub">{pending === 'github' ? 'redirecting to github.com/login/oauth' : 'recommended · org-linked'}</span>
            </span>
            <span className="auth-arrow">→</span>
          </button>

          <button className={`auth-btn ${pending === 'sso' ? 'pending' : ''}`}
                  disabled={!!pending} onClick={() => handle('sso')}>
            <span className="auth-icon"><I.Lock size={16}/></span>
            <span className="auth-label">
              <span className="auth-main">{pending === 'sso' ? 'Authorizing…' : 'Continue with SSO'}</span>
              <span className="auth-sub">SAML · Okta · Google Workspace</span>
            </span>
            <span className="auth-arrow">→</span>
          </button>

          <div className="login-meta">
            <div className="login-meta-row"><span className="muted">// trust</span><span>SOC 2 · GDPR · ISO 27001</span></div>
            <div className="login-meta-row"><span className="muted">// session</span><span>scoped tokens, 24h TTL</span></div>
          </div>

          <div className="login-fine">
            By continuing you agree to the <a href="#" onClick={e => e.preventDefault()}>Terms</a> and <a href="#" onClick={e => e.preventDefault()}>Privacy Policy</a>.
          </div>
        </div>
      </div>
    </div>
  );
}

// ---------- Mobile nav ----------
function MobileNav({ page, setPage }) {
  const I = window.I;
  const items = [
    { id: 'create',      label: 'Create',   icon: 'Plus' },
    { id: 'repos',       label: 'Repos',    icon: 'Folder' },
    { id: 'updates',     label: 'Updates',  icon: 'GitBranch' },
    { id: 'templates',   label: 'Templates',icon: 'Cube' },
    { id: 'deployments', label: 'Deploy',   icon: 'Cloud' },
  ];
  return (
    <nav className="mobile-nav">
      {items.map(item => {
        const Glyph = I[item.icon];
        return (
          <button key={item.id}
                  className={`mobile-nav-item ${page === item.id ? 'active' : ''}`}
                  onClick={() => setPage(item.id)}>
            {Glyph && <Glyph size={18}/>}
            <span>{item.label}</span>
          </button>
        );
      })}
    </nav>
  );
}

// Mount
ReactDOM.createRoot(document.getElementById('root')).render(<App/>);
