diff --git a/app/static/estilo.css b/app/static/estilo.css
index 7929402..6fa014b 100644
--- a/app/static/estilo.css
+++ b/app/static/estilo.css
@@ -235,6 +235,12 @@ a.botao:hover { border-color: var(--cor-acento); color: var(--cor-acento); }
}
.paginacao { display: flex; align-items: center; gap: 12px; justify-content: center; margin-top: 16px; }
+.paginacao-rodape { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px; margin-top: 16px; }
+.paginacao-rodape .paginacao { margin-top: 0; }
+.paginacao-por-pagina { display: flex; align-items: center; gap: 8px; }
+.paginacao-por-pagina label { margin: 0; white-space: nowrap; }
+.paginacao-atual { display: inline-flex; align-items: center; justify-content: center; min-width: 32px; height: 32px; padding: 0 6px; border-radius: 6px; background: var(--cor-acento); color: var(--cor-acento-texto); font-weight: 600; }
+.paginacao-reticencias { padding: 0 4px; color: var(--cor-texto-secundario); }
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { transition: none !important; }
diff --git a/app/templates/clientes_lista.html b/app/templates/clientes_lista.html
index 2f9eddd..d7e9b98 100644
--- a/app/templates/clientes_lista.html
+++ b/app/templates/clientes_lista.html
@@ -17,6 +17,8 @@
+ Novo cliente
+ {% set busca_qs = ('&busca=' + (busca | urlencode)) if busca else '' %}
+ {% set qs_base = ('&ordenar_por=' + ordenar_por + '&direcao=' + direcao + '&por_pagina=' + (por_pagina | string) + busca_qs) | safe %}
- {% if total_paginas and total_paginas > 1 %}
-
- {% if pagina > 1 %}
-
← Anterior
- {% endif %}
-
Página {{ pagina }} de {{ total_paginas }} ({{ total }} clientes)
- {% if pagina < total_paginas %}
-
Próxima →
- {% endif %}
-
- {% endif %}
+
+
+
Exibindo {{ primeiro_item }} a {{ ultimo_item }} de {{ total }} clientes
+ {% if total_paginas and total_paginas > 1 %}
+
+ {% if pagina > 1 %}
+
«
+
‹
+ {% endif %}
+ {% for p in janela_paginas %}
+ {% if p is none %}
+
…
+ {% elif p == pagina %}
+
{{ p }}
+ {% else %}
+
{{ p }}
+ {% endif %}
+ {% endfor %}
+ {% if pagina < total_paginas %}
+
›
+
»
+ {% endif %}
+
+ {% endif %}
+
{% endblock %}
diff --git a/tests/test_router_clientes.py b/tests/test_router_clientes.py
index 831bb5c..8777d3f 100644
--- a/tests/test_router_clientes.py
+++ b/tests/test_router_clientes.py
@@ -186,10 +186,38 @@ def test_listar_clientes_pagina_com_controles_de_paginacao(monkeypatch):
resposta = client.get("/clientes?pagina=2&por_pagina=100")
assert resposta.status_code == 200
- assert "Página 2 de 3" in resposta.text
- assert "250 clientes" in resposta.text
- assert "Anterior" in resposta.text
- assert "Próxima" in resposta.text
+ assert "Exibindo 101 a 200 de 250 clientes" in resposta.text
+ assert "pagina=1&ordenar_por=razao&direcao=asc&por_pagina=100" in resposta.text
+ assert "pagina=3&ordenar_por=razao&direcao=asc&por_pagina=100" in resposta.text
+
+
+def test_listar_clientes_footer_com_selecao_de_por_pagina(monkeypatch):
+ monkeypatch.setattr(
+ router_clientes.db_clientes,
+ "listar_clientes",
+ lambda busca=None, limite=100, offset=0, ordenar_por="razao", direcao="asc": [
+ {"ID": i, "CODIGO": f"{i:06d}", "RAZAO": f"Cliente {i}", "FANTASIA": f"C{i}", "CNPJ": "1"}
+ for i in range(1, 16)
+ ],
+ )
+ monkeypatch.setattr(router_clientes.db_clientes, "contar_clientes", lambda busca=None, ordenar_por="razao": 98)
+
+ resposta = client.get("/clientes?pagina=1")
+ assert resposta.status_code == 200
+ assert 'value="15" selected' in resposta.text
+ assert "Exibindo 1 a 15 de 98 clientes" in resposta.text
+ # 98 / 15 = 7 paginas -> <=7, sem reticencias, todas visiveis
+ assert "pagina=7&ordenar_por=razao&direcao=asc&por_pagina=15" in resposta.text
+
+
+def test_listar_clientes_paginacao_com_reticencias_quando_muitas_paginas(monkeypatch):
+ monkeypatch.setattr(router_clientes.db_clientes, "listar_clientes", lambda **kwargs: [])
+ monkeypatch.setattr(router_clientes.db_clientes, "contar_clientes", lambda busca=None, ordenar_por="razao": 500)
+
+ # 500 / 5 = 100 paginas, pedindo a pagina 10 (no meio) -> tem reticencias
+ resposta = client.get("/clientes?pagina=10&por_pagina=5")
+ assert resposta.status_code == 200
+ assert "…" in resposta.text
def test_listar_clientes_ordenar_por_invalido_cai_no_padrao(monkeypatch):