/* ============================================================
   PARQUE SICÍLIA — CAMADA DE MOVIMENTO (fx)

   Acompanha o fx.js. Divisão de trabalho:
     three.js     shader de fundo + folhas 3D no hero + maquete 3D do game
     GSAP + ST    coreografia de scroll (hero, títulos, trilho das regras)
     motion.dev   molas de ponteiro, tilt 3D dos cards, reveals, cursor
     anime.js     preloader, cortina de entrada, onda do tema, selos

   REGRA DE OURO DESTE ARQUIVO
   Nada aqui vale sem a classe .fx no <html>. O fx.js só a adiciona
   quando as bibliotecas carregaram E o usuário não pediu "reduzir
   movimento". Sem JS, sem CDN ou com movimento reduzido, o site
   continua se comportando exatamente como antes.
   ============================================================ */

/* ---------- 1. CANVAS 3D DO HERO ---------- */
/* fica dentro de .hero-bg (que já é z-index:-1), por cima dos blobs
   e da grade, sem nunca capturar clique */
#hero-3d{
  position:absolute; inset:0; width:100%; height:100%;
  pointer-events:none; opacity:0;
  transition:opacity 1.4s ease;
}
#hero-3d.on{ opacity:1; }

/* Com o shader no ar, os blobs borrados do CSS viram poluição: são a
   mesma ideia, feita pior. A grade fica, dá escala ao fundo.

   🔴 `opacity:0` SOZINHO NÃO BASTA — e essa era a versão anterior.
   O elemento invisível continuava rodando `drift`, que anima `scale`
   sobre um `filter:blur(90px)`. Escala invalida o borrão: o navegador
   re-borrava três círculos de meio metro de largura a cada quadro,
   para sempre, para ninguém ver. Era o segundo item mais caro da
   primeira página, atrás só do shader de tinta.

   `animation-play-state:paused` congela a escala na hora (o borrão
   vira uma camada estática, que o compositor só reaproveita), e o
   `visibility` com transição de atraso zero **no fim** dos 1.4s tira
   o elemento da pintura de vez, sem cortar o esmaecimento. */
html.fx .hero.has-3d .blob{
  opacity:0;
  visibility:hidden;
  animation-play-state:paused;
  transition:opacity 1.4s ease, visibility 0s linear 1.4s;
}

/* ---------- 2. O REVEAL DO CSS VIRA PLANO B ---------- */
/* Sem .fx, quem anima é a transição de .reveal → .reveal.in (script.js).
   Com .fx, o JS assume: zeramos o estado inicial para não brigar com os
   valores inline que GSAP/motion escrevem. */
html.fx .reveal{ opacity:1; transform:none; transition:none; }

/* ---------- 3. ELEMENTOS QUE O JS PASSA A CONTROLAR ---------- */
/* Estes tinham animação/hover em CSS puro. Sob .fx o controle é do JS —
   deixar os dois ligados faria o keyframe do CSS vencer o transform
   inline e a animação "travaria" no lugar. */
html.fx .hero-float{ animation:none; }
html.fx .marquee-track{ animation:none; }
html.fx .hero-cta .btn:hover,
html.fx .btn-game:hover,
html.fx .btn-outline:hover,
html.fx #back-top:hover,
html.fx .hour-card:hover,
html.fx .rule-card:hover,
html.fx .cat-btn:hover,
html.fx .gal-card:hover,
html.fx .contact-card:hover,
html.fx .amenity:hover{ transform:none; }

/* #back-top usava transform também para entrar/sair de cena. Como o
   motion.dev passa a escrever transform inline nele (efeito magnético),
   o inline venceria a regra do CSS e o botão ficaria preso no lugar
   errado — então aqui a entrada fica só por opacidade/visibilidade. */
html.fx #back-top,
html.fx #back-top.show{ transform:none; }

/* ---------- 4. TÍTULOS: DOBRADIÇA 3D ---------- */
/* O h1/h2 são editáveis pelo admin (o script.js reescreve o innerHTML
   deles quando as edições chegam do Supabase). Por isso NUNCA quebramos
   o texto em <span>: o fx.js embrulha o elemento INTEIRO neste wrapper
   — que fica POR FORA e sobrevive à troca de conteúdo — e gira o título
   como uma placa caindo no lugar. */
.fx-hinge{ perspective:1000px; perspective-origin:50% 0%; }
.fx-hinge > *{ transform-origin:50% 0%; will-change:transform, opacity; }

/* ---------- 5. TILT 3D DOS CARDS ---------- */
html.fx .gal-card,
html.fx .contact-card,
html.fx .hour-card,
html.fx .app-card{ transform-style:preserve-3d; }
/* brilho que varre o card conforme o cursor anda por cima */
.fx-shine{
  position:absolute; inset:0; border-radius:inherit; pointer-events:none;
  opacity:0; transition:opacity .35s; z-index:3;
  background:radial-gradient(320px circle at var(--mx,50%) var(--my,50%),
             rgba(255,255,255,.38), transparent 62%);
}
html[data-theme="dark"] .fx-shine{
  background:radial-gradient(320px circle at var(--mx,50%) var(--my,50%),
             rgba(141,198,63,.22), transparent 62%);
}

/* ---------- 6. TRILHO DAS REGRAS EM PERSPECTIVA ---------- */
/* O fx.js escreve rotateY/translateZ card a card conforme eles cruzam a
   tela. A perspectiva precisa morar no trilho, não no card. */
html.fx #h-track{ perspective:1400px; transform-style:preserve-3d; }
html.fx #h-track .rule-card{ will-change:transform; }

/* ---------- 6b. UMA CENA 3D POR SEÇÃO ---------- */
/* O fx.js insere um <canvas class="fx-scene"> como PRIMEIRO filho da
   seção (ou da .h-sticky, no caso das Regras). Fica absoluto, atrás de
   tudo e sem capturar clique. A opacidade final vem da variável
   --fx-op, que cada cena define conforme o peso de texto da seção:
   quanto mais texto, mais discreta a cena. */
/* 🔴 O canvas é FIXED, colado na janela — nem esticado na seção, nem
   sticky.

   Já tentamos as duas outras formas e as duas deixavam CORTE:
   · esticado na seção inteira → a cena era composta para uma tela que
     ninguém vê inteira (o horizonte caía abaixo da dobra);
   · sticky dentro do wrapper → o canvas só gruda enquanto sobra altura
     no wrapper. Numa seção de 1700px com janela de 800px ele desgruda
     na metade e desce junto, deixando o RESTO DA SEÇÃO sem efeito —
     era o corte visível antes de "Conheça cada espaço", e a emenda
     dura na passagem para as Regras.

   Fixo, o efeito cobre a janela do começo ao fim da seção. A troca
   entre cenas vizinhas é um cruzamento de opacidade (o Stage liga e
   desliga a classe .on conforme a seção entra e sai), não um corte.

   O wrapper continua existindo: é ele que marca a ÁREA da seção, e as
   cenas leem o rect dele para saber o progresso da rolagem. Ele NÃO
   pode ter overflow:hidden — clipar aqui traria o corte de volta. */
.fx-scene-wrap{
  position:absolute; inset:0; z-index:0;
  pointer-events:none;
}
.fx-scene{
  position:fixed; top:0; left:0; display:block;
  width:100%; height:100vh; height:100svh;
  pointer-events:none;
  opacity:0; transition:opacity 1s ease;
}
.fx-scene.on{ opacity:var(--fx-op, .5); }

/* A cena dos Documentos é um <iframe> (3D/Logo2026-3D.html), não um
   canvas do stage: o emblema tem renderizador WebGL2 próprio.
   O fundo dele é opaco (#05070a) e cobriria a seção como um retângulo
   preto — `screen` faz o quase-preto virar neutro sobre o claro e deixa
   passar só o emblema aceso, sem mexer no pipeline de bloom do 3D. */
.fx-logo3d{ border:0; mix-blend-mode:screen; }
/* no tema escuro o fundo da seção já é escuro: `screen` clarearia
   demais o conjunto, então ali o normal fica melhor */
html[data-theme="dark"] .fx-logo3d{ mix-blend-mode:normal; }

/* O conteúdo tem de subir para cima do canvas. Sem isto o texto some
   atrás da cena — o canvas é o primeiro filho, então ganharia no
   empilhamento natural. */
/* 🔴 A exceção é o WRAPPER (.fx-scene-wrap), não o canvas.
   Escrever `:not(.fx-scene)` aqui foi um bug caro: a regra pegava o
   wrapper, trocava o `position:absolute` dele por `relative` e o
   wrapper voltava para o fluxo, esticando a .h-sticky para 1463px.
   Uma .h-sticky mais alta que a janela NÃO GRUDA — e sem grudar, o
   trilho horizontal das Regras nunca anda: o visitante rolava 3000px
   no vazio. Ao mexer neste seletor, confira o seletor, não o efeito. */
html.fx .section > .container,
html.fx .h-sticky > *:not(.fx-scene-wrap){ position:relative; z-index:1; }

/* ⚠️ O .game-bg leva SÓ z-index. Ele já é `position:absolute; inset:0`
   no style.css — incluí-lo na regra acima trocava o absolute por
   relative, o `inset:0` parava de dimensioná-lo e o fundo estrelado da
   seção do game colapsava para altura zero. */
html.fx .game-bg{ z-index:1; }

/* ---------- 7. SEÇÃO DO GAME ---------- */
/* A maquete 3D giratória que existiu aqui foi REMOVIDA na v46: girando
   sem parar, competia com a moldura do game em vez de acompanhá-la. O
   mock em CSS (prédios, sol, o bonequinho andando) voltou a ser o
   protagonista e o 3D virou o ar em volta — ver a cena "vento" no
   fx.js. Não recrie o canvas dentro da .gf-screen. */

/* ---------- 8. GRÃO DE FILME ---------- */
/* Textura levíssima por cima do conteúdo (abaixo dos modais, z 940+),
   para tirar o aspecto "chapado" dos degradês. */
html.fx body::after{
  content:""; position:fixed; inset:0; z-index:899; pointer-events:none;
  opacity:.04; mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
html.fx[data-theme="dark"] body::after{ mix-blend-mode:screen; opacity:.05; }

/* ---------- 10. ONDA DA TROCA DE TEMA ---------- */
/* Anel que se expande a partir do botão de tema. Puramente decorativo.
   A posição e o transform vêm do fx.js (o anime.js escreve o transform
   inteiro, por isso não declaramos transform aqui — brigaríamos com ele). */
.fx-ripple{
  position:fixed; z-index:940; pointer-events:none;
  border-radius:50%; border:2px solid var(--green); opacity:0;
}

/* ---------- 11. PRELOADER E CORTINA ---------- */
.pre-text .fx-ch{ display:inline-block; will-change:transform, opacity; }
/* contador que sobe até 100 enquanto o site carrega */
.fx-count{
  font-family:var(--font-head); font-weight:800; font-size:.8rem;
  letter-spacing:.3em; color:var(--lime); opacity:.85; margin-top:6px;
}
/* ripas que sobem revelando a página, no lugar do fade seco */
#fx-curtain{
  position:fixed; inset:0; z-index:999; pointer-events:none; display:flex;
}
#fx-curtain > span{ flex:1 1 0; background:#14181c; will-change:transform; }

/* ---------- 11d. FIM DO CURSOR DE TEXTO ---------- */
/* O ponteiro virava "I" de seleção sobre qualquer palavra (Piscina,
   Quadras, títulos...), o que fazia o site parecer um documento.

   ⚠️ O truque aqui é o `:where()`: ele ZERA a especificidade do
   seletor. Estilos de autor sempre vencem a folha do navegador, então
   isto derruba o `cursor:auto` padrão — mas PERDE para qualquer regra
   de cursor já escrita no style.css. Ou seja: os `cursor:pointer`,
   `zoom-in` e `text` que já existem continuam valendo sozinhos, sem eu
   precisar listar um por um (e sem risco de esquecer algum).

   O texto continua SELECIONÁVEL — só o ícone do ponteiro muda. Quem
   quiser copiar um telefone ainda consegue arrastar e copiar. */
:where(html.fx body *){ cursor:default; }

/* campos de digitação precisam do "I" de volta */
html.fx textarea,
html.fx input:not([type="button"]):not([type="submit"]):not([type="checkbox"]):not([type="radio"]),
html.fx [contenteditable="true"]{ cursor:text; }

/* ---------- 11c. BARRA DE ROLAGEM ---------- */
/* A barra padrão do Windows é cinza e quadrada — destoa de tudo. Aqui
   ela vira um trilho fino e translúcido com o polegar no degradê da
   marca.
   ⚠️ Nada de `scrollbar-gutter: stable`: a página SEMPRE rola, então
   não há pulo de layout a prevenir, e a reserva só abre uma faixa
   vazia à direita quando o navegador esconde a barra. */
html.fx *{ scrollbar-width:thin; scrollbar-color:var(--green) transparent; }
html.fx ::-webkit-scrollbar{ width:11px; height:11px; }
html.fx ::-webkit-scrollbar-track{
  background:color-mix(in srgb, var(--line) 45%, transparent);
}
html.fx ::-webkit-scrollbar-thumb{
  border-radius:99px;
  background:var(--grad);
  /* a borda transparente com background-clip afina o polegar sem
     estreitar a área de clique */
  border:3px solid transparent;
  background-clip:content-box;
}
html.fx ::-webkit-scrollbar-thumb:hover{
  border-width:2px;
  background:linear-gradient(160deg, var(--green-dark), var(--green));
  background-clip:content-box;
}

/* ---------- 11b. ENXUGADO PARA O CELULAR ---------- */
/* No celular não há 3D (o fx.js nem baixa o three.js) nem molas de
   ponteiro. O que sobra de caro é composite de tela cheia — e é isso
   que sai daqui. O movimento continua, por opacidade e deslocamento. */
@media (max-width: 720px){
  /* o grão recompõe a tela inteira a cada quadro por causa do
     mix-blend-mode: caro demais para o que entrega num tela pequena */
  html.fx body::after{ display:none; }
  /* blur é o filtro mais caro numa GPU móvel — ver a nota no fx.js */
  html.fx .hero-copy, html.fx .section-head p, html.fx .reveal{ filter:none !important; }
}

/* ---------- 12. MOVIMENTO REDUZIDO ---------- */
/* Cinto de segurança: mesmo que a classe .fx entre por engano, quem
   pediu menos movimento não recebe nada disto. */
@media (prefers-reduced-motion: reduce){
  #hero-3d, #game-3d, .fx-scene, .fx-ripple, #fx-curtain, .fx-shine{ display:none !important; }
  html.fx body::after{ display:none; }
  html.fx .hero-float, html.fx .marquee-track{ animation:none; }
  html.fx #h-track{ perspective:none; }
}
