diff --git a/docs/plans/ancorar-busca-acoes-inicio-mobile.md b/docs/plans/ancorar-busca-acoes-inicio-mobile.md index aaa38b9e..33a0e9b5 100644 --- a/docs/plans/ancorar-busca-acoes-inicio-mobile.md +++ b/docs/plans/ancorar-busca-acoes-inicio-mobile.md @@ -43,7 +43,7 @@ Em scrollport com altura definida pelo flex do `SidebarInset`, filhos com só `m - No viewport **< `md`**, com Início **não** focado (query B47 inativa): o **grupo** strip de ações + barra de busca fica colado ao limite inferior do conteúdo útil (acima da bottom nav / `pb-24` do scroll), sem gap morto entre o grupo e esse limite. - Em **`md+`**: comportamento visual inalterado (busca acima das ações, no topo do conteúdo). -- Modo focado **B47** intacto: spacer/strip ocultos; input sobe; resultados abaixo. +- Modo focado **B47/B66** intacto: spacer/strip ocultos; input sobe; resultados abaixo. **B66** (quando landar) dispara a limpeza no **focus** e anima a retração — este item só ancora o dock no idle. - Leader (só strip, sem busca) também ancora a strip no inferior no mobile. - Sem migration / collection / Consent / server action / mudança de URL. - Pin em unit (cadeia de classes / presença do dock) + checklist visual mobile (viewport ~390) no e2e existente ou asserção de layout leve se couber sem flake. diff --git a/docs/plans/busca-global-inicio-input.md b/docs/plans/busca-global-inicio-input.md index 9ae2e9ee..49b4f136 100644 --- a/docs/plans/busca-global-inicio-input.md +++ b/docs/plans/busca-global-inicio-input.md @@ -44,7 +44,7 @@ Início blank (**B43**) + ações (**B44/B45**) + posição (**B46**). Pedido (2 - **Debounce no cliente; sem botão Pesquisar.** **Rejeitado:** submit form; busca a cada keystroke sem debounce. - **Staff-only.** Leader continua lockdown (contatos). **Rejeitado:** omnibox para leader com só apoiadores nesta fatia (outro job). -- **Expand = query não vazia**, não focus-only. **Rejeitado:** sumir a strip no focus vazio (rouba o ritual de ações). +- **Expand = query não vazia**, não focus-only. **Rejeitado:** sumir a strip no focus vazio (rouba o ritual de ações). **Supersedido 2026-07-29 por B66** ([modo-focado-busca-no-focus.md](modo-focado-busca-no-focus.md)): produto pediu limpeza **no focus** + animação de expansão; hits continuam gated por query. - **i18n:** `CampaignHomeSearch`, `homeSearchQuery`; label pt-BR “Buscar na campanha” (ou copy curta a fechar no craft). ## Questões em aberto diff --git a/docs/plans/chassis-wizard-campanha.md b/docs/plans/chassis-wizard-campanha.md index dd6005df..87032fd0 100644 --- a/docs/plans/chassis-wizard-campanha.md +++ b/docs/plans/chassis-wizard-campanha.md @@ -1,10 +1,10 @@ # Chassis do wizard de campanha (shell + voltar) Status: rascunho -Atualizado em: 2026-07-29 +Atualizado em: 2026-07-29 — absorve lembrete de produto: município em atualização sempre visível no topo (centro, semi-discreto) Item do roadmap: [docs/roadmap.md](../roadmap.md) (Trilha B, item B59 — UX-1 wizards) Impeccable: C — UI nova (shell de fluxo multi-passo sob `/campanha`) -Appetite: ~0,75 dia eng; layout de passo + header mobile + slot de conteúdo; sem migration +Appetite: ~0,75–1 dia eng; layout de passo + header mobile + slot de conteúdo + caption sticky do município; sem migration Responsável: — ## Design (Impeccable) @@ -15,11 +15,11 @@ Na implementação (`implement-roadmap-item`): shape → craft → critique → Brief compacto: -- **Persona / contexto:** CG/assessor no celular entre Zaps; um passo por vez, sem chrome de lista. -- **Job principal:** enquadrar qualquer etapa de wizard (busca, votos, sinal…) com volta óbvia no mobile e conteúdo focável. +- **Persona / contexto:** CG/assessor no celular entre Zaps; um passo por vez, sem chrome de lista — e sem esquecer **qual** município está atualizando enquanto edita votos/sinal/tendência. +- **Job principal:** enquadrar qualquer etapa de wizard (busca, votos, sinal…) com volta óbvia no mobile, conteúdo focável e **contexto de município sempre legível** após a escolha. - **Estratégia de cor:** Restrained. - **Edit where you see:** não — fluxo linear; escrita nas etapas filhas. -- **Anti-goals:** sidebar/nav do app competindo com o passo; seta “voltar” no desktop (lá é browser); segundo design system de wizard. +- **Anti-goals:** sidebar/nav do app competindo com o passo; seta “voltar” no desktop (lá é browser); segundo design system de wizard; badge/chip gritante de município no meio do passo; repetir o nome do município no título de cada pergunta. ## Dados → decisão → apresentação @@ -34,18 +34,20 @@ Este item é o **frame** compartilhado — não a busca, nem o ajuste de votos, ## Objetivos - Componente shell (nome final no PR, ex. `CampaignWizardShell`) com: título/pergunta do passo, slot `children`, slot opcional de ação no topo direito (ex. “Pular…” do B63), **back control só em viewport mobile** (`md:hidden` ou equivalente) que navega ao passo anterior / Início conforme o fluxo. +- **Contexto de município (pedido 2026-07-29):** quando o fluxo já tem município escolhido, o **nome** permanece visível no **limite superior central**, semi-discreto (`text-sm` / `muted-foreground` — craft), **sticky** no scroll do passo (não some ao rolar formulário longo). Ausente na etapa **B60** (ainda não há município). Não substitui o título/pergunta do passo. - Desktop: sem seta; documentar que `history.back` / rota anterior cobre o gesto. - Layout: uma coluna; conteúdo alinhado ao bottom em mobile quando a etapa pedir (B63 tipifica), top em `md+` — o shell expõe um prop de alinhamento (`contentAlign: 'start' | 'end'`) sem hardcodar o grid de sinais. - Rotas sob `/campanha/…` (recomendação UX-1 travada: rota, não Sheet — sobrevive a refresh/Zap). Este item define o layout e o header; as rotas concretas nascem com B60/B61/B63 ou com o wiring A1. - Sem migration / Consent / action de escrita. -- a11y: seta com nome acessível contendo o verbo visível (“Voltar”); foco gerenciado ao trocar de passo (mínimo: foco no heading do passo). +- a11y: seta com nome acessível contendo o verbo visível (“Voltar”); caption do município anunciável (`aria`-nomeada, não só cor); foco gerenciado ao trocar de passo (mínimo: foco no heading do passo). ## Decisões travadas - **Voltar mobile = chrome do wizard; desktop = browser.** **Rejeitado:** seta também em `md+` (ruído; duplica gesto nativo); só `Link` “Cancelar” no rodapé (longe do polegar no topo). - **Wizard = rota**, não Drawer sobre o Início. **Rejeitado:** Sheet full-screen (refresh/Zap perde contexto; URL não compartilha passo). Fonte: gate UX-1 2026-07-29 + rascunho. -- **Shell não grava estado de domínio** — só navegação/chrome. Estado de município/votos/sinal fica nas etapas ou num store mínimo do fluxo (Adiado com gatilho se 3º wizard pedir). -- **i18n:** ids em inglês (`WizardShell`, `onBack`, `trailingAction`); copy pt-BR. +- **Shell não grava estado de domínio** — só navegação/chrome. Estado de município/votos/sinal fica nas etapas ou num store mínimo do fluxo (Adiado com gatilho se 3º wizard pedir). O shell **recebe** o rótulo (`municipalityLabel?: string` / slot) — não resolve slug→nome sozinho. +- **Município no topo = caption sticky semi-discreta, centro superior.** **Rejeitado:** A) só no título do passo (some da hierarquia quando a pergunta muda); B) chip/badge primário gritante (compete com CTA); C) link obrigatório para `/municipios/[slug]` na v1 (abandona o wizard no meio do ritual — Adiado com gatilho). Fonte: produto 2026-07-29. +- **i18n:** ids em inglês (`WizardShell`, `onBack`, `trailingAction`, `municipalityLabel` / `contextCaption`); copy pt-BR. ## Questões em aberto @@ -58,13 +60,14 @@ flowchart TB Home["/campanha Início"] --> Route["rota de passo"] Route --> Shell["CampaignWizardShell"] Shell --> Back["Voltar md:hidden"] + Shell --> Ctx["municipalityLabel sticky centro"] Shell --> Trail["trailingAction?"] Shell --> Body["children = etapa"] ``` Componentes: -- **`CampaignWizardShell`** em `src/components/campaign/shared/` (ou `shell/`): header + main; reusa tokens/`Button` ghost para a seta (`ArrowLeft`). +- **`CampaignWizardShell`** em `src/components/campaign/shared/` (ou `shell/`): header (back | caption município | trailing) + main; reusa tokens/`Button` ghost para a seta (`ArrowLeft`); caption com `sticky top-0` no scroller do passo (respeitar safe-area / não cobrir a seta). - **Hook/helper de passo** (opcional neste item): `useWizardBack({ previousHref })` — se <2 call sites, inline no shell. - **Migration:** Sem migration, sem collection, sem server action. @@ -75,18 +78,21 @@ Componentes: ## Não escopo -- Busca de município → **B60**. Ajuste de votos → **B61**. Modelo/UI de sinal → **B62**/ **B63**. +- Busca de município → **B60** (é quem **escolhe**; o caption só aparece **depois**). Ajuste de votos → **B61**. Modelo/UI de sinal → **B62**/ **B63**. - Resumo final + CTA “Registrar atualização” do A1 → wiring do wizard A1 (após estas etapas). - Rascunho persistente cross-session → Adiado. +- Modo focado da busca do Início no focus → **B66**. ## Rabbit holes - **State machine genérica de wizard (XState / multi-route orchestrator).** **Mitigação:** shell burro + hrefs/query de passo por fluxo; extrair só no 3º wizard. - **App chrome (`CampaignSidebar`) dentro do wizard.** **Mitigação:** layout de `(app)` pode permanecer; visualmente o conteúdo é full-bleed de passo — não inventar segundo layout group sem medição. +- **Segundo header sticky competindo com `CampaignPageShell`.** **Mitigação:** um único sticky no chrome do wizard; não sticky o título do passo também. ## Adiado com gatilho - **Persistência de rascunho (município + ação) ao reabrir.** Revisitar quando a 1ª sessão real for interrompida por Zap e o CG reclamar (UX-1 § contrato #8). +- **Caption do município como `Link` para a ficha.** Revisitar se a mesa pedir “abrir município” sem sair do fluxo (ex. Sheet de leitura) — v1 é texto só. ## Referências diff --git a/docs/plans/fluxos-acao-primeiro-inicio.md b/docs/plans/fluxos-acao-primeiro-inicio.md index 348cc80b..0d6d06d7 100644 --- a/docs/plans/fluxos-acao-primeiro-inicio.md +++ b/docs/plans/fluxos-acao-primeiro-inicio.md @@ -107,7 +107,7 @@ Copy: zero “broker”, “campo sem captura”, “LQ” nos passos. Se precis | 2 | Que tipo? | Grid de tiles grandes + Drawer de info por tipo (**B63**); “Pular registro de sinal” no topo direito **só se** a origem ≠ ação `register-signal` | | 3 | Detalhe? | Texto livre; Skip (mesma regra); **Salvar** inferior direito (**B63**) | -Chrome de toda etapa: seta **Voltar** no topo esquerdo **só mobile**; desktop = browser (**B59**). +Chrome de toda etapa: seta **Voltar** no topo esquerdo **só mobile**; desktop = browser (**B59**). Após escolher o município: **nome do município sticky no limite superior central**, semi-discreto (**B59** — absorvido 2026-07-29). Opcional ao fim: “Isso muda a projeção de votos?” → entra em A1 / **B61**. diff --git a/docs/plans/modo-focado-busca-no-focus.md b/docs/plans/modo-focado-busca-no-focus.md new file mode 100644 index 00000000..7b43055d --- /dev/null +++ b/docs/plans/modo-focado-busca-no-focus.md @@ -0,0 +1,116 @@ +# Modo focado da busca no focus (não na digitação) + +Status: rascunho +Atualizado em: 2026-07-29 +Item do roadmap: [docs/roadmap.md](../roadmap.md) (Trilha B, item B66 — UX-1 busca Início) +Impeccable: B — encaixe de motion/estado no chrome do Início (`CampaignHomeLayout` / `CampaignHomeStaffChrome`) sob tema `campaign` +Appetite: ~0,5–0,75 dia eng; estado `focused` ≠ `query.isActive` + transição CSS; sem migration +Responsável: — + +## Design (Impeccable) + +Âncoras: `PRODUCT.md` (Clarity under pressure; Feel the action) / `DESIGN.md` · B47 `CampaignHomeSearch` / B46 layout · tema `data-theme='campaign'`. + +Na implementação (`implement-roadmap-item`): craft compacto → critique → polish. + +Brief compacto: + +- **Persona / contexto:** CG/assessor toca a busca no Início para achar um município; ainda não digitou — quer a tela limpa **já**, sem esperar a 1ª letra. +- **Job principal:** ao focar o input, o resto do Início cede espaço com animação (como se a barra expandisse para ocupar a tela); resultados só quando a query passar o limiar B47/B48. +- **Estratégia de cor:** Restrained — motion de layout/opacity, sem overlay escuro tipo modal. +- **Edit where you see:** não — chrome de descoberta. +- **Anti-goals:** modo focado só após digitar (decisão B47 supersedida); sumir o input; command palette ⌘K; `position:fixed` full-screen que compete com bottom nav / teclado. + +## Dados → decisão → apresentação + +Dados: N/A — chrome + motion; hits continuam em **B48–B55**. + +## Contexto + +**B47 ✓** entregou input + modo focado, com decisão travada: **expand = query não vazia** (rejeitou focus-only para “não roubar o ritual de ações”). Em produção visual, quem foca a barra ainda vê strip/resumo/dock até digitar — atrito no gesto de busca. + +**Pedido de produto (2026-07-29):** limpar a tela **ao focar** a barra (não ao começar a digitar) e **animar** a redução do resto do conteúdo, como se a busca expandisse para tomar a tela. + +Isto **emenda** B47 (não reabre B48+). Hits, debounce 250 ms e limiar ≥2 chars permanecem. + +Código vivo: `focused = searchState.query.isActive` em [`CampaignHomeStaffChrome.tsx`](../../src/components/campaign/dashboard/CampaignHomeStaffChrome.tsx); `CampaignHomeLayout` esconde spacer/strip com `focused`; contrato em [`campaignHomeSearchContract.ts`](../../src/lib/campaignHomeSearchContract.ts). + +## Objetivos + +- Separar **`uiFocused`** (input com foco **ou** query ativa) de **`query.isActive`** (debounced ≥ limiar — dispara fetch B48). +- Ao **focus** do input: entrar em modo focado imediatamente — strip de ações, spacer B46/B65, resumo B56 (quando landar) e demais chrome do Início fora da região busca+resultados **retraem com transição** (altura/opacity/transform — “expandir a busca”), não sumir em hard cut. +- Ao **blur** com query vazia (após trim): sair do modo focado e restaurar o chrome (mesma transição inversa). +- Com query ativa: permanecer focado mesmo se o foco for para um hit (Tab / toque na lista) — igual espírito atual, sem reaparecer strip no meio da leitura. +- Escape: limpa query (**B47**) e, se ficar vazia, sai do modo focado (blur ou `uiFocused=false`). +- `prefers-reduced-motion: reduce` → sem animação (só estado final). +- Soft: se **B65** já ancorou o dock no inferior, a animação parte dessa posição; se não, anima a partir do layout atual. +- Soft: etapa **B60** (busca só município) herda o mesmo critério se houver chrome residual no shell — senão N/A. +- Sem migration / collection / Consent / mudança de contrato JSON de busca. +- Pins: unit no predicado `uiFocused` / saídas blur+Escape; e2e leve “focus esconde strip antes de digitar” se estável. + +## Decisões travadas + +- **Focus dispara limpeza; digitação dispara só hits.** Opções rejeitadas: A) manter B47 “só query” (pedido explícito anula); B) focus **e** fetch com 0 chars (ruído / custo). **Escolhido:** `uiFocused = inputFocused || query.isActive`; fetch continua gated por `isActive`. +- **Animação = retração do chrome, não overlay modal.** **Rejeitado:** scrim escuro / Sheet full-screen / `fixed inset-0` que tapa bottom nav; teleportar o input para outro nó DOM (quebra foco/teclado). +- **Blur vazio restaura; blur com query ativa mantém focado.** **Rejeitado:** sticky forever até Escape (rouba Início se o usuário toca fora sem limpar). +- **Emenda B47, não novo input.** Reusa `CampaignHomeSearch` + layout; só o predicado e a transição mudam. Fonte: produto 2026-07-29. +- **i18n:** ids `uiFocused` / `home-search-expanding`; copy intacta. + +## Questões em aberto + +- **Duração / easing da transição?** **Opções:** A ~200–250 ms `ease-out` (paridade Feel the action) | B ~150 ms | C só opacity sem height. **Recomendação:** A com height/opacity no grupo chrome; medir jank no mobile — se layout thrash, cair para C. _(assumido — craft)_ +- **Pointer coarse: focus via tap já abre teclado — animar em paralelo ao teclado?** **Opções:** A animar sempre | B adiar animação até `visualViewport` estabilizar. **Recomendação:** A na v1; B só se critique mostrar salto. _(assumido)_ + +## Abordagem proposta + +```mermaid +flowchart LR + Focus["input focus"] --> UI["uiFocused=true"] + UI --> Anim["transição: strip/spacer/resumo retraem"] + Type["debounce ≥ limiar"] --> Hits["query.isActive → B48 fetch"] + BlurEmpty["blur + raw vazio"] --> Restore["uiFocused=false"] + Esc["Escape"] --> Clear["clear query"] --> Restore +``` + +Componentes: + +- **`useHomeSearchQuery` / `HomeSearchController`**: expor `inputFocused` + setters, ou mover `uiFocused` para `CampaignHomeStaffChrome` com `onFocus`/`onBlur` no input — depth: um predicado documentado, sem segundo hook. +- **`CampaignHomeSearch`**: encaminhar `onFocus`/`onBlur` (cuidado com blur→click em hit: `relatedTarget` / `pointerdown` prevent — padrão lista; não fechar antes do click no resultado). +- **`CampaignHomeLayout`**: `focused` passa a significar `uiFocused`; classes de transição (`transition-[…]`, `data-home-focused`) no spacer/actions; results slot inalterado. +- **`campaignHomeSearchContract`**: helper puro `homeSearchUiFocused({ inputFocused, isActive })` + unit spec; JSDoc atualiza a semântica supersedida de B47. +- **Migration:** Sem migration, sem collection, sem server action. + +## Dependências + +- Dura: **B47 ✓** (chrome existe). +- Soft: **B65** (âncora inferior — animação parte do dock certo); **B56** (resumo some no focus como o resto); **B60** (paridade visual se couber). + +## Não escopo + +- Providers / layout de hits → **B48–B55**. +- Âncora inferior idle → **B65**. +- Chassis wizard / município sticky → **B59**. +- Atalho ⌘K / busca na sidebar. + +## Rabbit holes + +- **Framer Motion / lib de spring.** **Mitigação:** CSS transitions + tokens; lib só se 3º call site de motion complexo. +- **Sincronizar pixel-perfect com teclado iOS.** **Mitigação:** não amarrar a `visualViewport` na v1. +- **Reescrever B47 plan como se nunca tivesse rejeitado focus.** **Mitigação:** as-built B47 fica; este item documenta a emenda. + +## Adiado com gatilho + +- **Persistir `?q=` na URL do Início.** Já adiado em B47 — reabrir só com pedido de shareable search. +- **Gesture “puxar para baixo para fechar” no modo focado.** Revisitar se mesa pedir dismiss sem Escape/blur. + +## Referências + +- [busca-global-inicio-input.md](busca-global-inicio-input.md) — decisão supersedida (“expand = query”) +- [ancorar-busca-acoes-inicio-mobile.md](ancorar-busca-acoes-inicio-mobile.md) — dock idle +- `src/components/campaign/dashboard/CampaignHomeStaffChrome.tsx` +- `src/components/campaign/dashboard/CampaignHomeLayout.tsx` +- `src/components/campaign/dashboard/CampaignHomeSearch.tsx` +- `src/components/campaign/dashboard/useHomeSearchQuery.ts` +- `src/lib/campaignHomeSearchContract.ts` +- `PRODUCT.md` / `DESIGN.md` — Field Desk / Feel the action +- AGENTS.md — naming; sem Consent diff --git a/docs/roadmap.md b/docs/roadmap.md index 98b3f9a9..a5f29045 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -1,6 +1,6 @@ # Roadmap — Teqo -Atualizado em: 2026-07-29 — ~~**B58**~~ ✓ (polimento strip Início); **B65** ancorar busca+ações no limite inferior mobile (B46 ✓ não ancorou); B48 ✓; B64; B59–B63; B47 ✓; B49–B55. +Atualizado em: 2026-07-29 — **B66** modo focado da busca no focus (+ animação); **B59** absorve município sticky no topo dos wizards; ~~**B58**~~ ✓; **B65**; B48 ✓; B64; B59–B63; B47 ✓; B49–B55. Registro canônico dos **próximos** planos e débitos. Histórico de entregas: resumo abaixo + planos em [`docs/plans/`](plans/) + notebook [`.cursor/rules/projects/nucleos-eleitorais.mdc`](../.cursor/rules/projects/nucleos-eleitorais.mdc). ## Âncoras do calendário eleitoral 2026 (Res. TSE 23.760/2026) @@ -83,20 +83,21 @@ O discovery literatura→persona→entrevista ([relatório aprovado](research/re ### Demais itens abertos -- **UX-1 fluxos ação-primeiro (prioridade pós-sessão 29/07)** — evidência: [snapshot](plans/sessao-observada-coordenador-2026-07-29-snapshot.md) · O9–O11 em CUSTOMER.md · **rascunho:** [fluxos-acao-primeiro-inicio.md](plans/fluxos-acao-primeiro-inicio.md). Soft deadline: **03/08**. **Chassis Início:** ~~**B43**~~ ✓ → ~~**B44**~~ ✓ → ~~**B45**~~ ✓ → ~~**B46**~~ ✓ → ~~**B47**~~ ✓ → ~~**B58**~~ ✓ → **B65** (âncora inferior mobile — B46 não ancorou) → ~~**B48**~~ ✓ → **B49–B55** (demais resultados busca) · **B56** (resumo) · **B57** delta 7d = futuro. **Wizards (etapas):** **B59** chassis → **B60** busca município · **B61** ajuste votos · **B62** simplificar sinal → **B63** wizard sinal · **B64** wizard tendência; wiring A1/A2 depois. +- **UX-1 fluxos ação-primeiro (prioridade pós-sessão 29/07)** — evidência: [snapshot](plans/sessao-observada-coordenador-2026-07-29-snapshot.md) · O9–O11 em CUSTOMER.md · **rascunho:** [fluxos-acao-primeiro-inicio.md](plans/fluxos-acao-primeiro-inicio.md). Soft deadline: **03/08**. **Chassis Início:** ~~**B43**~~ ✓ → ~~**B44**~~ ✓ → ~~**B45**~~ ✓ → ~~**B46**~~ ✓ → ~~**B47**~~ ✓ → ~~**B58**~~ ✓ → **B65** (âncora inferior mobile — B46 não ancorou) → **B66** (focus limpa tela + animação; emenda B47) → ~~**B48**~~ ✓ → **B49–B55** (demais resultados busca) · **B56** (resumo) · **B57** delta 7d = futuro. **Wizards (etapas):** **B59** chassis (+ município sticky topo) → **B60** busca município · **B61** ajuste votos · **B62** simplificar sinal → **B63** wizard sinal · **B64** wizard tendência; wiring A1/A2 depois. - ~~**B43** Início em branco + Quadro~~ — **entregue 2026-07-29** (`/campanha` blank; staff dashboard em `/campanha/quadro`; liderança em `/campanha/contatos`; nav Início+Quadro / Início+Meus contatos; `requireCampaignPageActor` manda leader bloqueado → `/campanha/contatos`; sem migration) · [plano](plans/inicio-em-branco-quadro.md) - ~~**B44** Botão de ação do Início + lista horizontal~~ — **entregue 2026-07-29** (`CampaignHomeActionButton` + `CampaignHomeActionStrip`; Tooltip fine / long-press Drawer coarse; montado no Início por B45 ✓) · ~1d · Janela 1 · Impeccable C · [plano](plans/botao-acao-inicio-strip.md) - ~~**B45** Catálogo de ações por persona~~ — **entregue 2026-07-29** (`src/lib/campaignHomeActions.ts` + `CampaignHomeActions`; staff 6 ações com `uncovered-municipalities` → `?coverage=sem_assessor&sort=votos`; leader 2 com `my-contacts` → `/campanha/contatos`; demais inertes; ilha client por limite RSC↔ícones Lucide) · [plano](plans/catalogo-acoes-inicio-por-persona.md) - **B58** Polimento visual da strip de ações do Início — ~~remover heading "O que você quer fazer?"; rótulos curtos (Ajustar votos, Registrar sinal, …; atalho → **"Ver esquecidos"** _(proposto — validar com produto)_); scale discreto no círculo (hover/long-press) + opacity no active; scrollbar horizontal oculta (pan preservado)~~ — **entregue 2026-07-29** (catálogo + strip + botão; e2e atualizado) · Depende de B45 ✓ · ~0,5d · Janela 1 · Impeccable B · [plano](plans/polimento-strip-acoes-inicio.md) -- **B59** Chassis do wizard (shell de passo + seta Voltar só mobile; desktop = browser) · Depende de B45 ✓ · ~0,75d · Janela 1 · Impeccable C · [plano](plans/chassis-wizard-campanha.md) +- **B59** Chassis do wizard (shell de passo + seta Voltar só mobile; desktop = browser; **município sticky** no limite superior central, semi-discreto, após escolha) · Depende de B45 ✓ · ~0,75–1d · Janela 1 · Impeccable C · [plano](plans/chassis-wizard-campanha.md) - **B60** Etapa busca município nos wizards (UX da busca do Início, só municípios; select → avança) · Depende de B59 · soft B48 · ~1d · Janela 1 · Impeccable B · [plano](plans/busca-municipio-wizard.md) - **B61** Etapa ajuste de votos (média→pessimista→otimista; atalhos 2×/±50/±100; coerência com jump+warning) · Depende de B59 · soft B60 · ~1–1,25d · Janela 1 · Impeccable C · [plano](plans/ajuste-votos-wizard.md) - **B62** Simplificar modelo de sinal (dropar Fonte/Triangulado; labels mesa sem “broker”; migration + E11) · Depende de C12 ✓ · ~0,75–1d · Janela 1 · Impeccable B · [plano](plans/simplificar-modelo-sinal.md) - **B63** Wizard registrar sinal (grid de tipos + Drawer info + texto + “Pular” se origem ≠ register-signal) · Depende de B59 + B62 · soft B60 · ~1–1,25d · Janela 1 · Impeccable C · [plano](plans/wizard-registro-sinal.md) - **B64** Wizard mudar tendência (grid colorido ≠ atual + Drawer info + justificativa com prefill/Limpar/Salvar + “Pular” sempre) · Depende de B59 · soft B60 · soft B24 ✓ · ~1–1,25d · Janela 1 · Impeccable C · [plano](plans/wizard-mudar-tendencia.md) - ~~**B46** Posição dos botões de ação (thumb zone)~~ — **entregue 2026-07-29** (`CampaignHomeLayout`: coluna `min-h-full` + spacer mobile; strip em `data-slot="home-actions"` na metade inferior do viewport; `md+` no topo; slot `searchSlot` + `data-slot="home-search"` para B47; sem migration) · [plano](plans/posicao-botoes-acao-inicio-thumb-zone.md) · **âncora inferior falhou em produção visual** → **B65** -- ~~**B47** Busca global — input (debounce, sem botão; modo focado: sobe e esconde o resto)~~ — **entregue 2026-07-29** (`CampaignHomeStaffChrome` + `CampaignHomeSearch` + `useHomeSearchQuery`; debounce 250 ms; query ativa ≥2 chars; `HomeSearchContext` para B48+; staff-only via `isStaffCampaignRole`; Escape limpa; região `aria-live` sem hits ainda; sem migration) · [plano](plans/busca-global-inicio-input.md) -- **B65** Ancorar busca + ações do Início no limite inferior (mobile) — B46 ✓ entregou ordem/slots mas o spacer `flex-1` não empurra: `min-h-full` no filho do scrollport não cria altura livre; preencher cadeia (`h-full`/flex fill) no chrome do Início; `md+` inalterado; modo focado B47 intacto · Depende de B46 ✓ / B47 ✓ (código) · ~0,25–0,5d · Janela 1 · Paralelizável com B58 / B49 / B59 · Impeccable B · [plano](plans/ancorar-busca-acoes-inicio-mobile.md) +- ~~**B47** Busca global — input (debounce, sem botão; modo focado: sobe e esconde o resto)~~ — **entregue 2026-07-29** (`CampaignHomeStaffChrome` + `CampaignHomeSearch` + `useHomeSearchQuery`; debounce 250 ms; query ativa ≥2 chars; `HomeSearchContext` para B48+; staff-only via `isStaffCampaignRole`; Escape limpa; região `aria-live` sem hits ainda; sem migration) · [plano](plans/busca-global-inicio-input.md) · **emenda B66:** limpeza no **focus** (não só na digitação) + animação +- **B66** Modo focado da busca no **focus** (não na digitação) + animação de retração do chrome (strip/spacer/resumo) como se a barra expandisse — emenda a decisão B47 “expand = query”; hits continuam gated por limiar ≥2 · Depende de B47 ✓ · soft B65 · ~0,5–0,75d · Janela 1 · Paralelizável com B49–B53 / B59 / B62 · Impeccable B · [plano](plans/modo-focado-busca-no-focus.md) +- **B65** Ancorar busca + ações do Início no limite inferior (mobile) — B46 ✓ entregou ordem/slots mas o spacer `flex-1` não empurra: `min-h-full` no filho do scrollport não cria altura livre; preencher cadeia (`h-full`/flex fill) no chrome do Início; `md+` inalterado; modo focado B47/B66 intacto · Depende de B46 ✓ / B47 ✓ (código) · soft B66 (animação parte do dock) · ~0,25–0,5d · Janela 1 · Paralelizável com B58 / B49 / B59 · Impeccable B · [plano](plans/ancorar-busca-acoes-inicio-mobile.md) - ~~**B48** Busca — resultados Municípios (+ TIs no mesmo grupo; flag de prioridade alinhada; “2022” / agregado à direita; sem card)~~ — **entregue 2026-07-29** (`POST /campanha/home-search`, `searchHomeMunicipalities`, `HomeSearchMunicipalityGroup`; word-start; assessor scoped; TIs via `loadTerritoryOverview`) · [plano](plans/busca-global-resultados-municipios.md) - **B49** Busca — resultados Lideranças · Depende de B47 · ~0,5–0,75d · Janela 1 · Impeccable B · [plano](plans/busca-global-resultados-liderancas.md) - **B50** Busca — resultados Assessores (access B19) · Depende de B47 · ~0,5d · Janela 1 · Impeccable B · [plano](plans/busca-global-resultados-assessores.md) @@ -213,6 +214,7 @@ flowchart TD B58n["B58 Polish strip
ações Início"] B46n["B46 ✓ Thumb zone
ações Início"] B47n["B47 ✓ Busca global
input + modo focado"] + B66n["B66 Focus limpa tela
+ animação busca"] B65n["B65 Âncora inferior
busca+ações mobile"] B48n["B48 ✓ Busca
Municípios + TIs"] B49n["B49 Busca Lideranças"] @@ -224,7 +226,7 @@ flowchart TD B55n["B55 Busca ações
WA / share"] B56n["B56 Resumo campanha
total + cobertura"] B57n["B57 Delta 7d estimativa
(futuro / baixa prio)"] - B59n["B59 Chassis wizard
shell + voltar mobile"] + B59n["B59 Chassis wizard
shell + município sticky"] B60n["B60 Busca município
nos wizards"] B61n["B61 Ajuste votos
cenários + atalhos"] B62n["B62 Simplificar
modelo de sinal"] @@ -298,6 +300,8 @@ flowchart TD B46n --> B47n B46n -.âncora falhou.-> B65n B47n -.slots/modo focado.-> B65n + B47n --> B66n + B65n -.dock idle.-> B66n B47n --> B48n B47n --> B49n B47n --> B50n @@ -315,6 +319,7 @@ flowchart TD E8i -.cobertura OMTM.-> B56n B46n -.thumb-zone layout.-> B56n B47n -.some no modo focado.-> B56n + B66n -.some no focus.-> B56n B56n --> B57n B45n --> B59n B59n --> B60n @@ -322,6 +327,7 @@ flowchart TD B59n --> B63n B59n --> B64n B48n -.UX/loader.-> B60n + B66n -.paridade focus.-> B60n B60n -.município.-> B61n B60n -.município standalone.-> B63n B60n -.município standalone.-> B64n @@ -421,11 +427,11 @@ flowchart TD B8F2 -.rank por ZE = débito aberto.-> B14n ``` -Paralelizáveis agora: **B65** (âncora inferior mobile — quick win do chassis); **B58** (polimento strip); **B59** (chassis wizard — desbloqueia B60/B61/B63/B64); **B62** (simplificar sinal — paralelo a B59; desbloqueia B63); **B56** (resumo Início); **B49–B53** após B47 ✓ / B48 ✓ (depois B54/B55). Após **B59**: **B60** ∥ **B61** ∥ **B64**. **B63** espera B59+B62. Prefills ricos de B64 com B61/B63 são soft. **B57** futuro (depende B56). Fill-ins / débitos `*+` e itens já ✓ permanecem fora do caminho crítico UX-1. **D3** só após smoke + folga se UX-1 não absorver o Zap. +Paralelizáveis agora: **B65** (âncora inferior mobile — quick win do chassis); **B66** (focus limpa busca — após B47 ✓; melhor após B65); **B59** (chassis wizard + município sticky — desbloqueia B60/B61/B63/B64); **B62** (simplificar sinal — paralelo a B59; desbloqueia B63); **B56** (resumo Início); **B49–B53** após B47 ✓ / B48 ✓ (depois B54/B55). Após **B59**: **B60** ∥ **B61** ∥ **B64**. **B63** espera B59+B62. Prefills ricos de B64 com B61/B63 são soft. **B57** futuro (depende B56). Fill-ins / débitos `*+` e itens já ✓ permanecem fora do caminho crítico UX-1. **D3** só após smoke + folga se UX-1 não absorver o Zap. ### Sequência por janela (só pendentes) -**Janela 1 — agora → 05/08 (convenções):** **prioridade pós-29/07 — ~~B43–B48~~ ✓ → B65** (âncora inferior mobile) **→ B58** (∥ B49–B53; depois B54/B55) · **B56** · **wizards B59 → B60∥B61∥B64 · B62 → B63** (soft 03/08) · [fluxos](plans/fluxos-acao-primeiro-inicio.md); smoke + onboarding Onda 0; **E4R ✓** aplicar seed em produção após smoke; demais entregues/pendentes da janela (E8/E9/E17/E18/B15–B42/B19/…) inalterados no detalhe abaixo — foco operacional = busca B49+ + etapas de wizard B59–B64. **E8 ✓** conta da cadeira entregue; **E17 ✓** tabela TI no Início; **B15 ✓** (sort por coluna) e **A11 ✓** (posição em votos + `sort=votos`; o default do staff passou a `deficit` no E9 ✓) entregues 2026-07-24; **E18 ✓** documentação de conceitos (`/campanha/conceitos`, v1 só E8) entregue 2026-07-24; **B19 ✓** gerenciar assessores (caminho do onboarding sem `/admin` — criar/ativar contas e carteiras) entregue 2026-07-24; **B16 ✓** filtros no header entregue 2026-07-25; **B20 ✓** Municípios prioritários no Início entregue 2026-07-25; ~~**B38**~~ ✓ sidebar recolhido em tablet (entregue 2026-07-26 — `offcanvas` + trigger `md+` + cookie/`matchMedia`); **B39** (lembrar de mim / sessão longa — o default de 2 h está derrubando sessão no onboarding; ~0,5 dia, entra cedo) e, logo atrás se folga, ~~**B40**~~ ✓ (biometria WebAuthn — entregue 2026-07-28); ~~**B41**~~ ✓ (scroll horizontal + sticky na lista de municípios — entregue 2026-07-27) e ~~**B42**~~ ✓ (polimento mobile da mesma lista — Drawer em Tendência/Assessores/Votos estimados + card compacto e clicável; entregue 2026-07-27); **B21** (página dos Territórios de Identidade — a leitura regional sai do painel do Início e ganha tela própria com sort/filtro; útil já no onboarding para dividir carteiras) se folga — e, logo atrás dela, **B25** (link do território na célula da lista: quarto de dia, é o que faz a página nova ser encontrada de dentro do trabalho); **B22** (explicação por coluna no header — a tabela deixa de exigir o autor do E8/E9 ao lado para ser lida; quick win de onboarding, meio dia); **B23** (tooltip nas células — nomes dos assessores no hover da coluna, hoje só iniciais, e a justificativa da tendência, hoje invisível na lista; capacidade genérica da célula, meio dia, casa com B22 pelo mesmo primitivo); ~~**B24**~~ ✓ (auto-save + justificativa no popover de Tendência — entregue 2026-07-26; a mesa corrige em massa as notas semeadas pelo E4R ✓ sem abrir 435 telas de edição); **B26** (registrar sinal na própria célula "Último sinal" — fecha o laço do E9 ✓: hoje a fila diz onde está frio e obriga a sair dela para registrar qualquer coisa; ~0,75 dia, e é o item que mais aumenta a chance do gate de adoção abaixo, porque o registro passa a caber no gesto de varrer a lista, inclusive no celular); **B27** (combobox + chips + auto-save nos Assessores — é literalmente a tela em que o CG divide as carteiras no onboarding: hoje procura o nome numa coluna de checkboxes e confirma num botão; ~0,75 dia, casa com B24 pelo mesmo endpoint e com B23 pelo mesmo gatilho); **B28** (e-mail + celular na lista de lideranças — copy + WhatsApp como em assessores, sem abrir a ficha; ~0,5–0,75 dia, quick win de campo no onboarding da rede); **B30** (convidar para completar cadastro por WhatsApp na mesma lista — reusa o convite que já existe no detalhe, sem abrir a ficha; ~0,25–0,5 dia, o quick win mais barato desta leva porque não toca action/collection nenhuma; casa com B28 pela mesma linha, ícone distinto); **B31** (coluna de dobradinhas na mesma lista — é o preenchimento em lote que o onboarding exige: o E4R ✓ deixou dobradinha só no município e as fichas vazias, e completar uma a uma pelo detalhe é o gesto que trava a mesa; ~1 dia, casa com B27 pela mesma peça de célula — quem for primeiro define o padrão do chip+combobox in-list); ~~**B32**~~ ✓ (editar Status de apoio na célula da mesma lista — entregue 2026-07-26; fecha o adiado do próprio B29); **B34** (chips editáveis de municípios na mesma lista — a coluna "Municípios" ganha o mesmo tratamento da coluna homônima em Assessores (B19 ✓): chips com link + Popover de edição com combobox, em vez do texto morto atual; ~1–1,25 dia, casa com B27/B31 pela mesma peça de célula editável — quem entrar antes define o padrão do combobox+chip in-list que os outros herdam); **B37** (o mesmo tratamento de chips editáveis na coluna "Municípios" de `/campanha/dobradinhas` — hoje um número morto, `municipalityCount`; ~0,75–1 dia, herda a lib promovida pelo B34 se ele já tiver landado, senão promove ela mesma); **B36** (a coluna "Lideranças" da mesma lista ganha o mesmo tratamento — chips nomeados + Popover + busca + auto-save por delta, reusando sem alteração a mutação que o B31 desenha para o lado oposto da mesma relação; ~0,5–1,5 dia dependendo de quem entre B31/B36 chega primeiro na corrida de extração da célula compartilhada); **B33** (sort + filtro no header de `/campanha/dobradinhas` — pedido explícito de reuso: Nome/Partido no header e filtro por Partido, sem duplicar o chrome de `/campanha/municipios`; ~0,5–1,5 dia dependendo de quem chega primeiro na corrida de extração do chrome compartilhado com B29/B21; entra perto de B29 por reusar a mesma peça); **B29** (sort + filtro no header da mesma lista — é a tela onde o assessor recebe a carteira e precisa recortar "quem ainda está a abordar aqui" / "quem ainda não tem acesso ao app" antes de convidar; ~1,5–2 dias porque paga também a extração do head compartilhado, então entra depois dos quick wins — mas antes se B21 for adiado, para o head nascer compartilhado); ~~**B17**~~ ✓ (seletor de colunas) / ~~**B18**~~ ✓ (filtros salvos + atalho sidebar) entregues 2026-07-28; fill-in **renomear coluna Cobertura** (header curto na fila — quarto de dia; glossário/KPI intactos); fill-in **remover coluna Tipo** (densidade morta na fila — quarto/meio dia; Salvador via slugs cobre ZE); ~~fill-in **remover lista de zonas do Início**~~ ✓ (entregue 2026-07-28); fill-in **selecionados no topo nos filtros do header** (desmarcar sem caçar checkbox; helper puro que B21 herda — quarto de dia); **C13 ✓** (renomeado "Plano de Ação" → "Atividade" em toda a vertical, incluindo a migration data-preserving — entregue 2026-07-25); gate de adoção: sinal Little Hire — ≥1 update espontâneo até 30/07, cobrança da tabela dispensada (planilhas já em `docs/sheets/`) — acompanhamento em [IMPROVE-APP-PLAN.md](IMPROVE-APP-PLAN.md); **R6** critique/polish; **E9 ✓** entregue no mesmo dia; **B14 ✓** (atalho geo entregue 2026-07-26); Onda 0 jurídica em paralelo (externa). +**Janela 1 — agora → 05/08 (convenções):** **prioridade pós-29/07 — ~~B43–B48~~ ✓ → B65** (âncora inferior mobile) **→ B66** (focus limpa busca) **→** **wizards B59** (chassis + município sticky) **→ B60∥B61∥B64 · B62 → B63** (soft 03/08) · **B56** · **B49–B55** · [fluxos](plans/fluxos-acao-primeiro-inicio.md); smoke + onboarding Onda 0; **E4R ✓** aplicar seed em produção após smoke; demais entregues/pendentes da janela (E8/E9/E17/E18/B15–B42/B19/…) inalterados no detalhe abaixo — foco operacional = busca B49+ + etapas de wizard B59–B64 + polish busca B65/B66. **E8 ✓** conta da cadeira entregue; **E17 ✓** tabela TI no Início; **B15 ✓** (sort por coluna) e **A11 ✓** (posição em votos + `sort=votos`; o default do staff passou a `deficit` no E9 ✓) entregues 2026-07-24; **E18 ✓** documentação de conceitos (`/campanha/conceitos`, v1 só E8) entregue 2026-07-24; **B19 ✓** gerenciar assessores (caminho do onboarding sem `/admin` — criar/ativar contas e carteiras) entregue 2026-07-24; **B16 ✓** filtros no header entregue 2026-07-25; **B20 ✓** Municípios prioritários no Início entregue 2026-07-25; ~~**B38**~~ ✓ sidebar recolhido em tablet (entregue 2026-07-26 — `offcanvas` + trigger `md+` + cookie/`matchMedia`); **B39** (lembrar de mim / sessão longa — o default de 2 h está derrubando sessão no onboarding; ~0,5 dia, entra cedo) e, logo atrás se folga, ~~**B40**~~ ✓ (biometria WebAuthn — entregue 2026-07-28); ~~**B41**~~ ✓ (scroll horizontal + sticky na lista de municípios — entregue 2026-07-27) e ~~**B42**~~ ✓ (polimento mobile da mesma lista — Drawer em Tendência/Assessores/Votos estimados + card compacto e clicável; entregue 2026-07-27); **B21** (página dos Territórios de Identidade — a leitura regional sai do painel do Início e ganha tela própria com sort/filtro; útil já no onboarding para dividir carteiras) se folga — e, logo atrás dela, **B25** (link do território na célula da lista: quarto de dia, é o que faz a página nova ser encontrada de dentro do trabalho); **B22** (explicação por coluna no header — a tabela deixa de exigir o autor do E8/E9 ao lado para ser lida; quick win de onboarding, meio dia); **B23** (tooltip nas células — nomes dos assessores no hover da coluna, hoje só iniciais, e a justificativa da tendência, hoje invisível na lista; capacidade genérica da célula, meio dia, casa com B22 pelo mesmo primitivo); ~~**B24**~~ ✓ (auto-save + justificativa no popover de Tendência — entregue 2026-07-26; a mesa corrige em massa as notas semeadas pelo E4R ✓ sem abrir 435 telas de edição); **B26** (registrar sinal na própria célula "Último sinal" — fecha o laço do E9 ✓: hoje a fila diz onde está frio e obriga a sair dela para registrar qualquer coisa; ~0,75 dia, e é o item que mais aumenta a chance do gate de adoção abaixo, porque o registro passa a caber no gesto de varrer a lista, inclusive no celular); **B27** (combobox + chips + auto-save nos Assessores — é literalmente a tela em que o CG divide as carteiras no onboarding: hoje procura o nome numa coluna de checkboxes e confirma num botão; ~0,75 dia, casa com B24 pelo mesmo endpoint e com B23 pelo mesmo gatilho); **B28** (e-mail + celular na lista de lideranças — copy + WhatsApp como em assessores, sem abrir a ficha; ~0,5–0,75 dia, quick win de campo no onboarding da rede); **B30** (convidar para completar cadastro por WhatsApp na mesma lista — reusa o convite que já existe no detalhe, sem abrir a ficha; ~0,25–0,5 dia, o quick win mais barato desta leva porque não toca action/collection nenhuma; casa com B28 pela mesma linha, ícone distinto); **B31** (coluna de dobradinhas na mesma lista — é o preenchimento em lote que o onboarding exige: o E4R ✓ deixou dobradinha só no município e as fichas vazias, e completar uma a uma pelo detalhe é o gesto que trava a mesa; ~1 dia, casa com B27 pela mesma peça de célula — quem for primeiro define o padrão do chip+combobox in-list); ~~**B32**~~ ✓ (editar Status de apoio na célula da mesma lista — entregue 2026-07-26; fecha o adiado do próprio B29); **B34** (chips editáveis de municípios na mesma lista — a coluna "Municípios" ganha o mesmo tratamento da coluna homônima em Assessores (B19 ✓): chips com link + Popover de edição com combobox, em vez do texto morto atual; ~1–1,25 dia, casa com B27/B31 pela mesma peça de célula editável — quem entrar antes define o padrão do combobox+chip in-list que os outros herdam); **B37** (o mesmo tratamento de chips editáveis na coluna "Municípios" de `/campanha/dobradinhas` — hoje um número morto, `municipalityCount`; ~0,75–1 dia, herda a lib promovida pelo B34 se ele já tiver landado, senão promove ela mesma); **B36** (a coluna "Lideranças" da mesma lista ganha o mesmo tratamento — chips nomeados + Popover + busca + auto-save por delta, reusando sem alteração a mutação que o B31 desenha para o lado oposto da mesma relação; ~0,5–1,5 dia dependendo de quem entre B31/B36 chega primeiro na corrida de extração da célula compartilhada); **B33** (sort + filtro no header de `/campanha/dobradinhas` — pedido explícito de reuso: Nome/Partido no header e filtro por Partido, sem duplicar o chrome de `/campanha/municipios`; ~0,5–1,5 dia dependendo de quem chega primeiro na corrida de extração do chrome compartilhado com B29/B21; entra perto de B29 por reusar a mesma peça); **B29** (sort + filtro no header da mesma lista — é a tela onde o assessor recebe a carteira e precisa recortar "quem ainda está a abordar aqui" / "quem ainda não tem acesso ao app" antes de convidar; ~1,5–2 dias porque paga também a extração do head compartilhado, então entra depois dos quick wins — mas antes se B21 for adiado, para o head nascer compartilhado); ~~**B17**~~ ✓ (seletor de colunas) / ~~**B18**~~ ✓ (filtros salvos + atalho sidebar) entregues 2026-07-28; fill-in **renomear coluna Cobertura** (header curto na fila — quarto de dia; glossário/KPI intactos); fill-in **remover coluna Tipo** (densidade morta na fila — quarto/meio dia; Salvador via slugs cobre ZE); ~~fill-in **remover lista de zonas do Início**~~ ✓ (entregue 2026-07-28); fill-in **selecionados no topo nos filtros do header** (desmarcar sem caçar checkbox; helper puro que B21 herda — quarto de dia); **C13 ✓** (renomeado "Plano de Ação" → "Atividade" em toda a vertical, incluindo a migration data-preserving — entregue 2026-07-25); gate de adoção: sinal Little Hire — ≥1 update espontâneo até 30/07, cobrança da tabela dispensada (planilhas já em `docs/sheets/`) — acompanhamento em [IMPROVE-APP-PLAN.md](IMPROVE-APP-PLAN.md); **R6** critique/polish; **E9 ✓** entregue no mesmo dia; **B14 ✓** (atalho geo entregue 2026-07-26); Onda 0 jurídica em paralelo (externa). **Janela 2 — 05/08 → 16/08 (pré-propaganda):** C2 dados reais assim que o jurídico liberar; ~~**E9** fila de alocação~~ (entregue 2026-07-24, antecipada da janela 2); ~~**E16** dossiê do município~~ (entregue 2026-07-25, antecipado da janela 2); D2 se sobrar folga. @@ -435,9 +441,9 @@ Paralelizáveis agora: **B65** (âncora inferior mobile — quick win do chassis ### Cortes seguros / não cortáveis -**Não cortáveis:** Onda 0 (jurídico/Consent); ~~**B43–B48** chassis UX-1 + busca Municípios~~ ✓; **B65** âncora inferior mobile (B46 ✓ não ancorou — cortar = thumb zone continua falhando no celular); **B59–B61** etapas mínimas do wizard de votos (chassis + busca município + ajuste — cortar = ações do Início continuam inertes no ritual A1); **B62** simplificar sinal (schema — cortar = wizard B63 e B26 seguem exigindo Fonte/Triangulado); ~~**E4R** seed da planilha~~ (entregue 2026-07-24 — ainda aplicar em produção após smoke); ~~**E8** conta da cadeira~~ (entregue 2026-07-24); ~~**C12** registro-fundação~~ (entregue 2026-07-24); C2 dados reais; assimetria declarado×estimado (relação de campo); ~~**E9** fila de alocação~~ (entregue 2026-07-24 — era o mínimo de "inteligência, não planilha"); ~~**B19** gerenciar assessores~~ (entregue 2026-07-24 — CG/candidato não entram em `/admin`); **B39** lembrar de mim / sessão longa (default de 2 h derruba sessão no onboarding/campo — atrito diário de adoção). +**Não cortáveis:** Onda 0 (jurídico/Consent); ~~**B43–B48** chassis UX-1 + busca Municípios~~ ✓; **B65** âncora inferior mobile (B46 ✓ não ancorou — cortar = thumb zone continua falhando no celular); **B66** focus limpa busca (cortar = strip compete com o gesto de buscar até digitar — emenda explícita de produto); **B59–B61** etapas mínimas do wizard de votos (chassis + município sticky + busca município + ajuste — cortar = ações do Início continuam inertes no ritual A1 **e** o CG perde o contexto de município no meio do passo); **B62** simplificar sinal (schema — cortar = wizard B63 e B26 seguem exigindo Fonte/Triangulado); ~~**E4R** seed da planilha~~ (entregue 2026-07-24 — ainda aplicar em produção após smoke); ~~**E8** conta da cadeira~~ (entregue 2026-07-24); ~~**C12** registro-fundação~~ (entregue 2026-07-24); C2 dados reais; assimetria declarado×estimado (relação de campo); ~~**E9** fila de alocação~~ (entregue 2026-07-24 — era o mínimo de "inteligência, não planilha"); ~~**B19** gerenciar assessores~~ (entregue 2026-07-24 — CG/candidato não entram em `/admin`); **B39** lembrar de mim / sessão longa (default de 2 h derruba sessão no onboarding/campo — atrito diário de adoção). -**Cortes seguros** (se o prazo apertar, nesta ordem): **B58** polimento da strip (rótulos longos e heading continuam funcionais — cortar = polish visual antes do 03/08); **B64** wizard tendência standalone (A1 ainda pode embutir tendência via B24 ✓ / passo curto; cortar = sem grid colorido + prefill até folga); **B63** wizard sinal standalone (A1 ainda pode embutir select pós-B62; cortar = sem grid/Drawer de tipos até folga); **B57** delta 7d (Início continua com total+cobertura do B56; Δ era futuro de propósito); **B56** resumo no Início (Quadro já tem os mesmos agregados — cortar = Início sem briefing numérico); **B55** ações WA/share na busca (linha continua clicável); **B54** grid/cap (empilhar sempre); **B51**/**B53**/**B52**/**B50**/**B49** grupos secundários da busca (nessa ordem — Municípios B48 fica); **D5** inbox→rascunhos (manter registro manual + `wa.me`); **D4** envio bridge (manter `wa.me`); **D3** fundação do canal (atalho `wa.me` continua); **E12** camada TI (rollup manual por lista; **E17** já dá a leitura regional básica no Início); **E13** planejador de giros (rebaixado na fila de corte em 2026-07-24: "perna"/agenda é a restrição dominante nomeada em campo — cortar só depois de E12; agenda segue manual com J-A/J-B como guia); **E15** backtest (pós-eleição por definição — cortar = perder o aprendizado 2030); **E11** motor v1 (manter a fila E9 ✓ sem sugestões); **B13** símbolo proporcional (manter quantis/LQ como escala); ~~**E14** níveis~~ (entregue 2026-07-27 — `priority` continua, intocado); ~~**B8 F2** polígonos~~ (entregue 2026-07-26 — o mapa não é mais agregado em Salvador); **D2** push (adiar); **A6**; ~~**B14** município mais próximo~~ (entregue 2026-07-26); ~~**B38** sidebar recolhido em tablet~~ (entregue 2026-07-26); ~~**B40** login biométrico~~ (entregue 2026-07-28 — senha + B39 ✓ continuam, e cortar teria custado só o atalho de digital/Face ID; era o mais caro e o primeiro a cair desta leva B39–B42); **B42** polimento mobile da lista de municípios (Popover e card longos continuam usáveis — cortar custa conforto de teclado e densidade no celular); ~~**B41** scroll horizontal + sticky~~ (entregue 2026-07-27) (a tabela continua legível com zoom/pan da página — cortar custa o overflow em tablet; cai **depois** de B42 porque o bug de layout em mesa é mais caro que o polish mobile); ~~**B18** filtros salvos~~ ✓ entregue (lista + filtros manuais continuam; Visitados cobrem “voltar”); **B21** página dos Territórios de Identidade (o painel do E17 ✓ no Início continua entregando a leitura regional) — **B25** cai junto por definição (sem destino, sem link); ~~**B17** seletor de colunas~~ ✓ entregue (tabela completa continua; scroll horizontal); ~~**B22** explicação no header~~ (entregue 2026-07-26); ~~**B23** tooltip nas células~~ (entregue 2026-07-26); ~~**B24** auto-save + justificativa na Tendência~~ (entregue 2026-07-26); **B27** combobox + chips nos Assessores (a lista de checkboxes com "Salvar" continua atribuindo — cortar custa a mesma coerência do B24 mais o tempo do CG procurando nomes numa coluna durante o onboarding; corte junto com B24, já que dividem o endpoint); **B28** e-mail + celular na lista de lideranças (a ficha `/liderancas/[id]` continua mostrando o contato — cortar custa o gesto de copiar/abrir ZAP na varredura; quick win barato de cortar e de fazer); ~~**B30** convite de completar cadastro por WhatsApp na lista~~ (entregue 2026-07-26); **B31** coluna de dobradinhas nas lideranças (o `RelationMultiSelect` da ficha interna continua vinculando — cortar custa o preenchimento em lote do onboarding, uma ficha aberta por liderança, e mantém o vínculo invisível na varredura; corte junto com B27, já que dividem a peça de célula, e antes de B29 só se a mesa já tiver preenchido as dobradinhas à mão); ~~**B32** editar Status de apoio na célula~~ (entregue 2026-07-26); **B34** chips editáveis de municípios na lista de lideranças (o texto simples `row.municipalityNames.join(', ')` continua legível e a ficha `/liderancas/[id]` continua vinculando município via formulário — cortar custa o link direto ao município, a navegação por chip e o atalho de adicionar/remover sem abrir a ficha; corte junto com B31, já que dividem a mesma peça de célula editável, e antes de B29 pelo mesmo motivo de coerência); **B37** chips editáveis de municípios na lista de dobradinhas (o número `municipalityCount` continua legível e a ficha de município continua vinculando dobradinha pelo `MunicipalityStrategyForm` — cortar custa o link direto, a navegação por chip e o atalho de adicionar/remover sem abrir a ficha do município; corte junto com B34, já que dividem a mesma lib e a mesma decisão de container); ~~**B36** coluna de lideranças na lista de dobradinhas~~ (entregue 2026-07-26; a contagem `leadershipCount` era o fallback e a ficha `/liderancas/[id]` continua vinculando dobradinha via formulário — cortar custa o link direto à liderança, a navegação por chip e o atalho de adicionar/remover sem abrir a ficha; corte junto com B31, já que dividem a mesma mutação/schema/lock); ~~**B33** sort + filtro no header das dobradinhas~~ (entregue 2026-07-26); **B29** sort + filtro no header das lideranças (a busca por nome continua funcionando e o escopo do assessor já reduz a lista — cortar custa o recorte por status/setor/município no onboarding da rede e mantém o header rico como cópia única de municípios; por ser o item mais caro desta faixa (~1,5–2 dias com a extração do head), cai **antes** do B26, que é o que sustenta o gate de adoção); **B26** registrar sinal na célula (o formulário completo em `/[slug]?tab=updates` continua sendo o caminho — cortar custa o laço da fila do E9 ✓ e o registro em campo pelo celular, que é justamente onde o gate de adoção se decide; por isso cai **depois** de B22/B23/B24); ~~**C13** renomear Plano de Ação → Atividade~~ (entregue 2026-07-25); **B20** prioritários no Início (lista `?priority=alta` continua; só perde o atalho — mas a seção atual mente, então cortar = conviver com o bug); fill-in **renomear coluna Cobertura** (a lista continua legível com o rótulo longo — corte = header mais largo); fill-in **remover coluna Tipo** (a lista continua completa; só mantém densidade morta — corte = conviver com a coluna); ~~fill-in **remover lista de zonas do Início**~~ ✓ (entregue 2026-07-28 — o mapa B8 F2 ✓ continua abrindo cada ZE); ~~**B16** filtros no header~~ (entregue 2026-07-25); ~~**B15** sort por coluna~~ (entregue 2026-07-24); ~~**A11**/**E17**~~ (entregues 2026-07-24); ~~**E18** documentação de conceitos~~ (entregue 2026-07-24); ~~**E16** dossiê~~ (entregue 2026-07-25); demais débitos/fill-ins. +**Cortes seguros** (se o prazo apertar, nesta ordem): **B64** wizard tendência standalone (A1 ainda pode embutir tendência via B24 ✓ / passo curto; cortar = sem grid colorido + prefill até folga); **B63** wizard sinal standalone (A1 ainda pode embutir select pós-B62; cortar = sem grid/Drawer de tipos até folga); **B57** delta 7d (Início continua com total+cobertura do B56; Δ era futuro de propósito); **B56** resumo no Início (Quadro já tem os mesmos agregados — cortar = Início sem briefing numérico); **B55** ações WA/share na busca (linha continua clicável); **B54** grid/cap (empilhar sempre); **B51**/**B53**/**B52**/**B50**/**B49** grupos secundários da busca (nessa ordem — Municípios B48 fica); **D5** inbox→rascunhos (manter registro manual + `wa.me`); **D4** envio bridge (manter `wa.me`); **D3** fundação do canal (atalho `wa.me` continua); **E12** camada TI (rollup manual por lista; **E17** já dá a leitura regional básica no Início); **E13** planejador de giros (rebaixado na fila de corte em 2026-07-24: "perna"/agenda é a restrição dominante nomeada em campo — cortar só depois de E12; agenda segue manual com J-A/J-B como guia); **E15** backtest (pós-eleição por definição — cortar = perder o aprendizado 2030); **E11** motor v1 (manter a fila E9 ✓ sem sugestões); **B13** símbolo proporcional (manter quantis/LQ como escala); ~~**E14** níveis~~ (entregue 2026-07-27 — `priority` continua, intocado); ~~**B8 F2** polígonos~~ (entregue 2026-07-26 — o mapa não é mais agregado em Salvador); **D2** push (adiar); **A6**; ~~**B14** município mais próximo~~ (entregue 2026-07-26); ~~**B38** sidebar recolhido em tablet~~ (entregue 2026-07-26); ~~**B40** login biométrico~~ (entregue 2026-07-28 — senha + B39 ✓ continuam, e cortar teria custado só o atalho de digital/Face ID; era o mais caro e o primeiro a cair desta leva B39–B42); **B42** polimento mobile da lista de municípios (Popover e card longos continuam usáveis — cortar custa conforto de teclado e densidade no celular); ~~**B41** scroll horizontal + sticky~~ (entregue 2026-07-27) (a tabela continua legível com zoom/pan da página — cortar custa o overflow em tablet; cai **depois** de B42 porque o bug de layout em mesa é mais caro que o polish mobile); ~~**B18** filtros salvos~~ ✓ entregue (lista + filtros manuais continuam; Visitados cobrem “voltar”); **B21** página dos Territórios de Identidade (o painel do E17 ✓ no Início continua entregando a leitura regional) — **B25** cai junto por definição (sem destino, sem link); ~~**B17** seletor de colunas~~ ✓ entregue (tabela completa continua; scroll horizontal); ~~**B22** explicação no header~~ (entregue 2026-07-26); ~~**B23** tooltip nas células~~ (entregue 2026-07-26); ~~**B24** auto-save + justificativa na Tendência~~ (entregue 2026-07-26); **B27** combobox + chips nos Assessores (a lista de checkboxes com "Salvar" continua atribuindo — cortar custa a mesma coerência do B24 mais o tempo do CG procurando nomes numa coluna durante o onboarding; corte junto com B24, já que dividem o endpoint); **B28** e-mail + celular na lista de lideranças (a ficha `/liderancas/[id]` continua mostrando o contato — cortar custa o gesto de copiar/abrir ZAP na varredura; quick win barato de cortar e de fazer); ~~**B30** convite de completar cadastro por WhatsApp na lista~~ (entregue 2026-07-26); **B31** coluna de dobradinhas nas lideranças (o `RelationMultiSelect` da ficha interna continua vinculando — cortar custa o preenchimento em lote do onboarding, uma ficha aberta por liderança, e mantém o vínculo invisível na varredura; corte junto com B27, já que dividem a peça de célula, e antes de B29 só se a mesa já tiver preenchido as dobradinhas à mão); ~~**B32** editar Status de apoio na célula~~ (entregue 2026-07-26); **B34** chips editáveis de municípios na lista de lideranças (o texto simples `row.municipalityNames.join(', ')` continua legível e a ficha `/liderancas/[id]` continua vinculando município via formulário — cortar custa o link direto ao município, a navegação por chip e o atalho de adicionar/remover sem abrir a ficha; corte junto com B31, já que dividem a mesma peça de célula editável, e antes de B29 pelo mesmo motivo de coerência); **B37** chips editáveis de municípios na lista de dobradinhas (o número `municipalityCount` continua legível e a ficha de município continua vinculando dobradinha pelo `MunicipalityStrategyForm` — cortar custa o link direto, a navegação por chip e o atalho de adicionar/remover sem abrir a ficha do município; corte junto com B34, já que dividem a mesma lib e a mesma decisão de container); ~~**B36** coluna de lideranças na lista de dobradinhas~~ (entregue 2026-07-26; a contagem `leadershipCount` era o fallback e a ficha `/liderancas/[id]` continua vinculando dobradinha via formulário — cortar custa o link direto à liderança, a navegação por chip e o atalho de adicionar/remover sem abrir a ficha; corte junto com B31, já que dividem a mesma mutação/schema/lock); ~~**B33** sort + filtro no header das dobradinhas~~ (entregue 2026-07-26); **B29** sort + filtro no header das lideranças (a busca por nome continua funcionando e o escopo do assessor já reduz a lista — cortar custa o recorte por status/setor/município no onboarding da rede e mantém o header rico como cópia única de municípios; por ser o item mais caro desta faixa (~1,5–2 dias com a extração do head), cai **antes** do B26, que é o que sustenta o gate de adoção); **B26** registrar sinal na célula (o formulário completo em `/[slug]?tab=updates` continua sendo o caminho — cortar custa o laço da fila do E9 ✓ e o registro em campo pelo celular, que é justamente onde o gate de adoção se decide; por isso cai **depois** de B22/B23/B24); ~~**C13** renomear Plano de Ação → Atividade~~ (entregue 2026-07-25); **B20** prioritários no Início (lista `?priority=alta` continua; só perde o atalho — mas a seção atual mente, então cortar = conviver com o bug); fill-in **renomear coluna Cobertura** (a lista continua legível com o rótulo longo — corte = header mais largo); fill-in **remover coluna Tipo** (a lista continua completa; só mantém densidade morta — corte = conviver com a coluna); ~~fill-in **remover lista de zonas do Início**~~ ✓ (entregue 2026-07-28 — o mapa B8 F2 ✓ continua abrindo cada ZE); ~~**B16** filtros no header~~ (entregue 2026-07-25); ~~**B15** sort por coluna~~ (entregue 2026-07-24); ~~**A11**/**E17**~~ (entregues 2026-07-24); ~~**E18** documentação de conceitos~~ (entregue 2026-07-24); ~~**E16** dossiê~~ (entregue 2026-07-25); demais débitos/fill-ins. ## Bloqueadores atuais