/* ============================================================
   Villandry Reserve — Movimento
   Gramática de animação do site. Somente movimento:
   nenhum token, nenhuma regra de layout, nenhuma cor nova.

   Regras da casa (docs/02 §6.4):
   - Anima apenas transform e opacity. Nada de width/height/top/left.
   - 400–700 ms, ease-out. Sem bounce, sem spring, sem overshoot.
   - O usuário deve sentir o movimento sem conseguir descrevê-lo.

   Dependências:
   - Tokens de base.css: --dur-fast, --dur, --dur-slow, --ease-out
   - JS opcional: IntersectionObserver que adiciona .is-visible
     em elementos com [data-reveal]; e, no hero, a custom property
     --scroll-y (número sem unidade, em px de rolagem).
   ============================================================ */

/* ---------- 0. Tokens locais de movimento ----------
   Prefixo --mo- para não colidir com base.css. */
:root {
  /* Curvas — todas desaceleram, nenhuma volta atrás */
  --mo-ease: var(--ease-out);
  --mo-ease-soft: cubic-bezier(0.33, 0, 0.2, 1); /* entrada+saída, para painéis */

  /* Durações de coreografia */
  --mo-dur-reveal: 700ms;
  --mo-dur-image: 900ms;
  --mo-dur-panel: 480ms;

  /* Passo do escalonamento em listas e grids */
  --mo-stagger: 90ms;

  /* Deslocamento vertical do reveal — contido de propósito */
  --mo-rise: 24px;

  /* Amplitude do parallax do hero, em px por px de scroll.
     0.18 = a foto anda 18% do que o conteúdo anda. */
  --mo-parallax: 0.18;

  /* Fallback: sem JS, --scroll-y não existe e o cálculo precisa
     continuar válido. Este zero é o valor herdado padrão. */
  --scroll-y: 0;
}

/* Registrar --scroll-y como número permite ao navegador
   interpolá-la e mantém o cálculo fora do caminho do layout.
   Navegadores sem @property simplesmente ignoram este bloco —
   o fallback acima já garante o valor 0. */
@property --scroll-y {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}


/* ============================================================
   1. REVEAL DE ENTRADA EM SCROLL
   Uso: <div data-reveal> ... </div>
   O JS adiciona .is-visible quando o elemento entra na viewport.
   ============================================================ */

[data-reveal] {
  opacity: 0;
  transform: translate3d(0, var(--mo-rise), 0);
  transition:
    opacity var(--mo-dur-reveal) var(--mo-ease),
    transform var(--mo-dur-reveal) var(--mo-ease);
  transition-delay: var(--mo-delay, 0ms);
  will-change: opacity, transform;
}

[data-reveal].is-visible {
  opacity: 1;
  transform: translate3d(0, 0, 0);
  /* Libera a camada de composição depois que o elemento assenta.
     Manter will-change vivo em dezenas de elementos custa memória
     de GPU em celular mediano. */
  will-change: auto;
}

/* Variantes direcionais — mesma contenção, eixo diferente */
[data-reveal="up"]    { transform: translate3d(0, var(--mo-rise), 0); }
[data-reveal="down"]  { transform: translate3d(0, calc(var(--mo-rise) * -1), 0); }
[data-reveal="left"]  { transform: translate3d(var(--mo-rise), 0, 0); }
[data-reveal="right"] { transform: translate3d(calc(var(--mo-rise) * -1), 0, 0); }

/* Fade puro — para elementos que não devem se mover
   (números, filetes ornamentais, legendas curtas) */
[data-reveal="fade"] { transform: none; }

/* Escala mínima — para blocos de destaque isolados.
   0.98 é o limite: acima disso vira "efeito". */
[data-reveal="scale"] {
  transform: translate3d(0, var(--mo-rise), 0) scale(0.98);
}
[data-reveal="scale"].is-visible {
  transform: translate3d(0, 0, 0) scale(1);
}

/* ---------- Atrasos escalonados ----------
   Aplicar nos filhos para coreografar listas e grids.
   Uso: <li data-reveal class="delay-1"> */
.delay-1 { --mo-delay: calc(var(--mo-stagger) * 1); }
.delay-2 { --mo-delay: calc(var(--mo-stagger) * 2); }
.delay-3 { --mo-delay: calc(var(--mo-stagger) * 3); }
.delay-4 { --mo-delay: calc(var(--mo-stagger) * 4); }

/* Escalonamento automático até 8 filhos — evita ter de
   escrever .delay-n à mão em grids gerados por loop.
   Uso: <ul class="reveal-stagger"><li data-reveal>…</li></ul> */
.reveal-stagger > *:nth-child(1) { --mo-delay: 0ms; }
.reveal-stagger > *:nth-child(2) { --mo-delay: calc(var(--mo-stagger) * 1); }
.reveal-stagger > *:nth-child(3) { --mo-delay: calc(var(--mo-stagger) * 2); }
.reveal-stagger > *:nth-child(4) { --mo-delay: calc(var(--mo-stagger) * 3); }
.reveal-stagger > *:nth-child(5) { --mo-delay: calc(var(--mo-stagger) * 4); }
.reveal-stagger > *:nth-child(6) { --mo-delay: calc(var(--mo-stagger) * 5); }
.reveal-stagger > *:nth-child(7) { --mo-delay: calc(var(--mo-stagger) * 6); }
.reveal-stagger > *:nth-child(n + 8) { --mo-delay: calc(var(--mo-stagger) * 7); }


/* ============================================================
   2. REVEAL DE IMAGEM — máscara em vez de fade
   A imagem é descoberta por uma cortina que sobe, enquanto a
   própria foto recua de um leve zoom. Duas camadas, dois ritmos:
   é isso que dá a sensação de peso.

   Marcação:
   <figure class="img-reveal" data-reveal>
     <img src="..." alt="...">
   </figure>
   ============================================================ */

.img-reveal {
  position: relative;
  overflow: hidden;
  /* A máscara é o próprio elemento, deslocado; nada de clip-path
     animado, que força repaint em alguns motores móveis. */
}

.img-reveal > img,
.img-reveal > picture {
  transform: scale(1.08);
  transform-origin: center;
  transition: transform var(--mo-dur-image) var(--mo-ease);
  transition-delay: var(--mo-delay, 0ms);
  will-change: transform;
}

/* Cortina: um pseudo-elemento opaco que desliza para fora.
   Herda a cor do fundo via currentColor do container pai
   quando aplicada a classe modificadora abaixo. */
.img-reveal::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--vr-base);
  transform: translate3d(0, 0, 0);
  transition: transform var(--mo-dur-image) var(--mo-ease);
  transition-delay: var(--mo-delay, 0ms);
  will-change: transform;
  pointer-events: none;
}

.img-reveal.is-visible::after {
  /* Sobe e sai. 101% evita a linha de subpixel na borda. */
  transform: translate3d(0, -101%, 0);
}

.img-reveal.is-visible > img,
.img-reveal.is-visible > picture {
  transform: scale(1);
  will-change: auto;
}

/* Direção da cortina — alternar entre seções para não ficar mecânico */
.img-reveal--down.is-visible::after  { transform: translate3d(0, 101%, 0); }
.img-reveal--left.is-visible::after  { transform: translate3d(-101%, 0, 0); }
.img-reveal--right.is-visible::after { transform: translate3d(101%, 0, 0); }

/* Cortina sobre fundo claro */
.img-reveal--on-light::after { background: var(--vr-text); }

/* Segurança: se o JS nunca rodar, a imagem existe e é legível —
   só a cortina ficaria por cima. Por isso a cortina é removida
   quando o documento não tem a classe de JS ativo. */
html:not(.js) .img-reveal::after { display: none; }
html:not(.js) .img-reveal > img,
html:not(.js) .img-reveal > picture { transform: none; }


/* ============================================================
   3. KEN BURNS — hero
   Zoom lentíssimo e contínuo. 28 s de ida, 28 s de volta:
   o alternate elimina o corte brusco do loop.
   Escala máxima 1.06 — acima disso o olho percebe o movimento.

   Marcação:
   <div class="hero__media"><img class="ken-burns" src="…"></div>
   ============================================================ */

@keyframes vr-ken-burns {
  from { transform: scale(1) translate3d(0, 0, 0); }
  to   { transform: scale(1.06) translate3d(-1.2%, -0.8%, 0); }
}

/* Variante espelhada — usar em heros secundários para que a
   direção do movimento não se repita de seção em seção. */
@keyframes vr-ken-burns-alt {
  from { transform: scale(1.06) translate3d(1.2%, 0.6%, 0); }
  to   { transform: scale(1) translate3d(0, 0, 0); }
}

.ken-burns {
  animation: vr-ken-burns 32s var(--mo-ease-soft) alternate infinite;
  transform-origin: center;
  will-change: transform;
  /* backface-visibility evita cintilação de textura em WebKit
     durante escalas fracionárias longas. */
  backface-visibility: hidden;
}

.ken-burns--alt {
  animation-name: vr-ken-burns-alt;
  animation-duration: 38s; /* dessincronizar de propósito */
}

/* Só anima quando o hero está em tela. Sem isso, um hero fora da
   viewport continua consumindo GPU durante todo o scroll. */
.ken-burns--paused,
.hero:not(.is-onscreen) .ken-burns { animation-play-state: paused; }


/* ============================================================
   4. PARALLAX DO HERO
   O JS seta --scroll-y no elemento (ou no :root) com o valor de
   window.scrollY. Se o JS não rodar, --scroll-y = 0 e o elemento
   simplesmente fica parado: degrada sem quebrar.

   Nada aqui lê o scroll em JS por frame — o cálculo é do
   compositor, via calc() sobre translate3d.
   ============================================================ */

.parallax {
  /* Deslocamento contido: no máximo ~18% da velocidade do scroll */
  transform: translate3d(0, calc(var(--scroll-y, 0) * var(--mo-parallax) * 1px), 0);
  will-change: transform;
}

/* Camadas com profundidades distintas dentro do mesmo hero */
.parallax--deep    { --mo-parallax: 0.28; }
.parallax--shallow { --mo-parallax: 0.10; }

/* Conteúdo do hero: sobe mais devagar e desaparece antes do fim.
   O fade usa uma segunda custom property, --scroll-progress
   (0 a 1), setada pelo mesmo JS. Sem JS, fica opaco e visível. */
.hero__content--parallax {
  transform: translate3d(0, calc(var(--scroll-y, 0) * 0.06 * 1px), 0);
  opacity: calc(1 - var(--scroll-progress, 0) * 0.9);
}

/* Progressive enhancement: em telas pequenas o parallax é ruído.
   Desliga por completo abaixo de 48em. */
@media (max-width: 47.99em) {
  .parallax,
  .parallax--deep,
  .parallax--shallow,
  .hero__content--parallax {
    transform: none;
    opacity: 1;
    will-change: auto;
  }
}


/* ============================================================
   5. COREOGRAFIA DE ENTRADA DA PÁGINA
   Cascata do hero no load: eyebrow → título → lead → CTA.
   Não depende de IntersectionObserver: dispara sozinha via
   animation-delay, com fill-mode both para que o estado inicial
   valha desde o primeiro frame pintado.

   Marcação:
   <section class="hero">
     <span class="eyebrow enter enter-1">…</span>
     <h1 class="enter enter-2">…</h1>
     <p class="lead enter enter-3">…</p>
     <div class="hero__actions enter enter-4">…</div>
   </section>

   Timeline (ms a partir do load):
     0     fundo/hero já pintado, foto estática
     200   eyebrow
     360   título
     560   lead
     760   CTAs
     1100  indicador de scroll
   ============================================================ */

@keyframes vr-enter {
  from { opacity: 0; transform: translate3d(0, 18px, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

.enter {
  animation: vr-enter var(--mo-dur-reveal) var(--mo-ease) both;
  animation-delay: var(--mo-delay, 0ms);
}

.enter-1 { --mo-delay: 200ms; }
.enter-2 { --mo-delay: 360ms; }
.enter-3 { --mo-delay: 560ms; }
.enter-4 { --mo-delay: 760ms; }
.enter-5 { --mo-delay: 940ms; }

/* O título entra um pouco mais lento que o resto — dá peso */
h1.enter, .enter--slow { animation-duration: var(--mo-dur-slow); }

/* Fundo do hero: a foto surge por opacidade sobre o poster,
   sem corte seco. Nunca começa em preto total. */
@keyframes vr-hero-media-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.hero__media > video,
.hero__media--fade {
  animation: vr-hero-media-in 1200ms var(--mo-ease) both;
}

/* ---------- Indicador de scroll ----------
   Pulso lento e contínuo, amplitude mínima, opacidade baixa.
   Some assim que o usuário rola (JS adiciona .is-hidden). */
@keyframes vr-scroll-hint {
  0%, 100% { transform: translate3d(0, 0, 0); opacity: 0.45; }
  50%      { transform: translate3d(0, 8px, 0); opacity: 0.9; }
}

.scroll-hint {
  animation:
    vr-enter 600ms var(--mo-ease) 1100ms both,
    vr-scroll-hint 2600ms var(--mo-ease-soft) 1700ms infinite;
  transition: opacity var(--dur) var(--mo-ease);
}

.scroll-hint.is-hidden {
  opacity: 0;
  pointer-events: none;
  animation-play-state: paused;
}


/* ============================================================
   6. HEADER — transparente → sólido no scroll
   O JS alterna .is-scrolled (passou do limiar) e .is-hidden
   (rolando para baixo). Histerese fica no JS; aqui só o visual.
   ============================================================ */

.site-header {
  transition:
    transform var(--dur) var(--mo-ease),
    background-color var(--dur) var(--mo-ease),
    border-color var(--dur) var(--mo-ease),
    backdrop-filter var(--dur) var(--mo-ease);
  will-change: transform;
}

/* Sólido: fundo e filete aparecem. background-color e
   backdrop-filter não são propriedades de composição, mas
   transicionam uma única vez por mudança de estado — não em loop —
   e o custo é irrelevante fora do caminho do scroll contínuo. */
.site-header.is-scrolled {
  background-color: color-mix(in srgb, var(--vr-base) 88%, transparent);
  backdrop-filter: blur(14px) saturate(1.1);
  border-bottom-color: color-mix(in srgb, var(--vr-green-mid) 30%, transparent);
}

/* Retração: sai de cena rolando para baixo, volta rolando para cima */
.site-header.is-hidden {
  transform: translate3d(0, -100%, 0);
}

/* Enquanto o menu mobile está aberto, o header nunca se esconde */
.site-header.is-menu-open {
  transform: none;
}

/* ---------- Link de menu — sublinhado que cresce ---------- */
.nav-link {
  position: relative;
  text-decoration: none;
  transition: color var(--dur-fast) var(--mo-ease);
}

.nav-link::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -0.35em;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--dur) var(--mo-ease);
}

.nav-link:hover::after,
.nav-link:focus-visible::after {
  transform: scaleX(1);
}

/* Saída pelo lado oposto — o filete recua por onde não entrou */
.nav-link:not(:hover)::after {
  transform-origin: right center;
}

/* Página atual: filete permanente, sem hover */
.nav-link[aria-current="page"]::after {
  transform: scaleX(1);
  transform-origin: left center;
  background: var(--vr-gold);
}


/* ============================================================
   7. MICRO-INTERAÇÕES DE HOVER
   Todas por transform/opacity. Elevação sutil, nunca salto.
   Só aparecem em dispositivos com ponteiro fino — em touch,
   :hover fica "grudado" depois do toque.
   ============================================================ */

@media (hover: hover) and (pointer: fine) {

  /* ---------- Card de casa ---------- */
  .card {
    transition: transform var(--dur) var(--mo-ease);
  }
  .card__media {
    overflow: hidden; /* contém o zoom da foto */
  }
  .card__media img {
    transition: transform 600ms var(--mo-ease);
    will-change: transform;
  }
  /* Véu escuro do card: um pseudo-elemento cuja opacidade cai.
     Nada de animar background — só opacity. */
  .card__media::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(to top,
      color-mix(in srgb, var(--vr-base) 85%, transparent),
      transparent 60%);
    opacity: 1;
    transition: opacity var(--dur) var(--mo-ease);
    pointer-events: none;
  }

  .card:hover,
  .card:focus-within {
    transform: translate3d(0, -6px, 0);
  }
  .card:hover .card__media img,
  .card:focus-within .card__media img {
    transform: scale(1.04);
  }
  .card:hover .card__media::after,
  .card:focus-within .card__media::after {
    opacity: 0.7;
  }

  /* ---------- Thumb de galeria ----------
     Mais discreto que o card: a galeria é uma grade densa e
     qualquer exagero vira ruído visual. */
  .thumb {
    overflow: hidden;
    transition: transform var(--dur) var(--mo-ease);
  }
  .thumb img {
    transition: transform 600ms var(--mo-ease), opacity var(--dur) var(--mo-ease);
    will-change: transform;
  }
  .thumb:hover img,
  .thumb:focus-visible img {
    transform: scale(1.05);
    opacity: 0.88;
  }

  /* Escurece as irmãs quando uma é apontada — foco por contraste */
  .gallery:hover .thumb:not(:hover) img {
    opacity: 0.62;
  }

  /* ---------- Botão ----------
     base.css já define a transição do .btn. Aqui só a seta,
     quando houver, e o realce por escala. */
  .btn__arrow {
    display: inline-block;
    transition: transform var(--dur) var(--mo-ease);
  }
  .btn:hover .btn__arrow { transform: translate3d(4px, 0, 0); }

  /* Link de texto com seta (leia mais, ver galeria) */
  .link-arrow .btn__arrow,
  .link-arrow__icon {
    display: inline-block;
    transition: transform var(--dur) var(--mo-ease);
  }
  .link-arrow:hover .link-arrow__icon { transform: translate3d(4px, 0, 0); }
}

/* Feedback tátil no toque — vale em qualquer dispositivo */
.btn:active,
.card:active,
.thumb:active {
  transform: scale(0.985);
  transition-duration: 100ms;
}


/* ============================================================
   8. MENU MOBILE
   Painel que desliza da direita + backdrop que esmaece.
   O JS alterna .is-open no painel e no <html> (para travar o scroll).
   O painel usa visibility para sair da ordem de foco quando fechado —
   visibility não anima, apenas comuta ao fim da transição.
   ============================================================ */

.nav-drawer {
  transform: translate3d(100%, 0, 0);
  visibility: hidden;
  transition:
    transform var(--mo-dur-panel) var(--mo-ease-soft),
    visibility 0s linear var(--mo-dur-panel);
  will-change: transform;
}

.nav-drawer.is-open {
  transform: translate3d(0, 0, 0);
  visibility: visible;
  transition:
    transform var(--mo-dur-panel) var(--mo-ease-soft),
    visibility 0s linear 0s;
}

.nav-drawer__backdrop {
  opacity: 0;
  visibility: hidden;
  transition:
    opacity var(--mo-dur-panel) var(--mo-ease),
    visibility 0s linear var(--mo-dur-panel);
}

.nav-drawer.is-open ~ .nav-drawer__backdrop,
.nav-drawer__backdrop.is-open {
  opacity: 1;
  visibility: visible;
  transition:
    opacity var(--mo-dur-panel) var(--mo-ease),
    visibility 0s linear 0s;
}

/* Itens do menu entram em cascata depois que o painel assenta */
.nav-drawer__item {
  opacity: 0;
  transform: translate3d(0, 12px, 0);
  transition:
    opacity 420ms var(--mo-ease),
    transform 420ms var(--mo-ease);
}

.nav-drawer.is-open .nav-drawer__item {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

.nav-drawer.is-open .nav-drawer__item:nth-child(1) { transition-delay: 160ms; }
.nav-drawer.is-open .nav-drawer__item:nth-child(2) { transition-delay: 220ms; }
.nav-drawer.is-open .nav-drawer__item:nth-child(3) { transition-delay: 280ms; }
.nav-drawer.is-open .nav-drawer__item:nth-child(4) { transition-delay: 340ms; }
.nav-drawer.is-open .nav-drawer__item:nth-child(5) { transition-delay: 400ms; }
.nav-drawer.is-open .nav-drawer__item:nth-child(n + 6) { transition-delay: 460ms; }

/* ---------- Botão hambúrguer → X ----------
   Três traços, cada um com transform próprio.
   Marcação: <button class="menu-toggle"><span></span>×3</button> */
.menu-toggle span {
  display: block;
  transition:
    transform var(--mo-dur-panel) var(--mo-ease-soft),
    opacity 200ms var(--mo-ease);
  transform-origin: center;
}

.menu-toggle[aria-expanded="true"] span:nth-child(1) {
  transform: translate3d(0, 7px, 0) rotate(45deg);
}
.menu-toggle[aria-expanded="true"] span:nth-child(2) {
  opacity: 0;
  transform: scaleX(0.4);
}
.menu-toggle[aria-expanded="true"] span:nth-child(3) {
  transform: translate3d(0, -7px, 0) rotate(-45deg);
}


/* ============================================================
   9. LIGHTBOX DA GALERIA
   Abre por opacidade + escala mínima a partir do centro.
   A escala de entrada é 0.96 → 1: percebe-se como "aproximar",
   não como "pop". Fechamento é o reverso, mais rápido.
   ============================================================ */

.lightbox {
  opacity: 0;
  visibility: hidden;
  transition:
    opacity var(--mo-dur-panel) var(--mo-ease),
    visibility 0s linear var(--mo-dur-panel);
}

.lightbox.is-open {
  opacity: 1;
  visibility: visible;
  transition:
    opacity var(--mo-dur-panel) var(--mo-ease),
    visibility 0s linear 0s;
}

.lightbox__figure {
  transform: scale(0.96) translate3d(0, 12px, 0);
  opacity: 0;
  transition:
    transform var(--mo-dur-reveal) var(--mo-ease),
    opacity var(--mo-dur-panel) var(--mo-ease);
  will-change: transform, opacity;
}

.lightbox.is-open .lightbox__figure {
  transform: scale(1) translate3d(0, 0, 0);
  opacity: 1;
  transition-delay: 60ms; /* deixa o fundo escurecer primeiro */
}

/* Legenda entra por último */
.lightbox__caption {
  opacity: 0;
  transform: translate3d(0, 8px, 0);
  transition:
    opacity var(--dur) var(--mo-ease) 260ms,
    transform var(--dur) var(--mo-ease) 260ms;
}
.lightbox.is-open .lightbox__caption {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

/* Troca de imagem dentro do lightbox — crossfade curto.
   O JS aplica .is-swapping enquanto o novo src carrega. */
.lightbox__figure.is-swapping {
  opacity: 0;
  transition-duration: 180ms;
}

/* Setas de navegação */
.lightbox__nav {
  transition: transform var(--dur) var(--mo-ease), opacity var(--dur) var(--mo-ease);
}
@media (hover: hover) and (pointer: fine) {
  .lightbox__nav--prev:hover { transform: translate3d(-4px, 0, 0); }
  .lightbox__nav--next:hover { transform: translate3d(4px, 0, 0); }
}


/* ============================================================
   10. TRANSIÇÃO ENTRE PÁGINAS
   View Transitions API onde houver suporte; nada onde não houver
   (a navegação simplesmente acontece, como sempre aconteceu).
   ============================================================ */

@view-transition { navigation: auto; }

::view-transition-old(root) {
  animation: vr-fade-out 220ms var(--mo-ease) both;
}
::view-transition-new(root) {
  animation: vr-fade-in 380ms var(--mo-ease) both;
}

@keyframes vr-fade-out { to { opacity: 0; } }
@keyframes vr-fade-in  { from { opacity: 0; } }


/* ============================================================
   11. MOVIMENTO REDUZIDO — rede de segurança
   base.css §8 já zera durações. Aqui garantimos o que aquele
   reset genérico não garante: que nenhum elemento fique preso
   em opacity:0, translate ou atrás de uma cortina.

   Regra inegociável: com movimento reduzido, ou com o JS morto,
   TODO conteúdo precisa estar visível e no lugar.
   ============================================================ */

@media (prefers-reduced-motion: reduce) {

  /* Reveals: estado final imediato, independente de .is-visible */
  [data-reveal],
  [data-reveal].is-visible,
  [data-reveal="scale"],
  .enter,
  .nav-drawer__item,
  .lightbox__caption,
  .nav-drawer.is-open .nav-drawer__item {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    animation: none !important;
    will-change: auto !important;
  }

  /* Reveal de imagem: sem cortina, sem zoom. Imagem parada. */
  .img-reveal::after {
    display: none !important;
  }
  .img-reveal > img,
  .img-reveal > picture {
    transform: none !important;
    transition: none !important;
  }

  /* Ken Burns vira frame fixo, na escala 1 */
  .ken-burns,
  .ken-burns--alt {
    animation: none !important;
    transform: none !important;
  }

  /* Parallax vira imagem parada */
  .parallax,
  .parallax--deep,
  .parallax--shallow,
  .hero__content--parallax {
    transform: none !important;
    opacity: 1 !important;
    will-change: auto !important;
  }

  /* Indicador de scroll: visível e imóvel, ainda cumpre a função */
  .scroll-hint {
    animation: none !important;
    opacity: 0.6;
    transform: none !important;
  }
  .scroll-hint.is-hidden { opacity: 0; }

  /* Painéis: comutam sem deslizar, mas continuam funcionando —
     o estado fechado permanece fechado, o aberto permanece aberto. */
  .nav-drawer,
  .nav-drawer__backdrop,
  .lightbox,
  .lightbox__figure {
    transition: none !important;
  }
  .nav-drawer { transform: translate3d(100%, 0, 0); }
  .nav-drawer.is-open { transform: none; }
  .lightbox__figure { transform: none !important; }
  .lightbox.is-open .lightbox__figure { opacity: 1; }

  /* Hover: mantém a mudança de estado, remove o deslocamento */
  .card:hover,
  .card:focus-within,
  .thumb:hover,
  .btn:active,
  .card:active,
  .thumb:active {
    transform: none !important;
  }
  .card:hover .card__media img,
  .thumb:hover img {
    transform: none !important;
  }

  /* Header: nunca se esconde — retração é movimento */
  .site-header.is-hidden { transform: none !important; }

  /* Transição de página: nenhuma */
  ::view-transition-old(root),
  ::view-transition-new(root) { animation: none !important; }
}

/* ---------- Rede de segurança para JS morto ----------
   Se o JS falhar, [data-reveal] nunca recebe .is-visible e o
   conteúdo ficaria invisível para sempre. O JS deve adicionar
   a classe .js em <html> como primeira coisa que faz.
   Sem essa classe, os reveals já nascem no estado final.

   No <head>, antes do CSS:
   <script>document.documentElement.classList.add('js')</script>
*/
html:not(.js) [data-reveal] {
  opacity: 1;
  transform: none;
  transition: none;
}
html:not(.js) .nav-drawer__item {
  opacity: 1;
  transform: none;
}
