/* =====================================================================
   MOCKUP — Empresa Bela (construção civil)
   Estrutura/layout inspirados em habitatinvest.pt
   Conteúdo 100% placeholder (Logo / Lorem / Imagem)
   Paleta: nobre, sóbria — não luxuosa
   ===================================================================== */

/* ---------- Fontes locais ---------- */
@font-face{
  font-family:"Kompot Display";
  src:url("/fonts/KompotDisplay.otf") format("opentype");
  font-weight:400 900;
  font-style:normal;
  font-display:swap;
}

/* ---------- Tokens ---------- */
:root{
  /* Site só claro: impede o "modo escuro automático" do browser (Chrome/Edge)
     de inverter/escurecer as cores quando o SO está em dark mode. */
  color-scheme: only light;

  --paper:      #ffffff;   /* fundo principal (branco) */
  --paper-alt:  #f5f4f2;   /* fundo de seção alternada (cinza muito claro) */
  --ink:        #121212;   /* texto principal (quase preto) */
  --ink-soft:   #565654;   /* texto secundário */
  --ink-faint:  #9a9997;   /* labels discretos */
  --line:       #e8e7e4;   /* linhas/divisores */
  --accent:     #ea5a17;   /* laranja vibrante (identidade AM Santos) */
  --accent-deep:#c1470c;
  --accent-dk:  #ff7d38;   /* laranja sobre fundos escuros (mais brilhante) */
  --dark:       #141414e5;   /* seções escuras / hero (preto neutro) */
  --dark-soft:  #0a0a0a;


  --maxw: 1480px;
  --gutter: clamp(18px, 3.4vw, 52px);
  /* Ritmo: mais distância de scroll por gesto. Cada elemento passa a percorrer
     a sua animação ao longo de mais píxeis, o que se lê como suavidade — é o
     segundo maior fator, depois do scroll interpolado. */
  --section-y: clamp(110px, 13vw, 220px);
  /* Espaçamento curto: usado *dentro* de um grupo narrativo, para que a
     proximidade indique que as duas secções são o mesmo capítulo. */
  --section-y-tight: clamp(28px, 3.4vw, 56px);
  /* Altura da cunha diagonal (.stitch). Global porque o conteúdo que desce
     para dentro do corte (ver .section--panels-cut) precisa da mesma medida. */
  --stitch-rise: clamp(40px, 4.6vw, 72px);

  --serif: "Fraunces", Georgia, "Times New Roman", serif;
  --sans:  "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;

  --ease: cubic-bezier(.22,.61,.36,1);

  /* Tratamento da foto da hero: mais clara e mais fria (azulada).
     Duas camadas: (1) filtro na própria imagem — levanta as luzes, abre as
     sombras e tira saturação quente; (2) véu por cima — a gradação preta de
     legibilidade, aliviada, mais um wash azul-aço.
     A cortina de transição usa exatamente estes tokens: mostra a mesma foto
     por cima da hero real e qualquer diferença de cor abriria costura. */
  --hero-img-filter: brightness(1.14) contrast(.9) saturate(.78);
  --hero-veil:
    linear-gradient(180deg, rgba(0,0,0,.34) 0%, rgba(0,0,0,.06) 45%, rgba(0,0,0,.55) 100%),
    linear-gradient(180deg, rgba(104,146,196,.30) 0%, rgba(132,172,214,.20) 50%, rgba(58,92,138,.34) 100%);
}

/* ---------- Reset ---------- */
*,*::before,*::after{ box-sizing:border-box; margin:0; padding:0; }
/* scroll-behavior fica em `auto`: só afeta saltos programáticos e âncoras,
   nunca a roda do rato, e entrava em conflito com o scroll interpolado do
   Lenis (ver Base.astro). A suavidade real vem do Lenis. */
html{ -webkit-font-smoothing:antialiased; }
/* Esconde a barra de scroll vertical da página (o scroll continua a funcionar).
   Só afeta a lateral do documento; os scrollers internos (.scroller) mantêm a
   sua própria barra estilizada. */
html{ scrollbar-width:none; }
html::-webkit-scrollbar{ width:0; height:0; }
/* Trava o transbordo horizontal na borda da página: as marcas-d'água (.wm)
   sangram para fora das secções/containers (overflow:visible na .wm-layer) e
   escapariam ao clip do body — que não as contém porque resolvem contra o ICB.
   `clip` corta na borda sem criar barra de scroll nem quebrar o header fixo. */
html{ overflow-x:clip; }
/* Regras mínimas exigidas pelo Lenis (equivalente ao lenis.css do pacote). */
html.lenis, html.lenis body{ height:auto; }
.lenis:not(.lenis-autoToggle).lenis-stopped{ overflow:clip; }
.lenis.lenis-smooth [data-lenis-prevent]{ overscroll-behavior:contain; }
.lenis.lenis-smooth iframe{ pointer-events:none; }
body{
  font-family:var(--sans);
  background:var(--paper);
  color:var(--ink);
  line-height:1.6;
  font-size:16px;
  overflow-x:hidden;
}
img{ display:block; max-width:100%; }
a{ color:inherit; text-decoration:none; }
ul{ list-style:none; }

/* ---------- Utilidades ---------- */
.container{ width:100%; max-width:var(--maxw); margin-inline:auto; padding-inline:var(--gutter); }
.section{ padding-block:var(--section-y); }
.section--dark{ background:var(--dark); color:var(--paper); }
.section--alt{ background:var(--paper-alt); }
/* Ritmo por grupos: aperta o espaço do lado que encosta à secção irmã. */
.section--tight-top{ padding-top:var(--section-y-tight); }
.section--tight-bottom{ padding-bottom:var(--section-y-tight); }
/* Faixa de acento: fundo laranja, bem marcante (preto/branco/laranja) */
.section--accent{ background:var(--accent); color:#fff; }
.section--accent .display{ color:#fff; }
.section--accent .dofazemos .display em{ color:#141414; }  /* palavra em destaque a preto */
.section--accent .stat{ border-left-color:rgba(255,255,255,.28); }
.section--accent .stat__num{ color:#fff; }
.section--accent .stat__label{ color:rgba(255,255,255,.86); }

/* Scroll snap desativado na home: fazia cada secção comportar-se como um
   slide isolado, que é o oposto da leitura contínua que a página pede.
   A continuidade passa a vir do ritmo de espaçamento e da costura (.seam). */

.emodal__estado{
  font-family:var(--sans);
  font-size:.72rem;
  letter-spacing:.32em;
  text-transform:uppercase;
  color:var(--accent);
  font-weight:600;
  display:inline-flex;
  align-items:center;
  gap:.7rem;
  margin-bottom:1.4rem;
}
.emodal__estado::before{
  content:"";
  width:34px; height:1px;
  background:var(--accent);
  opacity:.7;
}

.display{
  font-family:var(--serif);
  font-weight:500;
  line-height:1.05;
  letter-spacing:-.01em;
  font-size:clamp(2.1rem, 5.2vw, 4.1rem);
}
.display--sm{ font-size:clamp(1.7rem, 3.6vw, 2.8rem); }
.lead{
  font-family:var(--serif);
  font-weight:300;
  font-size:clamp(1.15rem,2.1vw,1.6rem);
  line-height:1.45;
  color:var(--ink-soft);
  max-width:42ch;
}
.muted{ color:var(--ink-soft); }

/* Em fundo escuro o texto secundário (lead, parágrafos, labels, bios) usa
   --ink-soft/--ink-faint, tons pensados para papel branco — sobre o preto
   ficavam quase ilegíveis. Aqui passa tudo a branco. */
.section--dark .lead,
.section--dark .muted,
.section--dark .split__body p,
.section--dark .service p,
.section--dark .stat__label,
.section--dark .member__bio,
.section--dark .check,
.section--dark .field label{ color:var(--paper); }

/* Botão / link de ação */
.btn{
  position:relative;
  display:inline-flex; align-items:center; gap:.7rem;
  font-size:.74rem; letter-spacing:.22em; text-transform:uppercase;
  font-weight:600; color:var(--ink);
  padding-bottom:.5rem;
  border-bottom:1px solid var(--ink);
  transition:gap .3s var(--ease), color .3s var(--ease), border-color .3s var(--ease);
}
.btn::after{ content:"\2192"; font-size:1rem; }
/* sublinhado accent que preenche da esquerda no hover (sobre a linha base) */
.btn::before{
  content:""; position:absolute; left:0; bottom:-1px; width:100%; height:1px;
  background:var(--accent); transform:scaleX(0); transform-origin:left;
  transition:transform .4s var(--ease);
}
.btn:hover::before{ transform:scaleX(1); }
.btn:hover{ gap:1.1rem; color:var(--accent); }
.section--dark .btn{ color:var(--paper); border-color:rgba(255,255,255,.5); }
.section--dark .btn::before{ background:var(--accent-dk); }
.section--dark .btn:hover{ color:var(--accent-dk); }

/* Placeholder de imagem */
.ph{
  position:relative;
  background:
    repeating-linear-gradient(45deg,
      rgba(0,0,0,.035) 0, rgba(0,0,0,.035) 1px,
      transparent 1px, transparent 11px),
    var(--paper-alt);
  border:1px solid var(--line);
  display:flex; align-items:center; justify-content:center;
  color:var(--ink-faint);
  overflow:hidden;
}
.ph::after{
  content:"Imagem";
  font-size:.7rem; letter-spacing:.28em; text-transform:uppercase;
  font-weight:600;
}
.ph[data-label]::after{ content:attr(data-label); }
.ph--dark{
  background:
    repeating-linear-gradient(45deg,
      rgba(255,255,255,.04) 0, rgba(255,255,255,.04) 1px,
      transparent 1px, transparent 11px),
    var(--dark-soft);
  border-color:rgba(255,255,255,.12);
  color:rgba(255,255,255,.45);
}

/* =====================================================================
   HEADER
   ===================================================================== */
.site-header{
  position:fixed; inset:0 0 auto 0; z-index:100;
  padding-block:1.4rem;
  transition:background .4s var(--ease), padding .4s var(--ease), box-shadow .4s var(--ease);
}
.site-header .container{ display:flex; align-items:center; justify-content:space-between; gap:2rem; }
.site-header.scrolled{
  background:rgba(249,241,230,.92);
  backdrop-filter:blur(10px);
  padding-block:.85rem;
  box-shadow:0 1px 0 var(--line);
}

.logo{
  display:inline-flex; align-items:center;
  height:54px; transition:height .4s var(--ease);
}
.logo__img{ height:100%; width:auto; display:block; }
.logo__img--dark{ display:none; }
.scrolled .logo{ height:44px; }
.scrolled .logo__img--light{ display:none; }
.scrolled .logo__img--dark{ display:block; }

.nav{ display:flex; align-items:center; gap:2rem; }
.nav__list{ display:flex; align-items:center; gap:1.7rem; }
.nav__list a{
  font-size:.74rem; letter-spacing:.2em; text-transform:uppercase;
  font-weight:600; color:#fff; opacity:.9; white-space:nowrap;
  transition:color .3s var(--ease), opacity .3s var(--ease);
  position:relative; padding-block:.4rem;
}
.nav__list a:hover{ opacity:1; color:var(--accent-dk); }
.scrolled .nav__list a{ color:var(--ink); opacity:.85; }
.scrolled .nav__list a:hover{ color:var(--accent); opacity:1; }
.nav__lang{ font-size:.74rem; letter-spacing:.2em; font-weight:700; color:#fff; }
.scrolled .nav__lang{ color:var(--ink); }

/* Botão hambúrguer */
.nav-toggle{
  display:none; flex-direction:column; gap:5px; background:none; border:0;
  cursor:pointer; padding:6px;
}
.nav-toggle span{ width:26px; height:2px; background:#fff; transition:background-color .3s var(--ease), transform .3s var(--ease); }
.scrolled .nav-toggle span{ background:var(--ink); }

/* =====================================================================
   HERO
   ===================================================================== */
.hero{
  position:relative; min-height:100vh;
  display:flex; align-items:flex-end;
  color:#fff; overflow:hidden;
  /* Fundo escuro por baixo da imagem: na home a hero tem will-change:transform e
     é promovida a uma camada GPU cuja 1.ª rasterização pode chegar um frame
     depois do swap. Sem esta cor, esse frame deixaria ver o branco do body (o
     flash); com ela, o pior caso é escuro — a condizer com a cortina, imperceptível. */
  background-color:var(--dark);
}
.hero__bg{
  position:absolute; inset:0; z-index:0;
  background:
    repeating-linear-gradient(45deg,
      rgba(255,255,255,.03) 0, rgba(255,255,255,.03) 1px,
      transparent 1px, transparent 14px),
    linear-gradient(180deg, #1c1c1c 0%, #0a0a0a 100%);
}
.hero__bg::after{
  content:"Imagem — Hero (full screen)";
  position:absolute; inset:0; display:grid; place-items:center;
  font-size:.78rem; letter-spacing:.3em; text-transform:uppercase;
  color:rgba(255,255,255,.22); font-weight:600;
}
.hero__bg--img{
  background-size:cover; background-position:center; background-repeat:no-repeat;
  filter:var(--hero-img-filter);
}
.hero__bg--img::after{ content:none; }
/* Hero com imagem: ecrã inteiro, para coincidir com a cortina de transição
   (que cobre 100vh) — a cortina é retirada sobre a hero sem salto. Mais altura
   corta um pouco mais as laterais da foto (fundo cover, centrado). */
.hero:has(.hero__bg--img){ min-height:100vh; }
.hero__overlay{
  position:absolute; inset:0; z-index:1;
  background:var(--hero-veil);
}
.hero__inner{ position:relative; z-index:2; width:100%; padding-bottom:clamp(64px,10vh,128px); }
.hero .display{ max-width:16ch; }
.hero__title-page{ font-size:clamp(2.6rem,7vw,5.5rem); }
.hero__scroll{
  position:absolute; left:50%; bottom:34px; transform:translateX(-50%);
  z-index:2; display:flex; flex-direction:column; align-items:center; gap:.6rem;
  font-size:.62rem; letter-spacing:.3em; text-transform:uppercase; color:rgba(255,255,255,.7);
}
.hero__scroll .line{ width:1px; height:46px; background:rgba(255,255,255,.5); animation:scrollLine 2s var(--ease) infinite; transform-origin:top; }
@keyframes scrollLine{ 0%{transform:scaleY(0)} 40%{transform:scaleY(1)} 100%{transform:scaleY(0); transform-origin:bottom} }

/* Hero da Home quase ancorada: a imagem fica praticamente parada no viewport,
   deslocando-se apenas ~15% do scroll (deriva subtil, não "arrastada"). A hero
   está em fluxo normal, por isso o h1 sai por cima do ecrã com o scroll em vez
   de ficar preso e ser tapado pela secção seguinte.

   A caixa não precisa de ser esticada: como a imagem desce 85% do scroll e a
   parte de cima da hero sai do ecrã a 100%, a caixa `inset:0` nunca deixa
   vazio — o topo dela desce sempre menos do que o topo visível da hero. Manter
   `inset:0` preserva o enquadramento `cover` centrado da foto.
   Sem JS (ou com prefers-reduced-motion) --hero-parallax fica a 0 e a imagem
   comporta-se como um fundo normal. */
body.is-home .hero__bg--img{
  transform:translate3d(0, var(--hero-parallax, 0px), 0);
  will-change:transform;
}
.home-reveal{
  position:relative; z-index:1; background:var(--paper);
  /* Sombra no rebordo superior: separa o conteúdo da imagem da hero, que se
     move mais devagar por baixo. */
  box-shadow:0 -26px 50px -12px rgba(0,0,0,.45);
}
/* O footer vem do layout Base, fora do .home-reveal. Mantém-no na mesma camada
   do conteúdo, acima da hero. */
body.is-home .site-footer{ position:relative; z-index:1; }

/* =====================================================================
   QUEM SOMOS (texto + imagem)
   ===================================================================== */
.split{ display:grid; grid-template-columns:1fr 1fr; gap:clamp(32px,5vw,80px); align-items:center; }
.split__media .ph{ aspect-ratio:4/5; width:100%; }
.split__img{ aspect-ratio:4/5; width:100%; height:auto; object-fit:cover; display:block; }
.split__body .display{ margin:.4rem 0 1.6rem; }

/* Título "Quem Somos": linha condensada em minúsculas seguida da palavra
   final em serifa grande e maiúscula (ref: titulo-quem-somos). */
.title-split{
  margin:.4rem 0 1.6rem;
  display:flex;
  flex-direction:column;
}
.title-split__lead{
  font-family:"Economica", var(--sans);
  font-weight:400;
  font-size:clamp(1.3rem,2.4vw,1.9rem);
  letter-spacing:.05em;
}
.title-split__word{
  font-family:"Kompot Display", var(--serif);
  font-weight:700;
  text-transform:uppercase;
  letter-spacing:.02em;
  line-height:1.05;
  font-size:clamp(2.6rem,6vw,4.6rem);
}
/* Variante para h1 de hero: linha condensada maior + palavra final ao nível
   do .hero__title-page (mesma altura visual dos heros existentes). */
.title-split--hero{ max-width:20ch; }
.title-split--hero .title-split__lead{ font-size:clamp(1.4rem,2.8vw,2.1rem); }
.title-split--hero .title-split__word{ font-size:clamp(3rem,8vw,6rem); }
/* Variante para títulos curtos (1-2 palavras) sem linha de contexto:
   fica só a palavra final grande. */
.title-split--word-only .title-split__lead{ display:none; }
.split__body p{ color:var(--ink-soft); max-width:46ch; margin-bottom:1.2rem; }
.split--reverse .split__media{ order:2; }

/* ---- "Quem Somos" da home: composição editorial + imagem full-bleed por
   baixo, no idioma do site de referência (kononenkogroup). O bloco vive dentro
   do .container; a imagem é filha directa da <section>, fora do container, e
   ocupa toda a largura do ecrã. O título grande fica ao centro e o botão
   ancora o canto inferior direito. ---- */
.quemsomos__intro{
  display:flex; flex-direction:column;
  gap:clamp(30px,5vw,68px);
}
.quemsomos__intro .display{
  align-self:center; text-align:center;
  max-width:20ch; margin:0;
  font-size:clamp(2.8rem, 8vw, 6.4rem);   /* maior que o .display base */
}
.quemsomos__intro .btn{ align-self:flex-end; }                          /* canto inferior direito */

.title-split--center{
  align-self:center; align-items:center;
  text-align:center; max-width:60ch; margin:0;
}
.title-split--center .title-split__word{
  font-size:clamp(3.2rem, 9vw, 7.2rem);   /* maior que a variante da secção "Sobre Nós" */
}

.quemsomos__media{
  margin-top:clamp(40px,6vw,96px);
  /* Full-bleed (bordo a bordo), mais achatada: rácio largo baixa a altura sem
     mexer na largura. */
  position:relative; aspect-ratio:21/9;
  overflow:clip;   /* recorta a imagem ampliada/deslocada do parallax (clip, não hidden, para não criar scroll container) */
}
.quemsomos__img,
.quemsomos__media .ph{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:cover; display:block;
}

/* Parallax conduzido pelo Lenis (JS), como a hero: a imagem desliza mais
   devagar que a moldura e fica quase ancorada ao passar pelo ecrã. O Base.astro
   escreve --qs-parallax (px) a cada frame do Lenis; o scale(1.45) dá a folga que
   o deslocamento consome, para nunca abrir vazios. A ordem (translate depois
   scale) mantém --qs-parallax em px de ecrã, sem ser multiplicado pelo scale.
   Sem JS ou com prefers-reduced-motion --qs-parallax fica a 0 e a imagem fica
   estática (cover ampliado, sem buracos). Mantém-se sincronizado com o scroll
   fluido porque corre no mesmo evento do Lenis que a hero. */
.quemsomos__img{
  transform:translate3d(0, var(--qs-parallax, 0px), 0) scale(1.45);
  will-change:transform;
}

/* =====================================================================
   O QUE FAZEMOS + contadores
   ===================================================================== */
/* Alinhado à esquerda, como todas as outras secções da home: um eixo
   vertical único que o olho segue do hero ao rodapé. */
/* A frase encosta aos contadores (são a mesma unidade de leitura) e afasta-se
   bem do bloco escuro que vem a seguir.
   Vem depois de .section no ficheiro: mesma especificidade, ganha por ordem. */
.section--fazemos{
  padding-top:clamp(12px,1.4vw,24px);
  padding-bottom:clamp(96px,11vw,190px);
}

/* Centrada em relação ao cartão dos contadores: ambos ocupam a caixa de
   conteúdo do .container, logo centrar aqui alinha os dois eixos médios. */
.dofazemos{ text-align:center; }
/* Uma linha só. O Fraunces tem optical sizing, por isso a largura por px de
   corpo não é constante: ~17,1px em corpo grande mas ~18,8px em corpo
   pequeno. 4,8vw é o coeficiente que cabe nos 90vw do .container em toda a
   gama; o topo fica em 4rem porque acima de 1440px o .container deixa de
   crescer (fica em 1280px). */
.dofazemos .display{
  margin:.4rem 0 0;
  font-size:clamp(1.6rem, 4.8vw, 4rem);
}
/* Abaixo disto uma linha só exigiria ~15px de corpo, ilegível para um
   título — deixa-se quebrar. */
@media (min-width:700px){
  .dofazemos .display{ white-space:nowrap; }
}
.dofazemos .display em{ font-style:normal; color:var(--accent); }

/* ---------------------------------------------------------------------
   CONTADORES (.seam) — faixa de números entre "Quem Somos" e "O Que
   Fazemos". As duas secções vizinhas são brancas, por isso o cartão não
   atravessa fronteira de cor nenhuma: a sua presença vem do corpo (altura
   e escala dos números), da moldura e da sombra.
   Fica fora de .section de propósito: a cortina de revelação
   (body.is-home .section::after) não o deve tapar.
   --------------------------------------------------------------------- */
.seam{
  position:relative;
  background:var(--paper);
  --thread:clamp(56px,6.5vw,104px);   /* respiro entre o "Quem Somos" e a faixa */
  padding-top:var(--thread);
}

/* ---- Costura entre o "Quem Somos" e os contadores ----
   Fio vertical que desce do vão entre as duas colunas do split e vai
   encontrar o topo do cartão. Como as duas secções são brancas não há
   fronteira de cor para atravessar: é o fio que faz a ligação.
   Sobe para dentro do "Quem Somos" pelo padding que essa secção tem em
   baixo (--section-y-tight), cobrindo assim o vão inteiro. */
.seam::before{
  content:"";
  position:absolute; z-index:1; pointer-events:none;
  left:calc(50% - .5px);             /* left, não transform: deixa o transform livre para a animação */
  top:calc(-1 * var(--section-y-tight));
  width:1px;
  height:calc(var(--thread) + var(--section-y-tight));
  background:linear-gradient(to bottom,
    transparent 0, var(--line) 34%, var(--accent) 100%);
}
/* O fio desenha-se de cima para baixo ao entrar no ecrã. Gated por
   .reveal-ready, que o Base.astro só liga quando o utilizador não pediu
   menos movimento — sem isso o fio aparece já desenhado. O gatilho é o
   .is-visible dos próprios contadores, via :has(), evitando ter de somar
   o .seam ao seletor observado no Base.astro. */
html.reveal-ready .seam::before{
  transform:scaleY(0); transform-origin:top;
  transition:transform .9s var(--ease) .1s;
}
html.reveal-ready .seam:has(.stat.is-visible)::before{ transform:scaleY(1); }
.seam .stats{
  margin-top:0;                      /* anula o respiro do uso normal */
  background:var(--paper);
  border:1px solid var(--line);
  box-shadow:0 18px 44px -30px rgba(0,0,0,.4);
}
/* Mais corpo: a faixa é agora um elemento por direito próprio, não um
   remate da secção anterior. */
.seam .stat{ padding-block:clamp(34px,4.4vw,62px); }
.seam .stat__num{ font-size:clamp(2.9rem,5.4vw,4.3rem); min-height:clamp(2.9rem,5.4vw,4.3rem); }
.seam .stat__num--word{ font-size:clamp(1.45rem,2.4vw,2rem); }
.seam .stat__label{ margin-top:1.1rem; }

@media (max-width:860px){
  .seam .stats{ box-shadow:none; }
  .seam .stat{ padding-block:clamp(24px,5vw,34px); }
}

/* ---- Variante escura: os contadores abrem o capítulo da Obra ----
   Aqui não há cartão nenhum. A faixa É o fundo escuro do Portfolio, e os
   números vivem diretamente sobre ele — o peso vem do contraste e da
   escala, não de uma moldura. O laranja recua para os rótulos, deixando os
   números em branco: sobre o escuro, o branco é que é o gesto forte.
   A cascata de entrada já vem de borracha do Base.astro, que escreve
   transition-delay inline por índice de irmão (70ms). */
.seam--dark{
  background:var(--dark);
  color:var(--paper);
  padding-bottom:var(--thread);
}
/* O fio vertical era a ligação entre duas secções brancas. Aqui a fronteira
   já é feita pela cunha da costura, e o fio atravessá-la-ia. */
.seam--dark::before{ content:none; }
.seam--dark .stats{
  background:none;
  border:0;
  box-shadow:none;
}
.seam--dark .stat{ border-left-color:rgba(255,255,255,.18); }
.seam--dark .stat__num{ color:var(--paper); }
.seam--dark .stat__label{ color:var(--accent); }

@media (max-width:1024px){
  .seam--dark .stat:nth-child(even){ border-left-color:rgba(255,255,255,.18); }
}

/* ---------------------------------------------------------------------
   COSTURA DIAGONAL (.stitch) — remate entre secções de cor diferente.
   Um triângulo da cor da secção ANTERIOR desce sobre o topo da seguinte
   (linha de telhado / blueprint), cortando a fronteira na diagonal. Vive
   fora de <section>, por isso a cortina de revelação
   (body.is-home .section::after) não o tapa; sobrepõe-se ao topo da
   secção seguinte por z-index, sem cortar a caixa nem o conteúdo.
   --------------------------------------------------------------------- */
.stitch{
  position:relative; z-index:6;   /* acima da cortina (::after z-index:5) */
  height:0;                        /* não ocupa espaço: as secções continuam a encostar */
}
.stitch__cut{
  position:absolute; left:0; top:0; width:100%;
  height:var(--stitch-rise);
  display:block; pointer-events:none; overflow:visible;
}
.stitch--light .stitch__wedge{ fill:var(--paper); }     /* branco sobre a secção seguinte */
.stitch--alt   .stitch__wedge{ fill:var(--paper-alt); } /* cinza-claro (.section--alt) sobre a seguinte */
.stitch--dark  .stitch__wedge{ fill:var(--dark); }      /* escuro sobre a Equipa */

@media (max-width:640px){
  :root{ --stitch-rise:clamp(26px,5vw,44px); }
}

.stats{
  display:grid; grid-template-columns:repeat(5,1fr);
  margin-top:clamp(48px,6vw,86px);
}
.stat{ padding:clamp(20px,2.5vw,38px) 1rem; text-align:center; border-left:1px solid var(--line); }
.stat:first-child{ border-left:0; }
.stat__num{
  font-family:var(--serif); font-weight:400;
  font-size:clamp(2.4rem,4.6vw,3.7rem); line-height:1;
  color:var(--accent); letter-spacing:.01em;
  font-variant-numeric:tabular-nums;
  /* min-height alinha os rótulos entre o contador e os pilares de texto,
     que têm corpos diferentes. */
  display:flex; align-items:center; justify-content:center;
  min-height:clamp(2.4rem,4.6vw,3.7rem);
}
/* Pilares não-numéricos: palavras precisam de corpo menor para caber na coluna. */
.stat__num--word{
  font-size:clamp(1.3rem,2.1vw,1.75rem);
  line-height:1.15; overflow-wrap:break-word;
}
.stat__label{ margin-top:.9rem; font-size:.86rem; letter-spacing:.01em; color:var(--ink-soft); }

/* 1024px, não 860: é aos 1024 que a grelha passa a 2 colunas (ver secção
   RESPONSIVO). Com o reset dos separadores mais abaixo, entre 861 e 1024 os
   itens que abriam linha ficavam com um fio vertical solto na margem. */
@media (max-width:1024px){
  .stats{ row-gap:clamp(26px,6vw,40px); }
  .stat{ border-left:0; }
  .stat:nth-child(even){ border-left:1px solid var(--line); }
}

/* =====================================================================
   CARROSSEL / SCROLLER de projetos (Portfolio & Track Record na home)
   ===================================================================== */
.block-head{ display:flex; align-items:flex-end; justify-content:space-between; gap:2rem; margin-bottom:clamp(32px,4vw,56px); flex-wrap:wrap; }
.block-head .display{ margin-top:.3rem; }
.block-head__text .lead{ font-size:1.05rem; margin-top:.4rem; }

/* Cabeçalho centrado (portfólio): empilha título + lead ao centro, em vez
   do layout partido esquerda/direita do .block-head base. */
.section--centered-head .block-head{ flex-direction:column; align-items:center; text-align:center; }
.section--centered-head .block-head__text{ display:flex; flex-direction:column; align-items:center; }
.section--centered-head .block-head__text .lead{ max-width:56ch; }

.scroller{
  display:grid; grid-auto-flow:column; grid-auto-columns:minmax(340px,36%);
  gap:clamp(16px,2vw,28px); overflow-x:auto; scroll-snap-type:x mandatory;
  padding-bottom:1.5rem; margin-inline:calc(var(--gutter)*-1); padding-inline:var(--gutter);
  scrollbar-width:thin;
}
.scroller::-webkit-scrollbar{ height:4px; }
.scroller::-webkit-scrollbar-thumb{ background:var(--accent); }

/* Cartão de projeto */
.card{ scroll-snap-align:start; background:transparent; }
.card__media{ position:relative; aspect-ratio:3/4; overflow:hidden; }
.card__media .ph{ position:absolute; inset:0; width:100%; height:100%; transition:transform .7s var(--ease); }
.card:hover .card__media .ph{ transform:scale(1.05); }
.card__img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; transition:transform .7s var(--ease); }
.card:hover .card__img{ transform:scale(1.05); }
/* Selo para imagens que ainda não retratam o empreendimento (imagemReal:false). */
.img-prov{
  position:absolute; top:.7rem; left:.7rem; z-index:2;
  background:rgba(0,0,0,.6); color:#fff;
  font-size:.56rem; letter-spacing:.16em; text-transform:uppercase; font-weight:600;
  padding:.32rem .5rem;
}
/* No hero fica em baixo à direita, longe do título e do botão de voltar. */
.img-prov--hero{
  top:auto; left:auto; right:var(--gutter); bottom:1.4rem;
  background:rgba(0,0,0,.5); backdrop-filter:blur(4px);
}
/* Scrim alto e em três paragens: com fotos reais por baixo, um título de duas
   linhas subia para a zona transparente e ficava ilegível sobre céu claro. */
.card__overlay{
  position:absolute; inset:auto 0 0 0; z-index:2; padding:3.4rem 1.4rem 1.4rem;
  background:linear-gradient(180deg, transparent 0%, rgba(0,0,0,.5) 42%, rgba(0,0,0,.85) 100%);
  color:#fff;
}
/* text-shadow além do scrim: as fotos variam muito (céu claro, campo, interiores)
   e o gradiente sozinho não garante contraste em títulos/meta de duas linhas. */
.card__title{ font-family:var(--serif); font-weight:400; font-size:1.5rem; line-height:1.1; text-shadow:0 1px 12px rgba(0,0,0,.55); }
.card__meta{ font-size:.76rem; letter-spacing:.1em; opacity:.92; margin-top:.4rem; text-shadow:0 1px 10px rgba(0,0,0,.6); }
.card__cta{ margin-top:1rem; font-size:.68rem; letter-spacing:.22em; text-transform:uppercase; font-weight:600; color:var(--accent-dk); display:inline-flex; gap:.5rem; }
.card__cta::after{ content:"\2192"; }

/* =====================================================================
   PAINÉIS EXPANSÍVEIS (dark section — efeito content-office)
   Fileira de painéis estreitos; ao passar o pointer, o painel apontado
   cresce e os outros encolhem. 100% CSS.
   ===================================================================== */
.panels{
  /* Container de consulta: dá aos rótulos uma largura FIXA (a largura do painel
     em repouso), para o nome não se voltar a partir quando um painel abre e os
     outros encolhem. --n vem do componente (nº de painéis). */
  container-type:inline-size;
  --n:5; --panel-gap:6px;
  display:flex; gap:var(--panel-gap);
  height:clamp(380px,58vh,580px);
  margin-top:clamp(28px,4vw,52px);
}
.panel{
  position:relative;
  flex:1 1 0; min-width:0;
  overflow:hidden;
  border:1px solid rgba(255,255,255,.10);
  cursor:pointer;
  transition:flex-grow .6s var(--ease);
}
/* Em repouso todos os painéis têm a mesma largura; só o apontado expande. */
.panel:hover{ flex-grow:6; }

.panel__bg{
  position:absolute; inset:0; width:100%; height:100%;
  object-fit:cover;
  transform:scale(1.02);
  transition:transform .6s var(--ease);
}
.panel:hover .panel__bg{ transform:scale(1.06); }
/* Escurecimento + toque de bronze por cima do placeholder */
.panel::before{
  content:""; position:absolute; inset:0; z-index:1;
  background:linear-gradient(to top,
    rgba(15,17,20,.82) 0%,
    rgba(15,17,20,.35) 45%,
    rgba(138,111,78,.10) 100%);
  transition:opacity .6s var(--ease);
}

/* Nome horizontal (estado colapsado): assenta no canto inferior esquerdo, no
   mesmo alinhamento do conteúdo expandido, e quebra em várias linhas quando o
   painel está estreito. */
.panel__label{
  position:absolute; z-index:2;
  left:0; bottom:1.4rem;
  /* Largura do painel em repouso — congela a quebra de linha do nome. */
  width:calc((100cqw - (var(--n) - 1) * var(--panel-gap)) / var(--n));
  padding-inline:clamp(20px,2vw,34px);
  font-family:var(--serif); font-weight:400;
  font-size:1.15rem; line-height:1.15; letter-spacing:.06em;
  color:var(--paper);
  transition:opacity .35s var(--ease);
}

/* Conteúdo horizontal (estado expandido) */
.panel__content{
  position:absolute; z-index:2; inset:auto 0 0 0;
  padding:clamp(20px,2vw,34px);
  opacity:0; transform:translateY(12px);
  transition:opacity .5s var(--ease), transform .5s var(--ease);
  pointer-events:none;
}
.panel__title{
  font-family:var(--serif); font-weight:400;
  font-size:clamp(1.5rem,2.4vw,2.1rem); line-height:1.05;
  color:var(--paper);
}
.panel__meta{
  margin-top:.6rem;
  font-size:.72rem; letter-spacing:.16em; text-transform:uppercase;
  color:var(--accent-dk); font-weight:600;
  display:inline-flex; align-items:center; gap:.6rem;
  white-space:nowrap;
}
.panel__meta::after{ content:"\2192"; font-size:1rem; }

/* Troca label <-> conteúdo quando o painel está expandido */
.panel:hover .panel__label{ opacity:0; }
.panel:hover .panel__content{ opacity:1; transform:translateY(0); }

/* ---- Variante "cortada" (Histórico, na home) ----------------------------
   Os painéis crescem em altura, sangram de bordo a bordo (saem do .container)
   e o seu bordo inferior é recortado (clip-path) na MESMA diagonal da costura,
   ficando RENTE à linha transversal. A secção perde o padding de baixo e os
   painéis recuperam-no com margem negativa. O CTA fica ABAIXO da costura, já no
   cinza (ver .panels-cta).
   flow-root: sem BFC próprio, essa margem negativa colapsava com a da secção e
   puxava a costura para cima em vez de fazer os painéis descer. */
.section--panels-cut{ padding-top:clamp(140px,15vw,260px); padding-bottom:0; display:flow-root; }
/* Cabeçalho do Histórico (home) no molde do "Quem Somos": título e lead
   centrados, maiores e mais presentes que o base. O botão não vive aqui —
   está na .panels-cta, abaixo da costura. */
.section--panels-cut .block-head{ flex-direction:column; align-items:stretch; }
.section--panels-cut .block-head__text{ display:flex; flex-direction:column; }
.section--panels-cut .block-head__text .display{
  align-self:center; text-align:center;
  font-size:clamp(2.4rem,5vw,4rem);        /* acima do display--sm, bem presente */
}
.section--panels-cut .block-head__text .lead{ align-self:center; text-align:center; max-width:56ch; }
/* CTA do Histórico: faixa própria, já do lado cinza da costura. Toma a cor da
   secção seguinte (Equipa) para a fronteira diagonal continuar a ser a única
   linha visível; o botão encosta à direita, onde a diagonal está rente ao topo. */
.panels-cta{
  background:var(--paper-alt);
  padding-top:clamp(36px,5vw,64px);
}
.panels-cta .container{ display:flex; justify-content:flex-end; }
.panels-cta .btn{
  font-size:.95rem;                        /* base .74rem */
}
.panels-cta .btn::after{ font-size:1.25rem; }  /* seta a condizer */
.section--panels-cut .panels{
  position:relative; z-index:7;   /* acima da cunha (6) */
  /* Descem exatamente a altura da cunha para lá da fronteira... */
  height:calc(clamp(460px,72vh,760px) + var(--stitch-rise));
  margin-bottom:calc(-1 * var(--stitch-rise));
  /* ...e o bordo inferior é recortado NA MESMA diagonal da costura: à direita
     rente à fronteira, à esquerda uma cunha abaixo. */
  clip-path:polygon(0 0, 100% 0, 100% calc(100% - var(--stitch-rise)), 0 100%);
}
/* Sobe o rótulo e o conteúdo --stitch-rise para nenhum texto cair na zona
   recortada, seja qual for o card expandido. */
.section--panels-cut .panel__label{ bottom:calc(1.4rem + var(--stitch-rise)); }
.section--panels-cut .panel__content{ bottom:calc(var(--stitch-rise) + .4rem); }

/* Responsivo: vira pilha vertical de cards, sem efeito de expansão */
@media (max-width:720px){
  .panels,
  .section--panels-cut .panels{ flex-direction:column; height:auto; gap:10px; }
  .panel,
  .panel:hover{ flex:0 0 auto; height:180px; }
  .panel__label{ display:none; }
  .panel__content{ opacity:1; transform:none; }
}

/* =====================================================================
   GRID de portfólio (página Portfólio)
   ===================================================================== */
.grid-projects{ display:grid; grid-template-columns:repeat(3,1fr); gap:clamp(16px,2vw,28px); }
.grid-projects .card__media{ aspect-ratio:4/5; }

/* =====================================================================
   COMO TRABALHAMOS — grelha de imagens em cascata (masonry, 2 colunas),
   coluna esquerda a subir e coluna direita a descer em loop contínuo,
   independente do scroll. Cada coluna renderiza a lista de imagens
   duplicada (A+A) para o loop de 50% ficar sem costura (Sobre Nós).
   ===================================================================== */
/* Sem margem vertical: a cascata encosta ao topo e ao fundo da secção. A
   altura é ditada só pelo conteúdo (min-height da grelha). */
.section:has(.comotrabalhamos__grid){ padding-block:0; }
/* O corpo ocupa toda a altura da linha do grid (a mesma da cascata) e
   distribui o conteúdo por ela — título em cima, contadores em baixo — em vez
   de ficar centrado a deixar vazio em cima e em baixo. O padding-block é o
   único respiro, já que a secção tem padding 0. */
.comotrabalhamos .split__body{
  align-self:stretch;
  display:flex;
  flex-direction:column;
  justify-content:space-between;
  padding-block:clamp(40px,5vw,80px);
}
/* A grelha não tem altura intrínseca (as colunas são position:absolute), por
   isso o alinhamento por defeito do .split (center) colapsava-a a 0. Stretch
   fá-la ocupar toda a altura da linha do grid. O min-height é o que dá à
   cascata a sua janela — sem ele a altura era só a do parágrafo ao lado. */
.split.comotrabalhamos{
  align-items:stretch;
  grid-template-columns:0.9fr 1fr;
  gap:clamp(24px,3.4vw,56px);
}
.comotrabalhamos__grid{
  position:relative;
  height:100%;
  min-height:clamp(600px,70vw,1000px);
  overflow:clip;   /* clip, não hidden: não criar scroll container */
}
.comotrabalhamos__col{
  position:absolute;
  width:47%;
  display:flex;
  flex-direction:column;
  gap:clamp(10px,1.4vw,18px);
  will-change:transform;
}
/* Desfasamento vertical entre colunas: dá o efeito masonry. */
.comotrabalhamos__col--a{
  left:0; top:0;
  animation:ct-cascade-up 34s linear infinite;
}
.comotrabalhamos__col--b{
  right:0; top:0;
  animation:ct-cascade-down 42s linear infinite;
}
@keyframes ct-cascade-up{
  from{ transform:translate3d(0,0,0); }
  to{ transform:translate3d(0,-50%,0); }
}
@keyframes ct-cascade-down{
  from{ transform:translate3d(0,-50%,0); }
  to{ transform:translate3d(0,0,0); }
}
@media (prefers-reduced-motion:reduce){
  .comotrabalhamos__col--a, .comotrabalhamos__col--b{ animation:none; }
}
.comotrabalhamos__col img{
  width:100%; display:block;
  aspect-ratio:3/4; object-fit:cover;
}

/* Título com menos respiro que o uso normal do title-split: o corpo desta
   secção é curto (título + quadro), sem padding a esticá-lo. */
.comotrabalhamos .title-split{ margin:0; }

/* Quadro de valores compacto: a coluna .split__body é estreita de mais para
   os 5 pilares em linha do .stats de base — força 2 colunas sempre, com
   números menores que os da faixa cheia da home. */
.stats--compact{
  grid-template-columns:repeat(2,1fr);
  column-gap:clamp(20px,2.6vw,32px);
  row-gap:clamp(26px,3.6vw,40px);
  margin-top:.3rem;
}
.stats--compact .stat{ border-left:0; padding:0; text-align:left; }
.stats--compact .stat__num{
  justify-content:flex-start;
  font-size:clamp(2.4rem,3.6vw,3.6rem);
  min-height:clamp(2.4rem,3.6vw,3.6rem);
}
.stats--compact .stat__num--word{ font-size:clamp(1.3rem,2vw,1.75rem); }
.stats--compact .stat__label{ margin-top:.7rem; font-size:.92rem; }
@media (max-width:640px){
  .stats--compact{ grid-template-columns:1fr; }
}

/* =====================================================================
   SERVIÇOS (linhas alternadas — Sobre Nós)
   ===================================================================== */
.service{ display:grid; grid-template-columns:1fr 1fr; gap:clamp(32px,5vw,80px); align-items:center; }
.service + .service{ margin-top:clamp(48px,6vw,96px); }
.service:nth-child(even) .service__media{ order:2; }
.service__media .ph{ aspect-ratio:5/4; width:100%; }
.service h3{ font-family:var(--serif); font-weight:400; font-size:clamp(1.7rem,3vw,2.4rem); margin:.6rem 0 1.2rem; }
.service p{ color:var(--ink-soft); max-width:46ch; margin-bottom:1.4rem; }

/* =====================================================================
   EQUIPA
   ===================================================================== */
.team{ display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:clamp(20px,2.4vw,34px); margin-top:clamp(40px,5vw,64px); }
.team--lead{ grid-template-columns:repeat(2,minmax(0,1fr)); max-width:640px; gap:clamp(20px,2.4vw,34px); }
.member__media .ph{ aspect-ratio:1/1; width:100%; }
.member__role{ font-size:.64rem; letter-spacing:.2em; text-transform:uppercase; color:var(--accent); margin:.9rem 0 .3rem; font-weight:600; }
.member__name{ font-family:var(--serif); font-weight:400; font-size:1.2rem; margin-bottom:.6rem; }
.member__bio{ color:var(--ink-soft); font-size:.85rem; max-width:100%; }

/* =====================================================================
   CONTACTO
   ===================================================================== */
.contact{ display:grid; grid-template-columns:1fr 1fr; gap:clamp(32px,5vw,80px); align-items:start; }
.contact__form{ display:grid; gap:1.1rem; }
.field{ display:grid; gap:.4rem; }
.field label{ font-size:.68rem; letter-spacing:.2em; text-transform:uppercase; color:var(--ink-faint); font-weight:600; }
.field input, .field select, .field textarea{
  font-family:var(--sans); font-size:.95rem; color:var(--ink);
  background:transparent; border:0; border-bottom:1px solid var(--line);
  padding:.7rem 0; transition:border-color .3s var(--ease);
}
.field input:focus, .field select:focus, .field textarea:focus{ outline:0; border-color:var(--accent); }
.field textarea{ resize:vertical; min-height:90px; }
.check{ display:flex; gap:.7rem; align-items:flex-start; font-size:.8rem; color:var(--ink-soft); }
.check input{ margin-top:.25rem; }
.contact__form .btn{ justify-self:start; margin-top:.6rem; background:none; border:0; border-bottom:1px solid var(--ink); cursor:pointer; }

/* =====================================================================
   FOOTER
   ===================================================================== */
.site-footer{ background:var(--dark); color:#cdd0d4; padding-block:clamp(56px,7vw,96px) 2rem; }
.footer-grid{ display:grid; grid-template-columns:1.4fr 1fr 1fr 1.2fr; gap:clamp(28px,4vw,56px); }
.footer-col h4{ font-size:.7rem; letter-spacing:.24em; text-transform:uppercase; color:#fff; margin-bottom:1.1rem; font-weight:600; }
.footer-col p, .footer-col a{ font-size:.92rem; color:#a7abb1; line-height:1.8; }
.footer-col a{ background:linear-gradient(var(--accent-dk),var(--accent-dk)) 0 100%/0 1px no-repeat; transition:background-size .35s var(--ease), color .3s var(--ease); }
.footer-col a:hover{ color:var(--accent-dk); background-size:100% 1px; }
.footer-brand .logo{ margin-bottom:1.2rem; }
.footer-logo{ height:auto; }
.footer-logo img{ height:60px; width:auto; display:block; }
.socials{ display:flex; gap:.8rem; margin-top:1.2rem; }
.socials a{ display:grid; place-items:center; color:#cdd0d4; transition:color .35s var(--ease), transform .35s var(--ease); }
.socials a svg{ width:26px; height:26px; }
.socials a:hover{ color:var(--accent-dk); transform:translateY(-2px); }
.news{ display:flex; border-bottom:1px solid rgba(255,255,255,.25); }
.news input{ flex:1; background:none; border:0; color:#fff; padding:.6rem 0; font-size:.9rem; }
.news input:focus{ outline:0; }
.news button{ background:none; border:0; color:var(--accent-dk); cursor:pointer; font-size:1.1rem; }
.footer-bottom{ margin-top:clamp(40px,5vw,72px); padding-top:1.6rem; border-top:1px solid rgba(255,255,255,.12); display:flex; justify-content:space-between; gap:1rem; flex-wrap:wrap; font-size:.72rem; letter-spacing:.08em; color:#7e828a; text-transform:uppercase; }

/* =====================================================================
   MICRO-INTERAÇÕES
   ===================================================================== */

/* 1) Revelar ao rolar — estado inicial só quando o JS marca html.reveal-ready,
   evitando qualquer "flash". Fica inativo em prefers-reduced-motion.

   Só `transform` e `opacity`: são as duas propriedades que o compositor da GPU
   resolve sem repintar. O `clip-path` que aqui estava obrigava a repintar cada
   elemento revelado a cada frame — era o item mais caro do site e corria em
   todo o lado. A máscara que ele dava é substituída pelo wrapper .reveal-mask
   abaixo, onde for preciso.

   Durações separadas: a opacidade resolve-se depressa (.32s) e o deslocamento
   continua muito depois (1.1s). O elemento *aparece* rápido e só depois
   *assenta* — é isto que se lê como fluido. Durações iguais leem-se como
   lentas. */
html.reveal-ready :is(
  .card, .stat, .service, .member, .panels
){
  opacity:0;
  transform:translateY(26px);
  transition:opacity .32s var(--ease),
             transform 1.1s var(--ease);
  will-change:transform, opacity;
}
html.reveal-ready :is(
  .card, .stat, .service, .member, .panels
).is-visible{
  opacity:1;
  transform:none;
}

/* Máscara reutilizável: envolve o elemento e corta-o com overflow, para o
   filho poder subir por trás de um limite fixo sem animar clip-path. É a
   técnica que dá o reveal "por trás de uma aresta" a custo zero de repintura.
   Uso: <div class="reveal-mask"><algo class="…"></algo></div> */
.reveal-mask{ overflow:hidden; }

/* ===== Split-text por linha (line-mask reveal) ==============================
   O split-type parte o texto em .line; o JS envolve cada linha numa .line__inner.
   A .line clipa (overflow), a .line__inner sobe de translateY(110%) até 0. Só
   transform. Estado escondido gated por .split-ready (posta pelo JS por elemento)
   -> sem JS, nada disto se aplica e o texto fica legível. */
.split-ready .line { overflow: hidden; }   /* scoping: não colidir com outros .line (ex.: hero__scroll) */
.split-ready .line__inner {
  display: block;
  transform: translateY(110%);              /* escondida por baixo da máscara */
  transition: transform 1.2s cubic-bezier(.16,1,.3,1);
  transition-delay: calc(var(--i, 0) * 150ms);  /* stagger linha-a-linha */
  will-change: transform;
}
.split-ready.is-revealed .line__inner { transform: translateY(0); }
/* Resize: repor o estado revelado sem re-animar. */
.split-instant .line__inner { transition: none !important; }

/* Wipe da esquerda para a direita: a imagem surge revelando-se da borda
   esquerda até à direita ao entrar no ecrã. Gated por reveal-ready (respeita
   prefers-reduced-motion). Reutilizável em qualquer .split__media/imagem. */
html.reveal-ready .reveal-wipe-lr{
  clip-path:inset(0 100% 0 0);
  transition:clip-path .95s var(--ease);
  will-change:clip-path;
}
html.reveal-ready .reveal-wipe-lr.is-visible{ clip-path:inset(0 0 0 0); }

/* Revelação lenta de baixo para cima, para imagens grandes que merecem ser
   vistas a entrar (ex.: "Quem Somos" da home). Movimento mais demorado que o
   reveal genérico, mas com o mesmo princípio: opacidade rápida, deslocamento
   lento, e nada de clip-path. Gated por reveal-ready. */
html.reveal-ready .reveal-rise-slow{
  opacity:0;
  transform:translateY(40px);
  transition:opacity .4s var(--ease),
             transform 1.8s var(--ease);
  will-change:transform, opacity;
}
html.reveal-ready .reveal-rise-slow.is-visible{
  opacity:1;
  transform:none;
}

/* Entrada dos cards do portfólio: sobem de trás do fundo branco (cortina).
   O branco é o fundo estático da secção, visível através da moldura; só o
   card se move.

   IMPORTANTE — porquê .is-risen e não .is-visible: o reveal geral do Base.astro
   adiciona .is-visible SÍNCRONO no astro:page-load. Numa navegação suave
   (soft-nav pela navbar), isso acontece antes de o estado inicial
   (translateY(100%)) ser pintado → a transição ficava sem "frame de partida" e
   saltava (os cards apareciam já assentes). Por isso a subida é disparada por
   .is-risen, que o script do portfólio adiciona a partir do callback ASSÍNCRONO
   do seu observer (já depois do paint) — a transição corre sempre, mesmo em
   soft-nav.

   Especificidade: prefixo .grid-projects para o estado base (translateY(100%))
   vencer a regra genérica .is-visible{transform:none} ((0,4,1)) — senão o
   .is-visible do reveal geral puxava o card para 0 na mesma. .is-risen leva mais
   uma classe e vence ambos.

   display:block: o .card é um <a> (inline); precisa de block para preencher a
   moldura. FORA do gate reveal-ready, senão em reduced-motion a grelha partia. */
.card-rise .card{ display:block; }
html.reveal-ready .card-rise{ overflow:hidden; }
html.reveal-ready .grid-projects .card-rise .card{
  opacity:1;
  transform:translateY(100%);
  /* box-shadow no transition para o hover (sombra) continuar a suavizar. */
  transition:transform 1.2s cubic-bezier(.16,1,.3,1), box-shadow .5s var(--ease);
  will-change:transform;
}
html.reveal-ready .grid-projects .card-rise.is-risen .card{ transform:translateY(0); }
/* Cascata por coluna (grelha de 3): esquerda → direita. !important porque o
   reveal geral do Base.astro escreve um transition-delay INLINE em cada .card
   (índice de irmão = 0, pois o .card é filho único da moldura), e inline vence
   qualquer selector sem !important. */
html.reveal-ready .grid-projects .card-rise:nth-child(3n+2) .card{ transition-delay:.09s !important; }
html.reveal-ready .grid-projects .card-rise:nth-child(3n+3) .card{ transition-delay:.18s !important; }
/* Depois da subida assentar, reabrir a moldura para a sombra do hover não ser
   cortada pelo overflow:hidden. (A elevação translateY(-6px) do hover é
   suprimida site-wide pela regra genérica .is-visible{transform:none} — isto
   só garante que a sombra aparece inteira.) */
html.reveal-ready .card-rise.is-open{ overflow:visible; }

/* ── ENTRADA PESADA DO 1.º BLOCO DO PORTFÓLIO (após o fade branco) ──────────
   Só a 1.ª secção (.section--flat-top): título e cards fazem um slide "pesado"
   — lento e uniforme, percurso grande, travagem firme no fim. A 2.ª secção
   ("Futuros", .section--alt) mantém o reveal normal. Disparado pelo script do
   portfólio SÓ depois de um frame inicial pintado (gate da cortina / rAF), o
   que também corrige a navbar (que antes saltava sem transição).
   Easing partilhado (quase-linear com travagem): cubic-bezier(.1,.25,.25,1). */

/* Cards da 1.ª secção — versão pesada: mesmo percurso (translateY(100%)→0, via
   .is-risen já definido acima), mas mais lento (2s) e a arrancar depois do
   título (transition-delay base). !important nos delays porque o reveal geral
   escreve transition-delay inline em cada .card. */
html.reveal-ready .section--flat-top .grid-projects .card-rise .card{
  transition:transform 2s cubic-bezier(.1,.25,.25,1), box-shadow .5s var(--ease);
}
html.reveal-ready .section--flat-top .grid-projects .card-rise .card{ transition-delay:1s !important; }
html.reveal-ready .section--flat-top .grid-projects .card-rise:nth-child(3n+2) .card{ transition-delay:1.1s !important; }
html.reveal-ready .section--flat-top .grid-projects .card-rise:nth-child(3n+3) .card{ transition-delay:1.2s !important; }

/* Título da 1.ª secção (display/lead) — slide pesado, arranca a t=0.
   !important para vencer o .is-visible do reveal geral, que o Base.astro
   adiciona SÍNCRONO no astro:page-load: sem isto, resolveria o título cedo
   (leve, 26px) e faria saltar. Resolvido só por .is-entered, que o script
   adiciona depois de a cortina levantar. Gated por reveal-ready → em
   reduced-motion o título aparece normal, sem transição. */
html.reveal-ready .section--flat-top .block-head :is(.display, .lead){
  opacity:0 !important;
  transform:translateY(80px) !important;
  transition:opacity .45s var(--ease),
             transform 1.9s cubic-bezier(.1,.25,.25,1) !important;
  will-change:transform, opacity;
}
html.reveal-ready .section--flat-top.is-entered .block-head :is(.display, .lead){
  opacity:1 !important;
  transform:none !important;
}

/* h1 do 1.º bloco (portfólio + histórico): maior que o .display--sm, para dar
   mais destaque ao título de abertura. Especificidade (0,3,1) vence
   .block-head .display e .display--sm. */
.section--flat-top .block-head .display{
  font-size:clamp(2.5rem, 6vw, 4.6rem);
}

/* Cards do 1.º bloco do HISTÓRICO — entram DEPOIS do título (não antes).
   O reveal genérico do Base adiciona .is-visible SÍNCRONO no astro:page-load,
   por isso os cards subiam logo, muito antes do título (que espera a cortina).
   Aqui a entrada é gated pela mesma .is-entered da secção (script do histórico,
   já depois da cortina) e atrasada para arrancar a seguir ao título. Sem wrapper
   .card-rise, para não mexer na estrutura da grelha de que a modal depende.
   Só afeta o histórico: o portfólio usa .card-rise (não .card--modal).
   Especificidade .section--flat-top .grid-projects .card--modal (0,3,1) vence
   .card.is-visible (0,2,0); transition-delay com !important vence o delay inline
   que o Base escreve em cada card. */
html.reveal-ready .section--flat-top .grid-projects .card--modal{
  opacity:0;
  transform:translateY(52px);
  transition:opacity .5s var(--ease),
             transform 1.4s cubic-bezier(.1,.25,.25,1);
  transition-delay:.9s !important;
  will-change:transform, opacity;
}
html.reveal-ready .section--flat-top.is-entered .grid-projects .card--modal{
  opacity:1;
  transform:none;
}
/* Cascata por coluna (grelha de 3): esquerda → direita, a seguir ao título. */
html.reveal-ready .section--flat-top .grid-projects .card--modal:nth-child(3n+2){ transition-delay:1.05s !important; }
html.reveal-ready .section--flat-top .grid-projects .card--modal:nth-child(3n+3){ transition-delay:1.2s !important; }

/* 2) Sublinhado animado no menu + indicador da página atual */
.nav__list a::after{
  content:""; position:absolute; left:0; right:0; bottom:0; height:1.5px;
  background:currentColor; transform:scaleX(0); transform-origin:left;
  transition:transform .35s var(--ease);
}
.nav__list a:hover::after,
.nav__list a[aria-current="page"]::after{ transform:scaleX(1); }
.nav__list a[aria-current="page"]{ color:var(--accent-dk); opacity:1; }
.scrolled .nav__list a[aria-current="page"]{ color:var(--accent); }

/* 3) Hover dos cards: leve elevação + sombra + realce do overlay/CTA */
.grid-projects .card, .scroller .card{
  transition:transform .5s var(--ease), box-shadow .5s var(--ease);
}
.grid-projects .card:hover, .scroller .card:hover{
  transform:translateY(-6px);
  box-shadow:0 20px 44px -20px rgba(0,0,0,.5);
}
.card__overlay{ transition:background .4s var(--ease); }
.card:hover .card__overlay{ background:linear-gradient(180deg, transparent 0%, rgba(0,0,0,.62) 42%, rgba(0,0,0,.92) 100%); }
.card__cta{ transition:gap .3s var(--ease); }
.card:hover .card__cta{ gap:.9rem; }

/* 4) Links de texto no conteúdo: sublinhado que cresce */
.muted a{
  background:linear-gradient(var(--accent),var(--accent)) 0 100%/0 1px no-repeat;
  transition:background-size .35s var(--ease), color .3s var(--ease);
}
.muted a:hover{ background-size:100% 1px; color:var(--accent); }

@media (prefers-reduced-motion: reduce){
  .grid-projects .card:hover, .scroller .card:hover{ transform:none; box-shadow:none; }
}


/* =====================================================================
   TRANSIÇÃO ENTRE SECTIONS (home) — cortina que recolhe de cima para
   baixo, revelando cada secção ao entrar (encaixe à la modus).
   A cortina tem a cor de fundo da própria secção, logo lê-se como um
   "wipe" limpo. Não usa transform na secção → não soma ao slide dos
   elementos. Gated por reveal-ready (respeita prefers-reduced-motion).
   ===================================================================== */
body.is-home .section{ position:relative; }
html.reveal-ready body.is-home .section::after{
  content:""; position:absolute; inset:0; z-index:5; pointer-events:none;
  background:var(--paper);
  transform:scaleY(1); transform-origin:bottom;
  transition:transform .9s var(--ease);
}
html.reveal-ready body.is-home .section--alt::after{ background:var(--paper-alt); }
html.reveal-ready body.is-home .section--dark::after{ background:var(--dark); }
html.reveal-ready body.is-home .section--accent::after{ background:var(--accent); }
html.reveal-ready body.is-home .section.is-visible::after{ transform:scaleY(0); }

/* =====================================================================
   PÁGINA DE EMPREENDIMENTO (detalhe)
   ===================================================================== */
/* Cards e painéis que passaram a ser links */
a.card, a.panel{ text-decoration:none; color:inherit; }

.emp-back{
  display:inline-block; margin-bottom:1rem;
  color:rgba(255,255,255,.8); text-decoration:none;
  font-size:.85rem; letter-spacing:.02em;
  transition:color .3s var(--ease);
}
.emp-back:hover{ color:#fff; }
.emp-hero__meta{
  margin-top:1rem; color:rgba(255,255,255,.92); font-size:1.05rem;
  display:flex; align-items:center; gap:.9rem; flex-wrap:wrap;
}
.emp-chip{
  display:inline-block; padding:.34em .95em;
  border:1px solid rgba(255,255,255,.5); border-radius:999px;
  font-size:.72rem; letter-spacing:.14em; text-transform:uppercase;
}

/* Ficha / características */
.facts{
  display:grid; grid-template-columns:repeat(3,1fr);
  gap:clamp(8px,1.2vw,14px); margin-top:2.5rem;
}
.fact{
  background:var(--paper); border:1px solid var(--line); border-radius:12px;
  padding:clamp(18px,2.2vw,30px); display:flex; flex-direction:column; gap:.45rem;
}
.section--alt .fact{ background:#ffffff; }
.fact__v{ font-family:var(--serif); font-size:clamp(1.35rem,2.4vw,2rem); color:var(--ink); line-height:1.1; }
.fact__r{ font-size:.76rem; letter-spacing:.14em; text-transform:uppercase; color:var(--ink-soft); }

/* Galeria */
.gallery{
  display:grid; grid-template-columns:repeat(3,1fr);
  gap:clamp(10px,1.4vw,18px); margin-top:2.5rem;
}
.gallery .ph{ aspect-ratio:4/3; }
.gallery__img{ aspect-ratio:4/3; width:100%; height:100%; object-fit:cover; display:block; }

/* =====================================================================
   RESPONSIVO
   ===================================================================== */
@media (max-width: 1024px){
  .stats{ grid-template-columns:repeat(2,1fr); }
  .grid-projects{ grid-template-columns:repeat(2,1fr); }
  .facts, .gallery{ grid-template-columns:repeat(2,1fr); }
  .team{ grid-template-columns:repeat(2,1fr); }
  .footer-grid{ grid-template-columns:1fr 1fr; }
  /* Menu vira hambúrguer já no tablet, onde o nav horizontal não cabe */
  .nav__list, .nav__lang{ display:none; }
  .nav-toggle{ display:flex; }
  .nav.open .nav__list{
    display:flex; position:fixed; inset:0; background:var(--dark);
    flex-direction:column; align-items:center; justify-content:center; gap:1.8rem; z-index:90;
  }
  .nav.open .nav__list a{ color:#fff; font-size:1rem; opacity:1; }
}
@media (max-width: 760px){
  .split, .service, .contact{ grid-template-columns:1fr; }
  .split--reverse .split__media, .service:nth-child(even) .service__media{ order:0; }
  .team{ grid-template-columns:1fr; }
  .stats{ grid-template-columns:1fr; }
  .grid-projects{ grid-template-columns:1fr; }
  .facts{ grid-template-columns:repeat(2,1fr); }
  .gallery{ grid-template-columns:1fr; }
  .footer-grid{ grid-template-columns:1fr; }
  .scroller{ grid-auto-columns:minmax(260px,80%); }
}

/* =====================================================================
   JANELA MODAL DO EMPREENDIMENTO (histórico)
   Layout: imagem/título à esquerda, informação à direita.
   ===================================================================== */
/* Card do histórico é um botão (abre o modal) — herda o visual do link-card. */
button.card{
  appearance:none; -webkit-appearance:none; border:0; padding:0; margin:0;
  width:100%; text-align:left; font:inherit; color:inherit;
  background:transparent; cursor:pointer;
}

/* Painel inline do empreendimento: acordeão dentro de .grid-projects. Aberto
   pelos cards .card--modal (historico); ocupa a linha inteira e é inserido por
   JS a seguir ao último card da linha do card clicado. A altura anima com o
   truque grid 0fr → 1fr; o inner clipa o conteúdo durante o colapso. */
.epanel{ grid-column:1 / -1; }
.epanel[hidden]{ display:none; }

.epanel__wrap{ display:grid; grid-template-rows:0fr; transition:grid-template-rows .8s var(--ease); }
.epanel.is-open .epanel__wrap{ grid-template-rows:1fr; }

.epanel__inner{
  overflow:hidden; min-height:0;
  display:grid; grid-template-columns:1.05fr 1fr;
  background:var(--paper); border:1px solid var(--line);
  box-shadow:0 24px 60px rgba(0,0,0,.16);
}
/* Inline não tem cap de altura: a coluna de info cresce com o conteúdo. */
.epanel .emodal__info{ max-height:none; overflow:visible; }

/* Painel esquerdo — imagem escura com título e chips */
.emodal__media{ position:relative; min-height:340px; background:var(--dark); overflow:hidden; display:flex; flex-direction:column; }
.emodal__img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
.emodal__media-grad{ position:absolute; inset:0; background:linear-gradient(180deg, rgba(10,10,10,.78) 0%, rgba(10,10,10,.28) 34%, rgba(10,10,10,.22) 60%, rgba(10,10,10,.9) 100%); }
.emodal__media-head{ position:relative; z-index:1; padding:clamp(24px,3vw,40px) clamp(24px,3vw,40px) 0; }
.emodal__title{ font-family:var(--serif); font-weight:400; color:#fff; font-size:clamp(1.7rem,3vw,2.5rem); line-height:1.08; text-shadow:0 1px 14px rgba(0,0,0,.5); }
.emodal__subtitle{ color:rgba(255,255,255,.9); font-size:.86rem; letter-spacing:.06em; margin-top:.55rem; text-shadow:0 1px 10px rgba(0,0,0,.5); }
.emodal__chips{ position:relative; z-index:1; margin-top:auto; padding:clamp(20px,3vw,36px) clamp(24px,3vw,40px); display:flex; flex-wrap:wrap; gap:.5rem; }
.emodal__chip{
  display:inline-flex; align-items:center; padding:.42em 1em;
  background:rgba(255,255,255,.14); border:1px solid rgba(255,255,255,.28); border-radius:999px;
  color:#fff; font-size:.74rem; letter-spacing:.04em; backdrop-filter:blur(4px);
}
.emodal__media .img-prov{ z-index:2; }

/* Painel direito — informação. min-height:0 + max-height próprio para o
   overflow-y rolar dentro do diálogo (senão o grid estica e o rodapé é cortado). */
.emodal__info{ position:relative; padding:clamp(28px,3.2vw,48px); overflow-y:auto; min-height:0; max-height:min(680px,92vh); }
.emodal__close{
  position:absolute; top:clamp(14px,1.6vw,22px); right:clamp(14px,1.6vw,22px);
  width:40px; height:40px; border:0; border-radius:999px; background:transparent;
  font-size:1.7rem; line-height:1; color:var(--ink); cursor:pointer;
  display:flex; align-items:center; justify-content:center; transition:background .25s var(--ease);
}
.emodal__close:hover{ background:var(--paper-alt); }
.emodal__info-title{ font-family:var(--serif); font-weight:400; font-size:clamp(1.4rem,2.4vw,1.9rem); margin:.5rem 0 1rem; color:var(--ink); }
.emodal__resumo{ color:var(--ink-soft); font-size:.95rem; margin-bottom:1.6rem; }
.emodal__facts{ display:flex; flex-direction:column; gap:.5rem; }
.emodal__fact{
  display:flex; align-items:baseline; justify-content:space-between; gap:1rem;
  border:1px solid var(--line); padding:.85rem 1.1rem;
}
.emodal__fact-label{ font-size:.72rem; letter-spacing:.14em; text-transform:uppercase; color:var(--ink-soft); }
.emodal__fact-value{ font-family:var(--serif); font-size:1.05rem; color:var(--ink); text-align:right; }
.emodal__footer{ margin-top:1.8rem; display:flex; align-items:center; justify-content:space-between; gap:1rem; flex-wrap:wrap; }
.emodal__entrega{ font-size:.8rem; letter-spacing:.04em; color:var(--ink-faint); }

@media (max-width: 760px){
  /* Empilha (imagem no topo, info em baixo) — a grelha já é de 1 coluna aqui. */
  .epanel__inner{ grid-template-columns:1fr; }
  .emodal__media{ min-height:0; height:clamp(200px,34vh,280px); }
  .emodal__info{ max-height:none; overflow:visible; }
  .emodal__chips{ margin-top:auto; }
}
@media (prefers-reduced-motion: reduce){
  .epanel__wrap{ transition:none; }
}

/* =====================================================================
   DEPOIMENTOS (carrossel com pilha de imagens 3D)
   Componente src/components/Testimonials.astro. Config (cores/tamanhos)
   chega por CSS custom properties --t-* definidas por instância.
   ===================================================================== */
/* padding-inline a zero: o carrossel tem de assentar no mesmo eixo vertical
   que o título da secção, e não 2rem à direita dele. */
.testimonials{ width:100%; max-width:none; padding:2rem 0; outline:none; }
.testimonials__grid{ display:grid; gap:5rem; }
.testimonials__images{ position:relative; width:100%; height:38rem; perspective:1000px; }
.testimonials__img{
  position:absolute; width:100%; height:100%; object-fit:cover;
  border-radius:0; box-shadow:0 14px 40px rgba(0,0,0,.16); opacity:0;
}
/* Placeholder (membro sem foto): mesmo padrão diagonal do resto do site. */
.testimonials__img--ph{
  background:
    repeating-linear-gradient(45deg,
      rgba(0,0,0,.035) 0, rgba(0,0,0,.035) 1px,
      transparent 1px, transparent 11px),
    var(--paper-alt);
  border:1px solid var(--line);
}
.testimonials__img--ph::after{
  content:"Foto"; position:absolute; inset:0; display:grid; place-items:center;
  font-size:.7rem; letter-spacing:.28em; text-transform:uppercase; font-weight:600; color:var(--ink-faint);
}
/* Antes do JS: mostra o primeiro depoimento (fallback sem salto). */
.testimonials__img[data-index="0"]{ opacity:1; z-index:3; }
.testimonials__content{ display:flex; flex-direction:column; justify-content:flex-start; }
.testimonials__name{
  font-family:var(--serif); font-weight:400; margin-bottom:.5rem; line-height:1.1;
  color:var(--t-name,#000); font-size:var(--t-name-size,1.5rem);
}
.testimonials__designation{
  margin-bottom:2rem; color:var(--t-designation,#6b7280); font-size:var(--t-designation-size,.8rem);
  text-transform:uppercase; letter-spacing:.16em;
}
.testimonials__divider{ margin-bottom:1.6rem; }
.testimonials__quote{ line-height:1.8; color:var(--t-quote,#4b5563); font-size:var(--t-quote-size,1.125rem); max-width:62ch; }
.testimonials__body{ animation:testimonial-fade .5s var(--ease) both; }
.testimonials__arrows{ display:flex; gap:1.5rem; padding-top:3rem; }
.testimonials__arrow{
  width:2.7rem; height:2.7rem; border-radius:50%;
  display:flex; align-items:center; justify-content:center; cursor:pointer; border:none;
  background:var(--t-arrow-bg,#141414); color:var(--t-arrow-fg,#f1f1f7);
  transition:background-color .3s;
}
.testimonials__arrow:hover{ background:var(--t-arrow-hover-bg,#00a6fb); }
.testimonials__arrow svg{ width:28px; height:28px; }
@keyframes testimonial-fade{
  from{ opacity:0; transform:translateY(10px); }
  to{ opacity:1; transform:translateY(0); }
}
@media (min-width:768px){
  /* Coluna das imagens compacta à esquerda; o texto absorve a largura extra. */
  .testimonials__grid{ grid-template-columns:minmax(0,32rem) 1fr; }
}
@media (prefers-reduced-motion: reduce){
  .testimonials__body{ animation:none; }
  .testimonials__img{ transition:none !important; }
}

/* =====================================================================
   DOUBLE SLIDER — secção Portfolio da home
   Layout copiado de custom-double-slider.webflow.io (ver referencias/sites/
   LINKS.md), com a altura reduzida: a referência ocupa o ecrã inteiro.
   Slide de fundo full-bleed + fila de miniaturas dos PRÓXIMOS empreendimentos
   sangrada pela borda direita. Sem autoplay.
   ===================================================================== */
.section--flush{ padding-block:0; }
/* flow-root: sem BFC próprio, a margem negativa do card colapsava com a da
   secção e puxava a costura para cima em vez de fazer o card descer. */
.section--dark.section--flush{ display:flow-root; }

/* Primeira secção de uma página sem hero (body.no-hero): o header é fixo e
   sólido desde o topo, por isso damos folga extra para o título não encostar
   à barra. */
.no-hero .section--flat-top{ padding-top:calc(var(--section-y) + clamp(20px, 3vw, 48px)); }

.dslider{
  position:relative; z-index:7;   /* acima da cunha (6) */
  overflow:hidden;
  /* Desce exatamente a altura da cunha para lá da fronteira e o bordo inferior é
     recortado NA MESMA diagonal da costura — assim a própria imagem preenche o
     triângulo até à linha transversal, em vez de a cunha ficar em cor chapada
     abaixo do card. Mesmo idioma dos painéis do Histórico (.section--panels-cut). */
  min-height:calc(clamp(680px, 92vh, 900px) + var(--stitch-rise));
  margin-bottom:calc(-1 * var(--stitch-rise));
  clip-path:polygon(0 0, 100% 0, 100% calc(100% - var(--stitch-rise)), 0 100%);
  display:flex;
  color:#fff;
  /* Sem o scrim a escurecer a imagem, uma sombra leve mantém o texto branco a ler
     sobre céus claros. */
  text-shadow:0 2px 22px rgba(0,0,0,.55);
  background:var(--dark);
}

/* ---- Palco e slides ---- */
.dslider__stage{ position:absolute; inset:0; }
.dslider__slide{
  position:absolute; inset:0;
  opacity:0; visibility:hidden;
  transition:opacity .8s var(--ease), visibility .8s;
}
.dslider__slide.is-active{ opacity:1; visibility:visible; }
.dslider__img{
  width:100%; height:100%; object-fit:cover;
  transform:scale(1.06);
  transition:transform 1.2s var(--ease);
}
.dslider__img--ph{ background:#1d1d1d; }
.dslider__slide.is-active .dslider__img{ transform:scale(1); }

/* ---- Bloco central (só o nome) ---- */
.dslider__body{
  position:absolute; inset:0; z-index:2;
  display:flex; flex-direction:column; align-items:center; justify-content:flex-start;
  text-align:center;
  padding-inline:var(--gutter);
  /* O nome ancora no terço superior, logo abaixo da faixa de topo, para deixar
     o meio da imagem livre — o CTA vive no canto inferior esquerdo. */
  padding-top:clamp(8.4rem, 17vh, 11rem);
}
/* Canto inferior esquerdo: o CTA do empreendimento e, por cima dele, o selo de
   imagem provisória. Ficam fora do bloco central para o nome respirar sozinho e
   longe do header e das miniaturas (que sangram pela direita). */
.dslider__corner{
  position:absolute; z-index:3;
  /* +stitch-rise: o card desce a cunha e é recortado na diagonal, por isso o
     conteúdo sobe a mesma medida para não cair na zona cortada. */
  left:var(--gutter); bottom:calc(clamp(1.4rem, 3.5vh, 2.6rem) + var(--stitch-rise));
  display:flex; flex-direction:column; align-items:flex-start; gap:.8rem;
}
.dslider__corner .img-prov{ position:static; }
/* Caixa de altura fixa (2 linhas do maior corpo): garante que a meta e o CTA
   ficam sempre à mesma altura, quer o nome ocupe uma linha ou duas. */
.dslider__head{
  display:grid; place-items:center;
  width:100%; min-height:clamp(5.2rem, 12vw, 8.6rem);
}
.dslider__name{
  font-family:var(--serif); font-weight:300;
  text-transform:uppercase;
  letter-spacing:.14em;
  line-height:1.05;
  text-wrap:balance;
  font-size:var(--name-size, clamp(2rem, 6vw, 5rem));
  /* o letter-spacing empurra a última letra: compensa para ficar centrado */
  margin-right:-.14em;
}
/* ---- Faixa superior: "Ver portfólio" ----
   Encostada ao topo da imagem, mas ainda abaixo do header fixo (~72px = 4.5rem),
   senão fica tapada por ele quando a secção passa por baixo do header. */
.dslider__top{
  position:absolute; z-index:3;
  inset:clamp(4.8rem, 6.6vh, 5.2rem) var(--gutter) auto var(--gutter);
  display:flex; align-items:center; justify-content:flex-end; gap:1.5rem;
}


/* ---- Rodapé: setas + fila de miniaturas ----
   A caixa atravessa toda a largura mas a metade esquerda é espaço vazio (as
   setas são empurradas com margin-left:auto). Sem pointer-events:none essa
   metade tapava o CTA do canto inferior esquerdo, que deixava de ser clicável. */
.dslider__foot{
  position:absolute; z-index:3;
  inset:auto 0 calc(clamp(1.4rem, 3.5vh, 2.6rem) + var(--stitch-rise)) var(--gutter);
  display:flex; align-items:flex-end; gap:clamp(1rem, 2.5vw, 2rem);
  pointer-events:none;
}
.dslider__arrows,
.dslider__thumbs{ pointer-events:auto; }
.dslider__arrows{
  margin-left:auto;                       /* encosta as setas às miniaturas */
  display:flex; align-items:center; gap:.8rem;
  padding-bottom:clamp(1rem, 4vh, 2.4rem);
}
.dslider__arrow{
  width:48px; height:48px; flex:none;
  display:flex; align-items:center; justify-content:center;
  border:1px solid rgba(255,255,255,.45); border-radius:50%;
  background:transparent; color:#fff; cursor:pointer;
  transition:background-color .3s var(--ease), border-color .3s var(--ease), color .3s var(--ease);
}
.dslider__arrow:hover{ background:var(--accent); border-color:var(--accent); color:#fff; }
.dslider__arrow svg{
  width:20px; height:20px; fill:none; stroke:currentColor;
  stroke-width:1.5; stroke-linecap:round; stroke-linejoin:round;
}
.dslider__count{
  display:none;
  font-size:.72rem; letter-spacing:.22em; font-weight:600;
  color:rgba(255,255,255,.7);
}

.dslider__thumbs{ flex:none; width:min(52vw, 780px); overflow:hidden; }
.dslider__track{
  display:flex; gap:clamp(.6rem, 1.2vw, 1rem);
  transition:transform .8s var(--ease);
  will-change:transform;
}
.dslider__track.is-instant{ transition:none; }
.dslider__thumb{
  position:relative; flex:none;
  width:clamp(180px, 23vw, 340px); aspect-ratio:2 / 1;
  padding:0; border:none; background:#1d1d1d; cursor:pointer;
  overflow:hidden;
  transition:opacity .4s var(--ease);
}
.dslider__thumb img{ width:100%; height:100%; object-fit:cover; }
.dslider__thumb::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(180deg, transparent 40%, rgba(0,0,0,.65) 100%);
  transition:background .4s var(--ease);
}
.dslider__thumb:hover::after{ background:linear-gradient(180deg, rgba(0,0,0,.2) 0%, rgba(0,0,0,.8) 100%); }
.dslider__thumb-ph{ position:absolute; inset:0; background:#1d1d1d; }
.dslider__thumb-label{
  position:absolute; z-index:2; right:.9rem; bottom:.7rem;
  font-size:.66rem; letter-spacing:.2em; text-transform:uppercase; font-weight:600;
  color:#fff; text-align:right;
}

/* ---- Ecrãs estreitos: sem fila de miniaturas, com contador ---- */
@media (max-width: 900px){
  .dslider{ min-height:calc(clamp(580px, 78vh, 760px) + var(--stitch-rise)); }
  /* Sobrepõe-se ao --name-size: em ecrãs estreitos manda a largura, não o nome. */
  .dslider__name{ font-size:clamp(1.4rem, 7.4vw, 2.2rem); }
  .dslider__head{ min-height:clamp(4.4rem, 19vw, 6rem); }
  .dslider__body{ padding-top:clamp(10rem, 24vh, 13rem); }
  /* Sem miniaturas, as setas ficam centradas em baixo: o CTA sobe para cima
     delas e centra-se, em vez de disputar o canto esquerdo. */
  .dslider__corner{
    left:var(--gutter); right:var(--gutter);
    bottom:calc(clamp(5.6rem, 14vh, 7.4rem) + var(--stitch-rise));
    align-items:center; gap:.6rem;
  }
  .dslider__thumbs{ display:none; }
  .dslider__foot{ inset:auto var(--gutter) calc(clamp(1.4rem, 3.5vh, 2.6rem) + var(--stitch-rise)) var(--gutter); justify-content:center; }
  .dslider__arrows{ margin:0 auto; padding-bottom:0; }
  .dslider__count{ display:inline-block; margin-left:.6rem; }
}

@media (prefers-reduced-motion: reduce){
  .dslider__slide,
  .dslider__img,
  .dslider__track{ transition:none !important; }
  .dslider__slide.is-active .dslider__img,
  .dslider__img{ transform:none; }
}

/* A cortina É a transição toda. O crossfade nativo da View Transition do Astro é
   redundante e ainda corre ~250ms DEPOIS do swap, no top layer (acima de tudo,
   até da nav): quando a cortina se retira, esse crossfade está a terminar por
   cima e lê-se como um flash. Desligamo-lo — o swap passa a ser instantâneo por
   baixo da cortina. (O projeto não usa transition:name/animate, nada a perder.) */
::view-transition-old(root),
::view-transition-new(root) { animation: none; }

/* ===== Cortina de transição entre páginas =====================================
   Overlay fixo que desce a cobrir o ecrã, troca o DOM por baixo, e revela.
   Repousa fora do ecrã (acima) e escondido; só fica visível durante a troca. */
.curtain {
  position: fixed;
  inset: 0;
  z-index: 9999;                  /* acima do header e de tudo */
  clip-path: inset(100% 0 0 0);   /* recolhida no fundo, invisível em repouso */
  visibility: hidden;
  pointer-events: none;
  background: var(--dark);        /* fundo enquanto a imagem carrega / fallback */
}
.curtain--active { visibility: visible; will-change: clip-path; }
.curtain__img {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
}
/* Mesmo tratamento (mais claro/frio) da foto da hero. Só no caminho com imagem:
   na cortina sólida o filtro incidiria sobre o branco do papel. */
.curtain:not(.curtain--solid) .curtain__img { filter: var(--hero-img-filter); }
/* Sem imagem de destino (só o portfólio, página sem hero): cortina BRANCA.
   O caminho sólido faz um fade branco simples (não o wipe escuro), por isso a
   cor é o papel do site — a página branca por baixo esbate sem costura. */
.curtain--solid { background: var(--paper); }
.curtain--solid .curtain__img { background: var(--paper); }
/* Mesmo véu do .hero__overlay: a cortina (imagem) coincide com a hero real
   por baixo, para a remoção instantânea da cortina ficar sem costura. Só com
   imagem (na sólida não faz sentido).
   Fica no .curtain, não no .curtain__img: dentro do .curtain__img apanhava o
   `filter` do pai e o wash azul saía com outra cor que o da hero. */
.curtain:not(.curtain--solid)::after {
  content: ""; position: absolute; inset: 0;
  background: var(--hero-veil);
}

/* Durante a transição, a nav fica POR CIMA da cortina (z-index > .curtain): a
   barra de navegação não desaparece enquanto a página é trocada por baixo — fica
   fixa enquanto a cortina faz o wipe. A cortina tem transition:persist e mantém
   .curtain--active através do swap, por isso o :has() vale de forma contínua. */
body:has(#page-curtain.curtain--active:not(.curtain--solid)) .site-header { z-index: 10000; }

/* Durante a cortina, o header assenta sobre a hero (escura) de destino. Mesmo que
   a página que se deixa estivesse rolada (.scrolled preso, com o scroll congelado),
   a nav volta ao aspeto "sobre hero": fundo transparente, texto e logo claros —
   senão a barra creme do .scrolled contrasta com a cortina escura e quebra o wipe.
   Ao retirar-se a cortina a página nova já está no topo, por isso não há salto. */
body:has(#page-curtain.curtain--active:not(.curtain--solid)) .site-header.scrolled{
  background:transparent; backdrop-filter:none; box-shadow:none;
  padding-block:1.4rem;               /* tamanho de descanso, não o compacto */
}
body:has(#page-curtain.curtain--active:not(.curtain--solid)) .scrolled .logo{ height:54px; }
body:has(#page-curtain.curtain--active:not(.curtain--solid)) .scrolled .nav__list a{ color:#fff; opacity:.9; }
body:has(#page-curtain.curtain--active:not(.curtain--solid)) .scrolled .nav__list a[aria-current="page"]{ color:var(--accent-dk); opacity:1; }
body:has(#page-curtain.curtain--active:not(.curtain--solid)) .scrolled .nav__lang{ color:#fff; }
body:has(#page-curtain.curtain--active:not(.curtain--solid)) .scrolled .nav-toggle span{ background:#fff; }
body:has(#page-curtain.curtain--active:not(.curtain--solid)) .scrolled .logo__img--light{ display:block; }
body:has(#page-curtain.curtain--active:not(.curtain--solid)) .scrolled .logo__img--dark{ display:none; }

@media (prefers-reduced-motion: reduce) {
  .curtain { display: none; }  /* sem cortina; navegação direta */
}

/* ===== Preloader (só na 1.ª carga) ===========================================
   Escondido por defeito: sem JS, ou em navegação suave, não aparece. O script
   inline liga html.is-loading só na 1.ª carga real (ver Base.astro). */
.preloader {
  position: fixed;
  inset: 0;
  z-index: 10000;                 /* acima da cortina e do header */
  display: none;
  background: var(--paper);       /* branco/papel da marca */
  color: var(--ink);
  clip-path: inset(0 0 0 0);      /* base para a transição de saída animar */
  transition: clip-path 1.5s cubic-bezier(.8,0,.2,1);
  will-change: clip-path;
}
html.is-loading .preloader { display: block; }
html.is-loading { overflow: hidden; }   /* trava o scroll enquanto carrega */

.preloader__bar {
  position: absolute; top: 0; left: 0;
  height: 4px; width: 100%;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: left center;
  will-change: transform;
}
.preloader__count {
  position: absolute;
  left: clamp(16px, 4vw, 48px);
  bottom: clamp(12px, 3vh, 40px);
  font-size: clamp(3rem, 12vw, 9rem);
  line-height: .9;
  font-variant-numeric: tabular-nums;
}
/* Saída: wipe para cima, igual à cortina. */
.preloader--out { clip-path: inset(0 0 100% 0); }

@media (prefers-reduced-motion: reduce) {
  .preloader { display: none !important; }
}

/* ===== Marca-d'água do símbolo — identidade (spec 2026-07-28) ===== */
.has-wm{ position:relative; z-index:0; }
.wm-layer{ position:absolute; inset:0; overflow:visible; pointer-events:none; z-index:-1; }
.wm{ position:absolute; }
.wm--mid{ top:50%; transform:translateY(-50%); }
.wm--top{ top:6%; }
.wm--bottom{ bottom:6%; }
.wm--l{ left:-6%; }
.wm--r{ right:-6%; }
.wm--sm{ width:min(24%,210px); }
.wm--md{ width:min(34%,320px); }
.wm--lg{ width:min(46%,440px); }
.wm--line{ opacity:.5; }
.wm--line .bar, .wm--line .tab{ fill:none; stroke:var(--accent); stroke-width:2.4; vector-effect:non-scaling-stroke; }
.wm--fill{ opacity:.07; }
.wm--fill .bar, .wm--fill .tab{ fill:var(--accent); }
.wm--dark{ opacity:.08; }
.wm--dark .bar, .wm--dark .tab{ fill:#f2efe9; }

/* ===== Divisor-assinatura (3 linhas + encaixe) — 2ª vaga ===== */
.divider{ position:relative; display:flex; flex-direction:column; gap:6px; max-width:340px; margin:1.8rem 0; padding-top:16px; }
.divider__line{ height:4px; background:var(--ink); }
.divider__line--strong{ height:4px; background:var(--ink); }
.divider__tab{ position:absolute; top:0; left:0; width:52px; height:6px; background:var(--accent); }

/* ===== Moldura de imagem (encaixe preto + fio laranja) — 2ª vaga ===== */
.frame{ position:relative; }
.frame__tab{ position:absolute; top:38%; left:-14px; width:22px; height:34px; background:var(--ink); z-index:3; }
/* 3 faixas com as proporções de altura da marca do logótipo
   (topo→base ~74:126:189, a mais alta em baixo), todas pretas e mais
   subtis (bloco menor/estreito), frestas transparentes. */
.frame__bar{ position:absolute; top:0; right:0; width:40px; height:25px; z-index:3;
  background:linear-gradient(to bottom,
    var(--accent) 0 4px, transparent 4px 6px,
    var(--accent) 6px 13px, transparent 13px 15px,
    var(--accent) 15px 25px); }
/* Quando a Frame envolve a media, torna-se o item da grelha .split — herda a
   ordenação que era da .split__media. */
.split--reverse .frame{ order:2; }
@media (max-width:760px){ .split--reverse .frame{ order:0; } }
