/* Animated rainbow background */
:root{
--card-bg: rgba(255,255,255,0.96);
}
body{
min-height:100vh;
display:flex;
align-items:center;
justify-content:center;
padding:20px;
background: linear-gradient(120deg,#ff9a9e 0%, #fecfef 10%, #f6d365 20%, #fda085 30%, #a1c4fd 45%, #c2e9fb 55%, #d4fc79 70%, #96e6a1 85%, #fbc2eb 100%);
background-size: 400% 400%;
animation: rainbow 18s linear infinite;
}
@keyframes rainbow{
0%{background-position:0% 50%}
50%{background-position:100% 50%}
100%{background-position:0% 50%}
}
/* Container */
.container{
width:100%;
max-width:980px;
background: var(--card-bg);
border-radius:16px;
box-shadow:0 15px 40px rgba(0,0,0,0.18);
overflow:hidden;
position:relative;
}
/* Header */
.header{
padding:18px 22px;
text-align:center;
background: linear-gradient(90deg, rgba(255,255,255,0.06), rgba(255,255,255,0));
border-bottom: 1px solid rgba(0,0,0,0.06);
}
.title{
font-size:1.9rem;
font-weight:800;
letter-spacing:0.6px;
display:flex;
justify-content:center;
align-items:center;
gap:10px;
}
.title .heart{
color:#ff5c9e;
font-size:1.3rem;
transform:translateY(-2px);
}
.subtitle{ color:#666; margin-top:6px; font-size:0.95rem; opacity:0.95 }
/* Timer / progress */
.timer-container{
display:flex;
justify-content:space-between;
align-items:center;
padding:12px 20px;
background:linear-gradient(to right, rgba(255,255,255,0.6), rgba(255,255,255,0.4));
border-bottom:1px solid rgba(0,0,0,0.04);
}
.timer{ font-weight:700; color:#d6336c; background:#fff; padding:6px 12px;border-radius:20px; box-shadow:0 2px 6px rgba(0,0,0,0.06)}
.progress{ font-weight:600; color:#333 }
/* Selection screen */
.category-selection{ padding:26px; text-align:center }
.category-title{ font-size:1.4rem; font-weight:700; margin-bottom:16px; color:#222 }
.categories-container{ display:grid; gap:12px; grid-template-columns:repeat(auto-fit,minmax(160px,1fr)); margin:14px 0 22px }
.category-card{
background:linear-gradient(180deg,rgba(255,255,255,0.7),rgba(255,255,255,0.5));
padding:14px;border-radius:12px;border:2px solid rgba(0,0,0,0.04);
cursor:pointer;transition:transform .18s ease, box-shadow .18s ease;
display:flex;flex-direction:column;align-items:center;gap:8px;
min-height:84px;justify-content:center;
}
.category-card:hover{ transform:translateY(-6px); box-shadow:0 10px 25px rgba(0,0,0,0.08) }
.category-card.selected{ outline:3px solid rgba(0,0,0,0.06); transform:translateY(-2px); }
.category-icon{ font-size:1.6rem }
.category-name{ font-weight:700 }
/* Quiz screen */
.quiz-container{ padding:22px 26px 30px }
.question-container{ margin-bottom:18px }
.question-number{ color:#6c757d; margin-bottom:6px }
.question-text{ font-size:1.25rem; font-weight:700; color:#222; line-height:1.4; margin-bottom:10px }
.category-tag{ display:inline-block; padding:6px 10px; border-radius:999px; font-weight:700; color:#fff; margin-bottom:10px }
.options-container{ display:flex; flex-direction:column; gap:12px; margin-top:10px }
.option{
display:flex;align-items:center;gap:12px;padding:12px;border-radius:10px;border:2px solid rgba(0,0,0,0.06);
background:linear-gradient(180deg, #fff, #f8f9fb); cursor:pointer; transition:transform .12s ease, box-shadow .12s ease;
}
.option:hover{ transform:translateY(-4px); box-shadow:0 8px 20px rgba(0,0,0,0.06) }
.option.selected{ background: linear-gradient(90deg,#6a11cb,#2575fc); color:#fff; border-color:transparent }
.option-letter{ width:34px;height:34px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-weight:800;background:#eef2ff }
.option.selected .option-letter{ background: rgba(255,255,255,0.25) }
/* Navigation buttons */
.navigation{ display:flex; justify-content:space-between; gap:8px; margin-top:18px }
.btn{ padding:12px 20px;border-radius:10px;border:none;font-weight:800; cursor:pointer; box-shadow:0 6px 18px rgba(0,0,0,0.06) }
.btn:disabled{ opacity:0.5; cursor:not-allowed; transform:none; box-shadow:none }
.btn-prev{ background:#adb5bd; color:#fff }
.btn-next{ background: linear-gradient(90deg,#4a00e0,#8e2de2); color:#fff }
.btn-start{ background: linear-gradient(90deg,#ff7eb3,#ff758c); color:#fff; padding:14px 28px; font-size:1.05rem }
/* Result screen */
.results-container{ padding:22px }
.results-title{ font-size:1.6rem; color:#6a11cb; font-weight:800; text-align:center }
.score{ font-size:2.4rem; font-weight:900; color:#4a00e0; text-align:center; margin:10px 0 6px }
.results-summary{ margin-top:18px; background:#fff; padding:16px; border-radius:10px; max-height:360px; overflow:auto; border:1px solid rgba(0,0,0,0.04) }
.result-item{ padding:12px;border-bottom:1px dashed rgba(0,0,0,0.04) }
.result-question{ font-weight:800; margin-bottom:6px }
.correct{ color:#28a745; font-weight:800 }
.incorrect{ color:#dc3545; font-weight:800 }
/* Feedback overlay */
.feedback{
position: absolute;
left:50%;
transform:translateX(-50%);
top:26%;
z-index:60;
min-width:260px;
max-width:80%;
text-align:center;
padding:14px 18px;
border-radius:12px;
display:none;
align-items:center;
gap:10px;
box-shadow:0 14px 40px rgba(0,0,0,0.18);
font-weight:900;
font-size:1.05rem;
}
.feedback.show{ display:flex; animation:pop .32s ease both }
@keyframes pop{ from{ transform:translateX(-50%) scale(0.8); opacity:0 } to{ transform:translateX(-50%) scale(1); opacity:1 } }
.feedback.correct{ background: linear-gradient(90deg,#e9ffea,#d6ffe0); color:#1f7a3a }
.feedback.incorrect{ background: linear-gradient(90deg,#ffe7e7,#ffdcdc); color:#8a1f2b }
/* Confetti canvas covers whole container */
#confetti-canvas{ position:absolute; inset:0; pointer-events:none; z-index:50 }
/* Shake animation for incorrect */
.shake{ animation:shake .45s ease both }
@keyframes shake{
10%,90%{ transform:translateX(-1px) }
20%,80%{ transform:translateX(2px) }
30%,50%,70%{ transform:translateX(-4px) }
40%,60%{ transform:translateX(4px) }
}
/* Mobile tweaks */
@media(max-width:640px){
.title{ font-size:1.4rem }
.question-text{ font-size:1.05rem }
.btn{ padding:10px 14px }
}
<div class="header">
<div class="title">
<span class="heart">💗</span>
<span>TriviLocura</span>
<span class="heart">💗</span>
</div>
<div class="subtitle">Elige una categoría y demuestra lo que sabes — ¡diviértete! 🎉</div>
</div>
<!-- Timer / progress -->
<div class="timer-container">
<div class="progress">Pregunta <span id="current-question">1</span> de 10</div>
<div class="timer">Tiempo: <span id="time">01:00</span></div>
</div>
<!-- Category selection -->
<div id="category-screen" class="category-selection">
<h2 class="category-title">💖 Elige una categoría para estudiar</h2>
<div class="categories-container" id="categories-container"></div>
<button id="start-btn" class="btn btn-start" disabled>Comenzar Cuestionario</button>
</div>
<!-- Quiz screen -->
<div id="quiz-screen" class="quiz-container hidden" style="display:none">
<div class="question-container">
<div class="question-number">Pregunta <span id="question-number">1</span></div>
<div class="category-tag" id="question-category"></div>
<div class="question-text" id="question-text"></div>
</div>
<div id="feedback" class="feedback" role="status" aria-live="polite"></div>
<div class="options-container" id="options-container"></div>
<div class="navigation">
<button id="prev-btn" class="btn btn-prev" disabled>Anterior</button>
<button id="next-btn" class="btn btn-next">Siguiente</button>
</div>
</div>
<!-- Results screen -->
<div id="results-screen" class="results-container hidden" style="display:none">
<h2 class="results-title">Resultados del Cuestionario</h2>
<div class="score" id="final-score">0/10</div>
<p id="result-message" style="text-align:center"></p>
<div class="results-summary" id="results-summary"></div>
<div style="text-align:center; margin-top:14px;">
<button id="restart-btn" class="btn btn-start">Volver a seleccionar categorías</button>
</div>
</div>
${cat.icon}
${cat.name}
`;
card.addEventListener('click', ()=> selectCategory(cat.id, card));
categoriesContainer.appendChild(card);
});
}
function selectCategory(categoryId, cardEl){
document.querySelectorAll('.category-card').forEach(c=>c.classList.remove('selected'));
cardEl.classList.add('selected');
selectedCategory = categoryId;
startBtn.disabled = false;
}
/* -------------------------
Event listeners
------------------------- */
function setupEventListeners(){
startBtn.addEventListener('click', startQuiz);
prevBtn.addEventListener('click', prevQuestion);
nextBtn.addEventListener('click', nextQuestion);
restartBtn.addEventListener('click', restartQuiz);
}
/* -------------------------
Iniciar cuestionario
------------------------- */
function startQuiz(){
if(selectedCategory === 'mixtas'){
currentQuestions = getRandomQuestions(allQuestions, 10);
} else {
const pool = allQuestions.filter(q=> q.category === selectedCategory);
currentQuestions = getRandomQuestions(pool, 10);
}
currentQuestionIndex = 0;
userAnswers = Array(10).fill(null);
startTimer();
showQuestion();
categoryScreen.style.display = 'none';
quizScreen.style.display = 'block';
resultsScreen.style.display = 'none';
}
/* -------------------------
Random questions
------------------------- */
function getRandomQuestions(questions, count){
if(questions.length <= count) return [...questions];
return [...questions].sort(()=>0.5 - Math.random()).slice(0,count);
}
/* -------------------------
Mostrar pregunta
------------------------- */
function showQuestion(){
const q = currentQuestions[currentQuestionIndex];
const catInfo = categories.find(c=> c.id === q.category) || {name:'', color:'#888'};
questionText.textContent = q.question;
questionNumber.textContent = currentQuestionIndex + 1;
currentQuestionSpan.textContent = currentQuestionIndex + 1;
questionCategory.textContent = catInfo.name;
questionCategory.style.backgroundColor = catInfo.color;
questionCategory.style.color = '#fff';
// opciones
optionsContainer.innerHTML = '';
q.options.forEach((opt, idx)=>{
const el = document.createElement('div');
el.className = 'option';
if(userAnswers[currentQuestionIndex] === idx) el.classList.add('selected');
const letter = document.createElement('div');
letter.className = 'option-letter';
letter.textContent = String.fromCharCode(65 + idx);
const text = document.createElement('div');
text.textContent = opt;
el.appendChild(letter);
el.appendChild(text);
el.addEventListener('click', ()=> selectOption(idx));
optionsContainer.appendChild(el);
});
prevBtn.disabled = currentQuestionIndex === 0;
nextBtn.textContent = currentQuestionIndex === 9 ? 'Finalizar' : 'Siguiente';
}
/* -------------------------
Seleccionar opción (feedback inmediato)
------------------------- */
function selectOption(optionIndex){
const q = currentQuestions[currentQuestionIndex];
// Guardar respuesta
userAnswers[currentQuestionIndex] = optionIndex;
// Marcar seleccionado visualmente
// (re-render opciones)
showQuestion();
// Mostrar feedback inmediato
if(optionIndex === q.correct){
showFeedbackCorrect();
} else {
showFeedbackIncorrect();
}
}
/* -------------------------
Feedback: Correcto (confeti + cohete)
------------------------- */
function showFeedbackCorrect(){
// texto
feedbackDiv.className = 'feedback correct show';
feedbackDiv.innerHTML = `✅ ¡Correcto! 🎉🚀`;
// confetti por toda la pantalla
confettiBurst(80);
// ocultar después
setTimeout(()=>{ feedbackDiv.classList.remove('show'); }, 1600);
}
/* -------------------------
Feedback: Incorrecto (X roja + carita triste + vibración)
------------------------- */
function showFeedbackIncorrect(){
feedbackDiv.className = 'feedback incorrect show';
feedbackDiv.innerHTML = `❌ Incorrecto 😢`;
// efecto de temblor en contenedor de opciones
optionsContainer.classList.add('shake');
setTimeout(()=>{ optionsContainer.classList.remove('shake'); }, 480);
// vibrar si el dispositivo lo permite
if(window.navigator && navigator.vibrate){
navigator.vibrate([80,40,80]);
}
setTimeout(()=>{ feedbackDiv.classList.remove('show'); }, 1400);
}
/* -------------------------
Navegación preguntas
------------------------- */
function prevQuestion(){ if(currentQuestionIndex > 0){ currentQuestionIndex--; showQuestion(); } }
function nextQuestion(){ if(currentQuestionIndex < 9){ currentQuestionIndex++; showQuestion(); } else { finishQuiz(); } }
/* -------------------------
Temporizador
------------------------- */
function startTimer(){
clearInterval(timer);
timeLeft = 60;
updateTimerDisplay();
timer = setInterval(()=>{
timeLeft--;
updateTimerDisplay();
if(timeLeft <= 0){ clearInterval(timer); finishQuiz(); }
},1000);
}
function updateTimerDisplay(){
const m = Math.floor(timeLeft/60);
const s = timeLeft%60;
timeDisplay.textContent = `${String(m).padStart(2,'0')}:${String(s).padStart(2,'0')}`;
if(timeLeft <= 10){ timeDisplay.style.color = '#dc3545'; } else { timeDisplay.style.color = ''; }
}
/* -------------------------
Finalizar y mostrar resultados
------------------------- */
function finishQuiz(){
clearInterval(timer);
let score = 0;
currentQuestions.forEach((q,i)=>{ if(userAnswers[i] === q.correct) score++; });
finalScore.textContent = `${score}/10`;
if(score >= 9) resultMessage.textContent = "¡Excelente! Has demostrado un gran conocimiento.";
else if(score >= 7) resultMessage.textContent = "¡Buen trabajo! Tienes un buen nivel de conocimiento.";
else if(score >= 5) resultMessage.textContent = "Resultado aceptable. Sigue practicando para mejorar.";
else resultMessage.textContent = "Necesitas repasar más. ¡No te rindas!";
// Resumen
resultsSummary.innerHTML = '';
currentQuestions.forEach((q,i)=>{
const isCorrect = userAnswers[i] === q.correct;
const userAnsText = userAnswers[i] !== null ? `${String.fromCharCode(65+userAnswers[i])}. ${q.options[userAnswers[i]]}` : 'Sin responder';
const correctText = `${String.fromCharCode(65+q.correct)}. ${q.options[q.correct]}`;
const catInfo = categories.find(c=> c.id === q.category) || {color:'#999', name:q.category};
const item = document.createElement('div');
item.className = 'result-item';
item.innerHTML = `
${i+1}. ${q.question}
${catInfo.name}
${isCorrect ? '✅ Correcto 😁' : '❌ Incorrecto 😞'}
Tu respuesta: ${userAnsText}
Respuesta correcta: ${correctText}
${q.explanation}
`;
resultsSummary.appendChild(item);
});
// Cambiar pantallas
quizScreen.style.display = 'none';
resultsScreen.style.display = 'block';
}
/* -------------------------
Reiniciar
------------------------- */
function restartQuiz(){
selectedCategory = null;
document.querySelectorAll('.category-card').forEach(c=>c.classList.remove('selected'));
startBtn.disabled = true;
categoryScreen.style.display = 'block';
quizScreen.style.display = 'none';
resultsScreen.style.display = 'none';
}
/* -------------------------
Confetti system (canvas particles)
------------------------- */
(function setupConfetti(){
const ctx = confettiCanvas.getContext('2d');
let W = confettiCanvas.width = app.clientWidth;
let H = confettiCanvas.height = app.clientHeight;
const particles = [];
let animating = false;
// Resize canvas with container
function resize(){
W = confettiCanvas.width = app.clientWidth;
H = confettiCanvas.height = app.clientHeight;
}
window.addEventListener('resize', resize);
// Colors for confetti
const COLORS = ['#ff5c9e','#ffd166','#4ecdc4','#7209b7','#ff9e64','#4a00e0','#2575fc','#ffd6e0'];
function random(min, max){ return Math.random()*(max-min)+min; }
// Create burst
window.confettiBurst = function(count=60){
for(let i=0;i=0;i--){
const p = particles[i];
p.vy += p.gravity;
p.vx *= p.drag;
p.vy *= p.drag;
p.x += p.vx;
p.y += p.vy;
p.angle += p.angularVel;
p.ttl--;
ctx.save();
ctx.translate(p.x, p.y);
ctx.rotate(p.angle);
ctx.fillStyle = p.color;
ctx.fillRect(-p.w/2, -p.h/2, p.w, p.h);
ctx.restore();
if(p.y > H + 40 || p.ttl <= 0) particles.splice(i,1);
}
if(particles.length>0){ requestAnimationFrame(update); } else { animating = false; ctx.clearRect(0,0,W,H); }
}
})();
/* -------------------------
Fin del script
------------------------- */
</script>