/**
* CONSELHO ESCOLAR DEMOCRÁTICO - DIRETRIZES MEC & LEI 14.644/2023
* Script Interativo: Efeito Cascata Scrollytelling, Linha do Tempo e Simulador
*/
document.addEventListener('DOMContentLoaded', () => {
// 1. Inicializar Ícones Lucide
if (typeof lucide !== 'undefined') {
lucide.createIcons();
}
// Elementos do DOM
const progressBar = document.getElementById('reading-progress-bar');
const scrollTrack = document.getElementById('cascade-scroll-track');
const stickyStage = document.getElementById('cascade-sticky-stage');
const cards = document.querySelectorAll('.cascade-card');
const navSteps = document.querySelectorAll('.cascade-nav-step');
const prevBtn = document.getElementById('cascade-prev-btn');
const nextBtn = document.getElementById('cascade-next-btn');
const miniProgress = document.getElementById('cascade-mini-progress');
const counterElement = document.getElementById('cascade-counter');
// Elementos da Gravura Dinâmica da Cascata
const dynamicImg = document.getElementById('dynamic-dimension-img');
const badgeCategory = document.getElementById('dimension-badge-category');
const captionDesc = document.getElementById('dimension-caption');
// Metadados Visuais das 5 Dimensões MEC
const dimensionMetadata = [
{
category: "Poder Decisório Soberano",
caption: "O Conselho Escolar vota e aprova com força normativa o Projeto Político-Pedagógico (PPP), Regimento e destinação de recursos.",
image: "https://images.unsplash.com/photo-1544717305-2782549b5136?auto=format&fit=crop&w=1000&q=80",
colorClass: "bg-blue-600"
},
{
category: "Aconselhamento e Mediação",
caption: "Câmara de diálogo para resolução de conflitos, pareceres sobre inovações pedagógicas e fomento à cultura da paz.",
image: "https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?auto=format&fit=crop&w=1000&q=80",
colorClass: "bg-sky-600"
},
{
category: "Controle Social e Probidade",
caption: "Auditoria cidadã dos recursos do PDDE, conferência de notas fiscais, prestação de contas da UEx e vistoria predial.",
image: "https://images.unsplash.com/photo-1454165804606-c3d57bc86b40?auto=format&fit=crop&w=1000&q=80",
colorClass: "bg-amber-600"
},
{
category: "Engajamento Sociocomunitário",
caption: "Busca ativa escolar, engajamento familiar, articulação com a rede de proteção social (CRAS/UBS) e protagonismo estudantil.",
image: "https://images.unsplash.com/photo-1529156069898-49953e39b3ac?auto=format&fit=crop&w=1000&q=80",
colorClass: "bg-emerald-600"
},
{
category: "Aprendizagem e Qualidade Social",
caption: "Acompanhamento do IDEB, SAEB, taxas de aprovação, inclusão e validação de planos de reforço pedagógico.",
image: "https://images.unsplash.com/photo-1509062522246-3755977927d7?auto=format&fit=crop&w=1000&q=80",
colorClass: "bg-purple-600"
}
];
let currentCascadeIndex = 0;
// =========================================================================
// MOTOR DE ROLAGEM CASCATA (SCROLLYTELLING ENGINE)
// =========================================================================
function updateCascadeState(targetIndex) {
if (targetIndex < 0) targetIndex = 0;
if (targetIndex > cards.length - 1) targetIndex = cards.length - 1;
currentCascadeIndex = targetIndex;
// Atualiza os cards
cards.forEach((card, idx) => {
card.classList.remove('is-active', 'is-passed', 'is-upcoming');
if (idx === targetIndex) {
card.classList.add('is-active');
} else if (idx < targetIndex) {
card.classList.add('is-passed');
} else {
card.classList.add('is-upcoming');
}
});
// Atualiza os botões da linha do tempo da cascata
navSteps.forEach((step, idx) => {
if (idx === targetIndex) {
step.classList.add('active-step', 'bg-blue-600', 'text-white');
step.classList.remove('text-slate-400');
} else {
step.classList.remove('active-step', 'bg-blue-600', 'text-white');
step.classList.add('text-slate-400');
}
});
// Atualiza o painel visual esquerdo
const meta = dimensionMetadata[targetIndex];
if (meta && dynamicImg) {
if (dynamicImg.src !== meta.image) {
dynamicImg.style.opacity = '0.4';
setTimeout(() => {
dynamicImg.src = meta.image;
dynamicImg.style.opacity = '1';
}, 200);
}
if (badgeCategory) {
badgeCategory.textContent = meta.category;
}
if (captionDesc) {
captionDesc.textContent = meta.caption;
}
}
// Atualiza o contador e mini progresso
if (counterElement) {
counterElement.innerHTML = `Dimensão ${targetIndex + 1} de ${cards.length}`;
}
if (miniProgress) {
const pct = ((targetIndex + 1) / cards.length) * 100;
miniProgress.style.width = `${pct}%`;
}
// Atualiza os botões Prev/Next
if (prevBtn) prevBtn.disabled = targetIndex === 0;
if (nextBtn) nextBtn.disabled = targetIndex === cards.length - 1;
}
// Função para rolar a janela diretamente até um step específico da cascata
function scrollToCascadeStep(index) {
if (!scrollTrack) return;
const trackRect = scrollTrack.getBoundingClientRect();
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
const trackTop = trackRect.top + scrollTop;
const trackHeight = scrollTrack.offsetHeight - window.innerHeight;
// Calcula o ponto exato dentro da pista de rolagem
const targetScrollY = trackTop + (trackHeight * (index / (cards.length - 1)));
window.scrollTo({
top: targetScrollY,
behavior: 'smooth'
});
}
// Exportar para escopo global para links e cards externos
window.scrollToCascadeIndex = function(index) {
scrollToCascadeStep(index);
};
// Clique nos botões de Step da Linha do Tempo da Cascata
navSteps.forEach((step) => {
step.addEventListener('click', (e) => {
e.preventDefault();
const stepIdx = parseInt(step.getAttribute('data-step'), 10);
scrollToCascadeStep(stepIdx);
});
});
// Botões Próximo / Anterior
if (prevBtn) {
prevBtn.addEventListener('click', () => {
if (currentCascadeIndex > 0) {
scrollToCascadeStep(currentCascadeIndex - 1);
}
});
}
if (nextBtn) {
nextBtn.addEventListener('click', () => {
if (currentCascadeIndex < cards.length - 1) {
scrollToCascadeStep(currentCascadeIndex + 1);
}
});
}
// Teclado: Navegação pelas teclas de seta quando na zona da cascata
window.addEventListener('keydown', (e) => {
if (!scrollTrack) return;
const trackRect = scrollTrack.getBoundingClientRect();
// Se o sticky stage estiver visível na viewport
if (trackRect.top <= 50 && trackRect.bottom >= window.innerHeight - 50) {
if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {
if (currentCascadeIndex < cards.length - 1) {
e.preventDefault();
scrollToCascadeStep(currentCascadeIndex + 1);
}
} else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {
if (currentCascadeIndex > 0) {
e.preventDefault();
scrollToCascadeStep(currentCascadeIndex - 1);
}
}
}
});
// Monitoramento do Scroll Geral
function onScroll() {
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
const docHeight = document.documentElement.scrollHeight - window.innerHeight;
// 1. Barra de Leitura Global Superior
if (progressBar && docHeight > 0) {
const scrollPct = (scrollTop / docHeight) * 100;
progressBar.style.width = `${scrollPct}%`;
}
// 2. Controle do Efeito Cascata baseado na Pista de Rolagem
if (scrollTrack) {
const trackRect = scrollTrack.getBoundingClientRect();
const trackTop = trackRect.top;
const trackHeight = scrollTrack.offsetHeight - window.innerHeight;
if (trackTop <= 0 && Math.abs(trackTop) <= trackHeight) {
// Estamos dentro da zona de cascata!
const progress = Math.abs(trackTop) / trackHeight;
// Mapeia para índice de 0 a 4
const calculatedIndex = Math.min(
cards.length - 1,
Math.floor(progress * cards.length)
);
if (calculatedIndex !== currentCascadeIndex) {
updateCascadeState(calculatedIndex);
}
} else if (trackTop > 0 && currentCascadeIndex !== 0) {
updateCascadeState(0);
} else if (Math.abs(trackTop) > trackHeight && currentCascadeIndex !== cards.length - 1) {
updateCascadeState(cards.length - 1);
}
}
// 3. Atualizar Linha do Tempo Lateral Flutuante (Desktop)
updateFloatingTimeline();
}
window.addEventListener('scroll', onScroll, { passive: true });
// Inicialização do primeiro card
updateCascadeState(0);
// =========================================================================
// LINHA DO TEMPO LATERAL FLUTUANTE
// =========================================================================
const timelineButtons = document.querySelectorAll('.timeline-dot-btn');
const sectionsToTrack = [
'#hero',
'#marco-legal',
'#dimensoes-cascata',
'#composicao',
'#boas-praticas',
'#simulador',
'#faq'
];
timelineButtons.forEach(btn => {
btn.addEventListener('click', () => {
const targetSelector = btn.getAttribute('data-target');
const targetElement = document.querySelector(targetSelector);
if (targetElement) {
targetElement.scrollIntoView({ behavior: 'smooth' });
}
});
});
function updateFloatingTimeline() {
const scrollPosition = window.pageYOffset + 250;
sectionsToTrack.forEach(selector => {
const el = document.querySelector(selector);
const btn = document.querySelector(`.timeline-dot-btn[data-target="${selector}"]`);
if (el && btn) {
const top = el.offsetTop;
const height = el.offsetHeight;
if (scrollPosition >= top && scrollPosition < top + height) {
btn.classList.add('active');
} else {
btn.classList.remove('active');
}
}
});
}
// =========================================================================
// SIMULADOR DE DECISÕES DO CONSELHO ESCOLAR (QUIZ INTERATIVO)
// =========================================================================
const quizScenarios = [
{
title: "Cenário 1: Recursos do PDDE para Recomposição da Aprendizagem",
desc: "A escola recebeu um recurso suplementar do PDDE no valor de R$ 25.000,00. A gestão escolar propôs a compra de kits pedagógicos de robótica e matemática. Antes de efetivar a compra, a reunião oficial do conselho foi convocada para deliberar e votar se esses são de fato os itens prioritários para a escola.",
correct: "deliberativa",
feedback: "Excelente! Trata-se da **Função Deliberativa**. A destinação dos recursos financeiros e o plano de aplicação da Unidade Executora (UEx) exigem aprovação e voto soberano do Conselho Escolar em ata."
},
{
title: "Cenário 2: Mediação de Clima Escolar e Convivência",
desc: "Houve um aumento nos desentendimentos no recreio entre turmas do 8º e 9º anos. A equipe pedagógica chamou o conselho para ouvir os representantes de pais e alunos, acolher sugestões e emitir um parecer orientativo antes de alterar o horário do intervalo.",
correct: "consultiva",
feedback: "Muito bem! Trata-se da **Função Consultiva**. O conselho atua emitindo pareceres e conselhos fundamentados, servindo de espaço de escuta e mediação para que a gestão tome a melhor decisão coletiva."
},
{
title: "Cenário 3: Prestação de Contas e Conferência de Notas Fiscais",
desc: "Ao final do semestre, os conselheiros se reuniram para conferir o livro caixa, extratos bancários, os 3 orçamentos realizados para a reforma do telhado e assinar o parecer do relatório anual de prestação de contas do FNDE.",
correct: "fiscalizadora",
feedback: "Correto! É a **Função Fiscalizadora**. O conselho exerce o controle social e zela pela legalidade e transparência da coisa pública, conferindo comprovantes antes do envio aos órgãos de controle."
},
{
title: "Cenário 4: Busca Ativa Escolar de Alunos com Alta Infrequência",
desc: "O conselho organizou uma campanha no bairro junto ao posto de saúde da família e lideranças locais para visitar famílias cujos filhos faltaram mais de 20% das aulas no bimestre, sensibilizando-os para o retorno escolar.",
correct: "mobilizadora",
feedback: "Exato! É a **Função Mobilizadora**. O conselho atua articulando a comunidade escolar e o território, combatendo a evasão e criando pontes entre as famílias e a escola pública."
},
{
title: "Cenário 5: Análise dos Resultados do SAEB e Diagnóstico Pedagógico",
desc: "Após a divulgação dos resultados do SAEB e do IDEB, o Conselho Escolar reuniu-se para debater os níveis de alfabetização dos estudantes e aprovou uma reformulação no plano de reforço escolar do contraturno.",
correct: "pedagogica",
feedback: "Perfeito! É a **Função Pedagógica (ou Avaliativa)**. O conselho acompanha os indicadores educacionais e garante que todas as decisões da escola estejam orientadas para o sucesso e equidade na aprendizagem dos alunos."
}
];
let currentQuizStep = 0;
let quizScore = 0;
const quizQuestionNum = document.getElementById('quiz-question-number');
const quizScoreBadge = document.getElementById('quiz-score-badge');
const quizTitle = document.getElementById('quiz-scenario-title');
const quizDesc = document.getElementById('quiz-scenario-desc');
const quizOptionsContainer = document.getElementById('quiz-options-container');
const quizFeedbackBox = document.getElementById('quiz-feedback-box');
const quizFeedbackStatus = document.getElementById('quiz-feedback-status');
const quizFeedbackText = document.getElementById('quiz-feedback-text');
const quizNextBtn = document.getElementById('quiz-next-btn');
function loadQuizScenario(index) {
if (!quizTitle) return;
const scenario = quizScenarios[index];
quizQuestionNum.textContent = `Cenário ${index + 1} de ${quizScenarios.length}`;
quizTitle.textContent = scenario.title;
quizDesc.textContent = scenario.desc;
// Resetar feedback
quizFeedbackBox.classList.add('hidden');
quizNextBtn.classList.add('hidden');
// Habilitar opções
const optionBtns = quizOptionsContainer.querySelectorAll('.quiz-opt-btn');
optionBtns.forEach(btn => {
btn.disabled = false;
btn.classList.remove('correct-choice', 'wrong-choice', 'opacity-50');
});
}
if (quizOptionsContainer) {
quizOptionsContainer.addEventListener('click', (e) => {
const btn = e.target.closest('.quiz-opt-btn');
if (!btn || btn.disabled) return;
const chosenFunc = btn.getAttribute('data-function');
const scenario = quizScenarios[currentQuizStep];
const isCorrect = (chosenFunc === scenario.correct);
// Desabilitar todas as opções
const allBtns = quizOptionsContainer.querySelectorAll('.quiz-opt-btn');
allBtns.forEach(b => {
b.disabled = true;
if (b.getAttribute('data-function') === scenario.correct) {
b.classList.add('correct-choice');
} else if (b === btn && !isCorrect) {
b.classList.add('wrong-choice');
} else {
b.classList.add('opacity-50');
}
});
// Exibir Feedback Pedagógico
quizFeedbackBox.classList.remove('hidden', 'bg-emerald-950/40', 'border-emerald-800', 'bg-rose-950/40', 'border-rose-800');
if (isCorrect) {
quizScore++;
quizScoreBadge.textContent = `Pontuação: ${quizScore} acerto(s)`;
quizFeedbackBox.classList.add('bg-emerald-950/40', 'border-emerald-800');
quizFeedbackStatus.innerHTML = ` Resposta Correta!`;
} else {
quizFeedbackBox.classList.add('bg-rose-950/40', 'border-rose-800');
quizFeedbackStatus.innerHTML = ` Atenção à Diretriz!`;
}
quizFeedbackText.innerHTML = scenario.feedback;
if (typeof lucide !== 'undefined') lucide.createIcons();
// Mostrar botão próximo
if (currentQuizStep < quizScenarios.length - 1) {
quizNextBtn.innerHTML = `Avançar para o Próximo Cenário`;
} else {
quizNextBtn.innerHTML = `Finalizar Simulador (${quizScore}/${quizScenarios.length})`;
}
quizNextBtn.classList.remove('hidden');
if (typeof lucide !== 'undefined') lucide.createIcons();
});
}
if (quizNextBtn) {
quizNextBtn.addEventListener('click', () => {
if (currentQuizStep < quizScenarios.length - 1) {
currentQuizStep++;
loadQuizScenario(currentQuizStep);
} else {
// Finalização do Quiz
quizQuestionNum.textContent = "Simulação Concluída!";
quizTitle.textContent = `Parabéns! Você concluiu os 5 cenários com ${quizScore} de 5 acertos!`;
quizDesc.textContent = "Você compreendeu as nuances entre deliberar, consultar, fiscalizar, mobilizar e avaliar pedagogicamente conforme as diretrizes do MEC. Esse conhecimento é essencial para transformar o conselho da sua escola.";
quizOptionsContainer.innerHTML = `
`;
quizFeedbackBox.classList.add('hidden');
quizNextBtn.classList.add('hidden');
document.getElementById('restart-quiz-btn')?.addEventListener('click', () => {
location.reload();
});
}
});
}
// =========================================================================
// ACCORDION FAQ
// =========================================================================
const faqItems = document.querySelectorAll('.faq-item');
faqItems.forEach(item => {
const trigger = item.querySelector('.faq-trigger');
const content = item.querySelector('.faq-content');
if (trigger && content) {
trigger.addEventListener('click', () => {
const isActive = item.classList.contains('active');
// Fecha todos os outros itens
faqItems.forEach(otherItem => {
otherItem.classList.remove('active');
const otherContent = otherItem.querySelector('.faq-content');
if (otherContent) otherContent.classList.add('hidden');
});
// Alterna o atual
if (!isActive) {
item.classList.add('active');
content.classList.remove('hidden');
}
});
}
});
// =========================================================================
// MENU MOBILE
// =========================================================================
const mobileMenuBtn = document.getElementById('mobile-menu-btn');
const mobileMenu = document.getElementById('mobile-menu');
const mobileNavLinks = document.querySelectorAll('.mobile-nav-link');
if (mobileMenuBtn && mobileMenu) {
mobileMenuBtn.addEventListener('click', () => {
mobileMenu.classList.toggle('hidden');
});
mobileNavLinks.forEach(link => {
link.addEventListener('click', () => {
mobileMenu.classList.add('hidden');
});
});
}
});