// Additional impressive components for Paulyn's portfolio

// ─────────────────────────────────────────────────────────────
// Side Projects cards — placeholder but styled
// ─────────────────────────────────────────────────────────────
function SideProjects({ chromeGradient }) {
  const projects = [
    {
      n: '01',
      name: 'GoalBadger AI',
      tagline: 'AI-powered accountability for crushing your goals',
      description: 'Full-stack SaaS leveraging LLMs to decompose goals into daily tasks, adapt plans when you fall behind, and nudge you via SMS. Streak gamification and Stripe billing.',
      stack: ['Next.js', 'TypeScript', 'Supabase', 'LLM APIs', 'Trigger.dev'],
      impact: 'Waitlist open',
      icon: '✦',
      url: 'https://goalbadgerai.com',
    },
    {
      n: '02',
      name: 'PropFolio',
      tagline: 'Real estate portfolio intelligence dashboard',
      description: 'Investment management platform with market comps, amortization modeling, geographic heatmaps, and bulk CSV import with fuzzy column matching.',
      stack: ['Next.js', 'Firebase', 'Tailwind', 'Recharts', 'Leaflet'],
      impact: 'In progress',
      icon: '♡',
    },
    {
      n: '03',
      name: 'SignalPulse',
      tagline: 'Real-time market regime classifier for options traders',
      description: 'Ingests live market and options chain data, computes normalized signals, and classifies regimes. Local dashboard with trade setup scoring and paper journal.',
      stack: ['Python', 'Flask', 'pandas', 'SQLite', 'scipy'],
      impact: 'In progress',
      icon: '✧',
    },
  ];
  const [hover, setHover] = React.useState(null);
  const isMobile = window.innerWidth <= 768;

  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 20 }}>
      {projects.map((p, i) => {
        const active = hover === i;
        return (
          <div key={i} onMouseEnter={() => setHover(i)} onMouseLeave={() => setHover(null)}
            style={{
              position: 'relative', padding: 28, borderRadius: 20,
              background: 'var(--surface)', backdropFilter: 'blur(20px)',
              border: '1px solid var(--hairline)',
              transition: 'all 0.3s cubic-bezier(.2,.7,.3,1)',
              transform: active ? 'translateY(-6px)' : 'none',
              boxShadow: active ? '0 20px 50px rgba(255,158,199,0.25)' : 'none',
              cursor: 'pointer',
              minHeight: isMobile ? 180 : 260,
              display: 'flex', flexDirection: 'column',
              overflow: 'hidden',
            }}>
            {/* gradient border glow */}
            {active && (
              <div style={{ position: 'absolute', inset: -1, borderRadius: 20, background: 'var(--chrome)', opacity: 0.5, zIndex: -1, filter: 'blur(8px)' }} />
            )}
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 20 }}>
              <span style={{ fontFamily: '"JetBrains Mono", monospace', fontSize: 11, color: 'var(--muted)', letterSpacing: 2 }}>№ {p.n}</span>
              <span style={{ fontSize: 28, color: 'var(--accent)', lineHeight: 1, transition: 'transform 0.3s', transform: active ? 'rotate(20deg) scale(1.2)' : 'none' }}>{p.icon}</span>
            </div>
            <h3 style={{ fontFamily: '"Fraunces", serif', fontSize: 28, fontWeight: 400, margin: '0 0 6px', letterSpacing: -0.8, lineHeight: 1.1 }}>{p.name}</h3>
            <div style={{ fontFamily: '"Fraunces", serif', fontStyle: 'italic', fontSize: 13, color: 'var(--accent)', marginBottom: 14 }}>{p.tagline}</div>
            <p style={{ fontSize: 13, lineHeight: 1.6, color: 'var(--muted)', margin: '0 0 20px', flex: 1 }}>{p.description}</p>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 16 }}>
              {p.stack.map(s => (
                <span key={s} style={{ fontSize: 11, padding: '4px 10px', borderRadius: 10, background: 'var(--bubble-bg)', color: 'var(--fg)' }}>{s}</span>
              ))}
            </div>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', fontSize: 12 }}>
              <span style={{ color: 'var(--muted)' }}>Impact · <span style={{ color: 'var(--accent)' }}>{p.impact}</span></span>
              {p.url && <a href={p.url} target="_blank" rel="noreferrer" onClick={e => e.stopPropagation()} style={{ color: 'var(--accent)', fontWeight: 600, textDecoration: 'none', transition: 'transform 0.2s', transform: active ? 'translateX(4px)' : 'none', display: 'inline-block' }}>view →</a>}
            </div>
          </div>
        );
      })}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// "Now" status widget — what I'm up to
// ─────────────────────────────────────────────────────────────
function NowWidget() {
  const items = [
    { label: 'Shipping', value: 'GoalBadger AI — accountability SaaS', color: '#ff9ec7' },
    { label: 'Building', value: 'Every idea that sparks, I build it', color: '#a99eff' },
    { label: 'Exploring', value: 'AI as a creative engineering outlet', color: '#9ed3ff' },
    { label: 'Obsessed with', value: 'Turning ideas into shipped products', color: '#ffd4a3' },
  ];
  return (
    <div style={{ padding: 28, borderRadius: 20, background: 'var(--surface)', backdropFilter: 'blur(20px)', border: '1px solid var(--hairline)' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 20 }}>
        <div style={{ width: 10, height: 10, borderRadius: 5, background: '#6eff9e', boxShadow: '0 0 12px #6eff9e', animation: 'dotPulse 1.8s infinite' }} />
        <span style={{ fontFamily: '"JetBrains Mono", monospace', fontSize: 11, letterSpacing: 2, textTransform: 'uppercase', color: 'var(--muted)' }}>Now · live from atlanta</span>
      </div>
      {items.map((item, i) => (
        <div key={i} style={{ padding: '12px 0', borderTop: i > 0 ? '1px solid var(--hairline)' : 'none', display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <div style={{ width: 6, height: 6, borderRadius: 3, background: item.color }} />
            <span style={{ fontSize: 12, color: 'var(--muted)', letterSpacing: 0.5, textTransform: 'uppercase', fontWeight: 500 }}>{item.label}</span>
          </div>
          <span style={{ fontSize: 13, color: 'var(--fg)', fontFamily: '"Fraunces", serif', fontStyle: 'italic', textAlign: 'right' }}>{item.value}</span>
        </div>
      ))}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Command palette (⌘K / Ctrl+K)
// ─────────────────────────────────────────────────────────────
function CommandPalette() {
  const [open, setOpen] = React.useState(false);
  const [q, setQ] = React.useState('');
  const [idx, setIdx] = React.useState(0);
  const inputRef = React.useRef(null);

  const nav = (tab) => { window.__navigateTo?.(tab); setOpen(false); };
  const commands = [
    { icon: '🏠', label: 'Go to Home', hint: 'hero', action: () => nav('home') },
    { icon: '🎮', label: 'Go to Game', hint: 'sparkle hunt', action: () => nav('game') },
    { icon: '👤', label: 'Go to About', hint: 'bio + terminal', action: () => nav('about') },
    { icon: '✦', label: 'Go to Work', hint: 'timeline', action: () => nav('work') },
    { icon: '⚡', label: 'Go to Skills', hint: 'constellation', action: () => nav('skills') },
    { icon: '♕', label: 'Go to Patent', hint: 'rescue rover', action: () => nav('patent') },
    { icon: '💬', label: 'Go to Chat', hint: 'ask about paulyn', action: () => nav('chat') },
    { icon: '✉', label: 'Email Paulyn', hint: 'paulyn.oh1@gmail.com', action: () => window.location.href = 'mailto:paulyn.oh1@gmail.com' },
    { icon: 'in', label: 'Open LinkedIn', hint: 'linkedin.com/in/paulynoh', action: () => window.open('https://linkedin.com/in/paulynoh', '_blank') },
    { icon: '⌨', label: 'Open GitHub', hint: 'github.com/paulynoh-codes', action: () => window.open('https://github.com/paulynoh-codes', '_blank') },
    { icon: '↓', label: 'Download Resume', hint: '.docx', action: () => window.location.href = 'uploads/Paulyn_Oh-resume.docx' },
    { icon: '✨', label: 'Sparkle mode', hint: 'little treat', action: () => window.dispatchEvent(new CustomEvent('paulyn-sparkle')) },
    { icon: '🌓', label: 'Toggle theme', hint: 'dark/light', action: () => window.dispatchEvent(new CustomEvent('paulyn-toggle-theme')) },
  ];

  const filtered = commands.filter(c =>
    !q || c.label.toLowerCase().includes(q.toLowerCase()) || c.hint.toLowerCase().includes(q.toLowerCase())
  );

  React.useEffect(() => {
    const onKey = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') { e.preventDefault(); setOpen(o => !o); setQ(''); setIdx(0); }
      if (e.key === 'Escape') setOpen(false);
      if (open) {
        if (e.key === 'ArrowDown') { e.preventDefault(); setIdx(i => Math.min(i + 1, filtered.length - 1)); }
        if (e.key === 'ArrowUp') { e.preventDefault(); setIdx(i => Math.max(i - 1, 0)); }
        if (e.key === 'Enter') { e.preventDefault(); filtered[idx]?.action(); setOpen(false); }
      }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [open, filtered, idx]);

  React.useEffect(() => { if (open && inputRef.current) inputRef.current.focus(); }, [open]);
  React.useEffect(() => { setIdx(0); }, [q]);

  if (!open) return (
    <button onClick={() => setOpen(true)}
      style={{ position: 'fixed', bottom: 24, right: 24, zIndex: 40, padding: '10px 16px', borderRadius: 30,
        background: 'rgba(20,10,40,0.7)', backdropFilter: 'blur(20px)',
        border: '1px solid rgba(255,255,255,0.15)', color: '#f5f0ff',
        fontSize: 12, fontFamily: 'inherit', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 8,
        boxShadow: '0 8px 32px rgba(0,0,0,0.2)' }}>
      <span>⌘K</span>
      <span style={{ opacity: 0.6 }}>quick nav</span>
    </button>
  );

  return (
    <div onClick={() => setOpen(false)}
      style={{ position: 'fixed', inset: 0, zIndex: 100, background: 'rgba(10,5,20,0.5)', backdropFilter: 'blur(8px)',
        display: 'flex', alignItems: 'flex-start', justifyContent: 'center', paddingTop: 120 }}>
      <div onClick={e => e.stopPropagation()}
        style={{ width: 'min(560px, 90vw)', background: 'rgba(20,10,40,0.9)', backdropFilter: 'blur(30px)',
          border: '1px solid rgba(255,255,255,0.15)', borderRadius: 18,
          boxShadow: '0 30px 80px rgba(0,0,0,0.5), 0 0 0 1px rgba(255,158,199,0.2)',
          overflow: 'hidden', color: '#f5f0ff' }}>
        <div style={{ display: 'flex', alignItems: 'center', padding: '14px 18px', gap: 12, borderBottom: '1px solid rgba(255,255,255,0.1)' }}>
          <span style={{ fontSize: 16, opacity: 0.6 }}>✦</span>
          <input ref={inputRef} value={q} onChange={e => setQ(e.target.value)} placeholder="type to find anything…"
            style={{ flex: 1, background: 'transparent', border: 'none', outline: 'none', color: '#f5f0ff',
              fontSize: 15, fontFamily: 'inherit' }} />
          <span style={{ fontSize: 10, padding: '3px 7px', borderRadius: 4, background: 'rgba(255,255,255,0.1)', color: 'rgba(245,240,255,0.6)', fontFamily: '"JetBrains Mono", monospace' }}>ESC</span>
        </div>
        <div style={{ padding: 8, maxHeight: 400, overflow: 'auto' }}>
          {filtered.map((c, i) => (
            <button key={i} onClick={() => { c.action(); setOpen(false); }} onMouseEnter={() => setIdx(i)}
              style={{ display: 'flex', alignItems: 'center', gap: 14, width: '100%', padding: '10px 14px',
                background: i === idx ? 'rgba(255,158,199,0.15)' : 'transparent', border: 'none',
                borderRadius: 10, color: '#f5f0ff', cursor: 'pointer', textAlign: 'left', fontFamily: 'inherit' }}>
              <span style={{ width: 28, height: 28, borderRadius: 8, background: 'rgba(255,255,255,0.08)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 13 }}>{c.icon}</span>
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 14, fontWeight: 500 }}>{c.label}</div>
                <div style={{ fontSize: 11, color: 'rgba(245,240,255,0.5)', marginTop: 1 }}>{c.hint}</div>
              </div>
              {i === idx && <span style={{ fontSize: 12, color: '#ff9ec7' }}>↵</span>}
            </button>
          ))}
          {filtered.length === 0 && <div style={{ padding: 24, textAlign: 'center', fontSize: 13, color: 'rgba(245,240,255,0.5)' }}>nothing matches "{q}" · try another word ✦</div>}
        </div>
        <div style={{ padding: '10px 18px', borderTop: '1px solid rgba(255,255,255,0.1)', display: 'flex', gap: 16, fontSize: 10, color: 'rgba(245,240,255,0.5)', fontFamily: '"JetBrains Mono", monospace' }}>
          <span>↑↓ navigate</span><span>↵ select</span><span style={{ marginLeft: 'auto' }}>⌘K to toggle</span>
        </div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Konami code easter egg
// ─────────────────────────────────────────────────────────────
function KonamiEasterEgg() {
  const [triggered, setTriggered] = React.useState(false);
  const seq = React.useRef([]);
  const target = ['ArrowUp', 'ArrowUp', 'ArrowDown', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'ArrowLeft', 'ArrowRight', 'b', 'a'];

  React.useEffect(() => {
    const onKey = (e) => {
      seq.current.push(e.key.length === 1 ? e.key.toLowerCase() : e.key);
      if (seq.current.length > target.length) seq.current.shift();
      if (seq.current.join(',') === target.join(',')) {
        setTriggered(true);
        // mega sparkle
        for (let i = 0; i < 80; i++) {
          setTimeout(() => {
            const s = document.createElement('span');
            s.textContent = ['✦', '✧', '✨', '★', '♡', '♕'][Math.floor(Math.random() * 6)];
            s.style.cssText = `position:fixed;pointer-events:none;z-index:9999;left:50vw;top:50vh;color:${['#ff9ec7','#a99eff','#9ed3ff','#ffd4a3'][Math.floor(Math.random()*4)]};font-size:${16 + Math.random() * 24}px;transition:all 1.5s cubic-bezier(.2,.9,.3,1);transform:translate(-50%,-50%);opacity:1;`;
            document.body.appendChild(s);
            requestAnimationFrame(() => {
              const a = Math.random() * Math.PI * 2;
              const d = 200 + Math.random() * 400;
              s.style.transform = `translate(-50%,-50%) translate(${Math.cos(a)*d}px, ${Math.sin(a)*d}px) rotate(${(Math.random() - 0.5) * 720}deg) scale(0)`;
              s.style.opacity = '0';
            });
            setTimeout(() => s.remove(), 1500);
          }, i * 15);
        }
        setTimeout(() => setTriggered(false), 4000);
        seq.current = [];
      }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, []);

  if (!triggered) return null;
  return (
    <div style={{ position: 'fixed', inset: 0, zIndex: 9998, pointerEvents: 'none', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
      <div style={{ padding: '24px 40px', borderRadius: 20, background: 'rgba(20,10,40,0.9)', backdropFilter: 'blur(20px)',
        border: '1px solid rgba(255,158,199,0.5)', textAlign: 'center', animation: 'fadeIn 0.4s',
        boxShadow: '0 20px 80px rgba(255,158,199,0.4)' }}>
        <div style={{ fontFamily: '"Fraunces", serif', fontSize: 36, fontWeight: 400, background: 'linear-gradient(135deg, #ff9ec7, #a99eff)', WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent', marginBottom: 8 }}>
          ✦ you found it ✦
        </div>
        <div style={{ fontSize: 13, color: '#f5f0ff', opacity: 0.8 }}>secret sparkle mode unlocked · nice one</div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Live code snippet — animated typewriter of actual code
// ─────────────────────────────────────────────────────────────
function LiveCodeSnippet() {
  const code = `// How I think about AI workflows
class EngineeringAgent {
  context: TeamStandards;
  promptLibrary: Prompts;

  async ship(task: Feature) {
    const plan = await this.reason(task);
    const code = await this.draft(plan);
    const tests = await this.verify(code);
    return this.review(code, tests);
    // ✦ 3–5× velocity, same quality bar
  }
}`;
  const [shown, setShown] = React.useState(0);
  const [done, setDone] = React.useState(false);
  const ref = React.useRef(null);

  React.useEffect(() => {
    const io = new IntersectionObserver((entries) => {
      if (entries[0].isIntersecting && !done) {
        let i = 0;
        const id = setInterval(() => {
          i += 2;
          if (i >= code.length) { setShown(code.length); clearInterval(id); setDone(true); }
          else setShown(i);
        }, 20);
      }
    }, { threshold: 0.5 });
    if (ref.current) io.observe(ref.current);
    return () => io.disconnect();
  }, [done, code.length]);

  const displayed = code.slice(0, shown);
  // Simple syntax highlighting
  const highlight = (s) => {
    return s
      .replace(/(\/\/[^\n]*)/g, '<span style="color:#8a7ca0">$1</span>')
      .replace(/\b(class|const|async|await|return|this|new)\b/g, '<span style="color:#ff9ec7">$1</span>')
      .replace(/\b(EngineeringAgent|TeamStandards|Prompts|Feature)\b/g, '<span style="color:#a99eff">$1</span>')
      .replace(/\b(ship|reason|draft|verify|review)\b(?=\()/g, '<span style="color:#9ed3ff">$1</span>');
  };

  return (
    <div ref={ref} style={{ padding: 24, borderRadius: 16, background: '#0a0514', border: '1px solid rgba(255,255,255,0.1)', fontFamily: '"JetBrains Mono", monospace', fontSize: 13, lineHeight: 1.7, color: '#f5f0ff', position: 'relative', minHeight: 260, overflow: 'hidden' }}>
      <div style={{ display: 'flex', gap: 6, marginBottom: 16 }}>
        <span style={{ width: 10, height: 10, borderRadius: 5, background: '#ff5f57' }} />
        <span style={{ width: 10, height: 10, borderRadius: 5, background: '#febc2e' }} />
        <span style={{ width: 10, height: 10, borderRadius: 5, background: '#28c840' }} />
        <span style={{ marginLeft: 8, fontSize: 10, opacity: 0.5 }}>philosophy.ts</span>
      </div>
      <pre style={{ margin: 0, whiteSpace: 'pre-wrap', fontFamily: 'inherit' }} dangerouslySetInnerHTML={{ __html: highlight(displayed) + (done ? '' : '<span style="background:#ff9ec7;color:#0a0514;padding:0 2px">▊</span>') }} />
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Testimonial carousel — placeholders
// ─────────────────────────────────────────────────────────────
function TestimonialCarousel() {
  const items = [
    {
      quote: "I had the pleasure of working with Paulyn at T-Mobile. During my first year, Paulyn was instrumental in my growth and development — always eager to help and took on mentoring roles that were beyond her job description. She consistently fostered a positive work culture and her willingness to assist others made a significant impact on our team. I highly recommend her for any role that values teamwork, mentorship, and a strong work ethic.",
      author: "Henry Vy",
      org: "Full Stack Developer · T-Mobile",
    },
    {
      quote: "Paulyn is an excellent engineer! Her skills not only lie in front-end design and development, but in lead roles as well. From mentoring juniors to creating detailed design documents for new implementations, she has it covered. Any team would be lucky to have her!",
      author: "Asad Nawaz",
      org: "Java Backend Engineer · worked with Paulyn at T-Mobile",
    },
    {
      quote: "Paulyn is smart working and very enthusiastic. I worked with her on the One Experience & Styleguide project at Macy's. She is always committed to the quality of the work — React, GCP, Angular, Node, and mobile app development — and her positive attitude and zeal brings energy to the team. I'd be happy to recommend Paulyn for any position; I'm confident in her capabilities.",
      author: "Ratanpriya Shrivastava",
      org: "Lead Software Engineer · Macy's Systems & Technology",
    },
    {
      quote: "I wish I got to work with Paulyn longer. Always eager and energetic, Paulyn was a great team player and quickly jumped into the weeds. Paulyn had great suggestions and was very attentive to the problem at hand. Hopefully we get to work together again in the future!",
      author: "Karl Goodhew",
      org: "Technology Leader · managed Paulyn directly",
    },
  ];
  const [i, setI] = React.useState(0);
  const [paused, setPaused] = React.useState(false);
  const isMobile = window.innerWidth <= 768;

  // Auto-advance every 5s, pause on hover/touch
  React.useEffect(() => {
    if (paused) return;
    const id = setInterval(() => setI(x => (x + 1) % items.length), 5000);
    return () => clearInterval(id);
  }, [paused]);

  return (
    <div
      onMouseEnter={() => setPaused(true)}
      onMouseLeave={() => setPaused(false)}
      onTouchStart={() => setPaused(true)}
      onTouchEnd={() => { setTimeout(() => setPaused(false), 3000); }}
      style={{
        padding: isMobile ? '24px 20px' : '40px 48px',
        borderRadius: isMobile ? 16 : 24,
        background: 'var(--surface)',
        backdropFilter: 'blur(20px)',
        border: '1px solid var(--hairline)',
        position: 'relative',
        minHeight: isMobile ? 160 : 220,
        overflow: 'hidden',
      }}
    >
      <div style={{ position: 'absolute', top: isMobile ? 10 : 20, left: isMobile ? 14 : 28, fontFamily: '"Fraunces", serif', fontSize: isMobile ? 48 : 80, lineHeight: 0.5, color: 'var(--accent)', opacity: 0.3 }}>"</div>

      {/* Progress bar */}
      <div style={{ position: 'absolute', top: 0, left: 0, right: 0, height: 3, background: 'var(--hairline)', overflow: 'hidden' }}>
        <div key={i + '-' + paused} style={{
          height: '100%',
          background: 'var(--accent)',
          animation: paused ? 'none' : 'testimonialProgress 5s linear forwards',
          width: paused ? 'var(--paused-width, 0%)' : '0%',
        }} />
      </div>

      <div key={i} style={{ animation: 'fadeIn 0.5s' }}>
        <p style={{ fontFamily: '"Fraunces", serif', fontSize: isMobile ? 16 : 22, fontStyle: 'italic', lineHeight: 1.55, color: 'var(--fg)', margin: '0 0 16px', letterSpacing: -0.2 }}>
          {items[i].quote}
        </p>
        <div style={{ fontSize: isMobile ? 12 : 13, fontWeight: 600, color: 'var(--fg)' }}>{items[i].author}</div>
        <div style={{ fontSize: isMobile ? 11 : 12, color: 'var(--muted)', marginTop: 2 }}>{items[i].org}</div>
      </div>

      {/* Dots + arrows */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: isMobile ? 16 : 24 }}>
        <button onClick={() => setI((i - 1 + items.length) % items.length)}
          style={{ background: 'none', border: 'none', color: 'var(--muted)', cursor: 'pointer', fontSize: 14, padding: '4px 6px', lineHeight: 1 }}>‹</button>
        <div style={{ display: 'flex', gap: 6 }}>
          {items.map((_, j) => (
            <button key={j} onClick={() => setI(j)}
              style={{ width: j === i ? 24 : 8, height: 6, borderRadius: 3, border: 'none', padding: 0, cursor: 'pointer',
                background: j === i ? 'var(--accent)' : 'var(--hairline)', transition: 'all 0.3s' }} />
          ))}
        </div>
        <button onClick={() => setI((i + 1) % items.length)}
          style={{ background: 'none', border: 'none', color: 'var(--muted)', cursor: 'pointer', fontSize: 14, padding: '4px 6px', lineHeight: 1 }}>›</button>
        <span style={{ marginLeft: 'auto', fontSize: 10, color: 'var(--muted)', fontFamily: '"JetBrains Mono", monospace' }}>{i + 1}/{items.length}</span>
      </div>

      <style>{`
        @keyframes testimonialProgress {
          from { width: 0%; }
          to { width: 100%; }
        }
      `}</style>
    </div>
  );
}

Object.assign(window, { SideProjects, NowWidget, CommandPalette, KonamiEasterEgg, LiveCodeSnippet, TestimonialCarousel });
