// shared.jsx — primitives + project data + interactives shared across all 5 home page directions

const PROJECTS = [
  {
    id: 'officehours',
    name: 'Office Hours',
    tagline: 'A workplace survival quiz game.',
    blurb: 'Pick a workplace archetype, play real scenarios, find out your survival type.',
    href: 'https://techclatters.vercel.app/officehoursgame',
    kind: 'Game · Web',
    emoji: '☕',
    color: '#FF7A6B',
    accent: '#FFD66B',
    year: '2026',
  },
  {
    id: 'moneyticker',
    name: 'Money Ticker',
    tagline: 'Watch your hourly earnings tick up in real time.',
    blurb: 'Celebrations at every milestone and at the end of your work day.',
    href: 'https://chromewebstore.google.com/detail/money-ticker/agiaaekccnmeolhalkejpcjfmpogbngb',
    kind: 'Chrome Extension',
    emoji: '💸',
    color: '#7BB87A',
    accent: '#9DC3FF',
    year: '2026',
  },
  {
    id: 'soon1',
    name: 'Cooking…',
    tagline: 'Something tiny and useful is in the oven.',
    blurb: 'Idea-stage. Stay tuned.',
    href: '#',
    kind: 'Coming soon',
    emoji: '🍳',
    color: '#C9A2E6',
    accent: '#FFE66B',
    year: 'soon',
    soft: true,
  },
];

const ABOUT = {
  oneLine: "I build little things for fun & occasional utility.",
  likes: ['art', 'DIYs', 'machine learning', 'computer vision', 'software'],
  email: 'techclatters@gmail.com',
};

// ─────────────────────────────────────────────────────────────
// Pixel robot mascot — a chunky little buddy. Eyes blink + track cursor.
// ─────────────────────────────────────────────────────────────
function PixelBuddy({ size = 80, mood = 'happy', talking = false, palette }) {
  const p = palette || { body: '#FFE66B', shade: '#E8C932', shadow: '#1f1a14', eye: '#1f1a14', cheek: '#FF7A6B', antenna: '#7BB87A' };
  // 16x16 pixel-art robot. Each char maps to a color.
  // .=transparent, B=body, S=shade, K=outline, E=eye-bg(white), P=pupil, C=cheek, A=antenna, T=antennaTip
  const art = [
    '.......T........',
    '.......A........',
    '.......A........',
    '..KKKKKKKKKK....',
    '.KBBBBBBBBBBK...',
    'KBEEKBBKEEKBSK..',
    'KBEPKBBKEPKBSK..',
    'KBBBBCBBBCBBSK..',
    'KBBBBBBBBBBBSK..',
    'KBBBKKKKKKBBSK..',
    '.KBBBBBBBBBBSK..',
    '..KKKKKKKKKK....',
    '..K.KK..KK.K....',
    '..K.KK..KK.K....',
    '..KKKK..KKKK....',
    '................',
  ];
  const colors = { '.': 'transparent', B: p.body, S: p.shade, K: p.shadow, E: '#fffdf5', P: p.eye, C: p.cheek, A: p.antenna, T: p.antenna };
  const px = size / 16;
  return (
    <div style={{ position: 'relative', width: size, height: size, imageRendering: 'pixelated', display: 'inline-block' }}>
      <svg viewBox="0 0 16 16" width={size} height={size} style={{ display: 'block', shapeRendering: 'crispEdges' }}>
        {art.map((row, y) =>
          row.split('').map((ch, x) =>
            ch === '.' ? null : <rect key={`${x}-${y}`} x={x} y={y} width="1" height="1" fill={colors[ch]} />
          )
        )}
        {/* blink */}
        <g style={{ animation: 'buddy-blink 4.7s infinite' }}>
          <rect x="3" y="5" width="3" height="2" fill={p.body} opacity="0" />
          <rect x="10" y="5" width="3" height="2" fill={p.body} opacity="0" />
        </g>
      </svg>
      {talking && (
        <div style={{
          position: 'absolute', left: size + 8, top: -4,
          background: '#fff', border: `2px solid ${p.shadow}`, padding: '6px 10px',
          borderRadius: 8, fontSize: 12, whiteSpace: 'nowrap', fontFamily: 'inherit',
          color: p.shadow, boxShadow: `2px 2px 0 ${p.shadow}`,
        }}>
          {talking}
          <div style={{ position: 'absolute', left: -7, top: 12, width: 0, height: 0, borderTop: '5px solid transparent', borderBottom: '5px solid transparent', borderRight: `7px solid ${p.shadow}` }} />
        </div>
      )}
      <style>{`
        @keyframes buddy-blink {
          0%, 92%, 100% { opacity: 0; }
          94%, 96% { opacity: 1; }
        }
      `}</style>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Anagram reveal: SCARLETT ⇄ CLATTERS. Click letters scramble.
// ─────────────────────────────────────────────────────────────
function AnagramReveal({ size = 28, color = '#1f1a14', accent = '#FF7A6B' }) {
  const FROM = 'SCARLETT';
  const TO = 'CLATTERS';
  // permutation: which index of FROM each TO letter came from
  // S(0)C(1)A(2)R(3)L(4)E(5)T(6)T(7) → C(1)L(4)A(2)T(6)T(7)E(5)R(3)S(0)
  const perm = [1, 4, 2, 6, 7, 5, 3, 0];
  const [phase, setPhase] = React.useState(0); // 0 = SCARLETT, 1 = CLATTERS
  const letters = phase === 0 ? FROM.split('') : TO.split('');
  return (
    <button
      onClick={() => setPhase((p) => 1 - p)}
      style={{ border: 'none', background: 'transparent', padding: 0, cursor: 'pointer', display: 'inline-flex', gap: 1, fontFamily: 'inherit' }}
      title="click me"
    >
      {letters.map((ch, i) => (
        <span key={i}
          style={{
            display: 'inline-block', fontSize: size, fontWeight: 800,
            color, letterSpacing: '0.02em',
            transform: phase === 1 ? `translateY(${(i % 2 ? -2 : 2)}px) rotate(${(i % 2 ? -3 : 3)}deg)` : 'none',
            transition: `transform .35s cubic-bezier(.5,1.6,.4,1) ${i * 30}ms, color .2s`,
          }}>
          <span style={{ color: phase === 1 && (i === 0 || i === 7) ? accent : color }}>{ch}</span>
        </span>
      ))}
    </button>
  );
}

// ─────────────────────────────────────────────────────────────
// Tiny mini-game: "Feed the Kitty" — click flying treats to feed
// a sleepy cat. Cat purrs (gets bigger/happier) the more you feed.
// ─────────────────────────────────────────────────────────────
function FeedTheKitty({ width = 280, height = 180, palette }) {
  const p = palette || { bg: '#fffaf0', border: '#1f1a14', cat: '#FF7A6B', score: '#FF7A6B', ground: '#FFE66B' };
  const [treats, setTreats] = React.useState([]);
  const [score, setScore] = React.useState(0);
  const [running, setRunning] = React.useState(false);
  const [timeLeft, setTimeLeft] = React.useState(20);
  const [purr, setPurr] = React.useState(0); // 0..3 happiness
  const idRef = React.useRef(0);
  const runningRef = React.useRef(false);
  runningRef.current = running;

  React.useEffect(() => {
    if (!running) return;
    const spawn = setInterval(() => {
      if (!runningRef.current) return;
      idRef.current += 1;
      const id = idRef.current;
      const startX = 20 + Math.random() * (width - 40);
      const drift = (Math.random() - 0.5) * 60;
      const kind = Math.random() < 0.5 ? 'fish' : 'heart';
      setTreats((ts) => [...ts, { id, startX, drift, kind }]);
      setTimeout(() => setTreats((ts) => ts.filter((t) => t.id !== id)), 3500);
    }, 750);
    const tick = setInterval(() => setTimeLeft((t) => Math.max(0, t - 1)), 1000);
    return () => { clearInterval(spawn); clearInterval(tick); };
  }, [running, width]);

  React.useEffect(() => {
    if (timeLeft === 0 && running) setRunning(false);
  }, [timeLeft, running]);

  const start = () => { setTreats([]); setScore(0); setTimeLeft(20); setPurr(0); setRunning(true); };
  const feed = (id) => {
    setTreats((ts) => ts.filter((t) => t.id !== id));
    setScore((s) => s + 1);
    setPurr((p) => Math.min(3, p + 0.3));
    setTimeout(() => setPurr((p) => Math.max(0, p - 0.15)), 600);
  };

  // cat in bottom-right corner
  const catSize = 56 + purr * 6;

  return (
    <div style={{
      position: 'relative', width, height, background: p.bg,
      border: `2px solid ${p.border}`, borderRadius: 4, overflow: 'hidden',
      boxShadow: `3px 3px 0 ${p.border}`, fontFamily: 'inherit',
    }}>
      <div style={{ position: 'absolute', left: 0, right: 0, bottom: 0, height: 14, background: p.ground, borderTop: `2px dotted ${p.border}` }} />
      <div style={{ position: 'absolute', top: 6, left: 8, right: 8, display: 'flex', justifyContent: 'space-between', fontSize: 11, fontWeight: 700, color: p.border, letterSpacing: '.05em' }}>
        <span>FED · <span style={{ color: p.score }}>{score}</span> {purr > 1 ? '· purring 💕' : ''}</span>
        <span>{running ? `${timeLeft}s` : score > 0 ? `${score} treats · cat is happy` : 'FEED THE KITTY'}</span>
      </div>

      {/* the cat */}
      <div style={{
        position: 'absolute', right: 12, bottom: 14, width: catSize, height: catSize,
        transition: 'width .25s, height .25s, transform .15s',
        transform: purr > 0.5 ? `rotate(${Math.sin(Date.now() / 200) * 4}deg)` : 'none',
      }}>
        <svg viewBox="0 0 60 60" width={catSize} height={catSize} style={{ shapeRendering: 'geometricPrecision' }}>
          {/* body */}
          <ellipse cx="30" cy="42" rx="22" ry="14" fill={p.cat} stroke={p.border} strokeWidth="1.5" />
          {/* head */}
          <circle cx="30" cy="24" r="14" fill={p.cat} stroke={p.border} strokeWidth="1.5" />
          {/* ears */}
          <polygon points="18,16 16,6 24,12" fill={p.cat} stroke={p.border} strokeWidth="1.5" strokeLinejoin="round" />
          <polygon points="42,16 44,6 36,12" fill={p.cat} stroke={p.border} strokeWidth="1.5" strokeLinejoin="round" />
          {/* eyes — closed (happy) when purring */}
          {purr > 1 ? (
            <>
              <path d="M22 24 Q24 22 26 24" fill="none" stroke={p.border} strokeWidth="1.5" strokeLinecap="round" />
              <path d="M34 24 Q36 22 38 24" fill="none" stroke={p.border} strokeWidth="1.5" strokeLinecap="round" />
            </>
          ) : (
            <>
              <circle cx="24" cy="24" r="1.6" fill={p.border} />
              <circle cx="36" cy="24" r="1.6" fill={p.border} />
            </>
          )}
          {/* nose + mouth */}
          <path d="M29 28 L31 28 L30 29 Z" fill={p.border} />
          <path d="M30 29 Q28 32 26 30 M30 29 Q32 32 34 30" fill="none" stroke={p.border} strokeWidth="1" strokeLinecap="round" />
          {/* whiskers */}
          <line x1="14" y1="28" x2="22" y2="29" stroke={p.border} strokeWidth=".8" />
          <line x1="38" y1="29" x2="46" y2="28" stroke={p.border} strokeWidth=".8" />
          {/* tail */}
          <path d="M50 42 Q58 36 54 28" fill="none" stroke={p.border} strokeWidth="3" strokeLinecap="round" />
        </svg>
      </div>

      {/* falling treats */}
      {treats.map((t) => (
        <button key={t.id} onClick={() => feed(t.id)}
          style={{
            position: 'absolute', top: -24, left: t.startX,
            width: 26, height: 26, padding: 0, border: 'none', background: 'transparent', cursor: 'pointer',
            animation: `treat-fall-${t.id % 2} 3.3s linear forwards`,
            ['--drift']: `${t.drift}px`, ['--fall']: `${height - 30}px`,
          }}>
          {t.kind === 'fish' ? (
            <svg viewBox="0 0 24 24" width="24" height="24">
              <ellipse cx="11" cy="12" rx="7" ry="4.5" fill="#9DC3FF" stroke={p.border} strokeWidth="1.2" />
              <polygon points="18,12 23,8 23,16" fill="#9DC3FF" stroke={p.border} strokeWidth="1.2" strokeLinejoin="round" />
              <circle cx="8" cy="11" r="1" fill={p.border} />
            </svg>
          ) : (
            <svg viewBox="0 0 24 24" width="24" height="24">
              <path d="M12 21 C 4 14 4 8 8 6 C 10 5 12 7 12 9 C 12 7 14 5 16 6 C 20 8 20 14 12 21 Z"
                fill="#FF7A6B" stroke={p.border} strokeWidth="1.4" strokeLinejoin="round" />
            </svg>
          )}
        </button>
      ))}

      {!running && (
        <button onClick={start}
          style={{
            position: 'absolute', left: '34%', top: '50%', transform: 'translate(-50%, -50%)',
            background: p.score, color: '#fffdf5', border: `2px solid ${p.border}`,
            padding: '8px 16px', borderRadius: 4, fontFamily: 'inherit', fontWeight: 800,
            cursor: 'pointer', boxShadow: `2px 2px 0 ${p.border}`, fontSize: 12, letterSpacing: '.08em',
          }}>
          {score > 0 ? 'AGAIN' : 'FEED ME'}
        </button>
      )}

      <style>{`
        @keyframes treat-fall-0 {
          from { transform: translate(0, 0) rotate(0); }
          to   { transform: translate(var(--drift), var(--fall)) rotate(180deg); }
        }
        @keyframes treat-fall-1 {
          from { transform: translate(0, 0) rotate(0); }
          to   { transform: translate(var(--drift), var(--fall)) rotate(-180deg); }
        }
      `}</style>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Sparkle/confetti cursor trail (scoped to a container)
// ─────────────────────────────────────────────────────────────
function CursorTrail({ containerRef, kind = 'confetti', colors = ['#FF7A6B', '#FFE66B', '#7BB87A', '#9DC3FF', '#C9A2E6'], enabled = true }) {
  const [bits, setBits] = React.useState([]);
  const idRef = React.useRef(0);

  React.useEffect(() => {
    if (!enabled) return;
    const el = containerRef.current;
    if (!el) return;
    let last = 0;
    const onMove = (e) => {
      const now = Date.now();
      if (now - last < 40) return;
      last = now;
      const r = el.getBoundingClientRect();
      const x = e.clientX - r.left;
      const y = e.clientY - r.top;
      idRef.current += 1;
      const id = idRef.current;
      const color = colors[Math.floor(Math.random() * colors.length)];
      const dx = (Math.random() - 0.5) * 30;
      const dy = 30 + Math.random() * 20;
      const rot = (Math.random() - 0.5) * 360;
      setBits((b) => [...b.slice(-30), { id, x, y, color, dx, dy, rot, kind }]);
      setTimeout(() => setBits((b) => b.filter((p) => p.id !== id)), 900);
    };
    el.addEventListener('mousemove', onMove);
    return () => el.removeEventListener('mousemove', onMove);
  }, [containerRef, kind, enabled, colors.join('|')]);

  return (
    <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none', overflow: 'hidden', zIndex: 1000 }}>
      {bits.map((b) => (
        <span key={b.id}
          style={{
            position: 'absolute', left: b.x, top: b.y, width: kind === 'sparkle' ? 8 : 6, height: kind === 'sparkle' ? 8 : 10,
            background: kind === 'sparkle' ? 'transparent' : b.color, color: b.color,
            borderRadius: kind === 'star' ? '50%' : 0,
            animation: `trail-fall .9s ease-out forwards`,
            ['--dx']: `${b.dx}px`, ['--dy']: `${b.dy}px`, ['--rot']: `${b.rot}deg`,
            display: 'inline-flex', alignItems: 'center', justifyContent: 'center', fontSize: 12,
          }}>
          {kind === 'sparkle' ? '✦' : kind === 'star' ? '' : ''}
        </span>
      ))}
      <style>{`
        @keyframes trail-fall {
          from { transform: translate(0, 0) rotate(0); opacity: 1; }
          to   { transform: translate(var(--dx), var(--dy)) rotate(var(--rot)); opacity: 0; }
        }
      `}</style>
    </div>
  );
}

// Confetti dot pattern bg (decorative)
function ConfettiDots({ density = 1, palette = ['#FF7A6B', '#FFE66B', '#7BB87A', '#9DC3FF', '#C9A2E6'] }) {
  const dots = React.useMemo(() => {
    const seed = 42;
    const rand = (i) => {
      const x = Math.sin(seed + i * 12.9898) * 43758.5453;
      return x - Math.floor(x);
    };
    const n = Math.floor(60 * density);
    return Array.from({ length: n }, (_, i) => ({
      x: rand(i) * 100,
      y: rand(i + 1000) * 100,
      r: 2 + rand(i + 2000) * 4,
      c: palette[Math.floor(rand(i + 3000) * palette.length)],
      rot: rand(i + 4000) * 360,
      kind: rand(i + 5000) > 0.6 ? 'rect' : 'dot',
    }));
  }, [density, palette.join('|')]);
  return (
    <svg width="100%" height="100%" preserveAspectRatio="none" viewBox="0 0 100 100" style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>
      {dots.map((d, i) =>
        d.kind === 'dot'
          ? <circle key={i} cx={d.x} cy={d.y} r={d.r * 0.15} fill={d.c} opacity="0.8" />
          : <rect key={i} x={d.x} y={d.y} width={d.r * 0.4} height={d.r * 0.15} fill={d.c} opacity="0.7" transform={`rotate(${d.rot} ${d.x} ${d.y})`} />
      )}
    </svg>
  );
}

// Wiggle on hover wrapper
function Wiggle({ children, intensity = 1, ...rest }) {
  const ref = React.useRef(null);
  const [hov, setHov] = React.useState(false);
  return (
    <span ref={ref} {...rest}
      onMouseEnter={() => setHov(true)} onMouseLeave={() => setHov(false)}
      style={{
        display: 'inline-block',
        animation: hov ? `wiggle-${intensity} .35s ease-in-out infinite alternate` : 'none',
        ...rest.style,
      }}>
      {children}
      <style>{`
        @keyframes wiggle-1 { from { transform: rotate(-2deg); } to { transform: rotate(2deg); } }
        @keyframes wiggle-2 { from { transform: rotate(-5deg) scale(1.05); } to { transform: rotate(5deg) scale(1.05); } }
      `}</style>
    </span>
  );
}

// ─────────────────────────────────────────────────────────────
// Office Hours clock — minimal mark, light-mode treatment.
// Mirrors the favicon-scale clock from the brand sheet.
// ─────────────────────────────────────────────────────────────
function OfficeHoursClock({ size = 64, radius = 10, bg = '#F5F2ED', accent = '#C4622D', ink = '#2A2520', border }) {
  const cx = 32, cy = 32, r = 20;
  return (
    <svg viewBox="0 0 64 64" width={size} height={size} style={{ display: 'block' }}>
      <rect x="0.75" y="0.75" width="62.5" height="62.5" rx={radius} fill={bg} stroke={border || 'none'} strokeWidth={border ? 1.5 : 0} />
      <circle cx={cx} cy={cy} r={r} fill="none" stroke={accent} strokeWidth="1.5" />
      {Array.from({ length: 12 }).map((_, i) => {
        const a = (i / 12) * Math.PI * 2 - Math.PI / 2;
        const x1 = cx + Math.cos(a) * (r - 2);
        const y1 = cy + Math.sin(a) * (r - 2);
        const x2 = cx + Math.cos(a) * r;
        const y2 = cy + Math.sin(a) * r;
        return <line key={i} x1={x1} y1={y1} x2={x2} y2={y2} stroke={accent} strokeWidth="1" strokeLinecap="round" />;
      })}
      {/* minute hand pointing to 9 */}
      <line x1={cx} y1={cy} x2={cx - 14} y2={cy} stroke={accent} strokeWidth="2" strokeLinecap="round" />
      {/* hour hand pointing toward 1 */}
      <line x1={cx} y1={cy} x2={cx + 4} y2={cy - 16} stroke={ink} strokeWidth="1.5" strokeLinecap="round" />
      <circle cx={cx} cy={cy} r="2.2" fill={accent} />
    </svg>
  );
}

// ─────────────────────────────────────────────────────────────
// Jamón — Scarlett's gray guinea pig with a yellow fur patch on
// her back-left leg. Side-view, pear-shaped (fatter butt). Clickable.
// ─────────────────────────────────────────────────────────────
function JamonGuineaPig({ size = 140, onClick, talking, idle = true }) {
  const ink = '#1f1a14';
  const fur = '#a4a3a8';
  const furDark = '#74737a';
  const furLight = '#e3e2e6';
  const cheek = '#FF9CA0';
  const yellow = '#FFE066';
  const w = size;
  // Pear-shaped body: fat left butt, slimmer right toward head.
  const bodyD = "M 28 100 C 22 38, 80 24, 138 38 C 178 46, 200 64, 200 92 C 200 118, 180 132, 142 142 C 92 154, 28 158, 28 100 Z";
  return (
    <div style={{ position: 'relative', display: 'inline-block' }}>
      <button
        onClick={onClick}
        title="chat with Jamón"
        aria-label="Chat with Jamón"
        style={{
          border: 'none', background: 'transparent', padding: 0, margin: 0,
          cursor: onClick ? 'pointer' : 'default', display: 'block',
          animation: idle ? 'jamon-bob 3.6s ease-in-out infinite' : 'none',
          transformOrigin: '50% 90%',
        }}
      >
        <svg viewBox="0 0 220 175" width={w} height={w * 175 / 220} style={{ display: 'block', overflow: 'visible' }}>
          {/* drop shadow */}
          <ellipse cx="115" cy="162" rx="86" ry="6" fill={ink} opacity="0.12" />

          {/* back-left leg (yellow, drawn behind body) */}
          <ellipse cx="56" cy="158" rx="13" ry="9" fill={yellow} stroke={ink} strokeWidth="2" />

          {/* body fill (no stroke yet) */}
          <path d={bodyD} fill={fur} />
          {/* yellow fur patch on butt/back-left — entirely inside body */}
          <ellipse cx="50" cy="125" rx="34" ry="22" fill={yellow} />
          <ellipse cx="42" cy="115" rx="10" ry="6" fill={yellow} opacity="0.7" />
          {/* tummy */}
          <ellipse cx="115" cy="130" rx="62" ry="16" fill={furLight} opacity=".55" />
          {/* fur tufts on back */}
          <path d="M50 70 Q 56 62 62 70" fill="none" stroke={furDark} strokeWidth="1.4" strokeLinecap="round" />
          <path d="M82 56 Q 86 50 92 56" fill="none" stroke={furDark} strokeWidth="1.4" strokeLinecap="round" />
          <path d="M110 50 Q 114 44 120 50" fill="none" stroke={furDark} strokeWidth="1.4" strokeLinecap="round" />
          <path d="M138 54 Q 142 48 148 54" fill="none" stroke={furDark} strokeWidth="1.4" strokeLinecap="round" />
          {/* body stroke (outline last, on top of fills) */}
          <path d={bodyD} fill="none" stroke={ink} strokeWidth="2.5" />

          {/* front legs */}
          <ellipse cx="148" cy="146" rx="9" ry="7" fill={furDark} stroke={ink} strokeWidth="2" />
          <ellipse cx="124" cy="148" rx="9" ry="7" fill={furDark} stroke={ink} strokeWidth="2" />

          {/* head — bigger */}
          <circle cx="176" cy="84" r="44" fill={fur} stroke={ink} strokeWidth="2.5" />

          {/* ear */}
          <g transform="rotate(-18 164 50)">
            <ellipse cx="164" cy="50" rx="11" ry="14" fill={furDark} stroke={ink} strokeWidth="2" />
            <ellipse cx="164" cy="52" rx="5" ry="8" fill={cheek} opacity=".55" />
          </g>

          {/* eye */}
          <circle cx="196" cy="78" r="4.5" fill={ink} />
          <circle cx="197.8" cy="76.2" r="1.3" fill="#fff" />
          <rect x="190" y="76" width="10" height="5" rx="2.5" fill={fur}
            style={{ animation: 'jamon-blink 5.3s infinite', transformOrigin: '195px 78px' }} />

          {/* cheek */}
          <circle cx="186" cy="98" r="5" fill={cheek} opacity=".55" />

          {/* nose + mouth */}
          <path d="M212 88 Q 218 90 212 92 Q 208 90 212 88 Z" fill={ink} />
          <path d="M212 92 L212 97" stroke={ink} strokeWidth="1.5" strokeLinecap="round" fill="none" />
          <path d="M206 100 Q 212 97 218 100" stroke={ink} strokeWidth="1.5" strokeLinecap="round" fill="none" />

          {/* whiskers */}
          <line x1="206" y1="94" x2="224" y2="92" stroke={ink} strokeWidth=".8" strokeLinecap="round" />
          <line x1="206" y1="96" x2="226" y2="99" stroke={ink} strokeWidth=".8" strokeLinecap="round" />
        </svg>
      </button>

      {talking && (
        <div style={{
          position: 'absolute', left: -8, top: -38,
          background: '#fff', border: `2px solid ${ink}`, padding: '5px 10px',
          borderRadius: 8, fontSize: 12, whiteSpace: 'nowrap', color: ink,
          boxShadow: `2px 2px 0 ${ink}`, fontFamily: 'inherit', fontWeight: 700,
          pointerEvents: 'none',
        }}>
          {talking}
          <div style={{ position: 'absolute', left: 26, bottom: -7, width: 0, height: 0,
            borderLeft: '5px solid transparent', borderRight: '5px solid transparent',
            borderTop: `7px solid ${ink}` }} />
        </div>
      )}

      <style>{`
        @keyframes jamon-blink {
          0%, 92%, 100% { transform: scaleY(0); }
          94%, 96% { transform: scaleY(1); }
        }
        @keyframes jamon-bob {
          0%, 100% { transform: translateY(0) rotate(-1deg); }
          50% { transform: translateY(-3px) rotate(1deg); }
        }
      `}</style>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Jamón Chat — fixed bottom-right chat window. Jamón is a cute
// chatbot. Email is only sent if Jamón offers and the user agrees.
// ─────────────────────────────────────────────────────────────
function _jamonPick(arr) { return arr[Math.floor(Math.random() * arr.length)]; }

function JamonChat({ open, onClose, accent = '#FF7A6B' }) {
  const ink = '#1f1a14';
  const paper = '#FBF7EE';

  const [messages, setMessages] = React.useState([
    { from: 'jamon', text: "*squeak squeak!* hi! I'm Jamón, Scarlett's guinea pig 🐹 What's on your mind?" },
  ]);
  const [input, setInput] = React.useState('');
  const [typing, setTyping] = React.useState(false);
  const [waitingEmail, setWaitingEmail] = React.useState(false);
  const [emailForm, setEmailForm] = React.useState(false);
  const [formName, setFormName] = React.useState('');
  const [formEmail, setFormEmail] = React.useState('');
  const [sending, setSending] = React.useState(false);
  const msgsRef = React.useRef(null);
  const taRef = React.useRef(null);
  const endRef = React.useRef(null);

  React.useEffect(() => {
    if (open && taRef.current && !emailForm) setTimeout(() => taRef.current?.focus(), 50);
  }, [open, emailForm]);

  React.useEffect(() => {
    endRef.current?.scrollIntoView({ behavior: 'smooth' });
  }, [messages, typing, emailForm]);

  if (!open) return null;

  const addJamon = (text, delay = 900) => {
    setTyping(true);
    setTimeout(() => {
      setTyping(false);
      setMessages((m) => [...m, { from: 'jamon', text }]);
    }, delay);
  };

  const submitEmailForm = async () => {
    const name = formName.trim();
    const email = formEmail.trim();
    if (!name || !email || sending) return;
    setSending(true);

    const chatLog = messages
      .map((m) => `${m.from === 'user' ? name : 'Jamón'}: ${m.text}`)
      .join('\n');

    try {
      const r = await fetch('/api/send-chat', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ name, visitorEmail: email, chatLog }),
      });
      setSending(false);
      setEmailForm(false);
      setFormName('');
      setFormEmail('');
      if (r.ok) {
        addJamon("*sprints to inbox* 🏃💨 wheeeek!! Scarlett's got your message 📬 she'll reply to your email!", 300);
      } else {
        addJamon("*worried squeak* hmm, something went wrong 😅 maybe try again in a bit?", 300);
      }
    } catch {
      setSending(false);
      addJamon("*worried squeak* hmm, something went wrong 😅 maybe try again in a bit?", 300);
    }
  };

  const send = () => {
    const raw = input.trim();
    if (!raw || typing || emailForm) return;
    setMessages((m) => [...m, { from: 'user', text: raw }]);
    setInput('');
    const t = raw.toLowerCase();

    let reply;
    let nextWaiting = waitingEmail;
    let showForm = false;

    if (waitingEmail) {
      if (t.match(/\b(yes|yeah|yep|sure|ok|okay|send|do it|please|absolutely)\b/)) {
        nextWaiting = false;
        showForm = true;
        reply = "*squeak!!* let's do it 📬 just fill in your name and email below so Scarlett can write back!";
      } else if (t.match(/\b(no|nope|nah|not|skip|never|cancel)\b/)) {
        nextWaiting = false;
        reply = _jamonPick([
          "*shrugs tiny shoulders* no worries! I'll keep it in my heart 💕",
          "okay okay! *tucks it away* anything else? 🐹",
        ]);
      } else {
        reply = "*squeak?* just say yes or no — should I send it to Scarlett? 📬";
      }
    } else if (t.match(/\b(hi|hello|hey|howdy|hiya|sup|yo|heyy)\b/)) {
      reply = _jamonPick([
        "*wheek wheek!* hi hi!! 🐹✨ so happy you're here!",
        "*happy vibrate* HI!! you came to chat with me!! 🎉",
        "*squeak!* hello friend!! I'm Jamón 🐹",
      ]);
    } else if (t.match(/\b(thank|thanks|thx|ty|appreciate|grateful)\b/)) {
      reply = _jamonPick([
        "*happy squeak!* aww 🥹 you're SO sweet!!",
        "*popcorns excitedly* that made my whole tiny day!! 💕",
        "no no YOU'RE wonderful!! *wheek wheek*",
      ]);
    } else if (t.match(/\b(idea|build|feature|cool if|what if|suggest|should make|could add|wish|add a|you should)\b/)) {
      nextWaiting = true;
      reply = "*ears perk way up* 👀 ooh!! that sounds SO interesting! want me to send this idea to Scarlett's inbox? say yes or no!";
    } else if (t.match(/\b(feedback|bug|broken|issue|problem|annoying|confusing|wrong|fix|improve|doesn't work|not working)\b/)) {
      nextWaiting = true;
      reply = "*thoughtful nibble* 🌿 hmm I hear you! should I pass this feedback to Scarlett? she'll definitely want to know — yes or no?";
    } else if (t.match(/\b(who|scarlett|she|techclatters|made|built|this site|workshop)\b/)) {
      reply = _jamonPick([
        "Scarlett made all of this! 🛠️ she builds tiny fun things — games, extensions, all sorts of stuff!",
        "this is Scarlett's little workshop 🏠 she makes small software things for fun and curiosity!",
        "oh Scarlett is SO cool (I live with her so I'm an expert 🐹) — she makes lil apps and games!",
      ]);
    } else if (t.match(/\b(cute|adorable|love you|you're great|best|awesome|i like you|you're cool)\b/)) {
      reply = _jamonPick([
        "*blushes furiously* 🥺 stoppp you're making me popcorn!!",
        "*happy squeak intensifies* 💕💕 I LOVE THIS CONVERSATION",
        "I'M TELLING SCARLETT YOU SAID THAT 📢 *wheek*",
      ]);
    } else if (t.match(/\b(food|eat|snack|hungry|hay|pellets|lettuce|carrot|veggie|grass)\b/)) {
      reply = _jamonPick([
        "*perks up IMMEDIATELY* 👀 did someone say... snacks???",
        "*zooms to food bowl* WHEEK WHEEK WHEEK 🥬🥬",
        "I am ALWAYS thinking about food. always. what are we eating. 🥕",
      ]);
    } else if (t.match(/\b(bye|goodbye|cya|see ya|later|gotta go|leaving)\b/)) {
      reply = _jamonPick([
        "*sad squeak* nooo come back soon!! 🥹",
        "byeee!! *waves tiny paw* 🐾💕",
        "*runs after you* wait wait— okay okay. bye!! come back!! 🐹",
      ]);
    } else {
      reply = _jamonPick([
        "*squeak squeak!* interesting!! tell me more 👂",
        "*happy wheek!* I hear you!! 🐹",
        "*nibble nibble* hmm... *thinks with tiny brain*...",
        "*popcorns!* 🎉",
        "*runs in a tiny circle* I'm listening!!",
        "wheek wheek!! that's fascinating to me, a guinea pig 🐾",
        "*tilts head curiously* yeah? yeah!! *squeak*",
        "*vibrates with excitement* 🐹✨",
      ]);
    }

    if (nextWaiting !== waitingEmail) setWaitingEmail(nextWaiting);
    addJamon(reply);
    if (showForm) setTimeout(() => setEmailForm(true), 1100);
  };

  const inputStyle = { border: `1.5px solid ${ink}`, padding: '6px 8px', fontFamily: 'inherit', fontSize: 12, background: '#fff', outline: 'none', width: '100%', boxSizing: 'border-box' };

  return (
    <div style={{
      position: 'fixed', right: 16, bottom: 96, width: 320, maxWidth: 'calc(100vw - 32px)', zIndex: 9999,
      background: paper, border: `2px solid ${ink}`,
      boxShadow: `6px 6px 0 ${ink}`, display: 'flex', flexDirection: 'column',
      overflow: 'hidden', fontFamily: 'inherit',
      animation: 'jamon-pop .25s cubic-bezier(.4,1.6,.5,1)',
      transformOrigin: '95% 100%',
    }}>
      {/* header */}
      <div style={{
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        padding: '8px 10px', background: '#FFE66B', borderBottom: `2px solid ${ink}`,
        flexShrink: 0,
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, fontWeight: 800, fontSize: 13 }}>
          <span style={{
            display: 'inline-block', width: 9, height: 9, borderRadius: '50%',
            background: '#7BB87A', boxShadow: `0 0 0 1.5px ${ink}`,
            animation: 'jamon-pulse 1.6s ease-in-out infinite',
          }} />
          chat with Jamón 🐹
        </div>
        <button onClick={onClose} aria-label="Close chat" style={{
          border: `1.5px solid ${ink}`, background: paper, cursor: 'pointer',
          width: 22, height: 22, fontWeight: 800, fontSize: 14, padding: 0, lineHeight: 1, borderRadius: 2,
        }}>×</button>
      </div>

      {/* mascot strip */}
      <div style={{
        padding: '6px 10px', borderBottom: `1.5px dashed ${ink}`,
        background: '#fffdf5', display: 'flex', alignItems: 'center', gap: 8, flexShrink: 0,
      }}>
        <JamonFront size={40} />
        <div style={{ fontSize: 11, color: '#7a6a55', fontWeight: 600, letterSpacing: '.04em' }}>
          chatting with <b style={{ color: ink }}>jamón</b> · <span style={{ color: accent }}>online</span>
        </div>
      </div>

      {/* messages */}
      <div ref={msgsRef} style={{
        padding: 12, maxHeight: 220, overflowY: 'auto',
        display: 'flex', flexDirection: 'column', gap: 8,
        fontSize: 13, lineHeight: 1.4,
      }}>
        {messages.map((m, i) => (
          <div key={i} style={{
            alignSelf: m.from === 'user' ? 'flex-end' : 'flex-start',
            maxWidth: '85%',
            background: m.from === 'user' ? '#9DC3FF' : '#fff',
            border: `1.5px solid ${ink}`, padding: '6px 10px', borderRadius: 6,
            whiteSpace: 'pre-wrap',
          }}>{m.text}</div>
        ))}
        {typing && (
          <div style={{
            alignSelf: 'flex-start', background: '#fff',
            border: `1.5px solid ${ink}`, padding: '6px 12px', borderRadius: 6,
            fontSize: 18, letterSpacing: 3, color: '#999',
          }}>···</div>
        )}
        <div ref={endRef} />
      </div>

      {/* email form — shown after user agrees to send */}
      {emailForm && (
        <div style={{
          padding: 12, borderTop: `2px solid ${ink}`,
          background: '#fffdf5', display: 'flex', flexDirection: 'column', gap: 8, flexShrink: 0,
        }}>
          <div style={{ fontSize: 12, fontWeight: 700, color: ink }}>*squeak!* who should Scarlett reply to? 🐹</div>
          <input
            autoFocus
            value={formName}
            onChange={(e) => setFormName(e.target.value)}
            placeholder="your name"
            style={inputStyle}
          />
          <input
            value={formEmail}
            onChange={(e) => setFormEmail(e.target.value)}
            onKeyDown={(e) => { if (e.key === 'Enter') submitEmailForm(); }}
            placeholder="your email"
            type="email"
            style={inputStyle}
          />
          <div style={{ display: 'flex', gap: 6 }}>
            <button onClick={() => setEmailForm(false)} style={{
              flex: 1, background: paper, border: `1.5px solid ${ink}`, padding: '6px 0',
              fontFamily: 'inherit', fontWeight: 700, fontSize: 11, cursor: 'pointer', borderRadius: 2,
            }}>cancel</button>
            <button
              onClick={submitEmailForm}
              disabled={sending || !formName.trim() || !formEmail.trim()}
              style={{
                flex: 2, background: ink, color: paper, border: `1.5px solid ${ink}`,
                padding: '6px 0', fontFamily: 'inherit', fontWeight: 800, fontSize: 11,
                cursor: 'pointer', letterSpacing: '.04em', borderRadius: 2,
                opacity: (!formName.trim() || !formEmail.trim()) ? 0.45 : 1,
              }}>{sending ? 'SENDING…' : 'SEND TO SCARLETT 📬'}</button>
          </div>
        </div>
      )}

      {/* chat input — hidden while email form is open */}
      {!emailForm && (
        <div style={{
          padding: 10, borderTop: `2px dashed ${ink}`, display: 'flex', gap: 6,
          background: '#fffdf5', flexShrink: 0,
        }}>
          <textarea
            ref={taRef}
            value={input}
            onChange={(e) => setInput(e.target.value)}
            onKeyDown={(e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send(); } }}
            placeholder="say anything…"
            rows={2}
            style={{
              flex: 1, resize: 'none', border: `1.5px solid ${ink}`, padding: 6,
              fontFamily: 'inherit', fontSize: 12, background: '#fff', outline: 'none',
            }}
          />
          <button onClick={send} style={{
            background: ink, color: paper, border: `1.5px solid ${ink}`,
            padding: '0 12px', fontWeight: 800, fontSize: 11, cursor: 'pointer',
            letterSpacing: '.05em', borderRadius: 2,
          }}>SEND</button>
        </div>
      )}

      <style>{`
        @keyframes jamon-pop {
          from { transform: scale(.8) translateY(8px); opacity: 0; }
          to   { transform: scale(1) translateY(0); opacity: 1; }
        }
        @keyframes jamon-pulse {
          0%, 100% { transform: scale(1); }
          50% { transform: scale(1.4); }
        }
      `}</style>
    </div>
  );
}

// Fixed bottom-right trigger button — always on screen, opens/closes the chat.
function JamonFloatingTrigger({ open, onClick }) {
  const ink = '#1f1a14';
  return (
    <button
      onClick={onClick}
      aria-label={open ? 'Close chat' : 'Chat with Jamón'}
      style={{
        position: 'fixed', bottom: 24, right: 16, zIndex: 9999,
        width: 64, height: 64, border: `2px solid ${ink}`, borderRadius: '50%',
        background: '#FFE66B', boxShadow: `3px 3px 0 ${ink}`,
        cursor: 'pointer', padding: 0,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        animation: open ? 'none' : 'jamon-bob 3.6s ease-in-out infinite',
        transformOrigin: '50% 90%',
        transition: 'box-shadow .15s, transform .15s',
      }}
    >
      {open
        ? <span style={{ fontSize: 24, fontWeight: 800, color: ink, lineHeight: 1 }}>×</span>
        : <JamonFront size={48} />
      }
    </button>
  );
}

// ─────────────────────────────────────────────────────────────
// Jamón pose sprites — front (face), back (away), lay (resting)
// All scaled to a uniform ~140×120 box. Side view is JamonGuineaPig.
// ─────────────────────────────────────────────────────────────
const JAMON_INK = '#1f1a14';
const JAMON_FUR = '#a4a3a8';
const JAMON_FUR_DARK = '#74737a';
const JAMON_FUR_LIGHT = '#e3e2e6';
const JAMON_CHEEK = '#FF9CA0';
const JAMON_CAST = '#FFE66B';

function JamonFront({ size = 120 }) {
  const s = size, w = 140, h = 140;
  return (
    <svg viewBox={`0 0 ${w} ${h}`} width={s} height={s * h / w} style={{ display: 'block', overflow: 'visible' }}>
      <ellipse cx="70" cy="132" rx="42" ry="5" fill={JAMON_INK} opacity="0.12" />
      <ellipse cx="44" cy="38" rx="10" ry="14" fill={JAMON_FUR_DARK} stroke={JAMON_INK} strokeWidth="2" transform="rotate(-15 44 38)" />
      <ellipse cx="96" cy="38" rx="10" ry="14" fill={JAMON_FUR_DARK} stroke={JAMON_INK} strokeWidth="2" transform="rotate(15 96 38)" />
      <ellipse cx="44" cy="40" rx="4.5" ry="7" fill={JAMON_CHEEK} opacity=".55" transform="rotate(-15 44 40)" />
      <ellipse cx="96" cy="40" rx="4.5" ry="7" fill={JAMON_CHEEK} opacity=".55" transform="rotate(15 96 40)" />
      <ellipse cx="70" cy="80" rx="50" ry="46" fill={JAMON_FUR} stroke={JAMON_INK} strokeWidth="2.5" />
      <ellipse cx="70" cy="100" rx="32" ry="22" fill={JAMON_FUR_LIGHT} opacity=".55" />
      <path d="M58 32 Q62 24 66 32" fill="none" stroke={JAMON_INK} strokeWidth="1.4" strokeLinecap="round" />
      <path d="M74 32 Q78 24 82 32" fill="none" stroke={JAMON_INK} strokeWidth="1.4" strokeLinecap="round" />
      <circle cx="54" cy="62" r="4" fill={JAMON_INK} />
      <circle cx="55.5" cy="60.5" r="1.2" fill="#fff" />
      <circle cx="86" cy="62" r="4" fill={JAMON_INK} />
      <circle cx="87.5" cy="60.5" r="1.2" fill="#fff" />
      <circle cx="44" cy="78" r="6" fill={JAMON_CHEEK} opacity=".55" />
      <circle cx="96" cy="78" r="6" fill={JAMON_CHEEK} opacity=".55" />
      <path d="M65 78 Q70 84 75 78 Q70 80 65 78 Z" fill={JAMON_INK} />
      <path d="M70 80 L70 86" stroke={JAMON_INK} strokeWidth="1.4" strokeLinecap="round" fill="none" />
      <path d="M64 90 Q70 86 76 90" stroke={JAMON_INK} strokeWidth="1.4" strokeLinecap="round" fill="none" />
      <ellipse cx="50" cy="124" rx="9" ry="6" fill={JAMON_FUR_DARK} stroke={JAMON_INK} strokeWidth="2" />
      <ellipse cx="90" cy="124" rx="9" ry="6" fill={JAMON_FUR_DARK} stroke={JAMON_INK} strokeWidth="2" />
    </svg>
  );
}

function JamonBack({ size = 120 }) {
  const s = size, w = 140, h = 140;
  return (
    <svg viewBox={`0 0 ${w} ${h}`} width={s} height={s * h / w} style={{ display: 'block', overflow: 'visible' }}>
      <ellipse cx="70" cy="132" rx="42" ry="5" fill={JAMON_INK} opacity="0.12" />
      <ellipse cx="50" cy="38" rx="9" ry="12" fill={JAMON_FUR_DARK} stroke={JAMON_INK} strokeWidth="2" />
      <ellipse cx="90" cy="38" rx="9" ry="12" fill={JAMON_FUR_DARK} stroke={JAMON_INK} strokeWidth="2" />
      <ellipse cx="70" cy="80" rx="50" ry="46" fill={JAMON_FUR} />
      <ellipse cx="40" cy="108" rx="22" ry="18" fill={JAMON_CAST} />
      <ellipse cx="70" cy="80" rx="50" ry="46" fill="none" stroke={JAMON_INK} strokeWidth="2.5" />
      <path d="M40 56 Q44 50 48 56" fill="none" stroke={JAMON_FUR_DARK} strokeWidth="1.4" strokeLinecap="round" />
      <path d="M58 50 Q62 44 66 50" fill="none" stroke={JAMON_FUR_DARK} strokeWidth="1.4" strokeLinecap="round" />
      <path d="M74 50 Q78 44 82 50" fill="none" stroke={JAMON_FUR_DARK} strokeWidth="1.4" strokeLinecap="round" />
      <path d="M92 56 Q96 50 100 56" fill="none" stroke={JAMON_FUR_DARK} strokeWidth="1.4" strokeLinecap="round" />
      <path d="M55 76 Q60 70 65 76" fill="none" stroke={JAMON_FUR_DARK} strokeWidth="1" opacity=".55" />
      <path d="M75 76 Q80 70 85 76" fill="none" stroke={JAMON_FUR_DARK} strokeWidth="1" opacity=".55" />
      <ellipse cx="70" cy="108" rx="5" ry="3.5" fill={JAMON_FUR_DARK} stroke={JAMON_INK} strokeWidth="1.5" />
      <ellipse cx="92" cy="124" rx="9" ry="6" fill={JAMON_FUR_DARK} stroke={JAMON_INK} strokeWidth="2" />
      <ellipse cx="48" cy="126" rx="9" ry="6" fill={JAMON_CAST} stroke={JAMON_INK} strokeWidth="2" />
    </svg>
  );
}

function JamonLay({ size = 160 }) {
  const w = 220, h = 130;
  return (
    <svg viewBox={`0 0 ${w} ${h}`} width={size} height={size * h / w} style={{ display: 'block', overflow: 'visible' }}>
      <ellipse cx="110" cy="122" rx="84" ry="5" fill={JAMON_INK} opacity="0.12" />
      <ellipse cx="54" cy="118" rx="14" ry="5" fill={JAMON_CAST} stroke={JAMON_INK} strokeWidth="2" />
      <ellipse cx="100" cy="84" rx="84" ry="26" fill={JAMON_FUR} />
      <ellipse cx="50" cy="92" rx="30" ry="16" fill={JAMON_CAST} />
      <ellipse cx="100" cy="84" rx="84" ry="26" fill="none" stroke={JAMON_INK} strokeWidth="2.5" />
      <ellipse cx="100" cy="92" rx="62" ry="13" fill={JAMON_FUR_LIGHT} opacity=".55" />
      <path d="M40 70 Q44 64 48 70" fill="none" stroke={JAMON_FUR_DARK} strokeWidth="1.4" strokeLinecap="round" />
      <path d="M70 64 Q74 58 78 64" fill="none" stroke={JAMON_FUR_DARK} strokeWidth="1.4" strokeLinecap="round" />
      <path d="M104 60 Q108 54 112 60" fill="none" stroke={JAMON_FUR_DARK} strokeWidth="1.4" strokeLinecap="round" />
      <circle cx="176" cy="74" r="26" fill={JAMON_FUR} stroke={JAMON_INK} strokeWidth="2.5" />
      <ellipse cx="162" cy="56" rx="9" ry="11" fill={JAMON_FUR_DARK} stroke={JAMON_INK} strokeWidth="2" transform="rotate(-30 162 56)" />
      <path d="M178 70 Q182 67 186 70" fill="none" stroke={JAMON_INK} strokeWidth="1.6" strokeLinecap="round" />
      <circle cx="186" cy="84" r="4" fill={JAMON_CHEEK} opacity=".55" />
      <path d="M196 76 Q200 78 196 80 Q194 78 196 76 Z" fill={JAMON_INK} />
      <path d="M196 80 L196 84" stroke={JAMON_INK} strokeWidth="1.4" strokeLinecap="round" fill="none" />
      <line x1="190" y1="82" x2="206" y2="82" stroke={JAMON_INK} strokeWidth=".7" />
      <ellipse cx="80" cy="112" rx="10" ry="4" fill={JAMON_FUR_DARK} stroke={JAMON_INK} strokeWidth="2" />
      <ellipse cx="120" cy="114" rx="10" ry="4" fill={JAMON_FUR_DARK} stroke={JAMON_INK} strokeWidth="2" />
      <text x="200" y="42" fontSize="16" fontWeight="800" fill={JAMON_INK} fontFamily="'Caveat', cursive">z</text>
      <text x="212" y="28" fontSize="11" fontWeight="800" fill={JAMON_INK} fontFamily="'Caveat', cursive">z</text>
    </svg>
  );
}

function JamonSprite({ pose = 'right', size = 120 }) {
  if (pose === 'lay') return <JamonLay size={size * 1.4} />;
  if (pose === 'front' || pose === 'down' || pose === 'sit') return <JamonFront size={size} />;
  if (pose === 'back' || pose === 'up') return <JamonBack size={size} />;
  // side: right (default) or left (mirrored)
  return (
    <div style={{ transform: pose === 'left' ? 'scaleX(-1)' : 'none', display: 'inline-block' }}>
      <JamonGuineaPig size={size * 1.2} idle={false} />
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// JamonRoamer — wanders a rectangular bounds. Walks (with directional
// pose), sits to show face, lays at top-right corner. Click → onClick.
// ─────────────────────────────────────────────────────────────
function JamonRoamer({ width = 1280, height = 800, onClick, paused = false, hint = "click me — i'm jamón, a guinea pig 🐹" }) {
  const PAD = 36;
  const SPEED = 0.035; // px/ms
  const minX = PAD, maxX = width - PAD - 100;
  const minY = 90, maxY = height - 60 - 100;
  const layX = maxX - 30, layY = minY + 10;

  const [pos, setPos] = React.useState(() => ({ x: maxX - 200, y: minY + 20 }));
  const [pose, setPose] = React.useState('right');
  const [showHint, setShowHint] = React.useState(true);

  const stateRef = React.useRef({ pos, pose });
  stateRef.current = { pos, pose };
  const pausedRef = React.useRef(paused);
  React.useEffect(() => {
    pausedRef.current = paused;
    if (paused) setPose('front');
  }, [paused]);

  React.useEffect(() => {
    let raf;
    let mode = 'walk'; // walk | walk_to_lay | sit | lay
    let modeUntil = 0;
    let target = { x: minX + Math.random() * (maxX - minX), y: minY + Math.random() * (maxY - minY) };
    let lastT = performance.now();
    let frame = 0;

    const step = (now) => {
      if (pausedRef.current) { lastT = now; raf = requestAnimationFrame(step); return; }
      const dt = Math.min(50, now - lastT);
      lastT = now;
      frame++;
      const cur = stateRef.current.pos;

      if (mode === 'walk' || mode === 'walk_to_lay') {
        const dx = target.x - cur.x;
        const dy = target.y - cur.y;
        const dist = Math.hypot(dx, dy);
        if (dist < 4) {
          if (mode === 'walk_to_lay') {
            mode = 'lay';
            modeUntil = now + 4500 + Math.random() * 3500;
            setPose('lay');
          } else {
            const r = Math.random();
            if (r < 0.28) {
              target = { x: layX, y: layY };
              mode = 'walk_to_lay';
            } else if (r < 0.6) {
              mode = 'sit';
              modeUntil = now + 1800 + Math.random() * 1800;
              setPose('front');
            } else {
              target = { x: minX + Math.random() * (maxX - minX), y: minY + Math.random() * (maxY - minY) };
            }
          }
        } else {
          const move = Math.min(dist, SPEED * dt);
          const nx = cur.x + (dx / dist) * move;
          const ny = cur.y + (dy / dist) * move;
          // pose only every few frames to avoid jitter
          if (frame % 4 === 0) {
            let next;
            if (Math.abs(dx) > Math.abs(dy) * 1.2) next = dx > 0 ? 'right' : 'left';
            else next = dy > 0 ? 'down' : 'up';
            if (next !== stateRef.current.pose) setPose(next);
          }
          setPos({ x: nx, y: ny });
        }
      } else if (mode === 'sit' || mode === 'lay') {
        if (now > modeUntil) {
          mode = 'walk';
          target = { x: minX + Math.random() * (maxX - minX), y: minY + Math.random() * (maxY - minY) };
        }
      }
      raf = requestAnimationFrame(step);
    };
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
  }, [width, height]);

  React.useEffect(() => {
    const t = setTimeout(() => setShowHint(false), 5500);
    return () => clearTimeout(t);
  }, []);

  return (
    <div
      onClick={() => { setShowHint(false); onClick?.(); }}
      style={{
        position: 'absolute', left: pos.x, top: pos.y,
        width: 110, height: 100, cursor: 'pointer', zIndex: 30,
        userSelect: 'none',
      }}
    >
      <JamonSprite pose={pose} size={pose === 'lay' ? 110 : 90} />
      {showHint && pose === 'front' && (
        <div style={{
          position: 'absolute', left: 80, top: -12,
          background: '#fff', border: `2px solid ${JAMON_INK}`, padding: '4px 8px',
          borderRadius: 8, fontSize: 11, whiteSpace: 'nowrap', color: JAMON_INK,
          boxShadow: `2px 2px 0 ${JAMON_INK}`, fontWeight: 700,
          pointerEvents: 'none', fontFamily: 'inherit',
        }}>
          {hint}
        </div>
      )}
    </div>
  );
}

Object.assign(window, { PROJECTS, ABOUT, PixelBuddy, AnagramReveal, FeedTheKitty, CursorTrail, ConfettiDots, Wiggle, OfficeHoursClock, JamonGuineaPig, JamonChat, JamonFloatingTrigger, JamonSprite, JamonRoamer, JamonFront, JamonBack, JamonLay });
