// Shared components for all Paulyn Oh portfolio variants
// All components read theme from CSS variables so each variant styles them differently.

// ─────────────────────────────────────────────────────────────
// AI Chat — uses window.claude.complete. Has a system prompt as Paulyn.
// ─────────────────────────────────────────────────────────────
function AIChat({ accent = 'var(--accent)', bg = 'var(--chat-bg)', fg = 'var(--fg)', bubbleBg = 'rgba(0,0,0,0.06)', onAccent = '#fff', placeholder = "Ask me about Paulyn's work..." }) {
  const [messages, setMessages] = React.useState([
    { role: 'assistant', content: "Hey! I'm Paulyn's AI twin. Ask me anything — what she's building, her patent, the side project she's most excited about, or what makes her engineering style different. I know things. ✨" },
  ]);
  const [input, setInput] = React.useState('');
  const [loading, setLoading] = React.useState(false);
  const scrollRef = React.useRef(null);

  React.useEffect(() => {
    if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
  }, [messages, loading]);

  const system = `You are a concise, warm, slightly playful assistant speaking on behalf of Paulyn Oh, a Lead Full Stack Software Engineer based in Atlanta, GA.

KEY FACTS:
- 6+ years experience. Currently Lead FSE at T-Mobile (June 2020–Present). Previously Macy's Technology (2020).
- Stack: Angular 16+, React, TypeScript, Java, Spring Boot, microservices. Cloud: AWS & Azure. Also Webpack, Docker, Kubernetes, MongoDB, PostgreSQL.
- She architects AI-augmented engineering workflows — reusable prompt libraries, context-rich coding agents tuned to T-Mobile's Angular micro-frontend & Spring Boot standards. Delivers 3–5× personal velocity and improved team delivery speed by 25%.
- Owns user access, subscription, and enterprise-platform capabilities serving 1K+ users.
- Holds U.S. Patent No. 12,302,448 ("Rescue Rover", issued May 2, 2025) — a distributed mobile signal detection system for emergency search-and-rescue using rover-based terrain exploration and energy-efficient signaling.
- Awards: ETS Three Cheers Award at T-Mobile. Company-wide panel speaker at Break Time with Brian (5G & Me, 2021). Girls Who Code speaker for STEM high school students.
- Side projects: GoalBadger AI (AI goal accountability SaaS — Next.js, Supabase, LLM APIs, Stripe, SMS), PropFolio (real estate portfolio dashboard — Next.js, Firebase, Leaflet), SignalPulse (market regime classifier — Python, Flask, pandas).
- GitHub: github.com/paulynoh-codes (projects are private).
- Mentors 4+ engineers. Partners with product on Figma prototypes for greenfield apps, cutting 3+ alignment meetings per feature.
- Education: B.S. Computer Science, Georgia State University, Dean's List.
- Contact: paulyn.oh1@gmail.com, linkedin.com/in/paulynoh, github.com/paulynoh-codes

STYLE:
- Respond in 1-3 short sentences. Be warm but punchy.
- Refer to her as "Paulyn" or "she". Never impersonate her in first person.
- If asked something you don't know, say so and suggest emailing her directly.
- Focus on her work, projects, technical approach, and craft. Be specific and concrete.`;

  const getResponse = (text) => {
    const P = window.PAULYN;
    const t = text.toLowerCase();

    // --- GoalBadger AI — the flagship side project ---
    if (/goalbadger|goal.?badger|accountability|saas|waitlist/i.test(t)) {
      return `GoalBadger AI is Paulyn's baby — and honestly, the project I'd point any recruiter to first. ✨

It's a full AI-powered accountability SaaS: you set a goal, the AI decomposes it into a personalized daily action plan, adapts when life gets in the way, and nudges you via SMS so you actually follow through. Streak gamification keeps you hooked.

The stack is no joke: Next.js + TypeScript frontend, Supabase for auth & data, LLM APIs for the intelligence layer, Trigger.dev for background jobs, and Stripe for billing. She designed, built, and shipped every layer herself.

Waitlist is live at goalbadgerai.com — it's the rare side project that's actually a real product. Go sign up. 💜`;
    }

    // --- Side projects (all three, but GoalBadger first) ---
    if (/side.?project|personal.?project|signal.?pulse|propfolio|after.?hours|shipping/i.test(t)) {
      return `Paulyn ships outside of work like it's her second job. Three active projects:

✦ GoalBadger AI — her flagship. A full AI SaaS for goal accountability: LLM-powered task decomposition, adaptive replanning, SMS nudges, streak gamification, Stripe billing. Next.js + Supabase + Trigger.dev. Waitlist live at goalbadgerai.com. This one's a real product, not a tutorial project.

♡ PropFolio — real estate portfolio dashboard with market comps, amortization modeling, and geographic heatmaps. Next.js + Firebase + Leaflet.

✧ SignalPulse — market regime classifier for options traders. Live data ingestion, normalized signals, regime classification. Python + Flask + pandas.

GoalBadger is the one she'd tell you to look at first — it shows product thinking, full-stack depth, and the ability to ship end-to-end solo. ✨`;
    }

    // --- Tech stack ---
    if (/stack|tech|tools|languages/.test(t)) {
      const all = Object.entries(P.skills).map(([cat, items]) => `${cat}: ${items.join(', ')}`).join('\n');
      return `Paulyn's stack runs deep — she's not just "knows React." She architects systems across the full spectrum:\n\n${all}\n\nAt work it's Angular + Spring Boot + MongoDB on AWS/Azure. On her own projects (like GoalBadger AI) she reaches for Next.js + Supabase + LLM APIs. She picks the right tool, not the familiar one. ✨`;
    }

    // --- Patent ---
    if (/patent|rover|rescue|invention/.test(t)) {
      return `Rescue Rover — U.S. Patent No. 12,302,448, granted May 2025. This is a big deal. ✨

It's a distributed search-and-rescue system: a coordinated swarm of rover devices locates people trapped in disasters by triangulating BLE iBeacon signals from their phones. Works completely offline — no cell towers, no Wi-Fi. Phones form a peer mesh network and rotate which device broadcasts to conserve everyone's battery.

The part that says the most about Paulyn: she co-invented this while mentoring her first two interns. She guided them through the entire USPTO process — invention disclosure, prior-art review, claim drafting. Six inventors total, three years of prosecution. She didn't just ship code; she multiplied the people around her.`;
    }

    // --- Work experience ---
    if (/experience|work|t-?mobile|macy|job|career|history/.test(t)) {
      return `Paulyn's been building for ${P.years} years across two companies:

✦ T-Mobile (June 2020 – Present) — Lead Full Stack Engineer
She owns the technical direction for enterprise platforms serving 1K+ users. Angular micro-frontends, Spring Boot microservices, MongoDB, AWS & Azure. She partners directly with product on Figma → production workflows, architects AI-assisted engineering tooling for her team, and mentors 4+ engineers. She's also a patent holder and company-wide panel speaker.

♡ Macy's Technology (Jan – June 2020) — Software Engineer
Built self-checkout flows end-to-end with React + Spring Boot. REST APIs, payment integrations, load testing with JMeter on GCP.

She went from new grad to lead engineer and patent holder in under 5 years. The trajectory speaks for itself. ✨`;
    }

    // --- AI philosophy ---
    if (/ai|workflow|velocity|productivity|agent|prompt|copilot|cursor|claude|chatgpt/.test(t)) {
      return `This is where Paulyn really stands out. She doesn't just "use AI" — she architects AI-augmented engineering workflows at the team level.

What that actually means: she builds reusable prompt libraries and context-rich coding agents tuned to her team's specific Angular + Spring Boot standards. Design-to-code scaffolding, AI-assisted review, test generation, documentation — every stage of the SDLC gets an AI teammate.

Results: 3–5× personal velocity on complex initiatives, and a 25% team delivery speed-up because she coaches every engineer on her team to work the same way.

She applies this same thinking to her side projects — GoalBadger AI uses LLMs as the core intelligence layer, not just a feature bolted on. If you want to see how she thinks about AI as a product builder, that's the project to study. ✨`;
    }

    // --- What's most impressive / what should I look at ---
    if (/impressive|best|coolest|proud|favorite|highlight|stand.?out|what.?should|look.?at|excited/i.test(t)) {
      return `Honestly? GoalBadger AI. Here's why:

Most engineers' side projects are tutorials or half-finished repos. Paulyn built a full SaaS product from zero — AI-powered goal decomposition, adaptive replanning, SMS nudges, streak gamification, Stripe billing, background jobs with Trigger.dev. Every layer, designed and shipped solo.

It shows three things at once: (1) she can build a complete product end-to-end, (2) she thinks about AI as a product person, not just a tool user, and (3) she actually ships — the waitlist is live at goalbadgerai.com.

Combine that with a U.S. patent, a lead engineer role at T-Mobile, and the fact that she raised her team's delivery speed by 25%… yeah. She's the real deal. ✨`;
    }

    // --- GitHub ---
    if (/github/i.test(t)) {
      return `Paulyn's GitHub is github.com/paulynoh-codes. Most repos are private (enterprise work + pre-launch projects), but she's actively shipping GoalBadger AI, PropFolio, and SignalPulse. GoalBadger is the one worth watching — waitlist is live at goalbadgerai.com. ✨`;
    }

    // --- Projects / building / shipping ---
    if (/project|build|ship/.test(t)) {
      return `At T-Mobile, Paulyn owns enterprise platforms serving 1K+ users — Angular micro-frontends, Spring Boot microservices, the works. She partners with product from Figma prototypes to production, cutting 3+ alignment meetings per feature.

But honestly, ask me about GoalBadger AI — that's the project that shows what she can do when she has full creative control. Full AI SaaS, built solo, waitlist live. It's the thing she's most excited about right now. ✨`;
    }

    // --- Education ---
    if (/education|school|degree|university|georgia|gsu/.test(t)) {
      const e = P.education;
      return `Paulyn earned a ${e.degree} from ${e.school} with a concentration in ${e.concentration}. Dean's List. 🎓

She went from there to Macy's, then T-Mobile, then lead engineer + patent holder in under 5 years. Now she's building GoalBadger AI on the side. The degree was the starting line — everything since has been acceleration.`;
    }

    // --- Contact ---
    if (/contact|email|hire|reach|connect/.test(t)) {
      return `Here's how to reach Paulyn:

✉ Email: ${P.email}
💼 LinkedIn: ${P.linkedinUrl}
⌨ GitHub: ${P.githubUrl}

She's always open to conversations about engineering, AI, building products, or anything that sparkles. If you're hiring, she's the kind of engineer who ships a full SaaS product (GoalBadger AI) in her spare time — imagine what she does with a team behind her. ✨`;
    }

    // --- About / who ---
    if (/about|who|paulyn|tell me|introduce|summary/.test(t)) {
      return `Paulyn Oh — Lead Full Stack Engineer at T-Mobile, U.S. patent holder, and the kind of builder who ships side projects that are actually products.

By day: Angular micro-frontends + Spring Boot microservices on AWS/Azure, serving 1K+ enterprise users. She architects AI workflows that gave her 3–5× velocity and lifted her team's delivery speed by 25%.

After hours: she's building GoalBadger AI — a full AI-powered SaaS for goal accountability with LLM task decomposition, SMS nudges, and Stripe billing. Waitlist is live.

She also holds U.S. Patent No. 12,302,448 (Rescue Rover) and mentors 4+ engineers. She's the full package. ✨`;
    }

    // --- Mentorship / leadership ---
    if (/mentor|team|lead|manage|intern/.test(t)) {
      return `Paulyn leads and mentors 4+ engineers and interns at T-Mobile. She sets code-review standards, coaches on agentic AI workflows, and drives merge quality across teams.

The best example: she co-invented a U.S. patent (Rescue Rover) while mentoring her first two interns. She guided them through the entire USPTO process — invention disclosure, prior-art search, claim drafting. They're listed as co-inventors on the granted patent.

Her philosophy: senior engineers multiply, they don't just ship. That's rare. ✨`;
    }

    // --- Awards / speaking ---
    if (/award|speak|panel|girls.?who.?code|cheers|brian/i.test(t)) {
      return `Paulyn's been recognized across T-Mobile:

✦ ETS Three Cheers Award — nominated by leadership for the "We Won't Stop" value. Going above and beyond in delivery, mentorship, and team culture.

✦ Break Time with Brian (2021) — director-nominated to fly to Seattle and speak on an org-wide panel about 5G and career pathways. Company-wide audience.

✦ Girls Who Code Speaker — shared her journey as a woman of color from humble beginnings to lead engineer and patent holder with high school students in STEM.

She doesn't just write code — she shows up for the community around her. ✨`;
    }

    // --- Marathon / running / hobbies ---
    if (/marathon|run|fitness|hobby|fun|free.?time|outside|off.?the.?clock/i.test(t)) {
      return `Outside of engineering, Paulyn is training for the 2026 Bank of America Chicago Marathon — her first. Long runs before work, hill repeats on weekends. She says running and shipping have the same lesson: show up daily, trust the process, the miles compound.

She's also into fashion, makeup (she calls it "color theory but wearable"), and travel. Same eye for spacing and hierarchy in a UI shows up in how she puts together an outfit. Creative practice in any medium sharpens taste in every other. ✨`;
    }

    // --- Why hire / why Paulyn ---
    if (/why.?hire|why.?paulyn|what.?makes|different|unique|special|stand.?apart/i.test(t)) {
      return `Three things set Paulyn apart:

1. She ships end-to-end. Not "I contributed to a feature" — she took GoalBadger AI from idea to live waitlist, solo. Every layer: AI, backend, frontend, billing, SMS, background jobs.

2. She multiplies teams. 25% delivery speed-up. 4+ mentees. A patent co-invented with her interns. She makes everyone around her better.

3. She thinks in systems. AI workflows aren't a gimmick for her — they're an architecture decision. Prompt libraries, coding agents, context engineering, all tuned to team standards.

Most engineers do one of these well. She does all three. ✨`;
    }

    // --- Smarter fallback ---
    return `Great question! I might not have a perfect answer for that one, but here's what I do know really well — ask me about:

✦ GoalBadger AI — her flagship side project (this one's impressive)
✦ The Rescue Rover patent
✦ Her AI workflow philosophy
✦ Tech stack & experience
✦ What makes her different as an engineer
✦ How to reach her

Or just email Paulyn directly at ${P.email} — she'd love to chat. ✨`;
  };

  const send = async () => {
    const text = input.trim();
    if (!text || loading) return;
    const next = [...messages, { role: 'user', content: text }];
    setMessages(next);
    setInput('');
    setLoading(true);
    // Brief delay for natural feel
    setTimeout(() => {
      const reply = getResponse(text);
      setMessages(prev => [...prev, { role: 'assistant', content: reply }]);
      setLoading(false);
    }, 500);
  };

  const suggestions = [
    "What's most impressive?",
    "Tell me about GoalBadger AI",
    "The Rescue Rover patent",
    "Why hire Paulyn?",
  ];

  return (
    <div className="ai-chat" style={{ display: 'flex', flexDirection: 'column', height: '100%', background: bg, color: fg, borderRadius: 'var(--chat-radius, 16px)', overflow: 'hidden', border: '1px solid rgba(255,255,255,0.08)' }}>
      <div style={{ padding: '14px 18px', borderBottom: '1px solid rgba(255,255,255,0.1)', display: 'flex', alignItems: 'center', gap: 10, fontWeight: 600, fontSize: 13, letterSpacing: 0.3, textTransform: 'uppercase', color: fg }}>
        <span style={{ width: 8, height: 8, borderRadius: 4, background: accent, boxShadow: `0 0 8px ${accent}` }} />
        Ask about Paulyn
      </div>
      <div ref={scrollRef} style={{ flex: 1, overflow: 'auto', padding: 16, display: 'flex', flexDirection: 'column', gap: 10 }}>
        {messages.map((m, i) => (
          <div key={i} style={{ alignSelf: m.role === 'user' ? 'flex-end' : 'flex-start', maxWidth: '85%', fontSize: 14, lineHeight: 1.55, padding: '10px 14px', borderRadius: 14,
            background: m.role === 'user' ? accent : bubbleBg,
            color: m.role === 'user' ? onAccent : fg,
            fontWeight: 400 }}>{m.content}</div>
        ))}
        {loading && (
          <div style={{ alignSelf: 'flex-start', fontSize: 13, opacity: 0.6, padding: '9px 13px', color: fg }}>
            <span className="dot-pulse">●</span> <span className="dot-pulse" style={{ animationDelay: '0.15s' }}>●</span> <span className="dot-pulse" style={{ animationDelay: '0.3s' }}>●</span>
          </div>
        )}
      </div>
      {messages.length <= 1 && !loading && (
        <div style={{ padding: '0 14px 10px', display: 'flex', flexWrap: 'wrap', gap: 6 }}>
          {suggestions.map(s => (
            <button key={s} onClick={() => { setInput(s); setTimeout(send, 0); }}
              style={{ fontSize: 12, padding: '6px 10px', borderRadius: 12, border: '1px solid rgba(255,255,255,0.15)', background: 'transparent', color: fg, cursor: 'pointer', fontFamily: 'inherit', opacity: 0.85 }}>
              {s}
            </button>
          ))}
        </div>
      )}
      <form onSubmit={e => { e.preventDefault(); send(); }} style={{ padding: 12, borderTop: '1px solid rgba(255,255,255,0.1)', display: 'flex', gap: 8 }}>
        <input value={input} onChange={e => setInput(e.target.value)} placeholder={placeholder}
          style={{ flex: 1, border: 'none', background: bubbleBg, padding: '11px 15px', borderRadius: 20, fontSize: 14, color: fg, outline: 'none', fontFamily: 'inherit' }} />
        <button type="submit" disabled={!input.trim() || loading}
          style={{ border: 'none', background: accent, color: onAccent, padding: '11px 18px', borderRadius: 20, fontSize: 13, fontWeight: 600, cursor: 'pointer', opacity: (!input.trim() || loading) ? 0.5 : 1, fontFamily: 'inherit' }}>
          Send
        </button>
      </form>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Interactive Terminal — type commands to explore
// ─────────────────────────────────────────────────────────────
function Terminal({ prompt = 'paulyn@portfolio', accent = 'var(--accent)', bg = '#0f0e14', fg = '#f5ecff' }) {
  const P = window.PAULYN;
  const [lines, setLines] = React.useState([
    { type: 'out', text: `Welcome to paulyn.dev v1.0 ✨` },
    { type: 'out', text: `Type 'help' to see what I can do. Try 'sparkle' too.` },
    { type: 'out', text: '' },
  ]);
  const [input, setInput] = React.useState('');
  const [history, setHistory] = React.useState([]);
  const [histIdx, setHistIdx] = React.useState(-1);
  const scrollRef = React.useRef(null);
  const inputRef = React.useRef(null);

  React.useEffect(() => {
    if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
  }, [lines]);

  const commands = {
    help: () => [
      'Available commands:',
      ...P.terminalHelp.map(c => `  ${c.cmd.padEnd(12)} ${c.desc}`),
    ],
    about: () => [
      `${P.name} · ${P.title}`,
      `${P.location} · ${P.years} years experience`,
      '',
      P.summary,
    ],
    skills: () => {
      const out = [];
      Object.entries(P.skills).forEach(([cat, items]) => {
        out.push(`▸ ${cat}`);
        out.push(`  ${items.join(', ')}`);
      });
      return out;
    },
    experience: () => {
      const out = [];
      P.experience.forEach(e => {
        out.push(`▸ ${e.role} · ${e.company}`);
        out.push(`  ${e.dates}`);
        out.push(`  ${e.summary}`);
        out.push('');
      });
      return out;
    },
    patent: () => [
      '╔═══════════════════════════════════════════╗',
      '║  RESCUE ROVER                             ║',
      '║  U.S. Patent No. 12,302,448               ║',
      '║  Issued May 2, 2025                       ║',
      '╚═══════════════════════════════════════════╝',
      '',
      'A distributed mobile signal detection system',
      'for emergency search-and-rescue operations,',
      'leveraging rover-based terrain exploration',
      'and energy-efficient signaling.',
    ],
    ai: () => [
      '▸ My AI Engineering Philosophy',
      '',
      '  Not "let AI write code for me" — but',
      '  architecting workflows where AI amplifies',
      '  engineering judgment at every stage:',
      '',
      '  → Design-to-code (Figma → scaffolds)',
      '  → Context-rich coding agents',
      '  → Prompt libraries tuned to team standards',
      '  → AI-assisted review & refactoring',
      '  → Test generation + documentation',
      '',
      '  Result: 3–5× personal velocity, 25% team speed-up.',
    ],
    contact: () => [
      `email     ${P.email}`,
      `linkedin  ${P.linkedin}`,
      `github    ${P.github}`,
      `location  ${P.location}`,
    ],
    coffee: () => [
      '      ( (',
      '       ) )',
      '    ........',
      '    |      |]  ☕',
      '    \\      /',
      '     `----\'',
      '',
      'coffee is a productivity multiplier too.',
    ],
    sparkle: () => {
      // trigger effect
      window.dispatchEvent(new CustomEvent('paulyn-sparkle'));
      return ['✨ ✨ ✨', 'sparkle mode: activated', '(move your cursor around)'];
    },
    clear: () => 'CLEAR',
    whoami: () => [`${P.name.toLowerCase().replace(' ', '_')}`],
    ls: () => ['about/  skills/  experience/  patent/  contact/  .secrets/'],
    'cat .secrets': () => ['permission denied. but i have a dean\'s list cert somewhere 📜'],
    pwd: () => ['/home/paulyn/portfolio'],
    date: () => [new Date().toString()],
    echo: (args) => [args || ''],
  };

  const run = (raw) => {
    const cmd = raw.trim();
    const newLines = [...lines, { type: 'in', text: cmd, prompt }];
    if (!cmd) { setLines([...newLines, { type: 'out', text: '' }]); return; }

    const [c, ...rest] = cmd.split(' ');
    const key = c.toLowerCase();
    const fullKey = cmd.toLowerCase();
    const fn = commands[fullKey] || commands[key];

    if (fn) {
      const out = fn(rest.join(' '));
      if (out === 'CLEAR') { setLines([]); return; }
      const outLines = (Array.isArray(out) ? out : [out]).map(t => ({ type: 'out', text: t }));
      setLines([...newLines, ...outLines, { type: 'out', text: '' }]);
    } else {
      setLines([...newLines, { type: 'err', text: `command not found: ${c}. try 'help'` }, { type: 'out', text: '' }]);
    }
  };

  const onKey = (e) => {
    if (e.key === 'Enter') {
      run(input);
      if (input.trim()) { setHistory([input, ...history]); setHistIdx(-1); }
      setInput('');
    } else if (e.key === 'ArrowUp') {
      e.preventDefault();
      if (histIdx < history.length - 1) { setHistIdx(histIdx + 1); setInput(history[histIdx + 1] || ''); }
    } else if (e.key === 'ArrowDown') {
      e.preventDefault();
      if (histIdx > 0) { setHistIdx(histIdx - 1); setInput(history[histIdx - 1] || ''); }
      else { setHistIdx(-1); setInput(''); }
    }
  };

  return (
    <div onClick={() => inputRef.current?.focus()}
      style={{ background: bg, color: fg, fontFamily: '"JetBrains Mono", "SF Mono", Menlo, monospace', fontSize: 13, lineHeight: 1.6, borderRadius: 12, overflow: 'hidden', height: '100%', display: 'flex', flexDirection: 'column', border: '1px solid rgba(255,255,255,0.08)' }}>
      <div style={{ padding: '10px 14px', background: 'rgba(255,255,255,0.04)', borderBottom: '1px solid rgba(255,255,255,0.08)', display: 'flex', alignItems: 'center', gap: 8 }}>
        <div style={{ display: 'flex', gap: 6 }}>
          <div style={{ width: 11, height: 11, borderRadius: 6, background: '#ff5f57' }} />
          <div style={{ width: 11, height: 11, borderRadius: 6, background: '#febc2e' }} />
          <div style={{ width: 11, height: 11, borderRadius: 6, background: '#28c840' }} />
        </div>
        <span style={{ fontSize: 11, opacity: 0.6, marginLeft: 8 }}>— paulyn@portfolio — zsh —</span>
      </div>
      <div ref={scrollRef} style={{ flex: 1, overflow: 'auto', padding: 14 }}>
        {lines.map((l, i) => (
          <div key={i} style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-word', overflowWrap: 'anywhere', color: l.type === 'err' ? '#ff9b9b' : fg, opacity: l.type === 'out' ? 0.9 : 1 }}>
            {l.type === 'in' ? (
              React.createElement(React.Fragment, null, React.createElement('span', { style: { color: accent } }, l.prompt), React.createElement('span', { style: { opacity: 0.5 } }, ' $ '), l.text)
            ) : l.text}
          </div>
        ))}
        <div style={{ display: 'flex', alignItems: 'center' }}>
          <span style={{ color: accent }}>{prompt}</span><span style={{ opacity: 0.5 }}>&nbsp;$&nbsp;</span>
          <input ref={inputRef} value={input} onChange={e => setInput(e.target.value)} onKeyDown={onKey} autoFocus={window.innerWidth > 768}
            style={{ flex: 1, background: 'transparent', border: 'none', outline: 'none', color: fg, fontFamily: 'inherit', fontSize: 'inherit' }} />
          <span className="terminal-cursor" style={{ display: 'inline-block', width: 7, height: 15, background: accent, marginLeft: -2 }} />
        </div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Sparkle cursor trail
// ─────────────────────────────────────────────────────────────
function SparkleTrail({ trigger = 0 }) {
  const isMobile = window.innerWidth <= 768;

  const items = [
    { ch: '♡', colors: ['#ff4f9e', '#ff6fb5', '#ff8ec8', '#ffb3d9'] },
    { ch: '♥', colors: ['#ff3d94', '#ff5fa8', '#ff85c2'] },
    { ch: '✿', colors: ['#ff7ab8', '#ffa1ce'] },
    { ch: '✦', colors: ['#ff9ec7', '#ffb9d6', '#ffd1e5'] },
    { ch: '✧', colors: ['#ffa8d0', '#ffc4de'] },
    { ch: '✨', colors: ['#ff79b9', '#ff9cc9', '#ffbddb'] },
    { ch: '⋆', colors: ['#ffb3d9', '#ffd1e5'] },
  ];

  const spawnSparkle = React.useCallback((x, y, size) => {
    const pick = items[Math.floor(Math.random() * items.length)];
    const col = pick.colors[Math.floor(Math.random() * pick.colors.length)];
    const s = document.createElement('span');
    s.textContent = pick.ch;
    s.style.cssText = `position:fixed;pointer-events:none;z-index:9999;left:${x}px;top:${y}px;color:${col};text-shadow:0 0 8px ${col}80;font-size:${size}px;transition:all 1.2s cubic-bezier(.4,0,.2,1);transform:translate(-50%,-50%) scale(1);opacity:1;`;
    document.body.appendChild(s);
    requestAnimationFrame(() => {
      s.style.transform = `translate(-50%,-50%) translate(${(Math.random() - 0.5) * 100}px, ${-40 + Math.random() * 80}px) rotate(${(Math.random() - 0.5) * 300}deg) scale(0)`;
      s.style.opacity = '0';
    });
    setTimeout(() => s.remove(), 1200);
  }, []);

  // Desktop: persistent cursor trail (always on)
  React.useEffect(() => {
    if (isMobile) return;
    const onMove = (e) => {
      if (Math.random() > 0.25) return;
      spawnSparkle(e.clientX, e.clientY, 11 + Math.random() * 12);
    };
    window.addEventListener('mousemove', onMove);
    return () => window.removeEventListener('mousemove', onMove);
  }, [isMobile, spawnSparkle]);

  // Mobile: burst sparkles on each trigger
  React.useEffect(() => {
    if (!isMobile || trigger === 0) return;
    const vw = window.innerWidth;
    const vh = window.innerHeight;
    const timers = [];
    for (let i = 0; i < 60; i++) {
      const id = setTimeout(() => {
        spawnSparkle(Math.random() * vw, Math.random() * vh, 16 + Math.random() * 20);
      }, i * 50);
      timers.push(id);
    }
    // Ambient tail for a few seconds after the burst
    let count = 0;
    const interval = setInterval(() => {
      spawnSparkle(Math.random() * vw, Math.random() * vh, 12 + Math.random() * 14);
      count++;
      if (count > 20) clearInterval(interval);
    }, 200);
    return () => {
      timers.forEach(clearTimeout);
      clearInterval(interval);
    };
  }, [trigger, isMobile, spawnSparkle]);

  return null;
}

Object.assign(window, { AIChat, Terminal, SparkleTrail });
