/* ============================================================
   One Life · camada de movimento (D-061)

   ## Por que é um arquivo separado

   `app.css` é o design system: cor, espaço, tipografia, forma. Movimento é
   outra dimensão, e misturá-lo ali significaria mexer em 900 linhas que já
   funcionam para acrescentar comportamento. Aqui tudo é ADITIVO — nenhuma
   regra deste arquivo muda tamanho, posição final, cor ou fonte de nada. Se
   este arquivo sumir, o produto continua idêntico, só parado.

   ## As quatro regras que este arquivo segue

   1. **Nada anima duas vezes.** Entrada é `both` + `animation-delay` e acaba;
      não há laço, exceto onde o laço É a informação (o pulso do "ao vivo", o
      brilho do carregando).
   2. **Nada anima layout.** Só `opacity`, `transform` e `filter` — as três
      propriedades que a GPU resolve sem recalcular a página. Animar `height`,
      `top` ou `margin` engasga em celular fraco, que é justamente o aparelho
      de quem mais usa isto.
   3. **Nada anima na horizontal.** O §PWA trancou o zoom e escondeu o overflow
      horizontal; um `translateX` de 20px numa lista cria barra de rolagem
      lateral no celular. Todo movimento é vertical ou de escala.
   4. **Tudo respeita `prefers-reduced-motion`.** Não é acessibilidade
      decorativa: parte de quem usa um app de autocontrole tem sensibilidade a
      movimento, e a última coisa que a tela precisa fazer é atrapalhar.

   ## Duração

   Entrada 380 ms, reação ao toque 120 ms, transição de estado 200 ms. Acima de
   ~450 ms a interface passa a parecer lenta em vez de fluida; abaixo de ~90 ms
   o olho não vê movimento, vê um salto.
   ============================================================ */

:root{
  /* Curvas nomeadas pelo que fazem, não pelos números.
     `--saida` é simétrica (some sem chamar atenção);
     `--entrada` desacelera no fim (chega e assenta);
     `--mola` passa um pouquinho do ponto e volta — só para toque e alternância,
     onde a resposta física é o recado. */
  --entrada: cubic-bezier(.22,1,.36,1);
  --saida:   cubic-bezier(.4,0,.2,1);
  --mola:    cubic-bezier(.34,1.56,.64,1);
  --t-toque: 120ms;
  --t-estado: 200ms;
  --t-entrada: 380ms;
}

/* ============================================================
   1. ENTRADA — o conteúdo chega em vez de aparecer
   ============================================================ */

@keyframes olSobe{
  from{opacity:0;transform:translate3d(0,10px,0)}
  to{opacity:1;transform:none}
}
@keyframes olSurge{
  from{opacity:0;transform:scale(.985)}
  to{opacity:1;transform:none}
}
@keyframes olCresceLinha{
  from{transform:scaleX(0);opacity:0}
  to{transform:scaleX(1);opacity:1}
}

/* `.ol-entra` é posto pelo animacoes.js quando o elemento entra na área
   visível de `.main` (que é o único scroller do shell). O CSS sozinho não
   consegue saber disso, e animar tudo no load faria a página inteira tremer de
   uma vez — inclusive o que está três telas abaixo e ninguém está olhando. */
.ol-anima{opacity:0}
.ol-entra{animation:olSobe var(--t-entrada) var(--entrada) both}

/* O escalonamento é o que transforma "seis caixas aparecendo" em "uma lista
   sendo apresentada". Passo de 45 ms: some o suficiente para ser sequência,
   curto o suficiente para o último não parecer atrasado. */
.ol-entra.d1{animation-delay:45ms}
.ol-entra.d2{animation-delay:90ms}
.ol-entra.d3{animation-delay:135ms}
.ol-entra.d4{animation-delay:180ms}
.ol-entra.d5{animation-delay:225ms}
.ol-entra.d6{animation-delay:270ms}
.ol-entra.d7{animation-delay:315ms}
.ol-entra.d8{animation-delay:360ms}

/* O cabeçalho da página e o menu não esperam observador: estão sempre visíveis
   no primeiro quadro, e atrasá-los faria a tela nascer vazia. */
.phead{animation:olSobe 320ms var(--entrada) both}
.side{animation:olSurge 300ms var(--saida) both}

/* KPI: a régua de 26px do topo esquerdo cresce em vez de já estar lá.
   É o `::before` QUE JÁ EXISTE no app.css — este arquivo não inventa elemento
   nenhum, só põe em movimento o que o design system já desenhou. Se inventasse,
   deixaria de ser camada de movimento e viraria mudança de layout escondida
   num arquivo chamado "animações". */
.kpi::before{
  transform-origin:left center;
  animation:olCresceLinha 520ms var(--entrada) both;animation-delay:140ms;
}

/* ============================================================
   2. REAÇÃO AO TOQUE — a interface responde antes do servidor
   ============================================================
   O intervalo entre tocar e o dado voltar é onde mora a sensação de
   travamento. Não dá para deixar a rede mais rápida; dá para o botão reagir no
   mesmo quadro do toque. */

.btn,.iconbtn,.daybtn,.chip{
  transition:transform var(--t-toque) var(--mola),
             filter var(--t-toque) var(--saida),
             border-color var(--t-estado) var(--saida),
             background-color var(--t-estado) var(--saida),
             color var(--t-estado) var(--saida);
}
.btn:hover:not(:disabled),.iconbtn:hover,.daybtn:hover{filter:brightness(1.06)}
.btn:active:not(:disabled),.iconbtn:active,.daybtn:active{transform:scale(.97)}
.btn:disabled{filter:saturate(.5) opacity(.7)}

/* O foco de teclado cresce em vez de piscar. Quem navega por Tab acompanha
   para onde foi — um contorno que só liga/desliga obriga a procurar. */
@keyframes olFoco{from{box-shadow:0 0 0 0 color-mix(in srgb,var(--accent) 45%,transparent)}
                  to{box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 22%,transparent)}}
.btn:focus-visible,.iconbtn:focus-visible,input:focus-visible,select:focus-visible,
textarea:focus-visible,.ol-switch:focus-visible{
  animation:olFoco 180ms var(--saida) both;outline:none;
}

/* Interruptor: o botão anda com mola, o trilho troca de cor sem mola. Duas
   curvas de propósito — a cor com mola dá impressão de piscar. */
.ol-switch{transition:background-color var(--t-estado) var(--saida),
                      border-color var(--t-estado) var(--saida)}
.ol-switch .tr{transition:transform 220ms var(--mola)}
.ol-switch:active .tr{transform:scale(.92)}

/* Linha de lista: some com deslize quando é removida (classe posta pelo JS
   antes do `remove()`), e escurece de leve ao passar o mouse. */
.olist-i{transition:background-color var(--t-estado) var(--saida),opacity var(--t-estado) var(--saida)}
@keyframes olSai{to{opacity:0;transform:translate3d(0,-6px,0)}}
.olist-i.ol-saindo{animation:olSai 200ms var(--saida) both;pointer-events:none}

/* Só a transição, sem estado de hover novo.
   A primeira versão levantava painéis e cartões 1px sob o ponteiro. Ficava
   bonito no cartão pequeno e inquieto no painel grande — e, mais importante,
   era um estado VISUAL que o design system não tem, entrando pela porta dos
   fundos num arquivo de animação. Aqui fica só a curva: se um dia o app.css
   ganhar um hover próprio, ele passa a ser suave de graça. */
.panel,.blkcard{transition:transform var(--t-estado) var(--saida),
                           border-color var(--t-estado) var(--saida)}

/* ============================================================
   3. ESPERA — dizer "estou trabalhando" sem mentir que já terminou
   ============================================================ */

@keyframes olBrilho{
  from{background-position:-140% 0}
  to{background-position:240% 0}
}
/* Esqueleto: a faixa de luz atravessa da esquerda para a direita. Vai em
   `background-position` (não em `transform` de um filho) para não precisar de
   elemento extra em cada lugar que carrega. */
.ol-skel{
  border-radius:8px;min-height:14px;
  background:linear-gradient(100deg,
    color-mix(in srgb,var(--text) 6%,transparent) 20%,
    color-mix(in srgb,var(--text) 13%,transparent) 40%,
    color-mix(in srgb,var(--text) 6%,transparent) 60%);
  background-size:220% 100%;
  animation:olBrilho 1.35s linear infinite;
}

/* Botão em "Salvando…": pulsa fraquinho. Não é spinner porque o texto já
   informa; o pulso só confirma que a tela não morreu. */
@keyframes olPulsa{0%,100%{opacity:1}50%{opacity:.62}}
.ol-ocupado{animation:olPulsa 1.1s var(--saida) infinite;pointer-events:none}

/* O selo "ao vivo" respira. É o único laço permanente do arquivo, e ele é
   informação: parado significaria que o realtime caiu. */
@keyframes olRespira{0%,100%{opacity:1}50%{opacity:.45}}
#liveChip:not(.off){animation:olRespira 2.6s var(--saida) infinite}

/* ============================================================
   4. AVISO — o que muda de estado precisa ser visto mudando
   ============================================================ */

/* Toast: entra de baixo, sai encolhendo. */
@keyframes olToastEntra{
  from{opacity:0;transform:translate3d(0,14px,0) scale(.97)}
  to{opacity:1;transform:none}
}
#toast.show{animation:olToastEntra 260ms var(--mola)}

/* Um número que muda sem se mexer passa despercebido. `.ol-mudou` é posta pelo
   JS quando o valor renderizado é diferente do anterior. */
@keyframes olDestaca{
  0%{transform:scale(1)}
  35%{transform:scale(1.09)}
  100%{transform:scale(1)}
}
.ol-mudou{animation:olDestaca 420ms var(--mola) both}

/* A faixa vermelha do sinal de vida bate como um coração. Ela é a única coisa
   na tela que diz "a proteção pode ter caído", e uma faixa estática vira
   paisagem em dois dias. Devagar (1,9 s) para ser presença, não alarme. */
@keyframes olAlerta{
  0%,100%{box-shadow:0 0 0 0 color-mix(in srgb,var(--neg) 28%,transparent)}
  55%{box-shadow:0 0 0 7px color-mix(in srgb,var(--neg) 0%,transparent)}
}
.sinal.mudo{animation:olAlerta 1.9s var(--saida) infinite}
.sinal{animation:olSobe 340ms var(--entrada) both}

/* ============================================================
   5. NAVEGAÇÃO — a troca de página deixa de ser um piscar branco
   ============================================================
   Progressive enhancement puro: onde a View Transitions API não existe (hoje,
   Firefox e Safari antigos), nada acontece e a navegação é a de sempre. */

@view-transition{navigation:auto}
::view-transition-old(root){animation:olSaiPagina 160ms var(--saida) both}
::view-transition-new(root){animation:olEntraPagina 260ms var(--entrada) both}
@keyframes olSaiPagina{to{opacity:0}}
@keyframes olEntraPagina{from{opacity:0;transform:translate3d(0,6px,0)}to{opacity:1;transform:none}}

/* ============================================================
   6. O INTERRUPTOR GERAL

   Duas saídas, e as duas importam:
   - `prefers-reduced-motion` é a do sistema operacional;
   - `html.ol-sem-movimento` é a do próprio app (Ajustes › Aparência), para
     quem quer parar o movimento SÓ aqui.

   `animation-duration: .01ms` em vez de `none`: um `animationend` que nunca
   dispara deixaria pendurado qualquer código que espere o fim da animação.
   Com .01ms o evento acontece, e o elemento chega ao estado final no primeiro
   quadro. `!important` porque isto tem de ganhar de tudo acima.
   ============================================================ */

@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
    scroll-behavior:auto !important;
  }
  .ol-anima{opacity:1}
}
html.ol-sem-movimento *,
html.ol-sem-movimento *::before,
html.ol-sem-movimento *::after{
  animation-duration:.01ms !important;
  animation-iteration-count:1 !important;
  transition-duration:.01ms !important;
}
html.ol-sem-movimento .ol-anima{opacity:1}
