.birthday-container { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; pointer-events: none; z-index: 9999; overflow: hidden; contain: strict; } .birthday-cake { position: absolute; bottom: 2vh; left: 50vw; transform: translateX(-50%); font-size: 8rem; z-index: 50; filter: drop-shadow(0 0 10px rgba(255,255,255,0.4)); } .birthday-cake img { height: 15vh; width: auto; object-fit: contain; max-height: 150px; } .birthday-symbol { position: absolute; bottom: -10vh; /* balloons rise from bottom */ animation: birthday-rise linear infinite; font-size: 3rem; opacity: 0.95; z-index: 40; } .birthday-symbol img { width: 6vh; height: auto; max-width: 60px; object-fit: contain; } .birthday-confetti { position: absolute; top: -5vh; width: 10px; height: 10px; opacity: 0.9; animation: birthday-confetti-fall linear infinite; z-index: 30; /* Mix of circles and squares by using CSS variables or random in JS. For simplicity, we make all slightly rounded rectangles */ border-radius: 2px; } @keyframes birthday-rise { 0% { transform: translateY(10vh) rotate(var(--start-rot, 0deg)); opacity: 0; } 10% { opacity: 1; } 90% { opacity: 1; } 100% { transform: translateY(-110vh) rotate(calc(var(--start-rot, 0deg) * -1)); opacity: 0; } } @keyframes birthday-confetti-fall { 0% { transform: translateY(-5vh) rotateX(0deg) rotateY(0deg) rotateZ(0deg); opacity: 0; } 5% { opacity: 1; } 90% { opacity: 1; } 100% { transform: translateY(105vh) rotateX(720deg) rotateY(360deg) rotateZ(180deg); opacity: 0; } }