// Floating background suits + confetti + sound-free FX
const { useEffect, useState, useRef } = React;
function SuitsBG({ enabled = true }) {
if (!enabled) return null;
const suits = ["♠","♥","♦","♣"];
const pieces = React.useMemo(() => Array.from({ length: 14 }).map((_, i) => {
const suit = suits[i % 4];
const isRed = suit === "♥" || suit === "♦";
return {
suit,
isRed,
size: 38 + Math.random() * 90,
left: Math.random() * 100,
delay: -Math.random() * 28,
dur: 22 + Math.random() * 20,
startTop: 100 + Math.random() * 40,
};
}), []);
return (
{pieces.map((p, i) => (
{p.suit}
))}
);
}
function Confetti({ fire, onDone }) {
const [pieces, setPieces] = useState([]);
useEffect(() => {
if (!fire) return;
const colors = ["#f5c542","#e63946","#22d3ee","#ff4fa3","#d9f635","#4ade80","#f6efd9"];
const shapes = [
{ w: 14, h: 18, br: "2px" },
{ w: 10, h: 10, br: "50%" },
{ w: 6, h: 16, br: "2px" },
{ w: 18, h: 6, br: "3px" },
];
const arr = Array.from({ length: 90 }).map(() => {
const angle = Math.random() * Math.PI * 2;
const dist = 260 + Math.random() * 320;
const shape = shapes[Math.floor(Math.random() * shapes.length)];
return {
color: colors[Math.floor(Math.random() * colors.length)],
tx: Math.cos(angle) * dist + "px",
ty: Math.sin(angle) * dist + window.innerHeight * 0.15 + "px",
tr: (Math.random() * 720 - 360) + "deg",
delay: Math.random() * 120,
...shape,
};
});
setPieces(arr);
const t = setTimeout(() => { setPieces([]); onDone && onDone(); }, 2200);
return () => clearTimeout(t);
}, [fire]);
if (!pieces.length) return null;
return (
{pieces.map((p, i) => (
))}
);
}
Object.assign(window, { SuitsBG, Confetti });