/* =========================================================================
   PlayCash — abertura, transição entre telas, esqueletos e chegada.

   ESTE ARQUIVO É CARREGADO ANTES DE QUALQUER JS DE MÓDULO. Ele tem uma
   obrigação que nenhum outro tem: pintar o fundo escuro no PRIMEIRO QUADRO.
   Um PWA que abre branco e vira escuro meio segundo depois parece quebrado,
   e o defeito é o mais visível que existe na categoria.

   Como o lampejo branco morre, em duas camadas:
     1. index.html carrega este arquivo e carimba data-tema no <html> por um
        script embutido (sem rede, síncrono, antes do <body>). Com o atributo
        no lugar, var(--fundo) já resolve para #0B0A09 no primeiro quadro.
     2. html/body recebem o fundo aqui, e não só o body: o canvas do navegador
        é pintado a partir do <html>. Fundo só no body deixa a moldura branca
        aparecer nos primeiros quadros e na rolagem elástica do iOS.

   REFERÊNCIAS DE ABERTURA (Mobbin, iOS) — as oito que estudei concordam em
   três coisas, e as três viraram regra aqui:
     · Oura      mobbin.com/screens/11e3c10d-cdb8-41d7-a136-822aa8070aed
                 símbolo puro, 52px numa captura de 295 = 17,6% da largura.
     · Granola   .../b63248d6-da8c-440d-8cd2-ccfec2b18da7   36/295 = 12,2%
     · MLS       .../9d6fba4f-0a08-4102-ac7e-117e15ac6b3e   62/303 = 20,5%
     · Stake     .../d91bfc6a-b4d1-4cab-b4fa-4ca11cfa8ef9   72/303 = 23,8%
     · Finimize  .../9f3a778f-c90e-4573-9815-866324462613   52/295 = 17,6%
     · Tonal · MD Vinyl · Centr — mesma família.
   O que as oito têm em comum: fundo quase-preto (nenhuma usa preto puro),
   símbolo sozinho e centrado, NENHUMA barra de carregamento, NENHUM texto de
   apoio. Cinco das oito não têm nem o nome escrito.
   O que adotei: 72px de símbolo em 390px de tela = 18,5%, dentro da faixa das
   referências e acima do piso do nosso conjunto de ícones (o "R$" da moeda só
   é desenhado a partir de 40px — ver icone() em lib/dom.js).
   ========================================================================= */

/* ------------------------------------------------------- 1. O PRIMEIRO QUADRO
   Sem seletor de tema: qualquer que seja o tema, o canvas nasce com o fundo
   do app. O token já está resolvido porque o <html> foi carimbado no <head>. */
html {
  background: var(--fundo);
}

/* ============================================================ 2. A ABERTURA */

.abertura {
  position: fixed;
  inset: 0;
  z-index: 90;                 /* acima do modal (70), que é o teto do app */
  background: var(--fundo);
  display: grid;
  /* 47% e não 50%: nas capturas da Oura e da Granola o símbolo pousa um pouco
     acima do centro geométrico. Centro óptico — abaixo da metade a marca
     parece estar escorregando para o rodapé. */
  grid-template-rows: 47fr auto 53fr;
  justify-items: center;
  /* A abertura não recebe toque em momento nenhum: ela é uma cortina, não uma
     tela. O que estiver embaixo já pode ser tocado assim que aparecer. */
  pointer-events: none;
  opacity: 1;
}

/* A INTRO EM VÍDEO
   ----------------
   Ocupa a cortina inteira e fica por cima do símbolo desenhado. Nasce
   transparente: enquanto o arquivo não começou a tocar, o que se vê é o
   desenho — assim uma rede ruim degrada para a abertura antiga em vez de
   mostrar retângulo preto.

   `contain`, e não `cover`. Com cover, um vídeo 16:9 numa tela 9:19,5 é
   ampliado quase 1,2× até cobrir a altura — a moeda estourava as bordas e o
   nome, que vive logo abaixo dela, saía do quadro. Contain mostra a composição
   como ela foi desenhada; as faixas que sobram somem porque a cortina fica
   preta enquanto o vídeo está no ar, e o vídeo também abre em preto. */
.abertura-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* `cover` desde que a intro virou 1080x1920, em pé como o telefone. Era
     `contain` porque o vídeo antigo era deitado (1280x720) e cortá-lo comeria a
     marca; com a peça na proporção da tela, `cover` preenche a cortina inteira
     e sobra, no máximo, alguns pixels nas pontas de telas muito compridas. */
  object-fit: cover;
  opacity: 0;
  transition: opacity 220ms var(--curva, ease);
  pointer-events: none;
}

/* Só quando o navegador confirma que está tocando. */
.abertura-tocando .abertura-video { opacity: 1; }

/* O fundo acompanha o vídeo, senão a faixa de cima e a de baixo apareceriam
   como duas listras azuladas em volta de um retângulo preto. */
.abertura-tocando { background: #000; }

/* Com o vídeo no ar, a logo parada sai de cena — as duas juntas são duas marcas
   sobrepostas, disputando o mesmo lugar da tela.

   `animation: none` NÃO É ENFEITE, é o que faz a linha seguinte valer.

   A logo entra com `animation: ... both`, e o `both` mantém o estado final do
   keyframe depois que ele acaba — inclusive `opacity: 1`. Valor vindo de
   animação ganha de declaração normal na cascata, então um `opacity: 0` escrito
   aqui era simplesmente ignorado: a logo ficava por cima do vídeo, e as duas
   marcas apareciam juntas. Desligando a animação, a opacidade volta a ser uma
   propriedade comum e a regra abaixo passa a mandar.

   Isto não existia antes porque a marca era um SVG cujos FILHOS é que animavam;
   o elemento em si nunca teve animação própria. */
.abertura-tocando .abertura-marca {
  animation: none;
  opacity: 0;
  transition: opacity 160ms linear;
}

/* Quem pediu menos movimento não recebe dois segundos de vídeo na cara. O
   símbolo desenhado continua valendo, e ele já respeita a preferência. */
@media (prefers-reduced-motion: reduce) {
  .abertura-video { display: none; }
  .abertura-tocando .abertura-marca { opacity: 1; }
}

.abertura-marca {
  grid-row: 2;
  /* A logo é uma arte larga, não mais um quadrado de 72px. O teto em px impede
     que ela vire um cartaz em tela grande; o vw manda no telefone. */
  width: min(78vw, 350px);
  height: auto;
  display: block;
  /* O fundo preto da arte evapora por mistura, e não por recorte — o mesmo
     motivo do convite: o brilho em volta da moeda é parte da logo, e qualquer
     recorte o levaria junto. A cortina é sempre escura, nos dois temas, então
     aqui `screen` não precisa de exceção. */
  mix-blend-mode: screen;
  animation: abertura-marca 340ms var(--curva-abertura, cubic-bezier(.2, .7, .3, 1)) both;
}

/* ==========================================================================
   A ENTRADA DA MARCA

   Aqui moravam três animações — o contorno da moeda correndo pela borda, o
   relevo aparecendo e o play crescendo do centro — cronometradas em 450ms
   contra os 495-527ms que o app leva para ficar pronto. Elas desenhavam um
   SÍMBOLO, que era o substituto monocromático da marca enquanto a arte não
   existia. Com a logo de verdade no lugar, não há traço para desenhar: a marca
   chega inteira.

   O que sobrou é a mesma ideia em um tempo só. A logo entra crescendo de 92%,
   com o brilho subindo junto — 340ms, dentro da mesma folga medida, porque a
   regra não mudou: animação que termina depois de a cortina sair não existe.
   ========================================================================== */

@keyframes abertura-marca {
  0%   { opacity: 0; transform: scale(.92); filter: brightness(.6); }
  55%  { opacity: 1; transform: scale(1.02); filter: brightness(1.08); }
  100% { opacity: 1; transform: scale(1); filter: brightness(1); }
}

/* A SAÍDA. Não é um apagar: a marca avança um passo na direção de quem olha e
   a cortina abre. O conteúdo embaixo sobe junto (.abertura-entregue), então a
   troca é uma passagem e não um corte seco. 260ms — a abertura inteira tem
   1,6s de teto e a saída não pode comer o orçamento. */
.abertura.saindo {
  animation: abertura-sai 260ms var(--curva-saida) both;
}

.abertura.saindo .abertura-marca {
  animation: abertura-marca-sai 260ms var(--curva-saida) both;
}

@keyframes abertura-sai {
  from { opacity: 1; }
  to   { opacity: 0; }
}

@keyframes abertura-marca-sai {
  from { transform: scale(1); }
  to   { transform: scale(1.12); }
}

/* O outro lado da mesma passagem: a primeira tela recebe a entrega crescendo
   os últimos 3%, no mesmo tempo da cortina. */
.abertura-entregue {
  animation: abertura-entrega 260ms var(--curva) both;
}

@keyframes abertura-entrega {
  from { opacity: .4; transform: scale(1.03); }
  to   { opacity: 1; transform: none; }
}

/* ============================================== 3. TRANSIÇÃO ENTRE TELAS
   Três movimentos, e a diferença entre eles é a informação:
     fundo  → entrou em algo mais fundo (feed -> saque). Vem da direita.
     volta  → saiu de algo mais fundo. Vem da esquerda.
     irmao  → trocou de aba. Não tem direção horizontal porque não tem
              hierarquia: sobe 8px e assenta.
   Teto de 240ms em todas. Ninguém espera animação para pegar dinheiro:
   200ms nas direcionais, 160ms na troca de aba, que é a mais frequente. */

.tela-fundo { animation: tela-fundo 200ms var(--curva) both; }
.tela-volta { animation: tela-volta 200ms var(--curva) both; }
.tela-irmao { animation: tela-irmao 160ms var(--curva) both; }

@keyframes tela-fundo {
  from { opacity: 0; transform: translate3d(18px, 0, 0); }
  to   { opacity: 1; transform: none; }
}

@keyframes tela-volta {
  from { opacity: 0; transform: translate3d(-18px, 0, 0); }
  to   { opacity: 1; transform: none; }
}

@keyframes tela-irmao {
  from { opacity: 0; transform: translate3d(0, 8px, 0); }
  to   { opacity: 1; transform: none; }
}

/* ==================================================== 4. ESQUELETOS COM FORMA
   O esqueleto do app é um retângulo genérico (fx.js). Retângulo genérico não
   informa nada: ele diz "carregando", quando poderia dizer "vem um vídeo de
   tela cheia com uma barra de ações do lado direito".

   Estes três têm a planta do conteúdo que chega. As medidas saem do próprio
   app, não de chute — cada uma está anotada com o seletor que ela imita. */

.esq { background: var(--superficie-2); border-radius: var(--raio-p); }

/* A onda é a mesma do esqueleto de fx.js, para os dois conviverem numa tela
   sem parecer que são de apps diferentes. */
.esq,
.esq-palco,
.esq-bolha { animation: esq-onda 1.4s ease-in-out infinite; }

@keyframes esq-onda {
  0%, 100% { opacity: 1; }
  50%      { opacity: .55; }
}

/* ---- FEED. Imita .feed-palco-hosp + .feed-acao + o bloco de texto do rodapé.
   O vídeo é tela cheia, a barra de ações é vertical e encostada à direita, e
   o texto mora embaixo à esquerda — é essa planta que o esqueleto mostra. */
.esq-feed {
  position: relative;
  height: 100dvh;
  background: var(--palco);
  overflow: hidden;
}

.esq-palco {
  position: absolute;
  inset: 0;
  background: var(--superficie);
  opacity: .35;
}

/* A BARRA DE AÇÕES — o pedaço que mais denuncia esqueleto preguiçoso.

   Onde medi a proporção (Mobbin, TikTok iOS): na captura
   mobbin.com/screens/e8a9730d-ff55-4ed9-b969-3918178bdf4a, numa renderização
   de 295px de largura para um aparelho de 393pt, o avatar do criador tem 30px
   de diâmetro (= 40pt), os ícones ficam centrados a 18px da borda direita
   (= 24pt) e a distância de centro a centro entre dois itens é 48px (= 64pt),
   porque cada item carrega o número embaixo. Confere com
   mobbin.com/screens/438567b2-a83c-47fc-b773-ba2bd10e8387, onde a mesma
   medida dá 50px (= 66pt).

   O que adotei NÃO foram esses números: foram os do NOSSO feed já construído
   — .feed-acoes em css/telas/feed.css é right: 8px, bottom: nav-h + 128px,
   gap: 18px, e .feed-acao-icone é um círculo de 50px com o rótulo 4px abaixo.
   O esqueleto copia isso ao pixel, e é essa cópia que faz o critério passar:
   quando o feed real chega, NADA muda de lugar. Um esqueleto com as medidas
   do TikTok em cima do nosso layout empurraria tudo na troca — a referência
   serve para julgar a proporção (50 sobre 18 está na mesma família que 40
   sobre 24 e é folgado sobre o nosso piso de toque de 44px), não para ditar
   pixel de um app que já tem os dele. */
.esq-acoes {
  position: absolute;
  right: 8px;
  bottom: calc(var(--nav-h, 64px) + 128px);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
}

/* Cada item = círculo de 50px + 4px + rótulo. Igual a .feed-acao. */
.esq-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}

.esq-bolha {
  width: 50px;
  height: 50px;
  border-radius: 50%;
  background: var(--superficie-2);
  flex: none;
}

.esq-item .esq { width: 26px; height: 10px; }

/* O texto do rodapé: duas linhas, a de cima mais curta (é o nome), a de baixo
   mais longa (é a legenda). Para antes da barra de ações — o texto real
   também para. */
.esq-legenda {
  position: absolute;
  left: var(--pad-tela);
  right: calc(50px + 8px + var(--e-3));
  bottom: calc(var(--nav-h, 64px) + var(--e-6));
  display: flex;
  flex-direction: column;
  gap: var(--e-2);
}

.esq-legenda .esq:nth-child(1) { height: 14px; width: 62%; }
.esq-legenda .esq:nth-child(2) { height: 14px; width: 88%; }

/* O saldo flutuante do topo do feed (.feed-topo-saldo): pílula, não linha. */
.esq-pilula {
  position: absolute;
  top: calc(env(safe-area-inset-top, 0px) + var(--e-4));
  left: var(--pad-tela);
  height: 40px;
  width: 148px;
  border-radius: var(--raio-pill);
  background: var(--superficie-2);
}

/* ---- EXTRATO. Imita a linha do extrato: ícone redondo de 40px à esquerda,
   duas linhas de texto no meio (nome do lançamento e data) e o VALOR alinhado
   à direita. É o valor à direita que faz esta forma ser reconhecível como
   extrato e não como uma lista qualquer. */
.esq-extrato { padding: var(--pad-tela); display: flex; flex-direction: column; gap: var(--e-3); }

.esq-linha-extrato {
  display: flex;
  align-items: center;
  gap: var(--e-3);
  padding: var(--e-3);
  background: var(--superficie);
  border-radius: var(--raio);
  border: 1px solid var(--borda);
}

.esq-redondo { width: 40px; height: 40px; border-radius: 50%; background: var(--superficie-2); flex: none; }
.esq-meio { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--e-2); }
.esq-meio .esq:nth-child(1) { height: 14px; width: 58%; }
.esq-meio .esq:nth-child(2) { height: 11px; width: 34%; }
.esq-valor { width: 62px; height: 17px; flex: none; background: var(--superficie-2); }

/* ---- RANKING. Imita a linha do ranking: número da posição, avatar redondo,
   nome, e o valor à direita. O número da posição é estreito e vem primeiro —
   é ele que diz "isto é uma classificação". */
.esq-ranking { padding: var(--pad-tela); display: flex; flex-direction: column; gap: var(--e-2); }

.esq-linha-ranking {
  display: flex;
  align-items: center;
  gap: var(--e-3);
  padding: var(--e-3) var(--e-4);
  background: var(--superficie);
  border-radius: var(--raio);
}

.esq-posicao { width: 18px; height: 18px; flex: none; background: var(--superficie-2); }
.esq-nome { flex: 1; height: 14px; }

/* ================================================== 5. A CHEGADA
   Quem acabou de abrir a conta não cai no feed do nada. Um momento, curto, e
   ele é sobre a única coisa que já aconteceu: o dinheiro que entrou.
   Sem tutorial, sem "próximo/próximo/pular", sem explicação do app. */

.chegada {
  position: fixed;
  inset: 0;
  z-index: 80;
  background: var(--fundo);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--e-5);
  padding: var(--pad-tela);
  padding-top: calc(env(safe-area-inset-top, 0px) + var(--e-6));
  padding-bottom: calc(env(safe-area-inset-bottom, 0px) + var(--e-7));
  text-align: center;
  animation: chegada-entra 240ms var(--curva) both;
}

@keyframes chegada-entra {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.chegada.saindo { animation: abertura-sai 200ms var(--curva-saida) both; }

.chegada-simbolo {
  width: 56px;
  height: 56px;
  color: var(--marca);
  animation: chegada-simbolo 420ms var(--curva-mola) both;
}

@keyframes chegada-simbolo {
  from { opacity: 0; transform: scale(.7); }
  to   { opacity: 1; transform: none; }
}

/* O número é o assunto. Mesmo tamanho do saldo (--txt-valor): é o maior
   número do app, e este é o primeiro dele. */
.chegada-valor {
  font-size: var(--txt-valor);
  font-weight: var(--peso-extra);
  line-height: var(--altura-apertada);
  letter-spacing: var(--letra-titulo);
  color: var(--verde);
  font-variant-numeric: tabular-nums;
}

.chegada-titulo {
  font-size: var(--txt-titulo);
  font-weight: var(--peso-forte);
  line-height: var(--altura-apertada);
  letter-spacing: var(--letra-titulo);
  color: var(--texto);
  margin: 0;
}

.chegada-apoio {
  font-size: var(--txt-corpo);
  line-height: var(--altura-normal);
  color: var(--texto-fraco);
  margin: 0;
  max-width: 30ch;
}

.chegada-botao {
  margin-top: var(--e-3);
  min-height: var(--toque-min);
  padding: 0 var(--e-8);
  border: 0;
  border-radius: var(--raio-pill);
  background: var(--marca);
  color: var(--sobre-marca);
  font-family: var(--fonte);
  font-size: var(--txt-corpo);
  font-weight: var(--peso-forte);
  cursor: pointer;
  transition: transform var(--tempo-instante) var(--curva);
}

.chegada-botao:active { transform: scale(.97); }
.chegada-botao:focus-visible { outline: none; box-shadow: var(--anel-foco); }

/* =============================================== 6. QUEM PEDIU MENOS MOVIMENTO
   A regra não é "desliga a animação": é "entrega a mesma informação parada".
   A abertura CONTINUA existindo, continua mostrando a marca e continua saindo
   — ela só não se mexe. As transições viram corte, e a navegação não muda de
   comportamento em nada. */
@media (prefers-reduced-motion: reduce) {
  .abertura-marca,
  .abertura.saindo,
  .abertura.saindo .abertura-marca,
  .abertura-entregue,
  .chegada,
  .chegada-simbolo,
  .tela-fundo,
  .tela-volta,
  .tela-irmao {
    animation: none;
  }

  /* Sem animação de entrada, os elementos precisam nascer no estado final —
     senão ficam no `from` do keyframe (invisíveis) para sempre. */
  .abertura-marca,
  .abertura-entregue,
  .chegada,
  .chegada-simbolo {
    opacity: 1;
    transform: none;
  }

  /* A logo tinha `filter: brightness(.6)` no início do keyframe. `animation:
     none` devolve opacidade e transform, mas o filtro é declarado só dentro da
     animação — então aqui ele nasce no estado natural. A marca aparece com o
     brilho cheio, parada. */
  .abertura-marca { filter: none; }

  /* A saída vira um apagar de 1 quadro: a cortina some, mas nada desliza.
     JS espera este mesmo tempo antes de remover o nó (ABERTURA.saida). */
  .abertura.saindo,
  .chegada.saindo { opacity: 0; transition: opacity 1ms linear; }

  .esq, .esq-palco, .esq-bolha { animation: none; opacity: .8; }
}

/* ---- pular a apresentação ---------------------------------------------
   A ÚNICA COISA TOCÁVEL DA CORTINA. Ela inteira tem `pointer-events: none`
   porque é cortina, não tela — este botão devolve o toque só para si.

   No alto e à direita, que é onde "pular" mora em todo lugar que exibe vídeo
   antes do conteúdo. Longe do centro óptico, onde a marca está: ninguém deve
   tocar em pular por engano ao tentar tocar na marca. */
.abertura-pular {
  position: absolute;
  top: calc(env(safe-area-inset-top, 0px) + 14px);
  right: 14px;
  z-index: 2;
  pointer-events: auto;

  /* Área de toque de verdade, com a etiqueta menor por dentro. */
  min-height: var(--toque-min, 44px);
  padding: 8px 18px;
  border: 1px solid rgba(255, 255, 255, .28);
  border-radius: 999px;
  background: rgba(0, 0, 0, .42);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);

  color: rgba(255, 255, 255, .92);
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .02em;
  cursor: pointer;

  /* Entra depois do primeiro quadro do vídeo: aparecer junto com a marca
     dividiria a atenção logo no instante que a apresentação existe para ter. */
  opacity: 0;
  animation: pular-entra 260ms var(--curva, ease) 600ms forwards;
}

.abertura-pular:active { background: rgba(0, 0, 0, .62); }
.abertura-pular:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

@keyframes pular-entra {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .abertura-pular { animation: none; opacity: 1; }
}
