// shared.jsx — atoms used across all three directions
// PawntherMark (morphs pawn↔panther on hover), MiniBoard, MascotPeek, Logo,
// scroll reveal hook, glyph helpers.

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

// ──────────────────────────────────────────────────────────────────────
// 1. PAWNTHER WORDMARK — hover morphs the "Pawnther" word; the "P"
//    crossfades between a chess pawn glyph and a panther head silhouette.
//    Click 7 times → toast easter egg.
// ──────────────────────────────────────────────────────────────────────
function PawntherMark({ size = 28, dark = false, italic = true, onSecret }) {
  const [hover, setHover] = useState(false);
  const [clicks, setClicks] = useState(0);
  const [showSecret, setShowSecret] = useState(false);
  const ink = dark ? '#f5ead6' : '#191714';
  const gold = '#e39b44';

  function handleClick(){
    const next = clicks + 1;
    setClicks(next);
    if (next === 7){
      setShowSecret(true);
      onSecret && onSecret();
      setTimeout(() => setShowSecret(false), 2400);
      setTimeout(() => setClicks(0), 3000);
    }
  }

  return (
    <span
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
      onClick={handleClick}
      style={{
        position: 'relative',
        display: 'inline-flex',
        alignItems: 'baseline',
        cursor: 'pointer',
        fontFamily: 'Fraunces, serif',
        fontSize: size,
        fontWeight: 700,
        letterSpacing: '-.03em',
        color: ink,
        fontVariationSettings: '"opsz" 144, "SOFT" 50',
      }}
    >
      {/* P with morph */}
      <span style={{
        position: 'relative',
        display: 'inline-block',
        width: `${size * 0.78}px`,
        height: `${size * 1.02}px`,
        marginRight: `${size * 0.02}px`,
      }}>
        {/* Pawn glyph (default) */}
        <svg viewBox="0 0 64 80" style={{
          position: 'absolute', inset: 0, width: '100%', height: '100%',
          opacity: hover ? 0 : 1, transform: hover ? 'scale(.7) translateY(8px)' : 'scale(1)',
          transition: 'opacity .35s var(--ease-soft), transform .35s var(--ease-soft)',
        }}>
          {/* Stylized capital P that reads as a pawn */}
          <text x="32" y="62" textAnchor="middle"
            style={{
              fontFamily: 'Fraunces, serif',
              fontSize: 80,
              fontWeight: 700,
              fontStyle: italic ? 'italic' : 'normal',
              fontVariationSettings: '"opsz" 144, "SOFT" 60',
              fill: ink,
            }}>P</text>
          {/* pawn-ball dot above the P bowl — appears on hover-out only */}
          <circle cx="44" cy="14" r="3" fill={gold}
            style={{ opacity: hover ? 0 : 0.0, transition: 'opacity .35s' }} />
        </svg>

        {/* Panther silhouette (hover) */}
        <svg viewBox="0 0 64 80" style={{
          position: 'absolute', inset: 0, width: '100%', height: '100%',
          opacity: hover ? 1 : 0, transform: hover ? 'scale(1)' : 'scale(.7) translateY(8px)',
          transition: 'opacity .45s var(--ease-soft), transform .45s var(--ease-pop)',
        }}>
          {/* Stalking panther head — geometric, brass-toned eye */}
          <g fill={ink}>
            {/* head */}
            <path d="M10 60 C10 30, 22 16, 32 16 C42 16, 54 30, 54 56 L52 64 L42 64 L40 60 L24 60 L22 64 L12 64 Z" />
            {/* ears */}
            <path d="M14 24 L10 12 L20 20 Z" />
            <path d="M50 24 L54 12 L44 20 Z" />
          </g>
          {/* eye */}
          <ellipse cx="36" cy="40" rx="4" ry="2.6" fill={gold} />
          <circle cx="37" cy="40" r="1" fill={ink} />
        </svg>
      </span>
      <span style={{
        fontStyle: italic ? 'italic' : 'normal',
        fontVariationSettings: '"opsz" 144, "SOFT" 60',
        transition: 'color .3s',
        color: hover ? gold : ink,
      }}>awnther</span>

      {showSecret && (
        <span style={{
          position: 'absolute', top: '110%', left: 0,
          fontFamily: 'Patrick Hand, cursive',
          fontSize: 16, fontStyle: 'normal',
          color: gold,
          padding: '6px 10px',
          background: dark ? 'rgba(34,29,24,.95)' : 'rgba(255,253,248,.95)',
          border: `1px solid ${dark ? 'rgba(241,223,177,.4)' : '#bcae96'}`,
          borderRadius: 14,
          whiteSpace: 'nowrap',
          boxShadow: '0 8px 20px rgba(48,37,22,.18)',
          letterSpacing: 0,
          animation: 'pwSecretIn .35s var(--ease-pop)',
        }}>♞ You found the cub. +1 Amigo</span>
      )}
    </span>
  );
}

// ──────────────────────────────────────────────────────────────────────
// 2. MINI BOARD — 8x8 with optional pieces map. Squares can highlight.
//    fenPieces: { e4: 'wQ', e6: 'bN', ... }
//    highlights: { e4: 'gold', e6: 'rose' }
//    onSquare: (sq) => void  (for tap-the-square interactions)
// ──────────────────────────────────────────────────────────────────────
function MiniBoard({
  pieces = {}, highlights = {}, ring = [], dots = [], arrows = [],
  size = '100%', flipped = false, coords = true, onSquare,
  squareSizeKey = 'auto',
}){
  const files = flipped ? ['h','g','f','e','d','c','b','a'] : ['a','b','c','d','e','f','g','h'];
  const ranks = flipped ? [1,2,3,4,5,6,7,8] : [8,7,6,5,4,3,2,1];
  return (
    <div style={{
      position: 'relative',
      width: size, aspectRatio: '1/1',
      padding: 12,
      borderRadius: 18,
      background: 'linear-gradient(180deg, var(--board-frame), #e7d6b3)',
      border: '1px solid var(--line-strong)',
      boxShadow: '0 18px 40px -18px rgba(48,37,22,.32), inset 0 1px 0 rgba(255,255,255,.5)',
    }}>
      <div style={{
        position: 'relative',
        width: '100%', height: '100%',
        display: 'grid',
        gridTemplateColumns: 'repeat(8,1fr)',
        gridTemplateRows: 'repeat(8,1fr)',
        borderRadius: 8, overflow: 'hidden',
        border: '1px solid rgba(25,23,20,.18)',
        boxShadow: '0 6px 16px rgba(48,37,22,.18)',
      }}>
        {ranks.map((r, ri) => files.map((f, fi) => {
          const dark = (ri + fi) % 2 === 1;
          const sq = `${f}${r}`;
          const piece = pieces[sq];
          const hi = highlights[sq];
          const isRing = ring.includes(sq);
          const isDot  = dots.includes(sq);
          return (
            <div key={sq}
              onClick={() => onSquare && onSquare(sq)}
              style={{
                position: 'relative',
                background: dark ? 'var(--board-dark)' : 'var(--board-light)',
                display: 'grid', placeItems: 'center',
                cursor: onSquare ? 'pointer' : 'default',
              }}>
              {hi && (
                <span style={{
                  position: 'absolute', inset: 0,
                  background: hi === 'gold'  ? 'rgba(227,155,68,.42)'
                          :  hi === 'rose'  ? 'rgba(183,122,134,.45)'
                          :  hi === 'olive' ? 'rgba(141,152,112,.45)'
                          :  hi === 'blue'  ? 'rgba(110,138,160,.45)'
                          :  hi,
                }} />
              )}
              {isRing && (
                <span style={{
                  position: 'absolute', inset: 4,
                  border: '3px solid var(--gold)', borderRadius: '50%',
                  boxShadow: '0 0 0 1px rgba(0,0,0,.18)',
                  animation: 'pwPulse 1.8s var(--ease-soft) infinite',
                }} />
              )}
              {isDot && (
                <span style={{
                  position: 'absolute', width: '22%', height: '22%',
                  borderRadius: '50%', background: 'rgba(141,152,112,.55)',
                }} />
              )}
              {piece && (
                <img src={`pieces/${piece}.png`} alt=""
                  style={{
                    position: 'relative', width: '82%', height: '82%',
                    filter: 'drop-shadow(0 2px 3px rgba(48,37,22,.35))',
                    pointerEvents: 'none',
                  }} />
              )}
              {coords && fi === 0 && (
                <span style={{
                  position: 'absolute', left: 3, top: 2,
                  fontFamily: 'JetBrains Mono, monospace',
                  fontSize: 9, fontWeight: 800,
                  color: dark ? 'rgba(255,250,242,.6)' : 'rgba(25,23,20,.45)',
                }}>{r}</span>
              )}
              {coords && ri === 7 && (
                <span style={{
                  position: 'absolute', right: 4, bottom: 2,
                  fontFamily: 'JetBrains Mono, monospace',
                  fontSize: 9, fontWeight: 800,
                  color: dark ? 'rgba(255,250,242,.6)' : 'rgba(25,23,20,.45)',
                }}>{f}</span>
              )}
            </div>
          );
        }))}
        {/* Arrow overlay */}
        {arrows.length > 0 && (
          <svg viewBox="0 0 8 8" preserveAspectRatio="none" style={{
            position: 'absolute', inset: 0, width: '100%', height: '100%',
            pointerEvents: 'none',
          }}>
            <defs>
              <marker id="ar" viewBox="0 0 10 10" refX="6" refY="5"
                markerWidth="3.5" markerHeight="3.5" orient="auto">
                <path d="M0,0 L10,5 L0,10 Z" fill="var(--gold)" />
              </marker>
            </defs>
            {arrows.map((a, i) => {
              const [fx, fy] = sqToXY(a.from, flipped);
              const [tx, ty] = sqToXY(a.to,   flipped);
              return <line key={i} x1={fx} y1={fy} x2={tx} y2={ty}
                stroke="var(--gold)" strokeWidth=".14"
                strokeOpacity=".85" strokeLinecap="round"
                markerEnd="url(#ar)" />;
            })}
          </svg>
        )}
      </div>
    </div>
  );
}
function sqToXY(sq, flipped){
  const fl = sq[0].charCodeAt(0) - 97;  // 0..7
  const rk = parseInt(sq[1], 10) - 1;   // 0..7
  const x = (flipped ? 7 - fl : fl) + 0.5;
  const y = (flipped ? rk : 7 - rk) + 0.5;
  return [x, y];
}

// ──────────────────────────────────────────────────────────────────────
// 3. MASCOT PEEK — pokes briefly from an edge then ducks back.
//    side: 'bl' | 'br' | 'tl' | 'tr'
// ──────────────────────────────────────────────────────────────────────
function MascotPeek({ mascot = 'amigo', side = 'br', delay = 1400, size = 130, repeatEvery = 0, message }){
  const [out, setOut] = useState(false);
  useEffect(() => {
    const t1 = setTimeout(() => setOut(true), delay);
    const t2 = setTimeout(() => setOut(false), delay + 2200);
    let intv;
    if (repeatEvery > 0){
      intv = setInterval(() => {
        setOut(true);
        setTimeout(() => setOut(false), 2200);
      }, repeatEvery);
    }
    return () => { clearTimeout(t1); clearTimeout(t2); intv && clearInterval(intv); };
  }, [delay, repeatEvery]);

  const isBottom = side[0] === 'b';
  const isRight  = side[1] === 'r';
  const offset = -size * 0.78;
  const peekedY = -size * 0.55;
  const tilt = mascot === 'maia' ? (isRight ?  8 : -8) : (isRight ?  -10 : 10);

  return (
    <div style={{
      position: 'absolute',
      [isBottom ? 'bottom' : 'top']: offset,
      [isRight  ? 'right'  : 'left']: -size * 0.12,
      width: size, height: size * 1.15,
      pointerEvents: 'none',
      zIndex: 5,
      transition: 'transform 1.1s var(--ease-pop)',
      transform: out
        ? `translateY(${isBottom ? peekedY : -peekedY}px) rotate(${tilt}deg)`
        : `translateY(0) rotate(${tilt * 0.5}deg)`,
    }}>
      <img src={`assets/${mascot}.png`} alt=""
        style={{
          width: '100%', height: '100%', objectFit: 'contain',
          filter: 'drop-shadow(0 14px 22px rgba(38,33,28,.25))',
          transform: isBottom ? 'none' : 'scaleY(-1)',
        }} />
      {message && out && (
        <span style={{
          position: 'absolute',
          [isBottom ? 'bottom' : 'top']: '70%',
          [isRight ? 'right' : 'left']: '80%',
          padding: '6px 12px',
          background: 'var(--paper-cream)',
          border: '1.5px solid var(--line-strong)',
          borderRadius: 14,
          fontFamily: 'Patrick Hand, cursive',
          fontSize: 15,
          color: mascot === 'maia' ? 'var(--rose)' : 'var(--gold)',
          whiteSpace: 'nowrap',
          boxShadow: '0 6px 14px rgba(48,37,22,.16)',
          animation: 'pwBubbleIn .35s var(--ease-soft) .3s both',
        }}>{message}</span>
      )}
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────────
// 4. LOGOUT-BLOCKED BUTTON — mascots slide in to block the user
// ──────────────────────────────────────────────────────────────────────
function LogoutBlockedDemo({ dark = false }){
  const [hovered, setHovered] = useState(false);
  const [stage, setStage] = useState(0); // 0 idle, 1 amigo, 2 maia
  useEffect(() => {
    if (!hovered){ setStage(0); return; }
    const t1 = setTimeout(() => setStage(1), 180);
    const t2 = setTimeout(() => setStage(2), 600);
    return () => { clearTimeout(t1); clearTimeout(t2); };
  }, [hovered]);

  return (
    <div style={{
      position: 'relative',
      padding: '18px 20px',
      borderRadius: 18,
      background: dark ? 'rgba(255,255,255,.04)' : 'rgba(255,253,248,.7)',
      border: '1px solid var(--line)',
    }}>
      <div style={{
        display: 'flex', justifyContent:'space-between', alignItems:'center',
        marginBottom: 12, gap: 12,
      }}>
        <div>
          <div className="eyebrow">Account · Easter egg</div>
          <div style={{ fontFamily:'Fraunces, serif', fontSize:18, fontWeight:600, marginTop:4 }}>
            Try to log out
          </div>
        </div>
      </div>
      <div
        onMouseEnter={() => setHovered(true)}
        onMouseLeave={() => setHovered(false)}
        style={{
          position: 'relative',
          height: 60,
          borderRadius: 14,
          background: dark ? 'rgba(255,255,255,.05)' : 'rgba(255,253,248,.5)',
          border: '1px dashed var(--line-strong)',
          overflow: 'hidden',
          display:'grid', placeItems:'center',
        }}>
        <button style={{
          padding: '10px 16px',
          borderRadius: 999,
          background: dark ? 'rgba(255,255,255,.08)' : 'var(--ink)',
          color: dark ? 'var(--ink-warm)' : 'var(--paper-100)',
          fontWeight: 700, fontSize: 13,
          opacity: stage > 0 ? 0.4 : 1,
          transition: 'opacity .25s',
        }}>Log out</button>

        {/* Amigo slides in from left */}
        <img src="assets/amigo.png" alt="" style={{
          position: 'absolute', left: 0, bottom: -10,
          width: 64, height: 64, objectFit:'contain',
          pointerEvents: 'none',
          filter: 'drop-shadow(0 6px 8px rgba(38,33,28,.25))',
          transform: stage >= 1 ? 'translateX(0) rotate(-6deg)' : 'translateX(-80px) rotate(-30deg)',
          transition: 'transform .5s var(--ease-pop)',
        }} />
        {/* Maia slides in from right */}
        <img src="assets/maia.png" alt="" style={{
          position: 'absolute', right: 0, bottom: -10,
          width: 64, height: 64, objectFit:'contain',
          pointerEvents: 'none',
          filter: 'drop-shadow(0 6px 8px rgba(38,33,28,.25))',
          transform: stage >= 2 ? 'translateX(0) rotate(8deg)' : 'translateX(80px) rotate(30deg)',
          transition: 'transform .5s var(--ease-pop)',
        }} />
        {/* Block message */}
        {stage >= 2 && (
          <span style={{
            position: 'absolute', top: 6, left: '50%',
            transform: 'translateX(-50%)',
            fontFamily: 'Patrick Hand, cursive',
            fontSize: 14,
            color: 'var(--gold)',
            background: 'var(--paper-cream)',
            padding: '3px 10px',
            borderRadius: 999,
            border: '1px solid var(--line-strong)',
            animation: 'pwBubbleIn .35s var(--ease-pop)',
          }}>nope — one more puzzle?</span>
        )}
      </div>
      <p style={{ marginTop:10, fontSize:12.5, color: 'var(--ink-soft)' }}>
        Hover the button — Amigo and Maia jump in front of it for a second before letting you click.
      </p>
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────────
// 5. Reveal observer — adds .pw-in to children with .pw-reveal
// ──────────────────────────────────────────────────────────────────────
function useReveal(rootRef){
  useEffect(() => {
    if (!rootRef.current) return;
    const els = rootRef.current.querySelectorAll('.pw-reveal');
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting){ e.target.classList.add('pw-in'); io.unobserve(e.target); }
      });
    }, { threshold: 0.12, root: rootRef.current });
    els.forEach(el => io.observe(el));
    // fallback: reveal immediately if no IO fires within 1.2s
    const t = setTimeout(() => els.forEach(el => el.classList.add('pw-in')), 1400);
    return () => { io.disconnect(); clearTimeout(t); };
  }, []);
}

// ──────────────────────────────────────────────────────────────────────
// 6. PANTHER EYES (ambient) — two glowing eyes in dark margins, blink
//    occasionally. Used by The Hunt direction.
// ──────────────────────────────────────────────────────────────────────
function PantherEyes({ x = '10%', y = '40%', color = '#e39b44', scale = 1, side='l' }){
  const [blink, setBlink] = useState(false);
  useEffect(() => {
    const loop = () => {
      setBlink(true);
      setTimeout(() => setBlink(false), 180);
    };
    const i = setInterval(loop, 3800 + Math.random() * 2400);
    return () => clearInterval(i);
  }, []);
  return (
    <div style={{
      position: 'absolute', left: x, top: y,
      transform: `scale(${scale})`,
      transformOrigin: 'center',
      pointerEvents: 'none', zIndex: 1,
    }}>
      <div style={{ display:'flex', gap: 28, transform: side==='r'?'scaleX(-1)':'none' }}>
        <Eye color={color} blink={blink} />
        <Eye color={color} blink={blink} tiny />
      </div>
    </div>
  );
}
function Eye({ color, blink, tiny }){
  return (
    <div style={{
      width: tiny ? 16 : 20, height: 9,
      borderRadius: '50%',
      background: color,
      boxShadow: `0 0 16px ${color}, 0 0 4px ${color}`,
      filter: 'blur(.4px)',
      transform: blink ? 'scaleY(.05)' : 'scaleY(1)',
      transformOrigin: 'center',
      transition: 'transform .12s ease-in-out',
      opacity: .9,
    }} />
  );
}

// Shared keyframes — injected once
if (typeof document !== 'undefined' && !document.getElementById('pw-keyframes')){
  const s = document.createElement('style');
  s.id = 'pw-keyframes';
  s.textContent = `
    @keyframes pwPulse { 0%,100%{ transform: scale(1); opacity:.85 } 50%{ transform: scale(1.05); opacity:1 } }
    @keyframes pwBubbleIn { from{ opacity:0; transform: translateY(6px) scale(.94) } to{ opacity:1; transform:none } }
    @keyframes pwSecretIn { from{ opacity:0; transform: translateY(-4px) } to{ opacity:1; transform:none } }
    @keyframes pwBob { 0%,100%{ transform: translateY(0) } 50%{ transform: translateY(-6px) } }
    @keyframes pwDrift { 0%,100%{ transform: translateX(0) } 50%{ transform: translateX(-8px) } }
    @keyframes pwMarquee { from{ transform: translateX(0) } to{ transform: translateX(-50%) } }
    @keyframes pwStalk { 0%{ transform: translateX(-30px); opacity:.0 } 12%{ opacity:.55 } 50%{ transform: translateX(50vw); opacity:.45 } 88%{ opacity:.0 } 100%{ transform: translateX(110%); opacity:0 } }
    @keyframes pwLivePulse {
      0%   { box-shadow: 0 0 0 0 rgba(141,152,112,.6); }
      70%  { box-shadow: 0 0 0 9px rgba(141,152,112,0); }
      100% { box-shadow: 0 0 0 0 rgba(141,152,112,0); }
    }
    @keyframes pwTickerScroll { from{ transform: translateX(0) } to { transform: translateX(-50%) } }
    @keyframes pwEval { 0%{ height: 50% } 50%{ height: 62% } 100%{ height: 50% } }
    @keyframes pwGlowDrift { 0%{ transform: translate(0,0) } 100%{ transform: translate(30px,-12px) } }
    @keyframes pwBlink { 0%,90%,100%{ transform: scaleY(1) } 95%{ transform: scaleY(.05) } }
    @keyframes pwSpin { to { transform: rotate(360deg) } }
  `;
  document.head.appendChild(s);
}

Object.assign(window, {
  PawntherMark, MiniBoard, MascotPeek, LogoutBlockedDemo, useReveal,
  PantherEyes,
});
