Version UX Pilot design refs and map them to roadmap plans

Add the 11 UX Pilot design pairs (.png + .html) under
docs/design-refs/latest/ and link each to its roadmap item and plan.
Record the decision that UX/structure is the reference but the old
palette is not — implementation uses the light campaign theme tokens.
This commit is contained in:
Francisco Ignácio Fontoura Solla 2026-07-18 16:36:09 -03:00
parent 9c338b2d28
commit b0c86cf8e3
38 changed files with 3949 additions and 1 deletions

View file

@ -26,6 +26,7 @@ alwaysApply: false
- Em 2026-07-17, a Refactor Phase 4A consolidou as dez migrations locais não publicadas de `20260717_*` em `20260718_010733_consolidate_campaign_schema`, mantendo intacta a história rastreada até `20260716_010420_add_campaign_user`; os bancos locais foram reconciliados sem alterar dados de aplicação.
- Em 2026-07-18, o follow-up Phase 4C fixou o Playwright em dois workers por padrão, adicionou guardas automáticos de erros do navegador/console/5xx, fortaleceu privacidade HTML+Flight por papel e tornou o login por teclado uma interação real com Enter e cookie verificado.
- Em 2026-07-18, a projeção do dashboard omite `supportStatus` ausente por redação de acesso e lança invariante genérico se um valor não-vazio inválido chegar à fronteira; agregação e badge são exaustivos no enum.
- Em 2026-07-18, os designs UX Pilot dos próximos ciclos foram versionados em `docs/design-refs/latest/` (11 pares `.png`+`.html`) e mapeados aos itens do roadmap — tabela "Referências de design (UX Pilot)" em `docs/roadmap.md`, com seção "Referência visual (UX Pilot)" em cada plano. Decisão: a UX/estrutura dos designs é a referência; a paleta NÃO — os arquivos vieram na paleta antiga (vermelho escuro/navy/dourado) e toda implementação usa os tokens claros do tema `data-theme='campaign'`. Sem design nesta leva: dobradinha, mapa, demandas, detalhe do plano de ação, opt-in de push e fill-ins.
## Decisões

View file

@ -0,0 +1,278 @@
<!doctype html>
<html lang="pt-BR">
<head>
<script>
window.FontAwesomeConfig = {
autoReplaceSvg: 'nest',
}
</script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js"
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Ficha do Apoiador</title>
<script src="https://cdn.tailwindcss.com"></script>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css"
/>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#8E0E23',
'primary-light': '#B01C35',
'primary-xlight': '#F9E8EB',
gold: '#C8874B',
'gold-light': '#FDF3EC',
navy: '#1B2B4B',
wa: '#25D366',
},
},
},
}
</script>
<style>
body {
font-family: 'Inter', system-ui, sans-serif;
}
.seg-btn {
transition: all 0.15s;
}
.seg-btn.active {
background: #8e0e23;
color: white;
}
</style>
</head>
<body class="bg-gray-50 pb-28">
<!-- Header -->
<header id="header" class="bg-primary sticky top-0 z-20 px-4 py-3 flex items-center gap-3">
<button class="text-white p-1"><i class="fa-solid fa-arrow-left text-lg"></i></button>
<div class="flex-1 min-w-0">
<h1 class="text-white font-bold text-sm truncate">Maria das Dores Souza</h1>
<p class="text-white/60 text-xs">Apoiadora · Bom Jesus da Lapa</p>
</div>
<button class="text-white/70 p-1.5"><i class="fa-solid fa-ellipsis-vertical"></i></button>
</header>
<!-- Scope badge -->
<div class="px-4 pt-3 pb-1">
<span
class="inline-flex items-center gap-1.5 bg-gold-light border border-gold/30 text-xs font-semibold text-navy px-3 py-1.5 rounded-full"
>
<i class="fa-solid fa-shield-halved text-gold text-xs"></i> Coordenação Geral
</span>
</div>
<!-- Avatar + intent badge -->
<div
class="mx-4 mt-3 mb-3 bg-white border border-gray-200 rounded-2xl shadow-sm p-4 flex items-center gap-4"
>
<img
src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-6.jpg"
class="w-16 h-16 rounded-full object-cover border-2 border-primary/20 flex-shrink-0"
/>
<div class="flex-1 min-w-0">
<h2 class="text-base font-bold text-navy">Maria das Dores Souza</h2>
<p class="text-xs text-gray-500 mt-0.5">Cadastrada em 10/07/2025 · por João S.</p>
<div class="flex items-center gap-2 mt-2">
<span class="bg-green-100 text-green-800 text-xs font-bold px-2.5 py-1 rounded-full"
>Certo</span
>
<span class="text-xs text-gray-400">intenção de voto</span>
</div>
</div>
</div>
<div class="px-4 space-y-4">
<!-- Contato -->
<div class="bg-white border border-gray-200 rounded-xl shadow-sm p-4 space-y-3">
<p class="text-xs font-semibold text-gray-500 uppercase tracking-wide">Dados de contato</p>
<div class="flex items-center justify-between">
<div class="flex items-center gap-2 text-sm text-navy">
<i class="fa-solid fa-phone text-gray-400 w-4 text-center"></i>
<span>(77) 9 9000-1111</span>
</div>
<button
class="flex items-center gap-1.5 bg-wa text-white text-xs font-bold px-3 py-1.5 rounded-lg"
>
<i class="fa-brands fa-whatsapp text-sm"></i> WhatsApp
</button>
</div>
<div class="flex items-center gap-2 text-sm text-navy border-t border-gray-100 pt-3">
<i class="fa-solid fa-location-dot text-gray-400 w-4 text-center"></i>
<div>
<p class="font-semibold">Bom Jesus da Lapa</p>
<p class="text-xs text-gray-500">Bahia · Velho Chico</p>
</div>
</div>
<!-- Núcleo vinculado -->
<div class="flex items-center justify-between border-t border-gray-100 pt-3">
<div class="flex items-center gap-2 text-sm text-navy">
<i class="fa-solid fa-layer-group text-gray-400 w-4 text-center"></i>
<span class="text-primary font-semibold">Quilombo Rio das Rãs</span>
</div>
<button
class="text-xs text-gray-500 border border-gray-200 rounded-lg px-2.5 py-1 hover:border-primary hover:text-primary transition-colors"
>
Mudar
</button>
</div>
</div>
<!-- ══════════════════════════════════════════ -->
<!-- LGPD CONSENT BLOCK — visually distinct -->
<!-- ══════════════════════════════════════════ -->
<div id="lgpd-block" class="bg-blue-50 border-2 border-blue-200 rounded-xl p-4 space-y-3">
<div class="flex items-start gap-2">
<i class="fa-solid fa-shield text-blue-500 text-base mt-0.5 flex-shrink-0"></i>
<div>
<p class="text-sm font-bold text-blue-800">Consentimento LGPD</p>
<p class="text-xs text-blue-600 mt-0.5">
O apoiador deve ter consentido previamente o uso de seus dados para fins eleitorais.
</p>
</div>
</div>
<label class="flex items-start gap-3 cursor-pointer">
<input
type="checkbox"
checked
class="w-5 h-5 mt-0.5 rounded accent-blue-600 flex-shrink-0"
/>
<p class="text-xs text-blue-800">
Confirmo que <strong>Maria das Dores Souza</strong> consentiu o uso de seus dados
pessoais para comunicação da campanha de <strong>Jorge Solla</strong>, conforme a
<span class="underline cursor-pointer">Política de Privacidade</span>.
</p>
</label>
<p class="text-xs text-blue-500 flex items-center gap-1">
<i class="fa-solid fa-circle-info text-xs"></i>
Consentimento registrado em 10/07/2025 · Coletor: João Santos
</p>
</div>
<!-- Intenção de voto — segmented control (gated by LGPD) -->
<div class="bg-white border border-gray-200 rounded-xl shadow-sm p-4 space-y-3">
<p class="text-xs font-semibold text-gray-500 uppercase tracking-wide">Intenção de voto</p>
<div class="grid grid-cols-2 gap-2">
<button
class="seg-btn active text-xs font-bold py-3 rounded-xl border border-primary bg-primary text-white"
>
Certo
</button>
<button
class="seg-btn text-xs font-bold py-3 rounded-xl border border-gray-200 text-gray-600 bg-gray-50"
>
Tende a certo
</button>
<button
class="seg-btn text-xs font-bold py-3 rounded-xl border border-gray-200 text-gray-600 bg-gray-50"
>
Indeciso
</button>
<button
class="seg-btn text-xs font-bold py-3 rounded-xl border border-gray-200 text-gray-600 bg-gray-50"
>
Outro
</button>
</div>
<p class="text-xs text-gray-400">
Disponível somente após confirmação do consentimento LGPD
</p>
</div>
<!-- Kit de compartilhamento -->
<div
id="kit-compartilhamento"
class="bg-white border border-gray-200 rounded-xl shadow-sm p-4 space-y-3"
>
<p
class="text-xs font-semibold text-gray-500 uppercase tracking-wide flex items-center gap-2"
>
<i class="fa-solid fa-share-nodes text-primary text-sm"></i>
Kit de compartilhamento
</p>
<p class="text-xs text-gray-600">
Mensagem pronta para <strong>Maria</strong> encaminhar nos próprios contatos.
<em>Nunca disparada pela campanha.</em>
</p>
<!-- Ready-made message -->
<div class="bg-gray-50 border border-gray-200 rounded-xl p-3">
<p class="text-xs text-gray-700 leading-relaxed">
"Oi! Tô apoiando <strong>Jorge Solla</strong> para Deputado Federal pela Bahia. Ele tem
um histórico de luta pela saúde e pelos direitos da nossa comunidade. Se você ainda não
decidiu, vale conhecer o trabalho dele! 🌟 <br />solla.ba"
</p>
</div>
<!-- Action buttons -->
<div class="grid grid-cols-2 gap-2">
<button
class="flex items-center justify-center gap-2 bg-wa text-white text-xs font-bold py-3 rounded-xl"
>
<i class="fa-brands fa-whatsapp text-base"></i> Enviar no WhatsApp
</button>
<button
class="flex items-center justify-center gap-2 border border-gray-200 text-navy text-xs font-bold py-3 rounded-xl hover:bg-gray-50"
>
<i class="fa-solid fa-copy text-sm"></i> Copiar texto
</button>
</div>
<div class="border-t border-gray-100 pt-3">
<p class="text-xs text-gray-400 text-center">
<i class="fa-solid fa-circle-info text-gray-400 mr-1"></i>
A mensagem é enviada pelo celular de <strong>Maria</strong> — não é disparo em massa da
campanha
</p>
</div>
</div>
<!-- Remover dados -->
<div
class="bg-white border border-red-100 rounded-xl shadow-sm p-4 flex items-center justify-between"
>
<div>
<p class="text-sm font-semibold text-red-700">Remover meus dados</p>
<p class="text-xs text-gray-500 mt-0.5">Exclui todos os dados desta pessoa do sistema</p>
</div>
<button
class="flex items-center gap-1.5 border border-red-200 text-red-700 text-xs font-bold px-3 py-2 rounded-lg hover:bg-red-50 transition-colors"
>
<i class="fa-solid fa-trash text-xs"></i> Remover
</button>
</div>
</div>
<!-- Bottom action bar -->
<div class="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-200 px-4 py-4 z-20">
<button
class="w-full bg-primary text-white text-sm font-bold py-3 rounded-xl hover:bg-primary-light transition-colors flex items-center justify-center gap-2"
>
<i class="fa-solid fa-floppy-disk"></i> Salvar alterações
</button>
</div>
<script>
document.querySelectorAll('.seg-btn').forEach(function (btn) {
btn.addEventListener('click', function () {
document.querySelectorAll('.seg-btn').forEach(function (b) {
b.classList.remove('active', 'bg-primary', 'text-white', 'border-primary')
b.classList.add('bg-gray-50', 'text-gray-600', 'border-gray-200')
})
this.classList.add('active', 'bg-primary', 'text-white', 'border-primary')
this.classList.remove('bg-gray-50', 'text-gray-600', 'border-gray-200')
})
})
</script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

View file

@ -0,0 +1,312 @@
<!doctype html>
<html lang="pt-BR">
<head>
<script>
window.FontAwesomeConfig = {
autoReplaceSvg: 'nest',
}
</script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js"
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Apoiadores</title>
<script src="https://cdn.tailwindcss.com"></script>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css"
/>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#8E0E23',
'primary-light': '#B01C35',
'primary-xlight': '#F9E8EB',
gold: '#C8874B',
'gold-light': '#FDF3EC',
navy: '#1B2B4B',
},
},
},
}
</script>
<style>
body {
font-family: 'Inter', system-ui, sans-serif;
}
</style>
</head>
<body class="bg-gray-50 pb-24">
<!-- Header -->
<header
id="header"
class="bg-navy sticky top-0 z-20 px-4 py-3 flex items-center justify-between"
>
<div class="flex items-center gap-3">
<div class="w-7 h-7 rounded-full bg-primary flex items-center justify-center flex-shrink-0">
<i class="fa-solid fa-star text-white text-xs"></i>
</div>
<h1 class="text-white font-bold text-sm">Apoiadores</h1>
</div>
<div class="flex items-center gap-2">
<button class="relative text-white/70 p-1.5">
<i class="fa-solid fa-bell text-base"></i>
<span
class="absolute top-1 right-1 w-2 h-2 bg-primary rounded-full border border-navy"
></span>
</button>
<button
class="bg-white/10 text-white text-xs font-semibold px-3 py-1.5 rounded-lg flex items-center gap-1.5 border border-white/20"
>
<i class="fa-solid fa-file-arrow-up text-xs"></i> Importar CSV
</button>
<button
class="bg-primary text-white text-xs font-semibold px-3 py-1.5 rounded-lg flex items-center gap-1.5"
>
<i class="fa-solid fa-plus text-xs"></i> Novo
</button>
</div>
</header>
<!-- Scope badge -->
<div class="px-4 pt-3 pb-1">
<span
class="inline-flex items-center gap-1.5 bg-gold-light border border-gold/30 text-xs font-semibold text-navy px-3 py-1.5 rounded-full"
>
<i class="fa-solid fa-shield-halved text-gold text-xs"></i> Coordenação Geral · todos os
apoiadores
</span>
</div>
<!-- Summary strip -->
<div class="px-4 pt-3 pb-2 grid grid-cols-3 gap-2">
<div class="bg-white border border-gray-200 rounded-xl p-3 text-center shadow-sm">
<p class="text-2xl font-extrabold text-navy">1.847</p>
<p class="text-xs text-gray-500 mt-0.5">total</p>
</div>
<div class="bg-white border border-green-200 rounded-xl p-3 text-center shadow-sm">
<p class="text-2xl font-extrabold text-green-700">1.104</p>
<p class="text-xs text-green-600 mt-0.5">Certo + Tende</p>
</div>
<div class="bg-white border border-amber-200 rounded-xl p-3 text-center shadow-sm">
<p class="text-2xl font-extrabold text-amber-700">415</p>
<p class="text-xs text-amber-600 mt-0.5">Indecisos</p>
</div>
</div>
<!-- Search + Filters -->
<div class="px-4 pt-1 pb-3 space-y-2">
<div class="relative">
<input
type="text"
placeholder="Buscar por nome, telefone ou município…"
class="w-full pl-9 pr-4 py-2.5 text-sm border border-gray-200 rounded-xl bg-white focus:outline-none focus:ring-2 focus:ring-primary/20 text-navy placeholder-gray-300"
/>
<i
class="fa-solid fa-magnifying-glass absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 text-sm"
></i>
</div>
<div class="flex gap-2 overflow-x-auto pb-1">
<select
class="flex-shrink-0 text-xs border border-gray-200 rounded-lg px-3 py-2 text-navy bg-white focus:outline-none focus:ring-2 focus:ring-primary/20"
>
<option>Intenção de voto</option>
<option>Certo</option>
<option>Tende a certo</option>
<option>Indeciso</option>
<option>Outro</option>
</select>
<select
class="flex-shrink-0 text-xs border border-gray-200 rounded-lg px-3 py-2 text-navy bg-white focus:outline-none"
>
<option>Território</option>
<option>Velho Chico</option>
<option>Sertão do São Francisco</option>
</select>
<select
class="flex-shrink-0 text-xs border border-gray-200 rounded-lg px-3 py-2 text-navy bg-white focus:outline-none"
>
<option>Núcleo</option>
<option>Quilombo Rio das Rãs</option>
<option>Sindicato Rural Oeste</option>
</select>
</div>
</div>
<!-- List -->
<section id="apoiadores-list" class="px-4 space-y-2">
<!-- Item 1 -->
<div
class="bg-white border border-gray-200 rounded-xl shadow-sm p-4 cursor-pointer active:bg-gray-50"
>
<div class="flex items-center gap-3">
<img
src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-6.jpg"
class="w-10 h-10 rounded-full object-cover flex-shrink-0"
/>
<div class="flex-1 min-w-0">
<div class="flex items-center justify-between gap-2">
<p class="font-bold text-navy text-sm truncate">Maria das Dores Souza</p>
<span
class="bg-green-100 text-green-800 text-xs font-bold px-2 py-0.5 rounded-full flex-shrink-0"
>Certo</span
>
</div>
<p class="text-xs text-gray-500 mt-0.5">Bom Jesus da Lapa · Quilombo Rio das Rãs</p>
<div class="flex items-center gap-3 mt-1.5 text-xs text-gray-500">
<span><i class="fa-solid fa-phone text-gray-400 mr-1"></i>(77) 9 9000-1111</span>
</div>
</div>
</div>
</div>
<!-- Item 2 -->
<div
class="bg-white border border-gray-200 rounded-xl shadow-sm p-4 cursor-pointer active:bg-gray-50"
>
<div class="flex items-center gap-3">
<img
src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-8.jpg"
class="w-10 h-10 rounded-full object-cover flex-shrink-0"
/>
<div class="flex-1 min-w-0">
<div class="flex items-center justify-between gap-2">
<p class="font-bold text-navy text-sm truncate">Antônio Carlos Leal</p>
<span
class="bg-green-100 text-green-800 text-xs font-bold px-2 py-0.5 rounded-full flex-shrink-0"
>Tende a certo</span
>
</div>
<p class="text-xs text-gray-500 mt-0.5">Brumado · Sindicato Rural Oeste</p>
<div class="flex items-center gap-3 mt-1.5 text-xs text-gray-500">
<span><i class="fa-solid fa-phone text-gray-400 mr-1"></i>(77) 9 9111-2222</span>
</div>
</div>
</div>
</div>
<!-- Item 3 -->
<div
class="bg-white border border-gray-200 rounded-xl shadow-sm p-4 cursor-pointer active:bg-gray-50"
>
<div class="flex items-center gap-3">
<img
src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-7.jpg"
class="w-10 h-10 rounded-full object-cover flex-shrink-0"
/>
<div class="flex-1 min-w-0">
<div class="flex items-center justify-between gap-2">
<p class="font-bold text-navy text-sm truncate">Joelma Pereira</p>
<span
class="bg-amber-100 text-amber-800 text-xs font-bold px-2 py-0.5 rounded-full flex-shrink-0"
>Indeciso</span
>
</div>
<p class="text-xs text-gray-500 mt-0.5">Feira de Santana · sem núcleo vinculado</p>
<div class="flex items-center gap-3 mt-1.5 text-xs text-gray-500">
<span><i class="fa-solid fa-phone text-gray-400 mr-1"></i>(75) 9 8200-3333</span>
</div>
</div>
</div>
</div>
<!-- Item 4 -->
<div
class="bg-white border border-gray-200 rounded-xl shadow-sm p-4 cursor-pointer active:bg-gray-50"
>
<div class="flex items-center gap-3">
<img
src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-9.jpg"
class="w-10 h-10 rounded-full object-cover flex-shrink-0"
/>
<div class="flex-1 min-w-0">
<div class="flex items-center justify-between gap-2">
<p class="font-bold text-navy text-sm truncate">Roberto Bispo</p>
<span
class="bg-gray-100 text-gray-600 text-xs font-bold px-2 py-0.5 rounded-full flex-shrink-0"
>Outro</span
>
</div>
<p class="text-xs text-gray-500 mt-0.5">
Vitória da Conquista · Igreja Batista Central
</p>
<div class="flex items-center gap-3 mt-1.5 text-xs text-gray-400 italic">
<span>Sem telefone cadastrado</span>
</div>
</div>
</div>
</div>
<!-- Item 5 -->
<div
class="bg-white border border-gray-200 rounded-xl shadow-sm p-4 cursor-pointer active:bg-gray-50"
>
<div class="flex items-center gap-3">
<img
src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-5.jpg"
class="w-10 h-10 rounded-full object-cover flex-shrink-0"
/>
<div class="flex-1 min-w-0">
<div class="flex items-center justify-between gap-2">
<p class="font-bold text-navy text-sm truncate">Simone Oliveira</p>
<span
class="bg-green-100 text-green-800 text-xs font-bold px-2 py-0.5 rounded-full flex-shrink-0"
>Certo</span
>
</div>
<p class="text-xs text-gray-500 mt-0.5">Caetité · Quilombo Palmares II</p>
<div class="flex items-center gap-3 mt-1.5 text-xs text-gray-500">
<span><i class="fa-solid fa-phone text-gray-400 mr-1"></i>(77) 9 9444-5555</span>
</div>
</div>
</div>
</div>
<!-- Pagination hint -->
<p class="text-center text-xs text-gray-400 py-3">
Mostrando 5 de 1.847 · <span class="text-primary font-semibold">Carregar mais</span>
</p>
</section>
<!-- FAB -->
<div class="fixed bottom-20 right-4 z-30">
<button
class="bg-primary text-white w-14 h-14 rounded-full shadow-xl flex items-center justify-center"
>
<i class="fa-solid fa-plus text-xl"></i>
</button>
</div>
<!-- Bottom nav -->
<nav
id="bottom-nav"
class="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-200 flex z-20"
>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-gray-400">
<i class="fa-solid fa-house text-base"></i>
<span class="text-xs mt-0.5">Início</span>
</a>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-gray-400">
<i class="fa-solid fa-layer-group text-base"></i>
<span class="text-xs mt-0.5">Núcleos</span>
</a>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-primary">
<i class="fa-solid fa-user-group text-base"></i>
<span class="text-xs mt-0.5 font-semibold">Apoiadores</span>
</a>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-gray-400">
<i class="fa-solid fa-calendar-days text-base"></i>
<span class="text-xs mt-0.5">Agenda</span>
</a>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-gray-400">
<i class="fa-solid fa-users text-base"></i>
<span class="text-xs mt-0.5">Lideranças</span>
</a>
</nav>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 KiB

View file

@ -0,0 +1,422 @@
<!doctype html>
<html lang="pt-BR">
<head>
<script>
window.FontAwesomeConfig = {
autoReplaceSvg: 'nest',
}
</script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js"
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Baseline Eleitoral 2022</title>
<script src="https://cdn.tailwindcss.com"></script>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css"
/>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#8E0E23',
'primary-light': '#B01C35',
'primary-xlight': '#F9E8EB',
gold: '#C8874B',
'gold-light': '#FDF3EC',
navy: '#1B2B4B',
},
},
},
}
</script>
<style>
body {
font-family: 'Inter', system-ui, sans-serif;
}
.tab-btn.active {
color: #8e0e23;
border-bottom: 2px solid #8e0e23;
}
.tab-btn {
border-bottom: 2px solid transparent;
}
</style>
</head>
<body class="bg-gray-50 pb-24">
<!-- Header -->
<header
id="nucleo-header"
class="bg-primary sticky top-0 z-20 px-4 py-3 flex items-center gap-3"
>
<button class="text-white p-1"><i class="fa-solid fa-arrow-left text-lg"></i></button>
<div class="flex-1 min-w-0">
<h1 class="text-white font-bold text-sm leading-tight truncate">Quilombo Rio das Rãs</h1>
<p class="text-white/60 text-xs truncate">Comunidade · Bom Jesus da Lapa</p>
</div>
<button class="text-white/70 p-1.5"><i class="fa-solid fa-share-nodes text-lg"></i></button>
</header>
<!-- Scope badge -->
<div class="px-4 pt-3">
<span
class="inline-flex items-center gap-1.5 bg-gold-light border border-gold/30 text-xs font-semibold text-navy px-3 py-1.5 rounded-full"
>
<i class="fa-solid fa-eye text-gold text-xs"></i> Visível para você · Coord. de Núcleo
</span>
</div>
<!-- ZE chips + territory -->
<div class="px-4 pt-3 pb-2 flex items-center gap-2 flex-wrap">
<span class="text-sm text-gray-600">Comunidade · Bom Jesus da Lapa</span>
<span class="bg-gray-100 text-gray-600 text-xs font-mono font-semibold px-2 py-1 rounded"
>ZE 12</span
>
</div>
<!-- Vote estimate block -->
<div class="mx-4 mt-1 mb-3 bg-white rounded-2xl border border-gray-200 shadow-sm p-4">
<p class="text-xs text-gray-500 mb-1 font-medium">Estimativa de votos</p>
<div class="flex items-center gap-3">
<span class="text-4xl font-extrabold text-primary">1.200</span>
<span class="bg-green-100 text-green-800 text-sm font-bold px-3 py-1 rounded-full"
>Confirmada</span
>
</div>
<p class="text-xs text-gray-400 mt-1.5">por João S. em 12/07</p>
<button
class="mt-3 w-full border border-primary text-primary text-sm font-semibold py-2.5 rounded-xl hover:bg-primary-xlight transition-colors flex items-center justify-center gap-2"
>
<i class="fa-solid fa-pen-to-square text-xs"></i> Atualizar estimativa
</button>
</div>
<!-- Tabs -->
<div class="bg-white border-b border-gray-200 sticky top-14 z-10 overflow-x-auto">
<div class="flex whitespace-nowrap px-2">
<button class="tab-btn active text-xs font-semibold px-3 py-3">Visão geral</button>
<button class="tab-btn text-xs font-semibold px-3 py-3 text-gray-500">Território</button>
<button class="tab-btn text-xs font-semibold px-3 py-3 text-gray-500">Eleitorado</button>
<button class="tab-btn text-xs font-semibold px-3 py-3 text-gray-500">Lideranças</button>
<button class="tab-btn text-xs font-semibold px-3 py-3 text-gray-500">Atualizações</button>
</div>
</div>
<!-- Tab content: Visão Geral -->
<div class="px-4 py-4 space-y-4">
<!-- Strengths (existing block, compacted) -->
<div class="bg-white rounded-xl border border-gray-200 shadow-sm p-4">
<h3 class="text-sm font-bold text-navy mb-3 flex items-center gap-2">
<i class="fa-solid fa-circle-check text-green-500 text-xs"></i> Pontos fortes
</h3>
<ul class="space-y-1.5">
<li class="text-xs text-gray-700 flex gap-2">
<span class="text-green-500">•</span>Liderança comunitária consolidada há 15 anos
</li>
<li class="text-xs text-gray-700 flex gap-2">
<span class="text-green-500">•</span>Forte presença em saúde comunitária (ACS)
</li>
<li class="text-xs text-gray-700 flex gap-2">
<span class="text-green-500">•</span>Histórico de votação favorável ao candidato
</li>
</ul>
</div>
<!-- ══════════════════════════════════════════ -->
<!-- BASELINE ELEITORAL 2022 — new block -->
<!-- ══════════════════════════════════════════ -->
<div
id="baseline-block"
class="bg-white rounded-xl border border-gray-200 shadow-sm overflow-hidden"
>
<!-- Block header -->
<div class="px-4 py-3 border-b border-gray-100 flex items-center justify-between">
<h3 class="text-sm font-bold text-navy flex items-center gap-2">
<i class="fa-solid fa-chart-bar text-primary text-sm"></i> Baseline eleitoral 2022
</h3>
<span class="text-xs text-gray-400">Deputado Federal · Bahia</span>
</div>
<!-- Vote rows -->
<div class="divide-y divide-gray-50">
<!-- Solla — destaque row -->
<div class="px-4 py-3.5 bg-primary-xlight border-l-4 border-primary">
<div class="flex items-center justify-between">
<div class="flex items-center gap-2">
<div
class="w-7 h-7 rounded-full bg-primary flex items-center justify-center flex-shrink-0"
>
<i class="fa-solid fa-star text-white text-xs"></i>
</div>
<div>
<p class="text-sm font-bold text-navy">Jorge Solla</p>
<p class="text-xs text-primary font-semibold">PT · Dep. Federal</p>
</div>
</div>
<div class="text-right">
<p class="text-lg font-extrabold text-primary">850</p>
<p class="text-xs text-gray-500">votos · 2022</p>
</div>
</div>
<div class="mt-2 h-1.5 bg-primary/20 rounded-full overflow-hidden">
<div class="h-full bg-primary rounded-full" style="width: 34%"></div>
</div>
</div>
<!-- Lula -->
<div class="px-4 py-3">
<div class="flex items-center justify-between">
<div class="flex items-center gap-2">
<div
class="w-7 h-7 rounded-full bg-red-100 flex items-center justify-center flex-shrink-0"
>
<i class="fa-solid fa-person text-red-600 text-xs"></i>
</div>
<div>
<p class="text-sm font-semibold text-navy">Lula</p>
<p class="text-xs text-gray-500">PT · Presidente (2º turno)</p>
</div>
</div>
<p class="text-sm font-bold text-navy">1.480</p>
</div>
</div>
<!-- Jerônimo -->
<div class="px-4 py-3">
<div class="flex items-center justify-between">
<div class="flex items-center gap-2">
<div
class="w-7 h-7 rounded-full bg-red-100 flex items-center justify-center flex-shrink-0"
>
<i class="fa-solid fa-person text-red-600 text-xs"></i>
</div>
<div>
<p class="text-sm font-semibold text-navy">Jerônimo Rodrigues</p>
<p class="text-xs text-gray-500">PT · Governador</p>
</div>
</div>
<p class="text-sm font-bold text-navy">1.310</p>
</div>
</div>
<!-- Divider: eleitorado stats -->
<div class="px-4 py-3 bg-gray-50">
<p class="text-xs text-gray-500 font-semibold uppercase tracking-wide mb-2.5">
Eleitorado 2022
</p>
<div class="grid grid-cols-2 gap-x-4 gap-y-2">
<div class="flex items-center justify-between">
<span class="text-xs text-gray-600">Votos válidos</span>
<span class="text-xs font-bold text-navy">2.490</span>
</div>
<div class="flex items-center justify-between">
<span class="text-xs text-gray-600">Brancos</span>
<span class="text-xs font-bold text-navy">142</span>
</div>
<div class="flex items-center justify-between">
<span class="text-xs text-gray-600">Nulos</span>
<span class="text-xs font-bold text-navy">87</span>
</div>
<div class="flex items-center justify-between">
<span class="text-xs text-gray-600">Abstenções</span>
<span class="text-xs font-bold text-navy">680</span>
</div>
</div>
</div>
<!-- Mais votado aqui -->
<div class="px-4 py-3 flex items-center justify-between">
<div class="flex items-center gap-2">
<i class="fa-solid fa-trophy text-amber-400 text-sm flex-shrink-0"></i>
<div>
<p class="text-xs text-gray-500">Mais votado aqui em 2022</p>
<p class="text-sm font-semibold text-navy">Dep. Fulano de Tal (PP)</p>
</div>
</div>
<p class="text-sm font-bold text-gray-700">2.100</p>
</div>
</div>
<!-- ── INSIGHT LINE — negative scenario ──────── -->
<div
class="mx-4 mb-4 mt-1 flex items-start gap-2.5 bg-amber-50 border border-amber-200 rounded-xl px-3.5 py-3"
>
<i
class="fa-solid fa-triangle-exclamation text-amber-500 text-base mt-0.5 flex-shrink-0"
></i>
<div>
<p class="text-sm font-bold text-amber-800">Faltam 350 votos para o patamar de 2022</p>
<p class="text-xs text-amber-700 mt-0.5">
Estimativa atual (1.200) ainda abaixo do resultado de 2022 (850 → meta: 1.200
confirmada, mas patamar atingido exige esforço de ativação adicional)
</p>
</div>
</div>
<!-- ── INSIGHT LINE — positive scenario (alternate, commented) ──
<div class="mx-4 mb-4 mt-1 flex items-start gap-2.5 bg-green-50 border border-green-200 rounded-xl px-3.5 py-3">
<i class="fa-solid fa-circle-check text-green-500 text-base mt-0.5 flex-shrink-0"></i>
<div>
<p class="text-sm font-bold text-green-800">Já superamos 2022 em 12%</p>
<p class="text-xs text-green-700 mt-0.5">Estimativa de 1.200 supera os 850 votos de 2022 — território em crescimento.</p>
</div>
</div>
──────────────────────────────────────────── -->
</div>
<!-- end baseline block -->
<!-- ══════════════════════════════════════════ -->
<!-- INSIGHTS PANEL (Priority 3 — preview) -->
<!-- ══════════════════════════════════════════ -->
<div
id="insights-panel"
class="bg-white rounded-xl border border-gray-200 shadow-sm p-4 space-y-3"
>
<h3 class="text-sm font-bold text-navy flex items-center gap-2">
<i class="fa-solid fa-lightbulb text-amber-400 text-sm"></i> Insights do território
</h3>
<!-- Insight card 1: conversão -->
<div class="flex items-center gap-3 p-2.5 rounded-lg bg-green-50 border border-green-100">
<div
class="w-8 h-8 rounded-lg bg-green-100 flex items-center justify-center flex-shrink-0"
>
<i class="fa-solid fa-percent text-green-600 text-sm"></i>
</div>
<div class="flex-1 min-w-0">
<p class="text-xs font-bold text-green-800">
Taxa de conversão: 18% do eleitorado apto
</p>
<p class="text-xs text-green-700 mt-0.5">850 votos / 4.700 eleitores aptos</p>
</div>
</div>
<!-- Insight card 2: classificação -->
<div class="flex items-center gap-3 p-2.5 rounded-lg bg-gray-50 border border-gray-200">
<div
class="w-8 h-8 rounded-lg bg-green-100 flex items-center justify-center flex-shrink-0"
>
<i class="fa-solid fa-shield text-green-600 text-sm"></i>
</div>
<div class="flex-1 min-w-0">
<p class="text-xs font-bold text-navy">Território de defesa</p>
<p class="text-xs text-gray-600 mt-0.5">Base sólida — prioridade manter engajamento</p>
</div>
<span
class="bg-green-100 text-green-700 text-xs font-bold px-2 py-0.5 rounded-full flex-shrink-0"
>Defesa</span
>
</div>
<!-- Insight card 3: alavancagem -->
<div class="flex items-center gap-3 p-2.5 rounded-lg bg-blue-50 border border-blue-100">
<div
class="w-8 h-8 rounded-lg bg-blue-100 flex items-center justify-center flex-shrink-0"
>
<i class="fa-solid fa-link text-blue-600 text-sm"></i>
</div>
<div class="flex-1 min-w-0">
<p class="text-xs font-bold text-blue-800">Alavancagem da chapa: 22%</p>
<p class="text-xs text-blue-700 mt-0.5">Da base Lula/Jerônimo ainda não convertida</p>
</div>
</div>
<!-- Insight card 4: oportunidade -->
<div class="flex items-center gap-3 p-2.5 rounded-lg bg-amber-50 border border-amber-100">
<div
class="w-8 h-8 rounded-lg bg-amber-100 flex items-center justify-center flex-shrink-0"
>
<i class="fa-solid fa-bullhorn text-amber-600 text-sm"></i>
</div>
<div class="flex-1 min-w-0">
<p class="text-xs font-bold text-amber-800">Oportunidade de mobilização</p>
<p class="text-xs text-amber-700 mt-0.5">
142 brancos/nulos + 680 abstenções = 822 votos possíveis
</p>
</div>
</div>
<!-- Insight card 5: mais votado -->
<div class="flex items-center gap-3 p-2.5 rounded-lg bg-gray-50 border border-gray-200">
<div
class="w-8 h-8 rounded-lg bg-gray-100 flex items-center justify-center flex-shrink-0"
>
<i class="fa-solid fa-ranking-star text-gray-600 text-sm"></i>
</div>
<div class="flex-1 min-w-0">
<p class="text-xs font-bold text-navy">Mais votado aqui em 2022: Dep. Fulano (PP)</p>
<p class="text-xs text-gray-600 mt-0.5">
Solla ficou em 4º lugar · 2.100 votos à frente
</p>
</div>
</div>
</div>
<!-- end insights panel -->
<!-- Status lideranças -->
<div class="bg-white rounded-xl border border-gray-200 shadow-sm p-4">
<p class="text-xs text-gray-500 font-semibold uppercase tracking-wide mb-3">
Status das lideranças
</p>
<div class="space-y-2">
<div class="flex items-center justify-between text-sm">
<div class="flex items-center gap-2">
<span class="w-2.5 h-2.5 rounded-full bg-green-500"></span> Engajadas
</div>
<span class="font-bold text-green-700">5</span>
</div>
<div class="flex items-center justify-between text-sm">
<div class="flex items-center gap-2">
<span class="w-2.5 h-2.5 rounded-full bg-gray-400"></span> A abordar
</div>
<span class="font-bold text-gray-600">4</span>
</div>
<div class="flex items-center justify-between text-sm">
<div class="flex items-center gap-2">
<span class="w-2.5 h-2.5 rounded-full bg-amber-500"></span> Em disputa
</div>
<span class="font-bold text-amber-700">2</span>
</div>
<div class="flex items-center justify-between text-sm">
<div class="flex items-center gap-2">
<span class="w-2.5 h-2.5 rounded-full bg-red-500"></span> Negativas
</div>
<span class="font-bold text-red-700">1</span>
</div>
</div>
</div>
</div>
<!-- Bottom nav -->
<nav
id="bottom-nav"
class="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-200 flex z-20"
>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-gray-400">
<i class="fa-solid fa-house text-base"></i>
<span class="text-xs mt-0.5">Início</span>
</a>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-primary">
<i class="fa-solid fa-layer-group text-base"></i>
<span class="text-xs mt-0.5 font-semibold">Núcleos</span>
</a>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-gray-400">
<i class="fa-solid fa-user-group text-base"></i>
<span class="text-xs mt-0.5">Apoiadores</span>
</a>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-gray-400">
<i class="fa-solid fa-calendar-days text-base"></i>
<span class="text-xs mt-0.5">Agenda</span>
</a>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-gray-400">
<i class="fa-solid fa-users text-base"></i>
<span class="text-xs mt-0.5">Lideranças</span>
</a>
</nav>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

View file

@ -0,0 +1,259 @@
<!doctype html>
<html lang="pt-BR">
<head>
<script>
window.FontAwesomeConfig = {
autoReplaceSvg: 'nest',
}
</script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js"
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Compartilhar Núcleo</title>
<script src="https://cdn.tailwindcss.com"></script>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css"
/>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#8E0E23',
'primary-light': '#B01C35',
'primary-xlight': '#F9E8EB',
gold: '#C8874B',
'gold-light': '#FDF3EC',
navy: '#1B2B4B',
wa: '#25D366',
},
},
},
}
</script>
<style>
body {
font-family: 'Inter', system-ui, sans-serif;
}
</style>
</head>
<body class="bg-gray-900/60 pb-0" style="min-height: 840px">
<!-- Dimmed background — represents nuclei detail screen behind -->
<div class="bg-gray-50" style="height: 840px; position: relative">
<!-- Blurred header behind -->
<header class="bg-primary px-4 py-3 flex items-center gap-3 opacity-40">
<button class="text-white p-1"><i class="fa-solid fa-arrow-left text-lg"></i></button>
<div class="flex-1 min-w-0">
<h1 class="text-white font-bold text-sm truncate">Quilombo Rio das Rãs</h1>
<p class="text-white/60 text-xs">Comunidade · Bom Jesus da Lapa</p>
</div>
<button class="text-white/70 p-1.5"><i class="fa-solid fa-share-nodes text-lg"></i></button>
</header>
<div class="px-4 pt-3 opacity-30">
<span
class="inline-flex items-center gap-1.5 bg-gold-light border border-gold/30 text-xs font-semibold text-navy px-3 py-1.5 rounded-full"
>
<i class="fa-solid fa-eye text-gold text-xs"></i> Visível para você · Coord. de Núcleo
</span>
</div>
<!-- Dialog overlay -->
<div class="absolute inset-0 bg-black/40 flex items-end" style="z-index: 50">
<div
id="share-dialog"
class="w-full bg-white rounded-t-2xl shadow-2xl"
style="max-height: 660px; overflow-y: auto"
>
<!-- Handle -->
<div class="flex justify-center pt-3 pb-1">
<div class="w-10 h-1 bg-gray-300 rounded-full"></div>
</div>
<!-- Dialog header -->
<div class="px-5 pt-3 pb-4 border-b border-gray-100 flex items-center justify-between">
<div>
<h2 class="text-base font-bold text-navy">Compartilhar núcleo</h2>
<p class="text-xs text-gray-500 mt-0.5">
Quilombo Rio das Rãs · envia apenas o link, não concede acesso
</p>
</div>
<button class="text-gray-400 hover:text-navy p-1.5 rounded-lg hover:bg-gray-100">
<i class="fa-solid fa-xmark text-lg"></i>
</button>
</div>
<!-- Sections -->
<div class="px-5 py-4 space-y-5">
<!-- Section: Coordenação Geral -->
<div>
<p class="text-xs font-semibold text-gray-400 uppercase tracking-wide mb-2.5">
Com coordenação geral
</p>
<div class="space-y-2.5">
<!-- Person 1 -->
<div class="flex items-center gap-3">
<img
src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-2.jpg"
class="w-9 h-9 rounded-full object-cover flex-shrink-0"
/>
<div class="flex-1 min-w-0">
<p class="text-sm font-semibold text-navy truncate">Carlos Mendes</p>
<p class="text-xs text-gray-500">Coord. Geral</p>
</div>
<button
class="flex items-center gap-1.5 bg-wa text-white text-xs font-bold px-3 py-2 rounded-xl active:opacity-80 flex-shrink-0"
>
<i class="fa-brands fa-whatsapp text-base"></i> Abrir
</button>
</div>
<!-- Person 2 -->
<div class="flex items-center gap-3">
<img
src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-1.jpg"
class="w-9 h-9 rounded-full object-cover flex-shrink-0"
/>
<div class="flex-1 min-w-0">
<p class="text-sm font-semibold text-navy truncate">Ana Ribeiro</p>
<p class="text-xs text-gray-500">Coord. Geral</p>
</div>
<button
class="flex items-center gap-1.5 bg-wa text-white text-xs font-bold px-3 py-2 rounded-xl active:opacity-80 flex-shrink-0"
>
<i class="fa-brands fa-whatsapp text-base"></i> Abrir
</button>
</div>
</div>
</div>
<!-- Divider -->
<div class="border-t border-gray-100"></div>
<!-- Section: Coordenador do Núcleo -->
<div>
<p class="text-xs font-semibold text-gray-400 uppercase tracking-wide mb-2.5">
Com coordenador
</p>
<div class="space-y-2.5">
<div class="flex items-center gap-3">
<img
src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-3.jpg"
class="w-9 h-9 rounded-full object-cover flex-shrink-0"
/>
<div class="flex-1 min-w-0">
<p class="text-sm font-semibold text-navy truncate">João Santos</p>
<p class="text-xs text-gray-500">Coord. Núcleo</p>
</div>
<button
class="flex items-center gap-1.5 bg-wa text-white text-xs font-bold px-3 py-2 rounded-xl active:opacity-80 flex-shrink-0"
>
<i class="fa-brands fa-whatsapp text-base"></i> Abrir
</button>
</div>
<div class="flex items-center gap-3">
<img
src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-5.jpg"
class="w-9 h-9 rounded-full object-cover flex-shrink-0"
/>
<div class="flex-1 min-w-0">
<p class="text-sm font-semibold text-navy truncate">Patrícia Lima</p>
<p class="text-xs text-gray-500">Coord. Núcleo</p>
</div>
<button
class="flex items-center gap-1.5 bg-wa text-white text-xs font-bold px-3 py-2 rounded-xl active:opacity-80 flex-shrink-0"
>
<i class="fa-brands fa-whatsapp text-base"></i> Abrir
</button>
</div>
</div>
</div>
<!-- Divider -->
<div class="border-t border-gray-100"></div>
<!-- Section: Liderança -->
<div>
<p class="text-xs font-semibold text-gray-400 uppercase tracking-wide mb-2.5">
Com liderança
</p>
<div class="space-y-2.5">
<div class="flex items-center gap-3">
<img
src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-6.jpg"
class="w-9 h-9 rounded-full object-cover flex-shrink-0"
/>
<div class="flex-1 min-w-0">
<p class="text-sm font-semibold text-navy truncate">Dona Rosa Ferreira</p>
<p class="text-xs text-gray-500">Liderança · Engajada</p>
</div>
<button
class="flex items-center gap-1.5 bg-wa text-white text-xs font-bold px-3 py-2 rounded-xl active:opacity-80 flex-shrink-0"
>
<i class="fa-brands fa-whatsapp text-base"></i> Abrir
</button>
</div>
<!-- No phone — absent -->
<!-- (Person without phone simply not shown) -->
</div>
</div>
<!-- Divider -->
<div class="border-t border-gray-100"></div>
<!-- Copy link -->
<div>
<p class="text-xs font-semibold text-gray-400 uppercase tracking-wide mb-2.5">
Copiar link
</p>
<div
class="flex items-center gap-2 bg-gray-50 border border-gray-200 rounded-xl px-3 py-2.5"
>
<i class="fa-solid fa-link text-gray-400 text-sm flex-shrink-0"></i>
<p class="text-xs text-gray-600 truncate flex-1">
solla.app/nucleos/quilombo-rio-das-ras
</p>
<button
id="copy-btn"
onclick="copyLink()"
class="flex-shrink-0 bg-navy text-white text-xs font-bold px-3 py-1.5 rounded-lg active:opacity-80"
>
Copiar
</button>
</div>
<!-- Copied state (hidden by default) -->
<div
id="copied-msg"
class="hidden mt-2 flex items-center gap-1.5 text-green-700 text-xs font-semibold"
>
<i class="fa-solid fa-check-circle"></i> Link copiado!
</div>
</div>
</div>
<!-- Bottom padding -->
<div class="h-6"></div>
</div>
</div>
</div>
<script>
function copyLink() {
document.getElementById('copied-msg').classList.remove('hidden')
var btn = document.getElementById('copy-btn')
btn.textContent = 'Copiado ✓'
btn.classList.add('bg-green-600')
btn.classList.remove('bg-navy')
setTimeout(function () {
document.getElementById('copied-msg').classList.add('hidden')
btn.textContent = 'Copiar'
btn.classList.remove('bg-green-600')
btn.classList.add('bg-navy')
}, 2500)
}
</script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

View file

@ -0,0 +1,343 @@
<!doctype html>
<html lang="pt-BR">
<head>
<script>
window.FontAwesomeConfig = {
autoReplaceSvg: 'nest',
}
</script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js"
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Dia D – Operação Eleitoral</title>
<script src="https://cdn.tailwindcss.com"></script>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css"
/>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#8E0E23',
'primary-light': '#B01C35',
'primary-xlight': '#F9E8EB',
gold: '#C8874B',
'gold-light': '#FDF3EC',
navy: '#1B2B4B',
},
},
},
}
</script>
<style>
body {
font-family: 'Inter', system-ui, sans-serif;
}
.supporter-btn {
transition: all 0.2s;
}
.supporter-btn.votou {
background: #dcfce7;
border-color: #16a34a;
color: #166534;
}
.supporter-btn.confirmou {
background: #dbeafe;
border-color: #2563eb;
color: #1e40af;
}
</style>
</head>
<body class="bg-gray-50 pb-24">
<!-- Header -->
<header
id="header"
class="bg-primary sticky top-0 z-30 px-4 py-3 flex items-center justify-between"
>
<div>
<div class="flex items-center gap-2 mb-0.5">
<i class="fa-solid fa-flag text-white/90 text-sm"></i>
<h1 class="text-white font-bold text-sm">Dia D — 4 de outubro</h1>
</div>
<p class="text-white/70 text-xs">
Quilombo Rio das Rãs · <span class="font-mono">ZE 12</span>
</p>
</div>
<!-- Sync status -->
<div class="flex flex-col items-end gap-1">
<span
class="inline-flex items-center gap-1.5 bg-green-500 text-white text-xs font-bold px-2 py-0.5 rounded-full"
>
<i class="fa-solid fa-wifi text-xs"></i> Sincronizado
</span>
<p class="text-white/50 text-xs">às 08:42</p>
</div>
</header>
<!-- Sticky progress header -->
<div id="progress-header" class="sticky z-20 bg-navy px-4 py-3" style="top: 60px">
<div class="flex items-center justify-between mb-2">
<div>
<p class="text-white font-bold text-lg leading-none">62% da base</p>
<p class="text-white/60 text-xs mt-0.5">1.240 de 2.000 confirmados</p>
</div>
<div class="text-right">
<p class="text-white/80 text-xs">Votaram</p>
<p class="text-green-400 font-extrabold text-xl leading-none">830</p>
</div>
</div>
<!-- Progress bar -->
<div class="h-3 bg-white/20 rounded-full overflow-hidden">
<div
class="h-full rounded-full"
style="width: 62%; background: linear-gradient(to right, #22c55e, #86efac)"
></div>
</div>
<div class="flex items-center justify-between mt-1.5 text-xs">
<span class="text-white/60">0</span>
<span class="text-green-400 font-semibold">62% confirmados vão votar</span>
<span class="text-white/60">2.000</span>
</div>
</div>
<!-- Filter chips -->
<div
class="px-4 py-3 flex gap-2 overflow-x-auto bg-white border-b border-gray-200 sticky z-10"
style="top: 140px"
>
<button
class="flex-shrink-0 text-xs font-bold px-3 py-1.5 rounded-full border-2 border-primary bg-primary text-white"
>
Todos (2.000)
</button>
<button
class="flex-shrink-0 text-xs font-semibold px-3 py-1.5 rounded-full border border-gray-200 text-gray-600 hover:border-navy"
>
Ainda não confirmados (760)
</button>
<button
class="flex-shrink-0 text-xs font-semibold px-3 py-1.5 rounded-full border border-gray-200 text-gray-600 hover:border-navy"
>
Votaram (830)
</button>
</div>
<!-- Scope badge -->
<div class="px-4 pt-3 pb-1">
<span
class="inline-flex items-center gap-1.5 bg-gold-light border border-gold/30 text-xs font-semibold text-navy px-3 py-1.5 rounded-full"
>
<i class="fa-solid fa-eye text-gold text-xs"></i> Visão do coordenador · Quilombo Rio das
Rãs
</span>
</div>
<!-- Legend -->
<div class="px-4 pt-2 pb-3 flex items-center gap-4 text-xs">
<div class="flex items-center gap-1.5">
<div class="w-3 h-3 rounded-full bg-gray-200 border border-gray-300"></div>
<span class="text-gray-500">Não confirmado</span>
</div>
<div class="flex items-center gap-1.5">
<div class="w-3 h-3 rounded-full bg-blue-200 border border-blue-400"></div>
<span class="text-gray-500">Vai votar</span>
</div>
<div class="flex items-center gap-1.5">
<div class="w-3 h-3 rounded-full bg-green-400 border border-green-600"></div>
<span class="text-gray-500">Votou ✓</span>
</div>
</div>
<!-- Supporter list — big tap targets -->
<section id="supporter-list" class="px-4 space-y-2">
<!-- Item: Votou (confirmed voted) -->
<div class="bg-green-50 border border-green-200 rounded-xl p-4 flex items-center gap-4">
<div class="flex-1 min-w-0">
<p class="font-bold text-navy text-sm">Maria das Dores Souza</p>
<p class="text-xs text-gray-500">Seção 42 · ZE 12</p>
</div>
<button
class="supporter-btn votou text-xs font-bold px-4 py-3 rounded-xl border-2 min-w-[90px] text-center"
>
<i class="fa-solid fa-check-circle mr-1"></i> Votou ✓
</button>
</div>
<!-- Item: Confirmou que vai votar -->
<div class="bg-blue-50 border border-blue-200 rounded-xl p-4 flex items-center gap-4">
<div class="flex-1 min-w-0">
<p class="font-bold text-navy text-sm">Antônio Carlos Leal</p>
<p class="text-xs text-gray-500">Seção 42 · ZE 12</p>
</div>
<div class="flex flex-col gap-1.5">
<button
class="supporter-btn confirmou text-xs font-bold px-3 py-2 rounded-xl border-2 text-center whitespace-nowrap"
>
<i class="fa-solid fa-thumbs-up mr-1"></i> Vai votar
</button>
<button
onclick="markVotou(this)"
class="text-xs font-bold px-3 py-2 rounded-xl border-2 border-green-400 text-green-700 bg-white text-center whitespace-nowrap hover:bg-green-50"
>
Confirmar votou
</button>
</div>
</div>
<!-- Item: Não confirmado -->
<div class="bg-white border border-gray-200 rounded-xl p-4 flex items-center gap-4">
<div class="flex-1 min-w-0">
<p class="font-bold text-navy text-sm">Joelma Pereira</p>
<p class="text-xs text-gray-500">Seção 38 · ZE 12</p>
</div>
<div class="flex flex-col gap-1.5">
<button
onclick="markConfirmou(this)"
class="supporter-btn text-xs font-bold px-3 py-2.5 rounded-xl border-2 border-blue-300 text-blue-700 bg-blue-50 text-center whitespace-nowrap hover:bg-blue-100"
>
Confirmou que vai votar
</button>
</div>
</div>
<!-- Item: Não confirmado -->
<div class="bg-white border border-gray-200 rounded-xl p-4 flex items-center gap-4">
<div class="flex-1 min-w-0">
<p class="font-bold text-navy text-sm">Roberto Bispo</p>
<p class="text-xs text-gray-500">Seção 38 · ZE 12</p>
</div>
<div class="flex flex-col gap-1.5">
<button
onclick="markConfirmou(this)"
class="supporter-btn text-xs font-bold px-3 py-2.5 rounded-xl border-2 border-blue-300 text-blue-700 bg-blue-50 text-center whitespace-nowrap hover:bg-blue-100"
>
Confirmou que vai votar
</button>
</div>
</div>
<!-- Item: Votou -->
<div class="bg-green-50 border border-green-200 rounded-xl p-4 flex items-center gap-4">
<div class="flex-1 min-w-0">
<p class="font-bold text-navy text-sm">Simone Oliveira</p>
<p class="text-xs text-gray-500">Seção 45 · ZE 12</p>
</div>
<button
class="supporter-btn votou text-xs font-bold px-4 py-3 rounded-xl border-2 min-w-[90px] text-center"
>
<i class="fa-solid fa-check-circle mr-1"></i> Votou ✓
</button>
</div>
<!-- Item: Não confirmado -->
<div class="bg-white border border-gray-200 rounded-xl p-4 flex items-center gap-4">
<div class="flex-1 min-w-0">
<p class="font-bold text-navy text-sm">José Nascimento</p>
<p class="text-xs text-gray-500">Seção 40 · ZE 12</p>
</div>
<div class="flex flex-col gap-1.5">
<button
onclick="markConfirmou(this)"
class="supporter-btn text-xs font-bold px-3 py-2.5 rounded-xl border-2 border-blue-300 text-blue-700 bg-blue-50 text-center whitespace-nowrap hover:bg-blue-100"
>
Confirmou que vai votar
</button>
</div>
</div>
<!-- Item: Não confirmado -->
<div class="bg-white border border-gray-200 rounded-xl p-4 flex items-center gap-4">
<div class="flex-1 min-w-0">
<p class="font-bold text-navy text-sm">Ana Paula Ferreira</p>
<p class="text-xs text-gray-500">Seção 38 · ZE 12</p>
</div>
<div class="flex flex-col gap-1.5">
<button
onclick="markConfirmou(this)"
class="supporter-btn text-xs font-bold px-3 py-2.5 rounded-xl border-2 border-blue-300 text-blue-700 bg-blue-50 text-center whitespace-nowrap hover:bg-blue-100"
>
Confirmou que vai votar
</button>
</div>
</div>
<p class="text-center text-xs text-gray-400 py-3">
Mostrando 7 de 2.000 · <span class="text-primary font-semibold">Carregar mais</span>
</p>
</section>
<!-- Offline warning banner (example) -->
<div
id="offline-banner"
class="hidden fixed top-20 left-4 right-4 z-40 bg-amber-50 border border-amber-300 rounded-xl px-4 py-3 flex items-center gap-3 shadow-lg"
>
<i class="fa-solid fa-wifi-slash text-amber-600 text-lg flex-shrink-0"></i>
<div class="flex-1 min-w-0">
<p class="text-xs font-bold text-amber-800">Sem conexão — modo offline</p>
<p class="text-xs text-amber-600">
As marcações serão sincronizadas quando a conexão voltar
</p>
</div>
<span
class="text-xs font-bold text-amber-700 bg-amber-200 px-2 py-0.5 rounded-full flex-shrink-0"
>3 pend.</span
>
</div>
<!-- Bottom nav -->
<nav
id="bottom-nav"
class="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-200 flex z-20"
>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-gray-400">
<i class="fa-solid fa-house text-base"></i>
<span class="text-xs mt-0.5">Início</span>
</a>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-gray-400">
<i class="fa-solid fa-layer-group text-base"></i>
<span class="text-xs mt-0.5">Núcleos</span>
</a>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-gray-400">
<i class="fa-solid fa-user-group text-base"></i>
<span class="text-xs mt-0.5">Apoiadores</span>
</a>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-primary">
<i class="fa-solid fa-flag text-base"></i>
<span class="text-xs mt-0.5 font-semibold">Dia D</span>
</a>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-gray-400">
<i class="fa-solid fa-users text-base"></i>
<span class="text-xs mt-0.5">Lideranças</span>
</a>
</nav>
<script>
function markConfirmou(btn) {
var row = btn.closest('div.flex.flex-col')
row.innerHTML =
'<button onclick="markVotou(this)" class="text-xs font-bold px-3 py-2 rounded-xl border-2 border-blue-400 text-blue-700 bg-blue-50 text-center whitespace-nowrap">Confirmou que vai votar</button><button onclick="markVotou(this)" class="text-xs font-bold px-3 py-2 rounded-xl border-2 border-green-400 text-green-700 bg-white text-center whitespace-nowrap hover:bg-green-50">Confirmar votou</button>'
var card = btn.closest('.bg-white')
if (card) {
card.classList.remove('bg-white', 'border-gray-200')
card.classList.add('bg-blue-50', 'border-blue-200')
}
}
function markVotou(btn) {
var card = btn.closest('[class*="rounded-xl"]')
card.classList.remove('bg-blue-50', 'border-blue-200', 'bg-white', 'border-gray-200')
card.classList.add('bg-green-50', 'border-green-200')
var actionArea = btn.closest('.flex.flex-col') || btn.closest('.flex.items-center.gap-4')
var parent = card.querySelector('.flex.flex-col') || card.lastElementChild
if (parent)
parent.innerHTML =
'<button class="supporter-btn votou text-xs font-bold px-4 py-3 rounded-xl border-2 min-w-[90px] text-center"><i class="fa-solid fa-check-circle mr-1"></i> Votou ✓</button>'
}
</script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

View file

@ -0,0 +1,385 @@
<!doctype html>
<html lang="pt-BR">
<head>
<script>
window.FontAwesomeConfig = {
autoReplaceSvg: 'nest',
}
</script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js"
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Formulário – Território</title>
<script src="https://cdn.tailwindcss.com"></script>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css"
/>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#8E0E23',
'primary-light': '#B01C35',
'primary-xlight': '#F9E8EB',
gold: '#C8874B',
'gold-light': '#FDF3EC',
navy: '#1B2B4B',
},
},
},
}
</script>
<style>
body {
font-family: 'Inter', system-ui, sans-serif;
}
.chip-remove {
cursor: pointer;
}
.ze-chip {
user-select: none;
}
</style>
</head>
<body class="bg-gray-50 pb-28">
<!-- Header -->
<header id="header" class="bg-navy sticky top-0 z-20 px-4 py-3 flex items-center gap-3">
<button class="text-white p-1"><i class="fa-solid fa-arrow-left text-lg"></i></button>
<div class="flex-1">
<h1 class="text-white font-bold text-sm">Editar Núcleo</h1>
<p class="text-white/60 text-xs">Quilombo Rio das Rãs · Território</p>
</div>
<button
class="text-white/70 text-xs font-semibold px-3 py-1.5 border border-white/30 rounded-lg"
>
Salvar
</button>
</header>
<!-- Scope badge -->
<div class="px-4 pt-3 pb-1">
<span
class="inline-flex items-center gap-1.5 bg-gold-light border border-gold/30 text-xs font-semibold text-navy px-3 py-1.5 rounded-full"
>
<i class="fa-solid fa-shield-halved text-gold text-xs"></i> Coordenação Geral
</span>
</div>
<!-- Form -->
<form class="px-4 pt-4 space-y-5" onsubmit="return false">
<!-- Nome do núcleo -->
<div class="bg-white border border-gray-200 rounded-xl shadow-sm p-4 space-y-4">
<div>
<label class="block text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1.5"
>Nome do Núcleo <span class="text-primary">*</span></label
>
<input
type="text"
value="Quilombo Rio das Rãs"
class="w-full border border-gray-200 rounded-xl px-3 py-3 text-sm text-navy focus:outline-none focus:ring-2 focus:ring-primary/25 focus:border-primary"
/>
</div>
<div>
<label class="block text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1.5"
>Tipo de território <span class="text-primary">*</span></label
>
<select
class="w-full border border-gray-200 rounded-xl px-3 py-3 text-sm text-navy focus:outline-none focus:ring-2 focus:ring-primary/25 bg-white"
>
<option>Comunidade Quilombola</option>
<option>Sindicato</option>
<option>Religioso</option>
<option>Rural / Assentamento</option>
<option>Bairro</option>
<option>Outro</option>
</select>
</div>
</div>
<!-- ═══════════════════════════════════════ -->
<!-- TERRITÓRIO — multi-município block -->
<!-- ═══════════════════════════════════════ -->
<div
id="territorio-block"
class="bg-white border border-gray-200 rounded-xl shadow-sm p-4 space-y-4"
>
<h3 class="text-sm font-bold text-navy flex items-center gap-2">
<i class="fa-solid fa-map-location-dot text-primary text-sm"></i> Território
</h3>
<!-- Municípios multi-select -->
<div>
<label class="block text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1.5"
>Municípios <span class="text-primary">*</span></label
>
<!-- Selected chips -->
<div id="municipios-chips" class="flex flex-wrap gap-2 mb-2">
<span
class="inline-flex items-center gap-1.5 bg-navy text-white text-xs font-semibold px-3 py-1.5 rounded-full"
>
Bom Jesus da Lapa
<button
type="button"
onclick="removeChip(this, 'municipios-chips', 'municipios-count')"
class="chip-remove ml-0.5 opacity-70 hover:opacity-100"
>
<i class="fa-solid fa-xmark text-xs"></i>
</button>
</span>
<span
class="inline-flex items-center gap-1.5 bg-navy text-white text-xs font-semibold px-3 py-1.5 rounded-full"
>
Carinhanha
<button
type="button"
onclick="removeChip(this, 'municipios-chips', 'municipios-count')"
class="chip-remove ml-0.5 opacity-70 hover:opacity-100"
>
<i class="fa-solid fa-xmark text-xs"></i>
</button>
</span>
</div>
<!-- Combobox input -->
<div class="relative">
<input
id="municipio-input"
type="text"
placeholder="Buscar e adicionar município…"
class="w-full border border-gray-200 rounded-xl px-3 py-3 text-sm text-navy focus:outline-none focus:ring-2 focus:ring-primary/25 focus:border-primary pr-10"
oninput="showSuggestions(this.value)"
/>
<i
class="fa-solid fa-chevron-down absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 text-xs pointer-events-none"
></i>
<!-- Dropdown suggestions -->
<div
id="municipio-dropdown"
class="hidden absolute left-0 right-0 top-full mt-1 bg-white border border-gray-200 rounded-xl shadow-lg z-30 overflow-hidden"
>
<button
type="button"
onclick="addMunicipio('Malhada')"
class="w-full text-left px-4 py-3 text-sm text-navy hover:bg-gray-50 border-b border-gray-100"
>
Malhada
</button>
<button
type="button"
onclick="addMunicipio('Igaporã')"
class="w-full text-left px-4 py-3 text-sm text-navy hover:bg-gray-50 border-b border-gray-100"
>
Igaporã
</button>
<button
type="button"
onclick="addMunicipio('Serra do Ramalho')"
class="w-full text-left px-4 py-3 text-sm text-navy hover:bg-gray-50"
>
Serra do Ramalho
</button>
</div>
</div>
<p class="text-xs text-gray-400 mt-1.5 flex items-center gap-1">
<i class="fa-solid fa-circle-info text-blue-400 text-xs"></i>
<span id="municipios-count">2 municípios selecionados</span>
</p>
</div>
<!-- Territórios de Identidade — read-only auto-derived -->
<div>
<label class="block text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1.5">
Territórios de Identidade
<span class="normal-case font-normal text-gray-400 ml-1"
>(preenchido automaticamente)</span
>
</label>
<div class="flex flex-wrap gap-2">
<span
class="inline-flex items-center gap-1.5 bg-amber-50 border border-amber-200 text-amber-800 text-xs font-semibold px-3 py-1.5 rounded-full"
>
<i class="fa-solid fa-lock text-amber-400 text-xs"></i> Velho Chico
</span>
<span
class="inline-flex items-center gap-1.5 bg-amber-50 border border-amber-200 text-amber-800 text-xs font-semibold px-3 py-1.5 rounded-full"
>
<i class="fa-solid fa-lock text-amber-400 text-xs"></i> Sertão do São Francisco
</span>
</div>
<p class="text-xs text-gray-400 mt-1.5">
Derivados dos municípios selecionados · não é possível editar
</p>
</div>
<!-- Bairros — disabled because 2 municípios selected -->
<div>
<label class="block text-xs font-semibold text-gray-400 uppercase tracking-wide mb-1.5"
>Bairros</label
>
<div
class="w-full border border-gray-200 rounded-xl px-3 py-3 bg-gray-50 text-gray-400 text-sm flex items-center gap-2 cursor-not-allowed"
>
<i class="fa-solid fa-ban text-gray-300 text-sm"></i>
Selecione municípios primeiro
</div>
<p class="text-xs text-amber-600 font-semibold mt-1.5 flex items-center gap-1">
<i class="fa-solid fa-triangle-exclamation text-xs"></i>
Bairros exigem um único município selecionado
</p>
</div>
<!-- ═══════════════════════════════════════ -->
<!-- TSE ZONES AUTO-FILL block -->
<!-- ═══════════════════════════════════════ -->
<div id="tse-zones-block">
<label class="block text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1.5"
>Zonas Eleitorais (TSE)</label
>
<!-- Info caption -->
<div
class="bg-blue-50 border border-blue-200 rounded-xl px-3 py-2.5 mb-3 flex items-start gap-2"
>
<i class="fa-solid fa-circle-info text-blue-500 text-sm mt-0.5 flex-shrink-0"></i>
<p class="text-xs text-blue-700">
Zonas sugeridas pelo cadastro oficial do TSE — confira antes de salvar.
</p>
</div>
<!-- Pre-checked zone chips -->
<div class="space-y-2" id="ze-chips">
<!-- Suggested + checked -->
<label
class="flex items-center gap-3 p-3 bg-gray-50 border border-gray-200 rounded-xl cursor-pointer ze-chip"
>
<input type="checkbox" checked class="w-5 h-5 rounded accent-primary flex-shrink-0" />
<div class="flex-1 min-w-0">
<div class="flex items-center gap-2">
<span class="font-mono font-bold text-navy text-sm">ZE 12</span>
<span
class="bg-blue-100 text-blue-700 text-xs font-semibold px-1.5 py-0.5 rounded"
>sugerida</span
>
</div>
<p class="text-xs text-gray-500 mt-0.5">Bom Jesus da Lapa</p>
</div>
</label>
<label
class="flex items-center gap-3 p-3 bg-gray-50 border border-gray-200 rounded-xl cursor-pointer ze-chip"
>
<input type="checkbox" checked class="w-5 h-5 rounded accent-primary flex-shrink-0" />
<div class="flex-1 min-w-0">
<div class="flex items-center gap-2">
<span class="font-mono font-bold text-navy text-sm">ZE 41</span>
<span
class="bg-blue-100 text-blue-700 text-xs font-semibold px-1.5 py-0.5 rounded"
>sugerida</span
>
</div>
<p class="text-xs text-gray-500 mt-0.5">Carinhanha</p>
</div>
</label>
<!-- Unchecked suggestion -->
<label
class="flex items-center gap-3 p-3 bg-gray-50 border border-gray-200 rounded-xl cursor-pointer ze-chip opacity-60"
>
<input type="checkbox" class="w-5 h-5 rounded accent-primary flex-shrink-0" />
<div class="flex-1 min-w-0">
<div class="flex items-center gap-2">
<span class="font-mono font-bold text-navy text-sm">ZE 7</span>
<span
class="bg-blue-100 text-blue-700 text-xs font-semibold px-1.5 py-0.5 rounded"
>sugerida</span
>
</div>
<p class="text-xs text-gray-500 mt-0.5">Carinhanha (zona adicional)</p>
</div>
</label>
</div>
<!-- Add custom zone -->
<button
type="button"
class="mt-2.5 flex items-center gap-2 text-primary text-xs font-semibold"
>
<i class="fa-solid fa-plus-circle text-sm"></i> Adicionar zona manualmente
</button>
</div>
</div>
<!-- end território block -->
<!-- Validation error example -->
<div
id="validation-error"
class="hidden bg-red-50 border border-red-200 rounded-xl p-3 flex items-start gap-2"
>
<i class="fa-solid fa-circle-xmark text-red-500 text-sm mt-0.5 flex-shrink-0"></i>
<p class="text-xs text-red-700">Selecione pelo menos um município para continuar.</p>
</div>
</form>
<!-- Bottom action bar -->
<div
class="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-200 px-4 py-4 flex gap-3 z-20"
>
<button
type="button"
class="flex-1 border border-gray-200 text-navy text-sm font-semibold py-3 rounded-xl hover:bg-gray-50 transition-colors"
>
Cancelar
</button>
<button
type="button"
class="flex-1 bg-primary text-white text-sm font-bold py-3 rounded-xl hover:bg-primary-light transition-colors flex items-center justify-center gap-2"
>
<i class="fa-solid fa-floppy-disk text-sm"></i> Salvar território
</button>
</div>
<script>
function showSuggestions(val) {
var dd = document.getElementById('municipio-dropdown')
dd.classList.toggle('hidden', val.length < 1)
}
function addMunicipio(name) {
document.getElementById('municipio-dropdown').classList.add('hidden')
document.getElementById('municipio-input').value = ''
var container = document.getElementById('municipios-chips')
var chip = document.createElement('span')
chip.className =
'inline-flex items-center gap-1.5 bg-navy text-white text-xs font-semibold px-3 py-1.5 rounded-full'
chip.innerHTML =
name +
'<button type="button" onclick="removeChip(this,\'municipios-chips\',\'municipios-count\')" class="chip-remove ml-0.5 opacity-70"><i class="fa-solid fa-xmark text-xs"></i></button>'
container.appendChild(chip)
updateCount()
}
function removeChip(btn, containerId, countId) {
btn.closest('span').remove()
updateCount()
}
function updateCount() {
var chips = document.querySelectorAll('#municipios-chips span')
var c = document.getElementById('municipios-count')
c.textContent =
chips.length +
' município' +
(chips.length !== 1 ? 's' : '') +
' selecionado' +
(chips.length !== 1 ? 's' : '')
}
document.addEventListener('click', function (e) {
if (!e.target.closest('#municipio-input') && !e.target.closest('#municipio-dropdown')) {
document.getElementById('municipio-dropdown').classList.add('hidden')
}
})
</script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

View file

@ -0,0 +1,443 @@
<!doctype html>
<html lang="pt-BR">
<head>
<script>
window.FontAwesomeConfig = {
autoReplaceSvg: 'nest',
}
</script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js"
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Importar CSV – Apoiadores</title>
<script src="https://cdn.tailwindcss.com"></script>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css"
/>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#8E0E23',
'primary-light': '#B01C35',
'primary-xlight': '#F9E8EB',
gold: '#C8874B',
'gold-light': '#FDF3EC',
navy: '#1B2B4B',
},
},
},
}
</script>
<style>
body {
font-family: 'Inter', system-ui, sans-serif;
}
</style>
</head>
<body class="bg-gray-50 flex">
<!-- Sidebar -->
<aside id="sidebar" class="w-60 min-h-screen bg-navy flex flex-col fixed top-0 left-0 z-30">
<div class="flex items-center gap-3 px-5 py-5 border-b border-white/10">
<div class="w-9 h-9 rounded-full bg-primary flex items-center justify-center flex-shrink-0">
<i class="fa-solid fa-star text-white text-sm"></i>
</div>
<div>
<p class="text-white font-bold text-sm leading-tight">Jorge Solla</p>
<p class="text-white/40 text-xs">Bahia · Dep. Federal</p>
</div>
</div>
<div class="px-5 py-3">
<span
class="inline-flex items-center gap-1.5 bg-primary/20 text-primary-xlight text-xs font-semibold px-3 py-1.5 rounded-full border border-primary/30"
>
<i class="fa-solid fa-shield-halved text-xs"></i> Coordenação Geral
</span>
</div>
<nav class="flex-1 px-3 py-2 space-y-0.5">
<a
href="#"
class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-white/60 hover:bg-white/10 hover:text-white text-sm transition-colors"
>
<i class="fa-solid fa-house w-4 text-center"></i> Início
</a>
<a
href="#"
class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-white/60 hover:bg-white/10 hover:text-white text-sm transition-colors"
>
<i class="fa-solid fa-layer-group w-4 text-center"></i> Núcleos
</a>
<a
href="#"
class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-white/60 hover:bg-white/10 hover:text-white text-sm transition-colors"
>
<i class="fa-solid fa-users w-4 text-center"></i> Lideranças
</a>
<a
href="#"
class="flex items-center gap-3 px-3 py-2.5 rounded-lg bg-primary/20 text-white font-semibold text-sm"
>
<i class="fa-solid fa-user-group w-4 text-center text-primary-xlight"></i> Apoiadores
</a>
<a
href="#"
class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-white/60 hover:bg-white/10 hover:text-white text-sm transition-colors"
>
<i class="fa-solid fa-calendar-days w-4 text-center"></i> Planos de ação
</a>
<a
href="#"
class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-white/60 hover:bg-white/10 hover:text-white text-sm transition-colors"
>
<i class="fa-solid fa-newspaper w-4 text-center"></i> Atualizações
</a>
<a
href="#"
class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-white/60 hover:bg-white/10 hover:text-white text-sm transition-colors"
>
<i class="fa-solid fa-map w-4 text-center"></i> Territórios
</a>
</nav>
<div class="px-4 py-4 border-t border-white/10 flex items-center gap-3">
<img
src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-2.jpg"
class="w-8 h-8 rounded-full object-cover"
/>
<div class="flex-1 min-w-0">
<p class="text-white text-xs font-semibold truncate">Carlos Mendes</p>
<p class="text-white/40 text-xs truncate">Coord. Geral</p>
</div>
<button class="text-white/40 hover:text-white">
<i class="fa-solid fa-arrow-right-from-bracket text-xs"></i>
</button>
</div>
</aside>
<!-- Main -->
<main class="ml-60 flex-1">
<header
id="topbar"
class="sticky top-0 z-20 bg-white border-b border-gray-200 px-8 py-4 flex items-center justify-between"
>
<div class="flex items-center gap-3">
<button class="text-gray-500 hover:text-navy p-1.5 rounded-lg hover:bg-gray-100">
<i class="fa-solid fa-arrow-left"></i>
</button>
<div>
<h1 class="text-lg font-bold text-navy">Importar apoiadores via CSV</h1>
<p class="text-xs text-gray-500">
Importe uma planilha para adicionar apoiadores em lote
</p>
</div>
</div>
<button class="relative text-gray-500 hover:text-navy p-2 rounded-lg hover:bg-gray-100">
<i class="fa-solid fa-bell text-lg"></i>
<span
class="absolute top-1.5 right-1.5 w-2 h-2 bg-primary rounded-full border border-white"
></span>
</button>
</header>
<div class="px-8 py-6 max-w-5xl">
<!-- Step indicator -->
<div id="step-indicator" class="flex items-center gap-0 mb-8">
<!-- Step 1 — completed -->
<div class="flex items-center gap-2">
<div
class="w-8 h-8 rounded-full bg-green-600 flex items-center justify-center flex-shrink-0"
>
<i class="fa-solid fa-check text-white text-xs"></i>
</div>
<span class="text-sm font-semibold text-green-700">Upload do arquivo</span>
</div>
<div class="flex-1 h-0.5 bg-primary mx-3"></div>
<!-- Step 2 — active -->
<div class="flex items-center gap-2">
<div
class="w-8 h-8 rounded-full bg-primary flex items-center justify-center flex-shrink-0"
>
<span class="text-white text-xs font-bold">2</span>
</div>
<span class="text-sm font-bold text-primary">Conferir prévia</span>
</div>
<div class="flex-1 h-0.5 bg-gray-200 mx-3"></div>
<!-- Step 3 — pending -->
<div class="flex items-center gap-2">
<div
class="w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center flex-shrink-0"
>
<span class="text-gray-500 text-xs font-bold">3</span>
</div>
<span class="text-sm text-gray-400">Confirmação</span>
</div>
</div>
<!-- ── STEP 1: Upload (shown as completed, for reference) ──────── -->
<!-- (would be the drag-drop zone — already past) -->
<!-- ── STEP 2: Preview table ──────────────────────────────────── -->
<section id="preview-section" class="space-y-4">
<!-- Summary chips -->
<div class="flex flex-wrap gap-3 items-center">
<div
class="flex items-center gap-2 bg-green-50 border border-green-200 text-green-700 text-sm font-semibold px-4 py-2 rounded-xl"
>
<i class="fa-solid fa-check-circle text-green-600"></i>
<span><strong>412</strong> prontos para importar</span>
</div>
<div
class="flex items-center gap-2 bg-amber-50 border border-amber-200 text-amber-700 text-sm font-semibold px-4 py-2 rounded-xl"
>
<i class="fa-solid fa-copy text-amber-600"></i>
<span><strong>37</strong> duplicados (pelo telefone)</span>
</div>
<div
class="flex items-center gap-2 bg-red-50 border border-red-200 text-red-700 text-sm font-semibold px-4 py-2 rounded-xl"
>
<i class="fa-solid fa-circle-xmark text-red-600"></i>
<span><strong>3</strong> erros</span>
</div>
<button
class="ml-auto text-xs text-primary font-semibold hover:underline flex items-center gap-1"
>
<i class="fa-solid fa-download"></i> Baixar relatório de erros
</button>
</div>
<!-- Preview table -->
<div class="bg-white border border-gray-200 rounded-xl shadow-sm overflow-hidden">
<div class="px-5 py-3 border-b border-gray-100 flex items-center justify-between">
<p class="text-sm font-semibold text-navy">Prévia — 452 linhas no arquivo</p>
<div class="flex gap-2">
<button
class="text-xs border border-gray-200 rounded-lg px-3 py-1.5 text-gray-600 hover:border-primary hover:text-primary"
>
Todos
</button>
<button
class="text-xs border border-gray-200 rounded-lg px-3 py-1.5 text-gray-600 hover:border-primary hover:text-primary bg-red-50 border-red-200 text-red-700"
>
Só erros
</button>
</div>
</div>
<div class="overflow-x-auto">
<table class="w-full text-sm">
<thead>
<tr class="bg-gray-50 border-b border-gray-200">
<th
class="text-left px-4 py-3 text-xs font-semibold text-gray-500 uppercase tracking-wide w-8"
>
#
</th>
<th
class="text-left px-4 py-3 text-xs font-semibold text-gray-500 uppercase tracking-wide"
>
Nome
</th>
<th
class="text-left px-4 py-3 text-xs font-semibold text-gray-500 uppercase tracking-wide"
>
Telefone
</th>
<th
class="text-left px-4 py-3 text-xs font-semibold text-gray-500 uppercase tracking-wide"
>
Município
</th>
<th
class="text-left px-4 py-3 text-xs font-semibold text-gray-500 uppercase tracking-wide"
>
Intenção
</th>
<th
class="text-left px-4 py-3 text-xs font-semibold text-gray-500 uppercase tracking-wide"
>
Status
</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-100">
<!-- Row OK -->
<tr class="hover:bg-gray-50">
<td class="px-4 py-3 text-xs text-gray-400">1</td>
<td class="px-4 py-3 font-medium text-navy">Maria das Dores Souza</td>
<td class="px-4 py-3 text-gray-700">(77) 9 9000-1111</td>
<td class="px-4 py-3 text-gray-700">Bom Jesus da Lapa</td>
<td class="px-4 py-3">
<span
class="bg-green-100 text-green-800 text-xs font-bold px-2 py-0.5 rounded-full"
>Certo</span
>
</td>
<td class="px-4 py-3">
<span
class="inline-flex items-center gap-1 bg-green-100 text-green-700 text-xs font-bold px-2.5 py-1 rounded-full"
>
<i class="fa-solid fa-check text-xs"></i> ok
</span>
</td>
</tr>
<!-- Row OK -->
<tr class="hover:bg-gray-50">
<td class="px-4 py-3 text-xs text-gray-400">2</td>
<td class="px-4 py-3 font-medium text-navy">Antônio Carlos Leal</td>
<td class="px-4 py-3 text-gray-700">(77) 9 9111-2222</td>
<td class="px-4 py-3 text-gray-700">Brumado</td>
<td class="px-4 py-3">
<span
class="bg-green-100 text-green-800 text-xs font-bold px-2 py-0.5 rounded-full"
>Tende a certo</span
>
</td>
<td class="px-4 py-3">
<span
class="inline-flex items-center gap-1 bg-green-100 text-green-700 text-xs font-bold px-2.5 py-1 rounded-full"
>
<i class="fa-solid fa-check text-xs"></i> ok
</span>
</td>
</tr>
<!-- Row DUPLICADO -->
<tr class="hover:bg-amber-50 bg-amber-50/50">
<td class="px-4 py-3 text-xs text-gray-400">3</td>
<td class="px-4 py-3 font-medium text-navy">Joelma Pereira</td>
<td class="px-4 py-3 text-gray-700">(75) 9 8200-3333</td>
<td class="px-4 py-3 text-gray-700">Feira de Santana</td>
<td class="px-4 py-3">
<span
class="bg-amber-100 text-amber-800 text-xs font-bold px-2 py-0.5 rounded-full"
>Indeciso</span
>
</td>
<td class="px-4 py-3">
<span
class="inline-flex items-center gap-1 bg-amber-100 text-amber-700 text-xs font-semibold px-2.5 py-1 rounded-full"
>
<i class="fa-solid fa-copy text-xs"></i> duplicado pelo telefone
</span>
</td>
</tr>
<!-- Row ERRO -->
<tr class="hover:bg-red-50 bg-red-50/40">
<td class="px-4 py-3 text-xs text-gray-400">4</td>
<td class="px-4 py-3 font-medium text-navy">Roberto Bispo</td>
<td class="px-4 py-3 text-red-600 font-semibold">—</td>
<td class="px-4 py-3 text-gray-700">Vitória da Conquista</td>
<td class="px-4 py-3"><span class="text-xs text-gray-400 italic">—</span></td>
<td class="px-4 py-3">
<span
class="inline-flex items-center gap-1 bg-red-100 text-red-700 text-xs font-semibold px-2.5 py-1 rounded-full"
>
<i class="fa-solid fa-xmark text-xs"></i> telefone inválido
</span>
</td>
</tr>
<!-- Row OK -->
<tr class="hover:bg-gray-50">
<td class="px-4 py-3 text-xs text-gray-400">5</td>
<td class="px-4 py-3 font-medium text-navy">Simone Oliveira</td>
<td class="px-4 py-3 text-gray-700">(77) 9 9444-5555</td>
<td class="px-4 py-3 text-gray-700">Caetité</td>
<td class="px-4 py-3">
<span
class="bg-green-100 text-green-800 text-xs font-bold px-2 py-0.5 rounded-full"
>Certo</span
>
</td>
<td class="px-4 py-3">
<span
class="inline-flex items-center gap-1 bg-green-100 text-green-700 text-xs font-bold px-2.5 py-1 rounded-full"
>
<i class="fa-solid fa-check text-xs"></i> ok
</span>
</td>
</tr>
<!-- Row ERRO -->
<tr class="hover:bg-red-50 bg-red-50/40">
<td class="px-4 py-3 text-xs text-gray-400">6</td>
<td class="px-4 py-3 font-medium text-navy">Fernanda Costa</td>
<td class="px-4 py-3 text-gray-700">(71) 9 7777-8888</td>
<td class="px-4 py-3 text-red-600 font-semibold">Municipio Invalido</td>
<td class="px-4 py-3"><span class="text-xs text-gray-400 italic">—</span></td>
<td class="px-4 py-3">
<span
class="inline-flex items-center gap-1 bg-red-100 text-red-700 text-xs font-semibold px-2.5 py-1 rounded-full"
>
<i class="fa-solid fa-xmark text-xs"></i> município não reconhecido
</span>
</td>
</tr>
</tbody>
</table>
</div>
<div class="px-5 py-3 border-t border-gray-100 bg-gray-50 text-xs text-gray-500">
Mostrando 6 de 452 linhas ·
<span class="text-primary font-semibold cursor-pointer">Ver todas</span>
</div>
</div>
<!-- Action row -->
<div class="flex items-center justify-between pt-2">
<button
class="flex items-center gap-2 text-sm text-gray-600 border border-gray-200 rounded-xl px-4 py-2.5 hover:bg-gray-100 transition-colors"
>
<i class="fa-solid fa-arrow-left text-xs"></i> Voltar e substituir arquivo
</button>
<div class="flex items-center gap-3">
<p class="text-xs text-gray-500">
Serão importados <strong class="text-navy">412 apoiadores</strong> · 37 duplicados
ignorados · 3 erros pulados
</p>
<button
class="bg-primary text-white text-sm font-bold px-6 py-2.5 rounded-xl hover:bg-primary-light transition-colors flex items-center gap-2"
>
<i class="fa-solid fa-file-import"></i> Confirmar importação
</button>
</div>
</div>
<!-- ── STEP 3: Confirmation summary (success state shown below — would appear after confirm) ── -->
<div
id="confirmation-summary"
class="bg-green-50 border border-green-200 rounded-xl p-6 text-center mt-4"
>
<div
class="w-14 h-14 rounded-full bg-green-100 flex items-center justify-center mx-auto mb-3"
>
<i class="fa-solid fa-check-circle text-green-600 text-2xl"></i>
</div>
<h3 class="text-base font-bold text-green-800 mb-1">Importação concluída!</h3>
<p class="text-sm text-green-700 mb-4">
<strong>412 importados</strong> · <strong>37 duplicados ignorados</strong> ·
<strong>3 erros</strong>
</p>
<div class="flex items-center justify-center gap-3">
<button
class="text-sm text-gray-600 border border-gray-200 rounded-xl px-4 py-2 hover:bg-gray-50"
>
Baixar relatório
</button>
<button
class="bg-primary text-white text-sm font-bold px-5 py-2 rounded-xl hover:bg-primary-light"
>
Ver apoiadores
</button>
</div>
</div>
</section>
</div>
</main>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 KiB

View file

@ -0,0 +1,450 @@
<!doctype html>
<html lang="pt-BR">
<head>
<script>
window.FontAwesomeConfig = {
autoReplaceSvg: 'nest',
}
</script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js"
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Núcleos – Visão Geral</title>
<script src="https://cdn.tailwindcss.com"></script>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css"
/>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#8E0E23',
'primary-light': '#B01C35',
'primary-xlight': '#F9E8EB',
gold: '#C8874B',
'gold-light': '#FDF3EC',
navy: '#1B2B4B',
},
},
},
}
</script>
<style>
body {
font-family: 'Inter', system-ui, sans-serif;
}
</style>
</head>
<body class="bg-gray-50 pb-24">
<!-- Header -->
<header
id="header"
class="bg-navy sticky top-0 z-20 px-4 py-3 flex items-center justify-between"
>
<div class="flex items-center gap-3">
<div class="w-7 h-7 rounded-full bg-primary flex items-center justify-center flex-shrink-0">
<i class="fa-solid fa-star text-white text-xs"></i>
</div>
<h1 class="text-white font-bold text-sm">Núcleos Eleitorais</h1>
</div>
<div class="flex items-center gap-2">
<button class="relative text-white/70 p-1.5">
<i class="fa-solid fa-bell text-base"></i>
<span
class="absolute top-1 right-1 w-2 h-2 bg-primary rounded-full border border-navy"
></span>
</button>
<button
class="bg-primary text-white text-xs font-semibold px-3 py-1.5 rounded-lg flex items-center gap-1.5"
>
<i class="fa-solid fa-plus text-xs"></i> Novo
</button>
</div>
</header>
<!-- Scope badge -->
<div class="px-4 pt-3 pb-1">
<span
class="inline-flex items-center gap-1.5 bg-gold-light border border-gold/30 text-xs font-semibold text-navy px-3 py-1.5 rounded-full"
>
<i class="fa-solid fa-shield-halved text-gold text-xs"></i> Coordenação Geral · vê todos os
núcleos
</span>
</div>
<!-- Search + Filter -->
<div class="px-4 pt-2 pb-3 space-y-2">
<div class="relative">
<input
type="text"
placeholder="Buscar núcleo ou zona…"
class="w-full pl-9 pr-4 py-2.5 text-sm border border-gray-200 rounded-xl bg-white focus:outline-none focus:ring-2 focus:ring-primary/20 text-navy placeholder-gray-300"
/>
<i
class="fa-solid fa-magnifying-glass absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 text-sm"
></i>
</div>
<!-- Active filter chips -->
<div class="flex gap-2 flex-wrap">
<span
class="inline-flex items-center gap-1.5 bg-navy text-white text-xs font-semibold px-2.5 py-1 rounded-full"
>
Velho Chico
<button class="ml-0.5 opacity-70"><i class="fa-solid fa-xmark text-xs"></i></button>
</span>
<span
class="inline-flex items-center gap-1.5 bg-navy text-white text-xs font-semibold px-2.5 py-1 rounded-full"
>
ZE 12 <button class="ml-0.5 opacity-70"><i class="fa-solid fa-xmark text-xs"></i></button>
</span>
<button class="text-xs text-primary font-semibold">+ Filtros</button>
</div>
</div>
<!-- ════════════════════════════════ -->
<!-- OVERVIEW PANEL -->
<!-- ════════════════════════════════ -->
<section id="overview-panel" class="px-4 space-y-3 mb-4">
<!-- Caption -->
<p class="text-xs text-gray-500 flex items-center gap-1.5">
<i class="fa-solid fa-filter text-gray-400 text-xs"></i>
Mostrando agregados de <strong class="text-navy mx-0.5">14 núcleos</strong> filtrados
</p>
<!-- Estimativa de votos -->
<div id="card-estimativa" class="bg-white border border-gray-200 rounded-xl shadow-sm p-4">
<div class="flex items-start justify-between mb-3">
<div>
<p class="text-xs text-gray-500 font-semibold uppercase tracking-wide mb-1">
Estimativa de votos
</p>
<div class="flex items-baseline gap-2">
<span class="text-3xl font-extrabold text-navy leading-none">18.740</span>
</div>
<p class="text-xs text-gray-400 mt-0.5">votos estimados nos 14 núcleos</p>
</div>
<div
class="w-9 h-9 rounded-xl bg-primary-xlight flex items-center justify-center flex-shrink-0"
>
<i class="fa-solid fa-ballot-check text-primary"></i>
</div>
</div>
<!-- Progress -->
<div class="mb-3">
<div class="flex items-center justify-between text-xs mb-1">
<span class="text-gray-600">Com estimativa confirmada</span>
<span class="font-bold text-green-700">71%</span>
</div>
<div class="h-2 bg-gray-100 rounded-full overflow-hidden">
<div class="h-full bg-green-500 rounded-full" style="width: 71%"></div>
</div>
<p class="text-xs text-gray-400 mt-1">10 confirmadas · 4 pendentes</p>
</div>
<span
class="inline-flex items-center gap-1.5 bg-amber-50 border border-amber-200 text-amber-700 text-xs font-semibold px-2.5 py-1 rounded-full"
>
<i class="fa-solid fa-clock text-xs"></i> 3 sugestões pendentes
</span>
</div>
<!-- Cobertura + Baseline 2022 (two-col) -->
<div class="grid grid-cols-2 gap-3">
<!-- Cobertura -->
<div id="card-cobertura" class="bg-white border border-gray-200 rounded-xl shadow-sm p-3.5">
<div class="flex items-center justify-between mb-2">
<p class="text-xs text-gray-500 font-semibold uppercase tracking-wide">Cobertura</p>
<i class="fa-solid fa-user-shield text-blue-500 text-sm"></i>
</div>
<p class="text-2xl font-extrabold text-navy leading-none mb-1">86%</p>
<div class="h-1.5 bg-gray-100 rounded-full overflow-hidden mb-1.5">
<div class="h-full bg-blue-500 rounded-full" style="width: 86%"></div>
</div>
<p class="text-xs text-gray-400">12 de 14 com coordenador</p>
</div>
<!-- Baseline 2022 -->
<div id="card-baseline" class="bg-white border border-gray-200 rounded-xl shadow-sm p-3.5">
<div class="flex items-center justify-between mb-2">
<p class="text-xs text-gray-500 font-semibold uppercase tracking-wide">Baseline 2022</p>
<i class="fa-solid fa-chart-line text-primary text-sm"></i>
</div>
<p class="text-xl font-extrabold text-navy leading-none mb-1">+2.140</p>
<p class="text-xs text-gray-400 mb-2">votos acima do patamar</p>
<div class="flex flex-col gap-1 text-xs">
<span class="text-green-700 font-semibold flex items-center gap-1"
><i class="fa-solid fa-arrow-up text-xs"></i> 8 acima</span
>
<span class="text-amber-600 font-semibold flex items-center gap-1"
><i class="fa-solid fa-arrow-down text-xs"></i> 6 abaixo</span
>
</div>
</div>
</div>
<!-- Últimas atualizações -->
<div id="card-updates" class="bg-white border border-gray-200 rounded-xl shadow-sm p-4">
<div class="flex items-center justify-between mb-3">
<p class="text-xs text-gray-500 font-semibold uppercase tracking-wide">
Últimas atualizações
</p>
<a href="#" class="text-xs text-primary font-semibold">Ver todas</a>
</div>
<div class="space-y-3">
<!-- Row 1 -->
<div class="flex items-start gap-3">
<img
src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-3.jpg"
class="w-8 h-8 rounded-full object-cover flex-shrink-0"
/>
<div class="flex-1 min-w-0">
<div class="flex items-center gap-2 mb-0.5">
<span
class="bg-primary-xlight text-primary text-xs font-bold px-2 py-0.5 rounded-full"
>Semanal</span
>
<span class="text-xs text-gray-400">há 1 dia</span>
</div>
<p class="text-xs text-gray-700">
João S. · <span class="text-primary font-medium">Quilombo Rio das Rãs</span>
</p>
</div>
</div>
<!-- Row 2 -->
<div class="flex items-start gap-3">
<img
src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-5.jpg"
class="w-8 h-8 rounded-full object-cover flex-shrink-0"
/>
<div class="flex-1 min-w-0">
<div class="flex items-center gap-2 mb-0.5">
<span class="bg-amber-50 text-amber-700 text-xs font-bold px-2 py-0.5 rounded-full"
>Urgente</span
>
<span class="text-xs text-gray-400">há 2 dias</span>
</div>
<p class="text-xs text-gray-700">
Maria L. · <span class="text-primary font-medium">Sindicato Rural Oeste</span>
</p>
</div>
</div>
<!-- Row 3 -->
<div class="flex items-start gap-3">
<img
src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-4.jpg"
class="w-8 h-8 rounded-full object-cover flex-shrink-0"
/>
<div class="flex-1 min-w-0">
<div class="flex items-center gap-2 mb-0.5">
<span class="bg-gray-100 text-gray-600 text-xs font-bold px-2 py-0.5 rounded-full"
>Nota</span
>
<span class="text-xs text-gray-400">há 3 dias</span>
</div>
<p class="text-xs text-gray-700">
Pedro A. · <span class="text-primary font-medium">Igreja Batista Central</span>
</p>
</div>
</div>
</div>
</div>
</section>
<!-- end overview panel -->
<!-- List header -->
<div class="px-4 mb-2">
<p class="text-xs text-gray-500 font-semibold uppercase tracking-wide">
14 núcleos filtrados
</p>
</div>
<!-- Nuclei list -->
<section id="nucleos-list" class="px-4 space-y-2">
<!-- Item 1 -->
<div
class="bg-white border border-gray-200 rounded-xl shadow-sm p-4 cursor-pointer active:bg-gray-50 transition-colors"
>
<div class="flex items-start justify-between mb-2">
<div class="flex-1 min-w-0">
<p class="font-bold text-navy text-sm">Quilombo Rio das Rãs</p>
<p class="text-xs text-gray-500">
Bom Jesus da Lapa ·
<span
class="font-mono font-semibold bg-gray-100 text-gray-600 px-1.5 py-0.5 rounded text-xs"
>ZE 12</span
>
</p>
</div>
<span class="bg-green-100 text-green-800 text-xs font-bold px-2 py-0.5 rounded-full ml-2"
>Confirmada</span
>
</div>
<div class="flex items-center gap-4 text-xs text-gray-600">
<span><i class="fa-solid fa-users text-gray-400 mr-1"></i>12 lideranças</span>
<span><i class="fa-solid fa-ballot-check text-gray-400 mr-1"></i>1.200 votos</span>
<span class="text-green-700 font-semibold ml-auto"
><i class="fa-solid fa-arrow-up text-xs mr-0.5"></i>+12%</span
>
</div>
</div>
<!-- Item 2 -->
<div
class="bg-white border border-gray-200 rounded-xl shadow-sm p-4 cursor-pointer active:bg-gray-50 transition-colors"
>
<div class="flex items-start justify-between mb-2">
<div class="flex-1 min-w-0">
<p class="font-bold text-navy text-sm">Sindicato Rural Oeste</p>
<p class="text-xs text-gray-500">
Brumado ·
<span
class="font-mono font-semibold bg-gray-100 text-gray-600 px-1.5 py-0.5 rounded text-xs"
>ZE 5</span
>
<span
class="font-mono font-semibold bg-gray-100 text-gray-600 px-1.5 py-0.5 rounded text-xs"
>ZE 7</span
>
</p>
</div>
<span
class="bg-amber-100 text-amber-800 text-xs font-bold px-2 py-0.5 rounded-full ml-2 whitespace-nowrap"
>Sugestão pend.</span
>
</div>
<div class="flex items-center gap-4 text-xs text-gray-600">
<span><i class="fa-solid fa-users text-gray-400 mr-1"></i>16 lideranças</span>
<span><i class="fa-solid fa-ballot-check text-gray-400 mr-1"></i>3.400 votos</span>
<span class="text-amber-600 font-semibold ml-auto"
><i class="fa-solid fa-arrow-down text-xs mr-0.5"></i>−8%</span
>
</div>
</div>
<!-- Item 3 -->
<div
class="bg-white border border-amber-200 rounded-xl shadow-sm p-4 cursor-pointer active:bg-gray-50 transition-colors"
>
<div class="flex items-start justify-between mb-2">
<div class="flex-1 min-w-0">
<p class="font-bold text-navy text-sm">Assentamento Vitória</p>
<p class="text-xs text-gray-500">
Feira de Santana ·
<span
class="font-mono font-semibold bg-gray-100 text-gray-600 px-1.5 py-0.5 rounded text-xs"
>ZE 5</span
>
</p>
</div>
<span class="bg-green-100 text-green-800 text-xs font-bold px-2 py-0.5 rounded-full ml-2"
>Confirmada</span
>
</div>
<div class="flex items-center gap-4 text-xs text-gray-600">
<span><i class="fa-solid fa-users text-gray-400 mr-1"></i>7 lideranças</span>
<span><i class="fa-solid fa-ballot-check text-gray-400 mr-1"></i>900 votos</span>
<span class="text-amber-600 font-semibold ml-auto flex items-center gap-1"
><i class="fa-solid fa-triangle-exclamation text-xs"></i>Sem coord.</span
>
</div>
</div>
<!-- Item 4 -->
<div
class="bg-white border border-gray-200 rounded-xl shadow-sm p-4 cursor-pointer active:bg-gray-50 transition-colors"
>
<div class="flex items-start justify-between mb-2">
<div class="flex-1 min-w-0">
<p class="font-bold text-navy text-sm">Igreja Batista Central</p>
<p class="text-xs text-gray-500">
Vitória da Conquista ·
<span
class="font-mono font-semibold bg-gray-100 text-gray-600 px-1.5 py-0.5 rounded text-xs"
>ZE 8</span
>
</p>
</div>
<span
class="bg-amber-100 text-amber-800 text-xs font-bold px-2 py-0.5 rounded-full ml-2 whitespace-nowrap"
>Sugestão pend.</span
>
</div>
<div class="flex items-center gap-4 text-xs text-gray-600">
<span><i class="fa-solid fa-users text-gray-400 mr-1"></i>11 lideranças</span>
<span><i class="fa-solid fa-ballot-check text-gray-400 mr-1"></i>650 votos</span>
<span class="text-amber-600 font-semibold ml-auto"
><i class="fa-solid fa-arrow-down text-xs mr-0.5"></i>−5%</span
>
</div>
</div>
<!-- Item 5 -->
<div
class="bg-white border border-gray-200 rounded-xl shadow-sm p-4 cursor-pointer active:bg-gray-50 transition-colors"
>
<div class="flex items-start justify-between mb-2">
<div class="flex-1 min-w-0">
<p class="font-bold text-navy text-sm">Quilombo Palmares II</p>
<p class="text-xs text-gray-500">
Caetité · <span class="text-gray-400 italic text-xs">sem ZE</span>
</p>
</div>
<span class="bg-gray-100 text-gray-600 text-xs font-bold px-2 py-0.5 rounded-full ml-2"
>Sem estimativa</span
>
</div>
<div class="flex items-center gap-4 text-xs text-gray-600">
<span><i class="fa-solid fa-users text-gray-400 mr-1"></i>4 lideranças</span>
<span><i class="fa-solid fa-ballot-check text-gray-400 mr-1"></i>—</span>
<span class="text-amber-600 font-semibold ml-auto flex items-center gap-1"
><i class="fa-solid fa-triangle-exclamation text-xs"></i>Sem coord.</span
>
</div>
</div>
<p class="text-center text-xs text-gray-400 py-3">
Mostrando 5 de 14 · <span class="text-primary font-semibold">Ver mais</span>
</p>
</section>
<!-- FAB -->
<div class="fixed bottom-20 right-4 z-30">
<button
class="bg-primary text-white w-14 h-14 rounded-full shadow-xl flex items-center justify-center"
>
<i class="fa-solid fa-plus text-xl"></i>
</button>
</div>
<!-- Bottom nav -->
<nav
id="bottom-nav"
class="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-200 flex z-20"
>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-gray-400">
<i class="fa-solid fa-house text-base"></i>
<span class="text-xs mt-0.5">Início</span>
</a>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-primary">
<i class="fa-solid fa-layer-group text-base"></i>
<span class="text-xs mt-0.5 font-semibold">Núcleos</span>
</a>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-gray-400">
<i class="fa-solid fa-user-group text-base"></i>
<span class="text-xs mt-0.5">Apoiadores</span>
</a>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-gray-400">
<i class="fa-solid fa-calendar-days text-base"></i>
<span class="text-xs mt-0.5">Agenda</span>
</a>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-gray-400">
<i class="fa-solid fa-users text-base"></i>
<span class="text-xs mt-0.5">Lideranças</span>
</a>
</nav>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

View file

@ -0,0 +1,264 @@
<!doctype html>
<html lang="pt-BR">
<head>
<script>
window.FontAwesomeConfig = {
autoReplaceSvg: 'nest',
}
</script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js"
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Notificações</title>
<script src="https://cdn.tailwindcss.com"></script>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css"
/>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#8E0E23',
'primary-light': '#B01C35',
'primary-xlight': '#F9E8EB',
gold: '#C8874B',
'gold-light': '#FDF3EC',
navy: '#1B2B4B',
},
},
},
}
</script>
<style>
body {
font-family: 'Inter', system-ui, sans-serif;
}
</style>
</head>
<body class="bg-gray-50 pb-24" style="min-height: 840px; position: relative">
<!-- Background: Inicio Coordenador blurred behind sheet -->
<!-- Main screen content (dimmed) -->
<div class="opacity-30 pointer-events-none">
<header class="bg-navy px-4 py-3 flex items-center justify-between">
<div class="flex items-center gap-3">
<div
class="w-7 h-7 rounded-full bg-primary flex items-center justify-center flex-shrink-0"
>
<i class="fa-solid fa-star text-white text-xs"></i>
</div>
<h1 class="text-white font-bold text-sm">Início</h1>
</div>
<button class="relative text-white/70 p-1.5">
<i class="fa-solid fa-bell text-xl"></i>
<span
class="absolute top-1 right-1 w-2.5 h-2.5 bg-primary rounded-full border-2 border-navy"
></span>
</button>
</header>
<div class="px-4 pt-3">
<span
class="inline-flex items-center gap-1.5 bg-gold-light border border-gold/30 text-xs font-semibold text-navy px-3 py-1.5 rounded-full"
>
<i class="fa-solid fa-shield-halved text-gold text-xs"></i> Coordenação Geral
</span>
</div>
<div class="px-4 pt-4 grid grid-cols-2 gap-3">
<div class="bg-white border border-gray-200 rounded-xl p-4 shadow-sm">
<p class="text-xs text-gray-500">Núcleos ativos</p>
<p class="text-2xl font-extrabold text-navy">47</p>
</div>
<div class="bg-white border border-gray-200 rounded-xl p-4 shadow-sm">
<p class="text-xs text-gray-500">Apoiadores</p>
<p class="text-2xl font-extrabold text-navy">1.847</p>
</div>
</div>
</div>
<!-- ════════════════════════════════ -->
<!-- NOTIFICATION CENTER SHEET -->
<!-- ════════════════════════════════ -->
<div class="absolute inset-0 bg-black/40 flex items-end" style="z-index: 50">
<div
id="notif-sheet"
class="w-full bg-white rounded-t-2xl shadow-2xl"
style="max-height: 640px; display: flex; flex-direction: column"
>
<!-- Handle -->
<div class="flex justify-center pt-3 pb-0 flex-shrink-0">
<div class="w-10 h-1 bg-gray-300 rounded-full"></div>
</div>
<!-- Sheet header -->
<div
class="px-5 pt-3 pb-3 border-b border-gray-100 flex items-center justify-between flex-shrink-0"
>
<div>
<h2 class="text-base font-bold text-navy">Notificações</h2>
<span class="text-xs text-primary font-semibold">4 não lidas</span>
</div>
<div class="flex items-center gap-3">
<button class="text-xs text-primary font-semibold hover:underline">
Marcar todas como lidas
</button>
<button class="text-gray-400 hover:text-navy p-1 rounded-lg">
<i class="fa-solid fa-xmark text-lg"></i>
</button>
</div>
</div>
<!-- Notifications list -->
<div class="overflow-y-auto flex-1 divide-y divide-gray-50 px-1">
<!-- Unread -->
<div
class="flex items-start gap-3 px-4 py-4 bg-primary-xlight/40 cursor-pointer active:bg-primary-xlight"
>
<div
class="w-9 h-9 rounded-full bg-amber-100 flex items-center justify-center flex-shrink-0 mt-0.5"
>
<i class="fa-solid fa-clock text-amber-600 text-sm"></i>
</div>
<div class="flex-1 min-w-0">
<p class="text-sm font-bold text-navy leading-snug">
Estimativa aguardando confirmação — Núcleo Quilombo Rio das Rãs
</p>
<p class="text-xs text-gray-500 mt-0.5">
João Santos sugeriu 1.200 votos · confirme ou ajuste
</p>
<p class="text-xs text-primary font-semibold mt-1">há 2 horas</p>
</div>
<div class="w-2 h-2 bg-primary rounded-full flex-shrink-0 mt-2"></div>
</div>
<!-- Unread -->
<div
class="flex items-start gap-3 px-4 py-4 bg-primary-xlight/40 cursor-pointer active:bg-primary-xlight"
>
<div
class="w-9 h-9 rounded-full bg-green-100 flex items-center justify-center flex-shrink-0 mt-0.5"
>
<i class="fa-solid fa-user-plus text-green-600 text-sm"></i>
</div>
<div class="flex-1 min-w-0">
<p class="text-sm font-bold text-navy leading-snug">
Novo apoiador cadastrado — Sindicato Rural Oeste
</p>
<p class="text-xs text-gray-500 mt-0.5">Maria Lima adicionou Antônio Carlos Leal</p>
<p class="text-xs text-primary font-semibold mt-1">há 4 horas</p>
</div>
<div class="w-2 h-2 bg-primary rounded-full flex-shrink-0 mt-2"></div>
</div>
<!-- Unread -->
<div
class="flex items-start gap-3 px-4 py-4 bg-primary-xlight/40 cursor-pointer active:bg-primary-xlight"
>
<div
class="w-9 h-9 rounded-full bg-blue-100 flex items-center justify-center flex-shrink-0 mt-0.5"
>
<i class="fa-solid fa-newspaper text-blue-600 text-sm"></i>
</div>
<div class="flex-1 min-w-0">
<p class="text-sm font-bold text-navy leading-snug">
Novo reporte de campo — Igreja Batista Central
</p>
<p class="text-xs text-gray-500 mt-0.5">
Pedro Alves publicou uma atualização urgente
</p>
<p class="text-xs text-primary font-semibold mt-1">há 1 dia</p>
</div>
<div class="w-2 h-2 bg-primary rounded-full flex-shrink-0 mt-2"></div>
</div>
<!-- Unread -->
<div
class="flex items-start gap-3 px-4 py-4 bg-primary-xlight/40 cursor-pointer active:bg-primary-xlight"
>
<div
class="w-9 h-9 rounded-full bg-red-100 flex items-center justify-center flex-shrink-0 mt-0.5"
>
<i class="fa-solid fa-calendar-xmark text-red-600 text-sm"></i>
</div>
<div class="flex-1 min-w-0">
<p class="text-sm font-bold text-navy leading-snug">
Plano de ação precisa de atenção — Comício (Rascunho)
</p>
<p class="text-xs text-gray-500 mt-0.5">
Data ainda não definida · confirme ou cancele
</p>
<p class="text-xs text-primary font-semibold mt-1">há 2 dias</p>
</div>
<div class="w-2 h-2 bg-primary rounded-full flex-shrink-0 mt-2"></div>
</div>
<!-- Read -->
<div class="flex items-start gap-3 px-4 py-3.5 cursor-pointer active:bg-gray-50">
<div
class="w-9 h-9 rounded-full bg-gray-100 flex items-center justify-center flex-shrink-0 mt-0.5"
>
<i class="fa-solid fa-file-import text-gray-500 text-sm"></i>
</div>
<div class="flex-1 min-w-0">
<p class="text-sm font-semibold text-gray-700 leading-snug">
Importação de CSV concluída
</p>
<p class="text-xs text-gray-400 mt-0.5">
412 apoiadores importados · 37 duplicados ignorados
</p>
<p class="text-xs text-gray-400 mt-1">há 3 dias</p>
</div>
</div>
<!-- Read -->
<div class="flex items-start gap-3 px-4 py-3.5 cursor-pointer active:bg-gray-50">
<div
class="w-9 h-9 rounded-full bg-gray-100 flex items-center justify-center flex-shrink-0 mt-0.5"
>
<i class="fa-solid fa-user-shield text-gray-500 text-sm"></i>
</div>
<div class="flex-1 min-w-0">
<p class="text-sm font-semibold text-gray-700 leading-snug">
Bem-vindo ao Solla Campanha!
</p>
<p class="text-xs text-gray-400 mt-0.5">
Seu acesso de Coordenação Geral foi ativado
</p>
<p class="text-xs text-gray-400 mt-1">há 12 dias</p>
</div>
</div>
</div>
<!-- PWA install prompt inside sheet footer -->
<div
id="pwa-prompt"
class="flex-shrink-0 mx-4 my-3 bg-navy text-white rounded-xl p-3 flex items-center gap-3"
>
<div class="w-9 h-9 rounded-xl bg-primary flex items-center justify-center flex-shrink-0">
<i class="fa-solid fa-mobile-screen text-white text-sm"></i>
</div>
<div class="flex-1 min-w-0">
<p class="text-xs font-bold leading-snug">Instale o app da campanha</p>
<p class="text-xs text-white/60 mt-0.5">Acesse mais rápido e receba avisos</p>
</div>
<button class="bg-white text-navy text-xs font-bold px-3 py-1.5 rounded-lg flex-shrink-0">
Instalar
</button>
<button class="text-white/50 p-1 flex-shrink-0">
<i class="fa-solid fa-xmark text-xs"></i>
</button>
</div>
</div>
</div>
<!-- ════════════════════════════════ -->
<!-- PUSH OPT-IN SCREEN -->
<!-- (shown as a separate card below, for reference) -->
<!-- In production this appears on its own route -->
<!-- ════════════════════════════════ -->
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

View file

@ -0,0 +1,283 @@
<!doctype html>
<html lang="pt-BR">
<head>
<script>
window.FontAwesomeConfig = {
autoReplaceSvg: 'nest',
}
</script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js"
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Novo Plano de Ação</title>
<script src="https://cdn.tailwindcss.com"></script>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css"
/>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#8E0E23',
'primary-light': '#B01C35',
'primary-xlight': '#F9E8EB',
gold: '#C8874B',
'gold-light': '#FDF3EC',
navy: '#1B2B4B',
},
},
},
}
</script>
<style>
body {
font-family: 'Inter', system-ui, sans-serif;
}
</style>
</head>
<body class="bg-gray-50 pb-28">
<!-- Header -->
<header id="header" class="bg-navy sticky top-0 z-20 px-4 py-3 flex items-center gap-3">
<button class="text-white p-1"><i class="fa-solid fa-arrow-left text-lg"></i></button>
<div class="flex-1">
<h1 class="text-white font-bold text-sm">Novo Plano de Ação</h1>
<p class="text-white/60 text-xs">Preencha os dados do evento</p>
</div>
</header>
<!-- Scope badge -->
<div class="px-4 pt-3 pb-1">
<span
class="inline-flex items-center gap-1.5 bg-gold-light border border-gold/30 text-xs font-semibold text-navy px-3 py-1.5 rounded-full"
>
<i class="fa-solid fa-shield-halved text-gold text-xs"></i> Coordenação Geral
</span>
</div>
<form class="px-4 pt-4 space-y-4" onsubmit="return false">
<!-- Informações básicas -->
<div class="bg-white border border-gray-200 rounded-xl shadow-sm p-4 space-y-4">
<h3 class="text-sm font-bold text-navy">Informações básicas</h3>
<div>
<label class="block text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1.5"
>Título <span class="text-primary">*</span></label
>
<input
type="text"
placeholder="Ex: Caminhada no Centro Histórico"
class="w-full border border-gray-200 rounded-xl px-3 py-3 text-sm text-navy focus:outline-none focus:ring-2 focus:ring-primary/25 focus:border-primary placeholder-gray-300"
/>
</div>
<div>
<label class="block text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1.5"
>Tipo de ação <span class="text-primary">*</span></label
>
<select
class="w-full border border-gray-200 rounded-xl px-3 py-3 text-sm text-navy focus:outline-none focus:ring-2 focus:ring-primary/25 bg-white"
>
<option value="" disabled selected>Selecione o tipo…</option>
<option>Caminhada</option>
<option>Comício</option>
<option>Carreata</option>
<option>Panfletagem</option>
<option>Porta a porta</option>
<option>Reunião de apoio</option>
<option>Outro</option>
</select>
</div>
<div>
<label class="block text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1.5"
>Descrição (opcional)</label
>
<textarea
rows="3"
placeholder="Contexto, objetivo e observações do plano…"
class="w-full border border-gray-200 rounded-xl px-3 py-3 text-sm text-navy focus:outline-none focus:ring-2 focus:ring-primary/25 focus:border-primary placeholder-gray-300 resize-none"
></textarea>
</div>
</div>
<!-- Data e horário -->
<div class="bg-white border border-gray-200 rounded-xl shadow-sm p-4 space-y-4">
<h3 class="text-sm font-bold text-navy">Data e horário</h3>
<div class="grid grid-cols-2 gap-3">
<div>
<label class="block text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1.5"
>Data <span class="text-primary">*</span></label
>
<input
type="date"
class="w-full border border-gray-200 rounded-xl px-3 py-3 text-sm text-navy focus:outline-none focus:ring-2 focus:ring-primary/25 bg-white"
/>
</div>
<div>
<label class="block text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1.5"
>Início <span class="text-primary">*</span></label
>
<input
type="time"
class="w-full border border-gray-200 rounded-xl px-3 py-3 text-sm text-navy focus:outline-none focus:ring-2 focus:ring-primary/25 bg-white"
/>
</div>
</div>
<div>
<label class="block text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1.5"
>Término (opcional)</label
>
<input
type="time"
class="w-full border border-gray-200 rounded-xl px-3 py-3 text-sm text-navy focus:outline-none focus:ring-2 focus:ring-primary/25 bg-white"
placeholder="—"
/>
<p class="text-xs text-gray-400 mt-1">Deixe em branco se a duração for indefinida</p>
</div>
</div>
<!-- Território (multi-município — same pattern as Territory Form) -->
<div class="bg-white border border-gray-200 rounded-xl shadow-sm p-4 space-y-4">
<h3 class="text-sm font-bold text-navy flex items-center gap-2">
<i class="fa-solid fa-map-location-dot text-primary text-sm"></i> Território
</h3>
<div>
<label class="block text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1.5"
>Municípios <span class="text-primary">*</span></label
>
<div class="flex flex-wrap gap-2 mb-2">
<span
class="inline-flex items-center gap-1.5 bg-navy text-white text-xs font-semibold px-3 py-1.5 rounded-full"
>
Bom Jesus da Lapa
<button type="button" class="ml-0.5 opacity-70">
<i class="fa-solid fa-xmark text-xs"></i>
</button>
</span>
</div>
<div class="relative">
<input
type="text"
placeholder="Buscar município…"
class="w-full border border-gray-200 rounded-xl px-3 py-3 text-sm text-navy focus:outline-none focus:ring-2 focus:ring-primary/25 focus:border-primary pr-10"
/>
<i
class="fa-solid fa-chevron-down absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 text-xs pointer-events-none"
></i>
</div>
</div>
<div>
<label class="block text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1.5">
Território de identidade
<span class="normal-case font-normal text-gray-400 ml-1">(automático)</span>
</label>
<span
class="inline-flex items-center gap-1.5 bg-amber-50 border border-amber-200 text-amber-800 text-xs font-semibold px-3 py-1.5 rounded-full"
>
<i class="fa-solid fa-lock text-amber-400 text-xs"></i> Velho Chico
</span>
</div>
</div>
<!-- Pessoas responsáveis -->
<div class="bg-white border border-gray-200 rounded-xl shadow-sm p-4 space-y-4">
<h3 class="text-sm font-bold text-navy">Pessoas responsáveis</h3>
<div>
<label class="block text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1.5"
>Coordenadores</label
>
<!-- Selected person -->
<div class="flex items-center gap-3 mb-2">
<img
src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-3.jpg"
class="w-8 h-8 rounded-full object-cover flex-shrink-0"
/>
<div class="flex-1 min-w-0">
<p class="text-sm font-semibold text-navy truncate">João Santos</p>
<p class="text-xs text-gray-500">Coord. Núcleo · Bom Jesus da Lapa</p>
</div>
<button type="button" class="text-gray-400 hover:text-red-600 p-1.5">
<i class="fa-solid fa-xmark text-sm"></i>
</button>
</div>
<button
type="button"
class="flex items-center gap-2 text-primary text-xs font-semibold border border-dashed border-primary/40 rounded-xl px-3 py-2 w-full justify-center hover:bg-primary-xlight transition-colors"
>
<i class="fa-solid fa-plus text-xs"></i> Adicionar coordenador
</button>
</div>
<div class="border-t border-gray-100 pt-4">
<label class="block text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1.5"
>Responsável principal <span class="text-primary">*</span></label
>
<select
class="w-full border border-gray-200 rounded-xl px-3 py-3 text-sm text-navy focus:outline-none focus:ring-2 focus:ring-primary/25 bg-white"
>
<option>João Santos</option>
<option>Maria Lima</option>
<option>Pedro Alves</option>
<option>Carlos Mendes</option>
</select>
</div>
</div>
<!-- Status inicial -->
<div class="bg-white border border-gray-200 rounded-xl shadow-sm p-4">
<label class="block text-xs font-semibold text-gray-500 uppercase tracking-wide mb-3"
>Status inicial</label
>
<div class="grid grid-cols-2 gap-2">
<label
class="flex items-center gap-2.5 p-3 border-2 border-primary rounded-xl cursor-pointer bg-primary-xlight"
>
<input type="radio" name="status" value="planejado" checked class="accent-primary" />
<div>
<p class="text-xs font-bold text-primary">Planejado</p>
<p class="text-xs text-gray-500">Em organização</p>
</div>
</label>
<label
class="flex items-center gap-2.5 p-3 border border-gray-200 rounded-xl cursor-pointer hover:border-gray-300"
>
<input type="radio" name="status" value="rascunho" class="accent-primary" />
<div>
<p class="text-xs font-bold text-navy">Rascunho</p>
<p class="text-xs text-gray-500">Ainda indefinido</p>
</div>
</label>
</div>
</div>
</form>
<!-- Bottom action bar -->
<div
class="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-200 px-4 py-4 flex gap-3 z-20"
>
<button
type="button"
class="flex-1 border border-gray-200 text-navy text-sm font-semibold py-3 rounded-xl hover:bg-gray-50 transition-colors"
>
Cancelar
</button>
<button
type="button"
class="flex-1 bg-primary text-white text-sm font-bold py-3 rounded-xl hover:bg-primary-light transition-colors flex items-center justify-center gap-2"
>
<i class="fa-solid fa-calendar-plus text-sm"></i> Criar plano
</button>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

View file

@ -0,0 +1,341 @@
<!doctype html>
<html lang="pt-BR">
<head>
<script>
window.FontAwesomeConfig = {
autoReplaceSvg: 'nest',
}
</script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js"
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Planos de Ação</title>
<script src="https://cdn.tailwindcss.com"></script>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css"
/>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#8E0E23',
'primary-light': '#B01C35',
'primary-xlight': '#F9E8EB',
gold: '#C8874B',
'gold-light': '#FDF3EC',
navy: '#1B2B4B',
},
},
},
}
</script>
<style>
body {
font-family: 'Inter', system-ui, sans-serif;
}
.filter-tab.active {
background: #1b2b4b;
color: white;
}
</style>
</head>
<body class="bg-gray-50 pb-24">
<!-- Header -->
<header
id="header"
class="bg-navy sticky top-0 z-20 px-4 py-3 flex items-center justify-between"
>
<div class="flex items-center gap-3">
<div class="w-7 h-7 rounded-full bg-primary flex items-center justify-center flex-shrink-0">
<i class="fa-solid fa-star text-white text-xs"></i>
</div>
<h1 class="text-white font-bold text-sm">Planos de Ação</h1>
</div>
<div class="flex items-center gap-2">
<button class="relative text-white/70 p-1.5">
<i class="fa-solid fa-bell text-base"></i>
<span
class="absolute top-1 right-1 w-2 h-2 bg-primary rounded-full border border-navy"
></span>
</button>
<button
class="bg-primary text-white text-xs font-semibold px-3 py-1.5 rounded-lg flex items-center gap-1.5"
>
<i class="fa-solid fa-plus text-xs"></i> Novo
</button>
</div>
</header>
<!-- Scope badge -->
<div class="px-4 pt-3 pb-1">
<span
class="inline-flex items-center gap-1.5 bg-gold-light border border-gold/30 text-xs font-semibold text-navy px-3 py-1.5 rounded-full"
>
<i class="fa-solid fa-shield-halved text-gold text-xs"></i> Coordenação Geral
</span>
</div>
<!-- Filter tabs -->
<div class="px-4 pt-3 pb-2 flex gap-2 overflow-x-auto">
<button
class="filter-tab active flex-shrink-0 text-xs font-semibold px-3 py-1.5 rounded-full border border-navy transition-colors"
>
Próximos
</button>
<button
class="filter-tab flex-shrink-0 text-xs font-semibold px-3 py-1.5 rounded-full border border-gray-200 text-gray-600 hover:border-navy transition-colors"
>
Todos
</button>
<button
class="filter-tab flex-shrink-0 text-xs font-semibold px-3 py-1.5 rounded-full border border-gray-200 text-gray-600 hover:border-navy transition-colors"
>
Realizados
</button>
<button
class="filter-tab flex-shrink-0 text-xs font-semibold px-3 py-1.5 rounded-full border border-gray-200 text-gray-600 hover:border-navy transition-colors"
>
Rascunhos
</button>
</div>
<!-- Additional filters -->
<div class="px-4 pb-3">
<div class="flex gap-2 overflow-x-auto">
<select
class="flex-shrink-0 text-xs border border-gray-200 rounded-lg px-3 py-2 text-navy bg-white focus:outline-none"
>
<option>Tipo de ação</option>
<option>Caminhada</option>
<option>Comício</option>
<option>Carreata</option>
<option>Panfletagem</option>
<option>Porta a porta</option>
<option>Reunião de apoio</option>
</select>
<select
class="flex-shrink-0 text-xs border border-gray-200 rounded-lg px-3 py-2 text-navy bg-white focus:outline-none"
>
<option>Território</option>
<option>Velho Chico</option>
<option>Sertão do São Francisco</option>
</select>
<select
class="flex-shrink-0 text-xs border border-gray-200 rounded-lg px-3 py-2 text-navy bg-white focus:outline-none"
>
<option>Status</option>
<option>Planejado</option>
<option>Confirmado</option>
<option>Realizado</option>
<option>Cancelado</option>
</select>
</div>
</div>
<!-- Events list -->
<section id="events-list" class="px-4 space-y-3">
<!-- Event 1: Caminhada — Confirmado -->
<div
class="bg-white border border-gray-200 rounded-xl shadow-sm overflow-hidden cursor-pointer active:bg-gray-50"
>
<!-- Kind + date bar -->
<div class="flex items-center justify-between px-4 pt-3 pb-2">
<span
class="inline-flex items-center gap-1.5 bg-blue-50 border border-blue-200 text-blue-700 text-xs font-bold px-2.5 py-1 rounded-full"
>
<i class="fa-solid fa-person-walking text-xs"></i> Caminhada
</span>
<span
class="inline-flex items-center gap-1.5 bg-green-100 text-green-700 text-xs font-bold px-2.5 py-1 rounded-full"
>
<i class="fa-solid fa-circle-check text-xs"></i> Confirmado
</span>
</div>
<div class="px-4 pb-3">
<h3 class="font-bold text-navy text-sm mb-1">Caminhada no Centro Histórico</h3>
<div class="flex items-center gap-3 text-xs text-gray-500 mb-2">
<span><i class="fa-solid fa-calendar text-gray-400 mr-1"></i>Dom, 3 ago · 08h00</span>
<span
><i class="fa-solid fa-location-dot text-gray-400 mr-1"></i>Bom Jesus da Lapa</span
>
</div>
<div class="flex items-center gap-2">
<span
class="inline-flex items-center gap-1 bg-amber-50 border border-amber-200 text-amber-800 text-xs font-semibold px-2 py-0.5 rounded-full"
>Velho Chico</span
>
<span class="text-xs text-gray-500">· Resp: João Santos</span>
</div>
</div>
</div>
<!-- Event 2: Reunião de apoio — Planejado -->
<div
class="bg-white border border-gray-200 rounded-xl shadow-sm overflow-hidden cursor-pointer active:bg-gray-50"
>
<div class="flex items-center justify-between px-4 pt-3 pb-2">
<span
class="inline-flex items-center gap-1.5 bg-purple-50 border border-purple-200 text-purple-700 text-xs font-bold px-2.5 py-1 rounded-full"
>
<i class="fa-solid fa-handshake text-xs"></i> Reunião de apoio
</span>
<span
class="inline-flex items-center gap-1.5 bg-blue-100 text-blue-700 text-xs font-bold px-2.5 py-1 rounded-full"
>
<i class="fa-solid fa-clock text-xs"></i> Planejado
</span>
</div>
<div class="px-4 pb-3">
<h3 class="font-bold text-navy text-sm mb-1">Reunião com lideranças quilombolas</h3>
<div class="flex items-center gap-3 text-xs text-gray-500 mb-2">
<span><i class="fa-solid fa-calendar text-gray-400 mr-1"></i>Ter, 5 ago · 18h30</span>
<span><i class="fa-solid fa-location-dot text-gray-400 mr-1"></i>Brumado</span>
</div>
<div class="flex items-center gap-2">
<span
class="inline-flex items-center gap-1 bg-amber-50 border border-amber-200 text-amber-800 text-xs font-semibold px-2 py-0.5 rounded-full"
>Sertão do São Francisco</span
>
<span class="text-xs text-gray-500">· Resp: Maria Lima</span>
</div>
<!-- Tarefas progress -->
<div class="mt-2 flex items-center gap-2">
<div class="flex-1 h-1.5 bg-gray-100 rounded-full overflow-hidden">
<div class="h-full bg-primary rounded-full" style="width: 40%"></div>
</div>
<span class="text-xs text-gray-500">2/5 tarefas</span>
</div>
</div>
</div>
<!-- Event 3: Porta a porta — Confirmado -->
<div
class="bg-white border border-gray-200 rounded-xl shadow-sm overflow-hidden cursor-pointer active:bg-gray-50"
>
<div class="flex items-center justify-between px-4 pt-3 pb-2">
<span
class="inline-flex items-center gap-1.5 bg-amber-50 border border-amber-200 text-amber-700 text-xs font-bold px-2.5 py-1 rounded-full"
>
<i class="fa-solid fa-door-open text-xs"></i> Porta a porta
</span>
<span
class="inline-flex items-center gap-1.5 bg-green-100 text-green-700 text-xs font-bold px-2.5 py-1 rounded-full"
>
<i class="fa-solid fa-circle-check text-xs"></i> Confirmado
</span>
</div>
<div class="px-4 pb-3">
<h3 class="font-bold text-navy text-sm mb-1">Porta a porta Bairro Novo</h3>
<div class="flex items-center gap-3 text-xs text-gray-500 mb-2">
<span><i class="fa-solid fa-calendar text-gray-400 mr-1"></i>Sáb, 9 ago · 09h00</span>
<span><i class="fa-solid fa-location-dot text-gray-400 mr-1"></i>Feira de Santana</span>
</div>
<div class="flex items-center gap-2">
<span
class="inline-flex items-center gap-1 bg-amber-50 border border-amber-200 text-amber-800 text-xs font-semibold px-2 py-0.5 rounded-full"
>Bacia do Jacuípe</span
>
<span class="text-xs text-gray-500">· Resp: Pedro Alves</span>
</div>
</div>
</div>
<!-- Event 4: Comício — Rascunho -->
<div
class="bg-white border border-dashed border-gray-300 rounded-xl shadow-sm overflow-hidden cursor-pointer active:bg-gray-50 opacity-75"
>
<div class="flex items-center justify-between px-4 pt-3 pb-2">
<span
class="inline-flex items-center gap-1.5 bg-red-50 border border-red-200 text-red-700 text-xs font-bold px-2.5 py-1 rounded-full"
>
<i class="fa-solid fa-microphone text-xs"></i> Comício
</span>
<span
class="inline-flex items-center gap-1.5 bg-gray-100 text-gray-500 text-xs font-bold px-2.5 py-1 rounded-full"
>
<i class="fa-solid fa-pencil text-xs"></i> Rascunho
</span>
</div>
<div class="px-4 pb-3">
<h3 class="font-bold text-navy text-sm mb-1">Comício de encerramento (planejado)</h3>
<div class="flex items-center gap-3 text-xs text-gray-400 mb-2">
<span><i class="fa-solid fa-calendar text-gray-300 mr-1"></i>Data a definir</span>
<span
><i class="fa-solid fa-location-dot text-gray-300 mr-1"></i>Vitória da Conquista</span
>
</div>
</div>
</div>
<!-- Event 5: Panfletagem — Realizado -->
<div
class="bg-white border border-gray-200 rounded-xl shadow-sm overflow-hidden cursor-pointer active:bg-gray-50 opacity-70"
>
<div class="flex items-center justify-between px-4 pt-3 pb-2">
<span
class="inline-flex items-center gap-1.5 bg-gray-100 border border-gray-200 text-gray-600 text-xs font-bold px-2.5 py-1 rounded-full"
>
<i class="fa-solid fa-file-alt text-xs"></i> Panfletagem
</span>
<span
class="inline-flex items-center gap-1.5 bg-gray-100 text-gray-500 text-xs font-bold px-2.5 py-1 rounded-full"
>
<i class="fa-solid fa-flag-checkered text-xs"></i> Realizado
</span>
</div>
<div class="px-4 pb-3">
<h3 class="font-bold text-gray-600 text-sm mb-1">Panfletagem no mercado municipal</h3>
<div class="flex items-center gap-3 text-xs text-gray-400">
<span><i class="fa-solid fa-calendar text-gray-300 mr-1"></i>20 jul · Salvador</span>
</div>
</div>
</div>
<p class="text-center text-xs text-gray-400 py-3">
5 de 23 planos · <span class="text-primary font-semibold">Ver mais</span>
</p>
</section>
<!-- FAB -->
<div class="fixed bottom-20 right-4 z-30">
<button
class="bg-primary text-white w-14 h-14 rounded-full shadow-xl flex items-center justify-center"
>
<i class="fa-solid fa-plus text-xl"></i>
</button>
</div>
<!-- Bottom nav -->
<nav
id="bottom-nav"
class="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-200 flex z-20"
>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-gray-400">
<i class="fa-solid fa-house text-base"></i>
<span class="text-xs mt-0.5">Início</span>
</a>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-gray-400">
<i class="fa-solid fa-layer-group text-base"></i>
<span class="text-xs mt-0.5">Núcleos</span>
</a>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-gray-400">
<i class="fa-solid fa-user-group text-base"></i>
<span class="text-xs mt-0.5">Apoiadores</span>
</a>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-primary">
<i class="fa-solid fa-calendar-days text-base"></i>
<span class="text-xs mt-0.5 font-semibold">Agenda</span>
</a>
<a href="#" class="flex-1 flex flex-col items-center py-3 text-gray-400">
<i class="fa-solid fa-users text-base"></i>
<span class="text-xs mt-0.5">Lideranças</span>
</a>
</nav>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

View file

@ -5,6 +5,19 @@ Atualizado em: 2026-07-17
Item do roadmap: [docs/roadmap.md](../roadmap.md) (seção "Campanha → Próximos ciclos")
Responsável: —
## Referência visual (UX Pilot)
Design: [`Baseline-Eleitoral-2022.png`](../design-refs/latest/Baseline-Eleitoral-2022.png) · [`Baseline-Eleitoral-2022.html`](../design-refs/latest/Baseline-Eleitoral-2022.html) — a tela também contém o card "Insights do território", que pertence aos planos de insight separados (ver abaixo).
![Baseline eleitoral 2022 no detalhe do núcleo](../design-refs/latest/Baseline-Eleitoral-2022.png)
Como usar:
- **Adotar a estrutura (Fases 2 e 4 deste plano):** bloco "Baseline eleitoral 2022" na aba Visão geral do núcleo com: linha destacada de Solla (votos 2022 + barra), linhas secundárias de Lula (Presidente, 2º turno) e Jerônimo (Governador); sub-bloco "Eleitorado 2022" (válidos, brancos, nulos, abstenções); linha "Mais votado aqui em 2022"; e o alerta âmbar do insight Gap vs 2022 ("Faltam 350 votos para o patamar de 2022" com a conta estimativa vs. resultado). Os quatro estados do gap descritos na Fase 4 seguem esse mesmo formato de alerta (âmbar/verde/informativo).
- **Pertence aos planos de insight separados (não implementar junto):** o card "Insights do território" (taxa de conversão, território de defesa, alavancagem da chapa, oportunidade de mobilização, mais votado/ranking) é a referência visual dos cinco planos `insight-*.md` — cada linha do card corresponde a um plano. A arquitetura do componente (`NucleusInsights.tsx`, stack de cards com ícone + veredito de uma linha + número de apoio) deve nascer extensível conforme já previsto.
- **Overview da lista:** o bloco compacto "Baseline 2022" da Fase 3 aparece no design [`Lista-Nucleos-Overview.png`](../design-refs/latest/Lista-Nucleos-Overview.png) (gap total + "8 acima · 6 abaixo").
- **Ajustar cores:** paleta antiga no HTML/PNG (header vermelho escuro, destaque de Solla em vermelho escuro). Implementar com tokens do tema `campaign`: destaque de Solla pode usar `#C51414` sobre fundo claro; alerta do gap usa o par âmbar (`#FEF3C7`/`#92400E`) ou verde (`#DCFCE7`/`#166534`).
## Contexto
Os resultados das eleições passadas são **dados abertos públicos** do TSE (Portal de Dados Abertos, licença Creative Commons Atribuição), disponíveis por **município e zona eleitoral** (e por seção). Hoje o `/campanha` só tem a estimativa manual de votos (sugerir/confirmar); não há referência histórica. A decisão de produto (2026-07-17) é importar os resultados oficiais de 2022 (presidente, governador, dep. federal, dep. estadual) por município+zona e usá-los como **baseline histórico** em três lugares: no detalhe do núcleo, no overview da lista de núcleos (escopado pelos filtros), e em insights automáticos para coordenadores e lideranças.

View file

@ -5,6 +5,27 @@ Atualizado em: 2026-07-17
Item do roadmap: [docs/roadmap.md](../roadmap.md) (seção "Campanha → Próximos ciclos", linha 56)
Responsável: —
## Referência visual (UX Pilot)
Três designs cobrem este plano:
| Tela | Arquivos |
| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Lista de apoiadores (`/campanha/apoiadores`) | [`Apoiadores-Lista.png`](../design-refs/latest/Apoiadores-Lista.png) · [`Apoiadores-Lista.html`](../design-refs/latest/Apoiadores-Lista.html) |
| Ficha do apoiador | [`Apoiador-Ficha.png`](../design-refs/latest/Apoiador-Ficha.png) · [`Apoiador-Ficha.html`](../design-refs/latest/Apoiador-Ficha.html) |
| Import CSV (desktop, wizard 3 passos) | [`Importar-CSV-Apoiadores.png`](../design-refs/latest/Importar-CSV-Apoiadores.png) · [`Importar-CSV-Apoiadores.html`](../design-refs/latest/Importar-CSV-Apoiadores.html) |
![Lista de apoiadores](../design-refs/latest/Apoiadores-Lista.png)
![Ficha do apoiador](../design-refs/latest/Apoiador-Ficha.png)
![Import CSV de apoiadores](../design-refs/latest/Importar-CSV-Apoiadores.png)
Como usar:
- **Lista — adotar:** KPIs no topo (total / "Certo + Tende" / "Indecisos"), busca por nome/telefone/município, filtros "Intenção de voto" e "Território", linhas com nome + município + núcleo vinculado (ou "sem núcleo vinculado" — reflete a decisão de núcleo opcional) + badge de intenção + telefone; estado "Sem telefone cadastrado" em itálico; CTAs "Importar CSV" e "+ Novo".
- **Ficha — adotar:** é a tela que melhor materializa as decisões LGPD do plano: bloco destacado "Consentimento LGPD" com checkbox nominal, link para a Política de Privacidade e registro "Consentimento registrado em … · Coletor: …" (`consentedAt` + `createdBy`); segmented control de intenção de voto **desabilitado até o consentimento** ("Disponível somente após confirmação do consentimento LGPD" — consentimento destacado, chave `apoiador-intencao-voto`); seção "Kit de compartilhamento" com mensagem pronta, "Enviar no WhatsApp"/"Copiar texto" e a nota "A mensagem é enviada pelo celular de {nome} — não é disparo em massa da campanha" (art. 33 §2º); ação "Remover meus dados" (descadastramento art. 18).
- **Import — adotar:** wizard em 3 passos (Upload → Conferir prévia → Confirmação) com chips de contagem ("412 prontos" / "37 duplicados (pelo telefone)" / "3 erros"), tabela de prévia com status por linha (`ok`, `duplicado pelo telefone`, `telefone inválido`, `município não reconhecido`), toggle "Todos | Só erros", "Baixar relatório de erros" e resumo final. Corresponde ao `importSupporters` (dedup por telefone + preview de erros por linha). O sidebar desktop do design mostra a navegação-alvo (Início, Núcleos, Lideranças, Apoiadores, Planos de ação, Atualizações, Territórios) — usar como referência do shell desktop, mas só adicionar entradas de domínios que existirem.
- **Ajustar cores:** paleta antiga (navy/vermelho escuro) no HTML/PNG; implementar com tokens do tema `campaign` (sidebar clara `#FAFAF9`, primário `#C51414`, badges de intenção com os pares pastel claros). Avatares com foto viram iniciais; "solla.ba" no kit é placeholder — a URL real vem de `NEXT_PUBLIC_SITE_URL`.
## Contexto
Hoje a campanha só cadastra pessoas via `leadership` — a junção única `Contact`↔núcleo que carrega status de apoio, vínculo com `campaignUser` (acesso ao app) e consentimento. Não existe base nominal de apoiadores "comuns": eleitores que declaram apoio mas não são lideranças engajadas com acesso à plataforma. O roadmap pede explicitamente o cadastro nominal em massa via `Contact` + junção, **sem nunca criar uma collection "pessoa/apoiador" paralela** (decisão travada no AGENTS.md, espelhada por `Signature`/`Subscription`).

View file

@ -5,6 +5,19 @@ Atualizado em: 2026-07-17
Item do roadmap: [docs/roadmap.md](../roadmap.md) (seção "Campanha → Próximos ciclos", linha 51)
Responsável: —
## Referência visual (UX Pilot)
Design: [`Compartilhar-Nucleo.png`](../design-refs/latest/Compartilhar-Nucleo.png) · [`Compartilhar-Nucleo.html`](../design-refs/latest/Compartilhar-Nucleo.html)
![Compartilhar núcleo](../design-refs/latest/Compartilhar-Nucleo.png)
Como usar:
- **Adotar a estrutura:** bottom sheet no mobile com título "Compartilhar núcleo", subtítulo reforçando "envia apenas o link, não concede acesso" (copy que materializa a decisão travada), três seções de destinatários ("Com coordenação geral", "Com coordenador", "Com liderança" — nome + papel + botão verde "Abrir" com ícone WhatsApp) e a seção "Copiar link" com a URL canônica truncada + botão "Copiar".
- **Ajuste em relação ao plano:** o plano especifica `Dialog` central (como `LeadershipInviteDialog`); o design mostra bottom sheet. Adotar o padrão responsivo já usado no painel de lideranças (Sheet/Drawer no mobile, Dialog no desktop) — a estrutura interna do design vale para ambos.
- **Lembrar das regras que o design não mostra:** ocultar a seção "Com liderança" para o papel `lideranca`; ocultar destinatários sem telefone; ocultar seções vazias; estado "copiado" após o clique.
- **Ajustar cores:** paleta antiga no HTML/PNG (header vermelho escuro, navy). Implementar com os tokens do tema `campaign` e componentes `src/components/ui`; avatares com foto viram iniciais.
## Contexto
Hoje o detalhe do núcleo (`/campanha/nucleos/[slug]`) só tem ações de escrita (Editar, Nova liderança, Nova atualização, Arquivar). Não existe um caminho rápido para um usuário da campanha mandar o link daquele núcleo a outra pessoa do mesmo núcleo. A decisão de produto (2026-07-17) é adicionar um botão **Compartilhar** que oferece quatro destinos: coordenação geral, coordenador, liderança ou copiar link. Para os três primeiros, abre o WhatsApp via `wa.me` com o telefone do destinatário — o mesmo padrão já usado pelos convites, **sem WhatsApp Business API**.

View file

@ -5,6 +5,25 @@ Atualizado em: 2026-07-17
Item do roadmap: [docs/roadmap.md](../roadmap.md) (seção "Campanha → Próximos ciclos", linha 54)
Responsável: —
## Referência visual (UX Pilot)
Dois designs cobrem este plano:
| Tela | Arquivos |
| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| Lista de planos (`/campanha/planos`) | [`Planos-de-Acao.png`](../design-refs/latest/Planos-de-Acao.png) · [`Planos-de-Acao.html`](../design-refs/latest/Planos-de-Acao.html) |
| Form novo plano | [`Novo-Plano-de-Acao.png`](../design-refs/latest/Novo-Plano-de-Acao.png) · [`Novo-Plano-de-Acao.html`](../design-refs/latest/Novo-Plano-de-Acao.html) |
![Lista de planos de ação](../design-refs/latest/Planos-de-Acao.png)
![Form de novo plano de ação](../design-refs/latest/Novo-Plano-de-Acao.png)
Como usar:
- **Lista — adotar:** tabs de janela/status ("Próximos" default, "Todos", "Realizados", "Rascunhos"), filtros "Tipo de ação" e "Território", cards com badge de `kind` (Caminhada, Reunião de apoio, Porta a porta, Comício, Panfletagem — cada tipo com cor própria clara), badge de `status` (Confirmado verde, Planejado azul, Rascunho outline, Realizado cinza), data/hora + município, chip do Território de Identidade, "Resp: {nome}" e barra de progresso de tarefas ("2/5 tarefas"). O card de rascunho com "Data a definir" esmaecido é um bom estado para `startAt` pendente em rascunho — mas atenção: o plano define `startAt` obrigatório; se rascunho puder ficar sem data, registrar em "Questões em aberto".
- **Form — adotar:** seções "Informações básicas" (título, tipo, descrição opcional), "Data e horário" (data + início obrigatórios, término opcional com helper "Deixe em branco se a duração for indefinida"), "Território" (municípios multi-chip + território derivado automático — mesmo padrão de [`Formulario-Territorio.png`](../design-refs/latest/Formulario-Territorio.png), confirmando que o bloco nasce no modelo multi-município), "Pessoas responsáveis" (coordenadores com "+ Adicionar", responsável principal) e "Status inicial" (Planejado | Rascunho como radio cards).
- **Falta desenhar (não bloqueia):** o detalhe do plano com tabs "Visão geral / Tarefas / Atualizações" não veio nesta leva — seguir o padrão `NucleusTabNav` do detalhe do núcleo; o checklist de tarefas pode reusar o formato de linhas do design da lista.
- **Ajustar cores:** paleta antiga no HTML/PNG; implementar com tokens do tema `campaign`. A entrada "Agenda" do bottom nav só entra quando este domínio existir.
## Contexto
O roadmap lista "Eventos / presença e agenda de mobilização" como próximo ciclo da vertical `/campanha` (plano-arquitetura §4). Hoje a campanha só modela território (núcleo) e reporte (atualização); não há como planejar, escalar e acompanhar ações de campo — caminhadas, comícios, carreatas, panfletagens, reuniões de apoio, lançamentos, convenções, atos, entrevistas — nem ver o que vem a seguir.

View file

@ -5,6 +5,10 @@ Atualizado em: 2026-07-17
Item do roadmap: [docs/roadmap.md](../roadmap.md) (seção "Campanha → Próximos ciclos")
Responsável: —
## Referência visual (UX Pilot)
Design: [`Baseline-Eleitoral-2022.png`](../design-refs/latest/Baseline-Eleitoral-2022.png) — card "Insights do território", linha "Alavancagem da chapa: 22% · Da base Lula/Jerônimo ainda não convertida". Implementar como um card do stack `NucleusInsights.tsx` ([baseline-eleitoral-tse.md](baseline-eleitoral-tse.md)), com os tokens claros do tema `campaign` em vez da paleta antiga do HTML/PNG.
## Contexto
Solla apoia a chapa principal do PT (Lula para presidente, Jerônimo para governador, ambos nº 13). Os votos que Lula e Jerônimo receberam em 2022 numa geografia são o **teto natural do PT** no local — um piso de simpatia partidária que a candidatura de Solla pode capturar como dobradinha. Com o baseline TSE 2022 (ver [baseline-eleitoral-tse.md](baseline-eleitoral-tse.md)), podemos medir quanto da base da chapa a estimativa do núcleo já captura e quanto ainda falta — meta implícita de alavancagem.

View file

@ -5,6 +5,10 @@ Atualizado em: 2026-07-17
Item do roadmap: [docs/roadmap.md](../roadmap.md) (seção "Campanha → Próximos ciclos")
Responsável: —
## Referência visual (UX Pilot)
Design: [`Baseline-Eleitoral-2022.png`](../design-refs/latest/Baseline-Eleitoral-2022.png) — card "Insights do território", linha "Território de defesa · Base sólida — prioridade: manter engajamento" com chip de classificação à direita (`Defesa` em verde). Os quatro estados usam pares de badge do tema `campaign`: defesa = verde, ataque = contorno vermelho, indecisa = âmbar, perdida = cinza. Implementar como um card do stack `NucleusInsights.tsx` ([baseline-eleitoral-tse.md](baseline-eleitoral-tse.md)), ajustando a paleta antiga do HTML/PNG para os tokens claros.
## Contexto
A literatura de territorialização eleitoral (Politipédia AVM, OPUS, Seja Eleito) classifica cada território em quatro zonas operacionais — **defesa** (voto histórico favorável, meta: manter), **ataque** (desfavorável mas relevante, meta: virar/reduzir margem), **indecisa** (pulverizada, baixa rejeição, meta: consolidar) e **perdida** (desfavorável e elástica, meta: minimizar perda) — para alocar esforço de forma proporcional ao retorno. Hoje o `/campanha` não classifica núcleos; com o baseline TSE 2022 (ver [baseline-eleitoral-tse.md](baseline-eleitoral-tse.md)) podemos derivar uma primeira classificação a partir do histórico.

View file

@ -5,6 +5,10 @@ Atualizado em: 2026-07-17
Item do roadmap: [docs/roadmap.md](../roadmap.md) (seção "Campanha → Próximos ciclos")
Responsável: —
## Referência visual (UX Pilot)
Design: [`Baseline-Eleitoral-2022.png`](../design-refs/latest/Baseline-Eleitoral-2022.png) — card "Insights do território", linha "Mais votado aqui em 2022: Dep. Fulano (PP) · Solla ficou em 4º lugar · 2.100 votos à frente"; a linha "Mais votado aqui em 2022" do bloco de baseline também alimenta este insight. Implementar como um card do stack `NucleusInsights.tsx` ([baseline-eleitoral-tse.md](baseline-eleitoral-tse.md)), com os tokens claros do tema `campaign` em vez da paleta antiga do HTML/PNG.
## Contexto
Saber onde Solla foi bem é só metade; a outra é saber **quem o superou localmente** e por quanto. O baseline TSE 2022 (ver [baseline-eleitoral-tse.md](baseline-eleitoral-tse.md)) guarda o conjunto completo de candidatos por geografia, com flag de eleito — podemos dizer, por núcleo, quem foi o mais votado para deputado federal ali em 2022, qual a margem sobre Solla, e em que colocação Solla ficou. É inteligência competitiva: onde há adversário forte a desmontar e onde Solla já é o referencial.

View file

@ -5,6 +5,10 @@ Atualizado em: 2026-07-17
Item do roadmap: [docs/roadmap.md](../roadmap.md) (seção "Campanha → Próximos ciclos")
Responsável: —
## Referência visual (UX Pilot)
Design: [`Baseline-Eleitoral-2022.png`](../design-refs/latest/Baseline-Eleitoral-2022.png) — card "Insights do território", linha "Oportunidade de mobilização: 142 brancos/nulos + 680 abstenções = 822 votos possíveis". Implementar como um card do stack `NucleusInsights.tsx` ([baseline-eleitoral-tse.md](baseline-eleitoral-tse.md)), com os tokens claros do tema `campaign` em vez da paleta antiga do HTML/PNG.
## Contexto
Em 2022, parte significativa dos eleitores aptos de cada geografia não gerou voto útil: **abstenções** (não compareceu), **votos em branco** e **votos nulos** (compareceu mas não votou em candidato válido). Esses eleitores são potencial de mobilização — gente que, bem engajada, pode virar voto. O baseline TSE 2022 (ver [baseline-eleitoral-tse.md](baseline-eleitoral-tse.md)) traz `electionTally.abstencoes`, `votosBranco` e `votosNulo` por município+zona; hoje o `/campanha` não os usa.

View file

@ -5,6 +5,10 @@ Atualizado em: 2026-07-17
Item do roadmap: [docs/roadmap.md](../roadmap.md) (seção "Campanha → Próximos ciclos")
Responsável: —
## Referência visual (UX Pilot)
Design: [`Baseline-Eleitoral-2022.png`](../design-refs/latest/Baseline-Eleitoral-2022.png) — card "Insights do território", primeira linha: "Taxa de conversão: 18% do eleitorado apto · 850 votos / 4.700 eleitores aptos" (ícone + veredito de uma linha + números de apoio). Implementar como um card do stack `NucleusInsights.tsx` (arquitetura definida em [baseline-eleitoral-tse.md](baseline-eleitoral-tse.md)), com os tokens claros do tema `campaign` em vez da paleta antiga do HTML/PNG.
## Contexto
Com o baseline TSE 2022 importado (ver [baseline-eleitoral-tse.md](baseline-eleitoral-tse.md)), temos `electionTally.aptos` (eleitores aptos) por município+zona. A estimativa confirmada do núcleo (`confirmedVoteEstimate`) hoje só é comparada com o voto histórico de Solla (Gap vs 2022). Falta medir a estimativa contra o **tamanho do eleitorado apto** da geografia — ou seja, qual % do eleitorado potencial da zona a estimativa representa. É o indicador que separa "reduto consolidado" de "oportunidade de crescimento", segundo a literatura de estratégia eleitoral.

View file

@ -5,6 +5,18 @@ Atualizado em: 2026-07-17
Item do roadmap: [docs/roadmap.md](../roadmap.md) (seção "Campanha → Próximos ciclos")
Responsável: —
## Referência visual (UX Pilot)
Design: [`Notificacoes-PWA.png`](../design-refs/latest/Notificacoes-PWA.png) · [`Notificacoes-PWA.html`](../design-refs/latest/Notificacoes-PWA.html) — **compartilhado com [pwa-campanha.md](pwa-campanha.md)** (o banner de instalação no rodapé pertence àquele plano).
![Central de notificações + banner de instalação PWA](../design-refs/latest/Notificacoes-PWA.png)
Como usar (parte deste plano — o sino):
- **Adotar a estrutura:** sino no header com contagem; bottom sheet "Notificações" com "4 não lidas", ação "Marcar todas como lidas", itens com ícone por tipo de evento, título com o núcleo/entidade ("Estimativa aguardando confirmação — Núcleo Quilombo Rio das Rãs"), linha de detalhe (autor + ação), data relativa e ponto de não lida. Os quatro tipos exemplificados (estimativa aguardando confirmação, novo apoiador, novo reporte de campo, plano de ação precisa de atenção) são um bom ponto de partida para o enum `type` da collection `Notification` — dois deles dependem dos domínios C2/C3 existirem.
- **Falta desenhar (não bloqueia):** a tela de opt-in de push com o checkbox de consentimento LGPD (`campanha-notificacoes-push`) e a nota de limitação do iOS — seguir o padrão do bloco "Consentimento LGPD" da [`Apoiador-Ficha.png`](../design-refs/latest/Apoiador-Ficha.png).
- **Ajustar cores:** paleta antiga no HTML/PNG; implementar com tokens do tema `campaign` e componentes `Sheet`/`Drawer` existentes.
## Contexto
Coordenadores e lideranças precisam ser avisados de eventos da campanha (convite aceito, novo `nucleusUpdate`, estimativa aguardando confirmação) sem depender só do canal de WhatsApp. Este plano cobre dois canais de notificação dentro da vertical `/campanha`:

View file

@ -5,6 +5,18 @@ Atualizado em: 2026-07-17
Item do roadmap: [docs/roadmap.md](../roadmap.md) (seção "Campanha → Próximos ciclos", linha 50)
Responsável: —
## Referência visual (UX Pilot)
Design: [`Lista-Nucleos-Overview.png`](../design-refs/latest/Lista-Nucleos-Overview.png) · [`Lista-Nucleos-Overview.html`](../design-refs/latest/Lista-Nucleos-Overview.html)
![Overview da lista de núcleos](../design-refs/latest/Lista-Nucleos-Overview.png)
Como usar:
- **Adotar a estrutura:** header → busca → chips de filtro ativos → caption "Mostrando agregados de 14 núcleos filtrados" → blocos de overview → lista. O bloco "Estimativa de votos" (total grande + barra de "% com estimativa confirmada" + badge "3 sugestões pendentes") e os blocos compactos "Cobertura" e "Últimas atualizações" (autor, badge de tipo, data relativa, núcleo, "Ver todas") correspondem exatamente aos objetivos deste plano.
- **Fora deste plano:** o bloco "Baseline 2022" que aparece no design é a Fase 3 de [baseline-eleitoral-tse.md](baseline-eleitoral-tse.md) — só ganha UI quando aquele plano for implementado (mantém-se a decisão "sem UI órfã"). O bottom nav com "Apoiadores" e "Agenda" antecipa os domínios C2/C3; as entradas só entram quando existirem.
- **Ajustar cores e código:** o HTML/PNG usa a paleta antiga (vermelho escuro `#8E0E23`, navy `#1B2B4B`, dourado `#C8874B`) e Tailwind via CDN. Implementar com os componentes shadcn existentes (`src/components/ui`) e os tokens do tema `data-theme='campaign'` (`src/app/(frontend)/styles.css`): fundo branco, primário `#C51414`, superfícies neutras claras. O header navy do design vira o shell claro atual; avatares com foto viram avatares de iniciais (padrão do app).
## Contexto
Hoje `/campanha/nucleos` é só cabeçalho + filtros + lista paginada (25/página). Não há agregados: o usuário precisa varrer a lista (ou ir ao dashboard `/campanha`) para sentir quanto daquela seleção tem estimativa confirmada, quantos votos somam, ou quais foram os últimos reportes. O dashboard geral já calcula esses agregados, mas para **todos** os núcleos ativos — não respeita os filtros de território/cobertura/estimativa da lista.

View file

@ -5,6 +5,17 @@ Atualizado em: 2026-07-17
Item do roadmap: [docs/roadmap.md](../roadmap.md) (seção "Campanha → Próximos ciclos", linha 62)
Responsável: —
## Referência visual (UX Pilot)
Design: [`Notificacoes-PWA.png`](../design-refs/latest/Notificacoes-PWA.png) · [`Notificacoes-PWA.html`](../design-refs/latest/Notificacoes-PWA.html) — **compartilhado com [notifications.md](notifications.md)** (a central de notificações pertence àquele plano).
![Banner de instalação PWA no rodapé](../design-refs/latest/Notificacoes-PWA.png)
Como usar (parte deste plano — o banner de instalação no rodapé):
- **Adotar o conteúdo:** banner fixo inferior com ícone do app, título "Instale o app da campanha", subtítulo "Acesse mais rápido e receba avisos", botão "Instalar" e X de dispensa — exatamente o `InstallPwaToast` da seção "Toast de instalação" (Android chama `deferredPrompt.prompt()`; iOS abre o passo a passo no Drawer; X grava `sessionStorage`).
- **Ajuste:** o plano implementa isso via `<Toaster>` (sonner) já montado, não como barra fixa custom — usar o design como referência de conteúdo/hierarquia, não de posicionamento exato. Cores do design (navy) viram os tokens claros do tema `campaign`.
## Contexto
A vertical `/campanha` é a ferramenta de campo da campanha: coordenadores e lideranças acessam o app pelo celular, muitas vezes em locais com conexão instável. Transformar `/campanha` em um PWA instalável (com ícone na tela inicial, splash e capacidade offline básica) melhora a experiência de campo e desbloqueia o push web no iOS (que só recebe push com o PWA instalado — ver [plans/notifications.md](./notifications.md)).

View file

@ -5,6 +5,19 @@ Atualizado em: 2026-07-17
Item do roadmap: [docs/roadmap.md](../roadmap.md) (seção "Campanha → Próximos ciclos")
Responsável: —
## Referência visual (UX Pilot)
Design: [`Formulario-Territorio.png`](../design-refs/latest/Formulario-Territorio.png) · [`Formulario-Territorio.html`](../design-refs/latest/Formulario-Territorio.html) — **compartilhado com [zonas-por-municipio.md](zonas-por-municipio.md)** (a mesma tela cobre os dois planos).
![Formulário de território do núcleo](../design-refs/latest/Formulario-Territorio.png)
Como usar (parte deste plano — bloco Território):
- **Adotar a estrutura:** "Municípios" como combobox multi-seleção com chips removíveis + contagem "2 municípios selecionados"; "Territórios de Identidade" como chips derivados somente leitura com cadeado e legenda "Derivados dos municípios selecionados · não é possível editar" (materializa a regra 3 — `regions` rederivado no servidor); "Bairros" desabilitado com placeholder "Selecione municípios primeiro" e o aviso "Bairros exigem um único município selecionado" (regra 5).
- **Divergência a resolver na implementação:** no design o campo de bairros aparece desabilitado com 2 municípios e o aviso âmbar simultaneamente; a regra é: habilitar bairros somente com exatamente 1 município e limpar bairros ao passar para >1 (mostrar o aviso como helper text, não como erro).
- **Fora deste plano:** a seção "Zonas Eleitorais (TSE)" com chips "sugerida" pertence a [zonas-por-municipio.md](zonas-por-municipio.md).
- **Ajustar cores:** paleta antiga no HTML/PNG. Implementar com `StrictCombobox`/`NucleusTerritoryFields` existentes e os tokens do tema `campaign` (chips neutros claros; chips de município selecionado não precisam ser navy).
## Contexto
Hoje o território do Núcleo Eleitoral é modelado com campos **single-valued** em `src/collections/ElectoralNucleus.ts`:

View file

@ -5,6 +5,19 @@ Atualizado em: 2026-07-17
Item do roadmap: [docs/roadmap.md](../roadmap.md) (seção "Campanha → Próximos ciclos")
Responsável: —
## Referência visual (UX Pilot)
Design: [`Formulario-Territorio.png`](../design-refs/latest/Formulario-Territorio.png) · [`Formulario-Territorio.html`](../design-refs/latest/Formulario-Territorio.html) — **compartilhado com [territorio-multi-municipio-bairro.md](territorio-multi-municipio-bairro.md)** (a mesma tela cobre os dois planos).
![Formulário de território do núcleo — seção Zonas TSE](../design-refs/latest/Formulario-Territorio.png)
Como usar (parte deste plano — seção "Zonas Eleitorais (TSE)"):
- **Adotar a estrutura:** banner informativo "Zonas sugeridas pelo cadastro oficial do TSE — confira antes de salvar", lista de zonas como linhas com checkbox + número ("ZE 12"), badge "sugerida" e o município de origem como legenda — bom formato para o modo multi-município (união das zonas, cada uma rastreável ao município).
- **Divergências a resolver na implementação:** o design mostra checkboxes editáveis e um link "Adicionar zona manualmente" para todos os casos; o plano define 4 modos — no modo 1 (municípios sem bairro) as zonas são **somente leitura** (sem checkbox, sem adicionar manual); checkbox/edição vale para os modos 2 e 3 (restrito ao conjunto permitido); entrada manual livre só no modo 4. Usar o visual das linhas do design, trocando checkbox por badge estático no modo read-only.
- **Manter do design:** a zona desmarcada "ZE 7 (zona adicional)" ilustra bem o modo 2/3 (subconjunto permitido).
- **Ajustar cores:** paleta antiga no HTML/PNG; implementar com `TseZoneInput` + tokens do tema `campaign` (chips TSE `#F1F3F5`/`#3F4854`).
## Contexto
Hoje o campo **Zonas TSE** do formulário do núcleo (`TseZoneInput` em `src/components/campaign/TseZoneInput.tsx`) é sempre de preenchimento manual livre: o usuário digita números de 1 a 999, separados por vírgula/espaço/Enter, e o servidor só valida unicidade e intervalo (`parseTseZoneNumbers` em `src/utilities/nucleusUi.ts`, `validateNucleusTerritoryAndZones` em `src/collections/ElectoralNucleus.ts`, `validateGeographyAndZones` em `src/lib/schemas/nucleus.ts`). Não há nenhuma relação entre o município selecionado e as zonas informadas — o usuário precisa saber (ou adivinhar) quais zonas cobrem aquele município.

View file

@ -48,6 +48,26 @@ O MVP de Núcleos está **entregue em código** (ondas 1–8 + refactors; commit
MVP de território + reporte implementado e enviado (ondas 1–8 + refactors de composição/infra/fixtures): auth isolada `campaignUser` (`geral` / `coordenador` / `lideranca`), núcleos com slug canônico, designação de coordenador, lideranças, estimativas sugerir/confirmar com versão UUID, atualizações semanais, convites WhatsApp (`wa.me`, hash, uso único), dashboard e hardening. Território atual ainda é `region`/`city`/`neighborhood` unitários; multi-município permanece no item A1. Detalhes: [`.cursor/rules/projects/nucleos-eleitorais.mdc`](../.cursor/rules/projects/nucleos-eleitorais.mdc).
### Referências de design (UX Pilot, 2026-07-18)
Os designs gerados pelo UX Pilot para os próximos ciclos estão em [`docs/design-refs/latest/`](design-refs/latest/) (pares `.png` + `.html` com o mesmo nome). **A UX/estrutura é a referência a seguir; a paleta não é** — os arquivos usam a paleta antiga (vermelho escuro `#8E0E23`, navy `#1B2B4B`, dourado `#C8874B`); toda implementação usa os tokens claros do tema `data-theme='campaign'` (`src/app/(frontend)/styles.css`: fundo branco, primário `#C51414`, superfícies neutras). Cada plano detalha o uso na sua seção "Referência visual (UX Pilot)".
| Item do roadmap | Design | Plano com instruções |
| ------------------------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| B1 Overview da lista de núcleos | `Lista-Nucleos-Overview` | [overview-lista-nucleos.md](plans/overview-lista-nucleos.md) |
| C1 Compartilhar página | `Compartilhar-Nucleo` | [compartilhar-pagina.md](plans/compartilhar-pagina.md) |
| A1 Território multi-município/bairro | `Formulario-Territorio` (bloco Território) | [territorio-multi-municipio-bairro.md](plans/territorio-multi-municipio-bairro.md) |
| A2 Zonas TSE por município | `Formulario-Territorio` (seção Zonas TSE) | [zonas-por-municipio.md](plans/zonas-por-municipio.md) |
| A3/A4 Baseline TSE 2022 + Gap vs 2022 | `Baseline-Eleitoral-2022` (+ bloco "Baseline 2022" em `Lista-Nucleos-Overview`) | [baseline-eleitoral-tse.md](plans/baseline-eleitoral-tse.md) |
| A5 Insights (5 planos) | `Baseline-Eleitoral-2022` (card "Insights do território", uma linha por insight) | [conversão](plans/insight-taxa-conversao.md) · [classificação](plans/insight-classificacao-territorial.md) · [alavancagem](plans/insight-alavancagem-chapa.md) · [mobilização](plans/insight-mobilizacao-brancos-nulos.md) · [competitiva](plans/insight-inteligencia-competitiva.md) |
| C2 Cadastro nominal de apoiadores | `Apoiadores-Lista`, `Apoiador-Ficha`, `Importar-CSV-Apoiadores` | [cadastro-nominal-apoiadores.md](plans/cadastro-nominal-apoiadores.md) |
| C3 Eventos / agenda de mobilização | `Planos-de-Acao`, `Novo-Plano-de-Acao` | [eventos-agenda-mobilizacao.md](plans/eventos-agenda-mobilizacao.md) |
| D2 Notificações (sino) | `Notificacoes-PWA` (central de notificações) | [notifications.md](plans/notifications.md) |
| D1 PWA `/campanha` | `Notificacoes-PWA` (banner "Instale o app da campanha") | [pwa-campanha.md](plans/pwa-campanha.md) |
| C5 Operação dia D / GOTV | `Dia-D-GOTV` | sem plano ainda — o design é a primeira materialização do item (check-off de apoiadores por seção/zona, progresso "62% da base", filtro "Ainda não confirmados", estado "Sincronizado" offline-tolerante) |
**Sem design nesta leva** (encomendar na próxima rodada ou desenhar na implementação): A6 dobradinha 2026, B2/B3/B4 mapa da Bahia, C4 demandas, fill-ins (visitados recentemente, listas globais, reset de senha). O detalhe do plano de ação (tabs Visão geral/Tarefas/Atualizações) e a tela de opt-in de push também não vieram — os planos correspondentes indicam o padrão a seguir.
### Grafo de dependências
Setas cheias = dependência dura; tracejadas = dependência suave (melhora, não bloqueia).
@ -149,7 +169,7 @@ Itens sem seta de entrada (**paralelizáveis a qualquer momento**): A1, A3, B1,
| ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| 15 | A6 Insight dobradinha 2026 | [detalhes](plans/insight-dobradinha-2026.md) | A4 + TSE publicar candidaturas 2026 (externo, após 15/08) + taxonomia de alinhamento (produto) |
| 16 | B4 Camada de zonas TSE no mapa | ciclo seguinte do [plano do mapa](plans/mapa-bahia-geometrias.md) | A2 + B3 |
| 17 | C5 **Operação dia D / GOTV** _(item proposto nesta revisão — validar com produto)_: confirmação de comparecimento da base nominal em 04/10 (lista de apoiadores por núcleo/zona com marcação "confirmou que vai votar / votou", visão de cobertura para a coordenação). É o uso final da base construída em C2; a literatura de campanha trata a mobilização do dia como onde eleições apertadas se decidem. Sem plano ainda. | — | C2 |
| 17 | C5 **Operação dia D / GOTV** _(item proposto nesta revisão — validar com produto)_: confirmação de comparecimento da base nominal em 04/10 (lista de apoiadores por núcleo/zona com marcação "confirmou que vai votar / votou", visão de cobertura para a coordenação). É o uso final da base construída em C2; a literatura de campanha trata a mobilização do dia como onde eleições apertadas se decidem. Sem plano ainda. | design: [`Dia-D-GOTV`](design-refs/latest/Dia-D-GOTV.png) | C2 |
| 18 | Congelamento: a partir de ~20/09, só correção de bug e dados; nada de migration arriscada perto do dia D. | — | — |
**Fill-ins (qualquer janela, quando houver folga; nenhum bloqueia nada):**