/* ============================================================
   GoLive Mini — layout bento + identidade "grafite"
   ============================================================ */

/* Larguras das colunas laterais do bento. Registrar com @property é o que
   torna elas ANIMÁVEIS: custom property comum é sempre tratada como texto,
   então trocar 260px por 0px daria um salto seco. Declarada como <length>,
   o navegador sabe interpolar — e, como grid-template-columns lê essas
   variáveis, as colunas deslizam de verdade ao abrir/fechar um painel. */
@property --people-col {
  syntax: "<length>";
  inherits: false;
  initial-value: 0px;
}
@property --chat-col {
  syntax: "<length>";
  inherits: false;
  initial-value: 0px;
}

/* ---------- tokens ----------
   Paleta em OKLCH em vez de hex. A diferença que importa na prática: o
   primeiro número é clareza PERCEPTUAL — 21% parece 21% de luz pro olho,
   não pro monitor. Isso dá duas coisas que a paleta antiga em hex não
   tinha: degraus de superfície que realmente parecem espaçados igual, e
   mistura entre duas cores sem passar pela zona cinza-lama do meio.
   O matiz 265 (azul-violeta) com croma baixíssimo é o que dá a leitura
   "grafite frio" — a cor de marca aparece só onde precisa apontar algo. */
:root {
  color-scheme: dark;

  /* superfícies, do fundo pro que flutua mais alto */
  --bg:        oklch(14% 0.012 265);
  --surface-1: oklch(17.5% 0.013 265);
  --surface-2: oklch(21% 0.014 265);
  --surface-3: oklch(25% 0.015 265);
  --border:    oklch(27% 0.014 265);
  --border-lit: oklch(36% 0.02 265);

  --text:  oklch(97% 0.003 265);
  --muted: oklch(68% 0.014 265);
  --faint: oklch(50% 0.014 265);

  /* Acento usado com parcimônia: foco, estado ativo, CTA. O par
     íris/ciano também é a identidade de cada participante (avatar, borda da
     bolha) — duas matizes bem distantes no círculo cromático se distinguem
     melhor que roxo+rosa, inclusive pra quem tem daltonismo. */
  --accent:   oklch(66% 0.19 274);
  --accent-2: oklch(74% 0.13 210);
  --online:   oklch(75% 0.15 155);
  --danger:   oklch(63% 0.20 22);
  --warn:     oklch(80% 0.14 80);

  /* "véu" neutro por cima de qualquer superfície (fundo de repouso de botão
     de ícone, hover, divisória). No tema claro precisa VIRAR preto fraco —
     luz por cima de claro não aparece. */
  --overlay-1: oklch(100% 0 0 / .07);
  --overlay-2: oklch(100% 0 0 / .13);

  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --space-1: 6px;
  --space-2: 10px;
  --space-3: 16px;
  --space-4: 24px;

  /* respiro entre os blocos do bento — mesmo valor vira o padding externo
     do grid, que é o que faz tudo parecer "um conjunto de cartões" e não
     "caixas empilhadas". */
  --gap: clamp(10px, 1.1vw, 16px);

  --shadow-float: 0 16px 40px -20px oklch(0% 0 0 / .8);
  --ease: cubic-bezier(.2, .8, .2, 1);

  --font-body: "Inter", system-ui, -apple-system, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* ---------- temas ----------
   [data-theme] no <html>, trocado pelo popover de tema (ver theme.js).
   A chave "purple" é histórica (era o nome do tema quando a identidade era
   roxa) — hoje é o tema grafite padrão; mantida pra não invalidar o que já
   está salvo no localStorage de quem usa. */
:root[data-theme="white"] {
  color-scheme: light;
  --bg:        oklch(97% 0.003 265);
  --surface-1: oklch(100% 0 0);
  --surface-2: oklch(96% 0.004 265);
  --surface-3: oklch(100% 0 0);
  --border:    oklch(90% 0.006 265);
  --border-lit: oklch(80% 0.01 265);
  --text:  oklch(23% 0.015 265);
  --muted: oklch(50% 0.015 265);
  --faint: oklch(66% 0.012 265);
  --accent: oklch(55% 0.19 274);
  --overlay-1: oklch(20% 0.02 265 / .06);
  --overlay-2: oklch(20% 0.02 265 / .11);
  --shadow-float: 0 16px 40px -24px oklch(40% 0.05 265 / .35);
}
:root[data-theme="black"] {
  color-scheme: dark;
  --bg:        oklch(0% 0 0);
  --surface-1: oklch(10% 0.006 265);
  --surface-2: oklch(14% 0.008 265);
  --surface-3: oklch(18% 0.01 265);
  --border:    oklch(21% 0.01 265);
  --border-lit: oklch(32% 0.014 265);
  --shadow-float: 0 16px 40px -20px oklch(0% 0 0 / 1);
}

/* ---------- base ---------- */
* { box-sizing: border-box; }

html, body { overflow-x: hidden; }

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 16px;
  background: var(--bg);
  color: var(--text);
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  -webkit-font-smoothing: antialiased;
}

/* tracking negativo em títulos é metade da leitura "produto de engenharia"
   (Linear, Vercel, Stripe fazem isso) — texto corrido continua no tracking
   natural, senão cansa de ler. */
h1, h2, .brand {
  font-weight: 600;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

/* ---------- primitivos ---------- */
input, button {
  font: inherit;
  font-size: 16px; /* >=16px evita o zoom automático do iOS ao focar */
  padding: 12px 14px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  min-height: 44px;
}
input {
  background: var(--surface-2);
  color: var(--text);
  flex: 1;
  min-width: 0;
  width: 100%;
}
input::placeholder { color: var(--faint); }
input:focus-visible, button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
button { cursor: pointer; font-weight: 500; color: var(--text); }
button:disabled { opacity: .45; cursor: not-allowed; }

/* ícones herdam a cor do texto do botão via currentColor, então acompanham
   hover/disabled/.off sem nenhum CSS extra por estado. */
.icon { width: 18px; height: 18px; flex: none; stroke: currentColor; }

.btn-primary, .btn-secondary, .btn-pill, .icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
}

/* UMA cor sólida de acento, sem gradiente. Gradiente em botão era a cara da
   identidade antiga; a nova aposta em superfície neutra + um acento que só
   aparece onde tem ação. */
.btn-primary {
  background: var(--accent);
  border: 1px solid transparent;
  color: oklch(99% 0 0);
  font-weight: 600;
  transition: background .15s var(--ease), transform .12s var(--ease);
}
.btn-primary:hover { background: color-mix(in oklch, var(--accent) 86%, white); transform: translateY(-1px); }
.btn-primary:active { transform: translateY(0); }

.btn-secondary {
  background: var(--surface-2);
  border: 1px solid var(--border);
  transition: background .15s var(--ease), border-color .15s var(--ease);
}
.btn-secondary:hover { background: var(--surface-3); border-color: var(--border-lit); }

/* botão só-ícone: quadrado compacto, fundo neutro de repouso. */
.icon-btn {
  width: 34px; height: 34px; min-height: 34px; padding: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  border: 1px solid transparent;
  color: var(--muted);
  transition: background .15s var(--ease), color .15s var(--ease), border-color .15s var(--ease);
}
.icon-btn:hover { background: var(--overlay-1); color: var(--text); }
.icon-btn[aria-expanded="true"], .icon-btn.is-active {
  background: var(--overlay-2); color: var(--text); border-color: var(--border);
}
.icon-btn .icon { width: 16px; height: 16px; }

/* divisória fina que agrupa blocos de ícones — em vez de uma fileira só,
   sem hierarquia nenhuma. */
.control-divider {
  width: 1px; align-self: stretch; margin-block: 5px; flex: none;
  background: var(--border);
}

/* ---------- tela de entrada ---------- */
#join-section {
  position: relative; overflow: hidden;
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--space-4);
  padding: var(--space-4);
  background: var(--bg);
}

/* fundo animado: port 1:1 do algoritmo do componente "Animated Gradient
   Background" (um radial-gradient redesenhado a cada frame via JS — ver
   gradient-bg.js). Aqui o wrap só cuida da entrada (fade + scale). */
.agb-wrap {
  position: absolute; inset: 0; overflow: hidden; z-index: 0; pointer-events: none;
  opacity: 0; transform: scale(1.5);
  transition: opacity 2s var(--ease), transform 2s var(--ease);
}
.agb-wrap.agb-in { opacity: 1; transform: scale(1); }
.agb-inner { position: absolute; inset: 0; }
@keyframes bg-breathe {
  0%, 100% { transform: scale(1); opacity: .8; }
  50% { transform: scale(1.08); opacity: 1; }
}

.join-hero {
  position: relative; z-index: 1;
  display: flex; flex-direction: column; align-items: center; gap: var(--space-2);
}
.brand {
  margin: 0; font-size: 22px;
  display: inline-flex; align-items: center; gap: var(--space-2);
}
.logo-dot {
  width: 10px; height: 10px; border-radius: 3px; flex: none;
  background: var(--accent);
  box-shadow: 0 0 0 4px color-mix(in oklch, var(--accent) 18%, transparent);
}
.join-tagline {
  position: relative; z-index: 1;
  margin: 0; text-align: center; color: var(--muted); font-size: 15px; max-width: 300px;
  text-wrap: pretty;
}

.join-mascot { position: relative; width: 170px; height: 170px; }
.join-mascot::before {
  content: ''; position: absolute; inset: -40px; border-radius: 50%;
  background: radial-gradient(circle, color-mix(in oklch, var(--accent) 30%, transparent), transparent 70%);
  filter: blur(8px);
  animation: bg-breathe 6s ease-in-out infinite;
}
.join-mascot svg { position: relative; }

.join-card {
  position: relative; z-index: 1;
  width: 100%; max-width: 380px;
  display: flex; flex-direction: column; gap: var(--space-3);
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  box-shadow: var(--shadow-float);
}
/* fio de luz de 1px no topo do card — acabamento padrão de card dark-mode
   "premium". Não é borda colorida inteira (gritaria), só uma faixa que
   sugere uma fonte de luz vindo de cima. */
.join-card::before {
  content: ''; position: absolute; inset-inline: 12px; top: 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--border-lit), transparent);
}
.field { display: flex; flex-direction: column; gap: var(--space-1); }
.field label {
  font-size: 11px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase;
  color: var(--faint);
}
.input-icon-wrap { position: relative; flex: 1; min-width: 0; display: flex; }
.input-icon {
  position: absolute; inset-inline-start: 13px; top: 50%; translate: 0 -50%;
  width: 16px; height: 16px; color: var(--faint); pointer-events: none;
}
.input-icon-wrap input { padding-inline-start: 38px; }
#join-bar { display: flex; gap: var(--space-2); flex-wrap: wrap; }
#join-bar input { min-width: 140px; }
#join-bar button { flex: none; }

@media (max-width: 420px) {
  #join-bar { flex-direction: column; }
  #join-bar button { width: 100%; }
}

/* ============================================================
   BENTO
   ============================================================
   3 colunas x 3 linhas. As faixas de topo (config) e de baixo (controles)
   vivem só na coluna CENTRAL — não atravessam os painéis laterais. É isso
   que faz o layout ler como bento (blocos independentes, cada um com
   respiro em volta) em vez de dashboard com barras atravessadas.

     people │ topbar │ chat
     people │ stage  │ chat
     people │ dock   │ chat

   Área nomeada precisa formar um retângulo — por isso "people" e "chat"
   repetem nas três linhas em vez de tentar um recorte em L. */
#app {
  display: none;
  grid-template-areas:
    "people topbar chat"
    "people stage  chat"
    "people dock   chat";
  grid-template-columns: var(--people-col) minmax(0, 1fr) var(--chat-col);
  grid-template-rows: auto minmax(0, 1fr) auto;
  gap: var(--gap);
  padding: var(--gap);
  padding-top: calc(var(--gap) + env(safe-area-inset-top));
  padding-bottom: calc(var(--gap) + env(safe-area-inset-bottom));
  flex: 1;
  min-height: 0;
  /* as duas custom properties registradas lá em cima — é isso que faz a
     coluna deslizar em vez de saltar. */
  transition: --people-col .32s var(--ease), --chat-col .32s var(--ease);
}
#app.active { display: grid; }

#app[data-people="open"] { --people-col: clamp(190px, 16vw, 250px); }
#app[data-chat="open"]   { --chat-col:   clamp(240px, 19vw, 310px); }

/* superfície compartilhada por todo bloco do bento. Uma borda hairline de
   baixo contraste + um degrau de superfície já resolvem a hierarquia no
   escuro; sombra pesada em cada bloco deixaria a tela suja. */
#topbar, #stage, .bento-panel, #control-bar {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  min-width: 0;
  min-height: 0;
}

/* ---------- topbar (config, no meio acima do palco) ---------- */
#topbar {
  grid-area: topbar;
  display: grid;
  /* 1fr / auto / 1fr deixa o cronômetro no centro ÓPTICO da barra
     independente do tamanho do texto de status ou de quantos ícones tem do
     outro lado — coisa que flex com space-between não garante. */
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-2);
}
.topbar-lead {
  justify-self: start;
  display: flex; align-items: center; gap: var(--space-2);
  min-width: 0; padding-inline-start: var(--space-1);
}
#status {
  font-size: 12px; color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.online-dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--online); flex: none;
  display: none;
}
.online-dot.on, .online-dot.reconnecting { display: block; }
/* âmbar piscando = tentando se recuperar de uma queda. Diferente do
   vermelho (que no resto do app significa "desligado de propósito") e do
   verde fixo (tudo certo). */
.online-dot.reconnecting {
  background: var(--warn);
  animation: dot-pulse 1s ease-in-out infinite;
}
@keyframes dot-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .3; } }

#call-timer {
  justify-self: center;
  font-family: var(--font-mono);
  font-size: 13px; font-weight: 500;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  background: var(--surface-2);
  border-radius: var(--radius-sm);
  padding: 4px 10px;
}

.topbar-actions {
  justify-self: end;
  display: flex; align-items: center; gap: 2px;
}

/* ---------- painéis (pessoas / chat) ---------- */
/* container-type deixa o CONTEÚDO reagir à largura do próprio painel, não à
   da janela — necessário aqui porque as colunas encolhem/expandem sozinhas
   e um @media não enxerga isso. */
.bento-panel {
  container-type: inline-size;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  opacity: 1;
  transition: opacity .22s var(--ease) .05s;
}
#participants-panel { grid-area: people; }
#chat-panel { grid-area: chat; }

/* painel fechado: some junto com a coluna e sai do alcance do teclado
   (visibility, não só opacity — senão o Tab continua entrando nele). */
#app[data-people="closed"] #participants-panel,
#app[data-chat="closed"] #chat-panel {
  opacity: 0;
  visibility: hidden;
  transition: opacity .16s var(--ease), visibility 0s linear .32s;
}

.panel-header {
  flex: none;
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-2);
  padding: var(--space-2) var(--space-2) var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--border);
}
.panel-header h2 {
  margin: 0; font-size: 12px; font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase; color: var(--muted);
  display: flex; align-items: center; gap: var(--space-2);
  white-space: nowrap;
}
#participants-count {
  font-family: var(--font-mono); font-size: 11px; letter-spacing: 0;
  color: var(--text); background: var(--surface-2);
  border-radius: 999px; padding: 1px 7px;
}
.panel-close {
  width: 28px; height: 28px; min-height: 28px; padding: 0; flex: none;
  background: transparent; border: none; border-radius: var(--radius-sm); color: var(--faint);
  display: inline-flex; align-items: center; justify-content: center;
  transition: background .15s var(--ease), color .15s var(--ease);
}
.panel-close:hover { background: var(--overlay-1); color: var(--text); }
.panel-close .icon { width: 14px; height: 14px; }

#participants-list {
  list-style: none; margin: 0; padding: var(--space-1);
  display: flex; flex-direction: column; gap: 1px;
  overflow-y: auto; flex: 1;
}
.participant-row {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2);
  padding: var(--space-2);
  border-radius: var(--radius-sm);
  transition: background-color .15s var(--ease);
}
.participant-row.speaking { background: color-mix(in oklch, var(--online) 14%, transparent); }
.avatar {
  width: 22px; height: 22px; border-radius: var(--radius-sm); flex: none;
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 600; color: oklch(12% 0.01 265);
}
.avatar-iris { background: var(--accent); }
.avatar-cyan { background: var(--accent-2); }
.participant-row .name {
  flex: 1; min-width: 0; font-size: 13px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.participant-row .mic-state, .participant-row .cam-state { color: var(--danger); flex: none; display: flex; }
.participant-row .mic-state.on, .participant-row .cam-state.on { color: var(--faint); }
.participant-row .mic-state .icon, .participant-row .cam-state .icon { width: 15px; height: 15px; }
.participant-row .mic-state .off-slash, .participant-row .cam-state .off-slash { display: inline; }
.participant-row .mic-state.on .off-slash, .participant-row .cam-state.on .off-slash { display: none; }

/* linhas de outras pessoas abrem o menu de volume (clique ou botão direito) */
.participant-row[data-local="false"] { cursor: pointer; }
.participant-row[data-local="false"]:hover { background: var(--overlay-1); }
/* silenciada por você: some um pouco, igual o Discord faz */
.participant-row.locally-muted .name { color: var(--faint); text-decoration: line-through; }

/* painel estreito: aperta o respiro das linhas. Container query porque quem
   manda aqui é a largura da COLUNA, não a da janela. */
@container (max-width: 200px) {
  .participant-row { padding: var(--space-1) var(--space-2); }
}

/* ---------- chat ---------- */
#chat-messages {
  list-style: none; margin: 0; padding: var(--space-2);
  display: flex; flex-direction: column; gap: var(--space-2);
  overflow-y: auto; flex: 1;
}
.chat-msg { display: flex; flex-direction: column; gap: 2px; max-width: 88%; }
.chat-msg .chat-author {
  font-size: 10px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--faint); padding-inline: 2px;
}
.chat-msg .chat-bubble {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 7px 11px;
  font-size: 13px; line-height: 1.45; word-break: break-word;
}
.chat-msg.own { align-self: flex-end; align-items: flex-end; }
.chat-msg.own .chat-bubble {
  background: color-mix(in oklch, var(--accent) 16%, transparent);
  border-color: color-mix(in oklch, var(--accent) 30%, transparent);
}
.chat-msg.system { align-self: center; }
.chat-msg.system .chat-bubble {
  background: transparent; border-color: transparent;
  color: var(--faint); font-size: 12px; padding: 2px 8px;
}
#chat-form {
  flex: none; display: flex; gap: var(--space-2);
  padding: var(--space-2); border-top: 1px solid var(--border);
}
#chat-input { min-height: 38px; padding: 8px 12px; font-size: 14px; }
#chat-send {
  flex: none; width: 38px; min-height: 38px; padding: 0;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-sm);
  display: inline-flex; align-items: center; justify-content: center;
  transition: background .15s var(--ease), color .15s var(--ease);
}
#chat-send:hover { background: var(--accent); border-color: transparent; color: oklch(99% 0 0); }
#chat-send .icon { width: 15px; height: 15px; }

#chat-btn { position: relative; }
#chat-badge {
  position: absolute; top: 3px; inset-inline-end: 3px;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--accent);
  border: 2px solid var(--surface-1);
}
#chat-badge[hidden] { display: none; }

/* ---------- palco ---------- */
/* #stage é só um "quadro" de posicionamento: cada camada (vazio, vídeo,
   bolhas, reações) se posiciona absoluta e preenche 100% dele. Evita o bug
   clássico de flex em que align-items:center encolhe o filho. */
#stage {
  grid-area: stage;
  position: relative;
  overflow: hidden;
}

#stage-empty {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--space-4);
  padding: var(--space-4);
}
#stage-empty[hidden] { display: none; }

.stage-actions { display: flex; gap: var(--space-2); flex-wrap: wrap; justify-content: center; }
.stage-actions button { padding: 12px 20px; font-size: 14px; border-radius: var(--radius-md); }

.stage-bubbles { position: relative; width: 200px; height: 140px; }
.bubble {
  position: absolute; top: 8px; width: 118px; height: 118px; border-radius: 32%;
  opacity: .7;
  animation: floaty 6s ease-in-out infinite;
  transition: transform 1.1s var(--ease);
}
/* quadrado de canto arredondado em vez de círculo: círculo agora é
   exclusividade de "pessoa" (bolha de câmera), então a decoração do palco
   vazio não pode competir com esse significado. */
.bubble.iris {
  inset-inline-start: 0;
  background: radial-gradient(circle at 34% 30%, color-mix(in oklch, var(--accent) 70%, white), var(--accent));
}
.bubble.cyan {
  inset-inline-start: 82px;
  background: radial-gradient(circle at 34% 30%, color-mix(in oklch, var(--accent-2) 70%, white), var(--accent-2));
  animation-delay: .4s;
}
.bubble-glow {
  position: absolute; inset-inline-start: 60px; top: 24px; width: 88px; height: 88px; border-radius: 50%;
  background: radial-gradient(circle, oklch(100% 0 0 / .4), transparent 70%);
  opacity: 0; transition: opacity 1.1s var(--ease); pointer-events: none;
}
.stage-bubbles.merged .bubble.iris { transform: translateX(30px); }
.stage-bubbles.merged .bubble.cyan { transform: translateX(-30px); }
.stage-bubbles.merged .bubble-glow { opacity: 1; }
@keyframes floaty {
  0%, 100% { translate: 0 0; }
  50% { translate: 0 -12px; }
}

/* ---------- blocos (câmera e tela) ----------
   Todo bloco é absoluto dentro de #tiles; layout.js calcula posição e
   tamanho (grade, foco + faixa) e só troca translate/width/height. A
   transição daqui é que faz qualquer mudança de layout deslizar. */
/* o container em si não pega clique: sem isso ele taparia os botões do
   convite vazio que ficam embaixo dele */
#tiles { position: absolute; inset: var(--space-2); pointer-events: none; }
.tile {
  position: absolute; left: 0; top: 0;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--surface-2);
  cursor: pointer; pointer-events: auto;
  transition: translate .32s var(--ease), width .32s var(--ease), height .32s var(--ease);
  animation: tile-in .25s var(--ease);
}
.tile.no-anim { transition: none; }
.tile[hidden] { display: none; }
@keyframes tile-in { from { opacity: 0; scale: .96; } }
/* anel verde = "tá falando de verdade agora" (volume real do áudio, ver
   audio-level.js). Por cima do vídeo, então precisa ser uma camada própria. */
.tile::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit;
  box-shadow: inset 0 0 0 1px oklch(100% 0 0 / .06);
  pointer-events: none;
  transition: box-shadow .15s var(--ease);
}
.tile.speaking::after { box-shadow: inset 0 0 0 3px var(--online); }
.tile.locally-muted video { opacity: .55; }

.tile video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; background: oklch(0% 0 0); }
/* em foco mostra a imagem inteira; tela compartilhada nunca é cortada */
.tile.is-focused video, .tile-screen video { object-fit: contain; }
.tile.is-focused { cursor: default; }
.tile-screen.is-focused { cursor: crosshair; } /* clique = apontador */
/* sua própria câmera espelhada, como num espelho (e como no Discord) —
   dá pra desligar no menu do botão direito */
#tiles.mirror-self .tile-cam[data-local="true"] video { transform: scaleX(-1); }

/* arrastando a mini janela, a divisa da faixa ou a quina: segue o ponteiro
   sem a animação, que só atrasaria */
.tile.dragging, #tiles.resizing .tile { transition: none; }

/* mini janela (desencaixada): por cima dos outros, com sombra */
.tile.is-floating {
  z-index: 2; cursor: grab; touch-action: none;
  box-shadow: var(--shadow-float), 0 0 0 1px oklch(100% 0 0 / .12);
}
.tile.is-floating.dragging { cursor: grabbing; }

/* botão de desencaixar/encaixar: aparece com o mouse em cima do bloco */
.tile-dock {
  position: absolute; top: var(--space-1); inset-inline-end: var(--space-1);
  width: 28px; height: 28px; min-height: 28px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--radius-sm); border: 1px solid oklch(100% 0 0 / .16);
  background: oklch(0% 0 0 / .55); color: oklch(99% 0 0);
  opacity: 0; transition: opacity .15s var(--ease);
  z-index: 1;
}
.tile-dock .icon { width: 15px; height: 15px; }
.tile:hover .tile-dock, .tile-dock:focus-visible { opacity: 1; }
@media (hover: none) { .tile-dock { display: none; } } /* no toque: menu do toque longo */
/* bloco pequeno demais pro botão */
#stage[data-layout="focus"] .tile:not(.is-focused):not(.is-floating) .tile-dock { display: none; }

/* quina de redimensionar: só na mini janela, no canto virado pro centro */
.tile-resize { display: none; }
.tile.is-floating .tile-resize {
  display: block; position: absolute; width: 18px; height: 18px; z-index: 1;
  touch-action: none;
}
.tile.is-floating[data-corner$="r"] .tile-resize { left: 0; cursor: nwse-resize; }
.tile.is-floating[data-corner$="l"] .tile-resize { right: 0; cursor: nesw-resize; }
.tile.is-floating[data-corner^="b"] .tile-resize { top: 0; }
.tile.is-floating[data-corner^="t"] .tile-resize { bottom: 0; }
.tile.is-floating[data-corner="tr"] .tile-resize,
.tile.is-floating[data-corner="bl"] .tile-resize { cursor: nesw-resize; }
.tile.is-floating[data-corner="tl"] .tile-resize,
.tile.is-floating[data-corner="br"] .tile-resize { cursor: nwse-resize; }

/* divisa entre o foco e a faixa: arrastar muda a altura da faixa */
.strip-handle {
  position: absolute; left: 0; top: 0; width: 100%;
  cursor: row-resize; pointer-events: auto; touch-action: none;
}
.strip-handle[hidden] { display: none; }
.strip-handle::after {
  content: ''; position: absolute; left: 50%; top: 50%; translate: -50% -50%;
  width: 40px; height: 3px; border-radius: 2px;
  background: var(--border-lit); opacity: 0; transition: opacity .15s var(--ease);
}
.strip-handle:hover::after, #tiles.resizing .strip-handle::after { opacity: 1; }

/* sem câmera: avatar no lugar do vídeo */
.tile-cam[data-video="off"] video { visibility: hidden; }
.tile-avatar { position: absolute; inset: 0; display: none; align-items: center; justify-content: center; }
.tile-cam[data-video="off"] .tile-avatar { display: flex; }
.tile-avatar .avatar {
  width: clamp(36px, 28%, 96px); height: auto; aspect-ratio: 1; border-radius: 50%;
  font-size: clamp(15px, 2.4vw, 38px);
}
.tile.speaking .tile-avatar .avatar { box-shadow: 0 0 0 3px var(--online); }

.tile-footer {
  position: absolute; inset-inline-start: var(--space-1); bottom: var(--space-1);
  max-width: calc(100% - var(--space-2));
  display: flex; align-items: center; gap: 4px;
  padding: 3px 8px; border-radius: 999px;
  background: oklch(0% 0 0 / .55); color: oklch(99% 0 0);
  font-size: 12px; line-height: 1.2;
  pointer-events: none;
}
.tile-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tile-mic { display: none; color: var(--danger); }
.tile-mic .icon { width: 13px; height: 13px; }
.tile.mic-off .tile-mic { display: flex; }
.tile-live {
  flex: none; padding: 1px 5px; border-radius: 4px;
  background: var(--danger); color: oklch(99% 0 0);
  font-size: 10px; font-weight: 700; letter-spacing: .04em;
}
.tile-status {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center; text-align: center;
  font-size: 13px; padding: var(--space-2); background: oklch(0% 0 0 / .7); color: oklch(99% 0 0);
}
.tile-status[hidden] { display: none; }

/* blocos pequenos (faixa, celular): rótulo mais discreto */
#stage[data-layout="focus"] .tile:not(.is-focused) .tile-footer { font-size: 10px; padding: 2px 6px; }
#stage[data-layout="focus"] .tile:not(.is-focused) .tile-live { font-size: 8px; }
#stage[data-layout="focus"] .tile:not(.is-focused) .tile-status { font-size: 9px; }

/* barra do palco: membros sem vídeo, faixa, grade/foco e tela cheia */
.stage-toolbar {
  position: absolute; top: var(--space-3); inset-inline-end: var(--space-3);
  display: flex; gap: var(--space-1);
  z-index: 3;
  transition: opacity .2s var(--ease);
}
.stage-toolbar[hidden] { display: none; }
@media (hover: hover) {
  /* só aparece com o mouse em cima do palco, igual ao Discord */
  .stage-toolbar { opacity: 0; }
  #stage:hover .stage-toolbar, .stage-toolbar:focus-within { opacity: 1; }
}
.stage-icon-btn {
  width: 34px; height: 34px; min-height: 34px; padding: 0; border-radius: var(--radius-sm);
  background: oklch(0% 0 0 / .55);
  border: 1px solid oklch(100% 0 0 / .16);
  color: oklch(99% 0 0);
  display: flex; align-items: center; justify-content: center;
  backdrop-filter: blur(8px);
}
.stage-icon-btn[hidden] { display: none; }
.stage-icon-btn .off-slash { display: none; }
.stage-icon-btn.active .off-slash { display: inline; }
/* faixa escondida: a seta vira pra cima ("mostrar de volta") */
#strip-btn .icon { transition: rotate .2s var(--ease); }
#strip-btn.active .icon { rotate: 180deg; }
#layout-btn .icon-focus { display: none; }
#layout-btn.is-grid .icon-grid { display: none; }
#layout-btn.is-grid .icon-focus { display: block; }
#follow-btn .icon, #novideo-btn .icon { pointer-events: none; }
.stage-icon-btn.active:not(#novideo-btn):not(#strip-btn) { background: var(--accent); border-color: transparent; color: oklch(12% 0.01 265); }
/* janela separada: não existe tela cheia lá dentro */
#stage.is-popout #fullscreen-btn { display: none; }
#fullscreen-btn .icon-compress { display: none; }
#fullscreen-btn.is-fullscreen .icon-expand { display: none; }
#fullscreen-btn.is-fullscreen .icon-compress { display: block; }

/* ---------- palco na janela separada (popout.js) ---------- */
.stage-placeholder {
  grid-area: stage; display: none;
  flex-direction: column; align-items: center; justify-content: center; gap: var(--space-3);
  background: var(--surface-1); border: 1px dashed var(--border-lit); border-radius: var(--radius-lg);
  color: var(--muted); font-size: 14px; text-align: center; padding: var(--space-4);
}
#app.stage-popped .stage-placeholder { display: flex; }
/* dentro da janela separada o palco ocupa tudo */
.popout-body { margin: 0; height: 100vh; overflow: hidden; background: var(--bg); }
.popout-body #stage { position: fixed; inset: 0; border: none; border-radius: 0; }

/* ---------- reações / apontador ---------- */
#reactions-layer { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }
.reaction-emoji {
  position: absolute; bottom: 90px; font-size: 30px;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  animation: reaction-float 1.6s ease-out forwards;
}
.reaction-emoji-name {
  font-size: 11px; font-weight: 600; color: var(--text);
  background: var(--surface-3); padding: 1px 8px; border-radius: 999px; white-space: nowrap;
}
@keyframes reaction-float {
  0% { opacity: 0; translate: 0 0; }
  15% { opacity: 1; }
  100% { opacity: 0; translate: 0 -140px; }
}

.pointer-ping {
  position: absolute; width: 26px; height: 26px; margin: -13px 0 0 -13px;
  border-radius: 50%; border: 2px solid var(--accent);
  display: flex; align-items: center; justify-content: center;
  animation: pointer-ping-anim 1s ease-out forwards;
}
.pointer-ping-label {
  font-size: 10px; font-weight: 700; color: oklch(99% 0 0);
  background: var(--accent); width: 17px; height: 17px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
}
@keyframes pointer-ping-anim {
  0% { opacity: 0; scale: .4; }
  15% { opacity: 1; scale: 1; }
  70% { opacity: 1; scale: 1; }
  100% { opacity: 0; scale: 1.3; }
}

/* ---------- dock de controles ---------- */
#control-bar {
  grid-area: dock;
  display: flex; align-items: center; justify-content: center; gap: var(--space-1);
  padding: var(--space-1);
  flex-wrap: wrap;
}
/* "squircle": quadrado de canto arredondado = ação; círculo = pessoa. Cada
   forma comunica uma coisa só, em todo o app. */
#control-bar button {
  width: 38px; height: 38px; min-height: 38px; padding: 0;
  border-radius: 11px;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface-2); border: 1px solid var(--border); color: var(--text);
  transition: background .15s var(--ease), border-color .15s var(--ease), transform .08s var(--ease);
}
#control-bar button .icon { width: 16px; height: 16px; }
#control-bar button:hover { background: var(--surface-3); border-color: var(--border-lit); }
#control-bar button:active { transform: scale(.94); }
/* mic/câmera nascem desligados — o estado precisa ser inequívoco, então é
   vermelho sólido, não um vermelho "sujo" misturado com a superfície. */
#control-bar button.off {
  background: var(--danger); border-color: transparent; color: oklch(99% 0 0);
}
#control-bar button.off:hover { background: color-mix(in oklch, var(--danger) 86%, white); }
/* risco diagonal só no estado off: sem ele, ligado e desligado usariam o
   MESMO ícone só mudando de cor — ruim pra daltônico e pra tela ao sol. */
#control-bar .off-slash { display: none; }
#control-bar button.off .off-slash { display: inline; }
/* "ligado" (ex: modo cinema) — mesma família do .off, só que no acento, já
   que aqui não é alerta, é só "isso está ativo". */
#control-bar button.active {
  background: var(--accent); border-color: transparent; color: oklch(99% 0 0);
}
#control-bar button.active:hover { background: color-mix(in oklch, var(--accent) 86%, white); }

/* prefixo #control-bar pra vencer `#control-bar button` em especificidade —
   sem isso o botão quadrado sempre ganha e "Sair" nunca alarga. */
#control-bar .btn-pill {
  width: auto; height: 34px; min-height: 34px; padding: 0 12px;
  border-radius: var(--radius-sm); gap: 6px; font-size: 13px;
  background: transparent; border: 1px solid var(--border); color: var(--danger);
}
#control-bar .btn-pill .icon { width: 14px; height: 14px; }
#control-bar .btn-pill:hover {
  background: var(--danger); border-color: transparent; color: oklch(99% 0 0);
}

/* ---------- modo cinema ---------- */
/* apaga as luzes em volta do vídeo: tudo que não é palco recua, e volta no
   hover. Só CSS — cada um liga o seu, não precisa avisar o outro lado. */
body.cinema-mode #topbar,
body.cinema-mode #control-bar,
body.cinema-mode .bento-panel {
  opacity: .3;
  transition: opacity .25s var(--ease);
}
body.cinema-mode #topbar:hover,
body.cinema-mode #control-bar:hover,
body.cinema-mode .bento-panel:hover { opacity: 1; }
body.cinema-mode #app { background: oklch(0% 0 0); }
body.cinema-mode #stage { border-color: transparent; }

/* ---------- popovers nativos ---------- */
/* O atributo popover já dá top layer, Escape, clique-fora e fechar um
   quando o outro abre. Aqui só resta a aparência e ONDE ele aparece. */
.popover-card {
  margin: 0; padding: var(--space-1);
  inset: auto; /* neutraliza o centramento padrão do popover */
  width: 210px;
  background: color-mix(in oklch, var(--surface-3) 82%, transparent);
  backdrop-filter: blur(16px) saturate(150%);
  -webkit-backdrop-filter: blur(16px) saturate(150%);
  border: 1px solid var(--border-lit);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-float);
  color: var(--text);
  flex-direction: column; gap: 2px;
}
.popover-card:popover-open { display: flex; }
.popover-title {
  margin: 0; padding: var(--space-2) var(--space-2) var(--space-1);
  font-size: 10px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase;
  color: var(--faint);
}
.popover-card button {
  width: 100%; height: 34px; min-height: 34px; padding: 0 var(--space-2);
  font-size: 13px; text-align: start;
  background: transparent; border: none; border-radius: var(--radius-sm); color: var(--text);
  display: flex; align-items: center; gap: var(--space-2);
  transition: background .12s var(--ease);
}
.popover-card button:hover { background: var(--overlay-1); }
.popover-card button.active { background: var(--overlay-2); color: var(--accent); font-weight: 600; }
/* leitura ao vivo da conexão dentro do popover de qualidade — mono porque é
   número que muda sozinho a cada 2,5s e não pode ficar "dançando". */
.popover-stats {
  margin: 2px 2px 4px; padding-inline: var(--space-2);
  font-family: var(--font-mono); font-size: 10.5px; line-height: 1.5;
  color: var(--faint);
}

/* ponto de qualidade da conexão no botão de config: verde/âmbar/vermelho,
   mesma gramática da bolinha de online no topbar. */
#quality-btn { position: relative; }
.quality-dot {
  position: absolute; bottom: 3px; inset-inline-end: 3px;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--online);
  border: 2px solid var(--surface-1);
}
.quality-dot[hidden] { display: none; }
.quality-dot.fair { background: var(--warn); }
.quality-dot.poor { background: var(--danger); }

/* ---------- menu de volume da pessoa ---------- */
.user-menu { width: 250px; }
.menu-slider {
  display: grid; grid-template-columns: 1fr auto; align-items: center;
  gap: 6px var(--space-2);
  padding: var(--space-1) var(--space-2) var(--space-2);
  font-size: 12px; color: var(--muted);
}
.menu-slider[hidden] { display: none; }
.menu-value {
  font-family: var(--font-mono); font-size: 11px; color: var(--text);
  font-variant-numeric: tabular-nums;
}
/* o `input` genérico lá em cima tem padding, borda e 44px de altura
   (pensado pros campos de texto) — tudo isso quebraria um range. */
.menu-slider input[type="range"] {
  grid-column: 1 / -1;
  width: 100%; min-height: 0; height: 18px; padding: 0; margin: 0;
  border: none; background: transparent; accent-color: var(--accent); cursor: pointer;
}
#user-menu-mute { margin-top: 2px; border-top: 1px solid var(--border); border-radius: 0 0 var(--radius-sm) var(--radius-sm); }
#user-menu-mute.active { color: var(--danger); }
#user-menu-audio[hidden] { display: none; }
.menu-actions { display: flex; flex-direction: column; border-top: 1px solid var(--border); margin-top: 2px; padding-top: 2px; }
#user-menu-audio[hidden] + .menu-actions { border-top: none; margin-top: 0; }
.menu-actions button[hidden] { display: none; }
.menu-actions button.active::after { content: ' ✓'; color: var(--accent); }

.popover-note {
  margin: var(--space-1) 2px 2px; padding-inline: var(--space-2);
  font-size: 11px; color: var(--faint); line-height: 1.45;
}

/* Onde o navegador já tem CSS Anchor Positioning (Baseline 2026), o popover
   se ancora no próprio botão que o abriu — sem JS de medida, sem Floating
   UI. position-area faz o trabalho que antes pedia top/left calculados. */
@supports (anchor-name: --a) {
  #quality-btn { anchor-name: --quality-anchor; }
  #theme-btn   { anchor-name: --theme-anchor; }
  #quality-picker { position-anchor: --quality-anchor; }
  #theme-picker   { position-anchor: --theme-anchor; }
  #quality-picker, #theme-picker {
    position-area: block-end span-inline-start;
    margin-top: var(--space-2);
    position-try-fallbacks: flip-block, flip-inline;
  }
}
/* Sem anchor positioning, o popover continua na top layer (então não dá pra
   posicionar relativo ao botão) — vira uma folha centralizada no topo. Não
   é um "erro visual": é o mesmo padrão de sheet que a maioria dos apps usa
   no celular. */
@supports not (anchor-name: --a) {
  #quality-picker, #theme-picker {
    inset: auto; top: calc(var(--gap) * 2 + 44px);
    left: 50%; translate: -50% 0;
  }
}

/* ---------- seletor de tema ---------- */
/* cada opção mostra a superfície REAL daquele tema — a pessoa vê antes de
   clicar. Valores fixos de propósito (mostram o tema alvo, não o atual). */
.theme-swatch {
  width: 14px; height: 14px; border-radius: 4px; flex: none;
  border: 1px solid var(--border-lit);
}
.theme-swatch-graphite { background: linear-gradient(135deg, oklch(14% .012 265), oklch(25% .015 265)); }
.theme-swatch-white    { background: linear-gradient(135deg, oklch(100% 0 0), oklch(93% .004 265)); }
.theme-swatch-black    { background: linear-gradient(135deg, oklch(0% 0 0), oklch(18% .01 265)); }

/* ---------- toasts ---------- */
#toast-layer {
  position: fixed; top: calc(var(--space-3) + env(safe-area-inset-top)); left: 50%;
  translate: -50% 0;
  z-index: 50; display: flex; flex-direction: column; gap: var(--space-2); align-items: center;
  pointer-events: none;
}
.toast {
  background: color-mix(in oklch, var(--surface-3) 88%, transparent);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid var(--border-lit);
  box-shadow: var(--shadow-float);
  border-radius: var(--radius-md); padding: 9px 15px; font-size: 13px; color: var(--text);
  opacity: 0; transform: translateY(-8px);
  /* --toast-hold: quanto tempo fica visível antes de sumir — sobrescrito
     por toast (ver showToast em controls.js) pras mensagens de erro, que
     são longas e precisam de mais tempo de leitura. */
  animation: toast-in .25s var(--ease) forwards,
             toast-out .25s var(--ease) forwards var(--toast-hold, 2.6s);
  /* sem isso a "pílula" tentava caber numa linha só e estourava a largura
     da tela no celular com as mensagens de erro maiores. */
  max-width: min(360px, calc(100vw - 48px));
  text-align: center;
}
@keyframes toast-in { to { opacity: 1; transform: translateY(0); } }
@keyframes toast-out { to { opacity: 0; transform: translateY(-8px); } }

/* ============================================================
   FULLSCREEN
   ============================================================
   A Fullscreen API só desenha o que está DENTRO do elemento que virou tela
   cheia — tudo que fica fora some. Por isso fullscreen.js MOVE o dock, os
   painéis e a camada de toasts pra dentro de #stage ao entrar (e devolve ao
   sair). As regras abaixo só valem nesse momento: os mesmos elementos, com
   apresentação de "por cima do vídeo" em vez de bloco do bento. */
#stage:fullscreen { border-radius: 0; border: none; }

#stage #control-bar {
  position: absolute; left: 50%; bottom: var(--space-4); translate: -50% 0;
  width: auto; margin: 0; flex-wrap: nowrap;
  padding: var(--space-1) var(--space-2);
  border-radius: 999px;
  background: color-mix(in oklch, var(--surface-3) 80%, transparent);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  box-shadow: var(--shadow-float);
  z-index: 5;
  transition: opacity .25s var(--ease);
}
#stage .bento-panel {
  position: absolute; inset-block: var(--space-3); inset-inline-end: var(--space-3);
  width: min(320px, 80vw);
  z-index: 6;
  background: color-mix(in oklch, var(--surface-1) 92%, transparent);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  box-shadow: var(--shadow-float);
}

/* "estilo Discord": em tela cheia os controles somem sozinhos depois de um
   tempo parado e voltam quando o mouse mexe (ver fullscreen.js). */
#stage.is-overlay.controls-hidden .stage-toolbar,
#stage.is-overlay.controls-hidden #control-bar { opacity: 0; pointer-events: none; }
#stage.is-overlay.controls-hidden { cursor: none; }

/* ============================================================
   TELAS MENORES
   ============================================================
   Abaixo do ponto em que três colunas ainda respiram, os painéis deixam de
   ser coluna do bento e viram gaveta por cima do conteúdo. O JS não sabe
   disso: ele só liga/desliga data-people e data-chat — quem decide o que
   "aberto" significa é só o CSS (ver panels.js). */
@media (max-width: 1080px) {
  #app {
    grid-template-areas: "topbar" "stage" "dock";
    grid-template-columns: minmax(0, 1fr);
  }
  .bento-panel {
    position: fixed;
    inset-block: calc(var(--gap) + env(safe-area-inset-top)) calc(var(--gap) + env(safe-area-inset-bottom));
    inset-inline-end: var(--gap);
    width: min(330px, calc(100vw - var(--gap) * 2));
    z-index: 40;
    box-shadow: var(--shadow-float);
    translate: calc(100% + var(--gap)) 0;
    opacity: 1;
    transition: translate .3s var(--ease);
  }
  #app[data-people="open"] #participants-panel,
  #app[data-chat="open"] #chat-panel { translate: 0 0; visibility: visible; }
  /* mesma especificidade das regras de desktop lá em cima, e depois delas
     no arquivo — então estas vencem dentro do media query. */
  #app[data-people="closed"] #participants-panel,
  #app[data-chat="closed"] #chat-panel {
    opacity: 1;
    visibility: hidden;
    translate: calc(100% + var(--gap)) 0;
    transition: translate .3s var(--ease), visibility 0s linear .3s;
  }
}

@media (max-width: 640px) {
  #topbar { grid-template-columns: auto 1fr auto; padding: var(--space-1); }
  .topbar-lead { padding-inline-start: 2px; }
  #status { display: none; } /* a bolinha já diz o essencial em tela pequena */
  #call-timer { justify-self: start; }
  .stage-bubbles { width: 160px; height: 115px; }
  .bubble { width: 94px; height: 94px; }
  .bubble.cyan { inset-inline-start: 64px; }
  .bubble-glow { width: 70px; height: 70px; inset-inline-start: 44px; top: 20px; }
  .stage-actions button { padding: 11px 15px; font-size: 13px; }
  #tiles { inset: var(--space-1); }
  .stage-toolbar { top: var(--space-2); inset-inline-end: var(--space-2); }
  #control-bar button { width: 42px; height: 42px; }
}

/* celular deitado: sobra pouquíssima altura, o palco precisa de tudo */
@media (max-height: 430px) {
  #stage-empty { gap: var(--space-2); padding: var(--space-2); }
  .stage-bubbles { display: none; }
}
