รltimos argumentos antes de votar.
-
๐ณ๏ธ Votaciรณn secreta
+
Votaciรณn secreta
Pasa el mรณvil a Jugador. Elige 1 sospechoso(s).
@@ -162,7 +180,7 @@
-
๐ Resultados
+
Resultados
diff --git a/script.js b/script.js
index cd7c36a..05c0b74 100644
--- a/script.js
+++ b/script.js
@@ -5,6 +5,7 @@ const POOLS_CACHE_KEY = 'impostorWordPoolsV1';
const POOLS_MANIFEST_URL = 'word-pools/manifest.json';
const THEME_STORAGE_KEY = 'impostorGameTheme';
const LANGUAGE_STORAGE_KEY = 'impostorGameLanguage';
+const SCREEN_LOCK_STORAGE_KEY = 'impostorGameScreenLock';
// ---------- Internationalization system ----------
const TRANSLATIONS = {
@@ -74,7 +75,9 @@ const TRANSLATIONS = {
impostorsMustBeLess: 'Impostores debe ser menor que jugadores',
animalsNature: 'Animales y Naturaleza',
everydayObjects: 'Objetos Cotidianos',
- exitGame: 'Salir de la partida'
+ exitGame: 'Salir de la partida',
+ poolsSelection: 'Selecciรณn de Pools',
+ poolsSelectionText: 'Toca para seleccionar las categorรญas de palabras que quieres usar en la partida.'
},
en: {
gameTitle: 'The Impostor Game',
@@ -142,7 +145,9 @@ const TRANSLATIONS = {
impostorsMustBeLess: 'Impostors must be less than players',
animalsNature: 'Animals and Nature',
everydayObjects: 'Everyday Objects',
- exitGame: 'Exit Game'
+ exitGame: 'Exit Game',
+ poolsSelection: 'Pool Selection',
+ poolsSelectionText: 'Tap to select the word categories you want to use in the game.'
}
};
@@ -206,42 +211,42 @@ async function updateUI() {
function updateStaticTexts() {
// Welcome screen
const welcomeTitle = document.querySelector('.welcome-title');
- if (welcomeTitle) welcomeTitle.innerHTML = `๐ญ ${t('gameTitle')}`;
+ if (welcomeTitle) welcomeTitle.textContent = t('gameTitle');
const welcomeSubtitle = document.querySelector('.welcome-subtitle');
if (welcomeSubtitle) welcomeSubtitle.textContent = t('gameSubtitle');
const playBtn = document.querySelector('.btn-primary');
- if (playBtn) playBtn.innerHTML = `โถ๏ธ ${t('play')}`;
+ if (playBtn) playBtn.textContent = t('play');
const rulesBtn = document.querySelector('.btn-secondary');
- if (rulesBtn) rulesBtn.innerHTML = `๐ ${t('rules')}`;
+ if (rulesBtn) rulesBtn.textContent = t('rules');
const credits = document.querySelector('.welcome-credits');
if (credits) credits.textContent = t('createdBy');
// Rules screen
const rulesTitle = document.querySelector('#rules-screen h1');
- if (rulesTitle) rulesTitle.innerHTML = `๐ ${t('rulesTitle')}`;
+ if (rulesTitle) rulesTitle.textContent = t('rulesTitle');
const ruleSections = document.querySelectorAll('.rule-section');
if (ruleSections.length >= 4) {
- ruleSections[0].querySelector('h3').innerHTML = `๐ฏ ${t('objective')}`;
+ ruleSections[0].querySelector('h3').textContent = t('objective');
ruleSections[0].querySelector('p').innerHTML = t('objectiveText');
- ruleSections[1].querySelector('h3').innerHTML = `๐ฒ ${t('preparation')}`;
+ ruleSections[1].querySelector('h3').textContent = t('preparation');
const prepSteps = t('preparationSteps');
ruleSections[1].querySelectorAll('p').forEach((p, i) => {
if (prepSteps[i]) p.textContent = `${i + 1}. ${prepSteps[i]}`;
});
- ruleSections[2].querySelector('h3').innerHTML = `๐ฃ๏ธ ${t('gameplay')}`;
+ ruleSections[2].querySelector('h3').textContent = t('gameplay');
const gameSteps = t('gameplaySteps');
ruleSections[2].querySelectorAll('p').forEach((p, i) => {
if (gameSteps[i]) p.textContent = `${i + 1}. ${gameSteps[i]}`;
});
- ruleSections[3].querySelector('h3').innerHTML = `๐ณ๏ธ ${t('voting')}`;
+ ruleSections[3].querySelector('h3').textContent = t('voting');
const voteSteps = t('votingSteps');
ruleSections[3].querySelectorAll('p').forEach((p, i) => {
if (voteSteps[i]) p.textContent = `${i + 1}. ${voteSteps[i]}`;
@@ -250,7 +255,7 @@ function updateStaticTexts() {
// Setup screen
const setupTitle = document.querySelector('#setup-screen h1');
- if (setupTitle) setupTitle.innerHTML = `โ๏ธ ${t('configuration')}`;
+ if (setupTitle) setupTitle.textContent = t('configuration');
const labels = {
'num-players': t('players'),
@@ -264,45 +269,49 @@ function updateStaticTexts() {
if (label) label.textContent = text + ':';
});
- const poolsLabel = document.querySelector('#setup-screen .form-group:last-of-type label');
- if (poolsLabel) poolsLabel.textContent = t('pools') + ':';
+ // Pools screen
+ const poolsTitle = document.querySelector('#pools-screen h1');
+ if (poolsTitle) poolsTitle.textContent = t('poolsSelection');
+
+ const poolsText = document.querySelector('#pools-screen .info-text');
+ if (poolsText) poolsText.textContent = t('poolsSelectionText');
// Names screen
const namesTitle = document.querySelector('#names-screen h1');
- if (namesTitle) namesTitle.innerHTML = `๐ฅ ${t('playerNames')}`;
+ if (namesTitle) namesTitle.textContent = t('playerNames');
// Pre-reveal screen
const preRevealTitle = document.querySelector('#pre-reveal-screen h1');
- if (preRevealTitle) preRevealTitle.innerHTML = `๐ฒ ${t('readyToReveal')}`;
+ if (preRevealTitle) preRevealTitle.textContent = t('readyToReveal');
const preRevealText = document.querySelector('#pre-reveal-screen .info-text:not(#config-summary)');
if (preRevealText) preRevealText.textContent = t('eachPlayerSecret');
// Reveal screen
const revealTitle = document.querySelector('#reveal-screen h1');
- if (revealTitle) revealTitle.innerHTML = `๐ ${t('revelation')}`;
+ if (revealTitle) revealTitle.textContent = t('revelation');
// Game screen
const gameTitle = document.querySelector('#game-screen h1');
- if (gameTitle) gameTitle.innerHTML = `๐ฎ ${t('gameInProgress')}`;
+ if (gameTitle) gameTitle.textContent = t('gameInProgress');
const gameText = document.querySelector('#game-screen .info-text');
if (gameText) gameText.textContent = t('giveSynonyms');
// Deliberation screen
const delibTitle = document.querySelector('#deliberation-screen h1');
- if (delibTitle) delibTitle.innerHTML = `๐ฃ๏ธ ${t('deliberation')}`;
+ if (delibTitle) delibTitle.textContent = t('deliberation');
const delibText = document.querySelector('#deliberation-screen .info-text');
if (delibText) delibText.textContent = t('lastArguments');
// Voting screen
const votingTitle = document.querySelector('#voting-screen h1');
- if (votingTitle) votingTitle.innerHTML = `๐ณ๏ธ ${t('secretVoting')}`;
+ if (votingTitle) votingTitle.textContent = t('secretVoting');
// Results screen
const resultsTitle = document.querySelector('#results-screen h1');
- if (resultsTitle) resultsTitle.innerHTML = `๐ ${t('results')}`;
+ if (resultsTitle) resultsTitle.textContent = t('results');
// Buttons
const backButtons = document.querySelectorAll('button.ghost');
@@ -314,7 +323,8 @@ function updateStaticTexts() {
// Update all other buttons based on their onclick or content
document.querySelectorAll('button').forEach(btn => {
- if (btn.getAttribute('onclick') === 'goToNames()') btn.textContent = t('next');
+ if (btn.getAttribute('onclick') === 'goToPools()') btn.textContent = t('next');
+ else if (btn.getAttribute('onclick') === 'goToNames()') btn.textContent = t('next');
else if (btn.getAttribute('onclick') === 'startGame()') btn.textContent = t('startGame');
else if (btn.getAttribute('onclick') === "showScreen('reveal-screen'); loadCurrentReveal();") btn.textContent = t('startReveal');
else if (btn.id === 'next-player-btn') btn.textContent = t('nextPlayer') + ' โ';
@@ -561,7 +571,7 @@ function renderPoolButtons() {
}
// ---------- Setup and player names ----------
-function goToNames() {
+function goToPools() {
let nPlayers = parseInt(document.getElementById('num-players').value) || MIN_PLAYERS;
nPlayers = Math.min(Math.max(nPlayers, MIN_PLAYERS), MAX_PLAYERS);
const maxImpostors = Math.max(1, Math.floor(nPlayers / 2));
@@ -572,7 +582,14 @@ function goToNames() {
let dTime = parseInt(document.getElementById('deliberation-time').value) || defaultDeliberation(gTime);
dTime = Math.min(Math.max(dTime, 30), Math.round(900 / 3));
if (nImpostors >= nPlayers) { alert(t('impostorsMustBeLess')); return; }
- state.numPlayers = nPlayers; state.numImpostors = nImpostors; state.gameTime = gTime; state.deliberationTime = dTime;
+ state.numPlayers = nPlayers;
+ state.numImpostors = nImpostors;
+ state.gameTime = gTime;
+ state.deliberationTime = dTime;
+ showScreen('pools-screen');
+}
+
+function goToNames() {
buildNameInputs();
showScreen('names-screen');
}
@@ -662,6 +679,10 @@ function renderSummary() {
// ---------- Role revelation ----------
function loadCurrentReveal() {
state.phase = 'reveal'; saveState();
+
+ // Activar Wake Lock para mantener pantalla encendida durante el juego
+ requestWakeLock();
+
if (!state.revealOrder || state.revealOrder.length !== state.numPlayers) {
const step = state.turnDirection === 'horario' ? 1 : -1;
state.revealOrder = Array.from({length: state.numPlayers}, (_, k) => (state.startPlayer + step * k + state.numPlayers) % state.numPlayers);
@@ -716,13 +737,17 @@ function nextReveal() { state.currentReveal++; saveState(); loadCurrentReveal();
// Curtain system with GRAVITY - The curtain always tends to fall
// Supports both touch (mobile) and mouse (desktop)
+// On desktop: curtain stays up while mouse button is held, even if cursor leaves the area
let curtainState = { isRevealed: false };
+let curtainDragState = {
+ startY: null,
+ isDragging: false,
+ currentTranslateY: 0
+};
-(() => {
+function initCurtainHandlers() {
const curtain = document.getElementById('curtain');
- const cover = document.getElementById('curtain-cover');
- let startY = null;
- let isDragging = false;
+ if (!curtain) return;
// Function to get Y position from event (touch or mouse)
const getY = (e) => {
@@ -731,9 +756,9 @@ let curtainState = { isRevealed: false };
// Start function (touch and mouse)
const handleStart = (e) => {
- const coverEl = document.getElementById('curtain-cover');
- startY = getY(e);
- isDragging = true;
+ curtainDragState.startY = getY(e);
+ curtainDragState.isDragging = true;
+ curtainDragState.currentTranslateY = 0;
if (e.type === 'mousedown') {
e.preventDefault(); // Prevent text selection on desktop
}
@@ -741,21 +766,22 @@ let curtainState = { isRevealed: false };
// Move function (touch and mouse)
const handleMove = (e) => {
- if (startY === null || !isDragging) return;
+ if (curtainDragState.startY === null || !curtainDragState.isDragging) return;
const currentY = getY(e);
- const dy = currentY - startY;
+ const dy = currentY - curtainDragState.startY;
const coverEl = document.getElementById('curtain-cover');
+ if (!coverEl) return;
// Calculate displacement: negative = up, positive = down
- // Limit upward movement (not beyond curtain height)
- // and don't allow going below initial position (0)
- const translateY = Math.max(Math.min(dy, 0), -cover.offsetHeight);
+ // Allow going further up than the curtain height (user can keep dragging up)
+ // but don't allow going below initial position (0)
+ curtainDragState.currentTranslateY = Math.min(dy, 0);
- coverEl.style.transform = `translateY(${translateY}px)`;
+ coverEl.style.transform = `translateY(${curtainDragState.currentTranslateY}px)`;
coverEl.style.transition = 'none';
// If lifted enough, show content
- if (translateY < -80 && !curtainState.isRevealed) {
+ if (curtainDragState.currentTranslateY < -80 && !curtainState.isRevealed) {
curtainState.isRevealed = true;
const idx = state.revealOrder[state.currentReveal];
const role = state.roles[idx];
@@ -766,15 +792,14 @@ let curtainState = { isRevealed: false };
document.getElementById('word-text').textContent = word;
}
- if (e.type === 'mousemove') {
- e.preventDefault(); // Prevent selection on desktop
- }
+ e.preventDefault(); // Prevent selection
};
// End function (touch and mouse)
const handleEnd = (e) => {
- if (!isDragging || startY === null) return;
+ if (!curtainDragState.isDragging || curtainDragState.startY === null) return;
const coverEl = document.getElementById('curtain-cover');
+ if (!coverEl) return;
// ALWAYS bring the curtain down when released (GRAVITY)
coverEl.style.transition = 'transform 0.4s ease';
@@ -791,32 +816,126 @@ let curtainState = { isRevealed: false };
}, 400);
}
- startY = null;
- isDragging = false;
+ curtainDragState.startY = null;
+ curtainDragState.isDragging = false;
+ curtainDragState.currentTranslateY = 0;
};
// Touch events (mobile)
- curtain.addEventListener('touchstart', handleStart, {passive:true});
- curtain.addEventListener('touchmove', handleMove, {passive:true});
- curtain.addEventListener('touchend', handleEnd, {passive:true});
- curtain.addEventListener('touchcancel', handleEnd, {passive:true});
+ curtain.addEventListener('touchstart', handleStart, {passive: false});
+ curtain.addEventListener('touchmove', handleMove, {passive: false});
+ curtain.addEventListener('touchend', handleEnd, {passive: true});
+ curtain.addEventListener('touchcancel', handleEnd, {passive: true});
- // Mouse events (desktop)
+ // Mouse events (desktop) - start on curtain only
curtain.addEventListener('mousedown', handleStart);
- curtain.addEventListener('mousemove', handleMove);
- curtain.addEventListener('mouseup', handleEnd);
- curtain.addEventListener('mouseleave', (e) => {
- // If mouse leaves area while dragging, release (gravity)
- if (isDragging) {
- handleEnd(e);
+
+ // Mouse move and up events on WINDOW so we can track even when cursor leaves everything
+ window.addEventListener('mousemove', handleMove);
+ window.addEventListener('mouseup', handleEnd);
+}
+
+// Initialize curtain handlers when DOM is ready
+if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', initCurtainHandlers);
+} else {
+ initCurtainHandlers();
+}
+
+// ---------- Screen Wake Lock (prevent screen from sleeping during timers) ----------
+let wakeLock = null;
+let wakeLockVideo = null; // For iOS workaround
+
+// Detect if device is iOS
+function isIOS() {
+ return /iPad|iPhone|iPod/.test(navigator.userAgent) ||
+ (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
+}
+
+// Check if screen lock is enabled in settings
+function isScreenLockEnabled() {
+ const saved = localStorage.getItem(SCREEN_LOCK_STORAGE_KEY);
+ return saved === null ? true : saved === 'true'; // Default enabled
+}
+
+// Save screen lock preference
+function setScreenLockEnabled(enabled) {
+ localStorage.setItem(SCREEN_LOCK_STORAGE_KEY, enabled.toString());
+ updateScreenLockButton();
+}
+
+async function requestWakeLock() {
+ if (!isScreenLockEnabled()) return;
+
+ // Try native Wake Lock API first (works on Android Chrome, etc.)
+ if ('wakeLock' in navigator) {
+ try {
+ wakeLock = await navigator.wakeLock.request('screen');
+ wakeLock.addEventListener('release', () => {
+ wakeLock = null;
+ });
+ console.log('Wake Lock activated (native API)');
+ return;
+ } catch (err) {
+ console.log('Wake lock request failed:', err);
}
- });
-})();
+ }
+
+ // Fallback for iOS - use hidden video loop
+ if (isIOS() && !wakeLockVideo) {
+ try {
+ wakeLockVideo = document.createElement('video');
+ wakeLockVideo.setAttribute('playsinline', '');
+ wakeLockVideo.setAttribute('muted', '');
+ wakeLockVideo.style.position = 'fixed';
+ wakeLockVideo.style.opacity = '0';
+ wakeLockVideo.style.pointerEvents = 'none';
+ wakeLockVideo.style.width = '1px';
+ wakeLockVideo.style.height = '1px';
+
+ // Minimal base64 encoded video (1 frame, silent)
+ wakeLockVideo.src = 'data:video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAAAu1tZGF0AAACrQYF//+p3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE1NSByMjkwMSA3ZDBmZjIyIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxOCAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTMgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MzoweDExMyBtZT1oZXggc3VibWU9NyBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0xIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MSA4eDhkY3Q9MSBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0tMiB0aHJlYWRzPTMgbG9va2FoZWFkX3RocmVhZHM9MSBzbGljZWRfdGhyZWFkcz0wIG5yPTAgZGVjaW1hdGU9MSBpbnRlcmxhY2VkPTAgYmx1cmF5X2NvbXBhdD0wIGNvbnN0cmFpbmVkX2ludHJhPTAgYmZyYW1lcz0zIGJfcHlyYW1pZD0yIGJfYWRhcHQ9MSBiX2JpYXM9MCBkaXJlY3Q9MSB3ZWlnaHRiPTEgb3Blbl9nb3A9MCB3ZWlnaHRwPTIga2V5aW50PTI1MCBrZXlpbnRfbWluPTI1IHNjZW5lY3V0PTQwIGludHJhX3JlZnJlc2g9MCByY19sb29rYWhlYWQ9NDAgcmM9Y3JmIG1idHJlZT0xIGNyZj0yMy4wIHFjb21wPTAuNjAgcXBtaW49MCBxcG1heD02OSBxcHN0ZXA9NCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAwWWIhAAz//727L4FNf2f0JcRLMXaSnA+KqSAgHc0wAAAAwAAAwAAJuKiZ0WFMeJsgAAAHGAFBCwCPCVC';
+ wakeLockVideo.loop = true;
+
+ document.body.appendChild(wakeLockVideo);
+ await wakeLockVideo.play();
+ console.log('Wake Lock activated (iOS video workaround)');
+ } catch (err) {
+ console.log('iOS wake lock workaround failed:', err);
+ }
+ }
+}
+
+function releaseWakeLock() {
+ // Release native Wake Lock
+ if (wakeLock) {
+ wakeLock.release();
+ wakeLock = null;
+ }
+
+ // Stop iOS video workaround
+ if (wakeLockVideo) {
+ wakeLockVideo.pause();
+ wakeLockVideo.remove();
+ wakeLockVideo = null;
+ }
+}
+
+// Re-request wake lock when page becomes visible again
+document.addEventListener('visibilitychange', async () => {
+ if (document.visibilityState === 'visible' && (wakeLock !== null || wakeLockVideo !== null)) {
+ await requestWakeLock();
+ }
+});
// ---------- Timers ----------
let timerInterval = null;
-function startPhaseTimer(phase, seconds, elementId, onEnd) {
+async function startPhaseTimer(phase, seconds, elementId, onEnd) {
if (timerInterval) clearInterval(timerInterval);
+
+ // Request wake lock to keep screen on during timer
+ await requestWakeLock();
+
const now = Date.now();
state.timerPhase = phase;
state.timerEndAt = now + seconds*1000;
@@ -825,7 +944,12 @@ function startPhaseTimer(phase, seconds, elementId, onEnd) {
const tick = () => {
const remaining = Math.max(0, Math.round((state.timerEndAt - Date.now())/1000));
updateTimerDisplay(el, remaining);
- if (remaining <= 0) { clearInterval(timerInterval); playBeep(); onEnd(); }
+ if (remaining <= 0) {
+ clearInterval(timerInterval);
+ releaseWakeLock(); // Release wake lock when timer ends
+ playBeep();
+ onEnd();
+ }
};
tick();
timerInterval = setInterval(tick, 1000);
@@ -847,17 +971,48 @@ function updateTimerDisplay(el, remaining) {
}
function playBeep() {
+ // Play alarm sound - 3 ascending beeps pattern repeated twice
const ctx = new (window.AudioContext || window.webkitAudioContext)();
- const osc = ctx.createOscillator(); const gain = ctx.createGain();
- osc.connect(gain); gain.connect(ctx.destination); osc.frequency.value = 820; osc.type = 'sine';
- gain.gain.setValueAtTime(0.3, ctx.currentTime); gain.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.45);
- osc.start(); osc.stop(ctx.currentTime + 0.45);
+ const now = ctx.currentTime;
+
+ // Frequencies for alarm pattern (ascending)
+ const frequencies = [523, 659, 784]; // C5, E5, G5
+ const beepDuration = 0.15;
+ const gapDuration = 0.08;
+ const patternGap = 0.3;
+
+ let time = now;
+
+ // Play pattern twice
+ for (let pattern = 0; pattern < 2; pattern++) {
+ for (let i = 0; i < frequencies.length; i++) {
+ const osc = ctx.createOscillator();
+ const gain = ctx.createGain();
+
+ osc.connect(gain);
+ gain.connect(ctx.destination);
+ osc.frequency.value = frequencies[i];
+ osc.type = 'square'; // More alarm-like sound
+
+ gain.gain.setValueAtTime(0, time);
+ gain.gain.linearRampToValueAtTime(0.25, time + 0.02);
+ gain.gain.setValueAtTime(0.25, time + beepDuration - 0.02);
+ gain.gain.linearRampToValueAtTime(0, time + beepDuration);
+
+ osc.start(time);
+ osc.stop(time + beepDuration);
+
+ time += beepDuration + gapDuration;
+ }
+ time += patternGap;
+ }
}
// ---------- Game phases ----------
function startGamePhase() { state.phase = 'game'; saveState(); showScreen('game-screen'); startPhaseTimer('game', state.gameTime, 'game-timer', startDeliberationPhase); }
function startDeliberationPhase() { state.phase = 'deliberation'; saveState(); showScreen('deliberation-screen'); startPhaseTimer('deliberation', state.deliberationTime, 'deliberation-timer', startVotingPhase); }
function startVotingPhase(candidates = null, isTiebreak = false) {
+ releaseWakeLock(); // Release wake lock when voting starts (no timer)
state.phase = 'voting';
state.votingPlayer = 0;
state.votes = {};
@@ -868,8 +1023,8 @@ function startVotingPhase(candidates = null, isTiebreak = false) {
renderVoting();
showScreen('voting-screen');
}
-function skipToDeliberation() { if (timerInterval) clearInterval(timerInterval); startDeliberationPhase(); }
-function skipToVoting() { if (timerInterval) clearInterval(timerInterval); startVotingPhase(); }
+function skipToDeliberation() { if (timerInterval) clearInterval(timerInterval); releaseWakeLock(); startDeliberationPhase(); }
+function skipToVoting() { if (timerInterval) clearInterval(timerInterval); releaseWakeLock(); startVotingPhase(); }
function startTiebreakDeliberation(candidates) {
state.phase = 'deliberation';
state.tiebreakCandidates = candidates;
@@ -896,16 +1051,22 @@ function renderVoting() {
pool.forEach(i => {
const item = document.createElement('div');
item.className = 'player-item';
+
+ // Marcar como disabled ANTES de aรฑadir al DOM para que la animaciรณn correcta se aplique
+ if (i === state.votingPlayer) {
+ item.classList.add('disabled');
+ // NO aplicar opacity inline - dejamos que CSS lo maneje con la animaciรณn
+ item.style.pointerEvents = 'none';
+ }
+
item.textContent = state.playerNames[i];
if (state.votes[i]) item.innerHTML += `
${t('votes')}: ${state.votes[i]}`;
if (state.selections.includes(i)) item.classList.add('selected');
- if (i === state.votingPlayer) {
- item.classList.add('disabled');
- item.style.opacity = '0.5';
- item.style.pointerEvents = 'none';
- } else {
- item.onclick = () => toggleSelection(i, item);
- }
+
+ if (i !== state.votingPlayer) {
+ item.onclick = () => toggleSelection(i, item);
+ }
+
list.appendChild(item);
});
updateConfirmButton();
@@ -973,6 +1134,10 @@ function handleVoteOutcome() {
// ---------- Results ----------
function showResults(isTiebreak = false) {
state.phase = 'results'; saveState();
+
+ // Liberar Wake Lock cuando termina la partida
+ releaseWakeLock();
+
const executed = state.executed || [];
let impostorsAlive = 0;
state.roles.forEach((r,i) => { if (r === 'IMPOSTOR' && !executed.includes(i)) impostorsAlive++; });
@@ -1005,6 +1170,8 @@ function showScreen(id) {
function newMatch() {
clearState();
+ releaseWakeLock(); // Make sure wake lock is released when exiting game
+ if (timerInterval) clearInterval(timerInterval);
state = { ...state, phase:'welcome', timerEndAt:null, timerPhase:null, votingPool:null, isTiebreak:false, tiebreakCandidates:[] };
saveState();
showScreen('welcome-screen');
@@ -1023,14 +1190,20 @@ function confirmExitGame() {
function updateExitButtonVisibility() {
const exitBtn = document.getElementById('exit-game');
const langBtn = document.getElementById('language-toggle');
+ const screenLockBtn = document.getElementById('screen-lock-toggle');
- // Show exit button and hide language toggle in all phases except welcome and setup
+ // Show exit button and hide language/screen-lock toggles in all phases except welcome and setup
if (state.phase !== 'welcome' && state.phase !== 'setup') {
exitBtn.classList.add('visible');
if (langBtn) langBtn.style.display = 'none';
+ if (screenLockBtn) screenLockBtn.classList.remove('visible');
} else {
exitBtn.classList.remove('visible');
if (langBtn) langBtn.style.display = 'inline-flex';
+ // Only show screen lock button on iOS
+ if (screenLockBtn && isIOS()) {
+ screenLockBtn.classList.add('visible');
+ }
}
}
@@ -1067,6 +1240,35 @@ function toggleTheme() {
const initialTheme = loadTheme();
applyTheme(initialTheme);
+// ---------- Screen Lock Button ----------
+function updateScreenLockButton() {
+ const btn = document.getElementById('screen-lock-toggle');
+ if (!btn) return;
+
+ const enabled = isScreenLockEnabled();
+ const icon = btn.querySelector('.screen-lock-icon');
+
+ if (enabled) {
+ btn.classList.add('active');
+ btn.setAttribute('title', 'Bloqueo de pantalla activado');
+ if (icon) icon.textContent = '๐';
+ } else {
+ btn.classList.remove('active');
+ btn.setAttribute('title', 'Bloqueo de pantalla desactivado');
+ if (icon) icon.textContent = '๐';
+ }
+}
+
+function toggleScreenLock() {
+ const currentState = isScreenLockEnabled();
+ setScreenLockEnabled(!currentState);
+
+ // If disabling, release any active wake lock
+ if (currentState) {
+ releaseWakeLock();
+ }
+}
+
// Event listener for theme and language buttons
document.addEventListener('DOMContentLoaded', () => {
const themeToggle = document.getElementById('theme-toggle');
@@ -1079,6 +1281,12 @@ document.addEventListener('DOMContentLoaded', () => {
languageToggle.addEventListener('click', toggleLanguage);
}
+ const screenLockToggle = document.getElementById('screen-lock-toggle');
+ if (screenLockToggle) {
+ screenLockToggle.addEventListener('click', toggleScreenLock);
+ updateScreenLockButton();
+ }
+
// Initialize language
currentLanguage = loadLanguage();
setLanguage(currentLanguage);
@@ -1133,4 +1341,7 @@ document.addEventListener('DOMContentLoaded', () => {
// Initialize exit button visibility
updateExitButtonVisibility();
+
+ // Initialize screen lock button for iOS
+ initScreenLockButton();
})();
diff --git a/styles.css b/styles.css
index 499ffa5..8e4ebaf 100644
--- a/styles.css
+++ b/styles.css
@@ -1,203 +1,526 @@
-/* Theme variables */
+/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ EXPEDIENTE CLASIFICADO - IMPOSTOR GAME
+ Noir Cyberpunk Interrogation Aesthetic
+ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+@import url('https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Special+Elite&display=swap');
+
:root {
- /* Light theme (default) */
- --bg-gradient-start: #667eea;
- --bg-gradient-end: #764ba2;
- --container-bg: rgba(255, 255, 255, 0.15);
- --container-border: rgba(255, 255, 255, 0.2);
- --text-primary: #ffffff;
- --text-secondary: rgba(255, 255, 255, 0.85);
- --text-tertiary: rgba(255, 255, 255, 0.7);
- --input-bg: rgba(255, 255, 255, 0.95);
- --input-text: #2d3748;
- --input-focus: #f5576c;
- --button-gradient-start: #f093fb;
- --button-gradient-end: #f5576c;
- --button-secondary-start: #a8edea;
- --button-secondary-end: #fed6e3;
- --button-ghost-bg: rgba(255, 255, 255, 0.15);
- --card-bg: rgba(255, 255, 255, 0.18);
- --card-hover: rgba(255, 255, 255, 0.25);
- --border-color: rgba(255, 255, 255, 0.25);
- --shadow-color: rgba(31, 38, 135, 0.37);
- --info-bg: rgba(0, 0, 0, 0.2);
- --curtain-bg: #2d3748;
- --pool-gradient: rgba(102, 126, 234, 0.4);
+ /* LIGHT THEME: Interrogation Room */
+ --bg-primary: #dcd9d2;
+ --bg-secondary: #c8c3b8;
+ --bg-overlay: rgba(0, 0, 0, 0.05);
+
+ --surface-glass: rgba(255, 255, 255, 0.85);
+ --surface-card: rgba(255, 255, 255, 0.95);
+ --surface-hover: rgba(255, 255, 255, 1);
+
+ --text-primary: #0a0a0a;
+ --text-secondary: #2a2a2a;
+ --text-tertiary: #5a5a5a;
+ --text-inverted: #ffffff;
+
+ --accent-warning: #e6a73c;
+ --accent-danger: #d93626;
+ --accent-success: #2d8b3d;
+ --accent-info: #2e4e7a;
+
+ --border-light: rgba(0, 0, 0, 0.18);
+ --border-medium: rgba(0, 0, 0, 0.35);
+ --border-heavy: rgba(0, 0, 0, 0.55);
+
+ --shadow-sm: 0 3px 12px rgba(0, 0, 0, 0.15);
+ --shadow-md: 0 6px 24px rgba(0, 0, 0, 0.22);
+ --shadow-lg: 0 12px 48px rgba(0, 0, 0, 0.28);
+ --shadow-harsh: 6px 6px 0px rgba(0, 0, 0, 0.25);
+
+ --grain-opacity: 0.05;
+ --scanline-opacity: 0.025;
+
+ /* Spotlight effect */
+ --spotlight-color: rgba(255, 235, 180, 0.08);
+ --vignette-intensity: 0.4;
}
-/* Dark theme */
[data-theme="dark"] {
- --bg-gradient-start: #1a1a2e;
- --bg-gradient-end: #16213e;
- --container-bg: rgba(30, 30, 50, 0.85);
- --container-border: rgba(255, 255, 255, 0.1);
- --text-primary: #e0e0e0;
- --text-secondary: rgba(224, 224, 224, 0.85);
- --text-tertiary: rgba(224, 224, 224, 0.6);
- --input-bg: rgba(40, 40, 60, 0.9);
- --input-text: #e0e0e0;
- --input-focus: #ff6b9d;
- --button-gradient-start: #c850c0;
- --button-gradient-end: #ff6b9d;
- --button-secondary-start: #4158d0;
- --button-secondary-end: #c850c0;
- --button-ghost-bg: rgba(255, 255, 255, 0.08);
- --card-bg: rgba(60, 60, 80, 0.5);
- --card-hover: rgba(80, 80, 100, 0.6);
- --border-color: rgba(255, 255, 255, 0.15);
- --shadow-color: rgba(0, 0, 0, 0.5);
- --info-bg: rgba(0, 0, 0, 0.4);
- --curtain-bg: #1a1a2e;
- --pool-gradient: rgba(30, 30, 50, 0.6);
+ /* DARK THEME: Night Investigation */
+ --bg-primary: #050505;
+ --bg-secondary: #0f0f0f;
+ --bg-overlay: rgba(255, 255, 255, 0.03);
+
+ --surface-glass: rgba(25, 25, 25, 0.9);
+ --surface-card: rgba(35, 35, 35, 0.95);
+ --surface-hover: rgba(45, 45, 45, 1);
+
+ --text-primary: #f5f5f5;
+ --text-secondary: #d0d0d0;
+ --text-tertiary: #909090;
+ --text-inverted: #0a0a0a;
+
+ --accent-warning: #ffb84d;
+ --accent-danger: #ff3d2e;
+ --accent-success: #3dd46b;
+ --accent-info: #4d8ce0;
+
+ --border-light: rgba(255, 255, 255, 0.12);
+ --border-medium: rgba(255, 255, 255, 0.22);
+ --border-heavy: rgba(255, 255, 255, 0.35);
+
+ --shadow-sm: 0 3px 12px rgba(0, 0, 0, 0.6);
+ --shadow-md: 0 6px 24px rgba(0, 0, 0, 0.8);
+ --shadow-lg: 0 12px 48px rgba(0, 0, 0, 0.95);
+ --shadow-harsh: 6px 6px 0px rgba(0, 0, 0, 0.7);
+
+ --grain-opacity: 0.07;
+ --scanline-opacity: 0.035;
+
+ /* Spotlight effect */
+ --spotlight-color: rgba(255, 200, 100, 0.04);
+ --vignette-intensity: 0.6;
+}
+
+/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ BASE STYLES & TYPOGRAPHY
+ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+ -webkit-tap-highlight-color: transparent;
}
-/* Mobile styles and main UI */
-* { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
body {
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
- background: linear-gradient(135deg, var(--bg-gradient-start) 0%, var(--bg-gradient-end) 100%);
+ font-family: 'JetBrains Mono', 'Courier Prime', 'Courier New', monospace;
+ background:
+ radial-gradient(ellipse 80% 50% at 50% 20%, var(--spotlight-color) 0%, transparent 50%),
+ radial-gradient(circle at 20% 30%, rgba(230, 167, 60, 0.08) 0%, transparent 40%),
+ radial-gradient(circle at 80% 70%, rgba(217, 54, 38, 0.06) 0%, transparent 40%),
+ var(--bg-primary);
min-height: 100vh;
+ min-height: 100dvh;
display: flex;
justify-content: center;
- align-items: flex-start;
- padding: 80px 10px 10px 10px;
+ align-items: center;
+ padding: 70px 16px 16px;
color: var(--text-primary);
- transition: background 0.3s ease;
+ position: relative;
+ overflow: hidden;
+ font-size: 14px;
+ letter-spacing: 0px;
+ transition: background 0.5s ease, color 0.3s ease;
}
+
+/* Film grain texture overlay */
+body::before {
+ content: '';
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 400 400' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.5'/%3E%3C/svg%3E");
+ opacity: var(--grain-opacity);
+ pointer-events: none;
+ z-index: 9999;
+ mix-blend-mode: overlay;
+ animation: grain 8s steps(10) infinite;
+}
+
+@keyframes grain {
+ 0%, 100% { transform: translate(0, 0); }
+ 10% { transform: translate(-5%, -10%); }
+ 20% { transform: translate(-15%, 5%); }
+ 30% { transform: translate(7%, -25%); }
+ 40% { transform: translate(-5%, 25%); }
+ 50% { transform: translate(-15%, 10%); }
+ 60% { transform: translate(15%, 0%); }
+ 70% { transform: translate(0%, 15%); }
+ 80% { transform: translate(3%, 35%); }
+ 90% { transform: translate(-10%, 10%); }
+}
+
+/* Scanlines */
+body::after {
+ content: '';
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: repeating-linear-gradient(
+ 0deg,
+ transparent,
+ transparent 2px,
+ rgba(0, 0, 0, 0.1) 2px,
+ rgba(0, 0, 0, 0.1) 4px
+ );
+ opacity: var(--scanline-opacity);
+ pointer-events: none;
+ z-index: 9998;
+}
+
+/* Dramatic vignette overlay */
+.vignette-overlay {
+ position: fixed;
+ inset: 0;
+ background: radial-gradient(ellipse at center, transparent 40%, rgba(0,0,0,var(--vignette-intensity)) 100%);
+ pointer-events: none;
+ z-index: 9997;
+}
+
+/* VHS interference effect */
+@keyframes vhsInterference {
+ 0%, 100% { opacity: 0; }
+ 5% { opacity: 0.03; transform: translateX(-2px); }
+ 10% { opacity: 0; }
+ 15% { opacity: 0.02; transform: translateX(1px); }
+ 20% { opacity: 0; }
+}
+
+.vhs-line {
+ position: fixed;
+ left: 0;
+ width: 100%;
+ height: 3px;
+ background: linear-gradient(90deg, transparent, rgba(255,255,255,0.8), transparent);
+ pointer-events: none;
+ z-index: 9996;
+ animation: vhsScan 8s linear infinite;
+ opacity: 0.04;
+}
+
+@keyframes vhsScan {
+ 0% { top: -10px; }
+ 100% { top: 110%; }
+}
+
+h1 {
+ font-family: 'Bebas Neue', 'Crimson Text', Georgia, serif;
+ text-align: center;
+ margin-bottom: 20px;
+ font-size: 2.6em;
+ font-weight: 400;
+ letter-spacing: 4px;
+ text-transform: uppercase;
+ position: relative;
+ text-shadow: 3px 3px 0px var(--bg-secondary), 0 0 30px rgba(230, 167, 60, 0.2);
+ line-height: 1.1;
+ animation: titleReveal 0.6s cubic-bezier(0.22, 1, 0.36, 1) forwards;
+}
+
+@keyframes titleReveal {
+ from {
+ opacity: 0;
+ letter-spacing: 20px;
+ filter: blur(8px);
+ }
+ to {
+ opacity: 1;
+ letter-spacing: 4px;
+ filter: blur(0);
+ }
+}
+
+h1::after {
+ content: '';
+ display: block;
+ width: 80px;
+ height: 4px;
+ background: linear-gradient(90deg, var(--accent-danger) 0%, var(--accent-warning) 50%, var(--accent-danger) 100%);
+ background-size: 200% 100%;
+ margin: 14px auto 0;
+ box-shadow: 0 0 15px rgba(230, 167, 60, 0.5);
+ animation: shimmer 3s ease-in-out infinite;
+}
+
+@keyframes shimmer {
+ 0%, 100% { background-position: 0% 50%; }
+ 50% { background-position: 100% 50%; }
+}
+
+h2 {
+ font-family: 'Crimson Text', Georgia, serif;
+ text-align: center;
+ margin: 16px 0;
+ font-size: 1.4em;
+ font-weight: 700;
+ letter-spacing: 0.5px;
+}
+
+h3 {
+ font-family: 'JetBrains Mono', monospace;
+ font-size: 1em;
+ font-weight: 800;
+ text-transform: uppercase;
+ letter-spacing: 1.5px;
+ margin-bottom: 12px;
+}
+
+/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ CONTAINER & SCREENS
+ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
.container {
width: 100%;
max-width: 480px;
- background: var(--container-bg);
- backdrop-filter: blur(10px);
- border-radius: 20px;
- padding: 20px;
- box-shadow: 0 8px 32px var(--shadow-color);
- border: 1px solid var(--container-border);
+ background: var(--surface-glass);
+ backdrop-filter: blur(20px) saturate(150%);
+ border-radius: 0;
+ padding: 28px 22px;
+ box-shadow: var(--shadow-harsh), var(--shadow-lg);
+ border: 4px solid var(--border-heavy);
display: flex;
flex-direction: column;
- transition: background 0.3s ease, border 0.3s ease;
+ transition: all 0.4s ease;
margin-bottom: 20px;
+ position: relative;
+ overflow: hidden;
+ clip-path: polygon(
+ 0 20px,
+ 20px 0,
+ 100% 0,
+ 100% calc(100% - 20px),
+ calc(100% - 20px) 100%,
+ 0 100%
+ );
}
-h1 { text-align: center; margin-bottom: 12px; font-size: 1.5em; text-shadow: 2px 2px 4px rgba(0,0,0,0.3); }
-h2 { text-align: center; margin: 8px 0; font-size: 1.2em; }
-.screen { display: none; animation: fadeIn 0.25s ease; flex: 1; overflow-y: auto; }
-.screen.active { display: flex; flex-direction: column; }
-@keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
-.form-group { margin-bottom: 10px; }
-.form-group.compact { margin-bottom: 6px; }
-label { display: block; margin-bottom: 4px; font-weight: 700; font-size: 0.9em; color: var(--text-secondary); }
+
+.container::before {
+ content: 'โฌข CLASSIFIED โฌข';
+ position: absolute;
+ top: 8px;
+ left: 50%;
+ transform: translateX(-50%);
+ font-size: 0.65em;
+ letter-spacing: 3px;
+ opacity: 0.4;
+ font-weight: 800;
+ color: var(--accent-danger);
+ text-shadow: 0 0 10px rgba(217, 54, 38, 0.3);
+ animation: classifiedPulse 4s ease-in-out infinite;
+}
+
+@keyframes classifiedPulse {
+ 0%, 100% { opacity: 0.4; text-shadow: 0 0 10px rgba(217, 54, 38, 0.3); }
+ 50% { opacity: 0.6; text-shadow: 0 0 20px rgba(217, 54, 38, 0.6); }
+}
+
+/* Diagonal classified stamp */
+.container::after {
+ content: 'EXPEDIENTE';
+ position: absolute;
+ bottom: 15px;
+ right: -30px;
+ font-family: 'Special Elite', 'Courier Prime', monospace;
+ font-size: 0.7em;
+ letter-spacing: 3px;
+ color: var(--accent-danger);
+ opacity: 0.12;
+ transform: rotate(-45deg);
+ font-weight: 400;
+ white-space: nowrap;
+ pointer-events: none;
+}
+
+.screen {
+ display: none;
+ animation: screenEnter 0.35s cubic-bezier(0.22, 1, 0.36, 1);
+ flex: 1;
+ overflow: hidden;
+ min-height: 0;
+}
+
+.screen.active {
+ display: flex;
+ flex-direction: column;
+}
+
+@keyframes screenEnter {
+ 0% {
+ opacity: 0;
+ transform: translateY(30px) scale(0.95);
+ filter: blur(4px);
+ }
+ 60% {
+ opacity: 1;
+ filter: blur(0);
+ }
+ 100% {
+ opacity: 1;
+ transform: translateY(0) scale(1);
+ filter: blur(0);
+ }
+}
+
+/* Staggered children animation */
+.screen.active > * {
+ animation: fadeSlideUp 0.5s cubic-bezier(0.22, 1, 0.36, 1) backwards;
+}
+
+.screen.active > *:nth-child(1) { animation-delay: 0.05s; }
+.screen.active > *:nth-child(2) { animation-delay: 0.1s; }
+.screen.active > *:nth-child(3) { animation-delay: 0.15s; }
+.screen.active > *:nth-child(4) { animation-delay: 0.2s; }
+.screen.active > *:nth-child(5) { animation-delay: 0.25s; }
+.screen.active > *:nth-child(6) { animation-delay: 0.3s; }
+.screen.active > *:nth-child(7) { animation-delay: 0.35s; }
+.screen.active > *:nth-child(8) { animation-delay: 0.4s; }
+
+@keyframes fadeSlideUp {
+ from {
+ opacity: 0;
+ transform: translateY(15px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ FORM CONTROLS
+ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+.form-group {
+ margin-bottom: 16px;
+}
+
+.form-group.compact {
+ margin-bottom: 12px;
+}
+
+label {
+ display: block;
+ margin-bottom: 8px;
+ font-weight: 700;
+ font-size: 0.8em;
+ color: var(--text-secondary);
+ text-transform: uppercase;
+ letter-spacing: 1.2px;
+}
+
input {
width: 100%;
- padding: 10px 12px;
- border: 2px solid var(--border-color);
- border-radius: 10px;
+ padding: 12px 14px;
+ border: 2px solid var(--border-medium);
+ border-radius: 0;
font-size: 0.95em;
- background: var(--input-bg);
- color: var(--input-text);
- transition: border-color 0.2s ease, background 0.3s ease;
+ font-family: 'JetBrains Mono', monospace;
+ background: var(--surface-card);
+ color: var(--text-primary);
+ transition: all 0.2s ease;
+ box-shadow: inset 2px 2px 4px rgba(0, 0, 0, 0.1);
}
-input:focus { outline: none; border-color: var(--input-focus); }
+
+input:focus {
+ outline: none;
+ border-color: var(--accent-warning);
+ box-shadow: inset 2px 2px 4px rgba(0, 0, 0, 0.1), 0 0 0 3px rgba(212, 165, 116, 0.2);
+ transform: translateY(-1px);
+}
+
+/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ BUTTONS
+ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
button {
width: 100%;
- padding: 14px;
- border: none;
- border-radius: 12px;
- font-size: 1em;
+ padding: 16px 20px;
+ border: 3px solid var(--text-primary);
+ border-radius: 0;
+ font-size: 0.9em;
font-weight: 800;
+ font-family: 'JetBrains Mono', monospace;
cursor: pointer;
- background: linear-gradient(135deg, var(--button-gradient-start) 0%, var(--button-gradient-end) 100%);
- color: white;
- box-shadow: 0 4px 15px rgba(0,0,0,0.3);
- transition: transform 0.15s, box-shadow 0.15s, background 0.3s ease;
- margin-top: 10px;
-}
-button:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(0,0,0,0.4); }
-button:active { transform: scale(0.98); box-shadow: 0 2px 10px rgba(0,0,0,0.2); }
-button.secondary { background: linear-gradient(135deg, var(--button-secondary-start) 0%, var(--button-secondary-end) 100%); color: #fff; }
-button.ghost { background: var(--button-ghost-bg); color: var(--text-primary); font-weight: 600; }
-.player-names-list { max-height: 280px; overflow-y: auto; margin-bottom: 8px; -webkit-overflow-scrolling: touch; }
-.player-name-item { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; background: var(--card-bg); padding: 10px; border-radius: 10px; border: 1px solid var(--border-color); transition: background 0.2s ease; }
-.player-name-item:hover { background: var(--card-hover); }
-.player-name-item span { font-weight: 700; min-width: 76px; font-size: 0.9em; color: var(--text-secondary); }
-.player-name-item input { flex: 1; padding: 8px; margin: 0; font-size: 0.9em; }
-.curtain { position: relative; width: 100%; height: 280px; background: var(--curtain-bg); border-radius: 16px; overflow: hidden; margin: 12px 0; box-shadow: 0 6px 20px rgba(0,0,0,0.4); cursor: grab; user-select: none; border: 2px solid var(--border-color); transition: background 0.3s ease; }
-.curtain:active { cursor: grabbing; }
-.curtain-cover { position: absolute; inset: 0; background: linear-gradient(135deg, #ffa585 0%, #ffeda0 100%); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; font-size: 1.1em; font-weight: 800; color: #333; transition: transform 0.5s ease; z-index: 10; user-select: none; }
-.curtain-cover.lifted { transform: translateY(-100%); }
-.curtain-icon { font-size: 2.2em; }
-.curtain-content { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; padding: 16px; text-align: center; }
-.role { font-size: 2em; font-weight: 800; padding: 10px 20px; border-radius: 12px; text-transform: uppercase; border: 3px solid transparent; }
-.role.civil { background: rgba(74, 222, 128, 0.26); color: #4ade80; border-color: #4ade80; }
-.role.impostor { background: rgba(239, 68, 68, 0.28); color: #ef4444; border-color: #ef4444; }
-.word { font-size: 1.7em; font-weight: 800; background: rgba(255,255,255,0.16); padding: 16px 24px; border-radius: 10px; border: 2px solid rgba(255,255,255,0.28); }
-.timer { font-size: 2.8em; font-weight: 800; text-align: center; margin: 16px 0; text-shadow: 2px 2px 4px rgba(0,0,0,0.3); padding: 14px; background: rgba(0,0,0,0.22); border-radius: 12px; }
-.timer.warning { color: #fbbf24; animation: pulse 1s infinite; }
-.timer.danger { color: #ef4444; animation: pulse 0.55s infinite; }
-@keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.05); } }
-.info-text { text-align: center; margin: 10px 0; font-size: 0.95em; line-height: 1.5; background: var(--info-bg); padding: 12px; border-radius: 10px; color: var(--text-secondary); border: 1px solid var(--border-color); }
-.player-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); gap: 10px; margin: 12px 0; max-height: 300px; overflow-y: auto; -webkit-overflow-scrolling: touch; }
-.player-item { padding: 16px 12px; background: var(--card-bg); border-radius: 12px; text-align: center; cursor: pointer; transition: transform 0.18s, background 0.18s, border 0.18s; font-weight: 700; font-size: 0.95em; border: 2px solid var(--border-color); }
-.player-item:hover { background: var(--card-hover); transform: translateY(-2px); }
-.player-item:active { transform: scale(0.96); }
-.player-item.selected { background: var(--button-gradient-end); border-color: #fff; box-shadow: 0 0 16px rgba(245, 87, 108, 0.7); }
-.player-item .vote-count { display: block; font-size: 0.85em; margin-top: 4px; opacity: 0.88; }
-.results { background: rgba(255,255,255,0.16); border-radius: 10px; padding: 14px; margin: 10px 0; max-height: 400px; overflow-y: auto; -webkit-overflow-scrolling: touch; }
-.role-reveal { background: rgba(0,0,0,0.3); padding: 10px; border-radius: 8px; margin: 5px 0; border-left: 4px solid transparent; font-size: 0.9em; }
-.role-reveal.civil-reveal { border-left-color: #4ade80; }
-.role-reveal.impostor-reveal { border-left-color: #ef4444; }
-.role-reveal.executed { opacity: 0.6; background: rgba(0,0,0,0.45); }
-.tag { display: inline-block; padding: 5px 8px; border-radius: 6px; background: rgba(255,255,255,0.18); margin: 3px 0; font-weight: 700; font-size: 0.85em; }
-.pool-buttons {
- display: grid;
- grid-template-columns: repeat(2, 1fr);
- gap: 6px;
- max-height: 200px;
- overflow-y: auto;
- padding: 4px 0;
- -webkit-overflow-scrolling: touch;
-
- /* Hide scrollbar in all browsers */
- scrollbar-width: none; /* Firefox */
- -ms-overflow-style: none; /* IE/Edge */
-}
-.pool-buttons::-webkit-scrollbar {
- display: none; /* Chrome/Safari/Opera */
-}
-
-/* Wrapper for gradient effect */
-.pool-buttons-wrapper {
+ background: var(--text-primary);
+ color: var(--text-inverted);
+ box-shadow: var(--shadow-harsh);
+ transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
+ margin-top: 12px;
+ text-transform: uppercase;
+ letter-spacing: 0.8px;
position: relative;
+ overflow: hidden;
+ clip-path: polygon(
+ 0 0,
+ calc(100% - 12px) 0,
+ 100% 12px,
+ 100% 100%,
+ 12px 100%,
+ 0 calc(100% - 12px)
+ );
}
-.pool-buttons-wrapper::after {
+
+button::before {
content: '';
position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- height: 30px;
- background: linear-gradient(to bottom, transparent, rgba(102, 126, 234, 0.4));
- pointer-events: none;
- border-radius: 0 0 8px 8px;
+ top: 50%;
+ left: 50%;
+ width: 0;
+ height: 0;
+ border-radius: 50%;
+ background: rgba(255, 255, 255, 0.2);
+ transform: translate(-50%, -50%);
+ transition: width 0.5s ease, height 0.5s ease;
}
-.pool-btn {
- padding: 10px 8px;
- border-radius: 10px;
- border: 2px solid var(--border-color);
- background: var(--card-bg);
+button:hover::before {
+ width: 300px;
+ height: 300px;
+}
+
+button:hover {
+ box-shadow: 8px 8px 0px rgba(0, 0, 0, 0.3);
+ filter: brightness(1.1);
+}
+
+button:active {
+ box-shadow: 2px 2px 0px rgba(0, 0, 0, 0.15);
+ filter: brightness(0.95);
+}
+
+button.secondary {
+ background: linear-gradient(135deg, var(--accent-warning) 0%, #c48a2e 100%);
+ border-color: var(--accent-warning);
+ color: var(--text-inverted);
+ box-shadow: var(--shadow-harsh), 0 0 15px rgba(230, 167, 60, 0.25);
+}
+
+button.ghost {
+ background: transparent;
color: var(--text-primary);
- font-weight: 700;
- font-size: 0.85em;
- cursor: pointer;
- transition: transform 0.12s, border 0.12s, background 0.12s;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
+ border-color: var(--border-medium);
+ box-shadow: none;
}
-.pool-btn:hover { transform: translateY(-2px); background: var(--card-hover); }
-.pool-btn.selected { border-color: var(--button-gradient-start); background: var(--button-gradient-start); color: white; box-shadow: 0 0 12px rgba(240,147,251,0.6); }
-/* Welcome screen */
+button.ghost:hover {
+ background: var(--surface-hover);
+ box-shadow: var(--shadow-harsh);
+}
+
+button:disabled {
+ opacity: 0.4;
+ cursor: not-allowed;
+ pointer-events: none;
+}
+
+.btn-primary {
+ background: linear-gradient(135deg, var(--accent-danger) 0%, #b8301e 100%);
+ border-color: var(--accent-danger);
+ box-shadow: var(--shadow-harsh), 0 0 20px rgba(217, 54, 38, 0.3);
+}
+
+.btn-secondary {
+ background: linear-gradient(135deg, var(--accent-info) 0%, #1e3a5f 100%);
+ border-color: var(--accent-info);
+ box-shadow: var(--shadow-harsh), 0 0 20px rgba(46, 78, 122, 0.3);
+}
+
+/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ WELCOME SCREEN
+ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
.welcome-content {
display: flex;
flex-direction: column;
@@ -205,7 +528,7 @@ button.ghost { background: var(--button-ghost-bg); color: var(--text-primary); f
justify-content: center;
text-align: center;
height: 100%;
- gap: 20px;
+ gap: 24px;
padding: 20px 0;
}
@@ -213,31 +536,76 @@ button.ghost { background: var(--button-ghost-bg); color: var(--text-primary); f
width: 140px;
height: 140px;
object-fit: contain;
- filter: drop-shadow(0 8px 16px rgba(0,0,0,0.3));
- animation: float 3s ease-in-out infinite;
+ filter: drop-shadow(5px 5px 0px var(--bg-secondary))
+ drop-shadow(0 0 30px rgba(230, 167, 60, 0.3))
+ grayscale(0.2) contrast(1.15);
+ animation: logoFloat 4s ease-in-out infinite, logoGlitch 8s step-end infinite;
+ position: relative;
}
-@keyframes float {
- 0%, 100% { transform: translateY(0px); }
- 50% { transform: translateY(-10px); }
+@keyframes logoFloat {
+ 0%, 100% { transform: translateY(0) rotate(0deg); }
+ 25% { transform: translateY(-8px) rotate(-2deg); }
+ 75% { transform: translateY(-8px) rotate(2deg); }
+}
+
+@keyframes logoGlitch {
+ 0%, 90%, 100% {
+ filter: drop-shadow(4px 4px 0px var(--bg-secondary))
+ drop-shadow(0 0 20px var(--border-heavy))
+ grayscale(0.3) contrast(1.1);
+ }
+ 91% {
+ filter: drop-shadow(6px 4px 0px var(--accent-danger))
+ drop-shadow(0 0 20px var(--accent-danger))
+ grayscale(0) contrast(1.3);
+ }
+ 92% {
+ filter: drop-shadow(4px 6px 0px var(--accent-info))
+ drop-shadow(0 0 20px var(--accent-info))
+ grayscale(0) contrast(1.3);
+ }
+ 93% {
+ filter: drop-shadow(4px 4px 0px var(--bg-secondary))
+ drop-shadow(0 0 20px var(--border-heavy))
+ grayscale(0.3) contrast(1.1);
+ }
}
.welcome-title {
- font-size: 2em;
+ font-size: 2.8em;
margin: 0;
- background: linear-gradient(135deg, var(--button-gradient-start), var(--button-gradient-end));
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- background-clip: text;
- font-weight: 900;
- text-shadow: none;
+ font-family: 'Bebas Neue', 'Crimson Text', Georgia, serif;
+ font-weight: 400;
+ text-shadow: 4px 4px 0px var(--bg-secondary), 0 0 40px rgba(230, 167, 60, 0.25);
+ letter-spacing: 6px;
+ line-height: 1;
+ position: relative;
+ animation: welcomeTitleReveal 0.8s cubic-bezier(0.22, 1, 0.36, 1) forwards;
+}
+
+@keyframes welcomeTitleReveal {
+ 0% {
+ opacity: 0;
+ letter-spacing: 30px;
+ filter: blur(10px);
+ transform: scale(0.9);
+ }
+ 100% {
+ opacity: 1;
+ letter-spacing: 6px;
+ filter: blur(0);
+ transform: scale(1);
+ }
}
.welcome-subtitle {
- font-size: 1.1em;
+ font-size: 0.95em;
color: var(--text-secondary);
margin: -10px 0 0 0;
- font-weight: 500;
+ font-weight: 400;
+ letter-spacing: 0.5px;
+ font-family: 'JetBrains Mono', monospace;
}
.welcome-buttons {
@@ -245,224 +613,1217 @@ button.ghost { background: var(--button-ghost-bg); color: var(--text-primary); f
flex-direction: column;
gap: 12px;
width: 100%;
- max-width: 300px;
+ max-width: 320px;
margin-top: 10px;
}
.welcome-credits {
color: var(--text-tertiary);
- font-size: 0.85em;
+ font-size: 0.75em;
margin-top: auto;
- font-weight: 500;
+ font-weight: 400;
+ letter-spacing: 1px;
+ text-transform: uppercase;
}
-/* Rules screen */
+.welcome-credits::before {
+ content: 'โโโโโ ';
+}
+
+.welcome-credits::after {
+ content: ' โโโโโ';
+}
+
+/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ RULES SCREEN
+ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
.rules-content {
flex: 1;
overflow-y: auto;
+ overflow-x: hidden;
padding: 10px 0;
-webkit-overflow-scrolling: touch;
+ scrollbar-width: none;
+ -ms-overflow-style: none;
+}
+
+.rules-content::-webkit-scrollbar {
+ display: none;
}
.rule-section {
- background: var(--card-bg);
- border: 2px solid var(--border-color);
- border-radius: 12px;
- padding: 16px;
+ background: var(--surface-card);
+ border: 3px solid var(--border-medium);
+ border-left: 8px solid var(--accent-warning);
+ border-radius: 0;
+ padding: 18px;
margin-bottom: 16px;
- transition: background 0.3s ease, transform 0.2s ease;
+ transition: all 0.3s cubic-bezier(0.22, 1, 0.36, 1);
+ position: relative;
+ box-shadow: var(--shadow-md);
+ clip-path: polygon(
+ 0 0,
+ 100% 0,
+ 100% calc(100% - 10px),
+ calc(100% - 10px) 100%,
+ 0 100%
+ );
+ animation: ruleSlideIn 0.4s cubic-bezier(0.22, 1, 0.36, 1) backwards;
+}
+
+.rule-section:nth-child(1) { animation-delay: 0.1s; }
+.rule-section:nth-child(2) { animation-delay: 0.2s; }
+.rule-section:nth-child(3) { animation-delay: 0.3s; }
+.rule-section:nth-child(4) { animation-delay: 0.4s; }
+
+@keyframes ruleSlideIn {
+ from {
+ opacity: 0;
+ transform: translateX(-20px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+.rule-section::before {
+ content: 'โธ';
+ position: absolute;
+ left: -3px;
+ top: 18px;
+ font-size: 1.5em;
+ color: var(--accent-warning);
+ animation: blink 2s ease-in-out infinite;
+}
+
+@keyframes blink {
+ 0%, 49%, 100% { opacity: 1; }
+ 50%, 99% { opacity: 0; }
}
.rule-section:hover {
- background: var(--card-hover);
- transform: translateY(-2px);
+ background: var(--surface-hover);
+ border-left-color: var(--accent-danger);
+ box-shadow: var(--shadow-lg);
}
.rule-section h3 {
- margin: 0 0 12px 0;
+ margin: 0 0 14px 0;
color: var(--text-primary);
- font-size: 1.1em;
-}
-
-.rule-section p {
- margin: 6px 0;
- color: var(--text-secondary);
- line-height: 1.6;
font-size: 0.95em;
}
-.rule-section p:first-of-type {
- margin-top: 0;
+.rule-section p {
+ margin: 8px 0;
+ color: var(--text-secondary);
+ line-height: 1.7;
+ font-size: 0.85em;
+ letter-spacing: 0.3px;
}
.rule-section strong {
- color: var(--button-gradient-end);
+ color: var(--accent-danger);
font-weight: 800;
-}
-
-/* Theme toggle button */
-.theme-toggle {
- position: fixed;
- top: 20px;
- right: 20px;
- width: 50px;
- height: 50px;
- border-radius: 50%;
- border: 2px solid var(--border-color);
- background: var(--container-bg);
- backdrop-filter: blur(10px);
- cursor: pointer;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 1.5em;
- box-shadow: 0 4px 12px var(--shadow-color);
- transition: transform 0.2s ease, background 0.3s ease, border 0.3s ease;
- z-index: 1000;
- margin: 0;
- padding: 0;
-}
-.theme-toggle:hover {
- transform: scale(1.1) rotate(15deg);
- background: var(--card-hover);
-}
-.theme-toggle:active {
- transform: scale(0.95);
-}
-.theme-icon {
- transition: transform 0.3s ease;
- display: inline-block;
-}
-
-/* Language toggle button */
-.language-toggle {
- position: fixed;
- top: 80px;
- right: 20px;
- width: auto;
- min-width: 50px;
- height: 50px;
- padding: 0 15px;
- border-radius: 25px;
- border: 2px solid var(--border-color);
- background: var(--container-bg);
- backdrop-filter: blur(10px);
- cursor: pointer;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: 6px;
- font-size: 1em;
- font-weight: 600;
- box-shadow: 0 4px 12px var(--shadow-color);
- transition: transform 0.2s ease, background 0.3s ease, border 0.3s ease;
- z-index: 1000;
- color: var(--text-primary);
- margin: 0;
-}
-.language-toggle:hover {
- transform: scale(1.05);
- background: var(--card-hover);
-}
-.language-toggle:active {
- transform: scale(0.95);
-}
-.language-icon {
- font-size: 1.2em;
- transition: transform 0.3s ease;
- display: inline-block;
-}
-.language-text {
+ text-transform: uppercase;
font-size: 0.9em;
letter-spacing: 0.5px;
}
-/* Exit game button */
+/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ PLAYER MANAGEMENT
+ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+.player-names-list {
+ flex: 1 1 auto;
+ min-height: 0;
+ max-height: 360px; /* Altura mรกxima para activar scroll y mostrar fila parcial - efecto peek */
+ overflow-y: scroll;
+ overflow-x: hidden;
+ margin-bottom: 12px;
+ -webkit-overflow-scrolling: touch;
+ scrollbar-width: none; /* Firefox */
+ -ms-overflow-style: none; /* IE y Edge */
+ /* Visual frame to indicate scrollable area */
+ background: var(--surface-card);
+ border: 4px solid var(--border-heavy);
+ border-radius: 0;
+ padding: 12px;
+ box-shadow: inset 0 4px 12px rgba(0, 0, 0, 0.15),
+ inset 0 -4px 12px rgba(0, 0, 0, 0.15),
+ var(--shadow-md);
+ /* Gradiente para crear efecto peek - texto cortado visible */
+ -webkit-mask-image: linear-gradient(to bottom,
+ black 0%,
+ black calc(100% - 40px),
+ transparent 100%);
+ mask-image: linear-gradient(to bottom,
+ black 0%,
+ black calc(100% - 40px),
+ transparent 100%);
+}
+
+.player-names-list::-webkit-scrollbar {
+ display: none; /* Chrome, Safari, Opera */
+}
+
+.player-name-item {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ margin-bottom: 8px;
+ background: var(--bg-secondary);
+ padding: 12px;
+ border-radius: 0;
+ border: 2px solid var(--border-light);
+ border-left: 4px solid var(--accent-info);
+ transition: all 0.2s ease;
+ box-shadow: var(--shadow-sm);
+}
+
+.player-name-item:last-child {
+ margin-bottom: 0;
+}
+
+.player-name-item:hover {
+ background: var(--surface-hover);
+ border-left-color: var(--accent-warning);
+ transform: translateX(2px);
+}
+
+.player-name-item span {
+ font-weight: 800;
+ min-width: 80px;
+ font-size: 0.8em;
+ color: var(--text-secondary);
+ text-transform: uppercase;
+ letter-spacing: 1px;
+}
+
+.player-name-item input {
+ flex: 1;
+ padding: 10px;
+ margin: 0;
+ font-size: 0.85em;
+ border-width: 2px;
+}
+
+/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ CURTAIN REVEAL MECHANISM
+ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+.curtain {
+ position: relative;
+ width: 100%;
+ height: 280px;
+ background: var(--bg-secondary);
+ border-radius: 0;
+ overflow: hidden;
+ margin: 12px 0;
+ box-shadow: inset 0 0 40px rgba(0, 0, 0, 0.3), var(--shadow-harsh);
+ cursor: grab;
+ user-select: none;
+ border: 3px solid var(--border-heavy);
+ flex-shrink: 0;
+}
+
+.curtain:active {
+ cursor: grabbing;
+}
+
+.curtain-cover {
+ position: absolute;
+ inset: 0;
+ background:
+ repeating-linear-gradient(
+ 0deg,
+ #2a2a2a 0px,
+ #2a2a2a 8px,
+ #1a1a1a 8px,
+ #1a1a1a 12px
+ ),
+ linear-gradient(180deg, rgba(255,200,100,0.03) 0%, transparent 50%);
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 16px;
+ font-size: 1.1em;
+ font-weight: 800;
+ color: #888;
+ transition: transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
+ z-index: 10;
+ user-select: none;
+ box-shadow: inset 0 -20px 40px rgba(0, 0, 0, 0.5), inset 0 0 60px rgba(0,0,0,0.3);
+ letter-spacing: 2px;
+ font-family: 'Bebas Neue', 'JetBrains Mono', monospace;
+}
+
+.curtain-cover::after {
+ content: '';
+ position: absolute;
+ bottom: -8px;
+ left: 0;
+ right: 0;
+ height: 8px;
+ background: linear-gradient(90deg,
+ transparent 0%,
+ rgba(0,0,0,0.3) 25%,
+ rgba(0,0,0,0.5) 50%,
+ rgba(0,0,0,0.3) 75%,
+ transparent 100%);
+}
+
+.curtain-cover.lifted {
+ transform: translateY(-100%);
+}
+
+.curtain-icon {
+ font-size: 2.5em;
+ animation: bounce 2s ease-in-out infinite;
+}
+
+@keyframes bounce {
+ 0%, 100% { transform: translateY(0); }
+ 50% { transform: translateY(-12px); }
+}
+
+.curtain-content {
+ position: absolute;
+ inset: 0;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 20px;
+ padding: 20px;
+ text-align: center;
+}
+
+.role {
+ font-size: 2.4em;
+ font-weight: 400;
+ padding: 16px 32px;
+ border-radius: 0;
+ text-transform: uppercase;
+ border: 4px solid;
+ font-family: 'Bebas Neue', 'JetBrains Mono', monospace;
+ letter-spacing: 6px;
+ box-shadow: var(--shadow-harsh);
+ position: relative;
+ animation: roleReveal 0.4s cubic-bezier(0.22, 1, 0.36, 1) forwards;
+}
+
+@keyframes roleReveal {
+ 0% {
+ opacity: 0;
+ transform: scale(0.5) rotate(-5deg);
+ filter: blur(10px);
+ }
+ 50% {
+ transform: scale(1.1) rotate(2deg);
+ }
+ 100% {
+ opacity: 1;
+ transform: scale(1) rotate(0);
+ filter: blur(0);
+ }
+}
+
+.role.civil {
+ background: var(--accent-success);
+ color: var(--text-inverted);
+ border-color: #3d5a40;
+ animation: civilPulse 2s ease-in-out infinite;
+}
+
+.role.impostor {
+ background: var(--accent-danger);
+ color: var(--text-inverted);
+ border-color: #8a2e26;
+ animation: impostorPulse 1.5s ease-in-out infinite;
+}
+
+@keyframes civilPulse {
+ 0%, 100% { box-shadow: 4px 4px 0px rgba(0, 0, 0, 0.3), 0 0 0px rgba(90, 125, 95, 0.5); }
+ 50% { box-shadow: 4px 4px 0px rgba(0, 0, 0, 0.3), 0 0 25px rgba(90, 125, 95, 0.8); }
+}
+
+@keyframes impostorPulse {
+ 0%, 100% { box-shadow: 4px 4px 0px rgba(0, 0, 0, 0.3), 0 0 0px rgba(196, 69, 54, 0.5); }
+ 50% { box-shadow: 4px 4px 0px rgba(0, 0, 0, 0.3), 0 0 30px rgba(196, 69, 54, 0.9); }
+}
+
+.word {
+ font-size: 2em;
+ font-weight: 400;
+ background: var(--surface-card);
+ padding: 20px 36px;
+ border-radius: 0;
+ border: 3px solid var(--border-heavy);
+ font-family: 'Special Elite', 'Crimson Text', serif;
+ letter-spacing: 2px;
+ box-shadow: var(--shadow-harsh);
+ color: var(--text-primary);
+ text-transform: uppercase;
+ animation: wordReveal 0.5s cubic-bezier(0.22, 1, 0.36, 1) 0.2s forwards;
+ opacity: 0;
+}
+
+@keyframes wordReveal {
+ 0% {
+ opacity: 0;
+ transform: translateY(20px);
+ filter: blur(5px);
+ }
+ 100% {
+ opacity: 1;
+ transform: translateY(0);
+ filter: blur(0);
+ }
+}
+
+/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ TIMER
+ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+.timer {
+ font-size: 4em;
+ font-weight: 800;
+ text-align: center;
+ margin: 20px 0;
+ padding: 24px;
+ background: var(--surface-card);
+ border-radius: 0;
+ border: 5px solid var(--border-heavy);
+ font-family: 'Bebas Neue', 'JetBrains Mono', monospace;
+ letter-spacing: 8px;
+ box-shadow: var(--shadow-harsh), inset 0 0 30px rgba(0, 0, 0, 0.2);
+ position: relative;
+ clip-path: polygon(
+ 16px 0,
+ calc(100% - 16px) 0,
+ 100% 16px,
+ 100% calc(100% - 16px),
+ calc(100% - 16px) 100%,
+ 16px 100%,
+ 0 calc(100% - 16px),
+ 0 16px
+ );
+ animation: timerAppear 0.5s cubic-bezier(0.22, 1, 0.36, 1) forwards;
+}
+
+@keyframes timerAppear {
+ from {
+ opacity: 0;
+ transform: scale(0.8);
+ filter: blur(5px);
+ }
+ to {
+ opacity: 1;
+ transform: scale(1);
+ filter: blur(0);
+ }
+}
+
+.timer::before {
+ content: '';
+ position: absolute;
+ top: 8px;
+ right: 8px;
+ width: 12px;
+ height: 12px;
+ background: var(--accent-success);
+ border-radius: 50%;
+ box-shadow: 0 0 10px var(--accent-success);
+ animation: statusBlink 2s ease-in-out infinite;
+}
+
+@keyframes statusBlink {
+ 0%, 49%, 100% { opacity: 1; }
+ 50%, 99% { opacity: 0.3; }
+}
+
+.timer.warning {
+ color: var(--accent-warning);
+ border-color: var(--accent-warning);
+ animation: timerShake 0.5s ease-in-out infinite;
+}
+
+.timer.warning::before {
+ background: var(--accent-warning);
+ box-shadow: 0 0 10px var(--accent-warning);
+}
+
+.timer.danger {
+ color: var(--accent-danger);
+ border-color: var(--accent-danger);
+ animation: timerShake 0.25s ease-in-out infinite, dangerFlash 1s ease-in-out infinite;
+}
+
+.timer.danger::before {
+ background: var(--accent-danger);
+ box-shadow: 0 0 15px var(--accent-danger);
+ animation: statusBlink 0.5s ease-in-out infinite;
+}
+
+@keyframes timerShake {
+ 0%, 100% { transform: translateX(0); }
+ 25% { transform: translateX(-4px); }
+ 75% { transform: translateX(4px); }
+}
+
+@keyframes dangerFlash {
+ 0%, 100% { background: var(--surface-card); }
+ 50% { background: rgba(196, 69, 54, 0.15); }
+}
+
+/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ INFO BOXES & CONTENT
+ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+.info-text {
+ text-align: center;
+ margin: 14px 0;
+ font-size: 0.85em;
+ line-height: 1.7;
+ background: var(--surface-card);
+ padding: 14px 16px;
+ border-radius: 0;
+ color: var(--text-secondary);
+ border: 2px solid var(--border-light);
+ border-left: 5px solid var(--accent-info);
+ box-shadow: var(--shadow-sm), inset 4px 0 8px rgba(46, 78, 122, 0.1);
+ letter-spacing: 0.3px;
+}
+
+/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ PLAYER SELECTION GRID
+ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+.player-list {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
+ gap: 10px;
+ margin: 12px 0;
+ flex: 1;
+ overflow-y: auto;
+ overflow-x: hidden;
+ -webkit-overflow-scrolling: touch;
+ padding: 4px;
+ scrollbar-width: none;
+ -ms-overflow-style: none;
+}
+
+.player-list::-webkit-scrollbar {
+ display: none;
+}
+
+.player-item {
+ padding: 18px 14px;
+ min-height: 80px; /* Altura fija para evitar cambios de tamaรฑo con vote-count */
+ background: var(--surface-card);
+ border-radius: 0;
+ text-align: center;
+ cursor: pointer;
+ transition: all 0.25s cubic-bezier(0.22, 1, 0.36, 1);
+ font-weight: 800;
+ font-size: 0.85em;
+ border: 3px solid var(--border-medium);
+ box-shadow: var(--shadow-sm);
+ letter-spacing: 0.5px;
+ text-transform: uppercase;
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ clip-path: polygon(
+ 8px 0,
+ 100% 0,
+ 100% calc(100% - 8px),
+ calc(100% - 8px) 100%,
+ 0 100%,
+ 0 8px
+ );
+ animation: playerItemAppear 0.3s cubic-bezier(0.22, 1, 0.36, 1) backwards;
+}
+
+.player-item:nth-child(1) { animation-delay: 0.05s; }
+.player-item:nth-child(2) { animation-delay: 0.1s; }
+.player-item:nth-child(3) { animation-delay: 0.15s; }
+.player-item:nth-child(4) { animation-delay: 0.2s; }
+.player-item:nth-child(5) { animation-delay: 0.25s; }
+.player-item:nth-child(6) { animation-delay: 0.3s; }
+.player-item:nth-child(7) { animation-delay: 0.35s; }
+.player-item:nth-child(8) { animation-delay: 0.4s; }
+.player-item:nth-child(9) { animation-delay: 0.45s; }
+.player-item:nth-child(10) { animation-delay: 0.5s; }
+
+@keyframes playerItemAppear {
+ from {
+ opacity: 0;
+ transform: scale(0.8);
+ }
+ to {
+ opacity: 1;
+ transform: scale(1);
+ }
+}
+
+.player-item::before {
+ content: 'โก';
+ position: absolute;
+ top: 6px;
+ right: 6px;
+ font-size: 1.2em;
+ transition: all 0.2s ease;
+}
+
+.player-item:hover {
+ background: var(--surface-hover);
+ box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.25);
+ filter: brightness(1.05);
+}
+
+.player-item:active {
+ box-shadow: 2px 2px 0px rgba(0, 0, 0, 0.15);
+ filter: brightness(0.95);
+}
+
+.player-item.selected {
+ background: var(--accent-danger);
+ border-color: var(--text-primary);
+ color: var(--text-inverted);
+ box-shadow: 0 0 0 4px rgba(217, 54, 38, 0.5), 6px 6px 0px rgba(0, 0, 0, 0.4);
+ animation: selectPulse 0.3s ease-out;
+}
+
+@keyframes selectPulse {
+ 0% { transform: scale(1); }
+ 50% { transform: scale(1.08); }
+ 100% { transform: scale(1); }
+}
+
+.player-item.selected::before {
+ content: 'โ';
+ animation: checkAppear 0.2s ease-out;
+}
+
+@keyframes checkAppear {
+ from { transform: scale(0) rotate(-180deg); }
+ to { transform: scale(1) rotate(0); }
+}
+
+.player-item.disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ pointer-events: none;
+ background: var(--bg-secondary);
+ border-color: var(--border-light);
+ filter: grayscale(0.6);
+ animation: playerItemAppearDisabled 0.3s cubic-bezier(0.22, 1, 0.36, 1) backwards !important;
+}
+
+.player-item.disabled::before {
+ content: 'โ';
+ color: var(--text-tertiary);
+}
+
+.player-item .vote-count {
+ display: block;
+ font-size: 0.7em;
+ margin-top: 4px;
+ opacity: 0.75;
+ font-weight: 600;
+ letter-spacing: 0.3px;
+ min-height: 1em; /* Reservar espacio siempre */
+}
+
+/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ RESULTS
+ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+.results {
+ background: var(--surface-card);
+ border-radius: 0;
+ padding: 14px;
+ margin: 8px 0;
+ flex: 1;
+ overflow: visible;
+ border: 2px solid var(--border-medium);
+ box-shadow: var(--shadow-md);
+ animation: resultsReveal 0.5s cubic-bezier(0.22, 1, 0.36, 1) forwards;
+}
+
+@keyframes resultsReveal {
+ from {
+ opacity: 0;
+ transform: translateY(20px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+.results h2 {
+ font-family: 'Bebas Neue', 'Crimson Text', Georgia, serif;
+ font-size: 1.6em;
+ letter-spacing: 3px;
+ margin-bottom: 10px;
+ animation: winnerReveal 0.6s cubic-bezier(0.22, 1, 0.36, 1) forwards;
+}
+
+@keyframes winnerReveal {
+ 0% {
+ opacity: 0;
+ transform: scale(0.5);
+ filter: blur(10px);
+ }
+ 60% {
+ transform: scale(1.1);
+ }
+ 100% {
+ opacity: 1;
+ transform: scale(1);
+ filter: blur(0);
+ }
+}
+
+.role-reveal {
+ background: var(--bg-secondary);
+ padding: 8px 10px;
+ border-radius: 0;
+ margin: 5px 0;
+ border-left: 4px solid;
+ font-size: 0.8em;
+ letter-spacing: 0.2px;
+ box-shadow: var(--shadow-sm);
+ transition: all 0.2s ease;
+ animation: roleRevealSlide 0.4s cubic-bezier(0.22, 1, 0.36, 1) backwards;
+}
+
+.role-reveal:nth-child(1) { animation-delay: 0.3s; }
+.role-reveal:nth-child(2) { animation-delay: 0.4s; }
+.role-reveal:nth-child(3) { animation-delay: 0.5s; }
+.role-reveal:nth-child(4) { animation-delay: 0.6s; }
+.role-reveal:nth-child(5) { animation-delay: 0.7s; }
+.role-reveal:nth-child(6) { animation-delay: 0.8s; }
+.role-reveal:nth-child(7) { animation-delay: 0.9s; }
+.role-reveal:nth-child(8) { animation-delay: 1s; }
+.role-reveal:nth-child(9) { animation-delay: 1.1s; }
+.role-reveal:nth-child(10) { animation-delay: 1.2s; }
+
+@keyframes roleRevealSlide {
+ from {
+ opacity: 0;
+ transform: translateX(-20px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+.role-reveal:hover {
+ transform: translateX(3px);
+}
+
+.role-reveal.civil-reveal {
+ border-left-color: var(--accent-success);
+}
+
+.role-reveal.impostor-reveal {
+ border-left-color: var(--accent-danger);
+}
+
+.role-reveal.executed {
+ opacity: 0.5;
+ background: rgba(0, 0, 0, 0.2);
+ text-decoration: line-through;
+}
+
+.tag {
+ display: inline-block;
+ padding: 6px 10px;
+ border-radius: 0;
+ background: var(--surface-hover);
+ margin: 4px 0;
+ font-weight: 800;
+ font-size: 0.75em;
+ border: 2px solid var(--border-medium);
+ letter-spacing: 1px;
+ text-transform: uppercase;
+}
+
+/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ POOL SELECTION
+ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+.pool-buttons {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 8px;
+ padding: 0;
+}
+
+.pool-buttons-wrapper {
+ position: relative;
+ flex: 1 1 auto;
+ min-height: 0;
+ max-height: 320px; /* Ajustado para mostrar fila parcial - efecto peek */
+ overflow-y: scroll;
+ overflow-x: hidden;
+ -webkit-overflow-scrolling: touch;
+ scrollbar-width: none; /* Firefox */
+ -ms-overflow-style: none; /* IE y Edge */
+ /* Visual frame to indicate scrollable area */
+ background: var(--surface-card);
+ border: 4px solid var(--border-heavy);
+ border-radius: 0;
+ padding: 12px;
+ margin: 12px 0;
+ box-shadow: inset 0 4px 12px rgba(0, 0, 0, 0.15),
+ inset 0 -4px 12px rgba(0, 0, 0, 0.15),
+ var(--shadow-md);
+ /* Gradiente para crear efecto peek - texto cortado visible */
+ -webkit-mask-image: linear-gradient(to bottom,
+ black 0%,
+ black calc(100% - 50px),
+ transparent 100%);
+ mask-image: linear-gradient(to bottom,
+ black 0%,
+ black calc(100% - 50px),
+ transparent 100%);
+}
+
+.pool-buttons-wrapper::-webkit-scrollbar {
+ display: none; /* Chrome, Safari, Opera */
+}
+
+.pool-btn {
+ padding: 12px 10px;
+ border-radius: 0;
+ border: 2px solid var(--border-medium);
+ background: var(--surface-card);
+ color: var(--text-primary);
+ font-weight: 700;
+ font-size: 0.8em;
+ cursor: pointer;
+ transition: all 0.18s ease;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ box-shadow: var(--shadow-sm);
+}
+
+.pool-btn:hover {
+ background: var(--surface-hover);
+ box-shadow: 3px 3px 0px rgba(0, 0, 0, 0.15);
+ filter: brightness(1.05);
+}
+
+.pool-btn.selected {
+ border-color: var(--text-primary);
+ background: var(--accent-warning);
+ color: var(--text-inverted);
+ box-shadow: 0 0 0 3px rgba(212, 165, 116, 0.3), 3px 3px 0px rgba(0, 0, 0, 0.2);
+}
+
+/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ FIXED UI CONTROLS (Theme, Language, Exit)
+ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+.theme-toggle {
+ position: fixed;
+ top: 20px;
+ right: 20px;
+ width: 56px;
+ height: 56px;
+ border-radius: 0;
+ border: 3px solid var(--border-heavy);
+ background: var(--surface-glass);
+ backdrop-filter: blur(20px);
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 1.6em;
+ box-shadow: var(--shadow-harsh);
+ transition: all 0.2s ease;
+ z-index: 1000;
+ margin: 0;
+ padding: 0;
+}
+
+.theme-toggle:hover {
+ box-shadow: 8px 8px 0px rgba(0, 0, 0, 0.2);
+ filter: brightness(1.1);
+}
+
+.theme-toggle:active {
+ box-shadow: 2px 2px 0px rgba(0, 0, 0, 0.15);
+ filter: brightness(0.95);
+}
+
+.theme-icon {
+ transition: transform 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
+ display: inline-block;
+}
+
+.theme-toggle:hover .theme-icon {
+ transform: rotate(180deg) scale(1.1);
+}
+
+.language-toggle {
+ position: fixed;
+ top: 86px;
+ right: 20px;
+ width: auto;
+ min-width: 56px;
+ height: 56px;
+ padding: 0 16px;
+ border-radius: 0;
+ border: 3px solid var(--border-heavy);
+ background: var(--surface-glass);
+ backdrop-filter: blur(20px);
+ cursor: pointer;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ font-size: 1em;
+ font-weight: 800;
+ box-shadow: var(--shadow-harsh);
+ transition: all 0.2s ease;
+ z-index: 1000;
+ color: var(--text-primary);
+ margin: 0;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+}
+
+.language-toggle:hover {
+ box-shadow: 8px 8px 0px rgba(0, 0, 0, 0.2);
+ filter: brightness(1.1);
+}
+
+.language-toggle:active {
+ box-shadow: 2px 2px 0px rgba(0, 0, 0, 0.15);
+ filter: brightness(0.95);
+}
+
+.language-icon {
+ font-size: 1.3em;
+ transition: transform 0.3s ease;
+ display: inline-block;
+}
+
+.language-text {
+ font-size: 0.85em;
+ letter-spacing: 1.5px;
+ font-family: 'JetBrains Mono', monospace;
+}
+
.exit-game {
position: fixed;
top: 20px;
left: 20px;
width: auto;
- height: 50px;
- padding: 0 15px;
- border-radius: 25px;
- border: 2px solid var(--border-color);
- background: var(--container-bg);
- backdrop-filter: blur(10px);
+ height: 56px;
+ padding: 0 16px;
+ border-radius: 0;
+ border: 3px solid var(--border-heavy);
+ background: var(--surface-glass);
+ backdrop-filter: blur(20px);
cursor: pointer;
display: none;
align-items: center;
justify-content: center;
- gap: 8px;
- font-size: 0.9em;
- font-weight: 600;
- box-shadow: 0 4px 12px var(--shadow-color);
- transition: transform 0.2s ease, background 0.3s ease, border 0.3s ease;
+ gap: 10px;
+ font-size: 0.85em;
+ font-weight: 800;
+ box-shadow: var(--shadow-harsh);
+ transition: all 0.2s ease;
z-index: 1000;
color: var(--text-primary);
+ text-transform: uppercase;
+ letter-spacing: 1px;
}
+
.exit-game.visible {
display: inline-flex;
}
+
.exit-game:hover {
- transform: scale(1.05);
- background: var(--card-hover);
-}
-.exit-game:active {
- transform: scale(0.95);
-}
-.exit-icon {
- font-size: 1.2em;
-}
-.exit-text {
- font-size: 0.85em;
+ box-shadow: 8px 8px 0px rgba(0, 0, 0, 0.2);
+ background: var(--accent-danger);
+ color: var(--text-inverted);
}
-/* Mobile optimization */
+.exit-game:active {
+ box-shadow: 2px 2px 0px rgba(0, 0, 0, 0.15);
+}
+
+.exit-icon {
+ font-size: 1.3em;
+}
+
+.exit-text {
+ font-size: 0.9em;
+ font-family: 'JetBrains Mono', monospace;
+}
+
+.screen-lock-toggle {
+ position: fixed;
+ top: 152px;
+ right: 20px;
+ width: 56px;
+ height: 56px;
+ border-radius: 0;
+ border: 3px solid var(--border-heavy);
+ background: var(--surface-glass);
+ backdrop-filter: blur(20px);
+ cursor: pointer;
+ display: none;
+ align-items: center;
+ justify-content: center;
+ font-size: 1.6em;
+ box-shadow: var(--shadow-harsh);
+ transition: all 0.2s ease;
+ z-index: 1000;
+ margin: 0;
+ padding: 0;
+}
+
+.screen-lock-toggle.visible {
+ display: inline-flex;
+}
+
+.screen-lock-toggle:hover {
+ box-shadow: 8px 8px 0px rgba(0, 0, 0, 0.2);
+ filter: brightness(1.1);
+}
+
+.screen-lock-toggle:active {
+ box-shadow: 2px 2px 0px rgba(0, 0, 0, 0.15);
+ filter: brightness(0.95);
+}
+
+.screen-lock-toggle.active {
+ background: var(--accent-success);
+ color: var(--text-inverted);
+ border-color: var(--accent-success);
+}
+
+.screen-lock-icon {
+ transition: transform 0.3s ease;
+ display: inline-block;
+}
+
+.screen-lock-toggle:hover .screen-lock-icon {
+ transform: scale(1.1);
+}
+
+/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ RESPONSIVE DESIGN
+ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
@media (max-width: 600px) {
body {
- padding: 70px 10px 10px 10px;
+ padding: 60px 10px 10px 10px;
+ font-size: 13px;
}
- .theme-toggle {
- top: 10px;
- right: 10px;
- width: 45px;
- height: 45px;
- font-size: 1.3em;
+ h1 {
+ font-size: 1.7em;
+ margin-bottom: 14px;
+ }
+
+ .container {
+ padding: 20px 16px;
+ }
+
+ .theme-toggle,
+ .language-toggle,
+ .exit-game,
+ .screen-lock-toggle {
+ top: 8px;
+ width: 44px;
+ height: 44px;
+ min-width: 44px;
}
.language-toggle {
- top: 65px;
- right: 10px;
- min-width: 45px;
- height: 45px;
- padding: 0 12px;
- font-size: 0.9em;
+ top: 58px;
}
- .language-icon {
- font-size: 1.1em;
- }
-
- .language-text {
- font-size: 0.85em;
+ .screen-lock-toggle {
+ top: 108px;
}
.exit-game {
- top: 10px;
- left: 10px;
- height: 45px;
padding: 0 12px;
+ font-size: 0.75em;
+ height: 44px;
+ }
+
+ /* Ocultar textos en mรณvil, solo emojis */
+ .exit-text,
+ .language-text {
+ display: none;
+ }
+
+ .exit-game {
+ padding: 0;
+ width: 44px;
+ min-width: 44px;
+ }
+
+ .language-toggle {
+ padding: 0;
+ width: 44px;
+ min-width: 44px;
+ }
+
+ .exit-icon,
+ .language-icon {
+ font-size: 1.4em;
+ }
+
+ .timer {
+ font-size: 2.5em;
+ padding: 16px;
+ }
+
+ .welcome-title {
+ font-size: 1.8em;
+ }
+
+ .role {
+ font-size: 1.6em;
+ padding: 10px 18px;
+ }
+
+ .word {
+ font-size: 1.3em;
+ padding: 12px 20px;
+ }
+
+ .form-group {
+ margin-bottom: 10px;
+ }
+
+ .form-group.compact {
+ margin-bottom: 8px;
+ }
+
+ button {
+ padding: 12px 16px;
+ margin-top: 8px;
+ }
+
+ .rule-section {
+ padding: 12px;
+ margin-bottom: 12px;
+ }
+
+ .rule-section h3 {
font-size: 0.85em;
+ margin-bottom: 10px;
}
- .exit-icon {
- font-size: 1.1em;
- }
-
- .exit-text {
+ .rule-section p {
font-size: 0.8em;
+ margin: 6px 0;
+ }
+
+ .player-name-item {
+ padding: 10px;
+ margin-bottom: 6px;
+ }
+
+ .player-name-item span {
+ font-size: 0.75em;
+ min-width: 70px;
+ }
+
+ .player-item {
+ padding: 14px 10px;
+ min-height: 72px; /* Altura fija tambiรฉn en mรณvil */
+ font-size: 0.8em;
+ }
+
+ .pool-btn {
+ padding: 10px 8px;
+ font-size: 0.75em;
+ }
+
+ .pool-buttons-wrapper {
+ max-height: 240px; /* Ajustado para mostrar fila parcial en mรณvil - efecto peek */
+ padding: 10px;
+ margin: 10px 0;
+ }
+
+ .player-names-list {
+ max-height: 280px; /* Ajustado para mostrar fila parcial en mรณvil - efecto peek */
+ padding: 10px;
+ }
+
+ .info-text {
+ padding: 12px 14px;
+ font-size: 0.8em;
+ margin: 10px 0;
+ }
+
+ .curtain {
+ height: 240px;
+ margin: 10px 0;
}
}
+/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ UTILITY ANIMATIONS
+ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+
+@keyframes typewriter {
+ from { width: 0; }
+ to { width: 100%; }
+}
+
+@keyframes glitch {
+ 0% { transform: translate(0); }
+ 20% { transform: translate(-2px, 2px); }
+ 40% { transform: translate(-2px, -2px); }
+ 60% { transform: translate(2px, 2px); }
+ 80% { transform: translate(2px, -2px); }
+ 100% { transform: translate(0); }
+}
+
+/* Smooth scrolling */
+* {
+ scrollbar-width: thin;
+ scrollbar-color: var(--border-medium) transparent;
+}
+
+::-webkit-scrollbar {
+ width: 8px;
+ height: 8px;
+}
+
+::-webkit-scrollbar-track {
+ background: transparent;
+}
+
+::-webkit-scrollbar-thumb {
+ background: var(--border-medium);
+ border-radius: 0;
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background: var(--border-heavy);
+}