/* ========================================================================= ULTIMATE TIC-TAC-TOE — per-player camps + switchable stages ------------------------------------------------------------------------ Two orthogonal systems: 1. STAGE (global vibe) → [data-stage="sparkle|shred|mixed"] on Controls background, backdrop FX, fonts, surface (light/dark), winner. 2. CAMP (per player) → .camp-sparkle / .camp-shred on player elements Controls a player's accent color + glow on their display, score, and their pieces on the board. A player's camp comes from their avatar, so one player can be Sparkle (🦄) while the other is Shred (💀). ========================================================================= */ *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; } :root { --radius-lg: 28px; --radius-md: 16px; --radius-sm: 12px; --maxw: 940px; --transition: 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); /* Per-camp identity colors — constant across all stages so a player's flavor travels with their avatar. */ --sparkle-color: #f368e0; --sparkle-glow: rgba(243, 104, 224, 0.55); --sparkle-tint: rgba(243, 104, 224, 0.14); --shred-color: #ff2d2d; --shred-glow: rgba(255, 45, 45, 0.6); --shred-tint: rgba(255, 45, 45, 0.13); } /* ---------- Stage themes ---------- */ [data-stage="sparkle"] { --bg: linear-gradient(135deg, #667eea 0%, #764ba2 25%, #f093fb 50%, #4facfe 75%, #667eea 100%); --bg-size: 400% 400%; --surface: rgba(255, 255, 255, 0.95); --surface-2: rgba(255, 255, 255, 0.55); --surface-border: rgba(255, 255, 255, 0.85); --card-shadow: 0 20px 60px rgba(0, 0, 0, 0.3), 0 0 40px rgba(246, 79, 254, 0.5), inset 0 0 60px rgba(255, 255, 255, 0.5); --accent1: #f093fb; --accent2: #4facfe; --accent-hot: #f5576c; --text: #5a3d7a; --text-strong: #764ba2; --text-muted: #9b86b3; --heading-font: 'Fredoka', 'Segoe UI', sans-serif; --body-font: 'Fredoka', 'Segoe UI', Tahoma, sans-serif; --heading-spacing: 0px; --heading-transform: none; --cell-bg: #ffffff; --board-bg: linear-gradient(135deg, rgba(240, 147, 251, 0.2), rgba(79, 172, 254, 0.2)); --input-bg: rgba(255, 255, 255, 0.9); --title-gradient: linear-gradient(45deg, #f093fb, #f5576c, #4facfe, #f093fb); } [data-stage="shred"] { --bg: linear-gradient(135deg, #0a0a0c 0%, #1a0205 30%, #2b0508 50%, #160003 75%, #0a0a0c 100%); --bg-size: 300% 300%; --surface: rgba(18, 16, 18, 0.94); --surface-2: rgba(255, 255, 255, 0.06); --surface-border: rgba(255, 45, 45, 0.55); --card-shadow: 0 20px 60px rgba(0, 0, 0, 0.75), 0 0 45px rgba(255, 26, 26, 0.45), inset 0 0 70px rgba(255, 26, 26, 0.06); --accent1: #ff1a1a; --accent2: #ff6a00; --accent-hot: #ff2d2d; --text: #ededed; --text-strong: #ffffff; --text-muted: #9a9aa0; --heading-font: 'Metal Mania', 'Bebas Neue', 'Arial Black', Impact, sans-serif; --body-font: 'Bebas Neue', 'Arial Narrow', 'Segoe UI', sans-serif; --heading-spacing: 2px; --heading-transform: uppercase; --cell-bg: #161417; --board-bg: linear-gradient(135deg, rgba(255, 26, 26, 0.12), rgba(0, 0, 0, 0.4)); --input-bg: rgba(0, 0, 0, 0.45); --title-gradient: linear-gradient(45deg, #ff1a1a, #ff6a00, #ffd000, #ff1a1a); } /* Mixed: a neutral battleground where BOTH camps' colors pop. */ [data-stage="mixed"] { --bg: linear-gradient(135deg, #1a0b2e 0%, #2b0a1e 30%, #1d1033 55%, #2a0815 78%, #140a24 100%); --bg-size: 320% 320%; --surface: rgba(24, 18, 34, 0.93); --surface-2: rgba(255, 255, 255, 0.07); --surface-border: rgba(243, 104, 224, 0.4); --card-shadow: 0 20px 60px rgba(0, 0, 0, 0.7), 0 0 45px rgba(243, 104, 224, 0.3), 0 0 60px rgba(255, 45, 45, 0.18), inset 0 0 70px rgba(255, 255, 255, 0.04); --accent1: #f368e0; --accent2: #ff2d2d; --accent-hot: #ff6a00; --text: #f0e9f5; --text-strong: #ffffff; --text-muted: #b9a9c9; --heading-font: 'Bebas Neue', 'Fredoka', sans-serif; --body-font: 'Fredoka', 'Segoe UI', sans-serif; --heading-spacing: 1px; --heading-transform: uppercase; --cell-bg: #1c1428; --board-bg: linear-gradient(135deg, rgba(243, 104, 224, 0.14), rgba(255, 45, 45, 0.12)); --input-bg: rgba(0, 0, 0, 0.35); --title-gradient: linear-gradient(45deg, #f368e0, #b06bff, #ff2d2d, #ff6a00, #f368e0); } /* ---------- Camp accents (per player) ---------- */ .camp-sparkle { --pc: var(--sparkle-color); --pg: var(--sparkle-glow); --pt: var(--sparkle-tint); } .camp-shred { --pc: var(--shred-color); --pg: var(--shred-glow); --pt: var(--shred-tint); } /* ---------- Base layout (scroll-safe centering) ---------- */ body { font-family: var(--body-font); background: var(--bg); background-size: var(--bg-size); animation: gradientShift 15s ease infinite; min-height: 100vh; display: flex; flex-direction: column; overflow-x: hidden; position: relative; padding: 28px 16px; color: var(--text); transition: color 0.4s ease; } @keyframes gradientShift { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } } .container { margin: auto; width: 100%; max-width: var(--maxw); position: relative; z-index: 1; } /* ---------- Animated backdrops ---------- */ .backdrop { position: fixed; inset: 0; pointer-events: none; z-index: 0; overflow: hidden; } .stars { position: absolute; inset: 0; opacity: 0; transition: opacity 0.6s ease; } [data-stage="sparkle"] .stars { opacity: 1; } [data-stage="mixed"] .stars { opacity: 0.5; } .stars::before, .stars::after { content: ''; position: absolute; width: 2px; height: 2px; background: white; box-shadow: 100px 200px white, 300px 100px white, 500px 300px white, 700px 150px white, 200px 400px white, 600px 450px white, 150px 50px white, 450px 250px white, 350px 500px white, 800px 400px white, 50px 300px white, 550px 50px white, 900px 250px white, 1100px 400px white, 1300px 150px white, 250px 150px rgba(255,255,255,0.6), 650px 350px rgba(255,255,255,0.6), 400px 100px rgba(255,255,255,0.6), 100px 450px rgba(255,255,255,0.6), 1000px 500px rgba(255,255,255,0.6), 1200px 300px rgba(255,255,255,0.6); border-radius: 50%; animation: twinkle 3s infinite; } .stars::after { animation-delay: 1.5s; left: 40px; top: 30px; } @keyframes twinkle { 0%, 100% { opacity: 0.3; transform: scale(1); } 50% { opacity: 1; transform: scale(1.3); } } .embers { position: absolute; inset: 0; opacity: 0; transition: opacity 0.6s ease; } [data-stage="shred"] .embers { opacity: 1; } [data-stage="mixed"] .embers { opacity: 0.7; } .embers::before, .embers::after { content: ''; position: absolute; width: 3px; height: 3px; border-radius: 50%; background: #ff6a00; box-shadow: 10vw 90vh 0 0 #ff3000, 25vw 95vh 0 1px #ff6a00, 40vw 88vh 0 0 #ff1a1a, 55vw 96vh 0 1px #ff8c00, 70vw 92vh 0 0 #ff3000, 85vw 97vh 0 1px #ff6a00, 18vw 93vh 0 0 #ffae00, 33vw 91vh 0 0 #ff1a1a, 48vw 98vh 0 1px #ff6a00, 63vw 94vh 0 0 #ff3000, 78vw 90vh 0 1px #ff8c00, 92vw 95vh 0 0 #ff1a1a, 5vw 97vh 0 0 #ffae00, 30vw 99vh 0 0 #ff3000, 60vw 89vh 0 1px #ff6a00; animation: emberRise 6s linear infinite; } .embers::after { animation-delay: 3s; animation-duration: 8s; } @keyframes emberRise { 0% { transform: translateY(0) scale(1); opacity: 0; } 10% { opacity: 1; } 90% { opacity: 0.8; } 100% { transform: translateY(-100vh) scale(0.3); opacity: 0; } } .lightning { position: absolute; inset: 0; background: #fff; opacity: 0; } [data-stage="shred"] .lightning, [data-stage="mixed"] .lightning { animation: lightningFlash 9s infinite; } @keyframes lightningFlash { 0%, 92%, 100% { opacity: 0; } 93% { opacity: 0.16; } 94% { opacity: 0; } 95% { opacity: 0.26; } 96% { opacity: 0; } } /* ---------- Cards & screens ---------- */ .screen { display: none; animation: fadeIn 0.5s ease; } .screen.active { display: block; } @keyframes fadeIn { from { opacity: 0; transform: scale(0.96) translateY(10px); } to { opacity: 1; transform: scale(1) translateY(0); } } .card { background: var(--surface); border-radius: var(--radius-lg); box-shadow: var(--card-shadow); backdrop-filter: blur(10px); border: 3px solid var(--surface-border); transition: background 0.4s ease, border-color 0.4s ease, box-shadow 0.4s ease; } .name-card { padding: 30px 30px 34px; } .game-card { padding: 36px; } .winner-card { padding: 56px 40px; text-align: center; position: relative; overflow: hidden; } /* ---------- Headings ---------- */ .title, .game-title, .winner-title { text-align: center; font-family: var(--heading-font); font-weight: 700; letter-spacing: var(--heading-spacing); text-transform: var(--heading-transform); background: var(--title-gradient); background-size: 200% 200%; -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; animation: gradientText 3s ease infinite; line-height: 1.05; } .title { font-size: 2.4em; margin-bottom: 14px; } .game-title { font-size: 2.6em; margin-bottom: 22px; } .winner-title { font-size: 3.2em; margin-bottom: 22px; } @keyframes gradientText { 0%, 100% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } } .sparkle-divider { height: 3px; background: linear-gradient(90deg, transparent, var(--accent1), var(--accent2), var(--accent1), transparent); margin: 14px 0 20px; border-radius: 10px; overflow: hidden; position: relative; } .sparkle-divider::after { content: ''; position: absolute; inset: 0; background: linear-gradient(90deg, transparent, rgba(255,255,255,0.9), transparent); animation: sparkleMove 2s linear infinite; } @keyframes sparkleMove { 0% { transform: translateX(-100%); } 100% { transform: translateX(200%); } } /* ---------- Stage selector ---------- */ .stage-selector { margin-bottom: 16px; } .stage-label, .avatar-label, .setup-hint { display: block; text-align: center; color: var(--text-muted); font-weight: 700; letter-spacing: var(--heading-spacing); } .stage-label { margin-bottom: 10px; font-size: 0.95em; } .setup-hint { margin-bottom: 18px; font-size: 0.92em; font-weight: 500; } .setup-hint strong { color: var(--text-strong); } .stage-options { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; } .stage-option { display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 14px 8px; border-radius: var(--radius-md); border: 3px solid transparent; background: var(--surface-2); color: var(--text); cursor: pointer; transition: transform var(--transition), border-color 0.25s, box-shadow 0.25s, background 0.25s; font-family: var(--body-font); } .stage-emoji { font-size: 1.8em; line-height: 1; } .stage-name { font-size: 1.15em; font-weight: 700; color: var(--text-strong); letter-spacing: var(--heading-spacing); } .stage-desc { font-size: 0.78em; color: var(--text-muted); text-align: center; } .stage-option:hover { transform: translateY(-3px); border-color: var(--accent2); } .stage-option[aria-checked="true"] { border-color: var(--accent1); background: linear-gradient(135deg, color-mix(in srgb, var(--accent1) 24%, transparent), color-mix(in srgb, var(--accent2) 18%, transparent)); box-shadow: 0 0 22px color-mix(in srgb, var(--accent1) 45%, transparent); } /* ---------- Player setup ---------- */ .players-setup { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; } .name-input-group { margin-bottom: 16px; } .name-input-group label { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; font-size: 1.15em; font-weight: 700; color: var(--text-strong); letter-spacing: var(--heading-spacing); } .player-icon { font-size: 1.4em; animation: bounce 1.4s infinite; } @keyframes bounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-5px); } } .name-input-group input { width: 100%; padding: 13px 16px; font-size: 1.05em; font-family: var(--body-font); border: 3px solid var(--accent1); border-radius: var(--radius-sm); outline: none; transition: all 0.3s ease; background: var(--input-bg); color: var(--text); } .name-input-group input::placeholder { color: var(--text-muted); } .name-input-group input:focus { border-color: var(--accent2); box-shadow: 0 0 18px color-mix(in srgb, var(--accent2) 45%, transparent); transform: scale(1.02); } .avatar-label { margin-bottom: 8px; font-size: 0.95em; } .avatar-options { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; } .avatar-option { aspect-ratio: 1; font-size: 1.55em; display: flex; align-items: center; justify-content: center; border: 2px solid var(--surface-border); border-radius: var(--radius-sm); cursor: pointer; transition: transform var(--transition), border-color 0.25s, box-shadow 0.25s, background 0.25s; background: var(--cell-bg); color: var(--text); position: relative; } /* Camp tint so the two "teams" of avatars read at a glance */ .avatar-option.camp-sparkle { background: linear-gradient(135deg, var(--sparkle-tint), var(--cell-bg)); } .avatar-option.camp-shred { background: linear-gradient(135deg, var(--shred-tint), var(--cell-bg)); } .avatar-option:hover { transform: scale(1.15); border-color: var(--pc, var(--accent2)); box-shadow: 0 0 14px var(--pg, var(--sparkle-glow)); } .avatar-option.selected { border-color: var(--pc); box-shadow: 0 0 20px var(--pg); transform: scale(1.1); } .avatar-option.selected::after { content: '✓'; position: absolute; top: -6px; right: -6px; width: 18px; height: 18px; font-size: 11px; line-height: 18px; text-align: center; border-radius: 50%; background: var(--pc); color: #fff; font-weight: 700; } .avatar-option.selected:hover { transform: scale(1.18); } /* ---------- Buttons ---------- */ .btn { font-family: var(--heading-font); font-weight: 700; letter-spacing: var(--heading-spacing); border: none; border-radius: var(--radius-md); cursor: pointer; transition: transform var(--transition), box-shadow 0.25s, background 0.25s, color 0.25s; } .btn-primary { width: 100%; padding: 15px; font-size: 1.35em; background: linear-gradient(135deg, var(--accent1), var(--accent-hot)); color: #fff; box-shadow: 0 10px 30px color-mix(in srgb, var(--accent1) 40%, transparent); margin-top: 22px; text-transform: uppercase; } .btn-primary:hover { transform: translateY(-4px) scale(1.03); box-shadow: 0 16px 40px color-mix(in srgb, var(--accent1) 55%, transparent); } .btn-primary:active { transform: translateY(-1px) scale(1.01); } .btn-ghost { flex: 1; padding: 13px; font-size: 1.05em; border: 3px solid var(--accent1); background: var(--surface-2); color: var(--text-strong); } .btn-ghost:hover { background: linear-gradient(135deg, var(--accent1), var(--accent-hot)); color: #fff; transform: translateY(-3px); box-shadow: 0 10px 20px color-mix(in srgb, var(--accent1) 40%, transparent); } .btn-tiny { padding: 8px 12px; font-size: 0.85em; background: transparent; color: var(--text-muted); border: 2px solid var(--surface-border); margin-top: 4px; } .btn-tiny:hover { color: var(--text-strong); border-color: var(--accent1); } .icon-btn { position: fixed; top: 16px; right: 16px; z-index: 50; width: 48px; height: 48px; border-radius: 50%; border: 2px solid var(--surface-border); background: var(--surface); cursor: pointer; font-size: 1.3em; display: flex; align-items: center; justify-content: center; box-shadow: 0 6px 18px rgba(0,0,0,0.25); transition: transform var(--transition), border-color 0.25s; } .icon-btn:hover { transform: scale(1.1); border-color: var(--accent1); } .icon-btn .icon-off { display: none; } .icon-btn[aria-pressed="true"] .icon-on { display: none; } .icon-btn[aria-pressed="true"] .icon-off { display: inline; } /* ---------- Game layout ---------- */ .game-layout { display: flex; gap: 28px; align-items: flex-start; } .game-area { flex: 1; min-width: 0; } .player-info { display: flex; justify-content: space-around; align-items: center; margin-bottom: 18px; gap: 16px; } .player-display { flex: 1; display: flex; flex-direction: column; align-items: center; padding: 14px 18px; border-radius: var(--radius-md); background: var(--surface-2); border: 3px solid transparent; transition: all 0.3s ease; position: relative; overflow: hidden; } .player-display.active { border-color: var(--pc, var(--accent1)); box-shadow: 0 0 26px var(--pg, var(--sparkle-glow)); animation: pulse 1.5s ease-in-out infinite; } @keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.04); } } .player-glow { position: absolute; top: -50%; left: -50%; width: 200%; height: 200%; background: radial-gradient(circle, var(--pg, var(--sparkle-glow)), transparent 70%); opacity: 0; transition: opacity 0.3s ease; } .player-display.active .player-glow { opacity: 1; animation: rotate 4s linear infinite; } @keyframes rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } .player-symbol { font-size: 2em; margin-bottom: 4px; position: relative; z-index: 1; filter: drop-shadow(0 0 6px var(--pc, transparent)); } .player-name { font-size: 1.05em; font-weight: 700; color: var(--text-strong); position: relative; z-index: 1; letter-spacing: var(--heading-spacing); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .vs { font-size: 1.4em; font-weight: 700; color: var(--text-strong); font-family: var(--heading-font); letter-spacing: var(--heading-spacing); } /* ---------- Status ---------- */ .game-status { text-align: center; font-size: 1.4em; font-weight: 700; color: var(--text-strong); min-height: 38px; margin: 8px 0 16px; letter-spacing: var(--heading-spacing); } .game-status.draw { color: var(--accent-hot); animation: pulse 0.8s ease 3; } /* ---------- Board ---------- */ .game-board { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; padding: 18px; background: var(--board-bg); border-radius: var(--radius-md); aspect-ratio: 1; max-width: 460px; margin: 0 auto; } .cell { aspect-ratio: 1; background: var(--cell-bg); border: 4px solid color-mix(in srgb, var(--accent1) 60%, transparent); border-radius: var(--radius-sm); display: flex; justify-content: center; align-items: center; font-size: clamp(2rem, 9vw, 3.4rem); cursor: pointer; transition: transform var(--transition), border-color 0.25s, box-shadow 0.25s; position: relative; overflow: hidden; font-family: var(--body-font); color: var(--text); padding: 0; } .cell::before { content: ''; position: absolute; inset: 0; background: linear-gradient(45deg, transparent, color-mix(in srgb, var(--accent1) 30%, transparent), transparent); transform: translateX(-100%); transition: transform 0.6s ease; } .cell:hover:not(.filled)::before { transform: translateX(100%); } .cell:hover:not(.filled) { transform: scale(1.08); border-color: var(--accent2); box-shadow: 0 0 18px color-mix(in srgb, var(--accent2) 45%, transparent); } .cell:focus-visible { outline: 3px solid var(--accent2); outline-offset: 3px; } .cell.filled { cursor: not-allowed; animation: cellAppear 0.35s cubic-bezier(0.34, 1.56, 0.64, 1); } /* Filled cell takes the placing player's camp color */ .cell.filled.camp-sparkle { color: var(--sparkle-color); border-color: var(--sparkle-color); box-shadow: 0 0 16px var(--sparkle-glow); } .cell.filled.camp-shred { color: var(--shred-color); border-color: var(--shred-color); box-shadow: 0 0 16px var(--shred-glow); } @keyframes cellAppear { from { transform: scale(0) rotate(180deg); opacity: 0; } to { transform: scale(1) rotate(0deg); opacity: 1; } } .cell.winning { animation: winningCell 0.6s ease infinite; color: #fff; border-color: #fff; } .cell.winning.camp-sparkle { background: linear-gradient(135deg, var(--sparkle-color), #4facfe); } .cell.winning.camp-shred { background: linear-gradient(135deg, var(--shred-color), #ff6a00); } @keyframes winningCell { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.12); } } /* ---------- Buttons row ---------- */ .button-group { display: flex; gap: 14px; margin-top: 20px; } /* ---------- Scoreboard ---------- */ .score-sidebar { width: 210px; flex-shrink: 0; background: var(--board-bg); border-radius: var(--radius-md); padding: 22px 18px; border: 2px solid var(--surface-border); display: flex; flex-direction: column; gap: 16px; } .score-title { text-align: center; font-size: 1.3em; font-weight: 700; color: var(--text-strong); font-family: var(--heading-font); letter-spacing: var(--heading-spacing); text-transform: var(--heading-transform); } .score-item { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 14px; background: var(--surface-2); border-radius: var(--radius-sm); border: 2px solid transparent; } .score-item.camp-sparkle { border-color: color-mix(in srgb, var(--sparkle-color) 40%, transparent); } .score-item.camp-shred { border-color: color-mix(in srgb, var(--shred-color) 40%, transparent); } .score-avatar { font-size: 2.6em; animation: bounce 2.4s infinite; filter: drop-shadow(0 0 6px var(--pc, transparent)); } .score-name { font-size: 0.95em; font-weight: 700; color: var(--text-strong); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; letter-spacing: var(--heading-spacing); } .score-value { font-size: 2.2em; font-weight: 700; color: var(--pc, var(--accent-hot)); padding: 6px 18px; background: var(--cell-bg); border-radius: var(--radius-sm); border: 3px solid var(--pc, var(--accent1)); min-width: 64px; text-align: center; font-family: var(--heading-font); } .score-divider { font-size: 2.2em; text-align: center; animation: rotate 4s linear infinite; } .score-value.score-update { animation: scorePop 0.5s ease; } @keyframes scorePop { 0% { transform: scale(1); } 50% { transform: scale(1.5); box-shadow: 0 0 30px currentColor; } 100% { transform: scale(1); } } /* ---------- Winner screen ---------- */ .winner-title { animation: gradientText 3s ease infinite, popIn 0.6s ease; } @keyframes popIn { from { transform: scale(0.5); opacity: 0; } to { transform: scale(1); opacity: 1; } } .trophy { font-size: 7em; margin: 10px 0; } /* Winner card carries the winner's camp; trophy reacts accordingly */ .winner-card.camp-sparkle .trophy { animation: trophyBounce 1s ease-in-out infinite; } .winner-card.camp-shred .trophy { animation: headbang 0.5s ease-in-out infinite; filter: drop-shadow(0 0 16px var(--shred-color)); } .winner-card .trophy { animation: trophyBounce 1s ease-in-out infinite; } @keyframes trophyBounce { 0%, 100% { transform: translateY(0) rotate(-5deg); } 50% { transform: translateY(-18px) rotate(5deg); } } @keyframes headbang { 0%, 100% { transform: translateY(0) rotate(-8deg) scale(1); } 50% { transform: translateY(8px) rotate(8deg) scale(1.08); } } .winner-name { font-size: 2.4em; font-weight: 700; color: var(--text-strong); margin: 18px 0 6px; font-family: var(--heading-font); letter-spacing: var(--heading-spacing); text-transform: var(--heading-transform); text-shadow: 0 0 20px var(--pg, var(--sparkle-glow)); } .winner-sub { font-size: 1.1em; color: var(--text-muted); margin-bottom: 26px; } .winner-buttons { display: flex; flex-direction: column; gap: 12px; max-width: 320px; margin: 0 auto; } .winner-buttons .btn-primary { margin-top: 0; } .winner-buttons .btn-ghost { flex: none; } .celebration { position: absolute; inset: 0; pointer-events: none; overflow: hidden; } .confetti-piece { position: absolute; top: -10%; font-size: 1.8em; animation: confettiFall linear infinite; } @keyframes confettiFall { 0% { transform: translateY(0) rotate(0deg); opacity: 1; } 100% { transform: translateY(120vh) rotate(720deg); opacity: 0.3; } } /* ---------- Particle burst (move feedback) ---------- */ .particle { position: fixed; pointer-events: none; font-size: 1.5em; z-index: 9999; animation: particleBurst 0.8s ease-out forwards; } @keyframes particleBurst { 0% { transform: translate(0, 0) scale(1) rotate(0deg); opacity: 1; } 100% { transform: translate(var(--tx), var(--ty)) scale(0) rotate(360deg); opacity: 0; } } /* ---------- Screen shake (shred move) ---------- */ .shake { animation: shake 0.25s ease; } @keyframes shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-4px); } 75% { transform: translateX(4px); } } /* ---------- Responsive ---------- */ @media (max-width: 780px) { .game-layout { flex-direction: column; } .score-sidebar { width: 100%; flex-direction: row; flex-wrap: wrap; justify-content: space-around; align-items: center; padding: 16px; } .score-title { width: 100%; } .score-item { flex: 1; min-width: 120px; } .score-divider { display: flex; align-items: center; } #resetScoresBtn { width: 100%; order: 5; } } @media (max-width: 620px) { .players-setup { grid-template-columns: 1fr; gap: 18px; } .name-card, .game-card { padding: 24px 18px; } .winner-card { padding: 40px 22px; } .title { font-size: 2em; } .game-title { font-size: 2.1em; } .winner-title { font-size: 2.4em; } .trophy { font-size: 5.5em; } .button-group { flex-direction: column; } .player-info { gap: 10px; } .vs { display: none; } .avatar-option { font-size: 1.4em; } .stage-desc { display: none; } } @media (max-width: 380px) { .stage-options { gap: 8px; } .stage-option { padding: 10px 4px; } } /* ---------- Reduced motion ---------- */ @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; } }