/* ==========================================================================
   mobile.css — fundação de responsividade do AINEX/ForteTech
   --------------------------------------------------------------------------
   Carregado SEMPRE depois de styles.css (o tema Tailwind compilado), para
   poder corrigir sem !important. Arquivo escrito à mão: não passa pelo
   PostCSS, então nada de @apply nem de diretivas do Tailwind aqui.

   Baseline de navegador: Android 8+, Chrome/WebView 80+.
   PROIBIDO neste arquivo: :has(), @container, subgrid, dvh/svh/lvh,
   aninhamento CSS nativo, text-wrap: balance, @layer nativo.

   Contrato de breakpoints (iguais aos do Tailwind 3.4, para não criar um
   segundo sistema): base 0-639 = mobile, sm 640, md 768, lg 1024, xl 1280.
   Media query não aceita custom property, então os valores aparecem
   literais nos @media — o MOBILE_PLAN.md é o contrato escrito.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */
:root {
    /* Alvo de toque mínimo exigido pelo baseline. */
    --mob-toque: 44px;

    /* Tamanho de fonte de campo no mobile. Abaixo de 16px o Chrome do Android
       dá zoom sozinho ao focar o campo e desalinha a tela inteira. */
    --mob-fonte-campo: 16px;

    /* Pisos de legibilidade. Aplicados pelos padrões da Fase 2, não
       globalmente — ver MOBILE_PLAN.md, seção Decisões. */
    --mob-fonte-corpo: 16px;
    --mob-fonte-apoio: 14px;

    /* Espaçamento. A margem lateral da tela é o "gutter": em 320px ela é o
       que separa o conteúdo da borda do aparelho. */
    --mob-gutter: 16px;
    --mob-esp-1: 4px;
    --mob-esp-2: 8px;
    --mob-esp-3: 12px;
    --mob-esp-4: 16px;
    --mob-esp-5: 24px;
    --mob-esp-6: 32px;

    /* Alturas das barras fixas. O header do base.html é pt-16 = 64px. */
    --mob-altura-header: 64px;
    --mob-altura-barra-inferior: 56px;

    /* Recuo de área segura (notch / barra de gestos). env() existe desde o
       Chrome 69, então está dentro do baseline; onde não existir, cai em 0px. */
    --mob-safe-inferior: env(safe-area-inset-bottom, 0px);

    /* Camadas. Mantidas abaixo do z-50 do header e do z-40 da sidebar
       do base.html, exceto o que precisa cobrir tudo. */
    --mob-z-barra-inferior: 45;
    --mob-z-folha: 60;
    /* O fundo da gaveta precisa cobrir também os flutuantes de z altíssimo
       que existem no sistema (post-it de prazos 9500, assistente 9990, botão
       de notificações 9999). A gaveta fica em 10001, logo acima dele. */
    --mob-z-backdrop: 10000;
}

/* --------------------------------------------------------------------------
   2. Reset defensivo
   Vale em todas as larguras: são regras que não mudam o desktop, só evitam
   que um elemento estoure a caixa dele.
   -------------------------------------------------------------------------- */

/* O preflight do Tailwind já faz isto; repetido porque as telas que usam o
   Tailwind por CDN ou CSS próprio não têm o preflight. */
*,
*::before,
*::after {
    box-sizing: border-box;
}

/* Impede que o Android infle o texto sozinho em blocos largos. É a causa
   clássica de "no meu celular a fonte sai gigante em uma coluna só". */
html {
    -webkit-text-size-adjust: 100%;
}

/* Mídia fluida. */
img,
video,
canvas,
svg,
iframe,
embed,
object {
    max-width: 100%;
}

img,
video {
    height: auto;
}

/* Tabela nunca é mais larga que o pai...
   ...EXCETO quando ela já está dentro de um contêiner de rolagem horizontal
   (154 telas do sistema fazem isso hoje). Ali o max-width espremeria as
   colunas em vez de deixar rolar, que é pior do que está. A substituição
   desse padrão por cartões é trabalho da Fase 2. */
table {
    max-width: 100%;
}

.overflow-x-auto table,
.overflow-x-scroll table,
.overflow-auto table,
.mob-rolagem-h table {
    max-width: none;
}

/* Código e texto pré-formatado: quebram em vez de esticar a página. */
pre,
code,
samp,
kbd {
    max-width: 100%;
}

pre {
    overflow-x: auto;
    white-space: pre-wrap;
    word-break: break-word;
}

/* --------------------------------------------------------------------------
   3. Casca da página
   O overflow-x: hidden sai do <body> e vem para cá. No body ele escondia,
   em silêncio, qualquer conteúdo que passasse da largura da tela — que é
   justamente o defeito que este trabalho existe para achar.

   Aqui ele serve só para impedir que um elemento posicionado (um dropdown,
   um decorativo) crie barra de rolagem lateral na página inteira. O conteúdo
   de verdade encolhe pelas regras da seção 2, em vez de ser cortado.
   -------------------------------------------------------------------------- */
html .mob-casca {
    overflow-x: hidden;
}

/* Modo diagnóstico (só com DEBUG, via ?mobdiag=1).
   Solta a rolagem lateral da casca e marca os suspeitos, para o estouro
   aparecer em vez de ser cortado. Ver MOBILE_PLAN.md, seção Decisões. */
[data-mob-diag="1"] .mob-casca {
    overflow-x: auto;
}

[data-mob-diag="1"] table,
[data-mob-diag="1"] pre,
[data-mob-diag="1"] img,
[data-mob-diag="1"] .overflow-x-auto {
    outline: 2px dashed #dc2626;
    outline-offset: -2px;
}

/* --------------------------------------------------------------------------
   4. Utilitários de fundação
   Opt-in: nada aqui muda uma tela que não peça. Os padrões da Fase 2 são
   construídos em cima destes.
   -------------------------------------------------------------------------- */

/* Alvo de toque de 44x44. Em <a> e <button> que só têm um ícone.
   Só abaixo de 640px: no desktop a mira é o mouse e o botão fica do tamanho
   que a tela desenhou (regra: o desktop não muda). */
@media (max-width: 639px) {
    html .mob-toque {
        min-height: var(--mob-toque);
        min-width: var(--mob-toque);
    }

    /* Variante para quem já é largo e só precisa de altura. */
    html .mob-toque-alt {
        min-height: var(--mob-toque);
    }
}

/* Margem lateral padrão da tela. */
.mob-gutter {
    padding-left: var(--mob-gutter);
    padding-right: var(--mob-gutter);
}

/* Quebra palavra longa (chave PIX, e-mail, end-to-end id, URL) que é a
   origem mais comum de estouro em 320px. */
.mob-quebra {
    overflow-wrap: break-word;
    word-break: break-word;
}

/* Rolagem horizontal declarada — quando a tabela é numérica e rolar de lado
   é mesmo a melhor saída. Dá inércia no iOS e evita o corte pelo pai. */
html .mob-rolagem-h {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

/* Pisos de legibilidade, aplicados por quem escolhe aplicá-los. */
.mob-corpo {
    font-size: var(--mob-fonte-corpo);
}

.mob-apoio {
    font-size: var(--mob-fonte-apoio);
}

/* Some no mobile / some no desktop, para conteúdo que não é só estilo.
   Preferir sempre as classes do Tailwind (hidden lg:block); estas existem
   para uso dentro deste arquivo e dos padrões.
   São pares explícitos (bloco e flex) porque `display: revert` só chegou no
   Chrome 84 e o baseline é 80. */
html .mob-so-mobile,
html .mob-so-mobile-flex {
    display: none;
}

/* --------------------------------------------------------------------------
   5. Regras que valem só no mobile (0-639px)
   -------------------------------------------------------------------------- */
@media (max-width: 639px) {

    /* Campo com 16px: impede o zoom automático do Chrome ao focar.
       A especificidade do :not(...) é 0-1-1, então ganha de uma classe
       solta como text-sm ou text-xs sem precisar de !important. */
    input:not([type="hidden"]),
    select:not([hidden]),
    textarea:not([hidden]) {
        font-size: var(--mob-fonte-campo);
    }

    /* Nada dentro da casca pode ser mais largo que a casca.
       Isto conserta um padrão que se repete em dezenas de telas: um
       `<div class="max-w-3xl mx-auto">` como filho direto do `<main>`, que é
       `flex flex-col`. O `margin` lateral `auto` DESLIGA o `align-self: stretch`
       do flexbox, e aí o elemento passa a se dimensionar pelo conteúdo
       (`fit-content`), travando na largura máxima — 768px numa tela de 320px.
       `min-width: 0` não resolve, porque não se trata de encolher: o elemento
       nunca chegou a esticar. O seletor tem especificidade 0-1-1 e ganha do
       `.max-w-3xl` (0-1-0) sem `!important`. No desktop não vale. */
    /* `html ` na frente de propósito: dezenas de telas definem suas classes
       num `<style>` dentro do próprio template, que vem DEPOIS do mobile.css
       no documento e vence no empate de especificidade. Foi o caso do
       `.dash-wrapper { max-width: 1440px }` do dashboard de ocorrências, que
       deixava a casca com 774px numa tela de 320. Com `html ` a regra vai a
       0-1-1 e ganha sem precisar de !important. */
    html .mob-casca > * {
        max-width: 100%;
    }

    /* Título em linha flex com um complemento ao lado.
       O padrão se repete no sistema inteiro: um <h2 class="flex items-center">
       com o título e, depois, um <span> de apoio ("(válido para todos os
       materiais)", "— para onde foi", o número do lote). Sem quebra de linha
       o flex divide a largura entre os dois e, em 320px, sobram ~40px para o
       complemento, que desce uma letra por linha. Achado nos lotes M-27 a M-29
       (saida_form, entrada_form, material_form, movimentacao_detail) e
       corrigido aqui em vez de em cada template.
       `h2.flex` tem especificidade 0-1-1 e ganha de `.flex` (0-1-0) sem
       !important. Vale só até 639px: no desktop cabe na mesma linha. */
    h1.flex,
    h2.flex,
    h3.flex,
    h4.flex,
    h5.flex,
    h6.flex {
        flex-wrap: wrap;
    }

    /* Os três substitutos de <select> do projeto (Select2 em 8 telas, Tom Select
       em 26, Choices em 44) calculam a largura em JavaScript e a escrevem no
       atributo style. Estilo embutido ganha de classe, mas `width` e `max-width`
       são propriedades diferentes: o teto abaixo vale mesmo assim, e a largura
       calculada fica limitada ao pai em vez de esticar a tela. */
    .select2-container,
    .select2-selection__rendered,
    .ts-wrapper,
    .ts-control,
    .choices,
    .choices__inner {
        max-width: 100%;
    }

    /* Filho de flex/grid encolhe em vez de esticar o pai. É o motivo número
       um de rolagem lateral em layout feito para desktop. Restrito ao
       mobile de propósito: no desktop mudaria o comportamento de truncagem
       de telas que hoje estão certas. */
    .flex > *:not([class*="min-w-"]),
    .grid > *:not([class*="min-w-"]) {
        min-width: 0;
    }

    /* ...MENOS selo e icone, que nao podem encolher abaixo do proprio
       conteudo. Medido numa tela real: o selo de status recebia 48px para um
       conteudo de 78px e "NAO_OK" saia cortado; icone espremido vira glifo
       picado. Estes voltam ao minimo automatico, e quem encolhe e o texto ao
       lado, que tem para onde quebrar. */
    .flex > .inline-flex,
    .grid > .inline-flex,
    .flex > i[class*="fa-"],
    .grid > i[class*="fa-"],
    /* ...e menos CONTROLE. Botão e link numa linha de flex são comando, não
       texto corrido: encolher abaixo do rótulo só serve para picar a palavra
       ("Cancela/r", "Exclui/r", "Salvar assinat…"). `min-width: auto` num
       flex item vale o tamanho da MAIOR PALAVRA, então "Cancelar" mantém sua
       largura e quem cede é o texto ao lado, que tem onde quebrar. Quarta vez
       que este mesmo `min-width: 0` esprema um controle (Lotes A-4, A-8, A-12
       e A-14); daqui em diante é regra, não remendo por tela. */
    .flex > a,
    .grid > a,
    .flex > button,
    .grid > button,
    .flex > select,
    .grid > select {
        min-width: auto;
    }

    /* Link com cara de botão também não quebra no meio da palavra. A regra
       de `button` já existe mais abaixo; <a> não é botão para o CSS. */
    .flex > a,
    .grid > a {
        overflow-wrap: normal;
    }

    /* Palavra longa quebra por padrão no mobile. Vale para TEXTO: chave PIX,
       e-mail, NSU, URL no meio de um parágrafo. */
    body {
        overflow-wrap: break-word;
    }

    /* ...mas NÃO para selo/etiqueta. `overflow-wrap` é herdado, então a regra
       acima chegava dentro de toda pílula de status; junto com o `min-width: 0`
       dos filhos de flex (seção 5), um selo mais estreito que a própria palavra
       quebrava no meio dela — "COMUNI/CADO", "APROV/ADO", "NAO/_OK". O selo
       passa a manter a largura do conteúdo e a quebrar só no espaço.
       Descoberto medindo, no Lote A-12, depois de remendar o mesmo sintoma em
       três telas sem enxergar a origem. */
    button,
    [role="button"],
    .flex > .rounded-full,
    .grid > .rounded-full,
    .inline-flex > .rounded-full {
        overflow-wrap: normal;
    }

    /* O selo ainda precisa manter a largura do conteúdo: sem isto o
       `min-width: 0` o espreme e, sem poder quebrar, ele transborda. */
    .flex > .rounded-full,
    .grid > .rounded-full,
    .inline-flex > .rounded-full {
        min-width: auto;
    }

    /* `.status-badge` é a MESMA ideia escrita à mão: 16 templates do sistema
       definem a classe em CSS puro, com `border-radius: 9999px` — que a regra
       de `.rounded-full` acima não alcança, porque ali a pílula vem de classe
       do Tailwind. Sem isto o selo de status de `base_detail.html` saía uma
       letra por linha ("PR/O/NT/A"). Vale em qualquer pai, não só filho de
       flex, porque a classe já identifica o que o elemento é. */
    .status-badge {
        min-width: auto;
        overflow-wrap: normal;
    }

    /* Nada de toque com atraso de 300ms em aparelho antigo. */
    a,
    button,
    [role="button"],
    label,
    summary {
        touch-action: manipulation;
    }

    html .mob-so-mobile {
        display: block;
    }

    /* Ícone girando enquanto o "Atualizar o app" trabalha. Animação simples
       de transform: roda na GPU e não custa nada num aparelho de 2GB. */
    .mob-girando {
        animation: mob-girar 900ms linear infinite;
    }

    @keyframes mob-girar {
        from { transform: rotate(0deg); }
        to { transform: rotate(360deg); }
    }

    html .mob-so-mobile-flex {
        display: flex;
    }

    html .mob-so-desktop {
        display: none;
    }
}

/* --------------------------------------------------------------------------
   6. Espaço para a barra inferior (bottom nav)
   A barra é criada na Fase 2. O espaçador já fica aqui para que a última
   linha de conteúdo nunca termine embaixo dela.
   -------------------------------------------------------------------------- */
@media (max-width: 639px) {
    .mob-com-barra-inferior {
        padding-bottom: calc(var(--mob-altura-barra-inferior) + var(--mob-safe-inferior) + var(--mob-esp-4));
    }
}

/* ==========================================================================
   PADRÕES DA FASE 2 — o gatilho comum
   Filtros, ações e folha abrem e fecham com um checkbox escondido e o
   seletor de irmão. Sem JavaScript: num Android antigo em rede ruim a
   pessoa passa boa parte do tempo com a tela pronta e o script ainda
   baixando, e nesse intervalo um menu que só abre por JS não abre.
   ========================================================================== */
html .mob-gatilho {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    opacity: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
}

/* Foco pelo teclado precisa aparecer: quem enxerga o gatilho é o rótulo. */
.mob-gatilho:focus + label {
    outline: 2px solid #2563eb;
    outline-offset: 2px;
}

/* Texto que só o leitor de tela usa. */
html .mob-oculto-visual {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

/* ==========================================================================
   PADRÕES DA FASE 2
   Cada bloco daqui tem um tag correspondente em
   apps/home/templatetags/mobile_tags.py. O CSS sozinho não é o padrão: o
   padrão é o par tag + CSS, para a tela não precisar copiar classe nenhuma.
   Exemplo de uso de cada um está no MOBILE_PLAN.md e na página de kit.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Padrão 1 — Navegação mobile
   A sidebar do base.html já é off-canvas em toda largura; o que faltava era
   caber em 320px, fechar tocando fora e não deixar o fundo rolar junto.
   -------------------------------------------------------------------------- */

/* 288px é a largura de desktop (w-72). Em 320px isso deixaria 32px de fundo,
   que não é alvo de toque nem deixa ver o que está atrás. */
html .mob-sidebar {
    width: 288px;
    max-width: 85vw;
}

/* O fundo escuro da gaveta e a trava de rolagem existem SÓ no mobile.
   A visibilidade entra por classe (`mob-backdrop-visivel`), nunca por estilo
   embutido: `x-show` do Alpine escreve `style="display:..."` direto no
   elemento, e estilo embutido ganha de media query — o fundo apareceria
   também no desktop, que é mudança que ninguém aprovou. */
html .mob-backdrop {
    display: none;
}

@media (max-width: 639px) {
    html .mob-backdrop-visivel {
        position: fixed;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        display: block;
        background: rgba(2, 6, 23, .55);
        z-index: var(--mob-z-backdrop);
    }

    /* Trava a rolagem do conteúdo enquanto a gaveta está aberta. O seletor
       tem especificidade 0-1-1 para ganhar do overflow-y-auto do Tailwind. */
    main.mob-sem-rolagem {
        overflow: hidden;
    }

    /* A GAVETA TEM DE FICAR ACIMA DO FUNDO ESCURO.
       O <aside> nasce com o z-40 do Tailwind e o fundo (criado na Fase 1
       deste trabalho) tem 55: o fundo cobria a gaveta inteira, então todo
       toque dentro do menu acertava ELE — e o fundo fecha a gaveta ao ser
       tocado. Resultado: dava para abrir o menu e não dava para rolar nem
       escolher item, só fechar. Regressão introduzida por mim; medida com
       elementFromPoint em 21/09/2026.
       56 fica acima do fundo (55), da barra inferior (45) e do cabeçalho
       (50) — enquanto o menu está aberto, ele é a camada de cima. */
    html .mob-sidebar {
        /* Acima de TUDO enquanto está aberta: o fundo (10000), a barra
           inferior (45), o post-it de prazos do RH (9500) e o widget do
           assistente (9990) — todos cobriam a gaveta e roubavam o toque.
           Fechada, ela está fora da tela (translateX -100%) e não pega nada. */
        z-index: 10001;

        /* E ela COMEÇA ABAIXO do cabeçalho. Com `inset-y-0 pt-16` a caixa da
           gaveta ia até y=0 e os 64px de padding, mesmo transparentes, ficavam
           por cima do cabeçalho: com o menu aberto, o próprio botão de três
           linhas e a busca paravam de responder. Medido com elementFromPoint. */
        top: var(--mob-altura-header);
        bottom: 0;
        padding-top: 0;
    }

    /* Rolagem da gaveta: inércia no WebView antigo e sem arrastar a página
       de trás junto ao chegar no fim da lista. */
    html .mob-sidebar > div {
        -webkit-overflow-scrolling: touch;
        overscroll-behavior: contain;
    }
}

/* A APARENCIA da barra vale em qualquer largura; o que muda com o breakpoint e
   so ONDE ela fica. Separado assim, a pagina de kit consegue mostrar a barra
   inteira, do jeito certo, sem ter que desfazer regra de media query. */
html .mob-nav-inferior {
    display: none;
    background: #000;
    border-top: 1px solid rgba(255, 255, 255, .12);
    padding-bottom: var(--mob-safe-inferior);
}

html .mob-nav-item {
    flex: 1 1 0;
    min-width: 0;
    min-height: var(--mob-altura-barra-inferior);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    /* Sem folga lateral de propósito: em 320px cada item tem 64px, e "Pedidos"
       em 14px ocupa quase isso tudo. Com 2px de cada lado o rótulo estourava
       2px e era truncado — medido no aferidor, não estimado. O ellipsis abaixo
       continua como rede de segurança para um rótulo mais comprido. */
    padding: 6px 0;
    color: rgba(255, 255, 255, .62);
    text-decoration: none;
}

.mob-nav-item i {
    font-size: 18px;
    line-height: 1;
}

/* O piso de 14px do baseline vale tambem aqui. Com 5 destinos em 320px cada
   item fica com 64px, e os rotulos escolhidos ("Inicio", "Pedidos", "Avisos",
   "Escala", "Perfil") cabem em 14px — foi medido, nao estimado. A classe
   `mob-nav-n<N>` vem da tag e diz quantos destinos o usuario tem, para o dia em
   que um rotulo mais comprido precise de ajuste por quantidade. */
html .mob-nav-rotulo {
    font-size: var(--mob-fonte-apoio);
    font-weight: 600;
    line-height: 1.1;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mob-nav-item-ativo,
.mob-nav-item-ativo i {
    color: #fff;
}

@media (max-width: 639px) {
    html .mob-nav-inferior {
        position: fixed;
        right: 0;
        bottom: 0;
        left: 0;
        z-index: var(--mob-z-barra-inferior);
        display: flex;
    }
}

/* Header compacto (parte do padrão 1).
   Em 320px o cabeçalho pedia ~428px: só a logo tem `w-48` (192px), mais o botão
   de menu, a busca, o presente, o sino e o avatar, com `gap-4`/`space-x-4`
   entre eles. Resultado: estourava 27px e os ícones da direita ficavam cortados.

   As regras abaixo miram classes utilitárias do Tailwind de propósito — é o que
   a marcação usa hoje, e `.mob-header .gap-4` (0-2-0) corrige `.gap-4` (0-1-0)
   sem `!important`. Se a marcação do header mudar, isto tem que ser revisto:
   está anotado no MOBILE_PLAN.md. No desktop nada muda. */
@media (max-width: 639px) {
    .mob-header .container {
        padding-left: var(--mob-esp-2);
        padding-right: var(--mob-esp-2);
    }

    .mob-header .py-3 {
        padding-top: var(--mob-esp-2);
        padding-bottom: var(--mob-esp-2);
    }

    .mob-header img {
        max-height: 36px;
    }

    .mob-header .gap-4 {
        gap: var(--mob-esp-1);
    }

    .mob-header .space-x-4 > * + * {
        margin-left: 2px;
    }

    /* Alvo de toque nos botões do cabeçalho, sem passar dos 64px de altura
       que o `pt-16` do conteúdo reserva. */
    .mob-header button,
    .mob-header > div > div > div > a {
        min-height: 44px;
    }

    .mob-header .space-x-4 > button {
        min-width: 44px;
        justify-content: center;
    }
}

/* Avisos do cabeçalho: no celular eles vão para a gaveta.
   Decisão do dono do projeto em 18/09/2026. Medido com um usuário real (20
   atividades atrasadas, 77 de atenção), a barra do topo pedia
   `44 (menu) + 5x44 (ícones) = 264px` mais a logo, numa faixa útil de 304px em
   320px de tela: o avatar e o sino ficavam cortados e os dois alertas se
   sobrepunham. Presente, certificados e atrasadas saem da barra e aparecem no
   topo da gaveta; busca, sino e avatar ficam. Nada é escondido, só muda de
   lugar. A marcação é a MESMA (`mobile/_avisos.html` incluído nos dois
   lugares), então não há duas versões para manter em dia.
   No desktop, nada muda: a gaveta esconde o bloco e o cabeçalho o mostra. */
html .mob-avisos-gaveta {
    display: none;
}

@media (max-width: 639px) {
    html .mob-avisos-topo {
        display: none;
    }

    html .mob-avisos-gaveta {
        display: block;
        flex: 0 0 auto;
        padding: var(--mob-esp-3) var(--mob-esp-4);
        border-bottom: 1px solid rgba(255, 255, 255, .12);
    }

    .mob-avisos-gaveta-titulo {
        margin: 0 0 var(--mob-esp-2);
        font-size: 12px;
        font-weight: 700;
        letter-spacing: .06em;
        text-transform: uppercase;
        color: rgba(255, 255, 255, .55);
    }

    html .mob-avisos-gaveta-linha {
        display: flex;
        align-items: center;
        gap: var(--mob-esp-3);
        flex-wrap: wrap;
    }

    /* Cada botão de aviso vira alvo de 44px dentro da gaveta. */
    .mob-avisos-gaveta-linha > button,
    .mob-avisos-gaveta-linha > div > button {
        min-width: var(--mob-toque);
        min-height: var(--mob-toque);
    }

    /* Dentro da gaveta o painel abre EM FLUXO, empurrando o menu para baixo.
       Flutuando ele sairia dos 288px da gaveta (o de certificados tem 320px de
       largura fixa) e seria cortado pela rolagem dela. */
    .mob-avisos-gaveta .mob-aviso-painel {
        position: static;
        width: 100%;
        max-width: 100%;
        margin-top: var(--mob-esp-2);
        max-height: 50vh;
        overflow-y: auto;
        transform: none;
        left: auto;
        right: auto;
        top: auto;
    }

    /* Com os avisos fora da barra, sobra espaço: a logo volta a um tamanho que
       dá para ler. 112px é o maior valor que ainda deixa menu, busca, sino e
       avatar caberem com 44px de toque em 320px — medido, não estimado. */
    .mob-header img {
        width: 112px;
    }
}

/* Os dois botões flutuantes do base.html ("Instalar App" e "Ativar
   Notificações") nascem em `bottom-5`, que no celular é exatamente em cima da
   barra inferior e do botão de enviar de qualquer formulário. Aqui eles sobem
   para cima da barra. No desktop nada muda. */
@media (max-width: 639px) {
    html .mob-flutuante {
        bottom: calc(var(--mob-altura-barra-inferior) + var(--mob-safe-inferior) + var(--mob-esp-2));
        max-width: calc(50% - var(--mob-esp-3));
        padding-left: var(--mob-esp-3);
        padding-right: var(--mob-esp-3);
        font-size: var(--mob-fonte-apoio);
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    html .mob-flutuante-esq {
        left: var(--mob-esp-2);
    }

    html .mob-flutuante-dir {
        right: var(--mob-esp-2);
    }
}

/* --------------------------------------------------------------------------
   Padrão 2 — Tabela vira cartão
   Marque a tabela com table.mob-tabela-cartoes. O rótulo de cada célula sai do
   <th> correspondente (preenchido por mobile.js em data-rotulo), ou do
   data-rotulo escrito à mão no <td>, que sempre ganha.
   A coluna essencial é <th data-priority="1">; as demais ficam recolhidas
   atrás do botão "mais".
   -------------------------------------------------------------------------- */
html .mob-linha-mais,
html .mob-linha-mais-celula {
    display: none;
}

@media (max-width: 639px) {

    table.mob-tabela-cartoes,
    table.mob-tabela-cartoes tbody,
    table.mob-tabela-cartoes tr,
    table.mob-tabela-cartoes td {
        display: block;
        width: auto;
        max-width: none;
        /* `min-width` zerado junto com os outros: a tabela virou bloco, e bloco
           já ocupa a largura do pai sozinho. Sem isto, uma largura mínima posta
           na marcação continua valendo e o cartão nasce mais largo que a tela —
           foi o caso do `min-w-[1280px]` em `planos_acao/lista.html` (lote M-36).
           `min-w-full` (100%) nas outras telas convertidas não muda nada: bloco
           com width auto já preenche o pai. */
        min-width: 0;
    }

    table.mob-tabela-cartoes thead {
        display: none;
    }

    /* Exceção: tabela cujo cabeçalho carrega um controle (o "marcar todas").
       Escondê-lo junto com o resto tirava do celular a ação mais usada da
       tela. Aqui o cabeçalho volta, mas só a célula que tem o controle — as
       outras continuam fora, porque seus rótulos já estão dentro de cada
       cartão. O elemento é o mesmo do desktop; nada é clonado. */
    table.mob-cabecalho-visivel thead,
    table.mob-cabecalho-visivel thead tr {
        display: block;
    }

    table.mob-cabecalho-visivel thead tr {
        margin-bottom: var(--mob-esp-2);
        padding: var(--mob-esp-2) var(--mob-esp-3);
    }

    table.mob-cabecalho-visivel thead th {
        display: none;
    }

    /* 0-2-3: precisa ganhar do display: none logo acima (0-1-3).
       font-size 0: a célula costuma trazer, além da caixa, o nome da coluna
       ("#", "Comprovante") como texto solto ou num <span>. Na barra só
       interessa a caixa e o rótulo "Marcar todas"; o texto herdado some sem
       CSS saber o nome de cada tela. A caixa tem tamanho em px e o rótulo
       (::before) recebe o dele de volta logo abaixo. */
    table.mob-cabecalho-visivel thead th.mob-cabecalho-acao {
        display: flex;
        align-items: center;
        gap: var(--mob-esp-3);
        min-height: var(--mob-toque);
        padding: 0;
        border: 0;
        text-align: left;
        font-size: 0;
        line-height: 0;
    }

    table.mob-cabecalho-visivel th.mob-cabecalho-acao::before {
        content: attr(data-rotulo);
        order: 2;
        font-size: 12px;
        line-height: 1.3;
        font-weight: 600;
        color: #64748b;
        text-transform: uppercase;
    }

    table.mob-cabecalho-visivel th.mob-cabecalho-acao input[type="checkbox"],
    table.mob-cabecalho-visivel th.mob-cabecalho-acao input[type="radio"] {
        order: 1;
        width: 24px;
        height: 24px;
    }

    table.mob-tabela-cartoes tr {
        background: #fff;
        border: 1px solid #e2e8f0;
        border-radius: 10px;
        margin-bottom: var(--mob-esp-3);
        padding: var(--mob-esp-2) var(--mob-esp-3);
        overflow-wrap: break-word;
    }

    /* A celula e BLOCO e o rotulo FLUTUA a esquerda — nao e flex.
       Com flex, uma celula que tem mais de um filho (nome do pagador num <p> e
       o documento noutro, por exemplo) vira uma linha de colunas espremidas:
       cada <p> virava um item de flex e o nome quebrava no meio da palavra.
       Com float, o rotulo ocupa o canto esquerdo e TODO o resto do conteudo
       flui ao lado e por baixo dele, empilhando como foi escrito. */
    table.mob-tabela-cartoes td {
        display: block;
        padding: 6px 0;
        border: 0;
        border-bottom: 1px solid #f1f5f9;
        text-align: right;
        white-space: normal;
        font-size: var(--mob-fonte-apoio);
        overflow-wrap: break-word;
    }

    /* Fecha a caixa em volta do rotulo flutuante, senao a celula nao cresce
       quando o rotulo e mais alto que o valor. */
    table.mob-tabela-cartoes td::after {
        content: "";
        display: block;
        clear: both;
    }

    table.mob-tabela-cartoes td:last-child {
        border-bottom: 0;
    }

    /* O rótulo é a coluna estreita da esquerda; o valor fica com o resto e
       alinhado à direita, que é como se lê dinheiro e data. O valor é um nó de
       texto anônimo (não dá para selecioná-lo em CSS), então quem garante que
       ele encolhe é o `white-space: normal` acima. */
    table.mob-tabela-cartoes td::before {
        /* O rótulo é nome de coluna: uma ou duas palavras curtas. Quebrar no
           meio ("COLABORADO/R", "DATA AUTORIZAÇÃ/O") é sempre pior do que
           deixar passar alguns pixels da caixa de 60% — o valor é alinhado à
           direita e flui em volta do float, não por baixo dele. */
        word-break: normal;
        overflow-wrap: normal;
        content: attr(data-rotulo);
        float: left;
        max-width: 60%;
        padding-right: var(--mob-esp-3);
        text-align: left;
        font-size: 12px;
        font-weight: 600;
        color: #64748b;
        text-transform: uppercase;
        letter-spacing: .03em;
    }

    table.mob-tabela-cartoes td[data-rotulo] {
        text-align: right;
        overflow-wrap: break-word;
        word-break: break-word;
    }

    /* Célula sem rótulo (ações, por exemplo) ocupa a linha inteira. */
    table.mob-tabela-cartoes td:not([data-rotulo])::before {
        content: none;
    }

    /* A coluna marcada como essencial vira o título do cartão. */
    table.mob-tabela-cartoes td[data-priority="1"] {
        font-size: var(--mob-fonte-corpo);
        font-weight: 700;
        color: #0f172a;
        text-align: left;
    }

    /* No título, o rótulo sobe em vez de dividir a linha. Dividindo, sobravam
       ~110px para o valor e um nome de cliente quebrava no meio da palavra
       ("TRANSPORTAD / ORA IRMAOS"); com a linha inteira ele quebra no espaço,
       que é onde se lê. */
    table.mob-tabela-cartoes td[data-priority="1"]::before {
        float: none;
        display: block;
        max-width: none;
        margin-bottom: 2px;
        padding-right: 0;
    }

    /* Caixa de selecao dentro do cartao: no desktop ela e um alvo de mouse de
       16px, no telefone e um alvo de dedo. Cresce e ganha folga vertical para a
       linha inteira chegar aos 44px de toque. */
    table.mob-tabela-cartoes td input[type="checkbox"],
    table.mob-tabela-cartoes td input[type="radio"] {
        width: 24px;
        height: 24px;
        margin: 10px 0;
    }

    /* O resto fica recolhido até tocarem em "mais". */
    table.mob-tabela-cartoes td[data-secundaria="1"] {
        display: none;
    }

    table.mob-tabela-cartoes tr.mob-linha-aberta td[data-secundaria="1"] {
        display: block;
    }

    html .mob-linha-mais-celula {
        display: block;
        padding: 0;
        border: 0;
    }

    .mob-linha-mais-celula::before {
        content: "";
    }

    html .mob-linha-mais {
        display: block;
        width: 100%;
        min-height: var(--mob-toque);
        margin-top: 2px;
        padding: 8px 0;
        border: 0;
        border-top: 1px solid #f1f5f9;
        background: transparent;
        color: #1d4ed8;
        font-size: var(--mob-fonte-apoio);
        font-weight: 600;
        text-align: left;
        cursor: pointer;
    }
}

/* Alternativa para tabela realmente numérica: rola de lado com a primeira
   coluna presa. Marque o contêiner com .mob-tabela-fixa. */
html .mob-tabela-fixa {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

.mob-tabela-fixa table {
    max-width: none;
}

@media (max-width: 639px) {

    .mob-tabela-fixa th:first-child,
    .mob-tabela-fixa td:first-child {
        position: sticky;
        left: 0;
        z-index: 1;
        background: #fff;
        box-shadow: 1px 0 0 #e2e8f0;
    }

    .mob-tabela-fixa thead th:first-child {
        z-index: 2;
        background: #f8fafc;
    }
}

/* --------------------------------------------------------------------------
   Padrão 3 — Formulários
   -------------------------------------------------------------------------- */
@media (max-width: 639px) {

    /* Rótulo em cima, campo na largura toda. Vale para o form marcado com
       .mob-form — não é global, para não mexer em tela que já está certa. */
    .mob-form label {
        display: block;
        margin-bottom: var(--mob-esp-1);
        font-size: var(--mob-fonte-apoio);
        font-weight: 600;
        color: #334155;
    }

    .mob-form input:not([type="hidden"]):not([type="checkbox"]):not([type="radio"]),
    .mob-form select,
    .mob-form textarea {
        width: 100%;
    }

    /* Checkbox e radio ganham área de toque decente. */
    .mob-form input[type="checkbox"],
    .mob-form input[type="radio"] {
        width: 20px;
        height: 20px;
        margin-right: var(--mob-esp-2);
    }
}

html .mob-secao {
    border: 1px solid #e2e8f0;
    border-radius: 10px;
    background: #fff;
    margin-bottom: var(--mob-esp-3);
}

.mob-secao > summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--mob-esp-3);
    min-height: var(--mob-toque);
    padding: var(--mob-esp-3);
    font-size: var(--mob-fonte-corpo);
    font-weight: 600;
    color: #0f172a;
    cursor: pointer;
    list-style: none;
}

.mob-secao > summary::-webkit-details-marker {
    display: none;
}

.mob-secao > summary::after {
    content: "\f078";
    font-family: "Font Awesome 5 Free";
    font-weight: 900;
    font-size: 12px;
    color: #94a3b8;
}

.mob-secao[open] > summary::after {
    content: "\f077";
}

.mob-secao-corpo {
    padding: 0 var(--mob-esp-3) var(--mob-esp-3);
}

/* Barra de envio presa no rodapé. Só no mobile: no desktop o botão fica
   onde sempre esteve, no fim do formulário. */
html .mob-barra-envio {
    margin-top: var(--mob-esp-4);
}

@media (max-width: 639px) {
    html .mob-barra-envio {
        position: sticky;
        bottom: 0;
        z-index: calc(var(--mob-z-barra-inferior) - 2);
        /* Nada de margem negativa para "sangrar" até a borda: a tela que
           envolve o formulário tem padding próprio e desconhecido, e a margem
           negativa faz o formulário ficar mais largo que o pai — estouro de
           verdade em parte das 451 telas. A barra ocupa a largura do
           contêiner, que é o que sempre cabe. */
        margin: var(--mob-esp-4) 0 0;
        padding: var(--mob-esp-3);
        padding-bottom: calc(var(--mob-esp-3) + var(--mob-safe-inferior));
        background: #fff;
        border-top: 1px solid #e2e8f0;
        box-shadow: 0 -4px 12px rgba(2, 6, 23, .06);
    }

    .mob-barra-envio button,
    .mob-barra-envio [type="submit"] {
        width: 100%;
        min-height: var(--mob-toque);
    }
}

/* Erro visível sem precisar rolar. */
.mob-erro {
    display: block;
    margin-top: var(--mob-esp-1);
    font-size: var(--mob-fonte-apoio);
    font-weight: 600;
    color: #b91c1c;
}

.mob-resumo-erros {
    border: 1px solid #fecaca;
    border-left: 4px solid #dc2626;
    border-radius: 8px;
    background: #fef2f2;
    color: #991b1b;
    padding: var(--mob-esp-3);
    margin-bottom: var(--mob-esp-4);
    font-size: var(--mob-fonte-apoio);
}

.mob-resumo-erros ul {
    margin: var(--mob-esp-2) 0 0;
    padding-left: var(--mob-esp-5);
}

/* --------------------------------------------------------------------------
   Padrão 4 — Filtros e busca
   No desktop o painel é o que sempre foi. No mobile vira painel recolhido,
   aberto por um botão que mostra quantos filtros estão valendo.
   -------------------------------------------------------------------------- */
html .mob-filtros-botao {
    display: none;
}

.mob-filtros-contador {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    margin-left: var(--mob-esp-2);
    border-radius: 9999px;
    background: #dc2626;
    color: #fff;
    font-size: 12px;
    font-weight: 700;
}

@media (max-width: 639px) {
    html .mob-filtros-botao {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 100%;
        min-height: var(--mob-toque);
        margin-bottom: var(--mob-esp-3);
        padding: 0 var(--mob-esp-4);
        border: 1px solid #cbd5e1;
        border-radius: 10px;
        background: #fff;
        color: #0f172a;
        font-size: var(--mob-fonte-corpo);
        font-weight: 600;
    }

    .mob-filtros-botao i {
        margin-right: var(--mob-esp-2);
        color: #64748b;
    }

    html .mob-filtros-painel {
        display: none;
    }

    .mob-gatilho:checked ~ .mob-filtros-painel {
        display: block;
    }
}

/* --------------------------------------------------------------------------
   Padrão 5 — Ações por registro
   No desktop os botões seguem lado a lado. No mobile viram um menu.
   -------------------------------------------------------------------------- */
html .mob-acoes-botao {
    display: none;
}

html .mob-acoes-lista {
    display: flex;
    align-items: center;
    gap: var(--mob-esp-2);
}

@media (max-width: 639px) {
    html .mob-acoes {
        position: relative;
    }

    html .mob-acoes-botao {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-width: var(--mob-toque);
        min-height: var(--mob-toque);
        border: 1px solid #e2e8f0;
        border-radius: 10px;
        background: #fff;
        color: #334155;
    }

    html .mob-acoes-lista {
        position: absolute;
        top: calc(100% + 4px);
        right: 0;
        z-index: var(--mob-z-folha);
        display: none;
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        min-width: 200px;
        padding: var(--mob-esp-1);
        border: 1px solid #e2e8f0;
        border-radius: 10px;
        background: #fff;
        box-shadow: 0 12px 28px rgba(2, 6, 23, .18);
    }

    .mob-gatilho:checked ~ .mob-acoes-lista {
        display: flex;
    }

    .mob-acoes-lista > * {
        display: flex;
        align-items: center;
        gap: var(--mob-esp-2);
        width: 100%;
        min-height: var(--mob-toque);
        padding: 0 var(--mob-esp-3);
        border-radius: 8px;
        font-size: var(--mob-fonte-corpo);
        text-align: left;
    }
}

/* --------------------------------------------------------------------------
   Padrão 6 — Modal vira folha de baixo
   -------------------------------------------------------------------------- */
html .mob-folha-fundo {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: var(--mob-z-folha);
    display: none;
    align-items: center;
    justify-content: center;
    padding: var(--mob-esp-4);
    background: rgba(2, 6, 23, .55);
}

.mob-gatilho:checked ~ .mob-folha-fundo {
    display: flex;
}

/* O tapa-fundo é um rótulo do mesmo gatilho: tocar fora fecha, sem script. */
.mob-folha-tapa {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    cursor: pointer;
}

html .mob-folha {
    position: relative;
    display: flex;
    flex-direction: column;
    width: 100%;
    max-width: 640px;
    max-height: 90vh;
    border-radius: 14px;
    background: #fff;
    box-shadow: 0 24px 48px rgba(2, 6, 23, .28);
}

html .mob-folha-topo {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--mob-esp-3);
    flex: 0 0 auto;
    padding: var(--mob-esp-3) var(--mob-esp-4);
    border-bottom: 1px solid #e2e8f0;
}

.mob-folha-titulo {
    font-size: var(--mob-fonte-corpo);
    font-weight: 700;
    color: #0f172a;
}

.mob-folha-fechar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    min-width: var(--mob-toque);
    min-height: var(--mob-toque);
    border: 0;
    border-radius: 10px;
    background: #f1f5f9;
    color: #334155;
}

html .mob-folha-corpo {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: var(--mob-esp-4);
}

@media (max-width: 639px) {
    html .mob-folha-fundo {
        align-items: flex-end;
        padding: 0;
    }

    html .mob-folha {
        max-width: none;
        max-height: 92vh;
        border-radius: 16px 16px 0 0;
    }

    /* O fechar fica embaixo, ao alcance do polegar, e não no topo direito. */
    html .mob-folha-topo {
        order: 2;
        border-top: 1px solid #e2e8f0;
        border-bottom: 0;
        padding-bottom: calc(var(--mob-esp-3) + var(--mob-safe-inferior));
    }

    html .mob-folha-corpo {
        order: 1;
        padding: var(--mob-esp-4) var(--mob-gutter);
    }

    .mob-folha-fechar {
        min-width: 0;
        flex: 1 1 auto;
        font-weight: 600;
    }
}

/* O modal global do base.html (o que o HTMX preenche) recebe o mesmo
   tratamento sem precisar tocar em nenhuma das telas que o usam: no mobile
   ele encosta embaixo, rola por dentro e não estoura a altura da tela.
   Só propriedades de caixa — nada de `display`, senão o `hidden` do Tailwind,
   que é quem abre e fecha esse modal, pararia de funcionar. */
@media (max-width: 639px) {
    html .mob-modal-global {
        align-items: flex-end;
        padding: 0;
    }

    html .mob-modal-global-corpo {
        max-width: none;
        max-height: 92vh;
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
        border-top-left-radius: 16px;
        border-top-right-radius: 16px;
        border-bottom-right-radius: 0;
        border-bottom-left-radius: 0;
    }
}

/* --------------------------------------------------------------------------
   Padrão 7 — Dashboard e gráfico
   -------------------------------------------------------------------------- */
html .mob-cards {
    display: grid;
    gap: var(--mob-esp-3);
    grid-template-columns: repeat(4, minmax(0, 1fr));
}

html .mob-grafico {
    position: relative;
    width: 100%;
}

.mob-grafico canvas {
    max-width: 100%;
}

@media (max-width: 1023px) {
    html .mob-cards {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 639px) {
    html .mob-cards {
        grid-template-columns: minmax(0, 1fr);
    }

    html .mob-grafico {
        min-height: 220px;
    }
}

/* --------------------------------------------------------------------------
   Padrão 8 — Paginação
   -------------------------------------------------------------------------- */
html .mob-paginacao {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--mob-esp-2);
    margin-top: var(--mob-esp-4);
}

.mob-paginacao-link,
.mob-paginacao-inativo {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: var(--mob-toque);
    min-height: var(--mob-toque);
    padding: 0 var(--mob-esp-3);
    border: 1px solid #cbd5e1;
    border-radius: 10px;
    background: #fff;
    color: #0f172a;
    font-size: var(--mob-fonte-apoio);
    font-weight: 600;
    text-decoration: none;
}

.mob-paginacao-inativo {
    color: #cbd5e1;
    background: #f8fafc;
}

.mob-paginacao-posicao {
    flex: 1 1 auto;
    text-align: center;
    font-size: var(--mob-fonte-apoio);
    color: #475569;
    font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------------------
   Padrão 9 — Mensagens
   As mensagens do Django não podem cobrir conteúdo nem as barras fixas.
   -------------------------------------------------------------------------- */
@media (max-width: 639px) {
    .mob-mensagens > * {
        font-size: var(--mob-fonte-apoio);
    }

    /* Quando a tela tem barra inferior, o conteúdo precisa terminar acima
       dela. A classe entra no <body> pela tag da barra, não à mão. */
    .mob-tem-barra-inferior main {
        padding-bottom: calc(var(--mob-altura-barra-inferior) + var(--mob-safe-inferior) + var(--mob-esp-4));
    }
}
