diff --git a/docs/plans/restaurar-pan-strip-acoes-inicio.md b/docs/plans/restaurar-pan-strip-acoes-inicio.md new file mode 100644 index 00000000..5821c36a --- /dev/null +++ b/docs/plans/restaurar-pan-strip-acoes-inicio.md @@ -0,0 +1,106 @@ +# Restaurar pan/scroll na strip de ações (scrollbar oculta) + +Status: rascunho +Atualizado em: 2026-07-29 +Item do roadmap: [docs/roadmap.md](../roadmap.md) (Trilha B, item **B67** — UX-1 chassis) +Impeccable: B — encaixe em `CampaignHomeActionStrip` / `CampaignHomeActionButton` +Appetite: ~0,25–0,5 dia eng; overflow + drag-to-scroll; sem migration +Responsável: — + +## Design (Impeccable) + +Âncoras: `PRODUCT.md` (Feel the action) / `DESIGN.md` · tema `data-theme='campaign'`. + +Na implementação (`implement-roadmap-item`): craft compacto → critique → polish. + +Brief compacto: + +- **Persona / contexto:** staff no Início com viewport estreito (mobile / janela pequena) — as 6 ações não cabem; precisa rolar a strip sem ver barra feia. +- **Job principal:** descobrir e acionar qualquer ação da strip com wheel, toque-e-arrasta ou click+arrasta; a barra de scroll continua invisível. +- **Estratégia de cor:** Restrained — só comportamento; sem chrome novo. +- **Edit where you see:** não — só navegação. +- **Anti-goals:** `overflow-x-hidden` “para esconder a barra”; setas de carousel; lib de swipe; quebrar long-press / Tooltip do botão. + +## Dados → decisão → apresentação + +Dados: N/A — affordance de pan; sem KPI. + +## Contexto + +**B44 ✓** entregou `CampaignHomeActionStrip` com `overflow-x-auto` e adiou **drag-to-scroll** no desktop (“nativo basta”). **B58 ✓** pediu scrollbar **oculta** com pan preservado (`[scrollbar-width:none]` + WebKit hide) — classes ainda em [`CampaignHomeActionStrip.tsx`](../../src/components/campaign/dashboard/CampaignHomeActionStrip.tsx). + +**Pedido de produto (2026-07-29):** depois do polimento, a strip ficou **sem forma de rolar**. O desejado é exatamente o contrato B58: barra escondida, mas continuar possível rolar com **mouse (wheel/trackpad)**, **click+movimento** e **toque e puxar**. + +Diagnóstico a confirmar na implementação (não assumir um só culpado): parent que captura gesture; conflito `touch-action` × long-press; wheel vertical do scrollport do Início engolindo delta horizontal; ou só falta o drag desktop que B44 adiou e que, com scrollbar oculta, vira a única affordance descoberta no mouse. + +## Objetivos + +- Restaurar pan horizontal **nativo** (touch + wheel/trackpad) com `overflow-x-auto` intacto e scrollbar visual **continua oculta** (classes atuais ou utilitário `scrollbar-hide` de `styles.css` se for o 2º call site — B58 Adiado). +- Adicionar **drag-to-scroll** em `pointer-fine` (mousedown → move → `scrollLeft`), com limiar de movimento para **não** virar click/navegação do `CampaignHomeActionButton` nem cancelar long-press coarse. +- Não reintroduzir barra visível; não trocar por carousel/setas. +- Pins: unit no limiar drag-vs-click (jsdom + fake pointer events se estável); e2e smoke de classes/`overflow-x-auto` + ausência de scrollbar utility que zere overflow. +- Sem migration, collection, server action, Consent ou mudança de catálogo. + +## Decisões travadas + +- **Scrollbar oculta + pan real (nativo + drag fine).** **Rejeitado:** `overflow-x-hidden` (corta ações); reexibir scrollbar fina (pedido explícito: só esconder a barra); setas/lib swipe. +- **Drag-to-scroll no desktop agora** (fecha o Adiado de B44 — gatilho “sessão reclamar” disparou). **Rejeitado:** só wheel (em muitos mice o delta é vertical e a strip não se move sem Shift). +- **Limiar de arraste antes de cancelar click.** **Rejeitado:** `preventDefault` no primeiro `pointerdown` (mata Link/botão); `draggable` nativo de imagem. +- **i18n:** ids `useHomeActionStripPan` / `dragThresholdPx`; copy intacta. + +## Questões em aberto + +- **Fade nas bordas quando há overflow?** **Opções:** A neste item | B manter Adiado B58. **Recomendação:** **B** — affordance de pan primeiro; fade só se, após drag, ainda houver “não sei que tem mais”. _(assumido)_ +- **Hook compartilhado vs lógica só na strip?** **Opções:** A `useDragScroll` em `lib/` | B handlers locais na strip. **Recomendação:** **B** até 2º call site (depth check). _(assumido)_ + +## Abordagem proposta + +```mermaid +flowchart LR + Strip["CampaignHomeActionStrip
overflow-x-auto + scrollbar hide"] + Native["touch / wheel pan"] + Drag["pointer-fine drag → scrollLeft"] + Btn["CampaignHomeActionButton
click se |Δ| < limiar"] + Strip --> Native + Strip --> Drag + Drag -.limiar.-> Btn +``` + +Componentes: + +- **`CampaignHomeActionStrip.tsx`:** auditar/corrigir classes de overflow; listeners de pan por drag (ref no scroller); `cursor-grab`/`grabbing` só enquanto arrasta, sem mudar layout. +- **`CampaignHomeActionButton.tsx`:** se necessário, coordenar com o strip via limiar (não abrir Link se o strip marcou `didDrag`); não duplicar máquina de long-press. +- **Testes:** unit do limiar; e2e leve se já houver spec da strip. +- **Migration:** Sem migration, sem collection, sem server action. + +## Dependências + +- Dura: **B44 ✓** / **B58 ✓** (strip existe). +- Soft: **B65** (dock mobile — pan na faixa inferior); **B46 ✓**. + +## Não escopo + +- Fade edges → Adiado (B58 / questão acima). +- Reabrir rótulos/escala do B58. +- Busca / empty state → **B68**. +- Carousel / snap agressivo que force “página” de ações. + +## Rabbit holes + +- **Lib de swipe / Embla.** **Mitigação:** overflow + ~30 linhas de drag. +- **Unificar long-press + drag num gesture manager genérico.** **Mitigação:** limiar local; extrair só no 2º call site idêntico. +- **`overscroll-behavior` / nested scroll debugging em todos os shells.** **Mitigação:** só a cadeia do Início (`CampaignHomeLayout` → strip). + +## Adiado com gatilho + +- **Fade nas bordas.** Revisitar se, com pan restaurado, usuários ainda não descobrirem overflow. +- **`useDragScroll` compartilhado.** Revisitar no 2º scroller horizontal com a mesma política. + +## Referências + +- `docs/roadmap.md` (UX-1 / B58 / B44) +- [`CampaignHomeActionStrip.tsx`](../../src/components/campaign/dashboard/CampaignHomeActionStrip.tsx) +- [`CampaignHomeActionButton.tsx`](../../src/components/campaign/dashboard/CampaignHomeActionButton.tsx) +- [polimento-strip-acoes-inicio.md](polimento-strip-acoes-inicio.md) (B58 — “scrollbar oculta, pan preservado”) +- [botao-acao-inicio-strip.md](botao-acao-inicio-strip.md) (B44 — Adiado drag-to-scroll) +- `PRODUCT.md` / `DESIGN.md` — Feel the action; register product diff --git a/docs/plans/sugestoes-busca-vazia-inicio.md b/docs/plans/sugestoes-busca-vazia-inicio.md new file mode 100644 index 00000000..469344f7 --- /dev/null +++ b/docs/plans/sugestoes-busca-vazia-inicio.md @@ -0,0 +1,125 @@ +# Sugestões na busca aberta (empty state por papel) + +Status: rascunho +Atualizado em: 2026-07-29 +Item do roadmap: [docs/roadmap.md](../roadmap.md) (Trilha B, item **B68** — UX-1 busca Início) +Impeccable: B — região de resultados do Início (`HomeSearchResultsShell` / grupos B48) quando focus + query inativa +Appetite: ~1–1,25 dia eng; loader de sugestões por role + UI reusando linhas B48; v1 só Municípios (lógica simples); sem migration +Responsável: — + +## Design (Impeccable) + +Âncoras: `PRODUCT.md` (Clarity under pressure; ação→local) / `DESIGN.md` · chrome B47/B66 · hits B48 · tema `data-theme='campaign'`. + +Na implementação (`implement-roadmap-item`): craft compacto → critique → polish. + +Brief compacto: + +- **Persona / contexto:** assessor ou CG foca a busca no Início ainda sem digitar — a tela limpa (**B66**) não deve ser um deserto; deve “adivinhar” o próximo destino útil. +- **Job principal:** ao abrir a busca, já ver atalhos ranqueados por papel (carteira / esquecidos) e seguir com um toque — digitar continua refinando via B48+. +- **Estratégia de cor:** Restrained — mesmos hits da busca; título de seção discreto (“Sugestões” / “Seus municípios”), sem card. +- **Edit where you see:** não — descoberta/navegação. +- **Anti-goals:** command palette ⌘K; feed de motor E11 no Início; dashboard de KPIs no empty; fetch de word-start com 0 chars (isso **B66** rejeitou — aqui é **curadoria**, não search). + +## Dados → decisão → apresentação + +- **Vou apresentar dados?** Sim — lista curta de municípios (e, depois, outras entidades) como atalhos; readout A11 opcional se a linha B48 já o trouxer sem custo. +- **Decisões desbloqueadas:** + - Assessor: “abrir um município da minha carteira agora” sem digitar o nome. + - CG/candidato: “abrir um prioritário frio / com déficit” sem montar filtro na lista. +- **Forma escolhida:** lista ranqueada (mesmo degrau dos hits B48) — **por quê** decide “qual abrir”. **Rejeitado:** mapa no empty; `CampaignMetricStrip` de vaidade; chart. +- **Profile:** até ~8 itens (paridade `DASHBOARD_PRIORITY_SAMPLE_LIMIT`); scoped ao access; absoluto local (nome + opcional “2022”), sem % estadual. +- **Anti-goals de dado:** sem inventar métrica nova; reusar E9 frescor / B20 prioridade / escopo do assessor. + +## Contexto + +**B47 ✓** + **B48 ✓** entregam input e hits por query (≥2 chars). **B66** (rascunho) limpa o chrome **no focus**, deixando a região de resultados **vazia** até digitar — espaço morto no gesto mais comum. + +**Pedido de produto (2026-07-29):** empty state da busca aberta com o que “provavelmente importa” por role — assessor: municípios que administra, pedidos que registrou, atividades em que participa, lideranças dos seus municípios; CG: prioritários há muito sem atualização, etc. Começar **simples**; sofisticar depois. O vazio deve tentar achar o que o usuário procura. + +Distinção com B66: B66 rejeitou “focus ⇒ fetch de **search** com 0 chars”. Este item é um **modo sugestão** (payload curado por papel), não word-start vazio. + +## Objetivos + +- Quando `uiFocused` (B66) **ou**, se B66 ainda não landar, equivalente “busca aberta” **e** `!query.isActive`: mostrar **sugestões**, não o empty mudo nem “Nenhum resultado.”. +- **v1 (appetite):** só grupo **Municípios**, reusando `HomeSearchHitRow` / shape de [`HomeSearchMunicipalityGroup`](../../src/components/campaign/dashboard/HomeSearchMunicipalityGroup.tsx). + - **`advisor`:** municípios do escopo (`loadMunicipalityScope`), ordem estável útil — preferir frescor frio (`lastSignalAt` / E9) depois nome; cap ~8. + - **`coordinator` / `candidate`:** prioritários `priority === 'alta'` ordenados por frio (dias sem sinal) e/ou déficit `central` — reusar espírito de [`pickDashboardPriorityMunicipalities`](../../src/utilities/dashboardPriorityMunicipalities.ts) + frescor; **não** inventar segunda meta. +- Access: `overrideAccess: false`; assessor nunca vê fora da carteira. +- Digitar (≥ limiar B47) **substitui** sugestões pelos hits B48+ (mesmo shell; não misturar os dois modos na mesma lista). +- Blur com query vazia (B66) desmonta sugestões com o chrome. +- Soft: se **B49–B53** já existirem na árvore, **não** obrigar a plugar neste slice — ver Adiado. +- Sem migration / Consent / mudança do contrato de **search** por query (extensão tipada: `mode: 'suggest' | 'search'` ou rota irmã — ver decisões). + +## Decisões travadas + +- **Sugestão ≠ search com q="".** Endpoint/modo dedicado de curadoria; predicados por `role`. **Rejeitado:** chamar `searchHomeMunicipalities('')` (ruído + contradiz B66); client-only catálogo sem access. +- **v1 = só Municípios.** Demais entidades (demandas, atividades, lideranças) ficam no Adiado com gatilho dos grupos B49–B53. **Rejeitado:** montar 4 loaders neste appetite. +- **CG = prioritários frios / déficit; assessor = carteira (fria primeiro).** Lógica **simples** e pinável em unit; “mais inteligente” = Adiado. **Rejeitado:** motor E11 no empty do Início (triagem já tem superfície no Quadro/detalhe). +- **Mesmo visual de hit B48** (sem card; flag de prioridade se alta). **Rejeitado:** cards “recomendados”; hero de KPI acima da lista. +- **i18n:** `homeSearchSuggest`, `loadHomeSearchSuggestions`; título pt-BR curto (“Sugestões” ou “Para você” — craft; preferir “Sugestões”). + +## Questões em aberto + +- **Transporte: estender `POST /campanha/home-search` com `mode` vs rota `/campanha/home-search/suggest`?** **Opções:** A mesmo path + discriminated body | B path irmão. **Recomendação:** **A** — um wrapper `campaignJsonMutationRoute`, um cliente `postCampaignJson`, schema zod discriminado; `safeMessages` únicos. _(assumido)_ +- **Título da seção?** **Opções:** A “Sugestões” | B “Seus municípios” (assessor) / “Prioritários” (CG) dinâmico. **Recomendação:** **A** estável + subtítulo opcional depois. _(assumido — craft)_ +- **Incluir Visitados recentes (`recentVisits`) no topo?** **Opções:** A sim (client merge) | B não na v1. **Recomendação:** **B** — PII/localStorage já tem card no Quadro; misturar client+server no empty complica hidratação. Gatilho: se sessão pedir “o que eu abri ontem”. _(assumido)_ + +## Abordagem proposta + +```mermaid +flowchart LR + Focus["uiFocused + !isActive"] --> Suggest["POST home-search mode=suggest"] + Suggest --> Policy["pure rank by role"] + Policy --> Rows["HomeSearchMunicipalityGroup / HitRow"] + Type["query.isActive"] --> Search["mode=search B48"] + Search --> Rows2["mesmos grupos B48+"] +``` + +Componentes: + +- **`src/lib/homeSearchSuggest.ts`** (puro, client-safe se só rankear view models): política por `CampaignRole` + inputs numéricos/datas já no scope — unit-pinned. +- **`src/utilities/.../homeSearchSuggestData.ts`** (`server-only`): monta payload com `loadMunicipalityScope` + agregados já usados em B20/E9 (`lastSignalAt` / coverage); `overrideAccess: false`. +- **Rota** `home-search`: estender body schema (`mode` + `q` opcional no suggest); handler ramifica suggest vs search. +- **Client:** `HomeSearchResultsContext` (ou irmão fino) busca suggest quando focado e inativo; cancela ao digitar; `HomeSearchResultsShell` renderiza sugestões **ou** hits **ou** “Nenhum resultado.” (só no modo search vazio). +- **Reuse:** `HomeSearchHitRow`, `MunicipalityPriorityIndicator`, readout A11 se já no shape. +- **Migration:** Sem migration, sem collection, sem Consent. + +## Dependências + +- Dura: **B47 ✓**, **B48 ✓** (shell + linhas + rota). +- Soft: **B66** (focus abre o vazio a preencher — se B66 atrasar, dá para gatilhar suggest no focus do input mesmo com strip visível; visual pior). +- Soft: E9 ✓ / B20 ✓ (frescor + prioridade). +- Soft: **B49–B53** (grupos extras — Adiado). + +## Não escopo + +- Layout grid/cap → **B54**. +- Ações WA/share na linha → **B55**. +- Resumo numérico do Início → **B56**. +- Motor de sugestões E11 / `allocationDecision` no empty. +- Leader omnibox (continua lockdown). + +## Rabbit holes + +- **Personalização ML / “o que você costuma buscar”.** **Mitigação:** regras explícitas por role; Adiado sem evidência. +- **Duplicar `pickDashboardPriorityMunicipalities` com sort diferente.** **Mitigação:** extrair comparator compartilhado ou passar `sort` — depth check antes de 3ª cópia. +- **Prefetch suggest no mount do Início (antes do focus).** **Mitigação:** fetch só ao entrar em `uiFocused` (custo + não competir com mapa do Quadro). + +## Adiado com gatilho + +- **Grupos Lideranças / Demandas / Atividades / Assessores no empty.** Revisitar quando **B49–B53** landarem **e** o empty de municípios já estiver em uso (evidência de “falta X”). +- **Visitados recentes no topo do suggest.** Revisitar se sessão observada pedir continuidade de sessão no Início (não só no Quadro). +- **Ranking “mais inteligente”** (déficit × classe E10 × nível E14). Revisitar após 2 semanas de uso real do v1 simples. +- **Soft deadline UX-1 03/08:** se folga apertar, este item é cortável depois de B66 (busca ainda funciona digitando). + +## Referências + +- `docs/roadmap.md` (UX-1 B47–B55 / B66) +- [`HomeSearchResultsShell.tsx`](../../src/components/campaign/dashboard/HomeSearchResultsShell.tsx) +- [`HomeSearchResultsContext.tsx`](../../src/components/campaign/dashboard/HomeSearchResultsContext.tsx) +- [`HomeSearchMunicipalityGroup.tsx`](../../src/components/campaign/dashboard/HomeSearchMunicipalityGroup.tsx) +- [`dashboardPriorityMunicipalities.ts`](../../src/utilities/dashboardPriorityMunicipalities.ts) +- [modo-focado-busca-no-focus.md](modo-focado-busca-no-focus.md) (B66 — focus ≠ search fetch) +- [busca-global-resultados-municipios.md](busca-global-resultados-municipios.md) (B48) +- `PRODUCT.md` / `DESIGN.md` — register product; Clarity under pressure diff --git a/docs/roadmap.md b/docs/roadmap.md index 09292d28..8369dc91 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -1,6 +1,6 @@ # Roadmap — Teqo -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. +Atualizado em: 2026-07-29 — **B67** restaurar pan na strip (scrollbar oculta); **B68** sugestões na busca aberta (por papel); **B66**; **B59** sticky; ~~**B58**~~ ✓; **B65**; B48 ✓; 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,11 +83,12 @@ 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) → **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. +- **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 — regressão pós-B58) → **B65** (âncora inferior mobile) → **B66** (focus limpa tela + animação) → ~~**B48**~~ ✓ → **B68** (sugestões empty/focus por papel) → **B49–B55** · **B56** · **B57** futuro. **Wizards:** **B59** → **B60**/**B61**/**B64** · **B62** → **B63**. - ~~**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) +- **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) · **regressão de pan → B67** +- **B67** Restaurar pan/scroll na strip de ações (scrollbar continua oculta; wheel + toque-e-puxar + **click+arrasta** no desktop — fecha Adiado B44) · Depende de B44 ✓ / B58 ✓ · ~0,25–0,5d · Janela 1 · Paralelizável com B65/B66/B59 · Impeccable B · [plano](plans/restaurar-pan-strip-acoes-inicio.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) @@ -96,9 +97,10 @@ O discovery literatura→persona→entrevista ([relatório aprovado](research/re - **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) · **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) +- **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) · empty útil → **B68** - **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) +- **B68** Sugestões na busca aberta (empty state por papel) — focus + query inativa mostra atalhos curados (v1: Municípios — assessor = carteira fria; CG = prioritários frios/déficit); **não** é search com q=""; digitar → hits B48+; entidades extras quando B49–B53 · Depende de B47 ✓ / B48 ✓ · soft B66 · ~1–1,25d · Janela 1 · Paralelizável com B49–B53 / B59 / B67 · Impeccable B · [plano](plans/sugestoes-busca-vazia-inicio.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) - **B51** Busca — resultados Atividades · Depende de B47 · ~0,5–0,75d · Janela 1 · Impeccable B · [plano](plans/busca-global-resultados-atividades.md) @@ -211,12 +213,14 @@ flowchart TD B43n["B43 ✓ Início em branco
+ Quadro / Contatos"] B44n["B44 ✓ Botão ação
+ strip horizontal"] B45n["B45 ✓ Catálogo ações
por persona"] - B58n["B58 Polish strip
ações Início"] + B58n["B58 ✓ Polish strip
ações Início"] + B67n["B67 Restaurar pan
strip ações"] 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"] + B68n["B68 Sugestões busca
vazia por papel"] B49n["B49 Busca Lideranças"] B50n["B50 Busca Assessores"] B51n["B51 Busca Atividades"] @@ -297,12 +301,16 @@ flowchart TD B43n --> B44n --> B45n --> B58n B45n --> B46n B58n -.rótulos/scroll.-> B46n + B44n -.pan quebrado.-> B67n + B58n --> B67n B46n --> B47n B46n -.âncora falhou.-> B65n B47n -.slots/modo focado.-> B65n B47n --> B66n B65n -.dock idle.-> B66n B47n --> B48n + B48n --> B68n + B66n -.empty no focus.-> B68n B47n --> B49n B47n --> B50n B47n --> B51n @@ -310,6 +318,9 @@ flowchart TD B47n --> B53n B47n --> B54n B48n -.cap prioridade.-> B54n + B49n -.grupo no empty.-> B68n + B51n -.grupo no empty.-> B68n + B53n -.grupo no empty.-> B68n B49n --> B55n B50n --> B55n B51n --> B55n @@ -427,11 +438,11 @@ flowchart TD B8F2 -.rank por ZE = débito aberto.-> B14n ``` -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. +Paralelizáveis agora: **B67** (pan strip — regressão; quick win); **B65** (âncora inferior mobile); **B66** (focus limpa busca — melhor após B65); **B68** (sugestões empty — após B48 ✓; melhor após B66); **B59** (chassis wizard — desbloqueia B60/B61/B63/B64); **B62** (simplificar sinal — paralelo a B59); **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) **→ 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 1 — agora → 05/08 (convenções):** **prioridade pós-29/07 — ~~B43–B48~~ ✓ → B67** (pan strip) **→ B65** (âncora inferior) **→ B66** (focus limpa busca) **→ B68** (sugestões empty) **→** **wizards B59** → 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 inalterados no detalhe abaixo — foco operacional = pan B67 + polish busca B65/B66/B68 + busca B49+ + wizards 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 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. @@ -441,9 +452,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); **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). +**Não cortáveis:** Onda 0 (jurídico/Consent); ~~**B43–B48** chassis UX-1 + busca Municípios~~ ✓; **B67** pan na strip de ações (B58 ✓ escondeu a barra e o pan sumiu — cortar = ações fora da dobra inacessíveis no mobile); **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): **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): **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); **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