/* Design system. Mobile-first: o base descreve o telefone, telas maiores entram por
   `@media (min-width: ...)` — comecar pelo desktop produz o layout que "quase funciona"
   no celular. Nenhum valor literal de cor, espacamento ou raio: tudo vem de tokens.css.
   Componentes ao vivo em /styleguide. */

@import url("tokens.css");

/* --- 1. Base ----------------------------------------------------------------------- */

*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    /* Compensa a topbar fixa quando o navegador rola ate uma ancora. */
    scroll-padding-top: calc(var(--altura-topbar) + var(--e-4));
}

body {
    margin: 0;
    background: var(--bg);
    color: var(--text);
    font-family: var(--font-sans);
    font-size: var(--texto-base);
    line-height: var(--altura-linha);
    letter-spacing: var(--tracking-normal);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    /* Impede que o iOS aumente a fonte sozinho ao girar a tela. */
    -webkit-text-size-adjust: 100%;
}

/* --- 2. Tipografia ----------------------------------------------------------------- */

h1, h2, h3, h4 {
    margin: 0 0 var(--e-3);
    font-weight: 700;
    letter-spacing: var(--tracking-titulo);
    line-height: 1.15;
    /* Titulo com palavra longa (URL, identificador, termo tecnico) empurraria a pagina inteira
       para os lados no celular — principalmente com a fonte do sistema ampliada, que e' uma
       configuracao comum de acessibilidade. */
    overflow-wrap: break-word;
}

h1 { font-size: clamp(1.75rem, 5vw, 2.5rem); }
h2 { font-size: clamp(1.375rem, 3.5vw, 1.75rem); }
h3 { font-size: 1.1875rem; }
h4 { font-size: 1rem; }

p { margin: 0 0 var(--e-4); }

a {
    color: var(--blue);
    text-decoration: none;
}
a:hover {
    color: var(--blue-hover);
    text-decoration: underline;
}

/* Linha de apoio do titulo. Largura limitada porque linha longa demais cansa: o olho
   perde o inicio da proxima. */
.lead {
    font-size: 1.125rem;
    color: var(--text-2);
    /* Palavra composta por barra ("combustivel/lubrificante", "maiuscula/minuscula") nao tem
       ponto de quebra: a barra nao e' um. Com a fonte do sistema a 2rem, um token desses no
       paragrafo de apoio empurra a pagina — `/cadastros/custo-terminal` foi a 463px numa janela
       de 390px. `anywhere`, e nao `break-word`, porque so' ele reduz a largura MINIMA do texto,
       que e' o que decide se o bloco encolhe ou empurra.
       No tamanho normal isso nunca dispara: o texto so' quebra quando o token de fato nao cabe. */
    overflow-wrap: anywhere;
    max-width: 62ch;
}

/* Rotulo curto em caixa alta acima de um titulo. Em caixa alta o espacamento entre
   letras precisa ser POSITIVO — o negativo, que ajuda em peso alto, aqui embola. */
.kicker {
    display: block;
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--tracking-caixa-alta);
    color: var(--text-3);
    margin-bottom: var(--e-2);
}

.texto-2 { color: var(--text-2); }
.texto-3 { color: var(--text-3); }
.mono { font-family: var(--font-mono); font-size: 0.875em; }
.num { text-align: right; font-variant-numeric: tabular-nums; }
.centro { text-align: center; }

/* Coluna de leitura. Linha longa demais cansa: o olho perde o inicio da proxima. */
.texto-longo { max-width: 70ch; }

/* --- Bloco de codigo -----------------------------------------------------------
   `min-width: 0` e' o que faz a rolagem interna funcionar de verdade: sem isso, um
   item de grid ou flex tem largura minima igual ao seu conteudo, entao o bloco
   empurra a pagina inteira para os lados em vez de rolar sozinho. */
.bloco-codigo {
    margin: 0;
    min-width: 0;
    max-width: 100%;
    overflow-x: auto;
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    line-height: 1.6;
}
.bloco-codigo code { white-space: pre; }

/* `<code>` SOLTO na prosa (uma referencia de celula, um caminho de arquivo, um identificador) e'
   um token longo sem espaco por natureza — e um token que nao quebra nao encolhe, empurra. Com a
   fonte do sistema ampliada a 2rem, `TarifaReajuste!W,X:AI` no paragrafo de apoio levou a tela de
   tarifas a 497px numa janela de 390px: rolagem lateral na PAGINA, proibida pela decisao de
   arquitetura.

   Nao e' caso isolado: duas entregas seguidas tropecaram nisso, e a primeira "resolveu" tirando o
   caminho do texto. A regra fica aqui para nao depender de ninguem lembrar. `.bloco-codigo`
   continua com `white-space: pre` e rola sozinho — la' a quebra estragaria o codigo. */
:not(.bloco-codigo) > code { overflow-wrap: anywhere; }

/* --- 3. Layout --------------------------------------------------------------------- */

.container {
    width: 100%;
    max-width: var(--container);
    margin: 0 auto;
    padding: var(--e-6) var(--gutter);
}

.hero { margin-bottom: var(--e-7); }

.pilha > * + * { margin-top: var(--e-4); }

/* Espacamento de FLUXO: o respiro entre um bloco e o proximo e' o PADRAO da pagina, e nao mais um
   opt-in que 71 telas em 91 esqueciam de pedir (`.pilha`/`.secao` só em 20) — e' exatamente por
   isso que formulario, avisos e tabela apareciam colados uns nos outros em telas como
   `/relatorios/margem`. Duas escalas, os MESMOS tokens que ja regiam os componentes explicitos:

   - Entre os blocos GRANDES da pagina — a trilha, a `.hero`, cada `<section>` de primeiro nivel —
     `--e-7`. Generaliza o `.secao + .secao` logo abaixo (mantido: ele e' quem cobre uma `.secao`
     ANINHADA dentro de outra secao, fora do alcance de "filho direto do container").
   - DENTRO de uma secao, entre os elementos que ela contem (barra de filtro, aviso, grade,
     tabela, paginacao...) — `--e-4`, no mesmo grau do `.pilha > * + *` acima, so' que sem
     precisar da classe.

   Titulo (h1-h4) fica de fora dos dois lados dos dois seletores: ele nao EMPURRA o proximo
   elemento com o valor generico daqui (a distancia entre um titulo e o que vem depois e' o
   `margin-bottom` dele mesmo, ja pensado por nivel — `--e-3` no h1-h4, ver #2 acima), nem RECEBE
   margem de cima daqui (a margem acima de um titulo vem so' do elemento anterior — nada, ou algo
   com margem propria e deliberadamente menor, como o `.kicker`). Um titulo que preceda OU siga
   este seletor continua exatamente como sempre foi.

   Margem de bloco COLAPSA com a do vizinho (nao soma): `.hero { margin-bottom: --e-7 }` seguido
   de outra secao com o `margin-top: --e-7` daqui rende UM `--e-7`, nao dois — e' por isso que as
   20 telas que ja usavam `.secao`/`.pilha` no lugar certo nao mudam em nada visivel: o navegador
   sempre ficava com o MAIOR dos dois valores, e aqui os dois valores sao iguais. */
.container > *:not(h1, h2, h3, h4) + *:not(h1, h2, h3, h4) { margin-top: var(--e-7); }
section > *:not(h1, h2, h3, h4) + *:not(h1, h2, h3, h4) { margin-top: var(--e-4); }

.linha {
    display: flex;
    flex-wrap: wrap;
    gap: var(--e-3);
    align-items: center;
}
/* `.linha` numa CELULA de tabela nao pode quebrar. Fora da tabela, quebrar e' o certo (o espaco
   e' a largura da pagina); dentro, a largura da coluna e' NEGOCIADA pelo navegador contra as
   outras colunas, e uma coluna que aceita quebrar e' a primeira a ser espremida — o algoritmo de
   auto-layout entrega menos espaco justamente porque o conteudo "cabe" empilhado.

   Medido em 1280px, na listagem de fluxos (a de mais colunas):
       sem a regra    coluna 116px, os dois botoes em 2 linhas, altura da linha 118px
       com a regra    coluna 207px, 1 linha,                    altura da linha  78px
   Nas outras cinco listagens nao muda nada — la' a coluna ja' recebia 221-315px e cabia numa
   linha so'. A tabela ja' rola dentro do `.table-scroll`, entao nada se perde na horizontal; o
   que se ganha e' 34% de altura por linha, numa tela cujo trabalho e' conferir linha a linha
   contra o Excel. */
table.tabular td.linha { flex-wrap: nowrap; }

.linha-fim { justify-content: flex-end; }
.entre { justify-content: space-between; }
.crescer { flex: 1; }

/* Grade que se adapta sozinha: sem media query, as colunas cabem conforme o espaco. */
.grade {
    display: grid;
    gap: var(--e-4);
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}

/* Uma `.secao` ANINHADA dentro de outra `<section>` (duas subsecoes de uma mesma tela, cada uma
   com seu proprio `<h2>` — ex.: as duas grades de "Tarifa-base" e "Tarifa de crossdocking" em
   `/cadastros/tarifas`) nao e' filha direta do `.container`, entao a regra generica de cima nao
   a alcanca. Especificidade de classe (0,1,0) vence a de elemento (0,0,3) de proposito, para dar
   a estas subsecoes o respiro MAIOR de bloco grande (`--e-7`), e nao o `--e-4` de um item comum
   dentro de uma secao.

   O seletor e' `* + .secao`, e nao `.secao + .secao`: quem manda no respiro e' o que COMECA, nao
   o que termina. Medido em `/cadastros/tarifas`: a PRIMEIRA subsecao vem depois de um
   `div.table-scroll` (a tabela de cima), que nao carrega `.secao` — com o par exigindo a classe
   dos dois lados ela caia na regra generica e abria 16px, enquanto a SEGUNDA subsecao, essa sim
   precedida por uma `.secao`, abria 48px. A pagina apertava justamente onde troca de assunto, e
   so' no primeiro dos dois blocos irmaos. Mesmo padrao de template em custo_terminal, reajustes,
   ad_valorem, rotas_rodo, tarifas_custo e custo_ferro. */
* + .secao { margin-top: var(--e-7); }

/* --- 4. App shell — topbar, sidebar, conteudo -------------------------------------- */

.app {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

/* --- Topbar ------------------------------------------------------------------- */
.topbar {
    position: sticky;
    top: 0;
    z-index: 30;
    display: flex;
    align-items: center;
    gap: var(--e-3);
    height: var(--altura-topbar);
    padding: 0 var(--gutter);
    background: var(--surface-1);
    border-bottom: 1px solid var(--separator);
}

.topbar-marca {
    font-weight: 700;
    letter-spacing: var(--tracking-titulo);
    color: var(--text);
    /* A marca cede espaco e trunca; os controles a direita, nao. Com a fonte do sistema
       ampliada (configuracao comum de acessibilidade), "Framework" + "Entrar" + o botao de
       tema nao cabem em 390px — e sem estas tres linhas a barra empurra a pagina inteira
       para os lados. Truncar o nome e' o unico dos tres que nao impede ninguem de agir. */
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.topbar-marca:hover { text-decoration: none; color: var(--text); }

.topbar-acoes {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: var(--e-2);
    /* Nao encolhe: um botao espremido vira alvo de toque menor que os 44px exigidos. */
    flex: none;
}

/* O nome do usuario tambem cede espaco antes de a barra estourar. */
.topbar-acoes .btn-pequeno {
    max-width: 40vw;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: inline-block;
    line-height: 36px;
}

/* Abaixo de 900px a sidebar e' off-canvas e a barra fica apertada. Com a fonte do sistema
   ampliada, "Administrador" + "Sair" + o botao de tema passam de 375px mesmo com o nome
   truncado — e como `.topbar-acoes` nao encolhe (alvo de toque), a pagina inteira ganhava
   rolagem horizontal. O nome sai: e' o unico dos tres que nao e' acao, e a mesma conta esta
   a um toque no menu (Conta > Configuracoes). */
@media (max-width: 899px) {
    /* Dois niveis de classe de proposito: `.topbar-acoes .btn-pequeno` acima define
       `display: inline-block`, e um seletor de uma classe so' perderia para ele. */
    .topbar-acoes .topbar-nome { display: none; }
}

/* --- Sino de notificacoes -------------------------------------------------------
   O contador e' um badge posicionado sobre o icone. `position: relative` no link e' o que
   ancora o `absolute` do contador — sem ele o badge se prenderia a pagina inteira. */
.sino {
    position: relative;
    flex: none;
}
.sino-contador {
    position: absolute;
    top: 2px;
    right: 0;
    min-width: 18px;
    padding: 0 4px;
    border-radius: var(--r-pill);
    background: var(--red);
    color: var(--sobre-cor);
    font-size: 0.6875rem;
    font-weight: 700;
    line-height: 18px;
    text-align: center;
    /* Cor sozinha nao comunica (WCAG 1.4.1): o numero e' a informacao, o vermelho so' chama
       atencao. Quem nao distingue a cor continua lendo a contagem. */
    pointer-events: none;
}

/* --- Lista de notificacoes ------------------------------------------------------ */
.lista-notificacoes {
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: var(--e-2);
}
.notificacao {
    display: flex;
    align-items: flex-start;
    gap: var(--e-3);
    flex-wrap: wrap;
    padding: var(--e-4);
    background: var(--surface-1);
    border: 1px solid var(--separator);
    /* `--r-2` nao existe em `tokens.css` e nunca existiu: o navegador descartava a declaracao
       inteira e o cartao ficava de canto reto, sem erro em lugar nenhum. Os raios do sistema sao
       `--r-sm/--r-md/--r-lg`; este cartao tem o mesmo peso de `.mudanca` e do disclosure, entao
       `--r-md`. Ha' teste varrendo variavel usada e nao definida (`tests/test_css.py`). */
    border-radius: var(--r-md);
}
.notificacao-corpo {
    /* `min-width: 0` para o texto longo truncar em vez de empurrar o botao para fora. */
    flex: 1;
    min-width: 0;
}
.notificacao-titulo {
    display: flex;
    align-items: center;
    gap: var(--e-2);
    flex-wrap: wrap;
    font-weight: 600;
    color: var(--text);
}
/* Barra lateral colorida, e nao so' fundo diferente: sobrevive ao modo de alto contraste. */
.notificacao-nao-lida { border-left: 3px solid var(--blue); }

/* --- Sidebar -------------------------------------------------------------------
   No telefone a navegacao e' uma gaveta escondida, aberta pelo botao da topbar; a
   partir de 900px ela vira coluna fixa e o botao some. Um unico HTML nos dois casos:
   sem duplicar menu, nao ha como um lado ficar desatualizado. */
.sidebar {
    position: fixed;
    inset: var(--altura-topbar) auto 0 0;
    z-index: 25;
    width: var(--largura-sidebar);
    max-width: 85vw;
    padding: var(--e-4) var(--e-3);
    background: var(--surface-1);
    border-right: 1px solid var(--separator);
    overflow-y: auto;
    transform: translateX(-100%);
    transition: transform var(--t-media) var(--easing);
}

.sidebar[data-aberta="true"] { transform: translateX(0); }

.sidebar-grupo + .sidebar-grupo { margin-top: var(--e-5); }

.sidebar-titulo {
    font-size: 0.6875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--tracking-caixa-alta);
    color: var(--text-3);
    padding: 0 var(--e-3);
    margin-bottom: var(--e-2);
}

.sidebar-link {
    display: flex;
    align-items: center;
    gap: var(--e-3);
    min-height: var(--alvo-toque);
    padding: 0 var(--e-3);
    border-radius: var(--r-sm);
    color: var(--text-2);
    font-size: 0.9375rem;
    transition: background var(--t-rapida) var(--easing),
                color var(--t-rapida) var(--easing);
}

.sidebar-link:hover {
    background: var(--surface-2);
    color: var(--text);
    text-decoration: none;
}

/* `aria-current="page"` e' o que o leitor de tela anuncia; usar o MESMO atributo como
   gancho de estilo garante que o destaque visual e o anuncio nunca divirjam. */
.sidebar-link[aria-current="page"] {
    background: var(--blue-suave);
    color: var(--blue);
    font-weight: 600;
}

/* Escurece o conteudo quando a gaveta esta aberta no telefone. */
.sidebar-fundo {
    position: fixed;
    inset: var(--altura-topbar) 0 0 0;
    z-index: 24;
    background: var(--overlay);
    border: 0;
    padding: 0;
    cursor: pointer;
}

.conteudo {
    flex: 1;
    width: 100%;
    min-width: 0;
}

@media (min-width: 900px) {
    .sidebar {
        position: sticky;
        inset: auto;
        top: var(--altura-topbar);
        height: calc(100vh - var(--altura-topbar));
        transform: none;
        transition: none;
    }
    .app-corpo {
        display: grid;
        grid-template-columns: var(--largura-sidebar) 1fr;
        align-items: start;
    }
    .abre-menu,
    .sidebar-fundo { display: none; }
}

/* --- 5. Botoes --------------------------------------------------------------------- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--e-2);
    /* WCAG 2.5.5: alvo de toque nunca menor que 44px. */
    min-height: var(--alvo-toque);
    padding: 0 var(--e-5);
    border: 0;
    border-radius: var(--r-pill);
    background: var(--surface-2);
    color: var(--text);
    font-family: inherit;
    font-size: 0.9375rem;
    font-weight: 600;
    letter-spacing: var(--tracking-normal);
    text-align: center;
    cursor: pointer;
    transition: background var(--t-rapida) var(--easing),
                opacity var(--t-rapida) var(--easing);
}

.btn:hover { background: var(--surface-3); text-decoration: none; color: var(--text); }
.btn:active { opacity: 0.8; }

.btn[disabled],
.btn[aria-disabled="true"] {
    opacity: 0.45;
    cursor: not-allowed;
    pointer-events: none;
}

/* Um unico botao primario por secao: se tudo e' primario, nada e'. */
.btn-primario { background: var(--blue-solido); color: var(--sobre-cor); }
.btn-primario:hover { background: var(--blue-solido-hover); color: var(--sobre-cor); }

.btn-perigo { background: var(--red-solido); color: var(--sobre-cor); }
.btn-perigo:hover { background: var(--red-solido); color: var(--sobre-cor); opacity: 0.85; }

.btn-vazado {
    background: transparent;
    border: 1px solid var(--separator-strong);
    color: var(--text);
}
.btn-vazado:hover { background: var(--surface-2); }

.btn-discreto { background: transparent; color: var(--text-2); }
.btn-discreto:hover { background: var(--surface-2); color: var(--text); }

.btn-pequeno {
    min-height: 36px;
    padding: 0 var(--e-4);
    font-size: 0.875rem;
}

/* Com o DEDO, `.btn-pequeno` volta aos 44px da regra (WCAG 2.5.5). Ele e' a acao principal de
   toda listagem — "Editar", "Excluir", "Concluir" —, e 36px erra o alvo com frequencia.
   `pointer: coarse` e nao largura de tela: janela estreita no desktop continua com mouse
   preciso, e tablet largo continua sendo dedo. */
@media (pointer: coarse) {
    .btn-pequeno { min-height: var(--alvo-toque); }
}

/* Botao apenas com icone: quadrado, e o texto acessivel vai no aria-label.
   `border: 0` sozinho, e nao so' herdado de `.btn`: o hamburguer (`abre-menu`) e o alternador de
   tema (`data-alterna-tema`) usam SO' `.btn-icone`, sem `.btn` — sem esta linha o navegador
   aplicava a borda nativa de `<button>` (2px outset preto) nos dois, em toda pagina do sistema. */
.btn-icone {
    width: var(--alvo-toque);
    min-height: var(--alvo-toque);
    /* A `.topbar` e' flex, e `width` sozinho e' so' a base: sem esta linha o navegador ESPREME o
       botao quando o conteudo da barra nao cabe. Medido em 390px com o titulo atual ("Brado —
       Orcamento e Pricing", 173px): o hamburguer caiu para 28,12px — 36% abaixo do minimo da
       WCAG 2.5.5 — enquanto o alternador de tema, protegido por estar dentro de um `<form>`,
       ficou nos 44px. O alvo de toque e' justamente o que NAO pode ceder: quem perde o espaco
       e' o texto ao lado, que ja' tem para onde encolher. */
    flex-shrink: 0;
    padding: 0;
    border: 0;
    border-radius: var(--r-sm);
    background: transparent;
    color: var(--text-2);
    font-size: 1.125rem;
}
.btn-icone:hover { background: var(--surface-2); color: var(--text); }

/* --- 6. Formularios ---------------------------------------------------------------- */

.campo { margin-bottom: var(--e-5); }

.campo > label {
    display: block;
    margin-bottom: var(--e-2);
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--text-2);
}

.campo input,
.campo select,
.campo textarea {
    width: 100%;
    min-height: var(--alvo-toque);
    line-height: 1.25;
    padding: var(--e-3) var(--e-4);
    background: var(--surface-1);
    border: 1px solid var(--separator-strong);
    border-radius: var(--r-md);
    color: var(--text);
    font-family: inherit;
    /* 16px minimo: abaixo disso o Safari do iPhone da' zoom sozinho ao focar o campo. */
    font-size: 1rem;
    transition: border-color var(--t-rapida) var(--easing);
}

/* ALTURA FIXA no que e' de uma linha so'. MEDIDO no navegador: com o mesmo padding e a mesma
   fonte, um `input` dava 45px e um `select` 47px, porque o `line-height: normal` de cada controle
   resolve diferente. Dois pixels entre campos irmaos, lado a lado, em 25 telas — invisivel de
   perto, e e' o que faz um formulario parecer montado por duas pessoas. O padding vertical sai
   junto: com altura fixa o texto ja' centraliza sozinho, e mante-lo so' brigaria com a altura.
   E' a mesma receita que `.busca input` (barra de listagem) ja' usava e por isso pousava certo. */
.campo input:not([type="checkbox"]),
.campo select {
    height: var(--alvo-toque);
    padding: 0 var(--e-4);
}

/* A area de texto e' a excecao: ela cresce, entao mantem o respiro vertical. */
.campo textarea { min-height: 120px; padding: var(--e-3) var(--e-4); resize: vertical; }

.campo input:focus,
.campo select:focus,
.campo textarea:focus { border-color: var(--blue); }

.campo input::placeholder,
.campo textarea::placeholder { color: var(--text-3); }

.campo input[aria-invalid="true"],
.campo select[aria-invalid="true"],
.campo textarea[aria-invalid="true"] { border-color: var(--red); }

.campo-ajuda {
    display: block;
    margin-top: var(--e-2);
    font-size: 0.8125rem;
    color: var(--text-3);
}

/* O erro traz um simbolo alem da cor: quem nao distingue vermelho tambem precisa
   saber que este campo falhou (WCAG 1.4.1). */
.campo-erro {
    display: flex;
    align-items: flex-start;
    gap: var(--e-2);
    margin-top: var(--e-2);
    font-size: 0.8125rem;
    color: var(--red);
}
.campo-erro::before { content: "✗"; font-weight: 700; }

.campo-linha {
    display: grid;
    gap: var(--e-4);
    grid-template-columns: 1fr;
}
@media (min-width: 620px) {
    .campo-linha { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
}

/* Caixa de marcacao e radio: rotulo clicavel inteiro, com area de toque adequada. */
.campo-marcar {
    display: flex;
    align-items: center;
    gap: var(--e-3);
    min-height: var(--alvo-toque);
    cursor: pointer;
}
.campo-marcar input {
    width: 20px;
    height: 20px;
    min-height: 0;
    margin: 0;
    accent-color: var(--blue);
    flex: none;
}
.campo-marcar span { font-size: 0.9375rem; color: var(--text); }

fieldset {
    margin: 0 0 var(--e-5);
    padding: 0;
    border: 0;
}
legend {
    padding: 0;
    margin-bottom: var(--e-3);
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--text-2);
}

.form-acoes {
    display: flex;
    flex-wrap: wrap;
    gap: var(--e-3);
    margin-top: var(--e-5);
}

/* --- 7. Cards ---------------------------------------------------------------------- */

.card {
    display: block;
    background: var(--surface-1);
    border: 1px solid var(--separator);
    border-radius: var(--r-lg);
    overflow: hidden;
    /* Item de grid tem largura minima igual ao conteudo por padrao. Sem este `min-width: 0`, um
       card com bloco de codigo ou palavra longa estica a grade e empurra a pagina inteira para os
       lados no celular, em vez de o conteudo rolar dentro dele. */
    min-width: 0;
}

.card-topo {
    display: flex;
    align-items: center;
    gap: var(--e-3);
    padding: var(--e-4) var(--e-5);
    border-bottom: 1px solid var(--separator);
}
.card-topo h2,
.card-topo h3 { margin: 0; font-size: 1rem; }

.card-corpo { padding: var(--e-5); }

.card-rodape {
    padding: var(--e-4) var(--e-5);
    border-top: 1px solid var(--separator);
    background: var(--surface-2);
}

a.card { color: inherit; }
a.card:hover {
    text-decoration: none;
    border-color: var(--separator-strong);
}

/* --- 8. Badges --------------------------------------------------------------------- */

.badge {
    display: inline-flex;
    align-items: center;
    gap: var(--e-1);
    padding: 0.125rem var(--e-3);
    border-radius: var(--r-pill);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0;
    /* Fundo translucido com o texto na cor pura. Badge solido rouba atencao de tudo
       em volta e some quando ha varios lado a lado. */
    background: var(--surface-2);
    color: var(--text-2);
    white-space: nowrap;
}

.badge-sucesso { background: var(--green-suave); color: var(--green-sobre-suave); }
.badge-info    { background: var(--blue-suave);   color: var(--blue-sobre-suave); }
.badge-atencao { background: var(--orange-suave); color: var(--orange-sobre-suave); }
.badge-erro    { background: var(--red-suave);    color: var(--red-sobre-suave); }

/* --- 9. Metricas ------------------------------------------------------------------- */

.metrica { display: flex; flex-direction: column; gap: var(--e-1); }

.metrica-rotulo {
    font-size: 0.6875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--tracking-caixa-alta);
    color: var(--text-3);
}

.metrica-valor {
    font-size: 2rem;
    font-weight: 700;
    letter-spacing: var(--tracking-titulo);
    /* Digitos de mesma largura: sem isso o numero "pula" a cada atualizacao. */
    font-variant-numeric: tabular-nums;
    line-height: 1.1;
}

.metrica-unidade {
    font-size: 0.42em;
    font-weight: 600;
    color: var(--text-3);
    margin-left: var(--e-1);
}

/* --- 10. Tabelas ------------------------------------------------------------------- */

/* Toda tabela vai dentro deste involucro: no telefone ela rola na horizontal em vez
   de espremer as colunas ate ficarem ilegiveis. */
.table-scroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    border: 1px solid var(--separator);
    border-radius: var(--r-lg);
    /* `position: relative` para que elemento posicionado dentro da tabela (o texto
       `.so-leitor` de um cabecalho, por exemplo) tenha ESTE container como referencia. Sem
       isso ele se posiciona em relacao a pagina e, numa tabela larga rolada para a direita,
       aparece fora da area visivel — esticando a pagina inteira. E' um estouro que so
       acontece no celular e nao aparece em inspecao visual, porque o elemento e' invisivel. */
    position: relative;
}

table.tabular {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9375rem;
    font-variant-numeric: tabular-nums;
}

table.tabular th {
    padding: var(--e-3) var(--e-4);
    text-align: left;
    font-size: 0.6875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--tracking-caixa-alta);
    color: var(--text-3);
    background: var(--surface-1);
    border-bottom: 1px solid var(--separator);
    white-space: nowrap;
}

table.tabular td {
    padding: var(--e-4);
    border-bottom: 1px solid var(--separator);
    color: var(--text);
}

table.tabular tbody tr:last-child td { border-bottom: 0; }

/* Sem zebra: a linha divisoria ja separa. Zebra soma ruido e briga com o hover. */
table.tabular tbody tr:hover { background: rgba(128, 128, 128, 0.05); }

/* Cabecalho ordenavel: o link ocupa a celula e a seta indica a direcao atual. */
th .ordenar {
    display: inline-flex;
    align-items: center;
    gap: var(--e-1);
    color: inherit;
}
th .ordenar:hover { color: var(--text); text-decoration: none; }
th[aria-sort] .ordenar { color: var(--text); }

@media (pointer: coarse) {
    /* Ordenar e' a acao mais usada de uma tabela de dados, e sob o dedo o link tinha 17px de
       altura — abaixo dos 44px da WCAG 2.5.5. O alvo cresce sem mexer no cabecalho: o padding
       vertical some do calculo visual porque a celula ja' tem altura maior que isso. */
    th .ordenar {
        min-height: var(--alvo-toque);
        align-items: center;
    }
}

.acoes-linha {
    display: flex;
    gap: var(--e-2);
    justify-content: flex-end;
}

/* --- 11. Avisos e estado vazio ----------------------------------------------------- */

/* Estado vazio nunca e' so "Sem dados": ele diz o que aconteceu e oferece a proxima
   acao. Uma tela vazia sem saida deixa o usuario preso. */
.notice {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--e-3);
    padding: var(--e-7) var(--e-5);
    background: var(--surface-1);
    border: 1px dashed var(--separator-strong);
    border-radius: var(--r-lg);
    text-align: center;
}

.notice h3 { margin: 0; }
.notice p { margin: 0; color: var(--text-2); max-width: 46ch; }

/* --- Alerta em linha ------------------------------------------------------------
   Simbolo alem da cor, sempre: cor nunca e' o unico sinal (WCAG 1.4.1). */
/* `anywhere`, e nao `break-word`: os dois quebram palavra que nao cabe, mas so' o `anywhere`
   reduz a largura MINIMA do texto. E' a largura minima que importa aqui — como filho de flex, o
   texto se recusa a encolher abaixo do maior pedaco nao-quebravel da frase e empurra o card, a
   secao e por fim o `<html>`.

   Medido em 390px com fonte raiz a 2rem (quem amplia o texto do sistema), em
   `/cadastros/rotas-ferro/conflitos`, cuja frase tem "maiuscula/minuscula" — a barra nao e' ponto
   de quebra padrao:
       sem nada        scrollWidth 414 x clientWidth 390  -> rolagem horizontal na PAGINA
       break-word      414  (nao resolve, pelo motivo acima)
       anywhere        390
   Rolagem lateral na pagina inteira e' proibida pela decisao de arquitetura; dentro da tabela e'
   esperado. */
.alerta {
    display: flex;
    align-items: flex-start;
    gap: var(--e-3);
    padding: var(--e-4);
    border-radius: var(--r-md);
    font-size: 0.9375rem;
    overflow-wrap: anywhere;
}
.alerta::before { font-weight: 700; flex: none; }

.alerta-sucesso { background: var(--green-suave); color: var(--green-sobre-suave); }
.alerta-sucesso::before { content: "✓"; }

.alerta-info { background: var(--blue-suave); color: var(--blue-sobre-suave); }
.alerta-info::before { content: "i"; }

.alerta-atencao { background: var(--orange-suave); color: var(--orange-sobre-suave); }
.alerta-atencao::before { content: "!"; }

.alerta-erro { background: var(--red-suave); color: var(--red-sobre-suave); }
.alerta-erro::before { content: "✗"; }

/* --- 12. Mensagens efemeras (flash) ------------------------------------------------ */

.flashes {
    position: fixed;
    top: calc(var(--altura-topbar) + var(--e-3));
    left: var(--gutter);
    right: var(--gutter);
    z-index: 40;
    display: flex;
    flex-direction: column;
    gap: var(--e-2);
    /* Nao bloqueia clique no que esta embaixo; so o proprio aviso e' clicavel. */
    pointer-events: none;
}
.flashes > * { pointer-events: auto; }

@media (min-width: 620px) {
    .flashes {
        left: auto;
        right: var(--gutter);
        max-width: 420px;
    }
}

.flash {
    display: flex;
    align-items: flex-start;
    gap: var(--e-3);
    padding: var(--e-4);
    border-radius: var(--r-md);
    background: var(--surface-2);
    box-shadow: var(--sombra-alta);
    animation: entrar-lateral var(--t-media) var(--easing);
}

.flash-fechar {
    margin-left: auto;
    background: none;
    border: 0;
    color: inherit;
    font-size: 1.125rem;
    line-height: 1;
    cursor: pointer;
    opacity: 0.7;
    padding: var(--e-1);
}
.flash-fechar:hover { opacity: 1; }

@media (pointer: coarse) {
    /* Fechar o aviso e' a unica saida dele: 26px sob o dedo vira "clico e nao fecha". */
    .flash-fechar {
        min-width: var(--alvo-toque);
        min-height: var(--alvo-toque);
    }
}

/* --- 13. Modais -------------------------------------------------------------------- */

/* Elemento <dialog> nativo: o navegador ja entrega foco preso dentro do modal,
   fechamento por Esc e camada acima de todo o resto. Reimplementar isso em JS e'
   trabalho garantido de errar em acessibilidade. */
dialog.modal {
    width: min(560px, calc(100vw - 2 * var(--gutter)));
    padding: 0;
    border: 1px solid var(--separator);
    border-radius: var(--r-lg);
    background: var(--surface-1);
    color: var(--text);
    box-shadow: var(--sombra-alta);
}

dialog.modal::backdrop { background: var(--overlay); }

.modal-topo {
    display: flex;
    align-items: center;
    gap: var(--e-3);
    padding: var(--e-5);
    border-bottom: 1px solid var(--separator);
}
.modal-topo h2 { margin: 0; font-size: 1.125rem; }

.modal-corpo { padding: var(--e-5); }

.modal-rodape {
    display: flex;
    gap: var(--e-3);
    justify-content: flex-end;
    padding: var(--e-4) var(--e-5);
    border-top: 1px solid var(--separator);
    background: var(--surface-2);
}

/* --- 14. Abas ---------------------------------------------------------------------- */

.abas {
    display: flex;
    gap: var(--e-1);
    overflow-x: auto;
    border-bottom: 1px solid var(--separator);
    margin-bottom: var(--e-5);
}

.aba {
    display: inline-flex;
    align-items: center;
    min-height: var(--alvo-toque);
    padding: 0 var(--e-4);
    border: 0;
    border-bottom: 2px solid transparent;
    background: none;
    color: var(--text-2);
    font-family: inherit;
    font-size: 0.9375rem;
    font-weight: 600;
    white-space: nowrap;
    cursor: pointer;
}

.aba:hover { color: var(--text); text-decoration: none; }

.aba[aria-selected="true"],
.aba[aria-current="page"] {
    color: var(--blue);
    border-bottom-color: var(--blue);
}

/* --- 15. Trilha e paginacao -------------------------------------------------------- */

.trilha {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--e-2);
    margin-bottom: var(--e-5);
    padding: 0;
    list-style: none;
    font-size: 0.875rem;
    color: var(--text-3);
}

/* `min-width: 0`: item de flex tem largura minima igual ao conteudo por padrao. Sem isso, um
   nome de arquivo sem espaco ("Orcamento_2027_Pricing_ANONIMIZADO_principal.xlsx" — underscore
   nao e' ponto de quebra) empurra a trilha inteira para fora da tela no celular em vez de quebrar
   linha, que e' o unico caso de rolagem horizontal do sistema inteiro (o resto rola dentro do
   proprio container). */
.trilha li { display: flex; align-items: center; gap: var(--e-2); min-width: 0; }
.trilha li + li::before { content: "›"; color: var(--text-3); }
.trilha a { color: var(--text-2); }
.trilha [aria-current="page"] { color: var(--text); }
.trilha a,
.trilha [aria-current="page"] { min-width: 0; overflow-wrap: anywhere; }

.paginacao {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--e-2);
    margin-top: var(--e-5);
}

.paginacao-info {
    width: 100%;
    text-align: center;
    font-size: 0.875rem;
    color: var(--text-3);
    margin-bottom: var(--e-2);
}

.pagina-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: var(--alvo-toque);
    min-height: var(--alvo-toque);
    padding: 0 var(--e-3);
    border-radius: var(--r-sm);
    color: var(--text-2);
    font-size: 0.9375rem;
    font-variant-numeric: tabular-nums;
}
.pagina-link:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
.pagina-link[aria-current="page"] {
    background: var(--blue);
    color: var(--sobre-cor);
    font-weight: 600;
}
.pagina-link[aria-disabled="true"] {
    color: var(--text-disabled);
    pointer-events: none;
}

/* --- 16. Disclosure ---------------------------------------------------------------- */

details.disclosure {
    border: 1px solid var(--separator);
    border-radius: var(--r-md);
    background: var(--surface-1);
}
details.disclosure + details.disclosure { margin-top: var(--e-2); }

details.disclosure > summary {
    display: flex;
    align-items: center;
    gap: var(--e-3);
    min-height: var(--alvo-toque);
    padding: var(--e-3) var(--e-4);
    font-weight: 600;
    cursor: pointer;
    list-style: none;
}
details.disclosure > summary::-webkit-details-marker { display: none; }
details.disclosure > summary::before {
    content: "›";
    color: var(--text-3);
    font-size: 1.25rem;
    transition: transform var(--t-rapida) var(--easing);
}
details.disclosure[open] > summary::before { transform: rotate(90deg); }

.disclosure-corpo {
    padding: 0 var(--e-4) var(--e-4);
    color: var(--text-2);
}

/* --- 15b. Icones -------------------------------------------------------------------
   SVG em linha (`components/icones.html`), nao fonte de icones: a CSP barra recurso externo e o
   projeto nao tem etapa de build. `stroke: currentColor` faz o icone herdar a cor do link — um
   token a menos para manter, e o estado ativo/hover ja' pinta os dois juntos.

   Pontas retas e cantos vivos sao a assinatura do conjunto: o desenho vem do mundo de trilho,
   conteiner e portico que o produto opera, e nao do arredondado de aplicativo de consumo. */

.icone {
    width: 1.125rem;
    height: 1.125rem;
    /* O texto do link pode quebrar; o icone nunca encolhe nem se deforma. */
    flex-shrink: 0;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.5;
    stroke-linecap: square;
    stroke-linejoin: miter;
}

/* A pagina atual ganha traco mais grosso, e nao so' cor: o realce sobrevive ao modo de alto
   contraste e a quem nao distingue os dois tons de azul. */
.sidebar-link[aria-current="page"] .icone { stroke-width: 2; }

/* --- 16b. Mudancas de uma simulacao -------------------------------------------------
   A lista do cenario montado. Cada item e' texto + um botao de remover com o alvo de toque
   inteiro: e' uma acao destrutiva pequena, e um alvo apertado ao lado do texto e' onde o dedo
   erra. O `>` no `summary` vem do disclosure (secao 16), reusado aqui. */

.lista-mudancas {
    list-style: none;
    margin: 0;
    padding: 0;
}
.lista-mudancas > li + li { margin-top: var(--e-2); }

.mudanca {
    display: flex;
    align-items: center;
    gap: var(--e-3);
    padding: var(--e-3) var(--e-4);
    background: var(--surface-1);
    border: 1px solid var(--separator);
    border-radius: var(--r-md);
}
/* `min-width: 0` para o texto longo quebrar em vez de empurrar o botao para fora da caixa. */
.mudanca-texto { flex: 1; min-width: 0; }

/* Sinal + palavra, nunca so' cor: quem nao distingue verde de vermelho le' a seta e o texto. */
.delta {
    display: inline-flex;
    align-items: center;
    gap: var(--e-2);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.delta-positivo { color: var(--green-sobre-suave); }
.delta-negativo { color: var(--red-sobre-suave); }

/* --- 16c. Conversa do agente ---------------------------------------------------------
   Fala do usuario e fala do agente com fundos distintos E rotulo escrito ("Voce"/"Agente"):
   so' a cor deixaria a conversa ilegivel em alto contraste e para quem nao distingue os dois
   tons. A lista e' `<ol>` porque a ordem dos turnos E' o conteudo. */

.conversa {
    list-style: none;
    margin: 0;
    padding: 0;
}
.conversa > li + li { margin-top: var(--e-3); }

.fala {
    padding: var(--e-3) var(--e-4);
    border: 1px solid var(--separator);
    border-radius: var(--r-md);
    background: var(--surface-1);
}
.fala-usuario { border-left: 3px solid var(--blue); }
.fala-agente { border-left: 3px solid var(--green); }

.fala-quem {
    margin: 0 0 var(--e-2);
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--text-2);
}
/* `pre-wrap`: a resposta do agente vem com quebra de linha, e o HTML as engoliria. */
.fala-texto {
    margin: 0;
    white-space: pre-wrap;
}

/* --- 17. Barra de ferramentas de listagem ------------------------------------------ */

.barra-listagem {
    display: flex;
    flex-wrap: wrap;
    gap: var(--e-3);
    align-items: center;
    margin-bottom: var(--e-4);
}

.busca {
    display: flex;
    gap: var(--e-2);
    flex: 1;
    /* `min-width` em px nao acompanha a fonte; o `max-width` e' que impede a barra de empurrar a
       pagina quando o usuario amplia a fonte do sistema. */
    min-width: min(220px, 100%);
    max-width: 100%;
}
.busca input {
    flex: 1;
    /* SEM isto o input nao encolhe abaixo da largura intrinseca dele (o `size` padrao, ~20
       caracteres), que cresce junto com a fonte: a 32px ela passa de 460px e a pagina inteira
       ganha rolagem horizontal no telefone. */
    min-width: 0;
    min-height: var(--alvo-toque);
    padding: 0 var(--e-4);
    background: var(--surface-1);
    border: 1px solid var(--separator-strong);
    border-radius: var(--r-pill);
    color: var(--text);
    font-family: inherit;
    font-size: 1rem;
}
.busca input:focus { border-color: var(--blue); }

/* Select de filtro (situacao, tipo) ao lado da busca na mesma barra de ferramentas: mesma
   altura e formato pilula do campo de busca, para os controles nao "pularem" na linha. */
.select-filtro {
    /* A largura intrinseca vem da opcao mais longa e cresce com a fonte — mesmo motivo do
       `min-width: 0` no campo de busca. */
    max-width: 100%;
    min-height: var(--alvo-toque);
    padding: 0 var(--e-4);
    background: var(--surface-1);
    border: 1px solid var(--separator-strong);
    border-radius: var(--r-pill);
    color: var(--text);
    font-family: inherit;
    font-size: 1rem;
}
.select-filtro:focus { border-color: var(--blue); }

/* --- 18. Acessibilidade ------------------------------------------------------------ */

/* WCAG 2.4.1 — primeiro elemento focavel da pagina pula a navegacao repetida.
   `--blue-solido`, e nao `--blue`: e' o token feito para texto branco por cima de um fundo
   solido (ver comentario em `tokens.css`). `--blue` mede 3,65:1 aqui no tema escuro — abaixo do
   minimo de 4,5:1 — porque foi desenhado para SER o texto/acento sobre `--surface-1`, nao para
   levar texto branco em cima. `--blue-solido` mede 5,74:1 no escuro e 4,70:1 no claro (mesmo
   par que `.btn-primario` usa). */
.skip-link {
    position: absolute;
    left: -9999px;
    z-index: 100;
    padding: var(--e-3) var(--e-4);
    background: var(--blue-solido);
    color: var(--sobre-cor);
    border-radius: var(--r-sm);
    font-weight: 600;
}
.skip-link:focus {
    left: var(--gutter);
    top: var(--e-3);
    text-decoration: none;
}

/* WCAG 2.4.7 — `:focus-visible` e nao `:focus`: o navegador so desenha o anel para
   quem navega por teclado, sem poluir a interface de quem usa o mouse. Remover o
   outline sem repor um equivalente torna a navegacao por teclado inviavel. */
:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
    border-radius: var(--r-sm);
}

/* Visivel apenas para leitor de tela.
   `clip-path` no lugar do antigo `clip`, que esta obsoleto. O elemento continua no fluxo de
   acessibilidade (e' lido) e some da tela — diferente de `display: none`, que o removeria
   tambem do leitor de tela. */
.so-leitor {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* O <main> recebe foco por programa (destino do skip-link), mas nao e' um controle:
   desenhar o anel nele confundiria. */
main:focus { outline: none; }

/* --- 19. Movimento ----------------------------------------------------------------- */

.fade-up { animation: subir var(--t-entrada) var(--easing) both; }

/* Cascata sutil: cada bloco entra logo apos o anterior, o que guia o olho de cima
   para baixo sem parecer animacao. */
.delay-1 { animation-delay: 80ms; }
.delay-2 { animation-delay: 160ms; }
.delay-3 { animation-delay: 240ms; }

@keyframes subir {
    from { opacity: 0; transform: translateY(12px); }
    to   { opacity: 1; transform: none; }
}

@keyframes entrar-lateral {
    from { opacity: 0; transform: translateX(16px); }
    to   { opacity: 1; transform: none; }
}

/* Movimento causa enjoo e desconforto reais em parte das pessoas. Quem pediu menos
   movimento no sistema operacional recebe a interface sem animacao — e nao uma versao
   quebrada: tudo continua visivel e funcional. */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        /* O ATRASO tambem, e este e' o que faltava. `.fade-up` usa `animation-fill-mode: both`,
           entao durante o `animation-delay` o elemento fica preso no primeiro quadro — que e'
           `opacity: 0`. Zerar so' a duracao deixava `.delay-1`/`.delay-2`/`.delay-3` invisiveis
           por 80/160/240ms para quem pediu MENOS movimento: em vez de aparecer sem animacao, o
           conteudo sumia e piscava de volta.

           Medido com `prefers-reduced-motion: reduce`: `.hero.fade-up` (sem atraso) ja' vinha
           com `opacity: 1` e animacao `finished`, enquanto `.fade-up.delay-1` estava em
           `opacity: 0` e `running`. Foi o que apareceu numa captura de tela com o corpo da
           pagina em branco. */
        animation-delay: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        transition-delay: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* --- 19a. Barra de personificacao ----------------------------------------------------
   Cor de alerta, no topo de tudo e sem botao de fechar. Agir como outra pessoa sem
   perceber e' o pior desfecho deste recurso — um aviso dispensavel seria dispensado. */

.banner-personificacao {
    position: sticky;
    top: 0;
    z-index: 50;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--e-3);
    padding: var(--e-3) var(--gutter);
    background: var(--orange-suave);
    color: var(--orange);
    border-bottom: 1px solid var(--orange);
    font-size: 0.9375rem;
    font-weight: 600;
}

.banner-personificacao .btn {
    background: var(--orange);
    color: var(--sobre-cor);
}
.banner-personificacao .btn:hover {
    background: var(--orange);
    color: var(--sobre-cor);
    opacity: 0.85;
}

/* Com a barra presente, a topbar gruda logo abaixo dela em vez de sobrepo-la. */
.banner-personificacao ~ .topbar { top: auto; }

/* --- 19b. Paginas de acesso (entrar, cadastrar, redefinir) ---------------------------
   Cartao unico e centrado, sem barra lateral: nesta etapa a pessoa tem uma tarefa so,
   e qualquer outra coisa na tela e' distracao ou saida acidental. */

.acesso {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: calc(100vh - var(--altura-topbar));
    padding: var(--e-5) var(--gutter);
}

.acesso-cartao {
    width: 100%;
    max-width: 420px;
    background: var(--surface-1);
    border: 1px solid var(--separator);
    border-radius: var(--r-lg);
    padding: var(--e-6);
}

.acesso-cartao h1 {
    font-size: 1.5rem;
    margin-bottom: var(--e-2);
}

.acesso-cartao .btn { width: 100%; }

.acesso-rodape {
    margin-top: var(--e-5);
    padding-top: var(--e-4);
    border-top: 1px solid var(--separator);
    font-size: 0.9375rem;
    color: var(--text-2);
    text-align: center;
}

/* --- Codigos de recuperacao ------------------------------------------------------
   Monoespacada e em duas colunas: sao para ler e copiar, nao para decorar. */
.codigos {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--e-2);
    padding: var(--e-4);
    margin: var(--e-4) 0;
    background: var(--surface-2);
    border-radius: var(--r-md);
    font-family: var(--font-mono);
    font-size: 1rem;
    letter-spacing: 0.05em;
    text-align: center;
}

/* --- QR code do segundo fator ----------------------------------------------------
   Fundo branco fixo, e nao token: leitor de QR depende do contraste entre modulos
   escuros e fundo claro, e no tema escuro a leitura falha. */
.qrcode {
    display: flex;
    justify-content: center;
    padding: var(--e-5);
    margin: var(--e-4) 0;
    background: #fff;
    border-radius: var(--r-md);
}
.qrcode svg { width: 200px; height: 200px; }

/* --- Sessao ativa ------------------------------------------------------------------ */
.sessao-item {
    display: flex;
    flex-wrap: wrap;
    gap: var(--e-3);
    align-items: center;
    padding: var(--e-4);
    border-bottom: 1px solid var(--separator);
}
.sessao-item:last-child { border-bottom: 0; }
.sessao-dados { flex: 1; min-width: 200px; }
.sessao-agente { font-size: 0.9375rem; word-break: break-word; }

/* --- 20. Utilitarios de espacamento --------------------------------------------------
   Conjunto deliberadamente PEQUENO. Nao e' um sistema de utilitarios: sao os poucos
   ajustes pontuais que apareceriam como `style="..."` no HTML — o que a CSP
   (`style-src 'self'`) bloqueia, e com razao. Precisou de mais que isto? O lugar e'
   uma classe de componente, nao mais um utilitario. */

.mt-4 { margin-top: var(--e-4); }
.mt-5 { margin-top: var(--e-5); }
.mt-6 { margin-top: var(--e-6); }
.mb-2 { margin-bottom: var(--e-2); }
.mb-5 { margin-bottom: var(--e-5); }
.sem-margem { margin: 0; }
.ml-auto { margin-left: auto; }

/* Rodape de pagina publica. */
.rodape {
    border-top: 1px solid var(--separator);
    padding-top: var(--e-5);
}

/* --- 21. Guia de estilo (somente em desenvolvimento) ---------------------------------
   As amostras de cor precisam pintar cada token, o que sairia como `style` inline —
   bloqueado pela CSP. Uma regra por token resolve sem abrir excecao na politica.
   Vive aqui, e nao num arquivo separado, porque some junto com o resto se alguem
   remover o /styleguide de um projeto derivado. */

.amostra-superficie {
    height: 64px;
    border-bottom: 1px solid var(--separator);
}
.amostra-cor {
    height: 32px;
    border-radius: var(--r-sm);
}

.amostra-bg { background: var(--bg); }
.amostra-surface-1 { background: var(--surface-1); }
.amostra-surface-2 { background: var(--surface-2); }
.amostra-surface-3 { background: var(--surface-3); }

.amostra-blue { background: var(--blue); }
.amostra-green { background: var(--green); }
.amostra-orange { background: var(--orange); }
.amostra-red { background: var(--red); }
.amostra-yellow { background: var(--yellow); }
.amostra-indigo { background: var(--indigo); }
.amostra-teal { background: var(--teal); }

.exemplo-text { color: var(--text); }
.exemplo-text-2 { color: var(--text-2); }
.exemplo-text-3 { color: var(--text-3); }
.exemplo-text-disabled { color: var(--text-disabled); }

/* --- 21b. Grade mensal --------------------------------------------------------------
   Linhas de entidade x 12 meses. E' o componente de ~20 telas de dado do orcamento, e o
   concorrente dele e' o Excel: se a grade for pior que uma planilha, o sistema nao e' usado.

   As duas decisoes que fazem ela funcionar no celular:
     1. Tudo dentro de `.table-scroll` — a TABELA rola na horizontal, a pagina nunca.
     2. Coluna de identificacao e coluna de total FIXAS (`position: sticky`). Rolar ate outubro sem
        saber de que linha e' o numero transforma conferencia em adivinhacao. */

.grade-mensal { margin-bottom: var(--e-5); }

/* Barra de acoes acima da grade. Envolve no celular: os dois botoes descem inteiros, em vez de
   encolherem abaixo do alvo de toque. */
.grade-barra {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--e-3);
    margin-bottom: var(--e-3);
}

.grade-aviso {
    flex: 1;
    min-width: min(240px, 100%);
    margin: 0;
    font-size: 0.875rem;
    color: var(--text-2);
}
/* Alteracao pendente e' informacao, nao erro: azul (acao/informacao), com o texto sempre
   dizendo quantas celulas — a cor apenas reforca. */
.grade-aviso[data-tem-alteracao="true"] { color: var(--blue); font-weight: 600; }
.grade-aviso[data-tem-erro="true"] { color: var(--red); font-weight: 600; }

table.tabular.grade-tabela { font-variant-numeric: tabular-nums; }

/* Coluna de mes: largura minima para o numero nao quebrar em duas linhas. Em `ch` e nao em `px`,
   para acompanhar quem amplia a fonte do sistema. */
.grade-coluna-mes,
.grade-tabela td.grade-celula { min-width: 8ch; }

.grade-unidade {
    display: block;
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
    color: var(--text-3);
}

/* --- Colunas fixas ---------------------------------------------------------------
   O fundo OPACO e' obrigatorio: sem ele o conteudo rolado passa por baixo e os dois textos se
   sobrepoem. Por isso `--surface-1` (opaco nos dois temas) e nao uma cor com transparencia. */
.grade-tabela .grade-coluna-id {
    position: sticky;
    left: 0;
    z-index: 2;
    background: var(--surface-1);
    border-right: 1px solid var(--separator);
    text-align: left;
    /* Rotulo longo (nome de terminal, par origem-destino) nao pode empurrar os 12 meses para fora
       do alcance: a coluna tem teto e o texto quebra. O teto e' menor no celular — em 390px, uma
       coluna de 22ch deixaria UM mes visivel entre ela e a de total.

       16ch, e nao 13ch, por MEDICAO na tela de premissas em 390px (a de rotulo mais longo), como
       fatia da largura visivel da grade:
       13ch -> 35,4%  (rotulo espremido: 5 linhas quebram no meio da palavra, "Crossdockin/g IMO")
       16ch -> 43,5%  <- este
       20ch -> 43,5%  (identico)
       26ch -> 43,5%  (identico)
       43,5% e' a largura NATURAL do rotulo mais longo: passando de 16ch o teto para de apertar e
       nada muda. Ou seja, de 13 para 16 nao se paga nada. Quem for mexer neste numero: meca, nao
       estime — ha' teste que guarda os dois lados em `tests/e2e/test_premissas_browser.py`. */
    min-width: 9ch;
    max-width: 16ch;
    white-space: normal;
    /* Palavra unica mais longa que a coluna ("Reposicionamento") vazaria por cima do mes ao lado —
       o teto de largura sozinho nao quebra palavra.

       `hyphens: auto` foi TESTADO no navegador e descartado: em 13ch o Chromium silabifica toda
       palavra do vocabulario ("En-/coste/Ter-/loc", "Cross-/doc-/king"), a pagina de premissas
       passou de 4819px para 5642px de altura e a coluna ficou mais picotada, nao menos. O
       problema nao era a forma da quebra — era a largura. */
    overflow-wrap: break-word;
}

/* O rotulo da LINHA e' conteudo, nao cabecalho de coluna: sem esta correcao ele herda o caixa alta
   de 11px de `table.tabular th` e o nome do terminal vira legenda. */
.grade-tabela tbody .grade-coluna-id {
    text-transform: none;
    letter-spacing: var(--tracking-normal);
    font-size: 0.875rem;
    color: var(--text);
}

.grade-tabela .grade-coluna-total {
    /* Fixa so a partir do tablet: no celular, duas colunas fixas comem a tela e sobra um mes
       visivel. Ali o total continua na tabela, a uma rolagem de distancia. */
    background: var(--surface-1);
    border-left: 1px solid var(--separator);
    font-weight: 600;
}

@media (min-width: 700px) {
    .grade-tabela .grade-coluna-id { max-width: 24ch; }
    .grade-tabela .grade-coluna-total { position: sticky; right: 0; z-index: 2; }
    .grade-tabela thead .grade-coluna-total { z-index: 3; }
}

/* O cabecalho fixo cruza com a coluna fixa; sem subir o empilhamento, a celula do canto fica por
   baixo da que rola. */
.grade-tabela thead .grade-coluna-id { z-index: 3; }

.grade-descricao {
    display: block;
    margin-top: 2px;
    font-size: 0.75rem;
    font-weight: 400;
    color: var(--text-3);
}

/* --- Grade de margem: hierarquia invertida no celular ------------------------------
   O rotulo desta grade e' o ID2 da planilha (`Fluxo.chave`) — oito dimensoes concatenadas SEM
   separador, de proposito: e' o que permite conferir a linha contra a planilha original, e nao e'
   um texto que se abrevia (`features/calculo/routes_web.py`). Em negrito, a 0,875rem, dentro de
   uma coluna de 16ch, ele media 8-9 linhas ANTES de chegar ao primeiro mes — a legenda legivel
   ("LND → LDP · ROUND TRIP · ...") que ja existia ficava escondida embaixo de tudo isso.

   A correcao troca so' a APARENCIA no celular, nunca o dado: a legenda vira o titulo (major,
   destacada), o ID2 vira legenda monoespacada e secundaria — o valor INTEIRO continua no HTML,
   so' deixa de disputar atencao com o titulo. `column-reverse` inverte a ORDEM VISUAL sem tocar
   no HTML compartilhado por ~20 telas (`components/grade_mensal.html`): o texto do rotulo entra
   como item de flex anonimo, o `.grade-descricao` e' o outro item, e so' a grade de margem
   (`#margem`) e' afetada.

   So' ate' 699px: a partir de 700px a coluna tem 24ch e o ID2 ja cabe em poucas linhas — ali ele
   continua primario, como em qualquer outra grade do sistema. Decidido NAO truncar com reticencia
   (`text-overflow: ellipsis`): esconderia caracteres do ID2, e a razao dele existir e' justamente
   poder ser lido inteiro contra a planilha — quebrar linha (`overflow-wrap: break-word`, ja
   herdado de `.grade-tabela .grade-coluna-id`) preserva a conferencia, so' com menos peso visual. */
@media (max-width: 699px) {
    #margem .grade-tabela tbody th.grade-coluna-id {
        display: flex;
        flex-direction: column-reverse;
        gap: 2px;
        font-family: var(--font-mono);
        font-size: 0.6875rem;
        font-weight: 400;
        color: var(--text-3);
    }
    #margem .grade-tabela tbody .grade-descricao {
        min-width: 0;
        margin-top: 0;
        font-family: var(--font-sans);
        font-size: 0.875rem;
        font-weight: 600;
        color: var(--text);
    }
}

/* Linha de totais: mesma superficie do cabecalho, para ler como resumo e nao como mais um dado. */
.grade-tabela tfoot td,
.grade-tabela tfoot th {
    background: var(--surface-2);
    border-top: 1px solid var(--separator-strong);
    font-weight: 600;
}
.grade-tabela tfoot .grade-coluna-id,
.grade-tabela tfoot .grade-coluna-total { background: var(--surface-2); }

/* --- Celula editavel -------------------------------------------------------------
   O campo OCUPA a celula inteira: alvo de toque grande sem aumentar a densidade da grade, e o
   clique em qualquer ponto da celula cai no campo. */
.grade-tabela td.grade-celula { padding: 0; position: relative; }

.grade-entrada {
    width: 100%;
    min-height: var(--alvo-toque);
    padding: var(--e-2) var(--e-3);
    border: 0;
    background: transparent;
    color: var(--text);
    font-family: inherit;
    /* 16px minimo: abaixo disso o Safari do iPhone da zoom sozinho ao focar o campo — e numa grade
       de 12 colunas esse zoom perde o lugar de quem estava digitando. */
    font-size: 1rem;
    font-variant-numeric: tabular-nums;
    text-align: right;
}

/* --- Celula alterada -------------------------------------------------------------
   Fundo azul suave E marca textual. Cor sozinha nao comunica (WCAG 1.4.1) — e aqui a informacao
   "isto ainda nao foi salvo" e' cara demais para depender de enxergar azul. */
.grade-tabela td.grade-celula[data-alterada="true"] { background: var(--blue-suave); }

.grade-marca {
    position: absolute;
    top: 2px;
    left: var(--e-2);
    color: var(--blue);
    font-size: 0.875rem;
    line-height: 1;
    pointer-events: none;
}

.grade-tabela td.grade-celula:has(.grade-entrada[aria-invalid="true"]) {
    background: var(--red-suave);
}
.grade-entrada[aria-invalid="true"] { color: var(--red); font-weight: 600; }

/* --- Somente leitura -------------------------------------------------------------- */
.grade-tabela td.grade-celula:not(:has(.grade-entrada)) { padding: var(--e-3) var(--e-4); }

/* --- Lista da pre-visualizacao do colar -------------------------------------------- */
.grade-previa-linhas {
    margin: var(--e-3) 0 0;
    padding-left: var(--e-5);
    color: var(--text-2);
    font-size: 0.9375rem;
}

/* --- Estados (carregando, erro, vazio) -------------------------------------------- */
.grade-estado {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--e-4);
}
.grade-estado-texto { margin: 0; color: var(--text-2); }

.grade-esqueleto {
    display: flex;
    flex-direction: column;
    gap: var(--e-2);
    width: 100%;
}
.grade-esqueleto-linha {
    height: 40px;
    border-radius: var(--r-sm);
    /* `--surface-3` e nao `--surface-2`: no tema claro a superficie 2 e' igual ao fundo da pagina,
       e o esqueleto sumiria — exatamente a tela em branco que ele existe para evitar. */
    background: var(--surface-3);
    /* Pulsacao discreta: diz "esta vindo" sem virar animacao. Quem pediu menos movimento no sistema
       recebe a barra parada, pela regra global de `prefers-reduced-motion`. */
    animation: pulsar 1.4s var(--easing) infinite;
}

@keyframes pulsar {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.5; }
}

/* --- 22. Impressao ----------------------------------------------------------------- */

@media print {
    .topbar, .sidebar, .flashes, .paginacao, .btn { display: none !important; }
    body { background: #fff; color: #000; }
}
