/* =====================================================================
   app.css — o painel público do omni-meet.

   # NENHUM `#hex` AQUI DENTRO

   O "teste dos dois minutos" da norma procura cor literal em CSS de
   componente, e ele existe porque uma cor escrita à mão é uma cor que não
   acompanha o tema: ela fica igual no claro e no escuro, e quem trocar o
   contrato não tem como encontrá-la.

   Toda cor sai de `var(--ds-*)`, declarada em `tokens.css`, que é cópia
   byte a byte do contrato v2.4.0 da casa.

   # A ESCALA TIPOGRÁFICA É A DO CONTRATO

   O DS-31 mediu o uso real do ecossistema e abriu três degraus abaixo do
   corpo de 14 (`--ds-fs-body-sm` 13 · `--ds-fs-caption` 12 · `--ds-fs-micro`
   11). Este arquivo usa os degraus, e não pixels soltos.
   ===================================================================== */

/* ── O ESPAÇAMENTO É LOCAL, e a razão é uma LACUNA da norma ─────────
   O contrato `token.css` v2.4.0 declara tipografia, cor, raio, sombra,
   `z-index` e as medidas de zona — e **não declara escala de espaçamento**.
   Não há família `--ds-sp-*`, e conferi nome a nome.

   A consequência é que todo produto do ecossistema inventa a própria, e
   duas telas de dois produtos ficam com ritmos diferentes sem que nada
   acuse — que é exatamente o defeito que a família de tipografia sofreu
   antes do DS-31, e que o DS-31 corrigiu MEDINDO o uso real.

   Enquanto a norma não tiver a família, ela mora aqui, com prefixo `--sp-`
   e NÃO `--ds-`: usar o prefixo do contrato para um token que o contrato
   não tem é a forma de a lacuna virar invisível.

   Os degraus seguem a escala de 4px que os dois mocks de referência usam
   de fato — medida neles, e não inventada aqui. */
:root {
  --sp-1: .25rem;   /*  4px */
  --sp-2: .5rem;    /*  8px */
  --sp-3: .75rem;   /* 12px */
  --sp-4: 1rem;     /* 16px */
  --sp-5: 1.5rem;   /* 24px */
  /* O raio de pílula: o contrato tem `sm`/`md`/`lg`/`xl` e não tem pílula. */
  --sp-pill: 999px;
}

*, *::before, *::after { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  /* O fundo é EXPLÍCITO: um `body` transparente empresta o fundo do host,
     e a página passa a depender de onde foi embutida. */
  background: var(--ds-canvas);
  color: var(--ds-text);
  font-family: var(--ds-font);
  font-size: var(--ds-fs-body);
  line-height: 1.5;
  display: flex;
  flex-direction: column;
}

/* ── o salto para o conteúdo ───────────────────────────────────────────
   Ele é a primeira parada do Tab e fica invisível até receber foco. NÃO é
   `display:none` nem `visibility:hidden`: as duas o tirariam da ordem de
   tabulação, que é exatamente o que ele existe para ocupar. */
.salto {
  position: absolute;
  left: var(--sp-3); top: calc(var(--sp-3) * -6);
  z-index: 100;
  padding: var(--sp-2) var(--sp-3);
  background: var(--ds-accent);
  color: var(--ds-on-accent);
  border-radius: var(--ds-radius-sm);
  text-decoration: none;
  transition: top .15s ease;
}
.salto:focus-visible { top: var(--sp-3); }

/* ── topo ──────────────────────────────────────────────────────────── */
.topo {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--ds-border);
  background: var(--ds-surface);
}

/* A ÁREA RESERVADA da marca: medida, e sem arte.
   Ela ocupa o espaço desde o início para a tela não SALTAR quando a marca do
   tenant chegar, depois do segundo fator (MEE-5.2). */
.marca {
  width: var(--ds-wordmark-w);
  height: var(--ds-wordmark-h);
  flex: 0 0 auto;
}

.prefs {
  display: flex; align-items: center; gap: var(--sp-2);
  /* `min-width: 0` e a correcao de um defeito MEDIDO a 320px CSS.
     Por padrao um item de flex tem `min-width: auto`, e isso o impede de
     encolher abaixo do tamanho do proprio conteudo. O `<select>` carrega a
     largura da opcao mais longa ("Portugues (BR)"), entao a faixa nao cabia:
     361px numa janela de 320. E a rolagem horizontal reprova o SC 1.4.10 --
     medido pelo `reflow.js` da norma, que ate 2026-09-01 so media os mocks
     dela e nunca tinha visto esta tela. */
  min-width: 0;
  /* E quebrar linha, em vez de espremer: espremido, o seletor de idioma vira
     uma caixa de tres caracteres em que ninguem le o que escolheu. */
  flex-wrap: wrap;
  row-gap: var(--sp-1);
}

.btn-icone {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px;
  padding: 0;
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-sm);
  background: var(--ds-raised);
  color: var(--ds-text);
  cursor: pointer;
}
.btn-icone:hover { background: var(--ds-raised-2); }

.sel-idioma {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  color: var(--ds-text-2);
  /* A cadeia inteira precisa do zero: basta UM ancestral com `min-width: auto`
     para o filho voltar a nao encolher, e o sintoma reaparece longe daqui. */
  min-width: 0;
}
.sel-idioma select {
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-sm);
  background: var(--ds-raised);
  color: var(--ds-text);
  font: inherit;
  font-size: var(--ds-fs-body-sm);
  padding: var(--sp-1) var(--sp-2);
  min-width: 0;
  max-width: 100%;
}

.glifo { width: 18px; height: 18px; flex: 0 0 auto; }
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

/* ── palco e cartão ────────────────────────────────────────────────── */
.palco {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-4);
  padding: var(--sp-4);
}

.cartao {
  width: 100%;
  max-width: 400px;
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-lg);
  padding: var(--sp-5);
  box-shadow: var(--ds-shadow-md);
}

h1 {
  margin: 0 0 var(--sp-2);
  font-size: var(--ds-fs-title);
  font-weight: 600;
  /* `balance` em título: o DS o traz do CSS de referência (B-4.107). */
  text-wrap: balance;
}

.sub {
  margin: 0 0 var(--sp-4);
  color: var(--ds-text-2);
  font-size: var(--ds-fs-body-sm);
  text-wrap: pretty;
}

/* ── trilha das seis etapas ────────────────────────────────────────── */
.trilha { width: 100%; max-width: 400px; }
.trilha ol {
  display: flex; gap: var(--sp-1);
  list-style: none; margin: 0 0 var(--sp-2); padding: 0;
}
.trilha li {
  flex: 1; height: 3px;
  background: var(--ds-raised-2);
  border-radius: 2px;
}
/* `.on` é o ÚNICO nome de estado ativo no ecossistema (B-4.27). */
.trilha li.on { background: var(--ds-accent); }
.trilha-txt {
  margin: 0;
  font-size: var(--ds-fs-caption);
  color: var(--ds-text-2);
}

/* ── campos ────────────────────────────────────────────────────────── */
.campo { display: block; margin-bottom: var(--sp-3); }
.campo > span {
  display: flex; align-items: center; gap: var(--sp-1);
  margin-bottom: var(--sp-1);
  font-size: var(--ds-fs-body-sm);
  color: var(--ds-text-2);
}
.campo input, .campo select {
  width: 100%;
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-sm);
  background: var(--ds-raised);
  color: var(--ds-text);
  font: inherit;
}
/* A moldura acompanha o controle DESABILITADO sem JS espelhando estado numa
   classe do pai — que é a segunda fonte de verdade que sempre esquece. */
.campo:has(input:disabled), .campo:has(select:disabled) { opacity: .55; }

/* ── botões ────────────────────────────────────────────────────────── */
.btn-primario, .btn-secundario, .btn-texto {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--sp-1);
  width: 100%;
  padding: var(--sp-2) var(--sp-4);
  border-radius: var(--ds-radius-sm);
  font: inherit;
  font-weight: 500;
  cursor: pointer;
}
/* [B-4.17] A ação primária é `--ds-accent` com tinta `--ds-on-accent`.
   O verde voltou a significar SAÚDE, e branco sobre o âmbar dá 2,33:1. */
.btn-primario {
  border: 1px solid transparent;
  background: var(--ds-accent);
  color: var(--ds-on-accent);
}
.btn-primario:hover { background: var(--ds-accent-hover); }
.btn-primario:disabled { cursor: default; opacity: .55; }
.btn-secundario {
  border: 1px solid var(--ds-border);
  background: var(--ds-raised);
  color: var(--ds-text);
}
.btn-texto {
  border: 1px solid transparent;
  background: transparent;
  color: var(--ds-text-2);
  font-size: var(--ds-fs-body-sm);
  margin-top: var(--sp-2);
}
.btn-texto:hover { color: var(--ds-text); }

.acoes { margin-top: var(--sp-4); }

/* ── o anel de foco DUAL-TONE (B-4.48) ─────────────────────────────
   Dois anéis: um da cor do fundo e outro do accent. Um anel só desaparece
   quando o controle está sobre uma superfície da mesma cor dele. */
:where(a, button, input, select, video):focus-visible {
  outline: 2px solid var(--ds-focus-ring);
  outline-offset: 2px;
  box-shadow: 0 0 0 4px var(--ds-surface);
}

/* ── alerta inline ─────────────────────────────────────────────────── */
.alerta {
  display: flex; align-items: flex-start; gap: var(--sp-2);
  margin-bottom: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--ds-danger);
  border-radius: var(--ds-radius-sm);
  background: var(--ds-danger-tint);
  color: var(--ds-danger-text);
  font-size: var(--ds-fs-body-sm);
}
/* A regra de `[hidden]`, e ela é GLOBAL desde 2026-09-01.

   Ela existia aqui como `.alerta[hidden]`, com este mesmo comentário
   explicando o defeito — e o defeito aconteceu de novo, num seletor que a
   regra não cobria. `.etapa-sala { display: flex }` venceu o `display:none`
   do agente de usuário, e a barra de chamada da SEXTA etapa apareceu na
   PRIMEIRA, com o botão de desligar em vermelho ao lado do campo do convite.

   *Um remédio escrito para um seletor não protege o seletor seguinte.* A
   regra passa a valer para tudo, e o `!important` é o ponto: sem ele,
   qualquer `display` de classe volta a vencer, e a correção duraria até a
   próxima regra de layout.

   Ela vem ANTES das regras de componente por legibilidade; a cascata não
   depende disso — `!important` vence posição. */
[hidden] { display: none !important; }

/* ── a marcação de NÃO VERIFICADO ──────────────────────────────────── */
.marcacao {
  display: flex; flex-direction: column; gap: var(--sp-1);
  margin: 0 0 var(--sp-3);
}
.selo {
  align-self: flex-start;
  padding: 2px var(--sp-2);
  border-radius: var(--sp-pill);
  background: var(--ds-warning-tint);
  color: var(--ds-warning-text);
  font-size: var(--ds-fs-micro);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
}
.selo-txt { color: var(--ds-text-2); font-size: var(--ds-fs-caption); }

/* ── dispositivos ──────────────────────────────────────────────────── */
.perm {
  padding: var(--sp-3);
  border: 1px dashed var(--ds-border);
  border-radius: var(--ds-radius-sm);
  margin-bottom: var(--sp-3);
}
.perm p { margin: 0 0 var(--sp-2); font-size: var(--ds-fs-body-sm); }

.medidor { margin-bottom: var(--sp-3); }
.rot {
  display: block; margin-bottom: var(--sp-1);
  font-size: var(--ds-fs-body-sm); color: var(--ds-text-2);
}
.barra {
  height: 6px; border-radius: 3px; overflow: hidden;
  background: var(--ds-raised-2);
}
.barra > i {
  display: block; height: 100%; width: 0;
  background: var(--ds-success);
  transition: width .08s linear;
}

.previa { margin: 0 0 var(--sp-3); }
.previa video {
  width: 100%; aspect-ratio: 16 / 9;
  border-radius: var(--ds-radius-sm);
  background: var(--ds-raised-2);
  object-fit: cover;
}
.previa figcaption {
  margin-top: var(--sp-1);
  font-size: var(--ds-fs-caption);
  color: var(--ds-text-2);
}

/* ── antessala ─────────────────────────────────────────────────────── */
.estado-espera {
  display: flex; align-items: center; gap: var(--sp-2);
  margin: 0 0 var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--ds-radius-sm);
  background: var(--ds-raised);
  font-size: var(--ds-fs-body-sm);
}
.ok-grande { margin: 0 0 var(--sp-2); color: var(--ds-success); }
.ok-grande .glifo { width: 40px; height: 40px; }

/* ── refluxo até 320px CSS (WCAG 2.1 SC 1.4.10) ────────────────────
   Nada de rolagem horizontal: o cartão perde a moldura e ocupa a largura.
   O celular é o caso COMUM de quem recebe um link, não o excêntrico. */
@media (max-width: 380px) {
  .palco { padding: var(--sp-2); }
  .cartao {
    padding: var(--sp-3);
    border-radius: var(--ds-radius-sm);
  }
  .topo { padding: var(--sp-2); }
}

/* ── alto contraste do sistema (DS-32) ─────────────────────────────
   O modo descarta `background-color`, `box-shadow` e `background-image` — e
   com eles some o anel de foco dual-tone deste contrato, mais todo estado
   marcado só por fundo. Aqui os dois voltam por BORDA, que sobrevive. */
@media (forced-colors: active) {
  :where(a, button, input, select, video):focus-visible {
    outline: 3px solid CanvasText;
    outline-offset: 2px;
  }
  .trilha li { border: 1px solid CanvasText; }
  .trilha li.on { background: Highlight; }
  .cartao, .alerta, .estado-espera { border: 1px solid CanvasText; }
}

/* ── quem pediu menos movimento ────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
  }
}

/* ══════════════════════════════════════════════════════════════════════
   A SALA — a sexta etapa, e a única que não é um formulário
   ══════════════════════════════════════════════════════════════════════ */

/* Texto que só o leitor de tela lê.
   NÃO é `display:none`: isso o tiraria da árvore de acessibilidade junto com
   os pixels, e o título da etapa sumiria para quem depende dele. A técnica é a
   de recorte, que mantém o nó legível e fora da tela. */
.so-leitor {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}

/* A etapa da sala OCUPA a altura, ao contrário das outras cinco.
   As de formulário são um cartão centrado; esta é um palco com barra no pé, e
   tratá-la como as outras deixaria a grade de vídeo com a altura do conteúdo —
   ou seja, colapsada quando ninguém publica vídeo ainda. */
/* ── A SALA É UM PALCO, e não um cartão de formulário ──────────────────
   Medido com QUATRO participantes em 2026-09-02: os ladrilhos empilhavam numa
   coluna só dentro dos 400px do cartão, a página passava a rolar, e **a barra
   de controles saía da tela**. Numa reunião de quatro pessoas ninguém
   alcançava o botão de silenciar sem rolar para baixo.

   Isso não é um defeito de espaçamento: é o palco herdando o layout de cinco
   telas que são formulários. As cinco querem um cartão estreito e centrado; a
   sexta quer largura, altura, e um rodapé que não vai embora.

   O `data-etapa` no conteúdo é o que separa as duas sem duplicar o casco. */
#conteudo[data-etapa="room"] {
  /* O palco OCUPA, e não se centra. `center` numa área que transborda empurra
     o topo para fora da tela — e aí nem rolar resolve, porque o começo do
     conteúdo fica acima do ponto zero. */
  justify-content: stretch;
  padding: var(--sp-3);
  /* `min-height: 0` NA CADEIA, e este era o elo que faltava.
     ───────────────────────────────────────────────────────────────────
     Um item de flex usa o tamanho do conteúdo como mínimo, então o palco
     crescia além da janela e a página voltava a rolar — levando a barra junto.

     Até 2026-09-02 isso não aparecia, e não porque estivesse certo: o teto de
     `34vh` no ladrilho limitava a altura POR ACIDENTE. Ao mover esse teto para
     o único caso que o justifica — a coluna única do celular —, o elo faltante
     ficou visível. *Uma restrição que segura o layout pelo motivo errado é uma
     que some no dia em que alguém a corrige.*

     É a mesma lição que o refluxo a 320px já tinha registrado neste arquivo,
     no outro eixo: basta UM ancestral sem ela para a cadeia inteira falhar. */
  min-height: 0;
}

/* A TRILHA não pertence à sala.
   Ela é da máquina de ENTRADA, onde há um próximo passo. Dentro da chamada não
   há — e ela ocupava a faixa superior dizendo ao participante que ele ainda
   está preenchendo um formulário. `display: none` e não `visibility`: o que não
   se aplica também não é lido, e um leitor de tela anunciando "etapa 6 de 6"
   numa reunião em curso é a mesma confusão em outro canal. */
#conteudo[data-etapa="room"] .trilha { display: none; }

#conteudo[data-etapa="room"] .cartao {
  max-width: var(--ds-content-max);
  /* `min-height: 0` num filho de flex é o que permite ele ENCOLHER e rolar por
     dentro. Sem essa linha o item de flex usa o tamanho do conteúdo como
     mínimo, a rolagem sobe para a página, e a barra vai junto. */
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding: var(--sp-3);
}

.etapa-sala {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  min-height: 0;
  flex: 1;
}

.sala-estado {
  margin: 0;
  font-size: var(--ds-fs-body-sm);
  color: var(--ds-text-2);
  min-height: 1.4em; /* reserva a linha: sem ela o conteúdo pula a cada troca */
}

/* A grade. `auto-fit` + `minmax` porque o número de participantes muda em
   tempo de execução, e uma contagem de colunas fixa em CSS obrigaria o JS a
   escrever estilo — que é a segunda fonte de verdade que sempre esquece. */
.grade-video {
  display: grid;
  /* As colunas saem da LARGURA, e o `data-n` só entra para poucas pessoas.
     ─────────────────────────────────────────────────────────────────────
     O `auto-fit` sozinho enche a linha: com quatro pessoas em 1280px ele faz
     quatro colunas de ~300px, e o resultado medido foi **34% da altura usada,
     533px vazios** e cada rosto em 284×160. A tela cabia; ninguém cabia nela.

     Quatro pessoas numa reunião querem 2×2, e não 1×4 — é o que dobra a
     largura de cada ladrilho sem mudar mais nada. A contagem vem num atributo
     (`data-n`), como a etapa vem em `data-etapa`: o JS DECLARA o que existe, e
     quem decide a aparência continua sendo o CSS. Escrever `style.gridTemplate`
     do JavaScript seria a segunda fonte de verdade que este arquivo evita. */
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  gap: var(--sp-2);
  align-content: start;
  /* QUEM ROLA é a grade, e não a página.
     Com a página rolando, a barra de controles some junto — e ela é o único
     lugar onde se corta o microfone. Aqui o excesso fica dentro da grade e a
     barra continua onde estava. */
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

/* A GRADE POR CONTAGEM, e só acima do degrau em que cabem duas colunas.
   Abaixo dele a coluna única é a resposta certa e o `auto-fit` já a dá. */
@media (min-width: 560px) {
  .grade-video[data-n="2"],
  .grade-video[data-n="3"],
  .grade-video[data-n="4"] { grid-template-columns: repeat(2, 1fr); }
  .grade-video[data-n="5"],
  .grade-video[data-n="6"],
  .grade-video[data-n="7"],
  .grade-video[data-n="8"],
  .grade-video[data-n="9"] { grid-template-columns: repeat(3, 1fr); }
}

.ladrilho {
  position: relative;
  aspect-ratio: 16 / 9;
  background: var(--ds-canvas);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-md);
  overflow: hidden;
}

.ladrilho video {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}

/* Quem está sem câmera vira INICIAL, e não um retângulo preto.
   Um preto sem nada é indistinguível de "o vídeo não carregou". */
.ladrilho-vazio {
  display: grid;
  place-items: center;
  height: 100%;
  font-size: var(--ds-fs-headline);
  font-weight: 600;
  color: var(--ds-on-fill);
  background: var(--ds-avatar-fallback);
}

/* O TETO DE ALTURA vale só onde ele foi pensado: a coluna única.
   ─────────────────────────────────────────────────────────────────────────
   Ele nasceu para o celular — lá a coluna tem a largura da tela, e 16/9 disso
   é um ladrilho por tela, com a pessoa rolando para ver quem fala. Aplicado
   também na mesa, ele fazia o oposto: espremia quatro rostos em 160px de
   altura numa janela de mil. *Uma medida certa aplicada fora do caso que a
   justificou vira o defeito que ela existia para evitar.* */
@media (max-width: 559px) {
  .ladrilho { max-height: 34vh; }
}

/* QUEM ESTÁ FALANDO, e a marca não é só cor.
   ─────────────────────────────────────────────────────────────────────────
   O anel APARECE — presença e ausência de contorno é diferença de forma, e não
   de matiz —, então quem não distingue as cores continua vendo a mudança. Uma
   borda que só troca de cor falharia com quatro ladrilhos iguais na tela.

   `outline` e não `border`: borda entraria na caixa e faria o ladrilho MUDAR DE
   TAMANHO a cada palavra, com a grade inteira reflowando em volta. O contorno
   desenha por fora e não desloca nada.

   E ele não anima. Um pulso a cada sílaba, com quatro pessoas conversando, é
   movimento constante na periferia da visão -- e quem pediu menos movimento
   pediu justamente isso. */
.ladrilho.falando {
  outline: 3px solid var(--ds-accent);
  outline-offset: -1px;
}

.ladrilho-nome {
  position: absolute;
  left: var(--sp-2); bottom: var(--sp-2);
  display: inline-flex; align-items: center; gap: 6px;
  max-width: calc(100% - var(--sp-3) * 2);
  padding: 2px 8px;
  border-radius: var(--ds-radius-sm);
  /* O chip é OPACO, e essa é a decisão desta regra.
     O que está atrás é VÍDEO — imprevisível por definição —, e o DS-28 diz que
     cor translúcida não se mede sem dizer sobre o que ela assenta. A família
     `--ds-overlay-*` chega a 12%, e `--ds-scrim` cai para 45% no tema escuro:
     nenhuma delas GARANTE contraste sobre um quadro qualquer.
     Opaco tira a dúvida — o par `canvas`/`text` é do contrato e é medível. */
  background: var(--ds-canvas);
  color: var(--ds-text);
  font-size: var(--ds-fs-caption);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* O aviso de identidade não verificada acompanha o nome (MEE-5.2). */
.ladrilho-nome .glifo { width: 12px; height: 12px; flex: none; }
.nao-verificado { color: var(--ds-warning); }

.ladrilho-mudo {
  position: absolute;
  right: var(--sp-2); top: var(--sp-2);
  display: grid; place-items: center;
  width: 24px; height: 24px;
  border-radius: 50%;
  /* Opaco pela mesma razão do chip de nome, e em `danger`: o microfone mudo é
     um estado que se procura na tela, e não um enfeite. */
  background: var(--ds-danger);
  color: var(--ds-on-danger);
}
.ladrilho-mudo .glifo { width: 14px; height: 14px; }

/* ── a barra ─────────────────────────────────────────────────────────── */
.barra-sala {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--sp-2);
  padding: var(--sp-2);
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-lg);
  /* GRUDADA no pé, e opaca.
     `sticky` e não `fixed`: `fixed` a tiraria do fluxo e ela cobriria o último
     ladrilho — e o último ladrilho é onde entra quem chegou por último.
     O fundo opaco é o que impede o vídeo de passar por baixo dela. */
  position: sticky;
  bottom: 0;
  flex: none;
  z-index: 1;
}

/* O botão de mídia tem TRÊS aparências e uma só classe base.
   `.on` é o único nome de estado ativo do ecossistema (B-4.27): um `.ativo`
   aqui e um `.on` ali é como dois arquivos passam a descrever o mesmo estado
   com nomes que ninguém consegue procurar de uma vez. */
.btn-midia {
  display: grid; place-items: center;
  width: 44px; height: 44px;
  border: 1px solid var(--ds-border);
  border-radius: 50%;
  background: var(--ds-surface);
  color: var(--ds-text);
  cursor: pointer;
}
.btn-midia:hover { background: var(--ds-hover); }
.btn-midia .glifo { width: 18px; height: 18px; }

/* Ligado é o estado NORMAL, e desligado é o que se destaca.
   O inverso — pintar o ligado — faria uma sala inteira de botões acesos, e o
   microfone mudo, que é o que importa ver, seria o discreto. */
.btn-midia[aria-pressed="false"] {
  background: var(--ds-danger-tint);
  border-color: var(--ds-danger);
  color: var(--ds-danger-text);
}

.btn-sair {
  background: var(--ds-danger);
  border-color: var(--ds-danger);
  color: var(--ds-on-danger);
}
.btn-sair:hover { background: var(--ds-danger); filter: brightness(.92); }

.sala-conta {
  margin: 0;
  text-align: center;
  font-size: var(--ds-fs-caption);
  color: var(--ds-text-3);
}

/* O alto contraste do sistema DESCARTA `background-color` (DS-32), e com ele
   todo estado marcado só por fundo. O botão mudo é exatamente esse caso. */
@media (forced-colors: active) {
  .btn-midia[aria-pressed="false"] { outline: 2px solid; outline-offset: 2px; }
  .ladrilho { border: 1px solid; }
}

/* ── o painel de ajustes DURANTE a chamada ─────────────────────────────
   Ele fica DEPOIS da barra no documento, e por isso não precisa de
   `tabindex`: a ordem de tabulação já sai do botão e cai dentro dele. */
.painel-disp {
  margin-top: var(--sp-2);
  padding: var(--sp-3);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-md);
  background: var(--ds-surface);
}

.painel-disp h2 {
  margin: 0 0 var(--sp-2);
  font-size: var(--ds-fs-label);
  letter-spacing: var(--ds-ls-label);
  text-transform: uppercase;
  color: var(--ds-text-2);
}

/* O botão de ajustes ABERTO se destaca, e por FUNDO e por moldura.
   Só o fundo sumiria no alto contraste do sistema (DS-32), e o painel ficaria
   aberto com o botão parecendo fechado. */
.btn-midia[aria-expanded="true"] {
  background: var(--ds-accent);
  border-color: var(--ds-accent);
  color: var(--ds-on-accent);
}

@media (forced-colors: active) {
  .btn-midia[aria-expanded="true"] { outline: 2px solid; outline-offset: 2px; }
}

/* ── [MEE-6.6] os números da conexão ─────────────────────────────────
   Lista de definição em duas colunas: termo à esquerda, valor à direita,
   com os valores alinhados por tabular-nums. Sem isso um "9 ms" e um
   "12 ms" desalinham e a coluna vira zigue-zague a cada leitura. */
.stats {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--sp-1) var(--sp-3);
  margin: 0 0 var(--sp-2);
  font-size: var(--ds-fs-body-sm);
}

.stats dt { color: var(--ds-text-2); }

.stats dd {
  margin: 0;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.stats-nota {
  margin: 0;
  font-size: var(--ds-fs-caption);
  color: var(--ds-text-3);
}

/* O PONTO DE QUALIDADE, no canto do ladrilho.
   ─────────────────────────────────────────────────────────────────────
   Ele não aparece quando a conexão está boa: um indicador que está sempre
   aceso não é indicador, é decoração — e quatro pontos verdes na tela
   ensinam a pessoa a não olhar para eles. Só o que precisa de atenção
   aparece.

   A cor não é a única pista: o valor vai no nome acessível do ladrilho. */
.ladrilho[data-q="poor"]::after,
.ladrilho[data-q="lost"]::after {
  content: "";
  position: absolute;
  top: var(--sp-2);
  right: var(--sp-2);
  width: 10px;
  height: 10px;
  border-radius: 50%;
  border: 2px solid var(--ds-surface);
}

.ladrilho[data-q="poor"]::after { background: var(--ds-warning); }
.ladrilho[data-q="lost"]::after { background: var(--ds-danger); }

/* ── [MEE-6.7] a faixa da degradação ─────────────────────────────────
   A QUARTA superfície de alerta da norma (B-4.30): a faixa persistente de
   condição da sessão. Ela não é um aviso passageiro -- a rede ruim dura, e
   um alerta que some deixa a pessoa vendo a própria câmera desligada sem
   saber por quê.

   A cor sobe com o degrau, e ela não é a única pista: o TEXTO diz o que
   aconteceu e o que fazer. Quem não distingue as cores lê a mesma coisa. */
.faixa-rede {
  margin: 0;
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--ds-radius-sm);
  font-size: var(--ds-fs-body-sm);
  background: color-mix(in srgb, var(--ds-info) 14%, transparent);
  color: var(--ds-text);
  border: 1px solid color-mix(in srgb, var(--ds-info) 40%, transparent);
}

.faixa-rede[data-degrau="1"],
.faixa-rede[data-degrau="2"] {
  background: color-mix(in srgb, var(--ds-warning) 14%, transparent);
  border-color: color-mix(in srgb, var(--ds-warning) 40%, transparent);
}

.faixa-rede[data-degrau="3"],
.faixa-rede[data-degrau="4"] {
  background: color-mix(in srgb, var(--ds-danger) 14%, transparent);
  border-color: color-mix(in srgb, var(--ds-danger) 40%, transparent);
}

/* ── [MEE-15.1] o chat da sala ───────────────────────────────────────
   Ele fica ENTRE a barra e a contagem, e não numa gaveta: numa reunião de
   quatro pessoas o chat é onde vai o link que alguém acabou de citar, e um
   painel que precisa ser aberto é um painel que ninguém abre.

   A lista tem altura própria e rola por dentro, pela mesma razão da grade:
   se ela crescer, quem sai da tela é a barra de controles. */
.chat {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  flex: none;
}

.chat-linhas {
  list-style: none;
  margin: 0;
  padding: var(--sp-2);
  max-height: 22vh;
  overflow-y: auto;
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-md);
  font-size: var(--ds-fs-body-sm);
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}

.chat-linha {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: var(--sp-2);
  align-items: baseline;
}

.chat-quem {
  font-weight: 600;
  color: var(--ds-text-2);
  max-width: 12ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A MINHA linha se distingue por PESO, e não só por cor: quem não distingue
   as cores continua vendo qual foi a sua. */
.chat-linha.minha .chat-quem { color: var(--ds-accent); }

/* `overflow-wrap` e não `word-break`: uma URL longa quebra onde couber sem
   partir palavras normais no meio. Sem isto, um link colado estica a linha e
   a página passa a rolar de lado. */
.chat-corpo { overflow-wrap: anywhere; }

.chat-hora {
  color: var(--ds-text-3);
  font-size: var(--ds-fs-micro);
  font-variant-numeric: tabular-nums;
}

.chat-form { display: flex; gap: var(--sp-2); }
.chat-form input { flex: 1; min-width: 0; }
