/* ============================================================
   talude · engenharia e obras pesadas
   Demo neutr0 · conceito "A Cota"

   NADA AQUI É AFIRMADO, TUDO É MEDIDO.
   Uma variável só, --c (0→1), escrita pelo scroll, desenha toda
   linha de cota da página. Em vez de "somos grandes", uma cota
   mede 182.400 m². Em vez de "entregamos no prazo", uma cota mede
   prometido contra entregue, e o argumento é a distância zero.

   Idioma: painel de instrumento (teardown do hubtown.co.in).
   Código nosso. Zero asset, zero foto, zero biblioteca.
   ============================================================ */

/* ---------- tokens ---------- */
:root {
  /* DUAS CORES. A terceira é ação, e ela aparece em ~3% da página. */
  --breu:  #0a0d10;   /* fundo */
  --aco:   #dfe4ea;   /* tinta: texto, linha, cota, marca */
  --ambar: #ffb020;   /* SÓ ação e valor medido. Nunca decoração. */

  /* não temos cinza, temos aço com alpha (a lição da loud) */
  --aco-60: rgb(223 228 234 / .60);
  --aco-40: rgb(223 228 234 / .40);
  --aco-20: rgb(223 228 234 / .20);
  --aco-10: rgb(223 228 234 / .10);
  --aco-05: rgb(223 228 234 / .05);

  --grot: "Archivo", system-ui, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, monospace;

  --moldura: .625rem;
  --barra-h: 41px;    /* altura real da barra fixa do rodapé, medida */
  --nav-h: 50px;      /* altura real do header fixo, medida */
  --bevel: 28px;
  --max: 1200px;      /* container */
  --texto: 800px;     /* nenhum parágrafo passa disso */

  /* sai rápido, freia longo: peça pesada assentando */
  --ease: cubic-bezier(.2, 0, 0, 1);
}
@media (min-width: 768px) { :root { --moldura: 2.5rem; } }

*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--breu);
  color: var(--aco);
  font-family: var(--grot);
  font-size: 16px;
  line-height: 1.5;
  letter-spacing: .01em;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;              /* clip, NÃO hidden: hidden mata sticky */
}

img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }

/* ============================================================
   A MOLDURA · o site é uma janela dentro de um quadro chanfrado
   ============================================================ */
.moldura {
  position: fixed;
  inset: var(--moldura);
  border: 1px solid var(--aco-20);
  clip-path: polygon(
    var(--bevel) 0, 100% 0,
    100% calc(100% - var(--bevel)),
    calc(100% - var(--bevel)) 100%,
    0 100%, 0 var(--bevel)
  );
  pointer-events: none;
  z-index: 60;
}
@media (max-width: 767px) { .moldura { display: none; } }

/* As faixas de fora da moldura, em cima e embaixo.
   A moldura é decorativa, mas a página rola de borda a borda por trás
   dela: sempre rolou. Enquanto o header ia embora junto com o scroll
   ninguém via. Com o header FIXO, aparece conteúdo deslizando na fresta
   de 40px acima dele, e lê como defeito.
   Estas duas faixas tampam a fresta. z-index 55: acima do conteúdo,
   abaixo da moldura (60), da barra (65) e do header (70). */
@media (min-width: 768px) {
  body::before, body::after {
    content: "";
    position: fixed; left: 0; right: 0;
    height: var(--moldura);
    background: var(--breu);
    pointer-events: none;
    z-index: 55;
  }
  body::before { top: 0; }
  body::after  { bottom: 0; }
}

/* ============================================================
   CHANFRO · efeitos/formas/Beveled Box.txt
   2 cantos em diagonal. 4 cantos vira crachá, 2 vira sistema.
   px, nunca %: com % o chanfro muda de tamanho conforme a caixa.
   ============================================================ */
.bevel {
  --b: 18px;
  position: relative;
  background: var(--aco-20);      /* a caixa externa É a borda */
  padding: 1px;
  clip-path: polygon(
    var(--b) 0, 100% 0, 100% calc(100% - var(--b)),
    calc(100% - var(--b)) 100%, 0 100%, 0 var(--b)
  );
}
.bevel__in {
  height: 100%;
  background: var(--breu);
  clip-path: polygon(
    calc(var(--b) - 1px) 0, 100% 0, 100% calc(100% - var(--b) + 1px),
    calc(100% - var(--b) + 1px) 100%, 0 100%, 0 calc(var(--b) - 1px)
  );
}

/* ============================================================
   TIPOGRAFIA
   Grotesca no corpo. Mono SÓ em metadado. (mono no corpo = blog)
   Tracking negativo em em, NUNCA em px: em px o título colapsa
   no celular (o erro publicado da sunergy).
   ============================================================ */
h1, h2, h3 { font-weight: 600; letter-spacing: -.035em; line-height: 1.02; margin: 0; }

h1 { font-size: clamp(2.2rem, 6.5vw, 4.4rem); text-transform: uppercase; }
h2 { font-size: clamp(1.8rem, 4vw, 2.9rem); }
h3 { font-size: 1.05rem; letter-spacing: -.02em; }

p { margin: 0; max-width: var(--texto); color: var(--aco-60); line-height: 1.55; }

/* metadado · o único lugar onde a mono entra */
.meta {
  font-family: var(--mono);
  font-size: .68rem;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: .12em;
  color: var(--aco-40);
}
.eyebrow {
  display: inline-flex; align-items: center; gap: .6rem;
  font-family: var(--mono);
  font-size: .68rem; text-transform: uppercase; letter-spacing: .12em;
  color: var(--aco-40);
}
.eyebrow::before {
  content: ""; width: 7px; height: 7px;
  background: var(--ambar);      /* o acento, do tamanho de um grão */
  flex: none;
}

/* ============================================================
   >>> A COTA · o conceito <<<
   Uma linha de cota é: dois traços de chamada, uma linha entre
   eles com setas, e o valor. --c (0→1) desenha ela.
   O scroll escreve --c com animation-timeline, ZERO JS.
   ============================================================ */
.cota {
  --c: 1;                         /* padrão: cotada. sem suporte, aparece pronta */
  display: grid;
  /* nome · a linha que cresce · o valor. A do meio é que estica. */
  grid-template-columns: auto minmax(3rem, 1fr) auto;
  align-items: center;
  gap: 1rem;
  padding: .9rem 0;
  border-top: 1px solid var(--aco-10);
}

/* o trilho da cota: os dois traços de chamada + a linha */
.cota__linha {
  position: relative;
  height: 10px;
  min-width: 0;
}
.cota__linha::before,                     /* traço de chamada esquerdo */
.cota__linha::after {                     /* traço de chamada direito */
  content: "";
  position: absolute; top: 0; bottom: 0;
  width: 1px;
  background: var(--aco-40);
}
.cota__linha::before { left: 0; }
.cota__linha::after {
  left: calc(var(--c) * 100%);
  transform: translateX(-1px);
}
/* a linha que cresce entre as chamadas */
.cota__linha > i {
  position: absolute; top: 50%; left: 0;
  height: 1px; width: 100%;
  background: var(--aco-40);
  transform: scaleX(var(--c));
  transform-origin: 0 50%;
}
/* o valor: mono, e em âmbar porque é O DADO */
.cota__valor {
  font-family: var(--mono);
  font-size: .8rem;
  letter-spacing: .04em;
  color: var(--ambar);
  white-space: nowrap;
  opacity: var(--c);
}
.cota__nome { font-size: .9rem; color: var(--aco-60); }

/* o scroll escreve --c. CSS puro, sem listener, sem GSAP. */
@supports (animation-timeline: view()) {
  @property --c {
    syntax: "<number>"; inherits: true; initial-value: 1;
  }
  .cota {
    --c: 0;
    animation: cotar linear both;
    animation-timeline: view();
    animation-range: entry 15% cover 42%;
  }
  @keyframes cotar { from { --c: 0 } to { --c: 1 } }
}
/* sem suporte (Firefox hoje), a regra base --c:1 vale: cota pronta.
   NUNCA deixar o estado escondido fora de um gate: é a armadilha
   que já queimou 5 vezes na biblioteca. */
@media (prefers-reduced-motion: reduce) {
  .cota { --c: 1; animation: none; }
}

/* ============================================================
   ESTRUTURA
   ============================================================ */
.wrap { width: 100%; max-width: var(--max); margin-inline: auto; padding-inline: 1.5rem; }
@media (min-width: 768px) { .wrap { padding-inline: 3rem; } }

section { padding-block: clamp(4rem, 11vw, 8.5rem); }
.linha { border-top: 1px solid var(--aco-10); }

/* Com o header fixo, âncora sem isto entrega o título DEBAIXO dele:
   a pessoa clica em "Obras" e cai numa seção decapitada.
   Reserva a altura do header + a margem da moldura + respiro. */
section[id] { scroll-margin-top: calc(var(--moldura) + var(--nav-h) + 1.5rem); }

.cabeca { display: grid; gap: 1.1rem; margin-bottom: 3.2rem; }

/* ---------- nav ---------- */
/* O header ACOMPANHA o scroll, como nas outras demos (aurora e lumière
   são `fixed`, vitalis é `sticky`; a talude era a única `absolute` e
   ficava pra trás).

   Ele é o espelho da `.barra` do rodapé: mesmo fundo, mesmo blur, mesma
   margem. O site vira um quadro com uma barra em cima e outra embaixo. */
.nav {
  position: fixed;
  top: var(--moldura); left: var(--moldura); right: var(--moldura);
  z-index: 70;
  padding: .75rem 0;
  background: rgb(10 13 16 / .82);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--aco-10);
  /* o chanfro do canto superior esquerdo, igual ao da moldura: sem isto
     a barra passa reta por cima do canto cortado e denuncia o truque */
  clip-path: polygon(var(--bevel) 0, 100% 0, 100% 100%, 0 100%, 0 var(--bevel));
}
@media (max-width: 767px) {
  /* sem moldura no celular: a barra encosta nas bordas, igual à de baixo */
  .nav { top: 0; left: 0; right: 0; clip-path: none; padding: .7rem 0; }
}
.nav__in { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.nav__links { display: none; gap: 2rem; }
@media (min-width: 900px) { .nav__links { display: flex; } }
.nav__links a {
  font-family: var(--mono); font-size: .7rem;
  text-transform: uppercase; letter-spacing: .12em; color: var(--aco-60);
  transition: color .25s var(--ease), filter .4s;
}
/* foco por subtração: rebaixa os outros em vez de destacar um (loud) */
.nav__links:hover a { filter: blur(2px); opacity: .45; }
.nav__links a:hover { filter: none; opacity: 1; color: var(--aco); }

/* ---------- a marca, erguida em grade ---------- */
/* efeitos/intro/Logo Grid Build.txt · cada perna é uma célula que
   estica. transform-box: fill-box é OBRIGATÓRIO, senão o origin é
   a viewBox inteira e as peças voam pro meio da tela. */
.marca { height: 20px; width: auto; }
.marca rect { fill: var(--aco); transform-box: fill-box; }

@media (scripting: enabled) {
  .marca.build .col { transform: scaleY(0); transform-origin: 50% 0;
                      animation: colGrow .7s var(--ease) var(--d, 0ms) forwards; }
  .marca.build .row { transform: scaleX(0); transform-origin: 0 50%;
                      animation: rowGrow .7s var(--ease) var(--d, 0ms) forwards; }
}
@keyframes colGrow { to { transform: scaleY(1) } }
@keyframes rowGrow { to { transform: scaleX(1) } }
@media (prefers-reduced-motion: reduce) {
  .marca .col, .marca .row { transform: none !important; animation: none !important; }
}

/* ---------- botões · retângulo, nunca pílula ---------- */
/* pílula (border-radius: 999px) virou assinatura de site gerado
   por IA. Card de canto reto no lugar. */
.btn {
  display: inline-flex; align-items: center; gap: .8rem;
  padding: .85rem 1.4rem;
  background: var(--ambar); color: var(--breu);
  font-family: var(--mono); font-size: .72rem;
  text-transform: uppercase; letter-spacing: .1em;
  border: 0; cursor: pointer;
  transition: transform .25s var(--ease);
}
.btn:hover { transform: translateY(-2px); }
.btn--fantasma {
  background: transparent; color: var(--aco);
  border: 1px solid var(--aco-20);
}
.btn--fantasma:hover { border-color: var(--aco-40); }

/* ============================================================
   >>> O PALCO <<<  a peça que faz o site prender.

   O que faz a hubtown segurar não é "ter 3D": é ter UM OBJETO no
   centro, dentro de uma ATMOSFERA COM PROFUNDIDADE, e você rolar
   PARA DENTRO dele. Aqui isso é CSS puro: uma grade de terreno em
   perspectiva, névoa por cima, e a obra se ERGUENDO sozinha.

   Eles pagam 17 MB de GLB + KTX2 + Draco + Basis por isso.
   Aqui custa zero byte.

   A obra monta NO LOAD, não no scroll: cada peça tem o seu --d e a
   sequência inteira leva ~2,7s. A régua de fases acende junto, com o
   --fd de cada uma casando com o --d da peça correspondente:

     .25s  terreno            .37s  ▪ TERRENO
     .55s  sapatas            .73s  ▪ FUNDAÇÃO
     .65s  pilares           1.21s  ▪ ESTRUTURA
    1.10s  banzo inferior    1.57s  ▪ COBERTURA
    1.40s  banzo superior    2.29s  ▪ MEDIÇÃO
    1.75s  treliça
    2.15s  as cotas
   ============================================================ */
/* A obra monta SOZINHA no load, não no scroll.

   Antes um `@property --e` era escrito por `animation-timeline: view()`
   num runway de 220vh: quem abria via um terreno vazio e só descobria o
   efeito se rolasse. O melhor momento do site ficava escondido atrás de
   uma ação do usuário, e ainda obrigava a rolar 1080px de nada pra chegar
   no conteúdo.

   Trocar o motor de scroll por TEMPO derrubou, em cascata:
     · o runway de 220vh          → o palco é uma tela só
     · o `position: sticky`        → e as 3 armadilhas dele
     · o `contain` x `cover`       → não existe mais range pra errar
     · o `@property --e` + clamp   → cada peça tem seu --d, e o Firefox
                                     rejeitava o clamp sem unidade
     · ~45 linhas de JS            → intro + listener de scroll
     · a intro                     → a MONTAGEM é a abertura

   Sobrou @keyframes com delay, que todo navegador faz desde sempre, e o
   palco monta com o JS desligado. */
/* padding ZERO: a regra genérica `section { padding-block: clamp(4rem,
   11vw, 8.5rem) }` estava pegando o palco junto e enfiando 136px em cima
   dele. O palco tem altura de tela própria e paddings próprios, então o
   padding de seção empurrava a dobra inteira 136px pra baixo e derrubava
   os CTAs pra fora. Não apareceu como "layout torto": apareceu como
   "o CTA sumiu", que é bem mais difícil de ligar à causa. */
.palco { position: relative; padding: 0; }
.palco__stick {
  /* `relative` é OBRIGATÓRIO, e não é enfeite: o `.chao` é absolute e
     estoura 60% pros lados de propósito. `overflow: clip` só recorta
     descendente absoluto se ESTE elemento for o bloco-contêiner dele.
     Quando o palco era `sticky` ele já era contêiner e o clip valia; ao
     trocar sticky por tempo eu deixei ele estático, o contêiner do chão
     subiu pro `.palco` e o clip parou de valer: 864px de overflow
     horizontal no desktop, em silêncio. */
  position: relative;
  /* `height`, não `min-height`. Com min-height o palco CRESCE pra caber o
     conteúdo em vez de contê-lo: o `justify-content: center` para de
     comprimir e o subtítulo e os CTAs caem fora da dobra. Com height fixo
     a obra cede (ela tem `min-height: 0` e `max-height` em vh) e o texto,
     que é `flex: none`, fica inteiro. O objeto cede, o texto não. */
  height: 100dvh;
  /* flex, NÃO absolute. A obra e o texto dividem a altura entre si:
     com `position: absolute` eu tinha que adivinhar a altura do texto,
     e errei: os CTAs caíam fora da dobra. Aqui a obra encolhe (min-h:0)
     e o texto pega o que precisa. */
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: clamp(1.2rem, 3vh, 2.4rem);
  padding: 6rem 1.5rem 5.5rem;
  overflow: clip;
}

/* ---------- o chão · grade em perspectiva ---------- */
/* uma grade chapada, deitada com rotateX. é o truque mais barato
   que existe pra criar profundidade, e não usa nem imagem nem 3D. */
.chao {
  position: absolute; inset: 52% -60% -30% -60%;
  perspective: 340px;
  perspective-origin: 50% 0;
  pointer-events: none;
  z-index: 0;
}
.chao__malha {
  position: absolute; inset: 0;
  transform: rotateX(74deg);
  transform-origin: 50% 0;
  background:
    repeating-linear-gradient(90deg, var(--aco-10) 0 1px, transparent 1px 64px),
    repeating-linear-gradient(0deg,  var(--aco-10) 0 1px, transparent 1px 64px);
  /* a grade dissolve na distância: é isso que vira horizonte */
  -webkit-mask-image: linear-gradient(transparent 0%, #000 38%, #000 100%);
          mask-image: linear-gradient(transparent 0%, #000 38%, #000 100%);
}

/* ---------- a névoa ---------- */
/* fundo FIRME. o INDICE é claro: fundo mudando de cor com o scroll
   lê como estranho. isto não muda de cor, só dá ar à distância. */
.neblina {
  position: absolute; inset: 0;
  pointer-events: none; z-index: 1;
  background:
    radial-gradient(120% 62% at 50% 58%, rgb(223 228 234 / .07) 0%, transparent 62%),
    linear-gradient(var(--breu) 0%, transparent 22%, transparent 74%, var(--breu) 100%);
}

/* ---------- a obra ---------- */
.obra-svg {
  position: relative; z-index: 2;
  flex: 0 1 auto;
  min-height: 0;                   /* deixa a obra encolher em tela baixa */
  width: min(72%, 620px);
  display: flex;
}
.obra-svg svg { width: 100%; height: 100%; max-height: 46vh; object-fit: contain; overflow: visible; }
.obra-svg .est { fill: none; stroke: var(--aco); stroke-width: 1.4; stroke-linecap: square; }
.obra-svg .aux { fill: none; stroke: var(--aco-40); stroke-width: 1; }
.obra-svg .dim { fill: none; stroke: var(--ambar); stroke-width: 1; }
.obra-svg .rot { font-family: var(--mono); font-size: 7px; fill: var(--ambar); letter-spacing: .1em; }

/* Cada peça se desenha no seu tempo, com o próprio --d de atraso.
   pathLength="1" no HTML normaliza tudo pra comprimento 1: dashoffset
   1 = apagado, 0 = pronto. Sem medir nada em JS e sem o DrawSVGPlugin
   (que é pago).

   >>> Aqui morava um `clamp(0, calc((var(--ate) - var(--e)) / ...), 1)`
   que lia uma variável de progresso compartilhada. Duas razões pra ter
   morrido:

   1. O FIREFOX REJEITA. Medido, não deduzido:
      CSS.supports('stroke-dashoffset','clamp(0, calc((0.18 - 0.5) / 0.18), 1)')
      → false. Ele não aceita clamp/calc SEM UNIDADE nessa propriedade, a
      declaração inteira vira inválida e cai pro padrão 0px = desenhado.
      Resultado: no Firefox a obra nascia pronta e a régua de fases
      acendia do lado de uma estrutura parada. Pior que não ter efeito.
      (E cuidado: `CSS.supports` com `var()` dentro devolve TRUE sempre,
      porque não dá pra validar var() em tempo de parse. Ele mente. Testar
      com o valor literal.)

   2. NÃO PRECISA. A engenhoca do --e existia porque scroll precisa de uma
      variável de progresso compartilhada. Com o motor em TEMPO, cada peça
      só precisa do próprio atraso, e isso é @keyframes puro: funciona em
      todo navegador, sem @property, sem calc, sem clamp. */
.obra-svg [data-d] {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: desenha var(--dur, .45s) linear var(--d) both;
}
@keyframes desenha { from { stroke-dashoffset: 1 } to { stroke-dashoffset: 0 } }

.obra-svg .rot { opacity: 0; animation: surge .3s linear var(--d) both; }
@keyframes surge { from { opacity: 0 } to { opacity: 1 } }

@media (prefers-reduced-motion: reduce) {
  .obra-svg [data-d] { stroke-dashoffset: 0; animation: none; }
  .obra-svg .rot { opacity: 1; animation: none; }
}

/* ---------- a régua de fases, na esquerda ---------- */
/* a hubtown tem FUTURE/INNOVATION/... acendendo no scroll. aqui as
   fases são as da obra, que é o que a empresa de fato vende. */
.fases {
  position: absolute; left: 0; top: 50%; translate: 0 -50%;
  z-index: 3;
  display: grid; gap: .85rem;
  list-style: none; margin: 0; padding: 0;
}
@media (max-width: 899px) { .fases { display: none; } }
.fases li {
  display: flex; align-items: center; gap: .6rem;
  font-family: var(--mono); font-size: .64rem;
  text-transform: uppercase; letter-spacing: .12em;
  color: var(--aco-20);
  /* acende no seu momento da montagem. --fd vem inline no HTML e é o
     mesmo instante da fatia de --e da peça correspondente.
     Antes isto era JS lendo o scroll a cada frame; virou uma linha. */
  animation: faseOn .4s var(--ease) var(--fd) both;
}
@keyframes faseOn { from { color: var(--aco-20) } to { color: var(--aco) } }

.fases li::before {
  content: ""; width: 6px; height: 6px; flex: none;
  background: var(--aco-20);
  animation: faseDot .4s var(--ease) var(--fd) both;
}
@keyframes faseDot { from { background: var(--aco-20) } to { background: var(--ambar) } }

@media (prefers-reduced-motion: reduce) {
  .fases li { color: var(--aco); animation: none; }
  .fases li::before { background: var(--ambar); animation: none; }
}

/* ---------- o texto, DENTRO do palco ---------- */
/* a manchete e a obra dividem a mesma tela. É o que a hubtown faz:
   objeto no centro, manchete embaixo, índice na esquerda. Se o texto
   ficar depois do palco, a primeira dobra vira um terreno vazio. */
.palco__texto {
  position: relative; z-index: 4;
  flex: none;
  width: min(100%, var(--max));
  text-align: center;
}
/* no palco a manchete é MENOR que a de seção: ela divide a tela com a
   obra, e "quem grita é infoproduto" (hierarquia por posição, não escala) */
.palco__texto h1 {
  font-size: clamp(1.65rem, 4vw, 3.1rem);
  margin-bottom: .9rem;
}
.palco__sub {
  margin-inline: auto; margin-bottom: 1.4rem;
  max-width: 52ch;
  font-size: .92rem;
}
.hero__acoes { display: flex; flex-wrap: wrap; gap: .8rem; justify-content: center; }

@media (max-width: 767px) {
  .palco__stick { padding: 5rem 1.25rem 5rem; }
  .obra-svg { width: 96%; }
  .obra-svg svg { max-height: 34vh; }
  .palco__sub { display: none; }         /* na tela pequena, o palco é a manchete */
}
/* tela baixa e larga (notebook): a obra encolhe antes do texto */
@media (max-height: 720px) {
  .obra-svg svg { max-height: 38vh; }
  .palco__sub { display: none; }
}

/* sem scroll-timeline o palco é estático e vira um herói normal */
@supports not (animation-timeline: view()) {
  .palco__stick { height: auto; padding-block: 8rem 4rem; }
  .obra-svg svg { max-height: none; }
  .chao { display: none; }              /* sem o erguer, a grade não tem função */
}
@media (prefers-reduced-motion: reduce) {
  .obra-svg svg { max-height: none; }
  .chao { display: none; }
}

/* ============================================================
   INTRO · a marca se ergue, e some.
   >>> O SITE NÃO FICA ATRÁS DELA. <<<
   A armadilha nº1 do hubtown é o loader cobrindo tudo: com ele na
   tela o scrollHeight dele é 900px e a home não existe sem JS.
   Aqui a intro é um overlay que some, o conteúdo está sempre no
   DOM, e sem JS ela nunca aparece (mora em scripting: enabled).
   ============================================================ */
.intro { display: none; }
@media (scripting: enabled) {
  .intro {
    position: fixed; inset: 0; z-index: 200;
    display: grid; place-items: center;
    background: var(--breu);
    transition: opacity .6s var(--ease), visibility 0s .6s;
  }
  .intro[hidden], .intro.saiu { opacity: 0; visibility: hidden; pointer-events: none; }
}
.intro__marca { display: grid; gap: 1.1rem; justify-items: center; }
.intro__marca svg { height: 34px; width: auto; }
.intro__pct { font-family: var(--mono); font-size: .64rem; letter-spacing: .18em; color: var(--aco-40); }
@media (prefers-reduced-motion: reduce) { .intro { display: none !important; } }

/* ============================================================
   FICHA · tabela de spec com filete.
   NÃO é tira de stats. Rótulo à esquerda em mono, valor à direita.
   É a forma honesta de listar capacidade, e é o que separa
   "dado provando" de "número decorando".
   ============================================================ */
.ficha { display: grid; gap: 0; margin: 0; }
.ficha__linha {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 1rem;
  align-items: baseline;
  padding: 1.05rem 0;
  border-top: 1px solid var(--aco-10);
}
.ficha__linha:last-child { border-bottom: 1px solid var(--aco-10); }
.ficha dt { font-family: var(--mono); font-size: .7rem; text-transform: uppercase;
            letter-spacing: .1em; color: var(--aco-40); margin: 0; }
.ficha dd { margin: 0; font-size: 1.15rem; font-variant-numeric: tabular-nums;
            letter-spacing: -.02em; text-align: right; }
.ficha dd b { font-weight: 600; }
.ficha dd span { font-family: var(--mono); font-size: .72rem; color: var(--aco-40); margin-left: .4rem; }

/* ============================================================
   OBRAS · a seção que carrega o site.
   Cada obra é cotada em PROMETIDO vs ENTREGUE, e o argumento é
   que a distância é zero. É a única retórica da página.
   ============================================================ */
.obras { display: grid; gap: 1px; background: var(--aco-10); border-block: 1px solid var(--aco-10); }
.obra { background: var(--breu); padding: 2rem 0; counter-increment: o; }
@media (min-width: 900px) {
  .obra { display: grid; grid-template-columns: 3.5rem 1fr 1fr; gap: 2.5rem; align-items: start; }
}
/* numeração de graça, sem escrever número no HTML */
.obra::before {
  content: counter(o, decimal-leading-zero);
  font-family: var(--mono); font-size: .7rem; letter-spacing: .1em;
  color: var(--aco-20);
}
.obra__nome { margin-bottom: .45rem; }
.obra__local { font-family: var(--mono); font-size: .68rem; text-transform: uppercase;
               letter-spacing: .1em; color: var(--aco-40); }
.obra__dados { display: grid; gap: 0; margin-top: 1.2rem; }
@media (min-width: 900px) { .obra__dados { margin-top: 0; } }

/* o par que é o argumento */
.prazo { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-top: 1rem;
         padding-top: 1rem; border-top: 1px solid var(--aco-10); }
.prazo__item .meta { display: block; margin-bottom: .3rem; }
.prazo__item b { font-family: var(--mono); font-size: .92rem; font-weight: 400; letter-spacing: .02em; }
.prazo__item--ok b { color: var(--ambar); }
.prazo__nota { grid-column: 1 / -1; font-family: var(--mono); font-size: .64rem;
               letter-spacing: .08em; color: var(--aco-40); }

/* ============================================================
   MÉTODO · numerado, tracejado. counter faz o 01/02/03.
   ============================================================ */
.metodo { position: relative; counter-reset: m; padding-left: 3.6rem; }
.metodo::before {
  content: ""; position: absolute; left: 1.1rem; top: .6rem; bottom: .6rem;
  border-left: 1px dashed var(--aco-20);
}
.passo { position: relative; padding-block: 0 2.6rem; counter-increment: m; }
.passo:last-child { padding-bottom: 0; }
.passo::before {
  content: counter(m, decimal-leading-zero);
  position: absolute; left: -3.6rem; top: -.15rem;
  width: 2.2rem; height: 2.2rem;
  display: grid; place-items: center;
  border: 1px solid var(--aco-20); background: var(--breu);
  font-family: var(--mono); font-size: .64rem; color: var(--aco-60);
}
.passo h3 { margin-bottom: .5rem; }

/* ============================================================
   REGISTRO · CARDS, não pílulas.
   ============================================================ */
.registro { display: grid; gap: 1rem; }
@media (min-width: 700px) { .registro { grid-template-columns: repeat(3, 1fr); } }
.reg__in { padding: 1.6rem; height: 100%; }
.reg__num { font-family: var(--mono); font-size: 1.5rem; color: var(--ambar);
            letter-spacing: -.02em; margin-bottom: .5rem; }
.reg h3 { margin-bottom: .35rem; }
.reg p { font-size: .88rem; }

/* ============================================================
   CTA
   ============================================================ */
.cta { text-align: center; }
.cta h2 { margin-bottom: 1.2rem; }
.cta p { margin-inline: auto; margin-bottom: 2rem; }

/* ============================================================
   RODAPÉ
   ============================================================ */
/* O padding de baixo RESERVA o espaço da barra fixa.
   Ela é `position: fixed; bottom: var(--moldura)` com ~41px de altura,
   então ocupa os últimos ~81px da tela PRA SEMPRE. Sem esta reserva ela
   deita em cima da última linha do rodapé quando a pessoa chega no fim
   (medido: rodapé terminava em 852, barra começava em 819).
   No celular passava raspando por 7px, o que era sorte e não projeto:
   em outra altura de tela quebrava igual. */
.rodape {
  padding-top: 3rem;
  padding-bottom: calc(var(--moldura) + var(--barra-h) + 2rem);
  border-top: 1px solid var(--aco-10);
}
.rodape__in { display: grid; gap: 2rem; }
@media (min-width: 700px) { .rodape__in { grid-template-columns: repeat(3, 1fr); } }
.rodape a:hover { color: var(--ambar); }
.rodape__fim { margin-top: 2.5rem; padding-top: 1.5rem; border-top: 1px solid var(--aco-10); }

/* ============================================================
   REVEAL · o padrão de 3 atributos, com IntersectionObserver.
   Zero GSAP. E o estado escondido DENTRO de scripting: enabled,
   senão JS quebrado = página apagada pra sempre com o texto lá.
   ============================================================ */
@media (scripting: enabled) {
  [data-reveal] {
    opacity: 0;
    transform: translateY(14px);
    transition: opacity .6s var(--ease), transform .6s var(--ease);
  }
  [data-reveal].in { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1 !important; transform: none !important; transition: none !important; }
}

/* ============================================================
   RODAPÉ FIXO · som + scroll
   ============================================================ */
.barra {
  position: fixed; left: var(--moldura); right: var(--moldura); bottom: var(--moldura);
  z-index: 65;
  display: flex; align-items: center; justify-content: space-between;
  padding: .8rem 1.2rem;
  border-top: 1px solid var(--aco-10);
  background: rgb(10 13 16 / .82);
  backdrop-filter: blur(14px);
}
@media (max-width: 767px) { .barra { left: 0; right: 0; bottom: 0; } }
.som {
  display: inline-flex; align-items: center; gap: .55rem;
  background: none; border: 0; cursor: pointer; padding: 0;
  font-family: var(--mono); font-size: .64rem; text-transform: uppercase;
  letter-spacing: .1em; color: var(--aco-40);
}
.som:hover { color: var(--aco); }
.som__ind { width: 7px; height: 7px; background: var(--aco-20); flex: none; }
.som[aria-pressed="true"] .som__ind { background: var(--ambar); }

/* ============================================================
   MENU · abre em círculo a partir do hambúrguer.
   clip-path: circle() + backdrop-filter. 10 linhas.
   ============================================================ */
.burger {
  display: grid; gap: 4px; padding: .6rem; margin: -.6rem;
  background: none; border: 0; cursor: pointer;
}
@media (min-width: 900px) { .burger { display: none; } }
.burger i { display: block; width: 20px; height: 1px; background: var(--aco); }

#menu {
  position: fixed; inset: 0; z-index: 80;
  display: grid; place-items: center;
  background: rgb(10 13 16 / .96);
  backdrop-filter: blur(28px);
  clip-path: circle(0px at var(--cx, 90%) var(--cy, 6%));
  visibility: hidden;
  /* o delay em visibility é o que impede o menu de engolir clique
     enquanto invisível */
  transition: clip-path .53s var(--ease), visibility 0s .53s;
}
#menu.aberto {
  visibility: visible;
  clip-path: circle(var(--r, 150vmax) at var(--cx, 90%) var(--cy, 6%));
  transition: clip-path .8s var(--ease), visibility 0s;
  /* abre em 800ms, fecha em 533ms: abrir é convite, fechar é obediência */
}
#menu ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 1.6rem; text-align: center; }
#menu a { font-size: 1.6rem; font-weight: 600; letter-spacing: -.03em; }
#menu .fechar {
  position: absolute; top: 1.6rem; right: 1.6rem;
  background: none; border: 0; color: var(--aco); cursor: pointer;
  font-family: var(--mono); font-size: .7rem; letter-spacing: .1em;
}

/* ============================================================
   FAIXA DE DEMONSTRAÇÃO DA NEUTR0
   Prefixo n0- em tudo: este bloco entra em 4 sites de CSS
   diferente e não pode colidir com nenhum. Fonte: aurora.

   O VISUAL é igual ao das outras 3 de propósito: a faixa é da
   neutr0, não do site. Ela não segue a paleta da demo.

   TRÊS COISAS MUDAM AQUI, e as três são a mesma regra da aurora
   ("canto inferior esquerdo porque a vitalis tem o WhatsApp na
   direita"): a faixa não pode deitar em cima do site.

   1. SOBE A ALTURA DA BARRA. A talude tem `.barra` fixa no rodapé
      (som + scroll, --barra-h, z-65) que a aurora não tem. O
      `bottom: 16px` de lá cairia em cima dela. Mesma conta que o
      `.rodape` já faz no padding-bottom.

   2. z-index 70, não 90: acima da barra (65) e da moldura (60),
      mas ABAIXO do #menu (80), senão a faixa flutua por cima do
      menu aberto em tela cheia.

   3. SÓ ENTRA DEPOIS DO PALCO (o bloco `scripting: enabled` mais
      abaixo). Medido: parada no rodapé ela cobre o "Pedir uma
      medição" em TODA tela de desktop, de 1440x900 a 1024x768, e
      nos 1024 cobre os dois botões. O botão do cliente é o que a
      demo existe pra provar; a faixa cobrindo ele custa mais do
      que ela rende. Trocar de canto não resolve: os botões são
      centrados e a faixa tem 566px, então esquerda e direita
      colidem igual. Depois do palco o rodapé fica livre, e quem
      rolou até lá é quem interessa.
   ============================================================ */
.n0-demo {
  position: fixed; z-index: 70;
  left: calc(var(--moldura) + .6rem);
  bottom: calc(var(--moldura) + var(--barra-h) + .6rem);
  display: inline-flex; align-items: center; gap: 12px;
  padding: 9px 9px 9px 14px; border-radius: 999px;
  background: rgba(10,10,12,.92); backdrop-filter: saturate(180%) blur(14px);
  border: 1px solid rgba(255,255,255,.16);
  box-shadow: 0 10px 34px -10px rgba(0,0,0,.7);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
  color: #f4f5f7; text-decoration: none; line-height: 1.3;
  transition: transform .3s cubic-bezier(.16,1,.3,1), border-color .3s;
}
.n0-demo:hover { transform: translateY(-2px); border-color: rgba(255,255,255,.4); }
.n0-demo__m { font-size: .78rem; font-weight: 700; letter-spacing: -.03em; flex-shrink: 0; }
.n0-demo__t { font-size: .68rem; color: rgba(244,245,247,.62); white-space: nowrap; }
.n0-demo__t b { color: #f4f5f7; font-weight: 500; }
.n0-demo__c {
  display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0;
  padding: 7px 13px; border-radius: 999px; background: #f4f5f7; color: #0a0a0c;
  font-size: .66rem; font-weight: 600; white-space: nowrap;
}
.n0-demo__c svg { width: 11px; height: 11px; }
.n0-demo__x {
  display: grid; place-items: center; width: 22px; height: 22px; flex-shrink: 0;
  border-radius: 50%; border: 0; background: transparent; color: rgba(244,245,247,.45);
  font-size: 15px; line-height: 1; cursor: pointer; transition: color .25s, background .25s;
}
.n0-demo__x:hover { color: #f4f5f7; background: rgba(255,255,255,.1); }
.n0-demo.n0-off { display: none; }
@media (max-width: 767px) {
  /* no celular vira barra: pilula com esse texto todo não cabe.
     E a `.barra` cola no bottom: 0, então a conta perde a moldura. */
  .n0-demo {
    left: 10px; right: 10px;
    bottom: calc(var(--barra-h) + 8px);
    border-radius: 12px; padding: 10px 10px 10px 14px;
  }
  .n0-demo__t { white-space: normal; font-size: .62rem; flex: 1; }
}
@media (max-width: 420px){ .n0-demo__t { display: none; } }

/* O estado escondido mora DENTRO de scripting: enabled, igual o
   [data-reveal] ali em cima. Sem JS a faixa aparece de cara e a
   demo continua com saída: JS quebrado não pode apagar o CTA da
   neutr0 pra sempre. É a regra que já queimou 5 vezes aqui. */
@media (scripting: enabled) {
  .n0-demo {
    opacity: 0;
    transform: translateY(10px);
    pointer-events: none;
    transition: opacity .5s var(--ease), transform .5s var(--ease);
  }
  .n0-demo.n0-in { opacity: 1; transform: none; pointer-events: auto; }
  /* precisa repetir o hover: `.n0-demo.n0-in` vem depois do
     `.n0-demo:hover` e tem a mesma força, então mataria o lift */
  .n0-demo.n0-in:hover { transform: translateY(-2px); }
}

/* E o outro lado da mesma moeda: sem JS não há quem ponha o .n0-in,
   então a faixa fica parada em cima do "Pedir uma medição" pra
   sempre, e o × dela também não funciona (é onclick). Aí ela larga o
   fixed e vira um bloco no fim da página: não cobre nada, não precisa
   de botão de fechar, e a saída continua existindo. */
@media (scripting: none) {
  .n0-demo {
    position: static;
    display: flex;
    width: max-content;
    max-width: calc(100% - 2rem);
    margin: 0 auto calc(var(--moldura) + var(--barra-h) + 1rem);
  }
  .n0-demo__t { white-space: normal; }
  .n0-demo__x { display: none; }
}
