/* ---------- Densidade da interface (Pequena / Média / Grande) ----------
   Como quase todo o layout (inclusive os componentes do Bootstrap) é medido
   em rem, mudar o font-size da raiz escala a UI inteira proporcionalmente. */
:root {
    font-size: 13px;
}

:root[data-density="compact"] {
    font-size: 12px;
}

:root[data-density="spacious"] {
    font-size: 15px;
}

/* Trava anti-FOUC (ver `includes/theme_boot.php`) — aplicada no `<html>`
   pelo boot script ANTES do body pintar, e removida por `assets/js/app.js`
   só depois que os estados salvos da sidebar (colapso + grupos abertos)
   já foram aplicados. Sem ela, restaurar um estado salvo diferente do
   padrão do HTML (ex.: grupo fechado, sidebar colapsada) disparava a
   transição normal desses elementos, virando uma animação visível no
   carregamento da página em vez de já nascer no estado certo. */
html.js-boot,
html.js-boot * {
    transition: none !important;
}

/* ---------- Tema Claro (padrão) ---------- */
:root,
:root[data-theme="light"] {
    --sidebar-width: 16.25rem;
    --sidebar-width-collapsed: 3.75rem;
    --header-height: 3.75rem;

    --color-bg: #f4f6f9;
    --color-surface: #ffffff;
    --color-border: #d7dee7;
    --color-text: #1f2733;
    --color-text-muted: #6b7686;

    --color-brand: #ff6700;
    --color-brand-dark: #e05a00;
    --color-brand-soft: rgba(255, 103, 0, .12);
    --color-sidebar-bg: #16202e;
    --color-sidebar-text: #c7d0dc;
    --color-sidebar-hover: #22303f;
    --color-sidebar-active: #ff6700;

    --shadow-sm: 0 1px 2px rgba(16, 24, 40, .06);
    --shadow-md: 0 4px 12px rgba(16, 24, 40, .08);
    --radius: .6rem;
}

/* ---------- Tema Escuro (cinza neutro, alto contraste — "true dark") ---------- */
:root[data-theme="dark"] {
    --color-bg: #0a0a0b;
    --color-surface: #18181b;
    --color-border: #2c2c30;
    --color-text: #f4f4f5;
    --color-text-muted: #9a9aa1;

    --color-brand: #ff7a1a;
    --color-brand-dark: #ff6700;
    --color-brand-soft: rgba(255, 122, 26, .18);
    --color-sidebar-bg: #050506;
    --color-sidebar-text: #9a9aa1;
    --color-sidebar-hover: #1c1c1f;
    --color-sidebar-active: #ff7a1a;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
    --shadow-md: 0 4px 16px rgba(0, 0, 0, .5);
}

/* ---------- Tema Azul (escuro, dominante em azul-marinho) ---------- */
:root[data-theme="blue"] {
    --color-bg: #0a1628;
    --color-surface: #0f2036;
    --color-border: #1c3a5e;
    --color-text: #dce7f5;
    --color-text-muted: #7d97b8;

    --color-brand: #3b82f6;
    --color-brand-dark: #2563eb;
    --color-brand-soft: rgba(59, 130, 246, .18);
    --color-sidebar-bg: #060f1d;
    --color-sidebar-text: #7d97b8;
    --color-sidebar-hover: #13233b;
    --color-sidebar-active: #3b82f6;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
    --shadow-md: 0 4px 16px rgba(0, 0, 0, .5);
}

/* ---------- Tema Cinza (escuro, mais suave/"dimmed" que o Escuro) ---------- */
:root[data-theme="gray"] {
    --color-bg: #232326;
    --color-surface: #2c2c30;
    --color-border: #3a3a3f;
    --color-text: #e4e4e7;
    --color-text-muted: #9a9aa2;

    --color-brand: #0d9488;
    --color-brand-dark: #0f766e;
    --color-brand-soft: rgba(13, 148, 136, .18);
    --color-sidebar-bg: #1a1a1c;
    --color-sidebar-text: #9a9aa2;
    --color-sidebar-hover: #313136;
    --color-sidebar-active: #0d9488;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
    --shadow-md: 0 4px 16px rgba(0, 0, 0, .5);
}

* {
    box-sizing: border-box;
}

body {
    background: var(--color-bg);
    color: var(--color-text);
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
}

a {
    text-decoration: none;
}

/* ---------- Botão de marca (theme-aware) ---------- */

.btn-brand {
    background: var(--color-brand);
    border-color: var(--color-brand);
    color: #fff;
    font-weight: 600;
}

.btn-brand:hover,
.btn-brand:focus {
    background: var(--color-brand-dark);
    border-color: var(--color-brand-dark);
    color: #fff;
}

/* Botão `.btn-brand` desabilitado (ex.: "Gerar Relatório" em Relatórios >
   Financeiros, antes de escolher ao menos um Cliente/Projeto/Tarefa) — sem
   isso, o Bootstrap usa seu próprio disabled genérico (fundo transparente,
   borda/texto escuro fixo) por trás de QUALQUER classe de botão custom que
   não declare seus próprios `--bs-btn-disabled-*`, ficando com uma cara
   totalmente fora do tema (nem laranja, nem coerente com o resto). Mantém a
   cor da marca, só esmaece via opacidade — mesma linguagem visual que os
   variants nativos do Bootstrap (`.btn-primary:disabled` etc.) já usam. */
.btn-brand:disabled,
.btn-brand.disabled {
    background: var(--color-brand);
    border-color: var(--color-brand);
    color: #fff;
    opacity: .5;
}

/* ---------- Botão secundário/"ghost" (Filtrar, Baixar XLSX, Gerar PDF etc.),
   theme-aware — inspirado no `.btn-ghost-sm` do portalnoc-v2: fundo sólido
   (um tom entre o card e o texto, não transparente) + borda discreta +
   cantos mais arredondados, em vez do outline "vazado" padrão do Bootstrap
   (que em temas escuros quase somem, com --color-border colado em
   --color-surface). Cor de texto sozinha (sem ícone colorido dentro do
   botão) — mesmo peso visual em qualquer tema, claro ou escuro. */
.btn-outline-secondary {
    --bs-btn-color: var(--color-text-muted) !important;
    --bs-btn-bg: color-mix(in srgb, var(--color-text) 6%, var(--color-surface)) !important;
    --bs-btn-border-color: var(--color-border) !important;
    --bs-btn-border-radius: .5rem !important;
    --bs-btn-hover-color: var(--color-text) !important;
    --bs-btn-hover-bg: color-mix(in srgb, var(--color-text) 12%, var(--color-surface)) !important;
    --bs-btn-hover-border-color: var(--color-border) !important;
    --bs-btn-active-color: var(--color-text) !important;
    --bs-btn-active-bg: color-mix(in srgb, var(--color-text) 16%, var(--color-surface)) !important;
    --bs-btn-active-border-color: var(--color-border) !important;
    --bs-btn-disabled-color: var(--color-border) !important;
    --bs-btn-disabled-bg: transparent !important;
    --bs-btn-disabled-border-color: var(--color-border) !important;
}

/* ---------- Campos de formulário (sobrescreve o dark-mode "cru" do
   Bootstrap, que usa um cinza genérico sem relação com a cor do tema) ---------- */

.form-control,
.form-select {
    background-color: var(--color-bg);
    border-color: var(--color-border);
    color: var(--color-text);
}

.form-control:focus,
.form-select:focus {
    background-color: var(--color-bg);
    border-color: var(--color-brand);
    color: var(--color-text);
    box-shadow: 0 0 0 .2rem var(--color-brand-soft);
}

/* Utilitário .border do Bootstrap usa um cinza fixo que não acompanha o
   tema ativo (mesmo problema já visto em modal/form-control/checkbox). */
.border {
    border-color: var(--color-border) !important;
}

/* `input-group-text` (ex.: rótulo "De"/"Até" dentro do mesmo input-group
   do período, Relatórios > Projetos) — mesmo problema de sempre: o
   cinza/fundo padrão do Bootstrap não segue os 4 temas do app. */
.input-group-text {
    background-color: var(--color-surface);
    border-color: var(--color-border);
    color: var(--color-text-muted);
}

/* Anel de foco do botão de fechar (X) do modal — o padrão do Bootstrap é um
   azul fixo (#0d6efd) sem relação com nenhum dos 4 temas do app. */
.btn-close:focus {
    box-shadow: 0 0 0 .2rem var(--color-brand-soft);
}

.form-control::placeholder {
    color: var(--color-text-muted);
    opacity: .8;
}

.form-control:disabled,
.form-select:disabled,
fieldset:disabled .form-control,
fieldset:disabled .form-select {
    background-color: var(--color-surface);
    color: var(--color-text-muted);
    opacity: .6;
}

.form-label {
    color: var(--color-text);
}

/* ---------- Checkbox / switch / radio (sobrescreve o azul fixo do
   Bootstrap — sem isso, nenhum dos 4 temas afeta essas cores). ---------- */

/* Tamanho ABSOLUTO (`rem`, relativo à raiz/densidade — nunca `em`) — o
   padrão do Bootstrap é `1em`, relativo ao `font-size` do elemento mais
   próximo que o define; como `<th>` de cabeçalho de tabela usa um
   `font-size` menor que `<td>` do corpo (rótulos em uppercase, menores de
   propósito), o mesmo checkbox "1em" saía visivelmente menor no
   cabeçalho que no corpo da mesma tabela (ex.: "selecionar tudo" em
   Apontamentos > Aprovar OS) — nunca era um problema de tema/cor, mas de
   TAMANHO relativo ao contexto. Também um pouco maior que o padrão do
   Bootstrap (pedido do usuário, ficava pequeno demais). */
.form-check-input {
    width: 1.15rem;
    height: 1.15rem;
    background-color: var(--color-bg);
    border-color: var(--color-border);
}

.form-check-input:checked {
    background-color: var(--color-brand);
    border-color: var(--color-brand);
}

.form-check-input:focus {
    border-color: var(--color-brand);
    box-shadow: 0 0 0 .2rem var(--color-brand-soft);
}

/* ---------- Abas estilo "underline" ---------- */

.nav-tabs {
    border-bottom: 1px solid var(--color-border);
    gap: 1.75rem;
}

.nav-tabs .nav-link {
    border: none;
    background: none;
    color: var(--color-text-muted);
    font-weight: 500;
    padding: .1rem .1rem .85rem;
    border-radius: 0;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
}

.nav-tabs .nav-link:hover {
    background: none;
    color: var(--color-text);
    border-bottom-color: var(--color-border);
}

.nav-tabs .nav-link.active {
    color: var(--color-brand);
    border-bottom-color: var(--color-brand);
    background: none;
    font-weight: 600;
}

.nav-tabs .nav-link.disabled {
    color: var(--color-border);
    cursor: not-allowed;
}

/* ---------- Layout ---------- */

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

.sidebar {
    width: var(--sidebar-width);
    flex-shrink: 0;
    background: var(--color-sidebar-bg);
    color: var(--color-sidebar-text);
    display: flex;
    flex-direction: column;
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    z-index: 1030;
    transition: width .2s ease, background-color .2s ease;
}

.sidebar.collapsed {
    width: var(--sidebar-width-collapsed);
}

/* Botão flutuante de colapsar/expandir — uma bolinha na borda da sidebar,
   alinhada com a linha da logo (não no meio da altura inteira do menu). */
.sidebar-collapse-btn {
    position: absolute;
    top: calc(var(--header-height) / 2);
    right: -.7rem;
    transform: translateY(-50%);
    width: 1.35rem;
    height: 1.35rem;
    border-radius: 50%;
    background: var(--color-sidebar-bg);
    border: 1px solid rgba(255, 255, 255, .12);
    color: var(--color-sidebar-text);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: .65rem;
    cursor: pointer;
    box-shadow: var(--shadow-sm);
    z-index: 1035;
    padding: 0;
    transition: background-color .15s ease, color .15s ease;
}

.sidebar-collapse-btn:hover {
    background: var(--color-sidebar-hover);
    color: #fff;
}

.sidebar-brand {
    display: flex;
    align-items: center;
    gap: .75rem;
    height: var(--header-height);
    padding: 0 1.25rem;
    border-bottom: 1px solid rgba(255, 255, 255, .08);
    white-space: nowrap;
    overflow: hidden;
}

.sidebar-brand img {
    height: 1.875rem;
    flex-shrink: 0;
}

.nav-group-label span,
.nav-link span,
.sidebar-user-info {
    opacity: 1;
    max-width: 12rem;
    overflow: hidden;
    white-space: nowrap;
    transition: opacity .15s ease, max-width .2s ease;
}

.sidebar.collapsed .nav-group-label span,
.sidebar.collapsed .nav-link span,
.sidebar.collapsed .sidebar-user-info {
    opacity: 0;
    max-width: 0;
}

.sidebar-nav {
    flex: 1;
    overflow-y: auto;
    padding: .75rem .6rem;
}

.nav-group + .nav-group {
    margin-top: .15rem;
}

.nav-group-label {
    display: flex;
    align-items: center;
    gap: .65rem;
    width: 100%;
    padding: .45rem .75rem;
    background: none;
    border: none;
    color: var(--color-sidebar-text);
    font-size: .85rem;
    font-weight: 600;
    letter-spacing: .01em;
    border-radius: .5rem;
    cursor: pointer;
    transition: padding .2s ease, gap .2s ease;
}

.nav-group-label:hover {
    background: var(--color-sidebar-hover);
    color: #fff;
}

.nav-group-label i {
    font-size: 1.05rem;
    width: 1.3rem;
    text-align: center;
}

.nav-group-label .chevron {
    margin-left: auto;
    font-size: .75rem;
    opacity: 1;
    max-width: 1rem;
    overflow: hidden;
    transition: transform .15s ease, opacity .15s ease, max-width .2s ease;
}

.nav-group.open .nav-group-label .chevron {
    transform: rotate(90deg);
}

.nav-sublist {
    list-style: none;
    margin: 0;
    padding: 0;
    max-height: 0;
    overflow: hidden;
    transition: max-height .18s ease;
}

.nav-group.open .nav-sublist {
    max-height: 400px;
}

/* Menu encolhido: só ícones — sem setinha de expandir nem espaço reservado
   para os submenus (que ficariam sem rótulo, só ocupando espaço à toa). */
.sidebar.collapsed .nav-group-label,
.sidebar.collapsed .nav-link {
    justify-content: center;
    padding-left: 0;
    padding-right: 0;
    gap: 0;
}

.sidebar.collapsed .sidebar-brand {
    justify-content: center;
    padding: 0;
}

.sidebar.collapsed .nav-group-label .chevron {
    opacity: 0;
    max-width: 0;
    margin-left: 0;
}

.sidebar.collapsed .nav-sublist {
    max-height: 0 !important;
}

.sidebar.collapsed .sidebar-user-toggle {
    justify-content: center;
    gap: 0;
}

/* Item de nível raiz (Início) — mesmo recuo e tamanho de ícone dos grupos,
   sem depender de style inline (que atrapalharia a centralização no modo
   encolhido). */
.sidebar-nav > .nav-link {
    padding-left: .75rem;
}

.sidebar-nav > .nav-link i {
    font-size: 1.05rem;
    width: 1.3rem;
    text-align: center;
}

.nav-link {
    display: flex;
    align-items: center;
    gap: .65rem;
    padding: .4rem .75rem .4rem 2.4rem;
    color: var(--color-sidebar-text);
    font-size: .9rem;
    border-radius: .5rem;
    margin: 0;
    transition: padding .2s ease, gap .2s ease;
}

.nav-link:hover {
    background: var(--color-sidebar-hover);
    color: #fff;
}

.nav-link.active {
    background: var(--color-sidebar-active);
    color: #fff;
    font-weight: 600;
}

.sidebar-user {
    position: relative;
    border-top: 1px solid rgba(255, 255, 255, .08);
    padding: .85rem 1.1rem;
}

.sidebar-user-toggle {
    display: flex;
    align-items: center;
    gap: .65rem;
    width: 100%;
    background: none;
    border: none;
    color: #fff;
    cursor: pointer;
    padding: 0;
}

.avatar {
    width: 2.125rem;
    height: 2.125rem;
    border-radius: 50%;
    background: var(--color-brand);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    flex-shrink: 0;
}

.sidebar-user-info {
    text-align: left;
    overflow: hidden;
}

.sidebar-user-info .name {
    font-size: .85rem;
    font-weight: 600;
    color: #fff;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sidebar-user-info .role {
    font-size: .75rem;
    color: var(--color-sidebar-text);
}

.user-menu-dropdown {
    display: none;
    position: absolute;
    bottom: calc(100% + 6px);
    left: 1rem;
    right: 1rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-md);
    overflow: hidden;
    z-index: 1040;
}

.user-menu-dropdown.show {
    display: block;
}

/* Menu encolhido: o dropdown não cabe espremido na largura estreita da
   barra — vira um flyout à direita, fora dos limites da sidebar. */
.sidebar.collapsed .user-menu-dropdown {
    left: calc(100% + .25rem);
    right: auto;
    bottom: .75rem;
    width: 13rem;
}

.user-menu-dropdown a {
    display: flex;
    align-items: center;
    gap: .55rem;
    padding: .65rem .9rem;
    color: var(--color-text);
    font-size: .88rem;
}

.user-menu-dropdown a:hover {
    background: var(--color-bg);
}

.user-menu-dropdown .divider {
    height: 1px;
    background: var(--color-border);
    margin: 0;
}

/* ---------- Main content ---------- */

.main {
    flex: 1;
    min-width: 0;
    margin-left: var(--sidebar-width);
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    transition: margin-left .2s ease;
}

.main.collapsed {
    margin-left: var(--sidebar-width-collapsed);
}

.topbar {
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
    height: var(--header-height);
    padding: 0 1.5rem;
    display: flex;
    align-items: center;
    gap: 1rem;
    position: sticky;
    top: 0;
    z-index: 1020;
}

.topbar-title {
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--color-text);
}

.breadcrumb-nav {
    display: flex;
    align-items: center;
    gap: .4rem;
    font-size: 1.05rem;
}

.breadcrumb-link {
    color: var(--color-text-muted);
    font-weight: 500;
}

.breadcrumb-link:hover {
    color: var(--color-brand);
    text-decoration: underline;
}

.breadcrumb-item {
    color: var(--color-text-muted);
    font-weight: 500;
}

.breadcrumb-item.current {
    color: var(--color-text);
    font-weight: 600;
}

/* Antes usava --color-border (pensado pra bordas discretas, quase invisível
   de propósito) — some de vista como separador de texto num breadcrumb,
   onde precisa ser lido, não só notado. */
.breadcrumb-sep {
    font-size: .65rem;
    color: var(--color-text-muted);
}

.content {
    padding: 1.75rem;
    flex: 1;
    min-width: 0;
}

.card-panel {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    padding: 1.5rem;
}

/* Substitui `alert alert-light` (cinza fixo do Bootstrap, igual em
   qualquer tema) no informativo da Tarefa selecionada em "Novo
   Apontamento" — mesmo `color-mix` já usado nos botões outline
   (`--bs-btn-bg` acima) pra um destaque sutil que acompanha o tema. */
.task-info-box {
    background: color-mix(in srgb, var(--color-text) 6%, var(--color-surface));
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: .75rem 1rem;
    color: var(--color-text);
}

/* ---------- Tabelas (sobrescreve o dark-mode "cru" do Bootstrap,
   sempre usando as variáveis do nosso tema, não as dele) ---------- */

.table {
    --bs-table-bg: transparent;
    --bs-table-color: var(--color-text);
    --bs-table-striped-bg: transparent;
    --bs-table-hover-bg: transparent;
    --bs-table-hover-color: var(--color-text);
    --bs-table-border-color: var(--color-border);
    color: var(--color-text);
    /* O Bootstrap usa `border-collapse: collapse` por padrão — junto com
       coluna(s) `position:sticky`, isso é uma combinação conhecida por
       "vazar" a borda (linha divisória entre linhas) por CIMA da célula
       fixa: em modo `collapse` o navegador desenha a borda compartilhada
       entre células adjacentes fora da caixa de cada célula individual,
       ignorando o empilhamento normal (z-index/position) que a célula
       fixa depende. Como só usamos `border-bottom` (nunca `border-top`),
       trocar pra `separate` com `border-spacing: 0` fica visualmente
       idêntico (mesma linha fina entre linhas, sem vão nem duplicata) e
       elimina esse vazamento — cada borda passa a pertencer de fato só à
       própria célula. */
    border-collapse: separate;
    border-spacing: 0;
}

.table > thead > tr > th {
    position: relative;
    color: var(--color-text-muted);
    font-size: .78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .03em;
    border-bottom: 2px solid var(--color-border);
    background: transparent;
    white-space: nowrap;
}

/* Só o texto do título trunca com reticências — o <th> em si NÃO tem
   overflow:hidden, senão corta também o indicador de ordenação e o
   ícone/popover de filtro (que ficam fora deste span, ver smart-table.js). */
.st-th-label {
    display: inline-block;
    max-width: calc(100% - 1.6rem);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: middle;
}

/* Mesmo toggle "quebra de célula" (CELL_WRAP_ENABLED) já usado pra não
   truncar o CONTEÚDO das colunas — estendido pro TÍTULO do cabeçalho, que
   antes truncava com reticências mesmo com o toggle ligado ("SALÁRIO FI...",
   "FEZ MAIS QUE 176 HOR..."). Quebrar em várias linhas (em vez de forçar a
   coluna inteira a ficar tão larga quanto o título mais comprido) evita
   que 1 cabeçalho longo estique uma tabela de 20+ colunas ainda mais larga
   do que o conteúdo de verdade precisaria. */
.table.st-cell-wrap > thead > tr > th .st-th-label {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    max-width: none;
}

/* Usado só durante a MEDIÇÃO em `_lockColumnWidths()` (smart-table.js) —
   remove o teto de largura do título por uma fração de segundo pra medir
   sua largura NATURAL (texto inteiro, sem reticências), garantindo que a
   coluna nunca trave mais estreita do que o título precisa. Combinado com
   `.st-th-label` (2 classes) pra ganhar de propósito da regra acima em
   especificidade, não depende de ordem no arquivo. */
.st-th-label.st-th-label-locked {
    max-width: none;
    overflow: visible;
    text-overflow: clip;
    white-space: nowrap;
}

/* "Coluna divisória" — mesma ideia do legado (`class="between"`): uma
   coluna estreita e vazia entre os grupos "base"/"Total"/"Período" de
   Análise Projeto e Análise Projeto Resumido, só pra dar a impressão de
   duas tabelas coladas lado a lado em vez de uma tabela só corrida. */
.rf-th-spacer,
.rf-td-spacer {
    width: 14px;
    max-width: 14px;
    min-width: 14px;
    padding: 0 !important;
    background: var(--color-bg);
    /* Sem borda — precisa ler como um VÃO de verdade entre as tabelas
       "coladas", não só mais uma coluna com fundo diferente cortada por
       uma linha (o que fazia parecer quebrado, não uma divisão de
       propósito). */
    border-bottom: none !important;
    border-left: none !important;
    border-right: none !important;
}

/* Rótulo de grupo ("Total"/"Período") — 1ª linha do cabeçalho de 2 linhas
   de Análise Projeto/Resumido, cobrindo via colspan as colunas do grupo
   (ver `.st-header-row`/`smart-table.js`, que ignora essa linha por
   completo — é só decorativa). Fundo sólido pra ficar claramente um
   "banner" acima das colunas, não mais um cabeçalho comum. */
.table > thead > tr.rf-th-group-row > th {
    border-bottom: 1px solid var(--color-border);
    padding-top: .35rem;
    padding-bottom: .35rem;
}

/* Precisa da mesma especificidade de `.table > thead > tr > th` (mais
   específica que uma classe sozinha) pra vencer o `background: transparent`
   genérico de todo cabeçalho — sem isso o banner ficava sem cor nenhuma. */
.table > thead > tr > th.rf-th-group {
    text-align: left;
    padding-left: .6rem;
    text-transform: uppercase;
    letter-spacing: .03em;
    font-size: .78rem;
    font-weight: 700;
    color: #fff;
    background: var(--color-brand);
    border-radius: .3rem;
}

.table > tbody > tr > td,
.table > tfoot > tr > td {
    color: var(--color-text);
    border-bottom: 1px solid var(--color-border);
    vertical-align: middle;
    white-space: nowrap;
    max-width: var(--cell-max-width, 24rem);
    overflow: hidden;
    text-overflow: ellipsis;
}

/* `max-width` continua vindo de `--cell-max-width` (CELL_MAX_WIDTH) mesmo
   com quebra ligada — antes virava `none` aqui, ignorando por completo o
   valor configurado: a coluna só tomava a largura NATURAL do texto já
   quebrado (medida ainda mais estreita, já que quebrar em várias linhas
   deixa cada linha mais curta), resultando em colunas finas e MUITO altas
   em vez de largas como CELL_MAX_WIDTH pedia. Agora é a MESMA largura do
   modo sem quebra — só troca truncar com reticências por quebrar linha. */
.table.st-cell-wrap > tbody > tr > td,
.table.st-cell-wrap > tfoot > tr > td {
    white-space: normal;
    word-break: break-word;
    max-width: var(--cell-max-width, 24rem);
    overflow: visible;
    text-overflow: clip;
}

/* Coluna marcada com `.text-truncate` (ex.: Descrição em Aprovar OS) fica
   de FORA da quebra de linha do CELL_WRAP_ENABLED, mesmo com a tabela
   inteira quebrando — faz mais sentido ela continuar 1 linha só com
   reticências (uma descrição de milhares de caracteres quebrada estufaria
   a altura da linha inteira), com o botão de "ver descrição completa" já
   existente cobrindo o caso de querer ler tudo. Precisa da classe extra
   (`.text-truncate`) na seletor pra ganhar em especificidade da regra
   acima, que senão venceria e ignoraria esse `.text-truncate` sozinho. */
.table.st-cell-wrap > tbody > tr > td.text-truncate,
.table.st-cell-wrap > tfoot > tr > td.text-truncate {
    white-space: nowrap;
    word-break: normal;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Toggle da coluna Descrição (ícone no cabeçalho) — Relatórios > Projetos >
   Apontamentos, Relatórios > OS e Apontamentos > Aprovar OS. Independente
   do CELL_WRAP_ENABLED da tabela (funciona nos 2 estados, wrap ligado ou
   desligado, por isso usa o id de cada tabela pra ganhar de especificidade
   das 2 regras gerais de truncamento). Adicionar uma tabela nova a este
   toggle é só somar o `#idDaTabela` nos seletores abaixo (mesma classes
   `rp-desc-toggle`/`rp-desc-cell`/`rp-desc-expanded`, nenhum CSS novo por
   tela). */
#rpTable .rp-desc-toggle,
#reportsOsTable .rp-desc-toggle,
#approveOsTable .rp-desc-toggle {
    cursor: pointer;
    color: var(--color-text-muted);
    font-size: .85rem;
    margin-left: .25rem;
}

#rpTable .rp-desc-toggle:hover,
#reportsOsTable .rp-desc-toggle:hover,
#approveOsTable .rp-desc-toggle:hover {
    color: var(--color-text);
}

/* Descrição fica 50% mais larga que as outras colunas por padrão (visão
   compacta) — proporcional ao CELL_MAX_WIDTH configurado pra CADA tela
   (--cell-max-width vem de admin > preferências do sistema, uma seção por
   tabela), nunca um valor fixo, então continua respeitando o que o admin
   ajustar em cada uma. */
#rpTable td.rp-desc-cell,
#reportsOsTable td.rp-desc-cell,
#approveOsTable td.rp-desc-cell {
    max-width: calc(var(--cell-max-width, 24rem) * 1.5);
}

/* Mesmo raciocínio, pra Cliente/Projeto/Tarefa em Relatórios > OS e
   Apontamentos > Aprovar OS — nomes de cliente/projeto costumam ser mais
   longos que o teto padrão (confirmado: já truncavam batendo exatamente no
   CELL_MAX_WIDTH configurado), sem uma coluna "principal" só (ao contrário
   de Projetos, que já filtra por 1 cliente/projeto só e não repete essas
   colunas por linha). */
#reportsOsTable td.rp-wide-cell,
#approveOsTable td.rp-wide-cell {
    max-width: calc(var(--cell-max-width, 24rem) * 1.5);
}

#rpTable.rp-desc-expanded td.rp-desc-cell,
#reportsOsTable.rp-desc-expanded td.rp-desc-cell,
#approveOsTable.rp-desc-expanded td.rp-desc-cell {
    /* `pre-wrap` (não `normal`) — preserva as quebras de linha originais do
       texto (o backend manda a descrição crua, sem nl2br, só htmlspecialchars
       — que não mexe em quebra de linha) além de quebrar linha longa. */
    white-space: pre-wrap;
    word-break: break-word;
    overflow: visible;
    text-overflow: clip;
    max-width: none;
}

/* Sombra nas bordas de QUALQUER tabela com scroll horizontal — só quando
   há mais conteúdo pra rolar naquele lado (`assets/js/scroll-shadow.js`
   liga/desliga as 2 classes conforme `scrollLeft`/`scrollWidth`). Puro
   indicador visual, não muda como a rolagem funciona (o navegador já rola
   horizontal nativamente com Shift+roda do mouse). */
.table-responsive {
    position: relative;
}

.table-responsive.has-scroll-shadow-right {
    box-shadow: inset -8px 0 6px -8px color-mix(in srgb, var(--color-text) 24%, transparent);
}

.table-responsive.has-scroll-shadow-left {
    box-shadow: inset 8px 0 6px -8px color-mix(in srgb, var(--color-text) 24%, transparent);
}

.table-responsive.has-scroll-shadow-left.has-scroll-shadow-right {
    box-shadow:
        inset 8px 0 6px -8px color-mix(in srgb, var(--color-text) 24%, transparent),
        inset -8px 0 6px -8px color-mix(in srgb, var(--color-text) 24%, transparent);
}

/* Linha de usuário que o perfil logado não pode gerenciar (ex.: Gestor de
   Contas Adm tentando abrir um Administrador) — Configurações > Usuários.
   Antes clicava e "não acontecia nada" (o backend já bloqueava, redirecionando
   de volta pra listagem sem aviso nenhum) — agora a linha já nasce visualmente
   desabilitada, com o ícone de cadeado explicando o motivo (title/tooltip). */
.user-row-locked {
    opacity: .55;
    cursor: not-allowed;
}

.table-hover > tbody > tr.user-row-locked:hover > * {
    background-color: transparent;
}

.table-hover > tbody > tr:hover > * {
    background-color: color-mix(in srgb, var(--color-text) 6%, transparent);
    color: var(--color-text);
}

/* Início de um novo grupo (ex.: próximo Operador em Análise Equipe OS,
   onde as colunas do operador só aparecem 1 vez e ficam em branco nas
   linhas de tarefa seguintes) — só uma borda um pouco mais forte no topo,
   pra separar visualmente um grupo do outro sem precisar de rowspan
   (que impediria ordenar/filtrar linha a linha). */
.table > tbody > tr.rf-group-start > td {
    border-top: 2px solid var(--color-border);
}

/* Célula de uma coluna agrupada (ex.: Operador em Análise Equipe OS) numa
   linha que NÃO é a 1ª do grupo — o valor real continua no DOM (pro filtro
   de coluna/busca geral do SmartTable, que lê `textContent`, encontrar a
   linha certa), só escondido visualmente. `visibility: hidden` (não
   `display: none`) pra manter a altura da célula igual às demais. */
.rf-group-repeat {
    visibility: hidden;
}

/* Primeira coluna fixa ao rolar horizontalmente — útil nas tabelas de
   Relatórios > Financeiros, que chegam a ter mais de 50 colunas (mesmo
   comportamento do legado). Fica opaca mesmo no hover (regra depois da
   `.table-hover` acima), senão o conteúdo rolado por baixo apareceria
   through o tom semi-transparente do hover. */
.table > thead > tr > th:first-child,
.table > tbody > tr > td:first-child,
.table > tfoot > tr > td:first-child {
    position: sticky;
    left: 0;
    z-index: 2;
    background-color: var(--color-surface);
    /* Tampa uma possível fresta de 1-2px na borda direita da coluna fixa
       (arredondamento de sub-pixel entre a largura travada em JS e a
       posição real do sticky) — sem isso, o conteúdo rolando por baixo
       (o banner "Total"/"Período", cor forte) pode vazar uma linha fina
       bem na emenda, dando a impressão de estar "na frente" da coluna
       fixa. Mesma cor do fundo da própria coluna, só estende visualmente
       sem mudar layout/largura. */
    box-shadow: 2px 0 0 0 var(--color-surface);
}

.table > thead > tr > th:first-child {
    z-index: 3;
}

/* A coluna fixa acima tem `background-color` fixo (precisa ficar opaca,
   nunca semi-transparente, pra tampar o conteúdo rolando por baixo dela) —
   isso também a deixa com MAIS seletores de elemento (table/tbody/tr/td)
   que a regra genérica de hover (`.table-hover > tbody > tr:hover > *`),
   então vence por especificidade mesmo vindo antes no arquivo, e a coluna
   fixa nunca acompanhava o hover da linha (parecia "apagada"/sem reação).
   Mistura o mesmo tom de hover, mas sobre `--color-surface` (em vez de
   `transparent`) — continua 100% opaca, só muda de cor. */
.table-hover > tbody > tr:hover > td:first-child {
    background-color: color-mix(in srgb, var(--color-text) 6%, var(--color-surface));
    color: var(--color-text);
}

/* A 1ª célula da linha decorativa de grupo (`.rf-th-group-row`) agora é
   SEMPRE colspan=1 (ver reports_financials.js), do mesmo tamanho da coluna
   fixa de verdade — então a regra `:first-child` acima faz exatamente o
   que precisa aqui: fica opaca e fixa nessa faixa, bloqueando o banner
   "Total"/"Período" de vazar por cima da coluna fixa ao rolar. Antes essa
   célula cobria ~24 colunas via colspan e a regra genérica virava um
   retângulo STICKY enorme tampando os próprios banners — por isso tinha
   sido desativada aqui; já não é mais o caso. */

/* `scroll-snap` foi tentado nesta sessão (pra nunca parar o scroll no
   MEIO de uma coluna) e REMOVIDO de novo: mesmo só marcando alguns pontos
   como "parada limpa", qualquer distância grande sem ponto de parada no
   meio vira uma ZONA MORTA — `proximity` sempre puxa de volta pro ponto
   de parada mais próximo, então rolar um pouco (querendo avançar) na
   prática não movia NADA (voltava pro início), sentido como scroll
   "automático"/travado. Como isso é PIOR que o artefato cosmético que
   tentava resolver (uma coluna raramente mostrando só as reticências do
   título, ao parar de rolar bem no meio dela — comportamento normal/
   inevitável de qualquer coluna `position:sticky`, não um bug de
   verdade), a solução foi voltar a deixar o scroll 100% livre. */

/* ---------- Tela inicial (Início) ---------- */

.dashboard-greeting {
    padding: .5rem 0 1.5rem;
}

.dashboard-greeting h4 {
    margin-bottom: .25rem;
}

.dashboard-cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: .75rem;
}

.dashboard-card {
    display: flex;
    align-items: flex-start;
    gap: .75rem;
    padding: .85rem 1rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    color: var(--color-text);
    text-decoration: none;
    background: var(--color-surface);
    transition: border-color .15s ease, background-color .15s ease;
}

.dashboard-card:hover {
    border-color: var(--color-brand);
    background: var(--color-brand-soft);
    color: var(--color-text);
}

.dashboard-card i {
    font-size: 1.35rem;
    color: var(--color-brand);
    flex-shrink: 0;
    margin-top: .1rem;
}

.dashboard-card strong {
    display: block;
    margin-bottom: .15rem;
}

.dashboard-card p {
    margin: 0;
    font-size: .82rem;
    color: var(--color-text-muted);
}

/* Rodapé institucional — mesmo conteúdo/estrutura do `portalnoc-v2`
   (projeto irmão), adaptado pros ícones já usados aqui (Bootstrap Icons
   em vez de SVG inline próprio). */
.dashboard-footer {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 1rem;
}

.dashboard-footer-logo {
    height: 5rem;
    width: auto;
}

.dashboard-footer-social {
    display: flex;
    gap: 1rem;
}

.dashboard-footer-social a {
    color: var(--color-text-muted);
    font-size: 1.35rem;
    display: inline-flex;
}

.dashboard-footer-social a:hover {
    color: var(--color-brand);
}

.dashboard-footer-info {
    margin: 0;
    font-size: .8125rem;
    color: var(--color-text-muted);
}

.dashboard-footer-info p {
    margin: 0 0 .25rem;
}

.dashboard-footer-info p:last-child {
    margin-bottom: 0;
}

.dashboard-footer-info a {
    color: var(--color-text-muted);
}

.dashboard-footer-info a:hover {
    color: var(--color-brand);
}

.dashboard-footer-badges {
    display: flex;
    align-items: center;
    gap: 1.5rem;
    flex-wrap: wrap;
    justify-content: center;
}

.dashboard-footer-gptw,
.dashboard-footer-totvs {
    height: 3.5rem;
    width: auto;
}

.placeholder-block {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 3.5rem 1rem;
    color: var(--color-text-muted);
}

.placeholder-block i {
    font-size: 2.4rem;
    color: var(--color-brand);
    margin-bottom: 1rem;
}

/* ---------- Seletor de tema / densidade (tela de Preferências) ---------- */

.theme-swatch {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .55rem;
    cursor: pointer;
}

.theme-swatch-color {
    width: 3rem;
    height: 3rem;
    border-radius: .65rem;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .08);
    outline: 2px solid transparent;
    outline-offset: 3px;
    transition: outline-color .15s ease, transform .15s ease;
    color: #fff;
    font-size: 1.1rem;
}

.theme-swatch:hover .theme-swatch-color {
    transform: translateY(-1px);
}

.theme-swatch.active .theme-swatch-color {
    outline-color: var(--color-brand);
}

.theme-swatch-color i {
    opacity: 0;
    transition: opacity .15s ease;
}

.theme-swatch.active .theme-swatch-color i {
    opacity: 1;
}

.theme-swatch span.label {
    font-size: .85rem;
    font-weight: 500;
    color: var(--color-text-muted);
}

.theme-swatch.active span.label {
    color: var(--color-text);
    font-weight: 600;
}

.density-option {
    border: 2px solid var(--color-border);
    border-radius: .55rem;
    padding: 1rem;
    text-align: center;
    cursor: pointer;
    transition: border-color .15s ease;
}

.density-option.active {
    border-color: var(--color-brand);
    background: var(--color-brand-soft);
}

.density-option .bi {
    font-size: 1.4rem;
    color: var(--color-text-muted);
    margin-bottom: .4rem;
    display: block;
}

.density-option.active .bi {
    color: var(--color-brand);
}

@media (max-width: 991.98px) {
    .sidebar {
        width: var(--sidebar-width-collapsed);
    }
    .nav-group-label span,
    .nav-link span,
    .sidebar-user-info {
        opacity: 0;
        max-width: 0;
    }
    .nav-group-label,
    .nav-link {
        justify-content: center;
        padding-left: 0;
        padding-right: 0;
        gap: 0;
    }
    /* `.sidebar-nav > .nav-link` (Início) tem 2 classes de especificidade —
       mais que o `.nav-link` sozinho logo acima, que por isso NUNCA vencia
       aqui (o `padding-left: .75rem` de sempre continuava valendo, mesmo
       dentro deste breakpoint), descentralizando só o ícone do Início. */
    .sidebar-nav > .nav-link {
        padding-left: 0;
    }
    .sidebar-brand {
        justify-content: center;
        padding: 0;
    }
    .nav-group-label .chevron {
        opacity: 0;
        max-width: 0;
        margin-left: 0;
    }
    .nav-sublist {
        max-height: 0 !important;
    }
    .sidebar-user-toggle {
        justify-content: center;
        gap: 0;
    }
    .user-menu-dropdown {
        left: calc(100% + .25rem);
        right: auto;
        bottom: .75rem;
        width: 13rem;
    }
    .main {
        margin-left: var(--sidebar-width-collapsed);
    }
    .sidebar.mobile-expanded {
        width: var(--sidebar-width);
    }
    .sidebar.mobile-expanded .nav-group-label span,
    .sidebar.mobile-expanded .nav-link span,
    .sidebar.mobile-expanded .sidebar-user-info {
        opacity: 1;
        max-width: 12rem;
    }
    .sidebar.mobile-expanded .nav-group-label,
    .sidebar.mobile-expanded .nav-link {
        justify-content: flex-start;
        padding-right: .75rem;
    }
    .sidebar.mobile-expanded .nav-group-label {
        padding-left: .75rem;
    }
    /* Recuo dos itens DENTRO de um grupo (ex.: "OS"/"Aprovar OS" dentro de
       "Apontamentos") — sem isso ficam achatados no mesmo nível dos rótulos
       de grupo (o breakpoint estreito zera o padding-left de todo
       `.nav-link` pra centralizar ícone no modo só-ícone; expandir de novo
       via toque nunca devolvia esse recuo). Mesmo valor (`2.4rem`) do modo
       desktop expandido. "Início" (irmão direto de `.sidebar-nav`, não um
       item DENTRO de grupo) continua no recuo raso de sempre. */
    .sidebar.mobile-expanded .nav-link {
        padding-left: 2.4rem;
    }
    .sidebar.mobile-expanded .sidebar-nav > .nav-link {
        padding-left: .75rem;
    }
    .sidebar.mobile-expanded .sidebar-brand {
        justify-content: flex-start;
        padding: 0 1.25rem;
    }
    .sidebar.mobile-expanded .sidebar-user-toggle {
        justify-content: flex-start;
        gap: .65rem;
    }
    .sidebar.mobile-expanded .nav-group-label .chevron {
        opacity: 1;
        max-width: 1rem;
        margin-left: auto;
    }
    .sidebar.mobile-expanded .nav-group.open .nav-sublist {
        max-height: 400px !important;
    }
    .sidebar.mobile-expanded .user-menu-dropdown {
        left: 1rem;
        right: 1rem;
        bottom: calc(100% + 6px);
        width: auto;
    }
}

/* ---------- Notificações (toasts) — info / sucesso / erro ----------
   Superfície própria (não segue as cores específicas da tela), com texto e
   ícone tingidos na cor do tipo. No modo escuro (temas Escuro/Azul/Cinza)
   usa uma superfície escura elevada; no modo claro (Padrão) usa um tom
   pastel leve — cada um "pertence" ao seu grupo claro/escuro. */

.app-toast {
    border: 1px solid;
    border-radius: .6rem;
    box-shadow: 0 8px 24px rgba(0, 0, 0, .22);
    min-width: 20rem;
}

.app-toast .toast-body {
    font-size: .88rem;
    font-weight: 500;
}

.app-toast .btn-close {
    opacity: .6;
}

/* Modo escuro (Escuro/Azul/Cinza) */
:root[data-bs-theme="dark"] .app-toast {
    box-shadow: 0 8px 24px rgba(0, 0, 0, .35);
}

:root[data-bs-theme="dark"] .app-toast .btn-close {
    filter: invert(1) grayscale(100%) brightness(200%);
    opacity: .7;
}

:root[data-bs-theme="dark"] .app-toast-info {
    background: #1c2430;
    border-color: #2f3947;
    color: #c3ccd9;
}

:root[data-bs-theme="dark"] .app-toast-info .bi {
    color: #8fa2b8;
}

:root[data-bs-theme="dark"] .app-toast-success {
    background: #12271b;
    border-color: #1f4a2c;
    color: #a8e6bc;
}

:root[data-bs-theme="dark"] .app-toast-success .bi {
    color: #4ade80;
}

:root[data-bs-theme="dark"] .app-toast-error {
    background: #2c1618;
    border-color: #4c2528;
    color: #f2b8b5;
}

:root[data-bs-theme="dark"] .app-toast-error .bi {
    color: #f87171;
}

/* Modo claro (Padrão) */
:root[data-bs-theme="light"] .app-toast-info {
    background: #eef2f6;
    border-color: #cbd5e1;
    color: #334155;
}

:root[data-bs-theme="light"] .app-toast-info .bi {
    color: #64748b;
}

:root[data-bs-theme="light"] .app-toast-success {
    background: #e7f8ee;
    border-color: #a7e3bb;
    color: #0f5132;
}

:root[data-bs-theme="light"] .app-toast-success .bi {
    color: #16a34a;
}

:root[data-bs-theme="light"] .app-toast-error {
    background: #fbe9e9;
    border-color: #f1b3b3;
    color: #7a1f1f;
}

:root[data-bs-theme="light"] .app-toast-error .bi {
    color: #dc3545;
}

/* ---------- SmartTable (paginação/ordenação/filtro/busca) ---------- */

.st-sortable {
    user-select: none;
    position: relative;
    padding-right: 1.4rem !important;
}

.st-sort-indicator {
    position: absolute;
    right: .4rem;
    top: 50%;
    transform: translateY(-50%);
    font-size: .7rem;
    color: var(--color-border);
}

.st-sort-indicator.bi-caret-up-fill,
.st-sort-indicator.bi-caret-down-fill {
    color: var(--color-brand);
}

.st-filter-icon {
    background: none;
    border: none;
    padding: 0;
    margin-left: .4rem;
    font-size: .85rem;
    color: var(--color-text-muted);
    vertical-align: middle;
    line-height: 1;
}

.st-filter-icon:hover {
    color: var(--color-text-muted);
}

.st-filter-icon.active {
    color: var(--color-brand);
}

.st-filter-popover {
    display: none;
    /* `fixed`, não `absolute` — o popover vive em `document.body` (não
       dentro do <th>), posicionado via JS (`top`/`left` inline, ver
       `SmartTable.prototype._positionPopover`) pra escapar do clipping do
       `.table-responsive` (ver comentário em `smart-table.js`). */
    position: fixed;
    z-index: 1050;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: .5rem;
    box-shadow: var(--shadow-md);
    padding: .75rem;
    width: 15rem;
    text-transform: none;
    letter-spacing: normal;
    font-weight: 400;
    font-size: .85rem;
    cursor: default;
}

.st-filter-popover.show {
    display: block;
}

.st-filter-popover-check {
    display: flex;
    align-items: center;
    gap: .4rem;
    margin-top: .55rem;
    font-size: .8rem;
    color: var(--color-text-muted);
    font-weight: 400;
    cursor: pointer;
}

.st-filter-icon.negated {
    color: #dc3545;
}

.st-filter-popover-actions {
    display: flex;
    justify-content: flex-end;
    gap: .4rem;
    margin-top: .65rem;
}

/* Título breve e descritivo no topo de cada aba de Relatórios > Financeiros
   (acima do filtro) — o nome da aba já aparece na barra de abas; este título
   explica o QUE o relatório mostra (ex.: período de referência, escopo). */
.rf-report-title {
    color: var(--color-text-muted);
    font-weight: 500;
    font-size: .85rem;
    margin-bottom: .25rem;
}

/* 2ª linha, opcional (`CRITERIA`, Lote 80) — menor/mais discreta que o
   título, explica o PRÉ-REQUISITO pra um registro aparecer nesta aba (ex.:
   "só Tarefa com Monitora Consumo = Sim"). Editável na mesma seção do
   título em Admin > Preferências do Sistema. */
.rf-report-criteria {
    color: var(--color-text-muted);
    font-size: .78rem;
    opacity: .8;
    margin: 0 0 1rem;
}

/* ---------- Relatórios Financeiros: filtro em cascata Cliente/Projeto/Tarefa,
   um embaixo do outro (label com largura fixa), igual ao legado ---------- */

.rf-cascade-row {
    display: flex;
    align-items: center;
    gap: .75rem;
    margin-bottom: .75rem;
}

.rf-cascade-label {
    width: 90px;
    flex-shrink: 0;
    margin-bottom: 0;
}

/* ---------- Dropdown multiselect (checklist recolhida por padrão) ---------- */

.rf-multiselect {
    position: relative;
    max-width: 340px;
}

/* Placeholder de "Selecione ao menos um X.../Carregando..." dos filtros em
   cascata (Projetos/Tarefas antes do pai ser escolhido) — usa a classe
   `.form-select` só pela borda/aparência (não é um select de verdade), por
   isso tira a setinha de dropdown que viria de graça com a classe. */
.rf-cascade-placeholder {
    max-width: 340px;
    background-image: none;
    cursor: default;
    /* MESMO padding de `.rf-multiselect-toggle` (o dropdown já ativo/
       preenchido) — bug real reportado: sem isso, o placeholder ficava
       ~4px mais baixo (padding padrão do Bootstrap, `.375rem`) que o
       dropdown real (`.5rem`), então o campo "crescia" alguns pixels
       assim que deixava de ser placeholder (ex.: Cliente escolhido,
       Projeto vira select de verdade) — empurrando tudo abaixo dele
       (Tarefas, Período) de leve, dando a impressão de "a tela mexeu". */
    padding-top: .5rem;
    padding-bottom: .5rem;
}

/* Mês/Ano do filtro "Período", 50/50 dividindo a mesma largura máxima do
   dropdown de Clientes/Projetos logo acima (.rf-multiselect/
   .rf-cascade-placeholder) — pra os dois ficarem visualmente do mesmo
   tamanho combinado do filtro de cima, em vez de cada select ficar só do
   tamanho do próprio texto. */
.rf-period-group {
    display: flex;
    gap: .5rem;
    max-width: 340px;
    width: 100%;
}

.rf-period-group .form-select {
    flex: 1 1 0;
    min-width: 0;
}

/* Relatórios > Projetos: o card de Filtros é bem mais largo (col-lg-6,
   ~metade da tela) que o contexto original de 340px pensado pra outras
   telas (Aprovar OS/Financeiros, cards mais estreitos) — sem soltar essa
   largura MÁXIMA aqui, Cliente/Projeto/Tarefas ficavam visivelmente mais
   estreitos que "Período" (De+Até, que já usa `flex-grow` real, sem teto
   nenhum), quebrando a simetria entre os 4 filtros que o próprio usuário
   pediu. */
#reportsProjectsFilterForm .rf-multiselect,
#reportsProjectsFilterForm .rf-cascade-placeholder {
    max-width: none;
    width: 100%;
}

/* Mesma ideia acima, agora pro modal "Novo Apontamento" (Apontamentos >
   OS) — `modal-lg` é bem mais largo que o teto de 340px pensado pra
   outras telas, sobrando bastante espaço vazio à direita de Operador/
   Cliente/Projeto/Tarefa (pedido do usuário: usar 100% do espaço). */
#osForm .rf-multiselect,
#osForm .rf-cascade-placeholder {
    max-width: none;
    width: 100%;
}

/* Mesma tela: como sobra bastante espaço vertical (o card de Filtros é o
   único conteúdo até clicar "Ver Resultados"), o menu pode mostrar bem
   mais itens sem precisar rolar tão cedo — 16rem (padrão, pensado pra
   menus mais compactos noutras telas) virava só 5-6 linhas visíveis numa
   lista de 80+ clientes. */
#reportsProjectsFilterForm .rf-multiselect-menu {
    max-height: 24rem;
}

/* Padding um pouco maior que o padrão do Bootstrap (`.375rem` topo/baixo)
   — o `<select>` nativo do navegador costuma renderizar um pouco mais
   "alto" que isso na prática (variação de chrome nativo do SO entre
   navegadores, que nem sempre bate 1:1 com o box model do CSS); como
   esse toggle é um `<button>` fingindo de `<select>`, sem nenhum chrome
   nativo pra "encher", ficava sistematicamente menor que os `<select>`
   de verdade ao lado (ex.: "Pesquisar") em telas normais. */
.rf-multiselect-toggle {
    width: 100%;
    text-align: left;
    /* Mesmo token que `.form-select` (select nativo) usa — sem isso, ficava
       igual à cor do `.card-panel` onde o filtro mora, "sumindo" visualmente
       (bug real reportado pelo usuário: dropdown customizado sem contraste
       nenhum contra o fundo do card, diferente de qualquer select nativo ao
       lado dele). Não mexe em `.rf-multiselect-disabled` logo abaixo — esse
       usa `--color-surface` de propósito, mesmo padrão "esmaecido" que
       `fieldset:disabled .form-select` já usa pra campo desabilitado. */
    background-color: var(--color-bg);
    padding-top: .5rem;
    padding-bottom: .5rem;
}

/* Mesmo visual "esmaecido" de `.form-control:disabled` já usado em
   qualquer outro campo travado do app — o `<button>` do toggle já vira
   não-clicável sozinho via `disabled` nativo (`SingleSelectDropdown.
   setDisabled()`), essa classe só cuida da aparência. */
.rf-multiselect-disabled .rf-multiselect-toggle {
    background-color: var(--color-surface);
    color: var(--color-text-muted);
    opacity: .6;
}

/* Largura "padrão" = mesma do toggle/select pai (min-width:100%, resolvido
   contra `.rf-multiselect`, o ancestral posicionado mais próximo — 340px);
   só cresce ALÉM disso quando o conteúdo pedir (`width:max-content`, rótulos
   "Cliente > Projeto > Tarefa" nos níveis com hierarquia costumam ser bem
   mais longos que 340px) — nunca um tamanho maior FIXO. `max-width` trava o
   quanto pode crescer, pra 1 rótulo absurdamente longo não esticar o menu
   sem limite. `left:0` sozinho (sem `right:0`) ancora pela esquerda,
   independente da largura final do menu. */
.rf-multiselect-menu {
    position: absolute;
    top: 100%;
    left: 0;
    min-width: 100%;
    width: max-content;
    max-width: min(720px, 90vw);
    /* Sem `margin-top` de propósito — o vão entre o toggle e o menu ficava
       FORA da área de hover de ambos (mouseleave disparava assim que o
       mouse cruzava esse espaço pra descer até o menu, fechando antes de
       dar tempo de chegar nele). Encostado, o cursor nunca "sai" da área
       coberta ao descer do toggle pro menu. */
    margin-top: 0;
    z-index: 1050;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: .5rem;
    box-shadow: var(--shadow-md);
    /* Era 16rem (só uns 5 itens visíveis antes de rolar) — pedido do
       usuário, sobra espaço vertical de sobra na tela pra maioria dos
       casos. `min(...vh)` mantém um teto relativo à viewport (nunca
       estoura pra fora da tela em janelas mais baixas), só que bem mais
       generoso que o valor fixo de antes. */
    max-height: min(32rem, 70vh);
    /* `flex-direction:column` + `.rf-multiselect-menu-fixed`/`-scroll` como
       filhos: busca/Todos/Exibe Inativos ficam fixos no topo e só a lista de
       itens rola, ao invés do menu inteiro (pedido do usuário — perder de
       vista os checkboxes de topo ao rolar uma lista grande era ruim). */
    display: none;
    flex-direction: column;
}

.rf-multiselect-menu.show {
    display: flex;
}

.rf-multiselect-menu-fixed {
    flex-shrink: 0;
    padding: .5rem .5rem 0;
}

.rf-multiselect-menu-scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: .5rem;
}

/* Checkbox + rótulo (+ badge) desalinhados verticalmente: o Bootstrap
   centraliza o checkbox via `margin-top: .25em` (matemática calibrada
   pro tamanho PADRÃO do checkbox, ~1em); como `.form-check-input` foi
   aumentado pra 1.15rem noutro ajuste desta sessão, essa conta ficou
   desatualizada — sobrava ~1px a mais embaixo (medido via
   `getBoundingClientRect()`: centro do checkbox ~1px abaixo do centro
   do rótulo). Passar `.form-check` (cabeçalho E itens da lista) pra
   flexbox com `align-items:center` resolve de vez, sem depender de
   nenhuma conta em em/rem — centraliza checkbox/rótulo/badge um em
   relação ao outro sempre, não importa o tamanho de fonte ou do
   checkbox. Isso também troca a estratégia de alinhamento horizontal:
   antes o checkbox usava a margem negativa do Bootstrap
   (`margin-left:-1.5em`) puxado de volta pro `padding-left` do
   container; com flex isso não existe mais, então o `padding-left`
   dos itens/`.rf-todos-check` abaixo foi recalculado pro mesmo
   respiro visual final (sem a margem negativa no meio da conta).
   `.rf-todos-check` (no "Todos") recebe o mesmo `padding-left`
   recalculado dos itens da lista logo abaixo, pra alinhar os dois
   grupos verticalmente. */
.rf-multiselect-header .form-check,
.rf-multiselect-menu-scroll .form-check {
    display: flex;
    align-items: center;
    gap: .4rem;
}

.rf-multiselect-header .form-check .form-check-input,
.rf-multiselect-menu-scroll .form-check .form-check-input {
    float: none;
    margin: 0;
}

.rf-multiselect-header .form-check .form-check-label,
.rf-multiselect-menu-scroll .form-check .form-check-label {
    margin-bottom: 0;
}

/* Itens da lista mais espaçados (pedido do usuário — "bem apertados"
   antes), só dentro da área que rola de fato, não no cabeçalho fixo. */
.rf-multiselect-menu-scroll .form-check {
    padding-top: .2rem;
    padding-bottom: .2rem;
    padding-left: .35rem;
    border-radius: .3rem;
}

.rf-multiselect-menu-scroll .form-check:hover {
    background-color: var(--color-brand-soft);
}

.rf-multiselect-menu-scroll .form-check:not(:last-child) {
    margin-bottom: .1rem;
}

/* "Todos" (cabeçalho fixo) recebe o MESMO `padding-left` dos itens da
   lista logo abaixo — sem isso, o checkbox de "Todos" fica mais à
   esquerda que os checkboxes da lista, quebrando o alinhamento vertical
   entre os dois grupos. */
.rf-todos-check {
    padding-left: .35rem;
}

/* "Todos" + "Exibe Inativos" lado a lado na mesma linha, no topo do menu —
   "Exibe Inativos" é um ajuste pontual, não precisa da mesma linha/destaque
   que "Todos" tinha antes (pedido do usuário). */
.rf-multiselect-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
}

/* `SingleSelectDropdown` não tem "Todos" pra dividir a linha com "Exibe
   Inativos" via `space-between` (só 1 filho sempre vai pro INÍCIO da
   linha nesse caso) — este modificador força ele pro lado direito mesmo
   sozinho, mesma posição visual de sempre. */
.rf-multiselect-header.rf-header-end {
    justify-content: flex-end;
}

/* Item de um `SingleSelectDropdown` (Relatórios > Projetos: Cliente/
   Projeto) — mesmo menu/visual do dropdown-checklist de múltipla escolha,
   só que cada linha é um botão que já seleciona e fecha ao clicar, sem
   checkbox (o valor só pode ser 1 por vez). */
.rf-select-item {
    display: block;
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    border-radius: .3rem;
    padding: .35rem .75rem;
    color: var(--color-text);
    white-space: nowrap;
}

.rf-select-item:hover {
    background-color: var(--color-brand-soft);
}

.rf-multiselect-menu-scroll .rf-select-item:not(:last-child) {
    margin-bottom: .1rem;
}

.st-pagination {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-top: 1rem;
    flex-wrap: wrap;
}

.st-pagination-info {
    font-size: .82rem;
    color: var(--color-text-muted);
}

.st-pagination-nav {
    display: flex;
    align-items: center;
    gap: .5rem;
}

.st-pagination-page {
    font-size: .85rem;
    color: var(--color-text);
    min-width: 3.5rem;
    text-align: center;
}

.st-page-size {
    width: auto;
}

/* ---------- Usuários > Acesso a Clientes (link de projetos) ---------- */

.access-client-projects-btn {
    color: var(--color-text);
    border-bottom: 1px dashed var(--color-text-muted);
}

.access-client-projects-btn:hover {
    color: var(--color-brand);
    border-bottom-color: var(--color-brand);
}

/* ---------- Configurações > Relatórios (toggle "somente selecionados") ---------- */

/* O estado .active padrão do Bootstrap (troca só o background por
   --bs-btn-active-bg) fica sutil demais pra indicar "ligado/desligado" —
   aqui usa a cor de marca, igual a outros estados "ativo" do app. */
.js-recipient-toggle-selected.active {
    background: var(--color-brand) !important;
    border-color: var(--color-brand) !important;
    color: #fff !important;
}

/* Linhas de escopo (Acesso a Clientes/Projetos + busca) em grid: a coluna do
   grupo de botões usa max-content (não estica, fica compacta como antes); a
   busca ocupa as duas colunas por baixo, então sua largura total acompanha a
   largura combinada de label+botões em vez de um max-width fixo. */
.access-scope-grid {
    display: grid;
    grid-template-columns: 9rem max-content;
    column-gap: 1rem;
    row-gap: 0.75rem;
    align-items: center;
}

.access-scope-grid > .access-scope-search {
    grid-column: 1 / -1;
    width: 100%;
    min-width: 0;
}

/* ---------- Admin > Preferências do Sistema ---------- */

.setting-key {
    font-family: 'SFMono-Regular', Consolas, monospace;
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .02em;
    color: var(--color-text-muted);
}

/* ---------- Modal (theme-aware — o Bootstrap usa um cinza genérico fixo
   no modo escuro, sem relação com a cor de superfície de cada tema) ---------- */

.modal-content {
    background-color: var(--color-surface);
    color: var(--color-text);
    border-color: var(--color-border);
}

.modal-header,
.modal-footer {
    border-color: var(--color-border);
}

.modal-title {
    color: var(--color-text);
}

/* ---------- Accordion (theme-aware) ---------- */

.accordion-item {
    background: var(--color-surface);
    border-color: var(--color-border);
    color: var(--color-text);
}

.accordion-button {
    background: var(--color-surface) !important;
    color: var(--color-text) !important;
    box-shadow: none !important;
}

.accordion-button::after {
    filter: var(--accordion-icon-filter, none);
}

:root[data-bs-theme="dark"] .accordion-button::after {
    filter: invert(1) grayscale(100%) brightness(1.6);
}

.accordion-button:not(.collapsed) {
    background: var(--color-bg) !important;
    color: var(--color-brand) !important;
    border-bottom: 1px solid var(--color-border);
}

/* ---------- Acordeão discreto de modal de Tarefa (Lote 77 — nasceu só na
   Tarefa OS, estendido pra Body Shop/Produto depois) — mesmo componente
   Bootstrap, mas sem o "bloco" pesado padrão (fundo, borda em volta,
   padding grande): só o rótulo pequeno em maiúsculas + setinha ao lado +
   uma linha fina logo abaixo, no mesmo espírito do antigo
   <hr><strong>LABEL</strong> que ele substituiu. Classe `.task-accordion`
   (não um id) porque os 3 modais de Tarefa (OS/Body Shop/Produto) ficam
   todos no mesmo DOM ao mesmo tempo (3 abas da mesma tela) — cada um com
   seu próprio id de accordion, todos usando esta mesma classe. ---------- */

.task-accordion .accordion-item {
    background: transparent !important;
    border: none;
}

.task-accordion .accordion-header {
    margin-bottom: 0;
}

.task-accordion .accordion-button {
    background: transparent !important;
    box-shadow: none !important;
    padding: .25rem 0 .5rem !important;
    font-size: .75rem;
    font-weight: 600;
    letter-spacing: .02em;
    text-transform: uppercase;
    color: var(--color-text-muted) !important;
    border-bottom: 1px solid var(--color-border) !important;
    border-radius: 0 !important;
    justify-content: flex-start;
}

.task-accordion .accordion-button:not(.collapsed) {
    color: var(--color-brand) !important;
}

.task-accordion .accordion-button::after {
    width: .8rem;
    height: .8rem;
    background-size: .8rem;
    margin-left: .4rem !important;
}

.task-accordion .accordion-body {
    padding: .75rem 0 0;
}

.task-accordion .accordion-item + .accordion-item {
    margin-top: .75rem;
}

/* ---------- Barra de rolagem (theme-aware) ---------- */

* {
    scrollbar-width: thin;
    scrollbar-color: var(--color-border) transparent;
}

::-webkit-scrollbar {
    width: .65rem;
    height: .65rem;
}

::-webkit-scrollbar-track {
    background: transparent;
}

::-webkit-scrollbar-thumb {
    background: var(--color-border);
    border-radius: .35rem;
}

::-webkit-scrollbar-thumb:hover {
    background: var(--color-text-muted);
}

/* ---------- Flatpickr (calendário de data) — tema escuro. O CSS
   original do Flatpickr é só claro; nos temas Escuro/Azul/Cinza
   (data-bs-theme="dark") sobrescreve pra seguir as variáveis do tema
   ativo, senão fica um retângulo branco cru sobre a UI escura. ---------- */

:root[data-bs-theme="dark"] .flatpickr-calendar {
    background: var(--color-surface);
    box-shadow: var(--shadow-md);
}

:root[data-bs-theme="dark"] .flatpickr-calendar.arrowTop:before {
    border-bottom-color: var(--color-border);
}

:root[data-bs-theme="dark"] .flatpickr-calendar.arrowTop:after {
    border-bottom-color: var(--color-surface);
}

:root[data-bs-theme="dark"] .flatpickr-calendar.arrowBottom:before {
    border-top-color: var(--color-border);
}

:root[data-bs-theme="dark"] .flatpickr-calendar.arrowBottom:after {
    border-top-color: var(--color-surface);
}

:root[data-bs-theme="dark"] .flatpickr-months,
:root[data-bs-theme="dark"] .flatpickr-month,
:root[data-bs-theme="dark"] .flatpickr-current-month,
:root[data-bs-theme="dark"] .flatpickr-current-month input.cur-year,
:root[data-bs-theme="dark"] .flatpickr-current-month .flatpickr-monthDropdown-months {
    background: transparent;
    color: var(--color-text);
}

:root[data-bs-theme="dark"] .flatpickr-current-month .flatpickr-monthDropdown-months option {
    background: var(--color-surface);
    color: var(--color-text);
}

:root[data-bs-theme="dark"] .flatpickr-prev-month svg path,
:root[data-bs-theme="dark"] .flatpickr-next-month svg path {
    fill: var(--color-text-muted);
}

:root[data-bs-theme="dark"] .flatpickr-prev-month:hover svg path,
:root[data-bs-theme="dark"] .flatpickr-next-month:hover svg path {
    fill: var(--color-text);
}

/* Setinhas do spinner de ano (Flatpickr) — o padrão é um triângulo quase
   preto (rgba(0,0,0,.9)), pensado pra fundo claro; some no tema escuro. */
:root[data-bs-theme="dark"] .flatpickr-current-month .numInputWrapper span.arrowUp:after {
    border-bottom-color: var(--color-text-muted);
}

:root[data-bs-theme="dark"] .flatpickr-current-month .numInputWrapper span.arrowDown:after {
    border-top-color: var(--color-text-muted);
}

:root[data-bs-theme="dark"] .flatpickr-current-month .numInputWrapper span:hover {
    background: rgba(255, 255, 255, 0.1);
}

:root[data-bs-theme="dark"] .flatpickr-weekdays {
    background: transparent;
}

:root[data-bs-theme="dark"] span.flatpickr-weekday {
    background: transparent;
    color: var(--color-text-muted);
}

:root[data-bs-theme="dark"] .flatpickr-day {
    color: var(--color-text);
}

:root[data-bs-theme="dark"] .flatpickr-day.prevMonthDay,
:root[data-bs-theme="dark"] .flatpickr-day.nextMonthDay,
:root[data-bs-theme="dark"] .flatpickr-day.flatpickr-disabled {
    color: var(--color-border);
}

:root[data-bs-theme="dark"] .flatpickr-day:hover,
:root[data-bs-theme="dark"] .flatpickr-day:focus {
    background: var(--color-sidebar-hover);
    border-color: var(--color-sidebar-hover);
    color: #fff;
}

:root[data-bs-theme="dark"] .flatpickr-day.today {
    border-color: var(--color-brand);
}

:root[data-bs-theme="dark"] .flatpickr-day.selected,
:root[data-bs-theme="dark"] .flatpickr-day.selected:hover,
:root[data-bs-theme="dark"] .flatpickr-day.selected:focus {
    background: var(--color-brand);
    border-color: var(--color-brand);
    color: #fff;
}

/* Seletor de hora (`.js-datetime`, Admin > Logs) — mesma lacuna que o
   resto do Flatpickr tinha antes desta seção existir: texto escuro fixo
   da lib (pensado pra fundo claro) ficava quase ilegível sobre o fundo
   escuro herdado de `.flatpickr-calendar`. Nenhuma tela usava hora antes
   disso, por isso nunca tinha aparecido. */
:root[data-bs-theme="dark"] .flatpickr-time input,
:root[data-bs-theme="dark"] .flatpickr-time .flatpickr-time-separator,
:root[data-bs-theme="dark"] .flatpickr-time .flatpickr-am-pm {
    background: transparent;
    color: var(--color-text);
}

:root[data-bs-theme="dark"] .flatpickr-time input:hover,
:root[data-bs-theme="dark"] .flatpickr-time .flatpickr-am-pm:hover {
    background: rgba(255, 255, 255, 0.1);
}

:root[data-bs-theme="dark"] .flatpickr-time .numInputWrapper span.arrowUp:after {
    border-bottom-color: var(--color-text-muted);
}

:root[data-bs-theme="dark"] .flatpickr-time .numInputWrapper span.arrowDown:after {
    border-top-color: var(--color-text-muted);
}

:root[data-bs-theme="dark"] .flatpickr-time .numInputWrapper span:hover {
    background: rgba(255, 255, 255, 0.1);
}

/* Flatpickr é distribuído com layout todo em px fixo (base 14px), então não
   acompanha a densidade da interface (Pequena/Média/Grande = 13px/14px/16px
   no root). Já tentamos converter cada valor fixo pra rem (14px = 1rem) pra
   escalar junto com a densidade — funcionava perfeito em "Média" (que é
   literalmente o tamanho nativo da lib, sem mudança nenhuma), mas em
   "Pequena" o grid de dias vinha quebrado (coluna da direita cortada,
   linhas com espaçamento errado) e em "Grande" sobrava espaço sem
   necessidade. Revertido.
   O projeto irmão `portalnoc-v2` bateu nesse mesmo problema antes e também
   tentou `zoom` por densidade — revertido lá pelo mesmo motivo (zoom num
   elemento que também tem `top`/`left` explícitos, como o Flatpickr define
   via JS, tem comportamento inconsistente entre navegadores quanto a
   escalar ou não o próprio posicionamento). A solução final do
   `portalnoc-v2` (replicada aqui): TROCAR os valores fixos em `px` da lib
   por OUTROS valores fixos em `px`, ~20% menores — sem zoom/transform/rem
   nenhum, então não toca em nada que afete o cálculo de posição (que
   depende só de `input.getBoundingClientRect()`, nunca do tamanho do
   próprio calendário). Não diferencia por densidade (um valor só pras 3) —
   mais simples e testado, menos risco de bug novo. Efeito colateral aceito
   (mesmo trade-off do portalnoc-v2): o popup fica relativamente MAIOR que
   o resto da UI em "Pequena" e relativamente MENOR em "Grande", mas nunca
   quebra o grid de dias em nenhuma densidade. */
.flatpickr-calendar {
    font-size: 11.2px;
    line-height: 19px;
    width: 246px;
}

.flatpickr-days,
.flatpickr-calendar .dayContainer {
    width: 246px;
    min-width: 246px;
    max-width: 246px;
}

.flatpickr-calendar .flatpickr-month {
    height: 27px;
}

.flatpickr-calendar .flatpickr-current-month {
    padding-top: 6px;
}

.flatpickr-calendar .flatpickr-weekdays {
    height: 22px;
}

.flatpickr-calendar .flatpickr-weekday {
    line-height: 22px;
}

.flatpickr-calendar .flatpickr-day {
    max-width: 31px;
    height: 31px;
    line-height: 31px;
}

.flatpickr-calendar .flatpickr-time,
.flatpickr-calendar .flatpickr-time input {
    font-size: 11.2px;
}

.flatpickr-calendar .flatpickr-time {
    line-height: 32px;
    max-height: 32px;
}

/* Sem isso, o `<input>` de hora/minuto herda `height:inherit`/`line-height:
   inherit` do `.numInputWrapper` — mas só a `line-height` do `.flatpickr-
   time` acima foi encolhida de 40px (padrão da lib) pra 32px; a ALTURA do
   wrapper continuava travada em 40px (regra própria do Flatpickr), então
   o número ficava desalinhado pro topo de uma caixa mais alta que a linha
   de texto (Lote 83). */
.flatpickr-calendar .flatpickr-time .numInputWrapper {
    height: 32px;
}

/* Todo campo de data vive dentro de um modal do Bootstrap. Enquanto um modal
   está aberto, o Bootstrap aplica overflow:hidden no <body> pra travar o
   scroll de fundo — se o calendário (posicionado como position:absolute,
   anexado ao <body>) precisar de mais altura do que sobra na janela, essa
   parte fica cortada e sem como rolar até ela. position:fixed escapa desse
   corte (só é limitado pela viewport em si). O cálculo de top/left do
   flatpickr soma o scroll da página (`window.pageYOffset/pageXOffset`), mas
   com um modal aberto a página nunca rola (scroll sempre 0), então o valor
   fica correto também para position:fixed sem ajuste nenhum.
   Se um dia existir campo de data fora de modal, isso precisa ser revisto. */
.flatpickr-calendar.open {
    position: fixed;
}

/* Ícone de "recarregar status do Ticket (OTRS)" em Apontamentos > OS —
   fica estático (o indicador de "buscando" é o spinner-bolinha ao lado do
   rótulo, não o ícone girando). */
#osOtrsReload {
    cursor: pointer;
    margin-left: .35rem;
    color: var(--color-text-muted);
}

#osOtrsReload:hover {
    color: var(--color-brand);
}

/* Badge de contagem ao lado do título da aba (Configurações > Clientes >
   Projeto — "OS 3", "Produto 1" etc.) — usava `.text-bg-secondary` do
   Bootstrap, que é um cinza fixo sem relação com nenhum dos 4 temas
   (mesmo problema já corrigido antes em form-control/checkbox/borda). */
.tab-count-badge {
    background-color: var(--color-border);
    color: var(--color-text);
}

/* Métricas do "Resumo do Projeto e Tarefas Selecionadas" (Relatórios >
   Projetos) — `row/col-md-3` do Bootstrap decide quantas colunas cabem
   com base na largura da VIEWPORT, não na largura real do elemento pai;
   como esse card divide espaço com o de Filtros (`col-lg-6`, metade da
   tela), sobrava pouco espaço de verdade mesmo em telas largas o
   suficiente pro breakpoint `md` "achar" que cabem 4 colunas — cada
   métrica ficava espremida, quebrando o texto no meio. `grid` com
   `auto-fit`/`minmax` reage à largura REAL do container (2 colunas
   quando aperta, 4 quando sobra espaço), nunca força um número fixo de
   colunas independente do espaço disponível. */
.rp-summary-metrics {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: 1rem;
}

/* Cada métrica com sua própria "moldura" de painel — pedido do usuário,
   com 4 informativos agora (Total de Horas Excedentes voltou a
   aparecer) fica mais fácil de escanear cada um separado do que só
   texto solto lado a lado. */
.rp-summary-metrics > div {
    border: 1px solid var(--color-border);
    border-radius: .5rem;
    padding: .5rem .75rem;
}

/* Blocos de requisição/resposta em Admin > Testar API — não existia
   nenhum "code block" com fundo próprio no app antes (só <pre> puro do
   Bootstrap em Admin > Logs); usa as MESMAS variáveis de tema de sempre
   (não uma cor fixa) pra ficar compatível com claro/escuro/azul/cinza
   automaticamente. */
.api-tester-pre {
    background-color: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: .5rem;
    padding: .75rem;
    color: var(--color-text);
    font-size: .8rem;
    min-height: 4rem;
    max-height: 24rem;
    overflow: auto;
    white-space: pre-wrap;
    word-break: break-word;
    margin-bottom: 0;
}

/* Cabeçalho de cada coluna (REQUISIÇÃO/RESPOSTA) — botão "Copiar como
   curl" (btn-sm) e badge de status têm alturas diferentes, e os dois só
   aparecem depois do primeiro envio; sem uma altura mínima fixa aqui, o
   <pre> de cada coluna nasce em alturas diferentes assim que um dos dois
   vira visível, desalinhando as duas colunas lado a lado. */
.api-tester-header {
    min-height: 2rem;
}

/* ---------- Badges "Tipos de Contrato" (Config > Clientes > Listagem) ----------
   Cor por categoria, mas nenhum valor fixo de fundo/texto/borda — cada um é a
   MESMA matiz (hex fixo abaixo) misturada com `--color-surface`/`--color-text`
   do tema ATUAL via `color-mix()` (mesma técnica já usada em `--color-brand-soft`
   e nos botões acima). As classes "subtle"/"emphasis" nativas do Bootstrap não
   servem aqui: elas têm só 1 paleta fixa pra "claro" e 1 pra "escuro", e este
   app tem 3 temas escuros bem diferentes entre si (Escuro/Azul/Cinza, ver
   `:root[data-theme=...]` no topo deste arquivo) — o Bootstrap não sabe disso,
   então o resultado combinava só com 1 dos 4 temas. Misturando com
   `--color-surface`/`--color-text` em vez de um valor "dark mode" genérico, a
   cor final sempre nasce do MESMO tema que está ativo. */
.badge-contract-type {
    border: 1px solid;
    font-weight: 600;
}

.badge-contract-type.type-os {
    background: color-mix(in srgb, #3b82f6 20%, var(--color-surface));
    color: color-mix(in srgb, #3b82f6 65%, var(--color-text));
    border-color: color-mix(in srgb, #3b82f6 35%, var(--color-surface));
}

.badge-contract-type.type-body-shop {
    background: color-mix(in srgb, #06b6d4 20%, var(--color-surface));
    color: color-mix(in srgb, #06b6d4 65%, var(--color-text));
    border-color: color-mix(in srgb, #06b6d4 35%, var(--color-surface));
}

.badge-contract-type.type-product {
    background: color-mix(in srgb, var(--color-text) 10%, var(--color-surface));
    color: var(--color-text-muted);
    border-color: color-mix(in srgb, var(--color-text) 20%, var(--color-surface));
}

.badge-contract-type.type-banco-horas {
    background: color-mix(in srgb, #d97706 20%, var(--color-surface));
    color: color-mix(in srgb, #d97706 65%, var(--color-text));
    border-color: color-mix(in srgb, #d97706 35%, var(--color-surface));
}

/* ---------- Apontamentos > OS: pulso de borda ao trocar granularidade
   Início/Fim (1min/15min) — feedback visual de "essas 2 caixas mudaram",
   1x só, não fica piscando.

   Cor do brilho é `rgba()` LITERAL por tema (não `color-mix()` com
   `--color-brand`, como os badges acima) — motivo, achado testando de
   verdade: o Chromium usado aqui não interpola suavemente entre 2 cores
   produzidas por `color-mix()` dentro de uma `@keyframes` (o valor
   computado vira `color(srgb ...)`, um formato que esse motor trata como
   "não interpolável" e só troca de vez na metade da animação, em vez de
   suavizar — confirmado amostrando `getComputedStyle().boxShadow` quadro a
   quadro via `requestAnimationFrame`: ficava idêntico ao estado inicial
   até ~40% da duração, pulava direto pro estado final, sem nenhum
   intermediário). `rgba()` com número literal interpola sem esse
   problema — só que aí cada tema precisa da sua própria `@keyframes`
   (RGB da cor de marca de cada tema, ver `--color-brand` no topo deste
   arquivo), escolhida via seletor `[data-theme]`. ---------- */
@keyframes os-time-granularity-pulse {
    0% { box-shadow: 0 0 0 0 rgba(255, 103, 0, .55); }
    100% { box-shadow: 0 0 0 6px rgba(255, 103, 0, 0); }
}

.js-granularity-pulse {
    animation: os-time-granularity-pulse .6s ease-out;
}

:root[data-theme="blue"] .js-granularity-pulse {
    animation-name: os-time-granularity-pulse-blue;
}

@keyframes os-time-granularity-pulse-blue {
    0% { box-shadow: 0 0 0 0 rgba(59, 130, 246, .55); }
    100% { box-shadow: 0 0 0 6px rgba(59, 130, 246, 0); }
}

:root[data-theme="gray"] .js-granularity-pulse {
    animation-name: os-time-granularity-pulse-gray;
}

@keyframes os-time-granularity-pulse-gray {
    0% { box-shadow: 0 0 0 0 rgba(13, 148, 136, .55); }
    100% { box-shadow: 0 0 0 6px rgba(13, 148, 136, 0); }
}
