/* ==========================================================================
   Identidade visual — Domínio Automação
   Âmbar #FEC943 (destaque) · Creme #FAF8EF (fundo) · Tinta #1A1A1A (texto)
   Cinza #444444 (texto secundário) · Poppins (títulos) · Inter (corpo)
   Fundo sempre claro — nunca dark mode.
   ========================================================================== */

:root {
    --ambar: #FEC943;
    --ambar-escuro: #E6B53C;
    --ambar-claro: #FEF3D6;
    --creme: #FAF8EF;
    --tinta: #1A1A1A;
    --cinza: #444444;
    --cinza-claro: #8A8A8A;
    --branco: #FFFFFF;
    --borda: #E8E3D3;
    --verde: #1E6B1E;
    --verde-fundo: #DDF0DD;
    --vermelho: #B3261E;
    --vermelho-fundo: #F9DEDC;

    --fonte-titulo: 'Poppins', 'Segoe UI', sans-serif;
    --fonte-corpo: 'Inter', 'Segoe UI', sans-serif;
    --raio: 10px;
    --sombra: 0 1px 3px rgba(26, 26, 26, 0.06);

    /* Altura da barra do topo no computador. Vive aqui, e não escrita à mão em
       cada lugar, porque o cabeçalho congelado das tabelas de extrato
       (20/08/2026) gruda logo abaixo dela: com o número repetido em dois
       lugares, o dia em que a barra mudar de altura o cabeçalho descola sem
       ninguém notar. No celular a barra deixa de ter altura fixa — ver a seção
       "Interface no celular", no fim deste arquivo. */
    --altura-topo: 82px;
}

* { box-sizing: border-box; }

/* Remove a aparência nativa do sistema operacional em <button> (fundo e
   borda de "controle" do Windows/macOS, que fica por baixo do CSS mesmo
   com background/border "none" se `appearance` não for zerado). Sem isto,
   um botão sobre fundo escuro herdava um fundo claro do próprio sistema —
   texto claro (creme) virava ilegível até passar o mouse (o hover, com
   âmbar, tinha contraste mesmo contra esse fundo indesejado, por isso só
   "aparecia" no hover). */
button {
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    background: none;
    border: none;
    padding: 0;
    margin: 0;
    font: inherit;
    color: inherit;
    cursor: pointer;
}

html, body { height: 100%; }

body {
    margin: 0;
    background: var(--creme);
    color: var(--tinta);
    font-family: var(--fonte-corpo);
    font-size: 15px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 { font-family: var(--fonte-titulo); font-weight: 600; margin: 0 0 8px; }
h1 { font-size: 1.6rem; }
h2 { font-size: 1.25rem; }
h3 { font-size: 1.05rem; }

p { margin: 0 0 12px; }
a { color: var(--tinta); }

.texto-secundario { color: var(--cinza); font-size: 0.9rem; }
.texto-pequeno { font-size: 0.82rem; color: var(--cinza); }

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ---------- Barra superior ---------- */
.topo {
    background: var(--tinta);
    color: var(--creme);
    padding: 0 28px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: var(--altura-topo);
    position: sticky;
    top: 0;
    z-index: 30;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.12);
}

.topo .marca {
    font-family: var(--fonte-titulo);
    font-weight: 700;
    font-size: 1.05rem;
    letter-spacing: 0.03em;
    text-decoration: none;
    color: var(--creme);
}
.topo .marca span { color: var(--ambar); }

.topo nav { display: flex; align-items: center; gap: 22px; }
.topo nav a {
    color: var(--creme);
    text-decoration: none;
    font-size: 0.9rem;
    padding: 6px 0;
    border-bottom: 2px solid transparent;
}
.topo nav a:hover { color: var(--ambar); }
.topo nav a.ativo { color: var(--ambar); border-bottom-color: var(--ambar); }

/* Mesmo motivo do `.topo .menu-grupo-lista a` logo abaixo: precisa do
   prefixo `.topo` para ganhar de `.topo nav a` (o nome também é um <a>
   dentro de nav). Aqui o efeito era só cosmético — creme (da regra
   genérica) em vez do cinza-claro pretendido, ambos claros o bastante
   para ler — mas corrigido por consistência. */
.topo .usuario-topo {
    font-size: 0.85rem;
    color: var(--cinza-claro);
    border-left: 1px solid #3A3A3A;
    padding-left: 22px;
    text-decoration: none;
    border-bottom: 2px solid transparent;
}
.topo .usuario-topo:hover { color: var(--ambar); }
.topo .usuario-topo.ativo { color: var(--ambar); border-bottom-color: var(--ambar); }

/* O "Sair" usa `.botao-discreto`, que pinta o texto de cinza #444 — pensado
   para fundo claro. Sobre o preto da barra dá contraste de 1,7:1: legível de
   perto, some ao sol e para quem enxerga pouco. Corrigido no computador e no
   celular ao mesmo tempo, a pedido do Gerente de Engenharia em 02/08/2026,
   para os dois não divergirem. */
.topo nav form .botao-discreto {
    color: var(--cinza-claro);
    border-color: #3A3A3A;
}
.topo nav form .botao-discreto:hover {
    background: rgba(255, 255, 255, 0.07);
    border-color: var(--cinza-claro);
    color: var(--creme);
}

/* ---------- Grupos de menu com lista suspensa ---------- */
.menu-grupo { position: relative; }
.menu-grupo-rotulo {
    background: none;
    border: none;
    font-family: inherit;
    color: var(--creme);
    text-decoration: none;
    font-size: 0.9rem;
    padding: 6px 0;
    border-bottom: 2px solid transparent;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 5px;
}
.menu-grupo-rotulo::after {
    content: "";
    width: 0;
    height: 0;
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    border-top: 5px solid currentColor;
    opacity: 0.7;
}
.menu-grupo-rotulo:hover { color: var(--ambar); }
.menu-grupo.ativo .menu-grupo-rotulo { color: var(--ambar); border-bottom-color: var(--ambar); }

/* Rótulo em ícone (ex.: Administração) — sem seta, com área de toque redonda */
.menu-grupo-rotulo--icone {
    padding: 8px;
    border-radius: 8px;
    border-bottom: none;
    line-height: 0;
}
.menu-grupo-rotulo--icone::after { content: none; }
.menu-grupo-rotulo--icone:hover { color: var(--ambar); background: rgba(254, 201, 67, 0.14); }
.menu-grupo.ativo .menu-grupo-rotulo--icone {
    color: var(--ambar);
    background: rgba(254, 201, 67, 0.18);
    border-bottom: none;
}
.menu-grupo-rotulo--icone svg { display: block; width: 20px; height: 20px; }

/* O olho que esconde o financeiro — rodada 84, 18/08/2026.

   Pedido do Gerente na conferência visual: o gesto que todo aplicativo de
   banco e de corretora já ensinou. Mesmo tamanho e mesmo alinhamento do ícone
   de Administração, logo acima, para os dois não parecerem de sistemas
   diferentes na mesma barra.

   Fica ANTES da seção "Interface no celular", e isso não é arrumação: regra
   escrita depois dela vence por ordem e desliga o celular em silêncio — foi
   assim que o menu sumiu até a rodada 67, e há teste travando desde então. */
.topo nav form .botao-olho {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 8px;
    line-height: 0;
}
.topo nav form .botao-olho svg { display: block; width: 20px; height: 20px; }

.menu-grupo-lista {
    display: none;
    position: absolute;
    top: calc(100% + 14px);
    left: 0;
    background: var(--creme);
    border: 1px solid #E4E1D3;
    border-radius: 8px;
    box-shadow: 0 10px 26px rgba(0, 0, 0, 0.2);
    min-width: 180px;
    padding: 6px;
    z-index: 20;
}
/* Grupos próximos da borda direita da barra abrem a lista alinhada à
   direita, para não vazar para fora da tela nem invadir o nome do usuário. */
.menu-grupo--alinhar-direita .menu-grupo-lista { left: auto; right: 0; }
.menu-grupo.aberto .menu-grupo-lista { display: block; }
/* Especificidade proposital: `.topo nav a` (regra dos links da barra,
   texto claro) tem 1 classe + 2 elementos (nav, a). Como esta lista fica
   dentro de `nav`, sem o prefixo `.topo` aqui embaixo (2 classes + 1
   elemento) aquela regra vencia e pintava o texto claro por cima do fundo
   claro do próprio menu suspenso — ficava ilegível em repouso e só
   "aparecia" no hover, quando `.topo nav a:hover` (âmbar) também vazava
   para dentro da lista. Bug real, encontrado inspecionando a página ao
   vivo depois que a correção do <button> (round anterior) não resolveu. */
.topo .menu-grupo-lista a {
    display: block;
    color: var(--tinta);
    text-decoration: none;
    font-size: 0.88rem;
    padding: 8px 10px;
    border-radius: 6px;
    border-bottom: none;
}
.topo .menu-grupo-lista a:hover { background: #F1EEDF; color: var(--tinta); }
.topo .menu-grupo-lista a.ativo { color: #8A6400; font-weight: 600; background: #F1EEDF; }

/* O seletor de idioma (rodada 85, 19/08/2026) usa <button> e nao <a> porque a
   troca e' POST: um GET que muda estado um pre-carregador de link dispara
   sozinho. As tres regras abaixo espelham as de `.topo .menu-grupo-lista a`
   logo acima, COM O MESMO PREFIXO `.topo` e pelo mesmo motivo registrado la
   em cima -- sem ele, a regra dos links da barra pinta texto claro sobre o
   fundo claro do menu. O reset de background/border/font existe porque
   <button> nao herda nenhum dos tres do pai. */
.topo .menu-grupo-lista button {
    display: block;
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    font: inherit;
    font-size: 0.88rem;
    color: var(--tinta);
    padding: 8px 10px;
    border-radius: 6px;
    cursor: pointer;
}
.topo .menu-grupo-lista button:hover { background: #F1EEDF; color: var(--tinta); }
.topo .menu-grupo-lista button.ativo { color: #8A6400; font-weight: 600; background: #F1EEDF; }

/* A data curta nao quebra linha (rodada 85, 19/08/2026).
   `03/08/2026` nao tinha ponto de quebra para o navegador; `03-ago-2026` tem
   dois. Em 320px, na coluna Dia do Relatorio de Diarias, a data apareceu
   partida em tres linhas -- e o `conferir_visual` nao acusou nada, porque a
   tabela nao transbordou: ela so ficou ilegivel. Foi olhando a captura. */
.data-curta { white-space: nowrap; }

.menu-grupo-vazio {
    color: var(--cinza-claro);
    font-size: 0.9rem;
    opacity: 0.55;
    cursor: default;
    padding: 6px 0;
    border-bottom: 2px solid transparent;
}

/* ---------- Submenu aninhado (Gerenciamento > Cadastros) ----------
   Reorganização de 27/07/2026 (pedido do Gerente de Engenharia): os
   antigos grupos separados "Cadastros" e "Projetos" viraram um só grupo
   "Gerenciamento", com "Cadastros" agora um segundo nível (flyout para a
   direita, mesmo clique-para-abrir do nível de cima) e "Projetos" como
   link direto ao lado. Mesmo mecanismo do `.menu-grupo`, só que abre para
   o lado em vez de para baixo, já que já está dentro de uma lista aberta. */
.menu-subgrupo { position: relative; }
.menu-subgrupo-rotulo {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    background: none;
    border: none;
    font: inherit;
    color: var(--tinta);
    text-decoration: none;
    font-size: 0.88rem;
    text-align: left;
    padding: 8px 10px;
    border-radius: 6px;
    cursor: pointer;
}
.menu-subgrupo-rotulo::after {
    content: "";
    width: 0;
    height: 0;
    border-top: 4px solid transparent;
    border-bottom: 4px solid transparent;
    border-left: 5px solid currentColor;
    opacity: 0.5;
    flex-shrink: 0;
}
.menu-subgrupo-rotulo:hover { background: #F1EEDF; }
.menu-subgrupo.ativo .menu-subgrupo-rotulo { color: #8A6400; font-weight: 600; background: #F1EEDF; }

.menu-subgrupo-lista {
    display: none;
    position: absolute;
    top: -6px;
    left: calc(100% + 6px);
    background: var(--creme);
    border: 1px solid #E4E1D3;
    border-radius: 8px;
    box-shadow: 0 10px 26px rgba(0, 0, 0, 0.2);
    min-width: 180px;
    padding: 6px;
    z-index: 25;
}
.menu-subgrupo.aberto .menu-subgrupo-lista { display: block; }
/* Mesmo motivo do `.topo .menu-grupo-lista a` acima: precisa do prefixo
   `.topo` para ganhar de `.topo nav a` em especificidade. */
.topo .menu-subgrupo-lista a {
    display: block;
    color: var(--tinta);
    text-decoration: none;
    font-size: 0.88rem;
    padding: 8px 10px;
    border-radius: 6px;
    border-bottom: none;
}
.topo .menu-subgrupo-lista a:hover { background: #F1EEDF; color: var(--tinta); }
.topo .menu-subgrupo-lista a.ativo { color: #8A6400; font-weight: 600; background: #F1EEDF; }

/* ---------- Layout ---------- */
.conteudo { max-width: 1100px; margin: 0 auto; padding: 32px 24px 72px; }

.cabecalho-pagina {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 24px;
    flex-wrap: wrap;
}
/* O bloco do título encolhe em vez de empurrar, e as ações ficam encostadas à
   direita mesmo quando quebram para a linha de baixo (regra da casa,
   31/07/2026). Sem isto, um subtítulo longo — como o do Fechamento mensal —
   jogava "Exportar Excel / Exportar PDF" para a esquerda, e a mesma ação
   aparecia em lugares diferentes de tela para tela. */
.cabecalho-pagina > :first-child { flex: 1 1 22rem; min-width: 0; }
.cabecalho-pagina > .acoes-cabecalho { margin-left: auto; justify-content: flex-end; }

.cartao {
    background: var(--branco);
    border: 1px solid var(--borda);
    border-radius: var(--raio);
    box-shadow: var(--sombra);
    padding: 24px;
    margin-bottom: 20px;
}

.cartao-compacto { padding: 16px 20px; }

/* ---------- Etapas — arrastar para reordenar (PRD §33) ---------- */
.alca-arrastar {
    cursor: grab;
    color: var(--cinza-claro);
    font-size: 1rem;
    line-height: 1;
    user-select: none;
    padding: 2px 4px;
}
.alca-arrastar:hover { color: var(--tinta); }
.etapa-arrastavel[draggable="true"] { cursor: default; }
.etapa-arrastando { opacity: 0.45; border-color: var(--ambar); }
.etapa-alvo-solta { border-color: var(--ambar); border-style: dashed; }

/* Atividades dentro da etapa (ou transversais) — mesmo mecanismo de
   arrastar-e-soltar de Etapas, agora escopado por cartão (PRD §35). */
.item-escopo-arrastavel[draggable="true"] { cursor: default; }
.acoes-arrastar { width: 24px; text-align: center; padding-right: 0; }

/* Correção de 26/07/2026 (PRD §35.1): as atividades pareciam soltas dentro
   do cartão da etapa, sem nenhuma pista visual de que estavam "dentro"
   dela. O recuo + borda lateral + rótulo deixam a relação etapa → atividade
   clara à primeira vista, e o cabeçalho da tabela nomeia as colunas. */
.rotulo-subitens { margin: 12px 0 4px; text-transform: uppercase; letter-spacing: 0.04em; font-size: 0.72rem; }
.subitens-etapa {
    margin-left: 22px;
    padding: 10px 14px;
    border-left: 2px solid var(--ambar-claro);
    background: var(--creme);
    border-radius: 0 8px 8px 0;
}
.subitens-etapa table { background: transparent; }
.subitens-etapa th {
    font-size: 0.68rem; padding: 6px 12px; background: transparent;
}
.subitens-etapa td { padding: 8px 12px; border-bottom-color: var(--borda); }
.subitens-etapa tbody tr:last-child td { border-bottom: none; }
.subitens-etapa tbody tr:hover { background: var(--branco); }
.subitens-etapa .nome-celula { font-weight: 400; color: var(--cinza); }
.subitens-etapa .alca-arrastar { font-size: 0.85rem; }

/* Hierarquia Projeto > Etapa > Atividade > Sub-atividade (PRD §38, revisado
   em §39 por falta de contraste): a primeira versão só variava o tom entre
   creme e branco — diferença quase imperceptível. Agora a sub-atividade
   ganha uma borda-guia e fundo em âmbar (progressivamente mais intenso a
   cada nível), recuo maior e uma etiqueta "Sub-atividade" explícita, além
   do marcador "└" — várias pistas ao mesmo tempo, não só cor. Só
   apresentação: não muda a ordenação/arrastar-e-soltar (que continua
   olhando só EscopoItem.ordem). */
td.nome-celula.profundidade-1 { padding-left: 30px; border-left: 3px solid var(--ambar); }
td.nome-celula.profundidade-2 { padding-left: 50px; border-left: 3px solid var(--ambar); }
td.nome-celula.profundidade-3 { padding-left: 70px; border-left: 3px solid var(--ambar); }
td.nome-celula.profundidade-4 { padding-left: 90px; border-left: 3px solid var(--ambar); }
.marcador-sub-atividade { color: var(--ambar-escuro); font-weight: 700; margin-right: 6px; }

.subitens-etapa tr.profundidade-0 > td { background: rgba(254, 201, 67, 0.45); }
.subitens-etapa tr.profundidade-1 > td { background: rgba(254, 201, 67, 0.26); }
.subitens-etapa tr.profundidade-2 > td { background: rgba(254, 201, 67, 0.13); }
.subitens-etapa tr.profundidade-3 > td { background: rgba(254, 201, 67, 0.05); }
/* profundidade-4 sem tom adicional — nível mais profundo, funde com o fundo do cartão. */
.subitens-etapa tbody tr.profundidade-0:hover > td { background: rgba(254, 201, 67, 0.55); }
.subitens-etapa tbody tr.profundidade-1:hover > td { background: rgba(254, 201, 67, 0.34); }
.subitens-etapa tbody tr.profundidade-2:hover > td { background: rgba(254, 201, 67, 0.20); }
.subitens-etapa tbody tr.profundidade-3:hover > td { background: rgba(254, 201, 67, 0.11); }

/* Correção de 27/07/2026: dentro das linhas de atividade/sub-atividade
   acima (fundo âmbar, mais intenso quanto mais raso o nível), os botões
   "Editar", "Horas/nível", "Promover" e "Mover/copiar" usam o
   .botao-discreto padrão — fundo transparente e borda bem clara (--borda,
   um bege quase do mesmo tom do âmbar de fundo). O contraste ficava tão
   baixo que dava pra ler o texto mas não pra perceber que era um botão
   clicável (reportado pelo Gerente de Engenharia). Aqui — tanto na aba
   "Atividades" da tela do projeto quanto na árvore de projetos, que
   reaproveita a mesma marcação (.subitens-etapa/td.acoes) — o botão ganha
   um fundo sólido e borda mais escura, destacando-se do fundo âmbar em
   qualquer profundidade. */
.subitens-etapa td.acoes .botao-discreto {
    background: var(--branco);
    border-color: var(--cinza-claro);
    box-shadow: 0 1px 2px rgba(26, 26, 26, 0.12);
}
.subitens-etapa td.acoes .botao-discreto:hover {
    background: var(--creme);
    border-color: var(--tinta);
    color: var(--tinta);
}

/* Botão de expandir/recolher sub-atividades por nível (PRD §39). */
.expandir-recuo { display: inline-block; width: 16px; text-align: center; }
.botao-expandir {
    width: 16px; height: 16px; line-height: 14px; padding: 0;
    border: 1px solid var(--ambar-escuro); border-radius: 3px;
    background: var(--branco); color: var(--ambar-escuro);
    font-weight: 700; font-size: 0.75rem; cursor: pointer;
}
.botao-expandir:hover { background: var(--ambar-claro); }

/* Arrastar-e-soltar entre etapas, com reconfiguração de pai (PRD §40). */
.item-escopo-alvo-reparentar > td {
    background: var(--ambar-claro) !important;
    outline: 2px dashed var(--ambar-escuro);
    outline-offset: -2px;
}

/* Arrastar entre projetos, na árvore de projetos (PRD §44): destaca o grupo
   (lista de etapas ou de atividades) de OUTRO projeto que vai receber o
   item ao soltar ali — diferente de ".item-escopo-alvo-reparentar", que é
   sempre dentro do mesmo projeto. */
.lista-arvore-alvo-mover {
    outline: 2px dashed var(--ambar-escuro);
    outline-offset: 4px;
    border-radius: 8px;
}

/* Visualização compacta da árvore de projetos (PRD §45) — perfil mais de
   sistema/explorer do que de página web: cabem vários projetos na tela ao
   mesmo tempo, trocando o espaçamento generoso de cartão (bom para olhar
   UM projeto) por linhas curtas e recuo lateral, como uma árvore de
   arquivos. Alternada pelo botão "Visualização compacta", com o estado
   salvo no navegador (localStorage) — não muda nenhum dado, só a
   apresentação. */
#arvore-projetos.arvore-compacta .cartao,
#arvore-projetos.arvore-compacta .cartao-compacto {
    padding: 4px 8px;
    margin-bottom: 2px;
    border-radius: 4px;
    box-shadow: none;
    border-color: transparent;
}
#arvore-projetos.arvore-compacta .cartao:hover,
#arvore-projetos.arvore-compacta .cartao-compacto:hover {
    background: var(--creme);
}
#arvore-projetos.arvore-compacta .corpo-no-arvore {
    margin-top: 2px !important;
    margin-left: 18px;
    padding-left: 8px;
    border-left: 1px solid var(--borda);
}
#arvore-projetos.arvore-compacta .corpo-etapa {
    margin-top: 2px !important;
}
#arvore-projetos.arvore-compacta h3,
#arvore-projetos.arvore-compacta strong {
    font-size: 0.85rem;
}
#arvore-projetos.arvore-compacta .texto-pequeno {
    font-size: 0.72rem;
}
#arvore-projetos.arvore-compacta .subitens-etapa {
    margin-left: 12px;
    padding: 2px 6px;
}
#arvore-projetos.arvore-compacta .subitens-etapa table th {
    padding: 3px 8px;
    font-size: 0.66rem;
}
#arvore-projetos.arvore-compacta .subitens-etapa table td {
    padding: 3px 8px;
    font-size: 0.72rem;
}
#arvore-projetos.arvore-compacta .botao {
    padding: 2px 8px;
    font-size: 0.72rem;
}
#arvore-projetos.arvore-compacta .etiqueta {
    padding: 1px 6px;
    font-size: 0.6rem;
}
#arvore-projetos.arvore-compacta .rotulo-subitens {
    margin: 4px 0 2px;
}

.grade { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 18px; }

/* ---------- Botões ---------- */
.botao {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    background: var(--ambar);
    color: var(--tinta);
    font-family: var(--fonte-corpo);
    font-weight: 600;
    font-size: 0.9rem;
    padding: 10px 18px;
    border: 1px solid var(--ambar);
    border-radius: 7px;
    text-decoration: none;
    cursor: pointer;
    white-space: nowrap;
}
.botao:hover { background: var(--ambar-escuro); border-color: var(--ambar-escuro); }

.botao-secundario { background: transparent; border-color: var(--tinta); color: var(--tinta); }
.botao-secundario:hover { background: var(--tinta); color: var(--creme); }

.botao-discreto {
    background: transparent; border-color: var(--borda); color: var(--cinza);
    font-weight: 500; padding: 7px 13px; font-size: 0.84rem;
}
.botao-discreto:hover { background: var(--creme); border-color: var(--cinza-claro); color: var(--tinta); }

.botao-perigo { background: transparent; border-color: var(--vermelho); color: var(--vermelho); }
.botao-perigo:hover { background: var(--vermelho); color: var(--branco); }

.botao-largo { width: 100%; justify-content: center; }

/* ---------- Formulários ---------- */
.campo, input[type=text], input[type=email], input[type=password],
input[type=date], input[type=time], input[type=number], select, textarea {
    width: 100%;
    padding: 10px 12px;
    border: 1px solid var(--borda);
    border-radius: 7px;
    font-family: var(--fonte-corpo);
    font-size: 0.93rem;
    background: var(--branco);
    color: var(--tinta);
}
.campo:focus, input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: var(--ambar);
    box-shadow: 0 0 0 3px var(--ambar-claro);
}

.linha { margin-bottom: 18px; }
.linha label { display: block; font-size: 0.85rem; font-weight: 500; color: var(--cinza); margin-bottom: 6px; }
.linha .ajuda { font-size: 0.79rem; color: var(--cinza-claro); margin-top: 5px; }
.linha .erro { font-size: 0.82rem; color: var(--vermelho); margin-top: 5px; }

.colunas { display: grid; grid-template-columns: 1fr 1fr; gap: 0 20px; }
.colunas-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0 20px; }
/* Grade com TABELA dentro — lote M, 02/10/2026, a conciliação com o Zoho.
   A trilha `1fr` é `minmax(auto, 1fr)`: o item do grid fica com
   `min-width: auto` e estica até a largura da tabela, e o `.tabela-envolucro`
   nunca fica mais estreito que ela — quem rola é a PÁGINA. Medido em 320px:
   333px em es-mx e 335px em fr. Com `min-width: 0` o cartão fica da largura
   da trilha e o envólucro passa a conter a tabela.
   Classe própria, e não na `.colunas`: das 56 da casa, a da conciliação é a
   única com tabela dentro; as outras são formulários. Trava 22 de
   `apps/projetos/test_zoho_conciliacao.py`. */
.colunas-contidas > * { min-width: 0; }

.grupo-campos {
    border: 1px solid var(--borda);
    border-radius: var(--raio);
    padding: 20px 22px 4px;
    margin-bottom: 22px;
}
.grupo-campos > legend {
    font-family: var(--fonte-titulo);
    font-weight: 600;
    font-size: 0.95rem;
    padding: 0 8px;
    color: var(--tinta);
}

.caixas { display: flex; flex-wrap: wrap; gap: 14px; }
.caixas label {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: 0.88rem; color: var(--tinta); font-weight: 400; margin: 0;
}
.caixas input[type=checkbox] { width: auto; margin: 0; }
.caixas ul { list-style: none; display: flex; flex-wrap: wrap; gap: 14px; padding: 0; margin: 0; }

/* `flex-wrap` acrescentado em 02/08/2026: os rótulos destes botões carregam o
   nome do projeto ("Validar ZZ TESTE — conferência rodada 66"), e dois deles
   lado a lado passam de qualquer tela de celular. Sem quebra, o segundo saía
   para fora do cartão. */
.acoes-form { display: flex; gap: 12px; align-items: center; padding-top: 4px; flex-wrap: wrap; }

/* Um formulário que entra logo depois de outro — 14/09/2026, item 13.
   A composição de custo tem botão próprio (decisões (e) e (f) do Gerente) e
   HTML não aceita formulário dentro de formulário: ela é IRMÃ do cadastro do
   usuário, e começa logo depois do `.acoes-form` final — que tem
   `padding-top: 4px` e NENHUMA margem embaixo, porque em toda tela anterior
   a esta ele era a última coisa da página.
   O efeito, visto na conferência visual de 14/09 nas quatro línguas: a borda
   do `fieldset` seguinte encostava nos botões e o `legend` "Composição de
   custo" era desenhado ao lado de "Cancelar", em cima da linha da borda.
   Zero pixel entre os dois. Nada mede isso: não transborda, não some e não
   muda número nenhum — só se vê olhando.
   22px é a MESMA distância que `.grupo-campos` já usa entre dois blocos, e
   não um número novo. */
.form-irmao { margin-top: 22px; }

/* Rodapé de paginação das listas longas — 05/09/2026 (`_paginacao.html`).
   Vinte linhas por página, decisão do Gerente: é o tamanho em que o bloco
   por linha do celular foi aceito. Quebra em duas linhas no celular, como o
   `.acoes-form` acima, e pelo mesmo motivo. */
.paginacao {
    display: flex; justify-content: space-between; align-items: center;
    gap: 8px 12px; flex-wrap: wrap; padding: 10px 14px;
    border-top: 1px solid var(--borda);
}
.paginacao-links { display: flex; align-items: center; gap: 8px; }

/* ---------- Tabelas ---------- */
.tabela-envolucro { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 12px 14px; border-bottom: 1px solid var(--borda); }
th {
    font-size: 0.74rem; font-weight: 600; text-transform: uppercase;
    letter-spacing: 0.05em; color: var(--cinza); background: var(--creme);
}
tbody tr:hover { background: var(--creme); }
td.acoes { text-align: right; white-space: nowrap; }
.vazio { text-align: center; color: var(--cinza-claro); padding: 40px 14px; }

.nome-celula { font-weight: 500; }
.nome-celula a { text-decoration: none; }
.nome-celula a:hover { text-decoration: underline; }

/* O ícone que abre os lançamentos da atividade mora na célula do NOME, e não
   na de ações — decisão 1 do Gerente de Engenharia, 22/09/2026: a célula de
   ações inteira está atrás de `pode_gerenciar_projetos`, e a consulta de
   horas é aberta a todo usuário ativo.

   Duas correções, e as duas são de herança, não de tamanho:

   1. `.nome-celula a:hover` (0,2,1) ganha de `.botao-icone:hover` (0,2,0) e
      sublinharia o ícone ao passar o cursor — sublinhado num SVG não aparece
      como sublinhado, aparece como risco solto ao lado do glifo.
   2. `.botao-icone` é `inline-flex`, e caixa flexível alinha pela linha de
      base — dentro de texto corrido ela desce em relação ao nome. */
.nome-celula .botao-icone { vertical-align: middle; }
.nome-celula .botao-icone:hover { text-decoration: none; }

/* Linha de título de um nó da árvore de projetos: botão de expandir, código,
   nome e etiquetas. Precisa quebrar linha — sem isto, numa tela de 360px com a
   árvore cheia, as etiquetas de status empurravam a página inteira para o lado
   (documento em 451px). Achado no aparelho do Gerente em 02/08/2026: a
   varredura anterior mediu esta tela sem projeto nenhum e passou limpa. */
.linha-no-arvore {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    min-width: 0;
}

/* Fileiras de ação alinhadas à direita precisam quebrar linha. Sem isto o
   excesso vaza para a ESQUERDA da tela — e à esquerda do zero não existe
   rolagem, então o botão fica inalcançável para sempre, sem que
   `document.scrollWidth` acuse nada. Foi assim que "Visualização compacta"
   sumiu no celular (02/08/2026). */
.acoes-direita {
    display: flex;
    justify-content: flex-end;
    flex-wrap: wrap;
    gap: 8px;
}

/* ---------- Etiquetas ---------- */
.etiqueta {
    display: inline-block; padding: 3px 11px; border-radius: 999px;
    font-size: 0.75rem; font-weight: 600; white-space: nowrap;
}
/* A etiqueta ganhou `display`, e `display` GANHA do atributo `hidden` — a
   regra do navegador (`[hidden] { display: none }`) tem a menor especificidade
   que existe. Sem esta linha, uma etiqueta escrita com `hidden` aparece na
   tela. Foi o defeito de 13/08/2026, que já estava em produção, e é o que
   `apps/core/test_css_ocultos.py` guarda desde então — foi ele quem acusou
   isto em 27/08/2026, quando a etiqueta "parcial" do Extrato por dia passou a
   nascer escondida. */
.etiqueta[hidden] { display: none; }
.etiqueta-ativo { background: var(--verde-fundo); color: var(--verde); }
.etiqueta-inativo { background: #EFEFEF; color: var(--cinza); }
.etiqueta-perfil { background: var(--ambar-claro); color: #7A5700; }
.etiqueta-nivel { background: #E8EEF6; color: #2A4A73; }
.etiqueta-sub-atividade { background: var(--ambar-claro); color: #7A5700; margin-left: 6px; }
.etiqueta-alerta { background: var(--vermelho-fundo); color: var(--vermelho); margin-left: 6px; }
/* Seleção parcial de um dia do Extrato por dia (27/08/2026, decisão do Gerente
   Técnico). Âmbar, e não o vermelho de `.etiqueta-alerta`: não há defeito nem
   pendência — a linha está certa, e o que a etiqueta diz é que o DOCUMENTO vai
   levar menos do que ela mostra. Vermelho pediria conserto de algo que não
   está quebrado, e o Gerente pediu um indicador discreto.
   Menor que as demais etiquetas porque ela divide a célula mais estreita da
   tabela com a data, a caixa do dia e o botão das descrições. */
.etiqueta-parcial {
    background: var(--ambar-claro);
    color: #7A5700;
    margin-left: 6px;
    padding: 1px 7px;
    font-size: 0.68rem;
}

/* ---------- Idioma do documento (rodada 85) ----------
   As abas ficam no cabeçalho do cartão, e não num <select>: são quatro
   opções fixas, e trocar de idioma para conferir uma tradução é um vaivém —
   com abas o alvo do próximo clique já está na tela. */
.abas-idioma { display: flex; gap: 4px; flex-wrap: wrap; }
.aba-idioma {
    padding: 4px 12px; border-radius: 999px; font-size: 0.8rem;
    text-decoration: none; color: var(--cinza); background: #EFEFEF;
}
.aba-idioma:hover { background: var(--ambar-claro); color: #7A5700; }
.aba-idioma-ativa { background: var(--tinta); color: #FFF; }
.aba-idioma-ativa:hover { background: var(--tinta); color: #FFF; }

/* A célula que ainda está em português dentro de uma vista traduzida. */
.celula-pendente { background: var(--vermelho-fundo); }

/* A escolha do idioma na emissão. Sem marcador de lista: o botão de rádio já
   é o marcador, e o ponto ao lado dele vira ruído — apareceu na conferência
   visual de 20/08/2026, olhando a captura. */
.lista-idiomas { list-style: none; margin: 8px 0 16px; padding: 0; }
.lista-idiomas li { margin: 0 0 6px; }
.lista-idiomas label {
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    cursor: pointer;
}
/* O idioma incompleto fica visivelmente fora de alcance. `:has()` porque o
   texto do rótulo é nó de texto, não elemento: `input[disabled] + *` não o
   alcança e a opção desabilitada ficava preta como as outras. */
.lista-idiomas label:has(input[disabled]) { color: var(--cinza); cursor: default; }

/* Na tela de revisão: o cartão do texto que ainda não tem tradução, e o
   português de origem, que fica visível mas recuado — quem revisa compara,
   não lê os dois com o mesmo peso. */
.cartao-pendente { border-left: 3px solid var(--vermelho); }
.texto-original {
    margin: 8px 0; padding: 8px 12px; border-left: 2px solid var(--borda);
    color: var(--cinza); font-size: 0.9rem; white-space: pre-wrap;
}

/* Status do projeto — mesmas cores usadas na etiqueta e na barra do
   dashboard da Home, para o olho aprender o código de cores uma vez só. */
.etiqueta-status-proposta { background: var(--ambar-claro); color: #7A5700; }
.etiqueta-status-execucao { background: #E8EEF6; color: #2A4A73; }
.etiqueta-status-implantacao { background: #E3F2F0; color: #1F6F63; }
.etiqueta-status-garantia { background: var(--verde-fundo); color: var(--verde); }
.etiqueta-status-encerrado { background: #EFEFEF; color: var(--cinza); }
.etiqueta-status-cancelado { background: var(--vermelho-fundo); color: var(--vermelho); }

/* ---------- Filtros ---------- */
.filtros { display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-end; margin-bottom: 18px; }
.filtros .linha { margin-bottom: 0; }
.filtros .campo-busca { min-width: 260px; }

.abas { display: flex; gap: 4px; border-bottom: 1px solid var(--borda); margin-bottom: 20px; flex-wrap: wrap; }
.abas a, .abas .aba-botao {
    padding: 9px 16px; text-decoration: none; font-size: 0.89rem; color: var(--cinza);
    border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.abas a.ativo, .abas .aba-botao.ativo { color: var(--tinta); font-weight: 600; border-bottom-color: var(--ambar); }
.abas .aba-botao {
    background: none; border-left: none; border-right: none; border-top: none;
    cursor: pointer; font-family: inherit;
}

/* ---------- Mensagens ---------- */
.mensagens { list-style: none; padding: 0; margin: 0 0 22px; }
.mensagens li {
    padding: 12px 16px; border-radius: 8px; margin-bottom: 10px; font-size: 0.9rem;
    background: var(--ambar-claro); border: 1px solid var(--ambar);
}
.mensagens li.success { background: var(--verde-fundo); border-color: #A9D6A9; color: var(--verde); }
.mensagens li.error { background: var(--vermelho-fundo); border-color: #F2B8B5; color: var(--vermelho); }

.aviso-formulario {
    background: var(--vermelho-fundo); border: 1px solid #F2B8B5; color: var(--vermelho);
    padding: 12px 16px; border-radius: 8px; margin-bottom: 20px; font-size: 0.88rem;
}

/* ---------- Login ---------- */
.tela-login {
    min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 24px;
}
.caixa-login { width: 100%; max-width: 400px; }
.caixa-login .marca-login {
    text-align: center; font-family: var(--fonte-titulo); font-weight: 700;
    font-size: 1.5rem; letter-spacing: 0.04em; margin-bottom: 4px;
}
.caixa-login .marca-login span { color: var(--ambar); }
.caixa-login .subtitulo {
    text-align: center; color: var(--cinza); font-size: 0.9rem; margin-bottom: 26px;
}

/* ---------- Entrada pela conta Microsoft (rodada 75) ---------- */
/* O botão segue as regras de marca da Microsoft para "Sign in with
   Microsoft": fundo branco, borda cinza, o quadriculado de quatro cores à
   esquerda do texto. Não é enfeite — é o que faz a pessoa reconhecer, sem
   ler, que dali em diante quem pergunta a senha é a Microsoft e não nós. */
.botao-microsoft {
    display: flex; align-items: center; justify-content: center; gap: 12px;
    width: 100%; box-sizing: border-box;
    padding: 12px 16px; min-height: 44px;   /* 44px: alvo de toque em campo */
    background: #FFFFFF; color: #5E5E5E;
    border: 1px solid #8C8C8C; border-radius: 8px;
    font-family: inherit; font-size: 0.95rem; font-weight: 600;
    cursor: pointer; text-decoration: none;
}
.botao-microsoft:hover { background: #F3F3F3; }
.botao-microsoft:focus-visible { outline: 2px solid var(--ambar); outline-offset: 2px; }
.botao-microsoft .quadriculado {
    display: grid; grid-template-columns: 9px 9px; grid-template-rows: 9px 9px;
    gap: 2px; flex: none;
}
.botao-microsoft .quadriculado i { display: block; }

/* Em 320px o rótulo quebrava em duas linhas, com o quadriculado sobrando ao
   lado — visto na conferência de 08/08/2026. Encolher um pouco resolve sem
   encurtar o texto: "Entrar com a conta Microsoft" diz que a conta é a da
   empresa, e "Entrar com a Microsoft" não diria. O alvo de toque continua
   nos 44px, que é o que importa em campo. */
@media (max-width: 379px) {
    .botao-microsoft { font-size: 0.85rem; gap: 8px; padding: 12px 6px; }
    /* Só a caixa de entrada afrouxa as laterais — a folga vai para o texto
       do botão. O restante do sistema não muda. */
    .caixa-login .cartao { padding-left: 14px; padding-right: 14px; }
    .tela-login { padding-left: 12px; padding-right: 12px; }
}

/* Separador entre as duas portas, quando as duas aparecem. */
.ou-entao {
    display: flex; align-items: center; gap: 12px;
    margin: 20px 0; color: var(--cinza); font-size: 0.8rem; text-transform: uppercase;
    letter-spacing: 0.06em;
}
.ou-entao::before, .ou-entao::after {
    content: ""; flex: 1; height: 1px; background: var(--borda);
}

/* Aviso de porta de resgate aberta: informa sem assustar. */
.aviso-porta {
    background: var(--ambar-fundo, #FFF8E6); border: 1px solid var(--ambar);
    color: #6B4E00; padding: 12px 16px; border-radius: 8px;
    margin-bottom: 20px; font-size: 0.85rem; line-height: 1.45;
}

/* ---------- Dashboard (página inicial) ---------- */
.grade-indicadores {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 18px;
    margin-bottom: 20px;
}

.indicador {
    background: var(--branco);
    border: 1px solid var(--borda);
    border-radius: var(--raio);
    box-shadow: var(--sombra);
    padding: 20px 22px;
}
.indicador .indicador-rotulo {
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--cinza);
    margin-bottom: 8px;
}
.indicador .indicador-valor {
    font-family: var(--fonte-titulo);
    font-weight: 700;
    font-size: 1.7rem;
    color: var(--tinta);
    line-height: 1.15;
}
.indicador .indicador-valor .indicador-unidade {
    font-size: 1rem;
    font-weight: 600;
    color: var(--cinza);
    margin-left: 4px;
}
.indicador .indicador-comparativo {
    font-size: 0.82rem;
    color: var(--cinza-claro);
    margin-top: 6px;
}
.indicador.indicador--destaque { border-color: var(--ambar); }
.indicador.indicador--destaque .indicador-valor { color: #7A5700; }

.painel-titulo {
    font-family: var(--fonte-titulo);
    font-weight: 600;
    font-size: 1rem;
    margin-bottom: 16px;
}

.barra-status { display: flex; flex-direction: column; gap: 14px; }
.barra-status-linha { display: grid; grid-template-columns: 150px 1fr 90px; align-items: center; gap: 14px; }
.barra-status-rotulo { font-size: 0.88rem; color: var(--tinta); }
.barra-status-trilho {
    background: var(--creme);
    border-radius: 999px;
    height: 10px;
    overflow: hidden;
}
/* `display: block` NAO e' decoracao: sem ele a barra nunca aparece.
   O gabarito escreve `style="width: N%"` num <span>, e width/height nao se
   aplicam a elemento inline nao-substituido. Medido no navegador em
   06/09/2026: as quatro linhas do Resumo davam `display: inline` e
   0.0 x 0.0 px, inclusive a que pedia `width: 100%`. Quem guarda isto e'
   apps/core/test_barra_de_status.py. */
.barra-status-preenchimento { display: block; height: 100%; border-radius: 999px; }
/* Mesmo código de cor dos status usados na etiqueta (versão sólida, para
   contraste sobre o trilho claro). */
.barra-status-preenchimento--proposta { background: var(--ambar); }
.barra-status-preenchimento--execucao { background: #2A4A73; }
.barra-status-preenchimento--implantacao { background: #1F6F63; }
.barra-status-preenchimento--garantia { background: var(--verde); }
.barra-status-preenchimento--encerrado { background: var(--cinza-claro); }
.barra-status-preenchimento--cancelado { background: var(--vermelho); }
.barra-status-contagem { text-align: right; font-size: 0.85rem; color: var(--cinza); white-space: nowrap; }

@media (max-width: 620px) {
    .barra-status-linha { grid-template-columns: 100px 1fr 50px; gap: 8px; }
}

/* ---------- Detalhe ---------- */
.lista-dados { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 18px 28px; }
.lista-dados dt { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--cinza); margin-bottom: 3px; }
.lista-dados dd { margin: 0 0 4px; font-size: 0.95rem; }

/* As regras de cabeçalho que ficavam aqui foram para a seção "Interface no
   celular", no FIM deste arquivo — ver lá o porquê (rodada 67, 02/08/2026).
   Em resumo: escritas neste ponto, elas eram anuladas pelas regras do
   logotipo, escritas depois, e o menu inteiro nascia fora da tela. */
@media (max-width: 720px) {
    .colunas, .colunas-3 { grid-template-columns: 1fr; }
}

/* ---------- Linha de permissão (cadastro de usuário) ---------- */
.linha-permissao {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    padding: 10px 0;
    border-bottom: 1px solid var(--creme);
}
.linha-permissao:last-child { border-bottom: none; }
.linha-permissao select { font-size: 0.87rem; padding: 7px 10px; }

.lista-funcoes { list-style: none; padding: 0; margin: 0; }
.lista-funcoes li {
    padding: 7px 0;
    border-bottom: 1px solid var(--creme);
    font-size: 0.9rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}
.lista-funcoes li:last-child { border-bottom: none; }

@media (max-width: 720px) {
    .linha-permissao { flex-direction: column; align-items: stretch; gap: 8px; }
}

/* ---------- Cabeçalho de tabela ordenável ---------- */
th a.ordenavel {
    color: inherit;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    white-space: nowrap;
}
th a.ordenavel:hover { color: var(--tinta); }
th a.ordenavel .seta { font-size: 0.68rem; color: var(--ambar); }
th a.ordenavel.ordenado { color: var(--tinta); }

.acoes-exportar { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

/* ---------- Logotipo ---------- */
.logo-topo {
    height: 52px;
    width: auto;
    display: block;
}
.topbar .marca, .topo .marca {
    display: inline-flex;
    align-items: center;
    gap: 12px;
}
/* Correção de 27/07/2026: o cabeçalho só mostrava a sigla "SGE" solta —
   quem não conhece o sistema não tem como saber o que ela significa. Agora
   é um "lockup" de duas linhas: a sigla em destaque (âmbar, como antes) e,
   abaixo, o nome por extenso em tamanho menor — sem ocupar mais espaço
   horizontal na barra, já que empilha verticalmente ao lado da logo.

   Ajuste no mesmo dia (pedido do Gerente de Engenharia): a sigla ficou
   maior/mais visível, e ganhou um ícone próprio — três barras em
   ascensão, uma referência simples e minimalista a "gestão"/indicadores
   (o mesmo motivo dos gráficos gerenciais do sistema), distinto do
   logotipo da Domínio Automação que já ocupa a barra. */
.marca-sistema {
    display: flex;
    align-items: center;
    gap: 10px;
    border-left: 1px solid #3A3A3A;
    padding-left: 14px;
    align-self: stretch;
}
.icone-sge {
    width: 30px;
    height: 30px;
    flex-shrink: 0;
    color: var(--ambar);
    fill: currentColor;
}
.marca-sistema-texto {
    font-family: var(--fonte-titulo);
    display: flex;
    flex-direction: column;
    justify-content: center;
    line-height: 1.2;
}
.marca-sistema strong {
    color: var(--ambar);
    font-weight: 700;
    font-size: 1.5rem;
    letter-spacing: 0.03em;
}
.marca-sistema small {
    color: var(--creme);
    opacity: 0.65;
    font-weight: 400;
    font-size: 0.76rem;
    letter-spacing: 0.02em;
    white-space: nowrap;
}
.logo-login {
    max-height: 82px;
    max-width: 300px;
    width: auto;
}

/* ---------------------------------------------------------------------------
   Apontamento de horas
   Reaproveita .cartao, .abas, .etiqueta e .tabela-envolucro já existentes —
   só acrescenta o que a grade semanal e a fila de aprovação exigiram.
   --------------------------------------------------------------------------- */

.acoes-cabecalho { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

.navegacao-periodo {
    display: flex;
    gap: 8px;
    align-items: center;
    flex-wrap: wrap;
    margin-bottom: 16px;
}

.cabecalho-cartao {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 10px;
}
/* Sem `text-transform: capitalize`: ele põe maiúscula em toda palavra, e
   escrevia "Segunda-Feira, 27/07" no cabeçalho do dia. Em português só a
   primeira letra sobe. Quem precisa disso usa o filtro `capfirst`, que sabe
   onde a frase começa; os demais cabeçalhos já vêm escritos como devem sair. */
.cabecalho-cartao h2 { font-size: 1rem; }
.cabecalho-cartao > div { display: flex; gap: 10px; align-items: center; }

/* O dia de hoje precisa saltar na grade da semana sem depender de cor de
   fundo escura — o projeto é fundo claro sempre. */
.cartao-destaque { border-left: 3px solid var(--ambar); }

/* Situação do lançamento e da fatia mensal. Tons dentro da paleta clara. */
.situacao { font-size: 0.78rem; padding: 2px 8px; border-radius: 999px; white-space: nowrap; }
.situacao-aprovado { background: #e6f4ea; color: #1e6b34; }
.situacao-pendente { background: #fdf3d8; color: #7a5900; }
.situacao-devolvido { background: #fce8e6; color: #b3261e; }
.situacao-fechado { background: var(--creme); color: var(--cinza); }

/* Explicação da conta no detalhe do apontamento. */
.conta-parcela { font-variant-numeric: tabular-nums; white-space: nowrap; }
.faixa-alerta {
    border-left: 3px solid #b3261e;
    background: #fce8e6;
    padding: 10px 14px;
    border-radius: var(--raio);
    margin-bottom: 16px;
}

/* A mesma faixa, em âmbar, quando o aviso é uma tarefa esperando alguém e não
   um erro. O vermelho é para o que está errado; um pedido de recuperação à
   espera do líder está apenas à espera. */
.faixa-alerta--acao {
    border-left-color: var(--ambar);
    background: var(--creme);
}

/* ---------------------------------------------------------------------------
   Ações da página inicial (rodada 69).

   A primeira versão era uma fileira de botões soltos: seis larguras
   diferentes, quebrando em fileiras irregulares, cada um do tamanho do próprio
   texto. O Gerente de Engenharia devolveu em 04/08/2026 — "totalmente
   despadronizado e feio" —, e ele tem razão: botão em fileira serve para duas
   ou três ações de um formulário, não para um menu de seis.

   **A segunda tentativa também voltou** (04/08/2026): eram cartões — padding
   grande, duas linhas de texto, fundo branco e borda fina —, e cartão não
   parece botão de ação, por mais alinhado que esteja. "Ainda não ficou bom.
   Não se parecem com botões de ações."

   A terceira não inventa componente nenhum: usa o `.botao` da casa, o mesmo de
   todas as outras telas, e resolve só o que estava errado de fato — a largura
   desigual. A grade dá a todos a mesma largura, o ícone dá leitura rápida, e a
   explicação que estava na segunda linha virou `title`.

   `auto-fit` com `minmax` resolve as quatro larguras sem nenhuma media query.
   E **sem `grid-column: span`** — foi ele que espremeu a grade da conferência
   na rodada 68 (defeito nº 9), porque um item de duas colunas obriga a grade a
   ter duas colunas mesmo onde não cabem duas.
   --------------------------------------------------------------------------- */
.acoes-inicio {
    display: grid;
    /* 190px é o menor valor que ainda cabe "Fechamento mensal" com o ícone
       sem quebrar. A 1280 dá cinco colunas, e a sexta ação cai numa segunda
       fileira — medido, e aceito: para as seis numa fileira só seria preciso
       160px por botão, e aí o rótulo mais longo estoura a borda. */
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 8px;
}
.acoes-inicio .botao { width: 100%; justify-content: center; }
/* O <form> do botão de repetir não pode virar uma célula vazia da grade. */
.acoes-inicio form { display: contents; }
.icone-acao { width: 17px; height: 17px; flex: 0 0 auto; }

/* ---------------------------------------------------------------------------
   Formulário de apontamento — cascata Cliente > Unidade > Projeto > Etapa >
   Atividade, em duas colunas, com a descrição em largura inteira.
   --------------------------------------------------------------------------- */

/* Escapa das 2 colunas do .colunas e ocupa a linha inteira. */
.campo-largura-total { grid-column: 1 / -1; }

/* A descrição vai para o RDO apresentado ao cliente: ganha a largura toda,
   caixa maior e um realce discreto, para não competir com os seletores. */
.campo-destaque {
    grid-column: 1 / -1;
    background: var(--creme);
    border-left: 3px solid var(--ambar);
    border-radius: var(--raio);
    padding: 14px 16px;
    margin-bottom: 18px;
}
.campo-destaque > label { font-size: 0.92rem; font-weight: 600; color: var(--tinta); }
.campo-destaque textarea { min-height: 110px; }

/* Nível ainda bloqueado: continua visível (a pessoa vê o caminho inteiro),
   mas indica que depende do campo acima. */
.cascata .nivel-travado > label { color: var(--cinza-claro); }
.cascata .nivel-travado select { background: var(--creme); cursor: not-allowed; }

/* Cliente cujos projetos não têm planta vinculada — trabalho interno. */
.cascata .nivel-nao-aplicavel > label::after {
    content: " — não se aplica";
    font-weight: 400;
    color: var(--cinza-claro);
}

.linha-checkbox {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-bottom: 14px;
}
.linha-checkbox label { margin: 0; font-size: 0.88rem; color: var(--tinta); }
.linha-checkbox .ajuda { flex-basis: 100%; margin: 0 0 0 24px; }

/* Calendário de salto rápido na grade semanal do apontamento. */
.ir-para-semana {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 0 auto;
}
.ir-para-semana label {
    font-size: 0.82rem;
    color: var(--cinza);
    white-space: nowrap;
}
.ir-para-semana .campo { width: auto; margin: 0; }

/* ---------------------------------------------------------------------------
   Ações em ícone (29/07/2026)
   Os botões de texto ("Editar", "Horas/nível", "Promover", "Mover/copiar")
   consumiam metade da largura das tabelas de atividade e de apontamento. Em
   ícone, a coluna de ações encolhe e sobra espaço para a informação principal.
   O `title` de cada botão dá a descrição ao passar o cursor; `aria-label`
   mantém a ação legível para leitor de tela.
   --------------------------------------------------------------------------- */

.acoes-icones {
    display: flex;
    gap: 2px;
    align-items: center;
    justify-content: flex-end;
    white-space: nowrap;
}
.acoes-icones form { display: inline; margin: 0; }

.botao-icone {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    padding: 0;
    border-radius: 6px;
    color: var(--cinza);
    background: none;
    border: none;
    cursor: pointer;
    text-decoration: none;
    line-height: 0;
    transition: background 0.12s, color 0.12s;
}
.botao-icone:hover,
.botao-icone:focus-visible {
    background: var(--ambar-claro);
    color: var(--tinta);
}
.botao-icone svg {
    width: 15px;
    height: 15px;
    display: block;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.7;
    stroke-linecap: round;
    stroke-linejoin: round;
}
/* Ação destrutiva: só ganha cor no hover, para não poluir a linha em repouso. */
.botao-icone--perigo:hover,
.botao-icone--perigo:focus-visible {
    background: var(--vermelho-fundo);
    color: var(--vermelho);
}
/* Aprovação, mesma lógica em verde — a cor aparece no hover, e o ícone em
   repouso continua neutro para a linha não virar um semáforo. */
.botao-icone--aprovar:hover,
.botao-icone--aprovar:focus-visible {
    background: var(--verde-fundo);
    color: var(--verde);
}

/* Coluna de ações em ícone: encolhe ao conteúdo. */
td.acoes-compactas, th.acoes-compactas {
    width: 1%;
    white-space: nowrap;
    text-align: right;
    padding-left: 4px;
}

/* Identificação em três linhas na grade semanal do apontamento. */
.identificacao-lancamento { line-height: 1.35; }
.identificacao-lancamento .linha-cliente { font-weight: 600; }
.identificacao-lancamento .linha-etapa,
.identificacao-lancamento .linha-atividade {
    font-size: 0.84rem;
    color: var(--cinza);
}

/* Campo preenchido pelo próprio sistema (ex.: horas calculadas do horário).
   Continua visível e copiável, mas indica que não é para digitar. */
.campo-calculado {
    background: var(--creme);
    color: var(--cinza);
    cursor: default;
}

/* ---------------------------------------------------------------------------
   Grade semanal do apontamento — revisão de 29/07/2026
   --------------------------------------------------------------------------- */

/* Quatro linhas de identificação, cada nível com peso próprio: o cliente
   ancora a leitura, o projeto vem logo abaixo, e etapa e atividade se
   distinguem entre si (a etapa é contexto; a atividade é o que foi feito). */
.identificacao-lancamento { line-height: 1.35; }
.identificacao-lancamento .linha-cliente {
    font-weight: 700;
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--tinta);
}
.identificacao-lancamento .linha-projeto {
    font-weight: 600;
    font-size: 0.9rem;
    color: var(--tinta);
}
.identificacao-lancamento .linha-etapa {
    font-size: 0.82rem;
    color: var(--cinza-claro);
    font-style: italic;
}
.identificacao-lancamento .linha-atividade {
    font-size: 0.85rem;
    color: var(--cinza);
    border-left: 2px solid var(--ambar);
    padding-left: 6px;
    margin-top: 2px;
}

/* Cartão que envolve uma tabela não tem recuo próprio — 02/09/2026.

   A tabela já traz o respiro dela nas células; o recuo do cartão só empurra a
   moldura para dentro e come largura útil justamente onde ela falta.

   ## Isto não é regra nova: é regra que já valia, escrita à mão

   Havia **24 cartões** com `style="padding:0"` no atributo, espalhados por 17
   gabaritos — e a varredura de 02/09 mostrou que **todos os 24 têm tabela
   dentro. Nenhum é exceção.** Não era preferência caso a caso: era uma regra
   de desenho repetida manualmente, sem lugar onde morar.

   ## Por que não era inofensivo

   Na tela inicial, dois cartões com tabela tinham o inline e um não, o que dava
   **294px de moldura contra 262px na mesma página**. E os 32px de diferença
   custam coluna, medido com o corpo cheio em 02/09:

     tabela de margem, 320px    3 de 4 colunas  ->  2 de 4  com o recuo
     primeira tabela, 412px     4 de 4 colunas  ->  3 de 4  com o recuo

   **A medida de transbordo não via isso**: nenhuma das duas opções transborda,
   porque a moldura rola. Foi a contagem de colunas que separou as duas — a
   régua de que *página que não transborda pode estar inútil*, registrada
   quando o Relatório de Horas passou verde mostrando 2 de 6 colunas.

   ## Por que no CSS, e não em mais um inline

   Um `style` no gabarito vence qualquer media query, e a casa gastou a manhã de
   02/09 tirando `min-width` inline dos `<th>` exatamente por isso. Acrescentar
   o 25º inline resolveria a tela e pioraria o padrão. Aqui a regra tem um
   lugar, e quem quiser um cartão com tabela E com recuo agora precisa dizer
   isso explicitamente — que é como deve ser.

   ## Sem o `>`, e isso foi medido antes de escrever

   A primeira versão desta regra usava `:has(> .tabela-envolucro)`, exigindo
   que a tabela fosse **filha direta**. A varredura desmentiu: em **12 dos 24**
   cartões há uma `<div>` no meio. A regra pegaria metade, e ninguém veria —
   nenhum desses cartões transborda, o total não se mexeria, e o defeito seria
   invisível. O descendente vale em qualquer profundidade, de propósito.

   *(A mesma versão citava uma classe `.tabela-envolucro-fixa` que **não existe
   no repositório** — inventada por mim ao escrever a regra, e removida assim
   que a busca não a encontrou em lugar nenhum.)* */
.cartao:has(.tabela-envolucro) { padding: 0; }

/* A coluna que carrega o NOME da linha — 01/09/2026.

   Projeto, Profissional, Relatório, Líder. Ela precisa de largura para o nome
   não virar uma coluna de duas letras por linha, e por isso ganhou um piso.

   ## Por que o piso saiu do gabarito

   Ele vivia no atributo `style` do `<th>`, e **atributo inline vence media
   query**: enquanto estivesse ali, nenhuma regra de celular alcançava. Numa
   moldura de 262–294px, 200px de piso é 68% a 76% da tabela inteira — e as
   quatro tabelas da tela inicial transbordavam por isso, medido em 01/09/2026
   com o corpo da tabela vazio, o que exclui o dado como causa.

   A casa já tinha registrado a armadilha em agosto, com estas palavras:
   *"`style` inline ganha de media query. Larguras escritas inline travavam
   colunas em 110–140px no celular, e nenhuma regra de CSS conseguia
   soltá-las."* Era o mesmo defeito, em outro lugar.

   ## Por que dois valores, e não um

   Eram 180px e 200px, escolhidos por alguém em algum momento. Unificá-los
   mexeria no computador, que hoje não transborda em largura nenhuma — e
   trocar um número medido por um número redondo é o tipo de conserto que esta
   casa não faz. Os dois foram preservados como estavam. */
.tabela-envolucro th.coluna-nome { min-width: 200px; }
.tabela-envolucro th.coluna-nome-estreita { min-width: 180px; }
/* 280px, na tela de permissões por perfil. Ela **não está no roteiro da
   conferência visual**, então este piso nunca foi medido em largura nenhuma —
   veio junto para a trava do `min-width` inline não nascer com exceção. */
.tabela-envolucro th.coluna-nome-larga { min-width: 280px; }

/* Seleção múltipla para copiar lançamentos. */
td.coluna-selecao, th.coluna-selecao {
    width: 1%;
    padding-right: 0;
    text-align: center;
}

/* Ações da seleção, no cabeçalho do próprio dia (revisão de 29/07/2026):
   antes ficavam numa barra fixa no rodapé, longe do dia a que se referiam. */
.acoes-do-dia { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.acoes-selecao {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    background: var(--ambar-claro);
    border-radius: var(--raio);
    padding: 6px 10px;
}
.acoes-selecao label { font-size: 0.82rem; color: var(--cinza); white-space: nowrap; }
.acoes-selecao .campo { width: auto; margin: 0 0 0 6px; }
/* O painel da seleção já é âmbar; sem fundo próprio, o hover do ícone
   (também âmbar) sumiria dentro dele. */
.acoes-selecao .botao-icone { background: var(--branco); border: 1px solid var(--borda); }
/* Sem nada marcado, as duas ações continuam visíveis mas inertes — some o
   cursor de clique e o hover, para o botão parecer o que é. */
.acoes-selecao .botao-icone[disabled] {
    opacity: 0.45;
    cursor: not-allowed;
}
.acoes-selecao .botao-icone[disabled]:hover {
    background: var(--branco);
    color: var(--cinza);
}
.contagem-selecao { font-size: 0.84rem; color: var(--cinza); white-space: nowrap; }

/* Alternador entre a visualização do dia e a da semana. */
.alternador-visao {
    display: inline-flex;
    border: 1px solid var(--borda);
    border-radius: var(--raio);
    overflow: hidden;
    background: var(--branco);
}
.alternador-visao a {
    padding: 6px 14px;
    font-size: 0.85rem;
    text-decoration: none;
    color: var(--cinza);
}
.alternador-visao a:hover { background: var(--creme); }
.alternador-visao a.ativo {
    background: var(--ambar);
    color: var(--tinta);
    font-weight: 600;
}

/* Conflito de horário: sinaliza, não bloqueia. */
.etiqueta-conflito {
    background: var(--vermelho-fundo);
    color: var(--vermelho);
    border-color: var(--vermelho-fundo);
}
.linha-conflito { background: #FEF7F6; }
.aviso-conflito {
    font-size: 0.76rem;
    color: var(--vermelho);
    font-weight: 600;
    white-space: nowrap;
    cursor: help;
}

/* Extrato do mês: matriz dia × projeto. O dia útil em branco é o que se
   procura ao conferir o mês, então ele é quem ganha destaque — o fim de
   semana vazio é normal e fica discreto. */
.extrato-mes th .linha-cliente { font-size: 0.72rem; }
.extrato-mes th .linha-projeto { font-size: 0.8rem; font-weight: 600; }
.extrato-mes .dia-nao-util { color: var(--cinza-claro); background: var(--creme); }
.extrato-mes .dia-em-branco { background: #FEF7F6; }
.extrato-mes .dia-em-branco td:first-child { font-weight: 600; color: var(--vermelho); }

/* Extrato do mês: os projetos do dia ficam empilhados dentro da linha, um por
   quebra (revisão de 30/07/2026 — a matriz de uma coluna por projeto passava
   da largura da tela). As três colunas empilhadas usam a mesma altura de
   linha e o mesmo espaçamento, para cliente, projeto e horas do mesmo item
   ficarem na mesma altura entre si. */
.extrato-mes .item-do-dia {
    line-height: 1.5;
    min-height: 1.5em;
    padding: 5px 0;
}
/* Um filete separa um lançamento do outro dentro do mesmo dia: sem ele, três
   projetos empilhados viravam um bloco de texto em que não se sabia qual hora
   pertencia a qual projeto (pedido do Gerente de Engenharia, 30/07/2026). Como
   as três colunas têm o mesmo número de itens e o mesmo espaçamento, o filete
   atravessa a linha inteira. O último item não recebe filete — quem separa uma
   linha do dia da seguinte é a borda da própria <tr>. */
.extrato-mes .item-do-dia:not(:last-child) {
    border-bottom: 1px dashed var(--borda);
}
.extrato-mes .item-do-dia:first-child { padding-top: 0; }
.extrato-mes .item-do-dia:last-child { padding-bottom: 0; }
.extrato-mes .linha-cliente { color: var(--cinza); }

/* Colunas empilhadas alinham pelo topo; as que têm um valor só — o dia e o
   total do dia — ficam centradas na altura da linha, para não parecerem
   pertencer ao primeiro projeto da pilha. */
.extrato-mes .celula-empilhada { vertical-align: top; }
.extrato-mes .celula-do-dia { vertical-align: middle; }

/* NÃO HÁ MAIS COLUNA DE SELEÇÃO — 27/08/2026. Ela existiu de 22 a 27/08/2026 e
   tinha regras aqui, para a caixa empilhada bater com a altura do lançamento
   que ela marcava. A caixa desceu para a linha expandida (ver mais abaixo,
   "A caixa do lançamento"), e a coluna deixou de existir junto com elas. */

/* Extrato por dia, terceiro nível (25/08/2026): dentro de cada item empilhado
   — um projeto × pessoa do dia — vem uma sub-linha por apontamento, com as
   horas daquele lançamento e a atividade escolhida nele.

   `line-height` e `min-height` REPETEM os de `.item-do-dia`, e isso é o que
   segura o alinhamento entre as colunas: elas emitem todas o mesmo número de
   sub-linhas, e só com a mesma altura de linha a hora de um apontamento fica
   na altura do projeto a que ela pertence. Com um lançamento só — o caso
   comum — a sub-linha ocupa exatamente a altura que o item ocupava antes, e a
   tabela sai como sempre saiu. */
.extrato-mes .sub-linha-apontamento {
    line-height: 1.5;
    min-height: 1.5em;
}

/* O botão que abre as descrições do dia. Discreto de propósito: ele fica ao
   lado da data, na coluna mais estreita da tabela, e quem vem conferir horas
   não deve tropeçar nele. */
.extrato-mes .abrir-descricoes {
    background: none;
    border: 1px solid var(--borda);
    border-radius: 3px;
    color: var(--cinza);
    cursor: pointer;
    font-size: 0.75rem;
    line-height: 1;
    padding: 1px 5px;
    margin-left: 4px;
}
.extrato-mes .abrir-descricoes:hover { color: var(--tinta); border-color: var(--cinza); }

/* A linha das descrições, recolhida por padrão (decisão do Gerente de
   Engenharia, 25/08/2026). Ocupa a largura toda porque `Apontamento.descricao`
   não tem limite de tamanho — em coluna ela disputaria o espaço horizontal,
   que é o que falta em 320px. O fundo levemente distinto diz que ela pertence
   à linha de cima, e não é um dia novo. */
.extrato-mes .linha-descricoes[hidden] { display: none; }
.extrato-mes .linha-descricoes > td {
    background: var(--creme);
    padding: 8px 10px;
}
/* A CAIXA DO LANÇAMENTO, à frente da linha dele — 27/08/2026.

   O bloco de um lançamento passou a ser uma faixa horizontal: a caixa na
   frente, o texto do lado. `align-items: flex-start` põe a caixa na altura da
   PRIMEIRA linha do bloco e não no meio dele — uma descrição de cinco linhas
   centraria a caixa no meio do parágrafo, longe do que ela marca.

   `min-width: 0` no corpo não é enfeite: um item de flex tem `min-width: auto`
   por padrão, e uma descrição sem espaços — um caminho de arquivo, um nome de
   equipamento longo — empurraria a célula além da largura da tabela em vez de
   quebrar. É transbordo em 320px, que é a medida que esta casa conta. */
.extrato-mes .descricao-do-apontamento {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 4px 0;
    line-height: 1.45;
}
.extrato-mes .descricao-do-apontamento:not(:last-child) {
    border-bottom: 1px dashed var(--borda);
}
.extrato-mes .caixa-do-lancamento {
    flex: 0 0 auto;
    /* A margem que o navegador dá à caixa sairia por cima do filete tracejado
       do bloco anterior; os 2px de topo a descem até a linha de contexto, que
       é menor que o resto do texto (0.72rem). */
    margin: 2px 0 0;
}
.extrato-mes .corpo-da-descricao {
    flex: 1 1 auto;
    min-width: 0;
}
.extrato-mes .origem-da-descricao {
    display: block;
    color: var(--cinza);
    font-size: 0.72rem;
}
/* Duração e atividade abrem a linha da descrição, nesta ordem (decisão do
   Gerente de Engenharia, 27/08/2026; a ordem é a que ele fixou para o PDF em
   26/08/2026). A duração não quebra: "6:00" partido em duas linhas deixaria de
   ser uma duração. */
.extrato-mes .duracao-do-lancamento {
    font-weight: 600;
    white-space: nowrap;
}
.extrato-mes .atividade-do-lancamento { color: var(--cinza); }

/* A caixa do COBRÁVEL — 27/08/2026, decisão do Gerente de Engenharia.

   Ela flutua à direita do corpo da descrição, e não entra na linha de contexto
   nem na do texto: as duas já são compridas, e um controle no meio delas seria
   lido como mais um pedaço da frase. Flutuando, o parágrafo da descrição corre
   por baixo dela e nada é empurrado para uma linha nova em 320px — que é a
   largura em que este bloco aperta primeiro.

   `nowrap` porque "Cobrável" partido em duas linhas ao lado de uma caixa deixa
   de parecer o rótulo dela. Ela NÃO é `coluna-secundaria`: some no celular
   seria esconder o único jeito de marcar, e a decisão do Gerente é que quem vê
   a tela marca. */
.extrato-mes .marca-cobravel {
    float: right;
    margin-left: 10px;
    white-space: nowrap;
    font-size: 0.72rem;
    cursor: pointer;
}
.extrato-mes .marca-cobravel input {
    margin: 0 4px 0 0;
    vertical-align: middle;
}
/* O aviso de que a gravação não passou — nasce escondido e o script o acende.
   O texto mora no HTML, e não no script: texto que o JavaScript escreve sai do
   catálogo de tradução sem nada acusar, e o sistema fala quatro idiomas. */
.aviso-cobravel {
    margin: 6px 0 0;
    color: var(--vermelho);
}

/* A coluna que o seletor escondeu — 25/08/2026.

   O `hidden` é o do próprio HTML, e a folha do navegador já o faz sumir. Esta
   regra existe porque `display` numa célula de tabela é `table-cell`, e
   qualquer regra de autor com a mesma especificidade — `.extrato-mes
   .celula-empilhada`, logo acima — passaria na frente por ser mais tarde no
   arquivo. Ela vem depois delas de propósito.

   Serve ao `<th>` e ao `<td>` das três partes da tabela: cabeçalho, corpo e
   rodapé escondem juntos, ou a tabela desalinha. */
.extrato-mes [data-coluna][hidden] { display: none; }

/* O seletor de colunas do Extrato por dia — 25/08/2026.

   O componente inteiro é o `selecao-multipla` dos filtros; o que muda é de que
   lado o painel abre. Lá ele nasce num campo largo de uma grade, com `left: 0;
   right: 0`; aqui o controle é estreito e encostado na borda direita do
   cartão, e o painel de 240px sairia da página pela direita. Ancorado à
   direita, ele cresce para dentro. */
.seletor-colunas { min-width: 0; }
.seletor-colunas > .selecao-opcoes { left: auto; right: 0; }

/* O SELETOR VIROU ÍCONE — decisão (7) do Gerente de Engenharia, 26/08/2026.

   O `<details>`/`<summary>` continua sendo o que abre o painel sem JavaScript;
   o que muda é a aparência do `summary`, que passa a ser a do `.botao-icone`
   da casa (29/07/2026). Estas regras DESFAZEM as de `.selecao-multipla >
   summary` — a moldura, o padding de campo e a seta —, e por isso vêm depois
   dela no arquivo. A seta some porque um botão de 26px com seta ao lado do
   ícone tem duas pistas visuais para uma ação só.

   A largura mínima de 170px sai junto: ela existia para o rótulo em duas
   linhas caber, e não há mais rótulo. */
.seletor-colunas > summary {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    width: auto;
    min-height: 26px;
    padding: 0 4px;
    background: none;
    border: none;
    border-radius: 6px;
    line-height: 0;
    color: var(--cinza);
}
.seletor-colunas > summary::after { content: none; }
.seletor-colunas > summary:hover,
.seletor-colunas > summary:focus-visible {
    background: var(--ambar-claro);
    border-color: transparent;
    color: var(--tinta);
}

/* O contador de colunas escondidas (27/08/2026, decisão do Gerente Técnico).
   Com o rótulo em ícone, "3 escondidas" saiu da vista; este número devolve o
   aviso sem devolver a largura. Ele nasce `hidden` e o script o esconde de
   volta quando não há coluna escondida — ausência de marca é o estado normal.

   `tabular-nums` para o botão não mudar de largura entre "1" e "8", que numa
   barra de cabeçalho faz o título ao lado tremer. */
.contador-colunas {
    display: inline-block;
    min-width: 15px;
    padding: 0 4px;
    border-radius: 999px;
    background: var(--ambar);
    color: var(--tinta);
    font-size: 0.66rem;
    font-weight: 700;
    line-height: 15px;
    text-align: center;
    font-variant-numeric: tabular-nums;
}
.contador-colunas[hidden] { display: none; }

/* Filtros do relatório de horas: uma faixa que quebra sozinha, para caber
   oito campos sem virar oito linhas numa tela larga. */
.filtros-relatorio {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 10px 14px;
}
.filtros-relatorio .linha { margin: 0; }

/* Filtros dos relatórios: listas suspensas com marcação múltipla.
   A primeira versão usava <select multiple>, que ocupava meia tela e exigia
   segurar Ctrl para marcar mais de um. O Gerente de Engenharia pediu, em
   30/07/2026, um seletor suspenso — feito com <details>, que dá abrir/fechar
   nativamente, sem JavaScript, e caixas de marcação por dentro. */
.filtros-multiplos {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: 12px 14px;
    margin-top: 12px;
}

.selecao-multipla { position: relative; }
.selecao-multipla > summary {
    list-style: none;
    cursor: pointer;
    background: var(--branco);
    border: 1px solid var(--borda);
    border-radius: var(--raio);
    padding: 7px 26px 7px 10px;
    display: block;
}
.selecao-multipla > summary::-webkit-details-marker { display: none; }
/* Seta do lado direito, girando ao abrir — a mesma pista visual de um <select>. */
.selecao-multipla > summary::after {
    content: "";
    position: absolute;
    right: 10px;
    top: 50%;
    margin-top: -2px;
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    border-top: 5px solid var(--cinza);
}
.selecao-multipla[open] > summary::after { transform: rotate(180deg); }
.selecao-multipla > summary:hover { border-color: var(--ambar-escuro); }

.selecao-rotulo {
    display: block;
    font-size: 0.74rem;
    color: var(--cinza);
    line-height: 1.2;
}
.selecao-resumo {
    display: block;
    font-size: 0.9rem;
    color: var(--tinta);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* A lista flutua sobre o conteúdo, como um menu — assim abrir um filtro não
   empurra os outros quatro para baixo. */
.selecao-opcoes {
    position: absolute;
    z-index: 15;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    min-width: 240px;
    max-height: 260px;
    /* Cobre por inteiro o campo que estiver logo abaixo — 22/08/2026.

       Com uma opção só (ou nenhuma, quando o período não tem lançamentos) o
       painel ficava com 41px e terminava NO MEIO do texto do campo de baixo:
       "Todo o time" aparecia cortado ao meio pela borda, e isso se lê como
       defeito de desenho, não como um menu por cima de um campo.

       A conta é a geometria da grade, não um número escolhido: o painel abre
       em `100% + 4px`, a linha seguinte começa em `100% + 12px` (o `gap` de
       `.filtros-multiplos`) e o campo de lá tem a mesma altura deste — 100%.
       Para alcançar o fim dele: (12 + 100%) - 4 = 100% + 8px.

       Medido: campo de 51,4px, painel mínimo de 59,4px, campo de baixo
       terminando em 59,0px a partir do topo do painel. */
    min-height: calc(100% + 8px);
    overflow-y: auto;
    background: var(--branco);
    border: 1px solid var(--borda);
    border-radius: var(--raio);
    box-shadow: 0 8px 22px rgba(0, 0, 0, 0.14);
    padding: 4px;
}
.selecao-opcao {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 6px 8px;
    border-radius: 6px;
    font-size: 0.86rem;
    cursor: pointer;
}
.selecao-opcao:hover { background: var(--ambar-claro); }
.selecao-opcao input { margin: 3px 0 0; }
.selecao-opcao[hidden] { display: none; }
/* ---------------------------------------------------------------------------
   Composição do RDO (30/07/2026)
   --------------------------------------------------------------------------- */

/* O marcador do dia inteiro fica colado ao nome do dia, e não numa coluna
   solta: quem monta o relatório pensa "quero esta terça", não "quero marcar
   estas seis caixas". */
.marcar-dia-rdo {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    margin: 0;
}
.marcar-dia-rdo input { margin: 0; }

/* Fim de semana fica discreto: estar vazio é o comportamento normal dele —
   mesma leitura já adotada no Extrato do Mês. */
.cartao-fim-de-semana { background: var(--creme); }

/* Um relatório cobre um cliente só. O lançamento de outro cliente não some
   da lista — some seria confuso, porque a pessoa acabou de vê-lo ali —, mas
   fica visivelmente indisponível enquanto houver seleção. */
.linha-indisponivel { opacity: 0.4; }
.linha-indisponivel input { cursor: not-allowed; }

/* Calendário do mês na grade de apontamento (30/07/2026): a terceira visão,
   ao lado de dia e semana. Mostra só o total de horas de cada dia — o detalhe
   fica a um clique, na visão do dia. */
.calendario-mes {
    width: 100%;
    border-collapse: separate;
    border-spacing: 6px;
    table-layout: fixed;
}
.calendario-mes th {
    text-align: center;
    font-size: 0.76rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--cinza);
    padding: 0 0 2px;
    border: none;
    background: none;
}
.calendario-mes td {
    padding: 0;
    border: 1px solid var(--borda);
    border-radius: var(--raio);
    background: var(--branco);
    vertical-align: top;
}
/* A célula inteira é o alvo do clique, e não só o número: num calendário, a
   área do dia é o que a pessoa mira. */
.celula-calendario {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    min-height: 74px;
    padding: 7px 9px;
    text-decoration: none;
    color: var(--tinta);
    border-radius: var(--raio);
}
.celula-calendario:hover { background: var(--ambar-claro); }
.numero-do-dia {
    font-size: 0.84rem;
    color: var(--cinza);
    display: flex;
    align-items: center;
    gap: 6px;
}
.horas-do-dia {
    font-family: var(--fonte-titulo);
    font-weight: 600;
    font-size: 1.05rem;
    text-align: right;
}
.calendario-mes .fora-do-mes { background: transparent; border-color: transparent; }
.calendario-mes .fora-do-mes .celula-calendario { opacity: 0.35; }
.calendario-mes .dia-nao-util { background: var(--creme); }
.calendario-mes .dia-de-hoje { border-color: var(--ambar); border-width: 2px; }
.calendario-mes .dia-em-branco { background: var(--vermelho-fundo); }

/* A coluna do número da semana no calendário mensal (31/07/2026).

   Ela não é um dia: é a etiqueta da linha. Por isso a célula perde caixa e
   borda — uma moldura ao lado de sete molduras iguais vira o oitavo dia da
   semana, que foi o que aconteceu na primeira versão. O número sai numa marca
   âmbar, a cor de destaque da casa, que o separa da grade sem competir com os
   totais do dia. */
.calendario-mes .coluna-semana {
    width: 3.4rem;
    padding: 0 10px 0 0;
    text-align: center;
    vertical-align: middle;
    border: none;
    background: transparent;
}
/* O realce de linha das tabelas (`tbody tr:hover`) não faz sentido aqui: no
   calendário o alvo é o dia, e cada dia já tem o seu próprio realce. Como as
   células do dia têm fundo próprio, o realce da linha só aparecia atrás da
   coluna da semana — um retângulo creme que acendia sem querer dizer nada. */
.calendario-mes tbody tr:hover { background: transparent; }

.calendario-mes thead .coluna-semana {
    font-size: 0.62rem;
    letter-spacing: 0.08em;
    color: var(--cinza-claro);
}
.marca-semana {
    display: inline-block;
    min-width: 2.1rem;
    padding: 3px 7px;
    border-radius: 999px;
    background: var(--ambar-claro);
    border: 1px solid var(--ambar);
    font-family: var(--fonte-titulo);
    font-weight: 600;
    font-size: 0.82rem;
    color: var(--cinza);
    font-variant-numeric: tabular-nums;
}

/* O período exibido na grade de Apontamentos (31/07/2026). A semana e as datas
   são a primeira pergunta de quem abre a tela — "que semana é esta?" — e viviam
   como texto secundário, do mesmo tamanho de qualquer legenda. Passam a linha
   própria, com a semana na mesma marca âmbar usada no calendário. */
.faixa-periodo {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
    margin: 6px 0 0;
}
.marca-semana--titulo {
    font-size: 0.95rem;
    padding: 4px 12px;
    color: var(--tinta);
}
.periodo-datas {
    font-family: var(--fonte-titulo);
    font-weight: 600;
    font-size: 1.02rem;
    color: var(--tinta);
}
.periodo-total {
    font-size: 0.86rem;
    color: var(--cinza-claro);
}

/* Ações de confirmar em ícone (31/07/2026): emitir, validar e liberar a
   recuperação. Como no fechamento da equipe (§56.1), a cor só aparece no
   hover — a coluna de ações não fica colorida em repouso. */
.botao-icone--confirmar:hover { color: var(--verde); border-color: var(--verde); }
.botao-icone--recuperar:hover { color: var(--cinza); }

/* Seletor de profissional das grades de apontamento (31/07/2026). Uma linha
   só, com o rótulo ao lado do campo: é um recorte da tela, não um formulário
   de filtro com vários critérios. */
.seletor-profissional {
    display: flex;
    align-items: center;
    gap: 10px;
}
.seletor-profissional label {
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--cinza);
    margin: 0;
}
.seletor-profissional .campo { max-width: 22rem; }

/* Conferência da importação da planilha de campo — rodada 68.

   A mensagem de pendência de uma linha é uma frase inteira ("A atividade X
   não está no escopo do projeto Y"), e não um rótulo: precisa quebrar linha.
   Reaproveitar `.aviso-conflito`, que é `white-space: nowrap`, empurraria a
   tabela para fora da tela no celular — que é exatamente o defeito que a
   rodada 67 passou a rodada inteira caçando. */
tr.linha-pendente > td { background: #FEF7F6; }
/* O projeto do SGE selecionado na conciliacao com o Zoho -- 28/09/2026,
   decisao 54 ("clicar num projeto do SGE o destaca"). A marca e' o
   `aria-current="true"` que o gabarito ja' escreve para o leitor de tela;
   o fundo vem daqui, e nao de uma classe a mais. */
tr[aria-current="true"] > td { background: var(--ambar-claro); }
div.linha-pendente {
    background: #FEF7F6;
    border-radius: 8px;
    padding-left: 12px;
    padding-right: 12px;
    margin: 4px -12px;
}
.mensagem-pendencia {
    font-size: 0.78rem;
    color: var(--vermelho);
    margin: 4px 0 0;
}
.mensagem-pendencia[hidden] { display: none; }
.mensagem-observacao {
    font-size: 0.78rem;
    color: var(--cinza);
    margin: 4px 0 0;
}
.celula-numero { text-align: right; font-variant-numeric: tabular-nums; }

/* "Quando" reúne dia, horário e a origem no arquivo numa coluna só: com as
   três separadas a tabela media 787px numa tela de 320 e quebrava no meio da
   palavra. Encontrado olhando a tela, não pela varredura — que deu a página
   como limpa, porque o vazamento ficava dentro do envolucro rolável. */
.quando-horas { font-variant-numeric: tabular-nums; font-weight: 600; }
.quando-origem { font-size: 0.74rem; color: var(--cinza); }

/* A conferência virou editável em 03/08/2026, e com isso deixou de ser uma
   tabela: sete campos por linha numa tabela dariam a mesma tela de 787px que a
   varredura aprovava e ninguém lia no telefone. Cada linha é um bloco, e os
   campos se acomodam em grade — que quebra sozinha na largura que couber, sem
   rolagem lateral nenhuma. */
.conferencia-todas {
    padding-bottom: 12px;
    margin-bottom: 4px;
    border-bottom: 1px solid var(--borda);
}
.linha-conferencia {
    padding: 14px 0;
    border-top: 1px solid var(--borda);
}
.linha-conferencia:first-of-type { border-top: 0; padding-top: 0; }
.conferencia-marca {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 8px;
}
.marca-linha {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin: 0;
    cursor: pointer;
}
.marca-linha input { margin: 0; }
/* `align-items: start` e não `end`: a mensagem de pendência mora dentro da
   célula do campo a que se refere, e uma célula mais alta com alinhamento ao
   fim empurra as vizinhas para baixo — na captura de 03/08/2026 o campo INÍCIO
   com mensagem ficava acima do campo DIA, na mesma linha. Encontrado olhando a
   tela em 1280px; a varredura dá esta grade como limpa nos dois casos, porque
   nada vaza para fora: só fica torto por dentro. */
.conferencia-campos {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 10px 14px;
    align-items: start;
}
.campo-conferencia { min-width: 0; }
.campo-conferencia > label {
    display: block;
    font-size: 0.74rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--cinza);
    margin-bottom: 3px;
}
.campo-conferencia .campo { width: 100%; }
/* Projeto, etapa e atividade têm grade própria, com coluna mínima maior: o
   nome inteiro é o que permite escolher certo, e em 150px ele sai cortado.

   A primeira tentativa foi `grid-column: span 2` nos três. Não serve: um item
   que ocupa duas colunas **obriga a grade a ter duas colunas** mesmo quando
   não cabem duas — num celular de 360px a grade virava 150px + 114px e
   espremia todos os campos, inclusive os que pedem a largura inteira.
   Encontrado medindo a largura real do campo de descrição, não olhando o CSS.

   Uma grade própria resolve sem depender de um ponto de quebra em pixels, que
   ficaria amarrado por fora ao tamanho mínimo da coluna de cima. */
.conferencia-onde {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 10px 14px;
}
.campo-descricao { grid-column: 1 / -1; }
.campo-marcacao { grid-column: 1 / -1; }

/* O campo de horas só vale sem horário — com início e fim preenchidos, quem
   calcula é o servidor. O script o deixa em somente leitura, como já faz a
   tela de lançamento (§45.11): um campo que aceita digitação e ignora o que
   foi digitado é pior do que um campo travado. */
.campo-conferencia .campo[readonly] {
    background: var(--creme);
    color: var(--cinza);
}
.celula-mensagens { padding-top: 0; border-top: 0; }
.celula-mensagens .mensagem-pendencia:first-child,
.celula-mensagens .mensagem-observacao:first-child { margin-top: 0; }
.total-conferencia {
    margin: 12px 0 0;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

/* ---------- Aviso da troca para Contrato (rodada 79, 13/08/2026) ----------
   Aparece embaixo do Valor Negociado quando o Gerente marca como Contrato um
   projeto que já tem valor digitado. Mesma família visual do `.aviso-porta`,
   em versão de campo: ele mora dentro de um formulário, não no topo da tela.

   Empilhado, e não lado a lado: em 320px um botão ao lado de duas linhas de
   texto ou estoura a largura ou espreme o texto a três palavras por linha. */
/* O atributo `hidden` do HTML esconde por uma regra do proprio navegador
   (`[hidden] { display: none }`), e QUALQUER display escrito aqui vence essa
   regra por especificidade. Sem a linha abaixo a caixa fica visivel e vazia em
   todo projeto — foi assim que ela apareceu na conferencia visual de
   13/08/2026, ja em producao. Vale para qualquer classe que combine `display`
   com o atributo `hidden`; ha teste travando isso em apps/core/test_css_ocultos.py. */
.aviso-troca[hidden] { display: none; }

.aviso-troca {
    background: var(--ambar-fundo, #FFF8E6);
    border: 1px solid var(--ambar);
    color: #6B4E00;
    padding: 10px 12px;
    border-radius: 8px;
    margin-top: 8px;
    font-size: 0.82rem;
    line-height: 1.45;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
}
.aviso-troca .botao {
    font-size: 0.78rem;
    padding: 6px 12px;
    /* Alvo de toque confortável no celular sem inchar o aviso no desktop. */
    min-height: 36px;
}

/* A nota que diz de onde veio o numero do indicador. Discreta de proposito:
   ela explica, nao compete com o valor (rodada 79, 13/08/2026). */
.indicador .indicador-nota {
    font-size: 0.74rem;
    line-height: 1.35;
    color: var(--cinza-claro, #6B6B6B);
    margin-top: 6px;
}

/* ---------------------------------------------------------------------------
   Saldo do pacote — rodada 82 (14/08/2026)

   Duas cores para os dois níveis da decisão 8: âmbar ao cruzar o limiar
   configurado no projeto, vermelho ao passar do contratado. Nenhum dos dois
   trava coisa alguma — são estados de tela, e é assim de propósito.

   Só cor e peso, sem `display` nem caixa: são `<strong>` dentro de um
   parágrafo que já existe. Isso também evita a armadilha que a conferência
   visual da rodada 79 pegou, em que um `display` na folha da casa desligou o
   atributo `hidden` do navegador sem erro nenhum.

   Entra ANTES da seção de celular, pela regra da rodada 67: regra escrita
   depois dela vence por ordem e desliga o celular em silêncio.
   --------------------------------------------------------------------------- */
.saldo-atencao {
    /* Âmbar escurecido de propósito, e NÃO `--ambar-escuro` da paleta: aquele
       é #E6B53C, que sobre branco dá ~1,9:1 de contraste. Serve para marcador
       decorativo; não serve para a palavra que avisa que o pacote está
       acabando. Este tom dá ~6:1 e lê bem em 320px, que é onde a tela aperta. */
    color: #8A6D00;
    font-weight: 700;
}
.saldo-estouro {
    color: var(--vermelho);
    font-weight: 700;
}

/* As colunas de número do Relatório de Diárias — rodada 84, 18/08/2026.

   As larguras moravam em `style="width:110px"` dentro do HTML, e atributo
   inline vence folha de estilo: o bloco de celular não conseguia encolhê-las,
   e a coluna Valor ficava fora da tela em 320px mesmo depois de esconder duas
   outras. Vieram para cá para poderem ser relaxadas lá embaixo.

   Entra ANTES da seção de celular, pela regra da rodada 67. */
.coluna-numero { width: 110px; }

/* Cabeçalho de tabela congelado — 20/08/2026.

   Pedido do Gerente de Engenharia: a linha de título do "Extrato por dia" dos
   relatórios de Horas e de Diárias tem de continuar visível enquanto a PÁGINA
   rola. Só as tabelas que levarem a classe abaixo mudam de comportamento.

   A armadilha, medida antes de isto ser escrito: `.tabela-envolucro` declara
   `overflow-x: auto`, e pela regra do CSS o `overflow-y: visible` ao lado dele
   passa a valer `auto`. O envólucro é contêiner de rolagem nos DOIS eixos, e um
   `position: sticky` dentro dele grudaria no envólucro — que nunca rola
   verticalmente, porque não tem altura máxima. O cabeçalho não pareceria
   congelado: ele subiria com a página, exatamente como antes.

   Por isso o envólucro precisa parar de recortar. E só pode parar onde a tabela
   cabe sem ele: sem o recorte, numa largura estreita ela empurraria a PÁGINA
   para o lado — e transbordo de página é o defeito que a rodada 67 passou
   inteira caçando.

   O ponto de quebra é medido, não estimado. Em 20/08/2026 a conferência visual
   rodada em 320/360/412/768/900/1280 mostrou que abaixo de 949px a página já
   transborda por conta própria, em TODAS as telas do sistema — defeito
   anterior a esta mudança e registrado à parte. 1000px fica acima dessa faixa
   e acima da largura que as duas tabelas de extrato pedem.

   O `z-index` fica abaixo dos 30 da barra, para o cabeçalho deslizar POR
   BAIXO dela e não por cima.

   ## `top: 0`, e não `--altura-topo` — corrigido em 22/08/2026

   Até aqui o cabeçalho grudava em `var(--altura-topo)`, reservando os 82px da
   barra. Parecia certo e não era: **a barra é `sticky`, não `fixed`** — ela
   rola para fora da tela junto com o resto.

   Medido no estado rolado, que é o único em que o defeito existe:

       barra:               top -955, bottom -873   (fora da tela)
       cabeçalho congelado: top   82, bottom  126   (grudado em 82)

   Ou seja: o cabeçalho reservava espaço para uma barra que já não estava lá,
   e naquela faixa de 82px não havia nada. As linhas do corpo passavam por
   ela, aparecendo ACIMA do cabeçalho — foi o que o Gerente de Engenharia viu
   e relatou.

   Com `top: 0` o cabeçalho gruda no alto da janela. Enquanto a barra ainda
   está visível ela o cobre, porque tem `z-index` maior; quando a barra sai,
   o cabeçalho ocupa o lugar dela em vez de deixar um buraco.

   Fica ANTES da seção "Interface no celular", pela regra da rodada 67. */
@media (min-width: 1000px) {
    .tabela-envolucro--congelar { overflow: visible; }
    .tabela-envolucro--congelar thead th {
        position: sticky;
        top: 0;
        z-index: 5;
    }
}

/* ===========================================================================
   Interface no celular — rodada 67 (decisão do Gerente de Engenharia em
   02/08/2026)

   ESTA SEÇÃO PRECISA SER A ÚLTIMA DO ARQUIVO. Motivo, medido nesta rodada:
   o bloco @media de celular ficava no meio do arquivo e mandava
   `.marca-sistema { display: none }` e `.logo-topo { height: 38px }`. Só que
   as regras do lockup da marca (27/07/2026) foram escritas DEPOIS, com a
   mesma especificidade — e em CSS, empatada a especificidade, a última
   vence. O bloco de celular estava ativo e ignorado ao mesmo tempo.

   O estrago: a marca ocupava 380px numa tela de 360, empurrando o menu
   inteiro para fora. O documento ficava com 752px de largura em TODAS as
   telas (medido a 360x800: Início, Extrato, Projetos, Clientes, Usuários —
   todas 752, e todas 360 ao neutralizar só o <nav>). Pior: os botões
   transbordavam para fora do fundo escuro da barra e ficavam creme sobre
   creme — invisíveis, embora clicáveis. E o submenu "Cadastros" abria em
   x=704, mais de 340px além da borda da tela.

   `apps/core/test_css_celular.py` trava a volta: ele falha se qualquer
   regra escrita depois desta seção redeclarar uma propriedade que ela
   define. Não confie na memória de quem editar o arquivo daqui a seis meses.
   =========================================================================== */

/* O rótulo "Meu perfil" ao lado do nome só aparece no celular: no
   computador quem explica o link é o `title`, e tooltip não existe em tela
   de toque. */
.rotulo-perfil { display: none; }

/* Botão de abrir o menu: só existe no celular. */
.abre-menu {
    display: none;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    flex-shrink: 0;
    border-radius: 8px;
    color: var(--creme);
    cursor: pointer;
}
.abre-menu:hover,
.abre-menu[aria-expanded="true"] { color: var(--ambar); background: rgba(254, 201, 67, 0.14); }
/* Os três riscos, feitos com o próprio elemento e seus dois pseudos — sem
   imagem nem fonte de ícone, que seriam mais um arquivo a servir. */
.abre-menu-riscos { position: relative; }
.abre-menu-riscos,
.abre-menu-riscos::before,
.abre-menu-riscos::after {
    display: block;
    width: 22px;
    height: 2px;
    background: currentColor;
    border-radius: 2px;
}
.abre-menu-riscos::before { content: ""; position: absolute; top: -7px; left: 0; }
.abre-menu-riscos::after { content: ""; position: absolute; top: 7px; left: 0; }

/* 949px, e nao 720 -- corrigido em 21/08/2026, decisao do Gerente de
   Engenharia.
 
   A rodada 67 consertou o celular e o desenho ja cabia em 1280, entao a faixa
   ENTRE os dois nunca foi olhada: a conferencia visual media 320, 360, 412 e
   1280, e pulava por cima dela. Medida em 21/08/2026 com as larguras
   intermediarias, a barra do topo mostrou o seguinte:
 
       janela   documento   .topo        marca    menu
       720px    720px       wrap, 58px   144px    painel (hamburguer)
       768px    949px       nowrap, 82px 373px    548px
       900px    949px       nowrap, 82px 373px    548px
      1000px   1000px       nowrap, 82px 373px    571px
 
   Aos 721px as regras abaixo paravam de valer de uma vez: a barra voltava ao
   modo computador -- `nowrap`, marca por extenso com o logo, menu horizontal
   inteiro --, pedia 949px e recebia 768. A PAGINA INTEIRA transbordava, em
   todas as telas do sistema, entre 721px e 948px. Nao era a tabela vazando
   dentro do envolucro: era o documento.
 
   949 e a largura em que a barra cabe sozinha, medida e nao estimada. Ate la
   vale o painel que ja existe, ja funciona e ja tem teste. Tablet em paisagem
   passa a ver o menu em hamburguer -- e' a troca, aceita conscientemente: um
   menu horizontal que nao cabe nao e' um menu horizontal.
 
   O cabecalho congelado das tabelas de extrato nao se incomoda: ele so acende
   a partir de 1000px, onde a barra ja voltou aos 82px de `--altura-topo`. */
@media (max-width: 949px) {

    /* ---- Barra do topo ---------------------------------------------------
       Deixa de ser uma linha de altura fixa: o menu aberto entra como
       segunda linha da mesma barra (flex-wrap), em vez de disputar espaço
       horizontal que não existe. */
    .topo {
        flex-wrap: wrap;
        height: auto;
        min-height: 58px;
        padding: 0 14px;
    }
    .topbar .marca, .topo .marca { gap: 9px; min-width: 0; }
    .abre-menu { display: inline-flex; }

    /* A marca reduzida ao que ainda a identifica: logo pequena e a sigla
       SGE. A linha "Sistema de Gestão de Engenharia" por extenso sai — é
       justamente ela que não cabe (decisão do Gerente em 02/08/2026). */
    .logo-topo { height: 32px; }
    .marca-sistema { display: flex; padding-left: 10px; gap: 7px; }
    .marca-sistema small { display: none; }
    .marca-sistema strong { font-size: 1.15rem; }
    .icone-sge { width: 20px; height: 20px; }

    /* ---- O menu vira painel vertical ------------------------------------ */
    .topo nav {
        display: none;
        order: 3;
        flex-basis: 100%;
        width: 100%;
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        padding: 4px 0 12px;
        border-top: 1px solid #3A3A3A;
        /* Com todos os grupos abertos o painel passa da tela; ele rola
           dentro de si em vez de esticar a barra indefinidamente. */
        max-height: calc(100vh - 58px);
        overflow-y: auto;
    }
    .topo nav.aberto { display: flex; }

    /* Alvo de toque: 44px é o mínimo recomendado para o dedo, e quem usa
       este sistema no celular está em campo, em pé, no fim do dia. */
    .topo nav > a,
    .topo .menu-grupo-rotulo {
        display: flex;
        align-items: center;
        width: 100%;
        min-height: 46px;
        padding: 6px 4px;
        font-size: 1rem;
        border-bottom: none;
    }
    .topo nav a.ativo { border-bottom: none; }
    .menu-grupo.ativo .menu-grupo-rotulo { border-bottom-color: transparent; }

    /* Os grupos deixam de flutuar sobre a página: abrem para baixo,
       recuados, dentro do próprio painel. É o que resolve o submenu
       "Cadastros", que no formato antigo abria a 344px de distância da
       borda direita da tela — inalcançável por qualquer dedo. */
    .menu-grupo, .menu-subgrupo { position: static; width: 100%; }
    .menu-grupo-lista,
    .menu-subgrupo-lista,
    .menu-grupo--alinhar-direita .menu-grupo-lista {
        position: static;
        left: auto;
        right: auto;
        top: auto;
        width: 100%;
        min-width: 0;
        background: none;
        border: none;
        border-radius: 0;
        box-shadow: none;
        padding: 0 0 4px 16px;
    }

    /* No painel o fundo é escuro; na lista suspensa do computador é claro.
       As cores se invertem, e é por isso que estas regras precisam do
       prefixo `.topo` — para vencer as do menu de computador. */
    /* O <button> do seletor de idioma entra nas TRÊS regras abaixo, e não
       numa quarta regra própria (rodada 85, 19/08/2026). Ele nasceu fora
       delas e o defeito apareceu na conferência visual, não na medida: em
       320px só "Português" aparecia, porque a regra de computador pinta
       `var(--tinta)` — tinta escura sobre o painel escuro — e só o item
       ativo, que carrega fundo claro, ficava legível. Os outros três
       estavam lá, ocupando espaço, invisíveis.

       Separar em regra própria só adiaria o mesmo erro: quem mexer nas
       cores do painel amanhã mexe nestas três linhas e não teria por que
       lembrar de uma quarta. */
    .topo .menu-grupo-lista a,
    .topo .menu-grupo-lista button,
    .topo .menu-subgrupo-lista a,
    .topo .menu-subgrupo-rotulo {
        display: flex;
        align-items: center;
        min-height: 44px;
        color: var(--cinza-claro);
        font-size: 0.95rem;
        padding: 6px;
        border-radius: 6px;
        background: none;
    }
    .topo .menu-grupo-lista a:hover,
    .topo .menu-grupo-lista button:hover,
    .topo .menu-subgrupo-lista a:hover,
    .topo .menu-subgrupo-rotulo:hover { background: rgba(255, 255, 255, 0.07); color: var(--creme); }
    .topo .menu-grupo-lista a.ativo,
    .topo .menu-grupo-lista button.ativo,
    .topo .menu-subgrupo-lista a.ativo,
    .topo .menu-subgrupo.ativo .menu-subgrupo-rotulo { color: var(--ambar); background: none; font-weight: 600; }

    /* A seta do subgrupo apontava para o lado porque o submenu abria para o
       lado. Agora abre para baixo — a seta acompanha, senão vira mentira. */
    .menu-subgrupo-rotulo { justify-content: flex-start; gap: 8px; }
    .menu-subgrupo-rotulo::after {
        border-left: 4px solid transparent;
        border-right: 4px solid transparent;
        border-top: 5px solid currentColor;
        border-bottom: none;
        margin-left: auto;
    }

    /* Administração é um ícone só na barra do computador, onde o espaço é
       curto e o tooltip resolve. Empilhado no painel, um ícone solto não
       diz o que é: o texto que só o leitor de tela via passa a aparecer. */
    .menu-grupo-rotulo--icone { padding: 6px 4px; gap: 10px; line-height: normal; border-radius: 0; }
    .menu-grupo-rotulo--icone:hover { background: none; }
    .menu-grupo.ativo .menu-grupo-rotulo--icone { background: none; }
    .menu-grupo-rotulo--icone .sr-only {
        position: static;
        width: auto;
        height: auto;
        margin: 0;
        clip: auto;
        overflow: visible;
        white-space: normal;
    }

    /* ---- Fieldset com título ---------------------------------------------
       O <legend> fica encaixado NO traço da borda — desenho do próprio HTML.
       Cabe enquanto o título é uma linha só; quebrado em duas, metade fica
       acima e metade abaixo do traço, montado em cima dele. É o que acontecia
       com "Onde as horas foram trabalhadas" a 360px, na tela de lançar hora.
       Com `float`, o legend sai do encaixe e vira um título comum acima da
       caixa, com a borda fechando inteira. (rodada 67, 02/08/2026) */
    .grupo-campos { padding-top: 16px; }
    .grupo-campos > legend {
        float: left;
        width: 100%;
        padding: 0;
        margin-bottom: 10px;
    }
    /* O `clear` NÃO é enfeite. Um contêiner de grade (ou de flex) não se
       sobrepõe a um float: ele se encosta ao lado dele. Sem esta linha, a
       grade de duas colunas do bloco "Quando" ia parar à direita do legend
       flutuante, com metade dos campos fora da tela. Defeito introduzido pela
       própria correção do legend e encontrado pelo Gerente no aparelho dele,
       em 02/08/2026 — eu tinha conferido só o primeiro bloco da página. */
    .grupo-campos > legend + * { clear: both; }

    /* ---- Rótulo de botão que carrega nome de projeto -----------------------
       `.botao` usa `white-space: nowrap`, o que é certo para "Salvar" e
       "Cancelar" e mantém os botões curtos bonitos no computador. Mas alguns
       rótulos carregam o nome do projeto — "Validar ZZ TESTE — conferência
       rodada 66" mede 332px e não cabe em tela de celular nenhuma. No celular
       o nowrap cede. (achado no aparelho do Gerente, 02/08/2026) */
    .botao {
        white-space: normal;
        max-width: 100%;
        text-align: center;
    }

    /* ---- Cartões aninhados ------------------------------------------------
       A árvore de projetos empilha cartão dentro de cartão — Cliente, Unidade,
       Projeto, Etapa. Com o padding de computador, o recuo sozinho comia 91px
       dos 360 antes do primeiro caractere. */
    .cartao { padding: 16px; }
    .cartao-compacto { padding: 12px 14px; }
    /* `.etapa-no-arvore` junto -- 28/08/2026. O comentario acima lista
       "Cliente, Unidade, Projeto, Etapa" e o seletor so alcancava os tres
       primeiros: o cartao da etapa nao tem a classe `.no-arvore` (ver
       `templates/projetos/_arvore_etapa.html`). Ele ficava nos 28px do
       `.cartao-compacto` enquanto os irmaos cobravam 20, e era o transbordo
       que sobrava em 768px depois de a faixa de celular estar limpa. A mesma
       omissao esta consertada no bloco de 600px, e as duas linhas tem de
       andar juntas -- e a mesma classe. */
    .no-arvore .no-arvore,
    .etapa-no-arvore { padding: 10px; }

    /* O recuo da moldura de atividades cede no tablet -- 28/08/2026.

       `.subitens-etapa` nasceu com `margin-left: 22px` em 26/07 (PRD §35.1)
       para mostrar que as atividades estao DENTRO da etapa. Quem mostra isso
       de fato e a borda lateral ambar, que fica; os 22px eram o desenho de
       1280px cobrado tambem em 768, onde a tabela de seis colunas ja nao
       cabia por 8px. Cai para 10 e a folga passa a ser real, em vez de a
       tabela caber por um pixel. */
    .subitens-etapa { margin-left: 10px; }

    /* ---- Cabeçalho de página --------------------------------------------
       Os botões de ação (ex.: "+ Novo projeto") ganham a própria linha, à
       esquerda. Sem isto eles pediam a largura natural de todos juntos e
       vazavam 1 a 30px para fora da tela em aparelhos de 320px. */
    .cabecalho-pagina > .acoes-cabecalho {
        flex: 1 1 100%;
        margin-left: 0;
        justify-content: flex-start;
    }

    /* ---- Gráficos --------------------------------------------------------
       O Chart.js vem de CDN e o código já prevê que ele não carregue — nesse
       caso o <canvas> fica em branco, mas com os 300px de largura padrão do
       HTML, e empurra a página inteira para o lado. Justamente o cenário de
       campo: internet ruim no cliente. Achado a 320px na rodada 67. */
    canvas { max-width: 100%; }

    /* ---- Meu perfil e Sair, no pé do painel ------------------------------
       Antes desta rodada o nome da pessoa (que é o link para Meu perfil)
       tinha `display: none` no celular. Como Meu perfil é o único lugar
       onde se troca a senha, o celular ficava sem troca de senha — e a
       equipe vai justamente precisar trocar a primeira senha. */
    .topo .usuario-topo {
        display: flex;
        align-items: center;
        min-height: 46px;
        border-left: none;
        border-top: 1px solid #3A3A3A;
        border-bottom: none;
        padding: 6px 4px;
        margin-top: 6px;
        font-size: 0.95rem;
    }
    .topo .usuario-topo.ativo { border-bottom: none; }
    .topo nav form { width: 100%; }
    .topo nav form .botao {
        width: 100%;
        justify-content: center;
        min-height: 46px;   /* o "Sair" vinha com 36px — menor que o dedo */
        margin-top: 8px;
        /* No painel o "Sair" é um botão grande e principal, não um item de
           canto de barra: vai a creme cheio, um degrau acima do cinza-claro
           que ele tem no computador. */
        color: var(--creme);
    }
    .topo .usuario-topo .rotulo-perfil {
        display: block;
        margin-left: auto;
        font-size: 0.8rem;
        color: var(--cinza-claro);
    }

    /* ---- Listas de inativados do painel de exclusão -----------------------
       Medido a 320px na rodada 70: a tabela pedia 296px onde cabiam 270. As
       duas primeiras colunas ficavam inteiras e quem era cortada era a
       terceira — a lixeira, único comando da linha. O `.tabela-envolucro`
       rolava e salvava a informação, mas um botão que só aparece depois de
       rolar para o lado não é um botão: é um esconderijo.

       São 26px, e vêm de duas folgas. Primeiro o respiro de 14px das colunas
       de data e de ação, que a 320 não é respiro, é o que empurra o comando
       para fora. Segundo o nome do registro, que numa tabela de largura
       automática não encolhe além da palavra mais longa que carrega —
       "produtividade" sozinha reservava 100px. O `overflow-wrap` é o último
       recurso: com o respiro apertado, "Coleta de dados de produtividade
       (Axalta)" já cabe sem partir nenhuma palavra, e a quebra só entra em
       nomes maiores que este. Nome partido é feio; lixeira pela metade é
       defeito. (rodada 70, 05/08/2026)

       Vale só para as listas de inativados. A trilha de auditoria ao lado
       tem quatro colunas de texto e continua rolando dentro do envólucro —
       lá não há comando nenhum para se perder. */
    .tabela-inativados th:nth-child(2),
    .tabela-inativados td:nth-child(2) { padding-left: 6px; padding-right: 6px; }
    .tabela-inativados td.acoes-compactas { padding-right: 6px; }
    .tabela-inativados td:first-child { overflow-wrap: anywhere; }

    /* ---- Avisos por e-mail: a tabela deixa de ser tabela -------------------
       Medido a 320px na rodada 73: das três colunas — nome, e-mail e o
       `<select>` da frequência — a terceira ficava 104px fora da tela, e o
       documento inteiro passava a rolar para o lado (327px de largura numa
       tela de 320). Vale a lição escrita logo acima, na rodada 70: um
       comando que só aparece depois de rolar para o lado não é um comando, é
       um esconderijo. E aqui o `<select>` não é *um* comando da linha — é o
       único, a razão de a tela existir.

       Apertar respiro e quebrar palavra, que resolveram os 26px da rodada 70,
       não resolvem 104: o que sobraria para o `<select>` seria uma caixa mais
       estreita que o próprio rótulo "Desligado". Então a linha deixa de ser
       linha e vira bloco — nome, e-mail e frequência empilhados —, e o
       `<select>` ocupa a largura toda com 44px de altura, que é o alvo mínimo
       para o dedo já adotado no menu desta mesma seção.

       O cabeçalho da tabela sai junto: com as células empilhadas ele não tem
       coluna nenhuma para nomear. Quem diz o que a caixa faz passa a ser a
       linha de apoio no alto da página ("Com que frequência cada pessoa
       recebe...") mais o rótulo de leitor de tela que cada `<select>` já
       carrega. (rodada 73, 07/08/2026)

       Escopo estreito de propósito: `.tabela-avisos` existe só para esta
       tela. Nenhuma outra tabela do sistema muda de forma. */
    .tabela-avisos thead { display: none; }
    .tabela-avisos,
    .tabela-avisos tbody,
    .tabela-avisos tr,
    .tabela-avisos td { display: block; width: 100%; }
    .tabela-avisos tr { padding: 12px 0; border-bottom: 1px solid var(--borda); }
    .tabela-avisos tr:last-child { border-bottom: none; }
    .tabela-avisos td { border-bottom: none; padding: 1px 0; }
    /* O e-mail é o que menos encolhe e o que menos importa aqui; quebrar no
       meio dele é melhor que empurrar a linha para fora da tela. */
    .tabela-avisos td:nth-child(2) { overflow-wrap: anywhere; }
    .tabela-avisos select { width: 100%; min-height: 44px; margin-top: 6px; }
}

/* ---------------------------------------------------------------------------
   Relatório de diárias: as colunas que somem no celular — rodada 84, 18/08/2026

   Achado da conferência visual feita com viewport de verdade: em 320 e 360px
   a tabela mostrava **Projeto e Cliente, e nenhum dos três números**. Os
   valores ficavam atrás da rolagem lateral do `.tabela-envolucro` — a página
   não transbordava, então a verificação automática passou enquanto a tela
   estava inútil. Medir a página e não medir a tabela é não medir nada.

   Decisão do Gerente em 18/08/2026, vendo as capturas: no celular ficam
   **Projeto, Faturáveis e Valor** — qual projeto, quanto ele cobra e quanto
   dá em reais. Somem Cliente (e Cargo, quando o eixo é profissional) e
   Convertidas.

   **Convertidas some por ser comparação, não cobrança.** Ela existe para
   conferir contra o que seria se tudo fosse vendido por diária, e essa
   pergunta se faz sentado no computador. A faturável é a que vai para a
   fatura, e é a que fica.

   Esta regra está DENTRO da seção de celular, e não antes dela: aqui é o
   contrário da regra do olho, logo acima no arquivo — uma regra de celular
   escrita fora deste bloco não valeria em celular nenhum.
   --------------------------------------------------------------------------- */
/* A FAIXA DO TABLET herda o aperto que só o celular tinha — 04/09/2026.

   `usuarios` transbordava 233px em 768px mostrando 5 de 8 colunas — o maior
   transbordo isolado que restou depois de a tela virar bloco no celular.
   Medido coluna a coluna, com `width: min-content`, o piso da tabela era
   **951px contra 718px de moldura**, e em 601–900px TODA coluna já estava no
   mínimo: `agora` era igual a `piso` nas oito. Isso parece dizer "não há o que
   fazer", e a conclusão seria apressada.

   O piso de uma coluna é o MAIOR entre o piso do rótulo e o piso do conteúdo,
   e são coisas diferentes, com consertos diferentes. Separados, medidos:

     NOME             198px  <- o CONTEÚDO: o e-mail, que não tem onde quebrar
     CARGO            125px  <- o conteúdo: "Planejamento"
     NÍVEL            106px  <- o conteúdo: "Consultor"
     NÍVEL DE ACESSO  125px  <- o conteúdo: "Coordenador"
     JORNADA           93px  <- O RÓTULO (o conteúdo pede 71)
     CUSTO/HORA       117px  <- O RÓTULO (o conteúdo pede 72)
     SITUAÇÃO          97px  <- O RÓTULO (o conteúdo pede 80)
     (ações)           91px  <- o botão

   **Em três das oito colunas quem manda é o cabeçalho, não o valor** — e o
   conserto disso já existia nesta casa desde 02/09, com a razão escrita:
   "FATURÁVEIS em maiúsculas com 0,05em entre letras ocupa mais que o 4.950,00
   que ele encima". Junto com o respiro de 4px, são as duas regras que o
   celular já usava.

   Elas simplesmente **paravam em 600px** — porque em 02/09 a frente era do
   celular, e ninguém mediu 768. Este bloco não inventa número novo: ele
   estende à faixa do tablet o aperto que a folha já sabia fazer.

   Medido, em 768px: o rótulo apertado ganha 39px, o respiro ganha 128px, e os
   dois juntos deixavam 66px de sobra — não fechava. O que fecha é a terceira
   regra, a do e-mail: 951 -> 718px, e a tabela cabe.

   **Vem ANTES dos dois blocos de 600px de propósito.** Os valores são os
   mesmos que eles já usam, então abaixo de 600 nada muda: no empate ganha
   quem vem depois, e quem vem depois continua sendo o bloco de celular. Isso
   preserva o desempate documentado do `.subitens-etapa`, que custou uma
   medição em 28/08.

   E O QUE ELE NÃO FECHA FICA DITO: em 601px nem as cinco raspagens medidas
   fechavam — a melhor delas ainda deixava 29px. Abaixo de ~700px a decisão
   deixa de ser de CSS e passa a ser sobre o que sai da tela, que é decisão do
   Gerente. A moldura tem `overflow-x: auto`, e aceitar a rolagem ali é
   escolha registrada, não esquecimento. */
@media (max-width: 1023px) {
    /* A coluna secundária some **a partir do tablet**, e não só no celular —
       decisão do Gerente em 04/09/2026, tomada com o número na mão.

       Com as oito colunas na tela, `usuarios` cabe em 768px — mas a do nome
       fica com 103px e o e-mail parte em três linhas. Escondendo as duas
       secundárias (Jornada e Custo/hora), a do nome vai a 162px, o e-mail cai
       para duas linhas, e a tabela fica 28% mais baixa: 1032 -> 754px.

       **Isto não fecha nenhum transbordo**: a faixa do tablet já estava em
       zero com o aperto acima. Compra legibilidade, e paga com informação que
       sai da tela — que é por isso que a decisão foi dele, e não minha. A
       régua da casa é explícita no risco: *página que não transborda pode
       estar inútil*, e o Relatório de Horas já passou verde mostrando 2 de 6
       colunas.

       **Alcança os 15 gabaritos que usam a classe**, e não só este — exceção
       de desenho resolve uma tela e deixa a próxima pedindo a sua.

       Vem daqui, e não do bloco de 600px onde morava: o bloco de celular está
       depois, e a regra que o desliga dentro da tabela em blocos
       (`table.em-blocos tbody td.coluna-secundaria { display: flex }`) continua
       vencendo lá, por vir depois. Mover, e não copiar: duas cópias da mesma
       regra divergem no dia em que uma das duas for alterada. */
    .coluna-secundaria { display: none; }

    /* O cabeçalho é quem define a largura mínima de três das oito colunas. */
    /* (a legenda que acompanha a coluna secundária tem faixa própria, logo
        abaixo deste bloco — ver o porquê lá) */
    /* `hyphens` entra aqui — 04/09/2026, e o motivo é de OUTRO IDIOMA.

       Medida nos quatro, a conferência devolveu **13 transbordos ESTRUTURAIS**
       — com a tabela vazia — que em pt-BR são ZERO: 4 em inglês, 3 em espanhol
       e 6 em francês. Estrutural é o rótulo: não depende de dado nenhum, e
       nenhum banco o conserta. Um deles é o `extrato-do-mes`, que vai ao
       cliente.

       Duas candidatas foram medidas sobre a tabela VAZIA, que é como o defeito
       se define. `overflow-wrap: anywhere` fecha os 12 e leva o cabeçalho de
       `parametros-multiplicadores` em francês de 75 para **360px** — meia tela
       de cabeçalho. A hifenização fecha **7**, e custa de 17 a 33px: uma linha
       a mais, **uma vez por tabela**, e não uma vez por linha. É *caber não é o
       mesmo que ficou bom* aplicado antes de o defeito existir.

       E ela foi conferida na outra ponta, que é o que autorizou entrar: sobre
       as 49 telas em pt-BR ela **não piorou uma medida sequer**, melhorou 24 e
       fechou `parametros-multiplicadores` (50 -> 0px). *Não se piora o idioma
       que todos usam para consertar os outros.*

       **Ela não alcança o inglês, e isso é medido, não suposto:** 51->51,
       43->43, 11->11, 3->3 nos quatro casos estruturais, e 175->175, 180->180,
       123->123 no ensaio de conteúdo. Duas medições independentes, efeito
       exatamente zero — este navegador não hifeniza inglês. Os cinco casos que
       sobram estão nomeados, e o conserto deles é encurtar rótulo, que muda o
       que o cliente lê e é decisão do Gerente.

       Fica no bloco do tablet, e não na folha inteira: em 1280px o estrutural
       é zero em todos os idiomas, e lá ela partiria palavra sem ganho — medido,
       quatro cabeçalhos ficavam mais altos à toa.

       **DEPENDE DO `lang` DO HTML, e aqui isso não é formalidade: é o próprio
       motivo da regra.** A divisão silábica usa o dicionário do idioma
       DECLARADO — quem o decide é `formatos.etiqueta_idioma`, e não o gabarito
       —, então um `lang` errado parte a palavra francesa pelas regras do
       português, numa tela que o cliente vê. Foi por isso que o `<html lang>`
       deixou de estar cravado em "pt-br" em 28/08, no dia em que o primeiro
       `hyphens` entrou.

       E a medição de hoje é evidência de que o `lang` está chegando certo: a
       regra fecha estruturais em francês e espanhol e **não move um pixel em
       inglês**. Se o `lang` estivesse cravado, os três se comportariam igual. */
    .tabela-envolucro th { letter-spacing: 0; font-size: 0.70rem; hyphens: auto; }
    /* As duas tabelas novas da aba Adicionais (despesas faturáveis e despesas
       a vincular) DESLIGAM a regra de cima — lote K, 02/10/2026, decisão do
       Gerente: o cabeçalho delas quebra só entre palavras. Medido em 768px,
       ela partia "QUAN-TI-DADE", "LAN-ÇADO POR", "FOR-NECE-DOR" e
       "DES-CRI-ÇÃO". Por classe, e não na regra de cima, que vale para toda
       tabela da casa e tem medição própria. */
    .tabela-envolucro table.cabecalho-sem-hifen th { hyphens: manual; }
    /* Editar e Remover lado a lado (`td.acoes { white-space: nowrap }`)
       levavam a tabela de despesas faturáveis, de oito colunas, a transbordar
       em 768px nos quatro idiomas — pt-br +67, en +70, es-mx +55, fr +98px, com
       o "Remover" cortado. Soltos, os dois descem um sob o outro, e a coluna
       fica da largura do maior botão. Só nesta célula: as outras tabelas
       cabem com o par numa linha. */
    td.acoes.acoes-quebram { white-space: normal; }
    .tabela-envolucro th,
    .tabela-envolucro td { padding: 12px 4px; }
    /* Só os botões empilhados não bastaram: sobravam +36px em pt-br, +15 em
       en, +13 em es-mx e +33 em fr, porque o cabeçalho que não hifeniza é
       mais largo ("QUANTIDADE" inteiro) e os totais de oito dígitos não
       quebram. O resto sai do espaçamento — 2px de cada lado da célula em vez
       de 4, e 8px de cada lado do botão em vez de 13 —, sem tirar coluna nem
       texto. Só nesta tabela, que é a única de oito colunas da aba. */
    .tabela-envolucro table.aperto-do-tablet th,
    .tabela-envolucro table.aperto-do-tablet td { padding-left: 2px; padding-right: 2px; }
    .tabela-envolucro table.aperto-do-tablet td.acoes .botao-discreto { padding-left: 8px; padding-right: 8px; }
    /* O e-mail não tem espaço, hífen nem barra: sem isto ele sozinho põe um
       piso de 198px na coluna do nome, mais que o dobro do segundo maior. É a
       mesma regra que a tabela em blocos já usa no celular, e pela mesma
       razão — só que aqui ainda há rolagem lateral para onde fugir, e é
       justamente dela que se quer sair.

       **A quebra alcança o e-mail, e não a célula** — 04/09/2026, corrigido
       depois de olhar a captura. Aplicada à célula inteira ela derruba o piso
       da coluna do nome de 198px para 41px, e o navegador então lhe dá o que
       sobrar: a coluna mais importante da tela ficou com 83px, a MENOR da
       tabela, com o e-mail partido em quatro linhas. A tabela cabia, e ficou
       pior — *caber não é o mesmo que ficou bom*, e isso só apareceu na
       captura, não no número.

       Alcançando só o `.texto-pequeno`, o piso da coluna volta a ser a maior
       palavra do NOME PRÓPRIO (81px), que é conteúdo de verdade: a coluna fica
       com 103px e o e-mail com três linhas, e a tabela continua cabendo.

       É a mesma forma do conserto de 01/09, quando o piso do nome saiu no
       celular: escolhe-se QUEM quebra, e o piso passa a ser consequência do
       conteúdo — em vez de escolher um número, que seria inventado. */
    .tabela-envolucro td.nome-celula .texto-pequeno { overflow-wrap: anywhere; }
}

/* A LEGENDA ACOMPANHA A COLUNA QUE ELA EXPLICA — 04/09/2026.

   Achado OLHANDO a captura, e não medindo: com a coluna Custo/hora fora da
   tela no tablet, o rodapé de `usuarios` continuava explicando INT, EXT e o
   asterisco — que só existem nela. **Legenda órfã não transborda, não some da
   tela e não muda número nenhum**, então nenhuma medida desta casa a acusaria.
   É a mesma família do rótulo que diz o nome de outra coluna: defeito que só
   aparece a quem lê a tela.

   A faixa é FECHADA nos dois lados, e é por isso que ela não usa
   `.coluna-secundaria`: abaixo de 600px o desenho em blocos traz a coluna de
   volta, e a legenda tem de voltar com ela. Uma regra só, com a faixa exata,
   em vez de uma regra mais uma exceção — duas regras para o mesmo fato
   divergem no dia em que alguém mexer só numa. */
@media (min-width: 601px) and (max-width: 1023px) {
    .legenda-da-secundaria { display: none; }
}

/* ---------------------------------------------------------------------------
   O recuo da árvore de projetos no celular — 24/08/2026

   Medido antes de mexer: em 320px de tela, a tabela de atividades recebia
   **112px**. Os outros 208 eram recuo — três níveis de `.no-arvore` (cliente,
   projeto, etapa), cada um com padding, margem, padding-left e borda, mais o
   `.cartao` por fora e o `.subitens-etapa` por dentro.

   Esconder colunas (feito no mesmo dia) tirou o conteúdo de 289px para 161px e
   não resolveu: **nenhuma tabela cabe em 112px**. Com o nome de atividade
   descendo uma palavra por linha, a tela ficava alta e ilegível.

   A hierarquia continua legível porque quem a comunica é a **borda lateral
   colorida**, não a distância. No computador nada muda: estas regras vivem
   dentro do bloco de celular.
   --------------------------------------------------------------------------- */
@media (max-width: 600px) {
    /* A maior mordida isolada da tela, e ela não estava na árvore: o padding
       da PÁGINA tira 48px de uma tela de 320 — mais que qualquer nível do
       acordeão. Cair para 12 devolve 24px a todas as telas do sistema, e não
       só a esta. Medido na cadeia de ancestrais em 24/08/2026, elemento por
       elemento, depois de duas estimativas minhas erradas: a régua aqui é o
       navegador, não a leitura do CSS. */
    .conteudo { padding: 24px 12px 56px; }

    /* O cartao da ETAPA nao e um `.no-arvore` -- 28/08/2026.

       O comentario acima diz, desde 24/08, que esta secao trata "tres niveis
       de `.no-arvore` (cliente, projeto, etapa)". Ela nunca tratou a etapa: o
       cartao dela e
       `cartao cartao-compacto etapa-no-arvore etapa-arrastavel`
       (`templates/projetos/_arvore_etapa.html`), e `.etapa-no-arvore` nao casa
       com `.no-arvore`. O seletor passava por cima dele e a etapa caia no
       `.cartao-compacto { padding: 12px 14px }` do bloco de 720px.

       Medido na cadeia de ancestrais em 320px, antes de mexer: 28px de padding
       onde o cartao do cliente, da unidade e do projeto cobravam 12. Era a
       maior mordida da arvore inteira, e estava documentada como resolvida.

       A licao, que vale alem daqui: seletor de classe nao pergunta o que o
       elemento E, pergunta que classe ele TEM. `.etapa-no-arvore` le como
       "um no da arvore" para quem escreve e nao le como nada para o
       navegador. */
    #arvore-projetos .no-arvore .no-arvore,
    #arvore-projetos .etapa-no-arvore { padding: 6px; }

    /* O cartao de fora perde metade do padding -- 28/08/2026.

       Ele e o unico da pilha que ainda cobrava os 16px do bloco de 720px, e
       em 320px isso e 32px de uma tela onde a tabela recebia 154. Fica em 8,
       que e o mesmo respiro dos irmaos de dentro. Escopado no
       `#arvore-projetos` de proposito: `.cartao` e o recipiente de toda tela
       do sistema, e afrouxa-lo no geral mexeria em pagina que nao tem
       problema nenhum. */
    #arvore-projetos > .no-arvore { padding: 6px; }

    /* O recuo dos corpos vira zero -- 28/08/2026.

       Eram 6px de margem mais 6px de padding por nivel, tres niveis, 36px no
       total. Medido: **nao ha borda nem fundo nesse recuo** -- ele e espaco em
       branco puro, e espaco em branco de 6px entre dois cartoes que ja tem
       borda propria nao comunica hierarquia nenhuma numa tela de 320px. Quem
       comunica sao a borda e o fundo do cartao de dentro, que continuam.

       E o mesmo argumento que a secao acima ja aceitou em 24/08 -- "a
       hierarquia continua legivel porque quem a comunica e a borda lateral
       colorida, nao a distancia" --, levado ate o fim. No computador nada
       muda: isto vive dentro do bloco de celular. */
    #arvore-projetos .corpo-no-arvore,
    #arvore-projetos.arvore-compacta .corpo-no-arvore {
        margin-left: 0;
        padding-left: 0;
    }
    /* 4px de lado, e nao 6 -- 28/08/2026. Com todo o resto medido, a tabela
       mais larga da tela fechava em 223px numa moldura de 222: passava a
       caber por um pixel. Um pixel nao e folga, e o catalogo tem quatro
       idiomas -- "Sub-atividade" vira "Sous-activite" e o piso da tabela sobe
       com ele. Estes 4px, mais os 4 do cartao de fora, sao a folga. */
    .subitens-etapa {
        margin-left: 0;
        padding: 8px 4px;
    }
    /* O respiro de 12px por célula vira 6px: em 112px de tabela ele não era
       respiro, era o que empurrava o número para fora. Mesmo diagnóstico da
       coluna de ações e do `.coluna-numero`, logo abaixo. */
    /* ...e ate 28/08/2026 ele NAO virava. Medido no navegador: as celulas
       tinham 8px de padding lateral, nao 6. Este seletor
       (`.subitens-etapa th`, peso 0-1-1) empata com o
       `.tabela-envolucro th, .tabela-envolucro td { padding: 12px 8px }` do
       ultimo bloco de celular deste arquivo, e no empate ganha quem vem
       depois -- que e o outro. Eram 16px por tabela (4 colunas x 2 lados x
       2px) que a regra prometia devolver e nao devolvia.

       O `table` no meio sobe o peso para 0-1-2 e desempata. A licao vale para
       o arquivo inteiro: **regra escrita nao e regra aplicada**, e duas
       regras de mesmo peso em blocos `@media` iguais se resolvem pela ordem
       do arquivo, que ninguem le ao escrever a segunda. */
    .subitens-etapa table th,
    .subitens-etapa table td { padding: 6px; }

    /* O nome da atividade pode quebrar no meio da palavra -- 28/08/2026.

       Ultimo passo, e o unico que muda a aparencia. Depois de devolver 68px de
       moldura e de encolher acoes e recuo, as tabelas grandes ainda pediam
       245 a 299px numa moldura de 222. O que sobrava era a **largura minima da
       coluna Atividade**, e ela e a palavra mais longa do nome:
       "Desenvolvimento" sozinha pede 124px, e sem poder quebrar ela e o piso
       da tabela inteira.

       `overflow-wrap: anywhere` -- e nao `break-word` -- porque so o primeiro
       entra na conta de largura minima que o navegador faz; `break-word`
       quebra na hora de desenhar e deixa o piso onde estava.

       **Nao esconde nada.** O nome inteiro continua na tela; ele desce uma
       linha no meio de uma palavra quando nao ha largura. A alternativa era
       manter a rolagem lateral, e atras dela ficavam as Horas -- que e o
       numero pelo qual a tela existe. Em 24/08 este caminho foi recusado com
       a moldura em 112px, onde daria uma palavra por linha; com 222px o caso
       e outro, e foi medido antes de decidir. */
    .subitens-etapa .nome-celula {
        overflow-wrap: anywhere;
        /* `hyphens` junto, e a ordem entre os dois importa -- 28/08/2026.

           Olhando a captura depois de tudo pronto: o nome cabia, e cabia
           partido em lugar nenhum -- "Elaborac/ao de/Padroes". Quem decide
           onde a palavra parte, quando ha dicionario, e o `hyphens: auto`, e
           ele parte na silaba e deixa o traco: "Elabora-/cao". O
           `overflow-wrap: anywhere` continua sendo o que baixa a largura
           minima da coluna (o `hyphens` sozinho nao baixa) e o que resolve a
           palavra que o dicionario nao conhece -- codigo de projeto, sigla,
           nome proprio.

           O `lang` do `<html>` e o que faz o dicionario certo ser escolhido.
           Sem ele isto nao faz nada, e nao faz nada em silencio.

           ESTA LINHA DEPENDE DO `lang`, E O `lang` NAO E DECORATIVO -- corrigido
           em 28/08/2026, no mesmo dia. O paragrafo acima dizia
           `<html lang="pt-br">` porque era isso que estava escrito em
           `templates/base.html` e em `templates/500.html`: cravado, num
           sistema que fala quatro idiomas. Com ele cravado, a tela em ingles,
           em espanhol e em frances partia as palavras pelo dicionario do
           PORTUGUES -- e palavra partida na silaba errada se le na tela.

           Agora o `lang` sai de `formatos.etiqueta_idioma`
           (`ETIQUETA_BCP47`), que e a mesma tabela do `toLocaleString`.

           **Quem mexer numa das duas pontas olha a outra.** Voltar o `lang`
           para um valor fixo -- ou tira-lo -- desliga esta linha sem apagar
           nada e sem erro nenhum: o texto continua saindo, so que partido pelo
           dicionario errado, ou nao partido. Os dois templates dizem o mesmo,
           cada um no seu lugar. */
        hyphens: auto;
    }

    /* A etiqueta "Sub-atividade" deixa de ser indivisivel -- 28/08/2026.

       Medida na celula, depois de tudo o que esta acima: a coluna Atividade
       das duas tabelas com sub-atividade ainda tinha piso de 128px, e **102
       deles eram esta etiqueta**. `.etiqueta` declara `white-space: nowrap`,
       entao ela e uma peca solida de 102px que nenhuma quebra de linha
       atravessa -- e o piso da tabela inteira era o piso dela.

       Ela **fica na tela**; so passa a poder quebrar em duas linhas quando nao
       ha largura. Esconde-la seria o caminho curto e e o que a tarefa proibe:
       o numero cairia sem que nada tivesse melhorado.

       So no celular, e so dentro da arvore de atividades: `.etiqueta` veste
       status de projeto, nivel e situacao em toda tela do sistema, e um
       "EM ANDAMENTO" partido ao meio no computador seria estrago onde nao ha
       defeito. */
    .subitens-etapa .etiqueta-sub-atividade {
        white-space: normal;
        /* A capsula vira texto -- 28/08/2026, olhando a captura.

           Com `white-space: normal` a etiqueta passou a caber, e passou a
           caber QUEBRADA: "Sub-/ativid/ade" em tres linhas dentro de uma
           capsula arredondada, que se le como defeito de desenho e nao como
           uma marca. O remedio nao e devolver o `nowrap` (volta a rolagem
           lateral, e atras dela ficam as Horas) nem esconder a marca (ela e
           informacao). E tirar a capsula: as mesmas palavras, na mesma cor,
           como texto pequeno, que quebra em duas linhas sem parecer
           quebrado.

           So no celular e so dentro da arvore. No computador a capsula fica,
           porque la ela cabe inteira e e o desenho da casa. */
        padding: 0;
        background: none;
        border-radius: 0;
        font-size: 0.66rem;
        color: #7A5700;
    }

    /* Dois respiros que a coluna Atividade ganha de volta -- 28/08/2026.

       Depois de tudo o mais, a coluna do nome ficava com 84px dos 230 da
       tabela, e "Replicacao" quebrava no meio por 10px. A alca de arrastar
       nao existe no celular (`.coluna-secundaria` a esconde, e o
       arrastar-e-soltar nunca respondeu a toque), entao a celula dela nao
       precisa dos 24px reservados para a alca -- precisa dos 16 do botao de
       expandir, que e o que sobrou la dentro. Com isso e com 2px a menos
       antes dos icones, o nome ganha 10px e a palavra comum volta a caber
       numa linha. */
    .subitens-etapa .acoes-arrastar { width: 16px; }
    .subitens-etapa td.acoes-compactas { padding-left: 2px; }

    /* Os quatro icones em fila viram dois por dois -- 28/08/2026.

       Medido em 320px, antes de mexer: a coluna de acoes pedia **98px com tres
       icones e 126px com quatro** -- ate 82% da moldura de 154px que a tabela
       recebia. Os icones tem 26px cada e `td.acoes-compactas` declara
       `white-space: nowrap`, entao a coluna pedia a fila inteira em qualquer
       largura de tela, e nao havia largura em que ela cedesse.

       A grade de duas colunas resolve **sem tirar nenhum icone**: os mesmos
       quatro continuam na tela, empilhados dois por dois, e a coluna passa a
       pedir 64px. Nao e o mesmo que deixar o `flex-wrap` solto -- com ele a
       largura minima vira um icone so e os quatro descem numa torre, que
       estica a linha em quatro alturas. `repeat(2, auto)` fixa a forma.

       Escopado no `.subitens-etapa`: `.acoes-compactas` tambem veste a coluna
       de acoes de outras tabelas do sistema, e essas nao tem o problema. */
    .subitens-etapa .acoes-icones {
        display: grid;
        grid-template-columns: repeat(2, auto);
        justify-content: end;
    }

    /* O recuo da sub-atividade no celular -- 28/08/2026.

       `td.nome-celula.profundidade-N` cobra 30, 50, 70 e 90px de
       `padding-left`, e essas quatro linhas **nao estao dentro de media query
       nenhuma**: os 30px do primeiro nivel valiam igual num monitor de 1280 e
       num aparelho de 320. Medido: numa tabela cuja coluna Atividade pedia
       148px, 30 deles eram recuo -- um quinto da moldura inteira gasto em
       espaco em branco.

       O degrau cai para 6px por nivel. **Quem diz a profundidade continua
       sendo a borda lateral ambar** (`border-left: 3px`), mais o tom de fundo
       da linha e o marcador `└` -- tres sinais, nenhum deles a distancia. E o
       mesmo argumento de 24/08 aplicado a celula em vez do cartao.

       No computador nada muda: isto vive dentro do bloco de celular. */
    td.nome-celula.profundidade-1 { padding-left: 12px; }
    td.nome-celula.profundidade-2 { padding-left: 18px; }
    td.nome-celula.profundidade-3 { padding-left: 24px; }
    td.nome-celula.profundidade-4 { padding-left: 30px; }
}


@media (max-width: 600px) {
    /* `.coluna-secundaria { display: none }` MOROU AQUI ate 04/09/2026, e
       subiu para o bloco de 1023px: a coluna secundaria passa a sumir a partir
       do tablet, por decisao do Gerente. A razao esta escrita la'. */

    /* A coluna de acoes pode quebrar linha no celular -- 02/09/2026, medido.

       `td.acoes { white-space: nowrap; }` vive no bloco de computador desde
       sempre, e la' esta' certo: "Editar  Inativar" numa linha so'. Em 320px
       ele cobrava **148px de uma moldura de 294** -- metade da tela para dois
       botoes.

       ## O que a medicao mostrou, e o que ela DESMENTIU

       Do transbordo somado a 320px -- 2341px em 21 tabelas --, a coluna de
       acoes responde por **904px** e as etiquetas por 172px: **46% do numero
       "com dado" nao e' dado, e' codigo**, e portanto ja era comparavel entre
       dias sem banco nenhum.

       Deixar quebrar recupera **333px**, e nao os 904. O resto e' a largura
       PROPRIA dos botoes, que so' sai trocando o que o botao e' -- nao como
       ele quebra. Duas tabelas zeram por isto: `inicio` e
       `categorias-de-despesa`.

       Duas hipoteses vizinhas foram medidas e **eliminadas por darem o mesmo
       numero**: encolher a fonte da celula (o botao tem a propria) e empilhar
       com `flex-direction: column` (nao vence a quebra normal). As tres deram
       1318px identicos. */
    td.acoes, td.acoes-compactas { white-space: normal; }

    /* A tabela vira BLOCO POR LINHA no celular -- 02/09/2026, medido.

       ## Por que existe

       Sete tabelas mostravam **metade ou menos** das colunas a 320px, e o que
       ficava de fora nao era decoracao: `SALARIO` na tabela salarial, `HORAS`
       no historico de RDO, `DESCRICAO` no proprio RDO -- o conteudo do
       documento que vai ao cliente.

       Tres consertos de moldura foram medidos e nenhum resolve: encolher
       etiqueta devolve 82px, trocar rotulo por icone devolve 410px, e apagar
       a coluna de acoes INTEIRA devolve 571px **sem zerar uma tabela sequer**.
       Seis a oito colunas de dado real nao cabem em 320px por caminho nenhum.

       ## O que ela cobra, e por que so' algumas tabelas a usam

       Nada fica fora da tela, porque nada esta' lado a lado. O preco e'
       ALTURA, e ele **escala com o numero de linhas**:

           permissoes-por-perfil   3 a 6 linhas    854 ->   665px   0,8x
           rdo                         2 linhas    227 ->   384px   1,7x
           historico-de-rdo           17 linhas   2322 ->  4659px   2,0x
           usuarios                    8 linhas    872 ->  2340px   2,7x
           parametros-feriados        13 linhas    929 ->  2569px   2,8x
           cargos                     66 linhas   4679 -> 14955px   3,2x

       **`cargos` foi RECUSADA com o numero escrito**: 47 telas de rolagem
       para listar 66 cargos e' pior que a rolagem lateral, e a resposta ali
       nao e' desenho, e' paginacao ou filtro. As tres da faixa do meio ficam
       como decisao separada do Gerente.

       A regua que fica: **bloco por linha e' otimo em tabela curta e pessimo
       em tabela longa. Nao e' questao de qual tela -- e' quantas linhas.**

       ## Como se usa

       `<table class="em-blocos">`, e cada `<td>` com `data-texto-rotulo`. O rotulo
       vem do `<th>` correspondente e **e' traduzido**, senao a tabela fala
       portugues dentro de uma tela em ingles. `test_tabela_em_blocos.py`
       exige que os dois lados digam a mesma coisa: rotulo que diverge do
       cabecalho poe o valor sob o nome errado, e isso nenhuma medida de
       transbordo pega. */
    table.em-blocos, table.em-blocos tbody, table.em-blocos tfoot,
    table.em-blocos tr, table.em-blocos td { display: block; width: auto; }
    table.em-blocos thead { display: none; }
    /* A linha que um filtro esconde (`hidden`) continua escondida em bloco
       -- 28/09/2026, o filtro da conciliacao com o Zoho (decisao 55). O
       `display: block` logo acima vence o `[hidden]` do navegador, que tem a
       menor especificidade; quem declara `display` declara o caso escondido. */
    table.em-blocos tbody tr[hidden] { display: none; }
    table.em-blocos tbody tr, table.em-blocos tfoot tr {
        border: 1px solid var(--borda); border-radius: 8px;
        margin-bottom: 8px; padding: 6px 8px;
    }
    table.em-blocos tbody td, table.em-blocos tfoot th {
        border: 0; padding: 3px 0; text-align: left;
        display: flex; justify-content: space-between; gap: 12px;
    }
    /* O que nao tem onde quebrar quebra assim mesmo -- 03/09/2026.

       `usuarios/lista.html` continuou transbordando 12px DEPOIS de virar
       bloco, e o dono foi medido: o e-mail. `fabio.rodrigues@dominio-aut.com.br`
       nao tem espaco, hifen nem barra, entao o navegador nao tem onde parti-lo
       e ele empurra o cartao para fora.

       A tabela normal disfarca isso -- a moldura tem `overflow-x: auto` e a
       pessoa rola. **Em bloco nao ha' para onde rolar**: o desenho existe
       justamente para acabar com a rolagem lateral, entao aqui a palavra
       longa TEM de quebrar, ou o desenho nao cumpre o que promete.

       `anywhere`, e nao `break-all`: o navegador so' parte no meio da palavra
       quando nao houver outro jeito, e continua preferindo o espaco. O
       `min-width: 0` vai junto porque o `td` e' item flex, e item flex nao
       encolhe abaixo do proprio conteudo sem isso -- a regra de quebra
       sozinha ficaria escrita e sem efeito. */
    table.em-blocos tbody td, table.em-blocos tfoot th {
        min-width: 0; overflow-wrap: anywhere;
    }
    table.em-blocos tbody td[data-texto-rotulo]::before,
    table.em-blocos tfoot th[data-texto-rotulo]::before {
        content: attr(data-texto-rotulo);
        font-size: 0.72rem; font-weight: 600; opacity: 0.65;
        white-space: nowrap; flex: 0 0 auto;
    }
    /* O RODAPE entra no desenho -- 03/09/2026.
       A linha de total do apontamento tem celulas VAZIAS nas colunas que ela
       nao soma. Em tabela elas sao espaco em branco alinhado; em bloco
       virariam linhas vazias dentro do cartao do total. `:empty` as tira.

       E' a licao de `test_celular_relatorio_horas.py`, de 23/08, pela porta
       nova: **o total tem de acompanhar o corpo**, senao ele fica sob a
       coluna errada -- e aqui nao ha' coluna, entao ele ficaria sob nada. */
    table.em-blocos tfoot th:empty { display: none; }
    /* Numa tabela em blocos NAO ha' disputa por largura, entao esconder
       coluna deixa de ter motivo -- e esconder sem motivo e' so' perder
       informacao. A regra desliga o `.coluna-secundaria` aqui dentro. */
    table.em-blocos tbody td.coluna-secundaria { display: flex; }
    /* A LINHA EXPANDIDA das descricoes continua EMPILHADA -- 21/09/2026,
       medido. Na tela de horas do projeto (`projetos/horas.html`, a primeira
       tabela de extrato em blocos) a `<tr class="linha-descricoes">` tem um
       `<td>` so', com um bloco `.descricao-do-apontamento` por lancamento.
       A regra geral de cima faz desse `<td>` um flex em LINHA, e um dia com
       dois lancamentos punha as duas descricoes lado a lado em 320px: a
       segunda ficou com 74px de largura (x=214, medido pela bancada
       `ferramentas/bancada-em-blocos-expandido.py`), a palavra partida em
       tres linhas. A celula NAO tem `data-texto-rotulo` -- ela e' a propria
       linha, nao um valor --, entao nada se perde ao voltar a bloco. */
    table.em-blocos tbody tr.linha-descricoes > td { display: block; }
    /* Sem largura fixa: com duas colunas a menos, as três que ficam se
       acomodam sozinhas. E o respiro de 14px vira 8px — em 320px ele não é
       respiro, é o que empurra o número para fora, o mesmo diagnóstico da
       coluna de ações medido numa rodada anterior. */
    .coluna-numero { width: auto; }
    /* O respiro lateral cai de 8px para 4px — 02/09/2026, medido.

       Numa tabela de seis colunas isso são 48px de volta, e foi o único
       caminho com ganho real entre os quatro medidos no relatório diário:

         como está          401px   3 de 6 colunas visíveis em 320px
         cabeçalho curto    385px   3 de 6   (ganha 16px, e cobraria rótulo
                                              curto traduzido em 4 idiomas)
         SEM a coluna da marca      340px   4 de 6   (ganha 61px, e tira
                                                      informação da tela)
         PADDING 4px        353px   4 de 6   (ganha 48px, e não tira nada)

       Em 412px o padding sozinho faz a tabela **caber inteira** — 6 de 6, sem
       transbordo. Em 320px ela continua transbordando, e isso é decisão
       tomada com o número na mão: **seis colunas de conteúdo real não cabem
       em 262px**, e nem esconder a coluna da marca resolvia (ainda estourava
       78px). O melhor cenário de todos ainda passava 75px.

       A moldura tem `overflow-x: auto` de propósito. Aceitar a rolagem em
       320 e 360 é escolha registrada, não esquecimento — e mesmo lá o ganho
       é real: a tabela passa de três para quatro colunas na tela.

       Vale para TODAS as tabelas, e não só para a do relatório: exceção de
       desenho resolve uma tela e deixa a próxima pedindo a sua. */
    .tabela-envolucro th,
    .tabela-envolucro td { padding: 12px 4px; }
    /* O cabeçalho é quem define a largura mínima da coluna, não o número:
       "FATURÁVEIS" em maiúsculas com 0,05em entre letras ocupa mais que o
       "4.950,00" que ele encima. Sem o espaçamento e um ponto menor, os
       centavos param de ser cortados em 320px — medido, eram 28px faltando. */
    .tabela-envolucro th { letter-spacing: 0; font-size: 0.70rem; }

    /* O piso da coluna do nome sai de cena no celular — 01/09/2026.

       `min-width: 0`, e não um número menor: 180 e 200 foram escolhidos para
       o computador, e qualquer valor que eu pusesse aqui seria inventado.
       Sem piso, o navegador dá à coluna a largura que o conteúdo pede, que é
       a única medida que não é chute.

       O nome passa a quebrar em mais linhas em 320px. É a troca: **tabela
       mais alta em vez de tabela cortada**, e a coluna continua na tela em
       vez de sair pela direita. Esconder colunas foi recusado pela régua da
       casa — *página que não transborda pode estar inútil*, e o Relatório de
       Horas já passou verde mostrando 2 de 6 colunas.

       Esta regra só alcança porque o piso saiu do atributo `style` no mesmo
       lote. Enquanto ele estava inline, esta linha aqui não faria nada — e
       não haveria erro nenhum a acusar. */
    .tabela-envolucro th.coluna-nome,
    .tabela-envolucro th.coluna-nome-estreita,
    .tabela-envolucro th.coluna-nome-larga { min-width: 0; }

    /* A tabela "Projetos do SGE" da conciliação com o Zoho — lote M,
       02/10/2026, opção A do Gerente: caber, e não rolar de lado.

       Contido o cartão (`.colunas-contidas`), o envólucro tem 294px em 320, e
       a tabela pedia 304 em pt-br, 297 em en, 319 em es-mx e 321 em fr. O
       piso das três colunas, medido em fr: o cliente (texto, 105px), a
       etiqueta "Zoho : en attente" (sem quebra, 11px de cada lado, 126px) e
       o botão "Pas d'ancien projet" (13px de cada lado, 90px).

       O que sai é só espaçamento: 2px de célula em vez de 4, e 6px de cada
       lado no botão e na etiqueta. A tabela fica com 294px nos quatro idiomas
       em 320, sem tirar coluna nem texto e sem `overflow-wrap` — o código do
       projeto continua quebrando só no hífen, como já quebrava antes (e numa
       linha só ele pede 154px, que não cabem em 320 em idioma nenhum).
       Trava 22 de `apps/projetos/test_zoho_conciliacao.py`. */
    .tabela-envolucro table.aperto-da-conciliacao th,
    .tabela-envolucro table.aperto-da-conciliacao td { padding-left: 2px; padding-right: 2px; }
    .tabela-envolucro table.aperto-da-conciliacao .botao-discreto { padding-left: 6px; padding-right: 6px; }
    .tabela-envolucro table.aperto-da-conciliacao .etiqueta { padding-left: 6px; padding-right: 6px; }
}
