/* /Diagnostics/LogViewport.razor.rz.scp.css */
/* O bloco rola DENTRO de si: sem isto uma linha longa empurra a página inteira para o lado. */
.log-pre[b-is4jdp8ga6] {
    max-height: 60vh;
    overflow: auto;
    margin-bottom: 0;
    /* Veio do `<pre>` que este componente substituiu — num `div` a fonte precisa ser declarada. */
    font-family: var(--bs-font-monospace);
    font-size: .875em;
}

/* Superfície escura fixa nos dois temas: é a aparência de terminal do conteúdo mostrado aqui, e o
   contraste foi medido contra ela. */
.log-pre-dark[b-is4jdp8ga6] {
    background: #1e1e1e;
    color: #e8e8e8;
}

/* Cada linha é um bloco que preserva o próprio espaço em branco. É o que permite o container ser um
   `div` em vez de um `<pre>`. */
.log-linha[b-is4jdp8ga6] {
    display: block;
    white-space: pre-wrap;
    word-break: break-word;
}

/* Níveis por cor. A cor NÃO é o único sinal — o nível segue escrito na própria linha, e quem não
   distingue as duas ainda lê qual é. Tons medidos contra a superfície escura. */
.log-linha-aviso[b-is4jdp8ga6] {
    color: var(--at-warn);
}

.log-linha-erro[b-is4jdp8ga6] {
    color: var(--at-fail);
}

/* ⚠️ No bloco de terminal a superfície é #1e1e1e SEMPRE, tema claro incluído — então ali valem as
   cores do par ESCURO, e não as do tema. Medido: o par claro dá 3,39:1 no aviso e 2,58:1 no erro
   sobre esse fundo, os dois reprovados. Com o par escuro, 9,99:1 e 6,03:1. */
.log-pre-dark .log-linha-aviso[b-is4jdp8ga6] {
    color: var(--at-warn-escuro);
}

.log-pre-dark .log-linha-erro[b-is4jdp8ga6] {
    color: var(--at-fail-escuro);
}
/* /Layout/AppFooter.razor.rz.scp.css */
/* Assinatura discreta: é referência, não conteúdo — não deve competir com a página. */
.app-footer[b-xvxz0xm4i1] {
    /* Altura vinda do token compartilhado com o rodapé da coluna lateral (--at-footer-h): é o que
       mantém os dois filetes na mesma linha. Centrar por flex, e não por padding, porque a
       safe-area do iPhone entra como padding e desalinharia o texto se ele dependesse dela. */
    display: flex;
    align-items: center;
    justify-content: center;
    height: calc(var(--at-footer-h) + env(safe-area-inset-bottom, 0px));
    padding: 0 1.5rem env(safe-area-inset-bottom, 0px);
    font-size: .72rem;
    /* Um passo além do --at-text-muted, misturando com o fundo. Feito por color-mix e NÃO por
       `opacity`: opacidade multiplica contra o que estiver atrás, então o mesmo valor daria tons
       diferentes conforme a superfície — aqui a cor é a mesma em qualquer fundo do tema. */
    /* A mistura é POR TEMA, e não um valor só, porque o --at-text-muted de cada um parte de um lugar
       diferente: no claro (#5c6b7a) ele já nasce perto do piso — mede 5,05:1 puro —, então quase não
       há margem para apagar; no escuro (#98a5b3) sobra folga. Um valor único ou reprovaria no claro
       ou seria tímido demais no escuro.

       Padrão = claro. Medido: 4,56:1. */
    color: color-mix(in srgb, var(--at-text-muted) 95%, var(--at-surface-sunken));
    border-top: 1px solid var(--at-border);
}

/* No escuro há folga para apagar mais: 75% mede 4,65:1 e ainda passa o AA. */
[data-bs-theme="dark"] .app-footer[b-xvxz0xm4i1] {
    color: color-mix(in srgb, var(--at-text-muted) 75%, var(--at-surface-sunken));
}
/* /Layout/EmptyLayout.razor.rz.scp.css */
/* A casca é quem tem a altura da tela; o conteúdo cresce para preencher o que sobra acima do rodapé.
   Antes era a própria página de login que declarava `min-height: 100vh` — com o rodapé depois dela,
   isso o empurraria para fora da tela, e só se chegaria nele rolando uma página que não rola. */
.empty-shell[b-wai7ihab68] {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    background-color: var(--at-surface-sunken);
}
/* /Layout/InstallTip.razor.rz.scp.css */
/* O texto do banner ocupa toda a linha e, sendo o alerta um flex, o botão de fechar era espremido —
   medido, sobrava 30 px de largura mesmo com a largura declarada. */
.btn-close[b-a52pm07fpq] {
    flex: 0 0 auto;
}

/* O .btn-close do Bootstrap tem 1em: medido, dava 16x24 px de alvo — pequeno demais para o dedo,
   e este banner só aparece justamente em celular. Mesmo tratamento das outras ações da barra
   (app.css): cresce só onde o apontador é impreciso, sem inchar o layout no desktop. */
@media (pointer: coarse) {
    .btn-close[b-a52pm07fpq] {
        width: 2.75rem;
        height: 2.75rem;
        padding: 0;
        background-position: center;
    }
}
/* /Layout/MainLayout.razor.rz.scp.css */
.page[b-cjlcl2usvb] {
    position: relative;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

main[b-cjlcl2usvb] {
    flex: 1;
    min-width: 0; /* deixa o conteúdo largo rolar em si, sem esticar o layout */
    background-color: var(--at-surface-sunken);
    /* Coluna com o conteúdo crescendo: sem isto, numa página curta o rodapé encostaria logo abaixo
       do último elemento, deixando um vazio embaixo dele. */
    display: flex;
    flex-direction: column;
}

.sidebar[b-cjlcl2usvb] {
    background-color: var(--at-rail);
    /* O padding da safe-area do iOS NÃO fica aqui: ele mora no .top-row do NavMenu. Aquele bloco
       pinta um rgba(0,0,0,.25) por cima do --at-rail, então a faixa da barra de status precisa ser
       do MESMO elemento — senão sobra um degrau entre um --at-rail puro em cima e o escurecido logo
       abaixo, que foi exatamente o que apareceu no iPhone. */
}

.top-row[b-cjlcl2usvb] {
    background-color: var(--at-surface);
    border-bottom: 1px solid var(--at-border);
    height: 3.5rem;
    display: flex;
    align-items: center;
    gap: .75rem;
}

/* ⚠️ O `:not(.top-brand)` NÃO é preciosismo — é o que faz a marca ter a própria cor.
   O `::deep` compila para `.top-row[b-x] a`, que soma um seletor de ELEMENTO e por isso vence
   `.top-brand[b-x]`: (0,3,1) contra (0,3,0). Sem a exclusão, a marca herdava a cor de AÇÃO da barra
   nos dois estados — cinza no normal e o accent no hover.

   ⛔ Foi por isso que fixar a cor nos estados da marca, em 2026-08-27, não resolveu: a regra estava
   certa e simplesmente perdia. O relato voltou em 2026-09-07 ("a logo acende ao tocar, e fica"), e no
   celular o `:hover` gruda até se tocar noutro lugar — daí parecer aceso, e não um piscar.

   Medido no navegador, no elemento real e em `:hover`: com a exclusão a cor vai de rgb(30,144,255)
   para o branco que a regra da marca manda. A marca é assinatura; esta regra é para as ações. */
.top-row[b-cjlcl2usvb]  a:not(.top-brand),
.top-row[b-cjlcl2usvb]  .btn-link {
    white-space: nowrap;
    text-decoration: none;
    color: var(--at-text-muted);
}

.top-row[b-cjlcl2usvb]  a:hover:not(.top-brand),
.top-row[b-cjlcl2usvb]  .btn-link:hover {
    color: var(--at-accent);
}

article.content[b-cjlcl2usvb] {
    padding-top: 1.5rem;
    padding-bottom: 2.5rem;
    flex: 1;   /* empurra o rodapé para o fim da tela nas páginas curtas */
    /* A safe-area do iPhone saiu daqui para o .app-footer: com o rodapé abaixo do conteúdo, é ELE o
       último elemento, e é dele que o indicador de início precisa se afastar. */
}

/* O hambúrguer e a marca da barra só existem no celular: em tela larga a navegação é a coluna
   lateral, que já carrega a marca no alto. */
.nav-toggle[b-cjlcl2usvb],
.top-brand[b-cjlcl2usvb],
/* Também some no desktop: girar o aparelho com o menu aberto deixaria um véu sobre um menu que ali
   é coluna fixa. */
.nav-backdrop[b-cjlcl2usvb] {
    display: none;
}

/* Empurra as ações para a direita, com ou sem a marca antes delas. */
.top-actions[b-cjlcl2usvb] {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: .75rem;
}

@media (max-width: 640.98px) {
    /* A barra ÚNICA: hambúrguer, página e ações na mesma linha. Assume a cor da navegação (era a
       clara do conteúdo) porque agora é ela que encosta na barra de status do iOS — o mesmo tom já
       usado pela marca no desktop, para as duas faixas não divergirem. */
    .top-row[b-cjlcl2usvb] {
        background-color: var(--at-rail);
        border-bottom-color: rgba(255, 255, 255, .07);
        /* No app instalado no iPhone a barra de status é opaca desde 2026-09-21 (index.html), e este
           inset vale 0 em pé. Fica assim mesmo: quem instalou antes e não reinstalou continua com a
           barra translúcida, e sem o padding o conteúdo passaria por baixo do relógio. */
        height: calc(3.5rem + env(safe-area-inset-top, 0px));
        padding-top: env(safe-area-inset-top, 0px);
        position: sticky;
        top: 0;
        z-index: 30;
    }

    .nav-toggle[b-cjlcl2usvb] {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 2.75rem;
        height: 2.75rem;
        flex: 0 0 auto;
        margin-left: -.75rem;
        padding: 0;
        background: none;
        border: 0;
        color: var(--at-rail-text-strong);
    }

    .nav-toggle svg[b-cjlcl2usvb] {
        width: 1.5rem;
        height: 1.5rem;
        fill: none;
        stroke: currentColor;
        stroke-width: 2;
        stroke-linecap: round;
    }

    /* A marca trunca em vez de empurrar as ações. Com a forma curta isso só aconteceria abaixo de
       360 px de tela (ela ocupa 100 px e o cromo fixo, 260) — rede de segurança, não o caso comum. */
    .top-brand[b-cjlcl2usvb] {
        display: block;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        font-size: 1.05rem;
        font-weight: 600;
        letter-spacing: .01em;
        /* Virou <a> para levar à Início: sem estas duas, herdaria o azul e o sublinhado de link e
           deixaria de parecer a marca. O alvo de toque continua o do texto, que é o que se toca. */
        color: var(--at-rail-text-strong);
        text-decoration: none;
    }

    /* ⚠️ `:active` e `:visited` entram aqui, e não por simetria: no iPhone, TOCAR a marca a pintava de
       azul e ela FICAVA assim até se tocar em outro lugar da tela. O `:hover` e o `:focus` já estavam
       cobertos — o estado que faltava era justamente o do toque. Relatado pelo dono em 2026-08-27.

       O `-webkit-tap-highlight-color` é a outra metade: sem ele o iOS acende um retângulo cinza-azulado
       sobre a marca a cada toque. Nenhum dos dois aparece no desktop, então nenhum aparece num print. */
    .top-brand:hover[b-cjlcl2usvb],
    .top-brand:focus[b-cjlcl2usvb],
    .top-brand:focus-visible[b-cjlcl2usvb],
    .top-brand:active[b-cjlcl2usvb],
    .top-brand:visited[b-cjlcl2usvb] {
        color: var(--at-rail-text-strong);
        text-decoration: none;
    }

    .top-brand[b-cjlcl2usvb] {
        -webkit-tap-highlight-color: transparent;
    }

    /* Véu do menu aberto: escurece o conteúdo e recebe o toque que fecha. Começa ABAIXO da barra,
       para o hambúrguer continuar alcançável (tocar nele de novo também fecha). */
    .nav-backdrop[b-cjlcl2usvb] {
        display: block;
        position: fixed;
        top: calc(3.5rem + env(safe-area-inset-top, 0px));
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 15;
        background-color: rgba(0, 0, 0, .45);
    }

    /* O alternador de tema não aparece aqui. Duas razões, e a segunda decide: no piso da escada ele
   custa a marca (medido a 320 px, ela trunca), e há um só lugar para ele na interface — dois pontos
   de entrada para o mesmo controle é o que faz ninguém achar nenhum. Medidas em docs/UI-WEB.md. */
    .top-row[b-cjlcl2usvb]  .theme-toggle {
        display: none;
    }

    /* Os ícones da barra herdavam a cor do conteúdo; sobre a faixa escura eles sumiriam. */
    .top-row[b-cjlcl2usvb]  .icon-button {
        color: var(--at-rail-text);
    }

    .top-row[b-cjlcl2usvb]  .icon-button:hover {
        color: var(--at-rail-text-strong);
    }
}

@media (min-width: 641px) {
    .page[b-cjlcl2usvb] {
        flex-direction: row;
    }

    .sidebar[b-cjlcl2usvb] {
        width: 250px;
        height: 100vh;
        position: sticky;
        top: 0;
        flex-shrink: 0;
    }

    .top-row[b-cjlcl2usvb] {
        position: sticky;
        top: 0;
        z-index: 1;
    }

    .top-row[b-cjlcl2usvb] {
        padding-left: 2rem !important;
        padding-right: 1.5rem !important;
    }

    /* O TETO da coluna de conteúdo (--at-w-page). Sem ele nada tinha limite: numa tela de 1920 o
   conteúdo ganhava 1670 px, com tabelas de 1614 px para 153 px de dados.
   ENCOSTADA NA ESQUERDA, e não centrada: a coluna acompanha a barra lateral. Ver docs/UI-WEB.md §1. */
    article[b-cjlcl2usvb] {
        width: 100%;
        max-width: var(--at-w-page);
        margin-inline: 0 auto;
        padding-left: 2rem !important;
        padding-right: 2rem !important;
    }
}

/* --- Canto dos flutuantes ------------------------------------------------ */
/* Dono único do canto inferior direito: o toast de ação (§9) e o aviso de versão empilham aqui, em
   vez de cada um se fixar por conta própria e um cobrir o outro.

   `pointer-events: none` na coluna e `auto` em cada cartão: sem isso a faixa vazia da coluna ficaria
   por cima da página e engoliria cliques num canto que quase sempre está vazio. */
.canto-avisos[b-cjlcl2usvb] {
    position: fixed;
    /* Canto superior direito (decisão do dono, 2026-08-20). Abaixo da `.top-row`, que é sticky e tem
       3,5rem — cobri-la esconderia o sino e o "atualizar" justo quando um aviso aparece. A safe-area
       entra na conta porque no iPhone instalado a barra empurra a `.top-row` para baixo. */
    top: calc(3.5rem + env(safe-area-inset-top, 0px) + .5rem);
    right: 1rem;
    z-index: 1060;   /* acima do painel flutuante (1050), o mais alto da interface */
    display: flex;
    flex-direction: column;
    align-items: flex-end;   /* cartão mais estreito que o canto encosta na direita, não na esquerda */
    gap: .5rem;
    max-width: calc(100vw - 2rem);
    pointer-events: none;
}

/* No celular o canto atravessa a tela e os cartões ocupam a largura: com 375px, 24rem de cartão
   ancorado à direita deixaria uma margem esquerda de 1px — na prática, largura cheia com sobra. */
@media (max-width: 640.98px) {
    .canto-avisos[b-cjlcl2usvb] {
        left: .5rem;
        right: .5rem;
        max-width: none;
        align-items: stretch;
    }
}
/* /Layout/NavMenu.razor.rz.scp.css */
/* A marca é o cabeçalho da coluna lateral, e só existe em tela larga: no celular a barra superior
   mostra a PÁGINA, e a assinatura por extenso volta no conteúdo da Home. */
.navbar-brand[b-rdbx9rzqar] {
    display: none;
}

@media (min-width: 641px) {
    .navbar-brand[b-rdbx9rzqar] {
        display: flex;
        align-items: center;
        min-height: 3.5rem;
        padding-left: 1rem;
        background-color: rgba(0, 0, 0, .25);
        border-bottom: 1px solid rgba(255, 255, 255, .07);
    }
}

.navbar-brand[b-rdbx9rzqar] {
    font-size: 1.05rem;
    font-weight: 600;
    letter-spacing: .01em;
    color: var(--at-rail-text-strong);
    -webkit-tap-highlight-color: transparent;
}

/* A mesma cor em TODOS os estados: a marca é assinatura, não uma ação que responde ao toque. A barra
   do celular tem o par disto no MainLayout.razor.css, com o relato que motivou os dois. */
.navbar-brand:hover[b-rdbx9rzqar],
.navbar-brand:focus[b-rdbx9rzqar],
.navbar-brand:focus-visible[b-rdbx9rzqar],
.navbar-brand:active[b-rdbx9rzqar],
.navbar-brand:visited[b-rdbx9rzqar] {
    color: var(--at-rail-text-strong);
    text-decoration: none;
}

/* A cor do sufixo da assinatura mora no app.css (.brand-version): ela aparece em três telas, e uma
   cópia por componente já havia começado a divergir. */

.bi[b-rdbx9rzqar] {
    display: inline-block;
    position: relative;
    width: 1.1rem;
    height: 1.1rem;
    margin-right: .7rem;
    top: -1px;
    flex-shrink: 0;
    background-size: cover;
    opacity: .85;
}

.bi-house-door-fill-nav-menu[b-rdbx9rzqar] {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E");
}

/* Controles deslizantes, e não outra engrenagem: o item logo acima (apesar do nome da classe) já é
   uma, e duas iguais no mesmo menu não se distinguem de relance. */
.bi-sliders-nav-menu[b-rdbx9rzqar] {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M11.5 2a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3M9.05 3a2.5 2.5 0 0 1 4.9 0H16v1h-2.05a2.5 2.5 0 0 1-4.9 0H0V3zM4.5 7a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3M2.05 8a2.5 2.5 0 0 1 4.9 0H16v1H6.95a2.5 2.5 0 0 1-4.9 0H0V8zm9.45 4a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3m-2.45 1a2.5 2.5 0 0 1 4.9 0H16v1h-2.05a2.5 2.5 0 0 1-4.9 0H0v-1z'/%3E%3C/svg%3E");
}

.bi-plus-square-fill-nav-menu[b-rdbx9rzqar] {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' viewBox='0 0 16 16'%3E%3Cpath d='M9.405 1.05c-.413-1.4-2.397-1.4-2.81 0l-.1.34a1.464 1.464 0 0 1-2.105.872l-.31-.17c-1.283-.698-2.686.705-1.987 1.987l.169.311c.446.82.023 1.841-.872 2.105l-.34.1c-1.4.413-1.4 2.397 0 2.81l.34.1a1.464 1.464 0 0 1 .872 2.105l-.17.31c-.698 1.283.705 2.686 1.987 1.987l.311-.169a1.464 1.464 0 0 1 2.105.872l.1.34c.413 1.4 2.397 1.4 2.81 0l.1-.34a1.464 1.464 0 0 1 2.105-.872l.31.17c1.283.698 2.686-.705 1.987-1.987l-.169-.311a1.464 1.464 0 0 1 .872-2.105l.34-.1c1.4-.413 1.4-2.397 0-2.81l-.34-.1a1.464 1.464 0 0 1-.872-2.105l.17-.31c.698-1.283-.705-2.686-1.987-1.987l-.311.169a1.464 1.464 0 0 1-2.105-.872l-.1-.34zM8 10.93a2.929 2.929 0 1 1 0-5.86 2.929 2.929 0 0 1 0 5.858z'/%3E%3C/svg%3E");
}

.bi-list-nested-nav-menu[b-rdbx9rzqar] {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' viewBox='0 0 16 16'%3E%3Cpath d='M2 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V2zm4.5 10a.5.5 0 0 0 0 1h3a.5.5 0 0 0 0-1h-3z'/%3E%3C/svg%3E");
}

.bi-arrow-bar-left-nav-menu[b-rdbx9rzqar] {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M12.5 15a.5.5 0 0 1-.5-.5v-13a.5.5 0 0 1 1 0v13a.5.5 0 0 1-.5.5zM10 8a.5.5 0 0 1-.5.5H3.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L3.707 7.5H9.5a.5.5 0 0 1 .5.5z'/%3E%3C/svg%3E");
}

.bi-arrow-bar-right-nav-menu[b-rdbx9rzqar] {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M6 8a.5.5 0 0 0 .5.5h5.793l-2.147 2.146a.5.5 0 0 0 .708.708l3-3a.5.5 0 0 0 0-.708l-3-3a.5.5 0 0 0-.708.708L12.293 7.5H6.5A.5.5 0 0 0 6 8zm-2.5 7a.5.5 0 0 1-.5-.5v-13a.5.5 0 0 1 1 0v13a.5.5 0 0 1-.5.5z'/%3E%3C/svg%3E");
}

/* Mini rodapé da navegação. Mais apagado que os itens: é referência, não destino. */
.nav-version[b-rdbx9rzqar] {
    display: flex;
    align-items: center;
    gap: .4rem;
    /* Mesma altura do rodapé do conteúdo (--at-footer-h), para os dois filetes caírem na mesma
       linha na base da tela. Antes cada um derivava a altura do próprio padding e dava 2px de
       diferença — invisível no código, visível na tela. */
    height: var(--at-footer-h);
    flex-shrink: 0;   /* com o menu longo, quem rola é a lista — a versão não pode ser espremida */
    /* 1,75rem alinha com o TEXTO dos itens: eles têm px-3 (1rem) no .nav-item mais .75rem no link. */
    padding: 0 1.75rem;
    font-size: .7rem;
    font-variant-numeric: tabular-nums;
    /* 62% é o piso: mede 4,61:1 sobre o rail e passa o AA. Com 55% ficava em 3,90 e reprovava. */
    color: color-mix(in srgb, var(--at-rail-text) 62%, var(--at-rail));
    border-top: 1px solid rgba(255, 255, 255, .07);
    /* Como virou link, precisa desarmar as duas regras globais de <a>: a cor de link do Bootstrap e o
   sublinhado no hover. */
    text-decoration: none;
}

/* Como é clicável, precisa dizer isso ao passar o mouse — mas sem virar destaque: só clareia. */
.nav-version:hover[b-rdbx9rzqar],
.nav-version:focus-visible[b-rdbx9rzqar] {
    color: var(--at-rail-text);
    background-color: var(--at-rail-hover);
    text-decoration: none;
}

.nav-version svg[b-rdbx9rzqar] {
    width: .85rem;
    height: .85rem;
    flex-shrink: 0;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.nav-item[b-rdbx9rzqar] {
    font-size: .9rem;
    padding-bottom: .2rem;
}

.nav-item:first-of-type[b-rdbx9rzqar] { padding-top: .75rem; }
.nav-item:last-of-type[b-rdbx9rzqar] { padding-bottom: 1rem; }

.nav-item[b-rdbx9rzqar]  a,
.nav-item[b-rdbx9rzqar]  .btn-link {
    color: var(--at-rail-text);
    border-radius: var(--at-radius);
    height: 2.75rem;
    display: flex;
    align-items: center;
    line-height: 2.75rem;
    padding-inline: .75rem;
    width: 100%;
    text-decoration: none;
    transition: background-color .15s ease, color .15s ease;
}

.nav-item[b-rdbx9rzqar]  a:hover,
.nav-item[b-rdbx9rzqar]  .btn-link:hover {
    background-color: var(--at-rail-hover);
    color: var(--at-rail-text-strong);
    text-decoration: none;
}

/* Item ativo: barra do accent à esquerda em vez do realce branco do template. */
.nav-item[b-rdbx9rzqar]  a.active {
    background-color: var(--at-rail-hover);
    color: var(--at-rail-text-strong);
    box-shadow: inset 3px 0 0 var(--at-accent);
}

.nav-item[b-rdbx9rzqar]  a.active .bi { opacity: 1; }

/* Nome de quem está na sessão — rótulo, não item clicável. */
.nav-link-user[b-rdbx9rzqar] {
    display: block;
    padding: .35rem .75rem;
    font-size: .78rem;
    font-weight: 600;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--at-rail-text);
    opacity: .65;
    border-top: 1px solid rgba(255, 255, 255, .08);
    margin-top: .5rem;
    padding-top: .9rem;
}

/* No celular o menu é SOBREPOSIÇÃO, ancorada abaixo da barra. Antes ele empurrava o conteúdo, o que
   agora seria impossível: a barra pertence ao <main>, que vem DEPOIS deste bloco no DOM — em fluxo, o
   menu aberto apareceria ACIMA da barra. Sobrepondo, ele cai onde se espera e não desloca a página. */
@media (max-width: 640.98px) {
    .nav-scrollable[b-rdbx9rzqar] {
        /* FIXED, não absolute: era `absolute` dentro de `.page { position: relative }`, ou seja
           ancorado ao topo do DOCUMENTO. A barra que o abre é `sticky` e acompanha a viewport, então
           com a página rolada o menu abria lá em cima, fora da tela — e era preciso rolar para achá-lo.
           Fixo, ele cai logo abaixo da barra em qualquer posição de rolagem, igual ao véu (que já era
           fixo, e por isso escurecia a tela certa enquanto o menu abria na errada). */
        position: fixed;
        top: calc(3.5rem + env(safe-area-inset-top, 0px));
        left: 0;
        right: 0;
        z-index: 20;
        max-height: calc(100vh - 3.5rem - env(safe-area-inset-top, 0px));
        overflow-y: auto;
        background-color: var(--at-rail);
        border-bottom: 1px solid rgba(255, 255, 255, .07);
    }
}

@media (min-width: 641px) {
    .collapse[b-rdbx9rzqar] {
        /* Nunca colapsa a sidebar em tela larga */
        display: block;
    }

    /* Coluna com o menu crescendo: é o que empurra a versão para o PÉ da barra lateral. No celular
       não é preciso — lá o menu é sobreposição do tamanho do conteúdo, e a versão já cai por último. */
    .nav-scrollable[b-rdbx9rzqar] {
        height: calc(100vh - 3.5rem);
        overflow-y: auto;
        display: flex;
        flex-direction: column;
    }

    .nav-scrollable > nav[b-rdbx9rzqar] {
        flex: 1;
    }
}
/* /Layout/NotificationBell.razor.rz.scp.css */
/* SEM `position: relative`, de propósito. Com ele, o painel se ancorava no SINO e o `top: 100%` caía
   logo abaixo do botão — dentro da barra, cobrindo o filete que a fecha. Sem ele, o ancestral
   posicionado mais próximo passa a ser a própria `.top-row` (que é `sticky`, e portanto posicionada),
   e `top: 100%` vira exatamente a linha divisória do cabeçalho.

   O selo de não-lidas não depende disto: ele se ancora no <button>, que tem `position-relative`
   próprio. */
.notif-bell[b-lynpysp1ch] {
    display: inline-flex;
}

/* O botão em si usa a classe global .icon-button (app.css), compartilhada com o tema e o atualizar. */

.notif-panel[b-lynpysp1ch] {
    position: absolute;
    right: 0;
    /* +1px: o bloco de contenção de um absoluto é a caixa de PREENCHIMENTO do ancestral, então
       `100%` para exatamente onde o filete começa — e o painel o cobriria. O pixel devolve o filete,
       e o painel encosta logo abaixo dele. Casa com a `border-bottom: 1px` da `.top-row`. */
    top: calc(100% + 1px);
    width: 340px;
    max-width: 90vw;
    max-height: 70vh;
    overflow: auto;
    z-index: 1050;
}

/* Numa tela estreita o painel saía pela ESQUERDA: ancorado ao sino (`right: 0`) e com 340px, a borda
   esquerda caía em coordenada negativa — o `max-width: 90vw` não salva, porque limita a largura sem
   reposicionar. Abaixo de 480px ele passa a se ancorar na VIEWPORT, com folga dos dois lados. */
@media (max-width: 480px) {
    .notif-panel[b-lynpysp1ch] {
        position: fixed;
        /* `top` EXPLÍCITO. Era `top: auto`, e num elemento fixo isso não significa "onde estava":
           significa a posição ESTÁTICA, a que ele ocuparia no fluxo — que muda conforme a rolagem,
           porque o sino vive numa barra `sticky`. Daí o painel aparecer em alturas aleatórias, às
           vezes no rodapé. Ancorado logo abaixo da barra, ele cai sempre no mesmo lugar. */
        top: calc(3.5rem + env(safe-area-inset-top, 0px) + .25rem);
        left: .5rem;
        right: .5rem;
        width: auto;
        max-width: none;
        /* Com o topo fixo, a altura precisa caber no que sobra da tela — senão o fim da lista fica
           inalcançável, já que um elemento fixo não rola com a página. */
        max-height: calc(100vh - 3.5rem - env(safe-area-inset-top, 0px) - 1rem);
    }
}

.notif-list[b-lynpysp1ch] {
    max-height: 60vh;
    overflow: auto;
}

/* O realce da não-lida vinha em `rgba(13, 110, 253, .08)` — o azul PADRÃO do Bootstrap, que não é
   token de nada aqui: num tema em que o accent mudasse, a lista continuaria azul-Bootstrap. Mesmo
   caso do item selecionado dos logs (V5). Agora é o accent do produto, com alfa pelo `--at-accent-rgb`. */
.notif-unread[b-lynpysp1ch] {
    background-color: rgba(var(--at-accent-rgb), .08);
}

/* O item da lista é um <button> (V4) — o que traz junto o cromo de botão do navegador, que aqui não
   serve: a linha inteira é a área de toque e ela precisa parecer texto. Daí o fundo e a borda
   transparentes e o alinhamento à esquerda. */
.notif-item[b-lynpysp1ch] {
    display: block;
    width: 100%;
    text-align: left;
    background: none;
    border: 0;
    color: inherit;
    cursor: pointer;
}

/* O anel PARA DENTRO (`outline-offset` negativo): a lista rola (`.notif-list { overflow: auto }`), e
   um contorno desenhado fora da caixa seria cortado justamente no primeiro e no último item. */
.notif-item:focus-visible[b-lynpysp1ch] {
    outline: 2px solid var(--at-accent);
    outline-offset: -2px;
}

.notif-hora[b-lynpysp1ch] {
    font-size: .7rem;
}

/* Recebe o toque fora do painel para fechá-lo. Transparente e abaixo do painel (que está em 1050),
   mas acima de tudo o mais — senão o toque cairia num link da página em vez de fechar. */
.notif-backdrop[b-lynpysp1ch] {
    position: fixed;
    inset: 0;
    z-index: 1040;
    background: none;
}
/* /Layout/StationAssignment.razor.rz.scp.css */
/* Linhas da lista em repouso: separadas por régua, sem marcador — não são itens de escolha, são o
   que já vale. */
.assign-row[b-ncrjao596m] {
    padding: .35rem 0;
    border-top: 1px solid var(--at-border);
}

.assign-row:first-child[b-ncrjao596m] {
    border-top: 0;
}
/* /Layout/StationPicker.razor.rz.scp.css */
/* O seletor é uma caixa: deixa claro que aquilo é um estado de edição, e não parte da página. Rola
   sozinho porque a lista pode passar da altura útil. */
.assign-picker[b-janifwrde1] {
    max-height: 18rem;
    overflow-y: auto;
    padding: .75rem;
    border: 1px solid var(--at-border);
    border-radius: var(--at-radius);
    background-color: var(--at-surface-sunken);
}
/* /Layout/ToastHost.razor.rz.scp.css */
/* Toast de ação (docs/UI-WEB.md §9). O canto flutuante é do MainLayout (`.canto-avisos`), que empilha
   estes e o aviso de versão numa coluna só — antes o UpdateToast era `position: fixed` por conta
   própria, e dois flutuantes no mesmo canto se sobrepõem. Aqui só existe o cartão. */

.toast-acao[b-r5e2qhi63i] {
    display: flex;
    align-items: flex-start;
    gap: .625rem;
    max-width: 24rem;
    padding: .625rem .75rem;
    border: 1px solid var(--t-cor);
    border-left-width: 3px;
    border-radius: var(--at-radius);
    background: var(--at-surface);
    box-shadow: var(--at-shadow);
    pointer-events: auto;   /* o canto não captura cliques; o toast sim, por causa do "×" */

    /* Entra deslizando do canto. `prefers-reduced-motion` desliga logo abaixo. */
    animation: toast-entra-b-r5e2qhi63i .18s ease-out;
}

/* Fundo tingido em vez de fundo cheio: o texto continua sendo o token de texto normal (contraste alto
   nos dois temas), e a cor fica na borda e no ícone. Um cartão verde-cheio com texto branco exigiria
   um par de cores próprio por tema — mais uma coisa para envelhecer. */
.toast-acao.sucesso[b-r5e2qhi63i] {
    --t-cor: var(--at-ok);
    background: color-mix(in srgb, var(--at-ok) 8%, var(--at-surface));
}

.toast-acao.falha[b-r5e2qhi63i] {
    --t-cor: var(--at-fail);
    background: color-mix(in srgb, var(--at-fail) 8%, var(--at-surface));
}

.toast-acao .ic[b-r5e2qhi63i] {
    width: 1.125rem;
    height: 1.125rem;
    flex: none;
    margin-top: .05rem;
    fill: none;
    stroke: var(--t-cor);
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.toast-acao .texto[b-r5e2qhi63i] {
    flex: 1 1 auto;
    min-width: 0;
    font-size: .875rem;
    line-height: 1.35;
    color: var(--at-text);
    overflow-wrap: anywhere;   /* nome de arquivo longo não pode estourar o cartão */
}

.toast-acao .fechar[b-r5e2qhi63i] {
    flex: none;
    display: flex;
    padding: .125rem;
    border: 0;
    border-radius: .25rem;
    background: transparent;
    color: var(--at-text-muted);
    cursor: pointer;
}

.toast-acao .fechar:hover[b-r5e2qhi63i] { color: var(--at-text); }

.toast-acao .fechar:focus-visible[b-r5e2qhi63i] {
    outline: 2px solid var(--at-accent);
    outline-offset: 1px;
}

.toast-acao .fechar svg[b-r5e2qhi63i] {
    width: .875rem;
    height: .875rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
}

@keyframes toast-entra-b-r5e2qhi63i {
    /* Desliza de CIMA: o canto é o superior, e entrar subindo seria contra a borda de onde o cartão
       nasce. */
    from { opacity: 0; transform: translateY(-.5rem); }
    to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
    .toast-acao[b-r5e2qhi63i] { animation: none; }
}
/* /Layout/UpdateToast.razor.rz.scp.css */
/* Flutuante que NÃO bloqueia: o portal segue utilizável com ele na tela. Por isso um canto, e não
   um diálogo — a versão velha funciona, só está velha.
   O canto em si é do MainLayout (`.canto-avisos`): desde que existe o toast de ação, são DOIS
   flutuantes disputando o mesmo lugar, e quem empilha é o container. Aqui ficou só o cartão. */
.toast-versao[b-vgmomm2w35] {
    pointer-events: auto;   /* o canto não captura cliques; este cartão tem botões */
    display: flex;
    align-items: center;
    gap: .75rem;
    max-width: 24rem;
    padding: .75rem .9rem;
    background-color: var(--at-surface);
    border: 1px solid var(--at-border);
    border-radius: var(--at-radius);
    box-shadow: var(--at-shadow);
}

.toast-versao .ic[b-vgmomm2w35] {
    width: 1.25rem;
    height: 1.25rem;
    flex-shrink: 0;
    fill: none;
    stroke: var(--at-accent);
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.toast-versao .texto[b-vgmomm2w35] {
    display: flex;
    flex-direction: column;
    min-width: 0;
    line-height: 1.3;
}

.toast-versao .texto strong[b-vgmomm2w35] {
    font-size: .85rem;
    font-weight: 600;
}

.toast-versao .texto span[b-vgmomm2w35] {
    font-size: .75rem;
    color: var(--at-text-muted);
}

.toast-versao .btn[b-vgmomm2w35] {
    flex-shrink: 0;
}

.toast-versao .fechar[b-vgmomm2w35] {
    flex-shrink: 0;
    padding: 0;
    border: 0;
    background: none;
    color: var(--at-text-muted);
    cursor: pointer;
    line-height: 0;
}

.toast-versao .fechar svg[b-vgmomm2w35] {
    width: 1rem;
    height: 1rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
}

/* No celular ocupa a largura que o canto der. O texto e a ação vão em duas linhas: lado a lado, com
   375px, o botão espremeria o título até quebrar em três linhas.
   ⚠️ Aqui NÃO se posiciona nada: desde que o canto virou `.canto-avisos`, este cartão é filho de um
   flex e `left`/`right`/`bottom` não têm efeito nenhum — ficaram meses como regra morta. */
@media (max-width: 640.98px) {
    .toast-versao[b-vgmomm2w35] {
        max-width: none;
        flex-wrap: wrap;
    }

    .toast-versao .texto[b-vgmomm2w35] {
        flex: 1;
    }

    .toast-versao .btn[b-vgmomm2w35] {
        width: 100%;
        order: 3;
    }
}
/* /Lists/SortableHeader.razor.rz.scp.css */
/* O cabeçalho continua parecendo cabeçalho: o botão não pode trazer aparência de botão para dentro
   da tabela. O que muda ao passar o mouse é só a seta. */
.sortable-header[b-chw7htfebh] {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: 0;
    background: none;
    border: 0;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;

    /* ⚠️ As DUAS herdam à mão, e não por descuido de quem escreveu: o `button` do navegador chega com
       `text-transform: none` próprio, e o `font: inherit` acima zera o `letter-spacing` junto. O
       cabeçalho do portal é caixa alta com respiro entre letras (`.table > thead th`), e sem estas
       linhas a coluna ordenável ficava em caixa mista e apertada — duas fontes de cabeçalho na mesma
       tabela. Não se via enquanto TODA coluna ordenava: só apareceu quando uma coluna comum
       ("Dias", em admin/rotinas) sentou ao lado para comparação. */
    text-transform: inherit;
    letter-spacing: inherit;
}

.sortable-caret[b-chw7htfebh] {
    /* Reservado sempre, e não só na coluna ordenada: aparecendo e sumindo, a largura da coluna
       mudaria a cada clique e a tabela inteira dançaria. */
    display: inline-block;
    min-width: .75rem;
    color: var(--at-text-muted);
    opacity: .45;
}

.sortable-header:hover .sortable-caret[b-chw7htfebh],
.sortable-header:focus-visible .sortable-caret[b-chw7htfebh] {
    opacity: .85;
}

.sortable-caret.ativa[b-chw7htfebh] {
    opacity: 1;
    color: var(--at-text);
}
/* /Pages/Admin/Devices.razor.rz.scp.css */
/* Botões de ação com largura igual: cada um do tamanho do próprio texto deixava a coluna com as
   bordas desalinhadas linha a linha. */
.acoes .btn[b-h41bdcaa1v] {
    min-width: 5.5rem;
}

/* A coluna da marcação fica só com a largura da caixa: sem isto ela ganharia uma fatia proporcional
   como qualquer outra coluna, e o espaço sairia das que têm texto. */
.col-marca[b-h41bdcaa1v] {
    width: 1px;
    white-space: nowrap;
}

/* A coluna de endereço com um IPv6 (39 caracteres) ia a 266 px e empurrava a tabela para 983 px
   dentro de um espaço de 896. Um teto força a quebra e devolve a largura ao resto. */
.ip-celula[b-h41bdcaa1v] {
    /* 22ch, medido: o IPv6 quebra em duas linhas e a tabela volta a caber. */
    max-width: 22ch;

    /* ⚠️ O PISO é o conserto, e a falta dele era o defeito (§20, B1). Permitir a quebra em qualquer ponto
   derruba a coluna a poucos caracteres quando o espaço aperta, e o conteúdo vira uma torre ilegível.
   O par teto+piso é o que mantém a coluna dentro de uma faixa útil. Medidas em docs/UI-WEB.md §10.1. */
    min-width: 16ch;

    /* `anywhere` no lugar de `break-all`: os dois quebram uma cadeia sem ponto de quebra natural, mas o
   `anywhere` também deixa o navegador contá-la ao calcular a largura mínima. */
    overflow-wrap: anywhere;
}
/* /Pages/Admin/Downloads.razor.rz.scp.css */
/* O texto vem em markdown cru. `pre` preserva as quebras — sem ele vira um parágrafo só —, mas o
   `pre` padrão não quebra linha, então a quebra é reativada à parte. */
.notas[b-992ay1qfe6] {
    white-space: pre-wrap;
    word-break: break-word;
    max-height: 18rem;
    overflow-y: auto;
}

/* A pílula desta tela virou `.badge-acento` no app.css: ela aparece em mais de um lugar, e a cópia
   local ficaria para trás na primeira mudança de cor. */

/* Arquivo que ninguém baixa: `.nupkg` e índices do Velopack. Apagado, não escondido — ele conta na
   soma de arquivos do cabeçalho. A opacidade fica em .55 e não menos porque o nome do arquivo ainda
   precisa ser LEGÍVEL para quem confere o que subiu. */
.arquivo-interno[b-992ay1qfe6] {
    opacity: .55;
}

/* Blocos colapsáveis desta tela (versões anteriores, rollback). O marcador padrão do navegador fica
   colado no texto e muda de forma entre Chrome e Safari; a seta própria é a mesma nos dois e
   acompanha o estado. */
.bloco-colapsavel > summary[b-992ay1qfe6] {
    cursor: pointer;
    list-style: none;
    display: flex;
    flex-direction: column;
    position: relative;
    padding-right: 2.25rem !important;
}

.bloco-colapsavel > summary[b-992ay1qfe6]::-webkit-details-marker { display: none; }

.bloco-colapsavel > summary[b-992ay1qfe6]::after {
    content: "";
    position: absolute;
    right: 1rem;
    top: 1.1rem;
    width: .5rem;
    height: .5rem;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(45deg);
    opacity: .55;
    transition: transform .15s ease;
}

.bloco-colapsavel[open] > summary[b-992ay1qfe6]::after {
    transform: rotate(-135deg);
    top: 1.35rem;
}

/* A ação destrutiva desta tela. A tarja vermelha à esquerda é o que a separa do resto — quem chega
   aqui precisa ver que este bloco é diferente antes de ler. */
.cartao-rollback[b-992ay1qfe6] {
    border-left: 3px solid var(--at-fail);
}

.cartao-rollback > summary .fw-semibold[b-992ay1qfe6] {
    color: var(--at-fail);
}

@media (prefers-reduced-motion: reduce) {
    .bloco-colapsavel > summary[b-992ay1qfe6]::after { transition: none; }
}
/* /Pages/Admin/ErrorCodes.razor.rz.scp.css */
/* Colunas de contagem: os dígitos têm de alinhar entre as linhas, senão comparar 12 com 120 vira
   trabalho de olho. É a mesma razão do `tabular-nums` das outras tabelas de número do portal. */
.tabular[b-ts7b77qxl2] {
    font-variant-numeric: tabular-nums;
    text-align: right;
}
/* /Pages/Admin/Installations.razor.rz.scp.css */
/* Cabeçalho de grupo: é uma linha da tabela, para as colunas seguirem alinhadas entre os grupos. */
.group-row > td[b-bk51g59tee] {
    background-color: var(--at-surface-sunken);
    border-top: 1px solid var(--at-border);
}

/* Botão de largura inteira em vez de <tr> clicável: linha de tabela não recebe foco pelo teclado
   nem se anuncia como acionável. */
.group-toggle[b-bk51g59tee] {
    display: flex;
    /* BASELINE, não center: o nome do grupo e a contagem têm tamanhos de fonte diferentes (a
       contagem é `.small`), e centrar caixas de alturas diferentes deixa os dois textos apoiados em
       linhas distintas. Alinhando pela linha de base, eles se sentam na mesma. */
    align-items: baseline;
    width: 100%;
    padding: .5rem .75rem;
    background: none;
    border: 0;
    text-align: left;
    color: var(--at-text);
    font-weight: 600;
}

.group-toggle:hover[b-bk51g59tee] {
    background-color: var(--at-rail-hover);
}

.group-caret[b-bk51g59tee] {
    display: inline-block;
    width: 1rem;
    color: var(--at-text-muted);
    font-weight: 400;
}

/* "Expira em" é curto o bastante para caber numa linha — o rótulo deixou de ser o que dimensiona a
   coluna, que era o problema que a quebra em duas linhas resolvia antes. */
.dias-restantes[b-bk51g59tee] {
    white-space: nowrap;
    text-align: center;
}
/* /Pages/Admin/Logs.razor.rz.scp.css */
/* Os blocos desta tela viraram um componente próprio, e o CSS com escopo foi junto — um `.razor.css`
   só vale para o componente do mesmo nome. */
/* /Pages/Admin/Notifications.razor.rz.scp.css */
/* O traço separa uma regra da anterior — antes da primeira não há o que separar, e ele viraria um
   segundo sublinhado logo abaixo do texto de introdução do cartão. */
.regra:first-of-type[b-8kgn9tyqs8] {
    border-top: 0 !important;
    padding-top: 0 !important;
    margin-top: 0 !important;
}
/* /Pages/Admin/Routines.razor.rz.scp.css */
/* Rotina pausada continua legível, só recuada visualmente — o mesmo tratamento que ela tem na tela
   da instalação. Sumir com ela seria esconder metade do motivo de abrir esta página. */
.rotina-pausada > td[b-l2elo815pd] {
    opacity: .55;
}

/* A linha do motivo do pulo cola na linha da rotina, sem borda entre as duas: são a mesma coisa. */
.rotina-nota > td[b-l2elo815pd] {
    border-top: 0;
}

/* O nome da rotina é o que se lê; a instalação é a coluna por onde se procura. Nenhuma das duas
   quebra no meio de uma palavra numa tabela de oito colunas. */
.rotinas td:first-child[b-l2elo815pd],
.rotinas td:nth-child(2)[b-l2elo815pd] {
    min-width: 8rem;
}
/* /Pages/Admin/StationDetails.razor.rz.scp.css */
/* ==========================================================================
   Diagrama hierárquico (três níveis) e a tira de resumo acima dele.
   ========================================================================== */

.topo[b-rp1jgts2js] {
    display: flex;
    flex-direction: column;
    gap: .75rem;
}

/* --- Tira de resumo -------------------------------------------------------- */

.topo-resumo[b-rp1jgts2js] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .375rem .5rem;
    margin-bottom: .25rem;
}

.topo-porta[b-rp1jgts2js] {
    display: inline-flex;
    align-items: center;
    gap: .375rem;
    padding: .2rem .55rem;
    border: 1px solid var(--at-border);
    border-radius: 999px;
    background: var(--at-surface-sunken);
    font-size: .8125rem;
    font-weight: 600;
    color: var(--at-text);
}

.topo-porta svg[b-rp1jgts2js] {
    width: 1rem;
    height: 1rem;
    color: var(--at-text-muted);
}

/* Contagem por tipo: responde a pergunta do resumo sem varrer item por item. */
.topo-cat[b-rp1jgts2js] {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    padding: .2rem .5rem;
    border-radius: 999px;
    border: 1px solid color-mix(in srgb, var(--cat-cor) 35%, transparent);
    background: color-mix(in srgb, var(--cat-cor) 10%, transparent);
    font-size: .75rem;
    color: var(--at-text);
}

.topo-cat b[b-rp1jgts2js] {
    color: var(--cat-cor);
    font-variant-numeric: tabular-nums;
}

/* --- Nível 1 --------------------------------------------------------------- */

.n1[b-rp1jgts2js] {
    border: 1px solid var(--at-border);
    border-radius: var(--at-radius);
    overflow: hidden;
    background: var(--at-surface);
}

.n1-cab[b-rp1jgts2js] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
    padding: .5rem .75rem;
    background: var(--at-surface-sunken);
    border-bottom: 1px solid var(--at-border);
}

.n1-ic[b-rp1jgts2js] {
    width: 1.125rem;
    height: 1.125rem;
    color: var(--at-accent);
    flex: none;
}

.n1-nome[b-rp1jgts2js] {
    font-weight: 600;
    font-size: .9375rem;
}

.n1-tag[b-rp1jgts2js] {
    padding: .1rem .45rem;
    border: 1px solid var(--at-border);
    border-radius: 999px;
    background: var(--at-surface);
    font-size: .6875rem;
    color: var(--at-text-muted);
}

.n1-tag-off[b-rp1jgts2js] {
    border-color: color-mix(in srgb, var(--at-warn) 45%, transparent);
    color: var(--at-warn);
}

/* Item inativo continua na tela — sumir com ele esconderia justamente o que não está ativo —,
   mas recuado. */
.n1-off[b-rp1jgts2js] {
    opacity: .62;
}

/* --- Nível 2 --------------------------------------------------------------- */
/* A régua vertical amarra os filhos ao pai sem repetir o número em cada um. */

/* O número fica CENTRADO na altura dos filhos: alinhado ao topo, parecia pertencer só ao primeiro
   cartão da linha em vez de ao grupo. */
.no[b-rp1jgts2js] {
    display: flex;
    align-items: center;
    gap: .625rem;
    padding: .625rem .75rem;
}

.no + .no[b-rp1jgts2js] {
    border-top: 1px dashed var(--at-border);
}

.no-num[b-rp1jgts2js] {
    flex: none;
    width: 1.5rem;
    height: 1.5rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 999px;
    background: color-mix(in srgb, var(--at-accent) 14%, transparent);
    border: 1px solid color-mix(in srgb, var(--at-accent) 40%, transparent);
    color: var(--at-accent);
    font-size: .75rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

/* --- Nível 3 --------------------------------------------------------------- */
/* `auto-fill` com piso de 10.5rem: uma coluna em 320 px, quantas couberem no desktop. */

.n3-lista[b-rp1jgts2js] {
    flex: 1 1 auto;
    min-width: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(10.5rem, 1fr));
    gap: .375rem;
}

.n3[b-rp1jgts2js] {
    display: flex;
    align-items: center;
    gap: .5rem;
    min-width: 0;
    padding: .375rem .5rem;
    border: 1px solid var(--at-border);
    border-left: 3px solid var(--cat-cor);
    border-radius: .375rem;
    background: var(--at-surface);
}

/* O sufixo é o que distingue dois filhos do mesmo pai. */
.n3-pos[b-rp1jgts2js] {
    flex: none;
    width: 1.375rem;
    height: 1.375rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: .3rem;
    background: color-mix(in srgb, var(--cat-cor) 16%, transparent);
    color: var(--cat-cor);
    font-size: .6875rem;
    font-weight: 700;
}

.n3-txt[b-rp1jgts2js] {
    display: flex;
    flex-direction: column;
    min-width: 0;
    line-height: 1.25;
}

.n3-num[b-rp1jgts2js] {
    font-size: .8125rem;
    font-weight: 600;
}

/* Rótulo longo em cartão estreito: quebra em duas linhas em vez de estourar a coluna. */
.n3-cat[b-rp1jgts2js] {
    font-size: .6875rem;
    color: var(--at-text-muted);
    overflow-wrap: anywhere;
}

.topo-vazio[b-rp1jgts2js] {
    margin: 0;
    font-size: .8125rem;
    color: var(--at-text-muted);
}

/* --- Bloco de medidas (fora do diagrama) ----------------------------------- */

.medidas[b-rp1jgts2js] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .375rem .5rem;
    margin-top: .75rem;
    padding-top: .75rem;
    border-top: 1px solid var(--at-border);
}

.medidas-rotulo[b-rp1jgts2js] {
    font-size: .75rem;
    font-weight: 600;
    color: var(--at-text-muted);
}

.medidas-item[b-rp1jgts2js] {
    padding: .15rem .5rem;
    border: 1px solid var(--at-border);
    border-radius: 999px;
    font-size: .75rem;
    color: var(--at-text-muted);
}

/* --- Cores por categoria --------------------------------------------------- */
/* A cor é o que faz o diagrama ser lido de relance, antes do texto. Uma cor por item, e não por
   família, senão os dois mais parecidos ficariam indistinguíveis.

   Dois conjuntos: no claro, tons escuros o bastante para o texto passar de 4,5:1 sobre o cartão; no
   escuro, os mesmos matizes clareados. `color-mix` deriva fundo e borda de cada um, então um ajuste
   mexe num lugar só.

   Duas famílias cinzentas convivem aqui e no escuro nasceram com o MESMO valor — cartões idênticos
   para itens diferentes. Medido no navegador, não notado a olho. Separadas por CLARIDADE, que é o
   que sobra quando o matiz é o mesmo. */

.cat-1[b-rp1jgts2js]    { --cat-cor: #b45309; }   /* âmbar */
.cat-2[b-rp1jgts2js] { --cat-cor: #c2410c; }   /* laranja */
.cat-3[b-rp1jgts2js]    { --cat-cor: #334155; }   /* ardósia escura */
.cat-4[b-rp1jgts2js] { --cat-cor: #0f766e; }   /* verde-azulado */
.cat-5[b-rp1jgts2js] { --cat-cor: #4338ca; }   /* índigo */
.cat-6[b-rp1jgts2js]    { --cat-cor: #15803d; }   /* verde */
.cat-7[b-rp1jgts2js] { --cat-cor: #4d7c0f; }   /* oliva */
.cat-8[b-rp1jgts2js]    { --cat-cor: #0369a1; }   /* azul */
.cat-0[b-rp1jgts2js]  { --cat-cor: #64748b; }   /* neutro */

[data-bs-theme="dark"] .cat-1[b-rp1jgts2js]    { --cat-cor: #fbbf24; }
[data-bs-theme="dark"] .cat-2[b-rp1jgts2js] { --cat-cor: #fb923c; }
[data-bs-theme="dark"] .cat-3[b-rp1jgts2js]    { --cat-cor: #cbd5e1; }
[data-bs-theme="dark"] .cat-4[b-rp1jgts2js] { --cat-cor: #2dd4bf; }
[data-bs-theme="dark"] .cat-5[b-rp1jgts2js] { --cat-cor: #a5b4fc; }
[data-bs-theme="dark"] .cat-6[b-rp1jgts2js]    { --cat-cor: #4ade80; }
[data-bs-theme="dark"] .cat-7[b-rp1jgts2js] { --cat-cor: #a3e635; }
[data-bs-theme="dark"] .cat-8[b-rp1jgts2js]    { --cat-cor: #38bdf8; }
[data-bs-theme="dark"] .cat-0[b-rp1jgts2js]  { --cat-cor: #94a3b8; }
/* /Pages/Admin/Statistics.razor.rz.scp.css */
/* Grade de números */
.kpis[b-jn8a8g74sc] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    gap: .75rem;
    margin-bottom: 1rem;
}

/* Mesmo visual do cartão */
.kpi[b-jn8a8g74sc] {
    display: flex;
    flex-direction: column;
    gap: .125rem;
    padding: 1rem;
    background-color: var(--at-surface);
    border: 1px solid var(--at-border);
    border-radius: var(--at-radius);
    box-shadow: var(--at-shadow);
}

.kpi-rotulo[b-jn8a8g74sc] {
    font-size: .875rem;
    font-weight: 500;
    color: var(--at-text-muted);
}

.kpi-valor[b-jn8a8g74sc] {
    font-size: 2rem;
    font-weight: 600;
    line-height: 1.15;
    letter-spacing: -.01em;
    color: var(--at-text);
}

.kpi-nota[b-jn8a8g74sc] {
    font-size: .8125rem;
    color: var(--at-text-muted);
}

.cabecalho[b-jn8a8g74sc] {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: .5rem;
    margin-bottom: .875rem;
}

/* Barras horizontais */
.barras[b-jn8a8g74sc] {
    display: flex;
    flex-direction: column;
    gap: .625rem;
}

.barra-linha[b-jn8a8g74sc] {
    display: grid;
    grid-template-columns: minmax(6rem, 11rem) minmax(0, 1fr) 6.5rem;
    align-items: center;
    gap: .75rem;
}

.barra-nome[b-jn8a8g74sc] {
    font-size: .9375rem;
}

.barra-trilho[b-jn8a8g74sc] {
    display: block;
}

.barra[b-jn8a8g74sc] {
    display: block;
    width: var(--p);
    height: .75rem;
    background-color: var(--at-accent);
    border-radius: 0 4px 4px 0;
}

.barra-valor[b-jn8a8g74sc] {
    text-align: right;
    font-size: .9375rem;
    font-variant-numeric: tabular-nums;
}

.barra-parte[b-jn8a8g74sc] {
    margin-left: .375rem;
    color: var(--at-text-muted);
}

/* Números alinhados */
.table td.tabular[b-jn8a8g74sc] {
    text-align: right;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.tags[b-jn8a8g74sc] {
    display: flex;
    flex-wrap: wrap;
    gap: .25rem;
}

.tag[b-jn8a8g74sc] {
    padding: .1rem .45rem;
    border: 1px solid var(--at-border);
    border-radius: 999px;
    background: var(--at-surface);
    font-size: .6875rem;
    color: var(--at-text-muted);
    white-space: nowrap;
}

.tag b[b-jn8a8g74sc] {
    color: var(--at-text);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.tag-aviso[b-jn8a8g74sc] {
    border-color: color-mix(in srgb, var(--at-warn) 45%, transparent);
    color: var(--at-warn);
}

.nota-data[b-jn8a8g74sc] {
    display: block;
    font-size: .75rem;
    color: var(--at-text-muted);
}

@media (max-width: 640.98px) {
    .barra-linha[b-jn8a8g74sc] {
        grid-template-columns: 6rem minmax(0, 1fr) 5.25rem;
        gap: .5rem;
    }

    /* Colunas só em tela larga */
    .table-responsive[b-jn8a8g74sc]  .col-larga {
        display: none;
    }
}
/* /Pages/Changelog.razor.rz.scp.css */
.versao[b-rhjub7bvuv] {
    max-width: var(--at-w-read);
    margin-bottom: 1.75rem;
}

.cabecalho[b-rhjub7bvuv] {
    display: flex;
    /* Pela linha de base, não pelo centro: o número e a data têm tamanhos diferentes, e centrar as
       caixas apoia os dois textos em linhas distintas (o mesmo defeito já corrigido nos grupos). */
    align-items: baseline;
    gap: .5rem;
}

.numero[b-rhjub7bvuv] {
    font-size: 1rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.data[b-rhjub7bvuv] {
    margin-left: auto;
    font-size: .8rem;
    color: var(--at-text-muted);
    font-variant-numeric: tabular-nums;
}

.itens[b-rhjub7bvuv] {
    margin: .5rem 0 0;
    padding-left: 1.1rem;
    line-height: 1.65;
}

.itens li[b-rhjub7bvuv] {
    margin-bottom: .2rem;
}

/* Selo do item: discreto, informa sem virar decoração. */
.selo[b-rhjub7bvuv] {
    display: inline-block;
    margin-right: .4rem;
    padding: 0 .4rem;
    border-radius: .25rem;
    background-color: var(--at-surface-sunken);
    border: 1px solid var(--at-border);
    color: var(--at-text-muted);
    font-size: .68rem;
    vertical-align: 1px;
}
/* /Pages/Home.razor.rz.scp.css */
/*
    A página inicial: uma saudação e um cartão por destino.

    Tudo aqui sai dos tokens que já existem (--at-surface, --at-border, --at-text-muted, --at-accent).
    Nenhuma cor nova entrou, e nenhuma medida está escrita em pixel solto onde a escada de largura já
    responde — o teto vem do `.larg-lista` no markup, e não daqui.
*/

.home-saudacao[b-ome9g7cs0t] {
    /* Um pouco maior que o h1 padrão: é a primeira linha da tela e a única que fala com a pessoa em vez
   de rotular um bloco. */
    font-size: 1.75rem;
    font-weight: 600;
    margin-bottom: .25rem;
    text-wrap: balance;
}

.home-linha-fina[b-ome9g7cs0t] {
    color: var(--at-text-muted);
    margin-bottom: 1.25rem;
}

/*
    Grade que decide sozinha quantas colunas cabem: `auto-fit` com um piso de 20rem faz os cartões
    caírem para uma coluna no celular sem nenhuma media query. O piso é o que impede a coluna de
    espremer o subtítulo — é a mesma lição da §20 B1, aplicada antes de ela virar defeito.
*/
.home-atalhos[b-ome9g7cs0t] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
    gap: 1rem;
}

.home-atalho[b-ome9g7cs0t] {
    display: flex;
    /* ⚠️ `flex-direction` explícito: o `.card` do Bootstrap declara `flex-direction: column`, e sem
       esta linha o ícone ficava EMPILHADO sobre o texto em vez de ao lado. O markup e os testes
       passavam iguais — foi a medição no navegador que mostrou o cartão com 125 px de altura onde o
       conteúdo pedia 83. */
    flex-direction: row;
    align-items: flex-start;
    gap: .875rem;
    padding: 1.125rem 1.25rem;
    color: inherit;
    text-decoration: none;
    /* O cartão INTEIRO é o alvo de toque; com o padding acima ele passa de 44 px com folga. */
    min-height: 44px;
    transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}

.home-atalho:hover[b-ome9g7cs0t] {
    border-color: var(--at-accent);
    text-decoration: none;
    transform: translateY(-1px);
}

/* O foco por teclado precisa ser tão visível quanto o hover — e mais: quem navega por Tab não tem o
   ponteiro para saber onde está. */
.home-atalho:focus-visible[b-ome9g7cs0t] {
    outline: 2px solid var(--at-accent);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    .home-atalho[b-ome9g7cs0t] {
        transition: none;
    }

    .home-atalho:hover[b-ome9g7cs0t] {
        transform: none;
    }
}

/* PREENCHIDO, e não contornado: os ícones vêm da barra lateral, que usa as silhuetas cheias do
   Bootstrap Icons. Um traçado desenhado para preencher, renderizado como contorno, sai como um
   borrão — o `stroke` de antes existia para os desenhos à mão que estavam aqui.

   A cor é o accent (e não o branco do menu) porque aqui o fundo é o do cartão, e não a coluna
   escura: o token faz o ícone acompanhar o tema. */
.home-atalho svg[b-ome9g7cs0t] {
    flex: 0 0 auto;
    width: 1.5rem;
    height: 1.5rem;
    margin-top: .125rem;
    fill: var(--at-accent);
    stroke: none;
}

.home-atalho-texto[b-ome9g7cs0t] {
    display: flex;
    flex-direction: column;
    gap: .125rem;
    /* Sem isto o texto empurra a grade e o `minmax` de 20rem deixa de valer como piso. */
    min-width: 0;
}

.home-atalho-titulo[b-ome9g7cs0t] {
    font-weight: 600;
}

.home-atalho-nota[b-ome9g7cs0t] {
    color: var(--at-text-muted);
    font-size: .875rem;
}

.home-rodape[b-ome9g7cs0t] {
    color: var(--at-text-muted);
    font-size: .875rem;
    margin-top: 1.5rem;
    margin-bottom: 0;
}
/* /Pages/Login.razor.rz.scp.css */
.login-page[b-x3q0tnxmb4] {
    /* A altura da tela agora é do .empty-shell (que também abriga o rodapé); aqui basta crescer para
       ocupar o que sobra — o cartão segue centrado nesse espaço. */
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
    background-color: var(--at-surface-sunken);
}

.login-card[b-x3q0tnxmb4] {
    width: 100%;
    max-width: 22rem;
    padding: 2rem;
    background-color: var(--at-surface);
    border: 1px solid var(--at-border);
    border-radius: calc(var(--at-radius) * 1.5);
    box-shadow: var(--at-shadow);
}

.login-brand[b-x3q0tnxmb4] {
    font-size: 1.6rem;
    font-weight: 600;
    letter-spacing: -.02em;
    color: var(--at-text);

    /* O título encostava no primeiro campo. O respiro fica aqui, e não num <br> no markup: quebra de
       linha é conteúdo, e este espaço é forma. */
    margin-bottom: 1.25rem;
}

.login-sub[b-x3q0tnxmb4] {
    margin-bottom: 1.5rem;
    font-size: .9rem;
    color: var(--at-text-muted);
}
/* /Pages/RemoteControl.razor.rz.scp.css */
/* --- Alvo: seleção múltipla em pílulas ------------------------------------ */
.alvo-pills[b-pp18abubu3] {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
}

.alvo-pill[b-pp18abubu3] {
    min-width: 2.75rem;
    padding: .35rem .9rem;
    border: 1px solid var(--at-border);
    border-radius: 50rem;
    background-color: transparent;
    color: var(--at-text-muted);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    cursor: pointer;
    transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}

.alvo-pill:hover[b-pp18abubu3] {
    border-color: var(--at-accent);
    color: var(--at-accent);
}

.alvo-pill.is-on[b-pp18abubu3] {
    background-color: var(--at-accent-solid);
    border-color: var(--at-accent-solid);
    color: var(--at-accent-contrast);
}

.alvo-pill:focus-visible[b-pp18abubu3] {
    outline: none;
    box-shadow: 0 0 0 .2rem rgba(var(--at-accent-rgb), .3);
}

/* --- Botões de ação -------------------------------------------------------- */
.command-grid[b-pp18abubu3] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
    gap: .75rem;
}

.command-btn[b-pp18abubu3] {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .35rem;
    /* Sem o subtítulo, duas linhas de texto viraram uma — a altura acompanha. */
    min-height: 5.5rem;
    padding: .9rem .6rem;
    /* Borda transparente para o botão não mudar de tamanho quando o foco desenha o anel. */
    border: 1px solid transparent;
    border-radius: calc(var(--at-radius) * 1.5);
    /* Fundo sólido: a tinta de 12% anterior ficava neutra demais para diferenciar de relance.
   Texto e ícone seguem `--tone-fg`, escolhido por tom para o contraste fechar. Fixos nos dois
   temas de propósito — aqui a cor é o significado. */
    background-color: var(--tone);
    color: var(--tone-fg);
    text-align: center;
    cursor: pointer;
    transition: border-color .15s ease, box-shadow .15s ease, transform .05s ease;
}

/* Com o fundo já colorido, o realce do hover é um clareado do próprio fundo mais a sombra. */
.command-btn:hover:not(:disabled)[b-pp18abubu3] {
    filter: brightness(1.12);
    box-shadow: var(--at-shadow);
}

.command-btn:active:not(:disabled)[b-pp18abubu3] { transform: translateY(1px); }

/* Dois anéis de foco: um claro colado e um escuro por fora, para aparecer sobre qualquer fundo. */
.command-btn:focus-visible[b-pp18abubu3] {
    outline: none;
    box-shadow: 0 0 0 .15rem rgba(255, 255, 255, .85), 0 0 0 .32rem rgba(0, 0, 0, .45);
}

.command-btn:disabled[b-pp18abubu3] {
    opacity: .5;
    cursor: not-allowed;
}

.command-btn svg[b-pp18abubu3] {
    width: 1.75rem;
    height: 1.75rem;
    fill: none;
    /* Ícone na cor do texto do tema: quem diferencia é o fundo. */
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.command-label[b-pp18abubu3] {
    font-weight: 600;
    font-size: .95rem;
    line-height: 1.15;
}

/* Preenchimento sólido por tom. São versões escurecidas do accent e do verde: os originais não
   fecham 4,5:1 com texto branco. O amarelo é o oposto — claro demais para branco, leva quase-preto.
   Medições em docs/UI-WEB.md §10.2. */
.tone-info[b-pp18abubu3] { --tone: #0b6fd4; --tone-fg: #ffffff; }
.tone-warn[b-pp18abubu3] { --tone: #e8a80c; --tone-fg: #1b2733; }
.tone-danger[b-pp18abubu3] { --tone: #c02626; --tone-fg: #ffffff; }
.tone-ok[b-pp18abubu3] { --tone: #157f3c; --tone-fg: #ffffff; }
.tone-neutral[b-pp18abubu3] { --tone: #5c6b7a; --tone-fg: #ffffff; }

/* --- Prévia de tabela ------------------------------------------------------ */
/* Três colunas curtas; sem limite a tabela esticava para a largura inteira do navegador. */
.preview[b-pp18abubu3] {
    border: 1px solid var(--at-border);
    border-radius: var(--at-radius);
    padding: .5rem .75rem;
    margin-bottom: .5rem;
}

.preview > summary[b-pp18abubu3] {
    cursor: pointer;
    font-size: .9rem;
    font-weight: 500;
}

/* O `overflow-x` cumpre o §2 do UI-WEB sem a classe `.table-responsive`: já há um envoltório com
   rolagem vertical, e o `display: block` dela quebraria o `max-width` da própria tabela. */
.preview-scroll[b-pp18abubu3] {
    max-height: 16rem;
    overflow-y: auto;
    overflow-x: auto;
}

.preview-table[b-pp18abubu3] {
    width: auto;
    min-width: 16rem;
    max-width: 26rem;
}

.preview-table td[b-pp18abubu3],
.preview-table th[b-pp18abubu3] {
    font-variant-numeric: tabular-nums;
}

/* Um componente por linha. `nowrap` porque o número não pode quebrar no meio. */
.k-cell[b-pp18abubu3] {
    display: flex;
    flex-direction: column;
    gap: 1px;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.k-label[b-pp18abubu3] {
    display: inline-block;
    min-width: 1.6rem;
    color: var(--at-text-muted);
    font-size: .75rem;
}

/* Campo estreito de propósito: cabe 0–100 e nada mais, e a tabela não estica a página. */
.price-input[b-pp18abubu3] {
    width: 5rem;
}

/* --- Lista de execuções ---------------------------------------------------- */
.history > summary[b-pp18abubu3] {
    cursor: pointer;
    font-weight: 600;
}

.history-item + .history-item[b-pp18abubu3] {
    margin-top: 1.25rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--at-border);
}

.history-head[b-pp18abubu3] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
    margin-bottom: .15rem;
}

/* Contexto DEPOIS do distintivo: a primeira linha é para o que se procura ao correr o olho. */
.history-meta[b-pp18abubu3] {
    margin-bottom: .5rem;
}

/* Cada item guarda a própria tabela atrás de um resumo, e só o mais recente nasce aberto — todos
   abertos empilhariam centenas de blocos num cartão só. */
.history-result > summary[b-pp18abubu3] {
    cursor: pointer;
    padding: .2rem 0;
    color: var(--at-text-muted);
    font-size: .875rem;
}

/* --- Agendamentos ---------------------------------------------------------- */
.routines > summary[b-pp18abubu3] {
    cursor: pointer;
    font-weight: 600;
}

/* Item inativo continua legível, só recuado visualmente. */
.routine-off > td[b-pp18abubu3] {
    opacity: .55;
}

/* A linha de observação cola na linha do item, sem borda entre as duas. */
.routine-note > td[b-pp18abubu3] {
    border-top: 0;
}

.routine-form[b-pp18abubu3] {
    padding: 1rem;
    border: 1px solid var(--at-border);
    border-radius: var(--at-radius);
    background-color: var(--at-surface-sunken);
}

/* Tabela no desktop, um bloco por linha no celular. A quebra é a MESMA do layout
   (MainLayout.razor.css) — o ponto em que a barra deixa de ser coluna lateral. Medido: a tabela
   pede 322 px onde há 319. */
.result-cards[b-pp18abubu3] {
    display: none;
}

@media (max-width: 640.98px) {
    .result-cards[b-pp18abubu3] {
        display: block;
    }

    .result-table[b-pp18abubu3] {
        display: none;
    }
}

.result-card[b-pp18abubu3] {
    padding: .5rem 0;
    border-top: 1px solid var(--at-border);
}

.result-card:first-child[b-pp18abubu3] {
    border-top: 0;
}

.result-card-head[b-pp18abubu3] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
}

.result-card-sub[b-pp18abubu3] {
    font-weight: 600;
}

/* `tabular-nums` fixa a largura do dígito, para os números alinharem entre blocos. */
.result-card-k[b-pp18abubu3] {
    margin-top: .15rem;
    color: var(--at-text-muted);
    font-size: .875rem;
    font-variant-numeric: tabular-nums;
}

/* --- Distintivos de estado -------------------------------------------------
   As cores foram medidas, não escolhidas: o palpite natural reprovava em cada caso, e cada tom tem
   dois trabalhos (texto e contorno), com barras diferentes. Tabelas em docs/UI-WEB.md §10.2. */
.chip[b-pp18abubu3] {
    display: inline-block;
    padding: .25em .6em;
    border: 1px solid transparent;
    border-radius: .375rem;
    font-size: .75em;
    font-weight: 700;
    line-height: 1;
    white-space: nowrap;
}

.chip-alterado[b-pp18abubu3] {
    background-color: #dc2626;
    color: #fff;
}

.chip-falha[b-pp18abubu3] {
    background-color: #0b0b0b;
    border-color: #ef4444;
    color: #ef4444;
}

/* Peso e cor pelo estado. As cores vêm dos tokens que já trocam por tema — nenhum hexadecimal
   único serve nos dois. O valor de referência não ganha cor em caso nenhum: colori-lo faria a linha
   ter duas afirmações competindo. */
.k-novo[b-pp18abubu3] {
    font-weight: 700;
}

.k-novo-ok[b-pp18abubu3] {
    color: var(--at-ok);
}

.k-novo-mudou[b-pp18abubu3] {
    color: var(--at-fail);
}

/* Ocupa a largura inteira e quebra à vontade: como coluna ficava espremido e cortado. */
.result-card-fail[b-pp18abubu3] {
    margin-top: .15rem;
    color: var(--at-fail);
    font-size: .875rem;
}

/* Observação de item concluído. Esmaecida, e não vermelha: não é erro. */
.result-card-nota[b-pp18abubu3],
.detail-nota[b-pp18abubu3] {
    margin-top: .15rem;
    color: var(--at-text-muted);
    font-size: .875rem;
}

/* --- Painel técnico -------------------------------------------------------- */
.depuracao > summary[b-pp18abubu3] {
    cursor: pointer;
    font-weight: 600;
}

/* Subtítulo dentro do cartão. Não é um `card-header` — o cartão já tem o dele, e dois cabeçalhos
   de mesmo peso pareceriam dois cartões colados. A margem de baixo é o respiro até o conteúdo. */
.depuracao-secao[b-pp18abubu3] {
    font-size: .8125rem;
    font-weight: 600;
    letter-spacing: .02em;
    text-transform: uppercase;
    color: var(--at-text-muted);
    margin: 0 0 .5rem;
}

/* Título sozinho no bloco: quem dá o respiro é o padding, e somar margem deixava o dobro. */
.depuracao-secao:only-child[b-pp18abubu3] {
    margin-bottom: 0;
}
/* /Pages/StationsDashboard.razor.rz.scp.css */
/* Cabeçalho de grupo. A admin/instalacoes tem os mesmos, mas como LINHAS de tabela — aqui a listagem
   é um `.list-group`, então o cabeçalho é um item dele. O vocabulário visual é o mesmo de propósito:
   quem alterna entre as duas telas reconhece a divisão. */
.group-row[b-u7zzdesdq2] {
    background-color: var(--at-surface-sunken);
    border-top: 1px solid var(--at-border);
}

/* Botão de largura inteira em vez do item clicável: um `<div>` de lista não recebe foco pelo teclado
   nem se anuncia como acionável. */
.group-toggle[b-u7zzdesdq2] {
    display: flex;
    /* BASELINE, não center: o nome do grupo e a contagem têm tamanhos de fonte diferentes (a contagem
       é `.small`), e centrar caixas de alturas diferentes deixa os dois textos apoiados em linhas
       distintas. Alinhando pela linha de base, eles se sentam na mesma. */
    align-items: baseline;
    width: 100%;
    padding: .5rem .75rem;
    background: none;
    border: 0;
    text-align: left;
    color: var(--at-text);
    font-weight: 600;
}

.group-toggle:hover[b-u7zzdesdq2] {
    background-color: var(--at-rail-hover);
}

.group-caret[b-u7zzdesdq2] {
    display: inline-block;
    width: 1rem;
    color: var(--at-text-muted);
    font-weight: 400;
}

/* O cabeçalho da tela: título, alternador, busca e ordenação numa grade só, com a largura da lista
   (`.larg-lista` no elemento). Assim a borda direita dos controles é a borda direita da lista, em
   qualquer largura de tela — e não a da página, como era.

   A coluna da direita tem a largura do seletor curto da escala: a ordenação a ocupa inteira, e o
   alternador, menor, encosta à direita dela. */
.dash-head[b-u7zzdesdq2] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) var(--at-w-field-sm);
    grid-template-areas:
        "title  mode"
        "search sort";
    gap: .5rem;
    align-items: center;
    margin-bottom: 1rem;
}

.dash-title[b-u7zzdesdq2] { grid-area: title; }
.dash-mode[b-u7zzdesdq2] { grid-area: mode; justify-self: end; }
.dash-search[b-u7zzdesdq2] { grid-area: search; }

/* O SearchBox traz `mb-3` para as telas em que ele fica sozinho numa linha. Aqui ele divide a linha
   com a ordenação, e a grade centra os dois: com a margem, o campo subia 8 px em relação ao select
   (medido). O `!important` só porque o utilitário do Bootstrap também o tem. */
.dash-search[b-u7zzdesdq2]  .search-box { margin-bottom: 0 !important; }
.dash-sort[b-u7zzdesdq2] { grid-area: sort; }

/* No celular (a mesma quebra da barra do topo, MainLayout): o alternador desce e fica na frente da
   ordenação, na mesma linha — no alto, ao lado do título, ele disputava espaço com ele. */
@media (max-width: 640.98px) {
    .dash-head[b-u7zzdesdq2] {
        grid-template-columns: auto minmax(0, 1fr);
        grid-template-areas:
            "title  title"
            "search search"
            "mode   sort";
    }

    /* Esticado até a altura da ordenação: o alternador é `btn-sm`, e lado a lado com o select ele ficava
       um degrau mais baixo. */
    .dash-mode[b-u7zzdesdq2] { justify-self: start; align-self: stretch; }

    /* Sem o alternador (quem não é admin), a ordenação ocupa a linha inteira em vez de começar depois
       de uma coluna vazia. */
    .dash-head.no-mode .dash-sort[b-u7zzdesdq2] { grid-column: 1 / -1; }
}
