/* ===========================================================================
   naveg-vida.css — movimento, resposta e luz.
   ---------------------------------------------------------------------------
   Escopo: AMBIENTE ISOLADO (_visual). Nao existe no repositorio.

   POR QUE ESTA CAMADA EXISTE, medido antes de escrever uma linha:

     631 regras CSS na tela do WhatsApp
      43 com :hover ......... 6,8%
      16 com :focus
       2 com :active ........ o painel nao devolve NADA ao ser clicado
       4 sombras que sao brilho, de 27 sombras

   Ou seja: nao faltava transicao (119 elementos ja tinham). Faltava RESPOSTA
   e faltava LUZ. Clicar em qualquer coisa parecia clicar numa imagem.

   O QUE ESTA CAMADA NAO FAZ — vem do `donts` do .impeccable/design.json:

     sem gradiente decorativo, sem glassmorphism/blur, sem texto-gradiente,
     sem matiz nova competindo com o teal, sem emoji.

   "Vibrante" aqui e feito com LUZ, nao com mais cores: o mesmo teal e as
   mesmas cores de status do DESIGN.md, usados com conviccao — brilho de acao,
   anel de foco, marcador de item ativo. O `do` do sistema manda criar
   profundidade subindo o TOM DA SUPERFICIE, e nao empilhando sombra; e manda
   manter o accent em ate 10% da tela. As duas regras sao respeitadas aqui.

   O movimento tem uma unica lei: MOVIMENTO SIGNIFICA ALGUMA COISA.
   Mensagem que chega desliza porque chegou. Lista que carrega nao desliza —
   carregar nao e evento. Nada anima em laco eterno, porque animacao continua
   numa sala de controle vira ruido de fundo que o olho aprende a ignorar,
   e ai o movimento que importa passa despercebido.
   =========================================================================== */

:root {
  /* Duracoes. A de estado e o `ease-standard` do design.json (0.2s); as
     outras duas existem porque tocar precisa ser mais rapido que pensar, e
     entrar precisa ser lento o bastante para o olho acompanhar.             */
  --nv-t-toque: 110ms;
  --nv-t-estado: 200ms;
  --nv-t-entrada: 300ms;

  /* Curvas. A padrao ja e usada pelas outras camadas — nao invento outra.
     A de entrada desacelera forte no fim: o elemento chega e assenta, em vez
     de parar seco.                                                          */
  --nv-curva: cubic-bezier(.4, 0, .2, 1);
  --nv-curva-entrada: cubic-bezier(.16, 1, .3, 1);

  /* Luz. Os dois primeiros sao tokens do design.json, copiados ao pe da
     letra: action-glow e focus-glow. O terceiro e o mesmo brilho de acao com
     mais alcance, para o estado pressionado.                                */
  --nv-brilho-acao: 0 0 16px rgba(45, 212, 191, .15);
  --nv-anel-foco: 0 0 0 3px rgba(45, 212, 191, .15);
  --nv-brilho-forte: 0 0 22px rgba(45, 212, 191, .28);
}

/* ===========================================================================
   0. A SALA CLAREIA UM TOM.
   ---------------------------------------------------------------------------
   O fundo era #0f172a — quase preto azulado. Sobe para um slate pastel, mais
   claro e menos saturado, sem sair do modo escuro.

   A ESCADA INTEIRA sobe junto, e nao so o fundo. O `do` do design.json manda
   criar profundidade subindo o tom da superficie: clarear so o fundo deixaria
   o card (#162032) MAIS ESCURO que a pagina e inverteria a profundidade —
   cada cartao viraria um buraco em vez de um plano acima.

   Ordem de luminancia preservada, do fundo para o topo:
     fundo -> cartao -> selecionado -> painel -> hover

   Vale so no tema escuro. O claro tem seletor proprio na pagina e nao e
   tocado por nenhuma linha daqui.

   As 52 paginas declaram os mesmos nomes de variavel, entao o site inteiro
   acompanha a partir deste unico lugar.
   =========================================================================== */
:root[data-theme="dark"] {
  --bg: #182130;
  --bg-card: #1f2937;
  --sel-bg: #232d3d;
  --bg-panel: #26313f;
  --bg-hover: #2c3849;
  --border: #2c4260;
  --border-light: #3b5578;
}

/* ===========================================================================
   1. RESPOSTA AO TOQUE — o buraco de 2 regras.
   ---------------------------------------------------------------------------
   Um controle que nao reage ao clique parece imagem. O afundamento e curto
   (110ms) e pequeno (3%): tem de ser sentido, nao visto.

   Escopo declarado: controles de barra, itens de lista e indicadores. Botao
   dentro de tabela e de formulario fica de fora — afundar celula de tabela
   embaralha a leitura de dados, que e o oposto do que uma sala de controle
   precisa.
   =========================================================================== */
.topbar button:active,
.topbar .btn:active,
.topbar-right button:active,
.tb-actions button:active,
.toolbar button:active,
.nv-ind:active,
.nv-seletor:active,
.conv-item:active,
.user-item:active,
.chat-header button:active,
.chat-input-area button:active,
.main-tab:active,
.msg-reply-btn:active,
.msg-eye:active,
.opa-alarm-close:active,
.msn-popup-btn:active {
  transform: scale(.97);
  transition-duration: var(--nv-t-toque);
}

/* Elementos que JA usam transform precisam compor, e nao substituir: escrever
   `scale()` sozinho apagaria o `translate` que os posiciona e eles pulariam
   de lugar no clique.                                                       */
/* A alca compoe centralizacao + aproximacao + toque numa expressao so, no
   naveg-dock.css. Aqui entra apenas o FATOR do toque — escrever `transform`
   de novo apagaria a lupa de proximidade dela.                             */
.nv-trilho-alca:active { --nv-toque: .94; }

/* ===========================================================================
   2. FOCO — um so anel, em tudo que recebe teclado.
   ---------------------------------------------------------------------------
   Eram 16 regras de foco em 631. Quem navega por teclado ficava perdido em
   toda tela que nao estivesse entre essas 16.

   `:focus-visible` e nao `:focus`: o anel aparece para o teclado e nao para o
   mouse, que ja tem o ponteiro como referencia.
   =========================================================================== */
button:focus-visible,
.btn:focus-visible,
[role="button"]:focus-visible,
a[href]:focus-visible,
select:focus-visible,
textarea:focus-visible,
input:not([type="hidden"]):focus-visible,
.conv-item:focus-visible,
.user-item:focus-visible {
  outline: 2px solid var(--accent, #2dd4bf);
  outline-offset: 2px;
  box-shadow: var(--nv-anel-foco);
}

/* Campo de texto em foco tambem acende — aqui vale `:focus`, porque digitar
   com o mouse tambem precisa mostrar onde o texto vai cair.                 */
.chat-input-area textarea:focus,
input[type="search"]:focus,
.search input:focus {
  border-color: var(--accent, #2dd4bf);
  box-shadow: var(--nv-anel-foco);
}

/* ===========================================================================
   3. LUZ NA ACAO PRINCIPAL
   ---------------------------------------------------------------------------
   Uma tela inteira em tom frio precisa de exatamente UM ponto que puxe o
   olho. E o enviar. O brilho e o token `action-glow` do design.json, sem
   invencao.
   =========================================================================== */
.send-btn,
.btn-primary,
.btn.primary {
  transition: background var(--nv-t-estado) var(--nv-curva),
              box-shadow var(--nv-t-estado) var(--nv-curva),
              transform var(--nv-t-toque) var(--nv-curva);
}
.send-btn:hover,
.btn-primary:hover,
.btn.primary:hover { box-shadow: var(--nv-brilho-acao); }

.send-btn:active,
.btn-primary:active,
.btn.primary:active {
  transform: scale(.94);
  box-shadow: var(--nv-brilho-forte);
}

/* ===========================================================================
   4. O PONTO DE CONEXAO FICA VIVO — sem piscar.
   ---------------------------------------------------------------------------
   Brilho ESTATICO, de proposito. A tentacao era faze-lo pulsar; seria movimento
   permanente dizendo "esta normal", e movimento que nunca para deixa de ser
   informacao. O pulso continua reservado ao alarme, que e onde ele significa
   "olhe para mim agora".

   A cor sai do proprio elemento — o mesmo verde `rgb(16,185,129)` que a tela
   ja usa para dizer ligado.
   =========================================================================== */
.status-dot.on { box-shadow: 0 0 9px rgba(16, 185, 129, .6); }

/* ===========================================================================
   5. PROFUNDIDADE POR TOM, NAO POR SOMBRA
   ---------------------------------------------------------------------------
   `do` do design.json, ao pe da letra: "criar profundidade subindo o tom da
   superficie, nao com sombra". O item sob o mouse sobe um degrau de tom e
   ganha uma marca teal na borda de ataque — dois canais, como o sistema pede
   para estado ativo (cor sozinha nao basta).
   =========================================================================== */
.conv-item,
.user-item {
  position: relative;
  transition: background var(--nv-t-estado) var(--nv-curva),
              transform var(--nv-t-toque) var(--nv-curva);
}
.conv-item:hover,
.user-item:hover { background: var(--bg-hover, #16212f); }

/* A marca de ativo cresce da borda, nao aparece pronta: 2px de teal que
   sobem de 0 a 100% da altura. E o unico lugar da lista onde o accent entra,
   o que mantem o teto de 10% de tela.                                       */
.conv-item::after,
.user-item::after {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  width: 2px;
  height: 0;
  background: var(--accent, #2dd4bf);
  border-radius: 0 2px 2px 0;
  transform: translateY(-50%);
  transition: height var(--nv-t-estado) var(--nv-curva);
  pointer-events: none;
}
.conv-item.active::after,
.user-item.active::after { height: 100%; }
.conv-item:hover::after,
.user-item:hover::after { height: 40%; }

/* ===========================================================================
   6. ENTRADA — anima o que CHEGA, nao o que carrega.
   ---------------------------------------------------------------------------
   As classes sao postas pelo naveg-vida.js, que distingue os dois casos:
   mensagem que chega agora desliza; conversa inteira que abre, nao. Sem essa
   distincao, trocar de conversa dispararia cinquenta animacoes ao mesmo tempo
   e a lista redesenhada a cada poll piscaria para sempre.
   =========================================================================== */
@keyframes nv-entra {
  from { opacity: 0; transform: translateY(9px); }
  to   { opacity: 1; transform: none; }
}
@keyframes nv-entra-lateral {
  from { opacity: 0; transform: translateX(-10px); }
  to   { opacity: 1; transform: none; }
}

.msg.nv-entrou { animation: nv-entra var(--nv-t-entrada) var(--nv-curva-entrada) both; }
.conv-item.nv-entrou,
.user-item.nv-entrou { animation: nv-entra-lateral 260ms var(--nv-curva-entrada) both; }

/* ===========================================================================
   7. NUMERO QUE MUDA SE ANUNCIA
   ---------------------------------------------------------------------------
   Contador que troca de valor sem avisar e informacao perdida: o operador so
   descobre na proxima vez que olhar. Um lampejo de 600ms resolve, e some.
   =========================================================================== */
@keyframes nv-lampejo {
  0%   { color: var(--accent, #2dd4bf); transform: translateY(-2px); }
  100% { transform: none; }
}
.nv-ind-n.nv-mudou,
.opa-n.nv-mudou { animation: nv-lampejo 600ms var(--nv-curva-entrada); }

/* ===========================================================================
   7b. LUPA — a fileira responde a aproximacao do ponteiro.
   ---------------------------------------------------------------------------
   O JS mede a distancia e escreve `--nv-lupa` (1 a ~1.22) em cada item. Aqui
   se decide o que isso significa.

   POR QUE `!important`, e nao especificidade: a secao 1 desta mesma camada ja
   escreve `transform` no `:active` desses botoes. Duas regras disputando a
   MESMA propriedade nao se resolvem com quem grita mais alto — se resolvem
   escolhendo um dono. O dono e esta regra, e o afundamento do clique entra
   como FATOR (`--nv-toque`), multiplicado junto. Sem isso, um dos dois efeitos
   apagaria o outro dependendo da ordem.

   `transform-origin: center` mantem o crescimento simetrico: com origem no
   canto o item pareceria escorregar em vez de crescer.                      */
.nv-lupa-item {
  transform: scale(calc(var(--nv-lupa, 1) * var(--nv-toque, 1))) !important;
  transform-origin: center center;
  transition: transform 130ms cubic-bezier(.2, 0, .2, 1);
  will-change: transform;
}
.nv-lupa-item:active { --nv-toque: .95; }

/* Item ativo/aberto continua reconhecivel enquanto a lupa passa: a escala
   nao substitui estado, so acrescenta relevo.                              */
.nv-lupa-item.aberto,
.nv-lupa-item.active { z-index: 2; }

/* ===========================================================================
   7c. PREENCHIMENTO A PARTIR DA ORIGEM — abas de secao.
   ---------------------------------------------------------------------------
   O JS informa onde o ponteiro entrou (`--nv-org-x/y`) e qual diametro cobre
   o botao a partir dali (`--nv-org-d`). O circulo cresce de 0 a 1 na mesma
   curva do componente original (0.5s, ease-out expo).

   `z-index: -1` no circulo, e nao 0: dentro do mesmo contexto de empilhamento
   um elemento POSICIONADO com z-index 0 pinta ACIMA do texto em fluxo — o
   preenchimento cobriria o rotulo. Com -1 ele fica atras do texto e ainda
   assim visivel, porque o proprio botao tem `background: none`.

   `overflow: hidden` prende o circulo dentro da aba; sem isso ele transborda
   sobre as vizinhas, ja que o diametro e maior que o botao por definicao.
   =========================================================================== */
.nv-origem {
  overflow: hidden;
  transition: color .3s cubic-bezier(.16, 1, .3, 1);
}

.nv-origem::before {
  content: "";
  position: absolute;
  z-index: -1;
  left: var(--nv-org-x, 50%);
  top: var(--nv-org-y, 50%);
  width: var(--nv-org-d, 0px);
  height: var(--nv-org-d, 0px);
  margin-left: calc(var(--nv-org-d, 0px) / -2);
  margin-top: calc(var(--nv-org-d, 0px) / -2);
  border-radius: 50%;
  background: var(--accent, #2dd4bf);
  transform: scale(0);
  transition: transform .5s cubic-bezier(.16, 1, .3, 1);
  pointer-events: none;
}
.nv-origem:hover::before,
.nv-origem:focus-visible::before,
.nv-origem:active::before { transform: scale(1); }

/* Sobre o teal, o rotulo vira tinta escura — o par `button-primary` do
   DESIGN.md (accent + accent-ink). Vale inclusive para a aba ativa, que ja
   era teal e ficaria invisivel sobre o proprio accent.                      */
.nv-origem:hover,
.nv-origem:focus-visible,
.nv-origem:active,
.nv-origem.active:hover { color: var(--accent-ink, #052723); }

/* Filhos (o badge de contagem) sobem para nao ficarem sob o circulo. */
.nv-origem > * { position: relative; z-index: 1; }

/* A opcao do popover precisa de `position: relative` — a aba ja tinha, esta
   nao. Sem isso o circulo se ancora num ancestral e escapa do botao.        */
.nv-pop-op.nv-origem { position: relative; }

/* E o fundo de hover dela SAI. Ele e opaco e o circulo mora atras do fundo
   do proprio botao (z-index -1), entao um cobriria o outro: ficariam os dois
   efeitos brigando e nenhum aparecendo direito. O preenchimento passa a ser
   a resposta ao mouse; o fundo antigo era a versao sem animacao dela.      */
.nv-pop-op.nv-origem:hover { background: transparent; }

/* A opcao do painel do "..." tem exatamente os dois mesmos problemas — nasce
   `static` e ganha fundo opaco no hover —, entao recebe exatamente o mesmo
   par de regras. Dois menus com a mesma funcao respondendo igual.          */
.nv-painel-op.nv-origem { position: relative; }
.nv-painel-op.nv-origem:hover { background: transparent; }

/* --- Dispensar, dentro dos alertas -------------------------------------- */
/* Aqui o circulo NAO e teal. Cada bloco carrega a cor do seu sistema (OPA
   laranja, IXC vermelho, menção amarelo) e um preenchimento teal no meio de
   um alerta laranja leria como outro assunto — justo no lugar onde a cor E a
   informacao. O botao herda `--nv-alerta-cor` do bloco que o contem.

   O texto vira o fundo da pagina: sobre laranja ou vermelho saturado, tinta
   escura e o unico jeito de continuar legivel.                              */
.nv-painel-alerta-x.nv-origem {
  position: relative;
  --nv-org-cor: var(--nv-alerta-cor, var(--accent, #2dd4bf));
}
.nv-painel-alerta-x.nv-origem::before { background: var(--nv-org-cor); }

/* As regras de hover que ja existiam pintavam borda e texto na cor do
   alerta. Com o fundo preenchido nessa MESMA cor, o texto sumiria — entao
   aqui elas cedem: borda solida e texto escuro.                             */
.nv-avisos .nv-painel-alerta[data-fonte] .nv-painel-alerta-x.nv-origem:hover,
.nv-painel-alerta-x.nv-origem:hover,
.nv-painel-alerta-x.nv-origem:focus-visible,
.nv-painel-alerta-x.nv-origem:active {
  color: var(--bg, #182130);
  border-color: var(--nv-org-cor);
}

/* ===========================================================================
   8. QUEM PEDIU MENOS MOVIMENTO CONTINUA TENDO TUDO — parado.
   ---------------------------------------------------------------------------
   Nenhuma informacao mora exclusivamente na animacao: o item ativo tem a
   marca teal, o foco tem o anel, o numero novo esta escrito. Desligar o
   movimento nao esconde nada.
   =========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .msg.nv-entrou,
  .conv-item.nv-entrou,
  .user-item.nv-entrou,
  .nv-ind-n.nv-mudou,
  .opa-n.nv-mudou { animation: none !important; }

  .topbar button:active,
  .nv-ind:active,
  .conv-item:active,
  .send-btn:active,
  .btn-primary:active { transform: none !important; }

  .conv-item::after,
  .user-item::after { transition: none !important; }

  /* A lupa some por completo — e o unico efeito daqui que existe so pelo
     movimento. Sem ele nao ha informacao perdida: nada do que ela mostra
     deixa de estar escrito.                                                */
  .nv-lupa-item {
    transform: none !important;
    transition: none !important;
  }

  /* O preenchimento continua acontecendo — ele e a resposta ao mouse, nao
     enfeite —, so que de uma vez, sem o crescimento.                       */
  .nv-origem::before { transition: none !important; }
  .nv-origem { transition: none !important; }
}

/* ====================================================== icones em glifo ===
   Os SVGs dos controles viraram Font Awesome (ver ICONES_FA em
   naveg-vida.js). Um detalhe nao sobrevive a troca sozinho: o SVG do
   "enviar" trazia stroke="#fff" FIXO no proprio path, entao desenhava
   branco sem depender do `color` do botao. O glifo herda currentColor, que
   ali resolve para preto. Esta regra devolve exatamente o que existia.

   MEDIDO, e o numero contraria o esperado: sobre o accent em repouso
   (#2dd4bf) o branco da contraste 1.86:1 — abaixo do piso de 3:1 para
   objeto grafico. O preto daria 11.28:1. O branco fica porque foi a
   escolha original e trocar cor nao era a tarefa; a decisao de corrigir o
   contraste e outra conversa, com o :hover (#2563eb) na conta.            */
.send-btn i { color: #fff; }

/* ========================================================= dialogo do painel
   Substitui a janela nativa do navegador (ver nvDialogo em naveg-vida.js).
   A nativa nao aceita estilo nenhum e ainda anuncia a origem — "127.0.0.1
   diz" no meio de um atendimento le como erro do sistema.

   Nasce escondido nao: nasce ja no ar, porque so existe no DOM enquanto
   estiver aberto. Quem o cria e o mesmo que o remove.                       */
.nv-dlg-fundo {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(3, 7, 18, .62);
  /* O desfoque diz "o que esta atras esta suspenso" sem escurecer a ponto de
     esconder o contexto do atendimento.                                     */
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  animation: nv-dlg-entra-fundo .16s ease both;
}

.nv-dlg {
  width: min(420px, 100%);
  max-height: calc(100vh - 40px);
  display: flex;
  flex-direction: column;
  overflow: hidden;

  background: var(--bg-panel, #0e1622);
  border: 1px solid var(--border-light, #28394f);
  border-radius: var(--r-card, 10px);
  box-shadow: 0 24px 60px rgba(0, 0, 0, .55);

  animation: nv-dlg-entra .2s cubic-bezier(.16, 1, .3, 1) both;
}

/* `--text-secondary` e nao `--text-muted`: MEDIDO, o muted desta pagina e
   #64748b e da 2,77:1 sobre o painel. O secondary da 5,13:1.               */
.nv-dlg-cab {
  padding: 11px 14px;
  border-bottom: 1px solid var(--border, #1e2b3d);
  color: var(--text-secondary, #93a4bb);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
}

.nv-dlg-corpo {
  padding: 16px 14px;
  overflow-y: auto;
}

/* A ordem dos tokens importa: o chat.html NAO define `--text-primary` — quem
   define e o whatsapp.html. Com so o primary aqui, o valor caia no fallback
   claro e no modo claro dava texto branco sobre fundo branco: 1,17:1. O
   `--text` existe nas duas paginas e nos dois temas.                        */
.nv-dlg-msg {
  color: var(--text, var(--text-primary, #e7eef7));
  font-size: 13.5px;
  line-height: 1.5;
  /* As mensagens vem com quebras de linha proprias (o menu de ping tem uma
     lista inteira dentro). `pre-wrap` preserva as quebras sem transformar o
     texto em linha unica nem em bloco monoespacado.                         */
  white-space: pre-wrap;
}

.nv-dlg-campo {
  width: 100%;
  margin-top: 12px;
  padding: 9px 11px;
  box-sizing: border-box;

  /* `--bg` e nao `--bg-card`: no modo claro o card e branco, igual ao painel,
     e o campo sumia dentro do dialogo. O fundo da pagina e um degrau abaixo
     nos dois temas, entao o campo sempre le como recuado.                   */
  background: var(--bg, #121c2b);
  border: 1px solid var(--border, #1e2b3d);
  border-radius: var(--nv-ctrl-r, 7px);
  color: var(--text, var(--text-primary, #e7eef7));
  font: inherit;
  font-size: 13.5px;
}
/* O anel segue o accent vigente em vez de um teal fixo — a paleta pode
   trocar a cor de destaque e o foco tem de acompanhar.                      */
.nv-dlg-campo:focus {
  outline: none;
  border-color: var(--accent, #2dd4bf);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent, #2dd4bf) 18%, transparent);
}

.nv-dlg-rodape {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 12px 14px;
  border-top: 1px solid var(--border, #1e2b3d);
}

/* O botao segue o mesmo desenho dos controles de barra: mesma altura, mesmo
   raio, e o mesmo preenchimento de origem (esta em ORIGEM_ALVOS).           */
.nv-dlg-btn {
  position: relative;
  min-height: var(--nv-ctrl-h, 32px);
  padding: 0 16px;

  background: transparent;
  border: 1px solid var(--border-light, #28394f);
  border-radius: var(--nv-ctrl-r, 7px);
  color: var(--text-secondary, #93a4bb);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.nv-dlg-btn:focus-visible {
  outline: 2px solid var(--accent, #2dd4bf);
  outline-offset: 2px;
}

/* O OK e a acao esperada: ganha a borda do accent para o olho achar sem ler.
   O preenchimento por cima continua sendo o mesmo dos outros botoes.        */
.nv-dlg-ok {
  border-color: var(--accent, #2dd4bf);
  color: var(--accent, #2dd4bf);
}

@keyframes nv-dlg-entra-fundo {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes nv-dlg-entra {
  from { opacity: 0; transform: translateY(8px) scale(.98); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .nv-dlg-fundo, .nv-dlg { animation: none; }
}
