/* global React */
const { useEffect, useRef, useState, useCallback } = React;

// ─────────── INTERACTIVE GOAL: kickable ball with physics ───────────
function GoalPlay() {
  const sectionRef = useRef(null);
  const stageRef = useRef(null);
  const ballRef = useRef(null);
  const aimSvgRef = useRef(null);
  const cleatRef = useRef(null);
  const stateRef = useRef({
    // ball physics (in stage-relative px)
    x: 0, y: 0, vx: 0, vy: 0, r: 28,
    // drag state
    dragging: false,
    dragStartX: 0, dragStartY: 0,
    dragX: 0, dragY: 0,
    // mouse (for cleat rotation + click-kick)
    mouseStageX: 0, mouseStageY: 0, mouseInStage: false,
    lastMouseX: 0, lastMouseY: 0, mouseAngle: 0,
    // resize-tracked
    stageW: 900, stageH: 460,
    goalRect: { x: 0, y: 0, w: 0, h: 0 },
    kickoff: { x: 0, y: 0 },
    scoring: false,
    // touch device
    isTouch: false,
  });
  const [showGoal, setShowGoal] = useState(false);
  const [confetti, setConfetti] = useState([]);
  const [shake, setShake] = useState(false);
  const isTouch = typeof window !== 'undefined' && ('ontouchstart' in window || navigator.maxTouchPoints > 0);

  const layout = useCallback(() => {
    const stage = stageRef.current;
    if (!stage) return;
    const { width, height } = stage.getBoundingClientRect();
    stateRef.current.stageW = width;
    stateRef.current.stageH = height;
    const mobile = width < 600;
    const goalW = Math.min(width * (mobile ? 0.275 : 0.55), mobile ? 240 : 480);
    const goalH = Math.min(height * (mobile ? 0.275 : 0.55), mobile ? 120 : 240);
    const goalX = (width - goalW) / 2;
    const goalY = height * 0.08;
    stateRef.current.goalRect = { x: goalX, y: goalY, w: goalW, h: goalH };
    const spawns = [
      { x: width / 2,      y: height - 70 },   // centre
      { x: width * 0.12,   y: height - 70 },   // left corner kick
      { x: width * 0.88,   y: height - 70 },   // right corner kick
    ];
    stateRef.current.spawnPositions = spawns;
    stateRef.current.kickoff = spawns[0];
    if (stateRef.current.x === 0 && stateRef.current.y === 0) {
      stateRef.current.x = stateRef.current.kickoff.x;
      stateRef.current.y = stateRef.current.kickoff.y;
    }
  }, []);

  useEffect(() => {
    layout();
    // re-run a couple times to catch font-load/reflow on wide screens
    const t1 = setTimeout(layout, 50);
    const t2 = setTimeout(layout, 250);
    const t3 = setTimeout(layout, 800);
    const onResize = () => layout();
    window.addEventListener('resize', onResize);
    return () => {
      clearTimeout(t1); clearTimeout(t2); clearTimeout(t3);
      window.removeEventListener('resize', onResize);
    };
  }, [layout]);

  // Score celebration
  const triggerGoal = useCallback(() => {
    if (stateRef.current.scoring) return;
    stateRef.current.scoring = true;
    setShake(true);
    setShowGoal(true);
    const colors = ['#FEE658', '#DF0024', '#FFEEAB', '#FFFFFF', '#F6D300'];
    const pieces = [];
    for (let i = 0; i < 70; i++) {
      pieces.push({
        id: i + Math.random(),
        x: 50 + (Math.random() - 0.5) * 16,
        y: 38 + (Math.random() - 0.5) * 8,
        vx: (Math.random() - 0.5) * 700,
        vy: -350 - Math.random() * 450,
        rot: Math.random() * 360,
        color: colors[i % colors.length],
        delay: Math.random() * 0.12,
      });
    }
    setConfetti(pieces);
    setTimeout(() => setShake(false), 500);
    setTimeout(() => setShowGoal(false), 1400);
    setTimeout(() => {
      // respawn at a random spawn position
      const s = stateRef.current;
      const spawns = s.spawnPositions || [s.kickoff];
      const spawn = spawns[Math.floor(Math.random() * spawns.length)];
      s.x = spawn.x; s.y = spawn.y;
      s.vx = 0; s.vy = 0;
      s.scoring = false;
      setConfetti([]);
    }, 2200);
  }, []);

  // Physics loop
  useEffect(() => {
    let raf;
    let lastT = performance.now();
    const tick = (t) => {
      const dt = Math.min(0.05, (t - lastT) / 1000);
      lastT = t;
      const s = stateRef.current;
      // friction
      const friction = 0.985;
      s.vx *= Math.pow(friction, dt * 60);
      s.vy *= Math.pow(friction, dt * 60);
      // step
      if (!s.dragging && !s.scoring) {
        s.x += s.vx * dt;
        s.y += s.vy * dt;
        // wall collisions (inside stage)
        const r = s.r;
        if (s.x - r < 0) { s.x = r; s.vx = -s.vx * 0.7; }
        if (s.x + r > s.stageW) { s.x = s.stageW - r; s.vx = -s.vx * 0.7; }
        if (s.y - r < 0) { s.y = r; s.vy = -s.vy * 0.7; }
        if (s.y + r > s.stageH) { s.y = s.stageH - r; s.vy = -s.vy * 0.7; }
        // stop tiny motion
        if (Math.abs(s.vx) < 2) s.vx = 0;
        if (Math.abs(s.vy) < 2) s.vy = 0;
        // Goal frame collisions — top + sides closed, bottom open
        const g = s.goalRect;
        const ballAtGoalX = s.x - r < g.x + g.w && s.x + r > g.x;
        const ballAtGoalY = s.y - r < g.y + g.h && s.y + r > g.y;
        // Crossbar: bounce if approaching from above (vy > 0 = moving down in screen)
        if (ballAtGoalX && s.y < g.y && s.y + r > g.y && s.vy > 0) {
          s.y = g.y - r;
          s.vy *= -0.65;
        }
        // Left post: bounce if approaching from left (vx > 0 = moving right)
        if (ballAtGoalY && s.y > g.y && s.x < g.x && s.x + r > g.x && s.vx > 0) {
          s.x = g.x - r;
          s.vx *= -0.65;
        }
        // Right post: bounce if approaching from right (vx < 0 = moving left)
        if (ballAtGoalY && s.y > g.y && s.x > g.x + g.w && s.x - r < g.x + g.w && s.vx < 0) {
          s.x = g.x + g.w + r;
          s.vx *= -0.65;
        }
        // Score: ball entered through open bottom (vy < 0 = moving upward toward goal)
        if (s.x > g.x && s.x < g.x + g.w && s.y > g.y && s.y < g.y + g.h && s.vy < 0) {
          triggerGoal();
        }
      }
      // render ball
      const ball = ballRef.current;
      if (ball) {
        const speed = Math.hypot(s.vx, s.vy);
        const rot = (t / 4) % 360;
        ball.style.transform = `translate(${s.x - s.r}px, ${s.y - s.r}px) rotate(${rot}deg)`;
      }
      // render cleat cursor (uses viewport/fixed coords)
      const cleat = cleatRef.current;
      if (cleat && !s.isTouch && s.viewportX != null) {
        cleat.style.left = s.viewportX + 'px';
        cleat.style.top = s.viewportY + 'px';
        cleat.style.transform = `translate(-50%,-50%) rotate(${s.mouseAngle + 90}deg)`;
      }
      // render aim line while dragging
      const svg = aimSvgRef.current;
      if (svg) {
        if (s.dragging) {
          // slingshot: aim opposite of drag direction
          const dx = s.dragStartX - s.dragX;
          const dy = s.dragStartY - s.dragY;
          const len = Math.min(160, Math.hypot(dx, dy));
          const ang = Math.atan2(dy, dx);
          const ex = s.x + Math.cos(ang) * len;
          const ey = s.y + Math.sin(ang) * len;
          svg.innerHTML = `
            <defs>
              <marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto">
                <path d="M0,0 L10,5 L0,10 z" fill="#DF0024"/>
              </marker>
            </defs>
            <line x1="${s.x}" y1="${s.y}" x2="${ex}" y2="${ey}"
                  stroke="#DF0024" stroke-width="4" stroke-linecap="round"
                  stroke-dasharray="6 6" marker-end="url(#arrow)" opacity="${0.4 + (len / 160) * 0.5}"/>
            <circle cx="${s.x}" cy="${s.y}" r="${s.r + 6}" stroke="#DF0024" stroke-width="2" fill="none" stroke-dasharray="3 4"/>
          `;
        } else {
          svg.innerHTML = '';
        }
      }
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [triggerGoal]);

  // Pointer handlers (works for mouse + touch via Pointer Events)
  useEffect(() => {
    const stage = stageRef.current;
    const section = sectionRef.current;
    if (!stage || !section) return;
    const s = stateRef.current;

    const stagePoint = (e) => {
      const r = stage.getBoundingClientRect();
      return { x: e.clientX - r.left, y: e.clientY - r.top };
    };

    const onMove = (e) => {
      const r = stage.getBoundingClientRect();
      const sectR = section.getBoundingClientRect();
      const inSection = e.clientX >= sectR.left && e.clientX <= sectR.right && e.clientY >= sectR.top && e.clientY <= sectR.bottom;
      const inStage = e.clientX >= r.left && e.clientX <= r.right && e.clientY >= r.top && e.clientY <= r.bottom;
      s.mouseInStage = inStage;
      const sx = e.clientX - r.left;
      const sy = e.clientY - r.top;
      // mouse velocity (px/sec) for kick power
      const now = performance.now();
      const dt = Math.max(0.008, (now - (s.lastMoveT || now)) / 1000);
      const dx = sx - s.lastMouseX;
      const dy = sy - s.lastMouseY;
      s.mouseVx = dx / dt;
      s.mouseVy = dy / dt;
      s.lastMoveT = now;
      if (Math.hypot(dx, dy) > 1.5) {
        s.mouseAngle = Math.atan2(dy, dx) * 180 / Math.PI;
      }
      s.lastMouseX = sx;
      s.lastMouseY = sy;
      s.mouseStageX = sx;
      s.mouseStageY = sy;
      // cleat uses viewport coords (fixed position)
      s.viewportX = e.clientX;
      s.viewportY = e.clientY;
      if (cleatRef.current) {
        cleatRef.current.classList.toggle('visible', inSection && !s.isTouch);
      }
      if (s.dragging) {
        s.dragX = sx; s.dragY = sy;
      } else if (inStage && !s.isTouch && !s.scoring) {
        // collision-based kick: if mouse overlaps ball, transfer mouse velocity
        const dxb = sx - s.x, dyb = sy - s.y;
        const dist = Math.hypot(dxb, dyb);
        if (dist < s.r + 18) {
          const speed = Math.hypot(s.mouseVx, s.mouseVy);
          if (speed > 60) {
            // direction: from mouse toward ball center (push ball away)
            const ang = Math.atan2(s.y - sy, s.x - sx);
            const power = Math.min(1400, 180 + speed * 0.85);
            s.vx = Math.cos(ang) * power;
            s.vy = Math.sin(ang) * power;
          }
        }
      }
    };

    const onPointerDown = (e) => {
      const { x, y } = stagePoint(e);
      const dist = Math.hypot(x - s.x, y - s.y);
      if (e.pointerType === 'touch' || e.pointerType === 'pen') s.isTouch = true;
      // mobile only: slingshot drag
      if (s.isTouch && dist < s.r + 30) {
        s.dragging = true;
        s.dragStartX = s.x;
        s.dragStartY = s.y;
        s.dragX = x;
        s.dragY = y;
        s.vx = 0; s.vy = 0;
        e.target.setPointerCapture?.(e.pointerId);
      }
    };

    const onPointerUp = (e) => {
      if (s.dragging) {
        const dx = s.dragStartX - s.dragX;
        const dy = s.dragStartY - s.dragY;
        const len = Math.min(160, Math.hypot(dx, dy));
        const ang = Math.atan2(dy, dx);
        const power = (len / 160) * 1100 + 80;
        s.vx = Math.cos(ang) * power;
        s.vy = Math.sin(ang) * power;
        s.dragging = false;
      }
    };

    stage.addEventListener('pointerdown', onPointerDown);
    window.addEventListener('pointermove', onMove);
    window.addEventListener('pointerup', onPointerUp);
    window.addEventListener('pointercancel', onPointerUp);
    return () => {
      stage.removeEventListener('pointerdown', onPointerDown);
      window.removeEventListener('pointermove', onMove);
      window.removeEventListener('pointerup', onPointerUp);
      window.removeEventListener('pointercancel', onPointerUp);
    };
  }, []);

  return (
    <section ref={sectionRef} className={`goal-section ${isTouch ? '' : 'cursor-cleat'}`}>
      <div className="goal-inner">
        <div className="goal-eyebrow">⚽ Make your goal</div>
        <h2 className="goal-title">Take Your Shot</h2>
        <p className="goal-sub">
          {isTouch
            ? 'Drag the ball back like a slingshot, then release to shoot. Score on the goal for the celebration.'
            : 'Move your cleat into the ball to kick it. The faster you swing, the harder you shoot. Score for confetti.'}
        </p>
        <div className="goal-stage" ref={stageRef}>
          <div className="stage-hint">
            {isTouch ? 'Drag & flick the ball into the goal' : 'Swipe your cleat through the ball'}
          </div>
          <GoalNet shake={shake} stateRef={stateRef} />
          <div className="pitch-line" />
          <div className="kickball" ref={ballRef}>
            <window.SoccerBallSVG size={56} />
          </div>
          <svg className="aim-line" ref={aimSvgRef} />
          <div className="goal-pop-wrap" style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>
            <div className={`goal-pop ${showGoal ? 'show' : ''}`} aria-hidden="true">
              ¡GOOOAL!
            </div>
          </div>
          <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none', overflow: 'visible' }}>
            {confetti.map(p => (
              <Confetti key={p.id} {...p} />
            ))}
          </div>
        </div>
      </div>
      {!isTouch && (
        <div className="cleat-cursor" ref={cleatRef} aria-hidden="true">
          <CleatSVG />
        </div>
      )}
    </section>
  );
}

function CleatSVG() {
  return (
    <svg viewBox="0 0 56 56" width="56" height="56" style={{ display: 'block' }}>
      {/* sole */}
      <ellipse cx="28" cy="38" rx="22" ry="6" fill="rgba(0,0,0,0.18)"/>
      {/* shoe body */}
      <path d="M 8 28 Q 8 18 22 16 L 44 22 Q 52 24 50 32 L 48 36 Q 46 40 38 40 L 14 40 Q 8 40 8 32 Z"
            fill="#DF0024" stroke="#1A1208" strokeWidth="2"/>
      {/* yellow stripe */}
      <path d="M 14 30 Q 26 26 46 30" stroke="#FEE658" strokeWidth="3" fill="none" strokeLinecap="round"/>
      {/* studs */}
      <g fill="#1A1208">
        <circle cx="14" cy="42" r="2.5"/>
        <circle cx="22" cy="43" r="2.5"/>
        <circle cx="30" cy="43" r="2.5"/>
        <circle cx="38" cy="42" r="2.5"/>
        <circle cx="44" cy="41" r="2.5"/>
      </g>
      {/* tongue / laces */}
      <path d="M 22 22 L 38 26" stroke="#fff" strokeWidth="1.5"/>
      <path d="M 24 25 L 36 28" stroke="#fff" strokeWidth="1.5"/>
    </svg>
  );
}

function GoalNet({ shake, stateRef }) {
  const [, force] = React.useState(0);
  React.useEffect(() => {
    let raf;
    const tick = () => {
      force(v => (v + 1) % 1000);
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, []);
  const s = stateRef.current;
  const g = s.goalRect;
  const sw = s.stageW;
  const sh = s.stageH;
  if (!g || !g.w || !sw) return null;
  const postW = 10;

  // Grass strip geometry — horizon sits at the base of the goal posts
  const grassTop = g.y + g.h - 30;
  const stripeCount = 12;
  const stripeW = sw / stripeCount;
  // Blade zigzag along the top edge of grass
  const bladeH = 14;
  const bladeCount = Math.ceil(sw / 10);
  let bladePath = `M 0 ${grassTop}`;
  for (let i = 0; i <= bladeCount; i++) {
    const bx = i * (sw / bladeCount);
    const tip = (i % 2 === 0) ? grassTop - bladeH : grassTop - bladeH * 0.45;
    bladePath += ` L ${bx} ${tip}`;
  }
  bladePath += ` L ${sw} ${grassTop} L ${sw} ${sh} L 0 ${sh} Z`;

  return (
    <svg
      viewBox={`0 0 ${sw} ${sh}`}
      preserveAspectRatio="none"
      xmlns="http://www.w3.org/2000/svg"
      style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', pointerEvents: 'none', zIndex: 2, overflow: 'visible' }}
    >
      {/* ── GRASS ── */}
      {/* alternating turf stripes */}
      {Array.from({ length: stripeCount }).map((_, i) => (
        <rect
          key={`stripe${i}`}
          x={i * stripeW} y={grassTop}
          width={stripeW} height={sh - grassTop}
          fill={i % 2 === 0 ? '#3a8c3f' : '#2e7a33'}
        />
      ))}
      {/* blade silhouette on top */}
      <path d={bladePath} fill="#2e7a33"/>
      {/* lighter blade highlights */}
      <path d={bladePath} fill="none" stroke="#4aac50" strokeWidth="1.2" strokeOpacity="0.5"/>

      {/* ── FIELD MARKINGS ── */}
      {(() => {
        const goalLine = g.y + g.h;          // base of goal posts
        const fieldH   = sh - goalLine - 8;  // available field depth
        const yard     = fieldH / 22;        // px per yard (18-yd box fills ~82% of field)
        const cx       = g.x + g.w / 2;     // centre x
        const b6       = 6  * yard;
        const b18      = 18 * yard;
        const psY      = goalLine + 12 * yard;  // penalty spot (12 yds out)
        const arcR     = 10 * yard;             // penalty arc radius
        const arcDx    = 8  * yard;             // arc–box intersection offset
        const lw       = Math.max(3, yard * 0.22);
        return (
          <g stroke="rgba(255,255,255,0.88)" strokeWidth={lw} fill="none" strokeLinecap="round">
            {/* Goal line — full stage width */}
            <line x1={0} y1={goalLine} x2={sw} y2={goalLine}/>

            {/* 6-yard box */}
            <line x1={g.x - b6}       y1={goalLine} x2={g.x - b6}           y2={goalLine + b6}/>
            <line x1={g.x + g.w + b6} y1={goalLine} x2={g.x + g.w + b6}     y2={goalLine + b6}/>
            <line x1={g.x - b6}       y1={goalLine + b6} x2={g.x + g.w + b6} y2={goalLine + b6}/>

            {/* 18-yard box */}
            <line x1={g.x - b18}       y1={goalLine} x2={g.x - b18}            y2={goalLine + b18}/>
            <line x1={g.x + g.w + b18} y1={goalLine} x2={g.x + g.w + b18}      y2={goalLine + b18}/>
            <line x1={g.x - b18}       y1={goalLine + b18} x2={g.x + g.w + b18} y2={goalLine + b18}/>

            {/* Penalty spot */}
            <circle cx={cx} cy={psY} r={Math.max(2.5, yard * 0.2)}
                    fill="rgba(255,255,255,0.88)" stroke="none"/>

            {/* Penalty arc (D) — curves away from goal, outside 18-yd box */}
            <path d={`M ${cx - arcDx},${goalLine + b18} A ${arcR},${arcR} 0 0 1 ${cx + arcDx},${goalLine + b18}`}
                  fill="none"/>
          </g>
        );
      })()}

      {/* ── GOAL (interior perspective) ── */}
      {(() => {
        const p = postW;
        // Vanishing point: centre-back of goal opening
        const vpx = g.x + g.w / 2;
        const vpy = g.y + g.h * 0.52;
        const lp = (a, b, t) => a + t * (b - a);
        // Back-net: proportional depth (~9.5% of goal half-width)
        const netDepth = g.w * 0.095;
        const dt = netDepth / ((vpx - g.x) || 1);
        const bx1 = g.x + netDepth;
        const bx2 = g.x + g.w - netDepth;
        const by1 = lp(g.y,       vpy, dt);
        const by2 = lp(g.y + g.h, vpy, dt);

        // Post inner face: proportional (~1.9% of goal width = ~6px on desktop)
        const innerDepth = g.w * 0.019;
        const it = innerDepth / ((vpx - g.x) || 1);
        const pilx = g.x + innerDepth;
        const pirx = g.x + g.w - innerDepth;
        const pity = lp(g.y - p,         vpy, it);
        const piby = lp(g.y + g.h + p/2, vpy, it);

        // Crossbar inner-bottom corners (same fixed depth)
        const cblx = lp(g.x - p,       vpx, it);
        const cbrx = lp(g.x + g.w + p, vpx, it);
        const cby  = lp(g.y,            vpy, it);

        const Q = (arr) => arr.map(([x, y]) => `${x},${y}`).join(' ');
        // Fewer grid divisions on small screens
        const cols = sw < 600 ? 8 : 16;
        const rows = sw < 600 ? 6 : 12;

        return (
          <g style={{
            transformOrigin: `${g.x + g.w / 2}px ${g.y + g.h}px`,
            transform: shake ? 'scale(1.02) rotate(0.4deg)' : 'none',
            transition: 'transform .12s',
          }}>
            {/* ── Net fill: full opening, 45% white ── */}
            <rect x={g.x} y={g.y} width={g.w} height={g.h}
                  fill="rgba(255,255,255,0.45)"/>

            {/* ── Net perspective grid ── */}
            <g stroke="rgba(185, 85, 45, 0.85)" strokeWidth="1" fill="none">

              {/* 4 corner edge lines */}
              <line x1={g.x}     y1={g.y}     x2={bx1} y2={by1}/>
              <line x1={g.x+g.w} y1={g.y}     x2={bx2} y2={by1}/>
              <line x1={g.x}     y1={g.y+g.h} x2={bx1} y2={by2}/>
              <line x1={g.x+g.w} y1={g.y+g.h} x2={bx2} y2={by2}/>

              {/* Top face: lines converging from crossbar → back-top edge */}
              {Array.from({length:cols-1}).map((_,i) => (
                <line key={`td${i}`}
                  x1={g.x+(i+1)*g.w/cols}            y1={g.y}
                  x2={bx1+(i+1)*(bx2-bx1)/cols}      y2={by1}/>
              ))}

              {/* Left face: height lines from left post → back-left */}
              {Array.from({length:rows-1}).map((_,i) => (
                <line key={`ld${i}`}
                  x1={g.x}  y1={g.y+(i+1)*g.h/rows}
                  x2={bx1}  y2={by1+(i+1)*(by2-by1)/rows}/>
              ))}

              {/* Right face: height lines from right post → back-right */}
              {Array.from({length:rows-1}).map((_,i) => (
                <line key={`rd${i}`}
                  x1={g.x+g.w}  y1={g.y+(i+1)*g.h/rows}
                  x2={bx2}      y2={by1+(i+1)*(by2-by1)/rows}/>
              ))}

              {/* Depth rings: 3 rectangular rings between front and back */}
              {[1,2,3].map((j) => {
                const t   = j / 4;
                const lx  = lp(g.x,     bx1, t);
                const rx  = lp(g.x+g.w, bx2, t);
                const ty  = lp(g.y,     by1, t);
                const bot = lp(g.y+g.h, by2, t);
                return (
                  <g key={`ring${j}`}>
                    <line x1={lx} y1={ty}  x2={rx} y2={ty}/>
                    <line x1={lx} y1={ty}  x2={lx} y2={bot}/>
                    <line x1={rx} y1={ty}  x2={rx} y2={bot}/>
                  </g>
                );
              })}

              {/* Back face grid */}
              <rect x={bx1} y={by1} width={bx2-bx1} height={by2-by1}/>
              {Array.from({length:cols-1}).map((_,i) => (
                <line key={`bv${i}`}
                  x1={bx1+(i+1)*(bx2-bx1)/cols} y1={by1}
                  x2={bx1+(i+1)*(bx2-bx1)/cols} y2={by2}/>
              ))}
              {Array.from({length:rows-1}).map((_,i) => (
                <line key={`bh${i}`}
                  x1={bx1} y1={by1+(i+1)*(by2-by1)/rows}
                  x2={bx2} y2={by1+(i+1)*(by2-by1)/rows}/>
              ))}

              {/* Front frame: top + sides, no bottom */}
              <path d={`M ${g.x} ${g.y+g.h} L ${g.x} ${g.y} L ${g.x+g.w} ${g.y} L ${g.x+g.w} ${g.y+g.h}`}/>
            </g>

            {/* ── Crossbar inner-bottom face ── */}
            <polygon
              points={Q([[g.x-p,g.y],[cblx,cby],[cbrx,cby],[g.x+g.w+p,g.y]])}
              fill="#A00018"
            />
            {/* ── Left post inner face ── */}
            <polygon
              points={Q([[g.x,g.y-p],[pilx,pity],[pilx,piby],[g.x,g.y+g.h+p/2]])}
              fill="#B0001E"
            />
            {/* ── Right post inner face ── */}
            <polygon
              points={Q([[g.x+g.w,g.y-p],[pirx,pity],[pirx,piby],[g.x+g.w,g.y+g.h+p/2]])}
              fill="#B0001E"
            />

            {/* ── Front posts (on top) ── */}
            <rect x={g.x-p} y={g.y-p/2} width={p} height={g.h+p} fill="#DF0024" rx="2"/>
            <rect x={g.x+g.w} y={g.y-p/2} width={p} height={g.h+p} fill="#DF0024" rx="2"/>
            <rect x={g.x-p} y={g.y-p} width={g.w+2*p} height={p} fill="#DF0024" rx="2"/>
          </g>
        );
      })()}
    </svg>
  );
}

function Confetti({ x, y, vx, vy, rot, color, delay }) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const start = performance.now() + delay * 1000;
    let raf;
    const tick = (now) => {
      const t = Math.max(0, (now - start) / 1000);
      const px = x + (vx * t) / 14;
      const py = y + ((vy * t + 0.5 * 980 * t * t) / 14);
      const op = Math.max(0, 1 - t / 1.6);
      el.style.left = px + '%';
      el.style.top = py + '%';
      el.style.opacity = String(op);
      el.style.transform = `translate(-50%,-50%) rotate(${rot + t * 720}deg)`;
      if (t < 2) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, []);
  return (
    <div ref={ref} style={{
      position: 'absolute',
      width: 10, height: 14,
      background: color,
      left: x + '%', top: y + '%',
      transform: 'translate(-50%,-50%)',
      borderRadius: 2,
    }}/>
  );
}

window.GoalPlay = GoalPlay;
