{"project":{"id":"uzI1Vfp","userId":"davidyarham@gmail.com","username":null,"userPicture":null,"name":"Pong","thumbnail":"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","visible":true,"contributors":"","githubRepo":null,"forkedFrom":null,"tags":"","files":{"folder":"","files":[{"name":"index.html","content":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>Untitled</title>\n  <link rel=\"stylesheet\" href=\"style.css\">\n</head>\n<body>\n<div class=\"pong\">\n\t<div class=\"pong__header\">\n\t\t<span class=\"pong__score pong__score--player\">0</span>\n\t\t<span class=\"pong__title\">PONG</span>\n\t\t<span class=\"pong__score pong__score--cpu\">0</span>\n\t</div>\n\t<canvas id=\"pongCanvas\" class=\"pong__canvas\"></canvas>\n\t<div class=\"pong__overlay\" id=\"overlay\">\n\t\t<h1 class=\"pong__start-title\">NEON PONG</h1>\n\t\t<p class=\"pong__start-sub\">Move your paddle with the mouse or touch</p>\n\t\t<button class=\"pong__btn\" id=\"startBtn\">START GAME</button>\n\t</div>\n\t<div class=\"pong__controls\">\n\t\t<span>▲▼ Mouse / Touch to move</span>\n\t\t<span>First to 7 wins</span>\n\t</div>\n</div>\n  <script type=\"module\" src=\"main.js\"></script>\n</body>\n</html>"},{"name":"main.js","content":"(() => {\n\tconst canvas = document.getElementById('pongCanvas');\n\tconst ctx = canvas.getContext('2d');\n\tconst overlay = document.getElementById('overlay');\n\tconst startBtn = document.getElementById('startBtn');\n\tconst playerScoreEl = document.querySelector('.pong__score--player');\n\tconst cpuScoreEl = document.querySelector('.pong__score--cpu');\n\n\tconst W = 800;\n\tconst H = 600;\n\tcanvas.width = W;\n\tcanvas.height = H;\n\n\tconst WINNING_SCORE = 7;\n\tconst PADDLE_W = 14;\n\tconst PADDLE_H = 100;\n\tconst BALL_R = 8;\n\tconst PADDLE_SPEED = 7;\n\tconst BALL_BASE_SPEED = 6;\n\tconst CPU_SPEED = 4.5;\n\n\tlet gameRunning = false;\n\tlet animId;\n\n\t// === AUDIO ENGINE (Web Audio API) ===\n\tlet audioCtx;\n\n\tfunction ensureAudio() {\n\t\tif (!audioCtx) audioCtx = new(window.AudioContext || window.webkitAudioContext)();\n\t\tif (audioCtx.state === 'suspended') audioCtx.resume();\n\t}\n\n\tfunction playTone(freq, duration, type = 'square', vol = 0.15, slide = 0) {\n\t\tif (!audioCtx) return;\n\t\tconst osc = audioCtx.createOscillator();\n\t\tconst gain = audioCtx.createGain();\n\t\tosc.type = type;\n\t\tosc.frequency.setValueAtTime(freq, audioCtx.currentTime);\n\t\tif (slide) osc.frequency.exponentialRampToValueAtTime(Math.max(slide, 20), audioCtx.currentTime + duration);\n\t\tgain.gain.setValueAtTime(vol, audioCtx.currentTime);\n\t\tgain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + duration);\n\t\tosc.connect(gain);\n\t\tgain.connect(audioCtx.destination);\n\t\tosc.start(audioCtx.currentTime);\n\t\tosc.stop(audioCtx.currentTime + duration);\n\t}\n\n\tfunction sndPaddleHit(intensity) {\n\t\t// Higher pitch based on hit intensity\n\t\tplayTone(440 + intensity * 200, 0.08, 'square', 0.12);\n\t\tplayTone(880 + intensity * 200, 0.06, 'sine', 0.06);\n\t}\n\n\tfunction sndWallBounce() {\n\t\tplayTone(220, 0.05, 'triangle', 0.08);\n\t}\n\n\tfunction sndScore(isPlayer) {\n\t\tif (isPlayer) {\n\t\t\t// Ascending happy tone\n\t\t\tplayTone(523, 0.12, 'square', 0.1);\n\t\t\tsetTimeout(() => playTone(659, 0.12, 'square', 0.1), 80);\n\t\t\tsetTimeout(() => playTone(784, 0.2, 'square', 0.12), 160);\n\t\t} else {\n\t\t\t// Descending sad tone\n\t\t\tplayTone(400, 0.15, 'sawtooth', 0.08, 100);\n\t\t\tsetTimeout(() => playTone(250, 0.25, 'sawtooth', 0.06, 80), 120);\n\t\t}\n\t}\n\n\tfunction sndWin() {\n\t\tconst notes = [523, 659, 784, 1047];\n\t\tnotes.forEach((n, i) => {\n\t\t\tsetTimeout(() => playTone(n, 0.2, 'square', 0.1), i * 120);\n\t\t\tsetTimeout(() => playTone(n * 1.5, 0.15, 'sine', 0.05), i * 120 + 30);\n\t\t});\n\t}\n\n\tfunction sndLose() {\n\t\tconst notes = [400, 350, 300, 200];\n\t\tnotes.forEach((n, i) => {\n\t\t\tsetTimeout(() => playTone(n, 0.25, 'sawtooth', 0.08, n * 0.5), i * 150);\n\t\t});\n\t}\n\n\tconst state = {\n\t\tplayer: {\n\t\t\tx: 30,\n\t\t\ty: H / 2 - PADDLE_H / 2,\n\t\t\tw: PADDLE_W,\n\t\t\th: PADDLE_H,\n\t\t\tscore: 0\n\t\t},\n\t\tcpu: {\n\t\t\tx: W - 30 - PADDLE_W,\n\t\t\ty: H / 2 - PADDLE_H / 2,\n\t\t\tw: PADDLE_W,\n\t\t\th: PADDLE_H,\n\t\t\tscore: 0\n\t\t},\n\t\tball: {\n\t\t\tx: W / 2,\n\t\t\ty: H / 2,\n\t\t\tvx: BALL_BASE_SPEED,\n\t\t\tvy: 3,\n\t\t\tspeed: BALL_BASE_SPEED,\n\t\t\tr: BALL_R\n\t\t},\n\t\tparticles: [],\n\t\ttrail: [],\n\t\tmouseY: H / 2\n\t};\n\n\t// Neon glow helper\n\tfunction setNeonStroke(ctx, color, width, blur) {\n\t\tctx.strokeStyle = color;\n\t\tctx.lineWidth = width;\n\t\tctx.shadowColor = color;\n\t\tctx.shadowBlur = blur;\n\t}\n\n\tfunction setNeonFill(ctx, color, blur) {\n\t\tctx.fillStyle = color;\n\t\tctx.shadowColor = color;\n\t\tctx.shadowBlur = blur;\n\t}\n\n\tfunction clearGlow(ctx) {\n\t\tctx.shadowBlur = 0;\n\t\tctx.shadowColor = 'transparent';\n\t}\n\n\t// Particles\n\tfunction spawnParticles(x, y, color, count) {\n\t\tfor (let i = 0; i < count; i++) {\n\t\t\tconst angle = Math.random() * Math.PI * 2;\n\t\t\tconst speed = 1 + Math.random() * 4;\n\t\t\tstate.particles.push({\n\t\t\t\tx,\n\t\t\t\ty,\n\t\t\t\tvx: Math.cos(angle) * speed,\n\t\t\t\tvy: Math.sin(angle) * speed,\n\t\t\t\tlife: 1,\n\t\t\t\tdecay: 0.02 + Math.random() * 0.03,\n\t\t\t\tcolor,\n\t\t\t\tsize: 2 + Math.random() * 3\n\t\t\t});\n\t\t}\n\t}\n\n\tfunction updateParticles() {\n\t\tfor (let i = state.particles.length - 1; i >= 0; i--) {\n\t\t\tconst p = state.particles[i];\n\t\t\tp.x += p.vx;\n\t\t\tp.y += p.vy;\n\t\t\tp.life -= p.decay;\n\t\t\tp.vx *= 0.98;\n\t\t\tp.vy *= 0.98;\n\t\t\tif (p.life <= 0) state.particles.splice(i, 1);\n\t\t}\n\t}\n\n\tfunction drawParticles() {\n\t\tfor (const p of state.particles) {\n\t\t\tctx.globalAlpha = p.life;\n\t\t\tsetNeonFill(ctx, p.color, 15 * p.life);\n\t\t\tctx.beginPath();\n\t\t\tctx.arc(p.x, p.y, p.size * p.life, 0, Math.PI * 2);\n\t\t\tctx.fill();\n\t\t}\n\t\tctx.globalAlpha = 1;\n\t\tclearGlow(ctx);\n\t}\n\n\t// Trail\n\tfunction updateTrail() {\n\t\tstate.trail.push({\n\t\t\tx: state.ball.x,\n\t\t\ty: state.ball.y,\n\t\t\tlife: 1\n\t\t});\n\t\tif (state.trail.length > 20) state.trail.shift();\n\t\tfor (const t of state.trail) {\n\t\t\tt.life -= 0.05;\n\t\t}\n\t\tstate.trail = state.trail.filter(t => t.life > 0);\n\t}\n\n\tfunction drawTrail() {\n\t\tfor (const t of state.trail) {\n\t\t\tctx.globalAlpha = t.life * 0.4;\n\t\t\tsetNeonFill(ctx, '#ffe600', 10 * t.life);\n\t\t\tctx.beginPath();\n\t\t\tctx.arc(t.x, t.y, BALL_R * t.life, 0, Math.PI * 2);\n\t\t\tctx.fill();\n\t\t}\n\t\tctx.globalAlpha = 1;\n\t\tclearGlow(ctx);\n\t}\n\n\t// Draw dashed center line\n\tfunction drawCenterLine() {\n\t\tctx.setLineDash([10, 14]);\n\t\tsetNeonStroke(ctx, '#ffffff15', 2, 0);\n\t\tctx.beginPath();\n\t\tctx.moveTo(W / 2, 0);\n\t\tctx.lineTo(W / 2, H);\n\t\tctx.stroke();\n\t\tctx.setLineDash([]);\n\t\tclearGlow(ctx);\n\t}\n\n\t// Draw paddle with neon glow\n\tfunction drawPaddle(paddle, color) {\n\t\tconst {\n\t\t\tx,\n\t\t\ty,\n\t\t\tw,\n\t\t\th\n\t\t} = paddle;\n\t\t// Outer glow\n\t\tsetNeonFill(ctx, color, 30);\n\t\tctx.beginPath();\n\t\tctx.roundRect(x, y, w, h, 4);\n\t\tctx.fill();\n\t\t// Inner bright\n\t\tsetNeonFill(ctx, '#fff', 10);\n\t\tctx.beginPath();\n\t\tctx.roundRect(x + 3, y + 3, w - 6, h - 6, 2);\n\t\tctx.fill();\n\t\tclearGlow(ctx);\n\t}\n\n\t// Draw ball\n\tfunction drawBall() {\n\t\tconst {\n\t\t\tx,\n\t\t\ty,\n\t\t\tr\n\t\t} = state.ball;\n\t\t// Outer glow\n\t\tsetNeonFill(ctx, '#ffe600', 40);\n\t\tctx.beginPath();\n\t\tctx.arc(x, y, r + 2, 0, Math.PI * 2);\n\t\tctx.fill();\n\t\t// Core\n\t\tsetNeonFill(ctx, '#fff', 15);\n\t\tctx.beginPath();\n\t\tctx.arc(x, y, r - 2, 0, Math.PI * 2);\n\t\tctx.fill();\n\t\tclearGlow(ctx);\n\t}\n\n\t// Draw scanlines\n\tfunction drawScanlines() {\n\t\tctx.globalAlpha = 0.03;\n\t\tctx.fillStyle = '#000';\n\t\tfor (let i = 0; i < H; i += 3) {\n\t\t\tctx.fillRect(0, i, W, 1);\n\t\t}\n\t\tctx.globalAlpha = 1;\n\t}\n\n\t// Reset ball\n\tfunction resetBall(direction) {\n\t\tstate.ball.x = W / 2;\n\t\tstate.ball.y = H / 2;\n\t\tstate.ball.speed = BALL_BASE_SPEED;\n\t\tconst angle = (Math.random() * 0.8 - 0.4);\n\t\tstate.ball.vx = Math.cos(angle) * state.ball.speed * direction;\n\t\tstate.ball.vy = Math.sin(angle) * state.ball.speed;\n\t\tstate.trail = [];\n\t}\n\n\t// Player input\n\tfunction handleMouseMove(e) {\n\t\tconst rect = canvas.getBoundingClientRect();\n\t\tconst scaleY = H / rect.height;\n\t\tstate.mouseY = (e.clientY - rect.top) * scaleY;\n\t}\n\n\tfunction handleTouchMove(e) {\n\t\te.preventDefault();\n\t\tconst rect = canvas.getBoundingClientRect();\n\t\tconst scaleY = H / rect.height;\n\t\tstate.mouseY = (e.touches[0].clientY - rect.top) * scaleY;\n\t}\n\n\tcanvas.addEventListener('mousemove', handleMouseMove);\n\tcanvas.addEventListener('touchmove', handleTouchMove, {\n\t\tpassive: false\n\t});\n\n\t// Update player paddle\n\tfunction updatePlayer() {\n\t\tconst target = state.mouseY - state.player.h / 2;\n\t\tconst diff = target - state.player.y;\n\t\tstate.player.y += diff * 0.15;\n\t\tstate.player.y = Math.max(0, Math.min(H - PADDLE_H, state.player.y));\n\t}\n\n\t// CPU AI\n\tfunction updateCPU() {\n\t\tconst ball = state.ball;\n\t\tlet targetY = ball.y - state.cpu.h / 2;\n\n\t\t// Only react when ball is coming towards CPU\n\t\tif (ball.vx > 0) {\n\t\t\t// Predict where ball will be\n\t\t\tconst timeToReach = (state.cpu.x - ball.x) / ball.vx;\n\t\t\tlet predictedY = ball.y + ball.vy * timeToReach;\n\t\t\t// Bounce prediction\n\t\t\twhile (predictedY < 0 || predictedY > H) {\n\t\t\t\tif (predictedY < 0) predictedY = -predictedY;\n\t\t\t\tif (predictedY > H) predictedY = 2 * H - predictedY;\n\t\t\t}\n\t\t\ttargetY = predictedY - state.cpu.h / 2;\n\t\t}\n\n\t\tconst diff = targetY - state.cpu.y;\n\t\tconst move = Math.sign(diff) * Math.min(CPU_SPEED, Math.abs(diff));\n\t\tstate.cpu.y += move;\n\t\tstate.cpu.y = Math.max(0, Math.min(H - PADDLE_H, state.cpu.y));\n\t}\n\n\t// Ball collision\n\tfunction paddleCollision(paddle, color) {\n\t\tconst bx = state.ball.x,\n\t\t\tby = state.ball.y,\n\t\t\tbr = state.ball.r;\n\t\tif (\n\t\t\tbx - br < paddle.x + paddle.w &&\n\t\t\tbx + br > paddle.x &&\n\t\t\tby - br < paddle.y + paddle.h &&\n\t\t\tby + br > paddle.y\n\t\t) {\n\t\t\t// Reflect\n\t\t\tstate.ball.vx *= -1;\n\t\t\t// Angle based on hit position\n\t\t\tconst hitPos = (by - (paddle.y + paddle.h / 2)) / (paddle.h / 2);\n\t\t\tstate.ball.vy = hitPos * 6;\n\t\t\t// Speed up\n\t\t\tstate.ball.speed = Math.min(state.ball.speed + 0.3, 12);\n\t\t\tconst magnitude = Math.sqrt(state.ball.vx ** 2 + state.ball.vy ** 2);\n\t\t\tstate.ball.vx = (state.ball.vx / magnitude) * state.ball.speed;\n\t\t\tstate.ball.vy = (state.ball.vy / magnitude) * state.ball.speed;\n\t\t\t// Push ball out of paddle\n\t\t\tif (paddle === state.player) {\n\t\t\t\tstate.ball.x = paddle.x + paddle.w + br;\n\t\t\t} else {\n\t\t\t\tstate.ball.x = paddle.x - br;\n\t\t\t}\n\t\t\tspawnParticles(state.ball.x, state.ball.y, color, 15);\n\t\t\tsndPaddleHit(Math.abs(hitPos));\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tfunction updateBall() {\n\t\tconst ball = state.ball;\n\t\tball.x += ball.vx;\n\t\tball.y += ball.vy;\n\n\t\t// Top/bottom walls\n\t\tif (ball.y - ball.r <= 0) {\n\t\t\tball.y = ball.r;\n\t\t\tball.vy *= -1;\n\t\t\tspawnParticles(ball.x, ball.y, '#ffe600', 8);\n\t\t\tsndWallBounce();\n\t\t}\n\t\tif (ball.y + ball.r >= H) {\n\t\t\tball.y = H - ball.r;\n\t\t\tball.vy *= -1;\n\t\t\tspawnParticles(ball.x, ball.y, '#ffe600', 8);\n\t\t\tsndWallBounce();\n\t\t}\n\n\t\t// Paddle collisions\n\t\tpaddleCollision(state.player, '#00f0ff');\n\t\tpaddleCollision(state.cpu, '#ff00aa');\n\n\t\t// Scoring\n\t\tif (ball.x < -30) {\n\t\t\tstate.cpu.score++;\n\t\t\tcpuScoreEl.textContent = state.cpu.score;\n\t\t\tspawnParticles(0, ball.y, '#ff00aa', 30);\n\t\t\tsndScore(false);\n\t\t\tresetBall(1);\n\t\t\tcheckWin();\n\t\t}\n\t\tif (ball.x > W + 30) {\n\t\t\tstate.player.score++;\n\t\t\tplayerScoreEl.textContent = state.player.score;\n\t\t\tspawnParticles(W, ball.y, '#00f0ff', 30);\n\t\t\tsndScore(true);\n\t\t\tresetBall(-1);\n\t\t\tcheckWin();\n\t\t}\n\t}\n\n\tfunction checkWin() {\n\t\tif (state.player.score >= WINNING_SCORE) {\n\t\t\tendGame('YOU WIN!');\n\t\t} else if (state.cpu.score >= WINNING_SCORE) {\n\t\t\tendGame('CPU WINS');\n\t\t}\n\t}\n\n\tfunction endGame(msg) {\n\t\tgameRunning = false;\n\t\tcancelAnimationFrame(animId);\n\t\toverlay.classList.remove('pong__overlay--hidden');\n\t\tdocument.querySelector('.pong__start-title').textContent = msg;\n\t\tdocument.querySelector('.pong__start-sub').textContent = 'Click below to play again';\n\t\tstartBtn.textContent = 'PLAY AGAIN';\n\t\tif (msg === 'YOU WIN!') sndWin();\n\t\telse sndLose();\n\t}\n\n\t// Render\n\tfunction draw() {\n\t\t// BG\n\t\tctx.fillStyle = '#0a0a20';\n\t\tctx.fillRect(0, 0, W, H);\n\n\t\t// Subtle radial gradient in center\n\t\tconst grad = ctx.createRadialGradient(W / 2, H / 2, 0, W / 2, H / 2, 400);\n\t\tgrad.addColorStop(0, 'rgba(100, 0, 150, 0.06)');\n\t\tgrad.addColorStop(1, 'transparent');\n\t\tctx.fillStyle = grad;\n\t\tctx.fillRect(0, 0, W, H);\n\n\t\tdrawCenterLine();\n\t\tdrawTrail();\n\t\tdrawParticles();\n\t\tdrawPaddle(state.player, '#00f0ff');\n\t\tdrawPaddle(state.cpu, '#ff00aa');\n\t\tdrawBall();\n\t\tdrawScanlines();\n\t}\n\n\tfunction gameLoop() {\n\t\tif (!gameRunning) return;\n\t\tupdatePlayer();\n\t\tupdateCPU();\n\t\tupdateBall();\n\t\tupdateTrail();\n\t\tupdateParticles();\n\t\tdraw();\n\t\tanimId = requestAnimationFrame(gameLoop);\n\t}\n\n\tfunction startGame() {\n\t\tstate.player.score = 0;\n\t\tstate.cpu.score = 0;\n\t\tstate.player.y = H / 2 - PADDLE_H / 2;\n\t\tstate.cpu.y = H / 2 - PADDLE_H / 2;\n\t\tstate.particles = [];\n\t\tstate.trail = [];\n\t\tplayerScoreEl.textContent = '0';\n\t\tcpuScoreEl.textContent = '0';\n\t\tresetBall(Math.random() > 0.5 ? 1 : -1);\n\t\tensureAudio();\n\t\toverlay.classList.add('pong__overlay--hidden');\n\t\tgameRunning = true;\n\t\tgameLoop();\n\t}\n\n\tstartBtn.addEventListener('click', startGame);\n\n\t// Initial static draw\n\tdraw();\n})();"},{"name":"style.css","content":"@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Rajdhani:wght@300;500;700&display=swap');\n\n:root {\n\tcolor-scheme: dark;\n\t--neon-cyan: #00f0ff;\n\t--neon-magenta: #ff00aa;\n\t--neon-yellow: #ffe600;\n\t--bg-deep: #050510;\n\t--bg-surface: #0a0a20;\n}\n\n* {\n\tbox-sizing: border-box;\n\tmargin: 0;\n\tpadding: 0;\n}\n\nbody {\n\tbackground: var(--bg-deep);\n\tmin-height: 100vh;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tfont-family: 'Rajdhani', sans-serif;\n\toverflow: hidden;\n}\n\n.pong {\n\tposition: relative;\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: 0;\n\twidth: 100%;\n\tmax-width: 900px;\n\tpadding: 1rem;\n}\n\n.pong__header {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\twidth: 100%;\n\tmax-width: 800px;\n\tpadding: 0.5rem 2rem 0.75rem;\n\tfont-family: 'Orbitron', sans-serif;\n}\n\n.pong__title {\n\tfont-size: 1rem;\n\tletter-spacing: 0.5em;\n\tcolor: #ffffff22;\n\tfont-weight: 400;\n\ttext-transform: uppercase;\n}\n\n.pong__score {\n\tfont-size: 3rem;\n\tfont-weight: 900;\n\tmin-width: 60px;\n\ttext-align: center;\n\tline-height: 1;\n}\n\n.pong__score--player {\n\tcolor: var(--neon-cyan);\n\ttext-shadow: 0 0 10px var(--neon-cyan), 0 0 30px var(--neon-cyan), 0 0 60px var(--neon-cyan);\n}\n\n.pong__score--cpu {\n\tcolor: var(--neon-magenta);\n\ttext-shadow: 0 0 10px var(--neon-magenta), 0 0 30px var(--neon-magenta), 0 0 60px var(--neon-magenta);\n}\n\n.pong__canvas {\n\tdisplay: block;\n\twidth: 100%;\n\tmax-width: 800px;\n\taspect-ratio: 4 / 3;\n\tborder: 1px solid #ffffff10;\n\tborder-radius: 8px;\n\tbackground: var(--bg-surface);\n\tcursor: none;\n}\n\n.pong__overlay {\n\tposition: absolute;\n\tinset: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tjustify-content: center;\n\tbackground: rgba(5, 5, 16, 0.85);\n\tbackdrop-filter: blur(10px);\n\tz-index: 10;\n\tborder-radius: 8px;\n\ttransition: opacity 0.4s, visibility 0.4s;\n}\n\n.pong__overlay--hidden {\n\topacity: 0;\n\tvisibility: hidden;\n\tpointer-events: none;\n}\n\n.pong__start-title {\n\tfont-family: 'Orbitron', sans-serif;\n\tfont-size: clamp(2.5rem, 7vw, 5rem);\n\tfont-weight: 900;\n\tletter-spacing: 0.08em;\n\tcolor: #fff;\n\ttext-shadow: 0 0 20px var(--neon-cyan), 0 0 60px var(--neon-cyan), 0 0 120px var(--neon-magenta);\n\tmargin-bottom: 0.5rem;\n}\n\n.pong__start-sub {\n\tfont-size: 1.1rem;\n\tcolor: #ffffff66;\n\tmargin-bottom: 2rem;\n\tletter-spacing: 0.05em;\n}\n\n.pong__btn {\n\tfont-family: 'Orbitron', sans-serif;\n\tfont-size: 1.1rem;\n\tfont-weight: 700;\n\tletter-spacing: 0.15em;\n\tpadding: 1rem 3rem;\n\tborder: 2px solid var(--neon-cyan);\n\tbackground: transparent;\n\tcolor: var(--neon-cyan);\n\tborder-radius: 4px;\n\tcursor: pointer;\n\ttransition: all 0.25s;\n\ttext-transform: uppercase;\n}\n\n.pong__btn:hover {\n\tbackground: var(--neon-cyan);\n\tcolor: var(--bg-deep);\n\tbox-shadow: 0 0 20px var(--neon-cyan), 0 0 60px var(--neon-cyan);\n}\n\n.pong__controls {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\twidth: 100%;\n\tmax-width: 800px;\n\tpadding: 0.75rem 1rem 0;\n\tfont-size: 0.8rem;\n\tcolor: #ffffff30;\n\tletter-spacing: 0.05em;\n}\n\n@media (max-width: 600px) {\n\t.pong__score {\n\t\tfont-size: 2rem;\n\t}\n\n\t.pong__controls {\n\t\tflex-direction: column;\n\t\talign-items: center;\n\t\tgap: 0.25rem;\n\t}\n}"}],"folders":[]},"variants":null,"createdAt":"2026-02-05T20:37:46.257Z","updatedAt":"2026-02-05T20:38:00.037Z"}}