/* Transições entre telas v3 ("Chevron Flow"), controladas por shell.js + transition.js (SPEC 3.10).
   Saída: cada elemento acelera no sentido do chevron (>) em formação ">" (o meio sai primeiro), anda de verdade
   (40 a 64 px no celular) e só depois apaga; todos terminam um pouco antes da troca, qualquer que seja o atraso.
   Troca: a tela nova já foi montada invisível durante a saída (.tx-pre); na troca ela só entra no fluxo,
   enquanto o núcleo do feixe cruza o centro da tela. Câmera <> confirmar: a moldura é um elemento compartilhado.
   Entrada: os elementos chegam do lado de trás, sobem um pouco e vêm da profundidade, escalonados de cima para baixo.
   Só transform e opacity animam (mais os clip-paths pequenos que já existiam: borda da foto e revelação do resultado). */

:root {
  --tx-magenta: 255, 43, 214;
  --tx-violet: 161, 0, 255;
  --tx-cyan: 63, 208, 255;
  --tx-yellow: 249, 233, 18;
}

/* ---------- feixe em chevron (>) que cruza a tela, atrás do conteúdo (entre .bgs e .app) ---------- */
.tx-sweep {
  --tx-w: 64vw; --tx-skew: 24deg; --tx-dur: 800ms;
  position: fixed; left: 0; top: 0; right: 0; bottom: 0; z-index: 0; overflow: hidden; pointer-events: none;
}
/* Parado, o feixe não existe (nem como camada); replay() força o reflow, então a corrida reinicia ao voltar o display. */
.tx-sweep:not(.is-run) { display: none; }
/* Soma luz ao fundo (como as ondas do KV) em vez de pintar por cima; só enquanto corre, para não manter mistura ociosa. */
.tx-sweep.is-run { mix-blend-mode: screen; }
.tx-band { display: none; position: absolute; left: 0; top: 0; bottom: 0; width: var(--tx-w); opacity: 0; }
.tx-sweep.is-run .tx-band { display: block; will-change: transform, opacity; animation: tx-cross var(--tx-dur) linear both; }
.tx-sweep.is-run .tx-band--echo { display: none; }
.tx-half {
  position: absolute; left: 0; right: 0; height: 50%;
  /* Rastro longo à esquerda, núcleo claro e borda amarela à frente: o mesmo espectro das ondas de luz do KV. */
  background: linear-gradient(90deg,
    rgba(var(--tx-magenta), 0) 0%, rgba(var(--tx-magenta), 0.22) 42%, rgba(var(--tx-violet), 0.42) 66%,
    rgba(var(--tx-cyan), 0.7) 84%, rgba(255, 255, 255, 0.9) 91%, rgba(var(--tx-yellow), 0.65) 94%, rgba(var(--tx-yellow), 0) 100%);
}
.tx-half--t { top: 0; transform: skewX(var(--tx-skew)); transform-origin: 50% 100%; }
.tx-half--b { bottom: 0; transform: skewX(calc(-1 * var(--tx-skew))); transform-origin: 50% 0; }
.tx-half { opacity: 0.78; }
.tx-band--echo .tx-half { opacity: 0.36; }

/* O núcleo (~90% da largura da faixa no gradiente de ida) cruza 50vw em 30% = 240 ms = a troca de telas. */
@keyframes tx-cross {
  0% { transform: translate3d(calc(-100% - 30vh), 0, 0); opacity: 0; animation-timing-function: cubic-bezier(0.4, 0, 0.7, 0.6); }
  10% { opacity: 1; }
  30% { transform: translate3d(calc(50vw - 90%), 0, 0); animation-timing-function: cubic-bezier(0.3, 0.4, 0.6, 1); }
  85% { opacity: 1; }
  100% { transform: translate3d(calc(100vw + 30vh), 0, 0); opacity: 0; }
}

/* Ao voltar só o sentido inverte: o chevron segue apontando para a frente (>) e o rastro de cor passa para a direita. */
.tx-sweep[data-dir='back'].is-run .tx-band { animation-name: tx-cross-back; }
.tx-sweep[data-dir='back'] .tx-half {
  background: linear-gradient(270deg,
    rgba(var(--tx-magenta), 0) 0%, rgba(var(--tx-magenta), 0.22) 42%, rgba(var(--tx-violet), 0.42) 66%,
    rgba(var(--tx-cyan), 0.7) 84%, rgba(255, 255, 255, 0.9) 91%, rgba(var(--tx-yellow), 0.65) 94%, rgba(var(--tx-yellow), 0) 100%);
}
/* No gradiente de volta (270deg) o núcleo fica a ~10% da largura. */
@keyframes tx-cross-back {
  0% { transform: translate3d(calc(100vw + 30vh), 0, 0); opacity: 0; animation-timing-function: cubic-bezier(0.4, 0, 0.7, 0.6); }
  10% { opacity: 1; }
  30% { transform: translate3d(calc(50vw - 10%), 0, 0); animation-timing-function: cubic-bezier(0.3, 0.4, 0.6, 1); }
  85% { opacity: 1; }
  100% { transform: translate3d(calc(-100% - 30vh), 0, 0); opacity: 0; }
}

/* Versão leve (fx.js marca o :root quando a composição é por software): sem feixe. Sem GPU ele custava 15 a 30% do
   desenho de cada quadro da troca; motion.js nem o dispara, isto é só a rede de segurança. */
:root[data-fx-lite] .tx-sweep { display: none; }

@media (min-width: 1024px) and (min-aspect-ratio: 5/4) {
  .tx-sweep { --tx-w: 42vw; --tx-skew: 30deg; --tx-dur: 800ms; }
  :root:not([data-fx-lite]) .tx-sweep.is-run .tx-band--echo { display: block; animation-delay: 60ms; }
  :root:not([data-fx-lite]) .tx-band:not(.tx-band--echo) .tx-half { opacity: 1; }
}

/* ---------- coreografia dos elementos ---------- */
:root {
  /* Saída: o deslocamento acelera desde o início (ease-in quadrático) e a opacidade segura até ~40% e então cai. */
  --tx-ease-in: cubic-bezier(0.11, 0, 0.5, 0);
  --tx-fade-out: cubic-bezier(0.32, 0, 0.67, 0);
  --tx-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  /* --tx-exit é o instante em que toda saída termina (10 ms antes da troca de transition.js); a duração de cada
     elemento é --tx-exit menos o atraso da formação (--xd), então nada ainda visível some de uma vez na troca. */
  --tx-exit: 230ms; --tx-enter: 460ms; --tx-stagger: 45ms; --tx-cap: 4;
  --tx-d: calc(20 * var(--m)); --tx-x: calc(56 * var(--m)); --tx-rise: calc(8 * var(--m));
  --tx-card-d: calc(16 * var(--m)); --tx-launch: calc(60 * var(--m)); --tx-recoil: calc(-4 * var(--m));
}
@media (min-width: 1024px) and (min-aspect-ratio: 5/4) {
  :root {
    --tx-d: calc(40 * var(--u)); --tx-x: calc(80 * var(--u)); --tx-rise: calc(10 * var(--u));
    --tx-card-d: calc(28 * var(--u)); --tx-launch: calc(100 * var(--u)); --tx-recoil: calc(-6 * var(--u));
  }
}
:root[data-tx-mode='lite'] { --tx-exit: 150ms; --tx-enter: 380ms; --tx-stagger: 40ms; --tx-cap: 2; }
.screen[data-variant='error'] { --tx-enter: 380ms; --tx-stagger: 40ms; }

/* Toque travado durante a troca (transition.js também barra clique e Enter/Espaço/Esc na captura). */
html.is-tx .app { pointer-events: none; }

/* Sinal do sentido: 1 em frente, -1 ao voltar. Tudo corre para onde o ">" aponta. */
.screen[data-dir] { --tx-sx: 1; }
.screen[data-dir='back'] { --tx-sx: -1; }

/* Papéis (motion.js stagger): --k = quanto anda, --z = profundidade. */
[data-tx] { --k: 0.75; --z: 0.02; }
[data-tx='title'] { --k: 1; --z: 0.03; }
[data-tx='media'] { --k: 0; --z: 0.06; }
[data-tx='brand'] { --k: 0; --z: 0.08; }
[data-tx='action'] { --k: 0.5; --z: 0; }
[data-tx='group'] { --k: 0.5; }
.screen.is-leaving[data-variant='to-generating'] .photo-frame { --z: -0.08; } /* a foto encolhe rumo ao anel */
.screen.tx-in[data-variant='to-generating'] .gen-loader { --k: 0.9; --z: 0.15; } /* o anel chega de trás e cresce */
.screen.is-leaving[data-variant='to-result'] .gen-loader { --z: 0.14; }
.screen[data-variant='error'] [data-tx] { --k: 0.5; --z: 0; }
:root[data-tx-mode='lite'] [data-tx] { --z: 0 !important; }

/* Deslocamento e opacidade em animações separadas, cada uma com a própria curva. */
@keyframes tx-out {
  to { transform: translate3d(calc(var(--tx-sx) * var(--k) * var(--tx-x)), 0, 0) scale(calc(1 + var(--tx-sx) * var(--z))); }
}
@keyframes tx-out-fade { to { opacity: 0; } }
@keyframes tx-in {
  from {
    opacity: 0;
    transform: translate3d(calc(-1 * var(--tx-sx) * var(--k) * var(--tx-d)), calc(var(--k) * var(--tx-rise)), 0) scale(calc(1 - var(--tx-sx) * var(--z)));
  }
  45% { opacity: 1; }
}
@keyframes tx-card { from { opacity: 0; transform: translate3d(calc(-1 * var(--tx-sx, 1) * var(--tx-card-d)), calc(0.4 * var(--tx-rise)), 0) scale(0.96); } }
@keyframes tx-fade-in { from { opacity: 0; } }
@keyframes tx-fade-out { to { opacity: 0; } }
@keyframes tx-chev-launch {
  35% { transform: translate3d(calc(var(--tx-sx) * var(--tx-recoil)), 0, 0); }
  to { opacity: 0; transform: translate3d(calc(var(--tx-sx) * var(--tx-launch)), 0, 0) scaleX(1.15); }
}

/* ---------- entrada (own fica de fora sem especificidade: as entradas próprias de screens.css continuam) ---------- */
/* Todas as regras de entrada que pegam [data-tx] ficam em no máximo (0,3,0) e antes das de saída, que então vencem. */
.screen.tx-in [data-tx]:where(:not([data-tx='own'], [data-tx='group'])) {
  animation: tx-in var(--tx-enter) var(--tx-ease-out) calc(min(var(--i, 0), var(--tx-cap)) * var(--tx-stagger)) backwards;
}
.screen.tx-in :where([data-tx='group']) { animation: none; } /* vence o rise de [data-s]; as cartas entram sozinhas */
.screen.tx-in [data-tx]:where([data-tx='action']) { animation-duration: calc(var(--tx-enter) - 80ms); }
.screen.tx-in .shutter { animation-name: tx-fade-in; } /* o obturador cuida dos próprios transforms */
.screen.tx-in .values-actions { animation-delay: 200ms; } /* chega depois que as cartas começam */
.screen.tx-in .value-card { animation: tx-card 400ms var(--tx-ease-out) calc(80ms + min(var(--ci, 0), 4) * 40ms) backwards; }
:root[data-tx-mode='lite'] .screen.tx-in .value-card { animation-duration: 340ms; animation-delay: calc(60ms + min(var(--ci, 0), 4) * 20ms); }
.screen.tx-in .frame-border { animation-delay: 200ms; animation-duration: 420ms; }
.screen.tx-in .result-frame.is-in { animation-delay: 200ms; animation-fill-mode: both; } /* sem lampejo antes da revelação */
.screen.tx-in .title-img { animation-delay: calc(min(var(--i, 0), var(--tx-cap)) * var(--tx-stagger) + 240ms); }
.screen.tx-in .final-headline {
  animation-delay: calc(min(var(--i, 0), var(--tx-cap)) * var(--tx-stagger)), calc(min(var(--i, 0), var(--tx-cap)) * var(--tx-stagger) + 300ms);
}
:root[data-tx-mode='lite'] .screen.tx-in .frame-border { animation: none; }
.screen.tx-in[data-variant='refresh'] [data-tx] { animation: tx-fade-in 300ms linear backwards; }

/* ---------- saída (depois das de entrada: mesma especificidade, a última vence; .tx-in nunca é removida) ---------- */
.screen.is-leaving { pointer-events: none; }
.screen.is-leaving [data-tx] {
  animation:
    tx-out calc(var(--tx-exit) - var(--xd, 0ms)) var(--tx-ease-in) var(--xd, 0ms) forwards,
    tx-out-fade calc(var(--tx-exit) - var(--xd, 0ms)) var(--tx-fade-out) var(--xd, 0ms) forwards;
}
:root:not([data-tx-mode='lite']) .screen.is-leaving[data-variant='to-result'] .gen-chev {
  animation: tx-chev-launch 220ms cubic-bezier(0.6, 0, 0.9, 0.5) forwards;
}
.screen.is-leaving[data-variant='refresh'] [data-tx] { animation: tx-fade-out 150ms linear forwards; }

/* ---------- tela nova montada durante a saída (shell.js): fora do fluxo, invisível e com as animações paradas ---------- */
/* Estilo e layout rodam no tempo ocioso da saída; na troca ela só entra no fluxo e as animações começam do zero. */
.screen.tx-pre { position: absolute; left: 0; top: 0; width: 100%; visibility: hidden; pointer-events: none; }
.screen.tx-pre, .screen.tx-pre *:not(.tx-share-to), .screen.tx-pre ::before, .screen.tx-pre ::after { animation-play-state: paused !important; }

/* ---------- moldura compartilhada (câmera <> confirmar, shell.js shareMedia) ---------- */
/* A velha fica parada (não apaga nem cresce). A nova nasce exatamente sobre ela (FLIP), funde por cima até a troca
   (tempos em shell.js shareMedia, contados da montagem),
   já opaca quando a velha sai do palco por baixo dela, e depois desliza para o próprio lugar (no PC são ~35 px). */
.screen.is-leaving [data-tx].tx-share-from { animation: none; }
.screen.is-leaving .tx-share-from .frame-border { animation: tx-fade-out var(--share-fade-dur, 140ms) linear var(--share-fade-delay, 90ms) forwards; }
.screen.tx-pre [data-tx].tx-share-to { visibility: visible; }
.screen:not(.is-leaving) [data-tx].tx-share-to {
  animation:
    tx-fade-in var(--share-fade-dur, 140ms) linear var(--share-fade-delay, 90ms) backwards,
    tx-share-move 420ms var(--tx-ease-out) var(--share-at, 240ms) backwards;
}
@keyframes tx-share-move { from { transform: translate3d(var(--share-x, 0px), var(--share-y, 0px), 0) scale(var(--share-s, 1)); } }

/* ---------- movimento reduzido e troca instantânea (aba oculta) ---------- */
:root[data-tx-mode='reduced'] .screen.is-leaving { opacity: 0; transition: opacity 120ms linear; }
:root[data-tx-mode='reduced'] .screen :is([data-tx], .value-card, .frame-border, .title-img, .gen-chev) { animation: none !important; }
:root[data-tx-mode='reduced'] .screen.tx-in { animation: tx-fade-in 180ms linear backwards; }
:root[data-tx-mode='instant'] .screen :is([data-tx], .value-card) { animation: none !important; }
@media (prefers-reduced-motion: reduce) { /* rede de segurança enquanto data-tx-mode ainda não existe (boot) */
  .tx-sweep { display: none; }
  .screen.tx-in [data-tx], .screen.is-leaving [data-tx] { animation: none !important; }
}
