/* ============================================================
   Skunk Club — estilos
   ============================================================ */

:root {
  /* fundos */
  --breu: #0b0908;
  --carvao: #161311;
  --fuligem: #231f1b;
  --ferro: #3b342d;
  /* cobre e creme */
  --cobre: #bea473;
  --cobre-claro: #e8d39a;
  --cobre-escuro: #6c5b40;
  /* Tom médio para texto secundário sobre o carvão: 5,0:1, contra os
     2,8:1 do cobre-escuro, que fica só em borda e detalhe de material. */
  --cobre-medio: #97835f;
  --pergaminho: #e9dbb3;
  --papel: #cfb682;
  --areia: #b9a98a;
  --tinta: #2d261b;
  --tinta-suave: #5c4d3a;
  /* vermelho */
  --sangue: #bc4442;
  --vinho: #5b1119;
  --borgonha: #581b1f;
  /* tela CRT (só dentro da tela) */
  --fosforo: #b7e67a;
  --fosforo-medio: #8ebb5b;
  --musgo: #6e984c;
  --vidro: #0d1f13;

  --topo-h: 84px;
  --rodape-h: 52px;
  /* altura do console = viewport menos topo, rodapé e os respiros */
  --console-h: min(calc(100svh - var(--topo-h) - var(--rodape-h) - 56px), 920px);
}

*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--breu);
  color: var(--pergaminho);
  font: 400 17px/1.6 var(--font-body);
  min-height: 100vh;
  overflow-x: hidden;
}
img { max-width: 100%; display: block; }
button { font: inherit; color: inherit; }
a { color: var(--cobre); text-decoration-color: rgba(190, 164, 115, .4); text-underline-offset: 3px; }
a:hover { color: var(--cobre-claro); }
:focus-visible { outline: 2px solid var(--cobre-claro); outline-offset: 3px; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* ---------- Topo ----------
   Fixo e transparente sobre a cena, como no site de referência: a marca
   e o lugar à esquerda, as seções em colunas curtas à direita. O console
   passa por baixo dele durante a rolagem; os vãos deixam o clique passar. */
.topo {
  position: fixed; top: 0; left: 0; right: 0; z-index: 20;
  display: flex; align-items: flex-start; gap: clamp(20px, 3vw, 48px);
  padding: 20px 4vw 0; min-height: var(--topo-h);
  pointer-events: none;
}
.topo > * { pointer-events: auto; position: relative; }
/* Escondido no começo da cena; entra assim que a rolagem começa. Fora da
   introdução (links diretos, menos movimento) fica sempre à vista. */
.topo { transition: opacity .35s ease, transform .35s ease, visibility 0s; }
body.topo-oculto .topo {
  opacity: 0; visibility: hidden; transform: translateY(-10px);
  transition: opacity .3s ease, transform .3s ease, visibility 0s .3s;
}
/* Véu curto no alto, só para o texto não brigar com a carcaça clara. */
.topo::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 150px;
  background: linear-gradient(rgba(11, 9, 8, .62), transparent); pointer-events: none;
}
.topo__logo { display: block; flex: none; margin-top: 1px; }
.topo__logo img { height: 34px; width: auto; filter: drop-shadow(0 2px 6px rgba(0, 0, 0, .6)); }
.topo__meta {
  margin: 0 auto 0 0; display: flex; flex-direction: column; gap: 2px;
  font: 500 11px/1.5 var(--font-interface); letter-spacing: .2em; text-transform: uppercase;
  color: var(--areia); white-space: nowrap;
}
.topo__meta span:last-child { color: var(--cobre-medio); font-variant-numeric: tabular-nums; min-height: 1.5em; }
.topo__nav { display: flex; align-items: flex-start; gap: clamp(22px, 3.2vw, 56px); }
.topo__nav button {
  display: block; width: 100%; background: transparent; border: 0; padding: 0; cursor: pointer; text-align: left;
  font: 500 11px/1.5 var(--font-interface); letter-spacing: .2em; text-transform: uppercase;
  color: var(--areia); white-space: nowrap;
  transition: color .2s;
}
.topo__nav button:hover, .topo__nav button[aria-current="true"] { color: var(--cobre-claro); }
.topo__hamb { display: none; }

/* Cada item do menu vira uma coluna: o pai em cima, em pergaminho, e os
   filhos listados embaixo, sempre à vista. O terceiro nível (os
   profissionais de cada categoria) fica para a tela do console e para o
   índice. */
.topo__item { display: flex; flex-direction: column; gap: 2px; }
.topo__item > button { color: var(--pergaminho); }
.topo__sub { display: flex; flex-direction: column; gap: 2px; }
.topo__sub .topo__sub { display: none; }
/* O Contato é a chamada, com a seta do site de referência (preso ao item,
   e não ao último da lista: com o menu reduzido, o último é "O Clube"). */
.topo__nav > .topo__item > button[data-nav="modal:contato"] { color: var(--cobre-claro); }
.topo__nav > .topo__item > button[data-nav="modal:contato"]::after { content: " \2197"; }

/* ---------- Hero ---------- */
.hero { position: relative; min-height: calc(100svh - var(--topo-h) - var(--rodape-h)); display: grid; overflow: hidden; isolation: isolate; }
.hero__grid {
  position: relative; z-index: 2; width: 100%; max-width: 1640px; margin: 0 auto;
  display: grid; grid-template-columns: auto auto; justify-content: center;
  align-items: center; align-content: center; gap: 24px clamp(40px, 6vw, 110px);
  padding: 16px 5vw 20px;
}
.hero__grid .stage { grid-column: 1; grid-row: 1; }
.hero__grid .legenda { grid-column: 2; grid-row: 1; }


.legenda { justify-self: start; margin: 0; max-width: 230px; font-family: var(--font-interface); color: var(--areia); font-size: 14px; letter-spacing: .1em; text-transform: uppercase; }
.legenda__titulo { color: var(--cobre); font-weight: 600; margin: 0 0 14px; padding-bottom: 10px; border-bottom: 1px solid var(--ferro); }
.legenda div { display: flex; align-items: center; gap: 10px; margin: 0 0 10px; }
.legenda kbd {
  display: inline-block; min-width: 30px; padding: 5px 7px; border: 1px solid var(--ferro); border-radius: 4px;
  background: rgba(0, 0, 0, .45); color: var(--pergaminho); font: 600 12px/1 var(--font-interface); text-align: center; letter-spacing: 0;
}
.legenda kbd.vermelho { border-color: var(--vinho); background: var(--borgonha); }

/* ---------- Introdução ----------
   O palco só dá altura de rolagem: o hero gruda no topo e o trilho
   abaixo dele é o que rola. Fora da introdução o trilho tem altura zero
   e a página é exatamente a de antes. */
/* Enquanto intro.js não monta o primeiro quadro, o console está no HTML
   na pose final: tamanho cheio, de frente. Pintá-lo assim e só depois
   encolher para o começo da cena mostrava o fim antes do começo. Some
   por visibility, não display, para o layout já nascer medido e nada
   saltar quando voltar. O que se vê no lugar é o fundo da página — uma
   página carregando, e não um console na pose errada. Ver o script no
   <head> de index.html. */
.intro-esperando .stage,
.intro-esperando .legenda { visibility: hidden; }

.palco { position: relative; }
.palco__trilho { height: 0; }
/* O topo é fixo e fica fora do fluxo; a cena gruda no alto da janela. */
body.intro-ativa .hero { position: sticky; top: 0; }

/* Camada de fora, só da introdução. A inclinação mora no .obj, uma
   camada abaixo, então as duas nunca escrevem no mesmo transform. */
.intro__obj { position: relative; width: 100%; transform-style: preserve-3d; }
.costas {
  position: absolute; inset: 0; width: 100%; height: 100%;
  /* Virada, e assentada na ponta funda do objeto: as fatias da frente
     vão de z = -6 a -72 (console.js), então a placa fica em -72, e
     depois do rotateY(180) o translateZ positivo aponta para lá. O
     scale é a compensação de perspectiva; intro.js o reescreve a cada
     quadro com o cosseno do giro. */
  transform: rotateY(180deg) translateZ(60px) scale(1.0667);
  visibility: hidden; pointer-events: none;
}
.intro__obj--verso .costas { visibility: visible; }
/* A luz da cena nas costas. A placa é um render com a luz gravada nos
   pixels; isto aqui é o que muda com o giro, por cima dela: a sombra é
   o mesmo degradê girante do #l-sombreado da frente, e o brilho uma
   faixa alta e macia que desliza. Os ângulos e as opacidades vêm de
   intro.js, calculados da normal de verdade das costas a cada quadro.
   1px à frente da placa, para o preserve-3d ordenar sem hesitar. */
.costas-luz {
  position: absolute; inset: 0; overflow: hidden;
  visibility: hidden; pointer-events: none;
  -webkit-mask-image: url("../assets/console/costas.webp"); mask-image: url("../assets/console/costas.webp");
  -webkit-mask-size: 100% 100%; mask-size: 100% 100%;
}
.intro__obj--verso .costas-luz { visibility: visible; }
body.ampliado--forte .costas-luz { display: none; }
/* Dentro da cena as duas trocam por visibility, e é de propósito: a
   virada acontece em 90 graus, no trecho mais rápido do giro, e ali um
   display não pode custar uma remontagem de caixa.

   Fora da cena é outra conversa. A placa de costas e a luz dela ficavam
   em visibility: hidden pelo resto da visita — duas áreas de console,
   uma delas com máscara, guardadas para nunca mais aparecer. Quem chega
   por #contato ou pede menos movimento nunca vê cena nenhuma e as
   carregava do mesmo jeito. Subir a rolagem repõe data-intro e as traz
   de volta antes de o giro passar de 90. */
body:not([data-intro="ativa"]) .costas,
body:not([data-intro="ativa"]) .costas-luz { display: none; }
/* Mesma caixa e mesmo degradê do #l-sombreado i da frente, pelo mesmo
   motivo: a diagonal basta para cobrir o console girando, e 200% x 200%
   era quatro vezes a área. */
.costas-luz__sombra {
  position: absolute; left: -48%; top: -8.5%; width: 196%; height: 117%; display: block;
  background: linear-gradient(0deg, transparent 32.906%, #000 118.376%);
  opacity: 0;
}
.costas-luz__brilho, #varredura-i {
  position: absolute; left: 25%; top: -5%; width: 50%; height: 110%; display: block;
  background: linear-gradient(90deg, transparent 0%, rgba(255, 236, 210, .65) 50%, transparent 100%);
}
/* Camada do tamanho do console, com máscara: só existe durante a cena.
   Parada ela fica em opacity 0, mas a camada continuava alocada. */
#l-varredura { overflow: hidden; opacity: 0; display: none; }
body[data-intro="ativa"] #l-varredura { display: block; }
.intro__obj--verso .obj { visibility: hidden; }
/* Espessura das costas. As fatias da frente (.borda) não servem: a
   máscara delas é o corpo menos a tela e os botões, e vista por trás
   mostra esses vazios como furos. Estas usam a própria silhueta de
   costas.webp, sólida, entre a placa (z = -72) e a face da frente:
   z de -6 a -66, os mesmos degraus da frente. Montadas em intro.js;
   display: none fora do verso para não segurar buffer de máscara.

   A cor de cada fatia sai de intro.js, em rampa pela profundidade: a
   parede não é pintada de um tom só, ela clareia junto ao filete de
   cobre da face e afunda para o breu no meio. É essa rampa que faz a
   faixa ler como superfície em vez de chapa. O degradê aqui é só o
   estado inicial, antes de o js escrever. */
.costas__fatia {
  position: absolute; inset: 0; display: none; pointer-events: none;
  -webkit-mask-image: url("../assets/console/costas.webp"); mask-image: url("../assets/console/costas.webp");
  -webkit-mask-size: 100% 100%; mask-size: 100% 100%;
  background: #1a1410;
}

/* A parede lateral. As fatias são planos chapados no eixo z: a 90 graus
   ficam todas de perfil, com largura zero, e a parede some — era por
   isso que a cena precisava pular os ângulos de lado. Este plano fica
   de pé na aresta esquerda (a única que aparece: o giro é sempre
   positivo), com 72px de fundo, o mesmo das camadas, e recebe a luz como
   uma borda de plástico: filete claro junto a cada face, breu no meio,
   o da frente mais forte. As fatias continuam por cima dos cantos
   arredondados, que o retângulo não sabe fazer; nas pontas ele se
   apaga numa máscara para não sobrar aba. */
.lado-parede {
  /* Posição, altura e transform vêm de intro.js, faceta a faceta, a
     partir do contorno do corpo. Aqui só o que é comum a todas. */
  position: absolute; left: 0; top: 0; width: 60px;
  transform-origin: 0 0;
  display: none; pointer-events: none;
  /* Perfil simétrico: filete claro junto às duas faces — a que estiver
     virada para a câmera é a que se vê —, caindo para um breu que não
     é preto, e uma junta escura no meio, onde a carcaça da frente
     encontra a de trás num portátil de verdade. O preto de antes virava
     tábua; a junta e os dois filetes dão escala. */
  /* A arte da lateral, em vista ortográfica, recortada no casco: os dois
     filetes de cobre, a junta das carcaças, o botão e o material gasto,
     tudo do mesmo render das outras duas faces. Substituiu um degradê
     feito à mão, que era o que ainda lia como desenho. O tamanho e o
     recorte de cada faceta saem de intro.js, porque dependem da altura
     real do objeto. Sem repeat: cada faceta mostra a sua fatia e mais
     nada. */
  background-image: url("../assets/console/lado.webp");
  background-repeat: no-repeat;
}
/* A sombra da parede (--lado-sombra-g, escrita por intro.js em cada
   faceta): um degradê pela largura, do plano de trás à face da frente,
   calculado da curvatura da parede a cada quadro. De perfil é nada — a
   arte como está, os dois filetes acesos por igual —, e conforme o
   objeto vira, o filete que se afasta apaga e o trecho reto escurece.
   Só escurece: o brilho dos filetes já vem gravado no render, e um
   clarão por cima lavava o material e, em blend, ainda rasterizava fora
   de registro no desktop. Pseudo-elemento, e não box-shadow, para não
   brigar com os filetes internos do botão. */
.lado-parede::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: var(--lado-sombra-g, none);
}
body[data-intro="ativa"] .lado-parede { display: block; }
/* A sombra projetada é uma imagem a z = -84 dentro do objeto: girando
   junto, aparecia de lado como uma lâmina escura solta atrás da parede.
   Some enquanto a cena roda e volta quando o console assenta. */
body[data-intro="ativa"] #l-sombra { visibility: hidden; }
/* Enquanto a cena roda o console é cenário, não instrumento: os alvos
   dos botões e a tela não recebem toque. Sem isto dava para apertar o A
   num console virado de costas, e o menu avançava atrás da placa, fora
   de vista. O teclado e os cliques na tela são barrados em console.js,
   no trigger, que é por onde todos passam. Solta junto com a
   inclinação, quando o console assenta. */
body[data-intro="ativa"] .hit,
body[data-intro="ativa"] .tela { pointer-events: none; }
/* No desktop o hero tem duas colunas, console e legenda de controles.
   Durante a cena a legenda ficaria ao lado de um objeto virado de
   costas: some, e volta em fade quando o console assenta. Mantém o
   espaço (visibility, não display) para o grid não mudar de largura e
   o console não pular de coluna no fim. */
.legenda { transition: opacity .5s ease; }
body[data-intro="ativa"] .legenda { opacity: 0; visibility: hidden; }
body.ampliado--forte .lado-parede { display: none; }

.intro__obj--verso .costas__fatia { display: block; }
/* As doze fatias da extrusão são doze camadas do tamanho do console,
   cada uma com a sua máscara: a 3x de um celular são ~117 MB de buffer,
   mais da metade de tudo o que a página segura, e foi o que passou do
   limite de memória da aba e derrubava o navegador no fim da cena.

   E não se veem paradas. A compensação de perspectiva existe para isso:
   cada fatia é ampliada por (900 - z)/900 e a projeção a encolhe na
   mesma medida, então de frente todas caem exatamente atrás do corpo.
   Conferido em pixels, a 3x: esconder as doze com o console parado muda
   no máximo 9 de 255 num punhado de pixels, e a 10 graus de giro não
   muda nada. Elas só aparecem quando o console inclina — que é
   exatamente quando .movendo está posta, do primeiro quadro do arrasto
   até a inclinação voltar a zero. Fora daí não custam nada. */
.obj .borda { display: none; }
.stage.movendo .obj .borda { display: block; }
/* Depois da regra acima, e com a mesma especificidade, para ganhar: com
   a parede texturizada no lugar, as fatias listrariam por baixo dela. */
.stage .intro__obj--parede .obj .borda,
.intro__obj--verso.intro__obj--parede .costas__fatia { display: none; }
body.ampliado--forte .costas__fatia { display: none; }
/* Lados dos botões da face (ver LADOS em console.js): a máscara é a
   imagem do próprio botão, e o wrapper tem a caixa da peça, como a peça
   — mesma transform-origin, mesma geometria.

   E seguem as fatias do corpo: de frente e parado não há vão nenhum
   entre o botão e a face para eles fecharem, e são 18 camadas com
   máscara paradas ali. Aparecem quando o console inclina (.movendo) e
   durante a cena, que é quando o objeto chega aos ângulos em que o
   botão se descolaria da face. */
.lyr--lado { inset: auto; display: none; }
.peca-lado { position: absolute; inset: 0; -webkit-mask-size: 100% 100%; mask-size: 100% 100%; pointer-events: none; }
.stage.movendo .lyr--lado,
body[data-intro="ativa"] .lyr--lado { display: block; }
/* O brilho não gira junto com o objeto: fica na caixa final, de frente e
   em tamanho cheio. Ligado ao progresso puro, ele já aparecia como uma
   silhueta fantasma ao lado do console pequeno e virado. Só entra nos
   últimos 15% do curso, quando o console está a 0,2% do tamanho final
   e sem giro nenhum. */
/* Sem rampa de opacidade: o brilho acompanha o transform da cena (escrito
   em intro.js) e por isso não precisa nascer no fim — não há mudança de
   luz nenhuma para o olho pegar. De costas ele se esconde junto com a
   face da frente, que é de quem ele é o reflexo; quem faz isso também é
   o js, já que ele não é mais descendente do #intro-obj. */

/* Sobe com a passagem: o bloco de quatro partes é bem mais alto que a
   linha única de antes, e a 6% as duas últimas linhas caíam em cima do
   rebordo do console. Não há altura para limpá-lo de todo — o objeto
   ocupa o meio do hero —, então a conta é deixar passar o título e a
   primeira linha, e a última encosta no breu da placa, onde o
   text-shadow dá conta. */
.intro {
  position: absolute; left: 50%; top: 3.5%; transform: translateX(-50%);
  z-index: 14; width: min(88vw, 46ch); text-align: center; pointer-events: none;
  transition: opacity .3s ease;
}
.intro__passo {
  position: absolute; left: 0; right: 0; top: 0; margin: 0;
  font: 500 clamp(15px, 4vw, 19px)/1.55 var(--font-interface);
  letter-spacing: .04em; color: var(--pergaminho);
  text-shadow: 0 2px 18px rgba(11, 9, 8, .95), 0 0 40px rgba(11, 9, 8, .8);
}
/* As três partes da passagem, na mesma escala da cabeça de uma ficha
   (.ficha__kicker, .ficha__titulo, .ficha__sub), trocadas as cores do
   papel pelas do breu: o lugar em cobre, a frase em pergaminho, as
   linhas em areia. É a mesma peça tipográfica que o visitante vai
   reencontrar quando abrir a primeira ficha. */
.intro__kicker, .intro__titulo, .intro__linha { display: block; }
.intro__kicker {
  font: 600 clamp(10px, 2.6vw, 12px)/1.35 var(--font-interface);
  letter-spacing: .28em; text-transform: uppercase; color: var(--cobre);
}
/* Barlow, e não a Grenze Gotisch das fichas: a frase aparece bem em
   cima do próprio console, que traz "SKUNK CLUB" gravado nas costas
   naquela mesma gótica. Duas góticas empilhadas brigavam entre si e a
   frase perdia — aqui ela é a voz de quem recebe, não mais um letreiro. */
.intro__titulo {
  margin-top: clamp(6px, 1.4vw, 10px);
  font: 500 clamp(27px, 5.4vw, 40px)/1.1 var(--font-body);
  letter-spacing: .005em; color: var(--pergaminho);
}
.intro__linha { margin-top: clamp(4px, 1vw, 7px); color: var(--areia); }
/* A primeira linha respira mais: é ela que sai debaixo do título. */
.intro__titulo + .intro__linha { margin-top: clamp(10px, 2vw, 15px); }
.intro__passo--vazio { color: var(--cobre); font-style: italic; opacity: .85; }
.intro__pular {
  position: fixed; left: 50%; bottom: 18px; transform: translateX(-50%);
  pointer-events: auto; z-index: 15;
  padding: 10px 18px; background: rgba(11, 9, 8, .78); border: 1px solid var(--ferro);
  border-radius: 4px; color: var(--cobre); cursor: pointer;
  font: 500 12px/1 var(--font-interface); letter-spacing: .18em; text-transform: uppercase;
  backdrop-filter: blur(2px);
}
.intro__pular:hover { border-color: var(--cobre); color: var(--cobre-claro); }

/* Sem movimento: o console já está de frente e no tamanho final, e as
   passagens viram um bloco comum, logo abaixo dele. Nada se move e a
   informação continua ali. */
body.intro-estatica .intro {
  position: static; transform: none; width: auto; max-width: 46ch;
  margin: 24px auto 0; opacity: 1 !important;
}
body.intro-estatica .intro__passo { position: static; margin: 0 0 12px; opacity: 1 !important; }
body.intro-estatica .intro__pular { display: none; }

/* ---------- Fundo (grão, luz de cobre, poeira, vinheta) ----------
   Fixo e atrás da página inteira: topo, hero e rodapé dividem o mesmo
   grão e a mesma vinheta, então não existe emenda entre eles. */
.fundo { position: fixed; inset: 0; z-index: -1; overflow: hidden; background: var(--breu); pointer-events: none; }
.fundo > div { position: absolute; inset: 0; pointer-events: none; }
.fundo__grao { background: url("../assets/textures/grain.webp") repeat; background-size: 640px; opacity: .6; mix-blend-mode: screen; }
.fundo__luz {
  background: radial-gradient(42% 58% at 50% 50%, rgba(190, 164, 115, .16) 0%, rgba(190, 164, 115, .05) 50%, transparent 72%);
  transition: background .9s ease;
}
/* Durante a introdução a luz nasce contida atrás da carcaça e vai se
   abrindo conforme o objeto se aproxima. */
/* O fundo acompanha de longe. A faixa é estreita de propósito: com o
   brilho já sem degrau, qualquer variação larga aqui voltaria a ler
   como a luz mudando sozinha. */
body.intro-ativa .fundo__luz { transform: scale(calc(.88 + .12 * var(--intro-p, 1))); opacity: calc(.88 + .12 * var(--intro-p, 1)); }
body.intro-ativa .fundo__grao { opacity: calc(.6 * (1 - .45 * (1 - var(--intro-p, 1)))); }
body[data-category="barber"] .fundo__luz { background: radial-gradient(46% 62% at 50% 50%, rgba(232, 211, 154, .2) 0%, rgba(232, 211, 154, .06) 50%, transparent 72%); }
body[data-category="tattoo"] .fundo__luz { background: radial-gradient(46% 62% at 50% 50%, rgba(188, 68, 66, .2) 0%, rgba(188, 68, 66, .06) 50%, transparent 72%); }
.fundo__poeira {
  background: url("../assets/textures/dust-particles-overlay.webp") repeat; background-size: 900px;
  opacity: .22; mix-blend-mode: screen; animation: poeira 60s linear infinite;
}
@keyframes poeira { to { background-position: 900px 700px; } }
.fundo__vinheta { background: radial-gradient(70% 80% at 50% 50%, transparent 40%, rgba(11, 9, 8, .75) 100%); }

/* ---------- Console ---------- */
/* manipulation: deixa passar rolagem e zoom, e o js decide gesto a gesto
   quem fica com o arrasto de um dedo (ver o limite de 35 graus em
   console.js). Com "none" o zoom morria; com "pan-y" o navegador ficava
   com toda rolagem vertical e a inclinação nesse eixo sumia. */
.stage { perspective: 900px; position: relative; width: calc(var(--console-h) * 840 / 1410); max-width: 100%; justify-self: center; touch-action: manipulation; user-select: none; -webkit-user-select: none; cursor: grab; }
.stage:active { cursor: grabbing; }
/* will-change só enquanto o console realmente se move. Ligado o tempo
   todo, ele mantinha seis camadas promovidas na GPU; ao dar zoom, o
   Safari precisa rasterizar tudo de novo na escala nova e a aba morria. */
.stage.movendo .obj,
.stage.movendo .brilho img,
.stage.movendo #l-sombreado i { will-change: transform; }
.stage.movendo .reflexo,
.stage.movendo .especular { will-change: transform, opacity; }
.stage .hit, .stage .tela { cursor: pointer; }
.luz { position: absolute; inset: 0; perspective: 900px; pointer-events: none; }
.obj { position: relative; width: 100%; aspect-ratio: 840 / 1410; transform-style: preserve-3d; }
.lyr { position: absolute; inset: 0; pointer-events: none; }
.lyr img { display: block; width: 100%; height: 100%; user-select: none; -webkit-user-drag: none; transition: filter .06s linear; }
/* Peças recortadas. A textura já era do tamanho da peça; agora a caixa
   transformada também é. Menu e Start eram 480x806 com 0,3% de pixel
   útil — e continuavam sendo uma caixa de 480x806 com transform 3D e
   camada própria para desenhar um botão de 51x24.

   A posição e a medida vêm em linha, de console.js, copiadas da peça, e
   com elas vai uma transform-origin que aponta para onde ela estava: o
   centro do console. A compensação de perspectiva escala em torno do
   mesmo ponto de antes, e a geometria sai idêntica. */
.lyr--peca { inset: auto; }
.lyr--peca > img.peca { position: absolute; inset: 0; }
/* Sem caixa em linha (peça sem medida no HTML) o wrapper fica cheio,
   como era, e é a imagem que se posiciona dentro dele. */
.lyr img.peca { position: absolute; }
#l-sombra { inset: -8.511% -14.286%; }
.brilho, .borda {
  position: absolute; inset: 0;
  -webkit-mask-image: url("../assets/console/mask.webp"); mask-image: url("../assets/console/mask.webp");
  -webkit-mask-size: 100% 100%; mask-size: 100% 100%;
}

/* O sombreado é 0,42 × inclinação na frente e a difusa da normal na
   cena: com o console parado e de frente ele é exatamente transparente.
   Mesmo assim ficavam alocadas a caixa mascarada do tamanho do console
   e, dentro dela, o degradê girante de 2,3 caixas — 3,3 áreas de
   console para não desenhar nada, o dobro das doze fatias. Mesmo caso
   do #l-varredura, e mesma solução: só existe quando pinta.

   A entrada e a saída não se veem porque nos dois limites a opacidade
   já é zero: no arrasto ela é proporcional à inclinação, que é nula no
   primeiro e no último quadro de .movendo; na cena, giro e tombo chegam
   a zero em p = 0,8, e data-intro só sai em 0,98. */
#l-sombreado { overflow: hidden; display: none; }
.stage.movendo #l-sombreado,
body[data-intro="ativa"] #l-sombreado { display: block; }
/* A caixa do degrau girante era 200% x 200% — quatro vezes a área do
   console para desenhar um escurecimento que só se vê dentro dele. Ela
   precisa cobrir o console em qualquer ângulo, e para isso basta a
   diagonal: 116,4% da altura. Com 196 x 117 sobra folga e sai 43% da
   área.

   O degradê é o mesmo, e continua caindo no mesmo lugar. Ele é lido em
   % da própria caixa, então as paradas foram refeitas a partir do
   centro, que é onde fica o eixo do giro: transparente 0,2 altura
   abaixo dele, preto 0,8 acima. Em 200% isso era 40% e 90%. */
#l-sombreado i {
  position: absolute; left: -48%; top: -8.5%; width: 196%; height: 117%; display: block;
  background: linear-gradient(0deg, transparent 32.906%, #000 118.376%);
}
#l-brilho img { -webkit-mask-image: linear-gradient(to bottom, #000 30%, transparent 52%); mask-image: linear-gradient(to bottom, #000 30%, transparent 52%); }
#l-brilho-bot img { -webkit-mask-image: linear-gradient(to bottom, transparent 38%, #000 60%); mask-image: linear-gradient(to bottom, transparent 38%, #000 60%); }
.borda { pointer-events: none; background: linear-gradient(180deg, #221b15 0%, #15110d 30%, #0c0908 100%); }
.borda.b0 { background: linear-gradient(180deg, #3a2f24 0%, #221b15 40%, #120e0b 100%); }

.tela {
  position: absolute; left: 16.43%; top: 15.04%; width: 67.26%; height: 36.31%;
  /* Vidro plano, como o do modelo: luz de fundo quase uniforme com queda
     suave para as bordas, sem a elipse de tubo. Os cantos seguem o raio de
     2,8 mm da abertura do bezel (2,8/60,6 na horizontal, 2,8/56,4 na vertical). */
  /* Opaca. Esta camada HTML só aparece nas telas ainda não portadas para
     o vidro (ver js/tela3d.js); as portadas são pintadas dentro do 3D. */
  background: radial-gradient(130% 130% at 50% 46%, rgba(38, 70, 30, .30) 0%, rgba(24, 44, 18, .12) 55%, transparent 100%), linear-gradient(180deg, #0f2016, #0a160e);
  border-radius: 4.6% / 5%; overflow: hidden; pointer-events: auto;
  /* text-align explícito: no celular o .hero__grid centraliza tudo, e esse
     centro vazava para dentro da tela, deixando o console diferente do
     desktop. A tela de abertura pede o centro por conta própria. */
  font-family: var(--font-crt); color: var(--fosforo); text-align: left;
  container-type: inline-size;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .04), inset 0 1px 4px rgba(0, 0, 0, .45);
}
.tela .vidro {
  position: absolute; inset: 0; pointer-events: none; z-index: 2;
  /* Sem varredura aqui: projetada em perspectiva, a linha fina serrilhava
     (19/09). A varredura das telas portadas é pintada na textura. */
  background: none;
}
.tela .fosforo { position: absolute; inset: 0; z-index: 1; }
/* As camadas de reflexo em CSS saíram: o reflexo é o do próprio vidro 3D,
   visível através do fundo translúcido da tela. Os elementos ficam no
   HTML por compatibilidade, escondidos. */
.tela .reflexo, .tela .especular { display: none; }

/* ligar a tela: risco que abre na horizontal e cresce, como TV de tubo */
.tela .ligar {
  position: absolute; inset: 0; z-index: 5; pointer-events: none; opacity: 0;
  transform-origin: 50% 50%;
  background: linear-gradient(180deg, #e7ffc4, #b7e67a 40%, #7fc24a);
  box-shadow: 0 0 18px rgba(199, 245, 141, .75);
}
.tela.ligando .ligar { animation: crtAbrir .96s cubic-bezier(.3, .7, .2, 1) both; }
.tela.ligando .fosforo { animation: crtConteudo .96s linear both; }
@keyframes crtAbrir {
  0%   { opacity: 1; transform: scale(0, .006); }
  16%  { opacity: 1; transform: scale(.5, .006); }
  32%  { opacity: 1; transform: scale(1, .006); }
  44%  { opacity: .92; transform: scale(1, .014); }
  56%  { opacity: .42; transform: scale(1, 1.05); }
  68%  { opacity: .12; transform: scale(1, 1); }
  100% { opacity: 0; transform: scale(1, 1); }
}
@keyframes crtConteudo {
  0%, 48% { opacity: 0; filter: brightness(2.4); }
  58%     { opacity: .4; filter: brightness(2.4); }
  68%     { opacity: 1; filter: brightness(1.7); }
  76%     { opacity: .45; filter: brightness(1.4); }
  86%     { opacity: 1; filter: brightness(1.1); }
  100%    { opacity: 1; filter: none; }
}

.hit {
  position: absolute; pointer-events: auto; cursor: pointer; -webkit-tap-highlight-color: transparent;
  background: transparent; border: 0; padding: 0; transform: translateZ(26px) scale(0.97111);
}
.hit:focus-visible { outline: 2px solid var(--fosforo); outline-offset: 2px; border-radius: 50%; }
/* Foco visível dentro da tela: o quadro do personagem e a lista do menu
   são alcançáveis por Tab; setas, Enter e Espaço agem sobre eles. */
.cena:focus-visible, .crt__list:focus-visible { outline: 2px solid var(--fosforo); outline-offset: 2px; }
#h-up, #h-down, #h-left, #h-right { border-radius: 4px; }
#h-a, #h-b { border-radius: 50%; }
#h-start, #h-menu { border-radius: 99px; }

/* ---------- Conteúdo da tela ---------- */
.crt { position: absolute; inset: 0; display: flex; flex-direction: column; padding: 5cqw 6cqw 4cqw; letter-spacing: .06em; }
.crt__kicker { font-size: 3.6cqw; letter-spacing: .3em; opacity: .7; }
.crt__title {
  font-size: 7.2cqw; font-weight: 700; line-height: 1.16; letter-spacing: .12em; margin: 1.2cqw 0 2.4cqw; padding-bottom: 2cqw;
  border-bottom: 1px solid rgba(142, 187, 91, .45); text-shadow: 0 0 8px rgba(183, 230, 122, .5);
}
.crt__list { list-style: none; margin: 0; padding: 0; flex: 1; }
/* Itens grandes (19/09: o menu ficou com dois itens e o proprietário os
   quis maiores). "SELECIONE SEU BRUXO" não cabe numa linha neste corpo,
   então a etiqueta quebra por palavra; o cursor e o número ficam
   centrados na altura da linha ou das duas. */
.crt__list li {
  display: flex; align-items: center; gap: 3cqw; padding: .3em 2.4cqw; margin-bottom: 1.6cqw; border: 1px solid transparent; border-radius: 2px;
  font-size: 7.6cqw; line-height: 1.35; letter-spacing: .1em; color: var(--fosforo-medio); cursor: pointer;
}
.crt__list li .crt__cursor { width: 5cqw; flex: none; opacity: 0; }
.crt__list li span:not(.crt__cursor):not(.crt__num) { text-wrap: balance; }
.crt__list li:hover { color: var(--fosforo); }
.crt__list li[aria-selected="true"] {
  color: var(--fosforo); border-color: rgba(168, 217, 106, .55);
  background: linear-gradient(90deg, rgba(168, 217, 106, .22), rgba(168, 217, 106, .06) 70%, transparent);
  text-shadow: 0 0 7px rgba(143, 224, 83, .6);
}
.crt__list li[aria-selected="true"] .crt__cursor { opacity: 1; }
.crt__num { margin-left: auto; flex: none; font-size: 4.2cqw; opacity: .6; letter-spacing: .1em; }
.crt__hints {
  display: flex; justify-content: space-between; gap: 2cqw; padding-top: 2cqw;
  font-size: 3.3cqw; letter-spacing: .14em; opacity: .75; border-top: 1px solid rgba(142, 187, 91, .3);
}

.crt--boot { align-items: center; justify-content: center; text-align: center; gap: 2cqw; cursor: pointer; }
.crt__logo { font-size: 12cqw; font-weight: 700; letter-spacing: .14em; text-shadow: 0 0 14px rgba(183, 230, 122, .6); }
.crt__sub { font-size: 3.6cqw; letter-spacing: .32em; opacity: .65; }
.crt__press { margin-top: 7cqw; font-size: 4.6cqw; letter-spacing: .26em; animation: piscar 1s steps(2) infinite; }
@keyframes piscar { 50% { opacity: 0; } }

/* seleção: cena (fundo + personagem, escala 1:1, altura total) à esquerda, painel à direita */
.crt--select { flex-direction: row; gap: 3.2cqw; padding: 4cqw 4cqw 3.4cqw; }
.cena { position: relative; flex: none; height: 100%; aspect-ratio: 340 / 516; font-size: 4cqw; border: 1px solid rgba(142, 187, 91, .5); border-radius: 3.2cqw; overflow: hidden; background: #000; cursor: pointer; box-shadow: 0 0 12px rgba(0, 0, 0, .6); }
.cena__fundo { display: block; height: 100%; width: auto; image-rendering: pixelated; }
.sprite { position: absolute; inset: 0; background-repeat: no-repeat; background-position: 0 0; image-rendering: pixelated; }
/* O personagem em canvas (js/yuri-canvas.js) só aparece aqui na
   alternativa em HTML; na tela dentro do vidro ele é copiado para a
   textura. */
canvas.sprite { width: 100%; height: 100%; image-rendering: auto; }
.painel { flex: 1; min-width: 0; display: flex; flex-direction: column; }
/* flex-wrap e espaçamento menor: "BARBEARIA 01/03" é uma linha que não
   quebra sozinha e, com o espaçamento cheio, passava da borda do painel
   e era cortada pela tela — em qualquer largura, do celular ao desktop. */
.painel__kicker { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 1cqw; font-size: 3.2cqw; letter-spacing: .14em; opacity: .75; padding-bottom: 1.6cqw; border-bottom: 1px solid rgba(142, 187, 91, .35); }
.painel__nome { flex: 1; display: flex; flex-direction: column; justify-content: center; gap: 1.4cqw; padding: 2cqw 0; }
.painel__nome strong { font-size: 6.2cqw; font-weight: 700; line-height: 1.08; letter-spacing: .06em; overflow-wrap: anywhere; text-shadow: 0 0 7px rgba(143, 224, 83, .5); }
.painel__nome > span { font-size: 3.3cqw; letter-spacing: .22em; opacity: .8; }
/* Especialidades separadas do nome por um filete, com rótulo. */
.painel__skills { margin-top: 1.6cqw; padding-top: 1.6cqw; border-top: 1px solid rgba(142, 187, 91, .38); }
.painel__rotulo { display: block; font-size: max(2.9cqw, 8px); letter-spacing: .3em; opacity: .6; margin-bottom: .8cqw; }
.painel__tags {
  display: flex; flex-wrap: wrap; gap: .3cqw 1.6cqw;
  font-size: max(3.1cqw, 8px); line-height: 1.35; letter-spacing: .03em; text-transform: none;
  color: var(--fosforo-medio); overflow-wrap: anywhere;
}
.painel__tags span { opacity: .9; }
.painel__nome.flash { animation: flash .16s steps(2) 3; }
@keyframes flash { 50% { opacity: .25; } }
.painel__setas { display: flex; gap: 1.6cqw; padding-top: 1.8cqw; border-top: 1px solid rgba(142, 187, 91, .35); }
.seta {
  flex: 1; min-width: 0; background: transparent; border: 1px solid rgba(168, 217, 106, .5); color: var(--fosforo); cursor: pointer;
  font: 700 max(4cqw, 10px)/1 var(--font-crt); padding: 1.6cqw 0; text-align: center; text-shadow: 0 0 6px rgba(183, 230, 122, .6); transition: background .12s;
}
.seta:hover { background: rgba(168, 217, 106, .16); }
.seta:active { background: rgba(168, 217, 106, .3); }
.painel__hints { display: flex; flex-direction: column; gap: .8cqw; font-size: max(3cqw, 8px); letter-spacing: .12em; opacity: .7; padding-top: 1.8cqw; white-space: nowrap; }

/* As faixas abaixo respondem à largura da tela do console, não à do
   aparelho: é ela que define quanto espaço sobra para o painel. Um
   notebook de 900px de altura tem tela de ~284px e cai na mesma faixa
   que um celular — o aperto é o mesmo e o remédio também. Só telas de
   ~330px para cima escapam das duas. */
/* Tela estreita: no celular a tela do console vai de ~210 a ~320px,
   contra 284 a 368 no desktop. O quadro do personagem fica em altura
   cheia — é ele o assunto da tela —, então sobram ~35% da largura
   para o painel, e é lá que o texto sufoca. O que dá para fazer aqui
   é apertar respiros e subir um pouco a escala do texto do painel.
   Escala, e não piso em pixel: o painel tem largura fixa em relação à
   tela, então um tamanho fixo cabe num aparelho e é cortado no
   seguinte. O menu é o contrário — ocupa a tela toda e aceita piso. */
@container (max-width: 330px) {
  .crt--select { gap: 2.6cqw; padding: 3.6cqw 3.4cqw 3cqw; }
  /* O painel tem ~35% da largura da tela e não estica: espremidas ali,
     as especialidades saíam a 10px e as dicas a 9,5px. Elas já estão
     na ficha, em chips legíveis, então aqui fica só o essencial —
     nome, função, navegação e a ação que abre a ficha — e o espaço que
     elas ocupavam vira tamanho de letra. */
  .painel__skills { display: none; }
  /* Nome e função são a informação principal: piso em pixel, não só
     proporção, para não encolherem junto com o aparelho. */
  .painel__nome strong { font-size: max(7.6cqw, 20px); }
  .painel__nome > span { font-size: max(4cqw, 11px); }
  /* Categoria e contador podem cair em duas linhas; sem isso o piso
     empurraria a linha para fora da borda do painel. */
  .painel__kicker { font-size: max(3.4cqw, 9px); }
  .painel__hints { font-size: max(3.8cqw, 10px); letter-spacing: .04em; white-space: normal; }
  /* Alvo de toque de 44px de altura. A seta desenhada continua
     pequena; quem cresce é a área que responde ao dedo. */
  .seta { font-size: max(4.8cqw, 13px); min-height: 44px; }
  .painel__setas { gap: 3cqw; }
  /* O menu ocupa a tela inteira, então aqui cabe piso de verdade. */
  .crt__kicker, .crt__num, .crt__sub { font-size: max(3.6cqw, 9px); }
  .crt__list li { font-size: max(7.6cqw, 14px); }
  .crt__hints { font-size: max(3.3cqw, 9px); }
  .crt__press { font-size: max(4.6cqw, 11px); }
}
/* Celular pequeno (tela do console abaixo de ~245px: iPhone SE, telas
   de 320px). O painel fica com ~79px e a altura da tela é curta, então
   os pisos da faixa de cima não cabem inteiros — aqui eles descem um
   degrau e os respiros cedem. A ordem de prioridade é a mesma: nome,
   função, navegação, ação. */
@container (max-width: 245px) {
  /* :not, senão esta regra vem depois e rouba da seleção o respiro
     menor que ela já pediu na faixa de cima. */
  .crt:not(.crt--select) { padding: 4cqw 5cqw 3cqw; }
  .crt__title { margin: 1cqw 0 1.6cqw; padding-bottom: 1.4cqw; }
  .crt__list li { line-height: 1.25; margin-bottom: 1cqw; }
  .crt__hints { padding-top: 1.4cqw; }
  .painel__nome { gap: .6cqw; padding: .6cqw 0; }
  .painel__nome strong { font-size: max(7.6cqw, 18px); }
  .painel__nome > span { font-size: max(4cqw, 10px); }
  .painel__hints { font-size: max(3.8cqw, 9px); padding-top: 1.2cqw; }
  .painel__setas { padding-top: 1.2cqw; }
  .seta { font-size: max(4.8cqw, 12px); min-height: 40px; padding: 0; }
}


/* ---------- Ficha (pop-up de papel) ---------- */
.ficha {
  border: 0; padding: 0; background: transparent; color: var(--tinta);
  /* svh, e não vh: no iPhone o vh mede a tela sem as barras do Safari,
     então uma ficha alta nascia 776px numa área visível de 668 e o topo
     dela — onde mora o botão de fechar — ficava atrás da barra de
     endereço. */
  width: min(960px, 94vw); max-width: none; max-height: 92svh; overflow: visible;
  filter: drop-shadow(0 30px 70px rgba(0, 0, 0, .75));
}
/* Sem backdrop-filter: um desfoque de tela cheia pede um buffer do
   tamanho da janela e trabalho de GPU o tempo todo em que a ficha está
   aberta, e por baixo de 80% de preto quase não se via. */
.ficha::backdrop { background: rgba(6, 4, 3, .8); }

/* Com uma ficha aberta o console continuava desenhado atrás dela: 37
   camadas, ~102 MB a 3x de celular, por baixo de um cartão que ali cobre
   a tela quase inteira. Era esse o piso de memória que cada ficha
   somava, e o que derrubava a aba depois de duas ou três.

   Some enquanto a ficha está aberta, e só no celular: é lá que a memória
   aperta e que o cartão cobre tudo menos uma moldura fina, que já é 80%
   preta. No desktop, onde o cartão é estreito e sobra janela em volta, o
   console continua atrás como sempre esteve.

   O box continua ocupando o mesmo lugar, e assim a página não muda de
   altura nem perde a rolagem ao fechar — mas quem sai agora é o
   conteúdo, por display, e não a vista dele por visibility. Uma
   subárvore invisível continua sendo desenho que o navegador pode
   manter alocado; uma que não tem caixa, não. A altura vem do
   aspect-ratio, que dá exatamente a mesma medida que o .obj dava
   (--console-h), então nada se move. */
@media (max-width: 600px) {
  body.ficha-aberta .stage { aspect-ratio: 840 / 1410; }
  body.ficha-aberta .stage > * { display: none; }
}
/* Poeira do fundo: um plano do tamanho da janela em mix-blend-mode,
   repintado para sempre. Debaixo de 80% de preto ninguém a vê. */
body.ficha-aberta .fundo__poeira { animation-play-state: paused; }
.ficha__papel {
  position: relative; max-height: 92svh; overflow: auto; padding: clamp(28px, 4vw, 48px);
  background: var(--papel) url("../assets/textures/aged-paper-tile.webp") center / 560px repeat;
  border: 2px solid var(--cobre-escuro); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .28), inset 0 0 80px rgba(92, 61, 30, .22);
}
.ficha__canto { position: absolute; width: 22px; height: 22px; background: url("../assets/brand/star.svg") center / contain no-repeat; opacity: .9; }
.ficha__canto:nth-child(1) { left: 10px; top: 10px; }
.ficha__canto:nth-child(2) { right: 10px; top: 10px; }
.ficha__canto:nth-child(3) { left: 10px; bottom: 10px; }
.ficha__canto:nth-child(4) { right: 10px; bottom: 10px; }
/* Fica preso à moldura da ficha: não some ao rolar um texto longo. */
.ficha__fechar {
  position: absolute; top: 14px; right: 14px; z-index: 4; width: 44px; height: 44px; border-radius: 50%;
  border: 1.5px solid var(--tinta); background: var(--papel); color: var(--tinta); cursor: pointer; font-size: 18px; line-height: 1;
  box-shadow: 0 2px 10px rgba(45, 38, 27, .35);
  transition: background .15s, color .15s;
}
.ficha__fechar:hover { background: var(--tinta); color: var(--pergaminho); }
/* padding-right reserva o canto do botão de fechar: é a única linha que
   fica na mesma altura dele, e textos longos passavam por baixo. */
.ficha__kicker { margin: 0; padding-right: 52px; font: 600 13px/1.35 var(--font-interface); letter-spacing: .28em; text-transform: uppercase; color: var(--sangue); }
.ficha__titulo { margin: 8px 0 0; font: 700 clamp(34px, 4.6vw, 52px)/1.05 var(--font-display); color: var(--tinta); letter-spacing: .01em; }
.ficha__sub { margin: 6px 0 0; font: 500 15px/1.4 var(--font-interface); letter-spacing: .22em; text-transform: uppercase; color: var(--tinta-suave); }
.ficha__linha { height: 2px; margin: 20px 0 24px; background: linear-gradient(90deg, var(--tinta) 0%, rgba(45, 38, 27, .35) 60%, transparent); }
/* Só o texto corrido. Escrito ".ficha p", este bloco pesava mais que as
   classes dos rótulos (0,1,1 contra 0,1,0) e achatava kicker, subtítulo,
   rótulos e nota todos em 17px/28px, apagando a hierarquia da ficha. */
.ficha p:not([class]),
.ficha p.suave { margin: 0 0 14px; font-size: 17px; line-height: 1.65; color: var(--tinta); }
.ficha p.suave { color: var(--tinta-suave); font-style: italic; }
.ficha__grid { display: grid; grid-template-columns: minmax(200px, 300px) 1fr; gap: clamp(24px, 3vw, 40px); align-items: start; }
.ficha__grid--mapa { grid-template-columns: 1fr 1fr; }
.retrato {
  position: relative; aspect-ratio: 340 / 516; width: 100%; overflow: hidden;
  border: 3px solid var(--tinta); box-shadow: 6px 6px 0 rgba(45, 38, 27, .18); transform: rotate(-1.2deg); background: #000;
}
.retrato img { position: absolute; inset: 0; width: 100%; height: 100%; image-rendering: pixelated; }
/* A foto é foto: sem o pixelated do sprite. Já vem cortada na proporção
   da moldura, mas o cover garante o enquadramento se vier outra. */
.retrato img.retrato__foto { image-rendering: auto; object-fit: cover; }
.retrato { font-size: 14px; }

/* Espaço reservado: categoria sem fundo (.semfundo) e/ou profissional sem sprite (.vazio).
   Tamanhos em em, para servir tanto na tela do console quanto na ficha. */
.semfundo {
  background:
    linear-gradient(rgba(127, 166, 83, .09) 1px, transparent 1px),
    linear-gradient(90deg, rgba(127, 166, 83, .09) 1px, transparent 1px),
    linear-gradient(180deg, #172b1c 0%, #0b1a10 62%, #061009 100%);
  background-size: 1.6em 1.6em, 1.6em 1.6em, 100% 100%;
}
.vazio {
  position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: .6em; background: rgba(6, 16, 9, .55); color: var(--fosforo); text-align: center; font-family: var(--font-crt);
}
.vazio__q { font-size: 5.5em; font-weight: 700; line-height: 1; opacity: .9; text-shadow: 0 0 .15em rgba(183, 230, 122, .6); }
.vazio__txt { font-size: .8em; font-weight: 600; line-height: 1.4; letter-spacing: .22em; color: var(--fosforo-medio); }
.retrato__num {
  position: absolute; right: 8px; top: 8px; padding: 4px 8px; border: 1.5px solid var(--pergaminho);
  font: 600 11px/1 var(--font-crt); letter-spacing: .14em; color: var(--pergaminho); background: rgba(0, 0, 0, .55);
}
.ficha__rotulo { margin: 0 0 8px; font: 600 12px/1 var(--font-interface); letter-spacing: .26em; text-transform: uppercase; color: var(--tinta-suave); }
.chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 20px; padding: 0; list-style: none; }
.chips li { padding: 6px 12px; border: 1px solid var(--tinta-suave); font: 500 13px/1 var(--font-interface); letter-spacing: .14em; text-transform: uppercase; color: var(--tinta); }
.acoes { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 22px; }
.btn {
  display: inline-flex; align-items: center; gap: 10px; padding: 13px 20px; border: 1.5px solid var(--tinta);
  background: var(--tinta); color: var(--pergaminho); text-decoration: none; cursor: pointer;
  font: 600 15px/1 var(--font-interface); letter-spacing: .18em; text-transform: uppercase; transition: background .15s, color .15s, border-color .15s;
}
.btn:hover { background: var(--vinho); border-color: var(--vinho); color: var(--pergaminho); }
.btn--outline { background: transparent; color: var(--tinta); }
.btn--outline:hover { background: var(--tinta); border-color: var(--tinta); color: var(--pergaminho); }
.btn svg { width: 18px; height: 18px; flex: none; }
.ficha__nota { margin: 16px 0 0; font: 500 12px/1.5 var(--font-interface); letter-spacing: .18em; text-transform: uppercase; color: var(--tinta-suave); }

.icones { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin: 8px 0 24px; }
.icones div { text-align: center; }
.icones img { height: 96px; width: auto; margin: 0 auto 10px; }
.icones span { font: 600 13px/1 var(--font-interface); letter-spacing: .24em; text-transform: uppercase; color: var(--tinta); }

.horarios { width: 100%; border-collapse: collapse; margin: 0 0 8px; }
.horarios td { padding: 8px 0; border-bottom: 1px dashed rgba(45, 38, 27, .35); font-size: 16px; }
.horarios td:last-child { text-align: right; font-weight: 600; }
.mapa { margin: 22px 0 0; border: 3px solid var(--tinta); box-shadow: 6px 6px 0 rgba(45, 38, 27, .18); overflow: hidden; }
.mapa iframe { display: block; width: 100%; height: 280px; border: 0; filter: grayscale(.55) sepia(.45) contrast(.95); }

.lista-bruxos { list-style: none; margin: 0; padding: 0; }
.lista-bruxos li { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 12px 0; border-bottom: 1px dashed rgba(45, 38, 27, .35); }
.lista-bruxos strong { font: 700 22px/1.1 var(--font-display); }
.lista-bruxos small { display: block; font: 500 12px/1.4 var(--font-interface); letter-spacing: .22em; text-transform: uppercase; color: var(--tinta-suave); }
.lista-bruxos .btn { padding: 10px 14px; font-size: 13px; }

/* ---------- Modo ampliado ----------
   Com zoom, o navegador precisa rasterizar tudo de novo na escala nova.
   As camadas caras aqui são as duas texturas de tela cheia em
   mix-blend-mode e o vidro da CRT, um SVG de ~100 curvas esticado. Em
   zoom elas viram borrão e ninguém as lê como textura, então saem de
   cena e a memória de vídeo para de estourar. Em 100% nada muda. */
body.ampliado .fundo__grao,
body.ampliado .fundo__poeira,
body.ampliado .tela .vidro { display: none; }

/* Zoom forte (acima de 2,5x): o console vira uma pilha simples de
   imagens. Saem as 12 bordas e os 2 brilhos, que carregam mask-image e
   por isso pedem um buffer cada um, mais a sombra projetada. E o 3D é
   achatado: sem inclinação, translateZ e a escala que o compensa se
   anulam, então as camadas continuam alinhadas, só perdem a espessura. */
/* Os dois primeiros seletores carregam .stage e .obj de propósito: as
   regras que acendem as fatias e os flancos com o console em movimento
   (.stage.movendo .obj .borda) são mais específicas do que
   body.ampliado--forte .borda sozinho, e ganhavam dela. Inclinar o
   console com zoom forte trazia de volta exatamente as camadas que este
   modo existe para tirar. */
body.ampliado--forte .stage .obj .borda,
body.ampliado--forte .stage .lyr--lado,
body.ampliado--forte .luz,
body.ampliado--forte #l-sombra { display: none; }
body.ampliado--forte .obj { transform-style: flat; }
body.ampliado--forte .obj,
body.ampliado--forte .lyr,
body.ampliado--forte .hit { transform: none !important; }

/* ---------- Camada semântica ----------
   Invisível por padrão (mesma técnica do .sr-only). Ao receber foco pelo
   teclado, entra no fluxo entre o hero e o rodapé, para que quem navega
   por Tab veja onde está. */
.indice { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
.indice:focus-within {
  position: static; width: auto; height: auto; overflow: visible; clip: auto; clip-path: none; white-space: normal;
  padding: 32px 5vw 40px; background: var(--carvao); border-top: 1px solid var(--ferro);
  color: var(--areia); font-size: 15px; line-height: 1.6;
}
.indice h2, .indice h3, .indice h4 { margin: 0; font: 600 13px/1.4 var(--font-interface); letter-spacing: .2em; text-transform: uppercase; color: var(--cobre); }
.indice h2 { font-size: 15px; }
.indice h3 { margin-top: 24px; }
.indice h4 { margin: 14px 0 2px; color: var(--pergaminho); letter-spacing: .12em; }
.indice p { margin: 4px 0; }
.indice address { font-style: normal; }
.indice article { margin: 10px 0; padding-left: 12px; border-left: 2px solid var(--ferro); }
.indice dl { margin: 6px 0 0; }
.indice dl div { display: flex; gap: 12px; }
.indice dt { min-width: 14ch; color: var(--pergaminho); }
.indice dd { margin: 0; }
.indice button {
  background: transparent; border: 1px solid var(--ferro); color: var(--cobre); padding: 4px 10px; cursor: pointer;
  font: 500 12px/1.2 var(--font-interface); letter-spacing: .14em; text-transform: uppercase;
}
.indice button:hover { border-color: var(--cobre); color: var(--cobre-claro); }

/* ---------- Rodapé ---------- */
.rodape {
  position: relative; z-index: 1; min-height: var(--rodape-h); padding: 14px 5vw;
  display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px 24px;
  background: transparent;
  font: 500 12px/1.5 var(--font-interface); letter-spacing: .16em; text-transform: uppercase; color: var(--cobre-escuro);
}
/* Filete que nasce e morre no transparente, em vez da linha dura de
   ponta a ponta que cortava a página em faixas. */
.rodape::before {
  content: ""; position: absolute; left: 5vw; right: 5vw; top: 0; height: 1px; pointer-events: none;
  background: linear-gradient(90deg, transparent, rgba(59, 52, 45, .7) 18%, rgba(59, 52, 45, .7) 82%, transparent);
}
.rodape a { color: var(--cobre); }
.rodape a:hover { color: var(--cobre-claro); }

/* ---------- Responsivo ---------- */
@media (max-width: 1023px) {
  /* svh, e não vh: no celular o vh ignora as barras do navegador e o
     conteúdo acaba escondido atrás delas. Reservado: 60 (topo) +
     8 e 10 (respiros) = 78. Cada pixel devolvido aqui vira 0,6 px de
     largura no console, e a tela do console é medida em cqw. */
  :root { --topo-h: 60px; --console-h: calc(100svh - 78px); }
  /* O rodapé sai da primeira tela e fica logo abaixo, ao rolar. */
  .hero { min-height: calc(100svh - var(--topo-h)); }
  /* Corta só na horizontal. O console encosta no topo do hero — a margem
     negativa o puxa para lá — e a inclinação de 7° levanta a borda de
     cima uns 15px, que o overflow: hidden decepava numa linha reta
     debaixo do cabeçalho. Com "clip visible" a horizontal continua
     contida (as laterais transparentes) e a vertical fica livre: ao
     inclinar, o console passa por trás do cabeçalho, que é transparente.
     Duas palavras numa declaração só, de propósito: onde clip não
     existir (Safari < 16) a regra inteira cai e volta o hidden de cima,
     que é o comportamento de hoje. */
  .hero { overflow: clip visible; }
  .topo { align-items: center; gap: 14px; padding: 8px 5vw 0; }
  .topo::before { height: 96px; }
  .topo__logo img { height: 30px; }
  .topo__meta { display: none; }

  /* menu sanduíche: mesmos atalhos do topo do desktop */
  .topo__hamb {
    display: flex; flex-direction: column; justify-content: center; gap: 5px;
    width: 44px; height: 44px; padding: 0 9px; flex: none; margin-left: auto;
    background: transparent; border: 1px solid var(--ferro); border-radius: 4px; cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .topo__hamb span { display: block; height: 2px; background: var(--cobre); transition: transform .2s ease, opacity .15s ease; }
  .topo__hamb[aria-expanded="true"] { border-color: var(--cobre-escuro); }
  .topo__hamb[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  .topo__hamb[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
  .topo__hamb[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

  .topo__nav {
    display: none; flex-direction: column; gap: 0; align-items: stretch;
    position: absolute; top: 100%; left: 0; right: 0; z-index: 30;
    max-height: calc(100svh - var(--topo-h)); overflow-y: auto;
    background: var(--carvao); border-top: 1px solid var(--ferro); border-bottom: 1px solid var(--ferro);
    box-shadow: 0 20px 44px rgba(0, 0, 0, .7);
  }
  .topo.aberto .topo__nav { display: flex; }
  /* No celular as colunas viram uma lista em fluxo, com recuo por nível.
     Os filhos ficam recolhidos sob o pai (retrátil, como o proprietário
     pediu em 19/09): o pai ganha um sinal e abre ao toque (.aberto,
     posto pelo app.js). */
  .topo__item, .topo__sub { gap: 0; }
  .topo__item--pai > .topo__sub { display: none; }
  .topo__item--pai.aberto > .topo__sub { display: flex; }
  .topo__item--pai > button { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
  .topo__item--pai > button::after { content: "+"; color: var(--cobre); font-size: 18px; line-height: 1; }
  .topo__item--pai.aberto > button::after { content: "\2212"; }
  /* O terceiro nível (profissionais) continua fora do topo: as categorias
     não ganham sinal nem abrem; navegam direto para a tela delas. */
  .topo__sub .topo__item--pai > button::after { content: none; }
  .topo__sub .topo__item--pai.aberto > .topo__sub { display: none; }
  .topo__nav button {
    width: 100%; min-height: 50px; padding: 14px 5vw; font-size: 14px; white-space: normal;
    border-bottom: 1px solid rgba(59, 52, 45, .55); border-left: 3px solid transparent;
  }
  .topo__sub button { min-height: 44px; padding: 10px 5vw 10px calc(5vw + 20px); font-size: 13px; }
  .topo__nav button:hover, .topo__nav button[aria-current="true"] {
    border-left-color: var(--cobre); background: rgba(190, 164, 115, .07);
  }
  .hero__grid { grid-template-columns: 1fr; justify-items: center; text-align: center; gap: 14px; padding-top: 8px; padding-bottom: 10px; }
  .hero__grid .stage { grid-column: auto; grid-row: auto; }
  .rodape { flex-direction: column; justify-content: center; text-align: center; gap: 6px; padding: 16px 5vw 20px; font-size: 11px; }
  .legenda { display: none; }
  /* A arte do console tem 1,86% de margem transparente em cima e
     embaixo (e 7,08% dos lados). Medindo pelo corpo visível, e não pela
     tela do arquivo, ele cresce sem invadir nada: só as margens vazias
     passam por cima do respiro. */
  .stage {
    width: min(96vw, calc(var(--console-h) * 1.0387 * 840 / 1410));
    margin-block: calc(var(--console-h) * -0.0193);
  }
  .ficha__grid { grid-template-columns: 1fr; }
  /* Numa coluna só, o contato sobe para logo abaixo do retrato: no celular
     o WhatsApp era a última coisa da ficha e exigia rolar tudo. O
     display:contents dissolve a coluna da direita, os três blocos viram
     itens do grid e o order os põe na ordem certa. No desktop nada disso
     existe e as duas colunas seguem como sempre. */
  .ficha__lado { display: contents; }
  .ficha__grid .retrato { order: 1; }
  .ficha__contato { order: 2; }
  .ficha__texto { order: 3; }
  .ficha__contato .acoes { margin-top: 0; }
  .retrato { max-width: 240px; margin: 0 auto 8px; }
  .icones img { height: 72px; }
}
/* Celular: o console deixa de caber inteiro na primeira tela.
   Limitado pela altura ele ficava com 74% da largura e a tela CRT com
   ~226px — texto ilegível. Agora a largura manda: o corpo visível ocupa
   94vw (o arquivo tem 7% de margem transparente de cada lado, por isso
   109,5vw). A altura só entra para manter Start e Menu acima da dobra:
   eles terminam em 84,6% da altura do console, e 0,87 deixa folga. O
   que rola é só o bezel de baixo, com a grade do alto-falante. */
@media (max-width: 600px) {
  :root { --topo-h: 52px; }
  /* Sem respiro lateral aqui: o console é mais largo que a pista do
     grid e as margens negativas abaixo é que o centram. */
  .hero__grid { padding: 4px 0 12px; }
  .stage {
    --stage-w: min(109.5vw, calc((100svh - 56px) / 0.87 * 840 / 1410));
    width: var(--stage-w);
    /* A regra-base tem max-width: 100%, que aqui cortaria justamente a
       margem transparente que precisa sobrar para fora. */
    max-width: none;
    /* Margens negativas iguais para a caixa de margem ficar do tamanho
       da pista. Sem elas o item transborda e o navegador usa alinhamento
       "seguro": em vez de centrar, encosta na borda esquerda para não
       cortar nada do começo — e o console ia todo para a direita. */
    margin-inline: calc((100% - var(--stage-w)) / 2);
    margin-top: calc(var(--stage-w) * 1410 / 840 * -0.0186);
    margin-bottom: 0;
  }
}
@media (max-width: 560px) {
  .ficha__papel { padding: 24px 20px; }
  .lista-bruxos li { flex-direction: column; align-items: flex-start; }
}
/* modo de captura da imagem de compartilhamento (?og) */
body.og .topo, body.og .legenda, body.og .rodape { display: none; }
body.og .hero { min-height: 100vh; }
body.og .fundo__vinheta { background: radial-gradient(70% 80% at 50% 50%, transparent 40%, rgba(11, 9, 8, .6) 100%); }
body.og .hero__grid { padding-top: 24px; padding-bottom: 24px; grid-template-columns: auto; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .crt__press, .fundo__poeira, .painel__nome.flash { animation: none; }
  .tela.ligando .ligar, .tela.ligando .fosforo { animation: none; }
  .tela .ligar { display: none; }
  .fundo__luz { transition: none; }
}
