/* ============================================================
   RAWDORI — styles.css
   1. Tokens  2. Base  3. Secções
   ============================================================ */

/* 1. TOKENS ------------------------------------------------- */
:root {
  --c-bg:        #000000;
  --c-bg-soft:   #0a0a0a;
  --c-surface:   #111111;
  --c-line:      #1e1e1e;
  --c-accent:    #39ff14;
  --c-accent-dim: rgba(57, 255, 20, 0.35);
  --c-text:      #f2f2f2;
  --c-text-mute: #9a9a9a;
  --c-error:     #ff3b30;
  --c-amber:     #ffb020;

  --f-mono: "SFMono-Regular", "Menlo", "Consolas", "Liberation Mono", monospace;
  --f-sans: "Helvetica Neue", "Arial", system-ui, sans-serif;

  --s-1: 0.5rem;
  --s-2: 1rem;
  --s-3: 1.5rem;
  --s-4: 2.5rem;
  --s-5: 4rem;
  --s-6: 6rem;
  --s-7: 9rem;

  --maxw: 1200px;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
}

/* 2. BASE --------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--c-bg);
  color: var(--c-text);
  font-family: var(--f-sans);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3 { line-height: 1.05; margin: 0; letter-spacing: -0.02em; }

img, video { max-width: 100%; display: block; }

a { color: inherit; }

.wrap { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 var(--s-3); }

.label {
  font-family: var(--f-mono);
  font-size: 0.72rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--c-accent);
}

section { padding: var(--s-6) 0; position: relative; }

@media (max-width: 720px) {
  section { padding: var(--s-5) 0; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

/* 3. SECÇÕES ------------------------------------------------ */

/* --- Seletor de idioma --- */
.langbar {
  position: fixed;
  top: var(--s-2);
  right: var(--s-3);
  /* Acima do .portal (95), que cria o seu próprio contexto de
     empilhamento — um z-index mais baixo aqui nunca conseguiria
     aparecer por cima dele, por maior que fosse. Abaixo do .boot
     (100), para não aparecer durante a sequência de arranque. */
  z-index: 97;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--f-mono);
  font-size: 0.75rem;
  letter-spacing: 0.12em;
  mix-blend-mode: difference;
}

.langbtn {
  background: none;
  border: 0;
  padding: 0.25rem;
  color: var(--c-text-mute);
  font: inherit;
  cursor: pointer;
  transition: color 0.2s var(--ease);
}

.langbtn:hover { color: var(--c-text); }
.langbtn.is-active { color: var(--c-accent); }
.langsep { color: var(--c-line); }

/* Fica isolado no canto inferior direito, longe do seletor de
   idioma — mesma lógica de z-index e blend-mode do .langbar, para se
   comportar da mesma forma por cima do resto do site (visível sempre,
   escondido atrás do boot). */
.mutebtn {
  position: fixed;
  bottom: var(--s-3);
  right: var(--s-3);
  z-index: 97;
  mix-blend-mode: difference;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 0;
  padding: var(--s-2);
  color: var(--c-text-mute);
  cursor: pointer;
  transition: color 0.2s var(--ease);
}

.mutebtn:hover { color: var(--c-text); }

/* Onda visível por omissão; o traço diagonal só aparece com o som
   desligado — o mesmo ícone universal de "mute", em vez de dois
   ícones a trocar entre si. */
.mute-wave, .mute-slash {
  transition: opacity 0.2s var(--ease);
}

.mute-slash { opacity: 0; }

.mutebtn.is-muted { color: var(--c-text); }
.mutebtn.is-muted .mute-wave { opacity: 0; }
.mutebtn.is-muted .mute-slash { opacity: 1; }

/* --- Boot sequence --- */
body.is-locked { overflow: hidden; }

.boot {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: var(--c-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.7s var(--ease);
}

.boot-crt { align-self: center; }

/* --- Arranque ------------------------------------------- */
/* Nada de fanfarra: a grelha assenta num fade e o terminal fica à
   espera, com o cursor a piscar, antes de começar a escrever. */
.boot-crt { opacity: 0; transition: opacity 0.5s var(--ease); }
.boot.is-ligado .boot-crt { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .boot-crt { opacity: 1; transition: none; }
}

.boot.is-out { opacity: 0; pointer-events: none; }

.boot-lines {
  position: relative;
  font-family: var(--f-mono);
  font-size: clamp(0.7rem, 2.2vw, 0.95rem);
  line-height: 2;
  color: var(--c-accent);
  text-shadow: 0 0 10px var(--c-accent-dim);
  white-space: pre;
  transition: opacity 0.35s var(--ease);
  /* Altura reservada para as cinco linhas: sem isto o bloco recentrava-se
     a cada linha nova e o texto saltava enquanto era escrito. */
  min-height: 10em;
}

.boot-line { min-height: 2em; }

.boot-cursor {
  display: inline-block;
  width: 0.6em;
  height: 1.1em;
  background: var(--c-accent);
  vertical-align: -0.15em;
  animation: boot-blink 1s steps(1) infinite;
}

@keyframes boot-blink { 50% { opacity: 0; } }

/* O gesto que desbloqueia o crash e a música — precisa de se notar
   como interactivo em vez de se perder no resto do texto do terminal.
   Aparece em repouso (opacity 0) e só ganha vida quando o JS junta
   .is-in, depois de uma pausa de suspense — sem isso "aparecia" de
   repente, a competir com o "access granted_" que a linha anterior
   acabou de escrever. */
/* Mesmo comportamento do DRIVER APPLICATION (.portal-enter +
   .portal-enter--forte): transparente em repouso, só um glow suave,
   preenche a verde sólido apenas no hover/foco — nada de pulsar
   sozinho, que o fazia "respirar" continuamente mesmo parado, uma
   linguagem diferente da do resto do portal. Valores copiados em vez
   de partilhar as classes porque o boot vive fora do .portal (irmãos
   no HTML) e não tem acesso a --txt, a escala de que essas classes
   dependem. */
.boot-enter {
  display: block;
  width: fit-content;
  margin: 0.9em 0 0;
  background: none;
  border: 1px solid var(--c-accent);
  padding: 0.5em 1.3em;
  font-family: var(--f-mono);
  font-size: clamp(0.7rem, 2.2vw, 0.95rem);
  line-height: 1.4;
  color: var(--c-accent);
  box-shadow: 0 0 22px rgba(57, 255, 20, 0.3);
  cursor: pointer;
  opacity: 0;
  transform: translateY(5px);
  transition:
    opacity 1.1s ease-out, transform 1.1s ease-out,
    background 0.25s var(--ease), color 0.25s var(--ease),
    box-shadow 0.25s var(--ease);
}

/* Sem isto, o "display: block" acima ganha ao "display: none" que o
   atributo hidden aplicaria — o botão ficava sempre visível, mesmo
   antes de as linhas do terminal terminarem de escrever. */
.boot-enter[hidden] {
  display: none;
}

.boot-enter.is-in {
  opacity: 1;
  transform: translateY(0);
}

.boot-enter:hover,
.boot-enter:focus-visible {
  background: #4dff2e;
  color: #000;
  box-shadow: 0 0 32px rgba(57, 255, 20, 0.45);
  outline: none;
}

.boot-skip {
  position: absolute;
  bottom: var(--s-3);
  right: var(--s-3);
  background: none;
  border: 0;
  padding: var(--s-1);
  font-family: var(--f-mono);
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  color: var(--c-text-mute);
  cursor: pointer;
  transition: color 0.2s var(--ease);
}

.boot-skip:hover { color: var(--c-accent); }

/* Crash do sistema no fim do boot ------------------------- */
/* O conteúdo do terminal vive dentro do .boot-crt para se poder
   estilhaçar em fatias durante o crash. */
.boot-crt {
  position: relative;
  transform-origin: center;
}

/* Durante o crash a opacidade é gerida pelas fatias, não pela entrada. */
.boot.is-crashing .boot-crt { opacity: 1; }

/* Corte para preto: tudo o que estava no ecrã desaparece no mesmo
   instante, senão o texto reaparecia intacto durante o fade. */
.boot.is-preto .boot-crt,
.boot.is-preto .boot-skip { opacity: 0; transition: none; }

/* --- Estilhaçar --- */
/* O bloco de texto é clonado em fatias horizontais que o JS atira em
   todas as direcções — o ecrã parte-se em vez de abanar. */
.boot-shards {
  position: absolute;
  inset: 0;
  display: none;
  pointer-events: none;
}

.boot.is-crashing .boot-shards { display: block; }
.boot.is-crashing .boot-lines { visibility: hidden; }

.boot-shard {
  position: absolute;
  inset: 0;
  font-family: var(--f-mono);
  font-size: clamp(0.7rem, 2.2vw, 0.95rem);
  line-height: 2;
  color: var(--c-accent);
  white-space: pre;
  will-change: transform;
  /* Origem no topo: com o scaleY centrado a faixa crescia para os dois
     lados e transbordava para as vizinhas. */
  transform-origin: 50% 0;
  /* As posições são atribuídas por JS a cada tique: uma animação CSS
     em ciclo dava-se a notar como repetitiva. */
}

.boot.is-crashing .boot-skip { opacity: 0; }

/* --- Reveal ao scroll --- */
.reveal {
  opacity: 0;
  transform: translateY(24px);
  clip-path: inset(0 0 100% 0);
  transition:
    opacity 0.8s var(--ease),
    transform 0.8s var(--ease),
    clip-path 0.9s var(--ease);
  transition-delay: var(--reveal-delay, 0ms);
}

.reveal.is-in {
  opacity: 1;
  transform: none;
  clip-path: inset(0 0 0 0);
}

@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; clip-path: none; transition: none; }
}

/* --- Botões --- */
.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  padding: 1rem 2rem;
  border: 1px solid var(--c-accent);
  background: transparent;
  color: var(--c-accent);
  font-family: var(--f-mono);
  font-size: 0.8rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.25s var(--ease), color 0.25s var(--ease);
}

.btn--primary { background: var(--c-accent); color: #000; }
.btn--primary:hover { background: #4dff2e; }
.btn--ghost:hover { background: var(--c-accent); color: #000; }

.btn:focus-visible { outline: 2px solid var(--c-text); outline-offset: 3px; }

/* Glitch RGB no hover */
.btn::before,
.btn::after {
  content: attr(data-glitch);
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  opacity: 0;
  pointer-events: none;
}

.btn:hover::before {
  color: #ff00e6;
  animation: glitch-a 0.28s steps(2) 1;
}

.btn:hover::after {
  color: #00e5ff;
  animation: glitch-b 0.28s steps(2) 1;
}

@keyframes glitch-a {
  0%   { opacity: 0.9; transform: translate(-2px, 1px); }
  100% { opacity: 0;   transform: translate(0, 0); }
}

@keyframes glitch-b {
  0%   { opacity: 0.9; transform: translate(2px, -1px); }
  100% { opacity: 0;   transform: translate(0, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .btn:hover::before, .btn:hover::after { animation: none; opacity: 0; }
}

/* --- Hero --- */
.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: flex-end;
  padding: 0 0 var(--s-6);
  overflow: hidden;
}

.hero-media {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: -2;
}

.hero-veil {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(180deg, rgba(0,0,0,0.75) 0%, rgba(0,0,0,0.35) 40%, rgba(0,0,0,0.92) 100%);
}

.hero-inner { position: relative; }

.hero-title {
  font-size: clamp(3.5rem, 15vw, 11rem);
  font-weight: 900;
  letter-spacing: -0.04em;
  margin: var(--s-2) 0 var(--s-1);
  text-transform: uppercase;
}

.hero-dates {
  font-family: var(--f-mono);
  font-size: clamp(0.9rem, 2.4vw, 1.4rem);
  letter-spacing: 0.3em;
  color: var(--c-accent);
  margin: 0 0 var(--s-2);
}

.hero-tagline {
  max-width: 34ch;
  color: var(--c-text-mute);
  font-size: clamp(1rem, 2vw, 1.15rem);
  margin: 0 0 var(--s-4);
}

.hero-actions { display: flex; flex-wrap: wrap; gap: var(--s-2); }

.hero-scroll {
  position: absolute;
  bottom: var(--s-3);
  right: var(--s-3);
  writing-mode: vertical-rl;
  color: var(--c-text-mute);
  animation: hero-bob 2.4s ease-in-out infinite;
}

@keyframes hero-bob {
  0%, 100% { transform: translateY(0); opacity: 0.5; }
  50%      { transform: translateY(8px); opacity: 1; }
}

@media (max-width: 720px) {
  .hero { padding-bottom: var(--s-5); }
  .hero-actions .btn { width: 100%; }
  .hero-scroll { display: none; }
}

/* --- Countdown --- */
.cd { border-top: 1px solid var(--c-line); border-bottom: 1px solid var(--c-line); }

.cd-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--s-2);
  margin-top: var(--s-3);
}

.cd-unit {
  border-left: 1px solid var(--c-line);
  padding-left: var(--s-2);
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.cd-num {
  font-family: var(--f-mono);
  font-size: clamp(2.2rem, 8vw, 5rem);
  font-variant-numeric: tabular-nums;
  color: var(--c-text);
  line-height: 1;
  transition: transform 0.25s var(--ease), color 0.25s var(--ease);
}

.cd-num.is-tick { transform: translateY(-4px); color: var(--c-accent); }

.cd-cap {
  font-family: var(--f-mono);
  font-size: 0.7rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--c-text-mute);
}

.cd-live {
  margin-top: var(--s-3);
  font-family: var(--f-mono);
  letter-spacing: 0.2em;
  color: var(--c-accent);
}

@media (max-width: 560px) {
  .cd-grid { grid-template-columns: repeat(2, 1fr); gap: var(--s-3); }
}

/* --- O evento --- */
.ev-title {
  font-size: clamp(2rem, 6vw, 4rem);
  font-weight: 800;
  text-transform: uppercase;
  margin: var(--s-2) 0 var(--s-4);
  max-width: 18ch;
}

.ev-body {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--s-4) var(--s-3);
  align-items: center;
}

.ev-body > p {
  grid-column: span 5;
  color: var(--c-text-mute);
  font-size: 1.05rem;
  margin: 0;
}

.ev-fig { grid-column: span 7; margin: 0; }
.ev-body > p:nth-of-type(2) { grid-column: 8 / span 5; grid-row: 2; }
.ev-body > .ev-fig:nth-of-type(2) { grid-column: 1 / span 7; grid-row: 2; }

.ev-fig img {
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  background: var(--c-surface);
  filter: saturate(0.85) contrast(1.1);
}

/* --- Info prática --- */
.info-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1px;
  background: var(--c-line);
  border: 1px solid var(--c-line);
  margin-top: var(--s-3);
}

.info-card {
  background: var(--c-bg-soft);
  padding: var(--s-3);
}

.info-card h3 {
  font-family: var(--f-mono);
  font-size: 0.78rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--c-accent);
  margin-bottom: var(--s-1);
}

.info-card p { color: var(--c-text-mute); margin: 0; font-size: 0.95rem; }

.info-link {
  display: inline-block;
  margin-top: var(--s-2);
  font-family: var(--f-mono);
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  color: var(--c-accent);
  text-decoration: none;
  border-bottom: 1px solid var(--c-accent-dim);
}

.info-link:hover { border-bottom-color: var(--c-accent); }

@media (max-width: 860px) {
  .ev-body { display: block; }
  .ev-body > p, .ev-fig { grid-column: auto !important; grid-row: auto !important; }
  .ev-body > p { margin-bottom: var(--s-3); }
  .ev-fig { margin-bottom: var(--s-4); }
}

/* --- Bilhetes --- */
.tk-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--s-2);
  margin-top: var(--s-3);
}

.tk-card {
  position: relative;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--c-line);
  background: var(--c-bg-soft);
  padding: var(--s-3);
  transition: border-color 0.3s var(--ease), transform 0.3s var(--ease);
}

.tk-card:hover { border-color: var(--c-accent-dim); transform: translateY(-4px); }

.tk-card--hero { border-color: var(--c-accent); }

.tk-tag {
  position: absolute;
  top: 0; right: 0;
  background: var(--c-accent);
  color: #000;
  font-family: var(--f-mono);
  font-size: 0.62rem;
  letter-spacing: 0.16em;
  padding: 0.35rem 0.7rem;
}

.tk-name {
  font-family: var(--f-mono);
  font-size: 0.82rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--c-text-mute);
}

.tk-price {
  font-size: clamp(2.4rem, 6vw, 3.4rem);
  font-weight: 800;
  margin: var(--s-1) 0 var(--s-2);
  letter-spacing: -0.03em;
}

.tk-desc { color: var(--c-text-mute); font-size: 0.92rem; margin: 0 0 var(--s-3); flex: 1; }

.tk-cta { width: 100%; }

.tk-note {
  margin-top: var(--s-3);
  font-family: var(--f-mono);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  color: var(--c-text-mute);
}

/* --- Formulário de pilotos --- */
.wrap--narrow { max-width: 860px; }

.fm { background: var(--c-bg-soft); border-top: 1px solid var(--c-line); }

/* C4: a ficha foi desenhada para a secção do site principal e trouxe a
   tipografia de lá quando passou para dentro do portal. Medido: o ecrã
   do portão é 100% monospace e o hero quase todo, mas a ficha tinha 25
   elementos em Helvetica/Arial — o título a 51px branco sans "gritava"
   mais alto que qualquer coisa nos outros dois ecrãs, com uma família
   tipográfica que não existe em nenhum deles.
   Passa a falar a mesma língua: monospace, escala --txt do portal,
   cores da marca. Só o título e a introdução mostravam sans de facto —
   o resto eram contentores sem texto próprio. */
.fm-intro {
  font-family: var(--f-mono);
  /* Piso de legibilidade: a escala --txt foi calibrada para rótulos
     curtos em maiúsculas com tracking largo (.portal-sub), onde 10.9px
     em mobile lê bem. Para texto corrido em minúsculas isso dava 10px —
     medido e corrigido. O mesmo vale para o painel de sucesso. */
  font-size: max(0.82rem, calc(var(--txt) * 0.92));
  line-height: 1.7;
  color: var(--c-text-mute);
  max-width: 52ch;
  margin: 0 0 var(--s-4);
}

.fm-hp { position: absolute; left: -9999px; }

.fm-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-2); }
.fm-row--3 { grid-template-columns: repeat(3, 1fr); }

/* Sem isto, um item de grid nunca encolhe abaixo do seu conteúdo
   mínimo — e um <fieldset> em particular ignora min-width:0 no
   próprio elemento em alguns browsers, por causa da caixa interna
   anónima que gera. Aplicar aos filhos directos do .fm-row cobre os
   dois casos (fieldset do Contest e qualquer .fm-field). */
.fm-row > * { min-width: 0; }

.fm-field { margin-bottom: var(--s-3); display: flex; flex-direction: column; }

.fm-lbl {
  font-family: var(--f-mono);
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  /* Era --c-text-mute (cinzento) — pouco legível sobre o fundo escuro
     do portal. A área de preenchimento é toda ela terminal verde;
     o rótulo devia falar a mesma língua, não destoar dela. */
  color: rgba(57, 255, 20, 0.75);
  margin-bottom: 0.45rem;
}

.fm-lbl::before { content: "> "; color: var(--c-accent); }

.fm-in {
  background: transparent;
  border: 0;
  /* Era --c-line (#1e1e1e) — quase invisível sobre o fundo escuro do
     portal. --c-accent-dim já é o verde esbatido usado no resto do
     terminal (ex.: brilho do ENTRAR), em vez de inventar um cinzento
     à parte que não se via. */
  border-bottom: 1px solid var(--c-accent-dim);
  padding: 0.7rem 0.2rem;
  /* Alvo de toque mínimo de 44px — a 0.7rem de padding ficava a 41px. */
  min-height: 2.75rem;
  color: var(--c-text);
  font-family: var(--f-mono);
  font-size: 0.95rem;
  transition: border-color 0.25s var(--ease);
}

.fm-in:focus {
  outline: none;
  border-bottom-color: var(--c-accent);
}

.fm-in.is-ok    { border-bottom-color: var(--c-accent); }
.fm-in.is-error { border-bottom-color: var(--c-error); }

.fm-err {
  min-height: 1.1rem;
  margin-top: 0.35rem;
  font-family: var(--f-mono);
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  color: var(--c-error);
}

.fm-err::before { content: "[ERRO] "; }
.fm-err:empty::before { content: ""; }

.fm-fieldset { border: 0; padding: 0; margin: 0 0 var(--s-3); }

.fm-check {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.5rem 0;
  /* Alvo de toque mínimo de 44px: a caixa visual mantém-se em 18px
     (não é o que se toca, é só o indicador), a linha inteira do
     rótulo é que precisa da altura. */
  min-height: 2.75rem;
  font-family: var(--f-mono);
  font-size: 0.9rem;
  cursor: pointer;
}

.fm-check input { position: absolute; opacity: 0; width: 0; height: 0; }

.fm-box {
  width: 18px; height: 18px;
  border: 1px solid var(--c-accent-dim);
  display: inline-grid;
  place-items: center;
  transition: border-color 0.2s var(--ease);
  flex: 0 0 auto;
}

.fm-box::after {
  content: "";
  width: 8px; height: 8px;
  background: var(--c-accent);
  transform: scale(0);
  transition: transform 0.18s var(--ease);
}

.fm-check input:checked + .fm-box { border-color: var(--c-accent); }
.fm-check input:checked + .fm-box::after { transform: scale(1); }
/* Branco sobre o fundo já muito luminoso do portal era o menos
   legível dos três estados de foco medidos; o verde do resto da
   marca funciona melhor aqui e mantém a linguagem consistente. */
.fm-check input:focus-visible + .fm-box { outline: 2px solid var(--c-accent); outline-offset: 2px; }

.fm-conditional {
  overflow: hidden;
  max-height: 0;
  opacity: 0;
  transition: max-height 0.4s var(--ease), opacity 0.3s var(--ease);
}

.fm-conditional.is-open { max-height: 200px; opacity: 1; }

/* O display:flex de .fm-field sobrepõe-se ao [hidden] do browser, por
   isso o campo colapsado continuaria focável e anunciado por leitores
   de ecrã. Esta regra devolve-lhe o efeito. */
.fm-conditional[hidden] { display: none; }

.fm-file {
  font-family: var(--f-mono);
  font-size: 0.8rem;
  color: var(--c-text-mute);
  padding: var(--s-2) 0;
}

.fm-file::file-selector-button {
  background: transparent;
  border: 1px solid var(--c-accent);
  color: var(--c-accent);
  font-family: var(--f-mono);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 0.6rem 1.1rem;
  margin-right: var(--s-2);
  cursor: pointer;
}

.fm-hint {
  font-family: var(--f-mono);
  font-size: 0.7rem;
  color: var(--c-text-mute);
  margin: 0 0 var(--s-2);
}

.fm-previews {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1);
}

.fm-thumb {
  width: 76px; height: 76px;
  object-fit: cover;
  border: 1px solid var(--c-line);
}

.fm-submit { margin-top: var(--s-2); }

.fm-status {
  margin-top: var(--s-2);
  font-family: var(--f-mono);
  font-size: 0.82rem;
  letter-spacing: 0.06em;
  color: var(--c-accent);
  min-height: 1.4rem;
}

.fm-status.is-error { color: var(--c-error); }

.fm-done {
  border: 1px solid var(--c-accent);
  padding: var(--s-4);
  font-family: var(--f-mono);
}

.fm-done h3 { color: var(--c-accent); font-size: max(0.9rem, calc(var(--txt) * 0.95)); letter-spacing: 0.1em; margin-bottom: var(--s-2); }
.fm-done p { font-family: var(--f-mono); color: var(--c-text-mute); font-size: max(0.82rem, calc(var(--txt) * 0.88)); line-height: 1.7; margin: 0; }

/* A4: antes deste botão o painel de sucesso era um beco sem saída —
   sem ele, a única forma de sair era o botão de voltar do portal, que
   levava ao portão como se nada se tivesse passado. Reaproveita o
   estilo do .portal-enter para se manter na linguagem do funil. */
.fm-done-back { margin-top: var(--s-3); }

@media (max-width: 720px) {
  .fm-row, .fm-row--3 { grid-template-columns: 1fr; }
  .fm-submit { width: 100%; }
}

/* --- Galeria --- */
.ga-hint {
  font-family: var(--f-mono);
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  color: var(--c-text-mute);
  margin: var(--s-1) 0 var(--s-3);
}

.ga-track {
  display: flex;
  gap: var(--s-1);
  overflow-x: auto;
  padding: 0 var(--s-3) var(--s-2);
  scroll-snap-type: x mandatory;
  scrollbar-width: thin;
  scrollbar-color: var(--c-line) transparent;
}

.ga-track img {
  flex: 0 0 auto;
  width: clamp(220px, 26vw, 340px);
  aspect-ratio: 4 / 5;
  object-fit: cover;
  background: var(--c-surface);
  scroll-snap-align: start;
  filter: saturate(0.85) contrast(1.1);
  transition: filter 0.35s var(--ease);
}

.ga-track img:hover { filter: saturate(1.05) contrast(1.15); }

/* --- Rodapé --- */
.ft {
  border-top: 1px solid var(--c-line);
  padding: var(--s-5) 0 var(--s-3);
  position: relative;
  z-index: 1;
}

.ft-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--s-4);
}

.ft-col--wide { grid-column: span 2; }

.ft-logo {
  font-size: 1.6rem;
  font-weight: 900;
  letter-spacing: -0.02em;
  margin: 0 0 0.4rem;
}

.ft-meta {
  font-family: var(--f-mono);
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  color: var(--c-text-mute);
  margin: 0;
}

.ft-col h4 { margin: 0 0 var(--s-2); font-weight: 400; }

.ft-link {
  display: block;
  font-family: var(--f-mono);
  font-size: 0.85rem;
  color: var(--c-text-mute);
  text-decoration: none;
  transition: color 0.2s var(--ease);
}

.ft-link:hover { color: var(--c-accent); }

.ft-sponsors { display: flex; flex-wrap: wrap; gap: var(--s-2); }

.ft-sponsor {
  border: 1px solid var(--c-line);
  padding: 0.7rem 1.1rem;
  font-family: var(--f-mono);
  font-size: 0.68rem;
  letter-spacing: 0.16em;
  color: var(--c-text-mute);
}

.ft-base {
  margin-top: var(--s-5);
  padding-top: var(--s-2);
  border-top: 1px solid var(--c-line);
  font-family: var(--f-mono);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  color: var(--c-text-mute);
}

@media (max-width: 720px) {
  .ft-col--wide { grid-column: auto; }
}

/* --- Linha de scanning entre secções --- */
.scanline {
  position: relative;
  height: 1px;
  background: var(--c-line);
  overflow: visible;
}

.scanline::after {
  content: "";
  position: absolute;
  top: -1px;
  left: 0;
  height: 3px;
  width: 0;
  background: linear-gradient(90deg, transparent, var(--c-accent), transparent);
  box-shadow: 0 0 12px var(--c-accent-dim);
}

.scanline.is-in::after {
  animation: scan-across 1.1s var(--ease) forwards;
}

@keyframes scan-across {
  0%   { width: 0;    opacity: 1; }
  70%  { width: 100%; opacity: 1; }
  100% { width: 100%; opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .scanline.is-in::after { animation: none; }
}

/* --- Portal de entrada --- */
body.is-gated { overflow: hidden; }

.portal {
  /* Escala tipográfica única do portal. Todos os tamanhos de texto
     derivam desta medida por um múltiplo fixo, para a hierarquia entre
     eles ser a mesma em qualquer largura.
     Com clamps independentes por elemento (a primeira tentativa), cada
     um atingia o seu teto a uma largura diferente — subtítulo aos
     884px, contagem aos 904, botão aos 1000, logo aos 1519 — por isso
     entre ~900px e ~1520px só o logo crescia e o texto ia ficando
     proporcionalmente mais pequeno. A razão logo/contagem variava de
     2.28 a 3.85 conforme o ecrã. */
  --txt: clamp(0.68rem, 0.40rem + 0.88vw, 1.3rem);

  position: fixed;
  inset: 0;
  z-index: 95;
  display: grid;
  /* Sem uma coluna explícita, um grid mede o item pelo max-content — a
     largura que o texto ocuparia numa única linha, sem quebrar. Textos
     longos (a ficha de pilotos) transbordavam da janela por causa disto. */
  grid-template-columns: minmax(0, 100%);
  /* stretch (não center): o único filho directo do grid agora é o
     .portal-scroll, que tem de preencher toda a célula para poder
     fazer scroll em qualquer ponto do ecrã — é ele que centra o
     conteúdo lá dentro, não o .portal. O fundo (canvas/halo/
     pseudo-elementos abaixo) fica fora deste grid, directamente no
     .portal, por isso nunca se mexe com o scroll. */
  place-items: stretch;
  padding: var(--s-4) var(--s-3);
  /* Vinhete marcado: o centro respira e as bordas fecham a preto. */
  background: radial-gradient(ellipse 78% 62% at 50% 44%,
    #10200e 0%, #0a160a 22%, #050c05 44%, #020402 66%, #000 88%);
  text-align: center;
  transition: opacity 0.8s var(--ease), transform 0.8s var(--ease);
}

.portal::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    repeating-linear-gradient(0deg, rgba(57,255,20,0.05) 0 1px, transparent 1px 26px),
    repeating-linear-gradient(90deg, rgba(57,255,20,0.05) 0 1px, transparent 1px 26px);
  pointer-events: none;
}

/* Scanlines finas por cima, como um monitor CRT */
.portal::after {
  content: "";
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(0deg, rgba(0,0,0,0.3) 0 1px, transparent 1px 3px);
  opacity: 0.5;
  pointer-events: none;
}

.portal.is-out { opacity: 0; transform: scale(1.04); pointer-events: none; }

/* --- Grid ondulante --- */
/* As linhas são desenhadas em canvas para poderem deformar-se; a grid
   estática do ::before é o que fica sem JS ou em movimento reduzido. */
.portal-grid {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.portal.tem-grid-viva::before { display: none; }

/* Halo que se abre do centro, ao mesmo ritmo da grelha a acender. */
.portal-luz {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(ellipse 70% 56% at 50% 44%,
    rgba(57, 255, 20, 0.15) 0%,
    rgba(57, 255, 20, 0.07) 30%,
    rgba(57, 255, 20, 0.02) 52%,
    transparent 72%);
  opacity: 0;
  transform: scale(0.2);
  transform-origin: 50% 44%;
  transition:
    opacity 2.2s ease-out,
    transform 2.8s cubic-bezier(0.22, 0.7, 0.25, 1);
}

.portal.is-ready .portal-luz { opacity: 1; transform: scale(1); }

@media (prefers-reduced-motion: reduce) {
  .portal-luz { opacity: 1; transform: none; transition: none; }
}

/* Preenche toda a célula do grid do .portal (por isso stretch acima)
   e é este elemento — não o .portal — que faz scroll e centra o
   conteúdo. Um item de grid não encolhe abaixo do tamanho do próprio
   conteúdo por omissão (min-height:auto); sem min-height:0 aqui, o
   overflow nunca chegava a activar-se — era o .portal inteiro que
   crescia para caber tudo, e como esse é fixed/inset:0, o excesso
   ficava simplesmente cortado pela janela, sem scroll nenhum. */
.portal-scroll {
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  display: grid;
  grid-template-columns: minmax(0, 100%);
  /* "safe" evita a armadilha clássica de grid centrado + overflow: sem
     isto, quando a ficha era mais alta que o disponível, o início do
     conteúdo ficava por cima da borda do container — inacessível,
     mesmo com scroll — porque um item maior que o container "center"
     invade os dois lados por igual, incluindo para fora da área
     scrollável. */
  place-items: safe center;
}

/* Coluna centrada: o .portal-cd é inline-flex (para a moldura encolher
   até ao conteúdo) e sem isto o botão fluiria ao lado dele. */
.portal-inner {
  position: relative;
  z-index: 1;
  width: 100%;
  min-width: 0;
  max-width: 900px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* --- Ecrãs do portal ---------------------------------------- */
/* Hero, portão e ficha partilham o mesmo fundo (grid/ripple, que vive
   fora do .portal-inner): só o conteúdo troca. */
.portal-screen {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  opacity: 1;
  transition: opacity 0.4s ease;
}

.portal-screen[hidden] { display: none; }
.portal-screen.is-fading { opacity: 0; }

@media (prefers-reduced-motion: reduce) {
  .portal-screen { transition: none; }
}

/* --- Vagas restantes (ficha) --- */
/* Vivia num ecrã do portão à parte, sozinho, e usava por isso o nível
   de espaçamento maior (isolar um CTA). Agora é só mais um bloco de
   contexto no topo da ficha, entre o rótulo e a ressalva — o mesmo
   nível moderado que separa qualquer bloco ali. */
.portal-vagas {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  margin: var(--s-3) 0;
  font-family: var(--f-mono);
  color: var(--c-amber);
}

.portal-vagas-num {
  /* Era 5.6× quando as vagas eram o único protagonista de um ecrã à
     parte — nesse tamanho, ao lado da contagem no mesmo ecrã, esmagava-a.
     1.9× fica claramente secundário à contagem (2.35×), mas ainda lê-se
     como um número com peso próprio, não uma legenda. */
  font-size: calc(var(--txt) * 1.9);
  font-variant-numeric: tabular-nums;
  line-height: 0.9;
  letter-spacing: -0.03em;
  text-shadow: 0 0 30px rgba(255, 176, 32, 0.45),
               0 0 76px rgba(255, 176, 32, 0.16);
}

.portal-vagas-cap {
  font-size: calc(var(--txt) * 0.82);
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: rgba(255, 176, 32, 0.72);
}

/* A ficha lê-se melhor alinhada à esquerda e mais larga que o resto,
   que é curto e fica centrado. */
.portal-screen--form {
  align-items: stretch;
  width: 100%;
  max-width: 640px;
  text-align: left;
  /* O scroll (quando a ficha é mais alta que o ecrã) vive no
     .portal-scroll — esta faixa de 640px era estreita a mais para
     apanhar a roda do rato fora dela. Mantém só o respiro
     lateral/inferior. */
  padding: 0 var(--s-1) var(--s-2);
}

.portal-screen--form .label { text-align: center; }
.portal-screen--form .fm-intro { text-align: center; }
.portal-screen--form .fm-intro { margin-left: auto; margin-right: auto; }
.portal-screen--form .portal-vagas { margin-left: auto; margin-right: auto; }

/* Entrada escalonada: o nome respira sozinho antes do resto aparecer. */
/* Entrada sem qualquer movimento: só a opacidade, como no nome.
   Easing suave mas previsível: com a --ease do resto do site a
   opacidade chegava ao fim a menos de metade da duração, e o
   encadeamento deixava de bater certo. */
.portal-logo,
.portal-word,
.portal-sub,
.portal-cd,
.portal-live,
.portal-enter {
  opacity: 0;
  transition: opacity var(--fade, 450ms) ease-out var(--entrada, 0ms);
}

/* O nome entra mais devagar, para continuar a ser ele a abrir. */
.portal-logo,
.portal-word { --fade: 900ms; }

.portal.is-ready .portal-logo,
.portal.is-ready .portal-word,
.portal.is-ready .portal-sub,
.portal.is-ready .portal-cd,
.portal.is-ready .portal-live,
.portal.is-ready .portal-enter {
  opacity: 1;
}

/* Encadeado: cada um arranca no instante em que o anterior acaba.
   900 + 450 + 450 + 450 = 2250ms no total. */
.portal-sub   { --entrada: 900ms; }
.portal-cd    { --entrada: 1350ms; }
.portal-live  { --entrada: 1350ms; }
.portal-enter { --entrada: 1800ms; }

@media (prefers-reduced-motion: reduce) {
  .portal-logo, .portal-word, .portal-sub,
  .portal-cd, .portal-live, .portal-enter {
    opacity: 1; transition: none;
  }
}

/* O logo é o único que não segue a escala do texto: é um objecto
   gráfico limitado pela largura disponível, não pela legibilidade. O
   teto está calibrado para chegar ao máximo por volta da mesma largura
   que o texto (~1540px), para os dois pararem de crescer juntos. */
.portal-logo { width: clamp(260px, 52vw, 800px); margin: 0 auto var(--s-2); }

/* O wordmark só aparece se a imagem do logo não existir. */
.portal-logo + .portal-word { display: none; }

/* --- Wordmark --- */
.portal-word {
  display: block;
  /* Mesma lógica do .portal-logo. */
  width: clamp(290px, 50vw, 770px);
  height: auto;
  margin: 0 auto var(--s-2);
  overflow: visible;
  /* Igual ao fotograma 0% de neon-respirar: com valores diferentes o
     glow dava um salto quando a animação arrancava. */
  filter:
    drop-shadow(0 0 18px rgba(57, 255, 20, 0.42))
    drop-shadow(0 0 46px rgba(57, 255, 20, 0.14));
}

/* Contorno por baixo do corpo, a engrossar a silhueta e a separar o
   lettering do fundo. */
.rd-contorno {
  fill: none;
  stroke: #082604;
  stroke-width: 10;
  stroke-linejoin: round;
}

.rd-corpo { fill: url(#rd-metal); }

.rd-brilho { fill: url(#rd-brilho); }


/* Néon vivo: só a respiração lenta. Arranca depois da entrada, para
   não competir com o fade do nome.
   Só o .portal-word (SVG, sem glow próprio) usa isto — o .portal-logo
   é uma imagem que já traz o néon cozinhado; somar-lhe o mesmo
   drop-shadow duplicava o brilho e rebentava as bordas. */
.portal.is-ready .portal-word {
  animation: neon-respirar 3.4s ease-in-out 2.6s infinite;
}

@keyframes neon-respirar {
  0%, 100% {
    filter:
      drop-shadow(0 0 18px rgba(57, 255, 20, 0.42))
      drop-shadow(0 0 46px rgba(57, 255, 20, 0.14));
  }
  50% {
    filter:
      drop-shadow(0 0 26px rgba(57, 255, 20, 0.6))
      drop-shadow(0 0 64px rgba(57, 255, 20, 0.26));
  }
}

/* A imagem recebe só uma respiração muito ligeira de opacidade —
   suficiente para não parecer estática, sem somar glow novo. */
.portal.is-ready .portal-logo {
  animation: logo-respirar 3.4s ease-in-out 2.6s infinite;
}

@keyframes logo-respirar {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.92; }
}

/* Falhas curtas, como um tubo de néon a pegar mal */
@media (prefers-reduced-motion: reduce) {
  .portal.is-ready .portal-word,
  .portal.is-ready .portal-logo { animation: none; }
}

.portal-sub {
  /* C3: subtítulo→contagem e contagem→botão tinham a mesma distância
     (var(--s-5) nos dois), o que agrupa visualmente a contagem com o
     botão de acção — quando devia agrupar-se com o subtítulo, que é a
     informação do mesmo evento. Três níveis em vez de dois iguais:
     nome→subtítulo continua apertado (mesmo bloco), subtítulo→contagem
     mais folgado, contagem→botão o mais largo de todos (destaca a
     acção). Mesmo princípio, com o tracking largo a sobrar à direita. */
  margin: 0 -0.28em var(--s-4) 0;
  font-family: var(--f-mono);
  font-size: var(--txt);
  letter-spacing: 0.28em;
  /* A transparência vive na cor: um opacity fixo aqui anularia o
     fade de entrada escalonado. */
  color: rgba(57, 255, 20, 0.8);
}

.portal-cd {
  position: relative;
  display: inline-flex;
  align-items: baseline;
  justify-content: center;
  gap: clamp(0.85rem, 2.8vw, 1.7rem);
  /* O maior dos três níveis — separa claramente a contagem (info) do
     botão (acção) a seguir. Ver nota em .portal-sub. */
  margin-bottom: var(--s-6);
  font-family: var(--f-mono);
  font-variant-numeric: tabular-nums;
  color: var(--c-amber);
}

/* O par número+unidade é um bloco: junto por dentro, separado por fora. */
.pcd-grupo {
  display: inline-flex;
  align-items: baseline;
  gap: 0.12em;
}

.pcd-num {
  font-size: calc(var(--txt) * 2.35);
  line-height: 1;
  letter-spacing: 0.02em;
  text-shadow: 0 0 16px rgba(255, 176, 32, 0.32);
  transition: color 0.45s var(--ease), text-shadow 0.45s var(--ease);
}

/* A unidade alinha pelo topo do número, como notação técnica, em vez
   de assentar na baseline a parecer um subscrito deslocado. */
.pcd-u {
  align-self: flex-start;
  font-size: calc(var(--txt) * 0.88);
  line-height: 1.1;
  letter-spacing: 0.1em;
  /* 0.5 dava 3.34:1 sobre o fundo do portal — abaixo do mínimo AA
     (4.5:1) para texto pequeno. 0.72 resolve sem mudar a hierarquia
     visual (continua claramente secundário face ao número). */
  color: rgba(255, 176, 32, 0.72);
}

/* Acende ao mudar, para a contagem não parecer parada. */
.pcd-num.is-tick {
  color: #ffd27a;
  text-shadow: 0 0 20px rgba(255, 176, 32, 0.65);
  transition: none;
}

@media (prefers-reduced-motion: reduce) {
  .pcd-num, .pcd-num.is-tick { transition: none; }
}

@media (max-width: 560px) {
  .portal-cd { gap: 0.8rem; }
}

.portal-live {
  font-family: var(--f-mono);
  font-size: clamp(1rem, 3.5vw, 1.6rem);
  letter-spacing: 0.18em;
  color: var(--c-amber);
  text-shadow: 0 0 22px rgba(255,176,32,0.5);
  /* Mesmo nível do .portal-cd que substitui — ocupa o mesmo lugar. */
  margin: 0 0 var(--s-6);
}

.portal-enter {
  background: transparent;
  border: 1px solid var(--c-accent);
  /* Antes fixo em 0.75rem/2rem em qualquer largura: é o
     call-to-action principal do ecrã e era o elemento mais pequeno
     dele. O max() garante o piso de legibilidade em mobile, onde a
     escala sozinha desceria abaixo de 12px. */
  padding: max(0.9rem, calc(var(--txt) * 0.8)) max(2rem, calc(var(--txt) * 2.6));
  font-family: var(--f-mono);
  font-size: max(0.75rem, calc(var(--txt) * 0.92));
  letter-spacing: 0.24em;
  color: var(--c-accent);
  cursor: pointer;
  /* Inclui opacity e transform: uma shorthand só com as do hover
     substituiria a transição de entrada e o botão apareceria já feito. */
  transition:
    background 0.25s var(--ease),
    color 0.25s var(--ease),
    box-shadow 0.25s var(--ease),
    opacity var(--fade, 450ms) ease-out var(--entrada, 0ms);
}

.portal-enter:hover {
  background: var(--c-accent);
  color: #000;
  box-shadow: 0 0 28px rgba(57,255,20,0.4);
}

.portal-enter:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 4px; }

/* Variante do portão: só um glow extra em repouso — o preenchimento a
   verde fica reservado para o hover/foco (herdado do .portal-enter
   base), tal como o resto dos botões do site. Preenchido já em
   repouso lia-se pesado a mais para um botão que agora vive dentro
   do hero, ao lado do logótipo, subtítulo e contagem.
   Também mais pequeno que o .portal-enter base: à escala herdada
   ficava do tamanho da contagem, competindo com ela por atenção em
   vez de se ler claramente como o passo a seguir. */
.portal-enter--forte {
  padding: max(0.7rem, calc(var(--txt) * 0.6)) max(1.6rem, calc(var(--txt) * 2));
  font-size: max(0.68rem, calc(var(--txt) * 0.78));
  box-shadow: 0 0 22px rgba(57, 255, 20, 0.3);
}

.portal-enter--forte:hover {
  background: #4dff2e;
  box-shadow: 0 0 32px rgba(57, 255, 20, 0.45);
}

@media (max-width: 720px) {
  /* 0.8rem dava 42px de altura total — abaixo dos 44px de alvo de
     toque mínimo. Medido: o botão nunca chegou aos 44px em mobile. */
  .portal-enter { padding: 0.95rem 1.8rem; letter-spacing: 0.18em; }
  /* Mesma proporção do C3 em desktop (dois níveis distintos, não um
     valor repetido), só que comprimida para caber num ecrã mais baixo. */
  .portal-sub { margin-bottom: var(--s-3); }
  .portal-cd, .portal-live { margin-bottom: var(--s-5); }
}

/* --- Voltar atrás --- */
/* Vive fora do .portal-inner, por isso fica fixo no canto mesmo
   quando a ficha (por baixo dele) tem scroll próprio. */
.portal-back {
  position: absolute;
  top: var(--s-3);
  left: var(--s-3);
  z-index: 2;
  background: none;
  border: 1px solid var(--c-line);
  /* 44px é o alvo de toque mínimo recomendado; 2.4rem (38.4px) ficava
     abaixo disso. */
  width: 2.75rem;
  height: 2.75rem;
  display: grid;
  place-items: center;
  color: var(--c-text-mute);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  transition: color 0.2s var(--ease), border-color 0.2s var(--ease);
}

.portal-back:hover { color: var(--c-accent); border-color: var(--c-accent); }
.portal-back:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 3px; }

/* [hidden] e .portal-back{display:grid} têm a mesma especificidade;
   sem isto, a regra da classe ganhava por vir depois na folha de
   estilos e o botão ficava visível mesmo escondido. */
.portal-back[hidden] { display: none; }

