// Shared Risograph theme + texture helpers + small UI primitives.
// Loaded as Babel script in both index.html and host.html.

const R = {
  paper: '#f5efe2',
  paper2: '#ebe3d0',
  paper3: '#ddd3bb',
  ink: '#1a1a1a',
  pink: '#ff5a7a',
  blue: '#3b6cff',
  yellow: '#ffd23f',
  green: '#7ad05a',
  purple: '#b870ff',
  orange: '#ff8c3b',
  teal: '#5ad6c8',
  muted: 'rgba(26,26,26,.55)',
  dim: 'rgba(26,26,26,.3)',
  font: '"Helvetica Neue", Helvetica, Arial, sans-serif',
};

const risoTex = (color = 'rgba(26,26,26,.06)', size = 3) =>
  `radial-gradient(${color} 0.6px, transparent 0.7px) 0 0/${size}px ${size}px`;

// Detects "this is a desktop / laptop": wide viewport + fine pointer (mouse).
// Watches matchMedia so the layout reacts if you resize or plug in a touch
// device. Returns false on iPad-without-mouse (touch-only is still a phone-
// shaped experience), true on real laptops.
function useIsWideDesktop() {
  const [wide, setWide] = React.useState(() => {
    if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return false;
    try {
      return window.matchMedia('(min-width: 1000px) and (pointer: fine)').matches;
    } catch { return false; }
  });
  React.useEffect(() => {
    if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return;
    const mq = window.matchMedia('(min-width: 1000px) and (pointer: fine)');
    const handler = (e) => setWide(e.matches);
    if (mq.addEventListener) mq.addEventListener('change', handler);
    else mq.addListener(handler);
    return () => {
      if (mq.removeEventListener) mq.removeEventListener('change', handler);
      else mq.removeListener(handler);
    };
  }, []);
  return wide;
}

// Tiny QR-ish riso pattern + "Better on phone" nudge card for desktop wings.
// Decorative — points at the same URL the user is already on; pure mood.
function DesktopPhoneNudge() {
  const N = 13;
  const cells = [];
  for (let i = 0; i < N; i++) for (let j = 0; j < N; j++) cells.push({ i, j, on: ((i*7+j*13)^((i*3)|(j*5))) % 5 < 2 });
  const cell = 120 / N;
  const isFinder = (i, j) => (i < 4 && j < 4) || (i < 4 && j >= N - 4) || (i >= N - 4 && j < 4);
  return (
    <div style={{
      padding: 22, background: R.paper, color: R.ink,
      border: `2px solid ${R.ink}`, boxShadow: `5px 5px 0 ${R.ink}`,
      width: 240, fontFamily: R.font,
    }}>
      <div style={{ fontSize: 10, fontWeight: 900, letterSpacing: '.22em', color: R.muted }}>BETTER ON PHONE</div>
      <div style={{ fontSize: 20, fontWeight: 900, letterSpacing: '-.02em', lineHeight: 1.05, marginTop: 6 }}>
        Scan to play here.
      </div>
      <div style={{ display: 'flex', gap: 12, marginTop: 14, alignItems: 'center' }}>
        <div style={{
          width: 110, height: 110, padding: 4, background: R.paper,
          border: `2px solid ${R.ink}`, flexShrink: 0,
        }}>
          <svg width="100" height="100" viewBox="0 0 120 120" style={{ display: 'block' }}>
            {cells.filter((c) => c.on && !isFinder(c.i, c.j)).map((c, idx) => (
              <rect key={idx} x={c.j * cell} y={c.i * cell} width={cell} height={cell} fill={R.ink} />
            ))}
            {[[0, 0], [0, N - 4], [N - 4, 0]].map(([i, j], idx) => (
              <g key={idx} transform={`translate(${j * cell} ${i * cell})`}>
                <rect width={cell * 4} height={cell * 4} fill={R.ink} />
                <rect x={cell * 0.7} y={cell * 0.7} width={cell * 2.6} height={cell * 2.6} fill={R.paper} />
                <rect x={cell * 1.4} y={cell * 1.4} width={cell * 1.2} height={cell * 1.2} fill={R.ink} />
              </g>
            ))}
          </svg>
        </div>
        <div style={{ fontSize: 10, fontWeight: 700, color: R.muted, lineHeight: 1.4 }}>
          You're on a laptop. Works here, but a phone fits better in your hand.
        </div>
      </div>
      <div style={{
        marginTop: 12, padding: '6px 10px',
        background: R.paper2, border: `2px dashed ${R.ink}`,
        fontSize: 10, fontWeight: 800, letterSpacing: '.06em', textAlign: 'center',
      }}>…or keep playing here →</div>
    </div>
  );
}

// Right-side explainer card. Mirrors the design's "What you're seeing" panel
// from Hitster Responsive.html.
function DesktopExplainer() {
  return (
    <div style={{ width: 240, color: R.ink, fontFamily: R.font }}>
      <div style={{ fontSize: 10, fontWeight: 900, letterSpacing: '.22em', color: R.muted }}>WHAT YOU'RE SEEING</div>
      <div style={{ fontSize: 20, fontWeight: 900, letterSpacing: '-.02em', lineHeight: 1.05, marginTop: 6 }}>
        Same UI, just centered on a wider screen.
      </div>
      <ul style={{ marginTop: 14, padding: 0, listStyle: 'none', display: 'flex', flexDirection: 'column', gap: 10 }}>
        {[
          ['🪟', 'No layout shift', 'Same code, same width. Letterboxed in paper.'],
          ['🎧', 'Music works anywhere', 'Solo plays in this tab. Multiplayer uses host laptop.'],
          ['🖱', 'Drum still spins', 'Pointer events work the same as touch.'],
        ].map(([icon, head, sub]) => (
          <li key={head} style={{
            padding: '8px 10px', background: R.paper2, border: `2px solid ${R.ink}`,
            boxShadow: `2px 2px 0 ${R.ink}`,
            display: 'flex', gap: 10, alignItems: 'flex-start',
          }}>
            <div style={{ fontSize: 16, lineHeight: 1, width: 22, textAlign: 'center', marginTop: 2 }}>{icon}</div>
            <div>
              <div style={{ fontSize: 12, fontWeight: 900, letterSpacing: '-.01em' }}>{head}</div>
              <div style={{ fontSize: 10, fontWeight: 700, color: R.muted, marginTop: 2, lineHeight: 1.35 }}>{sub}</div>
            </div>
          </li>
        ))}
      </ul>
    </div>
  );
}

// Wraps the whole app — fills the viewport with the riso paper background
// and centers a 420px-max content column. On desktop (≥1000px + fine pointer)
// AND when not on the host route, wraps the phone-shaped column in a paper
// shell with two side panels (a riso-QR nudge + 3-bullet explainer). On
// phones and on the host route, the column fills the screen unchanged.
function Stage({ children }) {
  const wide = useIsWideDesktop();
  // Host route gets its own desktop layout (see app-host.jsx). Don't apply
  // the player/solo phone-in-paper shell there — host on desktop is a full
  // TV view, not a phone embed.
  const isHost = typeof window !== 'undefined' && /\/host(\.|\/|$)/.test(window.location.pathname);
  const desktopShell = wide && !isHost;
  const phoneColumn = (
    <div style={{
      width: '100%', maxWidth: 460, margin: '0 auto',
      flex: 1, display: 'flex', flexDirection: 'column',
      position: 'relative', overflow: 'hidden',
    }}>
      {children}
    </div>
  );
  if (!desktopShell) {
    return (
      <div style={{
        minHeight: '100dvh', width: '100%', background: R.paper, color: R.ink,
        fontFamily: R.font, WebkitFontSmoothing: 'antialiased',
        backgroundImage: risoTex('rgba(26,26,26,.06)', 3),
        backgroundAttachment: 'fixed',
        display: 'flex', flexDirection: 'column',
        paddingTop: 'env(safe-area-inset-top, 16px)',
        paddingBottom: 'env(safe-area-inset-bottom, 16px)',
        paddingLeft: 'env(safe-area-inset-left, 0)',
        paddingRight: 'env(safe-area-inset-right, 0)',
      }}>{phoneColumn}</div>
    );
  }
  // Desktop shell: paper bg w/ rotating stamps + center phone-shaped column
  // + side panels. Phone column gets a card frame (border + shadow) so it
  // reads as "embedded device", not "narrow website".
  return (
    <div style={{
      minHeight: '100dvh', width: '100%', background: R.paper, color: R.ink,
      fontFamily: R.font, WebkitFontSmoothing: 'antialiased',
      backgroundImage: risoTex('rgba(26,26,26,.06)', 3),
      backgroundAttachment: 'fixed',
      position: 'relative', overflow: 'hidden',
    }}>
      <RisoStamp size={500} color={R.pink} top={-160} left={-220} duration={32} />
      <RisoStamp size={400} color={R.blue} top={120} left={'72vw'} duration={28} delay={1.2} />
      <RisoStamp size={300} color={R.yellow} top={460} left={-140} duration={36} delay={2.4} />
      <RisoStamp size={280} color={R.green} top={520} left={'78vw'} duration={30} delay={1.8} />
      <div style={{
        position: 'relative', zIndex: 2,
        minHeight: '100dvh',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        gap: 48, padding: '40px 24px',
      }}>
        <div style={{ display: 'none' }} className="hf-side hf-side-left">
          <DesktopPhoneNudge />
        </div>
        <div style={{
          width: 420, height: 820, maxHeight: 'calc(100dvh - 80px)',
          background: R.paper,
          border: `2px solid ${R.ink}`, boxShadow: `8px 8px 0 ${R.ink}`,
          display: 'flex', flexDirection: 'column',
          position: 'relative', overflow: 'hidden', flexShrink: 0,
        }}>{phoneColumn}</div>
        <div style={{ display: 'none' }} className="hf-side hf-side-right">
          <DesktopExplainer />
        </div>
      </div>
      <style>{`
        /* Show side panels only when there's room — phone embed always wins
           the center, side wings degrade gracefully on narrower laptops. */
        @media (min-width: 1180px) { .hf-side-left, .hf-side-right { display: block !important; } }
        @media (min-width: 1000px) and (max-width: 1179px) { .hf-side-right { display: block !important; } }
      `}</style>
    </div>
  );
}

// One screen — flex column inside the Stage with riso paper background overlay
function Screen({ children, bg }) {
  return (
    <div style={{
      flex: 1, display: 'flex', flexDirection: 'column',
      paddingTop: 16, paddingBottom: 18,
      position: 'relative', overflow: 'hidden',
      background: bg || 'transparent',
    }}>
      {children}
    </div>
  );
}

function Tag({ color, children }) {
  return (
    <span style={{
      display: 'inline-block', padding: '4px 10px',
      background: color, color: R.paper,
      fontSize: 10, fontWeight: 800, letterSpacing: '.18em', textTransform: 'uppercase',
      boxShadow: `2px 2px 0 ${R.ink}`,
    }}>{children}</span>
  );
}

function Btn({ children, onClick, bg = R.pink, fg = R.ink, big = true, disabled = false, style = {} }) {
  return (
    <button
      onClick={disabled ? undefined : onClick}
      disabled={disabled}
      style={{
        width: '100%', height: big ? 56 : 44,
        border: `2px solid ${R.ink}`,
        background: disabled ? R.paper3 : bg, color: disabled ? R.muted : fg,
        fontSize: big ? 16 : 14, fontWeight: 800, letterSpacing: '.02em',
        cursor: disabled ? 'not-allowed' : 'pointer',
        boxShadow: disabled ? 'none' : `4px 4px 0 ${R.ink}`,
        fontFamily: 'inherit', textTransform: 'uppercase',
        transform: 'translate(0,0)',
        transition: 'transform .08s, box-shadow .08s',
        ...style,
      }}
      onPointerDown={(e) => {
        if (disabled) return;
        e.currentTarget.style.transform = 'translate(2px,2px)';
        e.currentTarget.style.boxShadow = `2px 2px 0 ${R.ink}`;
      }}
      onPointerUp={(e) => {
        if (disabled) return;
        e.currentTarget.style.transform = 'translate(0,0)';
        e.currentTarget.style.boxShadow = `4px 4px 0 ${R.ink}`;
      }}
      onPointerLeave={(e) => {
        if (disabled) return;
        e.currentTarget.style.transform = 'translate(0,0)';
        e.currentTarget.style.boxShadow = `4px 4px 0 ${R.ink}`;
      }}
    >{children}</button>
  );
}

// 2-color overprint big text
function Overprint({ children, sizes = 92, color1 = R.pink, color2 = R.blue, offset = 4 }) {
  return (
    <div style={{
      position: 'relative', lineHeight: .85, letterSpacing: '-.04em',
      fontWeight: 900, fontSize: sizes,
    }}>
      <div style={{
        position: 'absolute', left: -offset, top: offset, color: color1,
        mixBlendMode: 'multiply', opacity: .9,
      }}>{children}</div>
      <div style={{ color: color2, mixBlendMode: 'multiply', opacity: .9 }}>{children}</div>
    </div>
  );
}

// Slow-rotating riso "stamp"
function RisoStamp({ size = 220, color = R.pink, top = 40, left = -60, delay = 0, duration = 22 }) {
  return (
    <div style={{
      position: 'absolute', top, left, width: size, height: size,
      borderRadius: '50%', background: color, mixBlendMode: 'multiply',
      opacity: .55,
      animation: `rstamp ${duration}s ${delay}s linear infinite`,
      backgroundImage: risoTex('rgba(0,0,0,.18)', 4),
      pointerEvents: 'none',
    }} />
  );
}

function RisoBars() {
  return (
    <div style={{ display: 'flex', alignItems: 'flex-end', gap: 3, height: 28 }}>
      {[12, 22, 16, 26, 14].map((h, i) => (
        <div key={i} style={{
          width: 4, height: h, background: R.blue,
          animation: `rbE ${0.5 + (i % 3) * 0.2}s ${i * 0.06}s ease-in-out infinite alternate`,
        }} />
      ))}
    </div>
  );
}

function RisoConfetti({ count = 50 }) {
  const colors = [R.pink, R.blue, R.yellow, R.ink];
  const pieces = React.useMemo(() => Array.from({ length: count }).map((_, i) => ({
    left: Math.random() * 100,
    delay: Math.random() * 0.5,
    dur: 2 + Math.random() * 1.5,
    color: colors[i % colors.length],
    rot: Math.random() * 360,
    size: 8 + Math.random() * 6,
    drift: (Math.random() - 0.5) * 100,
    shape: Math.random() > 0.5 ? '50%' : '0',
  })), [count]);
  return (
    <div style={{ position: 'absolute', inset: 0, overflow: 'hidden', pointerEvents: 'none', zIndex: 30 }}>
      {pieces.map((p, i) => (
        <div key={i} style={{
          position: 'absolute', left: `${p.left}%`, top: -20,
          width: p.size, height: p.size * 0.4, background: p.color, borderRadius: p.shape,
          mixBlendMode: 'multiply',
          transform: `rotate(${p.rot}deg)`,
          animation: `rconf ${p.dur}s ${p.delay}s linear forwards`,
          ['--drift']: `${p.drift}px`,
        }} />
      ))}
    </div>
  );
}

// Inject keyframes once globally
function GlobalRisoStyles() {
  return (
    <style>{`
      @keyframes rstamp {
        0% { transform: rotate(0deg) translateY(0); }
        50% { transform: rotate(180deg) translateY(8px); }
        100% { transform: rotate(360deg) translateY(0); }
      }
      @keyframes rbE { 0% { transform: scaleY(.4) } 100% { transform: scaleY(1) } }
      @keyframes rconf {
        0% { transform: translate(0, 0) rotate(0deg); opacity: 1; }
        100% { transform: translate(var(--drift), 110vh) rotate(720deg); opacity: 0.5; }
      }
      @keyframes rshake { 0%,100% { transform: translateX(0) } 25% { transform: translateX(-4px) } 75% { transform: translateX(4px) } }
      @keyframes rpop { 0% { transform: scale(.92) } 60% { transform: scale(1.06) } 100% { transform: scale(1) } }
      @keyframes rpopin { 0% { transform: translateX(-12px); opacity: 0 } 100% { transform: translateX(0); opacity: 1 } }
      @keyframes rpopin-r { 0% { opacity: 0; transform: translateX(-12px) } 100% { opacity: 1; transform: translateX(0) } }
      @keyframes rfade { 0% { opacity: 0 } 100% { opacity: 1 } }
      @keyframes rdrop {
        0% { transform: translateY(-40px) scale(.9); opacity: 0 }
        60% { transform: translateY(8px) scale(1.04); opacity: 1 }
        100% { transform: translateY(0) scale(1); opacity: 1 }
      }
      @keyframes rstamp-in {
        0% { transform: scale(2.4) rotate(-12deg); opacity: 0 }
        70% { transform: scale(.96) rotate(2deg); opacity: 1 }
        100% { transform: scale(1) rotate(0); opacity: 1 }
      }
      @keyframes rspin { 100% { transform: rotate(360deg) } }
      @keyframes rpulse { 0%,100% { transform: scale(1) } 50% { transform: scale(1.12) } }
      @keyframes rgrow { 0% { width: 0 } 100% { width: var(--w) } }
      html, body, #root { height: 100%; margin: 0; padding: 0; background: #f5efe2; }
      body { -webkit-tap-highlight-color: transparent; overscroll-behavior: none; }
      input, button, textarea { font-family: inherit; }
      * { box-sizing: border-box; }
    `}</style>
  );
}

window.R = R;
window.risoTex = risoTex;
window.Stage = Stage;
window.Screen = Screen;
window.Tag = Tag;
window.Btn = Btn;
window.Overprint = Overprint;
window.RisoStamp = RisoStamp;
window.RisoBars = RisoBars;
window.RisoConfetti = RisoConfetti;
window.GlobalRisoStyles = GlobalRisoStyles;
