/* =============================================================================
   dvgest.css — o padrão visual da plataforma
   -----------------------------------------------------------------------------
   Um arquivo, sem dependência, sem build. Para levar o padrão a outro projeto,
   copie ESTE arquivo e o `dvgest-graficos.js` ao lado dele. Nada mais.

   A galeria viva de tudo que está aqui é `padrao/index.html`.
   O quando-usar-o-quê é `padrao/REGRAS.md`.

   De onde cada metade veio:
   · CROMO (superfície, tinta, borda, sombra) — da tela `demonstracao`, que é a
     mais usada e a que já concilia o vocabulário do app shell.
   · GRÁFICO (séries, status, grade, linha de base) — da paleta validada que a
     `indices-financeiros` já usava sem que tivesse nome. Passa nos seis testes
     de daltonismo/contraste nas NOSSAS superfícies (ver REGRAS.md § Cor).

   Toda cor daqui é medida, não escolhida no olho. Antes de trocar qualquer hex
   de série, rode o validador — o procedimento está em REGRAS.md.
   ============================================================================= */

/* =============================================================================
   1 · TOKENS — tema claro
   ============================================================================= */
:root {
  color-scheme: light dark;

  /* ---- superfícies e planos ------------------------------------------------ */
  --page:           #f7f7f7;   /* o plano da página */
  --surface:        #ffffff;   /* cartão, painel, linha de tabela */
  --surface-2:      #f9fafb;   /* zebra, cabeçalho de tabela, campo */
  --surface-hover:  #f3f4f6;   /* estado de passagem do mouse */
  --app-bg:         var(--page);

  /* ---- tinta ---------------------------------------------------------------
     Contraste medido sobre --surface (#ffffff):
       --ink 12,6:1 · --ink-2 10,3:1 · --muted 4,8:1 · --muted-2 2,5:1
     --muted-2 NÃO passa em texto. Ele é só para placeholder e ícone decorativo. */
  --ink:            #333333;
  --ink-2:          #374151;
  --muted:          #6b7280;
  --muted-2:        #9ca3af;

  /* ---- traço --------------------------------------------------------------- */
  /* **Translucida, nao hex.** Sobre uma superficie de vidro uma borda opaca e
     uma linha dura POR CIMA do efeito; uma translucida pertence a ele -- ela
     clareia o que estiver atras em vez de cobrir. E o que a Indices
     Financeiros ja fazia, e foi de la que veio. */
  --borda:          rgba(11, 11, 11, .10);
  --borda-forte:    rgba(11, 11, 11, .20);
  --sombra:         0 1px 3px rgba(0,0,0,.08), 0 8px 24px rgba(0,0,0,.06);
  --sombra-alta:    0 12px 34px rgba(0,0,0,.18);

  /* ---- marca ---------------------------------------------------------------
     DOIS tokens, de propósito. O azul da marca dá 2,62:1 sobre branco — ele
     pinta, mas não escreve. Texto e link usam --acento-texto (5,6:1), que é o
     mesmo tom um passo mais escuro. Trocar um pelo outro é o erro que este
     padrão existe para impedir.

     "Não escreve" inclui DUAS coisas que passam despercebidas, porque nas duas
     o --acento é fundo e não tinta — e contraste é simétrico, não importa qual
     lado é a letra:
       · bloco preenchido COM TEXTO EM CIMA (botão principal): branco sobre
         #24a7fc é o mesmo 2,62:1. Preenchimento com texto usa --acento-texto.
       · indicador de FOCO: a WCAG 1.4.11 pede 3:1 para componente não-textual,
         e 2,62 reprova. O anel de foco também usa --acento-texto.
     Sobra para o --acento o preenchimento que não carrega letra nenhuma: blob,
     barra ativa, faixa, medidor, amostra de cor. */
  --acento:         #24a7fc;   /* preenchimento SEM texto: blob, barra ativa */
  --acento-texto:   #0a6ca8;   /* link, <summary>, botão principal, anel de foco */
  --acento-ink:     #ffffff;   /* tinta sobre um bloco de --acento */
  --acento-lavado:  #eff6ff;   /* fundo de realce, linha-chave */

  /* ---- status — significado reservado --------------------------------------
     Nunca reaproveitar como "série 4". Sempre acompanhados de ícone OU rótulo:
     no claro, --atencao e --grave ficam abaixo de 3:1 por desenho, e o rótulo
     é a mitigação. */
  /* --bom é o único status que aparece como bloco SÓLIDO com texto branco em
     cima (.chip.otimo). Por isso ele é mais escuro que o verde de marca óbvio:
     #0ca30c dava 3,35:1 com branco, e 12px em negrito não pega a isenção de
     texto grande (que começa em 18,66px). #0a7d0a dá 5,32:1. */
  --bom:            #0a7d0a;
  --atencao:        #fab219;
  --grave:          #ec835a;
  --critico:        #d03b3b;
  --bom-texto:      #006300;   /* o verde legível como texto no claro */
  --atencao-texto:  #7a5200;
  --grave-texto:    #8a3416;
  /* faltava: a família tinha "texto" para três dos quatro status. --critico
     escreve a 4,60:1 no claro (passa raspando) e a 3,00:1 no escuro (reprova),
     e foi o bloco de erro que descobriu isso. Aqui: 5,95 e 7,24. */
  --critico-texto:  #b52d2d;
  --bom-lavado:     rgba(10,125,10,.14);
  --atencao-lavado: rgba(250,178,25,.20);
  --grave-lavado:   rgba(236,131,90,.20);
  --critico-lavado: rgba(208,59,59,.14);

  /* ---- delta (subiu / desceu) ---------------------------------------------- */
  --delta-sobe:     #006300;
  --delta-desce:    #ab2323;

  /* ---- séries categóricas — ORDEM FIXA, nunca ciclada -----------------------
     Oito famílias. A ordem É o mecanismo de segurança para daltonismo: ela foi
     validada nesta sequência. Reordenar invalida a garantia. A 9ª série não
     existe — vira "Outros", vira facetas, ou vira tabela. */
  --serie-1:        #2a78d6;   /* azul     */
  --serie-2:        #eb6834;   /* laranja  */
  --serie-3:        #1baf7a;   /* água     */
  --serie-4:        #eda100;   /* amarelo  */
  --serie-5:        #e87ba4;   /* magenta  */
  --serie-6:        #008300;   /* verde    */
  --serie-7:        #4a3aa7;   /* violeta  */
  --serie-8:        #e34948;   /* vermelho */

  /* ---- rampa sequencial (magnitude: uma cor só, claro→escuro) --------------- */
  --seq-100:        #cde2fb;
  --seq-200:        #9ec5f4;
  --seq-300:        #6da7ec;
  --seq-400:        #3987e5;
  --seq-500:        #256abf;
  --seq-600:        #184f95;
  --seq-700:        #0d366b;

  /* ---- divergente (polaridade: dois polos + cinza neutro no meio) ----------- */
  --div-neg:        #e34948;
  --div-meio:       #f0efec;
  --div-pos:        #2a78d6;

  /* ---- cromo do gráfico ----------------------------------------------------- */
  --grade:          #e1e0d9;   /* fio de grade — 1px, sólido, recuado */
  --base-eixo:      #c3c2b7;   /* a linha de base, um passo mais forte */
  --tooltip-bg:     #21211f;
  --tooltip-ink:    #f4f3ef;

  /* ---- fundo animado -------------------------------------------------------- */
  --blob-a:         rgba(77,181,249,.38);
  --blob-b:         rgba(36,167,252,.30);
  --blob-c:         rgba(120,210,255,.26);

  /* ==========================================================================
     ESCALA TIPOGRÁFICA — 10 degraus, e só eles
     --------------------------------------------------------------------------
     O repositório tinha 40 tamanhos distintos em 8 arquivos (.82 / .85 / 0.85 /
     .86 / .88 / 0.88 / .9 / 0.9 / .92 / .94 / .95rem …). Isso é ruído, não
     desenho: nenhuma dessas diferenças é perceptível, e cada uma é uma decisão
     a mais para alguém tomar errado. Escolher um degrau é a decisão inteira.
     ========================================================================== */
  --t-micro:   0.6875rem;  /* 11px — rótulo de eixo, legenda densa            */
  --t-mini:    0.75rem;    /* 12px — rótulo de KPI, cabeçalho de tabela, chip */
  --t-menor:   0.8125rem;  /* 13px — célula de tabela, nota de rodapé         */
  --t-corpo:   0.875rem;   /* 14px — o texto padrão da interface              */
  --t-maior:   1rem;       /* 16px — corpo de leitura, resumo longo           */
  --t-h3:      1.125rem;   /* 18px — título de cartão                         */
  --t-h2:      1.375rem;   /* 22px — título de seção                          */
  --t-h1:      1.625rem;   /* 26px — título de tela                           */
  --t-numero:  1.875rem;   /* 30px — valor de KPI                             */
  --t-heroi:   3rem;       /* 48px — o número que a tela lidera. Um por tela.  */

  --lh-apertado: 1.25;     /* título, número — linhas curtas */
  --lh-normal:   1.5;      /* interface                      */
  --lh-leitura:  1.65;     /* parágrafo, resumo              */

  --peso-normal: 400;
  --peso-medio:  600;
  --peso-forte:  700;

  --rastreio-caixa-alta: 0.07em;  /* o único lugar onde caixa alta é permitida */
  --medida-leitura: 68ch;         /* largura máxima de parágrafo               */

  --fonte: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;

  /* ==========================================================================
     ESPAÇO — base 4px, 8 degraus
     ========================================================================== */
  --e1:  4px;
  --e2:  8px;
  --e3: 12px;
  --e4: 16px;
  --e5: 24px;
  --e6: 32px;
  --e7: 48px;
  --e8: 64px;

  /* ---- raio ----------------------------------------------------------------- */
  --r-min:  6px;    /* chip, campo pequeno */
  --r:     14px;    /* cartão, painel, ladrilho, figura        */
                    /* era 10px ate 06/09: num bloco largo o raio nao
                       chegava a ler, e o cartao parecia quadrado. */
  --r-g:   14px;    /* diálogo             */
  --r-pill: 999px;

  /* ---- marcas de gráfico (specs fixas — ver REGRAS.md § Marcas) -------------- */
  --marca-espessura-max: 24px;  /* barra/coluna nunca passa disto */
  --marca-ponta:          4px;  /* arredondamento SÓ na ponta do dado */
  --marca-linha:          2px;
  --marca-ponto:          4px;  /* raio; 8px de diâmetro é o mínimo de toque */
  --marca-vao:            2px;  /* o vão de superfície que separa duas marcas */
  --marca-area-opacidade: .10;
}

/* =============================================================================
   2 · TOKENS — tema escuro
   -----------------------------------------------------------------------------
   Declarado nos DOIS escopos, de propósito:
   · o `@media` cobre a preferência do sistema operacional;
   · o `[data-theme]` cobre o botão de tema, e precisa ganhar nos dois sentidos.
   O `:not([data-theme="light"])` é o que deixa a escolha "claro" vencer um
   sistema no escuro; o `:where()` mantém o bloco do media abaixo do botão.
   Sem essas duas guardas o botão funciona num sentido só — e falha calado.
   ============================================================================= */
@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) {
    --page:          #16181c;
    --surface:       #1f2226;
    --surface-2:     #262a30;
    --surface-hover: #2c3138;
    --app-bg:        linear-gradient(180deg, #101318 0%, #0b0d10 100%);
    --ink:           #e8e8e8;
    --ink-2:         #cbd5e1;
    --muted:         #9aa4b2;
    --muted-2:       #7b8595;
    --borda:         rgba(255, 255, 255, .10);
    --borda-forte:   rgba(255, 255, 255, .20);
    --sombra:        0 1px 3px rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.3);
    --sombra-alta:   0 12px 34px rgba(0,0,0,.5);
    --acento:        #4db5f9;
    --acento-texto:  #4db5f9;
    --acento-ink:    #0d0d0d;
    --acento-lavado: #1c2a42;
    --bom-texto:     #6fd06f;
    --atencao-texto: #f4c45c;
    --grave-texto:   #f2a483;
    --critico-texto: #f2a3a3;
    --delta-sobe:    #0ca30c;
    --delta-desce:   #e66767;
    --serie-1: #3987e5; --serie-2: #d95926; --serie-3: #199e70; --serie-4: #c98500;
    --serie-5: #d55181; --serie-6: #008300; --serie-7: #9085e9; --serie-8: #e66767;
    --seq-100: #0d366b; --seq-200: #184f95; --seq-300: #256abf; --seq-400: #3987e5;
    --seq-500: #5598e7; --seq-600: #86b6ef; --seq-700: #cde2fb;
    --div-neg: #e66767; --div-meio: #383835; --div-pos: #3987e5;
    --grade:       #2c2c2a;
    --base-eixo:   #383835;
    --tooltip-bg:  #f4f3ef;
    --tooltip-ink: #21211f;
    --blob-a: rgba(77,181,249,.20);
    --blob-b: rgba(36,167,252,.16);
    --blob-c: rgba(120,210,255,.14);
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --page:          #16181c;
  --surface:       #1f2226;
  --surface-2:     #262a30;
  --surface-hover: #2c3138;
  --app-bg:        linear-gradient(180deg, #101318 0%, #0b0d10 100%);
  --ink:           #e8e8e8;
  --ink-2:         #cbd5e1;
  --muted:         #9aa4b2;
  --muted-2:       #7b8595;
  --borda:         rgba(255, 255, 255, .10);
  --borda-forte:   rgba(255, 255, 255, .20);
  --sombra:        0 1px 3px rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.3);
  --sombra-alta:   0 12px 34px rgba(0,0,0,.5);
  --acento:        #4db5f9;
  --acento-texto:  #4db5f9;
  --acento-ink:    #0d0d0d;
  --acento-lavado: #1c2a42;
  --bom-texto:     #6fd06f;
  --atencao-texto: #f4c45c;
  --grave-texto:   #f2a483;
  --critico-texto: #f2a3a3;
  --delta-sobe:    #0ca30c;
  --delta-desce:   #e66767;
  --serie-1: #3987e5; --serie-2: #d95926; --serie-3: #199e70; --serie-4: #c98500;
  --serie-5: #d55181; --serie-6: #008300; --serie-7: #9085e9; --serie-8: #e66767;
  --seq-100: #0d366b; --seq-200: #184f95; --seq-300: #256abf; --seq-400: #3987e5;
  --seq-500: #5598e7; --seq-600: #86b6ef; --seq-700: #cde2fb;
  --div-neg: #e66767; --div-meio: #383835; --div-pos: #3987e5;
  --grade:       #2c2c2a;
  --base-eixo:   #383835;
  --tooltip-bg:  #f4f3ef;
  --tooltip-ink: #21211f;
  --blob-a: rgba(77,181,249,.20);
  --blob-b: rgba(36,167,252,.16);
  --blob-c: rgba(120,210,255,.14);
}
:root[data-theme="light"] { color-scheme: light; }

/* =============================================================================
   3 · BASE
   ============================================================================= */
*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  min-height: 100vh;
  /* o fundo vai no body, NÃO no html: sem fundo próprio no html o navegador
     propaga o do body para pintar atrás de tudo — inclusive atrás dos blobs,
     que têm z-index negativo. Com fundo nos dois, os blobs somem. */
  background: var(--app-bg);
  background-color: var(--page);
  color: var(--ink);
  font-family: var(--fonte);
  font-size: var(--t-corpo);
  line-height: var(--lh-normal);
  -webkit-font-smoothing: antialiased;
}

/* o anel de foco é componente não-textual: a WCAG 1.4.11 pede 3:1, e o
   --acento dá 2,62 no claro. Daí --acento-texto (5,64) também aqui. */
:focus-visible {
  outline: 2px solid var(--acento-texto);
  outline-offset: 2px;
  border-radius: var(--r-min);
}

/* =============================================================================
   4 · FUNDO ANIMADO E MARCA — a assinatura da plataforma
   ============================================================================= */
.bg-blobs { position: fixed; inset: 0; overflow: hidden; z-index: -1; pointer-events: none; }
.bg-blob  { position: absolute; border-radius: 50%; filter: blur(70px); }
.bg-blob-a { width: 900px; height: 900px; top: -22%; left: -12%;
             background: radial-gradient(circle, var(--blob-a), transparent 70%);
             animation: deriva-a 20s ease-in-out infinite alternate; }
.bg-blob-b { width: 520px; height: 520px; bottom: -16%; right: 2%;
             background: radial-gradient(circle, var(--blob-b), transparent 70%);
             animation: deriva-b 16s ease-in-out infinite alternate; }
.bg-blob-c { width: 340px; height: 340px; top: 34%; right: 26%;
             background: radial-gradient(circle, var(--blob-c), transparent 70%);
             animation: deriva-c 24s ease-in-out infinite alternate; }
@keyframes deriva-a { to { transform: translate( 8%,  6%) scale(1.08); } }
@keyframes deriva-b { to { transform: translate(-7%, -5%) scale(1.12); } }
@keyframes deriva-c { to { transform: translate( 5%, -8%) scale(0.92); } }

@media (prefers-reduced-motion: reduce) {
  .bg-blob { animation: none; }
  * { transition-duration: .01ms !important; }
}


/* ---- o logotipo -----------------------------------------------------------------
   O outro metade da assinatura. Anda com o fundo animado acima: as duas coisas
   juntas é o que faz uma tela ser reconhecida como desta plataforma antes de
   alguém ler uma palavra.

   **O SVG vai INLINE no HTML, não em `<img>`, e não é preguiça.** Três razões,
   e cada uma sozinha já decide:

     1. `<img>` não recebe `:hover` por dentro. A animação abaixo é gatilhada
        pelo hover do elemento que envolve o SVG -- com `<img>` não há elemento
        por dentro para animar.
     2. `<object>`/`<embed>` resolveriam o item 1 e são bloqueados: a CSP das
        nossas rotas é `default-src 'none'` sem `object-src`.
     3. `currentColor` só funciona inline. Em `<img>` a cor fica congelada no
        arquivo, e a marca precisa virar clara no tema escuro e escura no claro.


   **Chama-se `logotipo` e não `marca` por uma razão de sistema:** neste kit
   `marca-*` já é outra coisa -- `.marca-linha`, `.marca-ponto`, `.marca-area`
   são as marcas de GRÁFICO (§ Marcas do REGRAS.md). Dois sentidos para o mesmo
   prefixo é o defeito que um kit existe para não ter, e custa caro justamente
   quando alguém procura por nome e acha a coisa errada.

   **A cor sai de `color`, herdada.** O padrão é `--ink` porque a marca tem de
   ser legível nos dois temas; quem quiser a marca em azul põe
   `color: var(--acento)` no `.logotipo` -- é preenchimento sem texto em cima, que
   é exatamente o que o `--acento` existe para fazer.

   **A animação só no hover, nunca em repouso.** Movimento perpétuo numa tela
   que a pessoa vai ler é ruído: puxa o olho para o canto onde não há
   informação. O `bob` responde ao ponteiro e volta a parar. */
.logotipo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--ink);
  line-height: 0;               /* sem descida de linha por baixo do SVG */
}
.logotipo-svg {
  width: min(var(--logotipo-tam, 72px), 88vw);
  height: auto;
  display: block;
  /* **SVG corta no viewBox por padrao.** O movimento abaixo sobe as letras
     para fora dele, e sem isto elas aparecem decepadas no topo -- visto na
     tela em 06/09. Deixar transbordar custa zero de layout; alargar o viewBox
     custaria espaco vazio permanente para acomodar um movimento de 6px. */
  overflow: visible;
}

/* ---- o movimento: TRANSITION, nao ANIMATION -------------------------------
   Era um `bob` infinito ligado no `:hover`. Duas coisas erradas nisso, e a
   segunda so aparece usando:

     · **nao ha saida.** Tirando o ponteiro, a `animation` e removida de uma
       vez e as letras voltam de tranco, no meio do ciclo, de onde estiverem.
       Keyframe nao interpola para o estado de repouso -- ele simplesmente
       deixa de existir.
     · movimento perpetuo enquanto o ponteiro esta em cima e ruido: a marca
       fica balancando sem dizer nada.

   Com `transition`, o mesmo deslocamento sobe ao entrar e desce ao sair, com a
   mesma curva nos dois sentidos -- que e o que "fluido" quer dizer. O escalonar
   por letra vira `transition-delay`, e ele vale na ida E na volta, entao a
   sequencia C-S-C se desfaz na mesma ordem em que se fez.

   A curva e um ease-out longo (.22,1,.36,1): sai rapido e assenta devagar, que
   e como uma coisa com peso para de se mover. */
.logotipo .letter {
  transform-box: fill-box;      /* pivo na propria letra, imune ao viewBox */
  transform-origin: 50% 50%;
  transition: transform .5s cubic-bezier(.22, 1, .36, 1);
}
.logotipo:hover .letter,
.logotipo:focus-visible .letter { transform: translateY(-6px) scale(1.04); }
.logotipo .letter-2 { transition-delay: .06s; }
.logotipo .letter-3 { transition-delay: .12s; }

@media (prefers-reduced-motion: reduce) {
  .logotipo .letter { transition: none; }
  .logotipo:hover .letter,
  .logotipo:focus-visible .letter { transform: none; }
}


/* ---- a barra do topo ---------------------------------------------------------
   **Estava prometida e nao existia.** O REGRAS.md lista `.barra-app` como uma
   das tres zonas do painel, a galeria e os tres paineis de exemplo a usam, e o
   comentario da galeria diz que ela "virou `.barra-app` no padrao" -- mas o CSS
   nunca chegou aqui. Resultado: quatro telas renderizando um `<div>` cru, e
   nada reclamando. Documentado sem implementacao falha exatamente assim: em
   silencio, parecendo escolha.

   Translucida como o cartao, pelo mesmo motivo: o fundo animado passa por baixo
   e a barra le como parte da mesma superficie, nao como uma faixa colada em
   cima. */
.barra-app {
  position: sticky; top: 0; z-index: 10;
  display: flex; align-items: center; gap: var(--e4);
  padding: var(--e3) var(--e5);
  background: color-mix(in srgb, var(--surface) 82%, transparent);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--borda);
}
/* o que nao for a identidade vai para a direita */
.barra-app > :last-child { margin-left: auto; }
.barra-app .logotipo { --logotipo-tam: 44px; color: var(--ink); text-decoration: none; }

/* =============================================================================
   5 · TIPOGRAFIA
   ============================================================================= */
h1, h2, h3 { margin: 0; line-height: var(--lh-apertado); letter-spacing: -.01em; }
h1 { font-size: var(--t-h1); font-weight: var(--peso-forte); }
h2 { font-size: var(--t-h2); font-weight: var(--peso-forte); }
h3 { font-size: var(--t-h3); font-weight: var(--peso-medio); }

/* o resumo: a linha sob o título que diz o que aquilo responde. É obrigatório
   em seção e em gráfico — ver REGRAS.md § Enquadramento. */
.resumo {
  margin: var(--e1) 0 0;
  max-width: var(--medida-leitura);
  color: var(--ink-2);
  font-size: var(--t-menor);
  line-height: var(--lh-leitura);
}
.texto { max-width: var(--medida-leitura); line-height: var(--lh-leitura); }

/* caixa alta só aqui, e sempre com rastreio: sem ele, caixa alta apertada em
   11–12px fica ilegível. */
.rotulo {
  font-size: var(--t-mini);
  font-weight: var(--peso-medio);
  letter-spacing: var(--rastreio-caixa-alta);
  text-transform: uppercase;
  color: var(--muted);
}

.num      { font-variant-numeric: tabular-nums; }   /* SÓ em coluna alinhada */
.n-grande { font-size: var(--t-numero); font-weight: var(--peso-forte);
            line-height: var(--lh-apertado); letter-spacing: -.02em; }
.n-heroi  { font-size: var(--t-heroi);  font-weight: var(--peso-forte);
            line-height: 1.1; letter-spacing: -.03em; }

a, .link {
  color: var(--acento-texto);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

/* =============================================================================
   6 · LAYOUT
   ============================================================================= */
.wrap    { max-width: 1100px; margin: 0 auto; padding: var(--e6) var(--e5) var(--e8); }
.secao   { margin-top: var(--e7); }
.grade   { display: grid; gap: var(--e4); grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); }
.grade-2 { display: grid; gap: var(--e4); grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }
/* grade de gráficos tem piso maior de propósito: abaixo de ~400px o eixo perde
   rótulo e as marcas encostam. Melhor duas colunas largas que três apertadas. */
.grade-graficos { display: grid; gap: var(--e4); grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); }

/* ---- composição de painel ------------------------------------------------
   Painel é para VARRER, não para ler linha a linha — por isso um contêiner mais
   largo que a medida de leitura. `.wrap` (1100px) continua sendo o certo para
   página de texto; parágrafo dentro de painel segue preso a --medida-leitura. */
.wrap-largo { max-width: 1440px; margin: 0 auto; padding: var(--e5) var(--e5) var(--e8); }

/* A coluna estreita que FICA (o recorte, o número que a tela lidera, a
   composição) e o corpo que muda. Ela gruda ao rolar porque é ela que responde
   "isto é de quando, de quem, em que medida" — a pergunta que volta justamente
   quando o leitor já rolou para longe do topo.
   Abaixo de 1100px vira uma coluna só, e o rail vai para CIMA: enquadramento
   antes do detalhe, nunca depois. */
.painel { display: grid; gap: var(--e4); grid-template-columns: 300px minmax(0, 1fr); align-items: start; }
.painel-rail { display: flex; flex-direction: column; gap: var(--e4); position: sticky; top: var(--e4); }
@media (max-width: 1100px) {
  .painel { grid-template-columns: 1fr; }
  .painel-rail { position: static; }
}

/* ---- painel de TELA CHEIA — sem rolagem, posição fixa, troca por aba -------
   Um painel não é uma página, e a diferença não é estética: página rola e o
   leitor BUSCA; painel cabe numa tela e o leitor VARRE. Daí três consequências:

   · O orçamento é a viewport, não a página. Não existe "mais um gráfico" —
     existe trocar um gráfico por outro. É a restrição que faz painel bom, e é
     a que a página rolável remove sem avisar.
   · Posição fixa vira memória muscular. Quem abre a mesma tela todo dia acha
     "margem" no canto sem ler o rótulo. Grade que reflui destrói isso.
   · Navegação substitui rolagem: mais TELA, não mais altura.

   E uma válvula, que não é opcional: abaixo do piso de tamanho — ou quando o
   usuário dá zoom, que encolhe a viewport em CSS do mesmo jeito — a rolagem
   VOLTA. Painel que corta conteúdo no zoom reprova a WCAG 1.4.4 e 1.4.10, e
   "não rola" nunca vale mais que "dá para ler". */
.tela-fixa { height: 100dvh; display: grid; grid-template-rows: auto auto minmax(0, 1fr); overflow: hidden; }
.tela-fixa > * { min-height: 0; }

.painel-grade { display: grid; gap: var(--e3); height: 100%; padding: 0 var(--e5) var(--e4); }
/* sem isto, um item de grade se recusa a encolher abaixo do próprio conteúdo e
   estoura a linha — é a pegadinha clássica de grade com altura fixa. */
.painel-grade > * { min-height: 0; min-width: 0; }

/* barra discreta: ela aparece so quando ha o que rolar, e nao deve competir
   com o dado. */
.painel-grade > *::-webkit-scrollbar { width: 8px; height: 8px; }
.painel-grade > *::-webkit-scrollbar-thumb {
  background: var(--borda-forte); border-radius: var(--r-pill);
}
.painel-grade > *::-webkit-scrollbar-track { background: transparent; }
.painel-grade > * { scrollbar-width: thin; scrollbar-color: var(--borda-forte) transparent; }

/* No painel fixo o cartão não cresce: ele CONTÉM. O que não couber rola DENTRO
   dele — inclusive a tabela-gêmea, que é a garantia de chegar ao valor quando a
   cor falha e não pode ficar inalcançável só porque a página não rola.
   A regra é "a PÁGINA não rola", nunca "nada rola". */
.tela-fixa .fig, .tela-fixa .cartao { overflow: auto; }

/* **Uma superfície, três nomes.** `.cartao`, `.kpi` e `.fig` são a mesma coisa
   com conteúdos diferentes — um bloco, um número, um gráfico. Tinham três
   declarações idênticas de fundo/borda/raio/sombra e já haviam divergido: em
   06/09 o cartão virou translúcido e os outros dois ficaram opacos, o que
   aparece na tela como uma grade em que uns blocos deixam o fundo passar e
   outros não. Uma declaração só, e a divergência deixa de ser possível.

   **O translúcido também foi decidido olhando a tela**, não o documento. O
   padrão registrava o vidro como variante, com a ressalva de que 8% de tinta
   sobre o plano claro desenha um bloco cinza que compete com o dado. A Índices
   Financeiros já usava vidro em KPI e cartão — inclusive em tela de número — e
   o conjunto lê como uma superfície só. A ressalva não foi revogada: no claro a
   tinta é `--surface` a 72% (claro sobre claro), e no escuro `--ink` a 8%. */
.cartao, .kpi, .fig {
  background: color-mix(in srgb, var(--surface) 72%, transparent);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border: 1px solid var(--borda);
  border-radius: var(--r);
  box-shadow: var(--sombra);
}
.cartao { padding: var(--e5); }
@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) :is(.cartao, .kpi, .fig) {
    background: color-mix(in srgb, var(--ink) 8%, transparent);
  }
}
:root[data-theme="dark"] :is(.cartao, .kpi, .fig) {
  background: color-mix(in srgb, var(--ink) 8%, transparent);
}
.vidro { box-shadow: none; }

/* vidro com tabela dentro nao leva blur proprio: a coluna fixa ja tem o dela, e
   dois blurs aninhados bugam a renderizacao da coluna sticky ao rolar (texto
   fantasma, desalinhado). Um blur so, na coluna, resolve. */
.cartao:has(table), .vidro:has(table) { -webkit-backdrop-filter: none; backdrop-filter: none; }

/* =============================================================================
   8 · KPI / LADRILHO
   -----------------------------------------------------------------------------
   Contrato: rótulo · valor · delta (opcional) · tendência (opcional).
   Um número sozinho NÃO vira gráfico de uma barra — vira ladrilho.
   ============================================================================= */
.kpis { display: grid; gap: var(--e4); grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.kpi {
  padding: var(--e4) var(--e4) var(--e3);
  display: flex; flex-direction: column; gap: 2px;
}
.kpi .rotulo { font-size: var(--t-mini); }
/* valor de KPI usa algarismo PROPORCIONAL: tabular-nums em corpo grande deixa
   um "121" frouxo. Tabular é só para coluna que precisa alinhar. */
.kpi .valor  { font-size: var(--t-numero); font-weight: var(--peso-forte);
               line-height: var(--lh-apertado); letter-spacing: -.02em; }
.kpi .delta  { font-size: var(--t-menor); font-weight: var(--peso-medio); }
.kpi .delta small { font-weight: var(--peso-normal); color: var(--muted); }
/* A faísca vive fora do ladrilho também — no rail de um painel, numa célula de
   tabela. O dimensionamento morava só em `.kpi .spark`, e fora dali o SVG caía
   no tamanho intrínseco do viewBox: funcionava por coincidência quando os
   números batiam e encolhia calado quando não batiam. Agora a classe se vira
   sozinha, e a altura é ajustável sem CSS novo.
   Os argumentos `largura`/`altura` de `DV.faisca()` são o espaço de coordenadas
   do viewBox, não o tamanho na tela: quem manda no tamanho é o contêiner. */
.spark      { display: block; width: 100%; height: var(--spark-altura, 34px); }
.kpi .spark { margin-top: var(--e2); }
.sobe  { color: var(--delta-sobe); }
.desce { color: var(--delta-desce); }

/* medidor: o trilho é um passo mais claro da MESMA rampa, não um cinza */
.medidor { height: 10px; border-radius: var(--r-pill); background: var(--seq-100);
           overflow: hidden; margin-top: var(--e3); }
.medidor > i { display: block; height: 100%; background: var(--seq-500); }
.medidor.atencao > i { background: var(--atencao); }
.medidor.critico > i { background: var(--critico); }

/* =============================================================================
   9 · CHIP E SELO
   -----------------------------------------------------------------------------
   Status nunca é só cor: o chip SEMPRE carrega o rótulo. No tema claro
   "atenção" e "ruim" ficam abaixo de 3:1 por desenho — o texto é a mitigação.
   ============================================================================= */
.chip {
  display: inline-block; padding: 2px 9px; border-radius: var(--r-pill);
  font-size: var(--t-mini); font-weight: var(--peso-forte);
  letter-spacing: .04em; white-space: nowrap;
}
.chip.otimo   { background: var(--bom);            color: #fff; }
.chip.bom     { background: var(--bom-lavado);     color: var(--bom-texto); }
.chip.regular { background: var(--atencao-lavado); color: var(--atencao-texto); }
.chip.ruim    { background: var(--grave-lavado);   color: var(--grave-texto); }
.chip.critico { background: var(--critico);        color: #fff; }
.chip.neutro  { background: color-mix(in srgb, var(--ink) 10%, transparent); color: var(--ink-2); }

.selo {
  display: inline-block; padding: var(--e1) 9px; border-radius: var(--r-min);
  background: var(--atencao-lavado); color: var(--atencao-texto);
  font-size: var(--t-mini); font-weight: var(--peso-medio);
}

/* =============================================================================
   10 · TABELA
   -----------------------------------------------------------------------------
   Número à direita e tabular-nums não são preferência: sem os dois, comparar
   uma coluna exige ler dígito a dígito. Rótulo à esquerda, fixo ao rolar.
   ============================================================================= */
.tbl-scroll { overflow-x: auto; }
table {
  width: 100%;
  border-collapse: separate; border-spacing: 0;
  font-size: var(--t-menor);
  font-variant-numeric: tabular-nums;
}
caption {
  caption-side: top; text-align: left;
  font-size: var(--t-menor); color: var(--muted);
  padding-bottom: var(--e2);
}
th, td {
  padding: 7px var(--e3);
  text-align: right; white-space: nowrap;
  border-bottom: 1px solid var(--grade);
}
thead th {
  font-size: var(--t-mini); font-weight: var(--peso-forte);
  letter-spacing: var(--rastreio-caixa-alta); text-transform: uppercase;
  color: var(--muted);
  border-bottom: 1px solid var(--base-eixo);
}
th:first-child, td:first-child {
  text-align: left; min-width: 240px;
  position: sticky; left: 0; z-index: 2;
  /* opaca, e na cor da superfície: é o que de fato esconde a célula que passa
     por baixo ao rolar. Translúcida, o texto de trás aparece através dela. */
  background: var(--surface);
}
thead th:first-child { z-index: 3; }
tbody tr:last-child td { border-bottom: none; }
tbody tr:hover td { background: var(--surface-hover); }
td.centro { text-align: center; }
td.vazio  { color: var(--muted); text-align: center; }
/* coluna de TEXTO — alinha à esquerda e deixa quebrar. O padrão da tabela é
   número (direita, sem quebra); prosa alinhada à direita é difícil de ler
   porque a margem esquerda, que é onde o olho volta, fica irregular. */
th.txt, td.txt { text-align: left; white-space: normal; }
tr.total td { font-weight: var(--peso-forte); border-top: 1px solid var(--base-eixo); }
tr.destaque td { background: var(--acento-lavado); }

/* =============================================================================
   11 · CAMPOS E PARÂMETROS
   ============================================================================= */
.campo { display: flex; flex-direction: column; gap: var(--e1); }
.campo > label { font-size: var(--t-mini); font-weight: var(--peso-medio); color: var(--ink-2); }
.campo .ajuda  { font-size: var(--t-mini); color: var(--muted); }
.campo .erro   { font-size: var(--t-mini); color: var(--critico); font-weight: var(--peso-medio); }

input[type="text"], input[type="password"], input[type="number"],
input[type="date"], input[type="search"], input[type="email"], select, textarea {
  font: inherit;
  font-size: var(--t-corpo);
  padding: 7px var(--e3);
  color: var(--ink);
  background: var(--surface-2);
  border: 1px solid var(--borda);
  border-radius: var(--r-min);
  min-height: 34px;
}
input::placeholder, textarea::placeholder { color: var(--muted-2); }
input:disabled, select:disabled, textarea:disabled { opacity: .55; cursor: not-allowed; }
input[aria-invalid="true"], select[aria-invalid="true"] { border-color: var(--critico); }
input.num { text-align: right; font-variant-numeric: tabular-nums; }

/* a linha de parâmetros: UMA linha, acima de tudo que ela filtra. Nunca um
   filtro por gráfico, nunca um filtro dentro do cartão. */
.parametros {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--e3) var(--e4);
  padding: var(--e4);
  background: var(--surface);
  border: 1px solid var(--borda);
  border-radius: var(--r);
  margin-bottom: var(--e5);
}
.parametros .campo { min-width: 150px; }
.parametros .acoes { display: flex; gap: var(--e2); margin-left: auto; }

.marcador { display: inline-flex; align-items: center; gap: var(--e2);
            font-size: var(--t-menor); cursor: pointer; white-space: nowrap; }
.marcador input { margin: 0; cursor: pointer; }

/* =============================================================================
   12 · BOTÕES
   ============================================================================= */
.btn {
  font: inherit; font-size: var(--t-menor); font-weight: var(--peso-medio);
  padding: 7px var(--e4); min-height: 34px;
  border-radius: var(--r-min); cursor: pointer;
  border: 1px solid var(--borda);
  background: transparent; color: var(--ink);
  transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.btn:hover { border-color: var(--acento-texto); color: var(--acento-texto); }
/* preenchido COM texto em cima → --acento-texto, nunca --acento (ver § tokens).
   No tema escuro os dois são o mesmo #4db5f9, e a tinta escura dá 8,6:1. */
.btn.principal { background: var(--acento-texto); border-color: var(--acento-texto); color: var(--acento-ink); }
.btn.principal:hover { filter: brightness(1.06); color: var(--acento-ink); }
.btn.discreto { border-color: transparent; color: var(--muted); }
.btn.discreto:hover { background: var(--surface-hover); color: var(--ink); }
.btn.perigo { border-color: var(--critico); color: var(--critico); }
.btn.perigo:hover { background: var(--critico); color: #fff; }
.btn:disabled { opacity: .5; cursor: not-allowed; }

/* =============================================================================
   13 · GRÁFICO
   -----------------------------------------------------------------------------
   Todo gráfico é uma <figure> com <figcaption>. Não é estética: é o que garante
   que nenhum gráfico chegue à tela sem título e sem unidade. Ver REGRAS.md.
   ============================================================================= */
.fig {
  padding: var(--e4) var(--e5) var(--e3);
  margin: 0;
}
.fig > figcaption { margin-bottom: var(--e3); }
.fig-titulo  { font-size: var(--t-h3); font-weight: var(--peso-medio); line-height: var(--lh-apertado); }
.fig-resumo  { margin: var(--e1) 0 0; font-size: var(--t-menor); color: var(--ink-2);
               line-height: var(--lh-leitura); max-width: var(--medida-leitura); }
.fig-unidade { margin: var(--e1) 0 0; font-size: var(--t-mini); color: var(--muted); }
.fig svg     { display: block; width: 100%; overflow: visible; }

/* eixos e grade — fio de 1px, SÓLIDO. Tracejado lê como "projeção". */
.eixo-linha  { stroke: var(--base-eixo); stroke-width: 1; }
.grade-linha { stroke: var(--grade); stroke-width: 1; }
.eixo-texto  { fill: var(--muted); font-size: 11px; font-variant-numeric: tabular-nums; }
/* rótulo direto veste token de TEXTO, nunca a cor da série */
.marca-rotulo        { fill: var(--ink-2); font-size: 11px; font-weight: 600; }
.marca-rotulo-dentro { font-size: 11px; font-weight: 600; }

/* marcas */
.marca-linha { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.marca-area  { opacity: .10; }
.marca-ponto { stroke: var(--surface); stroke-width: 2; }  /* o anel de superfície */
.marca-alvo  { fill: transparent; cursor: pointer; }       /* área de toque ≥24px */

.legenda { display: flex; flex-wrap: wrap; gap: var(--e2) var(--e4);
           margin-top: var(--e3); font-size: var(--t-mini); color: var(--ink-2); }
.legenda-item { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.legenda-item i { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; }
.legenda-item b { color: var(--ink); font-weight: var(--peso-forte); }

/* barra empilhada 100% — a forma certa para parte-do-todo */
.faixa { display: flex; width: 100%; height: 12px; border-radius: var(--r-pill);
         overflow: hidden; background: var(--grade); margin-top: var(--e3); gap: 2px; }
.faixa > span { height: 100%; }

/* a tabela-gêmea: todo gráfico tem uma. É o que destrava o valor quando a cor
   falha (daltonismo, impressão) e o que autoriza série de baixo contraste. */
.fig details { margin-top: var(--e3); }
.fig summary { cursor: pointer; font-size: var(--t-mini); font-weight: var(--peso-medio);
               color: var(--acento-texto); }
.fig details table { margin-top: var(--e2); }
.fig details th:first-child, .fig details td:first-child {
  min-width: 0; position: static; background: none;
  -webkit-backdrop-filter: none; backdrop-filter: none;
}

.dica {
  position: fixed; z-index: 200; pointer-events: none;
  background: var(--tooltip-bg); color: var(--tooltip-ink);
  border-radius: 7px; padding: var(--e2) 11px;
  font-size: var(--t-mini); line-height: var(--lh-normal);
  box-shadow: var(--sombra-alta);
  opacity: 0; transition: opacity .12s;
  white-space: nowrap; transform: translate(-50%, -100%);
}
.dica[data-vis="1"] { opacity: 1; }
/* virada para baixo: nao cabendo acima do desenho, a dica vai para baixo do
   ponteiro -- e ai o pe dela deixa de ser a ancora, o topo passa a ser. */
.dica[data-abaixo="1"] { transform: translate(-50%, 0); }
.dica .linha { display: flex; align-items: center; gap: 6px; }
.dica .ponto { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.dica b { font-weight: var(--peso-forte); }

/* =============================================================================
   14 · ESTADOS — carregando, vazio, erro
   -----------------------------------------------------------------------------
   VAZIO e ERRO são respostas diferentes, e o padrão não deixa confundir as
   duas: "consultei e não há lançamento" contra "não consegui consultar". Um
   erro vestido de vazio faz alguém concluir que o mês não teve receita — e
   conclusão errada tirada de tela que não reclamou é o modo de falha mais caro
   que existe. Por isso eles não se parecem, e por isso `estado: 'erro'` exige
   mensagem.

   Nos três, o cabeçalho FICA. Título, resumo e unidade são o que diz o que
   está faltando; sem eles, sobra um vazio anônimo.
   ============================================================================= */
.fig-estado {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--e2); text-align: center;
  min-height: 168px; padding: var(--e5) var(--e4);
  border: 1px dashed var(--borda-forte);
  border-radius: var(--r);
  background: var(--surface-2);
}
.fig-estado .titulo-estado { font-size: var(--t-menor); font-weight: var(--peso-medio); color: var(--ink-2); }
.fig-estado .detalhe-estado { font-size: var(--t-mini); color: var(--muted);
                              max-width: 46ch; line-height: var(--lh-leitura); }
/* o erro NÃO herda a cara do vazio: traço sólido, faixa à esquerda e tinta
   própria. A diferença é o que impede a leitura errada. */
.fig-estado.erro {
  border-style: solid; border-color: var(--critico);
  border-left-width: 3px;
  background: var(--surface-2);
}
.fig-estado.erro .titulo-estado { color: var(--critico-texto); }

/* carregando: segura o desenho anterior APAGADO — nunca um esqueleto piscando,
   que causa salto de layout e tira do leitor a referência que ele tinha na
   tela. O bloco de estado em si não apaga: ele é o que restou para ler. */
[aria-busy="true"] > svg,
[aria-busy="true"] > .legenda,
[aria-busy="true"] > .faixa,
[aria-busy="true"] > details { opacity: .45; transition: opacity .15s ease; }
/* "atualizando…" só quando há mesmo um desenho anterior por baixo. No primeiro
   carregamento o bloco de estado já diz que está carregando, e repetir a mesma
   informação em dois lugares é o começo de ninguém ler nenhum dos dois. */
[aria-busy="true"]:has(> svg, > .faixa) > figcaption::after {
  content: 'atualizando…';
  display: block; margin-top: var(--e1);
  font-size: var(--t-mini); color: var(--muted);
}

/* =============================================================================
   15 · IMPRESSÃO
   -----------------------------------------------------------------------------
   O padrão citava "impressão" como uma das razões de a tabela-gêmea existir — e
   no papel ela não aparecia, porque `<details>` fechado não imprime. A garantia
   estava escrita e não valia. Some a isso que o navegador NÃO imprime cor de
   fundo por padrão: sem `print-color-adjust`, as barras somem e sobra um eixo
   vazio. Ou seja, os dois canais falhavam ao mesmo tempo, e em silêncio — o
   defeito só aparece em papel, onde ninguém testa.

   `dvgest-graficos.js` abre as tabelas no `beforeprint` e fecha no `afterprint`.
   Aqui fica o resto.
   ============================================================================= */
@media print {
  /* navegação e ação não são conteúdo — no papel não se clica em nada */
  .barra-app, .abas, .bg-blobs, .parametros .acoes, .dica { display: none !important; }

  /* fundo de marca precisa sair impresso: é ele que carrega o dado */
  * { -webkit-print-color-adjust: exact; print-color-adjust: exact; }

  body, .cartao, .fig, .kpi { background: #fff; box-shadow: none; }
  body { color: #000; }

  /* nada de figura, cartão ou ladrilho partido entre duas páginas */
  .fig, .cartao, .kpi, .fig-estado, tr { break-inside: avoid; page-break-inside: avoid; }
  h1, h2, h3 { break-after: avoid; page-break-after: avoid; }

  /* a tela fixa vira documento: no papel, "não rolar" não quer dizer nada */
  .tela-fixa { height: auto; overflow: visible; display: block; }
  .painel-grade { height: auto; display: block; }
  .painel-grade > * { margin-bottom: var(--e4); }
  [hidden] { display: none !important; }

  .fig details > summary { display: none; }
  .tbl-scroll { overflow: visible; }

  /* o endereço de um link vale no papel, onde não dá para passar o mouse */
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: var(--t-micro); color: #555; }
}

/* =============================================================================
   16 · UTILIDADES
   ============================================================================= */
.so-leitor {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.mudo   { color: var(--muted); }
.mudo-2 { color: var(--ink-2); }
[hidden] { display: none !important; }
