diff --git a/docs/plans/indicacao-carregamento-navegacao-wizard.md b/docs/plans/indicacao-carregamento-navegacao-wizard.md new file mode 100644 index 00000000..bd5fca2a --- /dev/null +++ b/docs/plans/indicacao-carregamento-navegacao-wizard.md @@ -0,0 +1,110 @@ +# Indicação de carregamento nas ações de navegação do wizard + +Status: rascunho +Atualizado em: 2026-07-30 +Item do roadmap: [docs/roadmap.md](../roadmap.md) (Trilha B, item **B78** — UX-1 wizards / Feel the action) +Impeccable: B — encaixe no shell e no chrome mobile do wizard; sem rota nova +Appetite: ~0,25–0,5 dia eng; boundary de transição + pending no conteúdo (+ shimmer opcional no header pós-B75); sem migration +Responsável: — + +## Design (Impeccable) + +Âncoras: `PRODUCT.md` § **Feel the action** · `.cursor/rules/campanha-action-feedback.mdc` · precedente `CampaignListPendingBoundary` / `CampaignListResults` / `useCampaignListTransition` (`src/components/campaign/shared/CampaignListPending.tsx`) e fill-in do compositor de giro ([feedback-pendente-compositor-giro.md](feedback-pendente-compositor-giro.md)) · tema `data-theme='campaign'`. + +Na implementação (`implement-roadmap-item`): craft compacto → critique → polish. Sem shape novo. + +Brief compacto: + +- **Persona / contexto:** CG/assessor no celular, no meio de um ritual (`/campanha/acoes/*`); toca **Voltar**, **X**, **Pular** ou escolhe um município e a rota troca — o passo anterior continua nítido enquanto o RSC carrega. +- **Job principal:** ao navegar entre passos do wizard, saber que a ação registrou e que o conteúdo visível está sendo substituído. +- **Estratégia de cor:** Restrained — `opacity-60` + `aria-busy` no corpo (mesmo idioma das listas); no header Mandate Red (**B75** ✓/soft), shimmer discreto só nos slots de título/subtítulo, não na barra inteira. +- **Edit where you see:** não — feedback de transição, não edição. +- **Anti-goals:** spinner full-page; segundo idioma de pending só no botão; `loading.tsx` por passo; skeleton que inventa layout do passo seguinte. + +## Dados → decisão → apresentação + +Dados: N/A — chrome de navegação; números/texto nas etapas B61/B63/B64/B70/B77. + +## Contexto + +**B59 ✓** entregou `CampaignWizardShell` e rotas `/campanha/acoes/` com navegação por `router.push` / `router.replace` (`?municipio=`, passos seguintes, Voltar). **B60 ✓** já trata loading da **busca** (debounce + estado local do `POST /campanha/home-search`) — isso **não** cobre a transição de rota após selecionar o município ou usar os controles do shell. + +**B75** (header mobile Mandate Red) vai concentrar Voltar / título do fluxo / subtítulo do município / X ou Pular no topo. Sem pending explícito, o usuário pode tocar de novo (double-submit mental) ou achar que Voltar não funcionou — especialmente em rede lenta entre Zaps. + +Pedido (2026-07-30): indicar carregamento nas **ações de navegação do shell**; após o ajuste de design do header (**B75**), considerar **shimmer** no header nos slots que mudam (título/subtítulo), não só dim no conteúdo. + +## Objetivos + +- Toda navegação do wizard que dispara transição de rota (`Voltar`, `dismissHref`, `skip`, seleção de município → `?municipio=`, avanço entre passos com `router.push`/`replace`) participa de **uma** `useTransition` compartilhada no layout do wizard. +- A região de **conteúdo** do passo (`
` do shell / filhos) dima com `data-pending` + `aria-busy` + live region “Atualizando…” (reuso de `CampaignListResults` ou wrapper equivalente sem renomear o mundo). +- Controles de navegação mostram feedback **imediato** no gatilho: `aria-busy` no link/botão ativo, `pointer-events-none` ou `disabled` enquanto `isPending` (evitar double-tap em Voltar/X). +- **Pós-B75 (soft):** enquanto `isPending`, título e subtítulo do header Mandate Red entram em estado de placeholder com `Skeleton` (shadcn) ou pulse equivalente — **só** os textos, ícones Voltar/X permanecem clicáveis ou já disabled conforme política acima. +- Não alterar o contrato de URL nem loaders de busca já existentes (B60). +- Guardrails: sem migration / Consent / action; `prefers-reduced-motion` respeitado (shimmer → opacity estática). + +## Decisões travadas + +- **Reusar a máquina de pending das listas, não inventar `WizardPending*`.** `CampaignListPendingBoundary` + `useCampaignListTransition` já resolvem boundary + hook; o compositor de giro (**E13** fill-in) provou que a peça não é acoplada a tabela. **Rejeitado:** par paralelo só para wizard (duplica `opacity`/`aria-live`); `loading.tsx` em `acoes/[slug]` (só cobre entrada direta, não troca de query). +- **Pending honesto no resultado, otimista no controle.** O passo **anterior** dima (não some) até o RSC novo chegar — mais informativo que skeleton que adivinha o layout. **Rejeitado:** skeleton full-page do próximo passo; manter passo antigo 100% opaco (parece travado). +- **Shimmer no header = soft dependency de B75.** Se B75 ainda não estiver no ar, entrega só dim + busy no conteúdo e nos triggers; shimmer nos slots `flowTitle` / `municipalityLabel` entra no mesmo PR ou imediatamente após B75 — não bloqueia o dim do corpo. **Rejeitado:** shimmer no sticky branco legado do B59 (morre com B75). +- **Escopo = navegação de rota, não debounce de busca nem POST de gravação.** Auto-save e `POST` batch (B61/B77) mantêm feedback próprio (`useCampaignCellAutosave`, spinner no CTA). **Rejeitado:** unificar save e nav num único pending global (mistura “Salvando…” com “Atualizando…”). +- **i18n:** ids `isPending`, `startTransition`, `flowTitle`; copy pt-BR reutiliza “Atualizando resultados…” ou variante “Carregando passo…” se critique achar melhor no wizard. + +## Questões em aberto + +- **Wrapper: `CampaignListResults` literal vs `CampaignWizardStepResults` fino?** **Opções:** A) usar `CampaignListResults` no `
` | B) extrair `CampaignPendingSurface` com as mesmas classes. **Recomendação:** **A** neste appetite — o nome é legado, o comportamento é o certo; extrair só no 3º domínio não-lista. _(assumido)_ +- **Live region: “Atualizando resultados…” soa errado?** **Opções:** A) reutilizar string das listas | B) prop `pendingMessage` | C) “Carregando passo…”. **Recomendação:** **C** no wizard via prop opcional em `CampaignListResults` (uma linha) — critique valida em voz. _(assumido)_ + +## Abordagem proposta + +```mermaid +flowchart TB + Layout["acoes/layout.tsx
CampaignListPendingBoundary"] --> Shell["CampaignWizardShell"] + Layout --> Main["CampaignListResults
envolve children"] + Shell --> Chrome["CampaignMobileTopBar / triggers
useCampaignListTransition"] + Chrome --> Nav["Voltar · X · Pular · links de passo"] + Nav --> Router["router.push/replace
dentro de startTransition"] + Main --> Step["Wizard*Step"] + Chrome -.soft B75.-> Shimmer["Skeleton em flowTitle /
municipalityLabel se pending"] +``` + +Componentes: + +- **`src/app/(campaign)/campanha/(app)/acoes/layout.tsx`**: envolver `{children}` em `CampaignListPendingBoundary` (provider client leve, filhos RSC como nas listas). +- **`CampaignWizardShell`** (`src/components/campaign/shared/CampaignWizardShell.tsx` — previsto B59 ✓): `
` passa a usar `CampaignListResults` (ou slot `stepSurface`) em volta de `children`; props de chrome chamam `useCampaignListTransition` nos `Link`/`button` de Voltar, dismiss e skip (`startTransition(() => router.push(...))`). +- **`WizardMunicipalitySearchStep`**: trocar `router.push` nu por transição compartilhada (mesmo padrão de `CampaignTransitionAnchor` ou hook direto). +- **`CampaignMobileTopBar`** (B75): quando `isPending`, renderizar `Skeleton` com `h-4`/`h-3` nos slots de título e subtítulo; ícones com `aria-busy` se forem o gatilho da navegação. +- **Testes:** unit jsdom — mock router + boundary: clicar Voltar marca `aria-busy` no main e no trigger; opcional snapshot de classes `data-pending`. E2e smoke: após selecionar município, assert `data-pending` ou opacity antes do próximo `h1` (timeout generoso — rede dev). +- **Migration:** Sem migration, sem collection, sem server action. + +## Dependências + +- Dura: **B59 ✓** (shell + rotas `/campanha/acoes`). Soft: **B75** (shimmer nos slots do header Mandate Red — corpo pending funciona sem). Soft: **B60 ✓** (seleção de município é o call site mais visível). +- Melhora percepção de **B77**, **B63**, **B64**, **B70** (todos navegam entre passos no mesmo layout). + +## Não escopo + +- Pending de **fetch** da busca no passo município (B60 — já local). Gravação batch/auto-save (B61/B77/B32+). +- `loading.tsx` segment por ação. Animação de transição entre passos (slide) — Adiado. +- Desktop `md+` (Voltar = browser; pending no corpo ainda vale em `router` client-side). + +## Rabbit holes + +- **State machine global de wizard.** Se alguém “só centralizar pending”: explode em store de passos. **Mitigação:** só boundary + hook existentes. +- **Skeleton que imita cada passo.** **Mitigação:** dim do conteúdo atual; shimmer só em duas linhas do header. +- **Renomear `CampaignListPending*` neste item.** **Mitigação:** defer até 3º domínio não-lista (compositor + wizard = 2). + +## Adiado com gatilho + +- **Transição animada entre passos (cross-fade/slide).** Revisitar se critique pós-B75 achar o dim “brusco” — só com `prefers-reduced-motion` e medição em 3G. +- **Extrair `CampaignPendingSurface` genérico.** Revisitar quando existir 3º consumidor não-lista além de giro + wizard. + +## Referências + +- `src/components/campaign/shared/CampaignListPending.tsx` — boundary, hook, results, `CampaignTransitionAnchor` +- `docs/plans/chassis-wizard-campanha.md` (B59 ✓) · `docs/plans/header-mobile-wizard-campanha.md` (B75) · `docs/plans/busca-municipio-wizard.md` (B60 ✓) +- `docs/plans/feedback-pendente-compositor-giro.md` — precedente não-lista +- `.cursor/rules/campanha-action-feedback.mdc` · `PRODUCT.md` § Feel the action +- AGENTS.md — sem Consent; naming + +Qualidade de decisão: 4/5 diff --git a/docs/roadmap.md b/docs/roadmap.md index 4a68f722..ad42ac30 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -1,6 +1,6 @@ # Roadmap — Teqo -Atualizado em: 2026-07-30 — **B77** simplificar wizard ajuste votos (3 cenários numa tela); ~~**B76**~~ ✓ coerência wizard ajuste votos; **B74** gap strip v2; **B75** header mobile do wizard; **B73** remover bottom nav; ~~**B66**~~ ✓ busca no focus; ~~**B71**~~ ✓ polish busca; ~~**B61**~~ ✓; ~~**B51**~~ ✓; ~~**B52**~~ ✓; ~~**B72**~~ ✓; ~~**B69**~~ ✓ liderança exclusiva (org fica); **B70** A4 liderança; ~~**B62**~~ ✓ simplificar sinal (E11 triage 1 por presença); ~~**B56**~~ ✓; ~~**B67**~~ ✓; ~~**B68**~~ ✓; ~~**B59**~~ ✓; ~~**B65**~~ ✓; ~~**B60**~~ ✓; ~~**B48**~~ ✓; ~~**B49**~~ ✓; ~~**B50**~~ ✓; B53–B55; wizards ~~B60~~ ✓/~~**B61**~~ ✓/~~**B76**~~ ✓/**B77**/B63–B64. +Atualizado em: 2026-07-30 — **B78** pending de navegação no wizard (dim + shimmer header pós-B75); **B77** simplificar wizard ajuste votos (3 cenários numa tela); ~~**B76**~~ ✓ coerência wizard ajuste votos; **B74** gap strip v2; **B75** header mobile do wizard; **B73** remover bottom nav; ~~**B66**~~ ✓ busca no focus; ~~**B71**~~ ✓ polish busca; ~~**B61**~~ ✓; ~~**B51**~~ ✓; ~~**B52**~~ ✓; ~~**B72**~~ ✓; ~~**B69**~~ ✓ liderança exclusiva (org fica); **B70** A4 liderança; ~~**B62**~~ ✓ simplificar sinal (E11 triage 1 por presença); ~~**B56**~~ ✓; ~~**B67**~~ ✓; ~~**B68**~~ ✓; ~~**B59**~~ ✓; ~~**B65**~~ ✓; ~~**B60**~~ ✓; ~~**B48**~~ ✓; ~~**B49**~~ ✓; ~~**B50**~~ ✓; B53–B55; wizards ~~B60~~ ✓/~~**B61**~~ ✓/~~**B76**~~ ✓/**B77**/B63–B64/**B78**. 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,7 +83,7 @@ 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**~~ ✓ → ~~**B67**~~ ✓ (pan strip) → ~~**B65**~~ ✓ (âncora inferior mobile) → ~~**B66**~~ ✓ (focus limpa tela + animação) → ~~**B48**~~ ✓ → ~~**B49**~~ ✓ → ~~**B68**~~ ✓ → ~~**B71**~~ ✓ (polish resultados busca) · ~~**B72**~~ ✓ (gap strip) → **B74** (gap strip v2) → **B73** (remover bottom nav mobile) → ~~**B50**~~ ✓ → ~~**B51**~~ ✓ → ~~**B52**~~ ✓ → **B53–B55** · ~~**B56**~~ ✓ · **B57** futuro. **Wizards:** ~~**B59**~~ ✓ → **B75** (header mobile wizard) → ~~**B60**~~ ✓/~~**B61**~~ ✓/~~**B76**~~ ✓ → **B77** (ajuste votos numa tela) /**B64** · ~~**B62**~~ ✓ → **B63** · ~~**B69**~~ ✓ → **B70** (A4 liderança). +- **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**~~ ✓ → ~~**B67**~~ ✓ (pan strip) → ~~**B65**~~ ✓ (âncora inferior mobile) → ~~**B66**~~ ✓ (focus limpa tela + animação) → ~~**B48**~~ ✓ → ~~**B49**~~ ✓ → ~~**B68**~~ ✓ → ~~**B71**~~ ✓ (polish resultados busca) · ~~**B72**~~ ✓ (gap strip) → **B74** (gap strip v2) → **B73** (remover bottom nav mobile) → ~~**B50**~~ ✓ → ~~**B51**~~ ✓ → ~~**B52**~~ ✓ → **B53–B55** · ~~**B56**~~ ✓ · **B57** futuro. **Wizards:** ~~**B59**~~ ✓ → **B75** (header mobile wizard) → **B78** (pending navegação shell) → ~~**B60**~~ ✓/~~**B61**~~ ✓/~~**B76**~~ ✓ → **B77** (ajuste votos numa tela) /**B64** · ~~**B62**~~ ✓ → **B63** · ~~**B69**~~ ✓ → **B70** (A4 liderança). - ~~**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) @@ -110,6 +110,7 @@ O discovery literatura→persona→entrevista ([relatório aprovado](research/re - **B73** Remover bottom navigation bar no mobile — paradigma UX-1 intenção-primeiro: apagar `CampaignBottomNav` + `getCampaignBottomNav`; sidebar Sheet (fechada por padrão, B38 ✓) como única nav estrutural; ajustar `pb-24` do scroll global; revalidar dock do Início (B65 ✓) · Depende de B43 ✓ · soft B65 ✓ / B38 ✓ · ~0,25–0,5d · Janela 1 · Paralelizável com B66 / B71 / B74 · Impeccable B · [plano](plans/remover-bottom-nav-mobile.md) - **B74** Apertar mais o espaçamento da strip de ações (`gap-4` → `gap-3`, critique pode `gap-2`) — pós-B72 ainda largo no mobile · Depende de B72 ✓ · soft B67 ✓ · ~0,25d · Janela 1 · Paralelizável com B73 / B66 / B71 · Impeccable B · [plano](plans/espacamento-strip-acoes-inicio-v2.md) - **B75** Header mobile do wizard — durante `/campanha/acoes/*`, o Mandate Red substitui sidebar+marca: título = fluxo (“Ajustar votos”), subtítulo = município; 1ª etapa só X; 2ª+ Voltar+X; encadeado X→“Pular <fluxo>”; context no `(app)` + shell sem sticky branco no mobile · Depende de B59 ✓ · soft B60 ✓ / B45 ✓ · ~1–1,25d · Janela 1 · Paralelizável com B61/B63/B64 (eles consomem o chrome) · Impeccable C · [plano](plans/header-mobile-wizard-campanha.md) +- **B78** Indicação de carregamento nas ações de navegação do wizard — `CampaignListPendingBoundary` no layout `acoes/`; Voltar/X/Pular/seleção de município dentro de `useCampaignListTransition`; corpo do passo dima (`CampaignListResults`); soft shimmer nos slots título/subtítulo do header Mandate Red (**B75**) · Depende de B59 ✓ · soft B75 / B60 ✓ · ~0,25–0,5d · Janela 1 · Paralelizável com B77/B63/B64 · Impeccable B · [plano](plans/indicacao-carregamento-navegacao-wizard.md) - ~~**B49** Busca — resultados Lideranças~~ — **entregue 2026-07-29** (`searchHomeLeaderships`, `HomeSearchLeadershipGroup`, `leaderships` no POST `/campanha/home-search`; word-start; assessor scoped; municípios no secundário; cap 25; sem WA — **B55**) · Depende de B47 ✓ · [plano](plans/busca-global-resultados-liderancas.md) - ~~**B50** Busca — resultados Assessores (access B19)~~ — **entregue 2026-07-29** (`searchHomeAdvisors` + `HomeSearchAdvisorGroup`; unrestricted only; word-start no nome; contagem de municípios na linha; `POST /campanha/home-search` agrega `advisors`) · Depende de B47 ✓ · [plano](plans/busca-global-resultados-assessores.md) - ~~**B51** Busca — resultados Atividades~~ — **entregue 2026-07-29** (`searchHomeActivities` + `HomeSearchActivityGroup`; word-start no título; access `activity`; rascunhos no escopo; secundário município + data; cap 25; `POST /campanha/home-search` agrega `activities`; sem WA — **B55**) · Depende de B47 ✓ · [plano](plans/busca-global-resultados-atividades.md) @@ -250,6 +251,7 @@ flowchart TD B61n["B61 ✓ Ajuste votos
cenários + atalhos"] B76n["B76 ✓ Coerência wizard
ajuste votos"] B77n["B77 Ajuste votos
3 cenários 1 tela"] + B78n["B78 Pending nav
wizard shell"] B62n["B62 ✓ Simplificar
modelo de sinal"] B63n["B63 Wizard sinal
tipo + texto"] B64n["B64 Wizard tendência
escolha + justificativa"] @@ -383,6 +385,12 @@ flowchart TD B61n -.simplificar UX.-> B77n B76n -.validação inline.-> B77n B75n -.chrome mobile.-> B77n + B59n --> B78n + B75n -.shimmer header.-> B78n + B60n -.select avança rota.-> B78n + B78n -.Feel the action.-> B77n + B78n -.idem.-> B63n + B78n -.idem.-> B64n B60n -.município standalone.-> B63n B60n -.município standalone.-> B64n B61n -.prefill votos.-> B64n @@ -481,11 +489,11 @@ flowchart TD B8F2 -.rank por ZE = débito aberto.-> B14n ``` -Paralelizáveis agora: **B73** (remover bottom nav — paralelo a B74); **B74** (gap strip v2 — após ~~B72~~ ✓; paralelo a B73); **B75** (header mobile wizard — após ~~B59~~ ✓; soft nos wizards restantes B63/B64/B70/B77); **B77** (simplificar ajuste votos — após ~~B61~~ ✓/~~B76~~ ✓; paralelo a B63/B64); **B49–B53** após B47 ✓ / B48 ✓ (depois B54/B55). Após **B59**: ~~**B60**~~ ✓ ∥ ~~**B61**~~ ✓ ∥ **B64** (B75 soft). **B63** espera B59+B62 ✓. **B70** espera ~~B59+B69~~ ✓ (+ soft B75). 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: **B73** (remover bottom nav — paralelo a B74); **B74** (gap strip v2 — após ~~B72~~ ✓; paralelo a B73); **B75** (header mobile wizard — após ~~B59~~ ✓; soft nos wizards restantes B63/B64/B70/B77); **B78** (pending navegação wizard — após ~~B59~~ ✓; soft B75 para shimmer no header; paralelo a B77/B63/B64); **B77** (simplificar ajuste votos — após ~~B61~~ ✓/~~B76~~ ✓; paralelo a B63/B64); **B49–B53** após B47 ✓ / B48 ✓ (depois B54/B55). Após **B59**: ~~**B60**~~ ✓ ∥ ~~**B61**~~ ✓ ∥ **B64** (B75 soft). **B63** espera B59+B62 ✓. **B70** espera ~~B59+B69~~ ✓ (+ soft B75). 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~~ ✓ → ~~B67~~ ✓ (pan strip) **→ ~~B65~~ ✓** (âncora inferior) **→ ~~B66~~ ✓** (focus limpa busca) **→ ~~B68~~ ✓\*\* **→ ~~B71~~ ✓** (polish resultados) **· ~~B72~~ ✓** / **B74** (gap strip) **→ B73** (remover bottom nav) **→** **wizards ~~B59~~ ✓ → B75** (header mobile) → ~~B60~~ ✓/~~B61~~ ✓/~~B76~~ ✓ → **B77** (ajuste votos 1 tela) ∥B64 · ~~B62~~ ✓ → B63 · ~~B69~~ ✓ → B70 (soft 03/08) · **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 inalterados no detalhe abaixo — foco operacional = polish Início B74 + chrome B73/B75 + busca B49+ + wizards B77/B63–B64 + A4 ~~B69~~ ✓/B70. +**Janela 1 — agora → 05/08 (convenções):** **prioridade pós-29/07 — ~~B43–B48~~ ✓ → ~~B67~~ ✓ (pan strip) **→ ~~B65~~ ✓** (âncora inferior) **→ ~~B66~~ ✓** (focus limpa busca) **→ ~~B68~~ ✓\*\* **→ ~~B71~~ ✓** (polish resultados) **· ~~B72~~ ✓** / **B74** (gap strip) **→ B73** (remover bottom nav) **→** **wizards ~~B59~~ ✓ → B75** (header mobile) **→ B78** (pending navegação) → ~~B60~~ ✓/~~B61~~ ✓/~~B76~~ ✓ → **B77** (ajuste votos 1 tela) ∥B64 · ~~B62~~ ✓ → B63 · ~~B69~~ ✓ → B70 (soft 03/08) · **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 inalterados no detalhe abaixo — foco operacional = polish Início B74 + chrome B73/B75 + busca B49+ + wizards B77/B78/B63–B64 + A4 ~~B69~~ ✓/B70. **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. @@ -497,7 +505,7 @@ Paralelizáveis agora: **B73** (remover bottom nav — paralelo a B74); **B74** **Não cortáveis:** Onda 0 (jurídico/Consent); ~~**B43–B48** chassis UX-1 + busca Municípios~~ ✓; ~~**B67** pan na strip de ações~~ ✓ (entregue 2026-07-29 — B58 escondia a barra; drag fine restaurado); ~~**B65** âncora inferior mobile~~ ✓ (entregue 2026-07-29); ~~**B66** focus limpa busca~~ ✓ (entregue 2026-07-30); **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); ~~**B76** coerência do ajuste de votos~~ ✓ (entregue 2026-07-30); **B77** simplificar ajuste de votos (cortar = manter ritual pesado de três passos `?cenario=` que o CG pediu simplificar — emenda a B61); **B75** header mobile do wizard (cortar = Voltar+título no conteúdo competem com Mandate Red+sidebar no meio do ritual — emenda explícita a B59); ~~**B62** simplificar sinal~~ ✓ (entregue 2026-07-29); ~~**B69** simplificar liderança~~ ✓ (entregue 2026-07-30 — `exclusive` default true; setor/`consentNote` dropados; **organização fica**: ramificação política, ex. SindMed); ~~**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): ~~**B71**~~ ✓; **B74** gap strip v2 (B72 já apertou uma vez — cortar = strip um pouco esparça); **B68** sugestões na busca aberta (digitação B48 continua; cortar = empty mudo no focus até folga); **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); **B70** wizard liderança standalone (A1 ainda pode embutir passo curto pós-B69; cortar = sem grid 2/3/4 até folga — pacote Cairu sofre); **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): ~~**B71**~~ ✓; **B74** gap strip v2 (B72 já apertou uma vez — cortar = strip um pouco esparça); **B78** pending navegação wizard (cortar = Voltar/seleção sem dim/shimmer até rede lenta reclamar — corpo pending pode shippar sem shimmer do B75); **B68** sugestões na busca aberta (digitação B48 continua; cortar = empty mudo no focus até folga); **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); **B70** wizard liderança standalone (A1 ainda pode embutir passo curto pós-B69; cortar = sem grid 2/3/4 até folga — pacote Cairu sofre); **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