// ═══════════════════════════════════════════════════════════════
// DATA · dados fictícios · sistema AVD (demo)
// ═══════════════════════════════════════════════════════════════

const SETORES = ['P&D e Escalonamento', 'Marketing e Leads', 'Prospecção', 'Propostas e Fechamento', 'Fidelização e NN', 'Fidelização', 'PMO', 'Novos Negócios e EVT', 'NNE', 'Editais de Fomento', 'Administrativo', 'Gente e Cultura', 'Associados e Editais', 'Associados de Projetos', 'VB', 'Redes', 'Diretoria'];

const COLABORADORES = [
  { id: 1, nome: "Amanda Dos Santos Da Paixão", cargo: "Analista Iii Step Ii", nivel: 'liderado', setor: "Carteira De Leads E Marketing", email: "amandapaixao@escalab.com.br", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 65, tempoCargo: 65, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'AD', gestorNome: "Maria Paula Duarte De Oliveira" },
  { id: 2, nome: "Ana Caroline De Oliveira Campos", cargo: "Analista Em Crescimento", nivel: 'liderado', setor: "Vb", email: "anacampos@escalab.com.br", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 40, tempoCargo: 40, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'AC', gestorNome: "Rochel Montero Lago" },
  { id: 3, nome: "Ana Paula De Carvalho Teixeira", cargo: "Diretor De Setor", nivel: 'diretor', setor: "Diretoria", email: "anapaula.cta1@gmail.com", senha: '123', perfil: 'admin', notasLiberadas: false, tempoEmpresa: 66, tempoCargo: 66, academico: 'Graduação Completa', cor: '#1F4A8A', iniciais: 'AP', gestorNome: null },
  { id: 4, nome: "André De Britto Anselmo", cargo: "Associado De Projetos", nivel: 'liderado', setor: "Associados De Projetos", email: "andre.anselmo@escalab.com.br", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 36, tempoCargo: 36, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'AD', gestorNome: "Felipe Keven De Carvalho Neves" },
  { id: 5, nome: "Breno Germano De Freitas Oliveira", cargo: "Diretor De Setor", nivel: 'diretor', setor: "Diretoria", email: "bgfoliveira@gmail.com", senha: '123', perfil: 'admin', notasLiberadas: false, tempoEmpresa: 59, tempoCargo: 59, academico: 'Graduação Completa', cor: '#1F4A8A', iniciais: 'BG', gestorNome: null },
  { id: 6, nome: "Bruno Da Costa Lacorte", cargo: "Analista Ii Step Ii", nivel: 'liderado', setor: "Administrativo Financeiro", email: "brunolacortee@escalab.com.br", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 41, tempoCargo: 41, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'BD', gestorNome: "Letícia Santos Bahia Silva" },
  { id: 7, nome: "Camilly Vitória Fernandes Morais", cargo: "Associado De Projetos", nivel: 'liderado', setor: "Associados De Projetos", email: "camillyfmorais@gmail.com", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 7, tempoCargo: 7, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'CV', gestorNome: "Clara Cardoso Costa" },
  { id: 8, nome: "Carolina Maria De Lima Alves", cargo: "Líder/especialista Ii Step Ii", nivel: 'lider', setor: "Fidelização E Gestão De Entregas- P&d & Escaloname", email: "carolinalima@escalab.com.br", senha: '123', perfil: 'gestor', notasLiberadas: false, tempoEmpresa: 60, tempoCargo: 60, academico: 'Graduação Completa', cor: '#00836B', iniciais: 'CM', gestorNome: "Breno Germano De Freitas Oliveira" },
  { id: 9, nome: "Clara Cardoso Costa", cargo: "Associado De Projetos", nivel: 'lider', setor: "Associados De Projetos", email: "claracardosocosta26@gmail.com", senha: '123', perfil: 'gestor', notasLiberadas: false, tempoEmpresa: 10, tempoCargo: 10, academico: 'Graduação Completa', cor: '#00836B', iniciais: 'CC', gestorNome: "Ana Paula De Carvalho Teixeira" },
  { id: 10, nome: "Davyston Carvalho Pedersoli", cargo: "Ceo", nivel: 'diretor', setor: "Nanofood", email: "davystonpedersoli@escalab.com.br", senha: '123', perfil: 'admin', notasLiberadas: false, tempoEmpresa: 83, tempoCargo: 83, academico: 'Graduação Completa', cor: '#1F4A8A', iniciais: 'DC', gestorNome: null },
  { id: 11, nome: "Eduarda Rezende Barbosa", cargo: "Líder/especialista I Step I", nivel: 'liderado', setor: "Novos Negócios E Evt", email: "eduarda.rezende@escalab.com.br", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 65, tempoCargo: 65, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'ER', gestorNome: "Rafaela Leal Pereira" },
  { id: 12, nome: "Emanuelle De Paula Ferreira", cargo: "Associado", nivel: 'liderado', setor: "Associados De Editais (ana P E Rochel)", email: "emanuellepaulaferreira@gmail.com", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 15, tempoCargo: 15, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'ED', gestorNome: "Gabriela Campos De Oliveira" },
  { id: 13, nome: "Fabiana Moreira Barbosa", cargo: "Analista I Step Iii", nivel: 'liderado', setor: "Administrativo Financeiro", email: "fabiana_moreira@escalab.com.br", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 30, tempoCargo: 30, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'FM', gestorNome: "Letícia Santos Bahia Silva" },
  { id: 14, nome: "Fabiano Gomes Ferreira De Paula", cargo: "Diretor De Área", nivel: 'diretor', setor: "Diretoria", email: "fabianogfp@escalab.com.br", senha: '123', perfil: 'admin', notasLiberadas: false, tempoEmpresa: 74, tempoCargo: 74, academico: 'Graduação Completa', cor: '#1F4A8A', iniciais: 'FG', gestorNome: null },
  { id: 15, nome: "Felipe Keven De Carvalho Neves", cargo: "Coordenador Técnico Step Ii", nivel: 'lider', setor: "P&d E Escalonamento", email: "felipeneves@escalab.com.br", senha: '123', perfil: 'gestor', notasLiberadas: false, tempoEmpresa: 3, tempoCargo: 3, academico: 'Graduação Completa', cor: '#00836B', iniciais: 'FK', gestorNome: "Carolina Maria De Lima Alves" },
  { id: 16, nome: "Gabriela Campos De Oliveira", cargo: "Associado De Projetos", nivel: 'lider', setor: "Associados De Editais (ana P E Rochel)", email: "gabrielacdeoliveira99@gmail.com", senha: '123', perfil: 'gestor', notasLiberadas: false, tempoEmpresa: 10, tempoCargo: 10, academico: 'Graduação Completa', cor: '#00836B', iniciais: 'GC', gestorNome: "Ana Paula De Carvalho Teixeira" },
  { id: 17, nome: "Gustavo Costa Bernardo", cargo: "Associado", nivel: 'liderado', setor: "Associados De Editais (ana P E Rochel)", email: "falta-email-001@escalab.com.br", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 4, tempoCargo: 4, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'GC', gestorNome: "Gabriela Campos De Oliveira" },
  { id: 18, nome: "Gustavo Spagnol Campos", cargo: "Analista Iii Step I", nivel: 'lider', setor: "Editais De Fomento", email: "gustavo.spagnol@escalab.com.br", senha: '123', perfil: 'gestor', notasLiberadas: false, tempoEmpresa: 31, tempoCargo: 31, academico: 'Graduação Completa', cor: '#00836B', iniciais: 'GS', gestorNome: "Breno Germano De Freitas Oliveira" },
  { id: 19, nome: "Hiago Lucas De Oliveira Costa", cargo: "Analista Ii Step I", nivel: 'liderado', setor: "Carteira De Leads E Marketing", email: "hiago.lucas@escalab.com.br", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 37, tempoCargo: 37, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'HL', gestorNome: "Jorge Filipe De Souza Santos" },
  { id: 20, nome: "Ingrid Fernandes Silva", cargo: "Líder/especialista Ii Step I", nivel: 'lider', setor: "Propostas E Fechamento", email: "ingridfernandesilva@hotmail.com", senha: '123', perfil: 'gestor', notasLiberadas: false, tempoEmpresa: 24, tempoCargo: 24, academico: 'Graduação Completa', cor: '#00836B', iniciais: 'IF', gestorNome: "Fabiano Gomes Ferreira De Paula" },
  { id: 21, nome: "Ingrid Luize Costa Gonçalves", cargo: "Associado De Projetos", nivel: 'liderado', setor: "Associados De Projetos", email: "ingridluizegoncalves@gmail.com", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 14, tempoCargo: 14, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'IL', gestorNome: "Felipe Keven De Carvalho Neves" },
  { id: 22, nome: "Isabella Silva Arantes", cargo: "Analista Ii Step Iii", nivel: 'liderado', setor: "Carteira De Leads E Marketing", email: "isabella.arantes@escalab.com.br", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 22, tempoCargo: 22, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'IS', gestorNome: "Jorge Filipe De Souza Santos" },
  { id: 23, nome: "Isabelly Reis Monteiro", cargo: "Analista Ii Step Ii", nivel: 'liderado', setor: "Novos Negócios E Evt", email: "falta-email-002@escalab.com.br", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 3, tempoCargo: 3, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'IR', gestorNome: "Rafaela Leal Pereira" },
  { id: 24, nome: "Izabella Cristinna Nogueira Passos Andrade", cargo: "Associado", nivel: 'liderado', setor: "Redes", email: "falta-email-003@escalab.com.br", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 66, tempoCargo: 66, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'IC', gestorNome: "Rochel Montero Lago" },
  { id: 25, nome: "Izabelle Fortes Meirelles", cargo: "Associado De Projetos", nivel: 'liderado', setor: "Associados De Projetos", email: "falta-email-004@escalab.com.br", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 1, tempoCargo: 1, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'IF', gestorNome: "Rafaela Leal Pereira" },
  { id: 26, nome: "Jeniffer Eduarda Fernandes Souza", cargo: "Associado", nivel: 'liderado', setor: "Associados De Editais (ana P E Rochel)", email: "jenifferefernandes@gmail.com", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 29, tempoCargo: 29, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'JE', gestorNome: "Gabriela Campos De Oliveira" },
  { id: 27, nome: "Jorge Filipe De Souza Santos", cargo: "Analista Iii Step Ii", nivel: 'lider', setor: "Carteira De Leads E Marketing", email: "jorge.filipe@escalab.com.br", senha: '123', perfil: 'gestor', notasLiberadas: false, tempoEmpresa: 62, tempoCargo: 62, academico: 'Graduação Completa', cor: '#00836B', iniciais: 'JF', gestorNome: "Maria Paula Duarte De Oliveira" },
  { id: 28, nome: "Julia Braga Marques Pereira", cargo: "Técnico/assistente Ii", nivel: 'liderado', setor: "P&d E Escalonamento", email: "juliabraga@escalab.com.br", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 42, tempoCargo: 42, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'JB', gestorNome: "Felipe Keven De Carvalho Neves" },
  { id: 29, nome: "Juliana Vieira Ferreira Ribeiro", cargo: "Analista Ii Step Ii", nivel: 'liderado', setor: "P&d E Escalonamento", email: "julianavfrufmg@gmail.com", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 34, tempoCargo: 34, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'JV', gestorNome: "Felipe Keven De Carvalho Neves" },
  { id: 30, nome: "Leonardo Silva Assunção", cargo: "Analista Ii Step I", nivel: 'liderado', setor: "Propostas E Fechamento", email: "leo.9463@gmail.com", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 36, tempoCargo: 36, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'LS', gestorNome: "Ingrid Fernandes Silva" },
  { id: 31, nome: "Letícia Santos Bahia Silva", cargo: "Analista Iii Step I", nivel: 'lider', setor: "Administrativo Financeiro", email: "leticiabahia@escalab.com.br", senha: '123', perfil: 'gestor', notasLiberadas: false, tempoEmpresa: 48, tempoCargo: 48, academico: 'Graduação Completa', cor: '#00836B', iniciais: 'LS', gestorNome: "Maria Paula Duarte De Oliveira" },
  { id: 32, nome: "Lucas Maciel Almeida", cargo: "Associado De Projetos", nivel: 'liderado', setor: "Associados De Projetos", email: "lucasmacielmaciel2004@gmail.com", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 14, tempoCargo: 14, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'LM', gestorNome: "Felipe Keven De Carvalho Neves" },
  { id: 33, nome: "Maria Clara Ferreira Silva", cargo: "Analista Ii Step Ii", nivel: 'liderado', setor: "Gente E Cultura", email: "mariaclaraferreirasilva2501@gmail.com", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 24, tempoCargo: 24, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'MC', gestorNome: "Maria Paula Duarte De Oliveira" },
  { id: 34, nome: "Maria Eduarda Amaral Leite", cargo: "Associado", nivel: 'liderado', setor: "Associados De Editais (ana P E Rochel)", email: "marymarall415@gmail.com", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 14, tempoCargo: 14, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'ME', gestorNome: "Gabriela Campos De Oliveira" },
  { id: 35, nome: "Maria Paula Duarte De Oliveira", cargo: "Ceo", nivel: 'diretor', setor: "Diretoria", email: "mariaduarte@escalab.com.br", senha: '123', perfil: 'admin', notasLiberadas: false, tempoEmpresa: 93, tempoCargo: 93, academico: 'Graduação Completa', cor: '#1F4A8A', iniciais: 'MP', gestorNome: null },
  { id: 36, nome: "Marina Luisa Silva Coelho", cargo: "Associado De Projetos", nivel: 'liderado', setor: "Associados De Projetos", email: "marina_luizacoelho@hotmail.com", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 9, tempoCargo: 9, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'ML', gestorNome: "Ana Paula De Carvalho Teixeira" },
  { id: 37, nome: "Maryna Moreira Barros", cargo: "Associado", nivel: 'liderado', setor: "Vb", email: "maryna.moreira.b@gmail.com", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 23, tempoCargo: 23, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'MM', gestorNome: "Rochel Montero Lago" },
  { id: 38, nome: "Natália Carvalhinho Windmöller", cargo: "Analista Ii Step Ii", nivel: 'liderado', setor: "Prospecção E Inteligência De Mercado", email: "natalia.cw@escalab.com.br", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 3, tempoCargo: 3, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'NC', gestorNome: "Vanessa Vital França" },
  { id: 39, nome: "Pedro Henrique De Souza Leão", cargo: "Analista Ii Step Ii", nivel: 'liderado', setor: "P&d E Escalonamento", email: "p.pedrohenriqueleao@gmail.com", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 3, tempoCargo: 3, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'PH', gestorNome: "Felipe Keven De Carvalho Neves" },
  { id: 40, nome: "Rafaela Leal Pereira", cargo: "Líder/especialista Iii Step I", nivel: 'lider', setor: "Fidelização E Gestão De Entregas  Nn E Viabilidade", email: "rafaelalealpereira@gmail.com", senha: '123', perfil: 'gestor', notasLiberadas: false, tempoEmpresa: 54, tempoCargo: 54, academico: 'Graduação Completa', cor: '#00836B', iniciais: 'RL', gestorNome: "Fabiano Gomes Ferreira De Paula" },
  { id: 41, nome: "Rochel Montero Lago", cargo: "Diretor Executivo", nivel: 'diretor', setor: "Diretoria", email: "rochellago@escalab.com.br", senha: '123', perfil: 'admin', notasLiberadas: false, tempoEmpresa: 93, tempoCargo: 93, academico: 'Graduação Completa', cor: '#1F4A8A', iniciais: 'RM', gestorNome: null },
  { id: 42, nome: "Sarah Faria Spelta", cargo: "Associado De Projetos", nivel: 'liderado', setor: "Associados De Projetos", email: "sarah.fspelta@gmail.com", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 26, tempoCargo: 26, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'SF', gestorNome: "Felipe Keven De Carvalho Neves" },
  { id: 43, nome: "Sarah Fernandes Coelho Viana", cargo: "Associado De Projetos", nivel: 'liderado', setor: "Associados De Projetos", email: "sarahfcviana@gmail.com", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 14, tempoCargo: 14, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'SF', gestorNome: "Rochel Montero Lago" },
  { id: 44, nome: "Vanessa Vital França", cargo: "Analista Iii Step Ii", nivel: 'lider', setor: "Prospecção E Inteligência De Mercado", email: "vanessa.vital@escalab.com.br", senha: '123', perfil: 'gestor', notasLiberadas: false, tempoEmpresa: 63, tempoCargo: 63, academico: 'Graduação Completa', cor: '#00836B', iniciais: 'VV', gestorNome: "Fabiano Gomes Ferreira De Paula" },
  { id: 45, nome: "Waleska Cristina Lúcio Santos", cargo: "Associado", nivel: 'liderado', setor: "Redes", email: "waleskacristina@escalab.com.br", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 20, tempoCargo: 20, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'WC', gestorNome: "Rochel Montero Lago" },
  { id: 46, nome: "Yasmim Rodrigues Dos Santos", cargo: "Líder/especialista Ii Step Ii", nivel: 'liderado', setor: "Pmo", email: "yasmim.santos@escalab.com.br", senha: '123', perfil: 'colaborador', notasLiberadas: false, tempoEmpresa: 63, tempoCargo: 63, academico: 'Graduação Completa', cor: '#6B3FA0', iniciais: 'YR', gestorNome: "Fabiano Gomes Ferreira De Paula" },
];

// CONQUISTAS, HISTORICO_PROFISSIONAL · sem dados reais por colab (ainda nao importado)
const CONQUISTAS = {};
const HISTORICO_PROFISSIONAL = {};

// CICLOS · populado em runtime via fetchCiclosSupabase() apos login.
// Antes ficava hardcoded; agora o banco e fonte de verdade (013_avd_tables.sql).
// Mantemos let pra que o array seja preenchido in-place sem quebrar imports.
let CICLOS = [];

// AVALIACOES · populado em runtime via fetchAvaliacoesSupabase() apos login.
// Antes vivia hardcoded em data.jsx — qualquer um podia fazer curl no JS e ver notas.
// Agora o banco filtra via RLS: admin tudo, gestor time, colab proprio se liberada.
let AVALIACOES = [];
const AVALIACOES_SETOR = [];
// Auto-gerado por scripts/gerar_seed_feedbacks.js a partir de "Documentos Treinamento/AVD e Feedback/"
const FEEDBACKS = [
  {"id":"F0001","colaboradorId":6,"data":"2025-07-15","responsavel":"Líder direto","trimestre":"2T2025","arquivo":"[AVD 3] Feedback Estruturado - Bruno.docx (1).pdf","preparoOk":true,"comentarios":[]},
  {"id":"F0002","colaboradorId":13,"data":"2025-07-15","responsavel":"Líder direto","trimestre":"2T2025","arquivo":"[AVD 3] Feedback Estruturado - Fabi.docx (1).pdf","preparoOk":true,"comentarios":[]},
  {"id":"F0003","colaboradorId":33,"data":"2025-07-15","responsavel":"Líder direto","trimestre":"2T2025","arquivo":"Feedback Estruturado - Maria Clara.docx.pdf","preparoOk":true,"comentarios":[]},
  {"id":"F0004","colaboradorId":40,"data":"2025-07-15","responsavel":"Líder direto","trimestre":"2T2025","arquivo":"Feedback Estruturado - Rafaela.pdf","preparoOk":true,"comentarios":[]},
  {"id":"F0005","colaboradorId":46,"data":"2025-07-15","responsavel":"Líder direto","trimestre":"2T2025","arquivo":"Feedback Estruturado - Yasmim.pdf","preparoOk":true,"comentarios":[]},
  {"id":"F0006","colaboradorId":5,"data":"2025-04-15","responsavel":"Líder direto","trimestre":"1T2025","arquivo":"[Feedback Breno] 2º Avaliação de Desempenho.xlsx","preparoOk":true,"comentarios":[]},
  {"id":"F0007","colaboradorId":20,"data":"2025-04-15","responsavel":"Líder direto","trimestre":"1T2025","arquivo":"[Feedback Ingrid - Leo] 2º Avaliação de Desempenho.xlsx","preparoOk":true,"comentarios":[]},
  {"id":"F0008","colaboradorId":30,"data":"2025-04-15","responsavel":"Líder direto","trimestre":"1T2025","arquivo":"[Feedback Ingrid - Leo] 2º Avaliação de Desempenho.xlsx","preparoOk":true,"comentarios":[]},
  {"id":"F0009","colaboradorId":38,"data":"2025-04-15","responsavel":"Líder direto","trimestre":"1T2025","arquivo":"[Feedback Nathália] 2º Avaliação de Desempenho.xlsx","preparoOk":true,"comentarios":[]},
  {"id":"F0010","colaboradorId":34,"data":"2025-07-15","responsavel":"Líder direto","trimestre":"2T2025","arquivo":"Feedback - Maria Eduarda.pdf","preparoOk":true,"comentarios":[]},
  {"id":"F0011","colaboradorId":26,"data":"2025-07-15","responsavel":"Líder direto","trimestre":"2T2025","arquivo":"Jeniffer - Feedback.pdf","preparoOk":true,"comentarios":[]},
  {"id":"F0012","colaboradorId":4,"data":"2024-09-30","responsavel":"Líder direto","trimestre":"3T2024","arquivo":"[Feedback Petrobrás + André + Sarah] 3º Avaliação de Desempenho.xlsx","preparoOk":true,"comentarios":[]},
  {"id":"F0013","colaboradorId":42,"data":"2024-09-30","responsavel":"Líder direto","trimestre":"3T2024","arquivo":"[Feedback Petrobrás + André + Sarah] 3º Avaliação de Desempenho.xlsx","preparoOk":true,"comentarios":[]},
];
const FEEDBACKS_TRIM = [];
const FEEDBACKS_SETOR_ATUAL = [
  {"setor":"Gente E Cultura","total":1,"receberam":1,"pct":100},
  {"setor":"Fidelização E Gestão De Entregas  Nn E Viabilidade","total":1,"receberam":1,"pct":100},
  {"setor":"Pmo","total":1,"receberam":1,"pct":100},
  {"setor":"Administrativo Financeiro","total":3,"receberam":2,"pct":67},
  {"setor":"Associados De Editais (ana P E Rochel)","total":5,"receberam":2,"pct":40},
  {"setor":"Carteira De Leads E Marketing","total":4,"receberam":0,"pct":0},
  {"setor":"Vb","total":2,"receberam":0,"pct":0},
  {"setor":"Diretoria","total":5,"receberam":0,"pct":0},
  {"setor":"Associados De Projetos","total":9,"receberam":0,"pct":0},
  {"setor":"Fidelização E Gestão De Entregas- P&d & Escaloname","total":1,"receberam":0,"pct":0},
  {"setor":"Nanofood","total":1,"receberam":0,"pct":0},
  {"setor":"Novos Negócios E Evt","total":2,"receberam":0,"pct":0},
  {"setor":"P&d E Escalonamento","total":4,"receberam":0,"pct":0},
  {"setor":"Editais De Fomento","total":1,"receberam":0,"pct":0},
  {"setor":"Propostas E Fechamento","total":2,"receberam":0,"pct":0},
  {"setor":"Redes","total":2,"receberam":0,"pct":0},
  {"setor":"Prospecção E Inteligência De Mercado","total":2,"receberam":0,"pct":0},
];
const EVOLUCAO_HISTORICA = [];
const TEMPO_CARGO = [];

const BANCO_PERGUNTAS = {
  'Analista II': [
    { bloco: 'tecnico',        pergunta: 'Domínio técnico das ferramentas e processos da área' },
    { bloco: 'tecnico',        pergunta: 'Qualidade e acurácia das entregas produzidas' },
    { bloco: 'comportamental', pergunta: 'Colaboração com o time e comunicação efetiva' },
    { bloco: 'comportamental', pergunta: 'Proatividade e iniciativa em melhorias' },
    { bloco: 'metas',          pergunta: 'Cumprimento de prazos e entrega de valor' },
    { bloco: 'metas',          pergunta: 'Alinhamento com OKRs do trimestre' },
  ],
  'Coordenador Técnico': [
    { bloco: 'tecnico',        pergunta: 'Visão técnica e tomada de decisão na área' },
    { bloco: 'comportamental', pergunta: 'Desenvolvimento das pessoas do time' },
    { bloco: 'lideranca',      pergunta: 'Capacidade de inspirar e motivar a equipe' },
    { bloco: 'lideranca',      pergunta: 'Gestão de conflitos e ambiente psicologicamente seguro' },
    { bloco: 'metas',          pergunta: 'Atingimento das metas da área' },
  ],
  'default': [
    { bloco: 'tecnico',        pergunta: 'Domínio técnico das atividades do cargo' },
    { bloco: 'comportamental', pergunta: 'Trabalho em equipe e comunicação' },
    { bloco: 'comportamental', pergunta: 'Proatividade e iniciativa' },
    { bloco: 'metas',          pergunta: 'Cumprimento de metas e prazos' },
    { bloco: 'metas',          pergunta: 'Contribuição para os resultados do setor' },
  ],
};

// ── Funções utilitárias ──────────────────────────────────────────────────────

function getMediaSetor(setor, cicloId) {
  const avs = AVALIACOES.filter(a => {
    const colab = COLABORADORES.find(c => c.id === a.avaliadoId);
    return colab && colab.setor === setor && a.cicloId === cicloId && a.nota != null;
  });
  if (!avs.length) return null;
  return avs.reduce((s, a) => s + a.nota, 0) / avs.length;
}

function getAvaliacoesColaborador(colaboradorId) {
  return AVALIACOES.filter(a => a.avaliadoId === colaboradorId && a.nota != null);
}

function getFeedbacksColaborador(colaboradorId) {
  return FEEDBACKS.filter(f => f.colaboradorId === colaboradorId);
}

// ── Categorias: Fixo vs Associado ────────────────────────────────────────────

const CATEGORIA_MAP = {};
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,40,41,42].forEach(id => {
  CATEGORIA_MAP[id] = { categoria: 'fixo', tipoAssociado: null };
});
[28,29,30,31,32,33].forEach(id => {
  CATEGORIA_MAP[id] = { categoria: 'associado', tipoAssociado: 'projetos' };
});
[34,35,36].forEach(id => {
  CATEGORIA_MAP[id] = { categoria: 'associado', tipoAssociado: 'editais' };
});
[37].forEach(id => {
  CATEGORIA_MAP[id] = { categoria: 'associado', tipoAssociado: 'vb' };
});
[38,39].forEach(id => {
  CATEGORIA_MAP[id] = { categoria: 'associado', tipoAssociado: 'redes' };
});

// Prioriza categoria definida pelo admin em dados_org (LS). Fallback: CATEGORIA_MAP hardcoded.
function getCategoriaColaborador(id) {
  try {
    if (typeof localStorage !== 'undefined') {
      const raw = localStorage.getItem(`escalab_dados_org_${id}`);
      if (raw) {
        const d = JSON.parse(raw);
        const c = parseCategoriaLabel(d.categoria);
        if (c) return c;
      }
    }
  } catch {}
  return CATEGORIA_MAP[id] || { categoria: 'fixo', tipoAssociado: null };
}

// Converte string do select ("Fixo" / "Associado Projetos" / ...) -> { categoria, tipoAssociado }
function parseCategoriaLabel(label) {
  if (!label || typeof label !== 'string') return null;
  if (label === 'Fixo') return { categoria: 'fixo', tipoAssociado: null };
  const m = /^Associado\s+(Projetos|Editais|VB|Redes)$/i.exec(label.trim());
  if (m) return { categoria: 'associado', tipoAssociado: m[1].toLowerCase() };
  return null;
}

// Inverso: { categoria, tipoAssociado } -> string p/ select. Usado p/ pre-preencher dropdown.
// IMPORTANTE: se categoria='associado' mas tipoAssociado falta, retorna '' (vazio)
// pra forcar o select mostrar placeholder e o admin escolher o tipo. Antes
// retornava 'Fixo' mentirosamente, que ficou parte do bug do dual-write.
function formatCategoriaLabel(c) {
  if (!c) return 'Fixo';
  if (c.categoria === 'fixo') return 'Fixo';
  if (c.categoria === 'associado' && c.tipoAssociado) {
    return 'Associado ' + (c.tipoAssociado.toUpperCase() === c.tipoAssociado
      ? c.tipoAssociado
      : c.tipoAssociado.charAt(0).toUpperCase() + c.tipoAssociado.slice(1));
  }
  // categoria='associado' sem tipo OU valor desconhecido: vazio pro select mostrar "·"
  return '';
}

const CATEGORIA_LABEL = {
  fixo: 'Fixo',
  associado_projetos: 'Assoc. Projetos',
  associado_editais:  'Assoc. Editais',
  associado_redes:    'Assoc. Redes',
  associado_vb:       'VB',
};

function getCategoriaKey(id) {
  const { categoria, tipoAssociado } = getCategoriaColaborador(id);
  if (categoria === 'fixo') return 'fixo';
  return `associado_${tipoAssociado}`;
}

// ── Utilitário: converte meses em "X ano(s) e Y mês(es)" ────────────────────────

function mesesParaTempo(meses) {
  if (!meses || meses <= 0) return 'Menos de 1 mês';
  const anos  = Math.floor(meses / 12);
  const resto = meses % 12;
  if (anos === 0) return `${resto} ${resto === 1 ? 'mês' : 'meses'}`;
  if (resto === 0) return `${anos} ${anos === 1 ? 'ano' : 'anos'}`;
  return `${anos} ${anos === 1 ? 'ano' : 'anos'} e ${resto} ${resto === 1 ? 'mês' : 'meses'}`;
}

// ── Cargo display: admin vê completo, colaborador vê "Analista de Setor" ───────

const SETOR_DESCRICAO = {
  'Prospecção':              'Prospecção e Inteligência de Mercado',
  'Marketing e Leads':       'Carteira de Leads e Marketing',
  'Propostas e Fechamento':  'Propostas e Fechamento',
  'Editais de Fomento':      'Editais de Fomento',
  'P&D e Escalonamento':     'P&D e Escalonamento',
  'Fidelização':             'Fidelização e Gestão de Entregas',
  'Fidelização e NN':        'Fidelização e Novos Negócios',
  'PMO':                     'PMO',
  'Novos Negócios e EVT':    'Novos Negócios e EVT',
  'NNE':                     'Novos Negócios',
  'Administrativo':          'Administrativo e Financeiro',
  'Gente e Cultura':         'Gente e Cultura',
  'Associados e Editais':    'Editais e Captação',
  'Associados de Projetos':  'Gestão de Projetos',
  'VB':                      'Venture Builder',
  'Redes':                   'Redes e Parcerias',
};

function getCargoDisplay(colaborador, isAdmin) {
  if (isAdmin) return colaborador.cargo;
  const m = colaborador.cargo.match(/^(Analista|Técnico\/Assistente|Coordenador[a]?|Associado[a]?)/i);
  if (!m) return colaborador.cargo;
  const tipo = m[1];
  const desc = SETOR_DESCRICAO[colaborador.setor];
  return desc ? `${tipo} de ${desc}` : colaborador.cargo;
}

// ── Férias · dados e funções ──────────────────────────────────────────────────

const FERIAS_KEY = 'escalab_ferias';

const FERIAS_INICIAL = [
  { id: 'FER001', colaboradorId: 15, inicio: '2025-06-02', fim: '2025-06-16', dias: 15, tipo: 'Férias anuais', observacao: '', status: 'aprovada',       criadoEm: '2025-04-01T10:00:00', liderNome: 'Marcus Ferreira Neto',       liderAprovadoEm: '2025-04-02T14:30:00', rhNome: 'Ana Carolina Lima Santos', rhAprovadoEm: '2025-04-03T09:00:00', motivoRejeicao: null },
  { id: 'FER002', colaboradorId: 10, inicio: '2025-07-07', fim: '2025-07-18', dias: 10, tipo: 'Férias anuais', observacao: 'Planejado com antecedência', status: 'pendente_rh',    criadoEm: '2025-05-01T08:00:00', liderNome: 'Carlos Eduardo Mendes Costa',liderAprovadoEm: '2025-05-03T11:00:00', rhNome: null, rhAprovadoEm: null, motivoRejeicao: null },
  { id: 'FER003', colaboradorId: 16, inicio: '2025-05-26', fim: '2025-06-06', dias: 10, tipo: 'Férias anuais', observacao: '',                            status: 'pendente_lider', criadoEm: '2025-05-11T10:00:00', liderNome: null, liderAprovadoEm: null, rhNome: null, rhAprovadoEm: null, motivoRejeicao: null },
  { id: 'FER004', colaboradorId: 6,  inicio: '2025-08-04', fim: '2025-08-15', dias: 10, tipo: 'Férias anuais', observacao: 'Férias planejadas',           status: 'aprovada',       criadoEm: '2025-06-01T09:00:00', liderNome: 'Roberto Silva Ferreira',     liderAprovadoEm: '2025-06-02T10:00:00', rhNome: 'Ana Carolina Lima Santos', rhAprovadoEm: '2025-06-03T11:00:00', motivoRejeicao: null },
  // ── Pendentes de aprovação do líder · demo no kanban do gestor ──────────
  { id: 'FER-DEMO-LIDER1', colaboradorId: 15, inicio: '2026-07-20', fim: '2026-07-29', dias: 10, tipo: 'Férias anuais', observacao: 'Viagem em família planejada há meses', status: 'pendente_lider', criadoEm: '2026-06-12T10:00:00', liderNome: null, liderAprovadoEm: null, rhNome: null, rhAprovadoEm: null, motivoRejeicao: null },
  { id: 'FER-DEMO-LIDER2', colaboradorId: 21, inicio: '2026-08-03', fim: '2026-08-17', dias: 15, tipo: 'Férias anuais', observacao: 'Casamento no exterior',                 status: 'pendente_lider', criadoEm: '2026-06-13T14:30:00', liderNome: null, liderAprovadoEm: null, rhNome: null, rhAprovadoEm: null, motivoRejeicao: null },
  { id: 'FER-DEMO-LIDER3', colaboradorId: 24, inicio: '2026-07-13', fim: '2026-07-22', dias: 10, tipo: 'Férias anuais', observacao: '',                                       status: 'pendente_lider', criadoEm: '2026-06-14T09:15:00', liderNome: null, liderAprovadoEm: null, rhNome: null, rhAprovadoEm: null, motivoRejeicao: null },
  // ── Demonstrativo de férias da Ana Carolina (id=1, admin) — histórico para visualizar a tabela populada ─
  { id: 'FER-DEMO-A1a', colaboradorId: 1, inicio: '2021-03-01', fim: '2021-03-15', dias: 15, tipo: 'Férias anuais', observacao: '', status: 'aprovada', criadoEm: '2021-01-15T10:00:00', liderNome: null, liderAprovadoEm: null, rhNome: 'Ana Carolina Lima Santos', rhAprovadoEm: '2021-01-20T10:00:00', motivoRejeicao: null },
  { id: 'FER-DEMO-A1b', colaboradorId: 1, inicio: '2021-05-03', fim: '2021-05-17', dias: 15, tipo: 'Férias anuais', observacao: '', status: 'aprovada', criadoEm: '2021-03-20T10:00:00', liderNome: null, liderAprovadoEm: null, rhNome: 'Ana Carolina Lima Santos', rhAprovadoEm: '2021-03-22T10:00:00', motivoRejeicao: null },
  { id: 'FER-DEMO-A2',  colaboradorId: 1, inicio: '2022-01-10', fim: '2022-01-29', dias: 20, tipo: 'Férias anuais', observacao: '', status: 'aprovada', criadoEm: '2021-11-10T10:00:00', liderNome: null, liderAprovadoEm: null, rhNome: 'Ana Carolina Lima Santos', rhAprovadoEm: '2021-11-12T10:00:00', motivoRejeicao: null },
  { id: 'FER-DEMO-A3',  colaboradorId: 1, inicio: '2023-02-06', fim: '2023-03-07', dias: 30, tipo: 'Férias anuais', observacao: '', status: 'aprovada', criadoEm: '2022-12-05T10:00:00', liderNome: null, liderAprovadoEm: null, rhNome: 'Ana Carolina Lima Santos', rhAprovadoEm: '2022-12-08T10:00:00', motivoRejeicao: null },
  { id: 'FER-DEMO-A4a', colaboradorId: 1, inicio: '2024-01-08', fim: '2024-01-22', dias: 15, tipo: 'Férias anuais', observacao: '', status: 'aprovada', criadoEm: '2023-11-10T10:00:00', liderNome: null, liderAprovadoEm: null, rhNome: 'Ana Carolina Lima Santos', rhAprovadoEm: '2023-11-12T10:00:00', motivoRejeicao: null },
  { id: 'FER-DEMO-A4b', colaboradorId: 1, inicio: '2024-04-08', fim: '2024-04-17', dias: 10, tipo: 'Férias anuais', observacao: '', status: 'aprovada', criadoEm: '2024-02-10T10:00:00', liderNome: null, liderAprovadoEm: null, rhNome: 'Ana Carolina Lima Santos', rhAprovadoEm: '2024-02-15T10:00:00', motivoRejeicao: null },
  { id: 'FER-DEMO-A5',  colaboradorId: 1, inicio: '2025-03-10', fim: '2025-03-29', dias: 20, tipo: 'Férias anuais', observacao: '', status: 'aprovada', criadoEm: '2025-01-10T10:00:00', liderNome: null, liderAprovadoEm: null, rhNome: 'Ana Carolina Lima Santos', rhAprovadoEm: '2025-01-12T10:00:00', motivoRejeicao: null },
  { id: 'FER-DEMO-A6',  colaboradorId: 1, inicio: '2026-04-06', fim: '2026-04-20', dias: 15, tipo: 'Férias anuais', observacao: '', status: 'aprovada', criadoEm: '2026-02-10T10:00:00', liderNome: null, liderAprovadoEm: null, rhNome: 'Ana Carolina Lima Santos', rhAprovadoEm: '2026-02-12T10:00:00', motivoRejeicao: null },
];

function getFeriasSolicitacoes() {
  try {
    const raw = localStorage.getItem(FERIAS_KEY);
    if (raw) return JSON.parse(raw);
    localStorage.setItem(FERIAS_KEY, JSON.stringify(FERIAS_INICIAL));
    return FERIAS_INICIAL;
  } catch { return FERIAS_INICIAL; }
}

function salvarFeriasSolicitacoes(lista) {
  try { localStorage.setItem(FERIAS_KEY, JSON.stringify(lista)); } catch {}
}

function addFeriasRequest(req) {
  const lista = getFeriasSolicitacoes();
  lista.push(req);
  salvarFeriasSolicitacoes(lista);
  return lista;
}

function updateFeriasRequest(id, updates) {
  const lista = getFeriasSolicitacoes().map(f => f.id === id ? { ...f, ...updates } : f);
  salvarFeriasSolicitacoes(lista);
  return lista;
}

// ── Gerenciamento de notas liberadas (persistido em localStorage) ────────────

function getNotasLiberadasIds() {
  try { return new Set(JSON.parse(localStorage.getItem('escalab_notas_lib') || '[]').map(Number)); }
  catch { return new Set(); }
}

function liberarNotasColaborador(id) {
  const s = getNotasLiberadasIds();
  s.add(Number(id));
  localStorage.setItem('escalab_notas_lib', JSON.stringify([...s]));
  setNotasLiberadasSupabase(id, true);
  return getNotasLiberadasIds().has(Number(id));
}

function bloquearNotasColaborador(id) {
  const s = getNotasLiberadasIds();
  s.delete(Number(id));
  localStorage.setItem('escalab_notas_lib', JSON.stringify([...s]));
  setNotasLiberadasSupabase(id, false);
  return !getNotasLiberadasIds().has(Number(id));
}

function isNotasLiberadas(id) {
  return getNotasLiberadasIds().has(Number(id));
}

// Dual-write da flag pro Supabase. Resolve uuid via email do seed (id numerico).
// E o RLS no banco que controla quem le notas; o LS continua sendo o cache de UI.
async function setNotasLiberadasSupabase(id, liberada) {
  if (typeof window === 'undefined' || !window.supabaseClient) return false;
  try {
    const seed = (typeof COLABORADORES !== 'undefined' && Array.isArray(COLABORADORES))
      ? COLABORADORES.find(c => Number(c.id) === Number(id)) : null;
    const email = seed?.email;
    if (!email) { console.warn('[supabase] setNotasLiberadas: colab nao encontrado pra id', id); return false; }
    const { error } = await window.supabaseClient
      .from('colaboradores')
      .update({ notas_liberadas: !!liberada })
      .eq('email', email);
    if (error) { console.warn('[supabase] setNotasLiberadas falhou:', error.message); return false; }
    return true;
  } catch (e) {
    console.warn('[supabase] setNotasLiberadas exception:', e?.message);
    return false;
  }
}

// Busca ciclos do banco (qualquer autenticado le).
async function fetchCiclosSupabase() {
  if (typeof window === 'undefined' || !window.supabaseClient) return null;
  try {
    const { data, error } = await window.supabaseClient
      .from('ciclos').select('*').order('inicio', { ascending: true });
    if (error || !data) return null;
    // Mutacao in-place pra manter referencias dos imports
    CICLOS.length = 0;
    data.forEach(c => CICLOS.push({
      id: c.id, nome: c.nome,
      inicio: c.inicio, fim: c.fim, status: c.status,
      avd_aberta: !!c.avd_aberta, avd_aberta_em: c.avd_aberta_em,
    }));
    return CICLOS;
  } catch (e) {
    console.warn('[supabase] fetchCiclos falhou:', e?.message);
    return null;
  }
}

// Sincroniza o LS `escalab_notas_lib` a partir do banco (colaboradores.notas_liberadas).
// Pra admin: traz a flag de todos. Pra outros: traz so a propria (RLS filtra).
// Resolve drift entre LS antigo (pre-013) e o banco que e a fonte de verdade do RLS.
async function syncNotasLiberadasFromSupabase() {
  if (typeof window === 'undefined' || !window.supabaseClient) return null;
  try {
    const { data, error } = await window.supabaseClient
      .from('colaboradores').select('email, notas_liberadas');
    if (error || !data) return null;
    const emailToSeedId = {};
    if (typeof COLABORADORES !== 'undefined' && Array.isArray(COLABORADORES)) {
      COLABORADORES.forEach(c => {
        if (c.email) emailToSeedId[String(c.email).toLowerCase().trim()] = c.id;
      });
    }
    const ids = [];
    data.forEach(c => {
      const seedId = emailToSeedId[(c.email || '').toLowerCase().trim()];
      if (seedId != null && c.notas_liberadas) ids.push(Number(seedId));
    });
    localStorage.setItem('escalab_notas_lib', JSON.stringify(ids));
    return ids;
  } catch (e) {
    console.warn('[supabase] syncNotasLiberadas falhou:', e?.message);
    return null;
  }
}

// Busca avaliacoes do banco. RLS filtra: admin tudo, gestor time, colab proprio se liberada.
// Traduz avaliado_id (uuid) -> avaliadoId (numerico do seed) por email, pro resto do app
// continuar comparando por id numerico.
async function fetchAvaliacoesSupabase() {
  if (typeof window === 'undefined' || !window.supabaseClient) return null;
  try {
    const { data, error } = await window.supabaseClient
      .from('avaliacoes')
      .select('id, avaliado_id, avaliador_id, ciclo_id, tipo, nota, status, data, colaboradores!avaliacoes_avaliado_id_fkey(email)');
    if (error || !data) {
      if (error) console.warn('[supabase] fetchAvaliacoes:', error.message);
      return null;
    }
    const seedByEmail = {};
    if (typeof COLABORADORES !== 'undefined' && Array.isArray(COLABORADORES)) {
      COLABORADORES.forEach(c => {
        if (c.email) seedByEmail[String(c.email).toLowerCase().trim()] = c.id;
      });
    }
    AVALIACOES.length = 0;
    data.forEach(a => {
      const email = (a.colaboradores?.email || '').toLowerCase().trim();
      const seedId = email ? seedByEmail[email] : null;
      if (seedId == null) return; // RLS bloqueou ou colab fora do seed
      AVALIACOES.push({
        id: a.id,
        avaliadoId: seedId,
        avaliadorId: null, // placeholder do seed; nao expomos uuid
        cicloId: a.ciclo_id,
        tipo: a.tipo,
        nota: a.nota != null ? Number(a.nota) : null,
        status: a.status,
        data: a.data,
      });
    });
    return AVALIACOES;
  } catch (e) {
    console.warn('[supabase] fetchAvaliacoes exception:', e?.message);
    return null;
  }
}

// ── Persistência de overrides (gestorNome, setor, bio, etc.) ────────────────────

const COLAB_OVERRIDES_KEY = 'escalab_colab_overrides';

(function () {
  try {
    const overrides = JSON.parse(localStorage.getItem(COLAB_OVERRIDES_KEY) || '{}');
    COLABORADORES.forEach((c, idx) => {
      if (overrides[c.id]) Object.assign(COLABORADORES[idx], overrides[c.id]);
    });
  } catch {}
})();

function atualizarColaborador(id, updates) {
  try {
    const overrides = JSON.parse(localStorage.getItem(COLAB_OVERRIDES_KEY) || '{}');
    overrides[id] = { ...(overrides[id] || {}), ...updates };
    localStorage.setItem(COLAB_OVERRIDES_KEY, JSON.stringify(overrides));
    const idx = COLABORADORES.findIndex(c => c.id === id);
    if (idx !== -1) Object.assign(COLABORADORES[idx], updates);
  } catch {}
}

// ── Foto de perfil ────────────────────────────────────────────────────────────

function getFoto(id) {
  try { return localStorage.getItem(`escalab_foto_${id}`) || null; } catch { return null; }
}
function salvarFoto(id, dataUrl) {
  try { localStorage.setItem(`escalab_foto_${id}`, dataUrl); } catch {}
}

// ── Opções padronizadas de diversidade (usadas em screen-perfil + screen-dashboard) ──

const GENERO_OPCOES = [
  'Mulher cisgênero',
  'Homem Cisgênero',
  'Mulher Transgênero',
  'Homem Transgênero',
  'Não-binário',
  'Gênero fluido',
  'Prefiro não declarar',
];

const ORIENTACAO_OPCOES = [
  'Heterossexual',
  'Homossexual',
  'Bissexual',
  'Assexual',
  'Prefiro não me classificar',
  'Prefiro não declarar',
];

// ── Dados de admissão / assinatura ────────────────────────────────────────────

const SECOES_ASSINATURA = [
  { titulo: 'Identificação', icon: 'user', campos: [
    { key: 'nomeCompleto',    label: 'Nome completo' },
    { key: 'cpf',             label: 'CPF',                      sensivel: true },
    { key: 'rg',              label: 'RG · Número',              sensivel: true },
    { key: 'rgOrgaoEmissor',  label: 'RG · Órgão emissor',       sensivel: true },
    { key: 'rgDataEmissao',   label: 'RG · Data de emissão',     tipo: 'date'   },
    { key: 'dataNascimento',  label: 'Data de nascimento',       tipo: 'date'  /* alimenta aniversariantes da intranet · ver getAniversariantesDoMes */ },
    { key: 'naturalidade',    label: 'Naturalidade' },
    { key: 'estadoCivil',     label: 'Estado civil', tipo: 'select', opcoes: ['Solteiro(a)', 'Casado(a)', 'Divorciado(a)', 'Viúvo(a)', 'União estável'] },
    { key: 'nomeMae',         label: 'Nome da mãe',              sensivel: true },
    { key: 'nomePai',         label: 'Nome do pai',              sensivel: true },
  ]},
  { titulo: 'Contato', icon: 'message', campos: [
    { key: 'emailPessoal',       label: 'E-mail pessoal',                 tipo: 'email' },
    { key: 'emailProfissional',  label: 'E-mail profissional',            tipo: 'email' },
    { key: 'celular',            label: 'Celular / WhatsApp',             tipo: 'tel'   },
    { key: 'contatoEmergencia',  label: 'Contato de emergência (nome e telefone)' },
    { key: 'instagram',          label: 'Instagram (opcional)' },
    { key: 'linkedin',           label: 'LinkedIn (opcional)' },
    { key: 'lattes',             label: 'Currículo Lattes (obrigatório)', obrigatorio: true },
  ]},
  { titulo: 'Endereço', icon: 'home', campos: [
    { key: 'cep',         label: 'CEP' },
    { key: 'logradouro',  label: 'Logradouro' },
    { key: 'endNumero',   label: 'Número' },
    { key: 'complemento', label: 'Complemento' },
    { key: 'bairro',      label: 'Bairro' },
    { key: 'cidade',      label: 'Cidade' },
    { key: 'uf',          label: 'UF' },
  ]},
  { titulo: 'Dados Bancários', icon: 'clipboard', campos: [
    { key: 'banco',      label: 'Banco',              sensivel: true },
    { key: 'agencia',    label: 'Agência',             sensivel: true },
    { key: 'conta',      label: 'Número da conta',     sensivel: true },
    { key: 'contaTipo',  label: 'Tipo de conta',       sensivel: true, tipo: 'select', opcoes: ['Conta corrente', 'Conta poupança'] },
    { key: 'chavePix',   label: 'Chave PIX',           sensivel: true },
  ]},
  { titulo: 'Dados Trabalhistas', icon: 'trend_up', campos: [
    { key: 'ctpsNumero',   label: 'CTPS · Número' },
    { key: 'ctpsSerie',    label: 'CTPS · Série' },
    { key: 'ctpsEmissao',  label: 'CTPS · Data emissão', tipo: 'date' },
    { key: 'pisPasep',     label: 'PIS/PASEP',            sensivel: true },
    { key: 'dataAdmissao', label: 'Data de admissão',     tipo: 'date' },
    { key: 'cbo',          label: 'CBO' },
    { key: 'cargaHoraria', label: 'Carga horária semanal' },
    { key: 'modalidade',   label: 'Modalidade', tipo: 'select', opcoes: ['Presencial', 'Remoto', 'Híbrido'] },
  ]},
];

const DOCS_ADMISSAO = [
  { key: 'docIdentidade',          label: 'Documento de identidade (RG/CNH)',  obrigatorio: true  },
  { key: 'docCpf',                 label: 'CPF',                               obrigatorio: true  },
  { key: 'docComprovanteResidencia', label: 'Comprovante de residência',       obrigatorio: true  },
  { key: 'docFoto3x4',             label: 'Foto 3x4',                          obrigatorio: true  },
  { key: 'docCtps',                label: 'Carteira de trabalho (CTPS)',        obrigatorio: true  },
  { key: 'docDiploma',             label: 'Diploma / Certificado de escolaridade', obrigatorio: false },
  { key: 'docContaBancaria',       label: 'Comprovante de conta bancária',     obrigatorio: true  },
];

const ASSINATURA_KEY = 'escalab_assinatura';

function getDadosAssinatura(colaboradorId) {
  try {
    const all = JSON.parse(localStorage.getItem(ASSINATURA_KEY) || '{}');
    return all[colaboradorId] || {};
  } catch { return {}; }
}

function salvarDadosAssinatura(colaboradorId, dados) {
  try {
    const all = JSON.parse(localStorage.getItem(ASSINATURA_KEY) || '{}');
    all[colaboradorId] = dados;
    localStorage.setItem(ASSINATURA_KEY, JSON.stringify(all));
  } catch {}
}

// ── Desligamento de colaboradores ─────────────────────────────────────────────

const MOTIVOS_DESLIGAMENTO = [
  { id: 'pedido',           label: 'Pedido do colaborador',  cor: '#1F4A8A' },
  { id: 'fim_contrato',     label: 'Fim de contrato/projeto', cor: '#6B3FA0' },
  { id: 'performance',      label: 'Performance',             cor: '#B3261E' },
  { id: 'reestruturacao',   label: 'Reestruturação',          cor: '#E89B3B' },
  { id: 'justa_causa',      label: 'Justa causa',             cor: '#7A0000' },
  { id: 'mudanca_carreira', label: 'Mudança de carreira',     cor: '#00836B' },
  { id: 'outro',            label: 'Outro',                   cor: '#4A5560' },
];

const DESLIG_ETAPAS = [
  { id: 'inicio',         label: 'Início do processo' },
  { id: 'documentos',     label: 'Documentos' },
  { id: 'entrevista',     label: 'Entrevista de desligamento' },
  { id: 'retiradaAcesso', label: 'Retirada de acesso' },
  { id: 'finalizado',     label: 'Finalizado' },
];

function checklistVazio() {
  return { inicio: false, documentos: false, entrevista: false, retiradaAcesso: false, finalizado: false };
}

function direitosVazios() {
  return {
    avisoPrevio:     { ativo: false, valor: 0 },
    comissao:        { ativo: false, valor: 0 },
    plr:             { ativo: false, valor: 0 },
    decimoTerceiro:  { ativo: false, valor: 0 },
  };
}

// helpers de data relativa a "hoje" (mantém os gráficos sempre nos últimos 12 meses)
function _ymd(d) {
  return d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0') + '-' + String(d.getDate()).padStart(2, '0');
}
function _dtMesesAtras(meses, dia) {
  const d = new Date();
  d.setHours(0, 0, 0, 0);
  d.setDate(1);
  d.setMonth(d.getMonth() - meses);
  d.setDate(Math.min(dia || 15, 28));
  return d;
}

// DESLIGAMENTOS_DEMO · 10 desligados REAIS extraidos de colabs_real.csv (Status=Inativo).
// Nomes e datas preservados. Motivo da planilha mapeado pra MOTIVOS_DESLIGAMENTO:
//   "Pedido de rescisão"                          -> 'pedido'
//   "Rescisão antecipada do contrato de exp."     -> 'fim_contrato'
//   "Rescisão sem justa causa"                    -> 'reestruturacao'
//   "Rescisão por acordo entre as partes"         -> 'outro' (acordo)
// Tipo Voluntario/Involuntario vira tipoDesligamento (pedido_colaborador/empresa/acordo).
// Os 10 NAO estao em COLABORADORES (so 46 ativos). colaboradorId fica null e o
// matching no dashboard e feito por nome (ver tipoPrimarioDe em screen-dashboard).
const DESLIGAMENTOS_DEMO = [
  { id: 'DSL001', colaboradorId: null, nome: 'Ana Gabriela Fernandes',              setor: 'P&D e Escalonamento',     cargo: 'Associado',                categoriaKey: 'associado_projetos', motivoId: 'pedido',         tipoDesligamento: 'pedido_colaborador', dataSaida: '2025-07-30' },
  { id: 'DSL002', colaboradorId: null, nome: 'Daniel Parenti Bicalho',              setor: 'P&D e Escalonamento',     cargo: 'Associado',                categoriaKey: 'associado_projetos', motivoId: 'fim_contrato',   tipoDesligamento: 'pedido_colaborador', dataSaida: '2026-01-30' },
  { id: 'DSL003', colaboradorId: null, nome: 'Germano Marques Cipriano Fagundes',   setor: 'Marketing e Leads',       cargo: 'Analista I Step II',       categoriaKey: 'fixo',               motivoId: 'pedido',         tipoDesligamento: 'pedido_colaborador', dataSaida: '2026-04-30' },
  { id: 'DSL004', colaboradorId: null, nome: 'Nathália Rodrigues de Oliveira',      setor: 'P&D e Escalonamento',     cargo: 'Analista Sênior',          categoriaKey: 'fixo',               motivoId: 'reestruturacao', tipoDesligamento: 'empresa',            dataSaida: '2025-08-11' },
  { id: 'DSL005', colaboradorId: null, nome: 'Rafael do Prado Gomes',               setor: 'VB',                       cargo: 'Associado',                categoriaKey: 'associado_vb',       motivoId: 'outro',          tipoDesligamento: 'acordo',             dataSaida: '2025-07-04' },
  { id: 'DSL006', colaboradorId: null, nome: 'Rafael Faustino Braga',               setor: 'Marketing e Leads',       cargo: 'Analista em Crescimento',  categoriaKey: 'fixo',               motivoId: 'reestruturacao', tipoDesligamento: 'empresa',            dataSaida: '2025-10-08' },
  { id: 'DSL007', colaboradorId: null, nome: 'Rebeca Gabriele Peter Oliveira',      setor: 'P&D e Escalonamento',     cargo: 'Analista Sênior',          categoriaKey: 'fixo',               motivoId: 'pedido',         tipoDesligamento: 'pedido_colaborador', dataSaida: '2025-10-30' },
  { id: 'DSL008', colaboradorId: null, nome: 'Suellen Almeida',                     setor: 'P&D e Escalonamento',     cargo: 'Associado',                categoriaKey: 'associado_projetos', motivoId: 'outro',          tipoDesligamento: 'acordo',             dataSaida: '2025-09-05' },
  { id: 'DSL009', colaboradorId: null, nome: 'Tainara Ramos Neves',                 setor: 'P&D e Escalonamento',     cargo: 'Associado',                categoriaKey: 'associado_projetos', motivoId: 'outro',          tipoDesligamento: 'acordo',             dataSaida: '2025-09-23' },
  { id: 'DSL010', colaboradorId: null, nome: 'Yasmin Alves de Carvalho',            setor: 'Associados de Projetos',   cargo: 'Associado de Projetos',    categoriaKey: 'associado_projetos', motivoId: 'outro',          tipoDesligamento: 'acordo',             dataSaida: '2026-03-06' },
];

// v2: bump da chave LS para sobrescrever cache vazio anterior dos primeiros usuarios.
const DESLIGAMENTOS_KEY = 'escalab_desligamentos_v2';

function getDesligamentos() {
  try {
    // cleanup chave v1 (era array vazio); seed real esta na v2.
    try { localStorage.removeItem('escalab_desligamentos'); } catch {}
    const raw = localStorage.getItem(DESLIGAMENTOS_KEY);
    if (raw) return JSON.parse(raw);
    localStorage.setItem(DESLIGAMENTOS_KEY, JSON.stringify(DESLIGAMENTOS_DEMO));
    return DESLIGAMENTOS_DEMO;
  } catch { return DESLIGAMENTOS_DEMO; }
}

function salvarListaDesligamentos(lista) {
  try { localStorage.setItem(DESLIGAMENTOS_KEY, JSON.stringify(lista)); } catch {}
}

function salvarDesligamento(rec) {
  const lista = getDesligamentos().filter(d => d.id !== rec.id);
  lista.unshift(rec);
  salvarListaDesligamentos(lista);
  return lista;
}

function atualizarDesligamento(id, updates) {
  const lista = getDesligamentos().map(d => d.id === id ? { ...d, ...updates } : d);
  salvarListaDesligamentos(lista);
  return lista;
}

function getDesligamentoPorColaborador(colaboradorId) {
  return getDesligamentos().find(d => d.colaboradorId === Number(colaboradorId)) || null;
}

function getIdsDesligados() {
  return new Set(getDesligamentos().map(d => d.colaboradorId).filter(x => x != null).map(Number));
}

function isDesligado(id) {
  return getIdsDesligados().has(Number(id));
}

function getColaboradoresAtivos() {
  const desl = getIdsDesligados();
  return COLABORADORES.filter(c => !desl.has(c.id));
}

function reativarColaborador(colaboradorId) {
  const lista = getDesligamentos().filter(d => d.colaboradorId !== Number(colaboradorId));
  salvarListaDesligamentos(lista);
  return lista;
}

function gerarIdDeslig() {
  return 'DSL' + Date.now().toString(36).toUpperCase();
}

// formulário de desligamento customizável (campos extras)
const DESLIG_FORM_KEY = 'escalab_deslig_form_campos';
function getCamposDesligForm() {
  try { const raw = localStorage.getItem(DESLIG_FORM_KEY); return raw ? JSON.parse(raw) : []; } catch { return []; }
}
function salvarCamposDesligForm(campos) {
  try { localStorage.setItem(DESLIG_FORM_KEY, JSON.stringify(campos)); } catch {}
}

// motivos de saída editáveis pelo GC (seed = MOTIVOS_DESLIGAMENTO)
const DESLIG_MOTIVOS_KEY = 'escalab_deslig_motivos';
function getMotivosDeslig() {
  try { const raw = localStorage.getItem(DESLIG_MOTIVOS_KEY); return raw ? JSON.parse(raw) : MOTIVOS_DESLIGAMENTO.map(m => ({ ...m })); } catch { return MOTIVOS_DESLIGAMENTO.map(m => ({ ...m })); }
}
function salvarMotivosDeslig(lista) { try { localStorage.setItem(DESLIG_MOTIVOS_KEY, JSON.stringify(lista)); } catch {} }
function getMotivoDeslig(id) { return getMotivosDeslig().find(m => m.id === id) || MOTIVOS_DESLIGAMENTO.find(m => m.id === id) || null; }

// ── Admissões (demo) · tempo abertura→admissão e admissões por mês ─────────────

const ADMISSOES_DEMO = [
  { nome: 'Tatiane Rocha Silva',     categoria: 'fixo',      mesesAtras: 0,  diasProcesso: 41 },
  { nome: 'Pedro Lucas Souza',       categoria: 'fixo',      mesesAtras: 1,  diasProcesso: 52 },
  { nome: 'Natalia Carvalho Mendes', categoria: 'fixo',      mesesAtras: 1,  diasProcesso: 38 },
  { nome: 'Isabela Ramos Costa',     categoria: 'fixo',      mesesAtras: 2,  diasProcesso: 47 },
  { nome: 'Mariana Lopes Reis',      categoria: 'associado', mesesAtras: 3,  diasProcesso: 24 },
  { nome: 'Felipe Andrade Nunes',    categoria: 'associado', mesesAtras: 4,  diasProcesso: 19 },
  { nome: 'Gabriela Souza Pinto',    categoria: 'fixo',      mesesAtras: 5,  diasProcesso: 55 },
  { nome: 'Thiago Barros Melo',      categoria: 'associado', mesesAtras: 6,  diasProcesso: 28 },
  { nome: 'Camille Ferreira Lima',   categoria: 'associado', mesesAtras: 7,  diasProcesso: 31 },
  { nome: 'Renata Oliveira Pinto',   categoria: 'fixo',      mesesAtras: 9,  diasProcesso: 44 },
  { nome: 'Lucas Henrique Costa',    categoria: 'fixo',      mesesAtras: 10, diasProcesso: 49 },
  { nome: 'Daniela Luisa Coelho',    categoria: 'associado', mesesAtras: 11, diasProcesso: 22 },
].map((a, i) => {
  const admit = _dtMesesAtras(a.mesesAtras, 10 + (i % 16));
  const abertura = new Date(admit); abertura.setDate(abertura.getDate() - a.diasProcesso);
  return { id: 'ADM' + (i + 1), nome: a.nome, categoria: a.categoria, admitidoEm: _ymd(admit), aberturaEm: _ymd(abertura), diasProcesso: a.diasProcesso };
});

function getDataAdmissao(c) {
  const d = new Date();
  d.setDate(1);
  d.setMonth(d.getMonth() - (c.tempoEmpresa || 0));
  return _ymd(d);
}

// ── Movimentações internas (progressão de carreira) · demo ────────────────────
const NIVEL_LABEL = { diretor: 'Diretoria', lider: 'Liderança', liderado: 'Contribuidor individual' };
const MOV_TIPOS = {
  promocao: { label: 'Promoção (mudança de nível)', cor: '#00836B' },
  merito:   { label: 'Mérito (mudança de cargo)',   cor: '#1F4A8A' },
  lateral:  { label: 'Movimentação lateral',        cor: '#B56500' },
};
// Auto-gerado por scripts/gerar_seed_movimentacoes.js a partir de "Documentos Treinamento/Colaboradores/tabela_movimentacoes.xlsx" (reexportado como CSV)
// 58 movimentacoes reais (ref 2026-06-26); 5 ex-colabs ignorados (Germano, Daniel, Suellen, Rebeca)
const MOVIMENTACOES = [
  { colaboradorId: 21, mesesAtras: 3, de: "Associado De Projetos", para: "Associado De Projetos", nivelDe: "liderado", nivelPara: "liderado", tipo: "merito" },
  { colaboradorId: 6, mesesAtras: 4, de: "Analista Ii Step Ii", para: "Analista Ii Step Ii", nivelDe: "liderado", nivelPara: "liderado", tipo: "lateral" },
  { colaboradorId: 22, mesesAtras: 4, de: "Analista Ii Step Iii", para: "Analista Ii Step Iii", nivelDe: "liderado", nivelPara: "liderado", tipo: "lateral" },
  { colaboradorId: 8, mesesAtras: 4, de: "Analista Sênior", para: "Líder/especialista Ii Step Ii", nivelDe: "liderado", nivelPara: "lider", tipo: "promocao" },
  { colaboradorId: 29, mesesAtras: 4, de: "Analista I Step Iii", para: "Analista Ii Step Ii", nivelDe: "liderado", nivelPara: "liderado", tipo: "promocao" },
  { colaboradorId: 11, mesesAtras: 4, de: "Líder/especialista I Step I", para: "Líder/especialista I Step I", nivelDe: "lider", nivelPara: "lider", tipo: "merito" },
  { colaboradorId: 40, mesesAtras: 4, de: "Analista Sênior", para: "Líder/especialista Iii Step I", nivelDe: "liderado", nivelPara: "lider", tipo: "promocao" },
  { colaboradorId: 19, mesesAtras: 4, de: "Analista Ii Step I", para: "Analista Ii Step I", nivelDe: "liderado", nivelPara: "liderado", tipo: "merito" },
  { colaboradorId: 31, mesesAtras: 4, de: "Analista Iii Step I", para: "Analista Iii Step I", nivelDe: "liderado", nivelPara: "liderado", tipo: "merito" },
  { colaboradorId: 46, mesesAtras: 4, de: "Analista Iii Step I", para: "Líder/especialista Ii Step Ii", nivelDe: "liderado", nivelPara: "lider", tipo: "promocao" },
  { colaboradorId: 33, mesesAtras: 4, de: "Analista Ii Step Ii", para: "Analista Ii Step Ii", nivelDe: "liderado", nivelPara: "liderado", tipo: "promocao" },
  { colaboradorId: 18, mesesAtras: 4, de: "Analista Iii Step I", para: "Analista Iii Step I", nivelDe: "liderado", nivelPara: "liderado", tipo: "merito" },
  { colaboradorId: 44, mesesAtras: 4, de: "Analista Iii Step I", para: "Analista Iii Step Ii", nivelDe: "liderado", nivelPara: "liderado", tipo: "lateral" },
  { colaboradorId: 20, mesesAtras: 4, de: "Líder/especialista Ii Step I", para: "Líder/especialista Ii Step I", nivelDe: "lider", nivelPara: "lider", tipo: "lateral" },
  { colaboradorId: 14, mesesAtras: 4, de: "Diretor De Área", para: "Diretor De Área", nivelDe: "diretor", nivelPara: "diretor", tipo: "merito" },
  { colaboradorId: 41, mesesAtras: 4, de: "Diretor Executivo", para: "Diretor Executivo", nivelDe: "diretor", nivelPara: "diretor", tipo: "merito" },
  { colaboradorId: 30, mesesAtras: 4, de: "Analista Ii Step I", para: "Analista Ii Step I", nivelDe: "liderado", nivelPara: "liderado", tipo: "promocao" },
  { colaboradorId: 5, mesesAtras: 4, de: "Diretor De Setor", para: "Diretor De Setor", nivelDe: "diretor", nivelPara: "diretor", tipo: "merito" },
  { colaboradorId: 28, mesesAtras: 4, de: "Estagiário I   Step Ii", para: "Técnico/assistente Ii", nivelDe: "liderado", nivelPara: "liderado", tipo: "promocao" },
  { colaboradorId: 27, mesesAtras: 4, de: "Analista Iii Step I", para: "Analista Iii Step Ii", nivelDe: "liderado", nivelPara: "liderado", tipo: "lateral" },
  { colaboradorId: 1, mesesAtras: 4, de: "Analista Iii Step I", para: "Analista Iii Step Ii", nivelDe: "liderado", nivelPara: "liderado", tipo: "lateral" },
  { colaboradorId: 3, mesesAtras: 4, de: "Diretor De Setor", para: "Diretor De Setor", nivelDe: "diretor", nivelPara: "diretor", tipo: "merito" },
  { colaboradorId: 10, mesesAtras: 4, de: "Ceo", para: "Ceo", nivelDe: "diretor", nivelPara: "diretor", tipo: "merito" },
  { colaboradorId: 35, mesesAtras: 4, de: "Ceo", para: "Ceo", nivelDe: "diretor", nivelPara: "diretor", tipo: "merito" },
  { colaboradorId: 13, mesesAtras: 4, de: "Analista I Step Iii", para: "Analista I Step Iii", nivelDe: "liderado", nivelPara: "liderado", tipo: "merito" },
  { colaboradorId: 19, mesesAtras: 7, de: "Analista I Step Iii", para: "Analista Ii Step I", nivelDe: "liderado", nivelPara: "liderado", tipo: "promocao" },
  { colaboradorId: 21, mesesAtras: 8, de: "Associado De Projetos", para: "Associado De Projetos", nivelDe: "liderado", nivelPara: "liderado", tipo: "lateral" },
  { colaboradorId: 4, mesesAtras: 8, de: "Analista Em Crescimento", para: "Associado De Projetos", nivelDe: "liderado", nivelPara: "liderado", tipo: "lateral" },
  { colaboradorId: 42, mesesAtras: 8, de: "Associado De Projetos", para: "Associado De Projetos", nivelDe: "liderado", nivelPara: "liderado", tipo: "lateral" },
  { colaboradorId: 43, mesesAtras: 8, de: "Associado De Projetos", para: "Associado De Projetos", nivelDe: "liderado", nivelPara: "liderado", tipo: "lateral" },
  { colaboradorId: 32, mesesAtras: 8, de: "Associado De Projetos", para: "Associado De Projetos", nivelDe: "liderado", nivelPara: "liderado", tipo: "lateral" },
  { colaboradorId: 2, mesesAtras: 9, de: "Analista Em Crescimento", para: "Analista Em Crescimento", nivelDe: "liderado", nivelPara: "liderado", tipo: "lateral" },
  { colaboradorId: 29, mesesAtras: 10, de: "Analista I Step Iii", para: "Analista I Step Iii", nivelDe: "liderado", nivelPara: "liderado", tipo: "lateral" },
  { colaboradorId: 28, mesesAtras: 10, de: "Estagiário I   Step Ii", para: "Estagiário I   Step Ii", nivelDe: "liderado", nivelPara: "liderado", tipo: "lateral" },
  { colaboradorId: 18, mesesAtras: 10, de: "Analista Pleno", para: "Analista Iii Step I", nivelDe: "liderado", nivelPara: "liderado", tipo: "promocao" },
  { colaboradorId: 26, mesesAtras: 11, de: "Associado", para: "Associado", nivelDe: "liderado", nivelPara: "liderado", tipo: "lateral" },
  { colaboradorId: 34, mesesAtras: 11, de: "Associado", para: "Associado", nivelDe: "liderado", nivelPara: "liderado", tipo: "lateral" },
  { colaboradorId: 12, mesesAtras: 11, de: "Associado", para: "Associado", nivelDe: "liderado", nivelPara: "liderado", tipo: "lateral" },
  { colaboradorId: 44, mesesAtras: 13, de: "Analista Iii Step I", para: "Analista Iii Step I", nivelDe: "liderado", nivelPara: "liderado", tipo: "merito" },
  { colaboradorId: 1, mesesAtras: 13, de: "Analista Iii Step I", para: "Analista Iii Step I", nivelDe: "liderado", nivelPara: "liderado", tipo: "merito" },
  { colaboradorId: 4, mesesAtras: 16, de: "Analista Em Crescimento", para: "Analista Em Crescimento", nivelDe: "liderado", nivelPara: "liderado", tipo: "promocao" },
  { colaboradorId: 46, mesesAtras: 16, de: "Analista Pleno", para: "Analista Iii Step I", nivelDe: "liderado", nivelPara: "liderado", tipo: "promocao" },
  { colaboradorId: 18, mesesAtras: 23, de: "Analista Pleno", para: "Analista Pleno", nivelDe: "liderado", nivelPara: "liderado", tipo: "promocao" },
  { colaboradorId: 2, mesesAtras: 23, de: "Analista Em Crescimento", para: "Analista Em Crescimento", nivelDe: "liderado", nivelPara: "liderado", tipo: "promocao" },
  { colaboradorId: 19, mesesAtras: 24, de: "Analista I Step Iii", para: "Analista I Step Iii", nivelDe: "liderado", nivelPara: "liderado", tipo: "promocao" },
  { colaboradorId: 8, mesesAtras: 28, de: "Analista Pleno", para: "Analista Sênior", nivelDe: "liderado", nivelPara: "liderado", tipo: "promocao" },
  { colaboradorId: 40, mesesAtras: 28, de: "Analista Em Crescimento", para: "Analista Sênior", nivelDe: "liderado", nivelPara: "liderado", tipo: "promocao" },
  { colaboradorId: 27, mesesAtras: 28, de: "Analista Líder", para: "Analista Iii Step I", nivelDe: "lider", nivelPara: "liderado", tipo: "promocao" },
  { colaboradorId: 11, mesesAtras: 29, de: "Líder/especialista I Step I", para: "Líder/especialista I Step I", nivelDe: "lider", nivelPara: "lider", tipo: "promocao" },
  { colaboradorId: 46, mesesAtras: 34, de: "Analista Em Crescimento", para: "Analista Pleno", nivelDe: "liderado", nivelPara: "liderado", tipo: "promocao" },
  { colaboradorId: 8, mesesAtras: 38, de: "Analista Em Crescimento", para: "Analista Pleno", nivelDe: "liderado", nivelPara: "liderado", tipo: "promocao" },
  { colaboradorId: 27, mesesAtras: 38, de: "Analista Pleno", para: "Analista Líder", nivelDe: "liderado", nivelPara: "lider", tipo: "promocao" },
  { colaboradorId: 46, mesesAtras: 40, de: "Analista Júnior", para: "Analista Em Crescimento", nivelDe: "liderado", nivelPara: "liderado", tipo: "promocao" },
  { colaboradorId: 31, mesesAtras: 43, de: "Analista Iii Step I", para: "Analista Iii Step I", nivelDe: "liderado", nivelPara: "liderado", tipo: "promocao" },
  { colaboradorId: 8, mesesAtras: 45, de: "Analista Em Crescimento", para: "Analista Em Crescimento", nivelDe: "liderado", nivelPara: "liderado", tipo: "promocao" },
  { colaboradorId: 40, mesesAtras: 46, de: "Analista Em Crescimento", para: "Analista Em Crescimento", nivelDe: "liderado", nivelPara: "liderado", tipo: "promocao" },
  { colaboradorId: 27, mesesAtras: 47, de: "Analista Pleno", para: "Analista Pleno", nivelDe: "liderado", nivelPara: "liderado", tipo: "promocao" },
  { colaboradorId: 46, mesesAtras: 58, de: "Analista Júnior", para: "Analista Júnior", nivelDe: "liderado", nivelPara: "liderado", tipo: "promocao" },
].map((m, i) => {
  const c = COLABORADORES.find(x => x.id === m.colaboradorId) || {};
  const d = _dtMesesAtras(m.mesesAtras, 15);
  return { id: 'MOV' + (i + 1), colaboradorId: m.colaboradorId, nome: c.nome || '', setor: c.setor || '', data: _ymd(d).slice(0, 7), de: m.de, para: m.para, nivelDe: m.nivelDe, nivelPara: m.nivelPara, tipo: m.tipo };
});

// ── Acesso por página (configurado pelo GC, por pessoa) ────────────────────────

// Páginas que o GC pode liberar/bloquear por colaborador (Intranet fica sempre acessível)
const PAGINAS_APP = [
  { id: 'avisos',           label: 'Avisos' },
  { id: 'dashboard',        label: 'Painel' },
  { id: 'colaboradores',    label: 'Colaboradores' },
  { id: 'organograma',      label: 'Organograma' },
  { id: 'recrutamento',     label: 'Recrutamento' },
  { id: 'admissao',         label: 'Admissão' },
  { id: 'ferias',           label: 'Férias & Day Off' },
  { id: 'ausencia',         label: 'Ausências' },
  { id: 'horas',            label: 'Horas' },
  { id: 'avd',              label: 'AVD & Feedback' },
  { id: 'outras_pesquisas', label: 'Outras Pesquisas' },
  { id: 'pco',              label: 'PCO' },
  { id: 'censo',            label: 'Censo de Diversidade' },
  { id: 'treinamentos',     label: 'Treinamentos' },
];

const PAGINAS_BLOQ_KEY = 'escalab_paginas_bloqueadas';
function getMapaPaginasBloqueadas() {
  try { return JSON.parse(localStorage.getItem(PAGINAS_BLOQ_KEY) || '{}'); } catch { return {}; }
}
function getPaginasBloqueadas(colaboradorId) {
  return getMapaPaginasBloqueadas()[colaboradorId] || [];
}
function setPaginasBloqueadas(colaboradorId, arr) {
  const m = getMapaPaginasBloqueadas();
  m[colaboradorId] = arr;
  try { localStorage.setItem(PAGINAS_BLOQ_KEY, JSON.stringify(m)); } catch {}
}
function togglePaginaBloqueada(colaboradorId, pageId) {
  const atual = getPaginasBloqueadas(colaboradorId);
  const novo = atual.includes(pageId) ? atual.filter(p => p !== pageId) : [...atual, pageId];
  setPaginasBloqueadas(colaboradorId, novo);
  return novo;
}
function paginaPermitida(user, pageId) {
  if (!user) return true;
  return !getPaginasBloqueadas(user.id).includes(pageId);
}

// ── Remuneração (demo) ─────────────────────────────────────────────────────────

// Calibrado para empresa de ~R$2M/ano de faturamento (~R$110-130k/mês de folha)
function getSalario(c) {
  // Associados (bolsa/projeto) recebem menos que CLT
  const cat = (typeof getCategoriaColaborador === 'function') ? getCategoriaColaborador(c.id) : { categoria: 'fixo' };
  if (cat.categoria === 'associado') {
    const baseAssoc = { projetos: 1500, editais: 1400, vb: 1800, redes: 1300 }[cat.tipoAssociado] || 1400;
    const varId = (c.id * 73) % 400;
    return Math.round((baseAssoc + varId) / 50) * 50;
  }
  const base = { diretor: 8500, lider: 5200, liderado: 2800 }[c.nivel] || 2500;
  const ajusteTempo = Math.min(c.tempoCargo || 0, 60) * 12;
  const varId = (c.id * 137) % 600;
  return Math.round((base + ajusteTempo + varId) / 50) * 50;
}

function medianaArr(arr) {
  if (!arr.length) return 0;
  const s = [...arr].sort((a, b) => a - b);
  const m = Math.floor(s.length / 2);
  return s.length % 2 ? s[m] : Math.round((s[m - 1] + s[m]) / 2);
}

// ── Aniversários dos colaboradores (MM-DD) ─────────────────────────────────────

const ANIVERSARIOS = {
  1:'01-15',  2:'02-09',  3:'03-22',  4:'04-05',  5:'11-28',  6:'02-17',  7:'07-12',  8:'06-12',
  9:'09-03', 10:'10-21', 11:'03-08', 12:'12-19', 13:'08-14', 14:'05-27', 15:'06-03', 16:'08-30',
  17:'01-19', 18:'04-25', 19:'07-18', 20:'10-11', 21:'02-02', 22:'11-09', 23:'01-30', 24:'05-16',
  25:'09-07', 26:'03-14', 27:'06-28', 28:'04-09', 29:'12-01', 30:'08-22', 31:'05-23', 32:'05-07',
  33:'10-05', 34:'07-30', 35:'02-26', 36:'05-29', 37:'11-13', 38:'03-19', 39:'09-24', 40:'06-15',
  41:'01-08', 42:'12-22',
};

// Retorna dia-mes "MM-DD" do colaborador. Prioriza dataNascimento preenchida em Dados Pessoais (assinatura)
// e usa o dicionário ANIVERSARIOS como fallback para os colaboradores que ainda não preencheram.
function _diaMesAniversario(colaboradorId) {
  try {
    const all = JSON.parse(localStorage.getItem(ASSINATURA_KEY) || '{}');
    const d = all[colaboradorId]?.dataNascimento;
    if (d && /^\d{4}-\d{2}-\d{2}/.test(d)) {
      // ISO YYYY-MM-DD → "MM-DD"
      return d.slice(5, 10);
    }
  } catch {}
  return ANIVERSARIOS[colaboradorId] || null;
}

function getAniversariantesDoMes(mes) {
  return getColaboradoresAtivos()
    .map(c => ({ c, n: _diaMesAniversario(c.id) }))
    .filter(x => x.n && Number(x.n.slice(0, 2)) === mes)
    .map(({ c, n }) => ({ id: c.id, nome: c.nome, setor: c.setor, cor: c.cor, iniciais: c.iniciais, dia: Number(n.slice(3, 5)), mes }))
    .sort((a, b) => a.dia - b.dia);
}

// ── Usuários cadastrados (auto-cadastro de novo colaborador + aprovação GC) ────
const USUARIOS_KEY = 'escalab_usuarios_cadastrados';
function getUsuariosCadastrados() { try { return JSON.parse(localStorage.getItem(USUARIOS_KEY) || '[]'); } catch { return []; } }
function salvarUsuariosCadastrados(l) { try { localStorage.setItem(USUARIOS_KEY, JSON.stringify(l)); } catch {} }
function _iniciaisDe(nome) { const p = (nome || '').trim().split(/\s+/); return (((p[0] || '')[0] || '') + ((p[1] || '')[0] || '')).toUpperCase() || 'NC'; }
function emailJaExiste(email) {
  const e = (email || '').toLowerCase().trim();
  return COLABORADORES.some(c => c.email.toLowerCase() === e) || getUsuariosCadastrados().some(c => (c.email || '').toLowerCase() === e);
}
function cadastrarUsuario({ nome, email, senha }) {
  const e = (email || '').toLowerCase().trim();
  if (!nome || !e || !senha) return { ok: false, erro: 'Preencha nome, e-mail e senha.' };
  if (emailJaExiste(e)) return { ok: false, erro: 'Este e-mail já está cadastrado.' };
  const novo = {
    id: Date.now(), nome: nome.trim(), email: e, senha, perfil: 'admissao', status: 'pendente',
    cargo: 'Novo colaborador', nivel: 'liderado', setor: '·', cor: '#6B3FA0', iniciais: _iniciaisDe(nome),
    notasLiberadas: false, tempoEmpresa: 0, tempoCargo: 0, criadoEm: new Date().toISOString(),
  };
  const lista = getUsuariosCadastrados(); lista.push(novo); salvarUsuariosCadastrados(lista);
  return { ok: true, user: novo };
}
// Lista colaboradores reais do Supabase (passa RLS). Retorna array ou null.
// Usado por telas que ja foram migradas pra ler do banco real.
// Merge Supabase + seed local. Retorna objetos com id=NUMERICO (do seed, pro
// resto do app que espera numero) e uuid=DO BANCO (pra dual-write helpers).
// Se um colab no banco nao bater nenhum email do seed, ganha id 1000+i e
// fields fake. Se um do seed nao estiver no banco, fica de fora (RLS pode
// ter filtrado, ou nao foi importado).
async function getColaboradoresSupabase() {
  if (typeof window === 'undefined' || !window.supabaseClient) return null;
  try {
    const { data, error } = await window.supabaseClient
      .from('colaboradores').select('*');
    if (error || !data) return null;
    const byUuid = Object.fromEntries(data.map(c => [c.id, c]));
    // index seed by email (lower) pra match
    const seedByEmail = {};
    if (typeof COLABORADORES !== 'undefined' && Array.isArray(COLABORADORES)) {
      COLABORADORES.forEach(c => {
        if (c.email) seedByEmail[String(c.email).toLowerCase().trim()] = c;
      });
    }
    const PALETA_COR = ['#1F4A8A', '#00836B', '#6B3FA0', '#E89B3B', '#B3261E', '#005E4D', '#4A5560'];
    return data.map((c, i) => {
      const emailLower = (c.email || '').toLowerCase().trim();
      const seed = seedByEmail[emailLower] || null;
      const iniciais = seed?.iniciais || (c.nome || '').split(' ').map(n => n[0]).filter(Boolean).slice(0, 2).join('').toUpperCase();
      const gestorDoBanco = c.gestor_id ? byUuid[c.gestor_id] : null;
      return {
        // ID consistente com o resto do app (numero do seed). Fallback 1000+ se nao houver seed.
        id: seed?.id != null ? seed.id : (1000 + i),
        uuid: c.id, // uuid do supabase, pra dual-write
        nome: c.nome || seed?.nome,
        email: c.email || seed?.email,
        cargo: c.cargo || seed?.cargo,
        nivel: c.nivel || seed?.nivel,
        setor: c.setor || seed?.setor,
        perfil: c.perfil || seed?.perfil,
        auth_user_id: c.auth_user_id,
        // Merge com prioridade pro banco quando existir
        gestorNome: gestorDoBanco?.nome || seed?.gestorNome || null,
        tempoEmpresa: seed?.tempoEmpresa ?? 0,
        tempoCargo:   seed?.tempoCargo   ?? 0,
        academico:    seed?.academico    || '',
        cor: seed?.cor || PALETA_COR[i % PALETA_COR.length],
        iniciais,
        notasLiberadas: seed?.notasLiberadas ?? false,
        // marca pra debug: vindo do banco
        _sb: true,
      };
    });
  } catch (e) {
    console.warn('[supabase] getColaboradores falhou:', e?.message);
    return null;
  }
}

// Restaura sessao Supabase no mount. Retorna o colab logado ou null.
// Usar no useEffect inicial pra evitar tela de login a cada F5.
async function restaurarSessaoSupabase() {
  if (typeof window === 'undefined' || !window.supabaseClient) return null;
  try {
    const { data: sess } = await window.supabaseClient.auth.getSession();
    if (!sess?.session?.user) return null;
    const authUser = sess.session.user;
    const { data: colab, error } = await window.supabaseClient
      .from('colaboradores').select('*')
      .eq('auth_user_id', authUser.id).single();
    if (error || !colab) return null;
    // Tenta achar o equivalente no seed local pra ID numerico consistente.
    const emailLower = (colab.email || '').toLowerCase().trim();
    const seed = (typeof COLABORADORES !== 'undefined' && Array.isArray(COLABORADORES))
      ? COLABORADORES.find(c => (c.email || '').toLowerCase().trim() === emailLower)
      : null;
    const iniciais = seed?.iniciais || (colab.nome || '').split(' ').map(n => n[0]).filter(Boolean).slice(0, 2).join('').toUpperCase();
    return {
      // id NUMERICO do seed (consistente com resto do app). uuid separado pra Supabase ops.
      id: seed?.id != null ? seed.id : colab.id,
      uuid: colab.id,
      nome: colab.nome, email: colab.email,
      cargo: colab.cargo || seed?.cargo || '·',
      nivel: colab.nivel || seed?.nivel || 'liderado',
      setor: colab.setor || seed?.setor || '·',
      perfil: colab.perfil || seed?.perfil || 'colaborador',
      gestorNome: seed?.gestorNome || null,
      cor: seed?.cor || '#00836B',
      iniciais,
      tempoEmpresa: seed?.tempoEmpresa ?? 0,
      tempoCargo:   seed?.tempoCargo   ?? 0,
      academico:    seed?.academico    || '',
      supabaseUser: authUser,
    };
  } catch (e) {
    console.warn('[auth] restaurarSessao falhou:', e?.message);
    return null;
  }
}

// Encerra sessao no Supabase. Chamar antes de limpar o user no React.
async function encerrarSessaoSupabase() {
  if (typeof window !== 'undefined' && window.supabaseClient) {
    try { await window.supabaseClient.auth.signOut(); } catch {}
  }
}

// Altera senha do user logado. Precisa estar logado via Supabase Auth.
async function alterarMinhaSenha(novaSenha) {
  if (!novaSenha || novaSenha.length < 6) return { ok: false, erro: 'Senha deve ter ao menos 6 caracteres.' };
  if (typeof window === 'undefined' || !window.supabaseClient) return { ok: false, erro: 'Supabase nao conectado.' };
  try {
    const { data: sess } = await window.supabaseClient.auth.getSession();
    if (!sess?.session?.user) return { ok: false, erro: 'Voce precisa estar logado via Supabase pra trocar a senha. Login mock nao suporta isso.' };
    const { error } = await window.supabaseClient.auth.updateUser({ password: novaSenha });
    if (error) return { ok: false, erro: error.message };
    return { ok: true };
  } catch (e) { return { ok: false, erro: e?.message || 'erro inesperado' }; }
}

// Admin define senha de colab SEM mandar email. Usa a Edge Function
// 'admin-set-password' que valida o JWT do caller e roda como Service Role.
// Bonus: se o user nao existir ainda em auth.users, cria automaticamente
// (resolve casos dos 13 colabs sem auth_user_id).
async function adminDefinirSenhaDe(email, novaSenha) {
  if (!email || !novaSenha || novaSenha.length < 6) return { ok: false, erro: 'email e nova senha (>=6) obrigatorios.' };
  if (typeof window === 'undefined' || !window.supabaseClient) return { ok: false, erro: 'Supabase nao conectado.' };
  try {
    const { data, error } = await window.supabaseClient.functions.invoke('admin-set-password', {
      body: { email, nova_senha: novaSenha },
    });
    if (error) return { ok: false, erro: error.message || 'falha invocando funcao' };
    if (!data?.ok) return { ok: false, erro: data?.erro || 'falha desconhecida' };
    return { ok: true, criado: data.criado };
  } catch (e) { return { ok: false, erro: e?.message || 'erro inesperado' }; }
}

// Dispara email de redefinicao de senha pra qualquer email. Nao precisa estar logado.
// Usado em (a) "Esqueci minha senha" na tela de login, (b) admin reseta senha de colab.
async function dispararResetSenha(email) {
  const e = (email || '').toLowerCase().trim();
  if (!e || !/.+@.+\..+/.test(e)) return { ok: false, erro: 'Email invalido.' };
  if (typeof window === 'undefined' || !window.supabaseClient) return { ok: false, erro: 'Supabase nao conectado.' };
  try {
    const { error } = await window.supabaseClient.auth.resetPasswordForEmail(e, {
      redirectTo: window.location.origin,
    });
    if (error) return { ok: false, erro: error.message };
    return { ok: true };
  } catch (err) { return { ok: false, erro: err?.message || 'erro inesperado' }; }
}

async function autenticar(email, senha) {
  const e = (email || '').toLowerCase().trim();
  // 1) Tenta Supabase primeiro (login real). Se o cliente nao estiver carregado
  //    ou a credencial nao bater, cai pro fallback localStorage abaixo.
  if (typeof window !== 'undefined' && window.supabaseClient) {
    try {
      const { data, error } = await window.supabaseClient.auth.signInWithPassword({ email: e, password: senha });
      if (!error && data?.user) {
        const { data: colabSb, error: errColab } = await window.supabaseClient
          .from('colaboradores').select('*')
          .eq('auth_user_id', data.user.id).single();
        if (!errColab && colabSb) {
          // Merge com seed local pra id numerico consistente + tempoEmpresa/etc.
          const emailLower = (colabSb.email || '').toLowerCase().trim();
          const seed = COLABORADORES.find(c => (c.email || '').toLowerCase().trim() === emailLower);
          const iniciais = seed?.iniciais || (colabSb.nome || '').split(' ').map(n => n[0]).filter(Boolean).slice(0, 2).join('').toUpperCase();
          return {
            id: seed?.id != null ? seed.id : colabSb.id,
            uuid: colabSb.id,
            nome: colabSb.nome,
            email: colabSb.email,
            cargo: colabSb.cargo || seed?.cargo || '·',
            nivel: colabSb.nivel || seed?.nivel || 'liderado',
            setor: colabSb.setor || seed?.setor || '·',
            perfil: colabSb.perfil || seed?.perfil || 'colaborador',
            gestorNome: seed?.gestorNome || null,
            cor: seed?.cor || '#00836B',
            iniciais,
            tempoEmpresa: seed?.tempoEmpresa ?? 0,
            tempoCargo:   seed?.tempoCargo   ?? 0,
            academico:    seed?.academico    || '',
            supabaseUser: data.user,
          };
        }
      }
    } catch (e) {
      console.warn('[auth] supabase falhou, tentando fallback local:', e?.message);
    }
  }
  // 2) Fallback: seed local + usuarios cadastrados no localStorage
  const colab = COLABORADORES.find(c => c.email.toLowerCase() === e && c.senha === senha);
  if (colab) return colab;
  return getUsuariosCadastrados().find(c => (c.email || '').toLowerCase() === e && c.senha === senha) || null;
}
function getUsuariosPendentes() { return getUsuariosCadastrados().filter(u => u.status === 'pendente'); }
function aprovarUsuario(id) {
  const l = getUsuariosCadastrados().map(u => u.id === id ? { ...u, perfil: 'colaborador', status: 'aprovado', aprovadoEm: new Date().toISOString() } : u);
  salvarUsuariosCadastrados(l); return l;
}
function rejeitarUsuario(id) { const l = getUsuariosCadastrados().filter(u => u.id !== id); salvarUsuariosCadastrados(l); return l; }
// dados preenchidos pelo novo colaborador (perfil admissao)
const NOVO_COLAB_DADOS_KEY = 'escalab_novo_colab_dados';
function getDadosNovoColab(id) { try { return (JSON.parse(localStorage.getItem(NOVO_COLAB_DADOS_KEY) || '{}'))[id] || {}; } catch { return {}; } }
function salvarDadosNovoColab(id, dados) { try { const all = JSON.parse(localStorage.getItem(NOVO_COLAB_DADOS_KEY) || '{}'); all[id] = dados; localStorage.setItem(NOVO_COLAB_DADOS_KEY, JSON.stringify(all)); } catch {} }

// ── E-mails do Escalab (padrão Hostinger / @escalab.com.br) ──────────────
// Para envio real automatizado, configure window.ESCALAB_EMAIL_SENDER apontando
// para uma função que aceita { to, subject, html } e usa EmailJS / Vercel Function
// conectada ao SMTP da Hostinger. Sem configuração, cai no fallback de mailto:
const ESCALAB_EMAIL_FROM      = 'gente.cultura@escalab.com.br';
const ESCALAB_EMAIL_RH        = 'gente.cultura@escalab.com.br';
const ESCALAB_EMAIL_HOSTINGER = { host: 'smtp.hostinger.com', port: 465, secure: true };

const ESCALAB_EMAIL_ASSINATURA = `\n\n--\nGente & Cultura · Escalab\ngente.cultura@escalab.com.br\nEsta mensagem foi enviada automaticamente pela plataforma Escalab Gestão de Pessoas.`;

function escalabEmailEnvelope(corpo) {
  // Garante padrão (signature) em todo email do Escalab
  if (!corpo) return ESCALAB_EMAIL_ASSINATURA.trim();
  if (corpo.includes('Gente & Cultura · Escalab')) return corpo;
  return corpo + ESCALAB_EMAIL_ASSINATURA;
}

async function enviarEmailEscalab({ to, subject, corpo, cc, replyTo }) {
  const corpoCompleto = escalabEmailEnvelope(corpo);
  // 1) Tenta sender configurado (ex: EmailJS, Vercel Function, etc.)
  if (typeof window !== 'undefined' && typeof window.ESCALAB_EMAIL_SENDER === 'function') {
    try {
      await window.ESCALAB_EMAIL_SENDER({
        from: ESCALAB_EMAIL_FROM,
        replyTo: replyTo || ESCALAB_EMAIL_RH,
        to, cc, subject, corpo: corpoCompleto,
      });
      return { enviado: true, via: 'smtp' };
    } catch (e) { console.warn('Falha no sender Hostinger, caindo no mailto:', e); }
  }
  // 2) Fallback: abre cliente local com identidade padronizada
  const url = mailtoEscalab({ to, cc, subject, corpo: corpoCompleto, replyTo });
  if (typeof window !== 'undefined') window.location.href = url;
  return { enviado: false, via: 'mailto', url };
}

function mailtoEscalab({ to, cc, subject, corpo, replyTo }) {
  const params = [];
  if (subject) params.push('subject=' + encodeURIComponent(subject));
  if (corpo)   params.push('body=' + encodeURIComponent(corpo));
  if (cc)      params.push('cc=' + encodeURIComponent(cc));
  // 'from' não é confiável em mailto: (cliente sobrescreve). Reply-To é honrado por muitos clientes.
  if (replyTo) params.push('reply-to=' + encodeURIComponent(replyTo));
  const q = params.join('&');
  return `mailto:${to || ''}${q ? '?' + q : ''}`;
}

// ── Intersetorial: modo livre vs. programas ───────────────────────────────
const INTER_PROGRAMAS_KEY = 'escalab_inter_programas';
const INTER_MODO_KEY = 'escalab_inter_modo'; // 'livre' (todos a todo tempo) ou 'programa'

function getModoIntersetorial() { try { return localStorage.getItem(INTER_MODO_KEY) || 'livre'; } catch { return 'livre'; } }
function setModoIntersetorial(modo) { try { localStorage.setItem(INTER_MODO_KEY, modo); } catch {} }
function getProgramasInter() {
  try { return JSON.parse(localStorage.getItem(INTER_PROGRAMAS_KEY) || '[]'); } catch { return []; }
}
function salvarProgramaInter(prog) {
  try {
    const arr = getProgramasInter();
    const idx = arr.findIndex(p => p.id === prog.id);
    if (idx >= 0) arr[idx] = prog; else arr.unshift(prog);
    localStorage.setItem(INTER_PROGRAMAS_KEY, JSON.stringify(arr));
    return arr;
  } catch { return []; }
}
function removerProgramaInter(id) {
  try {
    const arr = getProgramasInter().filter(p => p.id !== id);
    localStorage.setItem(INTER_PROGRAMAS_KEY, JSON.stringify(arr));
    return arr;
  } catch { return []; }
}
function getProgramasInterAtivosPara(setorUsuario) {
  const hoje = new Date().toISOString().slice(0, 10);
  return getProgramasInter().filter(p => p.ativo && p.setores?.includes(setorUsuario) && (!p.prazoFim || p.prazoFim >= hoje));
}

// ── Permissões por gestor sobre o perfil dos liderados ────────────────────
const GESTOR_PERMS_KEY = 'escalab_gestor_perms';
// Default G&C 16/06: gestor vê do liderado Geral (sempre), Sobre mim, Avaliações,
// Feedbacks, Histórico e Dados Organizacionais. NÃO vê Dados Pessoais nem salário.
const GESTOR_PERMS_DEFAULT = {
  verAvaliacoes: true,
  verFeedbacks: true,
  verDadosOrg: true,
  verDadosPessoais: false,
  verSalario: false,
  verHistorico: true,
  verSobreMim: true,
  verAdmissaoTudo: false,
  verRecrutamentoTudo: false,
};
function getGestorPerms(gestorId) {
  try {
    const all = JSON.parse(localStorage.getItem(GESTOR_PERMS_KEY) || '{}');
    return { ...GESTOR_PERMS_DEFAULT, ...(all[gestorId] || {}) };
  } catch { return GESTOR_PERMS_DEFAULT; }
}
function salvarGestorPerms(gestorId, perms) {
  try {
    const all = JSON.parse(localStorage.getItem(GESTOR_PERMS_KEY) || '{}');
    all[gestorId] = perms;
    localStorage.setItem(GESTOR_PERMS_KEY, JSON.stringify(all));
  } catch {}
}

// ── Ciclo AVD ativo (toggle para liberar AVD) ─────────────────────────────
// Fonte de verdade: ciclos.avd_aberta no Supabase (migration 016).
// CICLOS e populado por fetchCiclosSupabase no boot e refletido aqui.
function getCicloAvdAberto() {
  const c = (CICLOS || []).find(x => x.avd_aberta);
  if (!c) return null;
  return { cicloId: c.id, nome: c.nome, abertoEm: c.avd_aberta_em };
}
async function abrirCicloAvd(cicloId) {
  const ciclo = (CICLOS || []).find(c => c.id === cicloId) || { id: cicloId, nome: cicloId };
  if (typeof window !== 'undefined' && window.supabaseClient) {
    try {
      // Fecha todos os outros primeiro pra respeitar o unique index parcial.
      await window.supabaseClient.from('ciclos').update({ avd_aberta: false, avd_aberta_em: null }).eq('avd_aberta', true);
      const agora = new Date().toISOString();
      const { error } = await window.supabaseClient
        .from('ciclos').update({ avd_aberta: true, avd_aberta_em: agora }).eq('id', cicloId);
      if (error) { console.warn('[supabase] abrirCiclo falhou:', error.message); return null; }
      await fetchCiclosSupabase();
    } catch (e) {
      console.warn('[supabase] abrirCiclo exception:', e?.message);
      return null;
    }
  }
  return { cicloId: ciclo.id, nome: ciclo.nome, abertoEm: new Date().toISOString() };
}
async function fecharCicloAvd() {
  if (typeof window !== 'undefined' && window.supabaseClient) {
    try {
      const { error } = await window.supabaseClient
        .from('ciclos').update({ avd_aberta: false, avd_aberta_em: null }).eq('avd_aberta', true);
      if (error) { console.warn('[supabase] fecharCiclo falhou:', error.message); return false; }
      await fetchCiclosSupabase();
      return true;
    } catch (e) {
      console.warn('[supabase] fecharCiclo exception:', e?.message);
      return false;
    }
  }
  return false;
}

// ── Conquistas e Movimentações editáveis pelo GC ───────────────────────────
const CONQUISTAS_KEY = 'escalab_conquistas';
const HISTORICO_KEY  = 'escalab_historico';

function getConquistas(colaboradorId) {
  try {
    const m = JSON.parse(localStorage.getItem(CONQUISTAS_KEY) || '{}');
    if (m[colaboradorId]) return m[colaboradorId];
  } catch {}
  return CONQUISTAS[colaboradorId] || [];
}
function salvarConquistas(colaboradorId, arr) {
  try {
    const m = JSON.parse(localStorage.getItem(CONQUISTAS_KEY) || '{}');
    m[colaboradorId] = arr;
    localStorage.setItem(CONQUISTAS_KEY, JSON.stringify(m));
  } catch {}
}
function getHistorico(colaboradorId) {
  try {
    const m = JSON.parse(localStorage.getItem(HISTORICO_KEY) || '{}');
    if (m[colaboradorId]) return m[colaboradorId];
  } catch {}
  return HISTORICO_PROFISSIONAL[colaboradorId] || [];
}
function salvarHistorico(colaboradorId, arr) {
  try {
    const m = JSON.parse(localStorage.getItem(HISTORICO_KEY) || '{}');
    m[colaboradorId] = arr;
    localStorage.setItem(HISTORICO_KEY, JSON.stringify(m));
  } catch {}
}

// ═══════════════════════════════════════════════════════════════
// MOVIMENTAÇÃO PROFISSIONAL · kanban com 3 subguias
// Pedido pela Maria no Site AVD (3): GC/Gestor abrem solicitações;
// cards passam por etapas; cada um tem formulário, subtarefas e
// comentários (GC, Financeiro, Líder podem comentar).
// ═══════════════════════════════════════════════════════════════

const MOV_KEY = 'escalab_movimentacao';

// Etapas por subguia (id, label, cor)
const MOV_ETAPAS = {
  admissao: [
    { id: 'inicial',       label: 'Inicial',                   color: '#6B3FA0', bg: '#F4EEFF' },
    { id: 'documentacao',  label: 'Documentação',              color: '#7B5BD6', bg: '#EFE9FF' },
    { id: 'implementacao', label: 'Implementação da bolsa',    color: '#1976D2', bg: '#E3F2FD' },
    { id: 'analise',       label: 'Análise pela Fundação',     color: '#E58A00', bg: '#FFF4E0' },
    { id: 'admitido',      label: 'Admitido',                  color: '#00967B', bg: '#E6F5F1' },
  ],
  promocao: [
    { id: 'inicial',       label: 'Início',                    color: '#6B3FA0', bg: '#F4EEFF' },
    { id: 'documentacao',  label: 'Documentos',                color: '#7B5BD6', bg: '#EFE9FF' },
    { id: 'implementacao', label: 'Implementação',             color: '#1976D2', bg: '#E3F2FD' },
    { id: 'concluido',     label: 'Concluído',                 color: '#00967B', bg: '#E6F5F1' },
  ],
  desligamento: [
    { id: 'inicial',       label: 'Aviso recebido',            color: '#C0392B', bg: '#FDECEA' },
    { id: 'documentacao',  label: 'Documentos',                color: '#7B5BD6', bg: '#EFE9FF' },
    { id: 'implementacao', label: 'Implementação financeira',  color: '#1976D2', bg: '#E3F2FD' },
    { id: 'concluido',     label: 'Concluído',                 color: '#5A6678', bg: '#EEF0F3' },
  ],
};

const MOV_LABEL = {
  admissao:     'Admissão',
  promocao:     'Promoção',
  desligamento: 'Desligamento',
};

// Definição dos formulários (campos do form de criação) por subguia.
// Baseado direto no que a Maria especificou no docx (3).
const MOV_FORM_DEF = {
  admissao: [
    { id: 'nomeColaborador',  label: 'Nome do colaborador',                                         type: 'text',     req: true },
    { id: 'solicitante',      label: 'Quem está solicitando a vaga?',                               type: 'text',     req: true },
    { id: 'email',            label: 'E-mail do solicitante',                                       type: 'email',    req: true },
    { id: 'categoria',        label: 'Categoria',                                                   type: 'select',   options: ['Fixo','Associado'], req: true }, // PDF Site AVD 5 · item 24
    { id: 'dataInicio',       label: 'Data de início do contrato',                                  type: 'date',     req: true },
    { id: 'dataFim',          label: 'Data de término do contrato',                                 type: 'date' },
    { id: 'urgencia',         label: 'Justificativa de urgência (se houver)',                       type: 'textarea' },
    { id: 'nivelAcademico',   label: 'Nível acadêmico',                                             type: 'select',   options: ['Médio Completo','Técnico','Graduação Incompleta','Graduação Completa','Pós-graduação','Mestrado Incompleto','Mestrado Completo','Doutorado'] },
    { id: 'tempoExperiencia', label: 'Tempo de experiência',                                        type: 'select',   options: ['Sem experiência','Até 1 ano','1 a 3 anos','3 anos ou mais','5 anos ou mais'] },
    { id: 'vinculo',          label: 'Vínculo institucional',                                       type: 'select',   options: ['Sem vínculo','Tem vínculo institucional em MG','Tem vínculo institucional fora de MG (Brasil)','Tem vínculo institucional fora do Brasil'] },
    { id: 'valorMin',         label: 'Valor mínimo (R$)',                                           type: 'number' },
    { id: 'valorMax',         label: 'Valor máximo (R$)',                                           type: 'number' },
    { id: 'contato',          label: 'Contato do colaborador (telefone/e-mail)',                    type: 'textarea' },
    { id: 'projetoSetor',     label: 'Nome do Projeto/Setor',                                       type: 'text',     req: true },
    { id: 'atividades',       label: 'Atividades que serão realizadas pelo colaborador',            type: 'textarea', req: true },
  ],
  promocao: [
    { id: 'solicitante',      label: 'Nome do solicitante',                                         type: 'text',     req: true },
    { id: 'email',            label: 'E-mail do solicitante',                                       type: 'email',    req: true },
    { id: 'nomeColaborador',  label: 'Nome do colaborador',                                         type: 'text',     req: true },
    { id: 'categoria',        label: 'Categoria',                                                   type: 'select',   options: ['Fixo','Associado'], req: true }, // PDF Site AVD 5 · item 24
    { id: 'tipo',             label: 'Tipo de movimentação',                                        type: 'select',   options: ['Ajuste salarial','Admissão','Alteração de cargo','Alteração de departamento','Dissídio','Mudança de step (mérito)','Mudança de projeto','Promoção','Alteração de liderança'], req: true },
    { id: 'duracao',          label: 'Por quanto tempo?',                                           type: 'text' },
    { id: 'pretensaoMes',     label: 'Pretensão de mês de pagamento da nova bolsa/bônus',           type: 'text' },
    { id: 'cargoAtual',       label: 'Cargo Atual',                                                 type: 'text',     req: true },
    { id: 'cargoNovo',        label: 'Novo Cargo',                                                  type: 'text',     req: true },
    { id: 'valorAntigo',      label: 'Valor antigo (R$)',                                           type: 'number' },
    { id: 'valorNovo',        label: 'Novo valor (R$)',                                             type: 'number' },
    { id: 'justificativa',    label: 'Justificativa da mudança',                                    type: 'textarea', req: true },
    { id: 'perfil',           label: 'Perfil do colaborador',                                       type: 'select',   options: ['Tem vínculo com a UFMG','Não tem vínculo com a UFMG','Bolsista','CLT'] },
  ],
  desligamento: [
    { id: 'solicitante',      label: 'Quem está solicitando',                                       type: 'text',     req: true },
    { id: 'email',            label: 'E-mail do solicitante',                                       type: 'email',    req: true },
    { id: 'nomeColaborador',  label: 'Nome do colaborador',                                         type: 'text',     req: true },
    { id: 'cargo',            label: 'Cargo',                                                       type: 'text' },
    { id: 'setor',            label: 'Setor / Projeto',                                             type: 'text' },
    { id: 'tipoDesligamento', label: 'Tipo de desligamento (primário)',                              type: 'select',   options: ['Pedido do colaborador', 'Saída por parte da empresa', 'Acordo entre as partes'], req: true },
    { id: 'motivoSecundario', label: 'Motivo secundário (lista padronizada · pode adicionar novo)',  type: 'motivo-secundario',  req: true },
    { id: 'avisoPrevio',      label: 'Aviso prévio',                                                type: 'select',   options: ['Cumprido (trabalhado)', 'Indenizado', 'Dispensado', 'Não se aplica'] },
    { id: 'avisoPrevioInicio',label: 'Início do aviso prévio',                                      type: 'date' },
    { id: 'avisoPrevioFim',   label: 'Fim do aviso prévio',                                         type: 'date' },
    { id: 'dataSaida',        label: 'Data de saída prevista',                                      type: 'date',     req: true },
    { id: 'ultimoMes',        label: 'Último mês trabalhado',                                       type: 'text' },
    { id: 'feriasVencidas',   label: 'Possui férias vencidas?',                                     type: 'select',   options: ['Não','Sim · pendente de cálculo','Sim · já calculado'] },
    { id: 'saldoDayOff',      label: 'Saldo de Day Off em aberto (dias)',                           type: 'number' },
    { id: 'motivo',           label: 'Motivo do desligamento',                                      type: 'textarea', req: true },
    { id: 'observacoes',      label: 'Observações para o financeiro',                               type: 'textarea' },
    { id: 'devolucaoEquip',   label: 'Devolução de equipamentos (notebook, crachá, etc.)',          type: 'textarea' },
  ],
};

// Seeds: 1-2 exemplos por subguia (apenas se localStorage vazio)
const MOV_SEEDS = {
  admissao: [
    { id: 'MOV-A1', etapa: 'inicial', criadoEm: '2026-05-29', criadoPor: 'Carolina Maria de Lima Alves',
      dados: { nomeColaborador: 'Izabelle Fortes Meirelles', solicitante: 'Carolina Maria de Lima Alves', email: 'carolina.alves@escalab.com.br', dataInicio: '2026-06-01', dataFim: '2026-08-01', urgencia: 'Entrada de um novo projeto - CSN', nivelAcademico: 'Mestrado Incompleto', tempoExperiencia: '3 anos ou mais', vinculo: 'Tem vínculo institucional fora do Brasil', valorMin: 2500, valorMax: 3000, contato: '+55 31 9866-0800 / izabellefortesmeirelles@gmail.com', projetoSetor: 'CSN', atividades: 'Estudos de mercado de produtos estéreis para mineração, análise de fornecedores, monitoramento de tendências, pesquisa de preços e cotações.' },
      subtarefas: [{ id: 1, txt: 'Conferir documentação acadêmica', resp: 'Yasmim Santos', prazo: '2026-06-05', feita: false }],
      comentarios: [{ autor: 'Yasmim Santos', em: '2026-05-30', txt: 'Vou contatar a Izabelle pra confirmar disponibilidade.' }],
    },
  ],
  promocao: [
    { id: 'MOV-P1', etapa: 'documentacao', criadoEm: '2026-05-28', criadoPor: 'Yasmim Santos',
      dados: { solicitante: 'Yasmim Santos', email: 'yasmim.santos@escalab.com.br', nomeColaborador: 'Gabriela Oliveira', tipo: 'Mudança de projeto e valor da bolsa (associado)', duracao: '2 meses', pretensaoMes: 'junho', cargoAtual: 'Associado', cargoNovo: 'Associado', valorAntigo: 0, valorNovo: 1500, justificativa: 'Valor associado ao trabalho no projeto da Marca Ambiental', perfil: 'Não tem vínculo com a UFMG' },
      subtarefas: [{ id: 1, txt: 'Aprovação do gestor', resp: 'Marcus Ferreira Neto', prazo: '2026-06-03', feita: true }, { id: 2, txt: 'Atualização do contrato', resp: 'GC', prazo: '2026-06-10', feita: false }],
      comentarios: [],
    },
  ],
  desligamento: [],
};

function getMovSolicitacoes(tipo) {
  const t = tipo || 'admissao';
  try {
    const raw = localStorage.getItem(MOV_KEY);
    if (raw) {
      const all = JSON.parse(raw);
      return all[t] || [];
    }
    localStorage.setItem(MOV_KEY, JSON.stringify(MOV_SEEDS));
    return MOV_SEEDS[t] || [];
  } catch { return MOV_SEEDS[t] || []; }
}

function salvarMovSolicitacao(tipo, sol) {
  try {
    const raw = localStorage.getItem(MOV_KEY) || JSON.stringify(MOV_SEEDS);
    const all = JSON.parse(raw);
    const lista = (all[tipo] || []).filter(s => s.id !== sol.id);
    lista.unshift(sol);
    all[tipo] = lista;
    localStorage.setItem(MOV_KEY, JSON.stringify(all));
    return lista;
  } catch { return []; }
}

function removerMovSolicitacao(tipo, id) {
  try {
    const raw = localStorage.getItem(MOV_KEY) || JSON.stringify(MOV_SEEDS);
    const all = JSON.parse(raw);
    all[tipo] = (all[tipo] || []).filter(s => s.id !== id);
    localStorage.setItem(MOV_KEY, JSON.stringify(all));
    return all[tipo];
  } catch { return []; }
}

function gerarIdMov(tipo) {
  const prefix = { admissao: 'A', promocao: 'P', desligamento: 'D' }[tipo] || 'X';
  return 'MOV-' + prefix + Date.now().toString(36).slice(-5).toUpperCase();
}

// ═══════════════════════════════════════════════════════════════
// NOVIDADES · popup mostrado a colab/gestor ao entrar
// Pedido pela Maria: GC edita lista de novidades; cada novidade tem
// título, texto, foto, data e CAMPOS PERSONALIZADOS (text/textarea/
// link/numero/data). Mostra só pra quem ainda não viu.
// ═══════════════════════════════════════════════════════════════

const NOVIDADES_KEY        = 'escalab_novidades';
const NOVIDADES_VISTAS_KEY = 'escalab_novidades_vistas';

const NOVIDADE_TIPOS_CAMPO = [
  { id: 'text',     label: 'Texto curto'   },
  { id: 'textarea', label: 'Texto longo'   },
  { id: 'link',     label: 'Link / URL'    },
  { id: 'date',     label: 'Data'          },
  { id: 'number',   label: 'Número'        },
];

const NOVIDADES_SEED = [
  {
    id: 'NOV-DEMO1',
    titulo: 'Bem-vindos à nova Escalab Gestão de Pessoas',
    texto: 'Acabou de chegar uma rodada de melhorias na plataforma! Tem painel de movimentação profissional, popup de novidades (esse aqui!) e ajustes visuais. Aproveitem para explorar e qualquer dúvida fala com o GC.',
    fotoBase64: '',
    data: '2026-06-02',
    camposExtra: [
      { id: 'c1', label: 'Link do tutorial', tipo: 'link', valor: 'https://genteecultura.escalab.com.br/' },
    ],
    publico: ['gestor', 'colaborador'],
    ativa: true,
    criadoEm: '2026-06-02',
  },
];

function getNovidades() {
  try {
    const raw = localStorage.getItem(NOVIDADES_KEY);
    if (raw) return JSON.parse(raw);
    localStorage.setItem(NOVIDADES_KEY, JSON.stringify(NOVIDADES_SEED));
    return NOVIDADES_SEED;
  } catch { return NOVIDADES_SEED; }
}

function salvarNovidade(nov) {
  try {
    const lista = getNovidades().filter(n => n.id !== nov.id);
    lista.unshift(nov);
    localStorage.setItem(NOVIDADES_KEY, JSON.stringify(lista));
    return lista;
  } catch { return getNovidades(); }
}

function removerNovidade(id) {
  try {
    const lista = getNovidades().filter(n => n.id !== id);
    localStorage.setItem(NOVIDADES_KEY, JSON.stringify(lista));
    return lista;
  } catch { return getNovidades(); }
}

function gerarIdNovidade() {
  return 'NOV-' + Date.now().toString(36).toUpperCase();
}

function getNovidadesVistas(userId) {
  try {
    const m = JSON.parse(localStorage.getItem(NOVIDADES_VISTAS_KEY) || '{}');
    return m[userId] || [];
  } catch { return []; }
}

function marcarNovidadeVista(userId, novidadeId) {
  try {
    const m = JSON.parse(localStorage.getItem(NOVIDADES_VISTAS_KEY) || '{}');
    const set = new Set(m[userId] || []);
    set.add(novidadeId);
    m[userId] = [...set];
    localStorage.setItem(NOVIDADES_VISTAS_KEY, JSON.stringify(m));
  } catch {}
}

function resetarNovidadesVistas(novidadeId) {
  // GC pode "reapresentar" uma novidade: zera a flag de quem já viu.
  try {
    const m = JSON.parse(localStorage.getItem(NOVIDADES_VISTAS_KEY) || '{}');
    Object.keys(m).forEach(uid => {
      m[uid] = (m[uid] || []).filter(id => id !== novidadeId);
    });
    localStorage.setItem(NOVIDADES_VISTAS_KEY, JSON.stringify(m));
  } catch {}
}

// Retorna as novidades ativas que esse user ainda não viu e que
// alcançam o perfil dele (campo `publico`).
function getNovidadesPendentes(user) {
  if (!user) return [];
  const todas = getNovidades();
  const vistas = new Set(getNovidadesVistas(user.id));
  return todas
    .filter(n => n.ativa)
    .filter(n => (n.publico || []).includes(user.perfil))
    .filter(n => !vistas.has(n.id))
    .sort((a, b) => (a.data || '').localeCompare(b.data || ''));
}

// Helper para criar card automático de desligamento vindo do fluxo
// existente em screen-colaboradores.jsx (botão Desligar do GC).
function criarMovDesligamentoAuto({ colaborador, registroDeslig, atorNome, atorEmail }) {
  const sol = {
    id: gerarIdMov('desligamento'),
    etapa: 'inicial',
    criadoEm: new Date().toISOString().slice(0, 10),
    criadoPor: atorNome || 'GC',
    origem: 'auto-desligamento',
    desligamentoId: registroDeslig?.id || null,
    dados: {
      solicitante:     atorNome || 'GC',
      email:           atorEmail || ESCALAB_EMAIL_FROM,
      nomeColaborador: colaborador.nome,
      cargo:           colaborador.cargo || '',
      setor:           colaborador.setor || '',
      dataSaida:       registroDeslig?.dataSaida || '',
      ultimoMes:       registroDeslig?.ultimoMes || '',
      motivo:          registroDeslig?.motivoTexto || registroDeslig?.motivoId || '',
      observacoes:     registroDeslig?.feedback || '',
    },
    subtarefas: [
      { id: 1, txt: 'Aviso ao financeiro',                resp: 'GC',        prazo: '', feita: true },
      { id: 2, txt: 'Calcular direitos e rescisão',       resp: 'Financeiro', prazo: '', feita: false },
      { id: 3, txt: 'Entrevista de desligamento',         resp: 'GC',        prazo: '', feita: false },
      { id: 4, txt: 'Retirada de acessos',                resp: 'TI',        prazo: '', feita: false },
    ],
    comentarios: [],
  };
  return salvarMovSolicitacao('desligamento', sol);
}

// ── Upload de arquivo → base64 (para anexos em localStorage) ──────────────────
// Limite prático: 5MB (localStorage tem ~5MB total no navegador).
const ARQUIVO_MAX_BYTES = 5 * 1024 * 1024;

function lerArquivoBase64(file) {
  return new Promise((resolve, reject) => {
    if (!file) return reject(new Error('Nenhum arquivo'));
    if (file.size > ARQUIVO_MAX_BYTES) {
      return reject(new Error(`Arquivo excede ${Math.round(ARQUIVO_MAX_BYTES / 1024 / 1024)}MB`));
    }
    const reader = new FileReader();
    reader.onload = () => resolve({
      nome: file.name,
      tipo: file.type || 'application/octet-stream',
      tamanho: file.size,
      dataUrl: reader.result,
    });
    reader.onerror = () => reject(reader.error || new Error('Falha ao ler arquivo'));
    reader.readAsDataURL(file);
  });
}

function formatarTamanho(bytes) {
  if (!bytes && bytes !== 0) return '';
  if (bytes < 1024) return `${bytes} B`;
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
  return `${(bytes / 1024 / 1024).toFixed(2)} MB`;
}

// ═══════════════════════════════════════════════════════════════
// HORAS · Banco de horas simples (Site AVD 12)
// Pedido pela Maria: cada colaborador registra horas diárias
// divididas entre REUNIÃO e ATIVIDADE; o banco de horas (extras /
// negativas) sai automático. Feriados, day off aprovado e férias
// aprovadas contam como jornada cumprida (não precisa preencher).
// ═══════════════════════════════════════════════════════════════

const HORAS_KEY = 'escalab_horas_registros';
const HORAS_JORNADA_PADRAO = 8;     // h por dia útil
const HORAS_JORNADA_SEMANAL = 40;   // só pra display
// Feriados nacionais brasileiros (editáveis depois pelo GC se preciso)
const FERIADOS_BR = [
  // 2026
  '2026-01-01', '2026-02-16', '2026-02-17', '2026-04-03', '2026-04-21',
  '2026-05-01', '2026-06-04', '2026-09-07', '2026-10-12', '2026-11-02',
  '2026-11-15', '2026-11-20', '2026-12-25',
  // 2027 (essenciais)
  '2027-01-01', '2027-04-21', '2027-05-01', '2027-09-07', '2027-10-12',
  '2027-11-02', '2027-11-15', '2027-12-25',
];

function isFeriado(dateYmd) { return FERIADOS_BR.includes(dateYmd); }
function isFds(dateYmd) {
  const d = new Date(dateYmd + 'T00:00:00');
  const dia = d.getDay();
  return dia === 0 || dia === 6;
}

function getTipoDiaColaborador(colaboradorId, dateYmd) {
  if (isFeriado(dateYmd)) return 'feriado';
  try {
    const dos = (typeof getDayOffs === 'function' ? getDayOffs() : []) || [];
    if (dos.some(d => d.colaboradorId === colaboradorId && d.status === 'aprovado' && d.data === dateYmd)) {
      return 'dayoff';
    }
  } catch {}
  try {
    const fer = (typeof getFeriasSolicitacoes === 'function' ? getFeriasSolicitacoes() : []) || [];
    if (fer.some(f => f.colaboradorId === colaboradorId && f.status === 'aprovada' && dateYmd >= f.inicio && dateYmd <= f.fim)) {
      return 'ferias';
    }
  } catch {}
  if (isFds(dateYmd)) return 'fds';
  return 'util';
}

// Seed: gera registros realistas pros últimos 45 dias úteis (8h padrão, com
// variação leve, ocasionais extras e algumas faltas) pra que o banco de
// horas e os gráficos apareçam preenchidos por padrão.
function _seedHorasRegistros() {
  // Sub-amostra: ids dos colaboradores fixos ativos (não associados,
  // performance da janela atual). 18 pessoas é o suficiente pra povoar.
  const idsSeed = [1,6,7,10,13,14,15,16,17,18,19,20,21,22,23,26,27,40,41,42,43];
  const lista = [];
  const hoje = new Date(); hoje.setHours(0,0,0,0);
  for (let d = 0; d < 60; d++) {
    const dt = new Date(hoje); dt.setDate(dt.getDate() - d);
    const ymd = _ymd(dt);
    if (isFeriado(ymd) || isFds(ymd)) continue;
    idsSeed.forEach(id => {
      // ~88% dos dias preenchidos (12% esquece registrar)
      const seedKey = (id * 1009 + d * 17) % 100;
      if (seedKey < 12) return;
      // Reunião: 1.0 a 2.5h | Atividade: 5.5 a 7h | total ~ 7-9h
      const reuniao = Math.round(((seedKey % 30) / 30 * 1.5 + 1.0) * 2) / 2;
      let atividade = Math.round(((seedKey % 17) / 17 * 1.5 + 5.5) * 2) / 2;
      // Líderes/diretores fazem mais reunião e menos atividade individual
      if ([1,6,7,10,13,14,40].includes(id)) {
        atividade = Math.max(4, atividade - 1.5);
      }
      lista.push({
        id: 'HR-' + id + '-' + ymd,
        colaboradorId: id, data: ymd,
        reuniao, atividade, obs: '',
        em: dt.toISOString(),
      });
    });
  }
  return lista;
}
function getRegistrosHoras() {
  try {
    const raw = localStorage.getItem(HORAS_KEY);
    if (raw) return JSON.parse(raw);
    const seed = _seedHorasRegistros();
    localStorage.setItem(HORAS_KEY, JSON.stringify(seed));
    return seed;
  } catch { return []; }
}
function salvarRegistrosHoras(lista) {
  try { localStorage.setItem(HORAS_KEY, JSON.stringify(lista)); } catch {}
}
function getRegistroHoraDia(colaboradorId, dateYmd) {
  return getRegistrosHoras().find(r => r.colaboradorId === colaboradorId && r.data === dateYmd) || null;
}
function salvarRegistroHora({ colaboradorId, data, reuniao, atividade, obs }) {
  const lista = getRegistrosHoras().filter(r => !(r.colaboradorId === colaboradorId && r.data === data));
  const reg = {
    id: 'HR-' + colaboradorId + '-' + data,
    colaboradorId, data,
    reuniao: Math.max(0, Number(reuniao) || 0),
    atividade: Math.max(0, Number(atividade) || 0),
    obs: obs || '',
    em: new Date().toISOString(),
  };
  lista.unshift(reg);
  salvarRegistrosHoras(lista);
  return reg;
}
function removerRegistroHora(colaboradorId, dateYmd) {
  salvarRegistrosHoras(getRegistrosHoras().filter(r => !(r.colaboradorId === colaboradorId && r.data === dateYmd)));
}

function getHorasDia(colaboradorId, dateYmd) {
  const tipo = getTipoDiaColaborador(colaboradorId, dateYmd);
  if (tipo === 'feriado' || tipo === 'dayoff' || tipo === 'ferias') {
    // contam como jornada cumprida (não precisa preencher) · usa carga individual
    const jornada = typeof getJornadaDia === 'function' ? getJornadaDia(colaboradorId) : HORAS_JORNADA_PADRAO;
    return { total: jornada, reuniao: 0, atividade: jornada, tipo, automatico: true };
  }
  const reg = getRegistroHoraDia(colaboradorId, dateYmd);
  if (!reg) return { total: 0, reuniao: 0, atividade: 0, tipo, automatico: false };
  return { total: (reg.reuniao || 0) + (reg.atividade || 0), reuniao: reg.reuniao || 0, atividade: reg.atividade || 0, tipo, automatico: false, obs: reg.obs };
}

// Lê a carga horária individual do colaborador (em horas/dia útil).
// Fonte: campo 'horasMensais' em dados_org / dividido por 22 dias úteis.
// Fallback: 8h/dia (padrão antigo).
function getJornadaDia(colaboradorId) {
  try {
    const raw = localStorage.getItem(`escalab_dados_org_${colaboradorId}`);
    if (raw) {
      const d = JSON.parse(raw);
      const mensal = Number(d.horasMensais);
      if (mensal && mensal > 0) return Math.round((mensal / 22) * 10) / 10;
    }
  } catch {}
  return HORAS_JORNADA_PADRAO;
}

function getSaldoDia(colaboradorId, dateYmd) {
  const h = getHorasDia(colaboradorId, dateYmd);
  const jornada = getJornadaDia(colaboradorId);
  if (h.tipo === 'feriado' || h.tipo === 'dayoff' || h.tipo === 'ferias') return 0;
  if (h.tipo === 'fds') return h.total; // o que fizer no fds é extra
  return h.total - jornada;
}

// Banco de horas = soma dos saldos diários do ano corrente até hoje (limitado a 366 iterações)
function getBancoHoras(colaboradorId, dateLimiteYmd) {
  const lim = dateLimiteYmd || _ymd(new Date());
  const ini = lim.slice(0, 4) + '-01-01';
  let saldo = 0;
  const dIni = new Date(ini + 'T00:00:00');
  const dFim = new Date(lim + 'T00:00:00');
  let steps = 0;
  for (let d = new Date(dIni); d <= dFim && steps < 400; d.setDate(d.getDate() + 1), steps++) {
    saldo += getSaldoDia(colaboradorId, _ymd(d));
  }
  return Math.round(saldo * 100) / 100;
}

function getHorasColabMes(colaboradorId, ym) {
  const regs = getRegistrosHoras().filter(r => r.colaboradorId === colaboradorId && r.data.startsWith(ym));
  let reuniao = 0, atividade = 0;
  regs.forEach(r => { reuniao += r.reuniao || 0; atividade += r.atividade || 0; });
  return { reuniao, atividade, total: reuniao + atividade, dias: regs.length };
}

function getHorasSetorMes(setor, ym) {
  const colabs = COLABORADORES.filter(c => c.setor === setor || (c.setoresExtras || []).includes(setor));
  let reuniao = 0, atividade = 0, comRegistro = 0;
  colabs.forEach(c => {
    const h = getHorasColabMes(c.id, ym);
    reuniao += h.reuniao; atividade += h.atividade;
    if (h.dias > 0) comRegistro++;
  });
  return { reuniao, atividade, total: reuniao + atividade, n: colabs.length, comRegistro };
}

function fmtHoras(n) {
  if (n == null || isNaN(n)) return '0h';
  const sinal = n < 0 ? '-' : '';
  const abs = Math.abs(n);
  const h = Math.floor(abs);
  const m = Math.round((abs - h) * 60);
  if (m === 0) return `${sinal}${h}h`;
  return `${sinal}${h}h${String(m).padStart(2, '0')}`;
}

// ── Indicadores Financeiros Anuais (faturamento × lucro) ────────────────────
// Usados no Painel para cruzar média de pessoas por ano vs faturamento e
// número de pessoas × faturamento × lucro (PDF Site AVD (2)).
const INDIC_FIN_KEY = 'escalab_indicadores_financeiros';
const INDIC_FIN_SEED = [
  { ano: 2022, faturamento: 1_800_000, lucro: 252_000  /* 14% */ },
  { ano: 2023, faturamento: 1_950_000, lucro: 312_000  /* 16% */ },
  { ano: 2024, faturamento: 2_050_000, lucro: 287_000  /* 14% */ },
  { ano: 2025, faturamento: 2_180_000, lucro: 370_600  /* 17% */ },
  { ano: 2026, faturamento: 2_300_000, lucro: 322_000  /* 14% */ }, // projeção parcial
];
function getIndicadoresFinanceiros() {
  try {
    const r = localStorage.getItem(INDIC_FIN_KEY);
    if (r) return JSON.parse(r);
    localStorage.setItem(INDIC_FIN_KEY, JSON.stringify(INDIC_FIN_SEED));
    return INDIC_FIN_SEED;
  } catch { return INDIC_FIN_SEED; }
}
function salvarIndicadoresFinanceiros(arr) {
  try { localStorage.setItem(INDIC_FIN_KEY, JSON.stringify(arr)); } catch {}
}
function upsertIndicadorFinanceiro(reg) {
  const l = getIndicadoresFinanceiros().filter(x => Number(x.ano) !== Number(reg.ano));
  l.push({ ano: Number(reg.ano), faturamento: Number(reg.faturamento) || 0, lucro: Number(reg.lucro) || 0 });
  l.sort((a, b) => a.ano - b.ano);
  salvarIndicadoresFinanceiros(l);
}
function removerIndicadorFinanceiro(ano) {
  salvarIndicadoresFinanceiros(getIndicadoresFinanceiros().filter(x => Number(x.ano) !== Number(ano)));
}

// ── Config GC (custo de contratação) ────────────────────────────────────────
// Define qual analista de GC é referência pro cálculo de custo de contratação
// e quantas horas dela são gastas por contratação. PDF Site AVD (2).
const CONFIG_RH_KEY = 'escalab_config_rh';
const CONFIG_RH_DEFAULT = {
  analistaRhId: 42,             // Maria Clara Ferreira
  horasPorContratacao: 24,       // 3 dias úteis dedicados por vaga (triagem+entrevistas+onboarding)
  horasMensaisJornada: 176,      // p/ converter salário → custo/h
};
function getConfigRh() {
  try {
    const r = localStorage.getItem(CONFIG_RH_KEY);
    if (r) return { ...CONFIG_RH_DEFAULT, ...JSON.parse(r) };
    return { ...CONFIG_RH_DEFAULT };
  } catch { return { ...CONFIG_RH_DEFAULT }; }
}
function salvarConfigRh(cfg) {
  try { localStorage.setItem(CONFIG_RH_KEY, JSON.stringify({ ...CONFIG_RH_DEFAULT, ...cfg })); } catch {}
}
// Custo médio de contratação = (salário analista GC ÷ horas mensais) × horas por contratação
function calcularCustoContratacao() {
  const cfg = getConfigRh();
  const analista = COLABORADORES.find(c => c.id === cfg.analistaRhId);
  if (!analista) return { custoUnitario: 0, custoHora: 0, analistaNome: '·' };
  // Tenta puxar salário do Dados Org (override) primeiro
  let salario = 0;
  try {
    const dados = JSON.parse(localStorage.getItem(`escalab_dados_org_${cfg.analistaRhId}`) || '{}');
    if (dados.salarioBruto) {
      const num = String(dados.salarioBruto).replace(/[^0-9,.-]/g,'').replace('.','').replace(',','.');
      salario = parseFloat(num) || 0;
    }
  } catch {}
  if (!salario) salario = getSalario(analista);
  const custoHora = salario / (cfg.horasMensaisJornada || 176);
  const custoUnitario = custoHora * (cfg.horasPorContratacao || 24);
  return {
    custoUnitario: Math.round(custoUnitario),
    custoHora: Math.round(custoHora * 100) / 100,
    salarioAnalista: salario,
    analistaNome: analista.nome,
    analistaId: analista.id,
    horasPorContratacao: cfg.horasPorContratacao,
  };
}

// ── Catálogo de cargos (PDI · projeção de carreira) ─────────────────────────
// Lista oficial será enviada pelo RH (registrado em BACKLOG_AJUSTES.md "documentos pendentes").
// Enquanto não chega, geramos um catálogo derivado: cada família × 4 steps (I, II, III, IV).
// RH pode editar pelo storage (`escalab_cargos_catalogo`) — quando a lista oficial chegar,
// é só substituir esse seed.
const CARGOS_CATALOGO_KEY = 'escalab_cargos_catalogo';
const CARGOS_FAMILIAS_SEED = [
  { familia: 'Associado',             niveis: ['I', 'II', 'III', 'IV'], ordem: 1 },
  { familia: 'Associado de Projetos', niveis: ['I', 'II', 'III', 'IV'], ordem: 2 },
  { familia: 'Analista I',            niveis: ['I', 'II', 'III', 'IV'], ordem: 3 },
  { familia: 'Analista II',           niveis: ['I', 'II', 'III', 'IV'], ordem: 4 },
  { familia: 'Coordenador(a)',        niveis: ['I', 'II', 'III', 'IV'], ordem: 5 },
  { familia: 'Líder/Especialista I',  niveis: ['I', 'II', 'III', 'IV'], ordem: 6 },
  { familia: 'Líder/Especialista II', niveis: ['I', 'II', 'III', 'IV'], ordem: 7 },
  { familia: 'Diretor de Setor',      niveis: ['I', 'II', 'III'],        ordem: 8 },
  { familia: 'Diretor de Área',       niveis: ['I', 'II', 'III'],        ordem: 9 },
  { familia: 'Diretor Executivo',     niveis: ['I', 'II'],               ordem: 10 },
];
function getCargosCatalogo() {
  try {
    const r = localStorage.getItem(CARGOS_CATALOGO_KEY);
    if (r) return JSON.parse(r);
  } catch {}
  return CARGOS_FAMILIAS_SEED;
}
function salvarCargosCatalogo(arr) {
  try { localStorage.setItem(CARGOS_CATALOGO_KEY, JSON.stringify(arr)); } catch {}
}
// Lista plana ordenada pra usar em <select> — "Família · Step N"
function listarCargosComStep() {
  const cat = getCargosCatalogo().slice().sort((a, b) => (a.ordem || 0) - (b.ordem || 0));
  const out = [];
  cat.forEach(c => {
    (c.niveis || []).forEach(n => {
      out.push({ value: `${c.familia} · Step ${n}`, familia: c.familia, step: n });
    });
  });
  return out;
}

// ═══════════════════════════════════════════════════════════════════════════════
// CADASTRO DO COLABORADOR (modelo Caju): documentos + diversidade no Supabase
// (pgcrypto + Vault), dados pessoais em LS. Progresso lido de caches LS para
// que o banner do header nao precise de await.
// ═══════════════════════════════════════════════════════════════════════════════

const CADASTRO_DOCS_COUNT_KEY = id => `escalab_cadastro_docs_count_${id}`;
const CADASTRO_DIV_COUNT_KEY  = id => `escalab_cadastro_div_count_${id}`;

// Campos OBRIGATORIOS por secao (consistente com screen-completar-cadastro.jsx)
const CADASTRO_PESSOAIS_OBRIG = ['dataNascimento','telefone','endereco'];
const CADASTRO_DOCS_OBRIG     = ['cpf']; // RG opcional
const CADASTRO_DIV_OBRIG      = ['genero','etnia','orientacao','pcd','estadoCivil']; // religiao opcional (sensivel demais)

function getCadastroProgresso(colaboradorId) {
  // Pessoais (LS)
  let dadosOrg = {};
  try { dadosOrg = JSON.parse(localStorage.getItem(`escalab_dados_org_${colaboradorId}`) || '{}'); } catch {}
  const pessoaisPreenchidos = CADASTRO_PESSOAIS_OBRIG.filter(k => (dadosOrg[k] || '').toString().trim()).length;
  const temFoto = !!(typeof getFoto === 'function' && getFoto(colaboradorId));
  const pessoaisTotal = CADASTRO_PESSOAIS_OBRIG.length + 1; // +1 foto

  // Docs (Supabase): conta cacheada em LS na hora de salvar
  let docsCount = 0;
  try { docsCount = Number(localStorage.getItem(CADASTRO_DOCS_COUNT_KEY(colaboradorId)) || '0') || 0; } catch {}
  const docsTotal = CADASTRO_DOCS_OBRIG.length;

  // Diversidade (Supabase): idem
  let divCount = 0;
  try { divCount = Number(localStorage.getItem(CADASTRO_DIV_COUNT_KEY(colaboradorId)) || '0') || 0; } catch {}
  const divTotal = CADASTRO_DIV_OBRIG.length;

  const preenchidos = pessoaisPreenchidos + (temFoto ? 1 : 0) + Math.min(docsCount, docsTotal) + Math.min(divCount, divTotal);
  const total = pessoaisTotal + docsTotal + divTotal;
  const pct = total > 0 ? Math.round((preenchidos / total) * 100) : 100;

  const faltando = [];
  if (pessoaisPreenchidos < CADASTRO_PESSOAIS_OBRIG.length || !temFoto) faltando.push('dados pessoais');
  if (docsCount < docsTotal) faltando.push('CPF');
  if (divCount < divTotal) faltando.push('diversidade');

  return { pct, preenchidos, total, faltando };
}

// ── Helpers Supabase: documentos ─────────────────────────────────────────────

async function carregarDocumentosColab(colaboradorId) {
  const sb = typeof window !== 'undefined' ? window.supabaseClient : null;
  if (!sb) return null;
  try {
    const { data: sess } = await sb.auth.getSession();
    if (!sess?.session) return null;
    // Pega uuid do colab logado (a tabela usa uuid, nao o id numerico do seed)
    const colabUuid = await _colabUuidDoUsuarioLogado(sb);
    if (!colabUuid) return null;
    const { data, error } = await sb.from('documentos')
      .select('cpf_enc, rg_enc')
      .eq('colaborador_id', colabUuid)
      .maybeSingle();
    if (error) { console.warn('carregarDocumentosColab:', error.message); return null; }
    if (!data) return { cpf: '', rg: '' };
    // Decriptografa via RPC
    const [{ data: cpf }, { data: rg }] = await Promise.all([
      data.cpf_enc ? sb.rpc('crypto_get', { enc: data.cpf_enc }) : Promise.resolve({ data: '' }),
      data.rg_enc  ? sb.rpc('crypto_get', { enc: data.rg_enc  }) : Promise.resolve({ data: '' }),
    ]);
    return { cpf: cpf || '', rg: rg || '' };
  } catch (e) { console.warn('carregarDocumentosColab erro:', e); return null; }
}

async function salvarDocumentosColab(colaboradorId, dados) {
  const sb = typeof window !== 'undefined' ? window.supabaseClient : null;
  if (!sb) return { ok: false, erro: 'Supabase nao conectado. Faca login novamente.' };
  try {
    const colabUuid = await _colabUuidDoUsuarioLogado(sb);
    if (!colabUuid) return { ok: false, erro: 'Sessao expirada ou auth_user_id nao linkado. Faca login novamente.' };
    // Encripta via RPC crypto_set
    const [{ data: cpfEnc, error: e1 }, { data: rgEnc, error: e2 }] = await Promise.all([
      dados.cpf ? sb.rpc('crypto_set', { plain: dados.cpf }) : Promise.resolve({ data: null }),
      dados.rg  ? sb.rpc('crypto_set', { plain: dados.rg })  : Promise.resolve({ data: null }),
    ]);
    if (e1 || e2) return { ok: false, erro: (e1 || e2).message };
    const payload = { colaborador_id: colabUuid, cpf_enc: cpfEnc, rg_enc: rgEnc };
    console.log('[documentos] upsert payload (cpf/rg encriptados):', { ...payload, cpf_enc: cpfEnc ? '<encrypted>' : null, rg_enc: rgEnc ? '<encrypted>' : null });
    const { data, error } = await sb.from('documentos').upsert(payload, { onConflict: 'colaborador_id' }).select();
    if (error) { console.warn('[documentos] erro:', error); return { ok: false, erro: error.message }; }
    if (!data || data.length === 0) {
      console.warn('[documentos] upsert sem erro mas 0 linhas - RLS UPDATE bloqueando? colab_id:', colabUuid);
      return { ok: false, erro: 'RLS bloqueou silenciosamente. Verificar policy de UPDATE em documentos.' };
    }
    // Atualiza cache LS pro progresso
    const count = CADASTRO_DOCS_OBRIG.filter(k => (dados[k] || '').toString().trim()).length;
    try { localStorage.setItem(CADASTRO_DOCS_COUNT_KEY(colaboradorId), String(count)); } catch {}
    return { ok: true };
  } catch (e) { return { ok: false, erro: e?.message || 'erro inesperado' }; }
}

// ── Helpers Supabase: diversidade ────────────────────────────────────────────

async function carregarDiversidadeColab(colaboradorId) {
  const sb = typeof window !== 'undefined' ? window.supabaseClient : null;
  if (!sb) return null;
  try {
    const { data: sess } = await sb.auth.getSession();
    if (!sess?.session) return null;
    const colabUuid = await _colabUuidDoUsuarioLogado(sb);
    if (!colabUuid) return null;
    const { data, error } = await sb.from('diversidade')
      .select('genero_enc, etnia_enc, orientacao_enc, religiao_enc, pcd_enc, estado_civil_enc')
      .eq('colaborador_id', colabUuid)
      .maybeSingle();
    if (error) { console.warn('carregarDiversidadeColab:', error.message); return null; }
    if (!data) return {};
    const decifrar = enc => enc ? sb.rpc('crypto_get', { enc }) : Promise.resolve({ data: '' });
    const [g, e, o, r, p, ec] = await Promise.all([
      decifrar(data.genero_enc), decifrar(data.etnia_enc), decifrar(data.orientacao_enc),
      decifrar(data.religiao_enc), decifrar(data.pcd_enc), decifrar(data.estado_civil_enc),
    ]);
    return {
      genero: g.data || '', etnia: e.data || '', orientacao: o.data || '',
      religiao: r.data || '', pcd: p.data || '', estadoCivil: ec.data || '',
    };
  } catch (e) { console.warn('carregarDiversidadeColab erro:', e); return null; }
}

async function salvarDiversidadeColab(colaboradorId, dados) {
  const sb = typeof window !== 'undefined' ? window.supabaseClient : null;
  if (!sb) return { ok: false, erro: 'Supabase nao conectado.' };
  try {
    const colabUuid = await _colabUuidDoUsuarioLogado(sb);
    if (!colabUuid) return { ok: false, erro: 'Sessao expirada ou auth_user_id nao linkado.' };
    // NAO destrutivo: so encripta os campos preenchidos. Campos vazios ficam de
    // FORA do payload pra preservar valor anterior no banco (em vez de zerar).
    const enc = async v => v ? (await sb.rpc('crypto_set', { plain: v })).data : null;
    const payload = { colaborador_id: colabUuid, consentido_em: new Date().toISOString() };
    if (dados.genero)       payload.genero_enc       = await enc(dados.genero);
    if (dados.etnia)        payload.etnia_enc        = await enc(dados.etnia);
    if (dados.orientacao)   payload.orientacao_enc   = await enc(dados.orientacao);
    if (dados.religiao)     payload.religiao_enc     = await enc(dados.religiao);
    if (dados.pcd)          payload.pcd_enc          = await enc(dados.pcd);
    if (dados.estadoCivil)  payload.estado_civil_enc = await enc(dados.estadoCivil);
    console.log('[diversidade] upsert payload (campos sensiveis encriptados):', Object.keys(payload));
    const { data, error } = await sb.from('diversidade').upsert(payload, { onConflict: 'colaborador_id' }).select();
    if (error) { console.warn('[diversidade] erro:', error); return { ok: false, erro: error.message }; }
    if (!data || data.length === 0) {
      console.warn('[diversidade] upsert sem erro mas 0 linhas - RLS UPDATE bloqueando? colab_id:', colabUuid);
      return { ok: false, erro: 'RLS bloqueou silenciosamente. Verificar policy de UPDATE em diversidade.' };
    }
    const count = CADASTRO_DIV_OBRIG.filter(k => (dados[k] || '').toString().trim()).length;
    try { localStorage.setItem(CADASTRO_DIV_COUNT_KEY(colaboradorId), String(count)); } catch {}
    return { ok: true };
  } catch (e) { return { ok: false, erro: e?.message || 'erro inesperado' }; }
}

// ── Helpers Supabase: dados_org (NAO sensivel, dual-write LS+Supabase) ──────
// Mapeamento de camelCase (frontend) -> snake_case (postgres). Inclui campos
// adicionados em supabase/008 e supabase/009. Campos do form que NAO existem
// no schema (salarioBruto, vt, plr, decimoTerceiro, receitaAnual) vao pra
// tabela 'remuneracao' separadamente - NAO entram aqui.

const DADOS_ORG_FRONT_TO_DB = {
  vinculo:           'vinculo',
  centroCusto:       'centro_custo',
  jornadaTrabalho:   'jornada_trabalho',
  horasMensais:      'horas_mensais',
  dataContratacao:   'data_contratacao',
  tipoMovimentacao:  'tipo_movimentacao',
  comentario:        'comentario',
  cargoLideranca:    'cargo_lideranca',
  cargoConfianca:    'cargo_confianca',
  pessoaGestora:     'pessoa_gestora',
  categoria:         'categoria', // formato canonico 'fixo'|'associado'
  tipoAssociado:     'tipo_associado',
  // Auto-cadastro Caju (SQL 010): campos pessoais
  dataNascimento:    'data_nascimento',
  telefone:          'telefone',
  endereco:          'endereco',
};
const DADOS_ORG_DB_TO_FRONT = Object.fromEntries(Object.entries(DADOS_ORG_FRONT_TO_DB).map(([f,d]) => [d,f]));

// Mapeia label do select <-> enum vinculo_tipo do Postgres ('clt','pj','estagio','aprendiz','determinado')
const VINCULO_LABEL_TO_ENUM = {
  'contrato clt': 'clt',
  'clt': 'clt',
  'contrato por tempo determinado': 'determinado',
  'determinado': 'determinado',
  'prestador de serviço': 'pj',
  'prestador de servico': 'pj',
  'pj': 'pj',
  'estágio': 'estagio',
  'estagio': 'estagio',
  'aprendiz': 'aprendiz',
};

// Normaliza pessoaGestora (array ou string) -> string e categoria (label ou {})
function _normalizarDadosOrgPraSupabase(dados) {
  const out = {};
  Object.entries(DADOS_ORG_FRONT_TO_DB).forEach(([frontKey, dbKey]) => {
    // tipoAssociado eh setado dentro do passo 'categoria'. Skip total pra evitar
    // sobrescrever com null quando dados.tipoAssociado vier undefined.
    if (frontKey === 'tipoAssociado') return;
    let v = dados[frontKey];
    if (v == null || v === '') { out[dbKey] = null; return; }
    if (frontKey === 'pessoaGestora') {
      v = Array.isArray(v) ? v.join(', ') : String(v);
    }
    if (frontKey === 'vinculo') {
      // Converter label da UI -> enum esperado pelo Postgres. Se nao reconhecer, manda null pra nao quebrar upsert.
      const e = VINCULO_LABEL_TO_ENUM[String(v).toLowerCase().trim()];
      out[dbKey] = e || null;
      if (!e) console.warn('[dados_org] vinculo nao mapeado:', v);
      return;
    }
    if (frontKey === 'categoria') {
      // Caminho 1: label da UI ('Fixo' / 'Associado Projetos' etc)
      const parsed = typeof parseCategoriaLabel === 'function' ? parseCategoriaLabel(v) : null;
      if (parsed) {
        out['categoria'] = parsed.categoria;
        out['tipo_associado'] = parsed.tipoAssociado;
        return;
      }
      // Caminho 2: valor ja canonico (lowercase). Pode vir do banco re-hidratado em LS.
      const vLower = String(v).toLowerCase().trim();
      if (vLower === 'fixo') {
        out['categoria'] = 'fixo'; out['tipo_associado'] = null; return;
      }
      if (vLower === 'associado') {
        out['categoria'] = 'associado';
        // tipoAssociado vem do draft separadamente. Se nao tiver, NAO grava categoria-incompleta.
        const tipo = dados.tipoAssociado ? String(dados.tipoAssociado).toLowerCase().trim() : null;
        if (['projetos','editais','vb','redes'].includes(tipo)) {
          out['tipo_associado'] = tipo;
        } else {
          console.warn('[dados_org] categoria=associado sem tipoAssociado valido - revertendo pra null pra forcar admin selecionar tipo.');
          out['categoria'] = null;
          out['tipo_associado'] = null;
        }
        return;
      }
      // Caminho 3: nada reconhecido
      console.warn('[dados_org] categoria nao reconhecida (esperado Fixo|Associado <tipo>):', v);
      out['categoria'] = null;
      out['tipo_associado'] = null;
      return;
    }
    // (tipoAssociado ja foi skipped no topo do forEach)
    if (frontKey === 'horasMensais') {
      const n = Number(v); if (!isNaN(n) && n > 0) out[dbKey] = Math.round(n); else out[dbKey] = null;
      return;
    }
    if (frontKey === 'dataContratacao' || frontKey === 'dataNascimento') {
      // Espera YYYY-MM-DD; se vier outro formato, pula
      out[dbKey] = /^\d{4}-\d{2}-\d{2}/.test(String(v)) ? String(v).slice(0,10) : null;
      return;
    }
    out[dbKey] = String(v);
  });
  return out;
}

function _normalizarDadosOrgDoSupabase(row) {
  if (!row) return {};
  const out = {};
  Object.entries(DADOS_ORG_DB_TO_FRONT).forEach(([dbKey, frontKey]) => {
    if (row[dbKey] == null) return;
    if (frontKey === 'categoria') {
      // categoria + tipo_associado viram label unico
      const cat = { categoria: row['categoria'], tipoAssociado: row['tipo_associado'] };
      out['categoria'] = typeof formatCategoriaLabel === 'function' ? formatCategoriaLabel(cat) : '';
      return;
    }
    if (frontKey === 'tipoAssociado') return; // tratado junto
    out[frontKey] = row[dbKey];
  });
  return out;
}

async function carregarDadosOrgSupabase(colaboradorId) {
  const sb = typeof window !== 'undefined' ? window.supabaseClient : null;
  if (!sb) return null;
  try {
    const { data: sess } = await sb.auth.getSession();
    if (!sess?.session) return null;
    const colabUuid = await _colabUuidDoUsuarioColab(sb, colaboradorId);
    if (!colabUuid) return null;
    const { data, error } = await sb.from('dados_org')
      .select('vinculo, centro_custo, jornada_trabalho, horas_mensais, data_contratacao, tipo_movimentacao, comentario, cargo_lideranca, cargo_confianca, pessoa_gestora, categoria, tipo_associado, data_nascimento, telefone, endereco')
      .eq('colaborador_id', colabUuid)
      .maybeSingle();
    if (error) { console.warn('carregarDadosOrgSupabase:', error.message); return null; }
    return _normalizarDadosOrgDoSupabase(data);
  } catch (e) { console.warn('carregarDadosOrgSupabase erro:', e); return null; }
}

async function salvarDadosOrgSupabase(colaboradorId, dados) {
  const sb = typeof window !== 'undefined' ? window.supabaseClient : null;
  if (!sb) return { ok: false, erro: 'Supabase nao conectado.' };
  try {
    const colabUuid = await _colabUuidDoUsuarioColab(sb, colaboradorId);
    if (!colabUuid) return { ok: false, erro: 'Nao achei UUID do colab (email do seed nao bate com colaboradores no banco?).' };
    const normalizado = _normalizarDadosOrgPraSupabase(dados);
    // Invariante: categoria='associado' SEMPRE precisa tipo_associado preenchido,
    // senao zera os 2 pra evitar estado parcial no banco.
    if (normalizado.categoria === 'associado' && !normalizado.tipo_associado) {
      console.warn('[dados_org] payload teria categoria=associado/tipo_associado=null - zerando ambos. draft:', dados.categoria, 'tipoAssociado:', dados.tipoAssociado);
      normalizado.categoria = null;
      normalizado.tipo_associado = null;
    }
    const payload = { colaborador_id: colabUuid, ...normalizado, updated_at: new Date().toISOString() };
    console.log('[dados_org] upsert payload:', payload);
    // .select() faz o upsert retornar as linhas afetadas - permite detectar caso "0 rows" silencioso por RLS.
    const { data, error } = await sb.from('dados_org').upsert(payload, { onConflict: 'colaborador_id' }).select();
    if (error) { console.warn('[dados_org] erro:', error); return { ok: false, erro: error.message }; }
    if (!data || data.length === 0) {
      console.warn('[dados_org] upsert sem erro mas 0 linhas afetadas - provavel RLS UPDATE bloqueando. Payload:', payload);
      return { ok: false, erro: 'RLS bloqueou silenciosamente (0 linhas). Verificar policy de UPDATE em dados_org.' };
    }
    console.log('[dados_org] sincronizado:', data);
    return { ok: true, data };
  } catch (e) { return { ok: false, erro: e?.message || 'erro inesperado' }; }
}

// Resolve UUID de um colab arbitrario. Aceita tanto id numerico do seed local
// (lookup via email->Supabase) quanto UUID direto (telas que ja leem do banco).
// IMPORTANTE: SEM fallback pra auth.uid - se nada bater, retorna null pra que
// o caller mostre erro claro. Sem isso, admin editando outra pessoa gravava na
// propria linha por engano.
const _UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
async function _colabUuidDoUsuarioColab(sb, colaboradorId) {
  try {
    // Caso 1: ja eh UUID (telas que leem do Supabase). Confirma que existe no banco.
    if (typeof colaboradorId === 'string' && _UUID_RE.test(colaboradorId)) {
      const { data, error } = await sb.from('colaboradores').select('id').eq('id', colaboradorId).maybeSingle();
      if (error) { console.warn('[dados_org] erro confirmando uuid:', colaboradorId, error.message); return null; }
      if (!data?.id) { console.warn('[dados_org] uuid', colaboradorId, 'nao existe em colaboradores no Supabase.'); return null; }
      return data.id;
    }
    // Caso 2: id numerico do seed local. Acha email -> busca no banco.
    const colabLocal = (typeof COLABORADORES !== 'undefined' && Array.isArray(COLABORADORES))
      ? COLABORADORES.find(c => c.id === Number(colaboradorId))
      : null;
    if (!colabLocal) {
      console.warn('[dados_org] colab id', colaboradorId, 'nao existe em COLABORADORES (seed local) e nao eh UUID valido.');
      return null;
    }
    const emailLocal = colabLocal.email ? String(colabLocal.email).toLowerCase().trim() : null;
    if (!emailLocal) {
      console.warn('[dados_org] colab id', colaboradorId, '(', colabLocal.nome, ') sem email no seed local.');
      return null;
    }
    const { data, error } = await sb.from('colaboradores').select('id, email').ilike('email', emailLocal).maybeSingle();
    if (error) { console.warn('[dados_org] erro buscando colab por email:', emailLocal, error.message); return null; }
    if (!data?.id) { console.warn('[dados_org] email', emailLocal, 'nao existe em colaboradores no Supabase.'); return null; }
    return data.id;
  } catch (e) { console.warn('[dados_org] _colabUuidDoUsuarioColab erro:', e); return null; }
}

// Resolve o UUID do colaborador logado (auth.uid -> colaboradores.id)
async function _colabUuidDoUsuarioLogado(sb) {
  try {
    const { data: sess } = await sb.auth.getSession();
    const authId = sess?.session?.user?.id;
    if (!authId) return null;
    const { data, error } = await sb.from('colaboradores').select('id').eq('auth_user_id', authId).maybeSingle();
    if (error || !data) return null;
    return data.id;
  } catch { return null; }
}

Object.assign(window, {
  CARGOS_CATALOGO_KEY, CARGOS_FAMILIAS_SEED, getCargosCatalogo, salvarCargosCatalogo, listarCargosComStep,
  SETORES, COLABORADORES, CONQUISTAS, HISTORICO_PROFISSIONAL,
  getConquistas, salvarConquistas, getHistorico, salvarHistorico,
  getCicloAvdAberto, abrirCicloAvd, fecharCicloAvd,
  getModoIntersetorial, setModoIntersetorial,
  getProgramasInter, salvarProgramaInter, removerProgramaInter, getProgramasInterAtivosPara,
  ESCALAB_EMAIL_FROM, ESCALAB_EMAIL_RH, ESCALAB_EMAIL_HOSTINGER, ESCALAB_EMAIL_ASSINATURA,
  enviarEmailEscalab, mailtoEscalab, escalabEmailEnvelope,
  getUsuariosCadastrados, cadastrarUsuario, autenticar, emailJaExiste,
  getUsuariosPendentes, aprovarUsuario, rejeitarUsuario,
  getDadosNovoColab, salvarDadosNovoColab,
  CATEGORIA_MAP, CATEGORIA_LABEL, getCategoriaColaborador, getCategoriaKey,
  parseCategoriaLabel, formatCategoriaLabel,
  getCadastroProgresso, salvarDocumentosColab, carregarDocumentosColab,
  salvarDiversidadeColab, carregarDiversidadeColab,
  carregarDadosOrgSupabase, salvarDadosOrgSupabase,
  SETOR_DESCRICAO, getCargoDisplay,
  FERIAS_INICIAL, getFeriasSolicitacoes, salvarFeriasSolicitacoes, addFeriasRequest, updateFeriasRequest,
  CICLOS, AVALIACOES, AVALIACOES_SETOR, FEEDBACKS, FEEDBACKS_TRIM,
  FEEDBACKS_SETOR_ATUAL, EVOLUCAO_HISTORICA, TEMPO_CARGO, BANCO_PERGUNTAS,
  getMediaSetor, getAvaliacoesColaborador, getFeedbacksColaborador,
  getNotasLiberadasIds, liberarNotasColaborador, bloquearNotasColaborador, isNotasLiberadas,
  setNotasLiberadasSupabase, fetchCiclosSupabase, fetchAvaliacoesSupabase,
  syncNotasLiberadasFromSupabase,
  atualizarColaborador, getFoto, salvarFoto,
  SECOES_ASSINATURA, DOCS_ADMISSAO, getDadosAssinatura, salvarDadosAssinatura,
  GENERO_OPCOES, ORIENTACAO_OPCOES,
  mesesParaTempo,
  getColaboradoresVisiveis,
  MOTIVOS_DESLIGAMENTO, DESLIG_ETAPAS, checklistVazio, direitosVazios,
  getDesligamentos, salvarDesligamento, atualizarDesligamento, getDesligamentoPorColaborador,
  getIdsDesligados, isDesligado, getColaboradoresAtivos, reativarColaborador, gerarIdDeslig,
  getCamposDesligForm, salvarCamposDesligForm,
  getMotivosDeslig, salvarMotivosDeslig, getMotivoDeslig,
  ADMISSOES_DEMO, getDataAdmissao, DESLIGAMENTOS_DEMO,
  MOVIMENTACOES, MOV_TIPOS, NIVEL_LABEL,
  ANIVERSARIOS, getAniversariantesDoMes,
  getSalario, medianaArr,
  PAGINAS_APP, getPaginasBloqueadas, setPaginasBloqueadas, togglePaginaBloqueada, paginaPermitida,
  MOV_ETAPAS, MOV_LABEL, MOV_FORM_DEF,
  getMovSolicitacoes, salvarMovSolicitacao, removerMovSolicitacao, gerarIdMov, criarMovDesligamentoAuto,
  NOVIDADE_TIPOS_CAMPO,
  getNovidades, salvarNovidade, removerNovidade, gerarIdNovidade,
  getNovidadesVistas, marcarNovidadeVista, resetarNovidadesVistas, getNovidadesPendentes,
  lerArquivoBase64, formatarTamanho, ARQUIVO_MAX_BYTES,
  // Banco de horas (Site AVD 12)
  HORAS_KEY, HORAS_JORNADA_PADRAO, HORAS_JORNADA_SEMANAL, FERIADOS_BR,
  isFeriado, isFds, getTipoDiaColaborador,
  getRegistrosHoras, getRegistroHoraDia, salvarRegistroHora, removerRegistroHora,
  getHorasDia, getSaldoDia, getBancoHoras, getJornadaDia,
  getHorasColabMes, getHorasSetorMes, fmtHoras,
  // Indicadores financeiros anuais + custo de contratação (PDF Site AVD (2))
  INDIC_FIN_KEY, INDIC_FIN_SEED, getIndicadoresFinanceiros, salvarIndicadoresFinanceiros,
  upsertIndicadorFinanceiro, removerIndicadorFinanceiro,
  CONFIG_RH_KEY, CONFIG_RH_DEFAULT, getConfigRh, salvarConfigRh, calcularCustoContratacao,
});

// ── Filtro de visibilidade por perfil ────────────────────────────────────────

function getColaboradoresVisiveis(user) {
  if (!user) return COLABORADORES;
  if (user.perfil === 'admin' || user.perfil === 'financeiro') return COLABORADORES;
  if (user.perfil === 'gestor') {
    const liderados = COLABORADORES.filter(c => c.gestorNome === user.nome);
    const meuLider  = COLABORADORES.find(c => c.nome === user.gestorNome);
    const ids = new Set([user.id, ...liderados.map(c => c.id), ...(meuLider ? [meuLider.id] : [])]);
    return COLABORADORES.filter(c => ids.has(c.id));
  }
  return COLABORADORES.filter(c => c.id === user.id);
}

// Expor no window (declarado após o Object.assign original para sobrescrever)
window.getColaboradoresVisiveis = getColaboradoresVisiveis;

// ═══════════════════════════════════════════════════════════════════════════════
// SEED MASSIVO · popula dados organizacionais, diversidade, "sobre mim" e
// programas intersetoriais para TODOS os colaboradores. Garante que o
// painel/dashboard e o perfil de cada pessoa tenham conteúdo de exemplo.
// Marcado com flag para rodar apenas uma vez por navegador.
// ═══════════════════════════════════════════════════════════════════════════════

const SEED_FLAG_KEY = 'escalab_seed_demo_v5';

(function _seedDemoCompleto() {
  try {
    if (localStorage.getItem(SEED_FLAG_KEY) === 'ok') return;

    // · Distribuição de gênero/etnia/etc. para 43 colabs (consistente c/ CENSO_DADOS 2026)
    // Determinístico via id: same id → same data sempre.
    const GENEROS    = ['Mulher cisgênero','Homem Cisgênero','Mulher Transgênero','Homem Transgênero','Não-binário','Gênero fluido','Prefiro não declarar'];
    const ETNIAS     = ['Branca','Parda','Preta','Amarela','Indígena','Prefiro não declarar'];
    const ORIENTACAO = ['Heterossexual','Homossexual','Bissexual','Assexual','Prefiro não me classificar','Prefiro não declarar'];
    const RELIGIAO   = ['Sem religião','Católica','Evangélica','Espírita','Umbanda/Candomblé','Prefiro não declarar'];
    const ESTADO_CIVIL = ['Solteiro(a)','Casado(a)','União estável','Solteiro(a)','Solteiro(a)','Divorciado(a)','Prefiro não declarar'];
    const DEFICIENCIA  = ['Não possuo','Não possuo','Não possuo','Não possuo','Não possuo','Não possuo','Não possuo','Não possuo','Não possuo','Visual','Auditiva','Prefiro não declarar'];
    const JORNADA      = ['Híbrida','Híbrida','Híbrida','Presencial','Remota'];
    const VINCULOS     = { fixo: 'Contrato CLT', associado: 'Prestador de serviço' };

    // Genero mapeado por nome (heurística simples pra coerência visual)
    function generoPorNome(nome) {
      const primeiro = (nome || '').split(' ')[0].toLowerCase();
      // Termina em "a" → costuma ser feminino (heurística PT-BR, com exceções tratadas)
      const masc_a = new Set(['barnaba','baba','akira','akira']);
      if (masc_a.has(primeiro)) return 'Homem Cisgênero';
      const femExc = new Set(['hiago','hugo','rafael','daniel','andré','andre']);
      if (femExc.has(primeiro)) return 'Homem Cisgênero';
      if (primeiro.endsWith('a') || primeiro.endsWith('e') || primeiro.endsWith('ah')) return 'Mulher cisgênero';
      return 'Homem Cisgênero';
    }
    // Hash determinístico por id
    function pickByHash(arr, id, salt) {
      return arr[(id * 1009 + (salt || 0)) % arr.length];
    }

    // Data de nascimento → idade entre 22 e 48, depende do nível
    function dataNascimentoPara(c) {
      const baseAnos = c.nivel === 'diretor' ? 42
        : c.nivel === 'lider' ? 34
        : 27;
      const variacao = ((c.id * 31) % 9) - 4; // -4 a +4
      const ano = new Date().getFullYear() - (baseAnos + variacao);
      const mes = ((c.id * 7) % 12) + 1;
      const dia = ((c.id * 13) % 27) + 1;
      return `${ano}-${String(mes).padStart(2,'0')}-${String(dia).padStart(2,'0')}`;
    }

    // Data de contratação a partir do tempoEmpresa em meses
    function dataContratacaoPara(c) {
      const hoje = new Date();
      hoje.setDate(15);
      hoje.setMonth(hoje.getMonth() - (c.tempoEmpresa || 0));
      return hoje.toISOString().slice(0,10);
    }

    // · Bios curtas (Sobre Mim + Faz no Escalab) por id, fallback genérico
    const SOBRE_TEMPLATES = [
      { sobre: 'Apaixonado(a) por café, corrida ao ar livre e bons livros de não-ficção. Curto cozinhar nos fins de semana e tô sempre testando um pão novo.', faz: 'Atuo direto na execução do dia a dia da equipe, com foco em entregas de qualidade e melhoria contínua dos processos da nossa área.' },
      { sobre: 'Mãe/pai, viciado(a) em séries de detetive, fã de música ao vivo. Acordo cedo pra meditar antes do trabalho.', faz: 'Faço a ponte entre time técnico e clientes/stakeholders. Cuido de prazos, alinhamentos e qualidade das entregas.' },
      { sobre: 'Curto trilha, fotografia analógica e bichos. Tenho dois cachorros que aparecem em toda reunião por vídeo.', faz: 'Lidero iniciativas estratégicas dentro da área. Foco em desenvolver o time e garantir resultados sustentáveis.' },
      { sobre: 'Estudo idiomas no tempo livre (no momento, francês). Gosto de escrever, ouvir podcast de história e maratonar filme antigo.', faz: 'Sou a referência técnica do time. Apoio nas decisões críticas e na evolução do conhecimento coletivo.' },
      { sobre: 'Skatista nas horas vagas, faço aulas de violão e tô aprendendo a fazer cerâmica. Curto mato e silêncio.', faz: 'Toco projetos de ponta a ponta · do levantamento de requisitos até a entrega final. Foco em qualidade e prazo.' },
      { sobre: 'Boardgame addict, fã de FPL e fotografia urbana. Já viajei sozinho(a) por 6 países da América do Sul.', faz: 'Cuido das relações com associados e parceiros. Acompanho contratos, prazos e entregas alinhadas aos projetos.' },
      { sobre: 'Adoro plantas e tenho mais de 30 espécies em casa. Pratico crossfit 4x por semana e tô sempre buscando um novo café especial.', faz: 'Faço o operacional acontecer. Cuido de documentação, controles e suporte ao time.' },
    ];

    COLABORADORES.forEach((c, idx) => {
      // ── 1. dados_org ────────────────────────────────────────────────────
      const dadosOrgKey = `escalab_dados_org_${c.id}`;
      if (!localStorage.getItem(dadosOrgKey)) {
        const cat = getCategoriaColaborador(c.id);
        const isLideranca = ['diretor','lider'].includes(c.nivel);
        const salario = getSalario(c);
        // VT/13º/PLR · só pra fixos (associados não têm carteira assinada)
        const isFixo = cat.categoria === 'fixo';
        const vt = isFixo ? '200' : '';
        const decimoTerceiro = isFixo ? String(salario) : '';
        // PLR: 2 salários para diretor, 1.5 para líder, 1 para liderado
        const plrMult = isFixo ? (c.nivel === 'diretor' ? 2 : c.nivel === 'lider' ? 1.5 : 1) : 0;
        const plr = isFixo ? String(Math.round(salario * plrMult)) : '';
        // Receita gerada anual: só pra setores comerciais/produtivos
        const setoresComerciais = ['Prospecção','VB','Marketing e Leads','PMO','P&D e Escalonamento','Associados de Projetos','Associados e Editais','NNE & EVT'];
        const setorComercial = setoresComerciais.includes(c.setor);
        const receitaBase = c.nivel === 'diretor' ? 320_000
          : c.nivel === 'lider' ? 180_000
          : 95_000;
        const receitaVar = ((c.id * 53) % 40_000);
        const receitaAnual = setorComercial ? String(receitaBase + receitaVar) : '';
        const dados = {
          vinculo: VINCULOS[cat.categoria] || 'Contrato CLT',
          cargo: c.cargo,
          cargoLideranca: isLideranca ? 'Sim' : 'Não',
          cargoConfianca: c.nivel === 'diretor' ? 'Sim' : 'Não',
          pessoaGestora: c.gestorNome || '',
          departamento: c.setor,
          centroCusto: 'CC-' + String(c.id).padStart(3,'0'),
          salarioBruto: `R$ ${salario.toLocaleString('pt-BR')},00`,
          vt,
          decimoTerceiro,
          plr,
          receitaAnual,
          jornadaTrabalho: pickByHash(JORNADA, c.id, 3),
          horasMensais: cat.categoria === 'associado' ? '120' : '176',
          dataContratacao: dataContratacaoPara(c),
          dataNascimento: dataNascimentoPara(c),
          tipoMovimentacao: 'Admissão',
          comentario: '',
        };
        localStorage.setItem(dadosOrgKey, JSON.stringify(dados));
      }

      // ── 2. diversidade ──────────────────────────────────────────────────
      const divKey = `escalab_diversidade_${c.id}`;
      if (!localStorage.getItem(divKey)) {
        const genero = generoPorNome(c.nome);
        const div = {
          genero,
          estadoCivil: pickByHash(ESTADO_CIVIL, c.id, 11),
          etnia: pickByHash(ETNIAS, c.id, 17),
          orientacao: pickByHash(ORIENTACAO, c.id, 23),
          religiao: pickByHash(RELIGIAO, c.id, 29),
          deficiencia: pickByHash(DEFICIENCIA, c.id, 31),
        };
        localStorage.setItem(divKey, JSON.stringify(div));
      }

      // ── 3. sobre mim + faz no escalab ───────────────────────────────────
      const sobreKey = `escalab_sobre_${c.id}`;
      if (!localStorage.getItem(sobreKey)) {
        const tpl = SOBRE_TEMPLATES[idx % SOBRE_TEMPLATES.length];
        localStorage.setItem(sobreKey, JSON.stringify({
          sobreMim: tpl.sobre,
          fazNoEscalab: tpl.faz,
        }));
      }
    });

    // ── 4. Programas intersetoriais (2 programas-exemplo, modo "livre") ────
    const INTER_KEY = 'escalab_inter_programas';
    if (!localStorage.getItem(INTER_KEY)) {
      const hoje = new Date(); const f30 = new Date(); f30.setDate(f30.getDate()+45);
      const programas = [
        { id:'PRG001', titulo:'Mentorias Cruzadas 2026', descricao:'Conecte-se com alguém de outro setor pra troca de experiências. Encontros quinzenais de 30 min.', setores:['Marketing e Leads','P&D e Escalonamento','PMO','Gente e Cultura'], ativo:true, prazoFim: f30.toISOString().slice(0,10), criadoEm: hoje.toISOString().slice(0,10), inscritos: 14 },
        { id:'PRG002', titulo:'Hackathon Interno · Inovação aplicada', descricao:'Times multidisciplinares montam protótipos em 48h pra um desafio da diretoria. Inscrições abertas.', setores: SETORES.slice(0,8), ativo:true, prazoFim: f30.toISOString().slice(0,10), criadoEm: hoje.toISOString().slice(0,10), inscritos: 22 },
      ];
      localStorage.setItem(INTER_KEY, JSON.stringify(programas));
    }

    // ── 4b. Chamadas (presença) dos treinamentos concluídos ────────────────
    // Dashboard + perfil consomem escalab_chamadas: { [treinoId]: { [colabId]: true|false } }
    // Dados REAIS extraídos pelo scripts/gerar_presencas_reais.js a partir de
    // "Documentos Treinamento/Treinamentos/{2025,2026}/2- [ANO] LISTA DE PRESENÇA.xlsx".
    // Resumo: 11 treinos, 163 presenças, 75 ausências (238 marcações totais).
    const CHAMADAS_KEY = 'escalab_chamadas';
    // Versionamento: bump CHAMADAS_VER quando os dados mudam pra forçar refresh
    // (evita ficar com dados sintéticos antigos no LS dos colabs que ja usaram a v1).
    const CHAMADAS_VER = '2';
    const CHAMADAS_VER_KEY = 'escalab_chamadas_ver';
    if (localStorage.getItem(CHAMADAS_VER_KEY) !== CHAMADAS_VER || !localStorage.getItem(CHAMADAS_KEY)) {
      const chamadas = {
        'TR001': { 1: true, 2: true, 3: false, 4: true, 5: false, 6: false, 8: true, 11: true, 14: false, 18: true, 19: true, 20: true, 22: false, 27: true, 28: true, 29: true, 30: true, 31: true, 33: true, 35: true, 40: true, 41: false, 44: true, 46: true },
        'TR002': { 1: false, 2: true, 3: false, 4: true, 5: true, 6: false, 8: true, 11: false, 14: false, 18: true, 19: false, 20: true, 22: false, 27: true, 28: true, 29: false, 30: true, 31: true, 33: true, 35: false, 40: true, 41: false, 44: false, 46: true },
        'TR003': { 1: true, 2: true, 3: false, 4: true, 5: true, 6: true, 8: false, 11: false, 14: false, 18: true, 19: true, 20: false, 22: true, 27: true, 28: true, 29: true, 30: true, 31: false, 33: true, 35: true, 40: true, 41: false, 44: false, 46: true },
        'TR004': { 1: false, 2: true, 3: false, 4: true, 5: true, 6: true, 8: true, 11: false, 14: false, 18: false, 19: true, 20: false, 22: true, 27: true, 28: false, 29: false, 30: true, 31: true, 33: true, 35: false, 40: true, 41: false, 44: false, 46: true },
        'TR005': { 1: true, 2: true, 3: false, 4: true, 5: true, 6: true, 8: false, 11: false, 14: false, 18: false, 19: true, 20: true, 22: true, 27: false, 28: true, 29: false, 30: true, 31: true, 33: true, 35: true, 40: false, 41: false, 44: true, 46: true },
        'TR006': { 1: false, 2: true, 3: false, 4: true, 5: true, 6: true, 8: true, 11: true, 14: false, 18: true, 19: true, 20: true, 22: true, 27: true, 28: true, 29: false, 30: true, 31: true, 33: true, 35: false, 40: true, 41: false, 44: true, 46: true },
        'TR007': { 1: true, 2: true, 3: false, 4: false, 5: true, 6: false, 8: true, 11: false, 14: false, 18: true, 19: true, 20: true, 22: false, 27: true, 28: true, 29: false, 30: true, 31: false, 33: true, 35: true, 40: true, 41: false, 44: false, 46: false },
        'TR009': { 1: true, 2: false, 3: true, 4: true, 5: true, 6: false, 8: true, 11: false, 14: true, 18: true, 19: false, 20: true, 22: true, 27: true, 28: true, 29: false, 30: true, 31: false, 33: true, 35: true, 40: false, 41: true, 44: false, 46: true },
        'TR013': { 6: true, 18: true, 22: true, 27: true, 28: true, 29: false, 31: true, 33: true, 35: true, 40: true, 46: true },
        'TR014': { 1: true, 6: true, 8: true, 15: true, 18: true, 19: true, 20: false, 22: true, 27: true, 28: true, 29: false, 30: true, 31: true, 33: true, 35: true, 40: true, 46: true },
        'TR015': { 1: true, 6: true, 8: true, 15: true, 18: true, 19: true, 20: false, 22: false, 27: true, 28: true, 29: true, 30: true, 31: true, 33: true, 35: true, 39: true, 40: true, 46: true },
      };
      localStorage.setItem(CHAMADAS_KEY, JSON.stringify(chamadas));
      localStorage.setItem(CHAMADAS_VER_KEY, CHAMADAS_VER);
    }

    // ── 4c. Respostas PCO 2026 (anônimas, p/ histograma do dashboard) ──────
    const PCO_RESP_KEY = 'escalab_pco_respostas';
    if (!localStorage.getItem(PCO_RESP_KEY)) {
      const respostas = [];
      // 32 dos 43 responderam a PCO 2026 (média ~74%)
      const respondentes = COLABORADORES.filter((_,i) => i % 4 !== 0).slice(0, 32);
      respondentes.forEach((c, idx) => {
        // Cada resposta tem id por dimensão (dim0..dim7), nota 3-5 com tendência positiva
        const dims = {};
        for (let d = 0; d < 8; d++) {
          // Algumas perguntas por dimensão · apenas a primeira é o suficiente p/ médias
          for (let p = 0; p < 3; p++) {
            const seed = (c.id * 7 + d * 11 + p * 17 + idx) % 100;
            const nota = seed < 8 ? 2 : seed < 30 ? 3 : seed < 65 ? 4 : 5;
            dims[`dim${d}_p${p}`] = nota;
          }
        }
        respostas.push({
          id: `PR_2026_${c.id}`,
          pcoId: 'pco_hist_2026',
          colaboradorId: c.id,
          respostas: dims,
          enviadaEm: '2026-03-' + String(((idx % 28) + 1)).padStart(2,'0') + 'T10:00:00',
        });
      });
      localStorage.setItem(PCO_RESP_KEY, JSON.stringify(respostas));
    }

    // ── 4d. Respostas das pesquisas de Infraestrutura (2024 + 2025) ───────
    // Painel da Visão Executiva consome essas notas pra gráfico anual.
    const OP_RESP_KEY = 'escalab_op_respostas';
    try {
      const opResp = JSON.parse(localStorage.getItem(OP_RESP_KEY) || '[]');
      const jaTemInfra = opResp.some(r => r.pesquisaId === 'OP_INFRA_2025' || r.pesquisaId === 'OP_INFRA_2024');
      if (!jaTemInfra) {
        const novas = [];
        // 2025: ~35 respondentes; nota média ~7.2
        COLABORADORES.filter((_,i) => i % 5 !== 0).slice(0, 35).forEach((c, i) => {
          const r = {};
          ['Q1','Q2','Q3','Q4'].forEach((q, qi) => {
            const seed = (c.id * 11 + qi * 17 + i) % 100;
            // distribuição 6-9 com tendência positiva
            r[q] = seed < 10 ? 5 : seed < 25 ? 6 : seed < 50 ? 7 : seed < 80 ? 8 : 9;
          });
          r['Q5'] = '';
          novas.push({
            id: `OPR_INFRA25_${c.id}`, pesquisaId: 'OP_INFRA_2025',
            colaboradorId: null, respostas: r,
            enviadaEm: `2025-12-${String((i % 28) + 1).padStart(2,'0')}T11:00:00`,
          });
        });
        // 2024: ~28 respondentes; nota média ~6.8
        COLABORADORES.filter((_,i) => i % 6 !== 0).slice(0, 28).forEach((c, i) => {
          const r = {};
          ['Q1','Q2','Q3','Q4'].forEach((q, qi) => {
            const seed = (c.id * 13 + qi * 19 + i) % 100;
            r[q] = seed < 15 ? 5 : seed < 35 ? 6 : seed < 65 ? 7 : seed < 85 ? 8 : 9;
          });
          novas.push({
            id: `OPR_INFRA24_${c.id}`, pesquisaId: 'OP_INFRA_2024',
            colaboradorId: null, respostas: r,
            enviadaEm: `2024-12-${String((i % 28) + 1).padStart(2,'0')}T11:00:00`,
          });
        });
        // Acidentes graves: 3 registros fictícios (1 grave + 2 leves)
        novas.push({
          id: 'OPR_ACID_001', pesquisaId: 'OP_ACIDENTES_GRAVES',
          colaboradorId: null,
          respostas: { Q1: 'Colaborador anônimo (Logística)', Q2: '2026-02-14', Q3: 'Trânsito (deslocamento a trabalho)', Q4: 'Moderada', Q5: '5', Q6: 'Acidente leve a caminho de visita a cliente. Sem sequelas; afastamento de 5 dias.' },
          enviadaEm: '2026-02-15T09:00:00',
        });
        novas.push({
          id: 'OPR_ACID_002', pesquisaId: 'OP_ACIDENTES_GRAVES',
          colaboradorId: null,
          respostas: { Q1: 'Colaborador anônimo (Operações)', Q2: '2026-04-22', Q3: 'Esforço repetitivo', Q4: 'Leve com afastamento', Q5: '3', Q6: 'LER. Encaminhado para fisioterapia e ajuste ergonômico no posto de trabalho.' },
          enviadaEm: '2026-04-23T10:30:00',
        });
        localStorage.setItem(OP_RESP_KEY, JSON.stringify(opResp.concat(novas)));
      }
    } catch {}

    // ── 5. Conquistas para colabs sem entry ──────────────────────────────
    const CONQUISTAS_DEMO = {
      6:  [{ ano: 2025, texto: 'Liderou rollout do programa de retenção de clientes-chave' }, { ano: 2024, texto: 'Estruturou processo de NPS pós-entrega' }],
      8:  [{ ano: 2025, texto: 'Reduziu reclamações pós-projeto em 28% com playbook próprio' }],
      11: [{ ano: 2024, texto: 'Captou 4 novos projetos via EVT no semestre' }],
      14: [{ ano: 2025, texto: 'Triplicou volume de leads MQL em 6 meses' }, { ano: 2024, texto: 'Lançou nova landing page com 22% de conversão' }],
      16: [{ ano: 2025, texto: 'Identidade visual da plataforma AVD desenhada do zero' }],
      18: [{ ano: 2024, texto: 'Refez pipeline de prospecção, aumentando reuniões em 60%' }],
      40: [{ ano: 2025, texto: 'Implementou novo fluxo administrativo-financeiro' }],
    };
    const HISTORICO_DEMO = {
      6:  [{ data: '2024-04', evento: 'Promovida a Líder/Especialista III' }, { data: '2022-08', evento: 'Ingresso como Líder/Especialista II' }],
      8:  [{ data: '2024-01', evento: 'Promovido a Líder/Especialista II em Fidelização' }],
      11: [{ data: '2022-05', evento: 'Promovida a Líder/Especialista I em EVT' }],
      14: [{ data: '2024-10', evento: 'Promovido a Analista III' }, { data: '2023-02', evento: 'Ingresso como Analista II' }],
      16: [{ data: '2025-06', evento: 'Promovida a Analista II' }],
      18: [{ data: '2022-09', evento: 'Promovida a Analista III' }],
    };
    try {
      const cqMap = JSON.parse(localStorage.getItem('escalab_conquistas') || '{}');
      const hsMap = JSON.parse(localStorage.getItem('escalab_historico') || '{}');
      Object.entries(CONQUISTAS_DEMO).forEach(([id, arr]) => { if (!cqMap[id]) cqMap[id] = arr; });
      Object.entries(HISTORICO_DEMO).forEach(([id, arr]) => { if (!hsMap[id]) hsMap[id] = arr; });
      localStorage.setItem('escalab_conquistas', JSON.stringify(cqMap));
      localStorage.setItem('escalab_historico', JSON.stringify(hsMap));
    } catch {}

    localStorage.setItem(SEED_FLAG_KEY, 'ok');
  } catch (e) {
    console.warn('Seed demo falhou:', e);
  }
})();
