/* ==========================================================================
   Glimpses — camada de movimento
   Princípio do manual: "a espera é de propósito". Nada salta, nada quica.
   Tudo entra devagar, com peso, e para. Só transform / opacity / filter.
   Sem JS a página fica visível e estática — os estados iniciais dependem
   de .js no <html>.
   ========================================================================== */

:root {
  /* Desaceleração longa: a massa chega e assenta, sem overshoot. */
  --e-weight: cubic-bezier(.16, .84, .32, 1);
  --e-soft:   cubic-bezier(.33, 1, .68, 1);
  --e-inout:  cubic-bezier(.65, 0, .35, 1);

  --d-tap:  180ms;
  --d-ui:   420ms;
  --d-move: 760ms;
  --d-slow: 1200ms;
}

/* Âncoras não param embaixo do cabeçalho fixo. */
[id] { scroll-margin-top: 84px; }
@media (min-width: 1024px) { [id] { scroll-margin-top: 104px; } }

/* ── Entrada: blocos ──────────────────────────────────────────────────── */
.js .m-rise {
  opacity: 0;
  transform: translate3d(0, 22px, 0);
  transition:
    opacity   var(--d-move) var(--e-weight),
    transform var(--d-move) var(--e-weight);
  transition-delay: calc(var(--i, 0) * 70ms);
}
.js .m-rise.is-in { opacity: 1; transform: none; }

/* ── Entrada: palavras dos títulos ────────────────────────────────────── */
.js .m-word {
  display: inline-block;
  opacity: 0;
  transform: translate3d(0, .42em, 0);
  transition:
    opacity   700ms var(--e-soft),
    transform 900ms var(--e-weight);
  transition-delay: calc(var(--i, 0) * 38ms);
}
.js .m-word.is-in { opacity: 1; transform: none; }

/* No display o texto ainda "assenta" saindo de fora de foco. */
.js .display .m-word,
.js .editorial .m-word { filter: blur(7px); transition-property: opacity, transform, filter; }
.js .display .m-word.is-in,
.js .editorial .m-word.is-in { filter: blur(0); }

/* ── Entrada: fios de 1 px (a nossa única moldura) ────────────────────── */
.js .m-rule {
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 900ms var(--e-weight);
  transition-delay: calc(var(--i, 0) * 70ms);
}
.js .m-rule.is-in { transform: scaleX(1); }

/* ── Entrada: fotos "revelando" ───────────────────────────────────────── */
/* A foto chega como papel saindo do banho: clara, sem contraste, e fecha. */
.js img.m-photo {
  opacity: 0;
  transform: scale(1.05);
  filter: brightness(1.16) contrast(.82) saturate(.55);
  transition:
    opacity   var(--d-move) var(--e-soft),
    transform var(--d-slow) var(--e-weight),
    filter    var(--d-slow) var(--e-soft);
  transition-delay: calc(var(--i, 0) * 110ms);
}
.js img.m-photo.is-in { opacity: 1; transform: none; filter: none; }

/* ── Entrada: pontos da matriz ────────────────────────────────────────── */
.js .m-dot {
  opacity: 0;
  transform: scale(.2);
  transition:
    opacity   var(--d-ui) var(--e-soft),
    transform 560ms var(--e-weight);
  transition-delay: calc(var(--i, 0) * 45ms);
}
.js .m-dot.is-in { opacity: 1; transform: none; }

/* ── Entrada: barras (linha do tempo, scrubber) ───────────────────────── */
.js .m-bar {
  transform: scaleY(0);
  transform-origin: bottom center;
  transition: transform 820ms var(--e-weight);
  transition-delay: calc(var(--i, 0) * 55ms);
}
.js .m-bar.is-in { transform: scaleY(1); }

/* O marcador do momento sobe depois das barras. */
.js .scrubber__times .is-marked::before {
  transform: translateX(-1px) scaleY(0);
  transform-origin: bottom center;
  transition: transform 640ms var(--e-weight) 520ms;
}
.js .scrubber__times .is-marked::after {
  transform: translateX(-3px) scale(0);
  transition: transform 520ms var(--e-weight) 900ms;
}
.js .scrubber.is-in .is-marked::before { transform: translateX(-1px) scaleY(1); }
.js .scrubber.is-in .is-marked::after  { transform: translateX(-3px) scale(1); }

@media (min-width: 1024px) {
  .js .scrubber__times .is-marked::after { transform: translateX(-4px) scale(0); }
  .js .scrubber.is-in .is-marked::after  { transform: translateX(-4px) scale(1); }
}

/* ── Obturador: um disparo quando a tela entra ────────────────────────── */
@keyframes m-shutter-press {
  0%, 100% { transform: scale(1); }
  38%      { transform: scale(.88); }
  62%      { transform: scale(1.02); }
}
.js .shutter.is-fired { animation: m-shutter-press 620ms var(--e-inout); }

/* O anel é um fio de 1 px que se abre e some — sem brilho, sem sombra. */
.shutter { position: relative; }
.shutter::after {
  content: "";
  position: absolute;
  inset: -1px;
  border: 1px solid currentColor;
  border-radius: 999px;
  opacity: 0;
  pointer-events: none;
}
.shutter--accent::after { border-color: var(--accent); }
@keyframes m-ring {
  from { transform: scale(1);   opacity: .55; }
  to   { transform: scale(1.9); opacity: 0; }
}
.js .shutter.is-fired::after { animation: m-ring 1100ms var(--e-soft) 120ms; }

/* ── Visor: a moldura do momento respira uma vez ──────────────────────── */
@keyframes m-moment-edge {
  0%, 100% { box-shadow: inset 0 0 0 1.5px rgba(196, 64, 42, .6); }
  50%      { box-shadow: inset 0 0 0 3px   rgba(196, 64, 42, .95); }
}
.js .frame--moment.is-in { animation: m-moment-edge 2.4s var(--e-inout) 700ms 2; }
/* A composição com a paralaxe do visor está no @supports mais abaixo: o
   atalho `animation` zera animation-timeline, então as duas precisam ser
   declaradas juntas. */

/* ── Botões e alvos de toque ──────────────────────────────────────────── */
.btn, .link-underline, .qa summary, .nav__links a, .menu a { will-change: auto; }
.btn { transition: background-color var(--d-ui) var(--e-soft), color var(--d-ui) var(--e-soft), transform var(--d-tap) var(--e-weight); }
.btn:active { transform: scale(.98); }

.link-underline { position: relative; border-bottom-color: transparent; }
.link-underline::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: currentColor;
  transform: scaleX(1);
  transform-origin: left center;
  transition: transform 520ms var(--e-weight);
}
.link-underline:hover::after { transform: scaleX(0); transform-origin: right center; }

/* Links da navegação: o fio cresce da esquerda. */
.nav__links a:not(.btn) { position: relative; }
.nav__links a:not(.btn)::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -6px;
  height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 420ms var(--e-weight);
}
.nav__links a:not(.btn):hover::after { transform: scaleX(1); }

/* ── Cabeçalho: progresso da leitura no próprio fio do rodapé do nav ──── */
.nav { position: sticky; }
.nav::after {
  content: "";
  position: absolute;
  left: 0; bottom: -1px;
  width: 100%;
  height: 1px;
  background: var(--ink);
  transform: scaleX(var(--progress, 0));
  transform-origin: left center;
}
@supports (animation-timeline: scroll()) {
  .nav::after {
    transform: scaleX(0);
    animation: m-progress linear both;
    animation-timeline: scroll(root block);
  }
  @keyframes m-progress { to { transform: scaleX(1); } }
}

/* ══════════════════════════════════════════════════════════════════════
   LIGADO AO SCROLL — vale para os dois sentidos
   Onde há timeline nativa, a entrada deixa de ser um gatilho de uma vez só
   e passa a ser posição: o elemento chega ao subir a tela e recua ao sair.
   Rolando de volta, o mesmo caminho se desfaz. Fora do hero, que tem a
   entrada de carregamento da página.
   ══════════════════════════════════════════════════════════════════════ */
@supports (animation-timeline: view()) {

  /* Descendentes de .rail ficam de fora: o carrossel rola em x, mas o
     overflow-y dele computa como `auto`, então ele vira o scroller do
     view(block) e a linha do tempo congela. Esses voltam ao observador,
     que em motion.js também trabalha nos dois sentidos. */
  .js .m-rise:not(.m-load):not(.rail *) {
    /* desarma o modo observador */
    opacity: 1;
    transform: none;
    transition: none;

    animation: m-in linear both, m-recede linear forwards;
    animation-timeline: view(block), view(block);
    /* O escalonamento vira distância de rolagem, não tempo. */
    animation-range:
      entry calc(var(--i, 0) * 5%) entry calc(70% + var(--i, 0) * 5%),
      exit 20% exit 92%;
  }

  @keyframes m-in {
    from { opacity: 0; transform: translate3d(0, 26px, 0) scale(.988); }
    to   { opacity: 1; transform: none; }
  }
  /* Recuo: não some, só perde presença — como sair do foco da lente. */
  @keyframes m-recede {
    from { opacity: 1; transform: none; }
    to   { opacity: .32; transform: translate3d(0, -20px, 0) scale(.99); }
  }

  /* Títulos: entram palavra a palavra (uma vez) e recuam junto com o resto. */
  .js .display:not(.m-load),
  .js h2,
  .js .editorial p {
    animation: m-recede linear forwards;
    animation-timeline: view(block);
    animation-range: exit 20% exit 92%;
  }

  /* Hero: o texto sobe mais devagar que o aparelho — profundidade. */
  .hero__text {
    animation: m-drift linear both;
    animation-timeline: view(block);
    animation-range: cover 0% exit 100%;
  }
  @keyframes m-drift {
    from { transform: translate3d(0, 0, 0); }
    to   { transform: translate3d(0, -56px, 0); }
  }

  /* Colagem do portal: cada foto corre a uma velocidade — o grupo respira. */
  .gallery .frame {
    animation: m-drift-a linear both;
    animation-timeline: view(block);
    animation-range: entry 0% exit 100%;
  }
  .gallery .frame--g2 { animation-name: m-drift-b; }
  .gallery .frame--g3 { animation-name: m-drift-c; }
  .gallery .frame--g4 { animation-name: m-drift-b; }
  @keyframes m-drift-a { from { transform: translate3d(0, 14px, 0); } to { transform: translate3d(0, -14px, 0); } }
  @keyframes m-drift-b { from { transform: translate3d(0, 26px, 0); } to { transform: translate3d(0, -26px, 0); } }
  @keyframes m-drift-c { from { transform: translate3d(0, 6px, 0); }  to { transform: translate3d(0, -6px, 0); } }
}

/* ── O grifo da frase editorial se desenha conforme a rolagem ─────────── */
.mark {
  border-bottom: 0;
  background: linear-gradient(var(--accent), var(--accent)) left bottom / 100% 1px no-repeat;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
@supports (animation-timeline: view()) {
  .js .mark {
    background-size: 0% 1px;
    animation: m-underline linear both;
    animation-timeline: view(block);
    animation-range: entry 30% cover 30%;
  }
  @keyframes m-underline { to { background-size: 100% 1px; } }
}

/* ── Entrada de carregamento (só o que já está na primeira tela) ──────── */
.js .m-load {
  opacity: 0;
  transform: translate3d(0, 24px, 0);
  transition:
    opacity   var(--d-move) var(--e-weight),
    transform var(--d-move) var(--e-weight);
  transition-delay: calc(140ms + var(--i, 0) * 90ms);
}
.js .m-load.is-in { opacity: 1; transform: none; }

/* ── Mockups: paralaxe de bloco ligada ao scroll ──────────────────────── */
/* Os aparelhos flutuam contra a rolagem: dá massa sem mover o layout. */
@supports (animation-timeline: view()) {
  .phone:not(.phone--top),
  .browser {
    animation: m-float linear both;
    animation-timeline: view(block);
    animation-range: entry 0% exit 100%;
  }
  @keyframes m-float {
    from { transform: translate3d(0, 20px, 0); }
    to   { transform: translate3d(0, -20px, 0); }
  }

  /* A câmera "panora" sozinha dentro do visor. */
  .frame--a, .frame--moment {
    animation: m-pan linear both;
    animation-timeline: view(block);
    animation-range: entry 10% exit 90%;
  }
  @keyframes m-pan {
    from { object-position: center 26%; }
    to   { object-position: center 56%; }
  }

  /* Visor do momento: paralaxe ligada ao scroll + a moldura respirando. */
  .js .frame--moment.is-in {
    animation:
      m-pan linear both,
      m-moment-edge 2.4s var(--e-inout) 700ms 2;
    animation-timeline: view(block), auto;
    animation-range: entry 10% exit 90%, normal;
  }
}

/* ── Perguntas: abre e fecha com altura interpolada ───────────────────── */
.qa summary i::before { content: none; }        /* substitui o glifo +/− */
.qa[open] summary i::before { content: none; }

.qa summary i { position: relative; }
.qa summary i::before,
.qa summary i::after {
  content: "";
  position: absolute;
  left: 50%; top: 50%;
  width: 11px; height: 1px;
  background: currentColor;
  transform: translate(-50%, -50%);
  transition: transform 440ms var(--e-weight), opacity 440ms var(--e-weight);
}
.qa summary i::after { transform: translate(-50%, -50%) rotate(90deg); }
.qa[open] summary i::after { transform: translate(-50%, -50%) rotate(0deg); }
.qa summary { transition: color var(--d-ui) var(--e-soft); }

@supports selector(::details-content) {
  :root { interpolate-size: allow-keywords; }
  .qa::details-content {
    block-size: 0;
    overflow: clip;
    opacity: 0;
    transition:
      block-size 520ms var(--e-weight),
      opacity    420ms var(--e-soft),
      content-visibility 520ms allow-discrete;
  }
  .qa[open]::details-content { block-size: auto; opacity: 1; }
}

/* ── Menu móvel ───────────────────────────────────────────────────────── */
.menu { overflow: clip; }
.js .menu a {
  opacity: 0;
  transform: translate3d(0, 10px, 0);
  transition: opacity 380ms var(--e-soft), transform 460ms var(--e-weight);
  transition-delay: calc(var(--i, 0) * 45ms);
}
.js .menu.is-open a { opacity: 1; transform: none; }

/* ── CTA fixo: entra depois que o hero passa ──────────────────────────── */
.js .sticky-cta {
  transform: translate3d(0, 105%, 0);
  transition: transform 620ms var(--e-weight);
}
.js .sticky-cta.is-in { transform: none; }

/* ── Carrossel: a seta chama o dedo três vezes ────────────────────────── */
@keyframes m-nudge {
  0%, 100% { transform: translateX(0); }
  50%      { transform: translateX(5px); }
}
.js .rail__hint.is-in .mono { animation: m-nudge 2.2s var(--e-inout) 3; }
.rail__bars i { transition: background-color 420ms var(--e-soft); }

/* ── Rede de segurança ────────────────────────────────────────────────── */
/* Ligada por motion.js só se o observador nunca tiver disparado. */
.m-failsafe .m-rise,
.m-failsafe .m-load,
.m-failsafe .m-word,
.m-failsafe .m-photo,
.m-failsafe .m-dot {
  opacity: 1 !important;
  transform: none !important;
  filter: none !important;
  animation: none !important;
}
.m-failsafe .m-rule,
.m-failsafe .m-bar { transform: none !important; }

/* ── Números que contam ───────────────────────────────────────────────── */
[data-count] { font-variant-numeric: tabular-nums; }

/* ══════════════════════════════════════════════════════════════════════
   Sem movimento — respeitado de verdade: tudo visível, nada anima.
   ══════════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
  .js .m-rise,
  .js .m-word,
  .js .m-photo,
  .js .m-dot,
  .js .menu a {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    transition: none !important;
  }
  .js .m-rule, .js .m-bar { transform: none !important; transition: none !important; }
  .js .sticky-cta { transform: none !important; }
  .js .scrubber__times .is-marked::before { transform: translateX(-1px) !important; }
  .js .scrubber__times .is-marked::after  { transform: translateX(-3px) !important; }

  .js .m-load { opacity: 1 !important; transform: none !important; transition: none !important; }

  .nav::after,
  .phone, .browser,
  .frame--a, .frame--moment,
  .shutter, .shutter::after,
  .rail__hint .mono,
  .js .m-rise, .js .display, .js h2, .js .editorial p,
  .hero__text, .gallery .frame, .js .mark {
    animation: none !important;
  }
  .nav::after { transform: scaleX(0) !important; }
  .js .mark { background-size: 100% 1px; }
}
