Files
battle-royal-tetris/public/css/style.css
T
jozamudi 4a49c76cdc Add hold piece feature
- Added holdPiece and canHold state to TetrisGame class
- Implemented hold() method to swap current piece with held piece
- Added player-hold socket event on server
- Added HOLD preview canvas showing held piece (grayed when unavailable)
- Added C key keyboard shortcut and touch button for hold
- Fixed canHold reset on piece spawn for proper swap functionality

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 08:50:52 -07:00

523 lines
7.9 KiB
CSS

* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: #1a1a2e;
color: #fff;
font-family: 'Press Start 2P', cursive;
min-height: 100vh;
overflow-x: hidden;
}
/* CRT Scanline Effect */
body::before {
content: "";
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: repeating-linear-gradient(
0deg,
rgba(0, 0, 0, 0.15),
rgba(0, 0, 0, 0.15) 1px,
transparent 1px,
transparent 2px
);
pointer-events: none;
z-index: 1000;
}
#app {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
padding: 20px;
}
.screen {
display: none;
flex-direction: column;
align-items: center;
gap: 20px;
width: 100%;
max-width: 1200px;
}
.screen.active {
display: flex;
}
h1 {
font-size: 2rem;
text-align: center;
color: #0ff;
text-shadow: 4px 4px 0 #ff00ff;
margin-bottom: 30px;
}
h2 {
font-size: 1.2rem;
color: #0f0;
text-shadow: 2px 2px 0 #004400;
}
h3 {
font-size: 1rem;
color: #ff0;
text-shadow: 2px 2px 0 #444400;
}
.form-group {
display: flex;
flex-direction: column;
gap: 10px;
margin-bottom: 15px;
}
label {
font-size: 0.7rem;
color: #888;
}
input {
background: #0a0a1a;
border: 2px solid #333;
color: #fff;
font-family: 'Press Start 2P', cursive;
font-size: 0.8rem;
padding: 15px;
text-align: center;
outline: none;
}
input:focus {
border-color: #0ff;
}
button {
background: #ff00ff;
border: 4px solid #fff;
color: #fff;
font-family: 'Press Start 2P', cursive;
font-size: 1rem;
padding: 15px 30px;
cursor: pointer;
text-transform: uppercase;
transition: transform 0.1s;
}
button:hover {
transform: scale(1.05);
background: #0ff;
color: #000;
}
button:active {
transform: scale(0.95);
}
#player-list {
display: flex;
flex-direction: column;
gap: 10px;
margin: 20px 0;
min-height: 150px;
}
.player-item {
background: #0a0a1a;
border: 2px solid #333;
padding: 15px 20px;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 0.8rem;
}
.player-item .name {
color: #0ff;
}
.player-item .status {
color: #888;
}
.player-item .status.ready {
color: #0f0;
}
/* Battle Grid - Focused Layout */
#battle-grid {
position: relative;
width: 100%;
height: 80vh;
display: flex;
justify-content: center;
align-items: center;
margin-top: 20px;
}
/* Main player board - centered and large */
.player-board.main {
position: relative;
z-index: 10;
transform: scale(1);
}
/* Spectator boards - smaller and around the edges */
.player-board.spectator {
position: absolute;
transform: scale(0.5);
opacity: 0.7;
}
.player-board.eliminated {
opacity: 0.4;
}
/* Position spectator boards around the main board */
.player-board.spectator.top-left {
top: 20px;
left: 20px;
}
.player-board.spectator.top-right {
top: 20px;
right: 20px;
}
.player-board.spectator.bottom-left {
bottom: 20px;
left: 20px;
}
.player-board.spectator.bottom-right {
bottom: 20px;
right: 20px;
}
/* Single player - just show main board */
#battle-grid.single-player {
justify-content: center;
align-items: center;
}
/* Two players - main centered, spectator to the right */
#battle-grid.two-players .spectator {
position: static;
transform: none;
opacity: 1;
margin-left: 30px;
}
#battle-grid.two-players {
display: flex;
justify-content: center;
align-items: center;
gap: 30px;
}
/* Three+ players - main centered with spectators around */
#battle-grid.multi-player {
display: flex;
justify-content: center;
align-items: center;
}
.player-board {
background: #000;
border: 4px solid #333;
padding: 10px;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
}
.player-board.main {
border-color: #0ff;
box-shadow: 0 0 30px rgba(0, 255, 255, 0.3);
}
.player-board.spectator {
border-color: #444;
}
.player-board.eliminated {
border-color: #f00;
opacity: 0.4;
}
.player-board canvas {
display: block;
image-rendering: pixelated;
image-rendering: crisp-edges;
}
.board-info {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 5px;
font-size: 0.6rem;
}
.board-info .name {
color: #0ff;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.board-info .stats {
color: #888;
}
.next-piece-container {
display: flex;
align-items: center;
gap: 5px;
}
.next-piece-container canvas {
border: 1px solid #333;
}
/* Hold and Next piece previews side by side */
.board-info:has(canvas) {
justify-content: center;
gap: 20px;
padding: 8px 5px;
}
.board-info canvas {
border: 1px solid #333;
background: #000;
}
}
#game-header {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
padding: 10px 20px;
background: #0a0a1a;
border: 2px solid #333;
margin-bottom: 20px;
}
#game-header span {
font-size: 0.8rem;
color: #0f0;
}
#game-header button {
font-size: 0.7rem;
padding: 10px 15px;
}
#game-status {
margin-top: 20px;
padding: 15px;
background: #0a0a1a;
border: 2px solid #333;
text-align: center;
font-size: 0.8rem;
color: #ff0;
}
#winner-display {
margin: 20px 0;
font-size: 1.2rem;
}
#final-scores {
display: flex;
flex-direction: column;
gap: 10px;
margin: 20px 0;
width: 100%;
max-width: 400px;
}
#final-scores .score-item {
background: #0a0a1a;
border: 2px solid #333;
padding: 10px 15px;
display: flex;
justify-content: space-between;
}
#final-scores .score-item.winner {
border-color: #0f0;
color: #0f0;
}
/* Game Over Overlay */
#gameover-screen {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.85);
z-index: 999;
display: none;
justify-content: center;
align-items: center;
}
#gameover-screen.active {
display: flex;
}
#gameover-screen h2 {
font-size: 2rem;
margin-bottom: 20px;
}
#gameover-screen h3 {
font-size: 1.5rem;
margin: 20px 0;
}
#gameover-screen #final-scores {
margin: 30px 0;
}
/* Garbage row animation */
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-5px); }
75% { transform: translateX(5px); }
}
.player-board.shake {
animation: shake 0.2s ease-in-out;
}
/* Flash effect for row clear */
@keyframes flash {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.player-board.flash {
animation: flash 0.3s ease-in-out;
}
/* Touch Controls */
#touch-controls {
display: none;
width: 100%;
max-width: 400px;
margin-top: 20px;
gap: 20px;
justify-content: center;
align-items: flex-end;
padding-bottom: 20px;
}
#touch-dpad {
display: grid;
grid-template-columns: repeat(3, 70px);
grid-template-rows: repeat(2, 70px);
gap: 8px;
}
#btn-left {
grid-column: 1;
grid-row: 2;
}
#btn-down {
grid-column: 2;
grid-row: 2;
}
#btn-right {
grid-column: 3;
grid-row: 2;
}
#touch-actions {
display: grid;
grid-template-columns: repeat(2, 70px);
grid-template-rows: repeat(2, 70px);
gap: 8px;
}
#btn-rotate {
grid-column: 1;
grid-row: 1;
}
#btn-drop {
grid-column: 2;
grid-row: 1;
}
#btn-hold {
grid-column: 1;
grid-row: 2;
}
.touch-btn {
width: 70px;
height: 70px;
font-size: 1.5rem;
background: #333;
border: 3px solid #555;
border-radius: 10px;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
}
.touch-btn:active {
background: #0ff;
color: #000;
transform: scale(0.95);
}
.touch-btn.action-btn {
background: #444;
}
.touch-btn.drop-btn {
background: #ff00ff;
border-color: #ff00ff;
}
.touch-btn.hold-btn {
background: #ff8800;
border-color: #ff8800;
font-size: 0.9rem;
}
/* Show touch controls on mobile only */
@media (max-width: 768px) and (hover: none) {
#touch-controls {
display: flex;
}
#battle-grid {
height: 60vh;
}
.player-board.spectator {
display: none;
}
}