/* ------------------------------------------------------------------ *
 * Polish layer on top of Tailwind. Only things Tailwind utilities
 * can't express cleanly live here (shimmer, sparkbars, scrollbars,
 * the live banner sheen, segmented-control glow).
 * ------------------------------------------------------------------ */

/* As variáveis de cor (--accent, --ok, --warn, --crit, --info, --grape) já são
   definidas em :root no <style> inline do index.html, no formato "R G B"
   (sem '#'), exigido por rgb(var(--accent)) e pelas paletas [data-palette].
   Não redefinir aqui — um valor hex sobrescrevendo o triplo RGB quebra
   silenciosamente todo rgb(var(--accent)) do app (e o seletor de paleta). */

/* ===== Modos de Acessibilidade =============================================
   4 modos independentes (não são exclusivos entre si), ligados via classe na
   <html> (ver theme-init.js pra aplicação pré-pintura + #a11yPop/app.js pro
   painel e persistência em localStorage). Tudo aqui é só CSS — sem custo de
   performance real, sem dependência de fonte remota (ver nota da fonte de
   dislexia abaixo). */

/* --- Alto contraste ---------------------------------------------------
   Astigmatismo não corrigido e baixa visão em geral se beneficiam de bordas
   mais nítidas e texto nunca "apagado" demais.
   BUG CORRIGIDO (relatado: "não funciona no modo claro"): --line só é
   usada como fonte de cor no modo ESCURO (border-line etc.) — o modo
   claro não lê essa variável em quase nenhum componente, usa classes com
   cor fixa direto (`[.light_&]:border-[#E5DFD1]`, só 3 tons no total —
   recalibrados na revisão de paleta de 24/09/2026, ver CLAUDE.md).
   Reforçar só --line não tinha NENHUM efeito lá. Corrigido mirando essas
   3 classes compiladas diretamente (mesma técnica de especificidade
   usada em --accent-ink). */
html.a11y-contrast { --line: 255 255 255; }
html.a11y-contrast .\[\.light_\&\]\:border-\[\#E5DFD1\] { border-color: rgba(0,0,0,.55) !important; }
html.a11y-contrast .text-zinc-400,
html.a11y-contrast .text-zinc-500,
html.a11y-contrast .text-zinc-600 { color: rgb(228 228 231) !important; }
html.a11y-contrast.light .text-zinc-400,
html.a11y-contrast.light .text-zinc-500,
html.a11y-contrast.light .text-zinc-600 { color: rgb(39 39 42) !important; }

/* --- Fonte para dislexia -----------------------------------------------
   Comic Sans MS (e Comic Neue como equivalente livre em sistemas sem ela)
   são recomendadas pela British Dyslexia Association por terem letras bem
   diferenciadas entre si (b/d/p/q, por exemplo) — dá pra usar sem baixar
   nenhuma fonte nova (funciona offline, mesma filosofia da Sora
   autohospedada em tailwind.config.js). */
html.a11y-dyslexia,
html.a11y-dyslexia body,
html.a11y-dyslexia .font-sans,
html.a11y-dyslexia .font-mono {
  font-family: "Comic Sans MS", "Comic Neue", "Century Gothic", sans-serif !important;
}

/* --- Daltonismo: padrões na barra de Distribuição SLA ----------------------------------------------
   Os trechos da barra são vizinhos e, só pela cor, "Atenção"/"Crítico"/"Expirado" podem se confundir (em escala
   de cinza, sempre). Cada um ganha um padrão próprio por cima da cor: listras diagonais, verticais e pontos.
   `!important`: o estilo inline `background:<cor>` zera o background-image e venceria a folha de estilo. As
   cores da paleta são claras no tema escuro (padrão escuro por cima) e escuras no claro (padrão claro). */
html.a11y-colorblind .dist-bar > i[data-sla="Atenção"] { background-image: repeating-linear-gradient(135deg, rgba(0,0,0,.34) 0 2px, transparent 2px 7px) !important; }
html.a11y-colorblind .dist-bar > i[data-sla="Crítico"] { background-image: repeating-linear-gradient(90deg, rgba(0,0,0,.38) 0 2px, transparent 2px 6px) !important; }
html.a11y-colorblind .dist-bar > i[data-sla="Expirado"] { background-image: radial-gradient(rgba(255,255,255,.7) 1.2px, transparent 1.5px) !important; background-size: 6px 6px !important; }
html.a11y-colorblind.light .dist-bar > i[data-sla="Atenção"] { background-image: repeating-linear-gradient(135deg, rgba(255,255,255,.42) 0 2px, transparent 2px 7px) !important; }
html.a11y-colorblind.light .dist-bar > i[data-sla="Crítico"] { background-image: repeating-linear-gradient(90deg, rgba(255,255,255,.45) 0 2px, transparent 2px 6px) !important; }

/* --- Reduzir movimento ---------------------------------------------------
   Duração quase zero (não `none`) de propósito: código que espera o evento
   `transitionend` pra terminar uma ação (ex.: recolher a sidebar) continua
   funcionando — só o movimento em si fica imperceptível. */
html.a11y-reduced-motion *,
html.a11y-reduced-motion *::before,
html.a11y-reduced-motion *::after {
  animation-duration: 0.001ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.001ms !important;
  scroll-behavior: auto !important;
}

/* ===== Contraste do accent usado como TEXTO no modo claro ================
   O accent (ex.: lima 211,242,63) é uma cor CLARA — ótima como FUNDO (com
   texto escuro por cima) ou como texto sobre fundo escuro, mas como TEXTO
   sobre fundo claro tem contraste baixíssimo (medido ~1.3:1 no lima sobre
   branco, praticamente ilegível; o mínimo WCAG é 4.5:1). No modo claro,
   `--accent-ink` escurece o accent só quando ele é cor de TEXTO (links
   "Ver", cabeçalho de coluna ordenada, abas ativas), sem tocar nos
   fundos/badges cheios. Funciona pra qualquer paleta (color-mix a partir de
   --accent). No escuro, é o próprio accent (segue vibrante como hoje). */
:root { --accent-ink: rgb(var(--accent)); }
.light { --accent-ink: color-mix(in srgb, rgb(var(--accent)) 50%, #080808); }
.light .text-accent { color: var(--accent-ink); }
.light .hover\:text-accent:hover { color: var(--accent-ink); }
.light .tab-chip[data-active="true"] { color: color-mix(in srgb, var(--tab-color, rgb(var(--accent))) 50%, #080808); }
/* (a aba ativa da grid — .filter-tab[data-active] no modo claro — já usa
   --accent-ink direto na regra dela, mais abaixo) */

/* Mesmo problema de contraste do --accent-ink acima, mas pro chip "Vence
   em" do card "SLA ao vivo" (relatado: "no claro não dá pra ver muito") —
   a cor da severidade (ex.: verde #22C55E de "No Prazo") é vibrante/clara,
   ótima sobre o fundo escuro do tema dark, mas ilegível sobre o fundo bem
   claro (quase branco) do tema light. `--sev-c` é setado inline por chip
   (ver slaLiveDeadlineChipHtml em app.js); a cor de texto/ícone usa ela
   direto no escuro e escurecida via color-mix no claro — currentColor no
   ícone (stroke="currentColor") acompanha automaticamente. */
.sla-deadline-chip { color: var(--sev-c); }
.light .sla-deadline-chip { color: color-mix(in srgb, var(--sev-c) 55%, #080808); }

html { -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; overflow-x: hidden; }
/* color-scheme casa os controles/scrollbars NATIVOS (inputs, <select>, barra
   de rolagem do SO) com o tema atual — sem isso, no escuro eles vinham claros.
   Segue a classe .light no <html> (mesmo mecanismo do resto do tema). */
:root { color-scheme: dark; }
:root.light { color-scheme: light; }
/* "zero" 1 = zero cortado/pontilhado do JetBrains Mono — distingue o 0 do 8
   e do O (o 0 "cheio" em peso extrabold estava sendo confundido com 8). */
body { font-feature-settings: "tnum" 1, "cv01" 1, "zero" 1; overflow-x: hidden; }

/* Tabular numbers everywhere a count appears (+ zero cortado, mesma razão) */
.tnum { font-variant-numeric: tabular-nums slashed-zero; letter-spacing: -0.01em; }

/* ---- Sora (self-hosted, sem CDN) -----------------------------------
   Fonte do app inteiro (texto, IDs, contadores e relógios de SLA — sans e
   mono no tailwind.config.js apontam pra ela). Auto-hospedada em
   frontend/fonts/sora/, sem depender de Google Fonts em runtime. */
@font-face {
  font-family: "Sora";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/sora/sora-latin-400-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Sora";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/fonts/sora/sora-latin-500-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Sora";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/fonts/sora/sora-latin-600-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Sora";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/fonts/sora/sora-latin-700-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Sora";
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url("/fonts/sora/sora-latin-800-normal.woff2") format("woff2");
}

/* ---- Cards do painel "SLA ao vivo": micro-interação no hover (só o
   brilho que segue o mouse, sem subir/dar zoom no card — pedido) */
.sla-crit-card {
  position: relative;
  isolation: isolate;
  transition: box-shadow .35s cubic-bezier(.22,1,.36,1), border-color .35s cubic-bezier(.22,1,.36,1);
}
/* Altura previsível: o assunto reserva sempre 2 linhas (e o vazio, a altura de um cartão) — o tamanho do painel não depende do texto. */
.sla-c-subject { min-height: 2.5rem; }
.sla-c-empty { min-height: 13rem; }
.sla-compact .sla-c-empty { min-height: 10rem; }
.sla-crit-card:hover {
  box-shadow: 0 0 0 1px var(--glow), 0 14px 28px -14px var(--glow);
}
/* Brilho neon que acompanha o mouse — sempre atrás do card (z-index -1 no
   stacking context isolado acima); posição via --mx/--my, setados em JS no
   mousemove (ver wireSlaCardGlow). */
.sla-crit-card::before {
  content: '';
  position: absolute;
  inset: -22px;
  z-index: -1;
  border-radius: inherit;
  background: radial-gradient(240px circle at var(--mx, 50%) var(--my, 50%), var(--glow) 0%, transparent 70%);
  opacity: 0;
  filter: blur(20px);
  transition: opacity .35s ease;
  pointer-events: none;
}
.sla-crit-card:hover::before { opacity: .14; }
/* BUG CORRIGIDO (relatado: tooltip "?" ficando esverdeada/translúcida): o
   card usa "isolation: isolate" pra manter esse brilho contido dentro dele
   (senão o z-index negativo do brilho vazaria pra trás de elementos bem
   distantes na página) — mas isso também prende a tooltip (que "escapa"
   visualmente pra fora do card) dentro do mesmo grupo isolado, e o brilho
   acaba se misturando com o fundo da tooltip mesmo com z-index maior.
   Solução mais simples que reestruturar o HTML: suprime o brilho
   especificamente enquanto o "?" está em foco/hover — nos outros casos
   (resto do card) o efeito continua normal. */
/* transition próprio (bem mais rápido que os .35s do brilho normal): sem
   isso, se o mouse já estava sobre o card (brilho no meio da animação de
   aparecer) ao alcançar o "?", a supressão só "alcançava" o valor final
   depois de mais .35s — dava tempo de um flash verde passageiro atrás da
   tooltip antes de sumir de vez. */
.sla-crit-card:has(.info-tip:hover)::before,
.sla-crit-card:has(.info-tip:focus-visible)::before {
  opacity: 0 !important;
  transition: opacity .05s linear !important;
}

/* ---- Scrollbars ---------------------------------------------------- */
::-webkit-scrollbar { width: 9px; height: 9px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: #34343a; border-radius: 999px; border: 2px solid transparent; background-clip: padding-box; }
::-webkit-scrollbar-thumb:hover { background: #45454d; background-clip: padding-box; }
.dark ::-webkit-scrollbar-thumb { background: #34343a; }

/* Dashboard: sem rolagem (nem barra, nem o scroll em si — ver
   updateScrollbarVisibility em app.js, que liga/desliga esta classe no
   <html> conforme a página atual). O tamanho do conteúdo já foi calibrado
   pra caber na tela; as demais páginas (Chamados, SLA, listas longas)
   continuam rolando normalmente. */
html.hide-scrollbar, html.hide-scrollbar body {
  overflow: hidden;
  scrollbar-width: none;
}
html.hide-scrollbar::-webkit-scrollbar,
html.hide-scrollbar body::-webkit-scrollbar {
  display: none;
}

/* ---- Skeleton shimmer ---------------------------------------------- */
.skeleton {
  position: relative;
  overflow: hidden;
  background: rgba(255,255,255,0.05);
  border-radius: 8px;
}
.skeleton::after {
  content: "";
  position: absolute; inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.08), transparent);
  animation: shimmer 1.4s infinite;
}
@keyframes shimmer { 100% { transform: translateX(100%); } }

/* ---- Sidebar nav ------------------------------------------------------ */
/* Transição (transform/opacity/etc.) fica centralizada mais abaixo, junto
   com a transição de tema — evitar declarar "transition" pra #sidebar em
   dois lugares, senão o de especificidade igual que vier depois no arquivo
   sempre vence e apaga o de cima. */
#sidebar.is-open { transform: translateX(0); }

.side-nav-item {
  position: relative;
  z-index: 1; /* fica acima do .nav-active-pill, que desliza por baixo */
  transition: color .2s ease;
}
.side-nav-item[data-active="true"] { color: rgb(var(--accent)); }
.side-nav-item[data-active="true"] .side-nav-ico { color: rgb(var(--accent)); }
/* BUG CORRIGIDO (relatado: "no claro fica cinza primeiro, depois vira a cor
   do tema"): o item ativo ainda tinha seu PRÓPRIO hover (`hover:bg-white/5`
   escuro / `hover:bg-zinc-100` claro, vindo do Tailwind em navItemHtml).
   No claro o zinc-100 é sólido/opaco e fica ACIMA da pílula (z-index 1 >
   0), cobrindo o verde por inteiro enquanto o mouse está em cima — só ao
   tirar o mouse a pílula reaparece por baixo. A pílula já É o destaque do
   item ativo; o hover próprio dele fica supérfluo (e, no claro, prejudicial)
   nesse caso — desligado só quando `data-active="true"`. */
.side-nav-item[data-active="true"]:hover { background-color: transparent; }

/* Pílula que desliza entre os itens do menu ao trocar de página — pedido:
   "deslize suave... literalmente deslizando e corrido, sem fade". Um único
   elemento (não uma cor instantânea por item) que se move de posição via
   transform: translateY, criado uma vez em buildNav() e reposicionado a
   cada navegação em positionNavPill() (ver app.js). Sem opacity/fade: só
   o movimento. position:absolute dentro de #nav (position:relative) —
   offsetTop dos itens já é relativo a #nav mesmo atravessando os <div>
   de grupo no meio, que não são posicionados.
   BUG CORRIGIDO (relatado: "dropando fps"/"rasgado", pior no claro): a
   transição animava `height` JUNTO com `transform`. Todo item do menu tem a
   MESMA altura (mesmo padding/fonte), então animar height é desnecessário
   — e pior: misturar uma propriedade de layout (height, força recálculo de
   layout a cada frame) com uma de compositor (transform, só GPU) faz o
   navegador rebaixar a animação inteira pra thread principal, travando.
   `height` agora só é ATRIBUÍDO (instantâneo, via JS), nunca animado —
   `transition` cobre só `transform`, que fica liso em qualquer tema. */
.nav-active-pill {
  position: absolute;
  top: 0;
  left: .75rem;
  right: .75rem;
  border-radius: .75rem;
  background: rgb(var(--accent) / .14);
  transition: transform .22s cubic-bezier(.3,0,.2,1);
  will-change: transform;
  pointer-events: none;
  z-index: 0;
}
.light .nav-active-pill { background: rgb(var(--accent) / .1); }

/* Abas de filtro compactas (grupo CSP/CP/AM/Outros, PCM/PCA) — usam a cor
   de destaque (accent) do tema selecionado quando ativas, em vez de um
   simples texto branco sem contraste de cor. Separado de .side-nav-item
   (menu lateral) pra não interferir no estilo de lá. */
.filter-tab {
  position: relative;
  transition: color .2s ease, background-color .2s ease;
}
.filter-tab[data-active="true"] {
  background: rgb(var(--accent) / .16);
  color: rgb(var(--accent));
}
.light .filter-tab[data-active="true"] {
  background: rgb(var(--accent) / .12);
  color: var(--accent-ink); /* accent escurecido pra ler sobre fundo claro (ver --accent-ink) */
}
.filter-tab:hover:not([data-active="true"]) {
  color: rgb(var(--accent) / .8);
}
.light .filter-tab:hover:not([data-active="true"]) {
  color: color-mix(in srgb, var(--accent-ink) 85%, transparent);
}

/* Grupo de abas "pílula deslizante" (relatado: Chamados/SLA sem esse efeito
   — cada aba só trocava de cor sozinha, sem uma pílula visível se movendo
   entre elas). `.seg-tabs` marca o container do grupo — dentro dele, o
   fundo de "ativo" do .filter-tab normal é desligado (vira transparente),
   porque quem faz esse papel agora é a pílula única (.seg-tabs-indicator),
   posicionada/animada via JS (ver renderSegTabs em app.js — usa a técnica
   FLIP pra deslizar de verdade mesmo reconstruindo o HTML a cada clique).
   Escopado só a `.seg-tabs` pra não afetar outras abas que já usam
   .filter-tab sem esse indicador (PCM/PCA, Auditoria). */
.seg-tabs { position: relative; }
.seg-tabs .filter-tab[data-active="true"] { background: transparent; }
.seg-tabs-indicator {
  position: absolute;
  top: 4px; bottom: 4px; left: 0; width: 0;
  border-radius: 0.5rem;
  background: rgb(var(--accent) / .16);
  transition: left .22s cubic-bezier(.4,0,.2,1), width .22s cubic-bezier(.4,0,.2,1);
  pointer-events: none;
}
.light .seg-tabs-indicator { background: rgb(var(--accent) / .12); }

/* Fade-in de linha/item NOVO numa lista reconciliada por morph (ver
   morphChildren em app.js) — só o que não tinha um nó antigo com a mesma
   `data-key` pra reaproveitar entra assim; o que já estava na tela nunca é
   tocado. `transition` fica num seletor sempre ativo (`[data-key]`, não na
   classe que liga/desliga) — remover a classe no meio da transição não
   corta ela pela metade. Substitui o fade da grid inteira (relatado como
   "pisca" — escurecer/reexibir tudo a cada atualização, mesmo sem nada
   mudar de verdade nas linhas já visíveis). */
[data-key] { transition: opacity .4s ease; }
.row-enter { opacity: 0; }

/* Ícone "?" com tooltip visível (CSS puro, funciona por hover E foco de
   teclado — acessível). Usado nos cards do Resumo/SLA/PCM-PCA. */
.info-tip {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  border-radius: 999px;
  color: #71717a;
  cursor: help;
  flex-shrink: 0;
}
.info-tip svg { width: 100%; height: 100%; }
.info-tip:hover, .info-tip:focus-visible { color: rgb(var(--accent)); outline: none; }
/* Card "Resolvidos": fundo já É a cor do accent (stat-card-solid), então o
   hover padrão (que também vira accent) ficaria invisível ali — usa preto
   translúcido nos dois estados em vez da cor do tema. */
.info-tip-on-accent { color: rgba(0,0,0,.5); }
.info-tip-on-accent:hover, .info-tip-on-accent:focus-visible { color: rgba(0,0,0,.85); }
/* O balão do "?" (.info-tip) e das fatias de barra (.seg-hover-tip) é o tooltip único [data-tip]
   (position:fixed, mantido dentro da janela por setupUiTooltips) — as antigas bolhas em CSS puro, que
   estouravam a borda e eram cortadas por overflow:hidden, foram removidas. */
.seg-hover-tip { position: relative; cursor: help; }
/* ===== Botão de tema: sol <-> lua preenchida ===== */
/* Pílula larga com lua + sol lado a lado (referência) — em vez de um botão
   redondo só com um ícone, sempre mostra os dois; um "chip" atrás desliza
   pro lado que representa o tema atual. */
.theme-btn { position: relative; }
.theme-btn-chip {
  position: absolute; top: 3px; left: 3px; width: 32px; height: 32px;
  border-radius: 999px; background: rgba(255,255,255,.08);
  transition: transform .35s cubic-bezier(.22,1,.36,1);
}
/* 37px (não 38): o botão tem 76px com borda de 1px, então a área útil (76 -
   2px de borda) some 74px, dividida em 2 colunas de 37px pelo grid — 38px
   deslizava a bolinha 1px além do centro da coluna do sol, ficando com o
   ícone puxado pra esquerda dentro dela. */
.light .theme-btn-chip { background: rgba(0,0,0,.06); transform: translateX(37px); }
.theme-icon-moon, .theme-icon-sun { position: relative; z-index: 1; transition: color .25s ease-out; }
.theme-icon-sun { color: inherit; }
.light .theme-icon-sun { color: #f59e0b; }

/* ===== Botão de apresentação: rotação suave ao expandir/colapsar ===== */
.present-icon {
  transition: opacity .5s ease, transform .6s cubic-bezier(.4,0,.2,1);
}
.present-icon-expand { transform: rotate(0deg) scale(1); }
.presenting .present-icon-collapse { transform: rotate(180deg) scale(1); }
.present-btn:active .present-icon { transform: scale(.85); }

/* ===== Ícones do topo: animação de hover, uma por ícone ================
   Pedido: todo ícone do cabeçalho anima ao passar o mouse (exceto o botão
   de tema claro/escuro, que já tem sua própria transição de deslizar sol/
   lua) — cada um com um movimento que combina com o que ele representa.
   Sempre no ÍCONE/conteúdo interno, nunca no <button> em si — o botão já
   sobe 2px no hover via `.lift` (ver acima); animar o mesmo `transform` no
   mesmo elemento cancelaria um dos dois. Respeita prefers-reduced-motion. */
@media (prefers-reduced-motion: no-preference) {
  /* Sino: balança de um lado pro outro, como tocando — e duas "ondas de
     som" (pontinhos) pulsam dos dois lados, na cor do tema (referência:
     ícones animados de notificação do Flaticon, que costumam combinar o
     balanço com ondas de som saindo do sino). */
  /* .bell-ring: mesma animação do hover, mas disparada via JS (classe
     ligada/desligada) quando chega uma notificação NOVA de verdade — ver
     ringBellIcon() em app.js, chamado de fetchServerNotifs() só quando
     `fresh.length` (não em todo poll, só notificação inédita). */
  #bellBtn svg { transform-origin: 50% 10%; }
  #bellBtn:hover svg, #bellBtn.bell-ring svg { animation: header-icon-bell .5s ease-in-out; }
  @keyframes header-icon-bell {
    0%, 100% { transform: rotate(0deg); }
    20% { transform: rotate(15deg); }
    40% { transform: rotate(-13deg); }
    60% { transform: rotate(8deg); }
    80% { transform: rotate(-4deg); }
  }
  #bellBtn::before, #bellBtn::after {
    content: ''; position: absolute; top: 50%; width: 4px; height: 4px;
    border-radius: 50%; background: rgb(var(--accent));
    opacity: 0; transform: translateY(-50%) scale(.4); pointer-events: none;
  }
  #bellBtn::before { left: 4px; }
  #bellBtn::after { right: 4px; }
  #bellBtn:hover::before, #bellBtn.bell-ring::before { animation: header-icon-bell-wave .5s ease-in-out .05s; }
  #bellBtn:hover::after, #bellBtn.bell-ring::after { animation: header-icon-bell-wave .5s ease-in-out .2s; }
  @keyframes header-icon-bell-wave {
    0% { opacity: 0; transform: translateY(-50%) scale(.4); }
    45% { opacity: 1; transform: translateY(-50%) scale(1); }
    100% { opacity: 0; transform: translateY(-50%) scale(1.4); }
  }

  /* Tela cheia: um "respiro" de crescimento, sugerindo expandir. */
  #presentBtn:hover .present-icon { animation: header-icon-expand .45s ease-in-out; }
  @keyframes header-icon-expand {
    0%, 100% { transform: scale(1); }
    50% { transform: scale(1.22); }
  }

  /* Avatar: um aceninho (rotação leve pra lá e pra cá). */
  #avatarBtn > div { transition: transform .2s ease; }
  #avatarBtn:hover > div { animation: header-icon-wave .5s ease-in-out; }
  @keyframes header-icon-wave {
    0%, 100% { transform: rotate(0deg); }
    25% { transform: rotate(-12deg); }
    75% { transform: rotate(12deg); }
  }
}

/* ===== Transição suave ao trocar tema (cores de fundo/borda/texto) =====
   Só background-color/border-color/color, nunca "all": animar qualquer
   propriedade (incluindo box-shadow, que é cara) em milhares de elementos
   ao mesmo tempo é o que causava a queda de FPS e a sensação de transição
   "rasgada" ao trocar de tema. Sem seletor universal (*) — isso ligava
   "transition: all" por acidente em todo elemento da página, mesmo fora
   da troca de tema. */
body, aside, main, footer,
.side-nav-item, .card,
[class*="bg-panel"], [class*="bg-ink"], [class*="bg-zinc"], [class*="bg-white"],
[class*="border-line"], [class*="border-zinc"], [class*="text-zinc"], [class*="text-white"] {
  transition-property: background-color, border-color, color;
  transition-duration: .35s;
  transition-timing-function: ease-out;
}

/* ===== Transição ao entrar/sair do modo apresentação (+ sidebar off-canvas) ===== */
#sidebar {
  transition: opacity .45s ease, transform .3s ease-out, width .3s cubic-bezier(.4,0,.2,1), background-color .35s ease-out, border-color .35s ease-out;
}
#view {
  /* Só opacidade (composição na GPU). Antes animava max-width E padding —
     propriedades de LAYOUT — a cada troca de aba, forçando reflow por frame
     (o "trava/imagem rasgada" ao navegar). A largura/padding agora mudam na
     hora, escondidos pelo fade. */
  transition: opacity .3s ease;
}

/* Troca de tema instantânea: durante o swap (classe posta/removida por JS em
   toggleTheme) NENHUM elemento anima cor/fundo/borda — evita o storm de
   repaint que travava a imagem. Volta ao normal no frame seguinte. */
html.theme-anim-off,
html.theme-anim-off *,
html.theme-anim-off *::before,
html.theme-anim-off *::after {
  transition: none !important;
}
/* Modo apresentação: o menu recolhe DESLIZANDO (transform, na GPU, sem
   reflow) e o conteúdo expande animando a margem. Os gráficos recalculam só
   no FIM da transição (ver togglePresent), e a classe só é ligada depois que
   a tela cheia assenta — assim o reflow único da tela cheia não colide com a
   animação (era isso que travava/derrubava o FPS). */
#appContent {
  transition: margin-left .3s cubic-bezier(.4, 0, .2, 1);
}
:fullscreen, ::backdrop { transition: background-color .45s ease; }

/* ===== Sidebar recolhida (rail só-ícones) — só desktop =================
   O estado nasce aplicado por theme-init.js (classe .sidebar-collapsed no
   <html>) pra não animar no load; o clique no botão é que anima. Largura da
   aside e margem do #appContent animam em sincronia (transições acima). Os
   textos deslizam/somem via max-width/max-height/opacity — propriedades
   baratas, sem thrash de gráficos (as barras são CSS, não canvas). */
@media (min-width: 640px) {
  html.sidebar-collapsed #sidebar { width: 4.5rem; }
  html.sidebar-collapsed #appContent { margin-left: 4.5rem; }

  /* will-change só enquanto a animação roda (posto/removido por JS) — promove
     a camada e evita recalcular o backdrop-blur a cada frame. */
  html.sidebar-animating #sidebar { will-change: width; }
  /* Durante a animação o conteúdo já tem a largura FINAL (fixa): a página/tabela é medida UMA vez em vez de refluir a cada quadro; só a margem
     anda (posição). O que passar da janela no meio do caminho é cortado por overflow-x:clip e some quando a margem chega ao valor final. */
  html.sidebar-animating #appContent { flex: none; width: calc(100% - 16rem); }
  html.sidebar-animating.sidebar-collapsed #appContent { width: calc(100% - 4.5rem); }
  html.sidebar-animating, html.sidebar-animating body { overflow-x: clip; }

  /* Rótulos dos itens/rodapé: deslizam e somem; o ícone fica centralizado. */
  #sidebar .side-label {
    min-width: 0; max-width: 12rem; overflow: hidden; white-space: nowrap;
    transition: max-width .3s cubic-bezier(.4,0,.2,1), opacity .2s ease;
  }
  html.sidebar-collapsed #sidebar .side-label { max-width: 0; opacity: 0; }
  html.sidebar-collapsed #sidebar .side-nav-item,
  html.sidebar-collapsed #sidebar #sidebarSettingsBtn { justify-content: center; gap: 0; }

  /* Chip "Manutenção" some junto com o rótulo. */
  #sidebar .side-maint {
    max-width: 8rem; overflow: hidden;
    transition: max-width .25s ease, opacity .18s ease, padding .25s ease, margin .25s ease;
  }
  html.sidebar-collapsed #sidebar .side-maint {
    max-width: 0; opacity: 0; padding-left: 0; padding-right: 0; margin: 0;
  }

  /* Rótulos de grupo e caixa de busca recolhem em altura. */
  #sidebar .side-group-label {
    max-height: 2rem; overflow: hidden;
    transition: max-height .3s ease, opacity .2s ease, margin .3s ease;
  }
  html.sidebar-collapsed #sidebar .side-group-label {
    max-height: 0; opacity: 0; margin-top: 0; margin-bottom: 0;
  }
  /* Logo encolhe pra caber no rail (w-auto acompanha a altura, mantendo a
     proporção) e o cabeçalho reduz a folga lateral. Anima junto. */
  #sidebar .side-logo { transition: height .3s cubic-bezier(.4,0,.2,1); }
  html.sidebar-collapsed #sidebar .side-logo { height: .65rem; }
  #sidebar .side-logo-wrap { transition: padding .3s cubic-bezier(.4,0,.2,1); }
  html.sidebar-collapsed #sidebar .side-logo-wrap { padding-left: .5rem; padding-right: .5rem; }

  /* Seta do botão gira ao recolher. */
  .side-collapse-ico { transition: transform .3s cubic-bezier(.4,0,.2,1); }
  html.sidebar-collapsed .side-collapse-ico { transform: rotate(180deg); }

  /* Ícone "com lupa": no rail recolhido, o ícone cresce sutilmente no hover —
     compensa a falta do rótulo de texto ao lado, dando um retorno visual de
     "isto é clicável/isto é o item X". Só no estado recolhido (expandido o
     rótulo já basta, e o zoom no ícone destoaria do resto da lista). */
  html.sidebar-collapsed #sidebar .side-nav-ico,
  html.sidebar-collapsed #sidebar #sidebarSettingsBtn svg,
  html.sidebar-collapsed #sidebar #sidebarInstallBtn svg {
    transition: transform .2s cubic-bezier(.4,0,.2,1);
  }
  html.sidebar-collapsed #sidebar .side-nav-item:hover .side-nav-ico,
  html.sidebar-collapsed #sidebar #sidebarSettingsBtn:hover svg,
  html.sidebar-collapsed #sidebar #sidebarInstallBtn:hover svg {
    transform: scale(1.22);
  }

}

/* Tooltip do nome do item no rail recolhido — elemento ÚNICO, criado por JS
   (setupSidebarTooltip em app.js) e reposicionado por item no hover/foco.
   Não dá pra fazer isso só com CSS (content: attr() + ::after) porque #nav
   tem overflow-y:auto — e por regra do spec, "overflow-y != visible" força
   o overflow-x a virar auto também, cortando qualquer coisa posicionada pra
   FORA da caixa do nav (o balão abre à direita do ícone, então vazava e
   sumia). position:fixed num elemento fora da árvore da sidebar não sofre
   esse corte. Mesma linguagem visual do .info-tip-bubble. */
.side-tooltip {
  position: fixed;
  z-index: 70;
  top: 0; left: 0; /* reposicionado via JS (style.top/left) a cada hover */
  transform: translateY(-50%) translateX(-4px) scale(.95);
  transform-origin: left center;
  width: max-content;
  max-width: 200px;
  padding: 7px 11px;
  border-radius: 10px;
  background: #0a0a0b;
  color: #fafafa;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.35;
  box-shadow: 0 8px 24px -6px rgba(0,0,0,.5);
  border: 1px solid rgba(255,255,255,.08);
  opacity: 0;
  pointer-events: none;
  transition: opacity .18s cubic-bezier(.16,1,.3,1), transform .18s cubic-bezier(.16,1,.3,1);
}
.light .side-tooltip { background: #18181b; color: #fafafa; }
.side-tooltip.is-visible {
  opacity: 1;
  transform: translateY(-50%) translateX(0) scale(1);
}

/* ---- Card hover lift ------------------------------------------------ */
.lift { transition: transform .2s ease, box-shadow .2s ease, border-color .35s ease-out, background-color .35s ease-out, color .35s ease-out; }
.lift:hover { transform: translateY(-2px); }
/* Cards (tudo que usa o wrapper shadow-card, e o que tiver dentro dele) não
   sobem/"zoom" no hover — o efeito fica só nos botões e nos cards do banner
   "SLA ao vivo" (que não usam shadow-card). */
.shadow-card.lift:hover,
.shadow-card .lift:hover { transform: none; }


/* ---- Progress bars (rankings) -------------------------------------- */
.bar-track { background: rgba(255,255,255,.07); border-radius: 999px; overflow: hidden; }
.light .bar-track { background: rgba(0,0,0,.07); }
.bar-fill { position: relative; height: 100%; border-radius: 999px; overflow: hidden; transition: width .7s cubic-bezier(.22,1,.36,1); }

/* ---- Efeito "líquido": brilho diagonal varrendo as barras — puramente
   decorativo, via ::after pra não brigar com a cor de fundo (inline, por
   linha/segmento). Anima transform (não background-position): o brilho
   nasce e morre totalmente fora da área visível (translateX ±120%, fade a
   transparent nas pontas do próprio gradiente), então o restart do loop
   infinito acontece com as duas pontas invisíveis — sem o "corte"/salto que
   dava com background-position.
   Nos rankings (.bar-fill) cada barra tem seu próprio brilho. Já na
   "Distribuição SLA" (.dist-bar) é UM único brilho varrendo o componente
   inteiro de ponta a ponta — por isso vai no container (::after do
   .dist-bar), não em cada segmento <i> de cor. */
.bar-fill::after, .dist-bar::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(120deg, transparent 35%, rgba(255,255,255,.32) 50%, transparent 65%);
  animation: liquidSheen 3.2s linear infinite;
  mix-blend-mode: screen;
  pointer-events: none;
}
@keyframes liquidSheen {
  0% { transform: translateX(-120%); }
  100% { transform: translateX(120%); }
}
@media (prefers-reduced-motion: reduce) {
  .bar-fill::after, .dist-bar::after { animation: none; }
}

.pulse-dot {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 8px;
  height: 8px;
  flex-shrink: 0;
}
/* Halo com gradiente radial (esmaece nas bordas) em vez de um disco de cor
   sólida numa opacidade fixa — o disco liso "estourando" de uma vez (0→2x
   com só opacity mudando por baixo) lia como um flash duro, não um pulso
   suave. O ponto central também "respira" (opacidade) em sincronia. */
.pulse-dot::before {
  content: ""; position: absolute; inset: -7px; border-radius: 50%;
  background: radial-gradient(circle, currentColor 0%, currentColor 30%, transparent 72%);
  animation: pulse-dot-ring 2s cubic-bezier(.4,0,.6,1) infinite;
}
.pulse-dot .dot { animation: pulse-dot-core 2s ease-in-out infinite; }
@keyframes pulse-dot-ring {
  0% { transform: scale(.55); opacity: .55; }
  100% { transform: scale(1.7); opacity: 0; }
}
@keyframes pulse-dot-core {
  0%, 100% { opacity: 1; }
  50% { opacity: .6; }
}

/* ---- Painéis flutuantes (Colunas, Exportar, selects customizados) --- */
/* SEM transição de opacity/transform aqui (era translateY(-6px)+fade, e
   antes disso translateY+scale) — tirar o scale() não bastou: mesmo só
   com translateY, o painel ainda promove pra uma camada de composição
   própria (GPU) durante a transição, e isso dentro de um #dashScale com
   `zoom` fracionário (dashboard encolhido pra caber sem rolagem) seguia
   fazendo alguma opção nascer com o texto sumido/apagado no 1º paint —
   reportado 2x, com uma opção DIFERENTE em cada vez ("Hoje" depois "Mês"),
   o que aponta pra um problema de composição/rasterização, não de dado.
   Abrir/fechar agora é instantâneo (sem transition nenhuma): perde o fade
   sutil, mas elimina de vez essa classe de bug. */
.dropdown-panel[data-closed] {
  opacity: 0;
  pointer-events: none;
}
/* Exceção pontual (pedido: "transições de entrada e saída suaves" nos
   selects de filtro — Região/Empresa/etc.): só `.cs-panel-anim` (marcado
   só em `selectFilter()`, usada exclusivamente pelos filtros de Chamados/
   SLA) ganha uma transição de opacidade de volta. BUG QUASE REINTRODUZIDO
   nesta mesma correção: `[data-cs-panel]` sozinho (sem essa classe extra)
   TAMBÉM bate no seletor de período do card "Chamados Resolvidos" do
   Resumo — que fica DENTRO do `#dashScale` com zoom fracionário, exatamente
   onde o bug original acontecia. `.cs-panel-anim` existe só pra marcar os
   painéis que ficam FORA do dashboard/zoom (Chamados/SLA) e por isso podem
   ganhar a transição com segurança; o painel do "Chamados Resolvidos"
   continua sem a classe, então continua batendo só na regra instantânea
   do parágrafo acima. Só opacidade (sem transform/scale) e aberto/fechado
   usam funções próprias (openCustomSelectPanel/closeCustomSelectPanel em
   app.js), não as genéricas openDropdown/closeDropdown — que continuam
   instantâneas pra todo o resto (Colunas, Exportar, notificações, o
   seletor do Resumo etc.), sem risco de reintroduzir o bug ali. */
.cs-panel-anim {
  transition: opacity .26s ease;
}
/* ---- Row reveal on page switch ------------------------------------- */
.reveal { animation: rise .45s cubic-bezier(.22,1,.36,1) both; }
.reveal:nth-child(2) { animation-delay: .04s; }
.reveal:nth-child(3) { animation-delay: .08s; }
.reveal:nth-child(4) { animation-delay: .12s; }
@keyframes rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* ---- Status dot ----------------------------------------------------- */
.dot { width: 8px; height: 8px; border-radius: 999px; display: inline-block; }

/* ---- Modal ---------------------------------------------------------- */
.modal-enter { animation: modalIn .22s cubic-bezier(.22,1,.36,1) both; }
@keyframes modalIn { from { opacity: 0; transform: translateY(10px) scale(.985); } to { opacity: 1; transform: none; } }

/* overscroll-behavior: contain — ao rolar até o fim de uma área rolável
   dentro de um modal/painel, a rolagem não "vaza" pra página atrás (scroll
   chaining). Cobre as áreas com overflow-y-auto dos modais (detalhe do
   chamado, Configurações), o preview de imagem e os painéis flutuantes
   (notificações, selects, dropdowns). */
#modal [class*="overflow-y-auto"], #modal [class*="overflow-auto"],
#imgPreview, #notifPop, #userPop,
.dropdown-panel { overscroll-behavior: contain; }

/* ===== Modo Apresentação ===== */
/* Recolhe o menu deslizando pra fora (transform = GPU, animação suave) em vez
   de sumir na hora — #sidebar já tem transition de transform/opacity. */
.presenting #sidebar { transform: translateX(-100%) !important; opacity: 0; pointer-events: none; }
.presenting #appContent { margin-left: 0 !important; }
.presenting .max-w-\[1400px\] { max-width: 100% !important; }
.presenting #presentBtn { color: rgb(var(--accent)); border-color: rgb(var(--accent) / .5); }

@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

/* ===== Dashboard: cartão de métrica com barra de destaque lateral ===== */
.mini-icon-accent { background: rgb(var(--accent) / .5); color: rgb(var(--accent)); }
.stat-card { position: relative; }

/* ===== Distribuição SLA: barra segmentada + legenda ===== */
.dist-bar {
  position: relative;
  display: flex;
  width: 100%;
  height: 12px;
  border-radius: 999px;
  overflow: hidden;
  background: rgba(255,255,255,.06);
}
.light .dist-bar { background: rgba(0,0,0,.06); }
.dist-bar > i {
  display: block;
  height: 100%;
  min-width: 2px;
  transition: width .7s cubic-bezier(.22,1,.36,1);
}

/* ===== Painel "Chamados por Subcategoria": abas Todos/Materiais/... ===== */
.tab-chip {
  padding: .3rem .7rem;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  color: #71717a;
  transition: color .2s ease, background-color .2s ease;
}
.tab-chip:hover { color: #d4d4d8; }
.light .tab-chip:hover { color: #3f3f46; }
/* --tab-color: setado inline por botão (subcategoryPanel) — cor da tag do
   grupo (AM/CP) ou, na aba "Todos", a cor do tema; sem o var inline, cai no
   fallback (cor do tema), igual antes. */
.tab-chip[data-active="true"] {
  background: color-mix(in srgb, var(--tab-color, rgb(var(--accent))) 16%, transparent);
  color: var(--tab-color, rgb(var(--accent)));
}

/* ===== Botão "Ver todos" (design "Explore All") =========================
   Pílula cheia na cor do tema (--accent) — no hover, o fundo vira preto e
   o ícone "voa" pra fora (sobe/direita) enquanto uma cópia entra por baixo
   (desce/esquerda), trocando de lugar. O círculo do ícone sempre mostra a
   combinação INVERTIDA do estado atual (uma "prévia" do outro estado):
   parado = círculo preto + seta na cor do tema (preview de como fica no
   hover); hover = círculo na cor do tema + seta preta (preview de como
   era parado). Texto usa .on-accent-text (preto, mesma regra em qualquer
   paleta), virando cor do tema no hover. */
.pill-btn {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  border: none;
  cursor: pointer;
  background: rgb(var(--accent));
  border-radius: 999px;
  font-weight: 400;
  font-size: .75rem;
  line-height: 1;
  padding: .45rem 1.1rem .45rem .35rem;
  white-space: nowrap;
  transition: background-color .3s ease, color .3s ease;
}
.pill-btn:hover {
  background: #000;
  color: rgb(var(--accent)) !important;
}
.pill-btn__icon {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  position: relative;
  background: #000;
  color: rgb(var(--accent));
  border-radius: 50%;
  display: grid;
  place-items: center;
  overflow: hidden;
  transition: background-color .3s ease, color .3s ease;
}
.pill-btn:hover .pill-btn__icon {
  background: rgb(var(--accent));
  color: #0d0f10;
}
/* Modo claro: o mesmo esquema do escuro destoava do resto do tema —
   fundo do hover preto ficava pesado demais, e texto/ícone escuros no
   estado parado ficavam com pouco contraste ali. No claro (exceto lima,
   que já é clara demais pra texto branco): texto/ícone parados ficam
   brancos, e o hover usa um cinza quase branco em vez de preto. */
.light .pill-btn:hover { background: #f4f4f5; }
/* Ampliado de ".pill-btn.on-accent-text" pra ".on-accent-text" puro: essa
   classe também é usada fora de pill-btn (ex.: card sólido "Chamados
   Resolvidos", botões "Salvar"/"OK", badges de notificação) — todos com
   fundo sólido na cor do tema, e ficavam com texto quase preto (herdado do
   ambiente claro) em paletas mais escuras que a lima padrão, sem contraste
   nenhum contra o próprio fundo. */
.light[data-palette] .on-accent-text { color: #fff; }
/* Não era a seta (já estava certa, na cor do tema) — era o CÍRCULO atrás
   dela que ficava preto, destoando do texto branco ao lado. Círculo agora
   branco (mesma cor do texto), seta de volta pra cor do tema (contraste
   contra o círculo branco). */
.light[data-palette] .pill-btn__icon { background: #fff; color: rgb(var(--accent)); }
/* Lima sobre esse cinza quase branco do hover ficaria ilegível — mantém
   texto escuro mesmo no hover só pra esse caso (paleta padrão, sem
   [data-palette] no <html>). */
.light:not([data-palette]) .pill-btn:hover { color: #0d0f10 !important; }
/* Paletas de marca (azul/laranja/etc., não a lima padrão) no claro: hover
   ESCURECE a própria cor do tema (feito com o botão real do TOPDesk),
   em vez de virar cinza quase branco — pedido: "veja ele selecionado e
   não selecionado" comparando com o azul do TOPDesk, que escurece a MESMA
   cor no estado ativo/hover, não troca pra cinza. Mais específico que a
   regra `.light .pill-btn:hover` acima, então vence pra quem tem paleta. */
.light[data-palette] .pill-btn:hover {
  background: color-mix(in srgb, rgb(var(--accent)) 78%, #000);
  color: #fff !important;
}
.light[data-palette] .pill-btn:hover .pill-btn__icon {
  background: #fff;
  color: color-mix(in srgb, rgb(var(--accent)) 78%, #000);
}
.pill-btn__icon-svg--copy {
  position: absolute;
  transform: translate(-150%, 150%);
}
.pill-btn:hover .pill-btn__icon-svg:not(.pill-btn__icon-svg--copy) {
  transition: transform .3s ease-in-out;
  transform: translate(150%, -150%);
}
.pill-btn:hover .pill-btn__icon-svg--copy {
  transition: transform .3s ease-in-out .1s;
  transform: translate(0);
}

/* Seletor "Visão: Time todo | Meu grupo" no cabeçalho do Dashboard. Escondido por
   padrão; aparece (desktop) quando updateGroupSwitch põe data-on="true". */
#groupSwitchWrap { display: none; }
#groupSwitchWrap[data-on="true"] { display: flex; }
@media (max-width: 639px) { #groupSwitchWrap[data-on="true"] { display: none; } }
.group-switch { appearance: none; -webkit-appearance: none; padding-right: 16px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a1a1aa' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 0 center; background-size: 12px; }
.group-switch option { background: #1a1c1e; color: #e5e7eb; }
.light .group-switch option { background: #FAF8F5; color: #2B2D2F; }

/* Variante secundária ("Ver todos…" no rodapé dos painéis): contorno e texto
   neutros, a cor do tema só aparece no ícone e no hover. Assim o laranja fica
   reservado pra ação principal e os números dos painéis lideram a leitura.
   Mais específico que .pill-btn/.light .pill-btn (vem depois no arquivo). */
.pill-btn.pill-btn--ghost {
  background: transparent;
  border: 1px solid rgba(255, 255, 255, .14);
  color: #d4d4d8;
}
.pill-btn.pill-btn--ghost .pill-btn__icon { background: rgb(var(--accent) / .16); color: rgb(var(--accent)); }
.pill-btn.pill-btn--ghost:hover {
  background: rgba(255, 255, 255, .05);
  border-color: rgb(var(--accent) / .55);
  color: rgb(var(--accent)) !important;
}
.pill-btn.pill-btn--ghost:hover .pill-btn__icon { background: rgb(var(--accent)); color: #0d0f10; }
.light .pill-btn.pill-btn--ghost { background: transparent; border-color: #E5DFD1; color: #2B2D2F; }
.light .pill-btn.pill-btn--ghost:hover { background: #f4f1ea; border-color: rgb(var(--accent) / .6); color: #2B2D2F !important; }
.light[data-palette] .pill-btn.pill-btn--ghost .pill-btn__icon,
.light .pill-btn.pill-btn--ghost .pill-btn__icon { background: rgb(var(--accent) / .16); color: rgb(var(--accent)); }
.light .pill-btn.pill-btn--ghost:hover .pill-btn__icon { background: rgb(var(--accent)); color: #fff; }

/* Cartões clicáveis do Dashboard: hover discreto (borda mais clara + seta
   neutra), sem cor de tema — o cartão não "sobe" (decisão antiga) nem pinta. */
/* Mesmo hover discreto dos cards PCM/PCA (.pcm-tile): borda e brilho de canto na cor do tema, sombra
   suave, rótulo na cor do tema. A seta continua apontando para a DIREITA (a dos PCM/PCA é diagonal).
   Só onde há mouse de verdade.
   ATENÇÃO: NÃO usar `isolation`/`z-index` no .stat-card. Isso cria uma camada de empilhamento própria e
   prende o menu de período do card "Resolvidos" (que sai para fora do card) ABAIXO dos cards seguintes
   (PCM/PCA) — o menu ficava coberto e sem clique. O brilho fica atrás do texto porque os filhos diretos
   são posicionados e vêm DEPOIS do ::before na ordem de pintura. */
.stat-card { transition: border-color .25s ease, box-shadow .25s ease; }
.stat-card::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(120% 100% at 100% 0%, rgb(var(--accent) / .12), transparent 62%);
  opacity: 0;
  transition: opacity .3s ease;
  pointer-events: none;
}
.stat-card > :not(.stat-chevron) { position: relative; }
.stat-label { transition: color .25s ease; }
.stat-chevron {
  position: absolute; right: 14px; bottom: 12px; width: 16px; height: 16px;
  color: var(--accent-ink); opacity: 0; transform: translateX(-4px);
  transition: opacity .25s ease, transform .25s ease; pointer-events: none;
}
@media (hover: hover) {
  .stat-card:has(button):hover {
    border-color: rgb(var(--accent) / .5);
    box-shadow: 0 10px 22px -14px rgb(var(--accent) / .55);
  }
  .stat-card:has(button):hover::before { opacity: 1; }
  .stat-card:has(button):hover .stat-label { color: var(--accent-ink); }
  .stat-card:hover .stat-chevron { opacity: .9; transform: none; }
}
@media (prefers-reduced-motion: reduce) { .stat-card, .stat-card::before, .stat-label, .stat-chevron { transition: none; } }

/* ---- Botão "Ver" (linha da grid de Chamados) ---------------------------
   Inspirado num design da Uiverse.io (by vinodjangid07), adaptado pros
   tokens de tema do app: cor fixa do exemplo original trocada por
   rgb(var(--accent)) (acompanha a paleta escolhida em qualquer tema) e o
   ícone de salvar trocado por um olho (a ação aqui é "ver", não salvar).
   Hover: a pílula colorida do ícone cresce e cobre o botão inteiro,
   empurrando o texto "Ver" pra fora (encolhe a zero). */
.view-btn {
  width: 84px;
  height: 34px;
  border-radius: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  overflow: hidden;
}
.view-btn__icon {
  width: 26px;
  height: 26px;
  background: rgb(var(--accent));
  border-radius: 50px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  flex-shrink: 0;
  z-index: 2;
  transition: width .3s;
}
.view-btn__text {
  height: 100%;
  width: 50px;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1;
  font-size: .75rem;
  font-weight: 600;
  transition: width .3s, transform .3s, font-size .3s;
}
.view-btn:hover .view-btn__icon { width: 76px; }
.view-btn:hover .view-btn__text { transform: translateX(10px); width: 0; font-size: 0; }
.view-btn:active { transform: scale(.95); }

/* ===== Impressão / Exportar PDF =========================================
   Some o cabeçalho/menu inteiro e qualquer modal/toast — só o conteúdo da
   página (cards + grid) é impresso. O tema claro é forçado via JS antes de
   chamar window.print() (ver exportSlaPdf), então aqui só cuidamos de
   remover sombras/animações que não fazem sentido em papel e garantir que
   a tabela quebre de página de forma legível. */
@media print {
  #sidebar, header, #presentBtn, #toast, #modal,
  #exportSlaPdfBtn, #exportXlsxBtn, .no-print {
    display: none !important;
  }
  body, main#view {
    background: #fff !important;
    max-width: 100% !important;
    padding: 0 !important;
    margin: 0 !important;
  }
  .lift, .shadow-card, .shadow-hover { box-shadow: none !important; }
  table { page-break-inside: auto; }
  tr { page-break-inside: avoid; page-break-after: auto; }
  thead { display: table-header-group; } /* repete o cabeçalho da tabela em cada página impressa */
}

/* ===== Cartões do banner "SLA ao vivo" =====
   O cartão inteiro reflete o status — verde (No Prazo/tranquilo), amarelo
   (Atenção/aguardando), vermelho (Crítico/estourado) — só cor de fundo e
   borda, sem grossura extra nem brilho. */
.fr-card-ok {
  background: rgb(var(--ok) / .16) !important;
  border-color: rgb(var(--ok) / .5) !important;
}
.fr-card-warn {
  background: rgb(var(--warn) / .16) !important;
  border-color: rgb(var(--warn) / .5) !important;
}
.fr-card-crit {
  background: rgb(var(--crit) / .18) !important;
  border-color: rgb(var(--crit) / .5) !important;
}
/* Aguardando 1ª resposta: amarelo (Atenção) -> .fr-card-crit na janela de alerta (Crítico) -> .fr-card-exp ao vencer (Expirado, vermelho mais
   fechado). A cor do Expirado vem de --fr-stage-c (paleta do SLA, inclusive no modo Daltonismo), definida pelo cronômetro. */
.fr-card-exp {
  background: color-mix(in srgb, var(--fr-stage-c, #A32828) 22%, transparent) !important;
  border-color: color-mix(in srgb, var(--fr-stage-c, #A32828) 65%, transparent) !important;
}

/* ===== Seletor de período (card "Resolvidos no Ciclo") =====
   A lista suspensa de um <select> é renderizada pelo navegador/SO, fora do
   nosso controle de estilo normal — classes Tailwind no <select> não
   chegam até as <option> na maioria dos navegadores. Sem isso, a lista
   aberta ficava com fundo claro e fonte clara (herdado do padrão do
   sistema), quase ilegível. Definindo direto nas <option>, garante contraste
   em qualquer navegador, independente do tema do sistema operacional. */
.closed-range-select option {
  background: #1a1a1f;
  color: #e4e4e7;
}
.light .closed-range-select option {
  background: #ffffff;
  color: #18181b;
}

/* Remove as setinhas nativas de aumentar/diminuir dos inputs numéricos
   (spinner) — feias e desnecessárias num painel; digita-se o valor direto. */
input[type="number"].no-spinner::-webkit-inner-spin-button,
input[type="number"].no-spinner::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
input[type="number"].no-spinner {
  -moz-appearance: textfield;
  appearance: textfield;
}

/* Expandir/recolher suave dos blocos de cidade em Configurações de SLA —
   transição de max-height (mesma técnica do "ver mais" da linha do tempo);
   a altura em px é medida em JS (scrollHeight) na hora de abrir/fechar. */
.city-config {
  overflow: hidden;
  max-height: 0;
  transition: max-height .3s cubic-bezier(.22, 1, .36, 1);
}

/* Transição suave entre telas/atualizações (ver paint() em app.js) — o
   navegador já faz o crossfade sozinho via View Transitions API; aqui só
   ajustamos a duração/curva pra ficar rápido e discreto (não uma
   animação chamativa). */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 140ms;
  animation-timing-function: ease-out;
}
/* Troca de tema claro/escuro (toggleTheme em app.js): crossfade entre a "foto" da tela antiga e a da nova.
   Um pouco mais longo que o das telas (a mudança de luminosidade é grande e um corte rápido parece piscada),
   mas ainda curto e discreto. A classe só existe durante a transição. */
html.theme-vt::view-transition-old(root),
html.theme-vt::view-transition-new(root) {
  animation-duration: 360ms;
  animation-timing-function: cubic-bezier(.4, 0, .2, 1);
}

/* ==================================================================== *
 * Camada de qualidade — o "acabamento invisível" que separa um front
 * bonito de um profissional: foco de teclado acessível, respeito ao
 * "reduzir movimento" do SO, seleção de texto na cor do tema, sem o
 * flash cinza de toque no mobile e scrollbar temática no Firefox.
 * Tudo aqui é ADITIVO — não toca layout, cores nem as transições já
 * existentes (só acrescenta propriedades que não conflitam com elas).
 * ==================================================================== */

/* ---- Foco de teclado (WCAG 2.4.7) ----------------------------------
   Anel na cor do tema, visível SÓ quando o foco veio do teclado
   (:focus-visible) — quem usa mouse não vê nada mudar. Usa --accent-ink
   (accent escurecido no claro) pra ler bem sobre fundo claro também.
   :where() mantém especificidade 0: qualquer elemento que já tenha um
   foco próprio (ex.: .info-tip) continua vencendo. */
:where(a, button, [role="button"], input, select, textarea, summary,
       [tabindex]:not([tabindex="-1"])):focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: 2px;
}
/* Some o anel só quando o foco veio do mouse/toque (mantém o padrão do
   navegador de não poluir o clique), preservando-o pra navegação por Tab. */
:where(a, button, [role="button"], summary,
       [tabindex]:not([tabindex="-1"])):focus:not(:focus-visible) {
  outline: none;
}
/* ---- Seleção de texto na cor do tema -------------------------------
   Em vez do azul padrão do navegador — leve tinta do accent com texto
   preto por cima (legível em qualquer paleta). */
::selection { background: rgb(var(--accent) / .28); color: #0d0f10; }
.light ::selection { background: rgb(var(--accent) / .35); color: #0d0f10; }

/* ---- Toque no mobile ------------------------------------------------
   Remove o retângulo cinza/azul que o WebKit pisca a cada toque — os
   nossos próprios estados (hover/active) já dão o feedback. */
html { -webkit-tap-highlight-color: transparent; }

/* ---- Scrollbar no Firefox ------------------------------------------
   O ::-webkit-scrollbar acima só pega Chrome/Edge/Safari; aqui a versão
   padronizada (fina + polegar temático) pro Firefox, nos dois temas. */
* { scrollbar-width: thin; scrollbar-color: #34343a transparent; }
.light * { scrollbar-color: #c7c7cd transparent; }

/* ---- Respeitar "reduzir movimento" do sistema ----------------------
   Quando o usuário pede menos animação no SO, neutraliza as animações
   decorativas (glow, ping, shimmer, reveals, modal, view-transition) e
   encurta as transições — sem quebrar o layout, só remove o movimento. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ===== Botão "slide" — rótulo desliza pra fora e o ícone assume no hover ===
   Usado nos botões de ação com texto dos modais (salvar/cancelar/criar/etc.)
   da aba Usuários e da troca de senha. Portado do projeto de login antigo. */
.btn-slide {
  position: relative;
  overflow: hidden;
  padding-right: 2.75rem;
}
.btn-slide__label {
  display: inline-block;
  transition: transform .3s ease, opacity .3s ease;
}
.btn-slide__icon {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 2.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: inherit;
  transition: width .3s ease;
}
.btn-slide:hover .btn-slide__label,
.btn-slide:focus-visible .btn-slide__label {
  transform: translateX(140%);
  opacity: 0;
}
.btn-slide:hover .btn-slide__icon,
.btn-slide:focus-visible .btn-slide__icon {
  width: 100%;
}

/* ===== Botão de favoritar (coração) — rodapé do modal =================
   Coração VAZADO por padrão; ao passar o mouse ele "preenche" (o fill anima
   de transparente pra vermelho) com um leve pop; quando o chamado JÁ é
   favorito (.is-fav) fica preenchido de vermelho fixo. Ver #modalFavBtn em
   app.js (modalFooterHtml). */
.fav-btn { color: #71717a; transition: color .25s ease, border-color .25s ease, background-color .25s ease; }
.light .fav-btn { color: #a1a1aa; }
.fav-btn:hover, .fav-btn.is-fav { color: rgb(var(--crit)); border-color: rgb(var(--crit) / .4); }
/* Dois corações sobrepostos: o de CONTORNO fica sempre visível (segue a cor
   do botão); o PREENCHIDO (vermelho) é revelado de BAIXO pra CIMA via
   clip-path — o efeito "enchendo um copo d'água" pedido. Ao tirar o
   hover/desfavoritar, esvazia de cima pra baixo, na mesma animação. */
.fav-heart { transition: transform .25s cubic-bezier(.34, 1.56, .64, 1); }
.fav-btn:hover .fav-heart, .fav-btn.is-fav .fav-heart { transform: scale(1.1); }
.fav-heart-fill { color: rgb(var(--crit)); clip-path: inset(100% 0 0 0); transition: clip-path .5s cubic-bezier(.4, 0, .2, 1); }
.fav-btn:hover .fav-heart-fill,
.fav-btn.is-fav .fav-heart-fill { clip-path: inset(0 0 0 0); }

/* Saída de um card na aba Favoritos ao remover — some na hora, com animação,
   sem recarregar a página nem mostrar skeleton (ver removeFavCardAnimated). */
@keyframes favExit {
  to { opacity: 0; transform: scale(.92) translateY(-6px); }
}
.fav-exit { animation: favExit .2s cubic-bezier(.4, 0, .2, 1) forwards; pointer-events: none; }
/* Aviso "Removido dos favoritos — Desfazer" no lugar do card: a barrinha na base se esgota no prazo de desfazer (FAV_UNDO_MS = 7 s em app.js). */
.fav-undo-bar {
  position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: rgb(var(--accent) / .65); transform-origin: left center;
  animation: favUndoBar 7s linear forwards;
}
@keyframes favUndoBar { from { transform: scaleX(1); } to { transform: scaleX(0); } }
@media (prefers-reduced-motion: reduce) { .fav-undo-bar { animation: none; } }

/* Card de chamado minimizado (dock no rodapé, estilo SofaScore) — entra
   deslizando de baixo pra cima. */
@keyframes minChipIn { from { opacity: 0; transform: translateY(14px) scale(.96); } to { opacity: 1; transform: none; } }
.min-chip { animation: minChipIn .22s cubic-bezier(.22, 1, .36, 1) both; }

/* ===== Login (hero esquerdo): grid animado + contato do mouse ==========
   Linhas de luz na cor da marca percorrem o grid (horizontais descendo,
   verticais atravessando). No hover, um brilho radial e um recorte do grid
   acendem seguindo o cursor (--mx/--my atualizados em login.js). Sob
   prefers-reduced-motion o bloco global acima já congela as animações. */
/* Brilho radial que segue o cursor */
.login-contact {
  opacity: 0;
  transition: opacity .35s ease;
  background: radial-gradient(240px circle at var(--mx, 50%) var(--my, 50%),
    rgb(var(--accent) / .22), transparent 62%);
}
/* Grid na cor da marca, revelado só num círculo ao redor do cursor */
.login-contact-grid {
  opacity: 0;
  transition: opacity .35s ease;
  background-image:
    linear-gradient(rgb(var(--accent) / .55) 1px, transparent 1px),
    linear-gradient(90deg, rgb(var(--accent) / .55) 1px, transparent 1px);
  background-size: 44px 44px;
  -webkit-mask-image: radial-gradient(190px circle at var(--mx, 50%) var(--my, 50%), #000 0%, transparent 66%);
  mask-image: radial-gradient(190px circle at var(--mx, 50%) var(--my, 50%), #000 0%, transparent 66%);
}
#loginHero:hover .login-contact,
#loginHero:hover .login-contact-grid { opacity: 1; }

/* Setor ao lado de "Dashboard": texto + ponto na cor do setor (--tc, definida em app.js). É contexto,
   não ação, então não parece botão. Só vira controle (chevron, hover, menu) para quem tem mais de um
   setor liberado: classe .is-switchable, posta por setupTeamFlag em app.js. */
.team-flag {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 7px;
  margin: -5px -7px; /* área de clique maior sem mexer no layout */
  border-radius: 9px;
  font-weight: 700;
  letter-spacing: .08em;
  white-space: nowrap;
  color: color-mix(in srgb, var(--tc, #767980) 80%, #fff);
  transition: background-color .2s ease;
}
.light .team-flag { color: color-mix(in srgb, var(--tc, #767980) 68%, #000); } /* contraste no fundo claro */
/* `display: inline-flex` acima vence o `hidden` do Tailwind (styles.css carrega depois): sem esta regra o
   setor vazio aparecia fora do Dashboard e enquanto o sistema carregava. */
.team-flag.hidden { display: none; }
.team-flag-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--tc, #767980); flex-shrink: 0; }
.team-flag-chevron { display: none; width: 12px; height: 12px; opacity: .75; transition: transform .2s ease; }
.team-flag.is-switchable { cursor: pointer; }
.team-flag.is-switchable .team-flag-chevron { display: block; }
.team-flag[aria-expanded="true"] .team-flag-chevron { transform: rotate(180deg); }
.team-flag[aria-expanded="true"] { background: color-mix(in srgb, var(--tc, #767980) 14%, transparent); }
@media (hover: hover) {
  .team-flag.is-switchable:hover { background: color-mix(in srgb, var(--tc, #767980) 14%, transparent); }
}

/* Menu para trocar de setor (só quem tem mais de um). */
.team-menu-title { padding: 8px 12px 6px; font-size: 10px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: #71717a; }
.team-menu-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 12px;
  border-radius: 12px;
  text-align: left;
  font-size: 13px;
  font-weight: 600;
  color: #E5E7EB;
  transition: background-color .15s ease;
}
.light .team-menu-item { color: #2B2D2F; }
.team-menu-item:hover, .team-menu-item:focus-visible { background: rgb(var(--accent) / .12); }
.team-menu-item[aria-selected="true"] { cursor: default; }
.team-menu-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.team-menu-check { margin-left: auto; width: 15px; height: 15px; color: var(--accent-ink); flex-shrink: 0; }

/* Aviso "Trocando para <setor>…": cartão no CENTRO da tela sobre um fundo esmaecido que bloqueia cliques
   enquanto o setor troca (a página recarrega em seguida). */
.team-switch-overlay {
  position: fixed;
  inset: 0;
  z-index: 95;
  display: grid;
  place-items: center;
  padding: 24px;
  background: rgba(8, 9, 10, .55);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s ease;
}
.team-switch-overlay.is-visible { opacity: 1; pointer-events: auto; }
.light .team-switch-overlay { background: rgba(40, 36, 28, .35); }
.team-switch-card {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 18px 24px;
  border-radius: 20px;
  background: #17181a;
  border: 1px solid rgba(255,255,255,.08);
  box-shadow: 0 24px 60px -20px rgba(0,0,0,.7);
  color: #E5E7EB;
  transform: translateY(6px) scale(.97);
  transition: transform .22s cubic-bezier(.16,1,.3,1);
}
.team-switch-overlay.is-visible .team-switch-card { transform: none; }
.light .team-switch-card { background: #FAF8F5; border-color: #E5DFD1; color: #2B2D2F; box-shadow: 0 24px 60px -24px rgba(60,50,30,.45); }
.team-switch-spinner {
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 3px solid rgba(255,255,255,.14);
  border-top-color: var(--tc, #767980);
  animation: spin .8s linear infinite;
}
.light .team-switch-spinner { border-color: rgba(0,0,0,.1); border-top-color: var(--tc, #767980); }
.team-switch-title { font-size: 15px; font-weight: 600; line-height: 1.3; }
.team-switch-title b { font-weight: 800; }
.team-switch-sub { margin-top: 2px; font-size: 12px; color: #a1a1aa; }
.light .team-switch-sub { color: #71717a; }
@media (prefers-reduced-motion: reduce) {
  .team-switch-overlay, .team-switch-card { transition: none; }
  .team-switch-spinner { animation-duration: 2s; }
}


/* ---- Cards PCM / PCA do Dashboard: hover discreto ---------------------
   Só na cor do tema: borda e leve brilho de canto aparecem, o rótulo ganha a cor do
   tema e uma setinha entra no canto indicando que o card leva à lista filtrada. Sem
   zoom nem salto. Só onde há mouse de verdade (hover:hover) — no toque não gruda. */
.pcm-tile {
  position: relative;
  overflow: hidden;
  transition: border-color .25s ease, box-shadow .25s ease, transform .2s ease;
}
.pcm-tile::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 100% at 100% 0%, rgb(var(--accent) / .12), transparent 62%);
  opacity: 0;
  transition: opacity .3s ease;
  pointer-events: none;
}
.pcm-tile > * { position: relative; }
.pcm-tile-label { transition: color .25s ease; }
.pcm-tile-arrow {
  position: absolute !important;
  top: 11px;
  right: 11px;
  width: 15px;
  height: 15px;
  color: var(--accent-ink);
  opacity: 0;
  transform: translate(-3px, 3px);
  transition: opacity .25s ease, transform .25s ease;
}
@media (hover: hover) {
  .pcm-tile:hover {
    border-color: rgb(var(--accent) / .5);
    box-shadow: 0 10px 22px -14px rgb(var(--accent) / .55);
  }
  .pcm-tile:hover::before { opacity: 1; }
  .pcm-tile:hover .pcm-tile-label { color: var(--accent-ink); }
  .pcm-tile:hover .pcm-tile-arrow { opacity: .9; transform: translate(0, 0); }
}
.pcm-tile:active { transform: scale(.985); }
@media (prefers-reduced-motion: reduce) {
  .pcm-tile, .pcm-tile::before, .pcm-tile-label, .pcm-tile-arrow { transition: none; }
}

/* ---- Tooltip temático ÚNICO (data-tip) --------------------------------
   Substitui a legenda branca nativa do navegador (atributo title). Um só elemento
   position:fixed, criado e posicionado por JS (setupUiTooltips em app.js) — não é cortado
   por overflow:hidden (a barra de SLA tem). Mesma linguagem visual do .info-tip-bubble. */
.ui-tooltip {
  position: fixed;
  z-index: 80;
  top: 0; left: 0;
  display: flex;
  align-items: center;
  gap: 7px;
  width: max-content;
  max-width: min(280px, calc(100vw - 16px)); /* em tela estreita nunca passa da janela */
  padding: 7px 11px;
  border-radius: 10px;
  background: #0a0a0b;
  color: #fafafa;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.35;
  overflow-wrap: anywhere;
  box-shadow: 0 8px 24px -6px rgba(0,0,0,.5);
  border: 1px solid rgba(255,255,255,.08);
  opacity: 0;
  pointer-events: none;
  transform: translateY(var(--tip-shift, 4px)) scale(.96);
  transition: opacity .16s cubic-bezier(.16,1,.3,1), transform .16s cubic-bezier(.16,1,.3,1);
}
.light .ui-tooltip { background: #18181b; color: #fafafa; }
.ui-tooltip.is-visible { opacity: 1; transform: translateY(0) scale(1); }
.ui-tooltip-dot { width: 8px; height: 8px; border-radius: 999px; flex-shrink: 0; }
.ui-tooltip-dot[hidden] { display: none; }
@media (prefers-reduced-motion: reduce) { .ui-tooltip { transition: none; } }

/* ---- Resumo "no prazo" da Distribuição SLA: pílula com anel de progresso ---- */
/* O resumo "% no prazo" (32 px) some quando não há chamado em SLA — a linha do título reserva a mesma altura, senão o painel mudava de tamanho. */
.sla-dist-head { min-height: 32px; }
.sla-kpi {
  --ring-track: rgba(255,255,255,.14);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 32px;
  padding: 0 14px 0 6px;
  border-radius: 999px;
  background: var(--kbg);
  border: 1px solid var(--kbd);
  white-space: nowrap;
  cursor: default;
}
.light .sla-kpi { --ring-track: rgba(0,0,0,.12); }
.sla-ring {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  border-radius: 50%;
  background: conic-gradient(var(--c) calc(var(--p) * 1%), var(--ring-track) 0);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3.5px), #000 calc(100% - 3px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 3.5px), #000 calc(100% - 3px));
}
.sla-kpi-num {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 15px;
  font-weight: 800;
  line-height: 1;
  color: #E5E7EB;
}
.light .sla-kpi-num { color: #2B2D2F; }
.sla-kpi-label { font-size: 12px; font-weight: 600; color: #d4d4d8; }
.light .sla-kpi-label { color: #52525b; }
.sla-kpi-count { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 11.5px; font-weight: 600; color: #a1a1aa; }
.light .sla-kpi-count { color: #71717a; }
.sla-kpi-dot { margin-right: 8px; opacity: .6; }

/* Configurações de SLA em modo somente leitura (quem não é admin): campos travados mais apagados. */
#setCitiesList input:disabled { opacity: .6; cursor: not-allowed; }

/* Painel "SLA ao vivo" COMPACTO: usado só quando 6 chamados (2 linhas) não cabem na altura da coluna de cards ao
   lado com o espaçamento normal (ver fitSlaExtras em app.js). Espaços e textos mais justos, sem mexer em cores,
   fontes ou na informação mostrada — só a descrição passa a ocupar 1 linha (completa no detalhe do chamado). */
.sla-compact .sla-crit-card { padding: .6rem .8rem; }
.sla-compact .sla-c-badges { margin-bottom: .4rem; }
.sla-compact .sla-c-subject { margin-top: .3rem; -webkit-line-clamp: 1; line-clamp: 1; min-height: 1.25rem; }
.sla-compact .sla-c-footer { padding-top: .45rem; }
.sla-compact .sla-c-grid { gap: .5rem; }
.sla-compact .sla-c-dist { margin-top: .6rem; padding-top: .6rem; }


/* ---- Aba Chamados: atalhos rápidos, filtros ativos, "Mais filtros", linha clicável, painel lateral recolhível ---- */
.quick-chip {
  display: inline-flex; align-items: center; gap: .45rem;
  padding: .32rem .75rem; border-radius: 999px;
  font-size: .75rem; font-weight: 600; line-height: 1.2; white-space: nowrap;
  color: rgb(161 161 170); border: 1px solid rgb(var(--line)); background: transparent;
  transition: background-color .15s, border-color .15s, color .15s, opacity .15s;
}
.light .quick-chip { color: rgb(82 82 91); border-color: #E5DFD1; }
.quick-chip:hover { border-color: rgb(var(--accent) / .5); color: rgb(var(--accent)); }
.quick-chip[data-active="true"] { background: rgb(var(--accent) / .14); border-color: rgb(var(--accent) / .55); color: rgb(var(--accent)); }
.quick-chip.is-zero { opacity: .5; }
.quick-chip.is-zero:hover { opacity: 1; }
.quick-chip:focus-visible, .more-filters-btn:focus-visible, .active-chip:focus-visible { outline: 2px solid rgb(var(--accent) / .6); outline-offset: 2px; }
.quick-dot { width: .5rem; height: .5rem; border-radius: 999px; flex: none; }
.quick-count {
  min-width: 1.35rem; padding: .05rem .4rem; border-radius: 999px; text-align: center;
  font-size: .6875rem; background: rgb(255 255 255 / .08); color: inherit;
}
.light .quick-count { background: rgb(0 0 0 / .06); }
.quick-chip[data-active="true"] .quick-count { background: rgb(var(--accent) / .2); }

/* ===== Central de notificações (sino) ===== */
.notif-day {
  position: sticky; top: 0; z-index: 1; padding: .55rem 1rem .4rem;
  font-size: .625rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: rgb(113 113 122);
}
.notif-group { transition: background-color .15s ease; }
.notif-group .notif-main { cursor: pointer; }
.notif-group .notif-main:focus-visible { outline: 2px solid rgb(var(--accent) / .7); outline-offset: -2px; }
.notif-group:hover { background: rgb(255 255 255 / .04); }
.light .notif-group:hover { background: rgb(0 0 0 / .03); }
.notif-group.is-unread { background: rgb(var(--accent) / .07); box-shadow: inset 3px 0 0 rgb(var(--accent)); }
.notif-group.is-unread:hover { background: rgb(var(--accent) / .11); }
.notif-count { padding: .05rem .45rem; border-radius: 999px; font-size: .625rem; font-weight: 700; background: rgb(var(--accent) / .16); color: var(--accent-ink); }
.notif-read-btn { opacity: 0; transition: opacity .15s ease, background-color .15s ease, color .15s ease; }
.notif-group:hover .notif-read-btn, .notif-read-btn:focus-visible { opacity: 1; }
@media (hover: none) { .notif-read-btn { opacity: 1; } }
/* ---- Microinterações da central de notificações (botões, abas, opções): transições curtas e discretas ---- */
.nbtn { transition: color .16s ease, background-color .16s ease, border-color .16s ease, box-shadow .16s ease, transform .16s ease; }
.nbtn:active { transform: scale(.95); }
.nbtn:focus-visible { outline: 2px solid rgb(var(--accent) / .7); outline-offset: 2px; }
.nbtn svg { transition: transform .22s cubic-bezier(.22, 1, .36, 1); }
.nbtn-icon:hover svg { transform: scale(1.12); }
[data-notif-back]:hover svg { transform: translateX(-2px); }
.notif-chip[aria-pressed="true"], .notif-chip[aria-pressed="true"]:hover { background: rgb(var(--accent) / .15); border-color: rgb(var(--accent) / .5); color: rgb(var(--accent)); }
.notif-opt[aria-pressed="true"], .notif-opt[aria-pressed="true"]:hover { background: rgb(var(--accent) / .1); border-color: rgb(var(--accent) / .5); }
.notif-opt:active { transform: scale(.985); }
.notif-radio { width: 16px; height: 16px; flex: none; border-radius: 999px; border: 2px solid rgb(113 113 122); display: grid; place-items: center; transition: border-color .18s ease; }
.notif-radio > span { width: 6px; height: 6px; border-radius: 999px; background: rgb(var(--accent)); transform: scale(0); transition: transform .22s cubic-bezier(.34, 1.56, .64, 1); }
.notif-opt[aria-pressed="true"] .notif-radio { border-color: rgb(var(--accent)); }
.notif-opt[aria-pressed="true"] .notif-radio > span { transform: scale(1); }
/* Corpo rolável: nunca passa da altura da janela (as preferências eram cortadas em tela baixa); rolagem fina e visível nas preferências */
.notif-body { max-height: min(calc(100vh - 9rem), 640px); overflow-y: auto; overscroll-behavior: contain; }
.notif-scroll { scrollbar-width: thin; scrollbar-color: rgb(113 113 122 / .5) transparent; }
@keyframes notifPillIn { from { transform: scale(.88); opacity: .35; } to { transform: none; opacity: 1; } }
.notif-pill-in { animation: notifPillIn .24s cubic-bezier(.22, 1, .36, 1) backwards; }
@keyframes notifViewFwd { from { opacity: 0; transform: translateX(14px); } to { opacity: 1; transform: none; } }
@keyframes notifViewBack { from { opacity: 0; transform: translateX(-14px); } to { opacity: 1; transform: none; } }
.notif-view-fwd { animation: notifViewFwd .22s cubic-bezier(.22, 1, .36, 1) backwards; }
.notif-view-back { animation: notifViewBack .22s cubic-bezier(.22, 1, .36, 1) backwards; }
@media (prefers-reduced-motion: reduce) { .notif-pill-in, .notif-view-fwd, .notif-view-back { animation: none; } .nbtn:active, .notif-opt:active { transform: none; } }
/* Chave liga/desliga das preferências */
.notif-switch { position: relative; width: 38px; height: 22px; border-radius: 999px; flex: none; background: rgb(113 113 122 / .45); transition: background-color .18s ease; cursor: pointer; }
.notif-switch__dot { position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 999px; background: #fff; box-shadow: 0 1px 3px rgb(0 0 0 / .35); transition: transform .18s ease; }
.notif-switch[aria-checked="true"] { background: rgb(var(--accent)); }
.notif-switch[aria-checked="true"] .notif-switch__dot { transform: translateX(16px); }
.notif-switch:disabled { opacity: .45; cursor: not-allowed; }
.notif-switch:focus-visible { outline: 2px solid rgb(var(--accent) / .7); outline-offset: 2px; }
/* Aviso em tela de notificação nova: entra de baixo, discreto */
.notif-toast { animation: notifToastIn .28s cubic-bezier(.22, 1, .36, 1) both; }
@keyframes notifToastIn { from { opacity: 0; transform: translateY(14px) scale(.98); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .notif-toast { animation: none; } .notif-switch, .notif-switch__dot { transition: none; } }

/* Linha "N registros no total · página X de Y" do topo de Chamados: o total em destaque (sem o título repetido ao lado). */
#ticketsStatsLine .stats-total { font-weight: 700; color: #D4D4D8; }
.light #ticketsStatsLine .stats-total { color: #3F3F46; }

/* Cards de SLA do topo de Chamados: MESMO hover dos cards clicáveis do Dashboard (.stat-card): o card "acende" (brilho de canto, borda e
   sombra) e a seta .stat-chevron desliza para dentro — só que na cor do STATUS do card (--sla-c), não na do tema, para o verde/amarelo/
   vermelho continuarem dizendo qual é qual. Altura fixa: só cor/opacidade/transform animam. Ativo = borda + anel interno na cor do status. */
.sla-stat-card { position: relative; min-height: 5.5rem; cursor: pointer; transition: border-color .25s ease, box-shadow .25s ease; }
.sla-stat-card::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(120% 100% at 100% 0%, color-mix(in srgb, var(--sla-c) 16%, transparent), transparent 62%);
  opacity: 0;
  transition: opacity .3s ease;
  pointer-events: none;
}
.sla-stat-card > :not(.stat-chevron) { position: relative; }
.sla-stat-card .stat-chevron { color: var(--sla-c); }
@media (hover: hover) {
  .sla-stat-card:hover {
    border-color: color-mix(in srgb, var(--sla-c) 55%, transparent);
    box-shadow: 0 10px 22px -14px color-mix(in srgb, var(--sla-c) 65%, transparent);
  }
  .sla-stat-card:hover::before { opacity: 1; }
  .sla-stat-card:hover .stat-chevron { opacity: .9; transform: none; }
}
.sla-stat-card[data-active="true"] { border-color: var(--sla-c); box-shadow: 0 0 0 1px var(--sla-c) inset; }
.sla-stat-card[data-active="true"]::before { opacity: 1; }
.sla-stat-card:focus-visible { outline: 2px solid var(--sla-c); outline-offset: 2px; }
.sla-stat-card:focus-visible .stat-chevron { opacity: .9; transform: none; }
@media (prefers-reduced-motion: reduce) { .sla-stat-card, .sla-stat-card::before { transition: none; } }

.active-chip {
  display: inline-flex; align-items: center; gap: .4rem; max-width: 100%;
  padding: .28rem .6rem .28rem .75rem; border-radius: 999px; font-size: .75rem;
  background: rgb(var(--accent) / .12); border: 1px solid rgb(var(--accent) / .35); color: rgb(var(--accent));
  transition: background-color .15s, border-color .15s;
}
.active-chip:hover { background: rgb(var(--accent) / .2); border-color: rgb(var(--accent) / .6); }
.active-chip-label { opacity: .75; }
.active-chip-value { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 16rem; }

.more-filters-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem; flex: none;
  padding: 0 1rem; min-height: 2.75rem; border-radius: .75rem; font-size: .875rem; font-weight: 600;
  color: rgb(212 212 216); border: 1px solid rgb(var(--line)); background: rgb(var(--ink));
  transition: border-color .15s, color .15s;
}
.light .more-filters-btn { color: rgb(63 63 70); border-color: #E5DFD1; background: #F4F1EA; }
.more-filters-btn:hover, .more-filters-btn[data-open="true"] { border-color: rgb(var(--accent) / .5); color: rgb(var(--accent)); }
.more-filters-chevron { transition: transform .2s; }
.more-filters-btn[data-open="true"] .more-filters-chevron { transform: rotate(180deg); }
.more-filters-badge {
  min-width: 1.25rem; height: 1.25rem; padding: 0 .35rem; border-radius: 999px; display: inline-grid; place-items: center;
  font-size: .6875rem; font-weight: 700; background: rgb(var(--accent)); color: #0d0f10;
}
.light .more-filters-badge { color: #fff; }

/* Linha da grid de Chamados: inteira clicável */
.ticket-row { cursor: pointer; transition: background-color .15s; }
.ticket-row:hover { background: rgb(var(--accent) / .06); }
.ticket-row:focus-visible { outline: 2px solid rgb(var(--accent) / .6); outline-offset: -2px; background: rgb(var(--accent) / .06); }
.ticket-row .row-chevron { opacity: .35; transition: transform .15s, opacity .15s, color .15s; }
.ticket-row:hover .row-chevron, .ticket-row:focus-visible .row-chevron { opacity: 1; transform: translateX(2px); color: rgb(var(--accent)); }

/* Painel lateral (Volume + Atividades) recolhível, COM transição: no desktop as colunas da grade animam entre 7fr/3fr e 1fr/0fr (a lacuna
   também), e o painel some com fade. Abaixo de 1024px o painel vai para baixo da grid e, se escondido, simplesmente sai. */
#sideToggleBtn[data-on="true"] { border-color: rgb(var(--accent) / .45); color: rgb(var(--accent)); }
@media (min-width: 1024px) {
  /* #ticketsLayout é o contêiner de medidas (cqw = a largura dele): o conteúdo de cada coluna tem a largura FINAL fixa (7fr/3fr, ou tudo),
     e a coluna só "revela"/"cobre" esse conteúdo enquanto anima. A tabela é medida UMA vez (sem reflow por quadro) e o gráfico não se
     redimensiona por quadro (antes: Chart.js redesenhava a cada quadro, 230 ms de JS). */
  #ticketsLayout {
    container-type: inline-size; container-name: tlayout;
    grid-template-columns: minmax(0, 7fr) minmax(0, 3fr);
    column-gap: 1rem;
    transition: grid-template-columns .38s cubic-bezier(.22, 1, .36, 1), column-gap .38s cubic-bezier(.22, 1, .36, 1);
  }
  #ticketsLayout[data-side="closed"] { grid-template-columns: minmax(0, 1fr) minmax(0, 0fr); column-gap: 0; }
  #ticketsLayout[data-side="open"] .tickets-main-inner { width: calc((100cqw - 1rem) * .7); }
  #ticketsLayout[data-side="closed"] .tickets-main-inner { width: 100cqw; }
  .tickets-side-inner { width: calc((100cqw - 1rem) * .3); }
  #ticketsLayout > .tickets-side { overflow: hidden; opacity: 1; transition: opacity .26s ease .08s, visibility 0s linear 0s; }
  #ticketsLayout[data-side="closed"] > .tickets-side { opacity: 0; visibility: hidden; pointer-events: none; transition: opacity .18s ease, visibility 0s linear .38s; }
  /* Camadas prontas DESDE O INÍCIO (não criadas ao animar): promover uma camada na hora obriga a rasterizar a tabela inteira no 1º quadro
     (pico de ~100 ms). Com elas já existindo, o navegador só desloca/recorta/esmaece. O recorte no limite da coluna vale só ao animar. */
  .tickets-main-inner, .tickets-side-inner { will-change: transform; }
  #ticketsLayout > .tickets-side { will-change: opacity; }
  #ticketsLayout.is-animating-side > .tickets-main { overflow: hidden; }
}
@media (max-width: 1023.98px) {
  #ticketsLayout[data-side="closed"] > .tickets-side { display: none; }
}

/* Painel recolhível genérico ("Mais filtros", chips dos filtros escondidos): altura de 0 ao conteúdo por grid-template-rows, com fade. */
.collapsible {
  display: grid; grid-template-rows: 0fr; opacity: 0;
  transition: grid-template-rows .3s cubic-bezier(.22, 1, .36, 1), opacity .22s ease;
}
.collapsible[data-open="true"] { grid-template-rows: 1fr; opacity: 1; }
.collapsible > .collapsible-inner { min-height: 0; overflow: hidden; }
.collapsible.is-settled > .collapsible-inner { overflow: visible; }
/* O que vem abaixo do painel recolhível já é camada própria: ao animar a altura o navegador só o desloca, não repinta a tabela a cada quadro. */
#ticketsSubBar, #ticketsLayout { will-change: transform; } /* aberto e parado: as listas dos seletores precisam sair do painel */

/* Colunas da grid de Chamados escondidas por LARGURA REAL da grade (não da janela): com o painel lateral aberto a grade é mais estreita
   que a janela. As de menor prioridade somem primeiro (Status, depois Grupo, depois Empresa) para nunca haver rolagem horizontal no padrão. */
.tickets-main-inner { container-type: inline-size; container-name: tmain; }
@container tmain (max-width: 1200px) { .cq-1200 { display: none !important; } }
@container tmain (max-width: 1040px) { .cq-1040 { display: none !important; } }
@container tmain (max-width: 900px) { .cq-900 { display: none !important; } }

/* Selo "SLA" ao lado do prazo: marca o chamado de cidade com SLA CONTRATUAL (nos demais o prazo é só a data alvo do TOPDesk). */
.sla-tag {
  display: inline-flex; align-items: center; padding: .12rem .4rem; border-radius: .4rem;
  font-size: .625rem; font-weight: 800; letter-spacing: .06em; line-height: 1.2; cursor: default;
  color: rgb(var(--accent)); border: 1px solid rgb(var(--accent) / .5); background: rgb(var(--accent) / .08);
}

/* Reordenar colunas (menu "Colunas"): alça, linha flutuante e o espaço tracejado do destino. */
.col-grip { flex: none; display: grid; place-items: center; width: 1.6rem; height: 1.9rem; margin-left: .15rem; border-radius: .4rem; cursor: grab; touch-action: none;
  color: rgb(113 113 122); transition: color .15s, background-color .15s; }
.col-grip:hover { color: rgb(var(--accent)); background: rgb(var(--accent) / .1); }
.col-grip:active { cursor: grabbing; }
.col-grip:focus-visible { outline: 2px solid rgb(var(--accent) / .6); outline-offset: 1px; color: rgb(var(--accent)); }
.col-row.col-dragging { background: rgb(var(--panel)); box-shadow: 0 8px 22px -6px rgb(0 0 0 / .55); border: 1px solid rgb(var(--accent) / .45); }
.light .col-row.col-dragging { background: #FAF8F5; }
.col-placeholder { border-radius: .5rem; border: 1.5px dashed rgb(var(--accent) / .5); background: rgb(var(--accent) / .06); }

/* Chamado COM SLA (cidade com contrato): selo sólido ao lado do número, barra na lateral da linha e leve tom no fundo — inconfundível de relance.
   Sem contrato o prazo é só um indicador discreto (.prazo-soft: ícone + palavra, sem fundo). */
.sla-badge {
  display: inline-flex; align-items: center; margin-right: .45rem; padding: .05rem .4rem; border-radius: .35rem;
  font-family: inherit; font-size: .625rem; font-weight: 800; letter-spacing: .06em; line-height: 1.3; cursor: default;
  background: rgb(var(--accent)); color: #0d0f10;
}
.light .sla-badge { color: #fff; }
.sla-badge--chip { margin-right: 0; }
.row-sla { background: rgb(var(--accent) / .04); }
.row-sla > td:first-child { box-shadow: inset 3px 0 0 rgb(var(--accent)); }
.prazo-soft { display: inline-flex; align-items: center; gap: .35rem; font-size: .75rem; font-weight: 600; white-space: nowrap; }
.prazo-soft--ok { color: rgb(113 160 130); }
.light .prazo-soft--ok { color: #3f7d5a; }
.prazo-soft--warn { color: #E09E2F; }
.light .prazo-soft--warn { color: #A8590A; }
.prazo-soft--late { color: #E05A50; }
.light .prazo-soft--late { color: #B42318; }
.quick-sep { width: 1px; height: 1.2rem; background: rgb(var(--line)); }
.light .quick-sep { background: #E5DFD1; }

/* ---- Página Operador: barras (comprimento = volume, cor = composição), legenda, chips e cartões de pessoa ---- */
.op-row { transition: background-color .16s ease; }
.op-row.is-clickable { cursor: pointer; }
.op-row.is-clickable:hover { background: rgb(255 255 255 / .04); }
.light .op-row.is-clickable:hover { background: rgb(0 0 0 / .035); }
.op-rail { height: 10px; border-radius: 999px; background: rgb(255 255 255 / .06); }
.light .op-rail { background: rgb(0 0 0 / .06); }
.op-fill { display: flex; gap: 3px; height: 100%; }
.op-seg { height: 100%; min-width: 6px; border-radius: 999px; box-shadow: inset 0 1px 0 rgb(255 255 255 / .28); transform-origin: left center; animation: opSegGrow .75s cubic-bezier(.22, 1, .36, 1) backwards; animation-delay: calc(var(--i, 0) * 45ms); }
@keyframes opSegGrow { from { transform: scaleX(0); opacity: .4; } to { transform: none; opacity: 1; } }
.op-legend-item { transition: background-color .16s ease; }
.op-legend-item.is-clickable { cursor: pointer; }
.op-legend-item.is-clickable:hover { background: rgb(255 255 255 / .05); }
.light .op-legend-item.is-clickable:hover { background: rgb(0 0 0 / .04); }
.op-chip[aria-pressed="true"], .op-chip[aria-pressed="true"]:hover { background: rgb(var(--accent) / .15); border-color: rgb(var(--accent) / .5); color: rgb(var(--accent)); }
.op-person { transition: border-color .2s ease, transform .2s ease, box-shadow .2s ease; }
.op-person:hover { border-color: rgb(var(--accent) / .45); }
.op-ring { display: block; }
@media (prefers-reduced-motion: reduce) { .op-seg { animation: none; } }
