:root {
    --bg: #0f1115;
    --sidebar: #11161d;
    --surface: #171d25;
    --surface-raised: #1e2631;
    --surface-hover: #242e3a;
    --border: #2c3541;
    --border-strong: #3c4856;
    --ink: #f4f7fa;
    --ink-soft: #aeb9c6;
    --ink-faint: #72808f;
    --accent: #1d8f45;
    --accent-strong: #166b35;
    --accent-ink: #82e5a0;
    --accent-soft: #102a1a;
    --negative: #ff6b76;
    --negative-soft: #351b22;
    --warning: #f5c764;
    --warning-soft: #302714;
    --info: #58a6ff;
    --info-soft: #142236;
    --radius-sm: 8px;
    --radius-md: 12px;
    --radius-lg: 16px;
    --shadow: 0 18px 42px rgb(0 0 0 / 20%);
    --font-sans: "Bahnschrift", "Segoe UI Variable", "Trebuchet MS", sans-serif;
    --font-mono: "Cascadia Mono", "Consolas", monospace;
    color: var(--ink);
    color-scheme: dark;
    font-family: var(--font-sans);
}

* {
    box-sizing: border-box;
}

html {
    background: var(--bg);
}

body {
    margin: 0;
    background: var(--bg);
    color: var(--ink);
    font-family: var(--font-sans);
}

button,
input,
select,
textarea {
    font: inherit;
}

button {
    cursor: pointer;
}

button:focus-visible,
a:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
    outline: 2px solid var(--accent-ink);
    outline-offset: 3px;
}

a {
    color: inherit;
    text-decoration: none;
}

h1,
h2,
p {
    margin-top: 0;
}

.sr-only {
    clip: rect(0, 0, 0, 0);
    clip-path: inset(50%);
    height: 1px;
    overflow: hidden;
    position: absolute;
    white-space: nowrap;
    width: 1px;
}

.eyebrow {
    color: var(--ink-faint);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    margin-bottom: 8px;
    text-transform: uppercase;
}

.auth-page {
    min-height: 100vh;
}

.auth-layout {
    align-items: center;
    background: linear-gradient(135deg, #0f1115, #121820);
    display: grid;
    justify-items: center;
    min-height: 100dvh;
    padding: 24px;
}

.login-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
    padding: 36px;
    width: min(100%, 430px);
}

.brand {
    align-items: center;
    display: inline-flex;
}

/* Altura fixa, largura livre: o logo real (mp-transporte-express.png) é mais
   compacto/quadrado que a faixa larga do SVG antigo -- travar pela largura
   deixaria a marca alta demais para a sidebar. */
.brand-logo {
    display: block;
    height: 46px;
    width: auto;
}

.brand--login {
    /* `.brand` é `inline-flex` (encolhe ao tamanho do conteúdo), então sem
       isto o logo fica preso na borda esquerda do card, com o espaço vazio
       sobrando à direita. `display: flex` (bloco cheio) + `justify-content`
       centraliza a marca em cima do formulário de login. */
    display: flex;
    justify-content: center;
    margin-bottom: 30px;
}

.brand--login .brand-logo {
    height: 64px;
}

.login-form {
    width: 100%;
}

.login-form h1 {
    font-size: 1.65rem;
    font-weight: 700;
    line-height: 1.2;
    margin-bottom: 8px;
}

.form-description {
    color: var(--ink-soft);
    font-size: 0.9rem;
    line-height: 1.5;
    margin-bottom: 26px;
}

.form-field {
    /* `align-content: start` e obrigatorio: numa grade, o `.form-field` e
       esticado ate a altura do campo mais alto da linha (um vizinho com
       dica embaixo, por exemplo) e, sem isto, ele repassa a sobra para o
       proprio controle — o input de 46px virava 52px e o select, 68px. */
    align-content: start;
    display: grid;
    gap: 8px;
    margin-bottom: 18px;
}

.form-field label {
    color: var(--ink-soft);
    font-size: 0.82rem;
    font-weight: 650;
}

/* Um unico tratamento para todo controle de texto/escolha. Antes so
   `input` era estilizado, e `select`/`textarea` caiam no visual nativo do
   navegador -- que num tema escuro aparece branco e quebra a tela inteira. */
.form-field input:not([type="checkbox"]):not([type="radio"]),
.form-field select,
.form-field textarea {
    background-color: #12171e;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    color: var(--ink);
    min-height: 46px;
    /* Padding so na horizontal: a altura vem do `min-height`, que centra o
       texto sem depender de line-height. Padding vertical aqui empilha com
       o min-height e deixa o controle mais alto que o previsto. */
    padding: 0 13px;
    transition: border-color 140ms ease, box-shadow 140ms ease;
    width: 100%;
}

.form-field textarea {
    line-height: 1.5;
    min-height: 96px;
    padding: 11px 13px;
    resize: vertical;
}

/* Seta propria: `appearance: none` remove a do sistema, que nao acompanha
   o tema. SVG inline evita mais um arquivo estatico. */
.form-field select {
    appearance: none;
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='%23aeb9c6' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4 6 4 4 4-4'/%3E%3C/svg%3E");
    background-position: right 13px center;
    background-repeat: no-repeat;
    cursor: pointer;
    padding-right: 38px;
}

.form-field input::placeholder,
.form-field textarea::placeholder {
    color: var(--ink-faint);
}

.form-field input:not([type="checkbox"]):focus,
.form-field select:focus,
.form-field textarea:focus {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px rgb(29 143 69 / 20%);
    outline: 0;
}

.form-field input:disabled,
.form-field select:disabled,
.form-field textarea:disabled {
    background: var(--surface);
    color: var(--ink-faint);
    cursor: not-allowed;
}

/* O icone do seletor de data e desenhado pelo navegador; sem isto ele sai
   preto sobre fundo escuro. */
.form-field input[type="date"]::-webkit-calendar-picker-indicator {
    cursor: pointer;
    filter: invert(72%) sepia(8%) saturate(400%) hue-rotate(175deg);
}

.password-control {
    position: relative;
}

.password-control input {
    padding-right: 48px;
}

.password-toggle {
    align-items: center;
    background: transparent;
    border: 0;
    border-radius: 6px;
    color: var(--ink-faint);
    display: inline-flex;
    height: 34px;
    justify-content: center;
    position: absolute;
    right: 6px;
    top: 6px;
    width: 34px;
}

.password-toggle:hover,
.password-toggle[aria-pressed="true"] {
    background: var(--surface-hover);
    color: var(--ink);
}

.password-toggle svg,
.icon-button svg,
.topbar-search svg,
.menu-link svg,
.button svg {
    height: 16px;
    width: 16px;
}

.login-feedback {
    width: 100%;
}

.alert {
    border-radius: var(--radius-sm);
    font-size: 0.82rem;
    line-height: 1.4;
    margin: 2px 0 16px;
    padding: 11px 12px;
}

.alert-error {
    background: var(--negative-soft);
    border: 1px solid rgb(255 107 118 / 30%);
    color: #ffb7bd;
}

.button {
    align-items: center;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    display: inline-flex;
    font-size: 0.84rem;
    font-weight: 700;
    gap: 8px;
    justify-content: center;
    min-height: 40px;
    padding: 0 14px;
    transition: background-color 160ms ease, border-color 160ms ease, color 160ms ease, transform 160ms ease;
}

.button-primary {
    background: var(--accent);
    color: #f7fff9;
}

.button-primary:hover {
    background: #249f4e;
}

.button-primary:active {
    transform: translateY(1px);
}

.button-secondary {
    background: var(--surface-raised);
    border-color: var(--border-strong);
    color: var(--ink);
}

.button-secondary:hover {
    background: var(--surface-hover);
}

.button-full {
    width: 100%;
}

.button-loading {
    display: none;
}

.button.is-loading {
    cursor: wait;
    opacity: 0.82;
}

.button.is-loading .button-label {
    display: none;
}

.button.is-loading .button-loading {
    align-items: center;
    display: inline-flex;
    gap: 8px;
}

.button.is-loading .button-loading svg {
    animation: spin 900ms linear infinite;
}

.app-shell {
    display: grid;
    grid-template-columns: 224px minmax(0, 1fr);
    min-height: 100dvh;
}

.sidebar {
    background: var(--sidebar);
    border-right: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    gap: 30px;
    height: 100dvh;
    padding: 22px 14px;
    position: sticky;
    top: 0;
}

.sidebar .brand {
    display: flex;
    justify-content: center;
    padding: 0 8px;
}

.menu-list {
    display: grid;
    gap: 4px;
}

.menu-section {
    color: var(--ink-faint);
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    margin: 15px 8px 7px;
    text-transform: uppercase;
}

.menu-link {
    align-items: center;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    color: var(--ink-soft);
    display: flex;
    font-size: 0.84rem;
    gap: 11px;
    min-height: 40px;
    padding: 0 11px;
    transition: background-color 160ms ease, border-color 160ms ease, color 160ms ease;
}

.menu-link:hover {
    background: rgb(255 255 255 / 4%);
    color: var(--ink);
}

.menu-link.is-active {
    background: var(--accent-soft);
    border-color: rgb(29 143 69 / 45%);
    color: var(--accent-ink);
}

.menu-link svg {
    color: var(--ink-faint);
    flex: 0 0 auto;
}

.menu-link.is-active svg {
    color: var(--accent-ink);
}

.app-workspace {
    min-width: 0;
}

.topbar {
    align-items: center;
    background: rgb(15 17 21 / 94%);
    border-bottom: 1px solid var(--border);
    display: flex;
    gap: 20px;
    justify-content: space-between;
    min-height: 64px;
    padding: 10px clamp(20px, 3vw, 44px);
    position: sticky;
    top: 0;
    z-index: 5;
}

.topbar-search {
    align-items: center;
    background: #12171e;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    color: var(--ink-faint);
    display: flex;
    gap: 9px;
    max-width: 460px;
    min-height: 38px;
    padding: 0 11px;
    width: 100%;
}

.topbar-search:focus-within {
    border-color: var(--border-strong);
}

.topbar-search input {
    background: transparent;
    border: 0;
    color: var(--ink);
    min-width: 0;
    outline: 0;
    width: 100%;
}

.topbar-search input::placeholder {
    color: var(--ink-faint);
}

.topbar-user {
    align-items: center;
    display: flex;
    gap: 10px;
}

.user-name {
    color: var(--ink-soft);
    font-size: 0.82rem;
    font-weight: 650;
    margin: 0;
}

.user-avatar {
    align-items: center;
    background: var(--accent);
    border-radius: 50%;
    color: #071b10;
    display: flex;
    font-size: 0.68rem;
    font-weight: 800;
    height: 30px;
    justify-content: center;
    width: 30px;
}

.icon-button {
    align-items: center;
    background: transparent;
    border: 0;
    border-radius: var(--radius-sm);
    color: var(--ink-faint);
    display: inline-flex;
    height: 34px;
    justify-content: center;
    width: 34px;
}

.icon-button:hover {
    background: var(--surface-hover);
    color: var(--ink);
}

.app-content {
    margin: 0 auto;
    max-width: 1240px;
    padding: clamp(30px, 4vw, 52px);
    width: 100%;
}

.page-heading {
    align-items: flex-end;
    display: flex;
    gap: 24px;
    justify-content: space-between;
    margin-bottom: 24px;
}

.page-heading h1 {
    font-size: 2rem;
    line-height: 1.15;
    margin-bottom: 8px;
}

.page-heading p:not(.eyebrow) {
    color: var(--ink-soft);
    line-height: 1.5;
    margin-bottom: 0;
}

.metric-grid {
    display: grid;
    gap: 14px;
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

.metric-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    display: grid;
    gap: 9px;
    min-height: 132px;
    padding: 18px;
}

.metric-card-label {
    color: var(--ink-soft);
    font-size: 0.8rem;
    font-weight: 650;
}

.metric-card small {
    color: var(--ink-faint);
    font-size: 0.76rem;
    line-height: 1.35;
}

.metric-card strong {
    font-family: var(--font-mono);
    font-size: 1.65rem;
    font-variant-numeric: tabular-nums;
    line-height: 1;
}

.empty-state {
    align-items: center;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    display: flex;
    gap: 22px;
    justify-content: space-between;
    margin-top: 18px;
    padding: 24px;
}

.empty-state h2 {
    font-size: 1rem;
    margin-bottom: 6px;
}

.empty-state p {
    color: var(--ink-soft);
    font-size: 0.88rem;
    line-height: 1.45;
    margin-bottom: 0;
}

.nfe-panel {
    background: linear-gradient(145deg, rgb(30 38 49 / 90%), var(--surface));
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: inset 0 1px 0 rgb(255 255 255 / 3%), var(--shadow);
    padding: 22px;
}

.panel-heading {
    align-items: flex-start;
    display: flex;
    gap: 18px;
    justify-content: space-between;
    margin-bottom: 20px;
}

.panel-heading h2,
.action-panel h2 {
    font-size: 1rem;
    margin-bottom: 6px;
}

.panel-heading p,
.action-panel p,
.empty-copy {
    color: var(--ink-soft);
    font-size: 0.85rem;
    line-height: 1.5;
    margin-bottom: 0;
}

.data-table-wrap {
    overflow-x: auto;
}

.data-table {
    border-collapse: collapse;
    min-width: 680px;
    width: 100%;
}

.data-table th {
    color: var(--ink-faint);
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.09em;
    padding: 0 12px 12px;
    text-align: left;
    text-transform: uppercase;
}

.data-table td {
    border-top: 1px solid var(--border);
    color: var(--ink-soft);
    font-size: 0.84rem;
    padding: 12px 14px;
    vertical-align: middle;
}

.data-table td:first-child,
.data-table th:first-child {
    padding-left: 0;
}

.data-table td:last-child,
.data-table th:last-child {
    padding-right: 0;
}

.data-table small {
    color: var(--ink-faint);
    display: block;
    margin-top: 4px;
}

.table-link {
    color: var(--ink);
    font-weight: 650;
}

.table-link:hover {
    color: var(--accent-ink);
}

.mono {
    font-family: var(--font-mono);
    font-size: 0.78rem;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.status-pill {
    white-space: nowrap;
    background: rgb(114 128 143 / 16%);
    border: 1px solid rgb(174 185 198 / 18%);
    border-radius: 999px;
    color: var(--ink-soft);
    display: inline-flex;
    font-size: 0.72rem;
    font-weight: 650;
    padding: 4px 9px;
}

.status-concluido,
.status-aprovado,
.status-conferido {
    background: var(--accent-soft);
    border-color: rgb(29 143 69 / 40%);
    color: var(--accent-ink);
}

.status-parcial,
.status-processando {
    background: var(--warning-soft);
    border-color: #765c27;
    color: var(--warning);
}

.status-erro,
.status-rejeitado {
    background: var(--negative-soft);
    border-color: rgb(255 107 118 / 40%);
    color: #ffb7bd;
}

.status-pronto_para_emissao,
.status-autorizado,
.status-averbado {
    background: var(--accent-soft);
    border-color: rgb(29 143 69 / 40%);
    color: var(--accent-ink);
}

.status-preparado_pendente,
.status-transmitindo {
    background: var(--warning-soft);
    border-color: #765c27;
    color: var(--warning);
}

.status-erro_transmissao,
.status-erro_averbacao,
.status-cancelado {
    background: var(--negative-soft);
    border-color: rgb(255 107 118 / 40%);
    color: #ffb7bd;
}

/* --- Validade do certificado digital ---
   Nivel proprio em vez de reaproveitar `.status-aprovado` e companhia: o
   que se pinta aqui nao e o estado de um documento fiscal, e a semantica
   ("vence em 12 dias") merece nome proprio para nao migrar junto se as
   cores de status do CT-e mudarem. */
.status-certificado-ok {
    background: var(--accent-soft);
    border-color: rgb(29 143 69 / 40%);
    color: var(--accent-ink);
}

.status-certificado-atencao {
    background: var(--warning-soft);
    border-color: #765c27;
    color: var(--warning);
}

.status-certificado-critico,
.status-certificado-vencido {
    background: var(--negative-soft);
    border-color: rgb(255 107 118 / 40%);
    color: #ffb7bd;
}

.nfe-form {
    display: grid;
    gap: 20px;
    max-width: 640px;
}

.cte-filtros {
    align-items: end;
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
}

.cte-filtros .form-field {
    margin-bottom: 0;
    min-width: 200px;
}

/* Sem isso o botao (min-height: 40px) fica mais baixo que os inputs/selects
   ao lado (min-height: 46px) e a linha parece desalinhada mesmo com
   `align-items: end`. */
.cte-filtros .button {
    min-height: 46px;
}

.inline-upload-form input[type="file"] {
    height: 1px;
    opacity: 0;
    position: absolute;
    width: 1px;
}

.inline-upload-form label {
    cursor: pointer;
}

/* Seletor de arquivo do certificado. O `input[type=file]` nativo renderiza
   com o chrome claro do navegador e destoa do tema escuro -- some, e quem
   aparece e a `<label>` estilizada como botao. Mesma tecnica do
   `.inline-upload-form`, com o nome do arquivo escolhido ao lado. */
.certificado-arquivo {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    min-height: 46px;
}

/* `div.` e o `.form-field` no seletor nao sao decorativos: sem eles esta
   regra tem especificidade menor que a de
   `.form-field input:not([type=checkbox]):not([type=radio])` la em cima, que
   impoe `width: 100%` e `min-height: 46px`. O input continuaria invisivel
   (`opacity: 0` vence, porque a regra generica nao define opacidade) mas
   ocuparia 1265x46px ABSOLUTO por cima do painel -- capturando cliques de
   toda a area e criando barra de rolagem horizontal na pagina.
   `min-height: 0` e obrigatorio junto: `min-height` vence `height`. */
.form-field div.certificado-arquivo input[type="file"] {
    height: 1px;
    min-height: 0;
    opacity: 0;
    padding: 0;
    position: absolute;
    width: 1px;
}

/* `label` dentro de `.form-field` herdaria o estilo de rotulo de campo
   (0.82rem, cor apagada); aqui ela e um botao. */
.certificado-arquivo label.button {
    color: var(--ink);
    cursor: pointer;
    font-size: 0.84rem;
    font-weight: 700;
    margin: 0;
}

.certificado-arquivo-nome {
    color: var(--ink-faint);
    font-size: 0.8rem;
    /* Nome longo nao pode empurrar o botao para fora do painel. */
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.certificado-arquivo-nome.is-escolhido {
    color: var(--accent-ink);
}

.upload-dropzone {
    background: rgb(15 17 21 / 42%);
    border: 1px dashed var(--border-strong);
    border-radius: var(--radius-md);
    display: grid;
    min-height: 200px;
    padding: 0;
    text-align: center;
    transition: background-color .15s ease, border-color .15s ease;
}

.upload-dropzone-trigger {
    align-items: center;
    cursor: pointer;
    display: grid;
    gap: 6px;
    height: 100%;
    justify-items: center;
    padding: 28px;
    width: 100%;
}

.upload-dropzone-trigger > svg {
    color: var(--accent-ink);
    height: 30px;
    width: 30px;
}

.upload-dropzone-title {
    color: var(--ink);
    font-weight: 650;
}

.upload-dropzone input[type="file"] {
    height: 1px;
    opacity: 0;
    position: absolute;
    width: 1px;
}

.upload-dropzone:hover {
    background: rgb(255 255 255 / 4%);
    border-color: var(--ink-faint);
}

.upload-dropzone-trigger:active {
    background: rgb(255 255 255 / 6%);
}

.upload-dropzone:has(input[type="file"]:focus-visible) {
    border-color: var(--accent);
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.upload-dropzone.is-dragover {
    background: var(--accent-soft);
    border-color: var(--accent);
}

.upload-dropzone p,
.field-error {
    color: var(--ink-faint);
    font-size: 0.8rem;
    line-height: 1.45;
    margin: 0;
}

.field-error {
    color: #ffb7bd;
}

.import-errors {
    background: rgb(255 107 118 / 8%);
    border: 1px solid rgb(255 107 118 / 28%);
    border-radius: var(--radius-sm);
    color: #ffb7bd;
    font-size: 0.84rem;
    line-height: 1.5;
    margin-top: 20px;
    padding: 14px;
}

.import-errors p {
    margin: 6px 0 0;
}

.detail-grid {
    display: grid;
    gap: 18px;
    grid-template-columns: minmax(0, 1.6fr) minmax(260px, 0.7fr);
}

.detail-list {
    display: grid;
    gap: 14px 24px;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    margin: 0;
}

.detail-list div {
    display: grid;
    gap: 3px;
    min-width: 0;
}

.detail-list dt {
    color: var(--ink-faint);
    font-size: 0.72rem;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

.detail-list dd {
    color: var(--ink);
    font-size: 0.88rem;
    margin: 0;
    overflow-wrap: break-word;
}

/* Histórico do CT-e: uma linha do tempo, não pares curtos de campo/valor --
   ver comentário em `cte/_cte_detalhe.html`. Uma coluna só, com separador
   sutil entre eventos em vez do `gap` largo do grid padrão. */
.detail-list--historico {
    grid-template-columns: 1fr;
}

.detail-list--historico div {
    border-bottom: 1px solid var(--border);
    padding-bottom: 10px;
}

.detail-list--historico div:last-child {
    border-bottom: 0;
    padding-bottom: 0;
}

.action-panel {
    align-content: start;
    display: grid;
    gap: 14px;
}

.action-panel h2,
.action-panel p {
    margin: 0;
}

.action-panel form {
    display: grid;
}

.button-danger {
    background: var(--negative-soft);
    border-color: rgb(255 107 118 / 40%);
    color: var(--negative);
}

.button-danger:hover {
    background: rgb(255 107 118 / 18%);
}

.alert-success {
    background: var(--accent-soft);
    border: 1px solid rgb(29 143 69 / 40%);
    color: var(--accent-ink);
}

.alert-warning {
    background: var(--warning-soft);
    border: 1px solid rgb(245 199 100 / 35%);
    color: var(--warning);
}

.alert-info,
.alert-debug {
    background: var(--info-soft);
    border: 1px solid rgb(88 166 255 / 35%);
    color: var(--info);
}

/* Painel operacional do NF-e/CT-e/Home: usa quase toda a largura da
   viewport, sem afetar o container padrao (1240px) das demais paginas do
   app. Escopado via `.nfe-dashboard`, o wrapper que a propria pagina
   declara. Preso a telas acima do breakpoint mobile para nao brigar em
   especificidade com o `padding` de 16px que a media query de 640px define
   para `.app-content`. */
@media (min-width: 641px) {
    .app-content:has(.nfe-dashboard),
    .app-content:has(.config-dashboard),
    .app-content:has(.dashboard) {
        max-width: none;
        padding-inline: clamp(24px, 3vw, 48px);
    }
}

/* Espacamento uniforme entre os blocos empilhados da pagina (cabecalho,
   filtros, paineis) -- sem isso cada painel depende de ter sua propria
   `margin-bottom`, e paineis sem essa margem ficam colados um no outro. Os
   dois filhos que ja tem `margin-bottom` proprio (`.page-heading`,
   `.nfe-intro-grid`) tem a margem zerada aqui para nao somar com o `gap`. */
.nfe-dashboard {
    display: flex;
    flex-direction: column;
    gap: 24px;
}

.nfe-dashboard > .page-heading,
.nfe-dashboard > .nfe-intro-grid {
    margin-bottom: 0;
}

/* Tela unica do dominio NF-e: upload dominante a esquerda (~65%),
   como-funciona a direita (~35%), lado a lado em telas largas. */
.nfe-intro-grid {
    align-items: stretch;
    display: grid;
    gap: 20px;
    grid-template-columns: minmax(0, 2fr) minmax(320px, 1fr);
    margin-bottom: 24px;
}

.file-types {
    display: grid;
    gap: 12px;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    margin-top: 14px;
}

.type-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    display: grid;
    gap: 4px;
    padding: 12px 14px;
}

.type-card strong {
    align-items: center;
    color: var(--ink);
    display: flex;
    font-size: 0.82rem;
    gap: 6px;
}

.type-card strong svg {
    height: 15px;
    width: 15px;
}

.type-card--recommended strong {
    color: var(--accent-ink);
}

.type-card span {
    color: var(--ink-soft);
    font-size: 0.78rem;
    line-height: 1.45;
}

.example-import {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    margin-top: 14px;
}

.example-import p {
    color: var(--ink-faint);
    font-size: 0.8rem;
    margin: 0;
}

/* Ponto neutro em cores ja existentes: reorganiza a apresentacao de
   rota/CT-e sem fabricar um sistema de cores de rota que ainda nao existe. */
.status-dot {
    background: currentColor;
    border-radius: 50%;
    display: inline-block;
    height: 6px;
    margin-right: 6px;
    width: 6px;
}

/* Hierarquia de largura das colunas da tabela operacional. */
.col-nfe { width: 15%; }
.col-emitente,
.col-destino { width: 16%; }
.col-rota { width: 12%; }
.col-frete,
.col-peso,
.col-leitura,
.col-cte { width: 9%; }
.col-importado { width: 6%; }

.step-list {
    display: grid;
    gap: 16px;
}

.step-item {
    display: grid;
    gap: 12px;
    grid-template-columns: 30px 1fr;
}

.step-number {
    align-items: center;
    background: var(--accent-soft);
    border-radius: 999px;
    color: var(--accent-ink);
    display: flex;
    font-size: 0.78rem;
    font-weight: 700;
    height: 30px;
    justify-content: center;
    width: 30px;
}

.step-item h3 {
    color: var(--ink);
    font-size: 0.86rem;
    margin: 0 0 2px;
}

.step-item p {
    color: var(--ink-soft);
    font-size: 0.82rem;
    margin: 0;
}

/* Linha da tabela clicavel: abre o popup de detalhes da nota. */
.data-table tbody tr[data-modal-url] {
    cursor: pointer;
}

.data-table tbody tr[data-modal-url]:hover {
    background: var(--surface-hover);
}

/* Popup de detalhes (dialog nativo) -- reutilizado por qualquer tela que
   declare `<dialog data-modal>` (NF-e, CT-e). Seletor por atributo, nao por
   ID: cada pagina só tem um desses por vez, mas o nome do ID nao devia
   amarrar o CSS a um dominio especifico. */
dialog[data-modal],
dialog[data-form-dialog] {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
    color: var(--ink);
    max-height: 88vh;
    max-width: min(820px, 94vw);
    overflow: hidden;
    padding: 0;
    width: 100%;
}

dialog[data-modal]::backdrop,
dialog[data-form-dialog]::backdrop {
    background: rgb(6 8 11 / 65%);
}

.modal-shell {
    display: grid;
    grid-template-rows: auto 1fr auto;
    max-height: 88vh;
    min-height: 0;
}

.modal-header {
    align-items: flex-start;
    border-bottom: 1px solid var(--border);
    display: flex;
    gap: 12px;
    justify-content: space-between;
    padding: 20px 22px;
}

.modal-header h2 {
    font-size: 1.15rem;
    margin: 0 0 4px;
}

.modal-header p {
    color: var(--ink-soft);
    font-size: 0.82rem;
    margin: 0;
}

.modal-body {
    display: grid;
    gap: 16px;
    min-height: 0;
    min-width: 0;
    overflow-x: hidden;
    overflow-y: auto;
    padding: 20px 22px;
}

.modal-section {
    background: rgb(255 255 255 / 2%);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    min-width: 0;
    padding: 16px 18px;
}

.modal-section-title {
    color: var(--ink-faint);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    margin: 0 0 12px;
    text-transform: uppercase;
}

/* Mesmo título de seção, usado fora de um `.modal-section` (ex.: dentro de
   um `.nfe-panel` que já tem sua própria tabela acima) -- precisa de um
   respiro por cima que o `.modal-section-title` sozinho não tem. */
.modal-section-title--spaced {
    margin-top: 20px;
}

/* Form pequeno embutido numa célula de tabela (ex.: ativar/desativar uma
   cidade) -- não pode herdar o `display: grid` genérico de `.action-panel
   form`, senão o botão ocupa a célula inteira. */
.table-inline-form {
    display: inline-block;
    margin-top: 6px;
}

.modal-warning {
    background: var(--warning-soft);
    border: 1px solid rgb(245 199 100 / 35%);
    border-radius: var(--radius-sm);
    color: var(--warning);
    font-size: 0.82rem;
    min-width: 0;
    padding: 12px 14px;
}

.modal-warning ul {
    margin: 6px 0 0;
    padding-left: 18px;
}

/* Cada pendência de emissao ocupa uma linha propria: a lista costuma vir
   com o nome da tag do layout seguido de uma frase, e sem respiro entre os
   itens vira um paragrafo unico ilegivel. */
.modal-warning li + li {
    margin-top: 4px;
}

.modal-warning code {
    font-family: var(--font-mono);
    font-size: 0.76rem;
    opacity: 0.85;
}

/* Grade de campos editáveis dentro de uma seção do popup (ex.: revisão do
   CT-e) -- mesmo ritmo visual do `.detail-list` ao lado (mesmo `gap`,
   mesma lógica `auto-fill`), só que com inputs em vez de texto estático,
   para o popup ficar simétrico entre o modo leitura e o modo edição. */
.form-grid {
    display: grid;
    gap: 16px 20px;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr));
    /* Formulario nao acompanha a largura do monitor: um campo de 1600px e
       tao ruim de ler quanto de preencher. */
    max-width: 1080px;
}

.form-grid .form-field {
    margin-bottom: 0;
}

.form-grid .form-field--full {
    grid-column: 1 / -1;
}

/* Campo que precisa de duas colunas sem ocupar a linha toda (ex.: nome de
   rua ao lado do numero). */
.form-grid .form-field--wide {
    grid-column: span 2;
}

@media (max-width: 620px) {
    .form-grid .form-field--wide {
        grid-column: 1 / -1;
    }
}

.modal-inline-action {
    margin-top: 14px;
}

/* Valor do frete cobrado à mão. Fica na seção "Valores", logo abaixo da
   tabela de componentes, porque é ali que o operador raciocina sobre preço
   -- o `form=` do input o mantém pertencendo ao formulário de revisão, que
   vive na seção "Carga". Largura contida: é um valor monetário, não um
   campo de texto, e esticá-lo até a borda sugeriria o contrário. */
.frete-manual {
    margin-top: 14px;
    max-width: 260px;
}

/* Alíquota do ICMS ajustada à mão. Mesmo raciocínio de `.frete-manual`:
   fica junto do valor na seção "Valores", contida porque é um percentual,
   não texto livre. */
.aliquota-manual {
    margin-top: 14px;
    max-width: 260px;
}

/* Consulta avulsa por chave: campo largo (44 dígitos) e botão ao lado, na
   mesma linha de base. `align-items: flex-end` alinha o botão pela BASE do
   campo, e não pelo topo -- senão ele flutua na altura do rótulo. */
.consulta-chave-linha {
    align-items: flex-end;
    display: flex;
    gap: 12px;
    max-width: 720px;
}

.consulta-chave-linha .form-field {
    flex: 1;
    /* Zera a margem herdada para que a base do input e a do botão
       coincidam — mesma correção do popup de importação de NF-e. */
    margin-bottom: 0;
}

.consulta-chave-linha input {
    font-family: var(--font-mono, ui-monospace, monospace);
    font-variant-numeric: tabular-nums;
}

@media (max-width: 640px) {
    .consulta-chave-linha {
        align-items: stretch;
        flex-direction: column;
    }
}

/* Separador entre as duas portas de entrada da importação (arquivo | chave).
   A linha atravessa o container e a palavra "ou" fica sobre o fundo do
   popup, escondendo o trecho central da régua. */
.importar-ou {
    align-items: center;
    display: flex;
    gap: 12px;
    margin: 18px 0;
}

.importar-ou::before,
.importar-ou::after {
    background: var(--border);
    content: "";
    flex: 1;
    height: 1px;
}

.importar-ou span {
    color: var(--text-muted);
    font-size: 0.85rem;
    text-transform: uppercase;
}

/* A linha (campo + botão) e a dica são irmãs, não aninhadas: a dica dentro
   da coluna do campo somava altura e o `align-items: flex-end` alinhava o
   botão pela base DELA, deixando-o solto abaixo do input. */
.importar-por-chave-linha {
    align-items: flex-end;
    display: flex;
    gap: 10px;
}

.importar-por-chave-linha .form-field {
    flex: 1;
    /* Zera a margem inferior herdada de `.form-field` para que a base do
       input e a do botão coincidam de verdade. */
    margin-bottom: 0;
}

.importar-por-chave .field-hint {
    margin-top: 6px;
}

/* A chave tem 44 dígitos: tabular-nums evita que o campo "dance" enquanto
   se digita, e o mono deixa conferir dígito a dígito contra o DANFE. */
.importar-por-chave input {
    font-family: var(--font-mono, ui-monospace, monospace);
    font-variant-numeric: tabular-nums;
}

@media (max-width: 560px) {
    .importar-por-chave-linha {
        align-items: stretch;
        flex-direction: column;
    }
}

/* Campo individual marcado incerto (Identificação, Valores, Carga e
   volumes): destaque contido numa única célula da grade. */
.detail-list > div.field-uncertain {
    background: var(--warning-soft);
    border-radius: var(--radius-sm);
    margin: -6px -8px;
    padding: 6px 8px;
}

.field-uncertain dt {
    color: var(--warning);
}

/* Seção inteira marcada incerta (Emitente/Destinatário/Endereço de entrega
   vindos de PDF): realce discreto no cartão, em vez de pintar cada valor de
   amarelo -- a lista de campos a conferir já está no aviso do topo. */
.modal-section:has(> .detail-list.field-uncertain) {
    border-color: rgb(245 199 100 / 45%);
}

.modal-footer {
    align-items: center;
    border-top: 1px solid var(--border);
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    justify-content: flex-end;
    padding: 16px 22px;
}

/* O menu "Mais ações" ancora à esquerda e o par secundária+principal à
   direita; `justify-content: space-between` no rodapé separa os dois. */
.acoes-extras {
    margin-right: auto;
    position: relative;
}

.acoes-extras > summary {
    /* `list-style: none` + `::-webkit-details-marker` derruba o triângulo
       nativo nos dois motores -- sem isso o <summary> estilizado como botão
       aparece com uma seta colada no texto. */
    cursor: pointer;
    list-style: none;
}

.acoes-extras > summary::-webkit-details-marker {
    display: none;
}

.acoes-extras-menu {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    bottom: calc(100% + 6px);
    box-shadow: 0 12px 32px rgb(0 0 0 / 45%);
    display: flex;
    flex-direction: column;
    left: 0;
    min-width: 232px;
    padding: 6px;
    position: absolute;
    /* Abre para CIMA: o rodapé fica no pé do popup, e um menu descendo
       sairia da área visível do <dialog>. */
    z-index: 20;
}

.acoes-extras-menu > button,
.acoes-extras-menu > a {
    align-items: center;
    background: none;
    border: 0;
    border-radius: var(--radius-sm);
    color: var(--text);
    cursor: pointer;
    display: flex;
    font: inherit;
    gap: 10px;
    padding: 9px 10px;
    text-align: left;
    text-decoration: none;
    white-space: nowrap;
}

.acoes-extras-menu > button:hover,
.acoes-extras-menu > a:hover,
.acoes-extras-menu > button:focus-visible,
.acoes-extras-menu > a:focus-visible {
    background: var(--surface-hover, rgb(255 255 255 / 6%));
}

.acoes-extras-menu svg {
    height: 16px;
    width: 16px;
}

/* Cancelar é destrutivo e raro: fica no fim, separado por uma linha, para
   não ser clicado por inércia junto das ações rotineiras acima. */
.acoes-extras-danger {
    border-top: 1px solid var(--border) !important;
    border-radius: 0 0 var(--radius-sm) var(--radius-sm) !important;
    color: var(--danger) !important;
    margin-top: 4px;
    padding-top: 11px !important;
}

.modal-footer-acoes {
    display: flex;
    gap: 10px;
}

.modal-footer-danger {
    margin-right: auto;
}

@keyframes spin {
    to {
        transform: rotate(360deg);
    }
}

@media (max-width: 960px) {
    .app-shell {
        grid-template-columns: 1fr;
    }

    .sidebar {
        gap: 14px;
        height: auto;
        max-width: 100vw;
        min-width: 0;
        padding: 14px 20px;
        position: static;
        width: 100%;
    }

    .sidebar .brand {
        padding: 0;
    }

    .menu-list {
        display: flex;
        gap: 8px;
        max-width: 100%;
        min-width: 0;
        overflow-x: auto;
        padding-bottom: 2px;
        scrollbar-width: thin;
        width: 100%;
    }

    .menu-section {
        display: none;
    }

    .menu-link {
        flex: 0 0 auto;
        white-space: nowrap;
    }

    /* Tablet/notebook menor: a coluna de importacao continua dominante, so
       menos folgada que no desktop grande. */
    .nfe-intro-grid {
        grid-template-columns: minmax(0, 1.5fr) minmax(280px, 1fr);
    }
}

@media (max-width: 640px) {
    .auth-layout {
        padding: 16px;
    }

    .login-card {
        border-radius: var(--radius-md);
        padding: 28px 22px;
    }

    .brand--login {
        margin-bottom: 26px;
    }

    .brand--login .brand-logo {
        height: 56px;
    }

    .topbar {
        flex-wrap: wrap;
        gap: 10px;
        padding: 10px 16px;
    }

    .topbar-search {
        flex-basis: 100%;
        max-width: none;
        order: 2;
    }

    .topbar-user {
        margin-left: auto;
    }

    .topbar-user>div {
        display: none;
    }

    .app-content {
        padding: 28px 16px;
    }

    .page-heading {
        align-items: flex-start;
        flex-direction: column;
        margin-bottom: 24px;
    }

    .metric-grid {
        grid-template-columns: 1fr;
    }

    .empty-state {
        align-items: flex-start;
        flex-direction: column;
    }

    .detail-grid {
        grid-template-columns: 1fr;
    }

    .nfe-intro-grid {
        grid-template-columns: 1fr;
    }

    .file-types {
        grid-template-columns: 1fr;
    }

    .upload-dropzone {
        min-height: 180px;
    }

    .detail-list {
        grid-template-columns: 1fr;
    }

    dialog[data-modal],
    dialog[data-form-dialog] {
        max-height: 94vh;
    }

    .modal-footer {
        flex-direction: column-reverse;
    }

    .modal-footer .button {
        width: 100%;
    }

    .config-grid {
        grid-template-columns: 1fr;
    }

    .panel-heading .switch {
        margin-top: 4px;
    }
}

/* Tela de Configuracoes: sub-navegacao de abas (hoje so "Email de NF-e",
   mas ja em formato de lista para as abas futuras). */
/* Rola dentro de si, nao no body. Com seis abas a tira passa de 375px e,
   sem `overflow-x`, quem rolava era a PAGINA -- deslocando cabecalho,
   paineis e tudo mais no celular. Regra geral do projeto: conteudo largo
   rola no proprio container. */
.subnav {
    border-bottom: 1px solid var(--border);
    display: flex;
    gap: 4px;
    margin-bottom: 24px;
    overflow-x: auto;
    /* A barra de rolagem embaixo de uma tira de abas parece defeito, e o
       gesto de arrastar ja e obvio no toque. */
    scrollbar-width: none;
}

.subnav::-webkit-scrollbar {
    display: none;
}

.subnav-link {
    border-bottom: 2px solid transparent;
    color: var(--ink-soft);
    /* Sem `flex: none` o flex encolhe as abas ate quebrar o rotulo em duas
       linhas em vez de deixar rolar. */
    flex: none;
    font-size: 0.86rem;
    font-weight: 650;
    margin-bottom: -1px;
    padding: 10px 4px;
    white-space: nowrap;
}

.subnav-link:hover {
    color: var(--ink);
}

.subnav-link.is-active {
    border-bottom-color: var(--accent);
    color: var(--accent-ink);
}

/* Texto de apoio abaixo de um campo, sem peso de erro. */
.field-hint {
    color: var(--ink-faint);
    font-size: 0.8rem;
    line-height: 1.5;
    margin: 6px 0 0;
}

/* Formulario da tela de Configuracoes: um .nfe-panel por secao, com
   respiro entre eles -- sem isso os cartoes ficam colados um no outro. */
.config-form {
    display: grid;
    gap: 24px;
}

/* A tabela de mensagens processadas vem depois do </form> (nao pode estar
   dentro dele: e so leitura). Mesmo respiro dos cartoes de dentro do form. */
.config-dashboard > .nfe-panel {
    margin-top: 24px;
}

/* Campos de conexao pareados (servidor+porta, usuario+senha, pasta+
   intervalo), como no restante dos formularios do app -- nao a grade larga
   de 6 colunas que o auto-fit produzia num container sem limite de largura.
   `align-items: start` evita que um campo mais alto (ex.: Senha, com dica
   abaixo) estique e desalinhe o campo vizinho na mesma linha. */
/* Responsiva, nao fixa em duas colunas: num monitor largo a grade de dois
   campos deixava metade da tela vazia e empilhava o formulario numa coluna
   longa de rolagem. `auto-fill` com piso de 260px mantem os campos legiveis
   e usa o espaco que existir. */
.config-grid {
    align-items: start;
    display: grid;
    gap: 18px 24px;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr));
}

/* Campo que precisa de mais espaco que o vizinho (ex.: endereco, texto de
   observacao). */
.config-grid .form-field--wide {
    grid-column: span 2;
}

.config-grid .form-field--full {
    grid-column: 1 / -1;
}

@media (max-width: 620px) {
    .config-grid .form-field--wide {
        grid-column: 1 / -1;
    }
}

.config-subheading {
    color: var(--ink-faint);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    margin: 20px 0 10px;
    text-transform: uppercase;
}

.config-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 18px;
}

/* Painel de status do robo, na tela de Logs de e-mail. */
.log-status-grid {
    display: grid;
    gap: 18px 24px;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}

.log-status-item p {
    margin: 0;
}

.log-status-item .status-pill {
    margin-top: 2px;
}

.switch-group {
    display: grid;
    gap: 14px;
    margin-top: 14px;
}

/* Interruptor on/off em CSS puro -- sem JS, so um checkbox redesenhado. */
.switch {
    align-items: center;
    cursor: pointer;
    display: inline-flex;
    gap: 10px;
    width: fit-content;
}

.switch input {
    -webkit-appearance: none;
    appearance: none;
    background: #12171e;
    border: 1px solid var(--border-strong);
    border-radius: 999px;
    cursor: pointer;
    flex: none;
    height: 22px;
    margin: 0;
    position: relative;
    transition: background-color 0.15s ease, border-color 0.15s ease;
    width: 40px;
}

.switch input::before {
    background: var(--ink-faint);
    border-radius: 50%;
    content: "";
    height: 16px;
    left: 2px;
    position: absolute;
    top: 2px;
    transition: transform 0.15s ease, background-color 0.15s ease;
    width: 16px;
}

.switch input:checked {
    background: var(--accent-soft);
    border-color: var(--accent);
}

.switch input:checked::before {
    background: var(--accent);
    transform: translateX(18px);
}

.switch input:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.switch-label {
    color: var(--ink);
    font-size: 0.86rem;
    font-weight: 600;
}

/* Resultado das mensagens processadas pelo robo de e-mail. */
.status-importado {
    background: var(--accent-soft);
    border-color: rgb(29 143 69 / 40%);
    color: var(--accent-ink);
}

.status-ja_existia {
    background: var(--info-soft);
    border-color: rgb(88 166 255 / 35%);
    color: var(--info);
}

.status-sem_anexo {
    background: var(--warning-soft);
    border-color: #765c27;
    color: var(--warning);
}

.status-falha {
    background: var(--negative-soft);
    border-color: rgb(255 107 118 / 40%);
    color: #ffb7bd;
}

@media (prefers-reduced-motion: reduce) {

    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        scroll-behavior: auto !important;
        transition-duration: 0.01ms !important;
    }
}
/* ==========================================================================
   Formularios — camada compartilhada
   ========================================================================== */

/* Checkbox solto dentro de um `.form-field` vira interruptor, sem exigir
   que o template o embrulhe em `.switch`. Os formularios gerados por
   `{% for field in form %}` renderizam `{{ field }}` cru: sem esta regra o
   navegador desenha a caixa nativa gigante sobre o tema escuro. */
.form-field input[type="checkbox"] {
    appearance: none;
    background: #12171e;
    border: 1px solid var(--border-strong);
    border-radius: 999px;
    cursor: pointer;
    flex: none;
    height: 24px;
    justify-self: start;
    margin: 0;
    position: relative;
    transition: background-color 140ms ease, border-color 140ms ease;
    width: 44px;
}

.form-field input[type="checkbox"]::before {
    background: var(--ink-faint);
    border-radius: 50%;
    content: "";
    height: 18px;
    left: 2px;
    position: absolute;
    top: 2px;
    transition: transform 140ms ease, background-color 140ms ease;
    width: 18px;
}

.form-field input[type="checkbox"]:checked {
    background: var(--accent-soft);
    border-color: var(--accent);
}

.form-field input[type="checkbox"]:checked::before {
    background: var(--accent);
    transform: translateX(20px);
}

.form-field input[type="checkbox"]:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Campo booleano: o rotulo fica AO LADO do interruptor, nao acima — e como
   todo formulario de mercado apresenta um on/off, e evita a coluna de
   rotulo orfa que sobra quando o controle tem 44px de largura. */
.form-field--switch {
    align-items: center;
    /* `.form-field` usa `align-content: start`; aqui a linha precisa ficar
       centrada na caixa de 46px para o interruptor bater com o meio dos
       inputs vizinhos, que tem rotulo acima. */
    align-content: center;
    align-self: end;
    column-gap: 12px;
    grid-template-columns: auto minmax(0, 1fr);
    min-height: 46px;
}

.form-field--switch > label {
    grid-column: 2;
    grid-row: 1;
    margin: 0;
}

.form-field--switch > input[type="checkbox"] {
    grid-column: 1;
    grid-row: 1;
}

/* Dica e erro continuam ocupando a linha inteira abaixo do par. */
.form-field--switch > :not(label):not(input[type="checkbox"]) {
    grid-column: 1 / -1;
}

/* Dica curta sob o campo. `small` cru herdava o tamanho do body e competia
   visualmente com o proprio rotulo. */
.form-field small {
    color: var(--ink-faint);
    font-size: 0.76rem;
    line-height: 1.45;
}

.form-field .alert {
    margin: 0;
}

/* Agrupador de campos dentro de um cartao. Substitui o `<h3>` solto que
   antes separava blocos ("Adicionar cidade") sem nenhuma hierarquia. */
/* Separador entre blocos. O primeiro bloco de um formulario nao leva linha
   — ele ja vem logo abaixo do cabecalho do cartao. */
.form-section {
    border-top: 1px solid var(--border);
    margin-top: 26px;
    padding-top: 22px;
}

form > .form-section:first-child {
    border-top: 0;
    margin-top: 0;
    padding-top: 0;
}

.form-section-title {
    align-items: baseline;
    color: var(--ink);
    display: flex;
    font-size: 0.92rem;
    font-weight: 700;
    gap: 10px;
    /* Respiro suficiente para o titulo nao encostar no primeiro rotulo da
       grade logo abaixo. */
    margin: 0 0 14px;
}

.form-section-desc {
    color: var(--ink-faint);
    font-size: 0.82rem;
    line-height: 1.5;
    margin: 0 0 16px;
}

/* Rodape de acoes do formulario: separado por uma linha, botao principal a
   direita como manda o padrao de formulario longo. */
.form-actions {
    align-items: center;
    border-top: 1px solid var(--border);
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    justify-content: flex-end;
    margin-top: 24px;
    padding-top: 20px;
}

.form-actions--start {
    justify-content: flex-start;
}

.form-actions .form-actions-hint {
    color: var(--ink-faint);
    font-size: 0.8rem;
    margin: 0 auto 0 0;
}

/* Botao compacto para celula de tabela. O `.button` padrao (40px) empurra a
   altura da linha e faz a tabela parecer um formulario. */
.button-sm {
    font-size: 0.78rem;
    min-height: 32px;
    padding: 0 11px;
}

.button-danger-ghost {
    background: transparent;
    border-color: rgb(255 107 118 / 35%);
    color: #ffb7bd;
}

.button-danger-ghost:hover {
    background: var(--negative-soft);
}

/* Acoes de uma linha de tabela, lado a lado e alinhadas a direita. */
.table-actions {
    align-items: center;
    display: flex;
    gap: 8px;
    justify-content: flex-end;
}

.table-actions form {
    display: inline-flex;
    margin: 0;
}

/* ==========================================================================
   Mensagens da aplicacao
   ========================================================================== */

/* As variantes de cor por severidade ja existiam; o que faltava era a
   PILHA: sem regra nenhuma para `.message-stack`, dez pendencias de emissao
   viravam dez faixas soltas empurrando o titulo da pagina para fora da tela.
   Aqui a faixa e compacta, dispensavel, e o bloco rola quando a lista passa
   de meia duzia de itens. */
.message-stack {
    display: grid;
    gap: 8px;
    margin-bottom: 22px;
    max-height: 260px;
    overflow-y: auto;
    padding-right: 2px;
}

.message-stack .alert {
    align-items: flex-start;
    border-left-width: 3px;
    display: flex;
    gap: 10px;
    margin: 0;
    padding-right: 40px;
    position: relative;
}

.message-stack .alert::before {
    background: currentcolor;
    border-radius: 50%;
    content: "";
    flex: none;
    height: 7px;
    margin-top: 6px;
    opacity: 0.9;
    width: 7px;
}


.message-dismiss {
    background: transparent;
    border: 0;
    border-radius: 6px;
    color: inherit;
    line-height: 1;
    opacity: 0.55;
    padding: 4px 7px;
    position: absolute;
    right: 6px;
    top: 6px;
}

.message-dismiss:hover {
    background: rgb(255 255 255 / 10%);
    opacity: 1;
}

/* Resumo quando a operacao devolve muitas mensagens de uma vez (as
   pendencias de emissao do CT-e sao o caso tipico). Fechado por padrao, o
   operador abre se quiser a lista completa. */
/* Tom de atencao, nao neutro: o agrupamento so acontece quando uma acao
   devolve varias coisas a resolver. Um resumo cinza faria a recusa passar
   despercebida. */
.message-group {
    background: var(--warning-soft);
    border: 1px solid rgb(245 199 100 / 30%);
    border-radius: var(--radius-sm);
    margin-bottom: 22px;
}

.message-group > summary {
    color: var(--warning);
}

.message-group > summary svg {
    height: 15px;
    width: 15px;
}

.message-group > summary {
    align-items: center;
    cursor: pointer;
    display: flex;
    font-size: 0.84rem;
    font-weight: 650;
    gap: 8px;
    list-style: none;
    padding: 12px 14px;
}

.message-group > summary::-webkit-details-marker {
    display: none;
}

.message-group > summary::after {
    color: var(--ink-faint);
    content: "▾";
    margin-left: auto;
    transition: transform 140ms ease;
}

.message-group[open] > summary::after {
    transform: rotate(180deg);
}

.message-group .message-stack {
    margin: 0;
    padding: 0 12px 12px;
}

/* ==========================================================================
   Barra de filtros (listagens de NF-e e CT-e)
   ========================================================================== */

/* Flex, nao grid: a mesma barra serve telas com tres filtros e telas com
   um so. Com `grid-template-columns` fixo, o caso de um campo gerava
   trilhas vazias e jogava o botao para a linha de baixo. */
.filter-bar {
    align-items: end;
    display: flex;
    flex-wrap: wrap;
    gap: 14px 16px;
}

.filter-bar .form-field {
    flex: 1 1 190px;
}

/* O campo de busca e o principal: ganha o dobro do espaco livre. */
.filter-bar .form-field:first-child {
    flex: 2 1 260px;
}

.filter-bar .form-field {
    margin-bottom: 0;
}

.filter-bar .filter-actions {
    display: flex;
    gap: 8px;
}

/* Sem isto o botao (40px) fica mais baixo que os controles (46px) ao lado e
   a linha parece desalinhada mesmo com `align-items: end`. */
.filter-bar .button {
    min-height: 46px;
}

@media (max-width: 620px) {
    .filter-bar .form-field,
    .filter-bar .form-field:first-child {
        flex-basis: 100%;
    }

    .filter-bar .filter-actions {
        width: 100%;
    }

    .filter-bar .filter-actions .button {
        flex: 1;
    }
}

/* Chips de atalho por rota, acima da tabela: um clique filtra, sem abrir o
   select. */
.chip-row {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 16px;
}

.chip {
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: 999px;
    color: var(--ink-soft);
    display: inline-flex;
    align-items: center;
    font-size: 0.78rem;
    font-weight: 650;
    gap: 7px;
    min-height: 30px;
    padding: 0 12px;
    transition: background-color 140ms ease, border-color 140ms ease, color 140ms ease;
}

.chip:hover {
    background: var(--surface-hover);
    color: var(--ink);
}

.chip.is-active {
    background: var(--accent-soft);
    border-color: var(--accent);
    color: var(--accent-ink);
}


/* Cartao trazido para o primeiro plano (ex.: a regra da cidade que o
   operador acabou de abrir). Sem isto o formulario aparecia no fim de uma
   pagina longa sem nenhuma indicacao de que era o alvo do clique. */
.nfe-panel.is-highlighted {
    border-color: var(--accent);
    box-shadow: 0 0 0 1px rgb(29 143 69 / 22%), var(--shadow);
}

/* Linha da tabela correspondente ao item em edicao. */
.data-table tbody tr.is-selected {
    background: var(--accent-soft);
}

/* Só o fundo marca a linha em edicao. Uma barra lateral desenhada com
   `inset box-shadow` nao ocupa espaco e encostava no texto, e compensar com
   padding so nessa linha desalinhava a coluna em relacao as demais. */

/* Nota explicativa curta dentro de um cartao. Substitui os paineis inteiros
   de texto que ocupavam o topo das telas de cadastro empurrando a tabela e
   o formulario para fora da primeira dobra. */
.callout {
    background: rgb(88 166 255 / 7%);
    border: 1px solid rgb(88 166 255 / 22%);
    border-radius: var(--radius-sm);
    color: var(--ink-soft);
    display: flex;
    font-size: 0.82rem;
    gap: 10px;
    line-height: 1.55;
    margin-bottom: 20px;
    padding: 12px 14px;
}

.callout svg {
    color: var(--info);
    flex: none;
    height: 16px;
    margin-top: 2px;
    width: 16px;
}

.callout p {
    margin: 0;
}

.callout strong {
    color: var(--ink);
}

/* Formulario de uma unica linha dentro de uma celula de tabela (select +
   botao). Sem isto o `.form-field` empilhava o controle acima do botao e a
   linha da tabela dobrava de altura. */
.row-form {
    align-items: center;
    display: flex;
    gap: 10px;
}

.row-form .form-field {
    margin-bottom: 0;
    min-width: 190px;
}

.row-form select {
    min-height: 38px;
    padding-block: 8px;
}

.callout--warning {
    background: var(--warning-soft);
    border-color: rgb(245 199 100 / 30%);
}

.callout--warning svg {
    color: var(--warning);
}

/* ==========================================================================
   Popup de formulario
   ========================================================================== */

/* Reaproveita a casca do popup de detalhes (`.modal-shell`), mas o corpo
   rola sozinho: formularios de cadastro passam da altura da tela em telas
   menores. */
dialog[data-form-dialog] .modal-body {
    overflow-y: auto;
}

dialog[data-form-dialog] .form-grid {
    max-width: none;
}

/* O `.form-actions` do formulario faz o papel do rodape do popup: fica
   colado embaixo, com a linha divisoria do proprio modal. */
dialog[data-form-dialog] .form-actions {
    border-top: 0;
    margin-top: 22px;
    padding-top: 0;
}

/* Botao de acao principal no cabecalho de um cartao (ex.: "+ Nova rota"). */
.panel-heading .button {
    flex: none;
}

/* Linha de tabela navegavel: o clique vale na linha inteira (ver
   `initializeRowLinks`), entao o cursor e o realce precisam dizer isso — sem
   eles so o texto do link parecia clicavel. */
.data-table--clicavel tbody tr {
    cursor: pointer;
    transition: background-color 120ms ease;
}

.data-table--clicavel tbody tr:hover {
    background: var(--surface-hover);
}

.data-table--clicavel tbody tr:hover .table-link {
    color: var(--accent-ink);
}

/* Grupo de botoes no cabecalho da pagina (voltar + acao principal). */
.page-heading-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

/* Campo que ocupa a linha inteira do `.detail-list` (ex.: observacoes). */
.detail-list-full {
    grid-column: 1 / -1;
}

/* ==========================================================================
   Correcoes de espacamento
   ========================================================================== */

/* `.mono` traz `white-space: nowrap` — util numa tabela, onde manter a
   coluna intacta importa. Dentro do `.detail-list` (grade de duas ou tres
   colunas) isso fazia a chave de acesso de 44 digitos estourar a celula e
   passar POR CIMA do valor vizinho. Aqui o valor quebra. */
.detail-list dd.mono,
.detail-list dd .mono {
    overflow-wrap: anywhere;
    white-space: normal;
}

/* Respiro entre a barra de filtro/busca e a tabela logo abaixo: sem isto o
   cabecalho da tabela encostava no campo de busca. */
.filter-bar + .data-table-wrap,
.filter-bar + .empty-state,
.chip-row + .data-table-wrap,
.chip-row + .empty-state {
    margin-top: 22px;
}


/* ==========================================================================
   Paginacao
   ========================================================================== */

.paginacao {
    align-items: center;
    border-top: 1px solid var(--border);
    display: flex;
    flex-wrap: wrap;
    gap: 12px 20px;
    justify-content: space-between;
    margin-top: 18px;
    padding-top: 16px;
}

.paginacao-resumo {
    color: var(--ink-faint);
    font-size: 0.8rem;
    margin: 0;
}

.paginacao-resumo strong {
    color: var(--ink);
}

.paginacao-paginas,
.paginacao-tamanho {
    align-items: center;
    display: flex;
    gap: 4px;
}

.paginacao-tamanho span {
    color: var(--ink-faint);
    font-size: 0.78rem;
    margin-right: 4px;
}

.paginacao-item {
    align-items: center;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    color: var(--ink-soft);
    display: inline-flex;
    font-size: 0.8rem;
    font-weight: 650;
    justify-content: center;
    min-height: 32px;
    min-width: 32px;
    padding: 0 8px;
    transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease;
}

.paginacao-item:hover {
    background: var(--surface-hover);
    color: var(--ink);
}

.paginacao-item.is-active {
    background: var(--accent-soft);
    border-color: var(--accent);
    color: var(--accent-ink);
}

/* Extremos da lista: o link continua no DOM (a URL e valida) mas nao
   convida ao clique. */
.paginacao-item.is-disabled {
    opacity: 0.35;
    pointer-events: none;
}

.paginacao-item svg {
    height: 15px;
    width: 15px;
}

.paginacao-reticencias {
    color: var(--ink-faint);
    padding: 0 2px;
}

/* Cabecalho de coluna ordenavel. */
.data-table th .ordenavel {
    align-items: center;
    color: inherit;
    display: inline-flex;
    gap: 5px;
}

.data-table th .ordenavel:hover {
    color: var(--ink);
}

.data-table th .ordenavel svg {
    height: 13px;
    opacity: 0.45;
    width: 13px;
}

.data-table th .ordenavel.is-active {
    color: var(--accent-ink);
}

.data-table th .ordenavel.is-active svg {
    opacity: 1;
}

/* ==========================================================================
   Relatorios — construtor + folha A4
   ========================================================================== */

/* A tela precisa de mais largura que o resto do app: sao duas colunas, e o
   documento A4 (210mm ~ 794px) tem largura fixa. Regra propria e nao um
   acrescimo ao seletor de `.nfe-dashboard`, que da `max-width: none`.
   Precisa ficar DENTRO da media query, senao perde para o `padding: 16px`
   que a media query de 640px aplica em `.app-content`. */
@media (min-width: 641px) {
    .app-content:has(.relatorio-dashboard) {
        max-width: 1520px;
        padding-inline: clamp(24px, 3vw, 48px);
    }
}

.relatorio-dashboard {
    display: flex;
    flex-direction: column;
    gap: 20px;
}

.relatorio-dashboard > .page-heading {
    margin-bottom: 0;
}

/* --- Barra de acoes ------------------------------------------------------- */

.relatorio-acoes {
    align-items: center;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    display: flex;
    flex-wrap: wrap;
    gap: 10px 14px;
    justify-content: space-between;
    padding: 12px 14px;
}

.relatorio-acoes-grupo {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.relatorio-acoes-grupo--fim {
    margin-left: auto;
}

.relatorio-acoes .button[disabled],
.page-heading-actions .button[disabled] {
    cursor: not-allowed;
    opacity: 0.5;
}

/* --- Layout de duas colunas ---------------------------------------------- */

.relatorio-layout {
    align-items: start;
    display: grid;
    gap: 20px;
    grid-template-columns: 330px minmax(0, 1fr);
}

@media (max-width: 1100px) {
    .relatorio-layout {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* --- Painel construtor ---------------------------------------------------- */

.relatorio-construtor {
    display: flex;
    flex-direction: column;
    gap: 10px;
    position: sticky;
    top: 16px;
}

@media (max-width: 1100px) {
    .relatorio-construtor {
        position: static;
    }
}

.relatorio-aviso {
    align-items: center;
    background: var(--warning-soft);
    border: 1px solid #765c27;
    border-radius: var(--radius-sm);
    color: var(--warning);
    display: flex;
    font-size: 0.8rem;
    gap: 8px;
    padding: 9px 11px;
}

.relatorio-aviso svg {
    flex: none;
    height: 15px;
    width: 15px;
}

.relatorio-bloco {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    overflow: hidden;
}

.relatorio-bloco > summary {
    align-items: center;
    color: var(--ink-faint);
    cursor: pointer;
    display: flex;
    font-size: 0.7rem;
    font-weight: 700;
    justify-content: space-between;
    letter-spacing: 0.08em;
    list-style: none;
    padding: 13px 14px;
    text-transform: uppercase;
    user-select: none;
}

/* Remove o triangulo nativo (Safari usa `::-webkit-details-marker`). */
.relatorio-bloco > summary::-webkit-details-marker {
    display: none;
}

.relatorio-bloco > summary:hover {
    color: var(--ink-soft);
}

.relatorio-bloco > summary:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: -2px;
}

.relatorio-bloco > summary svg {
    height: 15px;
    transition: transform 160ms ease;
    width: 15px;
}

.relatorio-bloco[open] > summary svg {
    transform: rotate(180deg);
}

.relatorio-bloco-corpo {
    border-top: 1px solid var(--border);
    display: grid;
    gap: 12px;
    /* `minmax(0, 1fr)` e nao `auto`: itens de grid tem `min-width: auto`, que
       os impede de encolher abaixo do proprio `min-content`. O texto longo das
       opcoes ("Baixada Santista - Rota 2 (Guaruja/Bertioga)") define esse
       minimo, a coluna estoura os 330px do painel e o `overflow: hidden` do
       bloco corta os campos. Com `minmax(0, ...)` a coluna nunca passa do
       container. */
    grid-template-columns: minmax(0, 1fr);
    padding: 14px;
}

.relatorio-bloco-corpo .form-field {
    margin-bottom: 0;
    /* `.form-field` tambem e grid: sem isto o select herda o mesmo piso de
       `min-content` e volta a estourar, agora um nivel abaixo. */
    grid-template-columns: minmax(0, 1fr);
    min-width: 0;
}

/* Texto longo de `<option>` nao pode ditar a largura do `<select>`. */
.relatorio-bloco-corpo select,
.relatorio-bloco-corpo input,
.relatorio-bloco-corpo textarea {
    max-width: 100%;
    min-width: 0;
}

.relatorio-periodo {
    display: grid;
    gap: 10px;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    min-width: 0;
}

.relatorio-switch {
    align-items: center;
    display: flex;
    gap: 9px;
}

.relatorio-bloco-acoes {
    display: grid;
    gap: 8px;
    margin-top: 2px;
}

/* --- Palco da previa ------------------------------------------------------ */

.relatorio-palco {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    /* Rolagem horizontal em telas estreitas em vez de `transform: scale()`:
       `transform` altera o layout de impressao e a folha sairia errada no
       papel. */
    overflow: auto;
    padding: 20px;
}

.relatorio-documento {
    display: flex;
    justify-content: center;
}

/* A escala vem do JS (`ajustarEscala`), que mede o palco. `scale` preserva a
   proporcao do A4 e nao reflui o texto -- a folha continua com 210mm logicos,
   so e desenhada menor. Seguro porque a impressao tem rota propria, sem palco
   e sem transform. */
.relatorio-palco .folha-a4 {
    /* `flex: none` e obrigatorio: sem ele o container flex espreme a folha
       abaixo dos 210mm e o documento sai DISTORCIDO (texto refluido, colunas
       estreitas) em vez de apenas menor. A largura logica tem que ficar fixa
       para o `scale` ser a unica coisa que muda. */
    flex: none;
    transform: scale(var(--folha-escala, 1));
    transform-origin: top center;
}

.relatorio-palco.is-remontando {
    cursor: progress;
}

.relatorio-palco.is-remontando .relatorio-documento {
    opacity: 0.45;
    transition: opacity 120ms ease;
}

/* --- Folha A4 -------------------------------------------------------------
   DOCUMENTO, nao UI. Todas as cores sao variaveis locais: e assim que a folha
   continua branca num app inteiramente dark, sem precisar de tema claro. */

.folha-a4 {
    --doc-ink: #17212c;
    --doc-ink-soft: #55606d;
    --doc-border: #d8dee6;
    --doc-cabecalho: #1b2129;
    --doc-accent: #1d8f45;
    --doc-negativo: #b4232f;
    --doc-zebra: #f4f6f9;

    background: #fff;
    box-shadow: 0 10px 34px rgb(0 0 0 / 35%);
    color: var(--doc-ink);
    /* Fonte fixa e nao `var(--font-sans)`: Bahnschrift tem metricas proprias e
       a folha precisa renderizar igual na tela e no papel. */
    font-family: "Segoe UI", Arial, Helvetica, sans-serif;
    font-size: 10.5px;
    line-height: 1.45;
    min-height: 297mm;
    padding: 14mm 12mm;
    width: 210mm;
}

.folha-cabecalho {
    align-items: flex-start;
    background: var(--doc-cabecalho);
    color: #fff;
    display: flex;
    gap: 18px;
    justify-content: space-between;
    margin: -14mm -12mm 0;
    padding: 10mm 12mm 8mm;
}

.folha-logo-img {
    display: block;
    height: 40px;
    width: auto;
}

.folha-sublogo {
    color: #9fb0c2;
    font-size: 0.62rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    margin: 3px 0 0;
    text-transform: uppercase;
}

.folha-identificacao {
    text-align: right;
}

.folha-identificacao h1 {
    font-size: 1.05rem;
    margin: 0;
}

.folha-identificacao p {
    color: #9fb0c2;
    font-size: 0.72rem;
    margin: 3px 0 0;
}

.folha-periodo {
    color: #fff !important;
    font-weight: 600;
}

.folha-regua {
    background: var(--doc-accent);
    height: 4px;
    margin: 0 -12mm 8mm;
}

.folha-secao {
    margin-bottom: 7mm;
}

.folha-secao-titulo {
    border-bottom: 1px solid var(--doc-border);
    color: var(--doc-ink-soft);
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    margin: 0 0 3mm;
    padding-bottom: 2mm;
    text-transform: uppercase;
}

.folha-filtros {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 8px;
    list-style: none;
    margin: 0;
    padding: 0;
}

.folha-filtros li {
    background: var(--doc-zebra);
    border: 1px solid var(--doc-border);
    border-radius: 3px;
    display: inline-flex;
    gap: 5px;
    padding: 3px 7px;
}

.folha-filtros span {
    color: var(--doc-ink-soft);
}

.folha-kpis {
    display: grid;
    gap: 3mm;
    grid-template-columns: repeat(6, minmax(0, 1fr));
}

.folha-kpi {
    border: 1px solid var(--doc-border);
    border-radius: 4px;
    border-top: 3px solid var(--doc-ink-soft);
    padding: 3mm;
}

.folha-kpi span {
    color: var(--doc-ink-soft);
    display: block;
    font-size: 0.6rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    margin-bottom: 2px;
    text-transform: uppercase;
}

.folha-kpi strong {
    display: block;
    font-size: 0.95rem;
    font-variant-numeric: tabular-nums;
    line-height: 1.2;
    word-break: break-word;
}

.folha-kpi--positivo {
    border-top-color: var(--doc-accent);
}

.folha-kpi--positivo strong {
    color: var(--doc-accent);
}

.folha-kpi--atencao {
    border-top-color: var(--doc-negativo);
}

.folha-kpi--atencao strong {
    color: var(--doc-negativo);
}

.folha-resumo {
    display: grid;
    gap: 2mm;
    list-style: none;
    margin: 0;
    padding: 0;
}

.folha-resumo-item {
    border-left: 3px solid var(--doc-border);
    padding-left: 3mm;
}

.folha-resumo-item--positivo {
    border-left-color: var(--doc-accent);
}

.folha-resumo-item--atencao {
    border-left-color: var(--doc-negativo);
}

.folha-metricas {
    display: grid;
    gap: 3mm;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    margin: 0;
}

.folha-metricas dt {
    color: var(--doc-ink-soft);
    font-size: 0.6rem;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}

.folha-metricas dd {
    font-size: 0.85rem;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    margin: 2px 0 0;
}

/* `table-layout: fixed` + larguras percentuais: sem isso uma tabela larga
   estoura a margem do A4 e o Chrome corta a direita SEM aviso. */
.folha-tabela {
    border-collapse: collapse;
    table-layout: fixed;
    width: 100%;
}

.folha-tabela th {
    background: var(--doc-cabecalho);
    color: #fff;
    font-size: 0.6rem;
    font-weight: 600;
    letter-spacing: 0.05em;
    padding: 2.4mm 1.6mm;
    text-align: left;
    text-transform: uppercase;
}

.folha-tabela td {
    border-bottom: 1px solid var(--doc-border);
    padding: 2mm 1.6mm;
    vertical-align: top;
    word-break: break-word;
}

.folha-tabela tbody tr:nth-child(even) {
    background: var(--doc-zebra);
}

.folha-tabela tfoot td {
    background: var(--doc-zebra);
    border-top: 2px solid var(--doc-cabecalho);
    font-variant-numeric: tabular-nums;
}

.folha-tabela .col-numero {
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.folha-tabela .col-data { width: 9%; }
.folha-tabela .col-nf { width: 8%; }
.folha-tabela .col-cliente { width: 22%; }
.folha-tabela .col-cidade { width: 13%; }
.folha-tabela .col-rota { width: 13%; }
.folha-tabela .col-cte { width: 8%; }
.folha-tabela .col-valor { width: 10%; }
.folha-tabela .col-peso { width: 9%; }
.folha-tabela .col-status { width: 8%; }

.folha-vazio {
    border: 1px dashed var(--doc-border);
    border-radius: 4px;
    color: var(--doc-ink-soft);
    margin: 0;
    padding: 8mm;
    text-align: center;
}

.folha-rodape {
    border-top: 1px solid var(--doc-border);
    color: var(--doc-ink-soft);
    display: flex;
    font-size: 0.62rem;
    justify-content: space-between;
    margin-top: 6mm;
    padding-top: 2mm;
}

/* A paginacao e controle de tela, nao parte do documento. */
.folha-a4 .paginacao {
    border-top: 1px solid var(--doc-border);
    margin-top: 4mm;
    padding-top: 3mm;
}

/* --- Pagina de impressao -------------------------------------------------- */

.pagina-impressao {
    align-items: center;
    background: #2b333d;
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding: 20px;
}

.impressao-barra {
    align-items: center;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    color: var(--ink-soft);
    display: flex;
    flex-wrap: wrap;
    font-size: 0.8rem;
    gap: 12px;
    max-width: 210mm;
    padding: 12px 14px;
}

/* --- Impressao ------------------------------------------------------------
   Escopado a folha e a pagina de impressao: regra global vazaria para as
   outras telas do app. */

@page {
    margin: 12mm 10mm 14mm;
    size: A4 portrait;
}

@media print {
    html,
    body,
    .pagina-impressao {
        background: #fff !important;
        display: block;
        padding: 0;
    }

    /* Cromo que nao pertence ao documento. */
    .sidebar,
    .topbar,
    .impressao-barra,
    .relatorio-construtor,
    .relatorio-acoes,
    .page-heading,
    .message-stack,
    .folha-a4 .paginacao {
        display: none !important;
    }

    .app-content,
    .relatorio-layout,
    .relatorio-palco,
    .relatorio-documento {
        background: none;
        border: 0;
        display: block;
        max-width: none;
        overflow: visible;
        padding: 0;
    }

    .folha-a4 {
        box-shadow: none;
        margin: 0;
        min-height: 0;
        padding: 0;
        width: auto;
    }

    /* Na tela o cabecalho "sangra" para fora do padding da folha com margem
       NEGATIVA (`margin: -14mm -12mm 0`), para tocar as bordas da folha
       branca. Na impressao o padding da folha ja vira 0 (`.folha-a4` acima)
       -- nao ha mais padding para sangrar -- mas se so as margens
       horizontais forem resetadas, a margem superior negativa sobrevive e
       empurra o cabecalho para CIMA do topo da pagina, cortando-o. Por isso o
       reset aqui e `margin: 0` completo, nao `margin-inline`. */
    .folha-cabecalho {
        margin: 0;
        padding: 6mm;
    }

    .folha-regua {
        margin-inline: 0;
    }

    /* Obrigatorio: sem isto o Chrome descarta TODO fundo e o cabecalho grafite
       da tabela e a zebra saem em branco. O alias -webkit- ainda e necessario. */
    .folha-a4,
    .folha-a4 * {
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }

    /* Cabecalho repete em cada pagina; totais fecham no fim. */
    .folha-tabela thead {
        display: table-header-group;
    }

    .folha-tabela tfoot {
        display: table-footer-group;
    }

    .folha-tabela tr,
    .folha-kpi,
    .folha-resumo-item,
    .folha-secao--kpis,
    .folha-secao--resumo {
        break-inside: avoid;
    }
}

/* Link que age como botao desabilitado (exportar/imprimir sem registros).
   `<a>` nao aceita o atributo `disabled`, entao a trava e por CSS + o
   `aria-disabled` que o JS aplica. */
a.button.is-disabled {
    cursor: not-allowed;
    opacity: 0.5;
    pointer-events: none;
}

/* ==========================================================================
   Home — dashboard operacional
   ========================================================================== */

.dashboard {
    display: flex;
    flex-direction: column;
    gap: 18px;
}

.dashboard > .page-heading {
    margin-bottom: 0;
}

.dashboard-filtros {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

/* Grupo de rotas é o filtro PRIMÁRIO: chips maiores e com mais destaque que
   os demais controles, na própria primeira linha da barra -- não uma seção
   à parte embaixo dos cards. */
.chip-row--grupos {
    margin-top: 0;
}

.chip--grupo {
    font-size: 0.82rem;
    font-weight: 700;
    min-height: 34px;
    padding: 0 15px;
}

/* Segunda linha, densa: período + data + rota específica + limpar, tudo
   numa única faixa curta em vez de um bloco de `.form-field` empilhados. */
.filter-bar--compacto {
    align-items: center;
    gap: 10px;
}

.filter-bar--compacto .chip-row {
    margin-top: 0;
}

.filter-bar--compacto .form-field {
    flex: 0 1 150px;
}

.filter-bar--compacto #filtro-rota {
    min-width: 170px;
}

.filter-bar--compacto .form-field input,
.filter-bar--compacto .form-field select {
    min-height: 34px;
}

.filter-bar--compacto .filter-actions .button {
    min-height: 34px;
    padding: 0 10px;
}

@media (max-width: 620px) {
    .filter-bar--compacto .form-field {
        flex-basis: 100%;
    }
}

/* Painel de data/rota, fechado por padrão -- ver comentário em
   `core/_construtor.html`. `<details>` em vez de um toggle em JS: o
   navegador já dá o recolher e o teclado de graça (mesmo raciocínio do
   `<details>` de `relatorios/_construtor.html`). */
.dashboard-filtro-avancado > summary {
    align-items: center;
    cursor: pointer;
    display: flex;
    gap: 12px;
    justify-content: space-between;
    list-style: none;
    padding: 2px;
    user-select: none;
}

.dashboard-filtro-avancado > summary::-webkit-details-marker {
    display: none;
}

.dashboard-filtro-resumo {
    align-items: center;
    color: var(--ink-soft);
    display: inline-flex;
    font-size: 0.82rem;
    gap: 8px;
}

.dashboard-filtro-resumo svg {
    color: var(--ink-faint);
    flex: none;
    height: 15px;
    width: 15px;
}

.dashboard-filtro-resumo strong {
    color: var(--ink);
}

.dashboard-filtro-abrir {
    align-items: center;
    color: var(--ink-faint);
    display: inline-flex;
    flex: none;
    font-size: 0.76rem;
    font-weight: 650;
    gap: 5px;
    transition: color 140ms ease;
}

.dashboard-filtro-avancado > summary:hover .dashboard-filtro-abrir {
    color: var(--ink-soft);
}

.dashboard-filtro-abrir svg {
    height: 14px;
    transition: transform 160ms ease;
    width: 14px;
}

.dashboard-filtro-avancado[open] > summary .dashboard-filtro-abrir svg {
    transform: rotate(180deg);
}

.dashboard-filtro-avancado .filter-bar--compacto {
    margin-top: 12px;
}

/* Alerta acima da grade -- o aviso de "nenhuma NF-e automática" mora aqui,
   não dentro do card (texto longo dentro do card espremia o número, que é
   o dado que precisa saltar aos olhos). `margin-bottom` igual ao `gap` de
   `.dashboard`: o alerta vive DENTRO do palco (não é filho direto do
   flex), então não herda aquele espaçamento -- sem repetir o valor aqui,
   ficava colado na grade de cards logo abaixo, mais apertado que o resto
   do ritmo vertical da tela. */
.dashboard-alerta {
    align-items: center;
    display: flex;
    gap: 10px;
    margin: 0 0 18px;
}

.dashboard-alerta svg {
    flex: none;
    height: 18px;
    width: 18px;
}

/* --- Grade de indicadores ---------------------------------------------- */

/* Uma grade única, sem títulos de seção: a diferenciação NF-e/CT-e/Frete
   vem do ícone e da cor de cada card, não de um rótulo de bloco -- é isso
   que lê como um dashboard (referência do usuário), não como uma lista de
   três blocos empilhados. Em telas largas (a Home usa a largura cheia, ver
   `.app-content:has(.dashboard)`), `auto-fill` abre 5 colunas ou mais. */
.metric-grid--dashboard {
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}

.metric-card {
    border-top: 3px solid transparent;
    gap: 12px;
    padding: 18px 20px;
    transition: border-color 160ms ease, box-shadow 160ms ease, transform 160ms ease;
}

.metric-card:hover {
    box-shadow: 0 10px 26px rgb(0 0 0 / 22%);
    transform: translateY(-2px);
}

.metric-card-head {
    align-items: center;
    display: flex;
    justify-content: space-between;
}

.metric-card-icon {
    align-items: center;
    background: var(--surface-raised);
    border-radius: var(--radius-sm);
    color: var(--ink-faint);
    display: inline-flex;
    height: 32px;
    justify-content: center;
    width: 32px;
}

.metric-card-icon svg {
    height: 16px;
    width: 16px;
}

.metric-card strong {
    font-size: 2rem;
}

.metric-card--positivo {
    border-top-color: var(--accent);
}

.metric-card--positivo strong {
    color: var(--accent-ink);
}

.metric-card--positivo .metric-card-icon {
    background: var(--accent-soft);
    color: var(--accent-ink);
}

.metric-card--atencao {
    border-top-color: var(--warning);
}

.metric-card--atencao strong {
    color: var(--warning);
}

.metric-card--atencao .metric-card-icon {
    background: var(--warning-soft);
    color: var(--warning);
}

.metric-card--negativo {
    border-top-color: var(--negative);
}

.metric-card--negativo strong {
    color: var(--negative);
}

.metric-card--negativo .metric-card-icon {
    background: var(--negative-soft);
    color: var(--negative);
}

/* --- Estado ocupado (mesmo padrão do palco de relatórios) --------------- */

[data-dashboard-palco].is-remontando [data-dashboard-previa] {
    opacity: 0.55;
    transition: opacity 120ms ease;
}
