/* ============================================================
   Ápice, sistema de movimento
   Segue a especificação BuildV (skills/gerar-frontend/sistema-de-movimento.md):
   movimento curto, easing longo, uma ideia de movimento por seção, e nada
   que o conteúdo precise para existir.

   Intensidade calibrada em ~4/10: deslocamento de 24px, blur de 5px,
   parallax <= 0.12, sem bounce e sem scale exagerado.

   Todo o estado inicial invisível vive atrás de `html.js`, que o motor
   aplica antes do primeiro paint. Sem JS, ou sob prefers-reduced-motion,
   a página é 100% legível.
   ============================================================ */

:root{
  /* Easings canônicos da especificação */
  --e:  cubic-bezier(.16,.84,.28,1);   /* entradas e reveals */
  --e2: cubic-bezier(.4,0,.2,1);       /* UI: header, hover, chrome */

  --dur-ui:.45s;    /* microinteração */
  --dur-in:.85s;    /* entrada de bloco */
  --dur-fig:1.1s;   /* entrada de imagem */
  --dur-mask:1.5s;  /* cortina */
}

/* ------------------------------------------------------------
   1. Entradas: [data-anim]. A duração pode ser encurtada pelo motor
   via --dur quando não houver tela sobrando para a animação caber.
   ------------------------------------------------------------ */
.js [data-anim]{
  opacity:0;
  will-change:opacity,transform,filter;
  transition:
    opacity   var(--dur,var(--dur-in)) var(--e),
    transform var(--dur,var(--dur-in)) var(--e),
    filter    var(--dur,var(--dur-in)) var(--e),
    clip-path var(--dur,var(--dur-fig)) var(--e);
  transition-delay:var(--d,0ms);
}

.js [data-anim="up"]    {transform:translateY(24px);filter:blur(5px)}
.js [data-anim="down"]  {transform:translateY(-20px);filter:blur(5px)}
.js [data-anim="left"]  {transform:translateX(-26px);filter:blur(5px)}
.js [data-anim="right"] {transform:translateX(26px);filter:blur(5px)}

/* Bloco que já carrega um título dividido em palavras: só fade,
   para não duplicar deslocamento ("o texto carrega o movimento") */
.js [data-anim="soft"]  {transform:none;filter:none}

/* Figuras: anima o invólucro, nunca o <img>, senão o zoom de hover morre */
.js [data-anim="fig"]{transform:scale(.965);filter:blur(4px)}

/* Cortina de baixo para cima; a imagem interna sai de um leve zoom */
.js [data-anim="mask"]{
  opacity:1;
  transform:none;
  clip-path:inset(0 0 101% 0);
}
.js [data-anim="mask"] > img{
  transform:scale(1.08);
  transition:transform var(--dur-mask) var(--e);
  transition-delay:var(--d,0ms);
}

/* Cortina para texto: a folga vertical evita cortar acentos e descendentes */
.js [data-anim="curtain"]{
  opacity:1;
  transform:none;
  clip-path:inset(-.18em -.1em 101% -.1em);
}

.js [data-anim].is-in{
  opacity:1;
  transform:none;
  filter:none;
  --rule-scale:1;
}
.js [data-anim="mask"].is-in    {clip-path:inset(0 0 0 0)}
.js [data-anim="curtain"].is-in {clip-path:inset(-.18em -.1em -.35em -.1em)}
.js [data-anim="mask"].is-in > img{transform:none}

/* Terminou: devolve a camada de composição ao navegador */
.js [data-anim].is-done{will-change:auto}

/* Um contêiner que só orquestra o stagger — isto é, que carrega outro
   [data-anim] dentro — não pode também se deslocar: o filho somaria dois
   movimentos (no "sobre", ainda por cima em eixos cruzados, o pai para a
   esquerda e o filho para cima). O contêiner fica passivo e o filho carrega
   o único movimento da seção, como já fazem .services, .process e .grid. */
.js [data-anim]:has([data-anim]){
  opacity:1;transform:none;filter:none;transition:none;will-change:auto;
}

/* Revelação sem transição: para quem rolou rápido, voltou, saltou de âncora,
   já está no fim da página, ou não tem tela sobrando para a animação caber. */
.js [data-anim].is-instant,
.js [data-anim].is-instant > img,
.js [data-anim].is-instant .w > i,
.js .hero.is-instant .hero__inner > *,
.js .hero.is-instant .hero__media img{
  transition:none!important;
  transition-delay:0ms!important;
}

/* ------------------------------------------------------------
   2. Título palavra por palavra
   Cada palavra ganha uma máscara e sobe de dentro dela. O motor só
   divide títulos de texto puro, para não mexer em marcação alheia.
   ------------------------------------------------------------ */
.w{
  display:inline-block;
  overflow:hidden;
  vertical-align:top;
  /* a folga acomoda acentos e descendentes sem que a máscara os corte */
  padding:.14em .03em .2em;
  margin:-.14em -.03em -.2em;
}
.w > i{
  display:inline-block;
  font-style:inherit;
  will-change:transform;
}
.js .w > i{
  transform:translateY(112%);
  transition:transform .9s var(--e);
  transition-delay:var(--wd,0ms);
}
.js .is-in .w > i{transform:none}
.js .is-done .w > i{will-change:auto}

/* ------------------------------------------------------------
   3. Filetes que crescem da esquerda
   ------------------------------------------------------------ */
.eyebrow__rule{
  transform-origin:left center;
  transform:scaleX(var(--rule-scale,1));
  transition:transform var(--dur-in) var(--e);
  transition-delay:var(--d,0ms);
}

.step{position:relative;border-top-color:var(--rule)}
.step__rule{
  position:absolute;inset:-1px auto auto 0;
  display:block;height:1px;width:100%;
  background:var(--bronze);
  transform-origin:left center;
  transform:scaleX(var(--rule-scale,1));
  transition:transform var(--dur-fig) var(--e);
  transition-delay:var(--d,0ms);
}
.js .step[data-anim]{--rule-scale:0}
.js .step[data-anim].is-in{--rule-scale:1}
.js .eyebrow[data-anim]{--rule-scale:0}
.js .eyebrow[data-anim].is-in{--rule-scale:1}

/* ------------------------------------------------------------
   4. Hero: entrada encadeada no load, foto com parallax leve
   ------------------------------------------------------------ */
.js .hero__inner > *{
  opacity:0;
  transform:translateY(22px);
  filter:blur(4px);
  transition:
    opacity var(--dur-in) var(--e),
    transform var(--dur-in) var(--e),
    filter var(--dur-in) var(--e);
  transition-delay:var(--d,0ms);
}
.js .hero.is-ready .hero__inner > *{opacity:1;transform:none;filter:none}

.js .hero__media img{
  transform:scale(1.075);
  transition:transform 1.8s var(--e);
}
.js .hero.is-ready .hero__media img{transform:none}

.hero__media{will-change:transform}
.hero.is-ready .hero__media{transform:translate3d(0,var(--py,0px),0)}

/* ------------------------------------------------------------
   5. Faixas de imagem com parallax
   ------------------------------------------------------------ */
.band{position:relative;overflow:hidden}
.band__media{position:relative;display:grid;overflow:hidden;background:var(--ink);width:var(--shell);margin-inline:auto}
.band__frame{grid-area:1/1;position:relative;overflow:hidden;aspect-ratio:21/9}
.band__frame img{
  position:absolute;inset:-10% 0;
  width:100%;height:120%;object-fit:cover;
  transform:translate3d(0,var(--py,0px),0);
  will-change:transform;
}
.band__frame::after{
  content:"";position:absolute;inset:0;
  background:
    linear-gradient(102deg,
      rgba(18,18,18,.93) 0%,
      rgba(18,18,18,.86) 18%,
      rgba(18,18,18,.62) 38%,
      rgba(18,18,18,.3)  58%,
      rgba(18,18,18,.12) 78%,
      rgba(18,18,18,.06) 100%),
    linear-gradient(0deg,
      rgba(18,18,18,.6) 0%,
      rgba(18,18,18,.18) 34%,
      rgba(18,18,18,0)  62%);
}
.band__quote{
  grid-area:1/1;align-self:end;justify-self:start;z-index:1;
  width:min(36rem,88%);
  padding:clamp(1.5rem,4vw,3rem);
}
.band__quote p{
  font-family:"Jost",sans-serif;font-weight:300;
  font-size:clamp(1.15rem,2.2vw,1.8rem);line-height:1.22;
  letter-spacing:-.02em;color:var(--paper);
}
.band__quote span{
  display:block;margin-top:1rem;
  font-family:"Jost",sans-serif;font-size:var(--fs-eyebrow);font-weight:400;
  letter-spacing:.26em;text-transform:uppercase;color:var(--bronze);
}

/* ------------------------------------------------------------
   6. Sobre: composição de duas fotos
   ------------------------------------------------------------ */
.about__media{position:relative;padding-bottom:clamp(3rem,7vw,5.5rem)}
.about__media > .about__shot{position:relative;overflow:hidden}
.about__shot img{width:100%;aspect-ratio:4/3;object-fit:cover}
/* precisa da mesma especificidade do seletor do container acima,
   senão o position:relative dele vence e a foto sai do lugar */
.about__media > .about__shot--sub{
  position:absolute;right:clamp(-1rem,-1.5vw,0rem);bottom:0;z-index:2;
  width:min(46%,230px);
  border:6px solid var(--ink);
}
.about__shot--sub img{aspect-ratio:1/1}

/* ------------------------------------------------------------
   7. UI e microinterações
   ------------------------------------------------------------ */
.work::after{
  content:"";position:absolute;inset:0;z-index:2;
  border:1px solid transparent;
  transition:border-color var(--dur-ui) var(--e2);
  pointer-events:none;
}
.work:hover::after,.work:focus-visible::after{border-color:var(--bronze)}

.work__cap{opacity:.94;transition:transform var(--dur-ui) var(--e),opacity var(--dur-ui)}
.work:hover .work__cap,.work:focus-visible .work__cap{transform:translateY(-4px);opacity:1}

.service{position:relative}
.service::after{
  content:"";position:absolute;inset:auto 0 -1px 0;height:1px;
  background:var(--bronze-ink);
  transform:scaleX(0);transform-origin:left center;
  transition:transform var(--dur-ui) var(--e);
}
.service:hover::after{transform:scaleX(1)}

.footer a,.nav a{transition:color var(--dur-ui) var(--e2)}

/* Header: encolhe depois da primeira dobra, devolvendo altura à leitura */
.header{transition:background .45s var(--e2),border-color .45s var(--e2),height .45s var(--e2)}
.header.is-compact{height:60px}
.header .brand img{transition:width .45s var(--e2)}
.header.is-compact .brand img{width:clamp(104px,13vw,132px)}

/* Barra de leitura */
.progress{
  position:fixed;inset:0 0 auto;z-index:101;
  height:2px;background:var(--bronze);
  transform:scaleX(var(--p,0));transform-origin:left center;
  will-change:transform;pointer-events:none;
}

/* ------------------------------------------------------------
   8. prefers-reduced-motion desliga tudo
   O motor nem chega a aplicar a classe .js, então nenhum estado
   inicial escondido existe. Estas regras são o cinto de segurança.
   ------------------------------------------------------------ */
@media (prefers-reduced-motion:reduce){
  .js [data-anim],
  .js [data-anim="mask"],
  .js [data-anim="curtain"],
  .js [data-anim="fig"],
  .js .hero__inner > *{
    opacity:1!important;transform:none!important;
    filter:none!important;clip-path:none!important;
    transition:none!important;
  }
  .js [data-anim="mask"] > img,
  .js .hero__media img{transform:none!important;transition:none!important}
  .js .w > i{transform:none!important;transition:none!important}
  .w{overflow:visible;padding:0;margin:0}
  .hero.is-ready .hero__media,
  .band__frame img{transform:none!important}
  .eyebrow__rule,.step__rule{transform:scaleX(1)!important;transition:none!important}
  .progress{display:none}
  .work__cap{transform:none;opacity:1}
  .header,.header.is-compact{height:var(--header-h);transition:none}
  *,*::before,*::after{
    animation-duration:.001ms!important;
    animation-iteration-count:1!important;
    transition-duration:.001ms!important;
    scroll-behavior:auto!important;
  }
}

/* ------------------------------------------------------------
   9. Responsivo do que este arquivo acrescenta
   ------------------------------------------------------------ */
@media (max-width:1024px){
  .band__frame{aspect-ratio:16/9}
  .band__frame::after{
    background:linear-gradient(0deg,
      rgba(18,18,18,.94) 0%,rgba(18,18,18,.8) 26%,
      rgba(18,18,18,.42) 56%,rgba(18,18,18,.12) 100%);
  }
  .band__quote{width:min(32rem,100%)}
}
@media (max-width:560px){
  .band__frame{aspect-ratio:4/5}
  .about__media{padding-bottom:0}
  .about__media > .about__shot--sub{
    position:relative;right:auto;bottom:auto;
    width:62%;margin:-3.5rem 0 0 auto;border-width:5px;
  }
}
