/* =====================================================================
   DESPACHA BRASIL · DESIGN SYSTEM (despacha-ui.css)
   ---------------------------------------------------------------------
   Fonte única de verdade do padrão visual do sistema.
   Carregado globalmente (base.html) ANTES de style.css e dos CSS de
   página. Tudo que for reutilizável (cores, tipografia, botões, campos,
   superfícies, gradientes) mora aqui. Telas específicas só devem
   consumir os tokens/classes abaixo, não redefinir cores na mão.

   Baseado no Manual de Identidade Visual Despacha Brasil (com moderação).
   ===================================================================== */

/* ------------------------------------------------------------------ *
 * 0. FONTES AUTO-HOSPEDADAS
 * ------------------------------------------------------------------ */
/* FE-Schrift: fonte oficial das placas Mercosul (clone livre "FE-Font"). */
@font-face {
  font-family: 'FE-Schrift';
  src: url('../fonts/fe-schrift.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ------------------------------------------------------------------ *
 * 1. DESIGN TOKENS
 * ------------------------------------------------------------------ */
:root {
  /* --- Paleta institucional (cores cruas do manual) --- */
  --db-blue-900:  #013178;  /* azul mais escuro            */
  --db-blue-800:  #023373;  /* azul institucional primário */
  --db-blue-600:  #2B49A3;  /* azul médio (meio do degradê)*/
  --db-cyan-500:  #0095D9;  /* azul/ciano                  */
  --db-cyan-400:  #049DD9;  /* ciano claro                 */
  --db-green-700: #038C5A;  /* verde escuro                */
  --db-green-500: #5DBF4E;  /* verde claro                 */
  --db-yellow:    #F2E30C;  /* amarelo                     */

  /* --- Papéis semânticos --- */
  --db-primary:        var(--db-blue-800);
  --db-primary-dark:   var(--db-blue-900);
  --db-primary-soft:   var(--db-blue-600);
  --db-accent:         var(--db-cyan-500);
  --db-accent-light:   var(--db-cyan-400);
  --db-success:        var(--db-green-700);
  --db-success-light:  var(--db-green-500);
  --db-warning:        var(--db-yellow);
  --db-danger:         #dc3545;
  --db-info:           var(--db-cyan-500);

  /* --- Gradiente oficial (claro -> escuro) --- */
  --db-gradient:        linear-gradient(120deg, #0095D9 0%, #2B49A3 52%, #013178 100%);
  --db-gradient-h:      linear-gradient(90deg, #013178 0%, #2B49A3 55%, #0095D9 100%);
  --db-gradient-accent: linear-gradient(135deg, #2B49A3 0%, #0095D9 100%);
  --db-gradient-green:  linear-gradient(135deg, #038C5A 0%, #5DBF4E 100%);

  /* --- Superfícies / fundo --- */
  --db-bg:            #eef3fa;
  /* Fundo da página inteira (o do body). Fica aqui, e não solto no
     style.css, porque a barra de voltar precisa repetir exatamente este
     degradê para se confundir com o fundo ao grudar no topo. */
  --db-bg-page:       linear-gradient(180deg, #f7f9fc 0%, #eef3fa 100%) fixed;
  --db-surface:       #ffffff;
  --db-surface-2:     #f4f7fb;
  --db-border:        #dce4ef;
  --db-glass:         rgba(255, 255, 255, 0.16);
  --db-glass-strong:  rgba(255, 255, 255, 0.92);
  --db-glass-border:  rgba(255, 255, 255, 0.30);

  /* --- Texto --- */
  --db-text:        #1c2a3f;
  --db-text-muted:  #5b6b82;
  --db-text-soft:   #8595aa;
  --db-text-invert: #ffffff;

  /* --- Tipografia --- */
  --db-font:        'Poppins', system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
  --db-fw-regular:  400;
  --db-fw-medium:   500;
  --db-fw-semibold: 600;
  --db-fw-bold:     700;

  /* --- Raio de borda --- */
  --db-radius-xs:   6px;
  --db-radius-sm:   10px;
  --db-radius:      14px;
  --db-radius-lg:   20px;
  --db-radius-xl:   28px;
  --db-radius-pill: 999px;

  /* --- Sombras --- */
  --db-shadow-xs:    0 1px 2px rgba(2, 51, 115, 0.06);
  --db-shadow-sm:    0 2px 8px rgba(2, 51, 115, 0.08);
  --db-shadow:       0 8px 24px rgba(2, 51, 115, 0.12);
  --db-shadow-lg:    0 18px 50px rgba(1, 26, 64, 0.28);
  --db-shadow-brand: 0 10px 30px rgba(0, 149, 217, 0.35);
  --db-ring:         0 0 0 4px rgba(0, 149, 217, 0.25);

  /* --- Espaçamento (escala 4px) --- */
  --db-space-1: 0.25rem;
  --db-space-2: 0.5rem;
  --db-space-3: 0.75rem;
  --db-space-4: 1rem;
  --db-space-5: 1.5rem;
  --db-space-6: 2rem;
  --db-space-7: 3rem;

  /* --- Movimento --- */
  --db-transition: 0.25s ease;
  --db-transition-slow: 0.4s cubic-bezier(0.22, 1, 0.36, 1);

  /* --- Barra de rolagem ---
     Azul da marca CHEIO, não uma sombra translúcida: barra apagada no repouso
     é indistinguível da barra do sistema, e a identidade era justamente o que
     se queria ali. O segundo token é só o escurecido de quem está com o
     ponteiro em cima ou arrastando.
     São tokens porque contêiner de fundo escuro precisa inverter a barra: lá o
     azul da marca some no fundo. Quem for escuro redefine os dois dentro de si
     (ver o menu do celular em style.css). */
  --db-scroll-thumb:       var(--db-primary-soft);
  --db-scroll-thumb-ativo: var(--db-primary-dark);

  /* --- Bootstrap bridge (alinha o BS ao nosso tema) --- */
  --bs-primary:        #023373;
  --bs-primary-rgb:    2, 51, 115;
  --bs-link-color:     #0a5ec2;
  --bs-link-hover-color: #013178;
  --bs-body-font-family: var(--db-font);
  --bs-body-color:     var(--db-text);
  --bs-border-radius:  var(--db-radius-sm);
}

/* ------------------------------------------------------------------ *
 * 2. BASE
 * ------------------------------------------------------------------ */
body {
  font-family: var(--db-font);
  color: var(--db-text);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection {
  background: rgba(0, 149, 217, 0.25);
}

/* Foco acessível e consistente em todo o sistema */
:where(a, button, .btn, .form-control, .form-select, .form-check-input):focus-visible {
  outline: none;
  box-shadow: var(--db-ring);
}

/* Barra de rolagem discreta na identidade da marca, SÓ onde existe mouse.
 *
 * No toque a barra do sistema é flutuante: nasce durante o gesto, some sozinha
 * e não ocupa largura nenhuma. Estilizar `::-webkit-scrollbar` desliga esse
 * comportamento e põe no lugar uma barra clássica, permanente, que come 10px
 * de dentro do contêiner e fica desenhada por cima do conteúdo. O preço é
 * cobrado justamente onde a tela é menor, e em troca de nada: ninguém arrasta
 * uma barra de 10px com o dedo, rola-se o conteúdo direto.
 *
 * Por isso a personalização inteira mora dentro de `hover: hover` e
 * `pointer: fine`. Quem toca fica com o nativo. Não é `max-width`: notebook com
 * tela sensível ao toque e mouse continua sendo desktop, e janela estreita no
 * monitor também. */
@media (hover: hover) and (pointer: fine) {
  /* ⚠️ As duas camadas de CSS de barra de rolagem são EXCLUDENTES, e a ordem
     de quem vence não é a que parece. A partir do Chrome 121, declarar
     `scrollbar-color` ou `scrollbar-width` faz o navegador ignorar TODO o
     `::-webkit-scrollbar`. Declarar as duas, como estava aqui, é escrever a
     barra desenhada e receber a do sistema, com setinhas de fim de curso.
     Medido no Chrome 151: caixa com as duas camadas em cores diferentes pinta
     a cor da camada padrão.
     Por isso o `@supports`: quem tem o pseudo-elemento recebe só ele, quem não
     tem (Firefox) recebe só as propriedades padrão.

     ⚠️ E o teste é pelo `-thumb`, NÃO pelo `::-webkit-scrollbar` pelado: o
     Gecko aceita o pelado por compatibilidade e responde `true` sem saber
     desenhar nada. Testado com `::-webkit-scrollbar`, o Firefox caía no ramo
     errado e ficava com `scrollbar-width: auto` e `scrollbar-color: auto`, ou
     seja, a barra cinza do sistema, de 19px. Medido no Firefox 153: o pelado
     dá `true` ali, o `-thumb` dá `false`, e é o `-thumb` que pinta. */
  @supports not selector(::-webkit-scrollbar-thumb) {
    * {
      scrollbar-width: thin;
      scrollbar-color: var(--db-scroll-thumb) transparent;
    }
  }

  @supports selector(::-webkit-scrollbar-thumb) {
    *::-webkit-scrollbar { width: 10px; height: 10px; }
    /* Sem trilho: o cinza padrão desenha uma faixa na borda de toda lista
       rolável, e é ela que faz a barra parecer moldura. */
    *::-webkit-scrollbar-track { background: transparent; }
    /* As setas de fim de curso são da barra do sistema e não voltam. */
    *::-webkit-scrollbar-button { display: none; }
    /* Onde as duas barras se cruzam (tabela larga e alta) o padrão é um
       quadrado cinza, a única peça que não seguia o tema. */
    *::-webkit-scrollbar-corner { background: transparent; }

    /* Polegar de 6px na cor cheia da marca, sempre visível. Quem o afina é a
       borda transparente com `background-clip: content-box`, e não a largura
       do trilho: assim ele engorda no hover sem reposicionar nada em volta.
       `background-color`, e não o atalho `background`: o atalho reinicia o
       `background-clip` e o polegar volta a ocupar os 10px inteiros. */
    *::-webkit-scrollbar-thumb {
      background-color: var(--db-scroll-thumb);
      background-clip: content-box;
      border: 2px solid transparent;
      border-radius: var(--db-radius-pill);
    }
    /* Em cima da barra, ou arrastando: 8px, azul escuro.
       Sem `transition`: o Chromium pinta a barra fora do ciclo de animação, e
       nem `transition` nem `@keyframes` chegam nela. Medido: polegar com
       animação de cor sai idêntico byte a byte em três instantes, enquanto um
       `div` com a MESMA animação muda. A troca é seca por limite do motor, não
       por esquecimento. */
    *::-webkit-scrollbar-thumb:hover,
    *::-webkit-scrollbar-thumb:active {
      background-color: var(--db-scroll-thumb-ativo);
      border-width: 1px;
    }
  }

  /* A canaleta da barra fica reservada o tempo todo. Sem isso, todo modal que
     tranca o fundo (`body { overflow: hidden }`) apaga a barra e a página
     inteira salta para a direita ao abrir, e volta ao fechar. Medido no
     Chrome: 385px de largura útil com o modal fechado, 400px com ele aberto.
     O mesmo salto acontecia ao trocar de uma tela que rola para uma que não
     rola. Onde a barra é flutuante (celular) o navegador ignora a canaleta. */
  html { scrollbar-gutter: stable; }

  /* ...e aí o Bootstrap precisa parar de compensar. Ele mede a barra ANTES de
     trancar e soma a largura dela como `padding-right` no body e em todo
     `.fixed-top` (a navbar é um), para o conteúdo não escorregar. Com a
     canaleta reservada não há mais nada a compensar, e a compensação vira o
     próprio salto, na direção contrária. O `!important` é o que vence o estilo
     inline que ele escreve. */
  body.modal-open,
  body.modal-open .fixed-top,
  body.modal-open .fixed-bottom,
  body.modal-open .sticky-top { padding-right: 0 !important; }
  body.modal-open .sticky-top { margin-right: 0 !important; }
}

/* No toque a barra sai de cena, e é preciso DIZER isso. Não estilizar não
   basta: aí vale a barra do sistema, que em vários aparelhos e em toda
   emulação de celular no navegador de mesa é a clássica, larga e permanente,
   desenhada por cima do conteúdo. Era o que continuava aparecendo.
   Quem rola com o dedo não usa a barra para nada: rola o conteúdo direto. */
@media (hover: none), (pointer: coarse) {
  /* As duas linhas, porque são caminhos diferentes: a de cima é a padrão (é
     ela que vale no Chrome moderno), a de baixo cobre os motores antigos. */
  * { scrollbar-width: none; }
  *::-webkit-scrollbar { width: 0; height: 0; display: none; }
}

/* ------------------------------------------------------------------ *
 * 3. TIPOGRAFIA UTIL
 * ------------------------------------------------------------------ */
.db-display { font-weight: var(--db-fw-bold); letter-spacing: -0.5px; line-height: 1.1; }
.db-title   { font-weight: var(--db-fw-semibold); color: var(--db-primary); }
.db-subtitle{ font-weight: var(--db-fw-medium); color: var(--db-text-muted); }
.db-eyebrow {
  font-size: 0.72rem;
  font-weight: var(--db-fw-semibold);
  letter-spacing: 3px;
  text-transform: uppercase;
  color: var(--db-accent);
}
.db-text-muted { color: var(--db-text-muted) !important; }

.db-gradient-text {
  background: var(--db-gradient-h);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}

/* ------------------------------------------------------------------ *
 * 4. SUPERFÍCIES
 * ------------------------------------------------------------------ */
.db-surface {
  background: var(--db-surface);
  border: 1px solid var(--db-border);
  border-radius: var(--db-radius);
  box-shadow: var(--db-shadow-sm);
}

/* Vidro fosco claro (sobre fundo gradiente/imagem) */
.db-glass {
  position: relative;
  background: linear-gradient(180deg, rgba(255,255,255,0.22), rgba(255,255,255,0.08));
  border: 1px solid var(--db-glass-border);
  border-radius: var(--db-radius-lg);
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  box-shadow: var(--db-shadow-lg);
  background-clip: padding-box;
}

/* Vidro escuro moderno (card padrão sobre fundo escuro) */
.db-glass--dark {
  background: linear-gradient(158deg, rgba(16, 40, 92, 0.72) 0%, rgba(6, 20, 54, 0.66) 100%);
  border: 1px solid rgba(255, 255, 255, 0.10);
  color: var(--db-text-invert);
  box-shadow:
    0 30px 80px rgba(0, 0, 0, 0.45),
    inset 0 1px 0 rgba(255, 255, 255, 0.10);
}
/* Linha de acento (gradiente da marca) no topo do card */
.db-glass--accent { overflow: hidden; }
.db-glass--accent::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: var(--db-gradient-h);
  opacity: 0.9;
}

/* ------------------------------------------------------------------ *
 * 5. GRADIENTE / FUNDO IMERSIVO
 * ------------------------------------------------------------------ */
.db-bg-gradient {
  background: var(--db-gradient);
}

/* Fundo imersivo padrão do sistema: gradiente + brilhos radiais */
.db-immersive-bg {
  position: fixed;
  inset: 0;
  z-index: 0;
  background:
    radial-gradient(1100px 600px at 12% 8%,  rgba(0,149,217,0.55) 0%, rgba(0,149,217,0) 60%),
    radial-gradient(900px 600px at 88% 18%,  rgba(93,191,78,0.20) 0%, rgba(93,191,78,0) 55%),
    radial-gradient(1000px 700px at 78% 95%, rgba(1,26,64,0.55) 0%,  rgba(1,26,64,0) 60%),
    var(--db-gradient);
  overflow: hidden;
}

/* Fundo imersivo ESCURO/SÓBRIO (variação): azul-marinho profundo + animação */
.db-immersive-bg--dark {
  background:
    radial-gradient(1200px 720px at 16% 8%,  rgba(43, 73, 163, 0.50) 0%, rgba(43, 73, 163, 0) 60%),
    radial-gradient(1000px 700px at 86% 92%, rgba(0, 149, 217, 0.20) 0%, rgba(0, 149, 217, 0) 58%),
    radial-gradient(800px 600px at 78% 12%,  rgba(3, 140, 90, 0.12) 0%,  rgba(3, 140, 90, 0) 55%),
    linear-gradient(155deg, #03205a 0%, #021a4a 45%, #01102f 100%);
  background-size: 170% 170%, 170% 170%, 170% 170%, 220% 220%;
  background-attachment: fixed;
  animation: db-bg-pan 24s ease-in-out infinite alternate;
}
@keyframes db-bg-pan {
  0%   { background-position: 0% 0%,   100% 100%, 50% 0%,   0% 50%; }
  100% { background-position: 28% 18%, 72% 82%,   60% 30%, 100% 50%; }
}

/* Blobs decorativos inspirados no símbolo da marca */
.db-blob {
  position: absolute;
  border-radius: 45% 55% 52% 48% / 55% 45% 55% 45%;
  filter: blur(2px);
  opacity: 0.5;
  pointer-events: none;
}
.db-blob--green  { background: var(--db-green-500); }
.db-blob--yellow { background: var(--db-yellow); }
.db-blob--cyan   { background: var(--db-cyan-500); }
.db-blob--blue   { background: var(--db-primary-soft); }

/* Flutuação lenta dos blobs (cada um com fase própria via nth-of-type) */
.db-blob--float { animation: db-float 20s ease-in-out infinite alternate; }
.db-blob--float:nth-of-type(2) { animation-duration: 26s; animation-delay: -6s; }
.db-blob--float:nth-of-type(3) { animation-duration: 32s; animation-delay: -12s; }
@keyframes db-float {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(34px, -28px, 0) scale(1.12); }
}

/* Textura de grade de pontos sutil (overlay sobre fundos escuros). */
.db-dot-grid {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: radial-gradient(rgba(255, 255, 255, 0.13) 1.1px, transparent 1.5px);
  background-size: 26px 26px;
}
/* Deriva lenta dos pontos (loop perfeito: múltiplos de 24px) */
.db-dot-grid--drift { animation: db-dot-drift 32s linear infinite; }
@keyframes db-dot-drift {
  from { background-position: 0 0; }
  to   { background-position: 52px 78px; }
}

/* Faixas da bandeira (verde · amarelo · azul), motivo do manual.
   Três barras paralelas distintas, controladas em px. Posicione/gire
   via a classe de contexto (ex.: .db-login__stripes). Reutilizável em
   cabeçalhos, rodapés e acentos de canto. */
.db-flag-stripes {
  --db-stripe-w: 34px;   /* espessura de cada faixa */
  --db-stripe-gap: 24px; /* espaço entre as faixas (0 = grudadas) */
  --db-stripe-angle: 28deg;
  /* ordem das cores (esquerda → direita), sobrescrevível por contexto */
  --db-stripe-1: var(--db-green-500);
  --db-stripe-2: var(--db-yellow);
  --db-stripe-3: var(--db-cyan-500);
  position: absolute;
  pointer-events: none;
  width: var(--db-stripe-w);
  background: var(--db-stripe-1);
  transform: rotate(var(--db-stripe-angle));
  /* barras sólidas rotacionadas: bordas nítidas com anti-aliasing limpo
     do navegador (sem serrilhado e sem perder vivacidade). */
}
.db-flag-stripes::before,
.db-flag-stripes::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: var(--db-stripe-w);
}
.db-flag-stripes::before {
  left: calc(var(--db-stripe-w) + var(--db-stripe-gap));
  background: var(--db-stripe-2);
}
.db-flag-stripes::after {
  left: calc((var(--db-stripe-w) + var(--db-stripe-gap)) * 2);
  background: var(--db-stripe-3);
}

/* Animação de entrada (cards/seções) */
.db-rise { animation: db-rise 0.6s cubic-bezier(0.22, 1, 0.36, 1) both; }
@keyframes db-rise {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: none; }
}

/* ------------------------------------------------------------------ *
 * 6. BOTÕES
 * ------------------------------------------------------------------ */
.db-btn,
.btn.btn-primary {
  --db-btn-bg: var(--db-gradient-accent);
  position: relative;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  font-family: var(--db-font);
  font-weight: var(--db-fw-semibold);
  letter-spacing: 0.4px;
  border: none;
  border-radius: var(--db-radius-sm);
  padding: 0.75rem 1.5rem;
  color: #fff;
  text-decoration: none;
  background-image: var(--db-btn-bg);
  box-shadow: var(--db-shadow-sm);
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  transition: transform 0.22s cubic-bezier(0.22, 1, 0.36, 1),
              box-shadow 0.25s ease,
              filter 0.25s ease;
}
/* Brilho que cruza o botão no hover */
.db-btn::after,
.btn.btn-primary::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: -130%;
  width: 60%;
  background: linear-gradient(115deg, transparent 0%, rgba(255, 255, 255, 0.40) 50%, transparent 100%);
  transform: skewX(-18deg);
  transition: left 0.6s ease;
  pointer-events: none;
}
.db-btn:hover,
.btn.btn-primary:hover {
  color: #fff;
  text-decoration: none;
  transform: translateY(-2px);
  box-shadow: var(--db-shadow-brand);
  filter: saturate(1.08) brightness(1.03);
}
.db-btn:hover::after,
.btn.btn-primary:hover::after { left: 140%; }
.db-btn:active,
.btn.btn-primary:active { transform: translateY(0) scale(0.985); }
.db-btn:disabled,
.btn.btn-primary:disabled { opacity: 0.6; transform: none; box-shadow: none; cursor: not-allowed; }

/* Ícone que desliza no hover (ex.: seta do "Entrar") */
.db-btn__icon { transition: transform 0.25s ease; }
.db-btn:hover .db-btn__icon { transform: translateX(4px); }

/* Estado de carregamento (ex.: "Gerando PDF..."): trava cliques e mostra uma
   barra de progresso indeterminada na base do botão. Não há progresso real
   (a geração é server-side), então um segmento varre a largura em loop. As
   cores saem de currentColor, então serve em qualquer variante de botão. */
.db-btn.is-loading {
  pointer-events: none;
  cursor: progress;
  transform: none;
  filter: saturate(0.95);
}
.db-btn.is-loading::after { display: none; } /* desliga o brilho de hover */
.db-btn__bar {
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 3px; overflow: hidden;
  background-color: color-mix(in srgb, currentColor 22%, transparent);
}
/* Preenchimento controlado por JS. Não há progresso real (geração server-side):
   enche suave até ~90% e salta para 100% quando o arquivo chega. */
.db-btn__fill {
  position: absolute; left: 0; top: 0; height: 100%; width: 0;
  border-radius: 3px; background: currentColor;
  transition: width 0.35s ease;
}

/* Variantes */
.db-btn--block { width: 100%; }
.db-btn--pill  { border-radius: var(--db-radius-pill); }
.db-btn--lg    { padding: 0.9rem 1.75rem; font-size: 1.05rem; }
.db-btn--sm    { padding: 0.45rem 0.9rem; font-size: 0.82rem; gap: 0.4rem; }
.db-btn--sm svg { width: 16px; height: 16px; }
.db-btn--green   { --db-btn-bg: var(--db-gradient-green); }
.db-btn--solid   { --db-btn-bg: none; background-color: var(--db-primary); background-image: none; }
.db-btn--outline {
  background: transparent;
  background-image: none;
  color: var(--db-primary);
  border: 2px solid var(--db-primary);
  box-shadow: none;
}
.db-btn--outline:hover { background: var(--db-primary); color: #fff; }

/* Botão secundário discreto (ação terciária sobre fundo claro) */
.db-btn--ghost {
  background: transparent;
  background-image: none;
  color: var(--db-text-muted);
  box-shadow: none;
}
.db-btn--ghost::after { display: none; }
.db-btn--ghost:hover {
  background: rgba(2, 51, 115, 0.06);
  background-image: none;
  color: var(--db-primary);
  box-shadow: none;
  transform: none;
  filter: none;
}

/* Botão neutro (cinza leve): ação secundária discreta.

   O anel interno não é enfeite: o fundo do botão é #eef1f6 e o da página
   termina em #eef3fa, dois pontos de diferença por canal. Sem contorno, todo
   `--neutral` que não estivesse sobre um card branco lia como TEXTO, não como
   botão; "Baixar PDF" nas telas de resultado fica exatamente ali, sobre o
   fundo da página. Aparecia nas duas larguras; o celular só tornou óbvio, ao
   esticar o botão de ponta a ponta.

   É `box-shadow: inset` e não `border` de propósito: borda muda o box model e
   somaria 2px de altura a todo botão neutro já posicionado. */
/* ⚠️ O contorno é `outline` recuado, e não `box-shadow: inset`.
   Sombra interna de 1px é hairline: **no Firefox, com zoom de página
   fracionário (1,2 · 1,33 · 1,75 medidos), a borda de CIMA não é pintada** e as
   outras três ficam. Só o topo, e só em alguns zooms, o que faz o relato chegar
   como "o botão desta tela está cortado" em vez de defeito do componente.

   `outline` e não `border` porque o botão é auto-dimensionado: uma borda de 1px
   o deixaria 2px mais alto e 2px mais largo (medido), e ele aparece em lugares
   apertados, como a célula de ações de uma tabela. O contorno não ocupa espaço,
   e `outline-offset: -1px` o desenha exatamente onde a sombra estava.

   Não briga com o anel de foco: o `:focus-visible` global usa `box-shadow`
   (`--db-ring`), então os dois convivem. Verificado em
   `scripts/verificar_lojas_navegador.py`, que mede o pixel do topo contra o da
   base em três zooms. */
.db-btn--neutral {
  background: #eef1f6;
  background-image: none;
  color: var(--db-text-muted);
  outline: 1px solid var(--db-border);
  outline-offset: -1px;
}
.db-btn--neutral::after { display: none; }
/* ⚠️ O `box-shadow` PRECISA estar aqui. O hover do `.db-btn` base aplica
   `--db-shadow-brand` (0 10px 30px de ciano a 35%), e esta variante zerava
   `transform` e `filter` mas esquecia a sombra: o resultado era um brilho azul
   forte por baixo de um botão cinza, que é justamente o oposto de "ação
   secundária discreta". Aparecia em todo `--neutral` da casa (WhatsApp do
   convite, Cancelar dos modais, Baixar PDF do resultado). O `--ghost` logo
   acima já fazia o mesmo com `box-shadow: none`. */
.db-btn--neutral:hover {
  background: #e2e7f0;
  background-image: none;
  color: var(--db-primary);
  outline-color: var(--db-primary-soft, var(--db-border));
  box-shadow: var(--db-shadow-sm);
  transform: none;
  filter: none;
}

/* Botão de ação DESTRUTIVA (confirmação de cancelar/excluir, ver DBConfirm) */
.db-btn--danger {
  --db-btn-bg: linear-gradient(135deg, #e0616d 0%, #c92433 100%);
}
.db-btn--danger:hover { box-shadow: 0 10px 30px rgba(220, 53, 69, 0.38); }

/* Destrutivo SUAVE: o botão que só ABRE a confirmação (ex.: "Cancelar consulta"
   ao lado do "Concluir"). Lê como destrutivo sem competir em peso com a ação
   principal. O vermelho cheio fica para o passo que confirma de fato. */
.db-btn--danger-soft {
  background: color-mix(in srgb, #dc3545 8%, #fff);
  background-image: none;
  color: #c0303c;
  box-shadow: none;
}
.db-btn--danger-soft::after { display: none; }
.db-btn--danger-soft:hover {
  background: color-mix(in srgb, #dc3545 14%, #fff);
  background-image: none;
  color: #a3232f;
  box-shadow: none;
  transform: none;
  filter: none;
}

/* Botão fantasma claro (sobre fundo gradiente) */
.db-btn--ghost-light {
  background: rgba(255,255,255,0.12);
  background-image: none;
  border: 1px solid rgba(255,255,255,0.5);
  color: #fff;
}
.db-btn--ghost-light:hover { background: rgba(255,255,255,0.22); color: #fff; }

/* ------------------------------------------------------------------ *
 * 7. CAMPOS DE FORMULÁRIO
 * ------------------------------------------------------------------ */
.db-field { margin-bottom: var(--db-space-4); }

.form-label,
.db-label {
  font-weight: var(--db-fw-medium);
  color: var(--db-text);
  margin-bottom: var(--db-space-2);
}

.form-control,
.form-select {
  font-family: var(--db-font);
  border: 1.5px solid var(--db-border);
  border-radius: var(--db-radius-sm);
  padding: 0.7rem 0.9rem;
  color: var(--db-text);
  background-color: #fff;
  transition: border-color var(--db-transition), box-shadow var(--db-transition);
}
.form-control::placeholder { color: var(--db-text-soft); }
.form-control:focus,
.form-select:focus {
  border-color: var(--db-accent);
  box-shadow: var(--db-ring);
}

/* Caixa do que o cliente digita. Marca em ATRIBUTO, e não em classe: os macros
   de campo montam o `class=` deles e sobrescreveriam a nossa. Ela vem do
   `render_kw` do campo (app/forms.py) nos formulários WTForms e escrita à mão
   nos templates que montam o `<input>` direto.

   Três valores, um por regra do servidor:

     nome   nome, razão social, representante, rua, bairro, cidade…
     alta   onde a SIGLA é o dado (UF), e o número, que tem "S/N"
     baixa  e-mail

   `nome` e `alta` pintam igual (CAIXA ALTA) e continuam separados de propósito:
   o que muda entre eles é o que o SERVIDOR faz com o valor (`nome_proprio` x
   `caixa_alta`) e o teclado que o celular abre. Um dia a pintura pode divergir;
   a intenção não.

   ⚠️ Isto é só o RETORNO VISUAL: máscara. `text-transform` não muda o valor
   enviado no POST: o campo continua mandando o que foi digitado, e quem
   normaliza é o servidor (`app/utils/texto.py`, como filtro do WTForms e de novo
   nos serviços). Trocar a regra aqui não muda o que é gravado, e tirá-la daqui
   também não.

   > Caixa alta no CAMPO não briga com o nome próprio no BANCO (decisão de
   > 2026-08-04): um é a máscara de quem digita (e digitar um cadastro é
   > preencher formulário, onde caixa alta é a convenção da casa), o outro é
   > como o nome aparece LIDO, no painel, na lista do admin e no e-mail. O
   > `capitalize` é que não serve aqui: ele escreveria "João Da Silva" e a tela
   > desmentiria o que foi salvo. */
[data-caixa="nome"]  { text-transform: uppercase; }
[data-caixa="alta"]  { text-transform: uppercase; }
[data-caixa="baixa"] { text-transform: lowercase; }
/* O placeholder é instrução, não dado: "Apto, bloco, sala..." não vira grito. */
[data-caixa]::placeholder { text-transform: none; }

/* Neutraliza o amarelo do autofill do navegador em todo o sistema */
.form-control:-webkit-autofill,
.form-control:-webkit-autofill:hover,
.form-control:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--db-text);
  caret-color: var(--db-text);
  box-shadow: 0 0 0 1000px #fff inset;
  -webkit-box-shadow: 0 0 0 1000px #fff inset;
  transition: background-color 9999s ease-in-out 0s;
}

/* ------------------------------------------------------------------ *
 * Combobox pesquisável (.db-combo): realça um <select class="js-combo">.
 * O <select> nativo fica invisível por cima do controle, mas focável, para a
 * validação nativa continuar funcionando. Comportamento em js/db-combo.js.
 * ------------------------------------------------------------------ */
.db-combo { position: relative; }

.db-combo__native {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  pointer-events: none;   /* o controle recebe os cliques */
}

.db-combo__control {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  width: 100%;
  font-family: var(--db-font);
  font-size: 1rem;
  text-align: left;
  border: 1.5px solid var(--db-border);
  border-radius: var(--db-radius-sm);
  padding: 0.7rem 0.9rem;
  color: var(--db-text);
  background-color: #fff;
  cursor: pointer;
  transition: border-color var(--db-transition), box-shadow var(--db-transition);
}
.db-combo__control:hover { border-color: var(--db-text-soft); }
.db-combo.is-open .db-combo__control,
.db-combo__control:focus-visible {
  border-color: var(--db-accent);
  box-shadow: var(--db-ring);
  outline: none;
}
.db-combo.is-invalid .db-combo__control { border-color: var(--db-danger); }

.db-combo__value {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.db-combo__value--placeholder { color: var(--db-text-soft); }

.db-combo__caret {
  flex: none;
  display: inline-flex;
  color: var(--db-text-soft);
  transition: transform var(--db-transition), color var(--db-transition);
}
.db-combo__caret svg { width: 18px; height: 18px; }
.db-combo.is-open .db-combo__caret { transform: rotate(180deg); color: var(--db-accent); }

.db-combo__panel {
  position: absolute;
  z-index: 40;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  /* colunas estreitas (UF em col-md-2) ganham um menu utilizável: o min-width
     ultrapassa o `right:0`, crescendo para a direita a partir da esquerda. */
  min-width: 12rem;
  display: flex;
  flex-direction: column;
  max-height: 300px;
  background: #fff;
  border: 1px solid var(--db-border);
  border-radius: var(--db-radius-sm);
  box-shadow: var(--db-shadow);
  overflow: hidden;
}

.db-combo__search {
  position: relative;
  display: flex;
  align-items: center;
  padding: 0.55rem 0.7rem;
  border-bottom: 1px solid var(--db-border);
}
.db-combo__lupa {
  position: absolute;
  left: 1.1rem;
  display: inline-flex;
  color: var(--db-text-soft);
  pointer-events: none;
}
.db-combo__lupa svg { width: 16px; height: 16px; }
.db-combo__input {
  width: 100%;
  border: 0;
  outline: none;
  padding: 0.35rem 0.4rem 0.35rem 1.9rem;
  font-family: var(--db-font);
  font-size: 0.95rem;
  color: var(--db-text);
  background: transparent;
}
.db-combo__input::placeholder { color: var(--db-text-soft); }

.db-combo__list {
  list-style: none;
  margin: 0;
  padding: 0.3rem;
  overflow-y: auto;
  /* A lista é um painel solto por cima da tela: rolar até o fim dela não pode
     empurrar a página que está atrás. */
  overscroll-behavior: contain;
}
.db-combo__opt {
  padding: 0.55rem 0.65rem;
  border-radius: var(--db-radius-xs);
  font-size: 0.95rem;
  color: var(--db-text);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}
.db-combo__opt.is-active { background: var(--db-surface-2); }
.db-combo__opt[aria-selected="true"] {
  color: var(--db-primary);
  font-weight: var(--db-fw-semibold);
}
.db-combo__opt[aria-selected="true"]::after {
  content: "";
  flex: none;
  width: 16px;
  height: 16px;
  background: currentColor;
  -webkit-mask: no-repeat center / contain url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
  mask: no-repeat center / contain url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
}
.db-combo__empty {
  padding: 0.9rem 0.7rem;
  text-align: center;
  font-size: 0.9rem;
  color: var(--db-text-soft);
}

/* ------------------------------------------------------------------ *
 * Conferência no documento (.db-docpop): mostra, no hover do campo, o
 * recorte do PDF enviado de onde aquele valor foi lido.
 *
 * O leitor devolve a página em PNG e o retângulo de cada campo; aqui o
 * recorte é feito por CSS: a janela tem overflow hidden e a imagem é
 * deslocada/escalada para deixar só a região do campo visível. Uma imagem
 * só serve todos os campos.
 * ------------------------------------------------------------------ */
.db-doc-hint {                     /* selo no rótulo: "veio do documento" */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.05rem;
  height: 1.05rem;
  margin-left: 0.35rem;
  border: 0;
  padding: 0;
  border-radius: 5px;
  background: color-mix(in srgb, var(--db-accent) 14%, #fff);
  color: var(--db-accent);
  cursor: help;
  vertical-align: -2px;
  transition: background var(--db-transition), color var(--db-transition);
}
.db-doc-hint:hover,
.db-doc-hint:focus-visible {
  background: var(--db-accent);
  color: #fff;
  outline: none;
}
.db-doc-hint svg { width: 12px; height: 12px; }

.db-docpop {
  position: absolute;
  z-index: 11090;                  /* acima de navbar/footer fixos */
  width: 360px;
  max-width: calc(100vw - 1.5rem);
  padding: 0.5rem;
  border-radius: var(--db-radius-sm);
  background: var(--db-surface, #fff);
  border: 1px solid var(--db-border);
  box-shadow: 0 12px 34px rgba(28, 42, 63, 0.22);
  opacity: 0;
  transform: translateY(4px);
  pointer-events: none;            /* nunca rouba o clique do campo */
  transition: opacity 0.14s ease, transform 0.14s ease;
}
.db-docpop.is-open { opacity: 1; transform: none; }
.db-docpop__head {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-bottom: 0.4rem;
  font-size: 0.68rem;
  font-weight: var(--db-fw-semibold, 600);
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--db-text-muted);
}
.db-docpop__head svg { width: 13px; height: 13px; color: var(--db-accent); }
/* janela do recorte: a imagem da página é posicionada por dentro */
.db-docpop__viewport {
  position: relative;
  overflow: hidden;
  border-radius: 6px;
  background: #fff;
  border: 1px solid var(--db-border);
}
.db-docpop__viewport img {
  position: absolute;
  top: 0;
  left: 0;
  max-width: none;                 /* o recorte depende da largura calculada */
  image-rendering: -webkit-optimize-contrast;
}
.db-docpop__foot {
  margin: 0.4rem 0 0;
  font-size: 0.7rem;
  color: var(--db-text-muted);
}

/* ------------------------------------------------------------------ *
 * Zona de upload do CRLV-e (.db-crlv): atalho que lê o PDF e preenche.
 * ------------------------------------------------------------------ */
.db-crlv {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 1rem 1.2rem;
  margin-bottom: 1rem;
  border: 1.5px dashed color-mix(in srgb, var(--db-accent) 45%, var(--db-border));
  border-radius: var(--db-radius);
  background: color-mix(in srgb, var(--db-accent) 5%, #fff);
  cursor: pointer;
  transition: border-color var(--db-transition), background var(--db-transition),
              box-shadow var(--db-transition);
}
.db-crlv:hover,
.db-crlv:focus-visible,
.db-crlv.is-drag {
  border-color: var(--db-accent);
  background: color-mix(in srgb, var(--db-accent) 10%, #fff);
  box-shadow: var(--db-ring);
  outline: none;
}
.db-crlv.is-drag { border-style: solid; }
.db-crlv.is-busy { opacity: 0.7; pointer-events: none; }

.db-crlv__icon {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  border-radius: var(--db-radius-sm);
  background: var(--db-accent);
  color: #fff;
}
.db-crlv__icon svg { width: 24px; height: 24px; }
.db-crlv__body { flex: 1 1 auto; min-width: 0; }
.db-crlv__title { margin: 0; font-size: 1.02rem; font-weight: var(--db-fw-semibold); color: var(--db-primary); }
.db-crlv__sub { margin: 0.15rem 0 0; font-size: 0.88rem; color: var(--db-text-muted); }
.db-crlv__btn { flex: none; }

.db-crlv-status {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.7rem 1rem;
  margin: -0.4rem 0 1rem;
  border-radius: var(--db-radius-sm);
  font-size: 0.9rem;
}
.db-crlv-status svg { width: 18px; height: 18px; flex: none; margin-top: 1px; }
.db-crlv-status--ok {
  background: color-mix(in srgb, var(--db-success) 10%, #fff);
  border: 1px solid color-mix(in srgb, var(--db-success) 35%, var(--db-border));
  color: var(--db-success);
}
.db-crlv-status--erro {
  background: color-mix(in srgb, var(--db-danger) 8%, #fff);
  border: 1px solid color-mix(in srgb, var(--db-danger) 30%, var(--db-border));
  color: var(--db-danger);
}
.db-crlv-status--carregando {
  background: var(--db-surface-2);
  border: 1px solid var(--db-border);
  color: var(--db-text-muted);
}

/* Campo com ícone (input-group leve) */
.db-input-group {
  position: relative;
  display: flex;
  align-items: center;
}
.db-input-group .db-input-icon {
  position: absolute;
  left: 0.95rem;
  color: var(--db-text-soft);
  font-size: 0.95rem;
  pointer-events: none;
  transition: color var(--db-transition);
}
/* Sizing do ícone Lucide (svg) dentro do input */
.db-input-group svg.db-input-icon { width: 18px; height: 18px; }
.db-input-group .form-control { padding-left: 2.6rem; }
.db-input-group:focus-within .db-input-icon { color: var(--db-accent); }

.form-check-input {
  cursor: pointer;
  transition: background-color 0.2s ease, border-color 0.2s ease,
              transform 0.15s ease, box-shadow 0.2s ease;
}
.form-check-input:checked {
  background-color: var(--db-primary);
  border-color: var(--db-primary);
}
/* "Apertar" (escala) ao clicar e pop ao marcar */
.form-check-input:active { transform: scale(0.86); }
.form-check-input:checked { animation: db-check-pop 0.28s ease; }
@keyframes db-check-pop {
  0%   { transform: scale(0.8); }
  55%  { transform: scale(1.15); }
  100% { transform: scale(1); }
}
.form-check-label { cursor: pointer; }

/* Textos de interface (labels) não devem ser selecionáveis/copiáveis */
.form-label,
.db-label,
.form-check-label,
.db-eyebrow {
  user-select: none;
  -webkit-user-select: none;
}

/* Botão de ação dentro do input (ex.: mostrar/ocultar senha) */
.db-input-group .db-input-action {
  position: absolute;
  right: 0.5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--db-text-soft);
  cursor: pointer;
  border-radius: var(--db-radius-xs);
  transition: color var(--db-transition), background var(--db-transition);
}
.db-input-group .db-input-action:hover { color: var(--db-accent); background: rgba(2, 51, 115, 0.06); }
.db-input-group .db-input-action svg { width: 18px; height: 18px; }
/* reserva espaço à direita quando há botão de ação */
.db-input-group:has(.db-input-action) .form-control { padding-right: 2.8rem; }
/* evita o ícone de validação do Bootstrap sobrepor o botão de ação */
.db-input-group:has(.db-input-action) .form-control.is-invalid,
.db-input-group:has(.db-input-action) .form-control.is-valid {
  background-image: none;
  padding-right: 2.8rem;
}

/* Dica de campo (ex.: aviso de Caps Lock) */
.db-field-hint {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin-top: 0.4rem;
  font-size: 0.8rem;
}
.db-field-hint svg { width: 15px; height: 15px; }
.db-capslock-hint { color: #b45309; }
.db-field__help { display: block; margin-top: 0.35rem; font-size: 0.78rem; color: var(--db-text-soft); }

/* Botão "?" ao lado de um rótulo, com popover explicativo.
   `.db-help` é o âncora relativo; o popover é absoluto e transborda o card
   (nenhum card do form usa overflow:hidden). Aberto via `.is-open` (JS). */
.db-help { position: relative; display: inline-flex; vertical-align: middle; margin-left: 0.3rem; }
.db-help__btn {
  width: 16px; height: 16px; padding: 0; border: 0; cursor: pointer; flex: none;
  display: inline-flex; align-items: center; justify-content: center; border-radius: 50%;
  background: color-mix(in srgb, var(--db-accent) 14%, #fff); color: var(--db-accent);
  font-size: 0.7rem; font-weight: 700; line-height: 1; transition: background 0.15s ease, color 0.15s ease;
}
.db-help__btn:hover, .db-help.is-open .db-help__btn { background: var(--db-accent); color: #fff; }
.db-help__pop {
  position: absolute; top: calc(100% + 8px); left: 50%; transform: translateX(-50%) scale(0.96);
  width: 260px; max-width: 78vw; z-index: 60; opacity: 0; pointer-events: none;
  background: #fff; border: 1px solid var(--db-border); border-radius: var(--db-radius-sm);
  box-shadow: 0 14px 34px rgba(6, 15, 35, 0.18); padding: 0.85rem 0.95rem;
  transition: opacity 0.14s ease, transform 0.14s ease;
}
.db-help.is-open .db-help__pop { opacity: 1; pointer-events: auto; transform: translateX(-50%) scale(1); }
/* seta apontando para o botão */
.db-help__pop::before {
  content: ''; position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%);
  border: 7px solid transparent; border-bottom-color: #fff;
  filter: drop-shadow(0 -1px 0 var(--db-border));
}
.db-help__pop strong { display: block; color: var(--db-primary); font-size: 0.86rem; font-weight: var(--db-fw-semibold); }
.db-help__pop p { margin: 0.35rem 0 0; font-size: 0.8rem; line-height: 1.45; color: var(--db-text-muted); font-weight: 400; }
.db-help__pop a {
  display: inline-flex; align-items: center; gap: 0.35rem; margin-top: 0.7rem;
  font-size: 0.8rem; font-weight: var(--db-fw-semibold); color: var(--db-accent); text-decoration: none;
}
.db-help__pop a:hover { text-decoration: underline; }
.db-help__pop a svg { width: 14px; height: 14px; }
/* Encostado na borda direita da tela, o popover centralizado sairia cortado:
   ancora à direita do botão. */
@media (max-width: 575px) {
  .db-help__pop { left: auto; right: -8px; transform: translateX(0) scale(0.96); }
  .db-help.is-open .db-help__pop { transform: translateX(0) scale(1); }
  .db-help__pop::before { left: auto; right: 12px; transform: none; }
}

/* Variante: o "?" DENTRO do input, à direita. O wrapper embrulha input+botão+
   popover; o botão flutua sobre o input (centralizado na vertical) e o popover
   ancora abaixo do campo inteiro, alinhado à direita (seta sob o botão). */
.db-help--in-input { position: relative; display: block; margin: 0; }
.db-help--in-input .form-control.has-help { padding-right: 2.3rem; }
.db-help--in-input .db-help__btn {
  position: absolute; right: 9px; top: 50%; transform: translateY(-50%);
  width: 18px; height: 18px; font-size: 0.72rem;
}
.db-help--in-input .db-help__pop {
  top: calc(100% + 9px); left: auto; right: 0; transform: translateY(-4px) scale(0.97);
}
.db-help--in-input.is-open .db-help__pop { transform: translateY(0) scale(1); }
.db-help--in-input .db-help__pop::before { left: auto; right: 13px; transform: none; }
@media (max-width: 575px) {
  .db-help--in-input .db-help__pop { right: 0; }
  .db-help--in-input .db-help__pop::before { right: 13px; }
}
.db-capslock-hint[hidden] { display: none; }

/* Estados de erro (padrão do sistema) */
.form-control.is-invalid {
  border-color: var(--db-danger);
}
.form-control.is-invalid:focus {
  box-shadow: 0 0 0 4px rgba(220, 53, 69, 0.18);
}
.invalid-feedback {
  color: var(--db-danger);
  font-size: 0.85rem;
  margin-top: 0.3rem;
}
@keyframes db-shake {
  0%, 100% { transform: translateX(0); }
  25%      { transform: translateX(-4px); }
  75%      { transform: translateX(4px); }
}

/* Campo numérico SEM as setinhas (spin buttons). Elas convidam ao clique em
   valores que não são incrementais (ano, RENAVAM, CRV, valor) e desalinham a
   altura do campo. Vale para todo o sistema. */
.form-control[type="number"] { -moz-appearance: textfield; appearance: textfield; }
.form-control[type="number"]::-webkit-outer-spin-button,
.form-control[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* Identificadores digitados (placa, CPF/CNPJ, CEP, RENAVAM, CRV) em JetBrains
   Mono, mesma regra que já vale para exibição em `.db-info-card--mono`.
   Alinha os dígitos e facilita conferir número longo caractere a caractere. */
.form-control--mono {
  font-family: 'JetBrains Mono', 'Courier New', monospace;
  letter-spacing: 0.5px;
}

/* Campo obrigatório: asterisco discreto, sem poluir o rótulo. */
.form-label .db-req { color: var(--db-danger); margin-left: 0.15rem; font-weight: 400; }

/* Campo curto (UF, nº da via, ano): limita a LARGURA DO INPUT sem estreitar a
   coluna. Assim a grade continua fechando a linha (sem vão à direita) e o
   campo fica proporcional ao que se digita nele. */
.form-control--curto { max-width: 8.5rem; }

/* FLUXO: em que etapa o usuário está, numa faixa de uma linha.
   Diferente do `.db-steps` (lista vertical "como funciona", usada no coletor,
   boleto e PIX), que NÃO deve mudar: aquele explica o processo, este responde
   "onde eu estou".

   Sem círculos soltos ligados por trilha: o passo atual é uma PÍLULA no
   gradiente do sistema (a mesma linguagem dos chips de ícone) e os demais
   ficam discretos. Ocupa uma linha em vez de três, e o destaque vem do
   preenchimento, não de um anel em volta. */
.db-flow { display: flex; justify-content: center; }
.db-flow__list {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.35rem;
  list-style: none;
  margin: 0;
  padding: 0;
}
.db-flow__step {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.35rem 0.95rem 0.35rem 0.35rem;
  border-radius: var(--db-radius-pill);
  font-size: 0.9rem;
  font-weight: var(--db-fw-medium);
  color: var(--db-text-soft);
  white-space: nowrap;
}
.db-flow__n {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.78rem;
  font-weight: var(--db-fw-semibold);
  background: var(--db-surface-2);
  color: var(--db-text-soft);
}
.db-flow__n svg { width: 14px; height: 14px; }

/* Traço curto entre as etapas, só o suficiente para ligar a sequência. */
.db-flow__sep {
  width: 2rem;
  height: 2px;
  border-radius: 1px;
  background: var(--db-border);
}
.db-flow__sep.is-done { background: color-mix(in srgb, var(--db-primary) 55%, #fff); }

.db-flow__step.is-done { color: var(--db-text); }
.db-flow__step.is-done .db-flow__n {
  background: color-mix(in srgb, var(--db-primary) 12%, #fff);
  color: var(--db-primary);
}

.db-flow__step.is-active {
  background: linear-gradient(135deg, var(--db-primary), var(--db-accent));
  color: #fff;
  font-weight: var(--db-fw-semibold);
  box-shadow: 0 6px 16px color-mix(in srgb, var(--db-primary) 22%, transparent);
}
.db-flow__step.is-active .db-flow__n { background: rgba(255, 255, 255, 0.22); color: #fff; }

@media (max-width: 575.98px) {
  .db-flow__sep { width: 1rem; }
  .db-flow__step { font-size: 0.82rem; padding-right: 0.7rem; }
}

/* Variante EMPILHADA: coluna estreita (aside).
   Não é a fileira horizontal virada de lado: vira uma TRILHA à esquerda, com os
   números alinhados numa mesma coluna e os rótulos correndo ao lado. Foi o que
   faltava antes: cada passo se centralizava sozinho e os itens não batiam entre
   si, com os traços soltos no meio. */
.db-flow--col { display: block; }
.db-flow--col .db-flow__list {
  display: block;
  gap: 0;
}
.db-flow--col .db-flow__step {
  display: flex;
  width: 100%;
  justify-content: flex-start;
  gap: 0.7rem;
  padding: 0.4rem 0.7rem;
  border-radius: var(--db-radius-sm);
  white-space: normal;
}
/* Trilha: segmento vertical alinhado ao CENTRO do número (28px / 2 + padding). */
.db-flow--col .db-flow__sep {
  width: 2px;
  height: 0.75rem;
  margin: 0.1rem 0 0.1rem calc(0.7rem + 13px);
}

/* Rótulo + descrição. A descrição só existe na vertical: dá contexto do que a
   etapa faz sem exigir que o usuário adivinhe pelo nome. */
.db-flow--col .db-flow__txt { display: flex; flex-direction: column; gap: 0.1rem; }
.db-flow--col .db-flow__rotulo { line-height: 1.25; }
.db-flow--col .db-flow__desc {
  font-size: 0.76rem;
  font-weight: 400;
  line-height: 1.35;
  color: var(--db-text-soft);
}
.db-flow--col .db-flow__step.is-active .db-flow__desc {
  color: color-mix(in srgb, var(--db-primary) 65%, var(--db-text-soft));
}
/* Numa coluna de APOIO o gradiente cheio da fileira horizontal fica pesado: a
   barra ocupa a largura toda e compete com o conteúdo principal da página. Aqui
   o destaque vai para o número (que mantém o gradiente) e a linha recebe só um
   fundo insinuado. */
.db-flow--col .db-flow__step.is-active {
  background: color-mix(in srgb, var(--db-primary) 7%, #fff);
  color: var(--db-primary);
  box-shadow: none;
}
.db-flow--col .db-flow__step.is-active .db-flow__n {
  background: linear-gradient(135deg, var(--db-primary), var(--db-accent));
  color: #fff;
}
/* A trilha até o passo atual mostra o caminho já percorrido. */
.db-flow--col .db-flow__sep.is-done { background: color-mix(in srgb, var(--db-primary) 45%, #fff); }

/* Separador das seções DENTRO de um formulário.
   O `.db-section-head` padrão termina num degradê que some rápido. Funciona no
   painel, cujo fundo é azulado, mas sobre o card branco quase não se vê e a
   seção não lê como separada. Aqui a linha vai inteira, na mesma cor da
   divisória do cabeçalho do card, para os dois lerem como o mesmo sistema.
   Escopado ao formulário: nas telas de resultado o degradê discreto é o certo. */
.db-form-card .db-section-head::after {
  background: var(--db-border);
}

/* "Usar meus dados do cadastro": atalho das telas de PAGAMENTO.
   Elas não nascem preenchidas de propósito (quem paga confirma quem é), então o
   cadastro entra por este botão. É deliberadamente discreto: um botão fantasma
   acima dos campos, não uma ação primária competindo com a de pagar. */
.db-usarcad {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.7rem;
  margin: 0 0 var(--db-space-4);
}
.db-usarcad__btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.42rem 0.8rem;
  border: 1px solid var(--db-border);
  border-radius: var(--db-radius-sm);
  background: var(--db-surface-2);
  color: var(--db-text-muted);
  font-size: 0.83rem;
  font-weight: var(--db-fw-semibold);
  cursor: pointer;
  transition: border-color .15s, color .15s, background .15s;
}
.db-usarcad__btn:hover {
  border-color: var(--db-primary);
  color: var(--db-primary);
  background: color-mix(in srgb, var(--db-primary) 7%, var(--db-surface-2));
}
.db-usarcad__btn svg { width: 15px; height: 15px; flex-shrink: 0; }
.db-usarcad__nota {
  flex: 1 1 14rem;
  font-size: 0.78rem;
  line-height: 1.4;
  color: var(--db-text-soft);
}

/* Campos LADO A LADO numa grade. Em telas mais estreitas, um rótulo que quebra
   em duas linhas ("Ano de fabricação") empurrava só o seu campo para baixo e a
   linha inteira ficava desalinhada. Reservar a altura de duas linhas, com o
   mantém todos os inputs na mesma altura.

   É modificador porque `.db-field` sozinho (formulários de 1 coluna) não tem
   esse problema e não deve ganhar o espaço extra.

   O texto fica ancorado na BASE da área reservada: assim o rótulo continua
   colado no seu campo (reservar altura sem isso deixava um vão enorme abaixo
   dos rótulos de uma linha).

   O flex age sobre o `span` que envolve TODO o conteúdo do rótulo. Sem esse
   wrapper, o asterisco de obrigatório vira item flex irmão do texto e se solta
   para a outra linha.

   `min-height` era 2.7em (2 linhas cheias). No desktop NENHUM rótulo quebra,
   então isso reservava ~1 linha de espaço morto acima de CADA rótulo, o que
   afastava os campos na vertical e o rótulo do seu campo. Reduzido para ~1 linha
   (1.55em): rótulo de 1 linha cola no campo; rótulo que quebra cresce sozinho e
   só empurra o próprio input, no estreito intervalo em que isso acontece. */
.db-field--grid { margin-bottom: 0; }   /* o gutter da .row já separa as linhas */
.db-field--grid > .form-label {
  display: flex;
  align-items: flex-end;
  line-height: 1.3;
  min-height: 1.55em;
  margin-bottom: 0.3rem;
}
/* A quebra de rótulo em 2 linhas (ex.: "Ano de fabricação") só acontece na faixa
   md: abaixo de 768px os campos empilham em largura total (não há vizinho para
   desalinhar) e em ≥992px sobra largura e nada quebra. Só AQUI vale reservar as
   duas linhas: o desktop, caso comum, fica apertado. */
@media (min-width: 768px) and (max-width: 991.98px) {
  .db-field--grid > .form-label { min-height: 2.7em; }
}

/* Spinner inline (ex.: botão em carregamento) */
.db-spinner {
  display: inline-block;
  width: 1.1em;
  height: 1.1em;
  border: 2px solid rgba(255, 255, 255, 0.45);
  border-top-color: #fff;
  border-radius: 50%;
  animation: db-spin 0.7s linear infinite;
}
@keyframes db-spin { to { transform: rotate(360deg); } }
.db-btn.is-loading { pointer-events: none; opacity: 0.9; }
.db-btn.is-loading::after { display: none; } /* desliga o brilho durante o loading */

/* ------------------------------------------------------------------ *
 * 8. APOIO
 * ------------------------------------------------------------------ */
.db-divider {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  color: var(--db-text-soft);
  font-size: 0.85rem;
  margin: var(--db-space-4) 0;
}
.db-divider::before,
.db-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--db-border);
}

.db-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.25rem 0.7rem;
  border-radius: var(--db-radius-pill);
  font-size: 0.78rem;
  font-weight: var(--db-fw-medium);
  background: rgba(2, 51, 115, 0.08);
  color: var(--db-primary);
}

/* Faixa de gradiente (rodapé/topo de seções) */
.db-accent-bar {
  height: 4px;
  border: 0;
  border-radius: var(--db-radius-pill);
  background: var(--db-gradient-h);
}

/* ------------------------------------------------------------------ *
 * 9. ÍCONES (Lucide): padrão de ícones do sistema
 *    Uso: <i data-lucide="nome"></i> (substituído por <svg> no load).
 *    Os SVGs herdam a cor via currentColor e a espessura via stroke.
 * ------------------------------------------------------------------ */
.lucide,
[data-lucide] {
  display: inline-block;
  width: 1.15em;
  height: 1.15em;
  vertical-align: -0.18em;
  stroke-width: 2;
  flex-shrink: 0;
}
/* Tamanhos utilitários */
.db-icon-sm { width: 16px; height: 16px; }
.db-icon-md { width: 20px; height: 20px; }
.db-icon-lg { width: 28px; height: 28px; }
.db-icon-xl { width: 40px; height: 40px; }

/* ------------------------------------------------------------------ *
 * 10. LAYOUT CLARO (páginas internas)
 * ------------------------------------------------------------------ */
.db-page { padding: 2rem 0 3.5rem; }

/* Margem lateral no celular.
   O shorthand acima zera o `padding` horizontal que o `.container` do Bootstrap
   traz. No desktop isso não aparece: o `.container` tem `max-width` e sobra
   espaço de sobra dos dois lados. No celular ele é 100% da largura, então TODO
   card de TODA tela encostava nas duas bordas do aparelho: medido em 0px de
   margem em painel, histórico, carteira, faturas, recarga, comunicação de
   venda e nas telas de resultado.
   O fundo da barra de voltar não é afetado: ele sangra `-100vw` (ver §
   `.db-backbar::before`), então continua atravessando a tela de ponta a ponta. */
@media (max-width: 767.98px) {
  .db-page { padding-left: 0.9rem; padding-right: 0.9rem; }
}

/* Centraliza verticalmente o conteúdo em telas curtas (ex.: formulários) */
.db-page--center { min-height: calc(100vh - 130px); display: flex; flex-direction: column; }
.db-page__body { flex: 1; display: flex; align-items: center; }
.db-page__body > * { width: 100%; }

/* Cabeçalho de página */
.db-page-header { margin-bottom: 1.75rem; }
.db-page-header__title {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 0;
  font-size: 1.75rem;
  font-weight: var(--db-fw-bold);
  letter-spacing: -0.3px;
  color: var(--db-primary);
}
.db-page-header__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  border-radius: 13px;
  background: var(--db-gradient-accent);
  color: #fff;
  flex-shrink: 0;
  box-shadow: 0 8px 20px rgba(2, 51, 115, 0.22);
}
.db-page-header__icon svg { width: 24px; height: 24px; }
.db-page-header__subtitle {
  margin: 0.6rem 0 0;
  color: var(--db-text-muted);
  font-size: 1rem;
}

/* ------------------------------------------------------------------ *
 * VOLTAR: barra de contexto
 * ------------------------------------------------------------------ *
 * Uma faixa no topo do conteúdo com a pílula de voltar e a trilha do
 * caminho. Sempre pelo macro `_voltar.html`, nunca à mão.
 *
 * `sticky` na ALTURA DA NAVBAR, para a faixa encostar nela sem vão. A
 * medida vem de `--db-navbar-h`, que o `barraVoltarGrudada()` do main.js
 * escreve depois de medir a navbar de verdade. O 63px aqui é só a rede
 * de segurança. Já foi um 70px fixo (o `padding-top` do body), e os 7px
 * de diferença viravam uma fresta por onde o conteúdo aparecia passando
 * ao rolar.
 *
 * Grudada, a faixa não some numa tela longa, que era o problema do
 * voltar antigo, um link de texto que ficava lá em cima e não voltava.
 *
 * O z-index é de dentro do `<main>` (que tem z-index:1), então a faixa
 * NÃO sobe por cima da navbar nem do rodapé: ela para embaixo deles,
 * que é o que se quer.
 *
 * A faixa NASCE encostada, não só ao rolar: o `margin-top` negativo puxa
 * ela dos 102px em que cairia (70px do body + 2rem de `.db-page`) para a
 * altura da navbar. Como a posição de repouso passa a ser a MESMA do
 * `top` do sticky, ela nunca se move: vira a segunda linha do cabeçalho.
 * Antes ela boiava: 39px de vão até a navbar e 16px até o card, 109px
 * entre a navbar e o cabeçalho para uma pílula de 31px.
 *
 * O `- 2rem` é o `padding-top` do `.db-page` logo abaixo; se aquele mudar,
 * este muda junto.
 *
 * O FUNDO é permanente, opaco e BRANCO: uma superfície própria, não a cor
 * da página. Permanente porque é o que faz a faixa ler como parte do
 * cabeçalho; opaco porque o conteúdo passa por baixo dela ao rolar, e
 * translúcido apareceria através.
 *
 * Branco por causa do alinhamento: a navbar mora no `.container-fluid` (a
 * 12px da borda) e o conteúdo no `.container` (centralizado), então a
 * margem esquerda das duas NUNCA coincide, e a diferença ainda muda com a
 * largura da janela (115px a 1600, 39px a 1267). Enquanto havia vão entre
 * elas ninguém comparava; encostadas, o olho compara. Alinhamento só
 * incomoda entre coisas do mesmo material: virando superfície própria, a
 * faixa deixa de parecer a continuação torta da navbar e passa a ser outra
 * coisa apoiada ali.
 *
 * O `is-stuck` sobrou só para a SOMBRA: ela aparece quando há mesmo
 * conteúdo passando por baixo, e não com a página parada no topo. Quem o
 * liga é o main.js, por uma sentinela (CSS não sabe dizer que um sticky
 * grudou).
 */
.db-backbar {
  position: sticky;
  top: var(--db-navbar-h, 63px);
  /* O `1px` do fim é a altura da sentinela logo acima. Ela tem
     `margin-bottom: -1px` para não ocupar espaço, mas margens adjacentes
     COLAPSAM: entre -1px e este valor negativo vence só o mais negativo, e o
     1px de altura dela sobra empurrando a faixa. Sem descontar, fica 1px de
     fresta entre a navbar e a faixa. */
  margin-top: calc(var(--db-navbar-h, 63px) - 70px - 2rem - 1px);
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 0.7rem;
  flex-wrap: wrap;
  padding: 0.4rem 0 0.45rem;
  margin-bottom: 1.1rem;
}
/* Sangra até as bordas da viewport, que é o que faz a faixa parecer uma
   extensão da navbar em vez de um cartão centralizado. O `-100vw` só é seguro
   por causa do `overflow-x: clip` no `<main>` (style.css). Sem ele a área
   rolável cresce para a direita e nasce uma barra de rolagem horizontal.
   `clip`, e não `hidden`: `hidden` viraria contêiner de rolagem e mataria o
   `position: sticky` daqui.

   O fundo é translúcido com desfoque, e não branco chapado. O branco chapado
   resolvia o problema certo (o conteúdo passa por baixo e apareceria através de
   um fundo transparente), mas com a solução mais dura que existe: uma tira
   opaca de ponta a ponta, o único elemento do sistema com essa forma fora a
   navbar, e por isso a faixa lia como barra de ferramentas do navegador em vez
   de parte do produto. O desfoque resolve o mesmo problema deixando ver que há
   página ali embaixo, que é o que dá a sensação de camada. */
.db-backbar::before {
  content: "";
  position: absolute;
  /* Sobe 30px além da faixa. A faixa NÃO nasce encostada na navbar: o
     `margin-top` acima a puxa por uma conta com constantes (`70px` do body,
     `2rem` do `.db-page`), e sobra um resto de 11px a 14px conforme a tela.
     Enquanto o fundo era branco sobre página quase branca, ninguém via a
     tira; no celular, com o conteúdo passando por ali ao rolar, ela virou uma
     fresta com meio card aparecendo entre a navbar e a faixa.
     Cobrir é mais seguro que corrigir a conta: a posição de repouso depende do
     padding de duas caixas que mudam por breakpoint, e mexer nela mexe em toda
     tela do sistema. O excedente não vaza porque a navbar é `fixed` com
     z-index 1030 e esta faixa vive dentro do `<main>` (z-index 1): o que passar
     dos 30px fica ATRÁS dela. */
  inset: -30px -100vw 0;
  z-index: -1;
  /* 85%, e não 70%: o desfoque não pode ser a ÚNICA coisa que segura a
     legibilidade. Ele não compõe em toda situação (num Chrome sem GPU, por
     exemplo, o `@supports` diz que há suporte e o efeito não aparece), e nesse
     caso o que sobra é translucidez pura, que é o defeito que o fundo opaco
     existia para evitar. Em 85% o pior caso é um fantasma de nada. */
  background: color-mix(in srgb, var(--db-surface) 85%, transparent);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  backdrop-filter: blur(14px) saturate(140%);
  border-bottom: 1px solid color-mix(in srgb, var(--db-border) 65%, transparent);
  transition: box-shadow 0.18s ease, border-color 0.18s ease;
}
/* Sem suporte a desfoque o fundo volta a ser opaco: translúcido sem desfoque é
   exatamente o caso que o branco chapado existia para evitar. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .db-backbar::before { background: var(--db-surface); }
}
.db-backbar.is-stuck::before {
  border-bottom-color: var(--db-border);
  box-shadow: 0 8px 20px -14px rgba(2, 51, 115, 0.55);
}

/* Onde é seguro grudar. Todo elemento `position: sticky` de página (o resumo
 * do pedido, a navegação lateral da ficha, a coluna de trabalho do suporte)
 * usa ESTE valor no `top`, e nunca um número escrito à mão.
 *
 * O motivo é que a faixa de voltar ocupa de `--db-navbar-h` até
 * `--db-navbar-h + --db-backbar-h`, ou seja, de 63px a 110px na medida real, e
 * ela tem `z-index: 3` enquanto esses cartões não têm nenhum. Enquanto cada
 * tela escolheu o próprio número (84px na ficha e no editor de plano, 88px no
 * aside, 90px no resumo de pagamento, 1rem no suporte), TODOS pararam acima de
 * 110px: ao rolar, o cartão subia e a faixa passava por cima dele. Os números
 * não eram aleatórios, eram a altura da navbar mais um palpite, feitos antes
 * de a faixa existir, e nenhum foi revisto quando ela chegou.
 *
 * O `--db-backbar-h` é medido pelo `barraVoltarGrudada()` do main.js, e vale
 * `0px` na tela que não tem faixa. Os 47px aqui são só a rede de segurança. */
:root { --db-sticky-top: calc(var(--db-navbar-h, 63px) + var(--db-backbar-h, 47px) + 0.9rem); }

/* Sentinela da sombra: fica na posição de repouso ORIGINAL da faixa (a de
   antes do `margin-top` negativo), então ela cruza a linha da navbar quando o
   conteúdo de fato começa a passar por baixo. Não ocupa espaço.
   Ver `barraVoltarGrudada` em main.js. */
.db-backbar-sentinela { display: block; height: 1px; margin-bottom: -1px; }

.db-backbar__sep {
  width: 1px;
  height: 20px;
  background: color-mix(in srgb, var(--db-border) 80%, transparent);
  flex-shrink: 0;
}

/* A faixa é flex: sem isto o <form> do voltar em POST (a conferência da
   comunicação de venda) viraria um item de largura própria e empurraria a
   trilha para a linha de baixo. */
.db-backbar__form { display: contents; }

/* A pílula: chip de fundo suave com a seta num disco próprio.
   Voltar não é a ação principal de tela nenhuma, então ela continua discreta,
   sem cor de marca no repouso. O que mudou foi a FORMA: era um contorno
   fantasma de 1px, e contorno fino sobre faixa clara é a única peça do sistema
   desenhada assim. O resto usa a mesma gramática que está aqui agora, fundo
   `--db-surface-2` e ícone em ladrilho próprio (`.adm-sec__head`, `.svc-ic`,
   `.pnl-aba__ic`), e é isso que faz a faixa deixar de parecer emprestada.
   Serve <a> e <button> (o voltar em POST): daí o reset de fonte e cursor,
   que o <button> não herda sozinho. */
.db-back {
  font-family: inherit;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.25rem 0.85rem 0.25rem 0.25rem;
  background: var(--db-surface-2);
  border: 1px solid transparent;
  border-radius: var(--db-radius-pill);
  color: var(--db-text-muted);
  text-decoration: none;
  font-size: 0.8rem;
  font-weight: var(--db-fw-semibold);
  line-height: 1.5;
  white-space: nowrap;
  transition: background var(--db-transition), border-color var(--db-transition),
              color var(--db-transition), box-shadow var(--db-transition);
}
/* O disco é o próprio <svg>, com `padding` e `box-sizing`, e não um <span> à
   volta: o macro entrega a seta solta, e o mesmo truque já é o que desenha o
   ícone do cabeçalho de seção. Assim o desenho muda sem mexer no markup. */
.db-back svg {
  width: 26px;
  height: 26px;
  padding: 6px;
  box-sizing: border-box;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--db-surface);
  color: var(--db-primary);
  box-shadow: var(--db-shadow-xs);
  transition: transform var(--db-transition), background var(--db-transition),
              color var(--db-transition);
}
.db-back:hover {
  background: color-mix(in srgb, var(--db-primary) 9%, var(--db-surface-2));
  color: var(--db-primary);
}
.db-back:hover svg {
  transform: translateX(-2px);
  background: var(--db-primary);
  color: #fff;
}

/* Trilha. Substitui o `.adm-crumbs` que só o admin tinha: agora é o mesmo
   componente no sistema inteiro.
   Separador em texto (`/`), e não o chevron do Lucide: o ícone tinha peso
   de traço próprio e competia com as palavras. */
.db-crumbs {
  display: flex;
  align-items: center;
  gap: 0.42rem;
  flex-wrap: wrap;
  min-width: 0;
  margin: 0;
  font-size: 0.745rem;
  color: var(--db-text-soft);
}
.db-crumbs a { color: var(--db-text-soft); text-decoration: none; }
.db-crumbs a:hover { color: var(--db-primary); text-decoration: underline; }
.db-crumbs__sep { color: var(--db-border); flex-shrink: 0; }
/* A tela atual não vai em negrito: ela já é o título logo abaixo, em 1.7rem. */
.db-crumbs strong {
  color: var(--db-text-muted);
  font-weight: var(--db-fw-medium);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 46ch;
}

/* No celular a trilha sai: a pílula já diz o destino, e o título da tela
   vem logo abaixo dizendo onde você está.

   Sem a trilha sobra só a pílula, e a faixa passa a ser uma tira de 54px com um
   botão de 40px dentro dela e nada mais. Numa tela de 640px de altura isso é
   quase um doze avos do que se vê, gasto num controle secundário. A folga
   vertical encolhe, e a pílula fica mais estreita (a seta continua num disco,
   só menor). O `min-height: 40px` do alvo de toque NÃO muda: ele é a regra dos
   44px do design system, e é o que garante que o dedo acerte o botão. */
@media (max-width: 575px) {
  .db-backbar__sep, .db-crumbs { display: none; }
  .db-backbar { padding: 0.25rem 0 0.3rem; }
  .db-back { padding: 0.2rem 0.75rem 0.2rem 0.2rem; gap: 0.42rem; }
  .db-back svg { width: 24px; height: 24px; padding: 5px; }
}

/* Card de formulário (telas de consulta) */
.db-form-wrap { max-width: 560px; margin: 0 auto; }
.db-form-card {
  --db-card-accent: var(--db-primary);
  --db-card-ink: var(--db-card-accent);
  padding: 1.5rem 1.6rem;
  display: flex;
  flex-direction: column;
}
.db-form-card form { display: flex; flex-direction: column; flex: 1 1 auto; justify-content: flex-start; }
.db-form-card__head {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  margin-bottom: 1.4rem;
}
.db-form-card__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 12px;
  flex-shrink: 0;
  font-size: 1.1rem;
  background: color-mix(in srgb, var(--db-card-accent) 14%, #fff);
  color: var(--db-card-ink);
}
.db-form-card__icon svg { width: 22px; height: 22px; }
.db-form-card__title {
  margin: 0;
  font-size: 1.2rem;
  font-weight: var(--db-fw-semibold);
  letter-spacing: -0.2px;
  color: var(--db-primary);
}
.db-form-card__desc { margin: 0.15rem 0 0; color: var(--db-text-muted); font-size: 0.9rem; }
.db-form-actions { display: flex; flex-direction: column; gap: 0.7rem; margin-top: 1.6rem; }
.db-form-actions .db-btn { width: 100%; white-space: nowrap; }
.db-form-hint {
  display: block;
  text-align: center;
  margin-top: 0.7rem;
  color: var(--db-text-soft);
  font-size: 0.85rem;
}

/* Aside informativo (ao lado do formulário) */
.db-aside { padding: 1.5rem 1.6rem; }

/* Rodapé de observações de uma coluna de apoio.
   Alternativa ao `.db-note` quando são VÁRIAS: empilhar dois ou três blocos com
   fundo azul transforma a lateral num amontoado de caixas coloridas e rouba a
   atenção do conteúdo principal do card. */
.db-aside__pe {
  margin-top: 1.1rem;
  padding-top: 0.9rem;
  border-top: 1px solid var(--db-border);
}
.db-aside__pe p {
  display: flex;
  gap: 0.55rem;
  margin: 0 0 0.6rem;
  font-size: 0.82rem;
  line-height: 1.45;
  color: var(--db-text-muted);
}
.db-aside__pe p:last-child { margin-bottom: 0; }
.db-aside__pe svg {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
  margin-top: 2px;
  color: var(--db-text-soft);
}
.db-aside__pe strong { color: var(--db-text); font-weight: var(--db-fw-medium); }

/* Atalho dentro de uma coluna de apoio: leva a OUTRA tela que resolve um
   impedimento da atual. Fica entre o texto e o botão: precisa parecer
   clicável, mas sem competir com o CTA principal logo abaixo. */
.db-aside__atalho {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  margin-top: 1.1rem;
  padding: 0.7rem 0.85rem;
  border: 1px solid var(--db-border);
  border-radius: var(--db-radius-sm);
  background: var(--db-surface-2);
  color: var(--db-text-muted);
  font-size: 0.82rem;
  line-height: 1.4;
  text-decoration: none;
  transition: border-color var(--db-transition), background var(--db-transition);
}
.db-aside__atalho:hover {
  border-color: color-mix(in srgb, var(--db-accent) 45%, var(--db-border));
  background: #fff;
  color: var(--db-text-muted);
}
.db-aside__atalho strong { display: block; color: var(--db-text); font-weight: var(--db-fw-medium); }
.db-aside__atalho svg { width: 16px; height: 16px; flex-shrink: 0; color: var(--db-accent); }
.db-aside__atalho-seta { margin-left: auto; opacity: 0.6; }
.db-aside__atalho:hover .db-aside__atalho-seta { opacity: 1; }

/* Coluna de apoio que ACOMPANHA a rolagem. Numa página longa (formulário de
   vários blocos) a lateral termina na altura do primeiro card e o resto da tela
   fica com um terço vazio, e a ajuda some justamente quando o usuário chega nos
   campos difíceis. Só a partir de lg: abaixo disso as colunas empilham e sticky
   não faria sentido. */
@media (min-width: 992px) {
  .db-aside--sticky { position: sticky; top: var(--db-sticky-top); }
}
.db-aside__title {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 1.2rem;
  font-size: 1.05rem;
  font-weight: var(--db-fw-semibold);
  color: var(--db-primary);
}
.db-aside__title svg { width: 18px; height: 18px; color: var(--db-accent); }

/* Passos numerados */
.db-steps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 1.05rem; }
.db-steps li { display: flex; gap: 0.8rem; }
.db-steps__num {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--db-accent) 14%, #fff);
  color: var(--db-accent);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: var(--db-fw-semibold);
  font-size: 0.85rem;
}
.db-steps strong { display: block; color: var(--db-text); font-size: 0.93rem; font-weight: var(--db-fw-medium); }
.db-steps p { margin: 0.1rem 0 0; color: var(--db-text-muted); font-size: 0.85rem; line-height: 1.45; }

/* Nota/dica */
.db-note {
  display: flex;
  gap: 0.6rem;
  align-items: flex-start;
  margin-top: 1.3rem;
  padding: 0.8rem 0.95rem;
  border-radius: var(--db-radius-sm);
  background: color-mix(in srgb, var(--db-accent) 8%, #fff);
  border: 1px solid color-mix(in srgb, var(--db-accent) 18%, #fff);
  color: var(--db-text-muted);
  font-size: 0.85rem;
  line-height: 1.45;
}
.db-note svg { width: 17px; height: 17px; color: var(--db-accent); flex-shrink: 0; margin-top: 1px; }

/* Nota de ALERTA: o recado que precede uma ação destrutiva */
.db-note--danger {
  background: color-mix(in srgb, #dc3545 6%, #fff);
  border-color: color-mix(in srgb, #dc3545 20%, #fff);
  color: #8f2029;
}
.db-note--danger svg { color: #c0303c; }

/* Faixa de boas-vindas (banner do topo da página, tema claro) */
.db-welcome {
  position: relative;
  overflow: hidden;
  background: linear-gradient(120deg, #ffffff 0%, #eaf3fd 100%);
  border: 1px solid var(--db-border);
  border-radius: var(--db-radius-lg);
  padding: 1.6rem 1.9rem;
  margin-bottom: 1.9rem;
  box-shadow: var(--db-shadow-sm);
}
.db-welcome__title {
  margin: 0.25rem 0 0.35rem;
  font-size: 1.7rem;
  font-weight: var(--db-fw-bold);
  letter-spacing: -0.4px;
  color: var(--db-primary);
}
.db-welcome__sub { margin: 0; color: var(--db-text-muted); font-size: 1rem; }
/* O texto para ANTES das faixas, também no banner sem ícone.
   A variante `--with-icon` já reservava esse espaço no `__body`; a simples não,
   e o defeito ficou invisível enquanto os subtítulos foram curtos ("Escolha uma
   categoria..."). Um subtítulo mais longo passa por baixo das faixas, e o fim
   da frase sai lido sobre listras azul, verde e amarela.
   Nos próprios elementos de texto, e não no `.db-welcome`: o banner também
   hospeda chips e botões, que ali ficariam recuados sem motivo. As faixas são
   absolutas (`right: 8%`) e não se mexem com isto; abaixo de 576px elas somem,
   e a reserva some junto. */
@media (min-width: 576px) {
  .db-welcome > .db-eyebrow,
  .db-welcome > .db-welcome__title,
  .db-welcome > .db-welcome__sub { padding-right: clamp(120px, 18%, 210px); }
}
/* Variante com ícone grande identificando a tela (à esquerda do título) */
.db-welcome--with-icon { display: flex; align-items: center; gap: 1.4rem; }
.db-welcome--with-icon .db-welcome__body { position: relative; z-index: 1; min-width: 0; }
/* Reserva espaço à direita para o texto não cruzar as faixas (elas são absolutas
   em right:8%). Some no mobile, onde as faixas ficam ocultas. */
@media (min-width: 576px) {
  .db-welcome--with-icon .db-welcome__body { padding-right: clamp(120px, 18%, 210px); }
}
.db-welcome__icon {
  position: relative; z-index: 1; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  width: 74px; height: 74px; border-radius: 20px;
  /* cor fixa da marca (mesmo dos ícones de cabeçalho de seção) */
  background: linear-gradient(135deg, var(--db-primary), var(--db-accent));
  color: #fff;
  box-shadow: 0 12px 26px color-mix(in srgb, var(--db-primary) 30%, transparent),
              inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
.db-welcome__icon svg { width: 35px; height: 35px; }
/* No celular o cabeçalho EMPILHA: ícone em cima, texto em largura cheia.

   Lado a lado num aparelho de 390px sobravam 222px para o texto, uma fita de
   ~25 caracteres, em que um subtítulo de uma frase quebra em três linhas. E o
   ícone, com `align-items: center`, ficava alinhado ao MEIO do bloco de texto:
   não encostava no título nem em nada, parecendo solto na margem esquerda.

   Empilhado e centralizado, é o mesmo gesto do `.db-result-head` (que já
   empilha e centraliza a partir de 767px), então cabeçalho de tela e cabeçalho
   de resultado passam a se comportar igual no celular. */
@media (max-width: 575px) {
  .db-welcome--with-icon {
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 0.9rem;
  }
  .db-welcome--with-icon .db-welcome__body { width: 100%; }
  /* Agora que o cabeçalho é centralizado, centralizar os chips é intenção e
     não sobra de outra regra (ver o bloco do `.db-result-head`). */
  .db-welcome--with-icon .db-result-meta,
  .db-welcome--with-icon .db-result-tags { justify-content: center; }
  .db-welcome__icon { width: 60px; height: 60px; border-radius: 16px; }
  .db-welcome__icon svg { width: 28px; height: 28px; }
}
/* faixas da bandeira como acento no canto direito do banner */
.db-welcome__stripes {
  --db-stripe-w: 26px;
  --db-stripe-gap: 0px;
  --db-stripe-angle: 22deg;
  --db-stripe-1: var(--db-cyan-500);
  --db-stripe-2: var(--db-green-500);
  --db-stripe-3: var(--db-yellow);
  top: -40%;
  right: 8%;
  height: 200%;
  opacity: 0.85;
}
@media (max-width: 575px) {
  .db-welcome__stripes { display: none; }
}

/* Cartão de serviço/consulta (tema claro).
   Cada cartão tem uma cor-tema (--db-card-accent) da paleta do manual,
   que rege ícone, borda no hover e botão.
   --db-card-ink: tom do ícone/texto sobre claro (default = accent)
   --db-card-on:  cor do texto sobre o botão sólido (default = branco) */
.db-tool-card {
  --db-card-accent: var(--db-primary-soft);
  --db-card-ink: var(--db-card-accent);
  --db-card-btn: #2B4E9C;   /* botão SEMPRE no azul institucional; a cor do
                               serviço (--db-card-accent) fica só no ícone */
  --db-card-on: #fff;
  display: flex;
  flex-direction: column;
  height: 100%;
  background: #fff;
  border: 1px solid var(--db-border);
  border-radius: var(--db-radius);
  padding: 1.6rem;
  box-shadow: var(--db-shadow-xs);
  transition: box-shadow var(--db-transition), border-color var(--db-transition);
}
.db-tool-card:hover {
  border-color: color-mix(in srgb, var(--db-card-btn) 45%, var(--db-border));
  box-shadow: var(--db-shadow-sm);
}
/* Ícone: chip azul do sistema (monocromático); a identificação do serviço vem
   do ícone + nome. O botão também é azul, então o card fica uno/institucional. */
.db-tool-card__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border-radius: 14px;
  margin-bottom: 1.1rem;
  background: color-mix(in srgb, var(--db-card-btn) 14%, #fff);
  color: var(--db-card-btn);
}
.db-tool-card__icon svg { width: 26px; height: 26px; }
.db-tool-card__title {
  margin: 0 0 0.4rem;
  font-size: 1.18rem;
  font-weight: var(--db-fw-semibold);
  color: var(--db-primary);
}
.db-tool-card__desc {
  flex: 1;
  margin: 0;
  color: var(--db-text-muted);
  font-size: 0.92rem;
  line-height: 1.5;
}
.db-tool-card__action { margin-top: 1.4rem; }

/* Botão do cartão: azul institucional fixo (a cor do serviço vive no ícone) */
.db-tool-card .db-btn {
  background-image: none;
  background-color: var(--db-card-btn);
  color: var(--db-card-on);
  box-shadow: none;
}
.db-tool-card .db-btn:hover {
  background-image: none;
  background-color: color-mix(in srgb, var(--db-card-btn) 86%, #000);
  color: var(--db-card-on);
  box-shadow: 0 6px 16px color-mix(in srgb, var(--db-card-btn) 35%, transparent);
}
.db-tool-card .db-btn--outline {
  background-color: transparent;
  color: var(--db-card-ink);
  border: 1.5px solid color-mix(in srgb, var(--db-card-accent) 40%, #fff);
}
.db-tool-card .db-btn--outline:hover {
  background-color: var(--db-card-accent);
  border-color: var(--db-card-accent);
  color: var(--db-card-on);
}

/* Cartão de dados (telas de resultado) */
.db-data-card { padding: 1.5rem 1.6rem; margin-bottom: 1.4rem; }
.db-data-card:last-child { margin-bottom: 0; }
.db-data-card__title {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0 0 1.2rem;
  font-size: 1.1rem;
  font-weight: var(--db-fw-semibold);
  color: var(--db-primary);
}
.db-data-card__title svg { width: 20px; height: 20px; color: var(--db-accent); }
.db-data-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 0.8rem;
}
.db-data-item {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  padding: 0.85rem 1rem;
  border: 1px solid var(--db-border);
  border-radius: var(--db-radius-sm);
  background: #fff;
  transition: border-color var(--db-transition), box-shadow var(--db-transition);
}
.db-data-item:hover { border-color: rgba(0, 149, 217, 0.35); box-shadow: var(--db-shadow-xs); }
.db-data-item__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 11px;
  flex-shrink: 0;
  background: color-mix(in srgb, var(--db-accent) 12%, #fff);
  color: var(--db-accent);
}
.db-data-item__icon svg { width: 20px; height: 20px; }
.db-data-item__body { min-width: 0; display: flex; flex-direction: column; line-height: 1.25; }
.db-data-item__label { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.4px; color: var(--db-text-soft); }
.db-data-item__value { font-weight: var(--db-fw-semibold); color: var(--db-text); overflow: hidden; text-overflow: ellipsis; }

/* Cores por cartão: paleta institucional do manual */
/* Cores dos ÍCONES por serviço (o botão é sempre azul institucional, Opção 1).
   Escolhidas por sentido semântico e mantendo-se distintas entre si. */
.db-tool-card--blue   { --db-card-accent: #2E6FB0; } /* dados do veículo   */
.db-tool-card--navy   { --db-card-accent: #26305F; } /* dossiê oficial     */
.db-tool-card--slate  { --db-card-accent: #5B6B82; } /* documento/débitos  */
.db-tool-card--indigo { --db-card-accent: #4051B0; } /* linha do tempo     */
.db-tool-card--cyan   { --db-card-accent: #1E6F94; } /* (reserva)          */
.db-tool-card--green  { --db-card-accent: #2C7A5B; } /* CNH válida         */
.db-tool-card--lime   { --db-card-accent: #5DBF4E; --db-card-ink: #2f7a26; } /* (reserva) */
.db-tool-card--amber,
.db-tool-card--yellow { --db-card-accent: #B0741A; } /* dourado (leilão)   */
/* Cores adicionais, todas escuras o bastante p/ o botão "Consultar" ficar
   com texto branco legível (contraste >= 4.8:1 com #fff). */
.db-tool-card--teal   { --db-card-accent: #0E8090; } /* técnico (decodificador) */
.db-tool-card--purple { --db-card-accent: #6A4AA6; } /* financiamento (gravame) */
.db-tool-card--rose   { --db-card-accent: #B83A5E; } /* pessoas (proprietários) */
.db-tool-card--red    { --db-card-accent: #C0392B; } /* alerta (sinistro)       */
.db-tool-card--orange { --db-card-accent: #B85416; } /* laranja (reserva)       */

/* Ícones do admin (svc-ic-- / svcx__ic--) para as cores novas: tinta clara de
   fundo + ícone na cor. Os spans já trazem a classe-base; aqui só o tom. */
.svc-ic--teal,   .svcx__ic--teal   { background: color-mix(in srgb, #0E8090 14%, #fff); color: #0E8090; }
.svc-ic--purple, .svcx__ic--purple { background: color-mix(in srgb, #6A4AA6 14%, #fff); color: #6A4AA6; }
.svc-ic--rose,   .svcx__ic--rose   { background: color-mix(in srgb, #B83A5E 14%, #fff); color: #B83A5E; }
.svc-ic--red,    .svcx__ic--red    { background: color-mix(in srgb, #C0392B 14%, #fff); color: #C0392B; }
.svc-ic--indigo, .svcx__ic--indigo { background: color-mix(in srgb, #4051B0 14%, #fff); color: #4051B0; }
.svc-ic--slate,  .svcx__ic--slate  { background: color-mix(in srgb, #5B6B82 16%, #fff); color: #5B6B82; }
.svc-ic--orange, .svcx__ic--orange { background: color-mix(in srgb, #B85416 14%, #fff); color: #B85416; }

/* ------------------------------------------------------------------ *
 * N. RESULTADOS DE CONSULTA (tema claro)
 *    Componentes compartilhados por todas as telas de resultado.
 *    Específicos da tela (ex.: placa) ficam no <style> da própria página.
 * ------------------------------------------------------------------ */
/* Hero do resultado */
.db-result-head {
  position: relative; overflow: hidden;
  display: flex; align-items: center; gap: 2rem;
  padding: 1.85rem 2rem; margin-bottom: 1.1rem;
  background:
    radial-gradient(120% 140% at 100% 0%, color-mix(in srgb, var(--db-accent) 8%, #fff) 0%, transparent 55%),
    radial-gradient(120% 160% at 0% 100%, color-mix(in srgb, var(--db-primary) 6%, #fff) 0%, transparent 50%),
    var(--db-surface);
}
.db-result-head__aside { position: relative; z-index: 1; flex-shrink: 0; }
/* Cartão CNH um pouco menor no cabeçalho do resultado, para alinhar em altura
   com o bloco de nome/chips ao lado (não afeta o modal nem o PDF). */
.db-result-head__aside .db-idcard { zoom: 0.9; }
.db-result-head__info  { position: relative; z-index: 1; flex: 1 1 auto; min-width: 0; }
.db-result-head__info .db-eyebrow { margin-bottom: 0.5rem; }

/* faixas da bandeira no canto direito (mesmo acento do banner) */
.db-result-head__stripes {
  --db-stripe-w: 26px; --db-stripe-gap: 0px; --db-stripe-angle: 22deg;
  --db-stripe-1: var(--db-cyan-500);
  --db-stripe-2: var(--db-green-500);
  --db-stripe-3: var(--db-yellow);
  top: -40%; right: 9%; height: 200%; opacity: 0.85; z-index: 0;
}
.db-result-title {
  margin: 0 0 0.75rem; font-size: 1.5rem; line-height: 1.15;
  font-weight: var(--db-fw-bold); color: var(--db-primary); text-transform: capitalize;
}
.db-result-tags { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1rem; }
.db-chip {
  display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.35rem 0.75rem; border-radius: var(--db-radius-pill);
  background: var(--db-surface-2); border: 1px solid var(--db-border);
  font-size: 0.82rem; font-weight: var(--db-fw-medium);
  color: var(--db-text); text-transform: capitalize;
}
.db-chip svg { width: 14px; height: 14px; color: var(--db-accent); }
/* Chip como FILTRO (link clicável, um deles ativo). O `.db-chip` nasceu como
   etiqueta de leitura nas telas de resultado; aqui ele é controle, e precisa
   dizer qual está valendo. */
a.db-chip { text-decoration: none; transition: border-color .15s ease, color .15s ease, background .15s ease; }
a.db-chip:hover { border-color: var(--db-primary); color: var(--db-primary); background: rgba(2, 51, 115, 0.06); }
.db-chip--on, a.db-chip--on:hover {
  background: var(--db-primary); border-color: var(--db-primary);
  color: #fff; font-weight: var(--db-fw-semibold);
}
.db-chip--on svg { color: #fff; }
.db-result-meta { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }
.db-status {
  display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.3rem 0.7rem; border-radius: var(--db-radius-pill);
  font-size: 0.8rem; font-weight: 600;
}
.db-status svg { width: 15px; height: 15px; }
.db-status--ok   { background: rgba(3, 140, 90, 0.13);  color: #0f7a4f; }
.db-status--pend { background: rgba(217, 144, 0, 0.16); color: #946800; }
.db-status--err  { background: rgba(220, 53, 69, 0.12); color: #c0303c; }
/* `--warn` é o mesmo amarelo de `--pend`: os dois nomes já circulavam nos
   templates e só `--pend` existia aqui, então quem escreveu `--warn` ficava sem
   estilo nenhum. Mantidos os dois em vez de renomear o que já está em uso. */
.db-status--warn { background: rgba(217, 144, 0, 0.16); color: #946800; }
/* mini-spinner dentro do badge, para status "em andamento" */
.db-status__spin {
  width: 11px; height: 11px; flex-shrink: 0;
  border: 2px solid color-mix(in srgb, currentColor 28%, transparent);
  border-top-color: currentColor; border-radius: 50%;
  animation: db-spin 0.7s linear infinite;
}
.db-result-date { display: inline-flex; align-items: center; gap: 0.4rem; color: var(--db-text-muted); font-size: 0.85rem; }
.db-result-date svg { width: 15px; height: 15px; }

/* --- Badge de STATUS DA CONSULTA -------------------------------------------
   Vocabulário próprio do ciclo de vida da consulta (completo / processando /
   erro / não encontrado / aguardando dados / cancelada). O `.db-status` acima
   cobre outros casos e não tem esses nomes.

   Morava inline no <style> do histórico. Subiu para cá porque é componente do
   sistema: o vocabulário de status é do domínio, não de uma tela, e qualquer
   lugar que liste consultas precisa dele com as mesmas cores. */
.status-badge {
  display: inline-flex; align-items: center;
  padding: 0.28rem 0.65rem; border-radius: var(--db-radius-pill);
  font-size: 0.72rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.3px;
}
.status-badge.status-completo  { background: rgba(3, 140, 90, 0.14);  color: #0f7a4f; }
.status-badge.status-erro      { background: rgba(220, 53, 69, 0.12); color: #c0303c; }
.status-badge.status-pendente  { background: rgba(217, 144, 0, 0.16); color: #946800; }
.status-badge.status-not-found { background: rgba(217, 144, 0, 0.16); color: #946800; }
/* Ação necessária (falta um dado que a BIN não trouxe): azul do sistema,
   distinto do "processando" para sinalizar que depende do cliente. */
.status-badge.status-aguardando { background: rgba(0, 149, 217, 0.14); color: #0369a1; }
/* Cancelada pelo cliente (desistiu quando pedimos o dado que faltava),
   neutra de propósito: não é erro nosso nem falha, e o valor voltou. */
.status-badge.status-cancelado  { background: rgba(100, 116, 139, 0.14); color: #475569; }
.status-badge__spin {
  width: 11px; height: 11px; margin-right: 0.4rem; flex-shrink: 0;
  border: 2px solid color-mix(in srgb, currentColor 28%, transparent);
  border-top-color: currentColor; border-radius: 50%;
  animation: db-spin 0.7s linear infinite;
}
/* Badge com hint de prazo no hover (serviços que sabemos que demoram, ex.:
   CRLV-e do Ricio). O cursor sinaliza que há informação. */
.status-badge.has-tip { cursor: help; }

/* Documento (CPF/RG) no hero: equivalente à placa, para telas de pessoa.
   Cartão claro com faixa superior de acento, para combinar com o tema. */
.db-doc {
  position: relative; overflow: hidden;
  display: flex; align-items: center; gap: 1rem;
  width: 320px; max-width: 100%; padding: 1.2rem 1.35rem;
  border-radius: var(--db-radius);
  background: var(--db-surface);
  border: 1px solid var(--db-border);
  box-shadow: 0 8px 22px rgba(28, 42, 63, 0.08);
}
.db-doc::before {
  content: ''; position: absolute; inset: 0 0 auto 0; height: 5px;
  background: linear-gradient(90deg, var(--db-primary), var(--db-accent));
}
.db-doc__icon {
  display: flex; align-items: center; justify-content: center;
  width: 52px; height: 52px; flex-shrink: 0; border-radius: 14px;
  background: linear-gradient(135deg, var(--db-primary), var(--db-accent));
  color: #fff;
  box-shadow: 0 6px 16px color-mix(in srgb, var(--db-primary) 24%, transparent);
}
.db-doc__icon svg { width: 26px; height: 26px; }
.db-doc__label { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.1em; color: var(--db-text-soft); font-weight: var(--db-fw-semibold); }
.db-doc__value { font-family: 'JetBrains Mono', 'Courier New', monospace; font-size: 1.4rem; font-weight: 600; letter-spacing: 0.5px; color: var(--db-text); }

/* Mini-documento CNH (carteira de habilitação): mesma presença da placa no
   hero. Componente compartilhado: usado na tela de resultado, no PDF e no modal
   de confirmação do coletor (padronização). */
.db-idcard {
  width: 370px; max-width: 100%;
  border: 1px solid var(--db-border); border-radius: var(--db-radius);
  overflow: hidden; background: var(--db-surface);
  box-shadow: 0 8px 22px rgba(28, 42, 63, 0.08);
}
.db-idcard__head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 8px 14px; height: 36px;
  background: linear-gradient(90deg, var(--db-primary), var(--db-primary-soft));
  color: #fff;
}
.db-idcard__title { font-size: 11px; font-weight: 700; letter-spacing: 0.5px; text-transform: uppercase; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.db-idcard__flag { position: relative; width: 26px; height: 18px; flex-shrink: 0; background: #009c3b; border-radius: 2px; }
.db-idcard__flag-d { position: absolute; top: 2px; left: 3px; width: 20px; height: 14px; background: #ffdf00; clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%); }
.db-idcard__flag-c { position: absolute; top: 5.5px; left: 9px; width: 7px; height: 7px; background: #0033a0; border-radius: 50%; }
.db-idcard__body { display: flex; align-items: center; gap: 1.1rem; padding: 1.05rem 1.2rem; }
.db-idcard__photo {
  display: flex; align-items: center; justify-content: center;
  width: 66px; height: 82px; flex-shrink: 0; border-radius: 9px;
  background: color-mix(in srgb, var(--db-primary) 7%, #fff);
  border: 1px solid var(--db-border); color: var(--db-primary-soft);
}
.db-idcard__photo svg { width: 38px; height: 38px; }
.db-idcard__fields { min-width: 0; text-align: left; }
.db-idcard__label { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.1em; color: var(--db-text-soft); font-weight: var(--db-fw-semibold); }
.db-idcard__label--sep { margin-top: 0.55rem; }
.db-idcard__value { font-family: 'JetBrains Mono', 'Courier New', monospace; font-size: 1.6rem; font-weight: 600; letter-spacing: 0.5px; color: var(--db-text); line-height: 1.2; }
.db-idcard__sub { font-size: 1.05rem; font-weight: var(--db-fw-semibold); color: var(--db-text); }

/* Ações */
.db-result-actions { display: flex; gap: 0.7rem; flex-wrap: wrap; margin-bottom: 1.1rem; }

/* Estados (processando / erro / vazio) */
.db-state { text-align: center; padding: 2.5rem 1rem; }
.db-state__title { font-size: 1.1rem; font-weight: 600; color: var(--db-primary); margin: 0 0 0.3rem; }
.db-state__text { color: var(--db-text-muted); margin: 0; }
.db-state__icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 60px; height: 60px; border-radius: 50%; margin-bottom: 0.9rem;
}
.db-state__icon svg { width: 28px; height: 28px; }
.db-state__icon--err  { background: rgba(220, 53, 69, 0.12); color: #c0303c; }
.db-state__icon--warn { background: rgba(217, 144, 0, 0.16); color: #946800; }
.db-processing__spinner {
  width: 48px; height: 48px; border: 5px solid var(--db-border);
  border-top-color: var(--db-accent); border-radius: 50%;
  animation: db-spin 0.8s linear infinite; margin: 0 auto 1rem;
}

/* Estado vazio (sem resultados / sem movimentações): centralizado, ícone
   neutro. Usado no histórico e na carteira. */
.db-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; padding: 3rem 1.5rem; gap: 0.15rem;
}
.db-empty__icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 64px; height: 64px; border-radius: 50%; margin-bottom: 0.85rem;
  background: var(--db-surface-2); color: var(--db-text-soft);
}
.db-empty__icon svg { width: 30px; height: 30px; }
.db-empty__title {
  font-size: 1.15rem; font-weight: var(--db-fw-semibold);
  color: var(--db-primary); margin: 0 0 0.25rem;
}
.db-empty__text { color: var(--db-text-muted); margin: 0; max-width: 400px; }

/* Célula vazia: o `—` que ocupa o lugar de um valor que não existe. Morava no
   <style> do histórico e é escrito por três telas (histórico, indicados do
   afiliado, e o modal de dados pendentes, que vive no base.html e portanto
   aparece em qualquer página): fora do histórico o traço saía na cor e no
   tamanho do texto comum, competindo com os dados de verdade em vez de sumir. */
.hist-vazio {
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--db-text-soft); font-size: 1rem; user-select: none;
}

/* Tabela do design system (cabeçalho navy). Componente global usado no
   histórico e no extrato da carteira. */
.db-table-card { padding: 0; overflow: hidden; margin-bottom: 1.1rem; }
.db-table { width: 100%; border-collapse: collapse; }
.db-table thead th {
  background: var(--db-primary); color: rgba(255, 255, 255, 0.92);
  font-size: 0.74rem; text-transform: uppercase; letter-spacing: 0.5px;
  font-weight: 600; padding: 0.85rem 1.1rem; text-align: left; white-space: nowrap;
}
.db-table tbody td {
  padding: 0.8rem 1.1rem; border-bottom: 1px solid var(--db-border);
  vertical-align: middle; font-size: 0.9rem; color: var(--db-text);
}
.db-table tbody tr:last-child td { border-bottom: none; }
.db-table tbody tr { transition: background 0.15s ease; }
.db-table tbody tr:hover { background: var(--db-surface-2); }
.db-table .text-end { text-align: right; }

/* Moldura da tabela quando ela NÃO está dentro de um .db-table-card (tabela
   solta no meio de um card de dados). Estava só no <style> do SISCSV, mas a
   camada de densidade do PDF já a referenciava como componente global, e o
   decodificador de chassi passou a usá-la. */
.db-table-wrap {
  overflow-x: auto;
  /* No celular, arrastar a tabela até a borda esquerda continua o gesto na
     página e o navegador entende "voltar": a pessoa perde o resultado por
     tentar ler a última coluna. `contain` para o gesto na tabela. */
  overscroll-behavior-x: contain;
  border: 1px solid var(--db-border);
  border-radius: var(--db-radius-sm);
  margin-bottom: 1.1rem;
}
/* Célula de dinheiro: o valor é o dado que a pessoa procura na linha. */
.db-table__price {
  font-weight: var(--db-fw-semibold, 600);
  color: var(--db-text);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* ===== Tabela vira LISTA DE CARTÕES no celular ===========================
   A tabela do histórico mede 812px num aparelho de 390px. Ela ROLA de lado (o
   `.table-responsive` do Bootstrap é `overflow-x: auto`), então nada está
   tecnicamente inalcançável. O problema é outro: em 390px aparecem placa,
   tipo e cobrança, e data, status e o botão "Visualizar" ficam fora. A ação
   principal da tela exige um arrasto lateral DENTRO da tabela, gesto que não
   se anuncia: no toque não há barra de rolagem, e nada na borda direita diz
   que existe mais coisa ali.

   Abaixo de 768px cada <tr> vira um cartão e cada <td> ganha o rótulo da sua
   coluna, lido do `data-rotulo`. O ganho não é "passar a caber": é a ação
   deixar de depender de um gesto que ninguém descobre.

   É OPT-IN pela classe `db-table--cards`. Tabela de PDF e tabela de tela de
   resultado (que usam `.db-table-wrap`, com rolagem própria) não entram, e o
   `screen` é a segunda trava, porque o PDF renderiza a 794px com media=screen.

   Ao usar, o template precisa de três coisas (ver frontend-guide.md §4, 15):
     <table class="db-table db-table--cards">
     <td data-rotulo="Status">            em TODA célula
     <td class="db-td-acao">              na célula da ação */
@media screen and (max-width: 767.98px) {
  .db-table-card:has(.db-table--cards) {
    overflow: visible;
    background: transparent;
    box-shadow: none;
    border: 0;
  }

  .db-table--cards thead { display: none; }
  .db-table--cards,
  .db-table--cards tr,
  .db-table--cards td { display: block; width: 100%; }
  /* `tbody:not([aria-hidden])` e não `tbody`: os corpos de ESQUELETO
     (`.db-skel-body`, `.ext-skeleton`) se escondem com `display: none` numa
     regra de uma classe só. Um seletor `classe + elemento` tem especificidade
     maior e os traria de volta: as linhas-fantasma apareciam como cartões
     vazios abaixo da lista, o tempo todo. Os dois são `aria-hidden="true"`,
     que é justamente o que os separa do conteúdo de verdade. */
  .db-table--cards tbody:not([aria-hidden]) { display: block; width: 100%; }

  .db-table--cards tr {
    background: var(--db-surface);
    border: 1px solid var(--db-border);
    border-radius: var(--db-radius-md, 14px);
    box-shadow: 0 2px 10px rgba(16, 39, 78, 0.06);
    padding: 0.35rem 0.9rem 0.75rem;
    margin-bottom: 0.7rem;
  }
  .db-table--cards tbody tr:hover { background: var(--db-surface); }

  .db-table--cards td {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.9rem;
    text-align: right;
    padding: 0.55rem 0;
    border-bottom: 1px solid var(--db-border);
  }
  .db-table--cards td:last-child { border-bottom: none; }

  /* O rótulo da coluna vira a etiqueta da linha do cartão. */
  .db-table--cards td::before {
    content: attr(data-rotulo);
    flex: 0 0 auto;
    font-size: 0.7rem; font-weight: 600; letter-spacing: 0.5px;
    text-transform: uppercase; color: var(--db-text-muted);
    text-align: left;
  }
  /* Célula sem rótulo (a 1ª, a de ação) não desenha etiqueta vazia. */
  .db-table--cards td:not([data-rotulo])::before,
  .db-table--cards td[data-rotulo=""]::before { display: none; }

  /* A 1ª célula é o TÍTULO do cartão: a placa, o número da fatura. */
  .db-table--cards td:first-child {
    justify-content: flex-start;
    text-align: left;
    padding-top: 0.7rem;
    font-size: 1.05rem;
    font-weight: var(--db-fw-semibold, 600);
  }
  .db-table--cards td:first-child::before { display: none; }

  /* A ação ocupa a largura do cartão, é o que se quer tocar. Os templates
     embrulham as ações num wrapper (`span.d-inline-flex` no histórico,
     `div.fatlist-acts` nas faturas), e é ELE o filho flex da célula: mandar o
     botão crescer sem mandar o wrapper não cresce nada. */
  .db-table--cards td.db-td-acao { justify-content: flex-start; padding-top: 0.7rem; }
  .db-table--cards td.db-td-acao::before { display: none; }
  /* `:not([hidden])` é obrigatório: o conteúdo do menu "⋮" do histórico é um
     `<div class="hist-menu" hidden>` IRMÃO das ações, dentro da mesma célula.
     Sem a exclusão, o `display: flex !important` aqui vence o `[hidden]` e o
     menu inteiro ("Repetir consulta", "Falar com o suporte") aparece aberto
     dentro de todo cartão. */
  .db-table--cards td.db-td-acao > span:not([hidden]),
  .db-table--cards td.db-td-acao > div:not([hidden]) {
    flex: 1 1 auto;
    display: flex !important;
    align-items: center;
    justify-content: flex-start !important;
    gap: 0.5rem;
  }
  .db-table--cards td.db-td-acao .db-btn {
    flex: 1 1 auto; min-height: 46px; justify-content: center;
  }
  .db-table--cards td.db-td-acao .hist-mais { flex: 0 0 auto; min-width: 44px; min-height: 44px; }
  /* `hist-acao` fixa 148px para alinhar a COLUNA; no cartão não há coluna. */
  .db-table--cards td.db-td-acao .hist-acao { min-width: 0; }
}

/* ===== Alvos de toque e zoom do iOS =====================================
   A auditoria achou 520 alvos abaixo de 40px. E campo com fonte menor que 16px
   faz o Safari do iPhone DAR ZOOM ao focar, e não desfazer depois; os campos
   estavam em 14,7px. Aqui o 16px é regra de acessibilidade, não de estética. */
@media screen and (max-width: 767.98px) {
  .db-btn { min-height: 44px; }
  .db-btn--sm { min-height: 40px; padding-inline: 0.9rem; }
  .db-page-link { min-width: 44px; min-height: 44px; }
  /* A pílula de voltar é FANTASMA de propósito (peso visual baixo: voltar não
     é a ação principal de tela nenhuma), mas isso é sobre APARÊNCIA, não sobre
     tamanho de alvo: ela media 31px. Só o padding vertical cresce; borda, fundo
     e cor continuam iguais. */
  .db-back { min-height: 40px; }

  .form-control, .form-select, textarea, select,
  input[type="text"], input[type="email"], input[type="password"],
  input[type="number"], input[type="date"], input[type="tel"], input[type="search"] {
    font-size: 16px;
    min-height: 48px;
  }
}

/* Rodapé de tabela (contagem + paginação) */
.db-hist-foot {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 1rem; padding: 0.9rem 1.1rem 0;
}
.db-pagination { display: flex; align-items: center; gap: 0.3rem; list-style: none; margin: 0; padding: 0; }
.db-page-link {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 36px; height: 36px; padding: 0 0.6rem;
  border-radius: var(--db-radius-sm); color: var(--db-text-muted);
  text-decoration: none; font-weight: 500; font-size: 0.9rem; transition: all 0.15s ease;
}
.db-page-link svg { width: 16px; height: 16px; }
.db-page-link:hover { background: rgba(2, 51, 115, 0.06); color: var(--db-primary); }
.db-page-link.is-active { background: var(--db-primary); color: #fff; }
.db-page-link.is-disabled { color: var(--db-text-soft); opacity: 0.5; pointer-events: none; }
.db-page-link.is-dots { pointer-events: none; }

/* Célula/valor monoespaçado em tabela (placa, protocolo, documento): alinha os
   dígitos para conferência coluna a coluna. */
.db-mono { font-family: 'JetBrains Mono', 'Courier New', monospace; letter-spacing: 0.4px; font-size: 0.86rem; }

/* Célula com duas linhas: identificação em cima, complemento embaixo (ex.: nome
   do comprador + documento). Evita uma coluna só para o dado secundário. */
.db-cell-strong { display: block; font-weight: var(--db-fw-semibold); color: var(--db-text); line-height: 1.25; }
.db-cell-sub { display: block; font-size: 0.78rem; color: var(--db-text-muted); line-height: 1.3; }
/* Ações da linha: sempre à direita e sem quebrar entre os botões. */
.db-cell-acoes { white-space: nowrap; }
.db-cell-acoes .db-btn + .db-btn { margin-left: 0.4rem; }

/* Seletor composto de propósito: `.db-info-card__icon` é definido MAIS ABAIXO
   neste arquivo e, com a mesma especificidade, venceria o modificador: os
   ícones sairiam todos azuis. */
.db-info-card__icon.db-info-card__icon--ok   { background: rgba(3, 140, 90, 0.13);  color: #0f7a4f; }
.db-info-card__icon.db-info-card__icon--warn { background: rgba(217, 144, 0, 0.16); color: #946800; }
.db-info-card__icon.db-info-card__icon--err  { background: rgba(220, 53, 69, 0.12); color: #c0303c; }

/* Campo com `text-transform: uppercase` não deve gritar no placeholder: o
   texto de ajuda vira "BUSCAR..." e parece conteúdo digitado. */
.db-filtros .form-control::placeholder { text-transform: none; }

/* ===== Barra de filtros de listagem =====
   Estava só no <style> do histórico de consultas; promovida para o design
   system quando a listagem de comunicações passou a usar o mesmo padrão. */
/* `position: relative; z-index` para o que ABRE de dentro da barra (o painel do
   `.db-combo`, hoje no filtro de tipo do histórico) ficar por cima da tabela
   logo abaixo. O painel já tem `z-index: 40`, e não bastava: a barra tem um
   `transform` computado, e transform cria contexto de empilhamento: o 40 passa
   a valer só DENTRO dela, e o card da tabela, que vem depois no DOM, pinta por
   cima. Foi o que aconteceu: o dropdown abria e ficava atrás da lista, com duas
   linhas de opção aparecendo entre a barra e o cabeçalho da tabela. */
.db-filtros { padding: 1.25rem 1.4rem; margin-bottom: 1.25rem; position: relative; z-index: 2; }
.db-filtros .db-label {
  display: block;
  font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.4px;
  color: var(--db-text-muted); margin-bottom: 0.35rem;
}
.db-filtros .form-control, .db-filtros .form-select { font-size: 0.92rem; }

/* Campo de data com botões embutidos (calendário / limpar) */
.db-date { position: relative; display: flex; align-items: center; }
.db-date .form-control { padding-right: 4.3rem; }
.db-date__btn {
  position: absolute; width: 1.9rem; height: 1.9rem;
  display: inline-flex; align-items: center; justify-content: center;
  border: none; background: transparent; color: var(--db-text-soft);
  cursor: pointer; border-radius: var(--db-radius-xs);
  transition: color 0.2s ease, background 0.2s ease;
}
.db-date__btn:hover { color: var(--db-primary); background: rgba(2, 51, 115, 0.06); }
.db-date__btn svg { width: 16px; height: 16px; }
.db-date__btn--cal { right: 2.15rem; }
.db-date__btn--clear { right: 0.35rem; }

/* Campo de MÊS (par oculto/visível + popover). Espelha `.db-date` de propósito:
   os dois são "campo com botões embutidos que abre um popover", e o que muda é
   só o que o popover mostra. */
.db-month { position: relative; display: flex; align-items: center; }
/* `width` própria, e não `auto`: o campo é readonly e curto ("Setembro 2026"),
   então deixar o navegador arbitrar a largura padrão de um <input> abriria uma
   caixa larga demais no meio de uma faixa de chips. */
.db-month .form-control { width: 11.5rem; min-width: 0; padding-right: 3.6rem;
                          cursor: pointer; background: var(--db-surface); }
.db-month .form-control::placeholder { color: var(--db-text-soft); }
.db-month__lbl { display: inline-flex; align-items: center; gap: 0.25rem; margin: 0;
                 font-size: 0.78rem; font-weight: var(--db-fw-semibold);
                 color: var(--db-text-muted); white-space: nowrap; }
.db-month__lbl svg { width: 13px; height: 13px; }
.db-month__btn {
  position: absolute; width: 1.6rem; height: 1.6rem;
  display: inline-flex; align-items: center; justify-content: center;
  border: none; background: transparent; color: var(--db-text-soft);
  cursor: pointer; border-radius: var(--db-radius-xs);
  transition: color 0.2s ease, background 0.2s ease;
}
.db-month__btn:hover { color: var(--db-primary); background: rgba(2, 51, 115, 0.06); }
.db-month__btn svg { width: 15px; height: 15px; }
.db-month__btn--cal { right: 1.85rem; }
.db-month__btn--clear { right: 0.25rem; }

/* A caixa do seletor de mês é a MESMA do calendário (`.db-datepop`), só mais
   estreita: doze células de três letras não precisam da largura de sete
   colunas de dias. */
.db-monthpop { width: 232px; }
.month-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px; margin: 0.45rem 0 0; }
.month-cell {
  border: 1px solid transparent; border-radius: var(--db-radius-sm);
  padding: 0.5rem 0; cursor: pointer; background: #fff;
  font: inherit; font-size: 0.82rem; font-weight: 500; color: var(--db-text);
  transition: all 0.12s ease;
}
.month-cell:hover { background: rgba(2, 51, 115, 0.08); }
/* `current` = o mês de hoje, `selected` = o mês filtrado. Os dois papéis do
   calendário (`today` e `selected`), com os mesmos sinais: contorno para "onde
   você está", preenchimento para "o que está valendo". */
.month-cell.current { border-color: var(--db-primary); color: var(--db-primary); font-weight: 700; }
.month-cell.selected { background: var(--db-primary); color: #fff; font-weight: 700; border-color: transparent; }
.month-cell.selected:hover { background: var(--db-primary); }

/* ===== Skeleton de tabela dentro de <turbo-frame> =====
   Durante paginação/filtro o Turbo marca o frame com [busy]. O cabeçalho segue
   nítido e só o CORPO vira linhas-fantasma. Genérico por atributo: serve para
   qualquer frame, sem depender do id. */
turbo-frame { display: block; }
.db-skel-body { display: none; }
turbo-frame[busy] tbody:not(.db-skel-body) { display: none; }
turbo-frame[busy] .db-skel-body { display: table-row-group; }
turbo-frame[busy] .db-hist-foot { opacity: 0.45; pointer-events: none; }
.db-skel-body td { vertical-align: middle; }
.db-skel {
  display: inline-block; width: 100%; height: 13px; border-radius: 7px;
  background: linear-gradient(90deg,
    rgba(15,23,42,.06) 25%, rgba(15,23,42,.14) 37%, rgba(15,23,42,.06) 63%);
  background-size: 400% 100%;
  animation: dbSkeleton 1.15s ease-in-out infinite;
}
.db-skel--sm { width: 55%; }
.db-skel--md { width: 82%; }
.db-skel--pill { width: 92px; height: 22px; border-radius: 999px; }
.db-skel--btn { width: 96px; height: 30px; border-radius: 9px; margin-left: auto; }
@keyframes dbSkeleton { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }

/* ===== Date picker (popover ancorado no campo) ===== */
.db-datepop-overlay { position: fixed; inset: 0; z-index: 10000; display: none; background: transparent; }
.db-datepop {
  position: absolute; width: 300px; max-width: calc(100vw - 16px);
  background: var(--db-surface, #fff); border: 1px solid var(--db-border);
  border-radius: var(--db-radius-lg); box-shadow: 0 16px 40px rgba(6, 15, 35, 0.22);
  padding: 0.85rem; animation: dbDatepopIn 0.14s ease;
}
@keyframes dbDatepopIn { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
.db-datepicker__presets { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-bottom: 0.7rem; }
button.db-chip { cursor: pointer; font-family: inherit; padding: 0.3rem 0.62rem; font-size: 0.78rem; transition: border-color .15s ease, color .15s ease, background .15s ease; }
button.db-chip:hover { border-color: var(--db-primary); color: var(--db-primary); background: rgba(2, 51, 115, 0.06); }
.db-datepicker__nav { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.35rem; }
.db-datepicker__month { color: var(--db-primary); font-weight: var(--db-fw-semibold); font-size: 0.92rem; }
.db-datepicker__navbtn {
  width: 30px; height: 30px; display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--db-border); background: #fff; border-radius: var(--db-radius-sm);
  color: var(--db-text-soft); cursor: pointer; transition: border-color .15s ease, color .15s ease;
}
.db-datepicker__navbtn:hover { border-color: var(--db-primary); color: var(--db-primary); }
.db-datepicker__navbtn svg { width: 16px; height: 16px; }
.calendar-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; margin: 0.3rem 0 0; }
.calendar-day-header { text-align: center; font-weight: 600; color: var(--db-text-soft); font-size: 0.66rem; padding: 3px 0; text-transform: uppercase; letter-spacing: 0.03em; }
.calendar-day {
  aspect-ratio: 1; border: 1px solid transparent; border-radius: var(--db-radius-sm);
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  font-weight: 500; font-size: 0.82rem; transition: all 0.12s ease; background: #fff;
  min-height: 32px; color: var(--db-text);
}
.calendar-day:hover { background: rgba(2, 51, 115, 0.08); }
.calendar-day.today { border-color: var(--db-primary); color: var(--db-primary); font-weight: 700; }
.calendar-day.selected { background: var(--db-primary); color: #fff; font-weight: 700; border-color: transparent; }
.calendar-day.selected:hover { background: var(--db-primary); }
.calendar-day.other-month { color: var(--db-text-soft); opacity: 0.5; }
@media (max-width: 575px) { .db-hist-foot { justify-content: center; } }

/* Cabeçalho do card de dados */
.db-card-head {
  display: flex; align-items: center; gap: 0.9rem;
  margin: 0 0 1.15rem; padding-bottom: 0.9rem;
  border-bottom: 1px solid var(--db-border);
}
.db-card-head__icon {
  display: flex; align-items: center; justify-content: center;
  width: 46px; height: 46px; flex-shrink: 0; border-radius: 13px;
  background: linear-gradient(135deg, var(--db-primary), var(--db-accent));
  color: #fff; box-shadow: 0 6px 16px color-mix(in srgb, var(--db-primary) 28%, transparent);
}
.db-card-head__icon svg { width: 24px; height: 24px; }
.db-card-head__title { margin: 0; font-size: 1.15rem; font-weight: var(--db-fw-semibold); color: var(--db-primary); line-height: 1.2; }
.db-card-head__sub { margin: 0.1rem 0 0; font-size: 0.82rem; color: var(--db-text-muted); }

/* Variações por tipo de evento. Moraram no <style> de resultado_cnh.html e de
   resultado_siscsv.html, duas cópias com o âmbar em tons diferentes, e por isso
   `--danger` no leilão e `--warning` na comunicação de venda não pintavam nada:
   as duas telas escreviam a classe e não carregavam o CSS de nenhuma das duas.
   Cabeçalho de card é do design system, e alerta que sai em navy é pior que
   alerta nenhum, porque nada na tela diz que aquele card é o grave. */
.db-card-head--danger .db-card-head__icon {
  background: linear-gradient(135deg, #c0303c, #e06a72);
  box-shadow: 0 6px 16px rgba(192, 48, 60, 0.28);
}
.db-card-head--danger .db-card-head__title { color: #b02a37; }
.db-card-head--success .db-card-head__icon {
  background: linear-gradient(135deg, #0f7a4f, #2fae7a);
  box-shadow: 0 6px 16px rgba(15, 122, 79, 0.28);
}
.db-card-head--success .db-card-head__title { color: #0f7a4f; }
.db-card-head--warning .db-card-head__icon {
  background: linear-gradient(135deg, #b57d00, #e0a53a);
  box-shadow: 0 6px 16px rgba(181, 125, 0, 0.28);
}
.db-card-head--warning .db-card-head__title { color: #946800; }

/* Cabeçalho separativo de seção.
   `margin-bottom` = distância PADRÃO do título aos campos (0.9rem). É a mesma
   distância que a descrição usa abaixo (ver regra seguinte), para que os campos
   comecem SEMPRE no mesmo ponto, com ou sem descrição. Gaps diferentes entre
   seções com e sem descrição faziam o ritmo parecer bagunçado. */
.db-section-head { display: flex; align-items: center; gap: 0.6rem; margin: 1.6rem 0 0.9rem; }
.db-section-head:first-of-type { margin-top: 0.5rem; }
.db-section-head__icon {
  display: flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; flex-shrink: 0; border-radius: 9px;
  background: color-mix(in srgb, var(--db-primary) 10%, #fff); color: var(--db-primary);
}
.db-section-head__icon svg { width: 17px; height: 17px; }
.db-section-head__text { font-size: 0.95rem; font-weight: var(--db-fw-semibold); color: var(--db-primary); white-space: nowrap; }
/* Descrição ENCAIXADA na própria linha do divisor, entre o título e a linha em
   degradê, em vez de flutuar como um parágrafo solto abaixo. O `min-width:0` +
   truncamento garante que ela nunca empurre a linha para fora; textos curtos
   (que é a regra) cabem inteiros. */
.db-section-head__note {
  font-size: 0.8rem; color: var(--db-text-soft); font-weight: var(--db-fw-regular);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  flex: 0 1 auto; min-width: 0;
}
.db-section-head__note::before { content: '·'; margin-right: 0.5rem; color: var(--db-border); }
.db-section-head::after { content: ''; flex: 1 1 auto; height: 1px; min-width: 1.2rem; background: linear-gradient(90deg, var(--db-border), transparent); }
/* Em telas estreitas o divisor quebra: a descrição desce para a 2ª linha (sem a
   linha em degradê), tesa ao título, em vez de truncar e perder informação. */
@media (max-width: 575px) {
  .db-section-head { flex-wrap: wrap; }
  .db-section-head::after { display: none; }
  .db-section-head__note { flex-basis: 100%; white-space: normal; margin-top: 0.15rem; }
  .db-section-head__note::before { display: none; }
}
.db-section-head--danger  .db-section-head__icon { background: color-mix(in srgb, #dc3545 12%, #fff); color: #c0303c; }
.db-section-head--danger  .db-section-head__text { color: #b02a37; }
.db-section-head--success .db-section-head__icon { background: color-mix(in srgb, #038C5A 12%, #fff); color: #0f7a4f; }
.db-section-head--success .db-section-head__text { color: #0f7a4f; }

/* Grade de cards de dados: colunas largas para o texto quebrar pouco. */
/* `align-items: stretch` (padrão do grid), NÃO `start`: com `start` cada card
   fica com a altura do próprio conteúdo, então bastava UM valor quebrar em duas
   linhas ("26 - DETRAN - SAO PAULO", "NOME DA MÃE", um número de documento
   comprido) para a fileira inteira ficar desalinhada, com caixas de alturas
   diferentes lado a lado. Esticando, a linha toda acompanha o card mais alto e
   o bloco volta a ler como grade. Aparece mais no PDF (colunas de ~230px, onde
   o texto quebra com mais frequência) mas o defeito é o mesmo na tela. */
.db-info-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 0.75rem; align-items: stretch; }

/* Cartões de contagem no topo de uma listagem: mais estreitos que a grade de
   dados padrão, porque o valor é um número curto.

   ⚠️ Este modificador mora AQUI, logo depois da base, e não lá em cima junto
   dos tons de ícone: os dois seletores têm a mesma especificidade, então quem
   vem depois vence. Declarado antes, ele não pintava nada, e toda tela que o
   pedia continuava com a grade de dados.

   `auto-fit`, e não o `auto-fill` da base, porque é o que faz diferença quando
   os cartões não fecham a fileira: o `auto-fill` mantém a trilha vazia aberta e
   a fileira para no meio do caminho, desalinhada dos cards de cima; o
   `auto-fit` recolhe a sobra e os cartões esticam até a borda. */
.db-info-grid--resumo { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }

.db-info-card {
  display: flex; align-items: center; gap: 0.85rem; padding: 0.85rem 1rem;
  border: 1px solid var(--db-border); border-radius: var(--db-radius-sm);
  background: var(--db-surface); transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
/* Ocupa a linha inteira da grade: para valores longos que não cabem numa coluna
   (nome completo, endereço) sem virar bloco `.db-longs` separado. */
.db-info-card--wide { grid-column: 1 / -1; }
.db-info-card:hover {
  border-color: color-mix(in srgb, var(--db-accent) 45%, var(--db-border));
  box-shadow: 0 4px 14px rgba(28, 42, 63, 0.06);
}
.db-info-card__icon {
  display: flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; flex-shrink: 0; border-radius: 11px;
  background: color-mix(in srgb, var(--db-accent) 11%, #fff); color: var(--db-accent);
}
.db-info-card__icon svg { width: 20px; height: 20px; }
.db-info-card__body { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
/* Rótulo do dado. Era `--db-text-soft` (#8595aa): ~3:1 sobre o branco, abaixo do
   mínimo de 4.5:1 do WCAG para texto pequeno. Em 0.7rem o rótulo sumia ao lado
   do valor. `--db-text-muted` (#5b6b82) dá ~5.6:1 e ainda fica claramente
   subordinado ao valor, que é escuro e semibold. */
.db-info-card__label { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--db-text-muted); font-weight: var(--db-fw-semibold); }
.db-info-card__value { font-size: 0.98rem; font-weight: var(--db-fw-semibold); color: var(--db-text); line-height: 1.3; word-break: break-word; }
.db-info-card--mono .db-info-card__value { font-family: 'JetBrains Mono', 'Courier New', monospace; letter-spacing: 0.5px; font-size: 0.92rem; }

/* Campos longos (endereço, observações, modalidade) em bloco separado,
   abaixo da grade de campos curtos, para não bagunçar o alinhamento. */
.db-longs {
  display: flex; flex-wrap: wrap; gap: 0.75rem;
  margin-top: 1rem; padding-top: 1.1rem;
  border-top: 1px dashed var(--db-border);
}
.db-longs .db-info-card { flex: 1 1 340px; max-width: 720px; align-items: flex-start; }
.db-longs .db-info-card__icon { margin-top: 1px; }

/* Campo em destaque que ocupa 2 colunas da grade (ex.: o status mais relevante). */
.db-info-card--span2 { grid-column: span 2; }
@media (max-width: 575px) { .db-info-card--span2 { grid-column: auto; } }

/* Veredito no topo do resultado (banner .db-alert): separa do card de detalhes. */
.db-veredito { margin-bottom: 1rem; }

/* Linha do tempo de proprietários (histórico nacional / proprietários):
   trilho vertical com marcadores numerados, do mais antigo ao mais recente. */
.db-timeline { position: relative; display: flex; flex-direction: column; gap: 0.7rem; }
/* trilho: linha contínua ligando os marcadores (do 1º ao último) */
.db-timeline::before {
  content: ""; position: absolute; left: 1rem; top: 1.1rem; bottom: 1.1rem;
  width: 2px; transform: translateX(-1px); background: var(--db-border);
}
.db-tl-item { position: relative; display: flex; align-items: flex-start; gap: 0.9rem; }
.db-tl-dot {
  position: relative; z-index: 1; flex: none;
  width: 2rem; height: 2rem; border-radius: 999px;
  display: grid; place-items: center;
  background: var(--db-primary); color: #fff;
  font-weight: var(--db-fw-semibold); font-size: 0.8rem;
  box-shadow: 0 0 0 4px var(--db-surface); /* “fura” o trilho ao redor do marcador */
}
/* o registro mais recente ganha destaque em ciano */
.db-tl-item--atual .db-tl-dot { background: var(--db-accent); }

.db-owner {
  flex: 1; min-width: 0; padding: 0.8rem 1rem;
  border: 1px solid var(--db-border); border-radius: var(--db-radius-sm);
  background: var(--db-surface);
}
.db-owner--atual { border-color: var(--db-accent); background: var(--db-cyan-50, #f0f9ff); }
.db-owner--sem { background: var(--db-surface-2); }             /* registro sem proprietário nomeado */
.db-owner--sem .db-owner__name { color: var(--db-text-muted); font-weight: var(--db-fw-medium); }
.db-owner__top { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.db-owner__name { font-weight: var(--db-fw-semibold); color: var(--db-text); word-break: break-word; }
.db-owner__tag {
  font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.04em;
  font-weight: var(--db-fw-semibold); padding: 0.1rem 0.45rem; border-radius: 999px;
  background: var(--db-surface-2); color: var(--db-text-soft); white-space: nowrap;
}
.db-owner__tag--atual { background: var(--db-accent); color: #fff; }
.db-owner__meta {
  display: flex; flex-wrap: wrap; gap: 0.2rem 0.9rem;
  margin-top: 0.3rem; font-size: 0.85rem; color: var(--db-text-muted);
}
.db-owner__meta span { display: inline-flex; align-items: center; gap: 0.3rem; }
.db-owner__meta i { width: 14px; height: 14px; }

/* Pílula compacta (categoria/etiqueta), reutilizável no design system. */
.db-pill {
  display: inline-block; padding: 0.2rem 0.6rem; border-radius: var(--db-radius-pill);
  font-size: 0.72rem; font-weight: var(--db-fw-semibold);
  background: var(--db-surface-2); color: var(--db-text-muted);
}
.db-pill--danger  { background: #fdf0f1; color: #a12b33; }
.db-pill--warning { background: rgba(217, 144, 0, 0.16); color: #946800; }
.db-pill--success { background: #eef8f1; color: #256b3b; }

/* Ocorrências (sinistro/salvados): cards sóbrios com marcador numerado e um
   traço de alerta à esquerda; a natureza vem inteira (não fragmentada). */
.db-occ-list { display: flex; flex-direction: column; gap: 0.6rem; }
.db-occ {
  display: flex; gap: 0.85rem; align-items: flex-start;
  padding: 0.85rem 1rem; border: 1px solid var(--db-border);
  border-left: 3px solid #d9534f; border-radius: var(--db-radius-sm);
  background: var(--db-surface);
}
.db-occ__num {
  flex: none; width: 1.6rem; height: 1.6rem; border-radius: 999px;
  display: grid; place-items: center; margin-top: 1px;
  background: #fdeaec; color: #b02a37;
  font-weight: var(--db-fw-semibold); font-size: 0.8rem;
}
.db-occ__body { flex: 1; min-width: 0; }
.db-occ__title { font-weight: var(--db-fw-semibold); color: var(--db-text); word-break: break-word; line-height: 1.4; }
.db-occ__obs { margin-top: 0.35rem; color: var(--db-text-muted); font-size: 0.86rem; word-break: break-word; }
.db-occ__obs-label {
  font-weight: var(--db-fw-semibold); color: var(--db-text-soft);
  text-transform: uppercase; font-size: 0.68rem; letter-spacing: 0.03em; margin-right: 0.4rem;
}

/* Restrições do BIN (alertas empilhados): respiro entre um e outro. */
.db-restr + .db-restr { margin-top: 0.5rem; }

/* Placa realista (Mercosul / antiga), telas de resultado veicular.
   A Mercosul usa a FE-Schrift (ver @font-face no topo).

   ⚠️ TODA medida daqui é múltipla de `--pu` ("plate unit"), e não px cru.
   A placa é um desenho de proporção fixa: largura, altura, altura da tarja
   azul, tamanho da bandeira e corpo do número são um conjunto só. Encolher a
   largura sozinha não a reduz: esmaga o desenho.

   Antes eram 380px rígidos (`max-width: 100%` não segurava nada, porque o
   `.plate-wrapper` à volta também tem 380px de conteúdo). O `.db-result-head`
   tem `overflow: hidden`, então o excesso não transbordava: era CORTADO em
   silêncio. Num aparelho de 320px a placa começava 30px fora da tela, comendo
   o primeiro caractere, e placa é o dado que identifica o resultado inteiro.

   `--pu` é fluido e vale 1px enquanto couber: `min()` trava no tamanho de
   projeto e só encolhe quando o espaço aperta. Os 78px descontados são a
   margem lateral da página (0.9rem × 2) mais o padding do cartão (1.5rem × 2)
   no celular. No desktop e no PDF (que renderiza a 794px) a conta dá mais que
   1px, o `min()` trava em 1px e nada muda. */
.plate-wrapper {
  --pu: min(1px, (100vw - 78px) / 380);
  display: flex; justify-content: center;
}
.mercosul-plate-bg {
  width: calc(380 * var(--pu)); height: calc(126 * var(--pu));
  background-color: #fff;
  border: calc(2 * var(--pu)) solid #343a40;
  border-radius: calc(9 * var(--pu));
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.2); overflow: hidden;
  display: flex; flex-direction: column;
}
.plate-header-mercosul {
  background-color: #0033A0; color: #fff;
  display: flex; justify-content: space-between; align-items: center;
  padding: calc(4 * var(--pu)) calc(12 * var(--pu));
  height: calc(32 * var(--pu));
}
.mercosul-symbol { display: flex; align-items: center; gap: calc(5 * var(--pu)); font-size: calc(11 * var(--pu)); font-weight: bold; }
/* O <svg> traz width/height como ATRIBUTO (22×16); sem estas duas linhas ele
   ignora a escala e cresce dentro da tarja encolhida. */
.mercosul-symbol svg { width: calc(22 * var(--pu)); height: calc(16 * var(--pu)); flex-shrink: 0; }
.country-name-plate { font-size: calc(16 * var(--pu)); font-weight: bold; letter-spacing: calc(2 * var(--pu)); margin-right: calc(34 * var(--pu)); }
.brasil-flag-plate { width: calc(30 * var(--pu)); height: calc(20 * var(--pu)); background-color: #009c3b; position: relative; flex-shrink: 0; }
.flag-yellow { position: absolute; top: calc(2.5 * var(--pu)); left: calc(2.5 * var(--pu)); width: calc(25 * var(--pu)); height: calc(15 * var(--pu)); background: #ffdf00; clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%); }
.flag-blue { position: absolute; top: calc(6.5 * var(--pu)); left: calc(11 * var(--pu)); width: calc(8 * var(--pu)); height: calc(8 * var(--pu)); background: #0033a0; border-radius: 50%; }
.plate-body-mercosul { flex-grow: 1; display: flex; justify-content: center; align-items: center; }
.plate-number-main { font-family: 'FE-Schrift', 'Arial Narrow', sans-serif; font-weight: 400; font-size: calc(52 * var(--pu)); color: #000; letter-spacing: calc(4 * var(--pu)); text-transform: uppercase; }

/* Identificação em destaque */
.db-info-grid--id { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.db-info-grid--id .db-info-card {
  padding: 1.1rem 1.2rem;
  border-color: color-mix(in srgb, var(--db-accent) 35%, var(--db-border));
  background: color-mix(in srgb, var(--db-accent) 5%, #fff);
}
.db-info-grid--id .db-info-card__icon { width: 48px; height: 48px; border-radius: 13px; background: var(--db-accent); color: #fff; }
.db-info-grid--id .db-info-card__icon svg { width: 24px; height: 24px; }
.db-info-grid--id .db-info-card__value { font-size: 1.15rem; }
.db-info-grid--id .db-info-card--mono .db-info-card__value { font-size: 1.1rem; letter-spacing: 1px; }

/* Evento (sub-card com cabeçalho colorido por tipo) */
.db-event { border: 1px solid var(--db-border); border-radius: var(--db-radius); overflow: hidden; margin-bottom: 0.9rem; }
.db-event:last-child { margin-bottom: 0; }
.db-event__head {
  display: flex; align-items: center; gap: 0.6rem; padding: 0.8rem 1.1rem;
  background: var(--db-surface-2); border-bottom: 1px solid var(--db-border);
  font-weight: var(--db-fw-semibold); color: var(--db-primary); font-size: 0.92rem;
}
.db-event__head svg { width: 17px; height: 17px; color: var(--db-accent); }
.db-event__body { padding: 1rem 1.1rem; }
.db-event--danger  .db-event__head { background: color-mix(in srgb, #dc3545 10%, #fff); color: #b02a37; border-bottom-color: color-mix(in srgb, #dc3545 22%, var(--db-border)); }
.db-event--danger  .db-event__head svg { color: #c0303c; }
.db-event--success .db-event__head { background: color-mix(in srgb, #038C5A 10%, #fff); color: #0f7a4f; border-bottom-color: color-mix(in srgb, #038C5A 22%, var(--db-border)); }
.db-event--success .db-event__head svg { color: #0f7a4f; }
.db-event--warning .db-event__head { background: color-mix(in srgb, #d99000 13%, #fff); color: #946800; border-bottom-color: color-mix(in srgb, #d99000 24%, var(--db-border)); }
.db-event--warning .db-event__head svg { color: #b57d00; }

/* Alerta destacado (prazos/penalidades) */
.db-alert {
  display: flex; align-items: center; gap: 0.9rem;
  padding: 0.9rem 1.1rem; margin-top: 0.9rem;
  border-radius: var(--db-radius-sm); border: 1px solid;
}
.db-alert__icon { flex-shrink: 0; display: flex; }
.db-alert__icon svg { width: 26px; height: 26px; }
.db-alert__title { font-weight: var(--db-fw-semibold); font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.02em; }
.db-alert__text { font-size: 0.85rem; opacity: 0.92; }
.db-alert--danger  { background: #fdf0f1; border-color: #f5c2c7; color: #842029; }
.db-alert--warning { background: #fdf8ec; border-color: #f5e2b8; color: #8a6d3b; }
.db-alert--success { background: #eef8f1; border-color: #c3e6cb; color: #155724; }
/* Slot de conteúdo (cresce e empurra a ação p/ a direita) + slot de ação (CTA). */
.db-alert__body { flex: 1 1 auto; min-width: 0; }
.db-alert__body > * { margin: 0; }
.db-alert__body > * + * { margin-top: 0.15rem; }
.db-alert__text strong { font-weight: var(--db-fw-bold); }
.db-alert__action { flex-shrink: 0; display: flex; align-items: center; gap: 0.4rem; }
/* Faixa de acento à esquerda (dá mais peso ao alerta) */
.db-alert--accent { border-left-width: 4px; }
/* Alerta usado como FAIXA entre blocos da página (não dentro de um card):
   respira dos dois lados e ganha um pouco mais de corpo. Estava duplicado no
   <style> de resultado_leilao e resultado_siscsv; aqui vale para todas as telas. */
.db-alert--banner { margin: 0 0 1.1rem; padding: 1.1rem 1.3rem; }
.db-alert--banner .db-alert__icon svg { width: 30px; height: 30px; }
.db-alert--banner .db-alert__title { font-size: 1rem; }
/* Botão dentro do alerta: herda a cor do alerta, fundo sólido discreto */
.db-alert__action .db-btn svg { width: 15px; height: 15px; }
@media (max-width: 575px) {
  .db-alert { flex-wrap: wrap; }
  .db-alert__action { width: 100%; }
  .db-alert__action .db-btn { flex: 1 1 auto; justify-content: center; }
}

@media (max-width: 767px) {
  .db-result-head { flex-direction: column; text-align: center; padding: 1.5rem; }
  .db-result-head__info { width: 100%; }
  /* Escopado ao hero: `.db-result-meta` também é usada DENTRO do `.db-welcome`
     do coletor (os chips de custo e saldo). Solta, esta regra centralizava
     aqueles chips num cabeçalho que continua alinhado à esquerda: texto num
     alinhamento, chips noutro, no mesmo cartão. */
  .db-result-head .db-result-tags,
  .db-result-head .db-result-meta { justify-content: center; }
  .db-result-head__stripes { display: none; }

  /* O aside se dimensiona pelo CONTEÚDO, então o `max-width: 100%` do
     `.db-idcard` media 100% de 370px, ou seja, não limitava nada. Com o
     `zoom: 0.9` do hero o cartão ficava travado em 333px em qualquer aparelho,
     e o `overflow: hidden` do hero cortava o resto: a 320px ele começava 6px
     FORA da tela. Mesma família de defeito da placa, e a CNH é uma tela em que
     o cartão É o resultado.
     Aqui não precisa da unidade fluida da placa: os internos já são flex, com
     `min-width: 0` e reticências no título. Basta deixar o cartão preencher e
     encolher o que é fixo em px: a foto e os dois tamanhos grandes. */
  .db-result-head__aside { width: 100%; min-width: 0; }
  .db-result-head__aside .db-idcard { width: 100%; zoom: 1; }
  .db-idcard__body { gap: 0.85rem; padding: 0.95rem 1rem; }
  .db-idcard__photo { width: 54px; height: 68px; }
  .db-idcard__photo svg { width: 30px; height: 30px; }
  /* O CPF precisa caber em UMA linha. Sem o `nowrap` ele quebrava no hífen
     ("655.537.646-" / "53"), e documento partido ao meio lê como dois números.
     O `clamp` é calibrado para o pior caso (320px de tela, 14 caracteres): o
     mínimo tem que ser pequeno o bastante para não voltar a quebrar ali. */
  .db-idcard__value { font-size: clamp(0.82rem, 4.2vw, 1.6rem); white-space: nowrap; }
  .db-idcard__sub { font-size: clamp(0.9rem, 3.6vw, 1.05rem); }
}
@media (max-width: 575px) {
  .db-info-grid, .db-info-grid--id { grid-template-columns: 1fr; }
  .db-result-actions .db-btn { flex: 1 1 100%; }
}

/* ------------------------------------------------------------------ *
 * MODAL (diálogo central reutilizável)
 * ------------------------------------------------------------------ */
.db-modal {
  position: fixed; inset: 0; z-index: 11080;
  display: none; align-items: center; justify-content: center;
  padding: 1.5rem;
}
.db-modal.is-open { display: flex; }
.db-modal__backdrop { position: absolute; inset: 0; background: rgba(6, 15, 35, 0.55); backdrop-filter: blur(4px); }
.db-modal__box {
  position: relative; z-index: 1; width: 100%; max-width: 480px;
  background: var(--db-surface); border-radius: var(--db-radius-lg);
  box-shadow: 0 30px 60px rgba(6, 15, 35, 0.35);
  overflow: hidden; animation: db-rise 0.25s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.db-modal__head {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: 0.9rem 1.1rem;
  background: linear-gradient(120deg, #013178 0%, #0095D9 125%);
}
.db-modal__title { display: flex; align-items: center; gap: 0.6rem; margin: 0; font-size: 1.05rem; font-weight: var(--db-fw-semibold); color: #fff; }
/* chip do ícone no cabeçalho */
.db-modal__ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; flex-shrink: 0; border-radius: 10px;
  background: rgba(255, 255, 255, 0.16);
}
.db-modal__ico svg { width: 19px; height: 19px; color: #fff; }
.db-modal__title > svg { width: 20px; height: 20px; color: #fff; }
.db-modal__close {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; flex-shrink: 0; border: 0; border-radius: 50%;
  background: rgba(255, 255, 255, 0.12); color: rgba(255, 255, 255, 0.85); cursor: pointer; transition: background 0.15s ease, color 0.15s ease;
}
.db-modal__close:hover { background: #dc3545; color: #fff; }
.db-modal__close svg { width: 18px; height: 18px; }
.db-modal__body { padding: 1.5rem 1.3rem; text-align: center; }
.db-modal__body > p { color: var(--db-text-muted); margin: 0 0 1rem; }
.db-modal__preview { display: flex; justify-content: center; margin: 0.4rem 0 1rem; }
.db-modal__hint { font-size: 0.82rem; color: var(--db-text-soft); margin: 0.6rem 0 0; }
.db-modal__foot { display: flex; gap: 0.7rem; padding: 1rem 1.3rem 1.3rem; }
.db-modal__foot .db-btn { flex: 1; justify-content: center; }

/* Aplica o visual do db-modal ao .modal-content de um modal Bootstrap */
.db-dialog.modal-content {
  border: 0; border-radius: var(--db-radius-lg); overflow: hidden;
  background: var(--db-surface);
  box-shadow: 0 30px 60px rgba(6, 15, 35, 0.35);
}
.db-dialog .db-modal__body { text-align: left; padding: 1.4rem 1.3rem 0.4rem; }

/* ------------------------------------------------------------------ *
 * MODAL: variante FORMULÁRIO (pede dados, não confirma uma ação)
 * O corpo do modal é centralizado por padrão (pensado para diálogos de
 * confirmação, onde o texto é curto). Com campos, isso desalinha rótulo,
 * input e dica; aqui o corpo volta a ser um formulário normal.
 * ------------------------------------------------------------------ */
.db-modal--form .db-modal__body { text-align: left; }
.db-modal--form .db-modal__body > p { margin: 0 0 1.2rem; font-size: 0.9rem; line-height: 1.5; }
.db-modal--form .db-field { margin-bottom: 1.05rem; }
.db-modal--form .db-field:last-child { margin-bottom: 0; }
.db-modal--form .db-label { display: block; font-size: 0.88rem; margin-bottom: 0.35rem; }
.db-modal--form .form-control { width: 100%; }
/* dois campos curtos lado a lado a partir de telas médias */
.db-modal--form .db-modal__campos { display: grid; gap: 0 0.85rem; }
@media (min-width: 480px) {
  .db-modal--form .db-modal__campos--2 { grid-template-columns: 1fr 1fr; }
}

/* Rodapé de AÇÕES assimétrico: o padrão do modal dá `flex:1` a todo botão, o que
   deixa a ação destrutiva do mesmo tamanho da principal e, com rótulo longo,
   as duas quebram em duas linhas. Aqui a principal domina e a destrutiva encolhe
   para o seu conteúdo; nenhuma quebra. Em tela estreita, empilha (principal em
   cima) em vez de espremer. */
.db-modal__foot--acoes .db-btn { white-space: nowrap; }
.db-modal__foot--acoes .db-btn--danger-soft,
.db-modal__foot--acoes .db-btn--neutral {
  flex: 0 1 auto;
  font-size: 0.86rem;
  padding-left: 0.95rem;
  padding-right: 0.95rem;
}
.db-modal__foot--acoes .db-btn:not(.db-btn--danger-soft):not(.db-btn--neutral) { flex: 1 1 auto; }
@media (max-width: 430px) {
  .db-modal__foot--acoes { flex-direction: column-reverse; }
  .db-modal__foot--acoes .db-btn { width: 100%; flex: 0 0 auto; }
}

/* Identificação do que o modal está tratando: serviço + valor consultado */
.db-modal__alvos { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-bottom: 0.9rem; }
.db-modal__alvos .db-modal__alvo { margin-bottom: 0; }

/* placa/valor a que o modal se refere: âncora visual do topo do corpo */
.db-modal__alvo {
  display: inline-flex; align-items: center; gap: 0.4rem;
  margin-bottom: 0.9rem; padding: 0.3rem 0.7rem;
  border-radius: var(--db-radius-pill);
  background: color-mix(in srgb, var(--db-primary) 8%, #fff);
  border: 1px solid color-mix(in srgb, var(--db-primary) 16%, #fff);
  color: var(--db-primary);
  font-weight: var(--db-fw-semibold); font-size: 0.85rem; letter-spacing: 0.4px;
}
.db-modal__alvo svg { width: 15px; height: 15px; }
.db-modal__alvo:empty { display: none; }

/* O SERVIÇO é o que o cliente pediu, então vem em destaque; a placa fica secundária.
   Depois da regra base de propósito: mesma especificidade, então quem vem por
   último vence. */
.db-modal__alvo--servico {
  background: var(--db-primary);
  border-color: var(--db-primary);
  color: #fff;
}
.db-modal__alvo--servico svg { color: #fff; }

/* erro de validação do formulário do modal */
.db-modal__erro {
  display: flex; align-items: flex-start; gap: 0.45rem;
  margin: 1rem 0 0; font-size: 0.85rem; color: var(--db-danger);
}
.db-modal__erro svg { width: 16px; height: 16px; flex-shrink: 0; margin-top: 1px; }

/* ------------------------------------------------------------------ *
 * MODAL: variante ALERTA (conferência de dados)
 * Mesma identidade (cabeçalho navy + faixas da bandeira) com um toque de
 * atenção: badge âmbar pulsante, aviso destacado e checklist do que revisar.
 * ------------------------------------------------------------------ */
.db-modal--alerta .db-modal__box { max-width: 512px; }

/* cabeçalho claro: badge + (título · subtítulo) + fechar; um leve calor no topo */
.db-modal--alerta .db-modal__head {
  display: flex; align-items: center; justify-content: flex-start; gap: 0.85rem;
  padding: 1.15rem 1.25rem;
  background: linear-gradient(180deg, #FFFCF6 0%, var(--db-surface) 100%);
  border-bottom: 1px solid var(--db-border);
}
.db-modal__headtext { flex: 1; min-width: 0; }
.db-modal--alerta .db-modal__title {
  margin: 0; color: var(--db-primary); font-size: 1.1rem; letter-spacing: -0.2px;
}
.db-modal__subtitle {
  margin: 2px 0 0; font-size: 0.82rem;
  font-weight: var(--db-fw-regular); color: var(--db-text-soft);
}
.db-modal--alerta .db-modal__close {
  flex-shrink: 0; background: var(--db-surface-2); color: var(--db-text-soft);
}
.db-modal--alerta .db-modal__close:hover { background: var(--db-danger); color: #fff; }

/* badge de alerta: âmbar com halo pulsante suave, o "toque de alerta" */
.db-modal__ico--alerta {
  width: 42px; height: 42px; border-radius: 13px; flex-shrink: 0;
  background: linear-gradient(140deg, #FFCE63 0%, #F5A310 52%, #E4820A 100%);
  box-shadow: 0 8px 18px rgba(224, 124, 5, 0.30), inset 0 1px 0 rgba(255, 255, 255, 0.4);
  animation: db-alerta-pulse 2.4s ease-in-out infinite;
}
.db-modal__ico--alerta svg { width: 22px; height: 22px; color: #3a2400; }
@keyframes db-alerta-pulse {
  0%, 100% { box-shadow: 0 8px 18px rgba(224,124,5,0.30), 0 0 0 0 rgba(245,163,16,0.42), inset 0 1px 0 rgba(255,255,255,0.4); }
  50%      { box-shadow: 0 8px 18px rgba(224,124,5,0.30), 0 0 0 8px rgba(245,163,16,0), inset 0 1px 0 rgba(255,255,255,0.4); }
}

/* corpo */
.db-modal--alerta .db-modal__body { text-align: left; padding: 1.35rem 1.35rem 0.6rem; }
.db-modal__lead { color: var(--db-text-muted); margin: 0; font-size: 0.935rem; line-height: 1.6; }
.db-modal__lead strong { color: var(--db-primary); font-weight: var(--db-fw-semibold); }

/* nota de responsabilidade, discreta */
.db-modal__aviso {
  display: flex; align-items: flex-start; gap: 0.6rem;
  margin: 1.1rem 0 1.2rem; padding: 0.75rem 0.9rem;
  background: #FEF9EF; border: 1px solid #F3E4C0;
  border-radius: var(--db-radius); color: #85611A;
  font-size: 0.845rem; line-height: 1.5;
}
.db-modal__aviso svg { width: 17px; height: 17px; flex-shrink: 0; color: #E4820A; margin-top: 2px; }

/* checklist do que revisar: um card único, com divisórias e ícones circulares */
.db-checklist {
  list-style: none; margin: 0; padding: 0; overflow: hidden;
  border: 1px solid var(--db-border); border-radius: var(--db-radius);
  background: var(--db-surface);
}
.db-checklist li { display: flex; align-items: center; gap: 0.85rem; padding: 0.8rem 1rem; }
.db-checklist li + li { border-top: 1px solid var(--db-border); }
.db-checklist__ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; flex-shrink: 0; border-radius: 50%;
  background: color-mix(in srgb, var(--db-accent) 12%, #fff);
  color: var(--db-primary);
}
.db-checklist__ico svg { width: 17px; height: 17px; }
.db-checklist__txt { display: flex; flex-direction: column; gap: 1px; min-width: 0; line-height: 1.3; }
.db-checklist__txt strong { color: var(--db-primary); font-weight: var(--db-fw-semibold); font-size: 0.9rem; }
.db-checklist__txt small { color: var(--db-text-soft); font-size: 0.8rem; }

@media (prefers-reduced-motion: reduce) {
  .db-modal__ico--alerta { animation: none; }
}

/* ------------------------------------------------------------------ *
 * MODAL: variante OUTCOME (desfecho: sucesso / erro / aviso / info)
 * Para eventos que exigem reconhecimento (pagamento aprovado/recusado,
 * venda comunicada, saldo insuficiente). Layout centralizado com o CHIP
 * de ícone do sistema (quadrado-arredondado) tingido pelo tom, título,
 * destaque do dado que importa e ações. Disparado via DBOutcome.show().
 * ------------------------------------------------------------------ */
.db-modal--outcome .db-modal__box { max-width: 440px; }
/* aura do tom no topo do card, profundidade sutil */
.db-modal--outcome .db-modal__box::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 170px; pointer-events: none;
  background: radial-gradient(125% 100% at 50% -22%, color-mix(in srgb, var(--tone) 16%, transparent) 0%, transparent 66%);
}
.db-modal--outcome .db-modal__close {
  position: absolute; top: 0.8rem; right: 0.8rem; z-index: 2;
  background: var(--db-surface-2); color: var(--db-text-soft);
}
.db-modal--outcome .db-modal__close:hover { background: var(--db-danger); color: #fff; }

.db-outcome { position: relative; z-index: 1; padding: 2.2rem 1.7rem 0.4rem; text-align: center; }
.db-outcome__badge {
  position: relative; width: 76px; height: 76px; border-radius: 22px; margin: 0 auto 1.2rem;
  display: flex; align-items: center; justify-content: center; color: #fff;
  background: linear-gradient(145deg, var(--tone2) 0%, var(--tone) 100%);
  box-shadow:
    0 14px 28px color-mix(in srgb, var(--tone) 40%, transparent),
    0 0 0 7px color-mix(in srgb, var(--tone) 9%, transparent),
    0 0 0 15px color-mix(in srgb, var(--tone) 5%, transparent),
    inset 0 2px 3px rgba(255, 255, 255, 0.45),
    inset 0 -8px 15px rgba(0, 0, 0, 0.10);
}
.db-outcome__badge svg { width: 34px; height: 34px; position: relative; z-index: 1; filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.18)); }
.db-outcome__badge::after { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; }
.db-outcome__title { font-size: 1.3rem; font-weight: var(--db-fw-bold); letter-spacing: -0.35px; color: var(--db-primary); margin: 0 0 0.35rem; text-wrap: balance; }
.db-outcome__msg { color: var(--db-text-muted); font-size: 0.93rem; line-height: 1.55; margin: 0 auto; max-width: 36ch; }
.db-outcome__destaque {
  margin: 1.35rem 0 0.2rem; padding: 1rem; border-radius: var(--db-radius);
  background: color-mix(in srgb, var(--tone) 5%, var(--db-surface-2));
  border: 1px solid color-mix(in srgb, var(--tone) 15%, var(--db-border));
}
.db-outcome__valor { font-size: 1.65rem; font-weight: var(--db-fw-bold); letter-spacing: -0.4px; line-height: 1.1; color: var(--tone); font-variant-numeric: tabular-nums; }
.db-outcome__valor--mono { font-family: ui-monospace, "SFMono-Regular", Consolas, monospace; font-size: 1.2rem; letter-spacing: 0.5px; color: var(--db-primary); }
.db-outcome__sub { font-size: 0.82rem; color: var(--db-text-soft); margin-top: 0.3rem; }
.db-outcome__nota {
  display: inline-flex; align-items: center; gap: 0.45rem; margin-top: 1.1rem; padding: 0.5rem 0.85rem;
  border-radius: var(--db-radius-pill); background: color-mix(in srgb, var(--tone) 10%, #fff);
  border: 1px solid color-mix(in srgb, var(--tone) 25%, #fff); color: var(--tone); font-size: 0.82rem; font-weight: var(--db-fw-medium);
}
.db-outcome__nota svg { width: 15px; height: 15px; flex-shrink: 0; }
.db-outcome__foot { display: flex; flex-direction: column; gap: 0.6rem; padding: 1.5rem 1.7rem 1.7rem; }
.db-outcome__foot .db-btn { justify-content: center; }

/* tons (semânticos, os mesmos dos toasts/badges de status) */
.db-tom-sucesso { --tone: #12A150; --tone2: #37C978; }
.db-tom-erro    { --tone: #DC3545; --tone2: #F0616D; }
.db-tom-aviso   { --tone: #E08600; --tone2: #F5A310; }
.db-tom-info    { --tone: #0A74C4; --tone2: #22A5E8; }

/* micro-animações de entrada: o desfecho "chega" */
@media (prefers-reduced-motion: no-preference) {
  .db-outcome__badge { animation: db-pop 0.55s cubic-bezier(0.34, 1.42, 0.5, 1) both; }
  .db-outcome__badge::after { animation: db-ring 2.1s ease-out 0.3s infinite; }
  .db-outcome__title { animation: db-up 0.5s ease both 0.08s; }
  .db-outcome__msg { animation: db-up 0.5s ease both 0.14s; }
  .db-outcome__destaque, .db-outcome__nota { animation: db-up 0.5s ease both 0.2s; }
  .db-outcome__foot { animation: db-up 0.5s ease both 0.26s; }
}
@keyframes db-pop { from { opacity: 0; transform: scale(0.55); } to { opacity: 1; transform: none; } }
@keyframes db-up { from { opacity: 0; transform: translateY(9px); } to { opacity: 1; transform: none; } }
@keyframes db-ring {
  0%   { box-shadow: 0 0 0 2px color-mix(in srgb, var(--tone) 38%, transparent); }
  100% { box-shadow: 0 0 0 20px transparent; }
}

/* ===== Animação de entrada das telas (fade + leve subida, em cascata) =====
   Dá "vida" ao abrir cada tela. Como o Turbo recria o <body> a cada navegação,
   os elementos novos re-executam a animação, então cada tela "entra" animada.
   Alvo: os blocos de topo do conteúdo (filhos diretos do .container do main).
   É desligada automaticamente pela regra de prefers-reduced-motion abaixo. */
@keyframes dbEnter {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}
main > .container > * { animation: dbEnter 0.5s cubic-bezier(0.22, 0.61, 0.36, 1) both; }
main > .container > *:nth-child(2) { animation-delay: 0.06s; }
main > .container > *:nth-child(3) { animation-delay: 0.12s; }
main > .container > *:nth-child(4) { animation-delay: 0.18s; }
main > .container > *:nth-child(5) { animation-delay: 0.24s; }
main > .container > *:nth-child(n+6) { animation-delay: 0.30s; }

/* Movimento reduzido: desliga o que é DECORAÇÃO, e só isso.
 *
 * O `*` com `!important` é a rede que pega animação de entrada, pulso de
 * atenção, brilho de esqueleto: tudo que existe para agradar. O problema é que
 * ele pegava junto o que existe para INFORMAR. Com "reduzir animações" ligado
 * no sistema (Windows: Configurações > Acessibilidade > Efeitos visuais), o
 * botão de entrar, o "pendente" do histórico, o "Realizando consulta" e o anel
 * do overlay que bloqueia a tela inteira ficavam TODOS congelados.
 *
 * Spinner parado não é uma animação a menos: é a tela dizendo que travou. Quem
 * pediu menos movimento não pediu para deixar de saber se o sistema está
 * trabalhando, e o pior caso é o overlay bloqueante, onde o giro é o ÚNICO
 * sinal de vida numa tela que não aceita clique.
 *
 * Por isso os indicadores de estado voltam logo abaixo, e voltam MAIS LENTOS,
 * não na velocidade cheia: o pedido de calma continua respeitado, o giro só não
 * pode parar.
 *
 * ⚠️ Spinner novo entra nesta lista, mesmo o de uma tela só. Quem escreve o CSS
 * quase nunca tem "reduzir animações" ligado, então o congelamento não aparece
 * para ele: aparece para o cliente, e chega como "o sistema travou".
 * Trava contra regressão: `python scripts/verificar_animacao_estado.py`. */
@media (prefers-reduced-motion: reduce) {
  /* `::before` e `::after` na rede também: `*` casa com ELEMENTO, e não com
     pseudo-elemento. A rede vazava por eles, e vazava exatamente onde não
     deveria: o pulso do KPI do admin, o ponto de presença e o anel do modal de
     desfecho continuavam batendo para quem tinha pedido menos movimento. */
  *, *::before, *::after { animation: none !important; transition: none !important; }

  .db-spinner,
  .status-badge__spin,
  .db-status__spin        { animation: db-spin 1.4s linear infinite !important; }
  .db-processing__spinner { animation: db-spin 1.6s linear infinite !important; }
  .wz-hint--load svg      { animation: db-spin 1.6s linear infinite !important; }
  .an-live__spin          { animation: an-spin 1.6s linear infinite !important; }
  /* Único movimento do overlay bloqueante. A tentativa de reduzi-lo morava em
     style.css, como `animation-duration`, e era vencida pelo `!important` do
     `*` logo acima: a regra existia e não pintava. */
  .db-blockload__ring     { animation: dbBrandSpin 2.6s linear infinite !important; }
  .spinner,
  .loading-spinner        { animation: spin 1.8s linear infinite !important; }
  .spinner-border         { animation: spinner-border 1.4s linear infinite !important; }
}

/* =========================================================================
   CENTRAL DE NOTIFICAÇÕES
   O painel do sino e a tela "Ver todas" usam os MESMOS componentes
   (.db-notif, .db-aviso); só o container muda. Ver app/docs/notificacoes.md.
   ========================================================================= */

/* ---- o painel ancorado no sino ---------------------------------------- */
.db-notifpanel {
  position: absolute; top: calc(100% + 0.65rem); right: 0;
  width: 404px; max-width: calc(100vw - 2rem);
  background: var(--db-surface);
  border: 1px solid var(--db-border);
  border-radius: var(--db-radius);
  box-shadow: 0 22px 60px rgba(1, 26, 64, 0.22);
  overflow: hidden;
  display: flex; flex-direction: column;
  z-index: 20;
  /* O texto do painel é do TEMA CLARO do sistema, não do navbar escuro em que
     ele está ancorado. Sem isto, o `color` branco herdado da navbar apagaria
     o corpo de cada item. */
  color: var(--db-text);
}
.db-notifpanel[hidden] { display: none; }

/* ---- entrada dos dois painéis da navbar --------------------------------- *
 * O sino e o menu do usuário abrem ancorados na navbar e apareciam de estalo.
 * Uma animação só serve aos dois, porque eles são o mesmo gesto.
 *
 * Usa as propriedades INDIVIDUAIS `translate` e `scale`, e NÃO `transform`,
 * por causa do menu do usuário: ele é um dropdown do Bootstrap, e o Popper
 * escreve `transform: translate3d(...)` inline nele para posicionar. Animação
 * vence estilo inline na cascata, então um `transform: none` no fim do
 * keyframe apagaria o posicionamento e o menu pularia para o canto da tela.
 * As individuais COMPÕEM com o `transform` do Popper em vez de substituí-lo.
 *
 * `transform-origin` continua valendo para elas: a origem no canto superior
 * direito é o que faz o painel crescer a partir do botão que o abriu, e não do
 * próprio centro. A translação do Popper não é afetada por origem.
 *
 * Só na ABERTURA. Fechar continua imediato: animar a saída exigiria segurar o
 * elemento vivo depois do clique, e um menu que demora a sumir atrapalha quem
 * já está indo para a próxima coisa.
 *
 * `.db-usermenu` é definida em style.css; a regra mora aqui porque a animação
 * é do design system e o despacha-ui.css carrega antes.
 */
@keyframes dbAbreDaNavbar {
  from { opacity: 0; translate: 0 -7px; scale: 0.97; }
  to   { opacity: 1; translate: 0 0; scale: 1; }
}
@media (prefers-reduced-motion: no-preference) {
  .db-notifpanel:not([hidden]),
  .db-usermenu.show {
    animation: dbAbreDaNavbar 0.17s cubic-bezier(0.22, 1, 0.36, 1) both;
    transform-origin: top right;
  }
}
.db-notifpanel__head {
  display: flex; align-items: center; gap: 0.6rem;
  padding: 0.95rem 1rem 0.75rem;
  border-bottom: 1px solid var(--db-border);
}
.db-notifpanel__title {
  font-weight: var(--db-fw-semibold); font-size: 1rem;
  color: var(--db-primary); margin-right: auto;
}
.db-notifpanel__act {
  display: inline-flex; align-items: center; gap: 0.32rem;
  font-size: 0.78rem; font-weight: var(--db-fw-medium);
  color: var(--db-text-muted);
  background: none; border: 0; cursor: pointer;
  padding: 0.3rem 0.45rem; border-radius: var(--db-radius-xs);
}
.db-notifpanel__act:hover { background: var(--db-surface-2); color: var(--db-accent); }
.db-notifpanel__act svg { width: 14px; height: 14px; }
/* Alto o bastante para os avisos NÃO comerem a lista inteira: com três avisos
   fixos no topo, um teto de 460px deixava a primeira novidade cortada ao meio e
   o painel parecia só ter pendência. Preso a 72vh para não passar do rodapé da
   janela em tela baixa. */
/* `overscroll-behavior: contain`: chegar ao fim da lista não pode continuar
   rolando a página atrás do painel, nem disparar o "puxar para atualizar" do
   celular, que recarrega a tela e fecha o painel no meio da leitura. */
.db-notifpanel__scroll { overflow-y: auto; max-height: min(72vh, 620px); overscroll-behavior: contain; }
.db-notifpanel__avisos {
  padding: 0.75rem 0.75rem 0.3rem;
  background: linear-gradient(180deg, rgba(0, 149, 217, 0.05), transparent);
}
/* Cabeçalho de seção: "Precisa de você", "Hoje", "Ontem". */
.db-notifpanel__grupo {
  display: flex; align-items: center; gap: 0.45rem;
  font-size: 0.68rem; font-weight: var(--db-fw-bold);
  letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--db-text-soft);
  padding: 0.55rem 0.95rem 0.4rem; margin: 0;
}
.db-notifpanel__grupo svg { width: 13px; height: 13px; }
.db-notifpanel__avisos .db-notifpanel__grupo { padding-left: 0.35rem; padding-right: 0.35rem; }
.db-notifpanel__foot {
  padding: 0.6rem 1rem; border-top: 1px solid var(--db-border);
  background: var(--db-surface-2);
  display: flex; align-items: center; justify-content: space-between;
  font-size: 0.79rem;
}
.db-notifpanel__mute { color: var(--db-text-soft); }
.db-notifpanel__foot a {
  color: var(--db-accent); font-weight: var(--db-fw-semibold); text-decoration: none;
  display: inline-flex; align-items: center; gap: 0.28rem;
}
.db-notifpanel__foot a svg { width: 14px; height: 14px; transition: transform 0.15s ease; }
.db-notifpanel__foot a:hover svg { transform: translateX(3px); }
.db-notifpanel__vazio { padding: 2.4rem 1.5rem; text-align: center; }
.db-notifpanel__vazioic {
  display: inline-flex; align-items: center; justify-content: center;
  width: 48px; height: 48px; border-radius: 50%;
  background: var(--db-surface-2); color: var(--db-text-soft); margin-bottom: 0.7rem;
}
.db-notifpanel__vazioic svg { width: 22px; height: 22px; }
.db-notifpanel__vaziot {
  font-weight: var(--db-fw-semibold); color: var(--db-text); margin: 0 0 0.25rem;
}
.db-notifpanel__vaziox {
  font-size: 0.82rem; color: var(--db-text-muted); margin: 0; line-height: 1.5;
}

@media (max-width: 991px) {
  /* Menu recolhido: o painel deixa de ser flutuante e vira parte do menu, porque
     um dropdown absoluto ali cairia por cima dos links ou sairia da tela. */
  .db-notifpanel {
    position: static; width: 100%; max-width: none;
    margin-top: 0.5rem; box-shadow: var(--db-shadow-sm);
  }
  .db-notifpanel__scroll { max-height: 50vh; }
}

/* ---- um item (novidade) ------------------------------------------------ */
.db-notif {
  display: flex; gap: 0.7rem; align-items: flex-start;
  padding: 0.72rem 0.85rem;
  border-bottom: 1px solid var(--db-surface-2);
  text-decoration: none; color: inherit;
  transition: background 0.15s ease;
}
.db-notif:last-child { border-bottom: 0; }
a.db-notif:hover { background: var(--db-surface-2); color: inherit; text-decoration: none; }
/* Não lida: fundo levemente azul. É o mesmo azul de "ação necessária" do badge
   de status: o cliente já aprendeu que essa cor quer dizer "olhe isto". */
.db-notif--nova { background: rgba(0, 149, 217, 0.045); }
a.db-notif--nova:hover { background: rgba(0, 149, 217, 0.085); }
.db-notif__ic {
  width: 30px; height: 30px; border-radius: 50%; margin-top: 0.1rem;
  display: inline-flex; align-items: center; justify-content: center;
  flex: 0 0 auto;
}
.db-notif__ic svg { width: 15px; height: 15px; }
.db-notif__body { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.db-notif__title {
  font-size: 0.84rem; font-weight: var(--db-fw-semibold);
  color: var(--db-text); line-height: 1.35;
}
.db-notif__text {
  font-size: 0.765rem; color: var(--db-text-muted);
  line-height: 1.4; margin-top: 0.08rem;
  /* Trecho de resposta do suporte pode ser longo: duas linhas e reticências,
     para um item não empurrar os outros para fora do painel. */
  display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2;
  -webkit-box-orient: vertical; overflow: hidden;
}
/* Segunda linha do corpo (quem está do outro lado, na fila de cadastros).
   Uma linha só, e cortada com reticências: é identificação, e um e-mail longo
   não pode empurrar o resto do painel. */
.db-notif__meta {
  font-size: 0.74rem; color: var(--db-text-soft);
  line-height: 1.35; margin-top: 0.1rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.db-notif__when {
  font-size: 0.7rem; color: var(--db-text-soft); margin-top: 0.22rem;
  font-variant-numeric: tabular-nums;
}
.db-notif__dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--db-accent); flex: 0 0 auto; align-self: center;
}

/* Tons: os MESMOS dos toasts (.db-toast--*), para o aviso ter a mesma cor no
   canto da tela e no sino. Cor semântica, não decoração. */
.db-notif--success .db-notif__ic { background: rgba(3, 140, 90, 0.14); color: #0f7a4f; }
.db-notif--warning .db-notif__ic { background: rgba(217, 144, 0, 0.16); color: #946800; }
.db-notif--danger  .db-notif__ic { background: rgba(220, 53, 69, 0.12); color: #c0303c; }
.db-notif--info    .db-notif__ic { background: rgba(0, 149, 217, 0.14); color: #0369a1; }

/* ---- um aviso (estado, fixo no topo) ----------------------------------- */
.db-aviso {
  display: flex; gap: 0.7rem;
  padding: 0.7rem 0.75rem;
  border-radius: var(--db-radius-sm);
  border: 1px solid var(--db-border);
  background: var(--db-surface);
  box-shadow: var(--db-shadow-sm);
  margin-bottom: 0.5rem;
  position: relative; overflow: hidden;
}
/* Faixa lateral na cor do tom: o aviso precisa se distinguir da novidade mesmo
   para quem rola rápido, e a listra lê antes do texto. */
.db-aviso::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--db-accent);
}
.db-aviso__ic {
  width: 32px; height: 32px; border-radius: 9px; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
}
.db-aviso__ic svg { width: 16px; height: 16px; }
.db-aviso__body { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.db-aviso__title {
  font-weight: var(--db-fw-semibold); font-size: 0.855rem;
  line-height: 1.35; color: var(--db-text);
}
.db-aviso__text {
  font-size: 0.775rem; color: var(--db-text-muted);
  line-height: 1.45; margin-top: 0.1rem;
}
.db-aviso__cta {
  display: inline-flex; align-items: center; gap: 0.28rem; align-self: flex-start;
  margin-top: 0.4rem; font-size: 0.775rem;
  font-weight: var(--db-fw-semibold); text-decoration: none;
}
.db-aviso__cta svg { width: 13px; height: 13px; transition: transform 0.15s ease; }
.db-aviso__cta:hover svg { transform: translateX(3px); }

.db-aviso--success::before { background: #0f7a4f; }
.db-aviso--success .db-aviso__ic { background: rgba(3, 140, 90, 0.14); color: #0f7a4f; }
.db-aviso--success .db-aviso__cta { color: #0f7a4f; }
.db-aviso--warning::before { background: #946800; }
.db-aviso--warning .db-aviso__ic { background: rgba(217, 144, 0, 0.16); color: #946800; }
.db-aviso--warning .db-aviso__cta { color: #946800; }
.db-aviso--danger::before { background: #c0303c; }
.db-aviso--danger .db-aviso__ic { background: rgba(220, 53, 69, 0.12); color: #c0303c; }
.db-aviso--danger .db-aviso__cta { color: #c0303c; }
.db-aviso--info::before { background: #0369a1; }
.db-aviso--info .db-aviso__ic { background: rgba(0, 149, 217, 0.14); color: #0369a1; }
.db-aviso--info .db-aviso__cta { color: #0369a1; }

/* ---- a tela "Ver todas" ------------------------------------------------ */
/* Mesmos itens, num cartão de página: o cliente reconhece o que já viu no sino
   em vez de encontrar uma segunda linguagem para a mesma coisa. */
.db-notiflista { padding: 0; overflow: hidden; }
.db-notiflista .db-notif { padding: 0.9rem 1.15rem; }
/* Na largura da página o texto não ocupa a linha toda, e o ponto de "não lida"
   ficava encostado na borda direita, a 900px do assunto a que se refere, lido
   como enfeite de coluna em vez de marca daquele item. Aqui ele anda junto do
   texto, e a sobra fica depois dele. */
.db-notiflista .db-notif__body { flex: 0 1 auto; max-width: 72ch; }
.db-notiflista .db-notif__dot { margin-right: auto; margin-left: 0.15rem; }
.db-notiflista .db-notifpanel__grupo {
  padding: 0.85rem 1.15rem 0.5rem;
  background: var(--db-surface-2);
  border-bottom: 1px solid var(--db-border);
}
.db-notiflista .db-aviso { margin: 0.75rem 1.15rem; }

/* =========================================================================
   EXPLICAÇÃO EM HOVER (`data-tip`)
   -------------------------------------------------------------------------
   Um termo curto da tela ("Taxa", "No plano", "Aproveitamento") que só quem
   escreveu o código entende ganha a frase inteira ao lado, sem quebrar a
   tabela. Ver static/js/db-tip.js.

   O GATILHO é um "?" discreto: ele não pode competir com o dado. A BOLHA vive
   no <body> em `position: fixed`, porque os termos que mais precisam de
   explicação moram dentro de tabela com `overflow: auto`, e ali um
   pseudo-elemento seria cortado pela borda do contêiner.
   ========================================================================= */
.db-tip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 14px; height: 14px; margin-left: 0.28rem; padding: 0;
  border: 1px solid var(--db-border); border-radius: 50%;
  background: transparent; color: var(--db-text-soft);
  font-size: 9px; font-weight: 700; line-height: 1; cursor: help;
  vertical-align: middle; flex-shrink: 0;
  transition: border-color var(--db-transition), color var(--db-transition);
}
.db-tip::before { content: "?"; }
.db-tip:hover, .db-tip:focus-visible { border-color: var(--db-primary); color: var(--db-primary); }
.db-tip:focus { outline: none; }
.db-tip:focus-visible { box-shadow: 0 0 0 3px color-mix(in srgb, var(--db-primary) 18%, transparent); }

.db-tip__bolha {
  position: fixed; z-index: 12000; max-width: 280px;
  padding: 0.5rem 0.7rem; border-radius: 8px;
  background: #1c2a3f; color: #e8eef7;
  font-size: 0.76rem; font-weight: 400; line-height: 1.45;
  text-align: left; text-transform: none; letter-spacing: normal;
  box-shadow: 0 6px 20px rgba(16, 24, 40, 0.22);
  opacity: 0; visibility: hidden; pointer-events: none;
  transform: translateY(2px);
  transition: opacity .12s ease, transform .12s ease, visibility .12s;
}
.db-tip__bolha.is-open { opacity: 1; visibility: visible; transform: translateY(0); }
/* A seta segue o lado em que a bolha coube, e aponta para o GATILHO: perto da
   borda da janela a bolha é empurrada para dentro, e uma seta presa ao centro
   dela apontaria para um lugar onde não há nada. O JS mede e escreve
   `--db-tip-seta`; o `50%` é só o repouso, para o caso de ele não ter rodado. */
.db-tip__bolha::after {
  content: ""; position: absolute; left: var(--db-tip-seta, 50%); margin-left: -5px;
  border: 5px solid transparent; border-top-color: #1c2a3f; top: 100%;
}
.db-tip__bolha.is-abaixo::after {
  border-top-color: transparent; border-bottom-color: #1c2a3f;
  top: auto; bottom: 100%;
}

@media (prefers-reduced-motion: reduce) {
  .db-tip__bolha { transition: none; transform: none; }
}
