<?php
/**
 * MEC Command Center — App Principal (SPA)
 * Baseado no mockup funcional aprovado
 * Protegido por autenticação de sessão
 */
session_start();

// Verifica se está autenticado — se não, redireciona para login
if (!isset($_SESSION['mec_authenticated']) || $_SESSION['mec_authenticated'] !== true) {
    header("Location: login.php");
    exit;
}
?>
<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>MEC Command Center - CEUNSP</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
    <script src="https://unpkg.com/lucide@latest"></script>
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    fontFamily: { sans: ['Inter', 'sans-serif'] },
                    colors: {
                        brand: { 50: '#f0fdf4', 100: '#dcfce7', 500: '#22c55e', 600: '#16a34a', 900: '#14532d' }
                    }
                }
            }
        }
    </script>
    <style>
        body { font-family: 'Inter', sans-serif; background-color: #f8fafc; }
        ::-webkit-scrollbar { width: 6px; height: 8px; }
        ::-webkit-scrollbar-track { background: transparent; }
        ::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 10px; }
        ::-webkit-scrollbar-thumb:hover { background: #94a3b8; }
        .slide-in { animation: slideIn 0.3s ease-out forwards; }
        @keyframes slideIn { from { transform: translateY(-10px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
        .fade-in { animation: fadeIn 0.4s ease-out forwards; }
        @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
        .rich-text-toolbar button { padding: 4px 8px; border-radius: 4px; color: #475569; font-size: 12px; font-weight: 500; transition: background 0.2s;}
        .rich-text-toolbar button:hover { background: #e2e8f0; }
        details > summary { list-style: none; }
        details > summary::-webkit-details-marker { display: none; }
        
        /* Table Horizontal Scroll enhancement */
        .table-scroll { max-width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
        .table-scroll::-webkit-scrollbar { height: 10px; }
        .table-scroll::-webkit-scrollbar-track { background: #f1f5f9; border-radius: 8px; }
        .table-scroll::-webkit-scrollbar-thumb { background: #94a3b8; border-radius: 8px; }
        
        /* Spreadsheet input styles */
        .sheet-input {
            width: 100%;
            background: transparent;
            border: 1px solid transparent;
            padding: 6px 8px;
            border-radius: 4px;
            outline: none;
            transition: all 0.2s;
            font-size: 13px;
            color: #334155;
        }
        .sheet-input:hover { background-color: #f8fafc; border-color: #cbd5e1; }
        .sheet-input:focus { background-color: #ffffff; border-color: #22c55e; box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.1); }
    </style>
</head>
<body class="text-slate-800 h-screen overflow-hidden bg-slate-100">

    <!-- LOGIN agora é via login.php separado -->

    <!-- APP LAYOUT -->
    <div id="app-layout" class="h-screen w-full flex overflow-hidden">
        <!-- Sidebar Navigation -->
        <aside class="w-16 md:w-64 shrink-0 bg-white border-r border-slate-200 flex flex-col justify-between shadow-sm z-20 transition-all duration-300">
            <div class="flex-1 overflow-y-auto overflow-x-hidden">
                <div class="h-16 flex items-center justify-center md:justify-start md:px-6 border-b border-slate-100">
                    <i data-lucide="shield-check" class="text-brand-600 w-6 h-6 md:w-8 md:h-8 shrink-0"></i>
                    <span class="ml-3 font-bold text-slate-800 hidden md:block tracking-tight truncate">MEC Center</span>
                </div>
                <nav class="p-2 md:p-4 space-y-2" id="nav-menu">
                    <!-- Populated by JS -->
                </nav>
            </div>
            <div class="p-3 md:p-4 border-t border-slate-100 shrink-0">
                <div class="flex items-center justify-center md:justify-start">
                    <div class="w-8 h-8 rounded-full bg-brand-100 text-brand-600 flex items-center justify-center font-bold text-sm shrink-0">AD</div>
                    <div class="ml-3 hidden md:block min-w-0">
                        <p class="text-sm font-semibold truncate">Alex Sandro</p>
                        <p class="text-xs text-slate-500 truncate">Coordenador</p>
                    </div>
                </div>
            </div>
        </aside>

        <!-- Main Content Area -->
        <main class="flex-1 min-w-0 flex flex-col h-full overflow-hidden relative bg-[#f8fafc]">
            <header class="h-16 shrink-0 bg-white/80 backdrop-blur-md border-b border-slate-200 flex items-center justify-between px-4 md:px-6 z-10 shadow-sm gap-2">
                <div class="min-w-0 flex-1">
                    <h1 id="page-title" class="text-lg md:text-xl font-semibold text-slate-800 truncate">Dashboard</h1>
                    <p id="page-subtitle" class="text-xs md:text-sm text-slate-500 truncate">Ciclo de Avaliação 2026</p>
                </div>
                <div class="flex items-center space-x-2 md:space-x-4 shrink-0">
                    <button onclick="app.logout()" class="p-2 text-slate-400 hover:text-rose-600 transition-colors shrink-0" title="Sair do Sistema">
                        <i data-lucide="log-out" class="w-5 h-5"></i>
                    </button>
                    <span class="px-2 md:px-3 py-1 bg-slate-100 text-slate-600 rounded-full text-xs font-medium border border-slate-200 flex items-center shadow-sm shrink-0">
                        <i data-lucide="calendar" class="w-3 h-3 md:mr-1"></i> <span class="hidden md:inline">2026</span>
                    </span>
                </div>
            </header>

            <div id="app-content" class="flex-1 min-w-0 overflow-y-auto p-4 md:p-6 scroll-smooth">
                <!-- Content rendered here -->
            </div>
        </main>
    </div>

    <!-- Drawer / Modal -->
    <div id="drawer-overlay" class="fixed inset-0 bg-slate-900/40 backdrop-blur-sm z-40 hidden transition-opacity" onclick="app.closeDrawer()"></div>
    <div id="drawer" class="fixed top-0 right-0 h-full w-full md:w-[95vw] lg:w-[1000px] bg-white shadow-2xl z-50 transform translate-x-full transition-transform duration-300 flex flex-col">
        <div class="h-16 shrink-0 border-b border-slate-200 flex items-center justify-between px-4 md:px-6 bg-slate-50 gap-4">
            <h2 id="drawer-title" class="font-bold text-base md:text-lg text-slate-800 min-w-0 flex-1 truncate">Detalhes</h2>
            <button onclick="app.closeDrawer()" class="p-2 shrink-0 hover:bg-slate-200 rounded-full text-slate-500 transition-colors">
                <i data-lucide="x" class="w-5 h-5"></i>
            </button>
        </div>
        <div id="drawer-content" class="flex-1 min-w-0 overflow-y-auto p-4 md:p-6 bg-white">
            <!-- Details rendered here -->
        </div>
    </div>

    <script>
        // --- 1. STATE & DATA GENERATION ---
        const STATUSES = {
            'Pendente': { color: 'text-rose-600', bg: 'bg-rose-50', border: 'border-rose-200', icon: 'x-circle' },
            'Melhorar': { color: 'text-amber-600', bg: 'bg-amber-50', border: 'border-amber-200', icon: 'alert-triangle' },
            'Execucao': { color: 'text-blue-600', bg: 'bg-blue-50', border: 'border-blue-200', icon: 'clock' },
            'Pronto': { color: 'text-emerald-600', bg: 'bg-emerald-50', border: 'border-emerald-200', icon: 'check-circle' }
        };

        const STATUS_OPTIONS = [
            { value: 'Pendente', label: '❌ Pendente' },
            { value: 'Melhorar', label: '⚠️ Melhorar' },
            { value: 'Execucao', label: '⏳ Em Execução' },
            { value: 'Pronto', label: '✅ Pronto' }
        ];

        const MODULE_COLORS = {
            atas: { bg: 'bg-blue-50', iconBg: 'bg-blue-100', text: 'text-blue-600', border: 'border-blue-200', hover: 'hover:border-blue-400' },
            colegiado: { bg: 'bg-violet-50', iconBg: 'bg-violet-100', text: 'text-violet-600', border: 'border-violet-200', hover: 'hover:border-violet-400' },
            coordenadoria: { bg: 'bg-rose-50', iconBg: 'bg-rose-100', text: 'text-rose-600', border: 'border-rose-200', hover: 'hover:border-rose-400' },
            curriculo: { bg: 'bg-emerald-50', iconBg: 'bg-emerald-100', text: 'text-emerald-600', border: 'border-emerald-200', hover: 'hover:border-emerald-400' },
            discente: { bg: 'bg-fuchsia-50', iconBg: 'bg-fuchsia-100', text: 'text-fuchsia-600', border: 'border-fuchsia-200', hover: 'hover:border-fuchsia-400' },
            egressos: { bg: 'bg-orange-50', iconBg: 'bg-orange-100', text: 'text-orange-600', border: 'border-orange-200', hover: 'hover:border-orange-400' },
            estudos: { bg: 'bg-amber-50', iconBg: 'bg-amber-100', text: 'text-amber-600', border: 'border-amber-200', hover: 'hover:border-amber-400' },
            fe: { bg: 'bg-sky-50', iconBg: 'bg-sky-100', text: 'text-sky-600', border: 'border-sky-200', hover: 'hover:border-sky-400' },
            legal: { bg: 'bg-indigo-50', iconBg: 'bg-indigo-100', text: 'text-indigo-600', border: 'border-indigo-200', hover: 'hover:border-indigo-400' },
            planos: { bg: 'bg-teal-50', iconBg: 'bg-teal-100', text: 'text-teal-600', border: 'border-teal-200', hover: 'hover:border-teal-400' }
        };

        const uuid = () => 'id-' + Math.random().toString(36).substr(2, 9);

        // MEC Instrument Real Titles
        // Dimensão 1: Organização Didático-Pedagógica (24 itens - Nova Portaria)
        const MEC_DIM1 = [
            "Políticas institucionais no âmbito do curso",
            "Objetivos do curso",
            "Perfil profissional do egresso",
            "Estrutura curricular",
            "Conteúdos curriculares",
            "Metodologia",
            "Estágio curricular supervisionado. Obrigatório para cursos cujas DCN preveem o estágio supervisionado. NSA para cursos que não contemplam estágio no PPC (desde que não esteja previsto nas DCN)",
            "Estágio curricular supervisionado \u2013 relação com a rede de escolas da Educação Básica. Obrigatório para Licenciaturas. NSA para os demais cursos",
            "Estágio curricular supervisionado \u2013 relação teoria e prática. Obrigatório para licenciaturas. NSA para os demais cursos",
            "Atividades complementares. Obrigatório para cursos cujas DCN preveem atividades complementares. NSA para cursos que não contemplam atividades complementares no PPC (desde que não esteja previsto nas DCN)",
            "Trabalho de conclusão de curso (TCC). Obrigatório para cursos cujas DCN preveem TCC. NSA para cursos que não contemplam TCC no PPC (desde que não esteja previsto nas DCN)",
            "Apoio ao discente",
            "Gestão do curso e os processos de avaliação interna e externa",
            "Atividades de tutoria. Exclusivo para cursos na modalidade a distância e para cursos presenciais que ofertam disciplinas (integral ou parcialmente) na modalidade a distância (conforme Portaria nº 1.134, de 10 de outubro de 2016)",
            "Conhecimentos, habilidades e atitudes necessárias às atividades de tutoria. Exclusivo para cursos na modalidade a distância e para cursos presenciais que ofertam disciplinas (integral ou parcialmente) na modalidade a distância (conforme Portaria nº 1.134, de 10 de outubro de 2016)",
            "Tecnologias de Informação e Comunicação \u2013 TICs - no processo ensino-aprendizagem",
            "Ambiente Virtual de Aprendizagem (AVA). Exclusivo para cursos na modalidade a distância e para cursos presenciais que ofertam disciplinas (integral ou parcialmente) na modalidade a distância (conforme Portaria nº 1.134, de 10 de outubro de 2016)",
            "Material didático. NSA para cursos presenciais que não contemplam material didático no PPC",
            "Procedimentos de acompanhamento e de avaliação dos processos de ensino-aprendizagem",
            "Número de vagas",
            "Integração com as redes públicas de ensino. Obrigatório para licenciaturas. NSA para os cursos que não contemplam integração com as redes públicas de ensino no PPC",
            "Integração do curso com o sistema local e regional de saúde (SUS). Obrigatório para cursos da área da saúde que contemplam, nas DCN e/ou no PPC, a integração com o sistema local e regional de saúde/SUS",
            "Atividades práticas de ensino para áreas da saúde. Obrigatório para cursos da área da saúde que contemplam, nas DCN e/ou no PPC, a integração com o sistema local e regional de saúde/SUS",
            "Atividades práticas de ensino para licenciaturas. Obrigatório para licenciaturas. NSA para os demais cursos"
        ];
        // Dimensão 2: Corpo Docente e Tutorial (16 itens - Nova Portaria)
        const MEC_DIM2 = [
            "Núcleo Docente Estruturante (NDE)",
            "Equipe Multidisciplinar. Exclusivo para cursos na modalidade a distância e para cursos presenciais que ofertam disciplinas (integral ou parcialmente) na modalidade a distância conforme Portaria nº 1.134, de 10 de outubro de 2016)",
            "Atuação do coordenador",
            "Regime de trabalho do coordenador de curso",
            "Corpo Docente: titulação",
            "Regime de trabalho do corpo docente do curso",
            "Experiência Profissional Docente. Excluída a experiência no exercício da docência superior. NSA para cursos de licenciatura",
            "Experiência no exercício da docência na educação básica. Obrigatório para cursos de licenciatura e para CST da Rede Federal de Educação Profissional, Científica e Tecnológica. NSA para os demais cursos",
            "Experiência no exercício da docência superior",
            "Experiência no exercício da docência na educação a distância",
            "Experiência no exercício da tutoria na educação a distância. NSA para cursos totalmente presenciais",
            "Atuação do colegiado de curso ou equivalente",
            "Titulação e formação do corpo de tutores do curso. NSA para cursos totalmente presenciais",
            "Experiência do corpo de tutores em educação a distância. Exclusivo para cursos na modalidade a distância e para cursos presenciais que ofertam disciplinas (integral ou parcialmente) na modalidade a distância (conforme Portaria nº 1.134, de 10 de outubro de 2016)",
            "Interação entre tutores (presenciais – quando for o caso – e a distância), docentes e coordenadores de curso a distância. Exclusivo para cursos na modalidade a distância e para cursos presenciais que ofertam disciplinas (integral ou parcialmente) na modalidade a distância (conforme Portaria nº 1.134, de 10 de outubro de 2016)",
            "Produção científica, cultural, artística ou tecnológica"
        ];
        // Dimensão 3: Infraestrutura (18 itens - Nova Portaria)
        const MEC_DIM3 = [
            "Espaço de trabalho para docentes em tempo integral",
            "Espaço de trabalho para o coordenador",
            "Sala coletiva de professores. NSA para IES que possui espaço de trabalho individual para todos os docentes do curso",
            "Salas de aula. NSA para cursos a distância que não preveem atividades presenciais na sede",
            "Acesso dos alunos a equipamentos de informática",
            "Bibliografia básica por unidade curricular (UC)",
            "Bibliografia complementar por unidade curricular (UC)",
            "Laboratórios didáticos de formação básica. NSA para cursos que não utilizam laboratórios didáticos de formação básica, conforme PPC. Para cursos a distância, verificar os laboratórios especializados da sede e dos polos (cujas informações devem estar disponíveis na sede da instituição)",
            "Laboratórios didáticos de formação específica. NSA para cursos que não utilizam laboratórios didáticos de formação específica, conforme PPC. Para cursos a distância, verificar os laboratórios especializados da sede e dos polos (cujas informações devem estar disponíveis na sede da instituição)",
            "Laboratórios de ensino para a área de saúde. Obrigatório para os cursos da área de saúde, desde que contemplado no PPC e nas DCN",
            "Laboratórios de habilidades. Obrigatório para os cursos da área de saúde, desde que contemplado no PPC. NSA para os demais cursos",
            "Unidades hospitalares e complexo assistencial conveniados. Obrigatório para os cursos da área de saúde, desde que contemplado no PPC",
            "Biotérios. Obrigatório para os cursos da área de saúde, desde que contemplado no PPC. NSA para os demais cursos",
            "Processo de controle de produção ou distribuição de material didático (logística). NSA para cursos presenciais que não contemplam material didático no PPC",
            "Núcleo de práticas jurídicas: atividades básicas e arbitragem, negociação, conciliação, mediação e atividades jurídicas reais. Obrigatório para Cursos de Direito, desde que contemplado no PPC. NSA para os demais cursos",
            "Comitê de Ética em Pesquisa (CEP). Obrigatório para todos os cursos que contemplem, no PPC, a realização de pesquisa envolvendo seres humanos",
            "Comitê de Ética na Utilização de Animais (CEUA). Obrigatório para todos os cursos que contemplem no PPC a utilização de animais em suas pesquisas",
            "Ambientes profissionais vinculados ao curso. Exclusivo para cursos a distância com previsão no PPC de utilização de ambientes profissionais"
        ];

        const generateFE = () => {
            const fe = { dim1: [], dim2: [], dim3: [] };
            MEC_DIM1.forEach((t, i) => fe.dim1.push({ id: `fe-1-${i+1}`, title: `1.${i+1} - ${t}`, status: 'Pendente', text: '' }));
            MEC_DIM2.forEach((t, i) => fe.dim2.push({ id: `fe-2-${i+1}`, title: `2.${i+1} - ${t}`, status: 'Pendente', text: '' }));
            MEC_DIM3.forEach((t, i) => fe.dim3.push({ id: `fe-3-${i+1}`, title: `3.${i+1} - ${t}`, status: 'Pendente', text: '' }));
            return fe;
        };

        const generateAtas = () => {
            const years = [2024, 2025, 2026];
            const types = ['NDE', 'Colegiado', 'Reunião Docente', 'Rep. Discentes'];
            const data = {};
            years.forEach(y => {
                data[y] = {};
                types.forEach(t => {
                    data[y][t] = [
                        { id: `ata-${y}-${t.replace(/\s+/g,'')}-1`, label: '1º Sem / Ata 1', status: 'Pendente' },
                        { id: `ata-${y}-${t.replace(/\s+/g,'')}-2`, label: '1º Sem / Ata 2', status: 'Pendente' },
                        { id: `ata-${y}-${t.replace(/\s+/g,'')}-3`, label: '2º Sem / Ata 1', status: 'Pendente' },
                        { id: `ata-${y}-${t.replace(/\s+/g,'')}-4`, label: '2º Sem / Ata 2', status: 'Pendente' }
                    ];
                });
            });
            return data;
        };

        const generatePlanosDeEnsino = (semestersCount) => {
            const semesters = {};
            for(let i=1; i<=semestersCount; i++) {
                semesters[`${i}º Semestre`] = [];
                for(let d=1; d<=7; d++) {
                    semesters[`${i}º Semestre`].push({ id: uuid(), label: `Disciplina ${d}`, status: 'Pendente', isEditing: false });
                }
            }
            return semesters;
        };

        const DISCENTE_ROWS = [
            "Vagas Autorizadas Noturno",
            "Vagas Preenchidas/Ingressantes (Noturno)",
            "Vagas Ociosas (Noturno)",
            "Matriculados Totais (Noturno)",
            "Estrangeiros (Noturno)",
            "Desistentes (Cancelados / trancados) (Noturno)",
            "Vagas Autorizadas Matutino",
            "Vagas Preenchidas/Ingressantes (Matutino)",
            "Vagas Ociosas (Matutino)",
            "Matriculados Totais (Matutino)",
            "Estrangeiros (Matutino)",
            "Desistentes (Cancelados / trancados) (Matutino)",
            "Matriculados em TCC",
            "Participantes de projetos de extensão",
            "Participantes de Projetos de Pesquisa",
            "Matriculados em Estágio",
            "Participantes de Programas Internos e/ou Externos de Financiamento",
            "Quantidade Formandos"
        ];
        const DISCENTE_SEMS = ['2024.1', '2024.2', '2025.1', '2025.2', '2026.1', '2026.2'];

        const generateQuantitativo = () => {
            return DISCENTE_ROWS.map(row => {
                let vals = {};
                DISCENTE_SEMS.forEach(s => vals[s] = '0');
                return { label: row, values: vals };
            });
        };

        const initialState = {
            isAuthenticated: true, // Autenticação gerenciada pelo PHP (sessão)
            currentRoute: 'dashboard',
            currentCourseId: null,
            activeDrawerModule: null,
            planosSortBy: 'professor',
            showAddPlanoForm: false,   
            activeCoordenadoriaCategoryForm: null,
            activeEgressosCategoryForm: null,
            activeDiscenteForm: false,
            courses: [
                { id: 'admin', name: 'Administração', city: 'Salto', icon: 'briefcase', semesters: 8, modules: {}, pdi: null, ppc: null },
                { id: 'procger', name: 'Processos Gerenciais', city: 'Salto', icon: 'bar-chart-2', semesters: 4, modules: {}, pdi: null, ppc: null },
                { id: 'gestqual', name: 'Gestão da Qualidade', city: 'Salto', icon: 'award', semesters: 4, modules: {}, pdi: null, ppc: null }
            ]
        };

        // Initialize Complex Structures
        initialState.courses.forEach(c => {
            c.modules = {
                atas: { title: 'Ciclo de Atas', icon: 'folder-open', type: 'atas', prazo: '15/11/2026', avaliado: 'Não', data: generateAtas() },
                colegiado: {
                    title: 'Colegiado e Corpo Docente', icon: 'users', type: 'colegiado', prazo: '30/11/2026', avaliado: 'Não',
                    data: {
                        documentos: [{ id: uuid(), label: 'Registro/Ata do Colegiado', status: 'Pendente' }],
                        membros: [
                            {
                                id: uuid(),
                                nome: 'Alex Sandro Benetti Dias',
                                status: 'Pronto',
                                nde: 'Sim', cpf: '156.580.188-11', titulacao: 'Doutor', regime: '20 h', vinculo: 'Integral',
                                tempoCurso: '210 meses', tempoBasica: '18 anos', tempoSup: '18 anos', tempoSupEad: '2 anos (síncrono)', tempoFora: '32 anos',
                                compPedagogica: 'Sim',
                                artigosArea: '2', artigosOutras: '0', livrosArea: '0', livrosOutras: '0',
                                anaisCompletos: '2', anaisResumos: '2', traducoes: '0',
                                piDepositada: '0', piRegistrada: '0', projetosTecnicos: '1', prodDidatica: '2',
                                lattes: '', linkedin: ''
                            }
                        ] 
                    }
                },
                coordenadoria: {
                    title: 'Coordenadoria / Ações', icon: 'inbox', type: 'coordenadoria', prazo: '05/12/2026', avaliado: 'Não',
                    data: {
                        'Atendimento Coordenação': [],
                        'Tutorial': [],
                        'Email Encaminhados': [],
                        'Ações de Apoio': [],
                        'Salas de Aula': [],
                        'Sala dos Professores': [],
                        'Sala do NDE': [],
                        'Sala da Coordenação': [],
                        'Laboratórios': [],
                        'Auditórios': [],
                        'Biblioteca': [],
                        'Cantinas': [],
                        'CAA': [],
                        'Estacionamento': [],
                        'Reitoria': []
                    }
                },
                curriculo: { 
                    title: 'Estrutura Curricular', icon: 'book-open', type: 'curriculo', prazo: '20/12/2026', avaliado: 'Não',
                    data: {
                        basicos: [{ id: uuid(), label: 'Matriz Curricular (Grade)', status: 'Pendente' }, { id: uuid(), label: 'Ementário Geral', status: 'Pendente' }, { id: uuid(), label: 'Ementário NDE/Biblioteca', status: 'Pendente' }, { id: uuid(), label: 'Relação de Disciplinas', status: 'Pendente' }],
                        geral: [{ id: uuid(), label: 'Plano de Ensino Geral (Arquivo Único com todos)', status: 'Pendente' }],
                        planosDeEnsino: generatePlanosDeEnsino(c.semesters)
                    }
                },
                discente: { 
                    title: 'Discente/Projetos/Trabalhos', icon: 'graduation-cap', type: 'discente', prazo: '25/11/2026', avaliado: 'Não',
                    data: {
                        quantitativoItem: { id: uuid(), label: 'Quadro Resumo (Upload do Documento de Quantitativo)', status: 'Pendente', attachment: null },
                        quantitativoTable: generateQuantitativo(),
                        itinerario: {
                            normas: { id: uuid(), label: 'Normas e Regras do Itinerário Extensionista', status: 'Pendente', attachment: null },
                            projetos: []
                        },
                        grupos: [
                            { category: 'Projetos e Extensão', items: [{ id: uuid(), label: 'Projetos de Extensão e Cultura', status: 'Pendente' }, { id: uuid(), label: 'Convênios, Parcerias e Intercâmbio', status: 'Pendente' }] },
                            { category: 'TCC e Produção', items: [{ id: uuid(), label: 'Regulamento/Manual do TCC', status: 'Pendente' }, { id: uuid(), label: 'Repositório de Trabalhos/TCCs', status: 'Pendente' }, { id: uuid(), label: 'Produção Científica Discente', status: 'Pendente' }] },
                            { category: 'Atividades Complementares e Estágio', items: [{ id: uuid(), label: 'Regulamento de Atividades Complementares', status: 'Pendente' }, { id: uuid(), label: 'Quadro de Atividades', status: 'Pendente' }, { id: uuid(), label: 'Regulamento de Estágio Supervisionado', status: 'Pendente' }] },
                            { category: 'Apoio e Acompanhamento', items: [{ id: uuid(), label: 'Apoio Psicopedagógico ao Discente', status: 'Pendente' }, { id: uuid(), label: 'Acompanhamento de Egressos', status: 'Pendente' }] }
                        ]
                    }
                },
                egressos: {
                    title: 'Egressos', icon: 'user-check', type: 'egressos', prazo: '10/12/2026', avaliado: 'Não',
                    data: {
                        'Objetivos do Egresso': [],
                        'Relação com os Egressos': [],
                        'Fotos e Ações': []
                    }
                },
                estudos: { 
                    title: 'Estudos e Estratégia', icon: 'target', type: 'docs_grouped', prazo: '18/11/2026', avaliado: 'Não',
                    data: [ { category: 'Estudos Básicos', items: [{ id: uuid(), label: 'Estudo de Vagas', status: 'Pendente' }, { id: uuid(), label: 'Estudo Docente', status: 'Pendente' }, { id: uuid(), label: 'Plano de Carreira', status: 'Pendente' }, { id: uuid(), label: 'Contexto Regional', status: 'Pendente' }] } ]
                },
                fe: { title: 'Formulário Eletrônico', icon: 'monitor', type: 'fe', prazo: '10/10/2026', avaliado: 'Não', data: generateFE() },
                legal: { 
                    title: 'Portarias e Atos Legais', icon: 'scale', type: 'docs_grouped', prazo: '12/10/2026', avaliado: 'Não',
                    data: [
                        { category: 'Ato de Criação/Autorização', items: [{ id: uuid(), label: 'Ato de Criação/Autorização', status: 'Pendente' }] },
                        { category: 'Núcleo Docente Estruturante (NDE)', items: [{ id: uuid(), label: 'Portaria NDE (Atual)', status: 'Pendente' }, { id: uuid(), label: 'Portaria NDE (Anterior)', status: 'Pendente' }] },
                        { category: 'Colegiado e CPA', items: [{ id: uuid(), label: 'Portaria Colegiado', status: 'Pendente' }, { id: uuid(), label: 'Portaria CPA', status: 'Pendente' }] }
                    ]
                },
                planos: { 
                    title: 'Planos de Ação e Avaliação', icon: 'clipboard-list', type: 'planos', prazo: '28/11/2026', avaliado: 'Não',
                    data: {
                        coordenacao: [{ id: uuid(), label: 'Plano Coordenação 2024', status: 'Pendente' }, { id: uuid(), label: 'Plano Coordenação 2025', status: 'Pendente' }, { id: uuid(), label: 'Plano Coordenação 2026', status: 'Pendente' }],
                        cpa: [{ id: uuid(), label: 'CPA 2024.1', status: 'Pendente' }, { id: uuid(), label: 'CPA 2024.2', status: 'Pendente' }, { id: uuid(), label: 'CPA 2025.1', status: 'Pendente' }, { id: uuid(), label: 'CPA 2025.2', status: 'Pendente' }, { id: uuid(), label: 'CPA 2026.1', status: 'Pendente' }, { id: uuid(), label: 'CPA 2026.2', status: 'Pendente' }],
                        melhorias: [{ id: uuid(), label: 'Plano de Melhorias Contínuas', status: 'Pendente' }],
                        docentes: [] 
                    }
                }
            };
        });

        // --- 2. CORE LOGIC ---
        const debounce = (func, wait) => {
            let timeout;
            return function executedFunction(...args) {
                const later = () => { clearTimeout(timeout); func(...args); };
                clearTimeout(timeout);
                timeout = setTimeout(later, wait);
            };
        };

        const app = {
            state: JSON.parse(JSON.stringify(initialState)),

            async saveState() {
                try {
                    const response = await fetch('ajax_handler.php?action=save_app_state', {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify({ courses: this.state.courses })
                    });
                    if (!response.ok) console.error("Erro ao salvar estado.");
                } catch (e) {
                    console.error("Exceção ao salvar:", e);
                }
            },

            async loadState() {
                try {
                    const response = await fetch('ajax_handler.php?action=get_app_state');
                    if (response.ok) {
                        const data = await response.json();
                        if (data && data.courses && Array.isArray(data.courses)) {
                            // Merge modules to ensure all functions like generator work if new ones added
                            data.courses.forEach(c => {
                                const initialCourse = initialState.courses.find(ic => ic.id === c.id);
                                if (initialCourse) {
                                    // keep default modules if missing
                                    c.modules = { ...initialCourse.modules, ...c.modules };
                                    
                                    // Sincronizar títulos do FE com os arrays MEC_DIM atuais
                                    // Preserva texto e status, mas atualiza o título (nova portaria)
                                    if (c.modules.fe && c.modules.fe.data) {
                                        const freshFE = generateFE();
                                        ['dim1', 'dim2', 'dim3'].forEach(dimKey => {
                                            if (c.modules.fe.data[dimKey] && freshFE[dimKey]) {
                                                freshFE[dimKey].forEach((freshItem, idx) => {
                                                    if (c.modules.fe.data[dimKey][idx]) {
                                                        // Atualiza o título mas preserva texto e status
                                                        c.modules.fe.data[dimKey][idx].title = freshItem.title;
                                                        c.modules.fe.data[dimKey][idx].id = freshItem.id;
                                                    } else {
                                                        // Item novo que não existia antes
                                                        c.modules.fe.data[dimKey].push(freshItem);
                                                    }
                                                });
                                                // Remove itens excedentes se a nova lista for menor
                                                if (c.modules.fe.data[dimKey].length > freshFE[dimKey].length) {
                                                    c.modules.fe.data[dimKey].length = freshFE[dimKey].length;
                                                }
                                            }
                                        });
                                    }
                                }
                            });
                            this.state.courses = data.courses;
                        }
                    }
                } catch (e) {
                    console.error("Erro ao carregar estado do banco, usando default:", e);
                }
                this.render();
            },


            login() {
                const pwd = document.getElementById('login-password').value;
                if(pwd === '1010') {
                    this.state.isAuthenticated = true;
                    document.getElementById('login-layout').classList.add('hidden');
                    document.getElementById('app-layout').classList.remove('hidden');
                    this.render();
                } else {
                    alert('Senha incorreta! A senha do coordenador é 1010.');
                }
            },

            logout() {
                if(confirm("Deseja realmente sair?")) {
                    window.location.href = 'logout.php';
                }
            },

            getAllItemsForModule(module) {
                let items = [];
                const extract = (obj) => {
                    if (Array.isArray(obj)) {
                        obj.forEach(item => {
                            if (item && item.status && item.id) items.push(item);
                            else extract(item);
                        });
                    } else if (typeof obj === 'object' && obj !== null) {
                        if (obj.status && obj.id) items.push(obj);
                        else Object.values(obj).forEach(val => extract(val));
                    }
                };
                extract(module.data);
                return items;
            },

            calculateProgress(items) {
                if(!items || items.length === 0) return 0;
                const done = items.filter(i => i.status === 'Pronto').length;
                return Math.round((done / items.length) * 100);
            },

            getCourseProgress(course) {
                let allItems = [];
                Object.values(course.modules).forEach(m => { allItems = allItems.concat(this.getAllItemsForModule(m)); });
                return this.calculateProgress(allItems);
            },

            navigate(route, courseId = null) {
                this.state.currentRoute = route;
                this.state.currentCourseId = courseId;
                this.render();
            },

            openDrawer(moduleId) {
                this.state.activeDrawerModule = moduleId;
                this.state.showAddPlanoForm = false;
                this.state.activeCoordenadoriaCategoryForm = null;
                this.state.activeEgressosCategoryForm = null;
                this.state.activeDiscenteForm = false;
                const drawer = document.getElementById('drawer');
                const overlay = document.getElementById('drawer-overlay');
                this.renderDrawerContent();
                overlay.classList.remove('hidden');
                setTimeout(() => { drawer.classList.remove('translate-x-full'); }, 10);
            },

            closeDrawer() {
                const drawer = document.getElementById('drawer');
                const overlay = document.getElementById('drawer-overlay');
                drawer.classList.add('translate-x-full');
                setTimeout(() => { 
                    overlay.classList.add('hidden'); 
                    this.state.activeDrawerModule = null; 
                    this.state.activeCoordenadoriaCategoryForm = null; 
                    this.state.activeEgressosCategoryForm = null; 
                    this.state.activeDiscenteForm = false;
                }, 300);
            },

            findItemAndExecute(courseId, moduleId, itemId, callback) {
                const course = this.state.courses.find(c => c.id === courseId);
                const module = course.modules[moduleId];
                
                let found = false;
                const search = (obj) => {
                    if (found) return;
                    if (Array.isArray(obj)) {
                        obj.forEach(item => {
                            if (item && item.id === itemId) { callback(item); found = true; }
                            else if (typeof item === 'object') search(item);
                        });
                    } else if (typeof obj === 'object' && obj !== null) {
                        if (obj.id === itemId) { callback(obj); found = true; }
                        else Object.values(obj).forEach(val => search(val));
                    }
                };
                search(module.data);
                
                if(found && this.state.activeDrawerModule) {
                    this.renderDrawerContent();
                    this.render();
                }
            },

            updateStatus(courseId, moduleId, itemId, newStatus) {
                this.findItemAndExecute(courseId, moduleId, itemId, (item) => {
                    item.status = newStatus;
                });
            },

            // --- Lógica Central de Arquivos (Upload / Download) ---
            async handleUpload(courseId, moduleId, itemId, fileInput) {
                if(!fileInput.files || fileInput.files.length === 0) return;
                const file = fileInput.files[0];
                
                // Mudar UI pra loading
                const span = fileInput.parentElement.querySelector('span');
                if (span) span.innerText = 'Enviando...';

                const formData = new FormData();
                formData.append('file', file);
                formData.append('course_id', courseId);
                formData.append('item_id', itemId);

                try {
                    const res = await fetch('ajax_handler.php?action=upload_file', {
                        method: 'POST',
                        body: formData
                    });
                    const data = await res.json();
                    if(data.success) {
                        this.findItemAndExecute(courseId, moduleId, itemId, (item) => {
                            item.attachment = data.filename;
                            item.attachmentPath = data.path; // Store actual path
                        });
                    } else {
                        alert("Erro no upload: " + data.error);
                        if (span) span.innerText = 'Erro';
                    }
                } catch(e) {
                    alert("Erro ao enviar arquivo.");
                    if (span) span.innerText = 'Erro';
                }
            },

            removeAttachment(courseId, moduleId, itemId) {
                if(confirm("Tem certeza que deseja remover este anexo?")) {
                    this.findItemAndExecute(courseId, moduleId, itemId, (item) => {
                        item.attachment = null;
                    });
                }
            },

            downloadAttachment(attachmentPath, filename) {
                // Monta a URL do endpoint PHP de download
                // attachmentPath = caminho físico (ex: uploads/69xxx.docx)
                // filename = nome original amigável para o usuário
                const path     = encodeURIComponent(attachmentPath || '');
                const name     = encodeURIComponent(filename || '');
                const url      = `ajax_handler.php?action=download_file&path=${path}&filename=${name}`;
                // Abre em nova aba: o browser baixa o arquivo sem sair da página
                window.open(url, '_blank');
            },

            generateUploadDownloadHTML(courseId, moduleId, item) {
                if (item.attachment) {
                    // Usa attachmentPath (caminho físico) para o download real
                    // Fallback: se não houver attachmentPath, tenta montar o path a partir do attachment
                    const dlPath = item.attachmentPath || '';
                    const dlName = item.attachment || '';
                    return `
                        <div class="flex items-center space-x-1 shrink-0">
                            <button onclick="app.downloadAttachment('${dlPath}', '${dlName}')" class="flex items-center px-2 py-1.5 bg-emerald-50 border border-emerald-200 rounded text-xs font-semibold text-emerald-700 hover:bg-emerald-100 transition-colors whitespace-nowrap" title="Baixar ${dlName}">
                                <i data-lucide="download" class="w-3.5 h-3.5 mr-1"></i> <span class="hidden sm:inline truncate max-w-[80px]" title="${dlName}">Baixar</span>
                            </button>
                            <button onclick="app.removeAttachment('${courseId}', '${moduleId}', '${item.id}')" class="p-1.5 text-slate-400 hover:text-rose-600 hover:bg-rose-50 border border-transparent hover:border-rose-100 rounded transition-colors" title="Remover anexo">
                                <i data-lucide="trash-2" class="w-3.5 h-3.5"></i>
                            </button>
                        </div>
                    `;
                } else {
                    return `
                        <label class="flex items-center px-2 py-1.5 bg-slate-50 border border-slate-200 rounded text-xs font-medium text-slate-600 hover:bg-slate-100 cursor-pointer transition-colors whitespace-nowrap shrink-0">
                            <i data-lucide="upload-cloud" class="w-3.5 h-3.5 mr-1"></i> Upload
                            <input type="file" class="hidden" onchange="app.handleUpload('${courseId}', '${moduleId}', '${item.id}', this)">
                        </label>
                    `;
                }
            },

            // --- Lógica PDI / PPC ---
            async handleCourseDocUpload(courseId, docType, fileInput) {
                if(!fileInput.files || fileInput.files.length === 0) return;
                const file = fileInput.files[0];

                const formData = new FormData();
                formData.append('file', file);
                formData.append('course_id', courseId);
                formData.append('item_id', docType); // reutiliza campo para identificação

                try {
                    const res = await fetch('ajax_handler.php?action=upload_file', {
                        method: 'POST',
                        body: formData
                    });
                    const data = await res.json();
                    if (data.success) {
                        const course = this.state.courses.find(c => c.id === courseId);
                        course[docType]          = data.filename;   // nome original amigável
                        course[docType + 'Path'] = data.path;       // caminho físico para download
                        this.saveState();
                        this.render();
                    } else {
                        alert('Erro no upload: ' + (data.error || 'Falha desconhecida'));
                    }
                } catch(e) {
                    alert('Erro ao enviar arquivo. Verifique a conexão.');
                }
            },

            removeCourseDoc(courseId, docType) {
                if(confirm('Tem certeza que deseja remover este documento principal?')) {
                    const course = this.state.courses.find(c => c.id === courseId);
                    course[docType] = null;
                    this.render();
                }
            },

            generateCourseDocHTML(courseId, docType, filename, label) {
                if (filename) {
                    // Para PDI/PPC: o curso armazena só o filename original (upload antigo sem path físico)
                    // Tenta encontrar o path real a partir do estado do curso
                    const course   = this.state.courses.find(c => c.id === courseId);
                    const dlPath   = (course && course[docType + 'Path']) ? course[docType + 'Path'] : '';
                    const dlName   = filename;
                    return `
                        <div class="flex items-center space-x-2 bg-emerald-50 border border-emerald-200 p-2 rounded-xl shadow-md w-full sm:w-auto shrink-0">
                            <span class="text-sm font-bold text-emerald-800 px-3 hidden md:inline shrink-0">${label}:</span>
                            <button onclick="app.downloadAttachment('${dlPath}', '${dlName}')" class="flex items-center justify-center w-full sm:w-auto px-4 py-2 bg-white border border-emerald-300 rounded-lg text-sm font-bold text-emerald-700 hover:bg-emerald-100 transition-colors truncate max-w-full sm:max-w-[150px]" title="Baixar ${dlName}">
                                <i data-lucide="download" class="w-4 h-4 mr-2 shrink-0"></i> <span class="truncate">${dlName}</span>
                            </button>
                            <button onclick="app.removeCourseDoc('${courseId}', '${docType}')" class="p-2 text-slate-400 hover:text-rose-600 rounded-lg hover:bg-rose-50 transition-colors shrink-0" title="Remover Documento">
                                <i data-lucide="trash-2" class="w-4 h-4"></i>
                            </button>
                        </div>
                    `;
                } else {
                    return `
                        <label class="flex items-center justify-center w-full sm:w-auto px-4 py-2.5 bg-brand-50 border border-brand-300 rounded-xl text-sm font-bold text-brand-800 hover:bg-brand-100 cursor-pointer transition-colors shadow-md shrink-0">
                            <i data-lucide="upload-cloud" class="w-5 h-5 mr-2 shrink-0"></i> <span class="truncate">${label}</span>
                            <input type="file" class="hidden" onchange="app.handleCourseDocUpload('${courseId}', '${docType}', this)">
                        </label>
                    `;
                }
            },

            // --- Lógica Avaliação de Módulo ---
            updateModuleAvaliado(courseId, moduleId, value) {
                const course = this.state.courses.find(c => c.id === courseId);
                course.modules[moduleId].avaliado = value;
                this.render();
            },

            // --- Outras Funções Internas ---
            updateFEText(courseId, itemId, textPath, value) {
                const course = this.state.courses.find(c => c.id === courseId);
                const dim = course.modules.fe.data[textPath];
                const item = dim.find(i => i.id === itemId);
                if(item) item.text = value;
                
                const counter = document.getElementById(`count-${itemId}`);
                if(counter) {
                    counter.innerText = `${value.length} / 8000 caracteres`;
                    counter.className = `text-xs mt-1 text-right ${value.length > 7900 ? 'text-rose-600 font-bold' : 'text-slate-400'}`;
                }
                this.initAutoSave();
            },

            openAddPlanoForm() {
                this.state.showAddPlanoForm = true;
                this.renderDrawerContent();
            },

            cancelAddPlanoForm() {
                this.state.showAddPlanoForm = false;
                this.renderDrawerContent();
            },

            saveNovoPlanoDocente(courseId) {
                const nomeInput = document.getElementById('new-plano-nome');
                const discInput = document.getElementById('new-plano-disc');
                const semInput = document.getElementById('new-plano-sem');
                const anoInput = document.getElementById('new-plano-ano');
                const fileInput = document.getElementById('new-plano-file');

                const nome = nomeInput.value.trim();
                const disc = discInput.value.trim();
                const sem = semInput.value;
                const ano = anoInput.value;

                if(!nome || !disc) {
                    alert('Por favor, preencha o Nome do Professor e a Disciplina antes de salvar.');
                    return;
                }

                const course = this.state.courses.find(c => c.id === courseId);
                course.modules.planos.data.docentes.push({
                    id: uuid(),
                    nome: nome,
                    disciplina: disc,
                    semestre: sem,
                    ano: ano,
                    label: `${disc} (${sem} / ${ano})`,
                    status: 'Pendente',
                    attachment: fileInput.files.length > 0 ? fileInput.files[0].name : null
                });

                this.state.showAddPlanoForm = false;
                this.render();
                this.renderDrawerContent();
            },

            changePlanosSort(value) {
                this.state.planosSortBy = value;
                this.renderDrawerContent();
            },

            updateQuantitativo(courseId, rowIndex, sem, value) {
                const course = this.state.courses.find(c => c.id === courseId);
                course.modules.discente.data.quantitativoTable[rowIndex].values[sem] = value;
                
                let total = 0;
                DISCENTE_SEMS.forEach(s => {
                    total += parseInt(course.modules.discente.data.quantitativoTable[rowIndex].values[s]) || 0;
                });
                
                const totalEl = document.getElementById(`total-${courseId}-${rowIndex}`);
                if(totalEl) totalEl.innerText = total;
            },

            openAddItinerarioForm() {
                this.state.activeDiscenteForm = true;
                this.renderDrawerContent();
            },

            cancelAddItinerarioForm() {
                this.state.activeDiscenteForm = false;
                this.renderDrawerContent();
            },

            saveNovoProjetoItinerario(courseId) {
                const turmaInput = document.getElementById('new-itin-turma');
                const anoInput = document.getElementById('new-itin-ano');
                const fileInput = document.getElementById('new-itin-file');

                const turma = turmaInput.value.trim();
                const ano = anoInput.value;

                if(!turma) {
                    alert('Por favor, preencha a Turma antes de salvar.');
                    return;
                }

                const course = this.state.courses.find(c => c.id === courseId);
                course.modules.discente.data.itinerario.projetos.push({
                    id: uuid(),
                    turma: turma,
                    ano: ano,
                    label: `Turma: ${turma}`,
                    status: 'Pendente',
                    attachment: fileInput.files.length > 0 ? fileInput.files[0].name : null
                });

                this.state.activeDiscenteForm = false;
                this.render();
                this.renderDrawerContent();
            },

            openAddCoordenadoriaForm(category) {
                this.state.activeCoordenadoriaCategoryForm = category;
                this.renderDrawerContent();
            },

            cancelAddCoordenadoriaForm() {
                this.state.activeCoordenadoriaCategoryForm = null;
                this.renderDrawerContent();
            },

            saveNovaCoordenadoria(courseId, category) {
                const INFRA_CATEGORIES = ['Salas de Aula', 'Sala dos Professores', 'Sala do NDE', 'Sala da Coordenação', 'Laboratórios', 'Auditórios', 'Biblioteca', 'Cantinas', 'CAA', 'Estacionamento', 'Reitoria'];
                const isInfra = INFRA_CATEGORIES.includes(category);
                
                const course = this.state.courses.find(c => c.id === courseId);
                const fileInput = document.getElementById('new-coord-file');
                const attachment = fileInput && fileInput.files.length > 0 ? fileInput.files[0].name : null;

                if (isInfra) {
                    const campus = document.getElementById('new-coord-campus').value.trim();
                    const bloco = document.getElementById('new-coord-bloco').value.trim();
                    const sala = document.getElementById('new-coord-sala').value.trim();

                    if(!campus || !sala) {
                        alert('Por favor, preencha o Campus e a Identificação do Espaço.');
                        return;
                    }

                    course.modules.coordenadoria.data[category].push({
                        id: uuid(),
                        campus: campus,
                        bloco: bloco,
                        sala: sala,
                        isInfra: true,
                        label: `Sala/Local: ${sala} (Campus: ${campus}${bloco ? ' | Bloco: '+bloco : ''})`, 
                        status: 'Pendente',
                        attachment: attachment
                    });
                } else {
                    const titulo = document.getElementById('new-coord-titulo').value.trim();
                    const sem = document.getElementById('new-coord-sem').value;
                    const ano = document.getElementById('new-coord-ano').value;
                    const acao = document.getElementById('new-coord-acao').value.trim();

                    if(!titulo) {
                        alert('Por favor, preencha o campo "O que é?" (Título) antes de salvar.');
                        return;
                    }

                    course.modules.coordenadoria.data[category].push({
                        id: uuid(),
                        titulo: titulo,
                        semestre: sem,
                        ano: ano,
                        acao: acao,
                        isInfra: false,
                        label: titulo,
                        status: 'Pendente',
                        attachment: attachment
                    });
                }

                this.state.activeCoordenadoriaCategoryForm = null;
                this.render();
                this.renderDrawerContent();
            },

            openAddEgressosForm(category) {
                this.state.activeEgressosCategoryForm = category;
                this.renderDrawerContent();
            },

            cancelAddEgressosForm() {
                this.state.activeEgressosCategoryForm = null;
                this.renderDrawerContent();
            },

            saveNovoEgresso(courseId, category) {
                const acaoInput = document.getElementById('new-egresso-acao');
                const anoInput = document.getElementById('new-egresso-ano');
                const fileInput = document.getElementById('new-egresso-file');

                const acao = acaoInput.value.trim();
                const ano = anoInput.value;

                if(!acao) {
                    alert('Por favor, preencha a Ação/Atividade antes de salvar.');
                    return;
                }

                const course = this.state.courses.find(c => c.id === courseId);
                course.modules.egressos.data[category].push({
                    id: uuid(),
                    acao: acao,
                    ano: ano,
                    label: acao,
                    status: 'Pendente',
                    attachment: fileInput.files.length > 0 ? fileInput.files[0].name : null
                });

                this.state.activeEgressosCategoryForm = null;
                this.render();
                this.renderDrawerContent();
            },

            addMembroColegiado(courseId) {
                const course = this.state.courses.find(c => c.id === courseId);
                course.modules.colegiado.data.membros.push({
                    id: uuid(),
                    nome: '', 
                    status: 'Pendente',
                    nde: 'Não', cpf: '', titulacao: '', regime: '', vinculo: '',
                    tempoCurso: '', tempoBasica: '', tempoSup: '', tempoSupEad: '', tempoFora: '',
                    compPedagogica: 'Não',
                    artigosArea: '', artigosOutras: '', livrosArea: '', livrosOutras: '',
                    anaisCompletos: '', anaisResumos: '', traducoes: '',
                    piDepositada: '', piRegistrada: '', projetosTecnicos: '', prodDidatica: '',
                    lattes: '', linkedin: ''
                });
                this.render();
                this.renderDrawerContent();
                
                setTimeout(() => {
                    const tableContainer = document.querySelector('.table-scroll');
                    if(tableContainer) tableContainer.scrollLeft = 0; 
                }, 50);
            },

            updateMembro(courseId, membroId, field, value) {
                const course = this.state.courses.find(c => c.id === courseId);
                const membro = course.modules.colegiado.data.membros.find(m => m.id === membroId);
                if(membro) {
                    membro[field] = value;
                    if(field === 'lattes' || field === 'linkedin') {
                       this.renderDrawerContent(); 
                    }
                }
            },

            toggleEditDisciplina(courseId, semesterId, itemId) {
                const course = this.state.courses.find(c => c.id === courseId);
                const item = course.modules.curriculo.data.planosDeEnsino[semesterId].find(i => i.id === itemId);
                if(item) item.isEditing = !item.isEditing;
                this.renderDrawerContent();
            },

            saveDisciplinaName(courseId, semesterId, itemId, inputId) {
                const course = this.state.courses.find(c => c.id === courseId);
                const item = course.modules.curriculo.data.planosDeEnsino[semesterId].find(i => i.id === itemId);
                const newName = document.getElementById(inputId).value;
                if(item && newName.trim() !== '') {
                    item.label = newName;
                    item.isEditing = false;
                }
                this.renderDrawerContent();
            },


            _autoSave: null,
            initAutoSave() {
                if (!this._autoSave) {
                    this._autoSave = debounce(() => this.saveState(), 1500);
                }
                this._autoSave();
            },

            // --- 3. RENDERING ---
            render() {
                if (!this.state.isAuthenticated) return; // Segurança caso render dispare antes do login
                this.initAutoSave();
                
                this.renderNav();
                const contentArea = document.getElementById('app-content');
                if(this.state.currentRoute === 'dashboard') {
                    document.getElementById('page-title').innerText = 'Quadro Geral de Prontidão';
                    document.getElementById('page-subtitle').innerText = 'Visão comparativa dos cursos';
                    contentArea.innerHTML = this.templateDashboard();
                } else {
                    const course = this.state.courses.find(c => c.id === this.state.currentCourseId);
                    document.getElementById('page-title').innerText = 'Gestão do Curso';
                    document.getElementById('page-subtitle').innerText = 'Painel de Indicadores e Evidências';
                    contentArea.innerHTML = this.templateCourse(course);
                }
                lucide.createIcons();
            },

            renderNav() {
                const nav = document.getElementById('nav-menu');
                let html = `
                    <button onclick="app.navigate('dashboard')" class="w-full flex items-center p-3 rounded-xl mb-1 transition-colors ${this.state.currentRoute === 'dashboard' ? 'bg-brand-50 text-brand-700 font-semibold' : 'text-slate-600 hover:bg-slate-100'}">
                        <i data-lucide="layout-dashboard" class="w-5 h-5 md:mr-3 shrink-0"></i>
                        <span class="hidden md:inline truncate">Dashboard</span>
                    </button>
                    <div class="hidden md:block text-xs font-semibold text-slate-400 uppercase tracking-wider mt-6 mb-2 px-3 truncate">Cursos</div>
                `;
                this.state.courses.forEach(c => {
                    const isActive = this.state.currentRoute === 'course' && this.state.currentCourseId === c.id;
                    html += `
                        <button onclick="app.navigate('course', '${c.id}')" class="w-full flex items-center p-3 rounded-xl mb-1 transition-colors group ${isActive ? 'bg-slate-800 text-white shadow-md' : 'text-slate-600 hover:bg-slate-100'}">
                            <i data-lucide="${c.icon}" class="w-5 h-5 md:mr-3 shrink-0 ${isActive ? 'text-brand-400' : 'text-slate-400 group-hover:text-slate-600'}"></i>
                            <span class="hidden md:inline truncate text-sm">${c.name}</span>
                        </button>
                    `;
                });
                nav.innerHTML = html;
            },

            templateDashboard() {
                let html = `<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 md:gap-6">`;
                this.state.courses.forEach(c => {
                    const progress = this.getCourseProgress(c);
                    let colorClass = progress < 40 ? 'text-rose-500' : (progress < 80 ? 'text-amber-500' : 'text-emerald-500');
                    let bgClass = progress < 40 ? 'bg-rose-500' : (progress < 80 ? 'bg-amber-500' : 'bg-emerald-500');

                    html += `
                        <div class="bg-white rounded-2xl p-4 md:p-6 border border-slate-200 shadow-sm hover:shadow-md transition-shadow cursor-pointer flex flex-col min-w-0" onclick="app.navigate('course', '${c.id}')">
                            <div class="flex justify-between items-start mb-4">
                                <div class="p-3 bg-slate-50 rounded-xl border border-slate-100 shrink-0">
                                    <i data-lucide="${c.icon}" class="w-6 h-6 text-slate-700"></i>
                                </div>
                                <span class="text-2xl font-bold ${colorClass}">${progress}%</span>
                            </div>
                            <h3 class="font-bold text-slate-800 text-lg mb-1 truncate">${c.name}</h3>
                            <p class="text-slate-500 text-sm mb-6 flex items-center truncate"><i data-lucide="map-pin" class="w-3 h-3 mr-1 shrink-0"></i> <span class="truncate">${c.city}</span></p>
                            
                            <div class="w-full bg-slate-100 rounded-full h-2 mb-4 overflow-hidden shrink-0">
                                <div class="${bgClass} h-2 rounded-full transition-all duration-1000 ease-out" style="width: ${progress}%"></div>
                            </div>
                            
                            <div class="space-y-3 mt-4 flex-1">
                                <p class="text-xs font-semibold text-slate-400 uppercase">Status dos Módulos</p>
                    `;
                    // Sort modules alphabetically for Dashboard view as well
                    const sortedModulesDash = Object.entries(c.modules).sort((a,b) => a[1].title.localeCompare(b[1].title));
                    sortedModulesDash.forEach(([k, mod]) => {
                        const items = this.getAllItemsForModule(mod);
                        const modProg = this.calculateProgress(items);
                        html += `
                            <div class="flex justify-between items-center text-sm">
                                <span class="text-slate-600 truncate mr-2 min-w-0 flex-1" title="${mod.title}">${mod.title}</span>
                                <span class="font-medium shrink-0 ${modProg === 100 ? 'text-emerald-600' : 'text-slate-400'}">${modProg}%</span>
                            </div>
                        `;
                    });
                    html += `</div></div>`;
                });
                return html + `</div>`;
            },

            templateCourse(course) {
                let html = ``;
                
                // Header com PDI, PPC e Nome
                html += `
                <div class="flex flex-col lg:flex-row lg:items-center justify-between mb-6 md:mb-8 gap-4 md:gap-6 bg-white p-4 sm:p-6 rounded-2xl shadow-sm border border-slate-200">
                    <div class="bg-gradient-to-r from-brand-600 to-brand-800 p-4 sm:p-5 rounded-xl shadow-lg text-white flex-1 w-full lg:w-auto lg:min-w-[280px] break-words">
                        <h2 class="text-2xl md:text-3xl font-black tracking-tight drop-shadow-sm">${course.name}</h2>
                        <p class="text-brand-100 text-sm mt-2 font-medium flex items-center flex-wrap"><i data-lucide="map-pin" class="w-4 h-4 mr-1 opacity-80 shrink-0"></i> Unidade: ${course.city} | Coordenação</p>
                    </div>
                    <div class="flex flex-col sm:flex-row flex-wrap items-stretch sm:items-center gap-3 shrink-0 w-full lg:w-auto">
                        ${this.generateCourseDocHTML(course.id, 'pdi', course.pdi, 'PDI CEUNSP')}
                        ${this.generateCourseDocHTML(course.id, 'ppc', course.ppc, 'PPC')}
                    </div>
                </div>
                `;

                // Tabela de Resumo de Execução e Prazos (Antes dos botões)
                const sortedModules = Object.entries(course.modules).sort((a, b) => a[1].title.localeCompare(b[1].title));
                
                html += `
                <div class="bg-white rounded-2xl shadow-lg border border-brand-100 overflow-hidden mb-6 md:mb-8 ring-1 ring-black/5 flex flex-col min-w-0">
                    <div class="px-4 md:px-6 py-4 bg-gradient-to-r from-brand-600 to-emerald-500 border-b border-transparent font-bold text-white text-base flex items-center shadow-inner shrink-0">
                        <i data-lucide="bar-chart-2" class="w-5 h-5 mr-2 text-white/90 shrink-0"></i> <span class="truncate">Resumo de Execução e Prazos</span>
                    </div>
                    <div class="table-scroll w-full block">
                        <table class="w-full text-left whitespace-nowrap text-sm">
                            <thead class="bg-brand-50 text-brand-800 text-xs uppercase font-bold tracking-wider border-b border-brand-100">
                                <tr>
                                    <th class="px-4 md:px-6 py-4">Módulo</th>
                                    <th class="px-4 md:px-6 py-4 text-center">Execução</th>
                                    <th class="px-4 md:px-6 py-4 text-center">Prazo de Entrega</th>
                                    <th class="px-4 md:px-6 py-4 text-center">Avaliado (MEC/CPA)</th>
                                </tr>
                            </thead>
                            <tbody class="divide-y divide-slate-100">
                `;

                sortedModules.forEach(([moduleId, mod]) => {
                    const items = this.getAllItemsForModule(mod);
                    const progress = this.calculateProgress(items);
                    const isComplete = progress === 100 && items.length > 0;
                    let progColor = progress < 40 ? 'text-rose-500' : (progress < 80 ? 'text-amber-500' : 'text-emerald-500');
                    if(items.length === 0) progColor = 'text-slate-400';

                    const modColors = MODULE_COLORS[mod.type] || { bg: 'bg-slate-50', iconBg: 'bg-slate-100', text: 'text-slate-700', border: 'border-slate-200' };

                    html += `
                                <tr class="hover:${modColors.bg} transition-colors border-l-4 ${modColors.border} border-y border-y-slate-50 group">
                                    <td class="px-4 md:px-6 py-3 font-semibold ${modColors.text} flex items-center min-w-[200px]">
                                        <div class="w-8 h-8 shrink-0 rounded-lg ${modColors.iconBg} flex items-center justify-center mr-3 group-hover:scale-110 transition-transform shadow-sm border border-white">
                                            <i data-lucide="${mod.icon}" class="w-4 h-4"></i>
                                        </div>
                                        <span class="text-[15px] truncate">${mod.title}</span>
                                    </td>
                                    <td class="px-4 md:px-6 py-3 text-center font-bold ${progColor} text-base">${progress}%</td>
                                    <td class="px-4 md:px-6 py-3 text-center text-slate-600 font-medium">
                                        <span class="bg-slate-100 px-3 py-1 rounded-full text-xs border border-slate-200 shadow-sm whitespace-nowrap">${mod.prazo}</span>
                                    </td>
                                    <td class="px-4 md:px-6 py-3 text-center">
                                        <select onchange="app.updateModuleAvaliado('${course.id}', '${moduleId}', this.value)" class="w-full max-w-[140px] text-xs border rounded-lg px-2 py-1.5 outline-none focus:ring-2 focus:ring-brand-500 shadow-sm cursor-pointer transition-colors ${mod.avaliado === 'Sim' ? 'bg-emerald-500 text-white font-bold border-emerald-600' : 'bg-white text-slate-600 border-slate-200 hover:bg-slate-50'}">
                                            <option value="Não" ${mod.avaliado === 'Não' ? 'selected' : ''} class="text-slate-800">Não Avaliado</option>
                                            <option value="Em Avaliação" ${mod.avaliado === 'Em Avaliação' ? 'selected' : ''} class="text-slate-800">Em Avaliação</option>
                                            <option value="Sim" ${mod.avaliado === 'Sim' ? 'selected' : ''} class="text-emerald-800">Avaliado ✅</option>
                                        </select>
                                    </td>
                                </tr>
                    `;
                });

                html += `
                            </tbody>
                        </table>
                    </div>
                </div>
                `;

                // Grid de Módulos (Cards Coloridos e Alfabéticos)
                html += `<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 md:gap-6">`;
                
                sortedModules.forEach(([moduleId, mod]) => {
                    const items = this.getAllItemsForModule(mod);
                    const progress = this.calculateProgress(items);
                    const isComplete = progress === 100 && items.length > 0;
                    
                    const colors = MODULE_COLORS[mod.type] || { bg: 'bg-slate-50', iconBg: 'bg-slate-100', text: 'text-slate-600', border: 'border-slate-200', hover: 'hover:border-slate-300' };
                    
                    html += `
                        <div class="bg-white rounded-2xl p-4 md:p-6 border border-slate-200 shadow-sm flex flex-col justify-between transition-all duration-300 hover:-translate-y-1 ${colors.hover} group min-w-0">
                            <div>
                                <div class="flex justify-between items-start mb-4">
                                    <div class="p-3 shrink-0 rounded-xl ${isComplete ? 'bg-emerald-50 text-emerald-600' : `${colors.iconBg} ${colors.text}`}">
                                        <i data-lucide="${mod.icon}" class="w-6 h-6"></i>
                                    </div>
                                    <div class="text-right">
                                        <span class="text-xl font-bold ${isComplete ? 'text-emerald-600' : 'text-slate-800'}">${progress}%</span>
                                    </div>
                                </div>
                                <h3 class="font-bold text-slate-800 text-lg mb-2 leading-tight break-words">${mod.title}</h3>
                                <p class="text-sm text-slate-500 mb-6">${items.length} itens a verificar</p>
                            </div>
                            <div class="mt-auto shrink-0">
                                <div class="w-full bg-slate-100 rounded-full h-1.5 mb-4 overflow-hidden">
                                    <div class="${isComplete ? 'bg-emerald-500' : colors.bg.replace('50','500')} h-1.5 rounded-full transition-all" style="width: ${progress}%"></div>
                                </div>
                                <button onclick="app.openDrawer('${moduleId}')" class="w-full py-2.5 px-4 ${colors.bg} hover:bg-slate-100 ${colors.text} font-semibold rounded-xl border ${colors.border} transition-colors flex items-center justify-center">
                                    <span class="truncate">Acessar Módulo</span> <i data-lucide="arrow-right" class="w-4 h-4 ml-2 opacity-70 shrink-0"></i>
                                </button>
                            </div>
                        </div>
                    `;
                });
                
                return html + `</div>`;
            },

            // --- DRAWER TEMPLATES ---
            renderDrawerContent() {
                const course = this.state.courses.find(c => c.id === this.state.currentCourseId);
                const module = course.modules[this.state.activeDrawerModule];
                
                document.getElementById('drawer-title').innerHTML = `
                    <div class="flex items-center min-w-0">
                        <i data-lucide="${module.icon}" class="w-5 h-5 mr-2 text-brand-600 shrink-0"></i> 
                        <span class="truncate">${module.title}</span>
                    </div>
                `;
                
                const contentDiv = document.getElementById('drawer-content');
                if(module.type === 'fe') contentDiv.innerHTML = this.templateFE(course.id, module);
                else if(module.type === 'atas') contentDiv.innerHTML = this.templateAtas(course.id, module);
                else if(module.type === 'docs_grouped') contentDiv.innerHTML = this.templateDocsGrouped(course.id, module);
                else if(module.type === 'curriculo') contentDiv.innerHTML = this.templateCurriculo(course.id, module);
                else if(module.type === 'planos') contentDiv.innerHTML = this.templatePlanos(course.id, module);
                else if(module.type === 'colegiado') contentDiv.innerHTML = this.templateColegiado(course.id, module);
                else if(module.type === 'coordenadoria') contentDiv.innerHTML = this.templateCoordenadoria(course.id, module);
                else if(module.type === 'discente') contentDiv.innerHTML = this.templateDiscente(course.id, module);
                else if(module.type === 'egressos') contentDiv.innerHTML = this.templateEgressos(course.id, module);
                
                lucide.createIcons();
            },

            generateStatusDropdown(courseId, moduleId, itemId, currentStatus) {
                let html = `<select onchange="app.updateStatus('${courseId}', '${moduleId}', '${itemId}', this.value)" class="w-full md:w-auto text-sm rounded border-transparent px-2 py-1.5 font-medium focus:ring-1 focus:ring-brand-500 outline-none cursor-pointer appearance-none pr-6 bg-no-repeat bg-right ${STATUSES[currentStatus].bg} ${STATUSES[currentStatus].color} border ${STATUSES[currentStatus].border}" style="background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23475569%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E'); background-size: .65em auto; background-position: right .5em top 50%;">`;
                STATUS_OPTIONS.forEach(opt => {
                    html += `<option value="${opt.value}" ${opt.value === currentStatus ? 'selected' : ''}>${opt.label}</option>`;
                });
                return html + `</select>`;
            },

            generateRow(courseId, moduleId, item) {
                return `
                    <div class="bg-white border border-slate-200 rounded-xl p-3 flex flex-col md:flex-row md:items-center justify-between gap-3 hover:border-brand-300 transition-colors shadow-sm w-full">
                        <div class="flex-1 min-w-0">
                            <h4 class="font-medium text-slate-800 text-sm break-words">${item.label}</h4>
                        </div>
                        <div class="flex items-center space-x-2 shrink-0 w-full md:w-auto justify-between md:justify-end">
                            ${this.generateUploadDownloadHTML(courseId, moduleId, item)}
                            ${this.generateStatusDropdown(courseId, moduleId, item.id, item.status)}
                        </div>
                    </div>
                `;
            },

            generateDisciplinaRow(courseId, semesterId, item) {
                let labelHtml = '';
                if(item.isEditing) {
                    labelHtml = `
                        <div class="flex-1 flex flex-col sm:flex-row items-stretch sm:items-center gap-2 min-w-0">
                            <input type="text" id="edit-input-${item.id}" value="${item.label}" class="flex-1 border border-brand-300 rounded-md px-2 py-1.5 text-sm w-full outline-none focus:ring-2 focus:ring-brand-500 min-w-0">
                            <button onclick="app.saveDisciplinaName('${courseId}', '${semesterId}', '${item.id}', 'edit-input-${item.id}')" class="bg-emerald-100 text-emerald-700 hover:bg-emerald-200 px-3 py-1.5 rounded-md transition-colors flex justify-center shrink-0"><i data-lucide="check" class="w-4 h-4"></i></button>
                        </div>
                    `;
                } else {
                    labelHtml = `
                        <div class="flex-1 flex items-start sm:items-center gap-2 min-w-0">
                            <h4 class="font-medium text-slate-800 text-sm break-words flex-1 min-w-0">${item.label}</h4>
                            <button onclick="app.toggleEditDisciplina('${courseId}', '${semesterId}', '${item.id}')" class="p-1 text-slate-400 hover:text-brand-600 transition-colors shrink-0"><i data-lucide="edit-2" class="w-4 h-4"></i></button>
                        </div>
                    `;
                }

                return `
                    <div class="bg-white border border-slate-200 rounded-xl p-3 flex flex-col md:flex-row md:items-center justify-between gap-3 hover:border-brand-300 transition-colors shadow-sm w-full">
                        ${labelHtml}
                        <div class="flex items-center space-x-2 shrink-0 w-full md:w-auto justify-between md:justify-end">
                            ${this.generateUploadDownloadHTML(courseId, 'curriculo', item)}
                            ${this.generateStatusDropdown(courseId, 'curriculo', item.id, item.status)}
                        </div>
                    </div>
                `;
            },

            templateDocsGrouped(courseId, module) {
                let html = `<div class="space-y-6">`;
                
                const groupColors = [
                    { bg: 'bg-blue-50', border: 'border-blue-200', text: 'text-blue-800', inner: 'border-blue-100', icon: 'text-blue-600' },
                    { bg: 'bg-fuchsia-50', border: 'border-fuchsia-200', text: 'text-fuchsia-800', inner: 'border-fuchsia-100', icon: 'text-fuchsia-600' },
                    { bg: 'bg-emerald-50', border: 'border-emerald-200', text: 'text-emerald-800', inner: 'border-emerald-100', icon: 'text-emerald-600' },
                    { bg: 'bg-amber-50', border: 'border-amber-200', text: 'text-amber-800', inner: 'border-amber-100', icon: 'text-amber-600' }
                ];

                module.data.forEach((group, idx) => {
                    const colors = groupColors[idx % groupColors.length];
                    html += `
                        <div class="${colors.bg} rounded-2xl p-4 md:p-5 border ${colors.border}">
                            <h3 class="text-lg font-bold ${colors.text} mb-4 flex items-center break-words"><i data-lucide="folder" class="w-5 h-5 mr-2 shrink-0 ${colors.icon}"></i> <span class="min-w-0">${group.category}</span></h3>
                            <div class="bg-white/80 backdrop-blur-sm rounded-xl p-3 md:p-4 border ${colors.inner} shadow-sm space-y-3">
                                ${group.items.map(item => this.generateRow(courseId, this.state.activeDrawerModule, item)).join('')}
                            </div>
                        </div>
                    `;
                });
                return html + `</div>`;
            },

            // TEMPLATE COLEGIADO (MATRIZ / PLANILHA COMPLETA)
            templateColegiado(courseId, module) {
                let html = `<div class="space-y-8">`;
                
                // 1. Documentos
                html += `<div>
                    <h3 class="text-sm font-bold text-slate-400 uppercase tracking-wider mb-3 px-1 border-b border-slate-100 pb-2 flex items-center"><i data-lucide="file-text" class="w-4 h-4 mr-2 shrink-0"></i> Documentação Formal</h3>
                    <div class="space-y-3">
                        ${module.data.documentos.map(item => this.generateRow(courseId, 'colegiado', item)).join('')}
                    </div>
                </div>`;

                // 2. Membros (Tabela Planilha)
                html += `<div>
                    <div class="flex flex-col sm:flex-row justify-between items-start sm:items-end mb-4 px-1 border-b border-slate-100 pb-2 mt-6 gap-3">
                        <h3 class="text-sm font-bold text-slate-400 uppercase tracking-wider flex items-center min-w-0 break-words"><i class="w-4 h-4 mr-2 shrink-0" data-lucide="users"></i> Composição do Corpo Docente (Matriz)</h3>
                        <button onclick="app.addMembroColegiado('${courseId}')" class="w-full sm:w-auto justify-center text-xs bg-brand-600 hover:bg-brand-700 text-white font-semibold py-2 px-3 rounded-lg shadow-sm transition-colors flex items-center shrink-0">
                            <i data-lucide="plus" class="w-4 h-4 mr-1"></i> Adicionar Membro
                        </button>
                    </div>`;

                if(module.data.membros.length === 0) {
                    html += `<div class="text-center p-8 bg-slate-50 border border-dashed border-slate-300 rounded-xl text-slate-500 text-sm">Nenhum professor/membro cadastrado. Clique em "Adicionar Membro".</div>`;
                } else {
                    html += `
                    <div class="table-scroll border border-slate-200 rounded-xl bg-white shadow-sm pb-2 w-full block">
                        <table class="w-full text-left whitespace-nowrap min-w-max border-collapse">
                            <thead class="bg-slate-100 text-slate-600 text-[11px] uppercase font-bold tracking-wider">
                                <tr>
                                    <th class="p-3 sticky left-0 bg-slate-200 z-20 border-r border-slate-300 shadow-[2px_0_5px_-2px_rgba(0,0,0,0.1)]">Nome do Professor</th>
                                    <th class="p-3 border-r border-slate-200">Status MEC</th>
                                    <th class="p-3 border-r border-slate-200">NDE</th>
                                    <th class="p-3 border-r border-slate-200">CPF</th>
                                    <th class="p-3 border-r border-slate-200">Titulação máxima</th>
                                    <th class="p-3 border-r border-slate-200">Regime de Trabalho</th>
                                    <th class="p-3 border-r border-slate-200">Vínculo Empregatício</th>
                                    <th class="p-3 border-r border-slate-200" title="Tempo de atuação profissional no curso (em meses)">Atuação Curso (m)</th>
                                    <th class="p-3 border-r border-slate-200" title="Tempo de experiência docente na educação básica (em anos)">Exp. Ed. Básica (a)</th>
                                    <th class="p-3 border-r border-slate-200" title="Tempo de experiência docente no ensino superior (em anos)">Exp. Superior (a)</th>
                                    <th class="p-3 border-r border-slate-200" title="Tempo de experiência docente no ensino superior EAD (em anos)">Exp. Sup. EAD (a)</th>
                                    <th class="p-3 border-r border-slate-200" title="Tempo fora do magistério(Exp. Profissional) (em anos)">Fora Magistério (a)</th>
                                    <th class="p-3 border-r border-slate-200" title="Competência Acadêmica: Docente com formação/capacitação/experiência pedagógica?">Comp. Pedagógica</th>
                                    <th class="p-3 border-r border-slate-200" title="Artigos publicados em periódicos científicos na área">Artigos (Área)</th>
                                    <th class="p-3 border-r border-slate-200" title="Artigos publicados em periódicos científicos em outras áreas">Artigos (Outras)</th>
                                    <th class="p-3 border-r border-slate-200" title="Livros ou capítulos em livros publicados na área">Livros/Cap (Área)</th>
                                    <th class="p-3 border-r border-slate-200" title="Livros ou capítulos em livros publicados em outras áreas">Livros/Cap (Outras)</th>
                                    <th class="p-3 border-r border-slate-200" title="Trabalhos publicados em anais (Completos)">Anais (Completos)</th>
                                    <th class="p-3 border-r border-slate-200" title="Trabalhos publicados em anais (Resumos)">Anais (Resumos)</th>
                                    <th class="p-3 border-r border-slate-200" title="Traduções de livros, capítulos de livros ou artigos publicados">Traduções</th>
                                    <th class="p-3 border-r border-slate-200" title="Propriedade intelectual depositada">PI Depositada</th>
                                    <th class="p-3 border-r border-slate-200" title="Propriedade intelectual registrada">PI Registrada</th>
                                    <th class="p-3 border-r border-slate-200" title="Projetos e/ou produções técnicas artísticas e culturais">Proj/Prod Técnicas</th>
                                    <th class="p-3 border-r border-slate-200" title="Produção didático-pedagógica relevante, publicada ou não">Prod. Didático-Pedagógica</th>
                                    <th class="p-3 border-r border-slate-200">Link Lattes</th>
                                    <th class="p-3 border-r border-slate-200">Link LinkedIn</th>
                                    <th class="p-3 sticky right-0 bg-slate-200 z-20 shadow-[-2px_0_5px_-2px_rgba(0,0,0,0.1)] text-center">Dossiê (Upload)</th>
                                </tr>
                            </thead>
                            <tbody class="divide-y divide-slate-200">
                    `;

                    const inp = (m, f, p, w, a='text-center') => `<td class="p-1 border-r border-slate-200"><input type="text" placeholder="${p}" value="${m[f] || ''}" onchange="app.updateMembro('${courseId}', '${m.id}', '${f}', this.value)" class="sheet-input min-w-[${w}px] ${a}"></td>`;
                    const sel = (m, f, w) => `<td class="p-1 border-r border-slate-200"><select class="sheet-input min-w-[${w}px]" onchange="app.updateMembro('${courseId}', '${m.id}', '${f}', this.value)"><option value="Sim" ${m[f]==='Sim'?'selected':''}>Sim</option><option value="Não" ${m[f]==='Não'?'selected':''}>Não</option></select></td>`;
                    const lnk = (m, f, p) => `<td class="p-1 border-r border-slate-200"><div class="flex items-center gap-1"><input type="text" placeholder="${p}" value="${m[f]||''}" onchange="app.updateMembro('${courseId}', '${m.id}', '${f}', this.value)" class="sheet-input min-w-[160px] text-blue-600"><a href="${(m[f]||'').startsWith('http') ? m[f] : (m[f] ? 'https://'+m[f] : '#')}" target="_blank" class="${m[f] ? 'text-brand-600 hover:text-brand-800' : 'text-slate-300 pointer-events-none'}" title="Acessar Perfil/Currículo"><i data-lucide="external-link" class="w-4 h-4"></i></a></div></td>`;

                    module.data.membros.forEach(membro => {
                        html += `
                                <tr class="hover:bg-slate-50 transition-colors group">
                                    <td class="p-1 sticky left-0 bg-white group-hover:bg-slate-50 z-10 border-r border-slate-300 shadow-[2px_0_5px_-2px_rgba(0,0,0,0.05)]">
                                        <input type="text" placeholder="Nome do Professor..." value="${membro.nome}" onchange="app.updateMembro('${courseId}', '${membro.id}', 'nome', this.value)" class="sheet-input font-bold text-slate-800 min-w-[150px] sm:min-w-[200px]">
                                    </td>
                                    <td class="p-1 border-r border-slate-200 text-center min-w-[140px]">
                                        ${this.generateStatusDropdown(courseId, 'colegiado', membro.id, membro.status)}
                                    </td>
                                    ${sel(membro, 'nde', 80)}
                                    ${inp(membro, 'cpf', '000.000.000-00', 130, '')}
                                    ${inp(membro, 'titulacao', 'Doutor, Mestre...', 130, '')}
                                    ${inp(membro, 'regime', 'Ex: 20 h', 110, '')}
                                    ${inp(membro, 'vinculo', 'Integral, Horista...', 140, '')}
                                    ${inp(membro, 'tempoCurso', 'Ex: 210 meses', 120)}
                                    ${inp(membro, 'tempoBasica', 'Ex: 18 anos', 120)}
                                    ${inp(membro, 'tempoSup', 'Ex: 18 anos', 120)}
                                    ${inp(membro, 'tempoSupEad', 'Ex: 2 anos (síncrono)', 150)}
                                    ${inp(membro, 'tempoFora', 'Ex: 32 anos', 120)}
                                    ${sel(membro, 'compPedagogica', 100)}
                                    ${inp(membro, 'artigosArea', 'Qtd...', 80)}
                                    ${inp(membro, 'artigosOutras', 'Qtd...', 80)}
                                    ${inp(membro, 'livrosArea', 'Qtd...', 80)}
                                    ${inp(membro, 'livrosOutras', 'Qtd...', 80)}
                                    ${inp(membro, 'anaisCompletos', 'Qtd...', 80)}
                                    ${inp(membro, 'anaisResumos', 'Qtd...', 80)}
                                    ${inp(membro, 'traducoes', 'Qtd...', 80)}
                                    ${inp(membro, 'piDepositada', 'Qtd...', 80)}
                                    ${inp(membro, 'piRegistrada', 'Qtd...', 80)}
                                    ${inp(membro, 'projetosTecnicos', 'Qtd...', 80)}
                                    ${inp(membro, 'prodDidatica', 'Qtd / Descrição...', 120)}
                                    ${lnk(membro, 'lattes', 'http://lattes...')}
                                    ${lnk(membro, 'linkedin', 'https://linkedin...')}
                                    <td class="p-1 sticky right-0 bg-white group-hover:bg-slate-50 z-10 shadow-[-2px_0_5px_-2px_rgba(0,0,0,0.05)] text-center border-l border-slate-200 min-w-[120px]">
                                        <div class="flex justify-center w-full">
                                            ${this.generateUploadDownloadHTML(courseId, 'colegiado', membro)}
                                        </div>
                                    </td>
                                </tr>
                        `;
                    });

                    html += `
                            </tbody>
                        </table>
                    </div>`;
                }
                
                html += `</div></div>`;
                return html;
            },

            templateDiscente(courseId, module) {
                let html = `<div class="space-y-8">`;
                
                // 1. Tabela Número de Alunos
                html += `
                <div>
                    <div class="flex flex-col sm:flex-row justify-between items-start sm:items-end mb-4 px-1 border-b border-slate-100 pb-2 gap-3">
                        <h3 class="text-sm font-bold text-slate-400 uppercase tracking-wider flex items-center min-w-0 break-words"><i class="w-4 h-4 mr-2 shrink-0" data-lucide="bar-chart"></i> Número de Alunos (Quantitativo Discente)</h3>
                        <button onclick="alert('Dados do quadro salvos com sucesso!')" class="w-full sm:w-auto justify-center text-xs bg-brand-600 hover:bg-brand-700 text-white font-semibold py-2 px-3 rounded-lg shadow-sm transition-colors flex items-center shrink-0">
                            <i data-lucide="save" class="w-4 h-4 mr-1"></i> Salvar Tabela
                        </button>
                    </div>
                    
                    <div class="table-scroll border border-slate-200 rounded-xl bg-white shadow-sm pb-2 mb-4 w-full block">
                        <table class="w-full text-left whitespace-nowrap min-w-max border-collapse text-sm">
                            <thead class="bg-slate-100 text-slate-600 text-xs font-bold">
                                <tr>
                                    <th class="p-2.5 sticky left-0 bg-slate-200 z-10 border-r border-slate-300 shadow-[2px_0_5px_-2px_rgba(0,0,0,0.1)]">Situação</th>
                                    ${DISCENTE_SEMS.map(sem => `<th class="p-2 border-r border-slate-200 text-center">${sem}</th>`).join('')}
                                    <th class="p-2 text-center bg-brand-100 text-brand-800 border-l border-brand-200">Total</th>
                                </tr>
                            </thead>
                            <tbody class="divide-y divide-slate-200">
                `;
                
                module.data.quantitativoTable.forEach((row, idx) => {
                    let total = 0;
                    let colsHtml = '';
                    DISCENTE_SEMS.forEach(sem => {
                        let val = row.values[sem] || 0;
                        total += parseInt(val) || 0;
                        colsHtml += `<td class="p-1 border-r border-slate-200"><input type="number" value="${val}" onchange="app.updateQuantitativo('${courseId}', ${idx}, '${sem}', this.value)" class="w-full bg-transparent border border-transparent hover:border-slate-300 focus:border-brand-500 rounded p-1 outline-none transition-colors text-center text-slate-700 min-w-[70px]"></td>`;
                    });
                    
                    let bgClass = "bg-white hover:bg-slate-50";
                    if (idx >= 0 && idx <= 5) bgClass = "bg-sky-50/40 hover:bg-sky-100/50"; // Noturno
                    else if (idx >= 6 && idx <= 11) bgClass = "bg-orange-50/40 hover:bg-orange-100/50"; // Matutino
                    else if (idx === 17) bgClass = "bg-emerald-50/40 hover:bg-emerald-100/50"; // Formandos
                    
                    html += `
                        <tr class="${bgClass} transition-colors group">
                            <td class="p-2.5 sticky left-0 bg-white group-hover:bg-slate-50 z-10 border-r border-slate-300 font-medium text-slate-700 shadow-[2px_0_5px_-2px_rgba(0,0,0,0.05)] min-w-[200px]" style="background-color: inherit;">${row.label}</td>
                            ${colsHtml}
                            <td class="p-2 text-center font-bold bg-brand-50/50 text-brand-700 border-l border-brand-100 min-w-[70px]" id="total-${courseId}-${idx}">${total}</td>
                        </tr>
                    `;
                });
                
                html += `
                            </tbody>
                        </table>
                    </div>
                    
                    <!-- Upload row for the table -->
                    <div class="bg-slate-50 p-3 md:p-4 rounded-xl border border-slate-200 flex flex-col lg:flex-row lg:items-center justify-between gap-3 shadow-sm w-full">
                        <div class="flex-1 min-w-0"><span class="text-sm font-semibold text-slate-700 flex items-center break-words"><i data-lucide="paperclip" class="w-4 h-4 mr-2 text-slate-400 shrink-0"></i> Anexar documento comprobatório do quadro (Opcional)</span></div>
                        <div class="flex items-center space-x-2 w-full lg:w-auto justify-between lg:justify-end shrink-0">
                            ${this.generateUploadDownloadHTML(courseId, 'discente', module.data.quantitativoItem)}
                            ${this.generateStatusDropdown(courseId, 'discente', module.data.quantitativoItem.id, module.data.quantitativoItem.status)}
                        </div>
                    </div>
                </div>
                `;

                // 2. Itinerário Extensionista
                html += `<div class="pt-6 border-t border-slate-200 mt-6 space-y-6">`;
                
                html += `
                <div class="bg-indigo-50 rounded-2xl p-4 md:p-5 border border-indigo-200">
                    <div class="flex flex-col sm:flex-row sm:justify-between sm:items-end mb-4 gap-3">
                        <h3 class="text-lg font-bold text-indigo-800 flex items-center break-words min-w-0"><i data-lucide="map" class="w-5 h-5 mr-2 text-indigo-600 shrink-0"></i> <span class="min-w-0">Itinerário Extensionista</span></h3>
                        <button onclick="app.openAddItinerarioForm()" class="w-full sm:w-auto justify-center text-xs bg-indigo-600 hover:bg-indigo-700 text-white font-semibold py-2 px-3 rounded-lg shadow-sm transition-colors flex items-center shrink-0">
                            <i data-lucide="plus" class="w-4 h-4 mr-1"></i> Adicionar Projeto
                        </button>
                    </div>
                    <div class="bg-white/80 backdrop-blur-sm rounded-xl p-3 md:p-4 border border-indigo-100 shadow-sm mb-4">
                        <h4 class="font-semibold text-slate-700 mb-3 border-b border-slate-100/50 pb-2">Documentos Gerais</h4>
                        ${this.generateRow(courseId, 'discente', module.data.itinerario.normas)}
                    </div>
                `;

                if (this.state.activeDiscenteForm) {
                    html += `
                    <div class="bg-white border border-indigo-200 rounded-xl p-4 md:p-5 mb-4 slide-in shadow-sm">
                        <h4 class="font-bold text-indigo-800 text-sm mb-3">Novo Projeto do Itinerário</h4>
                        <div class="grid grid-cols-1 md:grid-cols-2 gap-3 mb-3">
                            <input type="text" id="new-itin-turma" placeholder="Turma (Ex: 1º Semestre, Turma A)" class="sheet-input bg-slate-50 border-slate-300">
                            <select id="new-itin-ano" class="sheet-input bg-slate-50 border-slate-300 cursor-pointer">
                                <option value="2024">2024</option>
                                <option value="2025" selected>2025</option>
                                <option value="2026">2026</option>
                            </select>
                        </div>
                        <div class="grid grid-cols-1 gap-3 mb-4 mt-3">
                            <div class="flex items-center">
                                <label class="flex items-center px-4 py-2 bg-slate-50 border border-slate-300 rounded-lg text-xs font-medium text-slate-600 hover:bg-slate-100 cursor-pointer transition-colors w-full justify-center">
                                    <i data-lucide="upload-cloud" class="w-4 h-4 mr-2 text-slate-400 shrink-0"></i> Anexar Projeto
                                    <input type="file" id="new-itin-file" class="hidden" onchange="this.parentElement.querySelector('span').innerText = this.files[0].name">
                                    <span class="ml-2 truncate max-w-[120px] sm:max-w-[200px]">Nenhum arquivo</span>
                                </label>
                            </div>
                        </div>
                        <div class="flex flex-col-reverse sm:flex-row justify-end gap-2">
                            <button onclick="app.cancelAddItinerarioForm()" class="px-4 py-2 w-full sm:w-auto text-xs font-medium text-slate-600 hover:bg-slate-200 rounded-lg transition-colors">Cancelar</button>
                            <button onclick="app.saveNovoProjetoItinerario('${courseId}')" class="px-4 py-2 w-full sm:w-auto text-xs font-medium bg-indigo-600 text-white hover:bg-indigo-700 rounded-lg transition-colors shadow-sm">Salvar Projeto</button>
                        </div>
                    </div>`;
                }

                html += `<div class="space-y-3">`;
                if(module.data.itinerario.projetos.length === 0) {
                    html += `<div class="text-center p-6 bg-white/50 border border-dashed border-indigo-200 rounded-xl text-indigo-500 text-sm">Nenhum projeto cadastrado. Clique em "Adicionar Projeto" acima.</div>`;
                } else {
                    module.data.itinerario.projetos.forEach(item => {
                        const displayLabel = `
                            <div class="flex flex-col min-w-0">
                                <span class="font-semibold text-slate-800 text-[13px] md:text-sm break-words">Turma: ${item.turma}</span>
                                <span class="text-[10px] font-medium text-indigo-600 bg-indigo-100 px-2 py-0.5 rounded-full inline-block w-max mt-1.5">Ano: ${item.ano}</span>
                            </div>
                        `;
                        const displayItem = { ...item, label: displayLabel };
                        html += this.generateRow(courseId, 'discente', displayItem);
                    });
                }
                html += `</div></div>`;


                // 3. Restante dos Grupos
                const groupColors = [
                    { bg: 'bg-emerald-50', border: 'border-emerald-200', text: 'text-emerald-800', innerBorder: 'border-emerald-100', icon: 'text-emerald-600' },
                    { bg: 'bg-rose-50', border: 'border-rose-200', text: 'text-rose-800', innerBorder: 'border-rose-100', icon: 'text-rose-600' },
                    { bg: 'bg-amber-50', border: 'border-amber-200', text: 'text-amber-800', innerBorder: 'border-amber-100', icon: 'text-amber-600' },
                    { bg: 'bg-sky-50', border: 'border-sky-200', text: 'text-sky-800', innerBorder: 'border-sky-100', icon: 'text-sky-600' }
                ];

                module.data.grupos.forEach((group, idx) => {
                    const colors = groupColors[idx % groupColors.length];
                    html += `
                        <div class="${colors.bg} rounded-2xl p-4 md:p-5 border ${colors.border}">
                            <h3 class="text-lg font-bold ${colors.text} mb-4 flex items-center break-words min-w-0"><i data-lucide="folder" class="w-5 h-5 mr-2 shrink-0 ${colors.icon}"></i> <span class="min-w-0">${group.category}</span></h3>
                            <div class="bg-white/80 backdrop-blur-sm rounded-xl p-3 md:p-4 border ${colors.innerBorder} shadow-sm space-y-3">
                                ${group.items.map(item => this.generateRow(courseId, 'discente', item)).join('')}
                            </div>
                        </div>
                    `;
                });
                html += `</div></div>`;
                return html;
            },

            templateCoordenadoria(courseId, module) {
                let html = `<div class="space-y-8">`;
                
                const INFRA_CATEGORIES = ['Salas de Aula', 'Sala dos Professores', 'Sala do NDE', 'Sala da Coordenação', 'Laboratórios', 'Auditórios', 'Biblioteca', 'Cantinas', 'CAA', 'Estacionamento', 'Reitoria'];
                
                const acoesKeys = Object.keys(module.data).filter(k => !INFRA_CATEGORIES.includes(k));
                const infraKeys = Object.keys(module.data).filter(k => INFRA_CATEGORIES.includes(k));

                const renderCategoryGroup = (keys, groupTitle, icon) => {
                    let groupHtml = `
                    <div class="mb-6">
                        <h2 class="text-base font-bold text-slate-700 uppercase tracking-wider mb-4 flex items-center border-b border-slate-200 pb-2 break-words min-w-0">
                            <i data-lucide="${icon}" class="w-5 h-5 mr-2 text-brand-600 shrink-0"></i> <span class="min-w-0">${groupTitle}</span>
                        </h2>
                        <div class="space-y-6">
                    `;
                    
                    keys.forEach(category => {
                        const items = module.data[category];
                        const isInfra = INFRA_CATEGORIES.includes(category);

                        groupHtml += `<div>
                            <div class="flex flex-col sm:flex-row sm:justify-between sm:items-end mb-3 px-1 gap-3 border-b border-slate-100 pb-2">
                                <h3 class="text-sm font-bold text-slate-400 uppercase tracking-wider flex items-center break-words min-w-0"><i class="w-4 h-4 mr-2 shrink-0" data-lucide="folder"></i> <span class="min-w-0">${category}</span></h3>
                                <button onclick="app.openAddCoordenadoriaForm('${category}')" class="w-full sm:w-auto justify-center text-xs bg-brand-50 hover:bg-brand-100 text-brand-700 font-semibold py-2 px-3 rounded-lg border border-brand-200 transition-colors flex items-center shadow-sm shrink-0">
                                    <i data-lucide="plus" class="w-4 h-4 mr-1"></i> Adicionar Registro
                                </button>
                            </div>`;

                        if (this.state.activeCoordenadoriaCategoryForm === category) {
                            groupHtml += `
                            <div class="bg-brand-50 border border-brand-200 rounded-xl p-4 md:p-5 mb-4 slide-in shadow-sm">
                                <h4 class="font-bold text-brand-800 text-sm mb-3 break-words">Novo Registro em ${category}</h4>`;
                                
                            if (isInfra) {
                                groupHtml += `
                                <div class="grid grid-cols-1 md:grid-cols-3 gap-3 mb-3">
                                    <input type="text" id="new-coord-campus" placeholder="Campus (Ex: Salto)" class="sheet-input bg-white border-slate-300">
                                    <input type="text" id="new-coord-bloco" placeholder="Bloco (Opcional)" class="sheet-input bg-white border-slate-300">
                                    <input type="text" id="new-coord-sala" placeholder="Identificação/Número do Espaço" class="sheet-input bg-white border-slate-300">
                                </div>`;
                            } else {
                                groupHtml += `
                                <div class="grid grid-cols-1 md:grid-cols-2 gap-3 mb-3">
                                    <input type="text" id="new-coord-titulo" placeholder="O que é? (Título/Assunto)" class="sheet-input bg-white border-slate-300">
                                    <input type="text" id="new-coord-acao" placeholder="Ação/Desdobramento" class="sheet-input bg-white border-slate-300">
                                </div>
                                <div class="grid grid-cols-1 md:grid-cols-2 gap-3 mb-3">
                                    <select id="new-coord-sem" class="sheet-input bg-white border-slate-300 cursor-pointer">
                                        <option value="1º Semestre">1º Semestre</option>
                                        <option value="2º Semestre">2º Semestre</option>
                                    </select>
                                    <select id="new-coord-ano" class="sheet-input bg-white border-slate-300 cursor-pointer">
                                        <option value="2024">2024</option>
                                        <option value="2025" selected>2025</option>
                                        <option value="2026">2026</option>
                                    </select>
                                </div>`;
                            }

                            groupHtml += `
                                <div class="grid grid-cols-1 gap-3 mb-4 mt-3">
                                    <div class="flex items-center">
                                        <label class="flex items-center px-4 py-2 bg-white border border-slate-300 rounded-lg text-xs font-medium text-slate-600 hover:bg-slate-50 cursor-pointer transition-colors w-full justify-center">
                                            <i data-lucide="upload-cloud" class="w-4 h-4 mr-2 text-slate-400 shrink-0"></i> ${isInfra ? 'Anexar Foto/Vídeo/Evidência' : 'Anexar Evidência'}
                                            <input type="file" id="new-coord-file" ${isInfra ? 'accept="image/*,video/*,application/pdf"' : ''} class="hidden" onchange="this.parentElement.querySelector('span').innerText = this.files[0].name">
                                            <span class="ml-2 truncate max-w-[120px] sm:max-w-[200px]">Nenhum arquivo</span>
                                        </label>
                                    </div>
                                </div>
                                <div class="flex flex-col-reverse sm:flex-row justify-end gap-2">
                                    <button onclick="app.cancelAddCoordenadoriaForm()" class="px-4 py-2 w-full sm:w-auto text-xs font-medium text-slate-600 hover:bg-slate-200 rounded-lg transition-colors">Cancelar</button>
                                    <button onclick="app.saveNovaCoordenadoria('${courseId}', '${category}')" class="px-4 py-2 w-full sm:w-auto text-xs font-medium bg-brand-600 text-white hover:bg-brand-700 rounded-lg transition-colors shadow-sm">Salvar Registro</button>
                                </div>
                            </div>`;
                        }

                        groupHtml += `<div class="space-y-3">`;
                        if (items.length === 0) {
                            groupHtml += `<div class="text-center p-6 bg-slate-50 border border-dashed border-slate-300 rounded-xl text-slate-500 text-sm">Nenhum registro inserido. Clique em "Adicionar Registro" acima.</div>`;
                        } else {
                            items.forEach(item => {
                                let displayLabel = '';
                                if (item.isInfra) {
                                    displayLabel = `
                                        <div class="flex flex-col font-normal min-w-0">
                                            <span class="font-bold text-slate-800 text-[13px] md:text-sm break-words">Sala/Espaço: ${item.sala}</span>
                                            <span class="text-xs text-slate-500 mt-1 break-words"><i data-lucide="map-pin" class="w-3 h-3 inline mr-1 shrink-0"></i>Campus: ${item.campus} ${item.bloco ? ' | Bloco: '+item.bloco : ''}</span>
                                        </div>
                                    `;
                                } else {
                                    displayLabel = `
                                        <div class="flex flex-col font-normal min-w-0">
                                            <span class="font-bold text-slate-800 text-[13px] md:text-sm break-words">${item.titulo}</span>
                                            <span class="text-xs text-slate-500 mt-1 break-words">Ação: ${item.acao || '-'}</span>
                                            <span class="text-[10px] font-medium text-brand-600 bg-brand-100 px-2 py-0.5 rounded-full inline-block w-max mt-1.5">${item.semestre} / ${item.ano}</span>
                                        </div>
                                    `;
                                }
                                const displayItem = { ...item, label: displayLabel };
                                groupHtml += this.generateRow(courseId, 'coordenadoria', displayItem);
                            });
                        }
                        groupHtml += `</div></div>`;
                    });
                    groupHtml += `</div></div>`;
                    return groupHtml;
                };

                html += renderCategoryGroup(acoesKeys, 'Gestão e Ações', 'inbox');
                html += renderCategoryGroup(infraKeys, 'Mapeamento de Infraestrutura', 'map');

                return html + `</div>`;
            },

            templateEgressos(courseId, module) {
                let html = `<div class="space-y-8">`;
                
                Object.entries(module.data).forEach(([category, items]) => {
                    html += `<div>
                        <div class="flex flex-col sm:flex-row sm:justify-between sm:items-end mb-3 px-1 gap-3 border-b border-slate-100 pb-2">
                            <h3 class="text-sm font-bold text-slate-400 uppercase tracking-wider flex items-center break-words min-w-0"><i class="w-4 h-4 mr-2 shrink-0" data-lucide="folder"></i> <span class="min-w-0">${category}</span></h3>
                            <button onclick="app.openAddEgressosForm('${category}')" class="w-full sm:w-auto justify-center text-xs bg-brand-50 hover:bg-brand-100 text-brand-700 font-semibold py-2 px-3 rounded-lg border border-brand-200 transition-colors flex items-center shadow-sm shrink-0">
                                <i data-lucide="plus" class="w-4 h-4 mr-1"></i> Adicionar Registro
                            </button>
                        </div>`;

                    if (this.state.activeEgressosCategoryForm === category) {
                        html += `
                        <div class="bg-brand-50 border border-brand-200 rounded-xl p-4 md:p-5 mb-4 slide-in shadow-sm">
                            <h4 class="font-bold text-brand-800 text-sm mb-3 break-words">Novo Registro em ${category}</h4>
                            <div class="grid grid-cols-1 sm:grid-cols-2 gap-3 mb-3">
                                <input type="text" id="new-egresso-acao" placeholder="Qual foi a Ação/Atividade?" class="sheet-input bg-white border-slate-300">
                                <select id="new-egresso-ano" class="sheet-input bg-white border-slate-300 cursor-pointer">
                                    <option value="2024">2024</option>
                                    <option value="2025" selected>2025</option>
                                    <option value="2026">2026</option>
                                </select>
                            </div>
                            <div class="grid grid-cols-1 gap-3 mb-4 mt-3">
                                <div class="flex items-center">
                                    <label class="flex items-center px-4 py-2 bg-white border border-slate-300 rounded-lg text-xs font-medium text-slate-600 hover:bg-slate-50 cursor-pointer transition-colors w-full justify-center">
                                        <i data-lucide="upload-cloud" class="w-4 h-4 mr-2 text-slate-400 shrink-0"></i> Anexar Evidência/Documento/Foto
                                        <input type="file" id="new-egresso-file" class="hidden" onchange="this.parentElement.querySelector('span').innerText = this.files[0].name">
                                        <span class="ml-2 truncate max-w-[120px] sm:max-w-[200px]">Nenhum arquivo</span>
                                    </label>
                                </div>
                            </div>
                            <div class="flex flex-col-reverse sm:flex-row justify-end gap-2">
                                <button onclick="app.cancelAddEgressosForm()" class="px-4 py-2 w-full sm:w-auto text-xs font-medium text-slate-600 hover:bg-slate-200 rounded-lg transition-colors">Cancelar</button>
                                <button onclick="app.saveNovoEgresso('${courseId}', '${category}')" class="px-4 py-2 w-full sm:w-auto text-xs font-medium bg-brand-600 text-white hover:bg-brand-700 rounded-lg transition-colors shadow-sm">Salvar Registro</button>
                            </div>
                        </div>`;
                    }

                    html += `<div class="space-y-3">`;
                    if (items.length === 0) {
                        html += `<div class="text-center p-6 bg-slate-50 border border-dashed border-slate-300 rounded-xl text-slate-500 text-sm">Nenhum registro inserido. Clique em "Adicionar Registro" acima.</div>`;
                    } else {
                        items.forEach(item => {
                            const displayLabel = `
                                <div class="flex flex-col min-w-0">
                                    <span class="font-semibold text-slate-800 text-[13px] md:text-sm break-words">${item.acao}</span>
                                    <span class="text-[10px] font-medium text-brand-600 bg-brand-100 px-2 py-0.5 rounded-full inline-block w-max mt-1.5">Ano: ${item.ano}</span>
                                </div>
                            `;
                            const displayItem = { ...item, label: displayLabel };
                            html += this.generateRow(courseId, 'egressos', displayItem);
                        });
                    }
                    html += `</div></div>`;
                });

                return html + `</div>`;
            },

            templateCurriculo(courseId, module) {
                let html = `<div class="space-y-6">
                    <div>
                        <h3 class="text-sm font-bold text-slate-400 uppercase tracking-wider mb-3 px-1 break-words">Documentos Básicos</h3>
                        <div class="space-y-3">
                            ${module.data.basicos.map(item => this.generateRow(courseId, 'curriculo', item)).join('')}
                        </div>
                    </div>
                    
                    <div>
                        <h3 class="text-sm font-bold text-slate-400 uppercase tracking-wider mb-3 px-1 mt-6 border-t border-slate-100 pt-6 break-words">Plano de Ensino (Arquivo Único)</h3>
                        <div class="bg-brand-50 border border-brand-200 rounded-xl p-3 md:p-4 shadow-sm mb-4">
                            ${module.data.geral.map(item => this.generateRow(courseId, 'curriculo', item)).join('')}
                        </div>
                        <p class="text-xs text-slate-500 px-1 mb-4">Anexe acima um arquivo em PDF contendo todos os planos de ensino, caso a IES adote um formato único consolidado.</p>
                    </div>

                    <div>
                        <h3 class="text-sm font-bold text-slate-400 uppercase tracking-wider mb-3 px-1 mt-6 border-t border-slate-100 pt-6 break-words">Planos de Ensino Individuais (Por Semestre)</h3>
                        <div class="space-y-3">
                `;
                
                Object.entries(module.data.planosDeEnsino).forEach(([semestre, disciplinas]) => {
                    html += `
                        <details class="bg-slate-50 border border-slate-200 rounded-xl group mb-3">
                            <summary class="p-4 font-semibold text-slate-700 cursor-pointer flex justify-between items-center hover:bg-slate-100 rounded-xl transition-colors min-w-0">
                                <span class="truncate"><i data-lucide="layers" class="w-4 h-4 inline mr-2 text-brand-600 shrink-0"></i> ${semestre}</span>
                                <i data-lucide="chevron-down" class="w-5 h-5 text-slate-400 group-open:rotate-180 transition-transform shrink-0"></i>
                            </summary>
                            <div class="p-3 md:p-4 pt-2 border-t border-slate-100 grid grid-cols-1 md:grid-cols-2 gap-3">
                                ${disciplinas.map(item => this.generateDisciplinaRow(courseId, semestre, item)).join('')}
                            </div>
                        </details>
                    `;
                });
                return html + `</div></div></div>`;
            },

            templatePlanos(courseId, module) {
                let html = `<div class="space-y-8">`;
                
                // Coordenação
                html += `<div>
                    <h3 class="text-sm font-bold text-slate-400 uppercase tracking-wider mb-3 px-1 flex items-center break-words"><i data-lucide="calendar" class="w-4 h-4 mr-2 shrink-0"></i> Planos de Coordenação (Anual)</h3>
                    <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
                        ${module.data.coordenacao.map(item => this.generateRow(courseId, 'planos', item)).join('')}
                    </div>
                </div>`;

                // Docentes
                html += `<div>
                    <div class="flex flex-col md:flex-row md:justify-between md:items-end mb-4 px-1 gap-3 border-t border-slate-100 pt-6">
                        <h3 class="text-sm font-bold text-slate-400 uppercase tracking-wider flex items-center break-words min-w-0"><i class="w-4 h-4 mr-2 shrink-0" data-lucide="users"></i> <span class="min-w-0">Planos de Ação Docente</span></h3>
                        <div class="flex flex-col sm:flex-row items-stretch sm:items-center gap-2 w-full md:w-auto shrink-0">
                            <select onchange="app.changePlanosSort(this.value)" class="text-sm sm:text-xs border border-slate-200 rounded-lg px-3 py-2 text-slate-600 bg-white outline-none focus:border-brand-500 shadow-sm cursor-pointer w-full sm:w-auto">
                                <option value="professor" ${this.state.planosSortBy === 'professor' ? 'selected' : ''}>Agrupar por: Professor</option>
                                <option value="semestre" ${this.state.planosSortBy === 'semestre' ? 'selected' : ''}>Agrupar por: Semestre</option>
                            </select>
                            <button onclick="app.openAddPlanoForm()" class="justify-center text-xs bg-brand-50 hover:bg-brand-100 text-brand-700 font-semibold py-2 px-4 rounded-lg border border-brand-200 transition-colors flex items-center shadow-sm w-full sm:w-auto">
                                <i data-lucide="plus" class="w-4 h-4 mr-1"></i> Adicionar Professor
                            </button>
                        </div>
                    </div>`;

                // Formulário Inline de Inclusão de Novo Plano
                if (this.state.showAddPlanoForm) {
                    html += `
                    <div class="bg-brand-50 border border-brand-200 rounded-xl p-4 md:p-5 mb-4 slide-in shadow-sm">
                        <h4 class="font-bold text-brand-800 text-sm mb-3">Novo Plano de Ação</h4>
                        <div class="grid grid-cols-1 md:grid-cols-2 gap-3 mb-3">
                            <input type="text" id="new-plano-nome" placeholder="Nome do Professor" class="sheet-input bg-white border-slate-300">
                            <input type="text" id="new-plano-disc" placeholder="Disciplina" class="sheet-input bg-white border-slate-300">
                        </div>
                        <div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-3 mb-4 mt-3">
                            <select id="new-plano-sem" class="sheet-input bg-white border-slate-300 cursor-pointer">
                                <option value="1º Semestre">1º Semestre</option>
                                <option value="2º Semestre">2º Semestre</option>
                                <option value="3º Semestre">3º Semestre</option>
                                <option value="4º Semestre">4º Semestre</option>
                                <option value="5º Semestre">5º Semestre</option>
                                <option value="6º Semestre">6º Semestre</option>
                                <option value="7º Semestre">7º Semestre</option>
                                <option value="8º Semestre">8º Semestre</option>
                            </select>
                            <select id="new-plano-ano" class="sheet-input bg-white border-slate-300 cursor-pointer">
                                <option value="2024">2024</option>
                                <option value="2025" selected>2025</option>
                                <option value="2026">2026</option>
                            </select>
                            <div class="flex items-center sm:col-span-2 md:col-span-1">
                                <label class="flex items-center px-4 py-2 bg-white border border-slate-300 rounded-lg text-xs font-medium text-slate-600 hover:bg-slate-50 cursor-pointer transition-colors w-full justify-center">
                                    <i data-lucide="upload-cloud" class="w-4 h-4 mr-2 text-slate-400 shrink-0"></i> Anexar Plano
                                    <input type="file" id="new-plano-file" class="hidden" onchange="this.parentElement.querySelector('span').innerText = this.files[0].name">
                                    <span class="ml-2 truncate max-w-[100px] sm:max-w-[150px]">Nenhum</span>
                                </label>
                            </div>
                        </div>
                        <div class="flex flex-col-reverse sm:flex-row justify-end gap-2">
                            <button onclick="app.cancelAddPlanoForm()" class="px-4 py-2 w-full sm:w-auto text-xs font-medium text-slate-600 hover:bg-slate-200 rounded-lg transition-colors">Cancelar</button>
                            <button onclick="app.saveNovoPlanoDocente('${courseId}')" class="px-4 py-2 w-full sm:w-auto text-xs font-medium bg-brand-600 text-white hover:bg-brand-700 rounded-lg transition-colors shadow-sm">Salvar Plano</button>
                        </div>
                    </div>`;
                }

                html += `<div class="space-y-4">`;

                if (module.data.docentes.length === 0) {
                    html += `<div class="text-center p-6 bg-slate-50 border border-dashed border-slate-300 rounded-xl text-slate-500 text-sm">Nenhum plano docente cadastrado. Clique em "Adicionar Professor" acima.</div>`;
                } else {
                    const sortBy = this.state.planosSortBy || 'professor';
                    const grouped = {};
                    module.data.docentes.forEach(item => {
                        const key = sortBy === 'professor' ? (item.nome || 'Sem Professor') : (item.semestre || 'Sem Semestre');
                        if(!grouped[key]) grouped[key] = [];
                        grouped[key].push(item);
                    });

                    Object.keys(grouped).sort().forEach(groupKey => {
                        html += `
                            <div class="bg-white border border-slate-200 rounded-xl overflow-hidden shadow-sm">
                                <div class="bg-slate-50 px-4 py-3 border-b border-slate-200 font-bold text-slate-700 text-sm flex items-center break-words min-w-0">
                                    <i data-lucide="${sortBy === 'professor' ? 'user' : 'layers'}" class="w-4 h-4 mr-2 text-brand-600 shrink-0"></i> <span class="min-w-0">${groupKey}</span>
                                </div>
                                <div class="p-3 space-y-3 bg-slate-50/30">
                        `;
                        grouped[groupKey].forEach(item => {
                            const displayLabel = sortBy === 'professor' 
                                ? `<span class="font-semibold text-slate-700 block sm:inline">${item.disciplina}</span> <span class="text-[10px] md:text-xs font-medium text-slate-500 mt-1 sm:mt-0 sm:ml-1 py-0.5 px-2 bg-slate-200 rounded-full inline-block">${item.semestre} / ${item.ano || '2025'}</span>`
                                : `<span class="font-semibold text-slate-700 block sm:inline">${item.nome}</span> <span class="text-xs text-slate-500 mt-1 sm:mt-0 sm:ml-1 block sm:inline break-words">- ${item.disciplina} (${item.ano || '2025'})</span>`;
                            
                            const displayItem = { ...item, label: displayLabel };
                            html += this.generateRow(courseId, 'planos', displayItem);
                        });
                        html += `</div></div>`;
                    });
                }
                html += `</div></div>`;

                // CPA
                html += `<div>
                    <h3 class="text-sm font-bold text-slate-400 uppercase tracking-wider mb-3 px-1 flex items-center border-t border-slate-100 pt-6 break-words"><i data-lucide="pie-chart" class="w-4 h-4 mr-2 shrink-0"></i> Autoavaliação CPA (Semestral)</h3>
                    <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
                        ${module.data.cpa.map(item => this.generateRow(courseId, 'planos', item)).join('')}
                    </div>
                </div>`;

                // Melhorias Contínuas
                html += `<div>
                    <h3 class="text-sm font-bold text-slate-400 uppercase tracking-wider mb-3 px-1 border-t border-slate-100 pt-6 break-words">Relatório de Melhorias</h3>
                    <div class="space-y-3">
                        ${module.data.melhorias.map(item => this.generateRow(courseId, 'planos', item)).join('')}
                    </div>
                </div>`;

                return html + `</div>`;
            },

            templateAtas(courseId, module) {
                let html = `<div class="space-y-8">`;
                
                const yearColors = {
                    '2024': { bg: 'bg-blue-50', border: 'border-blue-200', text: 'text-blue-800', innerBorder: 'border-blue-100', icon: 'text-blue-600' },
                    '2025': { bg: 'bg-indigo-50', border: 'border-indigo-200', text: 'text-indigo-800', innerBorder: 'border-indigo-100', icon: 'text-indigo-600' },
                    '2026': { bg: 'bg-violet-50', border: 'border-violet-200', text: 'text-violet-800', innerBorder: 'border-violet-100', icon: 'text-violet-600' }
                };

                Object.entries(module.data).forEach(([year, types]) => {
                    const colors = yearColors[year] || { bg: 'bg-slate-50', border: 'border-slate-200', text: 'text-slate-800', innerBorder: 'border-slate-100', icon: 'text-slate-600' };

                    html += `
                        <div class="${colors.bg} rounded-2xl p-4 md:p-5 border ${colors.border}">
                            <h3 class="text-lg font-bold ${colors.text} mb-4 flex items-center min-w-0"><i data-lucide="calendar" class="w-5 h-5 mr-2 shrink-0 ${colors.icon}"></i> <span class="min-w-0 truncate">Ano Base: ${year}</span></h3>
                            <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
                    `;
                    Object.entries(types).forEach(([type, items]) => {
                        html += `
                            <div class="bg-white/80 backdrop-blur-sm rounded-xl p-3 md:p-4 border ${colors.innerBorder} shadow-sm min-w-0">
                                <h4 class="font-semibold text-slate-700 mb-3 border-b border-slate-100/50 pb-2 break-words">${type}</h4>
                                <div class="space-y-3">
                                    ${items.map(item => `
                                        <div class="flex flex-col lg:flex-row items-start lg:items-center justify-between bg-white p-3 rounded-xl border border-slate-200 gap-3">
                                            <span class="text-sm text-slate-700 font-medium break-words w-full lg:w-auto">${item.label}</span>
                                            <div class="flex items-center gap-2 w-full lg:w-auto justify-between lg:justify-end shrink-0">
                                                ${this.generateUploadDownloadHTML(courseId, 'atas', item)}
                                                ${this.generateStatusDropdown(courseId, 'atas', item.id, item.status)}
                                            </div>
                                        </div>
                                    `).join('')}
                                </div>
                            </div>
                        `;
                    });
                    html += `</div></div>`;
                });
                return html + `</div>`;
            },

            templateFE(courseId, module) {
                const dimensions = [
                    { key: 'dim1', title: 'Dimensão 1: Organização Didático-Pedagógica' },
                    { key: 'dim2', title: 'Dimensão 2: Corpo Docente e Tutorial' },
                    { key: 'dim3', title: 'Dimensão 3: Infraestrutura' }
                ];

                let html = `<div class="space-y-6">
                    <div class="bg-amber-50 border-l-4 border-amber-500 p-4 rounded-r-lg mb-6 shadow-sm">
                        <p class="text-sm text-amber-800 break-words"><i data-lucide="info" class="w-5 h-5 inline mr-1 shrink-0"></i> Atenção: Responda exatamente o solicitado no instrumento. Limite restrito a 8.000 caracteres por indicador.</p>
                    </div>
                `;

                dimensions.forEach(dim => {
                    html += `
                        <details class="bg-white border border-slate-200 rounded-xl group overflow-hidden shadow-sm">
                            <summary class="p-4 md:p-5 bg-slate-50 font-semibold text-slate-800 cursor-pointer flex justify-between items-center hover:bg-slate-100 transition-colors min-w-0">
                                <span class="break-words mr-4">${dim.title}</span>
                                <i data-lucide="chevron-down" class="w-5 h-5 text-slate-500 group-open:rotate-180 transition-transform shrink-0"></i>
                            </summary>
                            <div class="p-3 md:p-5 space-y-6 border-t border-slate-100 bg-white">
                    `;
                    
                    module.data[dim.key].forEach(item => {
                        html += `
                            <div class="border border-slate-200 rounded-xl p-3 md:p-5 bg-slate-50/50">
                                <div class="flex flex-col md:flex-row md:justify-between md:items-start mb-4 gap-4">
                                    <h5 class="font-bold text-slate-800 text-sm md:text-[15px] leading-relaxed flex-1 break-words">${item.title}</h5>
                                    <div class="w-full md:w-auto shrink-0">
                                        ${this.generateStatusDropdown(courseId, 'fe', item.id, item.status)}
                                    </div>
                                </div>
                                <div class="bg-white border border-slate-300 rounded-lg overflow-hidden focus-within:ring-2 focus-within:ring-brand-500 focus-within:border-transparent transition-all mt-2">
                                    <div class="bg-slate-50 border-b border-slate-200 p-1.5 flex flex-wrap gap-1 rich-text-toolbar">
                                        <button title="Negrito"><b>B</b></button>
                                        <button title="Itálico"><i>I</i></button>
                                        <button title="Sublinhado"><u>U</u></button>
                                        <div class="w-px h-5 bg-slate-300 mx-1 self-center hidden sm:block"></div>
                                        <button title="Lista">• Lista</button>
                                    </div>
                                    <textarea 
                                        class="w-full p-3 md:p-4 text-sm text-slate-700 outline-none resize-y min-h-[140px] md:min-h-[120px]" 
                                        placeholder="Redija a justificativa e os indícios para este indicador..."
                                        maxlength="8000"
                                        onkeyup="app.updateFEText('${courseId}', '${item.id}', '${dim.key}', this.value)"
                                    >${item.text}</textarea>
                                </div>
                                <div id="count-${item.id}" class="text-xs mt-2 text-right ${item.text.length > 7900 ? 'text-rose-600 font-bold' : 'text-slate-400'}">
                                    ${item.text.length} / 8000 caracteres
                                </div>
                            </div>
                        `;
                    });

                    html += `</div></details>`;
                });
                return html + `</div>`;
            }
        };

        // --- 4. INITIALIZATION ---
        document.addEventListener('DOMContentLoaded', () => {
            lucide.createIcons();
            // Renderizar o app automaticamente (autenticação é via PHP)
            app.loadState();
        });

    </script>
</body>
</html>