﻿/* =========================================================
   METRIK Interiores — Apresentação Interna
   Template de apresentação de projeto residencial (base: Apto Maré)

   Identidade visual seguindo o Brand Guide v2.0:
   - Paleta 100% monocromática (preto, grafite, cinzas, off-white, branco)
   - Sem cor de acento gráfica. Cores vêm SÓ das fotos do projeto.
   - Tipografia: Inter (corpo), DM Serif Display (editorial),
     Maven Pro (display/slides). Sem decorativas.
   - Princípios: ordem, leveza, toque de arte. Respiro sempre.
   ========================================================= */

:root {
  /* === Brand tokens (Brand Guide v2.0) === */
  --color-black:      #1E1E1E;
  --color-graphite:   #3D3D3A;
  --color-gray-700:   #5F5E5A;
  --color-gray-500:   #888780;
  --color-gray-300:   #B4B2A9;
  --color-gray-100:   #D3D1C7;
  --color-offwhite:   #F5F4F0;
  --color-white:      #FFFFFF;

  /* === Fontes === */
  --font-primary:   'Inter', Arial, sans-serif;
  --font-slides:    'Maven Pro', 'Inter', Arial, sans-serif;
  --font-editorial: 'DM Serif Display', Georgia, serif;

  /* === Type scale === */
  --type-display:  clamp(2.5rem, 5vw, 4.5rem);
  --type-h1:       clamp(2rem, 3.5vw, 2.75rem);
  --type-h2:       clamp(1.5rem, 2.5vw, 1.75rem);
  --type-h3:       clamp(1.125rem, 1.5vw, 1.25rem);
  --type-body:     clamp(0.9375rem, 1vw, 1rem);
  --type-caption:  clamp(0.75rem, 0.8vw, 0.8125rem);
  --type-label:    clamp(0.625rem, 0.7vw, 0.6875rem);

  --tracking-label: 0.12em;
  --tracking-wide:  0.18em;
  --tracking-tight: -0.01em;

  --slide-margin: 8%;

  --ease: cubic-bezier(0.77, 0, 0.175, 1);
  --transition-slow: 300ms ease;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

/* =========================================================
   ROTATE PROMPT — visível só em celular em modo portrait.
   Em landscape no celular, o site se comporta como desktop.
   ========================================================= */
.rotate-prompt {
  display: none;
}
@media (max-width: 900px) and (orientation: portrait) {
  .rotate-prompt {
    display: flex;
    position: fixed;
    inset: 0;
    z-index: 99999;
    background: var(--color-black);
    color: var(--color-offwhite);
    align-items: center;
    justify-content: center;
    padding: 32px;
    text-align: center;
  }
  /* Bloqueia o restante do conteúdo */
  main,
  .brand-fixed,
  .lightbox {
    display: none !important;
  }
  body { overflow: hidden; }
}
.rotate-prompt__inner {
  max-width: 320px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
}
.rotate-prompt__icon {
  width: 80px;
  height: 80px;
  color: var(--color-offwhite);
  animation: rotate-hint 2.4s ease-in-out infinite;
  transform-origin: center;
}
@keyframes rotate-hint {
  0%, 40%   { transform: rotate(0deg); }
  60%, 100% { transform: rotate(-90deg); }
}
.rotate-prompt__title {
  font-family: var(--font-editorial);
  font-weight: 400;
  font-size: 1.75rem;
  line-height: 1.1;
  margin: 0;
}
.rotate-prompt__text {
  font-family: var(--font-primary);
  font-size: 0.95rem;
  line-height: 1.5;
  opacity: 0.85;
  margin: 0;
}

html, body {
  background: var(--color-offwhite);
  color: var(--color-black);
  font-family: var(--font-primary);
  font-weight: 400;
  font-size: 16px;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  user-select: none;
  -webkit-user-drag: none;
}

::selection { background: var(--color-black); color: var(--color-offwhite); }

main { width: 100%; background: var(--color-black); }

/* Helper — label uppercase com tracking padrão da marca */
.label {
  font-size: var(--type-label);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  font-weight: 500;
}

/* =========================================================
   DEV LOG — painel fixo de debug (desenvolvimento)
   ========================================================= */
.devlog {
  position: fixed;
  bottom: 16px;
  right: 16px;
  z-index: 9999;
  background: rgba(20, 20, 22, 0.88);
  color: #f5f4f0;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px;
  line-height: 1.4;
  padding: 12px 14px 12px 14px;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 6px;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  min-width: 180px;
  pointer-events: auto;
}
.devlog.is-hidden { display: none; }
.devlog__row {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  padding: 2px 0;
}
.devlog__k {
  color: rgba(245,244,240,0.55);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 9px;
  align-self: center;
}
.devlog__v {
  color: #fff;
  font-weight: 500;
  text-align: right;
  max-width: 130px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.devlog__close {
  position: absolute;
  top: 4px;
  right: 6px;
  background: transparent;
  border: 0;
  color: rgba(245,244,240,0.55);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  padding: 2px 6px;
}
.devlog__close:hover { color: #fff; }

/* =========================================================
   CHAPTER (todas as seções)
   ========================================================= */
.chapter {
  position: relative;
  width: 100vw;
}

/* =========================================================
   CAPA & CONCEITO — variações do molde .room
   ========================================================= */

/* Logo METRIK fixo no topo da capa */
/* Marca fixa — presente em todas as páginas, canto superior esquerdo */
.brand-fixed {
  position: fixed;
  top: 28px;
  left: 36px;
  z-index: 100;
  pointer-events: none;
  /* leve sombra de texto para ler em qualquer fundo */
  filter: drop-shadow(0 2px 8px rgba(0,0,0,0.45));
}
.brand-fixed__logo {
  width: 200px;
  height: auto;
  object-fit: contain;
  display: block;
}

/* =========================================================
   TOGGLE DE SOM — canto superior direito, fixo em todas as
   páginas. Mostra ícone de "muted" enquanto silencioso e
   ícone de "som" quando tocando. Estado controlado por JS
   via classe .is-on no <button>.
   ========================================================= */
/* Container fixo: ancora o botão + o slider que aparece abaixo dele. */
.audio-control {
  position: fixed;
  top: 28px;
  right: 36px;
  z-index: 101;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.audio-toggle {
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(15, 15, 17, 0.35);
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 999px;
  color: var(--color-offwhite);
  cursor: pointer;
  padding: 0;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  transition: background 200ms ease, border-color 200ms ease, transform 200ms ease;
}
.audio-toggle:hover {
  background: rgba(15, 15, 17, 0.55);
  border-color: rgba(255, 255, 255, 0.6);
  transform: scale(1.05);
}
.audio-toggle__icon {
  width: 18px;
  height: 18px;
  display: block;
}
/* Estado padrão: muted -> mostra ícone off, esconde on */
.audio-toggle .audio-toggle__icon--on { display: none; }
.audio-toggle.is-on .audio-toggle__icon--off { display: none; }
.audio-toggle.is-on .audio-toggle__icon--on { display: block; }

/* Barrinha de volume — escondida por padrão, aparece ao passar o mouse
   sobre o controle, ao focar o botão/slider, ou enquanto arrasta (JS
   adiciona .is-active). Um pequeno padding-top no slider preenche o gap
   pro hover não "cair" entre o botão e a barra. */
.audio-slider {
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  pointer-events: none;
  transition: max-height 220ms ease, opacity 220ms ease, margin-top 220ms ease;
  margin-top: 0;
}
.audio-control:hover .audio-slider,
.audio-control:focus-within .audio-slider,
.audio-control.is-active .audio-slider {
  max-height: 140px;
  opacity: 1;
  pointer-events: auto;
  margin-top: 10px;
}
.audio-slider__input {
  -webkit-appearance: none;
  appearance: none;
  /* slider vertical: gira um range horizontal */
  width: 110px;
  height: 4px;
  transform: rotate(-90deg);
  /* gambiarra de centralização do range rotacionado dentro de 40px */
  transform-origin: center;
  margin: 53px -35px;
  background: rgba(255, 255, 255, 0.3);
  border-radius: 999px;
  outline: none;
  cursor: pointer;
}
/* Trilha + thumb (WebKit) */
.audio-slider__input::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--color-offwhite);
  border: 1px solid rgba(0, 0, 0, 0.25);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
  cursor: pointer;
}
.audio-slider__input::-moz-range-thumb {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--color-offwhite);
  border: 1px solid rgba(0, 0, 0, 0.25);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
  cursor: pointer;
}
.audio-slider__input::-moz-range-track {
  height: 4px;
  background: rgba(255, 255, 255, 0.3);
  border-radius: 999px;
}

@media (max-width: 900px) {
  .audio-control { top: 20px; right: 20px; }
  .audio-toggle { width: 36px; height: 36px; }
  .audio-toggle__icon { width: 16px; height: 16px; }
}

/* Botão de planta baixa — ao lado esquerdo do controle de áudio */
.pdf-btn {
  position: fixed;
  top: 28px;
  right: 88px; /* 36px (margem) + 40px (largura do btn áudio) + 12px (gap) */
  z-index: 101;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(15, 15, 17, 0.35);
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 999px;
  color: #fff;
  text-decoration: none;
  transition: background 200ms ease, border-color 200ms ease, transform 200ms ease;
}
.pdf-btn svg {
  width: 18px;
  height: 18px;
}
.pdf-btn:hover {
  background: rgba(15, 15, 17, 0.55);
  border-color: rgba(255, 255, 255, 0.6);
  transform: scale(1.05);
}
@media (max-width: 900px) {
  .pdf-btn { top: 20px; right: 68px; width: 36px; height: 36px; }
  .pdf-btn svg { width: 16px; height: 16px; }
}

/* Sutil vinheta nas seções de capa/conceito pra dar peso ao texto */
.room--cover .room__stage::after,
.room--concept .room__stage::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(
      180deg,
      rgba(30,30,30,0.35) 0%,
      rgba(30,30,30,0.05) 35%,
      rgba(30,30,30,0.10) 55%,
      rgba(30,30,30,0.65) 100%
    );
  pointer-events: none;
  z-index: 1;
}

/* Texto da capa/conceito — maior que dos ambientes, ocupando mais espaço */
.room__text--cover {
  max-width: min(640px, 52vw);
  bottom: 10vh;
}
.room__name--cover {
  font-family: var(--font-editorial);
  font-weight: 400;
  font-size: clamp(2.6rem, 6vw, 5.5rem);
  line-height: 1.05;
  letter-spacing: var(--tracking-tight);
  margin-bottom: 22px;
}
.room__name--cover em { font-style: italic; }

/* Variante pequena do título na página 02 — coexiste com a frase
   editorial maior abaixo, sem competir com ela. */
.room__name--concept-small {
  font-size: clamp(1.2rem, 2vw, 1.8rem);
  margin-bottom: 14px;
  opacity: 0.85;
}

/* Frase única da página 02 (Conceito) — tipografia editorial,
   centralizada, ocupando o espaço onde antes havia título + copy. */
.room__copy--concept {
  font-family: var(--font-editorial);
  font-weight: 400;
  font-size: clamp(2rem, 4.6vw, 4rem);
  line-height: 1.15;
  letter-spacing: var(--tracking-tight);
  font-style: italic;
  color: var(--color-offwhite);
  text-shadow: 0 2px 18px rgba(0,0,0,0.45);
  margin: 0;
}

/* O sideword da capa tem texto longo — reduzir tamanho pra caber */
/* Capa: sideword vai pro topo-direito (logo ocupa o esquerdo) */
.room--cover .room__sideword {
  top: 40px;
  left: auto;
  right: var(--slide-margin);
  font-size: clamp(0.85rem, 1vw, 1rem);
  letter-spacing: 0.32em;
}

/* helper genérico (mantido pra compatibilidade) */
.reveal-text span { display: block; overflow: hidden; }
.reveal-text span .inner { display: inline-block; transform: translateY(110%); }

/* =========================================================
   3. MOODBOARD — vídeo controlado pelo scroll
   Seção alta (450vh) gera espaço de scroll; o container fica
   position:fixed APENAS quando a seção está no viewport
   (toggle por IntersectionObserver via .is-active). Assim
   evita vazar pra página 2/4. currentTime amarrado ao scroll
   por lerp em rAF loop.
   ========================================================= */
.moodboard {
  position: relative;
  width: 100%;
  height: 450vh;
  /* Cor do primeiro frame do vídeo — evita flash preto na transição
     entrando/saindo do moodboard. */
  background: #EAE4E5;
}
.moodboard__sticky {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh; height: 100dvh;
  overflow: hidden;
  z-index: 5;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  /* Fade só na SAÍDA (250ms). Sem background preto — o vídeo
     já cobre 100% do container, e não queremos um flash preto
     entre o offwhite da página 2 e o primeiro frame do vídeo. */
  transition: opacity 250ms ease, visibility 0s linear 250ms;
}
.moodboard.is-active .moodboard__sticky {
  opacity: 1;
  visibility: visible;
  /* Entrada instantânea — o frame inicial do vídeo já está pronto
     (applyFrame() roda no start()), então não precisa fade-in. */
  transition: opacity 0s linear 0s, visibility 0s linear 0s;
}
.moodboard__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
}
.moodboard__frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: none;
}
/* Touch devices (iPad/iPhone/Android): video.currentTime scrub é
   inviável no iOS Safari (seek só em keyframes, ~1 fps). Em touch
   mostramos apenas o último frame (cena final) estático, e
   colapsamos a altura da seção pra 1 viewport — sem scroll de scrub. */
html.is-touch .moodboard__video { display: none; }
html.is-touch .moodboard__frame { display: block; }
html.is-touch .moodboard { height: 100vh; height: 100dvh; }
/* Em touch a sticky vira a própria tela do capítulo — não há scrub,
   então não precisa ficar fixed à viewport. E forçamos opacidade
   total sem depender do JS adicionar .is-active. */
html.is-touch .moodboard__sticky {
  position: absolute;
  opacity: 1 !important;
  visibility: visible !important;
  transition: none !important;
}
/* Label "Moodboard" sempre visível em touch (cena final estática). */
html.is-touch .moodboard__sticky .moodboard__label { opacity: 1; }
/* Label "Moodboard" — aparece quando o scrub completa (JS adiciona
   .is-complete no container quando progress >= 0.95). Fica sobre o
   último frame, centralizado, em tipografia editorial. */
.moodboard__label {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  opacity: 0;
  transition: opacity 600ms ease;
}
.moodboard__sticky.is-complete .moodboard__label {
  opacity: 1;
}
.moodboard__label-text {
  font-family: var(--font-editorial);
  font-size: clamp(3rem, 9vw, 8rem);
  color: var(--color-offwhite);
  letter-spacing: 0.02em;
  text-shadow: 0 2px 24px rgba(0, 0, 0, 0.45);
}

/* =========================================================
   LIGHTBOX — clique numa imagem para abrir em tela cheia
   ========================================================= */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 9000;
  background: rgba(15,15,17,0.95);
  display: none;
  align-items: center;
  justify-content: center;
  cursor: zoom-out;
  opacity: 0;
  transition: opacity 0.25s ease;
}
.lightbox.is-open {
  display: flex;
  opacity: 1;
}
.lightbox__img {
  max-width: 92vw;
  max-height: 92vh;
  width: auto;
  height: auto;
  object-fit: contain;
  box-shadow: 0 30px 80px rgba(0,0,0,0.5);
}
.lightbox__close {
  position: absolute;
  top: 20px;
  right: 24px;
  background: transparent;
  border: 0;
  color: rgba(255,255,255,0.85);
  font-size: 32px;
  line-height: 1;
  cursor: pointer;
  padding: 6px 10px;
}
.lightbox__close:hover { color: #fff; }

/* Cursor pointer em imagens clicáveis */
.db-item img,
.room-slide img,
.room__aside-item img {
  cursor: zoom-in;
}

/* =========================================================
   AMBIENTE (.room) — uma seção por ambiente.
   Imagem completa SEM corte (contain), fundo escuro.
   Número/nome gigantes na lateral com mix-blend.
   Texto entra dentro da imagem via scroll.
   ========================================================= */

/* =========================================================
   CAPA — vídeo background + título centralizado.
   ========================================================= */
.cover {
  position: relative;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  background: var(--color-black);
}
.cover__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
  z-index: 0;
}
/* Overlay escurece levemente o vídeo pra dar legibilidade ao texto branco */
.cover__overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg,
    rgba(0,0,0,0.20) 0%,
    rgba(0,0,0,0.35) 50%,
    rgba(0,0,0,0.50) 100%);
  z-index: 1;
  pointer-events: none;
}
.cover__content {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 0 var(--slide-margin);
  color: var(--color-offwhite);
}
.cover__title {
  font-family: var(--font-editorial);
  font-weight: 400;
  font-size: clamp(3rem, 9vw, 8rem);
  line-height: 1.05;
  letter-spacing: 0.01em;
  margin: 0 0 24px;
  text-shadow: 0 2px 32px rgba(0, 0, 0, 0.4);
}
.cover__copy {
  font-family: var(--font-body, var(--font-sans, sans-serif));
  font-weight: 300;
  font-size: clamp(0.95rem, 1.1vw, 1.15rem);
  line-height: 1.6;
  letter-spacing: 0.02em;
  max-width: 640px;
  margin: 0;
  opacity: 0.95;
  text-shadow: 0 1px 12px rgba(0, 0, 0, 0.4);
}

.room {
  position: relative;
  height: 100vh; height: 100dvh;
  overflow: hidden;
  background: var(--color-black);
}

/* Stage onde rodam os crossfades das vistas */
.room__stage {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.room-slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* IMAGEM — padrão é cover (preenche a tela sem fundo preto).
   Salas com imagens VERTICAIS usam split-screen (.room--split). */
.room-slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* Vídeo dentro do stage (usado na página de conceito) — comportamento
   igual ao da imagem: cover full-bleed, sem controles. */
.room__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
}

/* =========================================================
   SPLIT-SCREEN — para imagens verticais.
   Coluna esquerda: imagem; coluna direita: mosaico ou placeholder.
   ========================================================= */
.room--split .room__stage {
  position: absolute;
  inset: 0;
  width: 50%;
  height: 100vh; height: 100dvh;
}
.room--split .room-slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
/* Em salas split (não-banheiro), imagem ocupa 100% da coluna esquerda */
.room--split .room-slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* COZINHA — layout assimétrico:
   - Slide principal ocupa 64% da tela
   - Aside ocupa 36% com 1 ou 2 imagens
   - Tudo em cover: sem black/white bars */
/* Cozinha 05 — stage de 50% acomoda melhor as imagens verticais
   (Cozinha 01a/01b, ratio 0.806). Aside 50% × 50vh dá ratio ~1.78
   pra cada item do stack-2, que combina com as horizontais 16:9. */
.room[data-name="Cozinha"]:not([data-chapter="05b"]) .room__stage {
  width: 50%;
}
.room[data-name="Cozinha"]:not([data-chapter="05b"]) .room__aside {
  width: 50%;
}
/* Cozinha 05b é full-bleed (não-split). Stage ocupa 100%. */
.room[data-chapter="05b"] .room__stage {
  width: 100%;
}
.room[data-name="Cozinha"] .room-slide img,
.room[data-name="Cozinha"] .room__aside-item img {
  object-fit: cover !important;
  object-position: center;
}
/* Cozinha 05b — o que importa é a BANCADA DE PEDRA do lado direito
   de cada imagem (uma com cuba, outra sem). Ancora o cover pela direita
   nas duas pra não perder esse detalhe. */
/* Cozinha 05b — stage full-bleed da Cozinha 05 (bancada com cuba).
   Ancora pelo centro pra mostrar a bancada bem. */
.room[data-chapter="05b"] .room-slide img {
  object-position: center;
}

/* Crop comparativo (Cozinha 04 sem cuba) — sobrepõe EXATAMENTE a região
   da bancada de pedra do stage da Cozinha 05. Como as duas imagens são
   a mesma cena, a img interna replica o full-bleed da Cozinha 04 e o
   container recorta só a janela da bancada. */
.room__compare {
  position: absolute;
  z-index: 4;
  top: 0;
  left: 60%;
  width: 38%;
  height: 60%;
  margin: 0;
  overflow: hidden;
  box-shadow: 0 0 0 3px var(--color-offwhite),
              0 18px 48px rgba(0,0,0,0.35);
}
/* Imagem interna deve aparecer na MESMA escala/posição que o stage
   (full-bleed 100vw × 100vh com object-fit cover, object-position
   center). O container recorta deslocando a imagem por -left × vw e
   -top × vh. */
.room__compare img {
  position: absolute;
  width: 100vw;
  height: 100vh; height: 100dvh;
  top: 0;
  left: -60vw;
  object-fit: cover;
  object-position: center;
  display: block;
}

/* =========================================================
   BANHEIROS (.room--bath)
   Imagem ocupa o MÁXIMO de espaço:
   - Altura = 100vh
   - Largura = automática (aspect ratio natural da imagem)
   - O restante da tela vira placeholder/aside
   Layout flex sobrescreve o split 50/50 padrão.
   ========================================================= */
/* Wrapper interno em banheiros — isola o layout flex do pin do ScrollTrigger.
   Vencer a especificidade do .room--split (que define stage/aside como
   absolutos com 50% de largura) usando este wrapper como container. */
.room--bath .room__bath-wrapper {
  display: flex;
  align-items: stretch;
  width: 100%;
  height: 100vh;
  height: 100dvh;
}

/* Stage encosta na esquerda, largura proporcional à imagem */
.room--bath .room__bath-wrapper > .room__stage {
  position: relative;
  inset: auto;
  width: auto;
  height: 100vh;
  height: 100dvh;
  flex: 0 0 auto;
  background: var(--color-black);
}

/* Slides ocupam altura cheia, largura natural */
.room--bath .room__bath-wrapper .room-slide {
  position: relative;
  inset: auto;
  width: auto;
  height: 100vh;
  height: 100dvh;
}
.room--bath .room__bath-wrapper .room-slide img {
  width: auto !important;
  height: 100vh !important; height: 100dvh !important;
  height: 100dvh !important;
  max-width: none;
  object-fit: cover !important;
  object-position: center;
  display: block;
}

/* Placeholder ou aside ocupa o restante da tela */
.room--bath .room__bath-wrapper > .room__placeholder,
.room--bath .room__bath-wrapper > .room__aside {
  position: relative;
  top: auto;
  right: auto;
  width: auto;
  height: 100vh;
  height: 100dvh;
  flex: 1 1 0;
  min-width: 0;
}

/* Em banheiros, aside sem padding/gap — imagem encosta nas bordas */
.room--bath .room__bath-wrapper > .room__aside {
  padding: 0;
  gap: 0;
  background: var(--color-black);
}

/* LAVABO — variante com 2 stages (vistas verticais) lado-a-lado + aside.
   Cada stage ocupa ~32% da largura; aside fica com o resto.
   Sobrescreve o comportamento padrão do .room--bath que deixaria as
   imagens em altura natural (vazariam fora da tela). */
.room--lavabo .room__bath-wrapper > .room__stage,
.room--lavabo .room__bath-wrapper > .room__stage--extra {
  flex: 1 1 0;
  min-width: 0;
  width: auto;
}
.room--lavabo .room__bath-wrapper .room-slide {
  width: 100%;
  height: 100vh;
  height: 100dvh;
}
.room--lavabo .room__bath-wrapper .room-slide img {
  width: 100% !important;
  height: 100% !important;
  max-width: none;
  object-fit: cover !important;
  object-position: center;
}
.room--lavabo .room__bath-wrapper > .room__aside {
  flex: 1 1 0;
  min-width: 0;
}
.room--bath .room__bath-wrapper .room__aside-item {
  background: var(--color-black);
}
.room--bath .room__bath-wrapper .room__aside-item img {
  object-fit: cover !important;
  width: 100% !important;
  height: 100% !important;
  object-position: center !important;
}
/* iPad portrait/landscape — telas mais estreitas que desktop. Usa
   object-fit: contain pra mostrar a imagem inteira em vez de cortar. */
@media (max-width: 1366px) and (orientation: portrait),
       (max-aspect-ratio: 4/3) {
  .room--bath .room__bath-wrapper .room__aside-item img {
    object-fit: contain !important;
    background: var(--color-black);
  }
}

/* Texto editorial nos banheiros — z-index acima do stage */
.room--bath .room__bath-wrapper .room__text {
  z-index: 5;
}

/* Mobile portrait — empilhar imagem + aside/placeholder verticalmente.
   Em landscape no celular, mantém layout desktop. */
@media (max-width: 900px) and (orientation: portrait) {
  .room--bath .room__bath-wrapper {
    flex-direction: column;
  }
  .room--bath .room__bath-wrapper > .room__stage,
  .room--bath .room__bath-wrapper .room-slide {
    width: 100% !important;
    height: 55vh !important;
  }
  .room--bath .room__bath-wrapper .room-slide img {
    width: 100% !important;
    height: 55vh !important;
    object-fit: cover !important;
  }
  .room--bath .room__bath-wrapper > .room__placeholder,
  .room--bath .room__bath-wrapper > .room__aside {
    width: 100%;
    height: 45vh;
  }
}

/* Painel da direita (mosaico OU placeholder) */
.room__aside {
  position: absolute;
  top: 0;
  right: 0;
  width: 50%;
  height: 100vh; height: 100dvh;
  z-index: 2;
  display: grid;
  gap: 0;
  padding: 0;
  background: var(--color-black);
}

/* Layouts de mosaico */
.room__aside--mosaic-2 { grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; }
.room__aside--mosaic-3 { grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; }
.room__aside--stack-2  { grid-template-columns: 1fr; grid-template-rows: 1fr 1fr; }
.room__aside--single   { grid-template-columns: 1fr; grid-template-rows: 1fr; }
.room__aside-item--span2 { grid-column: span 2; }

/* Variante .room--has-gaps: respiro branco uniforme entre stage e aside,
   e entre cada item do mosaico. Stage encosta na borda esquerda (não tem
   gap), as outras imagens ficam separadas por --img-gap. */
.room--has-gaps { --img-gap: 10px; background: var(--color-offwhite); }

/* Faixa de transição entre páginas — mesma largura do --img-gap,
   aparece no topo de cada seção com gap, criando consistência visual
   com os espaços internos entre imagens. */
.room--has-gaps::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: var(--img-gap);
  background: var(--color-offwhite);
  z-index: 10;
  pointer-events: none;
}
.details-block {
  border-top: var(--img-gap, 10px) solid var(--color-offwhite);
}
.room--has-gaps .room__aside {
  background: var(--color-offwhite);
  gap: var(--img-gap);
}
/* Aside absolute (cozinha 05/05b, lavanderia) — encolhe a largura
   pra criar espaço entre stage e aside. */
.room--has-gaps:not(.room--bath) .room__aside {
  width: calc(50% - var(--img-gap));
}
/* Cozinha — aside é 50% (era 36%). Desconta gap pra criar respiro. */
.room[data-name="Cozinha"].room--has-gaps .room__aside {
  width: calc(50% - var(--img-gap));
}
/* Bath-wrapper é flex — usa gap nativo do flex container.
   Stage continua encostado na esquerda (não tem margin); o gap nasce
   automaticamente entre stage e aside (e entre os 2 stages do lavabo). */
.room--has-gaps.room--bath .room__bath-wrapper {
  gap: var(--img-gap);
  background: var(--color-offwhite);
}
/* Sobrescreve gap: 0 e background black do .room--bath nos asides
   (mosaico interno precisa de gap branco entre os items). */
.room--has-gaps.room--bath .room__bath-wrapper > .room__aside {
  gap: var(--img-gap);
  background: var(--color-offwhite);
}

.room__aside-item {
  position: relative;
  overflow: hidden;
  background: var(--color-gray-100);
}
/* Reveal progressivo: items reveláveis começam invisíveis e ganham
   .is-revealed conforme o usuário aperta seta. */
.is-revealable {
  opacity: 0;
  transition: opacity 500ms ease, transform 500ms ease;
  transform: translateY(8px);
}
.is-revealable.is-revealed {
  opacity: 1;
  transform: translateY(0);
}
/* Touch: tudo aberto de cara, sem depender de JS adicionar .is-revealed. */
html.is-touch .is-revealable {
  opacity: 1;
  transform: none;
}
/* Slides reveláveis (troca de imagem no stage) — sem translateY pra
   evitar deslocamento estranho, só fade. Empilha sobre o slide ativo. */
.room-slide--reveal {
  position: absolute;
  inset: 0;
  z-index: 2;
}
.room-slide--reveal.is-revealable {
  transform: none;
}

.room__aside-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* Placeholder — campo aberto para receber detalhes futuros */
.room__placeholder {
  position: absolute;
  top: 0;
  right: 0;
  width: 50%;
  height: 100vh; height: 100dvh;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  background:
    repeating-linear-gradient(
      45deg,
      var(--color-offwhite) 0,
      var(--color-offwhite) 22px,
      #ECE9E2 22px,
      #ECE9E2 44px
    );
  color: var(--color-gray-500);
  text-align: center;
  padding: 0 8%;
}
.room__placeholder-label {
  font-family: var(--font-editorial);
  font-size: clamp(1rem, 1.4vw, 1.4rem);
  color: var(--color-graphite);
  line-height: 1.3;
}
.room__placeholder-sub {
  font-size: var(--type-label);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--color-gray-500);
}

/* No split, o sideword segue no topo-esquerdo da imagem (consistente com fullscreen) */
.room--split .room__sideword {
  top: 32px;
  left: auto;
  right: var(--slide-margin);
  font-size: clamp(0.85rem, 1vw, 1rem);
  z-index: 5;
}

/* No split, o texto fica sobre a imagem (canto inferior esquerdo) */
.room--split .room__text {
  right: auto;
  left: 4vw;
  max-width: min(360px, 36vw);
  bottom: 6vh;
}
.room--split .room__dots {
  left: 4vw;
}

/* Em telas estreitas EM PORTRAIT (tablet vertical / mobile) volta a empilhar.
   Landscape mantém layout desktop. */
@media (max-width: 900px) and (orientation: portrait) {
  .room--split .room__stage > .room-slide:not(.is-active),
  .room--split .room__stage > .room-slide.is-active {
    width: 100%;
    height: 55vh;
    left: 0;
    top: 0;
  }
  .room--split .room__aside,
  .room--split .room__placeholder {
    top: 55vh;
    width: 100%;
    height: 45vh;
  }
  .room--split .room__sideword {
    display: none;
  }
  .room--split .room__text {
    left: var(--slide-margin);
    bottom: auto;
    top: 50vh;
    transform: translateY(-50%);
    color: var(--color-graphite);
    text-shadow: none;
    background: rgba(245,244,240,0.92);
    padding: 16px 20px;
  }
  .room.has-text .room__text { transform: translateY(-50%); }
}

/* =========================================================
   Número + nome do ambiente em letras enormes na lateral esquerda
   (rotacionado 90° / vertical, com mix-blend-mode pra ficar legível
   sobre claro OU escuro).
   ========================================================= */
.room__sideword {
  position: absolute;
  z-index: 3;
  /* Canto superior DIREITO — evita conflito com a logo METRIK
     que fica fixa no canto superior esquerdo. */
  top: 32px;
  right: var(--slide-margin);
  left: auto;
  white-space: nowrap;
  font-family: var(--font-editorial);
  font-weight: 400;
  font-size: clamp(0.85rem, 1vw, 1rem);
  line-height: 1;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--color-white);
  text-shadow:
    0 1px 2px rgba(0,0,0,0.4),
    0 2px 12px rgba(0,0,0,0.5);
  pointer-events: none;
  user-select: none;
  /* GSAP anima opacity + x */
}

/* =========================================================
   Texto explicativo flutuando dentro da imagem — canto inferior direito.
   Aparece via ScrollTrigger (JS adiciona/remove .has-text).
   ========================================================= */
.room__text {
  position: absolute;
  z-index: 4;
  right: var(--slide-margin);
  bottom: 8vh;
  max-width: min(420px, 38vw);
  color: var(--color-white);
  text-shadow:
    0 1px 2px rgba(0,0,0,0.4),
    0 2px 20px rgba(0,0,0,0.55);
  /* opacity/transform controlados via GSAP no initRooms */
}

.room__num {
  display: block;
  font-family: var(--font-editorial);
  font-size: clamp(1.2rem, 1.4vw, 1.4rem);
  line-height: 1;
  color: var(--color-gray-100);
  margin-bottom: 14px;
  letter-spacing: 0.04em;
}
.room__name {
  font-family: var(--font-editorial);
  font-weight: 400;
  font-size: clamp(1.75rem, 2.6vw, 2.4rem);
  line-height: 1.15;
  letter-spacing: var(--tracking-tight);
  color: var(--color-white);
  margin: 0 0 16px;
}
.room__copy {
  font-family: var(--font-primary);
  font-weight: 300;
  font-size: clamp(0.9rem, 0.95vw, 1rem);
  line-height: 1.6;
  color: var(--color-offwhite);
  letter-spacing: 0.005em;
  max-width: 38ch;
}

/* =========================================================
   DETAILS-BLOCK — galeria de detalhes por suíte (grid)
   ========================================================= */
.details-block {
  background: var(--color-offwhite);
  padding: 48px var(--slide-margin) 48px;
  min-height: 100vh;
}
.details-block__header {
  max-width: 1280px;
  margin: 0 auto 28px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.details-block__label {
  font-size: var(--type-label);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  font-weight: 500;
  color: var(--color-gray-500);
}
.details-block__title {
  font-family: var(--font-editorial);
  font-weight: 400;
  font-size: var(--type-h1);
  line-height: 1.15;
  letter-spacing: var(--tracking-tight);
  color: var(--color-black);
  max-width: 680px;
}

/* =========================================================
   DETAILS — hero destacado + masonry abaixo
   GAP ÚNICO controlado por variável: horizontal e vertical iguais.
   ========================================================= */

.details-block { --detail-gap: 10px; }

/* Hero: primeira foto destacada — discreta, não panorâmica gigante */
.details-block__hero {
  position: relative;
  width: 100%;
  max-width: 1500px;
  margin: 0 auto var(--detail-gap);
  overflow: hidden;
  aspect-ratio: 16 / 5;
  max-height: 45vh;
  background: var(--color-gray-100);
}
.details-block__hero img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  transition: transform 0.7s var(--ease);
}
.details-block__hero:hover img {
  transform: scale(1.03);
}

/* Grid de 4 colunas com row height = col width (sincronizado via JS).
   Items preenchem 100% do espaço do grid (object-fit: cover faz leve crop
   onde necessário, mas garante fechamento sem buracos).

   - .db-item--square : 1 col × 1 row
   - .db-item--wide   : 2 cols × 1 row
   - .db-item--tall   : 1 col × 2 rows + gap interno
*/
.details-block__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-flow: dense;
  gap: var(--detail-gap);
  max-width: 1500px;
  margin: 0 auto;
  /* grid-auto-rows é setado via JS pra bater com a largura da coluna */
  grid-auto-rows: 220px; /* fallback enquanto JS não rodou */
}

.db-item {
  position: relative;
  overflow: hidden;
  background: var(--color-gray-100);
  display: block;
}
.db-item img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  object-position: center;
  transition: transform 0.6s var(--ease);
}
.db-item:hover img {
  transform: scale(1.04);
}

.db-item--square { /* 1 col × 1 row é o default */ }
.db-item--wide   { grid-column: span 2; }
.db-item--tall   { grid-row: span 2; }

/* Ancoragem do object-fit cover pra mostrar uma região específica
   quando o aspect ratio do slot não casa com o da foto. */
.db-item--anchor-bottom img { object-position: center bottom; }
.db-item--anchor-top    img { object-position: center top; }
.db-item--anchor-left   img { object-position: left center; }
.db-item--anchor-right  img { object-position: right center; }

@media (max-width: 1100px) {
  .details-block__grid {
    grid-template-columns: repeat(2, 1fr);
  }
  .db-item--wide { grid-column: span 2; }
  .db-item--tall { grid-row: span 2; }
}
@media (max-width: 640px) {
  .details-block__grid {
    grid-template-columns: 1fr;
  }
  .db-item--wide,
  .db-item--tall {
    grid-column: span 1;
    grid-row: span 1;
  }
}

/* =========================================================
   FIM
   ========================================================= */
.end {
  height: 100vh; height: 100dvh;
  background: var(--color-black);
  color: var(--color-offwhite);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 var(--slide-margin);
}

.end__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 36px;
  text-align: center;
  max-width: 680px;
}
.end__logo {
  width: 220px;
  height: auto;
  object-fit: contain;
}
.end__line {
  font-family: var(--font-editorial);
  font-size: var(--type-h2);
  line-height: 1.3;
  font-weight: 400;
  color: var(--color-white);
  letter-spacing: 0;
}
.end__meta {
  font-size: var(--type-label);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-gray-300);
  font-weight: 500;
}

/* =========================================================
   RESPONSIVE
   ========================================================= */
@media (max-width: 1024px) {
  :root { --slide-margin: 6%; }
}
@media (max-width: 720px) {
  :root { --slide-margin: 24px; }
  .hud { left: 16px; bottom: 16px; gap: 14px; }
  .hud__progress { width: 80px; }
  .panel { width: 86vw; }
  .panel__inner { padding: 32px 24px; }
  .cover__header { padding-top: 20px; }
  .brand-fixed__logo { width: 140px; }
  .brand-fixed { top: 20px; left: 20px; }
  .cover__meta { display: none; }
}

/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
  .cover__scroll-line::after { animation: none; }
  * { transition-duration: 0ms !important; }
}
