/* VizBird -- ajustes sobre o Bootstrap 5.3. Painel usado muito no celular,
   entao tudo aqui prioriza legibilidade em tela pequena. */

/* O Windows nao tem emoji de bandeira: 🇧🇷 aparece como as letras "BR".
   Como boa parte do publico usa Windows, embarcamos a fonte Twemoji apenas
   com as bandeiras (76 KB, hospedada aqui -- sem CDN de terceiro).
   `unicode-range` limita a fonte aos "regional indicator symbols", entao ela
   nunca substitui outro texto da pagina. */
@font-face {
    font-family: "Twemoji Country Flags";
    src: url("/vendor/fonts/TwemojiCountryFlags.woff2") format("woff2");
    unicode-range: U+1F1E6-1F1FF;
    font-display: swap;
}

:root {
    --vb-up: #198754;
    --vb-down: #dc3545;

    /* Fundos do treemap -- ver .vb-tm-* mais abaixo. */
    --vb-tm-up: #cfe6d6;
    --vb-tm-down: #f3d5d5;
    --vb-tm-flat: #dcdcd8;
    --vb-tm-new: #cfe0f2;

    /* TINTA sobre esses fundos. Precisa ser token pelo mesmo motivo que o
       fundo é: a legibilidade é uma relação entre os dois, e fixar um dos
       lados enquanto o outro muda com o tema garante que em algum tema o
       texto suma. Foi o que aconteceu -- os fundos viraram tokens e a tinta
       ficou para trás, escura sobre bloco escuro no escuro e no matrix. */
    --vb-tm-ink: #1c1c1a;
    --vb-tm-ink-up: #14683c;
    --vb-tm-ink-down: #9b2226;
    /* Aresta interna dos blocos (ver .vb-tm-cell): também é relação com o
       fundo -- escura sobre pastel claro, clara sobre bloco escuro. */
    --vb-tm-edge: rgba(28, 28, 26, .14);
    --vb-tm-edge-hover: rgba(28, 28, 26, .38);

    /* Como o número grande é pintado. Token porque DOIS lugares precisam do
       mesmo resultado: o card de verdade e a amostra do seletor de temas.
       Uma prévia pintada à mão deixa de corresponder ao painel na primeira
       alteração -- o cliente escolhe um tema e recebe outro.

       ATENÇÃO: `var()` dentro de uma custom property é substituído NO
       ELEMENTO QUE A DECLARA, não onde ela é usada. Declarado só aqui, este
       token congela a cor do tema CLARO e todo descendente herda o valor já
       resolvido -- inclusive a amostra do seletor, que carrega o próprio
       `data-vb-theme`. Era por isso que o número da prévia do escuro saía
       escuro sobre fundo escuro. Cada tema precisa REDECLARAR o token para
       que o `var()` seja resolvido no contexto dele. */
    --vb-metric-ink: var(--bs-body-color);
    --vb-metric-glow: none;
}

/* --- Temas -------------------------------------------------------------
   `data-bs-theme` (no <html>) comanda os componentes do Bootstrap; o
   `data-vb-theme` ao lado dele distingue temas que compartilham a mesma base
   -- escuro e matrix são os dois `dark` para o Bootstrap e não poderiam ser
   diferenciados sem ele.

   Aqui só moram SUPERFÍCIE e TINTA. As cores de série (fontes de tráfego,
   comparativo de blogs) NÃO estão no CSS: elas vêm do PHP, porque o mesmo hex
   precisa valer no Chart.js, no HTML e nos rótulos -- e porque a paleta escura
   tem passos próprios, validados contra a superfície escura, não a clara
   escurecida. Ver Support\Dimensions. */

/* O tema claro mora no `:root`, mas precisa de bloco PRÓPRIO por causa da
   armadilha do `var()` em custom property (ver a nota no :root): a amostra do
   claro dentro de uma página escura herdaria a tinta do escuro -- número claro
   sobre fundo branco, o espelho exato do defeito oposto. Só os tokens que
   dependem de `var()` precisam estar aqui; os literais já herdam certo. */
[data-vb-theme="light"] {
    --vb-metric-ink: var(--bs-body-color);
}

[data-vb-theme="dark"] {
    --bs-body-bg: #16181c;
    --bs-body-color: #e6e6e2;
    --bs-body-bg-rgb: 22, 24, 28;
    --bs-tertiary-bg: #101216;
    --bs-secondary-bg: #23262c;
    --bs-border-color: #2f333a;
    --bs-secondary-color: #a9aab0;
    --vb-up: #0ca30c;
    --vb-down: #e66767;
    --vb-tm-up: #1f4030;
    --vb-tm-down: #4a2626;
    --vb-tm-flat: #2b2e34;
    --vb-tm-new: #1e3550;
    --vb-tm-ink: #ececea;
    --vb-tm-ink-up: #79dfa4;
    --vb-tm-ink-down: #ff9d9d;
    --vb-tm-edge: rgba(255, 255, 255, .10);
    --vb-tm-edge-hover: rgba(255, 255, 255, .34);
    /* Redeclarado para o `var()` resolver com a tinta DESTE tema -- ver a
       nota no :root. Sem esta linha a amostra do escuro herda a cor do
       claro. */
    --vb-metric-ink: var(--bs-body-color);
}

/* Matrix: mesma base escura, tinta de fósforo verde.
   O verde é a MOLDURA (superfície, texto, bordas) -- as séries dos gráficos
   continuam com a paleta validada, senão o painel inteiro viraria um degradê
   de verdes em que nenhuma série se distingue de outra. É decoração da
   moldura, nunca do dado. */
[data-vb-theme="matrix"] {
    --bs-body-bg: #05100a;
    --bs-body-color: #b9f5cd;
    --bs-body-bg-rgb: 5, 16, 10;
    --bs-tertiary-bg: #030b06;
    --bs-secondary-bg: #0b2015;
    --bs-border-color: #124a2c;
    --bs-secondary-color: #6fd39a;
    --bs-primary: #21d67a;
    --bs-link-color: #4dea9b;
    --bs-link-hover-color: #8df3c1;
    --vb-up: #21d67a;
    --vb-down: #ff6b6b;
    --vb-tm-up: #14432a;
    --vb-tm-down: #4a2020;
    --vb-tm-flat: #123123;
    --vb-tm-new: #10323f;
    /* A tinta do matrix é a do próprio tema: rótulo de bloco é MOLDURA, não
       dado -- pintá-lo de verde aqui não repete o erro de pintar série. */
    --vb-tm-ink: #cdf7dd;
    --vb-tm-ink-up: #5fe39b;
    --vb-tm-ink-down: #ff9d9d;
    --vb-tm-edge: rgba(185, 245, 205, .12);
    --vb-tm-edge-hover: rgba(185, 245, 205, .38);
    --vb-metric-ink: #4dea9b;
    --vb-metric-glow: 0 0 12px rgba(33, 214, 122, .35);
}

[data-vb-theme="matrix"] body,
[data-vb-theme="matrix"] .vb-card {
    font-feature-settings: "tnum";
}


/* A navbar e os cards são branco fixo no claro; nos escuros seguem a
   superfície do tema. */
[data-vb-theme="dark"] .navbar.bg-white,
[data-vb-theme="matrix"] .navbar.bg-white {
    background: var(--bs-tertiary-bg) !important;
    border-color: var(--bs-border-color) !important;
}

.vb-card {
    border: 1px solid var(--bs-border-color);
    border-radius: .75rem;
    background: var(--bs-body-bg);
}

/* --- Card que mede OUTRA COISA -------------------------------------------
   Os três cards de topo são uma métrica (visualizações) em três janelas de
   tempo; o quarto é presença simultânea. Quatro cards idênticos em fila
   prometem série temporal, e a unidade escrita embaixo do número chega tarde
   demais para desfazer essa promessa.

   A distinção é SUPERFÍCIE E BORDA, não posição: no celular a fila vira uma
   grade 2×2 e "o último da linha" deixa de existir. A tinta é a mesma do
   `.vb-live-dot` (--vb-up), que neste produto já é o vocabulário de "ao vivo",
   então o card não estreia uma cor -- ele herda a que o ponto pulsante ao lado
   do título já usa. */
.vb-card-outra-metrica {
    border-color: color-mix(in srgb, var(--vb-up) 42%, var(--bs-border-color));
    background: color-mix(in srgb, var(--vb-up) 5%, var(--bs-body-bg));
}

/* Numero grande dos cards de topo e do tempo real */
.vb-metric {
    font-size: 2rem;
    font-weight: 700;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
    color: var(--vb-metric-ink);
    text-shadow: var(--vb-metric-glow);
}

@media (min-width: 768px) {
    .vb-metric { font-size: 2.5rem; }
}

/* Unidade da métrica, logo abaixo do número. Discreta mas SEMPRE presente:
   é o que impede o usuário de comparar visualizações com pessoas online. */
/* Numeral dos passos da página inicial. */
.vb-passo {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    height: 2.5rem;
    border-radius: 50%;
    background: var(--bs-primary-bg-subtle);
    color: var(--bs-primary);
    font-weight: 700;
}

.vb-unit {
    font-size: .75rem;
    font-weight: 600;
    color: var(--bs-secondary-color);
    text-transform: lowercase;
    margin-top: -.15rem;
    margin-bottom: .15rem;
}

.vb-delta        { font-size: .95rem; font-weight: 600; }
.vb-delta.up     { color: var(--vb-up); }
.vb-delta.down   { color: var(--vb-down); }
.vb-delta.flat   { color: var(--bs-secondary-color); }

.vb-label {
    font-size: .8rem;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--bs-secondary-color);
}

/* Ponto pulsante do "visitantes agora" */
.vb-live-dot {
    display: inline-block;
    width: .6rem; height: .6rem;
    border-radius: 50%;
    background: var(--vb-up);
    animation: vb-pulse 1.6s infinite;
}

@keyframes vb-pulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: .25; }
}

@media (prefers-reduced-motion: reduce) {
    .vb-live-dot { animation: none; }
}

/* --- Barra de participação (fonte do tráfego) ---
   Segmentos separados por 2px da própria superfície, para que fatias vizinhas
   nunca se toquem; pontas arredondadas só nas extremidades da barra. */
.vb-share {
    display: flex;
    height: 1.5rem;
    border-radius: .375rem;
    overflow: hidden;
    background: var(--bs-secondary-bg);
}

.vb-share span {
    display: block;
    height: 100%;
    box-shadow: 0 0 0 2px var(--bs-body-bg);
}

.vb-share span:first-child { border-radius: .375rem 0 0 .375rem; box-shadow: none; }
.vb-share span:last-child  { border-radius: 0 .375rem .375rem 0; }
.vb-share span:only-child  { border-radius: .375rem; box-shadow: none; }

/* --- Ranking com barra (países) ---
   Uma série só, hue único: a barra codifica magnitude, não identidade. */
.vb-rank { list-style: none; margin: 0; padding: 0; }

.vb-rank li + li { margin-top: .6rem; }

.vb-rank .vb-rank-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: .5rem;
    font-size: .9rem;
    margin-bottom: .2rem;
}

/* O link herda a cor do texto e só se sublinha no hover: numa lista de dez
   itens, dez links azuis competiriam com as barras, que são o dado. */
.vb-rank-link {
    color: inherit;
    text-decoration: none;
}

.vb-rank-link:hover,
.vb-rank-link:focus-visible {
    color: var(--bs-primary);
    text-decoration: underline;
}

/* O ícone de link externo só aparece no hover/foco: presente o tempo todo, dez
   ícones viram ruído; ausente por completo, nada indica que abre fora. */
.vb-rank-link .bi {
    font-size: .75em;
    opacity: 0;
    transition: opacity .12s ease;
}

.vb-rank-link:hover .bi,
.vb-rank-link:focus-visible .bi {
    opacity: .7;
}

.vb-rank .vb-rank-bar {
    height: .5rem;
    border-radius: .25rem;
    background: var(--bs-secondary-bg);
    overflow: hidden;
}

.vb-rank .vb-rank-bar > span {
    display: block;
    height: 100%;
    border-radius: .25rem;
    background: #2a78d6;
}

.vb-num { font-variant-numeric: tabular-nums; }

/* --- Mapa com halos pulsantes ---
   A camada de pulso não recebe eventos: o tooltip do Chart.js continua
   funcionando no canvas de baixo. */
.vb-map-wrap { position: relative; }

.vb-map-pulse {
    position: absolute;
    inset: 0;
    pointer-events: none;
}

/* --- Blocos arrastáveis do painel --- */
.vb-block-inner { position: relative; }

/* Os controles do bloco (esconder e arrastar) são posicionados de forma
   absoluta no canto superior direito -- e é exatamente ali que mora o canto
   direito do cabeçalho de cada card: o rótulo do período, o selo "sem
   localização", o ícone de ajuda. Os dois ocupavam o mesmo pixel.

   A solução é o cabeçalho RESERVAR o espaço, e não os controles saírem dali:
   o canto é o lugar aprendido para controles de card, e movê-los para dentro
   do conteúdo faria a alça de arrastar competir com o dado.

   Uma regra só, aplicada ao primeiro filho de todo card de bloco, em vez de
   ajustar 13 cabeçalhos à mão: um bloco novo nasce com o espaço reservado,
   sem ninguém precisar lembrar disso.

   4rem = os dois botões (1,9rem cada) mais as frestas, descontando o padding
   do card. Vale só até a altura do cabeçalho, porque é só ali que os
   controles passam. */
.vb-block .vb-card > :first-child {
    padding-right: 4rem;
}

/* Em telas de toque os controles ficam sempre visíveis (não há hover), então
   o espaço reservado também precisa valer sempre -- e ali a largura útil é
   menor, o que torna a sobreposição mais provável, não menos. */
@media (max-width: 575.98px) {
    .vb-block .vb-card > :first-child {
        padding-right: 3.4rem;
    }
}

/* A alça só aparece no hover/foco: o painel é para ler, não para arrumar.
   Arrastar exige a alça (Sortable `handle`) -- sem isso, no celular qualquer
   deslize sobre um card sequestraria a rolagem da página. */
button.vb-drag {
    position: absolute;
    top: .45rem;
    right: .45rem;
    z-index: 3;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.9rem;
    height: 1.9rem;
    padding: 0;
    border: 0;
    border-radius: .4rem;
    background: var(--bs-secondary-bg);
    color: var(--bs-secondary-color);
    opacity: 0;
    cursor: grab !important;
    transition: opacity .15s ease;
}

.vb-block:hover button.vb-drag,
button.vb-drag:focus-visible { opacity: 1; }

button.vb-drag:active { cursor: grabbing !important; }

/* Botão de esconder, ao lado da alça. Mesma aparência e mesma regra de
   revelação: os dois só aparecem quando o usuário está mexendo no bloco, para
   não competir com o dado dentro do card. */
.vb-hide {
    position: absolute;
    top: .45rem;
    right: 2.55rem;
    z-index: 3;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.9rem;
    height: 1.9rem;
    padding: 0;
    border: 0;
    border-radius: .4rem;
    background: var(--bs-secondary-bg);
    color: var(--bs-secondary-color);
    opacity: 0;
    cursor: pointer;
    transition: opacity .15s ease;
}

.vb-block:hover .vb-hide,
.vb-hide:focus-visible { opacity: 1; }

.vb-hide:hover { color: var(--bs-danger); }

/* Em telas de toque não existe hover: os controles ficam sempre visíveis,
   discretos. */
@media (hover: none) {
    button.vb-drag,
    button.vb-hide { opacity: .45; }
}

/* Alça de redimensionar: faixa fina na borda direita do card.
   Aparece junto com os outros controles do bloco, pela mesma razão -- só
   quando o usuário está mexendo, para não competir com o dado. */
/* A faixa COMEÇA ABAIXO dos botões do topo, e essa folga não é estética.
   Antes ela subia até 12% da altura e encostava na alça de arrastar, que é
   maior e mora no mesmo canto: mirando ali, quem ficava sob o mouse era a alça
   de mover -- e o cursor virava mãozinha em vez de seta de redimensionar. Dois
   controles diferentes não podem dividir o mesmo pixel; a folga de 3rem é a
   altura ocupada pelos botões mais uma fresta.

   `button.vb-resize` e não `.vb-resize`: o seletor de elemento é preciso para
   ganhar do reboot do Bootstrap, que pinta cursor em botão com especificidade
   maior que a de uma classe sozinha. */
button.vb-resize {
    position: absolute;
    top: 3rem;
    right: -3px;
    bottom: 1rem;
    z-index: 3;
    width: 14px;
    height: auto;
    padding: 0;
    border: 0;
    border-radius: 999px;
    background: var(--bs-secondary-bg);
    opacity: 0;
    /* `!important` aqui é deliberado, não preguiça de especificidade.
       O reboot do Bootstrap declara `button:not(:disabled) { cursor: pointer }`
       -- mesma especificidade de `button.vb-resize`, então o desempate vira
       ordem de carga, que depende de qual folha o navegador aplicou por
       último. Empate decidido por ordem é frágil: qualquer mudança na ordem
       dos <link> devolve a mãozinha, e nada no CSS explica o motivo. O cursor
       do arraste (no body) já usa `!important` pela mesma razão -- e é por
       isso que aquele funcionava enquanto este não. */
    cursor: col-resize !important;
    transition: opacity .15s ease, background-color .15s ease;
}

/* Área de agarre maior que o desenho: 14px de faixa é pouco para mira de
   mouse, e a mira falhando devolve o cursor do que está por baixo -- o card,
   ou a alça de arrastar. O retângulo invisível estende o alvo sem engordar a
   faixa, que precisa continuar discreta. */
button.vb-resize::before {
    content: "";
    position: absolute;
    inset: -6px -10px;
}

/* Trilho: duas linhas verticais no meio da faixa, o desenho que divisória de
   planilha usa. Sem ele a faixa é uma barra lisa, que lê como decoração --
   o usuário não tenta arrastar o que não parece agarrável. */
button.vb-resize::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 6px;
    height: 22px;
    transform: translate(-50%, -50%);
    border-left: 2px solid var(--bs-body-bg);
    border-right: 2px solid var(--bs-body-bg);
    opacity: .8;
}

.vb-block:hover button.vb-resize,
button.vb-resize:focus-visible { opacity: .9; }

button.vb-resize:hover,
button.vb-resize.vb-resizing { background: var(--bs-primary); opacity: 1; }

/* Enquanto arrasta, o cursor vale para a página toda: sair do card com o botão
   apertado não pode trocar o cursor nem selecionar texto. */
body.vb-resizing-on,
body.vb-resizing-on * {
    cursor: col-resize !important;
    user-select: none;
}

@media (hover: none) {
    button.vb-resize { display: none !important; }
}

/* Espaço reservado onde o bloco vai cair */
.vb-block-ghost > .vb-block-inner {
    outline: 2px dashed var(--bs-primary);
    outline-offset: -2px;
    border-radius: .75rem;
    opacity: .35;
}

.vb-block-drag > .vb-block-inner {
    box-shadow: 0 .75rem 2rem rgba(0, 0, 0, .18);
    border-radius: .75rem;
}

@media (prefers-reduced-motion: reduce) {
    .vb-drag { transition: none; }
}

/* --- Treemap de países ---
   Cada bloco é posicionado em % pelo layout squarified calculado no servidor
   (Support\Treemap), então o mesmo HTML serve em qualquer largura de tela. */
.vb-treemap {
    position: relative;
    width: 100%;
    min-height: 15rem;
    border-radius: .5rem;
    overflow: hidden;
    /* Habilita `cqw`/`cqh` nas células: o tamanho do rótulo é proporcional à
       área do bloco, e a área só existe em px no navegador (as coordenadas são
       %). `size` e não `inline-size` porque a altura também entra no cálculo --
       um bloco largo e baixo não pode receber fonte que não cabe. */
    container-type: size;
}

.vb-tm-cell {
    position: absolute;
    /* Frestas feitas com borda transparente: separam blocos vizinhos sem
       alterar a geometria, então a área continua proporcional ao valor.

       3px em vez de 2px porque a fresta precisa funcionar no pior caso, que
       é o comum: quando todos os países têm a MESMA direção de variação
       (todos "novos", por exemplo), os blocos vizinhos ficam da mesma cor e
       sem separação visível o treemap inteiro vira uma mancha só. */
    border: 3px solid transparent;
    background-clip: padding-box;
    border-radius: .5rem;
    overflow: hidden;
    /* Contorno de 1px por dentro: garante a aresta mesmo quando o vizinho tem
       cor idêntica e a fresta sozinha não basta para o olho separar. */
    box-shadow: inset 0 0 0 1px var(--vb-tm-edge);
    transition: filter .15s ease, box-shadow .15s ease;
}

/* Só o bloco que abre drill-down anuncia clique. "Outros países" é agregado
   da cauda e não tem tela própria. */
.vb-tm-clicavel { cursor: pointer; }

.vb-tm-cell:hover,
.vb-tm-cell:focus-visible {
    filter: brightness(1.06);
    /* No hover a aresta escurece: mostra qual bloco está sob o cursor sem
       mexer no tamanho, que aqui é dado (área ∝ tráfego) e não decoração. */
    box-shadow: inset 0 0 0 2px var(--vb-tm-edge-hover);
    outline: none;
}

/* Cor = direção da variação. Tons suaves para o texto continuar legível e
   para o bloco não competir com os gráficos ao lado. */
/* Fundos pastéis dos blocos do treemap: a cor é a DIREÇÃO da variação, e
   precisa ser um fundo recessivo sobre o qual bandeira e percentual se leiam.
   No claro isso é um pastel claro; no escuro, o mesmo pastel vira a área mais
   luminosa do card e o texto escuro em cima some. São tokens por tema, e não
   uma cor só, pelo mesmo motivo do mapa: cor de fundo depende da superfície
   embaixo dela. */
.vb-tm-up    { background: var(--vb-tm-up); }
.vb-tm-down  { background: var(--vb-tm-down); }
.vb-tm-flat  { background: var(--vb-tm-flat); }
.vb-tm-new   { background: var(--vb-tm-new); }

/* --- Países ao vivo: bolhas à deriva -----------------------------------
   Área ∝ tráfego (o raio vem da raiz, calculado no JS). As posições são
   empacotadas uma vez na montagem; aqui só mora a aparência e a deriva. */
.vb-bubbles {
    position: relative;
    width: 100%;
    min-height: 24rem;
    overflow: hidden;
}

/* DUAS camadas por bolha, e a separação é obrigatória: uma animação CSS
   sobrescreve qualquer `transform` escrito pelo JS no mesmo elemento.

   .vb-bubble    (pai)   -> desvio do cursor, via transform escrito pelo JS
   .vb-bubble-in (filho) -> deriva contínua, via animação CSS

   Numa camada só, um movimento anularia o outro. */
.vb-bubble {
    position: absolute;
    border-radius: 50%;
    /* Ponteiro de clique: o clique dá o empurrão e abre o drill-down do país,
       então o cursor precisa anunciar que há o que clicar. */
    cursor: pointer;
    will-change: transform;
}

/* --- Comparativo entre blogs ---
   O marcador colorido acompanha o NOME, nunca o substitui: três cores da
   paleta ficam abaixo de 3:1 de contraste com o fundo e a identidade da série
   não pode depender só da cor. */
.vb-compare-dot {
    display: inline-block;
    width: .65rem;
    height: .65rem;
    border-radius: 50%;
    margin-right: .45rem;
    vertical-align: baseline;
}

.vb-compare .vb-num {
    font-variant-numeric: tabular-nums;
}

/* Palco da prévia do selo: fundo neutro para o formato claro e o escuro serem
   julgados em condições parecidas com as de um blog. */
.vb-widget-preview {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 4.5rem;
    padding: .5rem;
    border-radius: .5rem;
    background: repeating-linear-gradient(45deg,
        #f4f4f2, #f4f4f2 6px, #ececea 6px, #ececea 12px);
}

/* Quem desenha bandeira PRECISA declarar a fonte embarcada.
   Sem ela, o Windows não tem emoji de bandeira e 🇵🇭 aparece como as letras
   "PH" -- foi o que aconteceu no feed, que nasceu com classe própria e sem
   esta declaração. Os seletores ficam juntos justamente para que o próximo
   bloco com bandeira seja acrescentado aqui. */
.vb-country-flag,
.vb-feed-flag,
.vb-flag {
    line-height: 1;
    font-family: "Twemoji Country Flags", "Noto Color Emoji", sans-serif;
}

.vb-country-flag {
    font-size: 1.35rem;
}

/* Pulso da bolha clicada.
   Anima `scale`, que é uma propriedade INDEPENDENTE de `transform`. Por isso
   convive com o translate que o JS escreve neste mesmo elemento (o empurrão) e
   com a deriva do filho -- os três movimentos coexistem sem se sobrescrever,
   que era o problema resolvido pelas duas camadas. */
.vb-bubble-pulso {
    animation: vb-bubble-pulso .45s cubic-bezier(.34, 1.56, .64, 1) 1;
}

@keyframes vb-bubble-pulso {
    0%   { scale: 1; }
    35%  { scale: 1.14; }
    100% { scale: 1; }
}

.vb-bubble-in {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .05rem;
    line-height: 1.1;
    text-align: center;
    box-shadow: inset 0 0 0 1px var(--vb-tm-edge);
    /* `filter` e `box-shadow` na transição, NUNCA width/height/left/top: os
       dois movimentos rodam em transform (compostos na GPU) para não disparar
       layout a cada quadro com dezenas de bolhas na tela. */
    transition: filter .15s ease, box-shadow .15s ease;
    animation-name: vb-bubble-deriva;
    animation-timing-function: ease-in-out;
    animation-iteration-count: infinite;
    animation-direction: alternate;
}

.vb-bubble:hover .vb-bubble-in,
.vb-bubble:focus-visible .vb-bubble-in {
    filter: brightness(1.06);
    box-shadow: inset 0 0 0 2px var(--vb-tm-edge-hover);
    /* Congela a deriva sob o cursor: sem isso sobra um vaivém de poucos pixels,
       suficiente para o ponteiro escorregar de uma bolha pequena antes do
       clique. */
    animation-play-state: paused;
}

.vb-bubble:focus-visible {
    outline: none;
}

/* O tamanho vem inline, proporcional ao raio: bandeira fixa transbordaria na
   bolha pequena e sumiria na grande. */
.vb-bubble-flag  { line-height: 1; font-family: "Twemoji Country Flags", "Noto Color Emoji", sans-serif; }
.vb-bubble-share { font-size: .8rem; font-weight: 700; color: var(--vb-tm-ink); font-variant-numeric: tabular-nums; }
.vb-bubble-name  {
    font-size: .72rem;
    font-weight: 600;
    color: var(--vb-tm-ink);
    max-width: 92%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Amplitude pequena de propósito: o suficiente para a tela parecer viva, longe
   de fazer o usuário perseguir um alvo móvel com o cursor ou o dedo. */
@keyframes vb-bubble-deriva {
    from { transform: translate(calc(var(--vb-dx, 3px) * -1), var(--vb-dy, 3px)); }
    to   { transform: translate(var(--vb-dx, 3px), calc(var(--vb-dy, 3px) * -1)); }
}

@media (prefers-reduced-motion: reduce) {
    /* Sem deriva e sem empurrão -- o JS também não liga o laço do clique nesse
       caso; aqui é só a garantia do lado do CSS. */
    .vb-bubble { transform: none !important; animation: none; }
    .vb-bubble-in { animation: none; transition: none; }
    .vb-bubble:hover .vb-bubble-in { filter: none; }
}

.vb-tm-inner {
    height: 100%;
    padding: .4rem .5rem;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    text-align: center;
    gap: .1rem;
    line-height: 1.15;
}

.vb-tm-flag  { font-size: 1.35rem; line-height: 1; font-family: "Twemoji Country Flags", "Noto Color Emoji", sans-serif; }

/* A bandeira ENCOLHE conforme o bloco, em vez de sumir: sem ela o retângulo
   vira área colorida sem identidade, e o usuário precisa passar o mouse item
   por item para descobrir o que é cada um.

   O tamanho real vem inline, em unidades de container, e é CONTÍNUO -- quanto
   maior a fatia, maior a bandeira e o percentual. As regras por faixa abaixo
   são o FALLBACK para navegador sem `cqw`/`cqh`: lá a declaração inline é
   inválida e estas assumem, em degraus.

   O padding acompanha, senão a bandeira do bloco mínimo é cortada: com ~30px
   de largura, `.5rem` de cada lado não deixa espaço para nada. */
.vb-tm-n-medio .vb-tm-inner { padding: .15rem; gap: 0; }
.vb-tm-n-medio .vb-tm-flag  { font-size: 1rem; }
.vb-tm-n-medio .vb-tm-share { font-size: .8rem; }

/* Sem padding e sem folga: no bloco mínimo cada pixel precisa sobrar para a
   bandeira e o percentual, que são obrigatórios em qualquer tamanho. */
.vb-tm-n-compacto .vb-tm-inner { padding: 0; gap: 0; }
.vb-tm-n-compacto .vb-tm-flag  { font-size: .75rem; }
.vb-tm-n-compacto .vb-tm-share { font-size: .65rem; line-height: 1; }
.vb-tm-name  { font-size: .78rem; font-weight: 600; color: var(--vb-tm-ink); }
.vb-tm-share { font-size: .95rem; line-height: 1.05; font-weight: 700; color: var(--vb-tm-ink); font-variant-numeric: tabular-nums; }

.vb-tm-delta { font-size: .72rem; font-weight: 600; }
.vb-tm-delta.up   { color: var(--vb-tm-ink-up); }
.vb-tm-delta.down { color: var(--vb-tm-ink-down); }

@media (prefers-reduced-motion: reduce) {
    .vb-tm-cell { transition: none; }
    .vb-tm-cell:hover, .vb-tm-cell:focus-visible { filter: none; }
}

/* --- Bandeiras dimensionadas por volume ---
   Cada bandeira é um emoji cujo font-size codifica a magnitude. Alinhadas
   pela base e centralizadas, para as pequenas não ficarem soltas no meio. */
.vb-flags {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: center;
    gap: .5rem .6rem;
    line-height: 1;
    min-height: 8rem;
}

.vb-flag {
    cursor: default;
    transition: transform .15s ease;
    /* Emoji de bandeira não renderiza no Windows; a fonte Twemoji do sistema
       ou o fallback textual (ex.: "BR") assumem o lugar. */
    font-family: "Twemoji Country Flags", "Noto Color Emoji", "Apple Color Emoji", sans-serif;
}

.vb-flag:hover,
.vb-flag:focus-visible {
    transform: scale(1.12);
    outline: none;
}

@media (prefers-reduced-motion: reduce) {
    .vb-flag { transition: none; }
    .vb-flag:hover, .vb-flag:focus-visible { transform: none; }
}

/* Marcador de cor da legenda: a identidade nunca depende só dele --
   o rótulo em texto vem sempre ao lado. */
.vb-dot {
    display: inline-block;
    width: .7rem;
    height: .7rem;
    border-radius: .2rem;
    vertical-align: -1px;
}

.vb-snippet {
    font-family: var(--bs-font-monospace);
    font-size: .85rem;
    word-break: break-all;
}


/* --- Seletor de tema (tela de preferências) --- */
.vb-theme-option {
    display: block;
    height: 100%;
    padding: .65rem .75rem;
    border: 1px solid var(--bs-border-color);
    border-radius: .6rem;
    cursor: pointer;
}

/* O destaque responde ao RADIO, não a uma classe vinda do servidor: a classe
   só mudaria depois de salvar, e o usuário fica sem retorno no instante do
   clique -- que é justamente quando ele precisa saber que a escolha pegou.

   Duas regras para o mesmo estado: `:has()` pinta na hora em qualquer
   navegador atual, e `.is-active` (escrita pelo JS, e também pelo servidor na
   carga) cobre quem não tem `:has`. Não é redundância inútil -- sem a segunda,
   um Safari antigo não daria retorno nenhum. */
.vb-theme-option.is-active,
.vb-theme-option:has(input:checked) {
    border-color: var(--bs-primary);
    /* Anel de 2px, não 1px: em cima de uma borda de 1px da mesma cor, um anel
       fino some e o cartão selecionado fica quase igual aos outros. */
    box-shadow: 0 0 0 2px var(--bs-primary);
    background: color-mix(in srgb, var(--bs-primary) 7%, transparent);
}

/* Foco de teclado é ESTADO DIFERENTE de seleção, e precisa continuar visível
   sobre o cartão já selecionado. */
.vb-theme-option:focus-within {
    outline: 2px solid var(--bs-body-color);
    outline-offset: 2px;
}

/* A amostra carrega o próprio `data-vb-theme`, então herda as variáveis
   daquele tema mesmo dentro de uma página pintada com outro. É o que permite
   ver o escuro sem sair do claro. */
/* A amostra é um card em miniatura: superfície, borda e tinta do tema à
   esquerda, paleta de série à direita. Sem o número, os dois temas escuros
   ficam idênticos -- eles compartilham a mesma paleta de série, e o que os
   separa é a moldura. */
.vb-theme-swatch {
    display: flex;
    gap: .5rem;
    align-items: center;
    justify-content: space-between;
    margin: .4rem 0;
    padding: .45rem .5rem;
    border: 1px solid var(--bs-border-color);
    border-radius: .4rem;
    background: var(--bs-body-bg);
    /* A chuva do matrix (abaixo) é posicionada dentro desta caixa. */
    position: relative;
    overflow: hidden;
}

/* Mesmos tokens do número grande do painel: a prévia não tem como divergir
   do card de verdade. */
.vb-theme-swatch-num {
    font-weight: 700;
    font-size: .95rem;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    color: var(--vb-metric-ink);
    text-shadow: var(--vb-metric-glow);
}

.vb-theme-swatch-bars { display: flex; gap: .25rem; align-items: center; }

.vb-theme-swatch i {
    display: block;
    width: 1.25rem;
    height: .5rem;
    border-radius: 999px;
}

/* Um fiapo da chuva, só no matrix: é o traço mais reconhecível do tema e o
   único que a superfície sozinha não comunica. Decoração pura -- fica atrás
   do conteúdo, não recebe clique e some para quem pediu menos movimento
   (é estática, mas some junto para a prévia continuar coerente com o painel,
   onde a chuva de verdade não existe nesse caso). */
[data-vb-theme="matrix"].vb-theme-swatch::before {
    content: "ｱ7ﾂ ｶ2ﾐ ﾖ9ｷ ﾈ4ﾗ";
    position: absolute;
    inset: 0;
    padding: 0 .5rem;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: .55rem;
    letter-spacing: .35em;
    line-height: 1.5;
    word-break: break-all;
    color: #21d67a;
    opacity: .32;
    pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
    [data-vb-theme="matrix"].vb-theme-swatch::before { content: none; }
}


/* --- Visitas ao vivo ---------------------------------------------------
   Lista curta e densa: cada linha é uma chegada. A altura é fixa e rola por
   dentro, senão o bloco cresceria e encolheria a cada polling -- e um card que
   muda de altura empurra tudo o que está abaixo dele na página. */
.vb-feed {
    max-height: 22rem;
    overflow-y: auto;
    font-size: .875rem;
}

.vb-feed-item {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .4rem 0;
    border-bottom: 1px solid var(--bs-border-color);
}

.vb-feed-item:last-child { border-bottom: 0; }

.vb-feed-flag { font-size: 1.05rem; line-height: 1; }

/* O caminho é o que interessa e o que é longo: ele fica com a sobra e corta
   com reticências, em vez de quebrar a linha e desalinhar o resto. */
.vb-feed-path {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--bs-font-monospace);
    font-size: .8125rem;
}

.vb-feed-site {
    flex: 0 0 auto;
    color: var(--bs-secondary-color);
    font-size: .75rem;
}

.vb-feed-when {
    flex: 0 0 auto;
    color: var(--bs-secondary-color);
    font-size: .75rem;
    font-variant-numeric: tabular-nums;
}

/* Entrada da linha nova: ela desliza do topo uma vez, para o olho perceber que
   ALGO chegou sem precisar comparar a lista com a de 10 segundos atrás. Uma
   animação só, na inserção -- nada pulsa continuamente aqui. */
/* A linha nova ABRE ESPAÇO em vez de aparecer pronta: a altura cresce de 0
   até o tamanho final, então as linhas de baixo deslizam suavemente em vez de
   saltar de uma vez. Era o que fazia o movimento parecer brusco -- o conteúdo
   inteiro pulava a cada chegada, e com este volume de tráfego isso acontece
   várias vezes por segundo.

   `grid-template-rows` de 0fr a 1fr é o truque que permite animar altura sem
   saber o valor final; `max-height` exigiria um chute, e chute errado corta a
   linha ou deixa a animação truncada. */
@keyframes vb-feed-entra {
    from {
        max-height: 0;
        padding-top: 0;
        padding-bottom: 0;
        opacity: 0;
        transform: translateY(-.25rem);
    }
    to {
        max-height: 3rem;
        padding-top: .4rem;
        padding-bottom: .4rem;
        opacity: 1;
        transform: none;
    }
}

.vb-feed-nova {
    /* `max-height` e não `height`: a linha é sempre de uma linha só (o caminho
       corta com reticências), então 3rem é teto seguro -- e como a animação
       não usa `fill-mode`, o valor volta a `none` no fim e nada fica cortado.
       A altura ANIMADA é o que faz as linhas de baixo deslizarem em vez de
       saltar; com este volume de tráfego, o salto acontecia várias vezes por
       segundo e era o que dava a sensação de movimento brusco. */
    overflow: hidden;
    /* Mais longa (.55s) e com desaceleração no fim: o olho acompanha a chegada
       em vez de só constatar o resultado. */
    animation: vb-feed-entra .55s cubic-bezier(.22, .61, .36, 1);
}

@media (prefers-reduced-motion: reduce) {
    .vb-feed-nova { animation: none; }
}


/* --- Recorde do dia ----------------------------------------------------
   A fita é ESTADO: fica o dia inteiro, marcando que hoje passou o melhor dia
   dos últimos 30. A comemoração é EVENTO e acontece uma vez só (o JS decide,
   via localStorage). Misturar as duas faria a tela festejar a cada F5, e um
   festejo repetido vira ruído -- exatamente o que esvazia o aviso. */
.vb-recorde {
    position: relative;
    overflow: hidden;
    border-color: var(--vb-up);
}

.vb-recorde-fita {
    position: absolute;
    top: .5rem;
    right: .5rem;
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    padding: .1rem .45rem;
    border-radius: 999px;
    background: color-mix(in srgb, var(--vb-up) 15%, transparent);
    color: var(--vb-up);
    font-size: .7rem;
    font-weight: 600;
    line-height: 1.4;
}

/* Comemoração: um brilho atravessa o card UMA vez. Sem confete e sem
   biblioteca -- o produto não carrega dependência de terceiro para enfeite, e
   um efeito discreto sobrevive melhor à repetição (o recorde volta a
   acontecer, e o cliente não pode passar a temer o painel festejando). */
@keyframes vb-recorde-brilho {
    from { transform: translateX(-120%) skewX(-18deg); }
    to   { transform: translateX(320%) skewX(-18deg); }
}

.vb-recorde-comemora::after {
    content: "";
    position: absolute;
    inset: 0 auto 0 0;
    width: 35%;
    background: linear-gradient(90deg,
        transparent,
        color-mix(in srgb, var(--vb-up) 22%, transparent),
        transparent);
    animation: vb-recorde-brilho 1.1s ease-out 1;
    pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
    .vb-recorde-comemora::after { animation: none; content: none; }
}


/* --- Chegada de país novo ----------------------------------------------
   Bolha de país que não tinha tráfego no período anterior. A animação é de
   ENTRADA: roda uma vez e acaba. Um pulso perpétuo competiria com a deriva e
   com a leitura do rótulo -- e um país que chegou não precisa continuar
   chamando atenção para sempre.

   O anel mora num ::after do PAI (.vb-bubble), não do filho: o filho já carrega
   a animação de deriva, e duas animações no mesmo elemento se sobrescrevem --
   é a mesma razão de existirem duas camadas por bolha. */
@keyframes vb-bubble-chega {
    from { transform: scale(.4); opacity: 0; }
    60%  { transform: scale(1.06); opacity: 1; }
    to   { transform: scale(1); opacity: 1; }
}

@keyframes vb-bubble-onda {
    from { transform: scale(1); opacity: .55; }
    to   { transform: scale(1.85); opacity: 0; }
}

.vb-bubble-nova {
    /* `scale` é propriedade independente de `transform`, então a entrada não
       atropela o empurrão do clique que o JS escreve em `transform`. */
    animation: vb-bubble-chega .5s cubic-bezier(.22, .61, .36, 1) both;
    animation-delay: var(--vb-nova-atraso, 0s);
}

.vb-bubble-nova::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 50%;
    border: 2px solid var(--vb-up);
    animation: vb-bubble-onda 1.1s ease-out 2 both;
    animation-delay: var(--vb-nova-atraso, 0s);
    pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
    .vb-bubble-nova { animation: none; }
    .vb-bubble-nova::after { animation: none; content: none; }
}


/* --- Mapa de calor: dia da semana x hora -------------------------------
   A intensidade é OPACIDADE sobre a superfície do card, não uma lista de
   hexes: assim os três temas funcionam com uma definição só -- sobre fundo
   claro a célula fica mais escura, sobre fundo escuro fica mais acesa. */
:root { --vb-heat-rgb: 42, 120, 214; }

[data-vb-theme="dark"] { --vb-heat-rgb: 57, 135, 229; }
[data-vb-theme="matrix"] { --vb-heat-rgb: 33, 214, 122; }

/* 24 colunas não cabem em 340px. Rolar é melhor que encolher: célula menor que
   o dedo deixa de ter alvo de toque, e o tooltip é a única forma de ler o
   número exato. */
.vb-heat-wrap { overflow-x: auto; }

.vb-heat {
    border-collapse: separate;
    border-spacing: 2px;
    width: 100%;
    min-width: 34rem;
}

.vb-heat th {
    font-size: .7rem;
    font-weight: 500;
    color: var(--bs-secondary-color);
    white-space: nowrap;
}

/* Centralizado, e não à esquerda: com todas as 24 horas rotuladas, cada número
   precisa ficar sobre a SUA coluna. Alinhado à esquerda ele encosta na borda e
   passa a parecer o rótulo da coluna anterior. */
.vb-heat thead th {
    text-align: center;
    padding-bottom: .15rem;
    /* Menor que o resto do cabeçalho: são 24 números lado a lado, e aqui o
       tamanho é o que decide se a faixa lê como marcação ou como texto. */
    font-size: .65rem;
    font-variant-numeric: tabular-nums;
}

/* O "h" do canto é a unidade da linha inteira. Discreto de propósito: é
   legenda, não dado. */
.vb-heat-unidade {
    text-align: right !important;
    opacity: .6;
}

.vb-heat th[scope="row"] { padding-right: .4rem; text-align: right; }

.vb-heat td {
    height: 1.35rem;
    min-width: 1rem;
    border-radius: .2rem;
    /* A fresta entre células vem do border-spacing: sem ela, uma faixa de
       horas parecidas vira uma mancha só e não dá para contar as horas. */
    background: var(--bs-secondary-bg);
}

/* Sem medição não é zero: a conta pode não existir naquele período, e pintar
   isso como "nenhum tráfego" seria inventar dado. Mesma regra do "sem medição"
   do gráfico de presença. */
.vb-heat-sem {
    background: repeating-linear-gradient(45deg,
        var(--bs-secondary-bg), var(--bs-secondary-bg) 3px,
        transparent 3px, transparent 6px) !important;
}

.vb-heat-melhor {
    outline: 2px solid var(--bs-body-color);
    outline-offset: 1px;
}

.vb-heat-legenda {
    display: inline-flex;
    align-items: center;
    gap: .2rem;
}

.vb-heat-legenda i {
    display: inline-block;
    width: 1.1rem;
    height: .55rem;
    border-radius: .15rem;
}

/* --- Chuva de caracteres (tema matrix) ---------------------------------
   Atrás do card "Agora", bem apagada. Segue a regra do tema: o verde é a
   MOLDURA, nunca o dado -- por isso ela mora atrás do único card que não
   desenha série nenhuma, e não atrás de um gráfico, onde competiria com a
   leitura.

   O canvas só é emitido no matrix (ver a view), então estas regras não têm
   efeito nos outros temas. */
.vb-rain-host {
    position: relative;
    /* Sem isto a chuva vaza pelos cantos arredondados do card. */
    overflow: hidden;
}

.vb-rain {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    /* O card inteiro continua clicável (popover do glossário) por cima. */
    pointer-events: none;
    opacity: .3;
}

/* O canvas é o primeiro filho; o conteúdo só fica por cima dele se estiver
   posicionado. Sem esta regra o número desapareceria atrás da chuva. */
.vb-rain-host > *:not(.vb-rain) { position: relative; }

@media (prefers-reduced-motion: reduce) {
    .vb-rain { display: none; }
}
