/* global window, React */
// Swipe stack + cards + favorite picker

const { useState, useEffect, useRef, useCallback, useMemo } = React;
const { OrnamentBall, CollectionBackdrop, Ticker, FloatingSticker } = window.KechHero;

// ---------- Ghost stack — visualises remaining cards behind ----------
function GhostStack({ remaining, collection, cardStyle, visibleLive }) {
  // remaining = total cards left including the live ones on top.
  // We render up to 6 ghost layers behind the live cards, scaled by how many remain.
  const behind = Math.max(0, remaining - visibleLive);
  // Skip ghost layers for small collections — the visible stack already conveys depth,
  // and empty dummy cards look like phantom entries.
  if (behind < 3) return null;
  const layers = Math.min(6, behind);
  if (layers <= 0) return null;
  // Ghost color: white-ish so it always pops against any collection bg.
  const ghostBg = collection.bg === '#191414' ? '#3a3232' : 'var(--kech-white)';
  const radius = cardStyle === 'polaroid' ? 8 : cardStyle === 'trading' ? 14 : 24;
  return (
    <>
      {Array.from({ length: layers }).map((_, k) => {
        // k=0 is the layer closest to the live cards; k=layers-1 is deepest.
        const depth = k + visibleLive; // overall stack depth
        const offsetY = depth * 14;
        const offsetX = (depth % 2 ? -1 : 1) * (6 + depth * 3);
        const scale = 1 - depth * 0.035;
        const rot = depth % 2 ? -4 : 4;
        const op = Math.max(0.55, 1 - k * 0.06);
        const isDeepest = k === layers - 1;
        return (
          <div
            key={k}
            aria-hidden="true"
            style={{
              position: 'absolute', inset: 0,
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              zIndex: 1 + (10 - k),
              pointerEvents: 'none',
              transform: `translate(${offsetX}px, ${offsetY}px) scale(${scale}) rotate(${rot}deg)`,
              opacity: op
            }}>
            
            <div style={{
              width: 320, height: 440,
              background: ghostBg,
              border: '4px solid var(--kech-black)',
              borderRadius: radius,
              boxShadow: '6px 6px 0 var(--kech-black)',
              position: 'relative',
              display: 'grid', placeItems: 'center'
            }}>
              {/* count badge on the deepest visible layer */}
              {isDeepest && behind > 0 &&
              <div style={{
                fontFamily: 'Kechfont, system-ui',
                fontWeight: 800,
                fontSize: 64,
                lineHeight: 0.9,
                color: collection.bg === '#191414' ? 'rgba(255,255,255,0.35)' : 'rgba(25,20,20,0.32)',
                letterSpacing: '-0.02em',
                textAlign: 'center'
              }}>
                  +{behind}<br />
                  <span style={{ fontSize: 18, letterSpacing: '0.18em', textTransform: 'uppercase' }}>nog te gaan</span>
                </div>
              }
            </div>
          </div>);

      })}
    </>);

}

// ---------- Fire burst — short celebratory blast over the card -----
function FireBurst({ trigger }) {
  const [bursts, setBursts] = useState([]);
  useEffect(() => {
    if (!trigger) return;
    const id = trigger;
    // ~28 small flames in two concentric rings + sparks, tightly clustered on the card
    const items = [];
    const ring = (count, baseDist, sizeRange, jitter) => {
      for (let i = 0; i < count; i++) {
        const angle = i / count * Math.PI * 2 + (Math.random() * jitter - jitter / 2);
        const dist = baseDist + (Math.random() * 30 - 15);
        items.push({
          i: items.length,
          dx: Math.cos(angle) * dist,
          dy: Math.sin(angle) * dist - 8,
          delay: Math.random() * 120,
          rot: (Math.random() * 80 - 40).toFixed(1),
          size: sizeRange[0] + Math.round(Math.random() * (sizeRange[1] - sizeRange[0])),
          kind: '🔥'
        });
      }
    };
    ring(14, 70, [16, 24], 0.35); // inner ring of mini flames
    ring(10, 130, [14, 20], 0.5); // outer ring even smaller
    // sparkles on top
    for (let s = 0; s < 6; s++) {
      const angle = Math.random() * Math.PI * 2;
      const dist = 50 + Math.random() * 90;
      items.push({
        i: items.length,
        dx: Math.cos(angle) * dist,
        dy: Math.sin(angle) * dist - 10,
        delay: 80 + Math.random() * 200,
        rot: (Math.random() * 90 - 45).toFixed(1),
        size: 14 + Math.round(Math.random() * 8),
        kind: '✨'
      });
    }

    setBursts([{ id, items }]);
    const t = setTimeout(() => {
      setBursts((prev) => prev.filter((b) => b.id !== id));
    }, 1800);
    return () => clearTimeout(t);
  }, [trigger]);

  if (bursts.length === 0) return null;
  return (
    <div
      aria-hidden="true"
      style={{
        position: 'absolute',
        inset: 0,
        pointerEvents: 'none',
        zIndex: 60,
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center'
      }}>
      
      {bursts.map((b) =>
      <div
        key={b.id}
        style={{
          position: 'relative',
          width: 340, height: 460
        }}>
        
          {/* warm flash */}
          {/* warm flash removed — drag-stamp & burst emojis carry the moment */}
          {/* FIRE stamp removed — drag-stamp already shows it */}
          {/* burst emojis */}
          {b.items.map((it) =>
        <div
          key={it.i}
          style={{
            position: 'absolute',
            left: '50%',
            top: '50%',
            fontSize: it.size,
            ['--dx']: `${it.dx}px`,
            ['--dy']: `${it.dy}px`,
            ['--r']: `${it.rot}deg`,
            animation: `kech-fire-burst 1500ms cubic-bezier(0.22, 1, 0.36, 1) ${it.delay}ms forwards`,
            filter: 'drop-shadow(0 2px 4px rgba(255,90,30,0.6))',
            transform: 'translate(-50%,-50%) scale(0.4)',
            opacity: 0
          }}>
          
              {it.kind}
            </div>
        )}
        </div>
      )}
    </div>);

}

// ---------- Stamp overlays --------------------------------------------
function Stamp({ kind, opacity }) {
  const map = {
    right: { text: 'jaaa', color: 'var(--kech-aqua)', rot: -10, side: 'left' },
    left: { text: 'nee', color: 'var(--kech-fuchsia)', rot: 8, side: 'right' },
    up: { text: '🔥 fire', color: 'var(--kech-fuchsia)', rot: -4, side: 'top' }
  };
  const cfg = map[kind];
  if (!cfg) return null;
  const positionStyle = {
    left: { top: 24, left: 22 },
    right: { top: 24, right: 22 },
    top: { top: 14, left: '50%', transform: `translateX(-50%) rotate(${cfg.rot}deg)` }
  }[cfg.side];
  return (
    <div style={{
      position: 'absolute', zIndex: 10,
      ...positionStyle,
      opacity,
      pointerEvents: 'none',
      transform: cfg.side === 'top' ? positionStyle.transform : `rotate(${cfg.rot}deg)`
    }}>
      <div style={{
        background: cfg.color,
        color: 'var(--kech-black)',
        border: '4px solid var(--kech-black)',
        padding: '8px 18px 12px',
        fontFamily: 'Kechfont, system-ui',
        fontWeight: 800,
        fontSize: 44,
        textTransform: 'lowercase',
        lineHeight: 1,
        letterSpacing: '-0.02em',
        borderRadius: 10,
        boxShadow: '5px 5px 0 var(--kech-black)'
      }}>{cfg.text}</div>
    </div>);

}

// ---------- The card itself (3 visual styles) -------------------------
function CardArt({ design, collection, style, compact = false }) {
  // style: 'sticker' | 'polaroid' | 'trading'
  // compact: smaller text + tighter padding for grid tiles
  const captionSize = compact ? 14 : 22;
  if (style === 'polaroid') {
    return (
      <div style={{
        background: 'var(--kech-white)',
        border: '3px solid var(--kech-black)',
        borderRadius: 8,
        padding: 14,
        paddingBottom: 56,
        position: 'relative',
        boxShadow: '6px 6px 0 var(--kech-black)'
      }}>
        <div style={{
          aspectRatio: '1 / 1',
          background: collection.bg === '#191414' ? '#2A2424' : collection.bgAlt,
          borderRadius: 4,
          border: '2px solid var(--kech-black)',
          display: 'grid', placeItems: 'center',
          overflow: 'hidden',
          position: 'relative'
        }}>
          <OrnamentBall design={design} collection={collection} size={260} />
          <div style={{
            position: 'absolute', top: 8, left: 8,
            fontFamily: 'var(--font-mono)', fontSize: 10, fontWeight: 700,
            letterSpacing: '0.18em', color: 'var(--kech-black)',
            background: 'var(--kech-aqua)', border: '2px solid var(--kech-black)',
            borderRadius: 999, padding: '3px 8px'
          }}>
            {collection.id} · {String(design.no).padStart(2, '0')}
          </div>
        </div>
        <div style={{
          position: 'absolute', bottom: 16, left: 14, right: 14,
          textAlign: 'center',
          fontFamily: 'var(--font-body)', fontWeight: 700, fontSize: compact ? 13 : 'clamp(13px, 4cqw, 18px)',
          color: 'var(--kech-black)', textTransform: 'none',
          lineHeight: 1.15, transform: 'rotate(-1deg)',
          wordBreak: 'break-word', overflowWrap: 'break-word', hyphens: 'auto'
        }}>{design.caption}</div>
      </div>);

  }

  if (style === 'trading') {
    return (
      <div style={{
        background: 'var(--kech-black)',
        border: '4px solid var(--kech-fuchsia)',
        borderRadius: 14,
        padding: 12,
        position: 'relative',
        boxShadow: '6px 6px 0 var(--kech-aqua), 6px 6px 0 4px var(--kech-black)',
        color: 'var(--kech-white)'
      }}>
        {/* Top bar */}
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 10 }}>
          <div style={{
            fontFamily: 'Kechfont, system-ui', fontWeight: 800, fontSize: 22,
            textTransform: 'lowercase', color: 'var(--kech-fuchsia)', lineHeight: 1
          }}>{collection.name}</div>
          <div style={{
            fontFamily: 'var(--font-mono)', fontSize: 12, fontWeight: 700,
            letterSpacing: '0.18em', color: 'var(--kech-aqua)'
          }}>#{String(design.no).padStart(2, '0')}/10</div>
        </div>
        {/* Art */}
        <div style={{
          aspectRatio: '1 / 1',
          background: collection.bg === '#191414' ? collection.bgAlt : collection.bg,
          border: '3px solid var(--kech-aqua)',
          borderRadius: 8,
          display: 'grid', placeItems: 'center',
          overflow: 'hidden',
          position: 'relative'
        }}>
          <OrnamentBall design={design} collection={collection} size={240} />
        </div>
        {/* Caption */}
        <div style={{
          marginTop: 14,
          fontFamily: 'var(--font-body)', fontWeight: 700, fontSize: compact ? 14 : 20,
          color: 'var(--kech-white)', textTransform: 'none',
          lineHeight: 1.2, letterSpacing: '-0.01em', textAlign: 'center',
          wordBreak: 'break-word', overflowWrap: 'break-word', hyphens: 'auto'
        }}>{design.caption}</div>
      </div>);

  }

  // 'sticker' default — bold brand card
  return (
    <div style={{
      background: collection.bg === '#191414' ? 'var(--kech-aqua)' : 'var(--kech-white)',
      border: '4px solid var(--kech-black)',
      borderRadius: 24,
      padding: 18,
      position: 'relative',
      boxShadow: '7px 7px 0 var(--kech-black)',
      color: 'var(--kech-black)'
    }}>
      <div style={{
        aspectRatio: '1 / 1',
        background: collection.bg === '#191414' ? collection.bg : collection.id === 'wannabe' ? '#9BF0E1' : collection.bgAlt,
        border: '3px solid var(--kech-black)',
        borderRadius: 14,
        display: 'grid', placeItems: 'center',
        overflow: 'hidden', position: 'relative'
      }}>
        <OrnamentBall design={design} collection={collection} size={260} />
      </div>
      <div style={{
        marginTop: compact ? 10 : 14,
        fontFamily: 'var(--font-body)', fontWeight: 700, fontSize: captionSize,
        textTransform: 'none', lineHeight: 1.15, letterSpacing: '-0.01em',
        textAlign: 'center',
        wordBreak: 'break-word', overflowWrap: 'break-word', hyphens: 'auto'
      }}>{design.caption}</div>
    </div>);

}

// ---------- Swipe card (drag) ----------------------------------------
function SwipeCard({ design, collection, isTop, stackIndex, cardStyle, onSwipe, onIgnite, forceExit }) {
  const ref = useRef(null);
  const [drag, setDrag] = useState({ x: 0, y: 0, dragging: false });
  const [exit, setExit] = useState(null); // 'left'|'right'|'up'|null
  const stateRef = useRef({ startX: 0, startY: 0, sx: 0, sy: 0, captured: false, pid: null });

  // External programmatic exit (from action buttons / keyboard)
  useEffect(() => {
    if (forceExit && !exit) {
      setExit(forceExit.dir);
    }
  }, [forceExit, exit]);

  // pointer drag handlers — stable listeners, not torn down on every drag tick
  useEffect(() => {
    if (!isTop) return;
    const el = ref.current;
    if (!el) return;
    const s = stateRef.current;

    const onDown = (e) => {
      if (exit) return;
      s.pid = e.pointerId;
      try {el.setPointerCapture(s.pid);} catch {}
      s.captured = true;
      s.startX = e.clientX;s.startY = e.clientY;
      s.sx = 0;s.sy = 0;
      setDrag({ x: 0, y: 0, dragging: true });
      e.preventDefault();
    };
    const onMove = (e) => {
      if (!s.captured) return;
      setDrag({ x: e.clientX - s.startX, y: e.clientY - s.startY, dragging: true });
    };
    const onUp = (e) => {
      if (!s.captured) return;
      s.captured = false;
      try {el.releasePointerCapture(s.pid);} catch {}
      const dx = e.clientX - s.startX;
      const dy = e.clientY - s.startY;
      if (dy < -110) {
        if (onIgnite) onIgnite('up');
        setExit('up');
        setTimeout(() => onSwipe('up'), 280);
      } else if (dx > 130) {
        setExit('right');
        setTimeout(() => onSwipe('right'), 280);
      } else if (dx < -130) {
        setExit('left');
        setTimeout(() => onSwipe('left'), 280);
      } else {
        setDrag({ x: 0, y: 0, dragging: false });
      }
    };
    el.addEventListener('pointerdown', onDown);
    window.addEventListener('pointermove', onMove);
    window.addEventListener('pointerup', onUp);
    window.addEventListener('pointercancel', onUp);
    return () => {
      el.removeEventListener('pointerdown', onDown);
      window.removeEventListener('pointermove', onMove);
      window.removeEventListener('pointerup', onUp);
      window.removeEventListener('pointercancel', onUp);
    };
  }, [isTop, exit, onSwipe, onIgnite]);

  // computed transform
  const exitT = exit === 'left' ? 'translate(-700px, 80px) rotate(-22deg)' :
  exit === 'right' ? 'translate(700px, 80px) rotate(22deg)' :
  exit === 'up' ? 'translate(700px, -120px) rotate(22deg)' :
  null;

  const stackOffsetY = stackIndex * 14;
  const stackOffsetX = stackIndex === 0 ? 0 : (stackIndex % 2 ? -1 : 1) * (6 + stackIndex * 3);
  const stackScale = 1 - stackIndex * 0.035;
  const stackRot = stackIndex === 0 ? 0 : stackIndex % 2 ? -4 : 4;

  const transform = exitT ?
  exitT :
  `translate(${drag.x + stackOffsetX}px, ${drag.y + stackOffsetY}px) rotate(${drag.x * 0.06}deg) scale(${stackScale}) rotate(${stackRot}deg)`;

  const rawLikeOp = Math.min(1, Math.max(0, (drag.x - 30) / 100));
  const rawNopeOp = Math.min(1, Math.max(0, (-drag.x - 30) / 100));
  const fireOp = Math.min(1, Math.max(0, (-drag.y - 40) / 100));
  // Fire wins over jaaa/nee — once the user is also pulling up, hide the side stamps
  const fireSuppress = fireOp > 0.05 ? 1 - Math.min(1, fireOp * 4) : 1;
  const likeOp = rawLikeOp * fireSuppress;
  const nopeOp = rawNopeOp * fireSuppress;

  return (
    <div
      ref={ref}
      style={{
        position: 'absolute', inset: 0,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        zIndex: 50 - stackIndex,
        pointerEvents: isTop && !exit ? 'auto' : 'none',
        cursor: isTop ? drag.dragging ? 'grabbing' : 'grab' : 'default',
        touchAction: 'none',
        transform,
        transition: exit === 'up' ? 'transform 520ms cubic-bezier(0.4, 0, 1, 1)' :
        exit ? 'transform 280ms cubic-bezier(0.4, 0, 1, 1)' :
        drag.dragging ? 'none' :
        'transform 320ms cubic-bezier(0.34, 1.56, 0.64, 1)',
        userSelect: 'none'
      }}>
      
      <div style={{ width: 320, position: 'relative' }}>
        {/* Direction-aware aura — subtle but visible glow behind the card */}
        {isTop &&
        <div
          aria-hidden="true"
          style={{
            position: 'absolute',
            inset: -28,
            borderRadius: 28,
            pointerEvents: 'none',
            opacity: Math.max(likeOp, nopeOp, fireOp) * 0.95,
            background:
            likeOp > nopeOp && likeOp > fireOp ?
            'radial-gradient(ellipse at center, rgba(155,240,225,0.85) 0%, rgba(155,240,225,0) 70%)' :
            nopeOp > fireOp ?
            'radial-gradient(ellipse at center, rgba(240,55,165,0.85) 0%, rgba(240,55,165,0) 70%)' :
            'radial-gradient(ellipse at center, rgba(255,170,40,0.85) 0%, rgba(255,170,40,0) 70%)',
            filter: 'blur(6px)',
            transition: 'opacity 80ms linear',
            zIndex: 0
          }} />

        }
        {/* Direction-aware outline ring on the card itself */}
        {isTop &&
        <div
          aria-hidden="true"
          style={{
            position: 'absolute',
            inset: -3,
            borderRadius: 21,
            pointerEvents: 'none',
            border: '3px solid transparent',
            borderColor:
            likeOp > nopeOp && likeOp > fireOp ?
            'var(--kech-aqua)' :
            nopeOp > fireOp ?
            'var(--kech-fuchsia)' :
            'rgb(255, 170, 40)',
            opacity: Math.max(likeOp, nopeOp, fireOp),
            boxShadow:
            likeOp > nopeOp && likeOp > fireOp ?
            '0 0 0 6px rgba(155,240,225,0.35)' :
            nopeOp > fireOp ?
            '0 0 0 6px rgba(240,55,165,0.35)' :
            '0 0 0 6px rgba(255,170,40,0.35)',
            transition: 'opacity 80ms linear',
            zIndex: 4
          }} />

        }
        {isTop &&
        <>
            <Stamp kind="right" opacity={likeOp} />
            <Stamp kind="left" opacity={nopeOp} />
            <Stamp kind="up" opacity={fireOp} />
          </>
        }
        <CardArt design={design} collection={collection} style={cardStyle} />
      </div>
    </div>);

}

// ---------- Action button (bottom bar) -------------------------------
function ActionButton({ kind, onClick, disabled }) {
  const map = {
    undo: { icon: '↺', label: 'undo', size: 50, bg: 'var(--kech-white)', fg: 'var(--kech-black)' },
    nope: { icon: '✕', label: 'nee', size: 64, bg: 'var(--kech-white)', fg: 'var(--kech-fuchsia)' },
    fire: { icon: '🔥', label: 'fire', size: 56, bg: 'var(--kech-fuchsia)', fg: 'var(--kech-black)' },
    like: { icon: '♥', label: 'ja', size: 64, bg: 'var(--kech-aqua)', fg: 'var(--kech-black)' }
  };
  const cfg = map[kind];
  return (
    <button
      onClick={onClick}
      disabled={disabled}
      aria-label={cfg.label}
      style={{
        width: cfg.size, height: cfg.size,
        borderRadius: 999,
        background: cfg.bg, color: cfg.fg,
        border: '3px solid var(--kech-black)',
        boxShadow: '4px 4px 0 var(--kech-black)',
        fontSize: cfg.size * 0.45, lineHeight: 1,
        display: 'grid', placeItems: 'center',
        opacity: disabled ? 0.3 : 1,
        cursor: disabled ? 'not-allowed' : 'pointer',
        transition: 'transform 140ms var(--ease-pop), box-shadow 140ms',
        fontFamily: 'Kechfont, system-ui', fontWeight: 800
      }}
      onMouseEnter={(e) => {if (!disabled) {e.currentTarget.style.transform = 'translate(-2px,-2px)';e.currentTarget.style.boxShadow = '6px 6px 0 var(--kech-black)';}}}
      onMouseLeave={(e) => {e.currentTarget.style.transform = 'translate(0,0)';e.currentTarget.style.boxShadow = '4px 4px 0 var(--kech-black)';}}>
      
      {cfg.icon}
    </button>);

}

// ---------- Swipe stack ---------------------------------------------
function SwipeStack({ collection, designs, cardStyle, onComplete, collectionIndex, totalCollections }) {
  const [idx, setIdx] = useState(0);
  const [history, setHistory] = useState([]);
  const [liked, setLiked] = useState([]);
  const [disliked, setDisliked] = useState([]);
  const [fireBurst, setFireBurst] = useState(0); // increments to retrigger animation
  const [buttonExit, setButtonExit] = useState(null); // {dir, key} — programmatic card exit
  const committedRef = React.useRef(new Set()); // dedupe across rapid double-fires

  const commitSwipe = useCallback((dir) => {
    const d = designs[idx];
    if (!d) return;
    if (committedRef.current.has(d.id)) return; // already counted this card
    committedRef.current.add(d.id);
    const tagged = { ...d, _collection: collection };
    if (window.KechDB) window.KechDB.recordSwipe(collection.id, d.id, dir);
    setHistory((h) => [...h, { design: d, dir }]);
    if (dir === 'right' || dir === 'up') {
      setLiked((l) => l.some((x) => x.id === tagged.id) ? l : [...l, tagged]);
    } else if (dir === 'left') {
      setDisliked((l) => l.some((x) => x.id === tagged.id) ? l : [...l, tagged]);
    }
    const next = idx + 1;
    setIdx(next);
    setButtonExit(null);
    if (next >= designs.length) {
      const finalLiked = dir === 'right' || dir === 'up' ? [...liked, tagged] : liked;
      const finalDisliked = dir === 'left' ? [...disliked, tagged] : disliked;
      setTimeout(() => onComplete(finalLiked, finalDisliked), 320);
    }
  }, [designs, idx, liked, disliked, onComplete, collection]);

  // Used both by drag (immediate) and buttons (with animated fly-out)
  const swipe = useCallback((dir) => {
    commitSwipe(dir);
  }, [commitSwipe]);

  const buttonSwipe = useCallback((dir) => {
    if (buttonExit) return;
    if (idx >= designs.length) return;
    if (dir === 'up') {
      // Fire flow: ignite first, let flames burn over the still-visible card,
      // THEN fly the card away (flames are still tailing off, so they exit together)
      setFireBurst((n) => n + 1);
      setTimeout(() => {
        setButtonExit({ dir, key: idx });
        setTimeout(() => commitSwipe(dir), 520);
      }, 750);
    } else {
      setButtonExit({ dir, key: idx });
      setTimeout(() => commitSwipe(dir), 300);
    }
  }, [buttonExit, idx, designs.length, commitSwipe]);

  const undo = useCallback(() => {
    if (history.length === 0) return;
    const last = history[history.length - 1];
    setHistory((h) => h.slice(0, -1));
    setIdx((i) => Math.max(0, i - 1));
    committedRef.current.delete(last.design.id);
    if (last.dir === 'right' || last.dir === 'up') {
      setLiked((l) => l.filter((x) => x.id !== last.design.id));
    } else if (last.dir === 'left') {
      setDisliked((l) => l.filter((x) => x.id !== last.design.id));
    }
  }, [history]);

  // keyboard
  useEffect(() => {
    const onKey = (e) => {
      if (idx >= designs.length) return;
      if (e.key === 'ArrowRight') buttonSwipe('right');else
      if (e.key === 'ArrowLeft') buttonSwipe('left');else
      if (e.key === 'ArrowUp') buttonSwipe('up');else
      if (e.key === 'z' || e.key === 'Z') undo();
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [idx, designs.length, buttonSwipe, undo]);

  const visible = designs.slice(idx, idx + 3);
  const isOnDarkCol = collection.bg === '#191414';

  return (
    <section className="page" style={{ position: 'relative', minHeight: '100vh', display: 'flex', flexDirection: 'column' }}>
      <CollectionBackdrop collection={collection} />

      {/* Tagline */}
      <div style={{
        position: 'relative', zIndex: 3, textAlign: 'center', padding: '24px 24px 0'
      }}>
        <h1 style={{
          fontFamily: 'Kechfont, system-ui', fontWeight: 800,
          fontSize: 'clamp(40px, 7vw, 80px)', lineHeight: 0.85, letterSpacing: '-0.02em',
          color: isOnDarkCol ? 'var(--kech-fuchsia)' : 'var(--kech-black)',
          textTransform: 'lowercase', margin: 0,
          textShadow: isOnDarkCol ? '0 3px 0 rgba(0,0,0,0.4)' : '0 3px 0 rgba(255,255,255,0.5)'
        }}>{collection.name}</h1>
        <div style={{
          marginTop: 14,
          display: 'inline-block',
          padding: '8px 18px 10px',
          fontWeight: 400,
          fontSize: 22,
          color: 'var(--kech-black)',
          background: isOnDarkCol ? 'var(--kech-aqua)' : 'var(--kech-white)',
          border: '2.5px solid var(--kech-black)',
          borderRadius: 999,
          boxShadow: '3px 3px 0 var(--kech-fuchsia), 3px 3px 0 2.5px var(--kech-black)',
          textTransform: 'lowercase',

          letterSpacing: '-0.005em',
          transform: 'rotate(-1.5deg)', fontFamily: "Inter"
        }}>{collection.tagline}</div>
      </div>

      {/* Card stack */}
      <div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', position: 'relative', zIndex: 2, padding: '24px 0' }}>
        <div style={{ position: 'relative', width: 340, height: 460 }}>
          <GhostStack
            remaining={designs.length - idx}
            collection={collection}
            cardStyle={cardStyle}
            visibleLive={visible.length} />
          
          {visible.map((d, i) =>
          <SwipeCard
            key={d.id}
            design={d}
            collection={collection}
            isTop={i === 0}
            stackIndex={i}
            cardStyle={cardStyle}
            onSwipe={swipe}
            onIgnite={(dir) => { if (dir === 'up') setFireBurst((n) => n + 1); }}
            forceExit={i === 0 ? buttonExit : null} />

          )}
          <FireBurst trigger={fireBurst} />
        </div>
      </div>

      {/* Action bar */}
      <div style={{ position: 'relative', zIndex: 3, padding: '8px 24px 24px' }}>
        <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', gap: 16 }}>
          <ActionButton kind="undo" onClick={undo} disabled={history.length === 0} />
          <ActionButton kind="nope" onClick={() => buttonSwipe('left')} />
          <ActionButton kind="like" onClick={() => buttonSwipe('right')} />
          <ActionButton kind="fire" onClick={() => buttonSwipe('up')} />
        </div>
      </div>
    </section>);

}

window.KechSwipe = { SwipeStack, CardArt };