/* Telemapa — camada de movimento.
   ==========================================================================

   Princípios seguidos aqui, e por quê:

   1. MOVIMENTO TEM FUNÇÃO. Cada animação responde a uma pergunta do usuário:
      "carregou?", "meu clique funcionou?", "de onde veio esta tela?".
      Nada se move só para parecer moderno.

   2. RÁPIDO. 120ms para reação a toque, 200ms para transições de estado,
      320ms para entradas de página. Acima disso, a interface parece lenta —
      e lentidão percebida é pior que lentidão real.

   3. SAÍDA MAIS RÁPIDA QUE ENTRADA. O que sai não deve fazer o usuário esperar.

   4. ACELERAÇÃO NATURAL. ease-out para o que entra (chega rápido e assenta),
      ease-in para o que sai. Nada de `linear`, que parece mecânico.

   5. ESQUELETO SÓ ONDE HÁ ESPERA DE VERDADE. O site é renderizado no servidor:
      o conteúdo já vem pronto no HTML. Fingir carregamento em conteúdo pronto
      seria piorar a experiência. Esqueleto aqui é para imagem que ainda baixa e
      para o formulário de pagamento, que depende de um script externo.

   6. REDUCED MOTION É RESPEITADO DE VERDADE — no fim do arquivo, tudo desliga.
   ========================================================================== */

:root {
  --dur-rapida: 120ms;
  --dur:        200ms;
  --dur-lenta:  320ms;

  --ease-out:   cubic-bezier(.22, .9, .28, 1);
  --ease-in:    cubic-bezier(.55, 0, .9, .3);
  --ease-suave: cubic-bezier(.4, 0, .2, 1);
}

/* ==========================================================================
   1. Transição entre páginas
   Navegação normal, sem SPA: o próprio navegador faz o cruzamento onde há
   suporte. Onde não há, a página troca como sempre — nada quebra.
   ========================================================================== */
@view-transition { navigation: auto; }

::view-transition-old(root) { animation: sair-suave var(--dur-rapida) var(--ease-in) both; }
::view-transition-new(root) { animation: entrar-suave var(--dur-lenta) var(--ease-out) both; }

@keyframes entrar-suave {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
@keyframes sair-suave {
  from { opacity: 1; }
  to   { opacity: 0; }
}

/* ==========================================================================
   2. Entrada do conteúdo
   Cartões e blocos sobem levemente ao aparecer. O atraso escalonado dá ritmo
   de leitura — o olho segue a ordem em vez de receber tudo de uma vez.
   ========================================================================== */
.card,
.cat-tile,
.kpi,
.pacote,
.plano,
.fila-item {
  animation: surgir var(--dur-lenta) var(--ease-out) both;
}

@keyframes surgir {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

/* Escalonamento curto: passar de ~8 itens vira espera, não ritmo. */
.grid > *:nth-child(1),  .cat-grid > *:nth-child(1),  .kpi-row > *:nth-child(1)  { animation-delay: 0ms; }
.grid > *:nth-child(2),  .cat-grid > *:nth-child(2),  .kpi-row > *:nth-child(2)  { animation-delay: 30ms; }
.grid > *:nth-child(3),  .cat-grid > *:nth-child(3),  .kpi-row > *:nth-child(3)  { animation-delay: 60ms; }
.grid > *:nth-child(4),  .cat-grid > *:nth-child(4),  .kpi-row > *:nth-child(4)  { animation-delay: 90ms; }
.grid > *:nth-child(5),  .cat-grid > *:nth-child(5)  { animation-delay: 110ms; }
.grid > *:nth-child(6),  .cat-grid > *:nth-child(6)  { animation-delay: 130ms; }
.grid > *:nth-child(7),  .cat-grid > *:nth-child(7)  { animation-delay: 150ms; }
.grid > *:nth-child(n+8), .cat-grid > *:nth-child(n+8) { animation-delay: 165ms; }

/* Conteúdo que entra depois da dobra só anima quando chega perto da tela. */
.revelar {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity var(--dur-lenta) var(--ease-out), transform var(--dur-lenta) var(--ease-out);
}
.revelar.visivel { opacity: 1; transform: none; }

/* ==========================================================================
   3. Esqueleto (só onde há espera real)
   ========================================================================== */
.esqueleto,
.card-avatar.carregando,
.group-avatar.carregando {
  background: linear-gradient(
    100deg,
    var(--surface-2) 30%,
    color-mix(in srgb, var(--surface-3) 80%, var(--accent-soft)) 50%,
    var(--surface-2) 70%
  );
  background-size: 220% 100%;
  animation: brilho 1.4s ease-in-out infinite;
}

@keyframes brilho {
  from { background-position: 180% 0; }
  to   { background-position: -20% 0; }
}

.esqueleto-bloco { border-radius: var(--radius-sm); min-height: 1rem; }
.esqueleto-texto { height: .85rem; border-radius: 999px; margin-bottom: .5rem; }
.esqueleto-texto:last-child { width: 60%; }

/* Área do formulário de pagamento enquanto o SDK externo não chegou. */
.mp-esqueleto {
  display: grid; gap: .75rem; padding: 1.25rem;
  border: 1px dashed var(--line); border-radius: var(--radius);
}
.mp-esqueleto > div { height: 44px; }

/* ==========================================================================
   4. Imagens: aparecem quando terminam de baixar
   Sem isso, a foto "pisca" no lugar. O fundo pulsante ocupa o espaço exato
   (width/height estão no HTML), então não há salto de layout.
   ========================================================================== */
img.card-avatar,
img.group-avatar {
  opacity: 0;
  transition: opacity var(--dur) var(--ease-out);
}
img.card-avatar.carregada,
img.group-avatar.carregada { opacity: 1; }

/* ==========================================================================
   5. Reação ao toque e ao clique
   ========================================================================== */
.btn, .card, .cat-tile, .page-btn, .toolbar-btn, .subcat-chip, .catbar-link {
  transition:
    background var(--dur-rapida) var(--ease-suave),
    border-color var(--dur-rapida) var(--ease-suave),
    color var(--dur-rapida) var(--ease-suave),
    transform var(--dur-rapida) var(--ease-out),
    box-shadow var(--dur) var(--ease-out);
}
.btn:active, .page-btn:active, .toolbar-btn:active { transform: translateY(1px) scale(.99); }

/* Botão ocupado: o rótulo dá lugar a um giro, e o clique repetido é bloqueado.
   Serve a dois propósitos ao mesmo tempo — informar e proteger. */
.btn[data-ocupado="1"] {
  color: transparent !important;
  pointer-events: none;
  position: relative;
}
.btn[data-ocupado="1"]::after {
  content: "";
  position: absolute; inset: 0; margin: auto;
  width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid currentColor; border-top-color: transparent;
  color: #04121c;
  animation: girar .6s linear infinite;
}
.btn--ghost[data-ocupado="1"]::after { color: var(--text); }

@keyframes girar { to { transform: rotate(360deg); } }

/* ==========================================================================
   6. Barra de progresso da navegação
   Aparece no clique e some ao carregar a próxima página. É a resposta visual
   ao "cliquei e nada aconteceu" em conexão lenta.
   ========================================================================== */
.barra-progresso {
  position: fixed; top: 0; left: 0; z-index: 100;
  height: 3px; width: 0;
  background: linear-gradient(90deg, var(--accent), var(--gold));
  box-shadow: 0 0 10px var(--accent-ring);
  transition: width var(--dur-lenta) var(--ease-out), opacity var(--dur) var(--ease-in);
  pointer-events: none;
}
.barra-progresso.ativa { width: 78%; }
.barra-progresso.fim   { width: 100%; opacity: 0; }

/* ==========================================================================
   7. Mensagens e diálogos
   ========================================================================== */
.flash-area .alert { animation: descer var(--dur-lenta) var(--ease-out) both; }
.flash-area .alert.saindo { animation: subir var(--dur) var(--ease-in) both; }

@keyframes descer {
  from { opacity: 0; transform: translateY(-10px); }
  to   { opacity: 1; transform: none; }
}
@keyframes subir {
  from { opacity: 1; transform: none; max-height: 8rem; }
  to   { opacity: 0; transform: translateY(-8px); max-height: 0; margin: 0; padding-block: 0; }
}

.agegate { animation: aparecer var(--dur) var(--ease-out) both; }
.agegate-box { animation: crescer var(--dur-lenta) var(--ease-out) both; }

@keyframes aparecer { from { opacity: 0; } to { opacity: 1; } }
@keyframes crescer {
  from { opacity: 0; transform: scale(.96) translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* Menu de categorias abrindo */
.catmenu[open] .catmenu-panel { animation: abrir-menu var(--dur) var(--ease-out) both; }
@keyframes abrir-menu {
  from { opacity: 0; transform: translateY(-6px) scale(.99); }
  to   { opacity: 1; transform: none; }
}

/* ==========================================================================
   8. Espera com resultado incerto (Pix aguardando pagamento)
   Pulso lento e discreto: comunica "estou acompanhando" sem competir com o
   conteúdo nem sugerir que algo está errado.
   ========================================================================== */
.pix-aviso { animation: pulsar 2.4s var(--ease-suave) infinite; }
@keyframes pulsar {
  0%, 100% { opacity: 1; }
  50%      { opacity: .62; }
}

.pagamento-ok-icone { animation: comemorar var(--dur-lenta) var(--ease-out) both; }
@keyframes comemorar {
  0%   { opacity: 0; transform: scale(.5); }
  60%  { opacity: 1; transform: scale(1.12); }
  100% { transform: scale(1); }
}

/* Gráfico desenhando a linha ao aparecer */
.chart-line {
  stroke-dasharray: 1200;
  stroke-dashoffset: 1200;
  animation: desenhar 900ms var(--ease-out) forwards;
}
@keyframes desenhar { to { stroke-dashoffset: 0; } }

/* ==========================================================================
   9. Quem pediu menos movimento recebe menos movimento
   Não é "quase nada": é nada. A preferência existe por acessibilidade —
   enjoo, vertigem, distração — e meia-obediência não serve.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }

  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }

  .card, .cat-tile, .kpi, .pacote, .plano, .fila-item,
  .flash-area .alert, .agegate, .agegate-box { animation: none !important; opacity: 1 !important; transform: none !important; }

  .revelar { opacity: 1 !important; transform: none !important; }
  img.card-avatar, img.group-avatar { opacity: 1 !important; }
  .chart-line { stroke-dasharray: none; stroke-dashoffset: 0; animation: none; }
  .esqueleto, .pix-aviso, .btn[data-ocupado="1"]::after { animation: none !important; }
}

/* Painel do bot: a luz de sinal e os cartões da ficha não devem piscar para
   quem pediu menos movimento. */
@media (prefers-reduced-motion: reduce) {
  .bot-pulso-luz { animation: none !important; }
  .bot-acao { animation: none !important; opacity: 1 !important; transform: none !important; }
}
