:root {
  /* App só tem tema escuro (sem alternância) — sem isto, as setas
     nativas dos campos type=number, entre outros controlos do próprio
     browser, vinham sempre no tema claro do sistema (fundo branco a
     destoar de tudo à volta, mesmo com o campo em si já escuro). */
  color-scheme: dark;
  /* As barras de deslocamento do próprio browser continuavam cinzentas ao
     lado de tudo o resto -- via-se sobretudo na barra horizontal por baixo
     dos separadores das listas. `color-scheme` já as escurece, mas o
     cinzento de sistema não é a nossa paleta. */
  scrollbar-color: var(--border-subtle) transparent;
  scrollbar-width: thin;
  /* O mesmo para caixas de seleção e botões de rádio: por omissão vinham
     no azul do sistema, alheio à marca do evento. */
  accent-color: var(--accent);
  --bg-page: #0e0b1a;
  --bg-sidebar: #100c1e;
  --bg-card: #16122a;
  --bg-card-alt: #1a1530;
  --border-subtle: #2a2440;
  --text-primary: #f2f0f8;
  --text-secondary: #9691b0;
  --text-muted: #6b6685;
  /* Cor da marca da plataforma -- o amarelo do selo do logotipo pass2
     (#FCB402, tirado do proprio ficheiro shared/pass2-logo.png). Isto e' so
     o valor por omissao: applyBranding()/applyEventBranding() reescrevem
     --accent em cada pagina, com a marca da plataforma ou a do evento. */
  --accent: #FCB402;
  --accent-text: #1a1530;
  /* Cores de estado. Ficam FORA da marca de proposito: a cor de destaque
     muda de evento para evento, estas nunca -- "aviso" e "perigo" tem de
     querer dizer sempre o mesmo em todo o lado. Com o amarelo da marca a
     ocupar o lugar que o ambar de aviso ocupava, o aviso desceu para
     laranja e o perigo afastou-se para um vermelho mais fechado, para os
     tres nao se confundirem (verificado com o validador de paletas:
     separacao suficiente tambem para daltonismo). Usar sempre com texto ao
     lado, nunca so' a cor. */
  --warn: #F97316;
  --danger: #E5484D;
  /* Verde de "escolhido/ligado". Fica FORA da marca, como as outras cores de
     estado: a cor de destaque muda de evento para evento, e uma escolha
     marcada tem de se ler como escolha em qualquer um deles. Com o amarelo
     da marca, uma caixa marcada parecia decoracao da marca e nao uma opcao
     que alguem ligou. */
  --ok: #4ADE80;
  /* Tipo de letra da marca (Super Admin ou evento, ver "Marca" em brand.html
     e o catálogo carregado em fonts.html) -- fica sempre com esta pilha de
     sistema como valor por omissão; escolher um tipo de letra carregado só
     troca esta variável (ver applyFontFamily em shared/branding.js), nunca
     esta declaração base. */
  --font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
}
* { box-sizing: border-box; }
body {
  margin: 0;
  font-family: var(--font-family);
  background: var(--bg-page);
  color: var(--text-primary);
}
a { color: inherit; }

/* Layout */
.app { display: grid; grid-template-columns: 220px minmax(0, 1fr); min-height: 100vh; }
.main { padding: 24px 28px 60px; min-width: 0; }
.main img, .main table, .main select, .main input, .main pre { max-width: 100%; }

/* Sidebar */
.sidebar {
  background: var(--bg-sidebar);
  border-right: 1px solid var(--border-subtle);
  padding: 20px 16px;
  display: flex;
  flex-direction: column;
}
.brand { display: flex; align-items: center; gap: 10px; padding: 0 4px 24px; text-decoration: none; }
.brand-logo {
  width: 34px; height: 34px; border-radius: 9px;
  background: var(--accent); color: var(--accent-text);
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 15px;
  overflow: hidden; flex-shrink: 0;
}
.brand-logo img { width: 100%; height: 100%; object-fit: cover; }
.brand-name { font-weight: 700; font-size: 17px; letter-spacing: -0.3px; }
/* "Só logótipo" (ver Marca/brand.html e a etapa "Imagem" em Criar/Gerir
   eventos) — o modificador é posto no próprio contentor (.brand,
   .guest-brand, e .mobile-topbar-brand mais abaixo) por applyBranding()/
   applyEventBranding() em shared/branding.js, só quando há mesmo logótipo
   carregado. Ocupa uma área bem maior que o quadrado do ícone de sempre —
   é para se notar — sem recortar a imagem (object-fit: contain, ao
   contrário do "cover" do ícone quadrado). */
.brand.brand-logo-only .brand-name,
.guest-brand.brand-logo-only .brand-name { display: none; }
.brand.brand-logo-only .brand-logo,
.guest-brand.brand-logo-only .brand-logo {
  width: auto; height: 44px; min-width: 0;
  background: none; border-radius: 0;
}
.brand.brand-logo-only .brand-logo img,
.guest-brand.brand-logo-only .brand-logo img { width: auto; height: 100%; object-fit: contain; }
.role-switcher { margin: 10px 4px 0; padding-top: 10px; border-top: 1px dashed var(--border-subtle); }
.role-switcher label { display: block; font-size: 9px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); font-weight: 600; margin-bottom: 4px; }
.role-switcher select {
  width: 100%; padding: 5px 20px 5px 6px; font-size: 11px;
  background: transparent; border: 1px solid var(--border-subtle); color: var(--text-muted);
  /* appearance:none -- sem isto, alguns Windows/navegadores pintam o
     proprio controlo (nao so' a lista de opcoes, essa nunca da' para
     estilizar) com o cinza/branco nativo do sistema por cima do que aqui
     se define, ficando "fora do tema" mesmo com fundo/cor certos. A seta
     deixa de vir do sistema operativo por isso desenha-se uma propria (o
     mesmo tom de --text-muted, escrito a mao porque um data-URI de SVG nao
     le' variaveis CSS). */
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%236b6685' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 7px center; background-size: 9px 6px;
}
/* A lista de opcoes ABERTA e sempre o proprio sistema operativo a desenhar
   -- nem o appearance:none acima chega la', so' cobre o controlo fechado --
   EXCETO o fundo/cor de cada <option>, que o Chrome/Edge/Firefox atuais ja'
   respeitam mesmo assim. Sem isto ficava sempre branco (tema claro do
   sistema) por baixo de texto escuro, ilegivel -- o "fora do tema" mais
   visivel dos dois seletores. */
.role-switcher select option { background: var(--bg-card); color: var(--text-primary); }

/* Toggle switch (ativar/desativar, rascunho/publicado, etc.) — texto à
   esquerda (ordem visual só, via `order`, mantendo input+track adjacentes
   no DOM para o seletor + funcionar) para os interruptores alinharem entre
   si mesmo com textos de larguras diferentes ("Ativo" vs "Desativado").
   Ligado = verde; desligado fica neutro (sem cor) — só o texto já diz qual
   é o estado, a cor do texto mantém-se normal em ambos. */
.toggle-switch { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; user-select: none; }
.toggle-switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.toggle-switch .track {
  width: 42px; height: 24px; border-radius: 999px; background: var(--border-subtle);
  position: relative; transition: background 0.15s; flex-shrink: 0;
}
.toggle-switch .track::after {
  content: ""; position: absolute; top: 2px; left: 2px; width: 20px; height: 20px;
  border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgba(0,0,0,0.35); transition: transform 0.15s;
}
.toggle-switch input:checked + .track { background: #4ADE80; }
.toggle-switch input:checked + .track::after { transform: translateX(18px); }
.toggle-switch input:focus-visible + .track { outline: 2px solid var(--accent); outline-offset: 2px; }
.toggle-switch .toggle-label { order: -1; font-size: 13px; font-weight: 700; }

/* =========================================================================
   O ASSISTENTE — a moldura, partilhada por todos
   =========================================================================
   Configurar um evento e configurar uma atividade são o mesmo gesto: cinco
   passos, guardar, sair. Chegaram a ter dois conjuntos de classes
   diferentes (.cfg-* num, .wizard-* no outro) e, como era de esperar,
   divergiram: o "Guardar e sair" mudava de aspeto de um para o outro, os
   botões de baixo estavam dentro da caixa num e fora no outro, e as etapas
   só eram clicáveis num deles. Quem usa tinha de reaprender o ecrã de cada
   vez.

   Está tudo aqui, com um nome só (.wiz-*). Um assistente novo herda a
   moldura inteira em vez de a inventar outra vez; o que cada um tem de
   próprio é o CONTEÚDO das etapas, não a moldura.

   A moldura, de cima para baixo:
     .wiz-topo          migalha + título à esquerda; estado, "guardado" e
                        "Guardar e sair" à direita — sempre nesta ordem
     .wiz-passos        as cinco etapas, numa caixa, TODAS clicáveis até
                        onde já se chegou
     .wiz-passos-mini   o mesmo em ecrã estreito: "Passo X de 5" + nome +
                        cinco marcadores
     .wiz-cartao        a caixa do conteúdo da etapa
     .wiz-nav           Voltar / Guardar / Seguinte — DENTRO da caixa, ao
                        fundo, com um traço a separar
     .wiz-nav-movel     a mesma navegação, fixa em baixo no telemóvel      */

/* O cabeçalho do assistente é o mesmo cabeçalho das outras páginas: os
   tamanhos de letra vêm de .page-header (ver lá em cima), aqui fica só o
   que é próprio do assistente. */
.wiz-topo { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-bottom: 24px; }
/* As ações do cabeçalho ficam sempre à direita e sempre por esta ordem:
   estado, "guardado", e por fim o botão que grava e sai. */
.wiz-topo-accoes { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

.wiz-selo { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 700; padding: 5px 12px; border-radius: 999px; border: 1px solid var(--border-subtle); color: var(--text-muted); }
.wiz-selo .ponto { width: 8px; height: 8px; border-radius: 50%; background: currentColor; }
.wiz-selo.rascunho { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 45%, transparent); }
.wiz-selo.publicado, .wiz-selo.ativa { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 45%, transparent); }
.wiz-selo.alterado { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, transparent); }
.wiz-selo.inativa { color: var(--text-muted); border-color: var(--border-subtle); }

.wiz-gravado { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-muted); }
.wiz-gravado.ok { color: var(--ok); }
.wiz-gravado.erro { color: var(--danger); }
.wiz-gravado svg { flex-shrink: 0; }

/* Envolve quando não cabe. Sem isto a barra transbordava para fora da
   caixa em silêncio: no editor de ecrãs, que tem SEIS etapas com nomes
   compridos, entre os 1080px (onde a versão mini toma conta) e os ~1300px
   a última etapa -- "Publicar", precisamente a que interessa -- ficava
   cortada pela borda. Não dava erro nem barra de deslocamento: o passo
   simplesmente não estava lá. */
.wiz-passos { display: flex; align-items: center; gap: 0; flex-wrap: wrap; row-gap: 14px; background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 14px; padding: 16px 20px; margin-bottom: 20px; }
.wiz-passos .passo-de { font-size: 12px; font-weight: 700; color: var(--text-muted); margin-right: 18px; white-space: nowrap; }
.wiz-passo { display: flex; align-items: center; gap: 9px; background: none; border: 0; padding: 0; font: inherit; color: inherit; cursor: default; }
.wiz-passo[data-clicavel="1"] { cursor: pointer; }
.wiz-passo .num { width: 30px; height: 30px; border-radius: 50%; border: 1.5px solid var(--border-subtle); color: var(--text-muted); display: inline-flex; align-items: center; justify-content: center; font-size: 13px; font-weight: 700; flex-shrink: 0; }
.wiz-passo .nome { font-size: 13px; font-weight: 700; color: var(--text-muted); white-space: nowrap; }
.wiz-passo.is-atual .num { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }
.wiz-passo.is-atual .nome { color: var(--text-primary); }
.wiz-passo.is-feito .num { background: color-mix(in srgb, var(--ok) 18%, transparent); border-color: var(--ok); color: var(--ok); }
.wiz-passo.is-feito .nome { color: var(--text-secondary); }
/* Uma etapa a que falta configuração obrigatória diz-se com um ! e a cor
   do aviso -- é o que faz olhar para ela sem ter de abrir cada uma. */
.wiz-passo.tem-falta .num { border-color: var(--warn); color: var(--warn); background: color-mix(in srgb, var(--warn) 14%, transparent); }
.wiz-passo:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 8px; }
/* O traço entre etapas cresce para as espalhar pela caixa, mas com um
   tecto: numa barra que envolveu, um traço sem tecto ficava sozinho a
   atravessar a linha toda antes da última etapa, com ar de engano. */
.wiz-passo-linha { flex: 1 1 14px; max-width: 110px; height: 2px; background: var(--border-subtle); margin: 0 12px; min-width: 14px; border-radius: 2px; }
.wiz-passo-linha.is-feito { background: var(--ok); }
.wiz-passos-mini { display: none; }

.wiz-cartao { background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 16px; padding: 22px; margin-bottom: 16px; }

.wiz-nav { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 24px; padding-top: 20px; border-top: 1px solid var(--border-subtle); }
.wiz-nav .direita { margin-left: auto; display: flex; gap: 10px; flex-wrap: wrap; }
/* Um link com aspeto de botão é um botão: nunca sublinhado. Isto vivia
   espalhado por regras locais de cada página, e por isso havia botões
   sublinhados ao lado de botões que não o eram. */
a.btn-ghost, a.btn-accent, a.btn-pill { text-decoration: none; }
.wiz-nav-movel { display: none; }

/* =========================================================================
   AS COMPETIÇÕES
   =========================================================================
   Um bloco à parte, com nomes `.cm-`, e tudo o que aqui está vive DENTRO
   de `.cm` -- a área de Competições e mais nada. É de propósito: a cor de
   acção desta área é o VERDE, e o resto da casa continua com o âmbar. Sem
   o âmbito, mudar uma linha aqui repintava as Inscrições.

   O verde já existia no tema (--ok, a cor do "concluído"). O que muda é o
   papel que ele faz aqui: acção principal, selecção e conclusão. O âmbar
   fica para os avisos, o vermelho para os erros e para apagar, e o violeta
   para a estrutura -- que é o que os cartões e as caixas já são.

   Nada aqui inventa um botão novo: `.cm-accao` é um `.btn-accent` pintado
   de outra cor, com a mesma altura e o mesmo raio. Um botão desta área ao
   lado de um botão de outra tem de parecer o mesmo botão. */

.cm { --cm-verde: var(--ok); --cm-verde-texto: #0b2a16; }

/* O caminho de volta. Um link com aspeto de link e não de botão -- mas sem
   sublinhado, que num cabeçalho se lê como um erro de estilo. */
.cm .cm-voltar { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px;
                 color: var(--text-secondary); text-decoration: none; margin-bottom: 6px; }
.cm .cm-voltar:hover { color: var(--text-primary); }

/* A acção principal. Herda tudo de .btn-accent -- só troca a cor. */
.cm .cm-accao { background: var(--cm-verde); color: var(--cm-verde-texto); }
.cm .cm-accao:hover:not(:disabled) { filter: brightness(1.06); }
/* Um contorno verde para a acção secundária que ainda é uma acção
   (o "Controlar" de uma competição a decorrer, quando já há um principal). */
.cm .cm-accao-leve { border-color: color-mix(in srgb, var(--cm-verde) 55%, transparent); color: var(--cm-verde); }

/* -------------------------------------------------------------------------
   Os cartões de números
   -------------------------------------------------------------------------
   O `.kpi-box` da casa é uma caixa só com divisórias. Aqui são cartões
   separados, porque o número de cartões MUDA: "com problemas" e
   "terminadas" só aparecem quando existem, e numa caixa única isso deixava
   buracos. */
.cm-numeros { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; margin-bottom: 20px; }
.cm-numero { display: flex; align-items: center; gap: 12px; background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 14px; padding: 16px 18px; }
.cm-numero .icone { display: flex; align-items: center; justify-content: center; width: 38px; height: 38px; border-radius: 11px; background: var(--bg-card-alt); color: var(--text-secondary); flex-shrink: 0; }
.cm-numero .icone svg { width: 19px; height: 19px; }
.cm-numero .valor { font-size: 22px; font-weight: 700; line-height: 1.15; }
.cm-numero .rotulo { font-size: 12px; color: var(--text-muted); margin-top: 1px; }
.cm-numero.is-bom .icone { background: color-mix(in srgb, var(--cm-verde) 16%, transparent); color: var(--cm-verde); }
.cm-numero.is-aviso .icone { background: color-mix(in srgb, var(--warn) 16%, transparent); color: var(--warn); }
.cm-numero.is-erro .icone { background: color-mix(in srgb, var(--danger) 16%, transparent); color: var(--danger); }
.cm-numero.is-erro .valor { color: var(--danger); }

/* -------------------------------------------------------------------------
   Os filtros
   ------------------------------------------------------------------------- */
/* Largura automática: com quatro caixas de 140px fixos, a linha partia-se
   em duas num portátil normal e ficava com um degrau no meio. */

/* -------------------------------------------------------------------------
   A lista
   ------------------------------------------------------------------------- */
.cm-lista { display: flex; flex-direction: column; }
/* A linha da lista.
   Envolve (`flex-wrap`) só no telemóvel. No ecrã largo NÃO envolve, e é de
   propósito: com envolvimento, cada linha partia num sítio diferente
   conforme o que tinha dentro -- uma com as ações à direita, a seguinte com
   as ações numa segunda linha -- e a lista lia-se como se estivesse
   desalinhada. Quem varre uma lista de cima a baixo procura a mesma coisa
   sempre no mesmo sítio. */
.cm-linha { display: flex; align-items: center; gap: 16px; padding: 16px 4px; border-top: 1px solid var(--border-subtle); flex-wrap: nowrap; }
.cm-linha:first-child { border-top: 0; }
.cm-emblema { display: flex; align-items: center; justify-content: center; width: 46px; height: 46px; border-radius: 13px; background: var(--bg-card-alt); border: 1px solid var(--border-subtle); color: var(--text-secondary); flex-shrink: 0; }
.cm-emblema svg { width: 22px; height: 22px; }
/* A identidade é a que cede espaço quando ele falta: o nome corta-se antes
   de o estado ou o botão saírem do sítio. */
.cm-identidade { flex: 1 1 210px; min-width: 0; }
/* Só o NOME se corta. O subtítulo e o aviso envolvem para uma segunda
   linha -- cortá-los escondia o formato da competição ("Mangas por
   eliminatória" virava "Mangas ...") e metade do que falta fazer, que é
   exactamente o que se vem aqui ler. Uma linha mais alta é melhor do que
   uma linha que mente. */
.cm-identidade .nome { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cm-identidade .nome { font-size: 15px; font-weight: 700; }
.cm-identidade .sob { font-size: 12.5px; color: var(--text-secondary); margin-top: 3px; }
.cm-identidade .quando { font-size: 12.5px; color: var(--text-muted); margin-top: 5px; display: flex; align-items: center; gap: 6px; }
.cm-identidade .quando svg { width: 13px; height: 13px; }
.cm-meio { display: flex; flex-direction: column; gap: 6px; flex: 0 0 auto; }
.cm-etiquetas { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.cm-contagens { font-size: 12px; color: var(--text-muted); }
.cm-accoes { display: flex; align-items: center; gap: 8px; margin-left: auto; flex-wrap: nowrap; flex-shrink: 0; }

/* O progresso. A barra é fina de propósito: é informação de relance, não o
   assunto da linha. */
.cm-progresso { flex: 0 1 200px; min-width: 120px; }
.cm-progresso .frase { font-size: 12.5px; color: var(--text-secondary); margin-bottom: 7px; }
.cm-barra { height: 6px; border-radius: 99px; background: var(--bg-card-alt); overflow: hidden; }
.cm-barra > i { display: block; height: 100%; background: var(--cm-verde); border-radius: 99px; }

/* Os selos de estado. Um por estado, e a cor diz a gravidade -- não a
   simpatia. */
.cm-selo { display: inline-flex; align-items: center; gap: 7px; font-size: 11.5px; font-weight: 700; padding: 5px 11px; border-radius: 999px; white-space: nowrap; }
.cm-selo .ponto { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex-shrink: 0; }
.cm-selo.tom-bom { background: color-mix(in srgb, var(--cm-verde) 15%, transparent); color: var(--cm-verde); }
.cm-selo.tom-info { background: color-mix(in srgb, var(--text-secondary) 15%, transparent); color: var(--text-secondary); }
.cm-selo.tom-neutro { background: var(--bg-card-alt); color: var(--text-muted); }
.cm-selo.tom-aviso { background: color-mix(in srgb, var(--warn) 15%, transparent); color: var(--warn); }
.cm-selo.tom-erro { background: color-mix(in srgb, var(--danger) 15%, transparent); color: var(--danger); }

.cm-falta { display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--warn); flex: 0 1 auto; min-width: 0; }
/* O aviso alinha pelo topo quando envolve: o triângulo fica ao pé da
   primeira linha do texto, e não a meio das duas. */
.cm-linha > .cm-falta { align-items: flex-start; }
.cm-linha > .cm-falta svg { margin-top: 2px; }
.cm-falta svg { width: 15px; height: 15px; flex-shrink: 0; }

/* -------------------------------------------------------------------------
   O menu dos três pontos
   -------------------------------------------------------------------------
   Aberto por clique e fechado por clique fora, por Escape, ou por rolar --
   um menu que fica pendurado a meio de uma página que rolou é a coisa que
   faz alguém carregar no item errado. */
.cm-menu-wrap { position: relative; }
.cm-menu-botao { width: 38px; padding: 9px 0; }
.cm-menu {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 40; min-width: 210px;
  background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 12px;
  padding: 6px; box-shadow: 0 18px 40px rgba(0, 0, 0, .45);
}
.cm-menu[hidden] { display: none !important; }
.cm-menu button {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  background: transparent; border: 0; border-radius: 8px; padding: 9px 10px;
  font: inherit; font-size: 13px; color: var(--text-primary); cursor: pointer;
}
.cm-menu button:hover:not(:disabled) { background: var(--bg-card-alt); }
.cm-menu button:disabled { opacity: .4; cursor: not-allowed; }
.cm-menu button svg { width: 16px; height: 16px; color: var(--text-secondary); flex-shrink: 0; }
.cm-menu .risco { height: 1px; background: var(--border-subtle); margin: 6px 4px; }
/* A vermelho, e em último. Uma acção destrutiva encostada às outras é a
   que se carrega por engano. */
.cm-menu button.perigo, .cm-menu button.perigo svg { color: var(--danger); }
.cm-menu button.perigo:hover { background: color-mix(in srgb, var(--danger) 12%, transparent); }

/* -------------------------------------------------------------------------
   O vazio
   ------------------------------------------------------------------------- */
.cm-vazio { text-align: center; padding: 46px 20px; }
.cm-vazio .icone { display: inline-flex; align-items: center; justify-content: center; width: 54px; height: 54px; border-radius: 16px; background: var(--bg-card-alt); color: var(--text-muted); margin-bottom: 16px; }
.cm-vazio .icone svg { width: 26px; height: 26px; }
.cm-vazio h3 { font-size: 16px; margin: 0 0 6px; }
.cm-vazio p { font-size: 13px; color: var(--text-muted); margin: 0 auto 20px; max-width: 420px; line-height: 1.6; }

/* -------------------------------------------------------------------------
   Telemóvel
   -------------------------------------------------------------------------
   A LISTA tem de funcionar no telemóvel de quem está no recinto -- é o
   assistente que pede um ecrã grande, não isto. Uma coluna, os números a
   dois, e as acções em baixo à largura toda. */
@media (max-width: 860px) {
  .cm-numeros { grid-template-columns: repeat(2, 1fr); gap: 10px; }
  .cm-numero { padding: 13px 14px; }
  .cm-numero .valor { font-size: 19px; }
  .cm-linha { align-items: flex-start; gap: 12px; }
  .cm-progresso { flex: 1 1 100%; }
  .cm-accoes { margin-left: 0; flex: 1 1 100%; }
  .cm-accoes .btn-accent, .cm-accoes .btn-ghost, .cm-accoes .cm-accao { flex: 1; }
  .cm-accoes .cm-menu-botao { flex: 0 0 38px; }
}

/* -------------------------------------------------------------------------
   O ASSISTENTE DA COMPETIÇÃO
   -------------------------------------------------------------------------
   Duas colunas: à esquerda o que se decide, à direita o que essa decisão
   PRODUZ. É a ideia que manda na área inteira -- primeiro configura-se,
   depois o sistema calcula -- posta no ecrã em vez de explicada.

   Num ecrã pequeno as duas colunas passam a uma, com a da direita em baixo:
   é consequência, e lê-se depois. */
.cm-duas { display: grid; grid-template-columns: minmax(0, 1fr) 380px; gap: 16px; align-items: start; }
.cm-lado { position: sticky; top: 16px; }

.cm-caixa { background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 16px; padding: 20px; }
.cm-caixa + .cm-caixa { margin-top: 14px; }
.cm-caixa > h2 { font-size: 16px; margin: 0 0 4px; }
.cm-caixa > .sub { font-size: 13px; color: var(--text-muted); margin: 0 0 16px; line-height: 1.55; }

/* Os cartões de formato. Com as sessões à vista, e não só o nome:
   escolher "Mangas por eliminatória" por um nome numa lista é como se
   descobre no dia que não era aquilo que se pensava. */
.cm-formatos { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 10px; }
.cm-formato {
  position: relative; display: flex; gap: 12px; text-align: left; font: inherit; cursor: pointer;
  background: var(--bg-card-alt); color: inherit;
  border: 1px solid var(--border-subtle); border-radius: 14px; padding: 14px;
}
.cm-formato:hover { border-color: color-mix(in srgb, var(--cm-verde) 45%, transparent); }
.cm-formato[aria-pressed="true"] { border-color: var(--cm-verde); background: color-mix(in srgb, var(--cm-verde) 7%, var(--bg-card-alt)); }
.cm-formato .icone { color: var(--text-secondary); flex-shrink: 0; margin-top: 1px; }
.cm-formato[aria-pressed="true"] .icone { color: var(--cm-verde); }
.cm-formato .t { font-size: 13.5px; font-weight: 700; padding-right: 22px; }
.cm-formato .d { font-size: 12px; color: var(--text-secondary); margin-top: 4px; line-height: 1.5; }
.cm-formato .s { font-size: 11.5px; color: var(--text-muted); margin-top: 7px; }
.cm-formato .visto { position: absolute; top: 12px; right: 12px; color: var(--cm-verde); display: none; }
.cm-formato[aria-pressed="true"] .visto { display: block; }

/* O painel do lado: uma linha por coisa que a escolha produz. */
.cm-produz { display: flex; flex-direction: column; gap: 12px; }
.cm-produz-linha { display: flex; align-items: center; gap: 12px; }
.cm-produz-linha .icone { display: flex; align-items: center; justify-content: center; width: 36px; height: 36px; border-radius: 11px; background: var(--bg-card-alt); color: var(--text-secondary); flex-shrink: 0; }
.cm-produz-linha .rotulo { font-size: 11.5px; color: var(--text-muted); }
.cm-produz-linha .valor { font-size: 13.5px; font-weight: 700; margin-top: 1px; }
.cm-produz-linha.em-falta .valor { color: var(--warn); font-weight: 600; }

/* A nota do fim: nada é definitivo até publicar. */
.cm-nota { display: flex; gap: 10px; align-items: flex-start; font-size: 12.5px; color: var(--text-secondary);
           background: var(--bg-card-alt); border: 1px solid var(--border-subtle); border-radius: 12px; padding: 12px 14px; line-height: 1.55; }
.cm-nota svg { flex-shrink: 0; margin-top: 1px; color: var(--text-muted); }

/* -------------------------------------------------------------------------
   Os cartões de sessão
   ------------------------------------------------------------------------- */
.cm-sessao { border: 1px solid var(--border-subtle); border-radius: 14px; background: var(--bg-card-alt); margin-top: 12px; overflow: hidden; }
.cm-sessao.tem-erro { border-color: color-mix(in srgb, var(--danger) 45%, transparent); }
.cm-sessao-topo { display: flex; align-items: center; gap: 10px; padding: 13px 14px; flex-wrap: wrap; }
.cm-sessao-topo .pega { color: var(--text-muted); cursor: grab; display: flex; }
.cm-sessao-topo .titulo { font-size: 14.5px; font-weight: 700; flex: 1 1 auto; min-width: 0; }
.cm-sessao-topo .titulo .n { color: var(--text-muted); font-weight: 600; }
.cm-sessao-botoes { display: flex; gap: 6px; align-items: center; }
.cm-sessao-botoes .btn-ghost { min-height: 30px; padding: 4px 9px; }
.cm-sessao-corpo { padding: 0 14px 14px; }
.cm-sessao.fechada .cm-sessao-corpo { display: none; }

/* As regras avançadas, recolhidas. Todas abertas ao mesmo tempo é um
   formulário de três ecrãs onde a duração -- que é o que quase sempre falta
   -- fica perdida lá no meio. */
.cm-regra { display: flex; align-items: center; gap: 10px; border-top: 1px solid var(--border-subtle); padding: 11px 2px; }
.cm-regra .icone { color: var(--text-muted); display: flex; flex-shrink: 0; }
.cm-regra .nome { font-size: 13px; font-weight: 700; }
.cm-regra .resumo { font-size: 12.5px; color: var(--text-muted); flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cm-regra .btn-ghost { min-height: 30px; padding: 4px 10px; font-size: 12.5px; }
.cm-regra-aberta { border-top: 1px solid var(--border-subtle); padding: 12px 2px; }

/* -------------------------------------------------------------------------
   O impacto no horário
   ------------------------------------------------------------------------- */
.cm-impacto-grelha { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin-bottom: 16px; }
.cm-impacto-item { display: flex; align-items: center; gap: 10px; background: var(--bg-card-alt); border: 1px solid var(--border-subtle); border-radius: 12px; padding: 11px 12px; }
.cm-impacto-item .icone { color: var(--text-secondary); display: flex; flex-shrink: 0; }
.cm-impacto-item .valor { font-size: 15px; font-weight: 700; line-height: 1.2; }
.cm-impacto-item .rotulo { font-size: 11px; color: var(--text-muted); }

/* A linha do tempo. Um ponto por bloco, ligados por um fio -- e o fio
   acaba onde o horário deixa de ser calculável. */
.cm-tempo { display: flex; flex-direction: column; }
.cm-tempo-bloco { display: grid; grid-template-columns: 56px 14px 1fr; gap: 10px; align-items: stretch; }
.cm-tempo-hora { font-size: 12.5px; color: var(--cm-verde); font-weight: 700; padding-top: 12px; text-align: right; }
.cm-tempo-bloco.is-pausa .cm-tempo-hora { color: var(--text-muted); }
.cm-tempo-fio { position: relative; display: flex; justify-content: center; }
.cm-tempo-fio::before { content: ""; position: absolute; top: 0; bottom: 0; width: 2px; background: var(--border-subtle); }
.cm-tempo-bloco:first-child .cm-tempo-fio::before { top: 16px; }
.cm-tempo-bloco:last-child .cm-tempo-fio::before { bottom: calc(100% - 16px); }
.cm-tempo-ponto { position: relative; width: 9px; height: 9px; border-radius: 50%; background: var(--cm-verde); margin-top: 15px; }
.cm-tempo-bloco.is-pausa .cm-tempo-ponto { background: var(--text-muted); }
.cm-tempo-cartao { background: var(--bg-card-alt); border: 1px solid var(--border-subtle); border-radius: 11px; padding: 10px 12px; margin-bottom: 8px; }
.cm-tempo-bloco:not(.is-pausa) .cm-tempo-cartao { border-color: color-mix(in srgb, var(--cm-verde) 35%, transparent); }
.cm-tempo-cartao .nome { font-size: 13px; font-weight: 700; }
.cm-tempo-cartao .nota { font-size: 12px; color: var(--text-muted); margin-top: 2px; }

/* O aviso de margem. Âmbar, e nunca com o mesmo desenho de um erro:
   desenhados iguais, quem monta aprende a ignorar os dois. */
.cm-recomenda { display: flex; gap: 11px; align-items: flex-start; border-radius: 14px; padding: 13px 15px; margin-top: 14px;
                background: color-mix(in srgb, var(--warn) 10%, transparent); border: 1px solid color-mix(in srgb, var(--warn) 35%, transparent); }
.cm-recomenda svg { color: var(--warn); flex-shrink: 0; margin-top: 1px; }
.cm-recomenda .titulo { font-size: 13px; font-weight: 700; color: var(--warn); }
.cm-recomenda p { font-size: 12.5px; color: var(--text-secondary); margin: 3px 0 0; line-height: 1.55; }

/* Os erros: vermelho, e com o desenho DIFERENTE. */
.cm-impede { display: flex; gap: 11px; align-items: flex-start; border-radius: 14px; padding: 13px 15px; margin-bottom: 14px;
             background: color-mix(in srgb, var(--danger) 10%, transparent); border: 1px solid color-mix(in srgb, var(--danger) 40%, transparent); }
.cm-impede svg { color: var(--danger); flex-shrink: 0; margin-top: 1px; }
.cm-impede .titulo { font-size: 13px; font-weight: 700; color: var(--danger); }
.cm-impede ul { margin: 6px 0 0; padding-left: 18px; font-size: 12.5px; color: var(--text-secondary); line-height: 1.7; }

/* -------------------------------------------------------------------------
   O HORÁRIO, bloco a bloco
   -------------------------------------------------------------------------
   Uma lista de blocos e não uma tabela: cada linha tem uma hora que se
   escreve, um problema que se lê e três acções, e isso numa célula de
   tabela fica apertado a partir do primeiro conflito. */
.cm-blocos { display: flex; flex-direction: column; gap: 8px; margin-top: 14px; }
.cm-bloco { display: flex; align-items: flex-start; gap: 14px; padding: 12px 14px; flex-wrap: wrap;
            background: var(--bg-card-alt); border: 1px solid var(--border-subtle); border-radius: 13px; }
.cm-bloco.is-pausa { background: transparent; border-style: dashed; }
.cm-bloco.tem-erro { border-color: color-mix(in srgb, var(--danger) 45%, transparent); }
.cm-bloco.tem-aviso { border-color: color-mix(in srgb, var(--warn) 40%, transparent); }
.cm-bloco-hora { display: flex; flex-direction: column; gap: 3px; flex-shrink: 0; }
/* Largura suficiente para o relógio de 12 horas com AM/PM: o campo de
   hora do browser fala a língua do sistema, e num sistema em inglês
   "01:00 PM" não cabe em 104px -- aparecia cortado. */
.cm-bloco-hora input[type="time"] { width: 128px; }
.cm-bloco-hora .dia { font-size: 11px; color: var(--text-muted); text-align: center; }
.cm-bloco-texto { flex: 1 1 220px; min-width: 0; padding-top: 4px; }
.cm-bloco-texto .nome { font-size: 13.5px; font-weight: 700; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.cm-bloco-texto .nome .n { color: var(--text-muted); font-weight: 600; }
.cm-bloco-texto .nota { font-size: 12px; color: var(--text-muted); margin-top: 3px; }
.cm-travada { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; font-weight: 600; color: var(--text-secondary); }
.cm-bloco-accoes { display: flex; gap: 6px; align-items: center; margin-left: auto; flex-wrap: wrap; }
.cm-bloco-accoes .btn-ghost { min-height: 32px; padding: 5px 10px; font-size: 12.5px; }
.cm-bloco-accoes [aria-pressed="true"] { border-color: color-mix(in srgb, var(--cm-verde) 55%, transparent); }

/* O problema dentro do bloco a que ele pertence -- e não numa lista à
   parte que obriga a procurar qual é a linha. */
.cm-bloco-problema { display: flex; gap: 8px; align-items: flex-start; font-size: 12px; line-height: 1.5; margin-top: 7px; }
.cm-bloco-problema strong { font-weight: 700; }
.cm-bloco-problema.erro { color: var(--danger); }
.cm-bloco-problema.erro span { color: var(--text-secondary); }
.cm-bloco-problema.erro strong { color: var(--danger); }
.cm-bloco-problema.aviso { color: var(--warn); }
.cm-bloco-problema.aviso span { color: var(--text-secondary); }
.cm-bloco-problema.aviso strong { color: var(--warn); }
/* O botão que RESOLVE o conflito, dentro da frase que o descreve. Um
   problema explicado sem um sítio onde carregar obriga quem o lê a
   descobrir qual das linhas é que tem o botão certo. */
.cm-resolver { background: transparent; border: 1px solid currentColor; border-radius: 7px;
               padding: 1px 8px; font: inherit; font-size: 11.5px; font-weight: 700;
               color: inherit; cursor: pointer; margin-left: 4px; }
.cm-resolver:hover { background: color-mix(in srgb, currentColor 12%, transparent); }

/* -------------------------------------------------------------------------
   O QUADRO DO DIA
   -------------------------------------------------------------------------
   Esta parte é lida DE PÉ, num tablet, com gente à espera. Daí o tamanho:
   o que está na pista ocupa o topo inteiro e o botão que interessa é o
   maior da página. Num ecrã de recinto, o que se procura tem de se
   encontrar sem aproximar a cara. */
.cm-agora { display: flex; align-items: center; gap: 20px; flex-wrap: wrap;
            background: var(--bg-card); border: 1px solid var(--border-subtle);
            border-radius: 18px; padding: 22px 24px; margin-bottom: 14px; }
/* A prova QUE ESTÁ NA PISTA leva a cor de acção -- é a única coisa do ecrã
   que está a acontecer agora. */
.cm-agora.na-pista { border-color: var(--cm-verde); background: color-mix(in srgb, var(--cm-verde) 6%, var(--bg-card)); }
.cm-agora.acabou { opacity: .85; }
.cm-agora-texto { flex: 1 1 260px; min-width: 0; }
.cm-agora-texto .rotulo { font-size: 11px; letter-spacing: .09em; text-transform: uppercase;
                          color: var(--text-muted); font-weight: 700; }
.cm-agora.na-pista .cm-agora-texto .rotulo { color: var(--cm-verde); }
.cm-agora-texto .nome { font-size: 28px; font-weight: 700; line-height: 1.15; margin-top: 4px; }
.cm-agora-texto .nota { font-size: 13px; color: var(--text-secondary); margin-top: 6px; }
.cm-agora-atraso { display: inline-flex; align-items: center; gap: 7px; font-size: 13px; font-weight: 700; margin-top: 10px; }
.cm-agora-atraso.tom-bom { color: var(--cm-verde); }
.cm-agora-atraso.tom-aviso { color: var(--warn); }
.cm-agora-atraso.tom-info, .cm-agora-atraso.tom-neutro { color: var(--text-secondary); }
.cm-agora-accoes { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
/* O botão grande. É o único do sistema com esta medida, e é de propósito:
   é o que se carrega com o polegar, de pé, sem olhar duas vezes. */
.cm .cm-grande { min-height: 58px; padding: 0 28px; font-size: 16px; border-radius: 14px; }
.cm-agora-porque { font-size: 12.5px; color: var(--warn); margin: -6px 0 14px; }

/* A grelha: uma caixa por simulador. */
.cm-grelha { background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 16px; padding: 18px 20px; margin-bottom: 20px; }
.cm-grelha-topo { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
.cm-grelha-topo h3 { display: flex; align-items: center; gap: 8px; font-size: 14px; margin: 0; }
.cm-lugares { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 10px; }
.cm-lugar { background: var(--bg-card-alt); border: 1px solid var(--border-subtle); border-radius: 13px; padding: 13px 14px; }
.cm-lugar.ocupado { border-color: color-mix(in srgb, var(--cm-verde) 40%, transparent); }
.cm-lugar .maquina { display: flex; align-items: center; gap: 6px; font-size: 11px; text-transform: uppercase;
                     letter-spacing: .06em; color: var(--text-muted); font-weight: 700; }
.cm-lugar .piloto { font-size: 15px; font-weight: 700; margin-top: 6px; }
.cm-lugar:not(.ocupado) .piloto { color: var(--text-muted); font-weight: 600; }
.cm-lugar .posicao { font-size: 11.5px; color: var(--text-muted); margin-top: 2px; }

/* No quadro do dia a hora não se edita -- lê-se. */
.cm-bloco-hora .so-hora { font-size: 15px; font-weight: 700; display: block; width: 62px; }
.cm-bloco.e-agora { border-color: var(--cm-verde); }
.cm-bloco.e-seguinte { border-color: color-mix(in srgb, var(--cm-verde) 30%, transparent); }

/* O livro do dia. */
.cm-livro { display: flex; flex-direction: column; }
.cm-livro-linha { display: flex; gap: 12px; padding: 9px 0; border-top: 1px solid var(--border-subtle); font-size: 12.5px; }
.cm-livro-linha:first-child { border-top: 0; }
.cm-livro-linha .quando { color: var(--text-muted); flex-shrink: 0; font-variant-numeric: tabular-nums; }
.cm-livro-linha .texto { color: var(--text-secondary); line-height: 1.5; }
.cm-livro-linha .quem { color: var(--text-muted); }
.cm-livro-linha .quem::before { content: "— "; }

/* As ordens do servidor de jogo. Uma grelha e não uma linha: são até
   sete botões, e numa linha só ficavam com quatro letras cada um. */
.cm-ordens { display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap: 7px; margin-top: 14px; }
.cm-ordens .btn-ghost { min-height: 36px; padding: 6px 10px; font-size: 12.5px; }

/* Escolher quem corre. */
.cm-escolha-lista { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 6px;
                    max-height: 44vh; overflow-y: auto; margin: 14px 0; }
.cm-escolha-piloto { display: flex; align-items: center; gap: 10px; padding: 9px 11px; border-radius: 10px;
                     background: var(--bg-card-alt); font-size: 13.5px; cursor: pointer; }
.cm-escolha-piloto:hover { background: color-mix(in srgb, var(--cm-verde) 8%, var(--bg-card-alt)); }
.cm-escolha-piloto input { flex-shrink: 0; }

/* Três degraus, e cada um existe por uma razão.
   Abaixo de 1200px a linha inteira já não cabe: continuar a forçá-la a uma
   só espremia o nome da competição contra o selo do estado e punha o aviso
   a uma palavra por linha. Envolve, e as ações descem para a sua própria
   linha, ainda encostadas à direita.
   Abaixo de 900px é um telemóvel na mão de quem está no recinto: os botões
   passam à largura toda, que é o que se carrega com o polegar. */
@media (max-width: 1200px) {
  .cm-linha { flex-wrap: wrap; }
  .cm-identidade { flex: 1 1 260px; }
  .cm-identidade .nome { white-space: normal; }
  .cm-accoes { flex: 0 0 auto; }
}

@media (max-width: 900px) {
  .cm-accoes { margin-left: 0; flex: 1 1 100%; flex-wrap: wrap; }
  /* Os botões ficam à largura do que dizem, e envolvem quando não cabem.
     Cheguei a pô-los a crescer para encher a linha: com dois botões
     ficava bem, mas nas linhas de um botão só o menu dos três pontos ia
     sozinho para uma segunda linha, e lia-se como um engano.
     Largura natural é a regra que se porta bem nos dois casos -- e é a
     mesma que o resto da aplicação usa. */
  .cm-accoes .cm-menu-wrap { flex: 0 0 auto; }
  /* E o que envolve encosta à direita, debaixo do que ficou por cima --
     à esquerda, um botão sozinho na segunda linha parece ter caído para
     lá. */
  .cm-accoes { justify-content: flex-end; }
}

@media (max-width: 860px) {
  /* De pé, no telemóvel: o nome da prova continua grande, e o botão fica à
     largura toda -- é o que se carrega com o polegar. */
  .cm-agora { padding: 18px; gap: 14px; }
  .cm-agora-texto .nome { font-size: 24px; }
  .cm-agora-accoes { flex: 1 1 100%; }
  .cm-agora-accoes .btn-accent, .cm-agora-accoes .btn-ghost { flex: 1; }
  .cm-lugares { grid-template-columns: repeat(2, 1fr); }
}

/* -------------------------------------------------------------------------
   O aviso de ecrã pequeno
   -------------------------------------------------------------------------
   Só no assistente. A lista e o controlo do dia têm de funcionar no
   telemóvel de quem está no recinto -- um aviso a tapá-los era pior do que
   o problema. E nunca bloqueia: avisa, e deixa continuar. */
.cm-ecra-pequeno { position: fixed; inset: 0; z-index: 900; display: flex; align-items: center; justify-content: center; padding: 20px;
                   background: color-mix(in srgb, var(--bg-page) 92%, transparent); backdrop-filter: blur(3px); }
.cm-ecra-pequeno[hidden] { display: none !important; }
.cm-ecra-pequeno .caixa { max-width: 420px; background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 18px; padding: 24px; text-align: center; }
.cm-ecra-pequeno .icone { display: inline-flex; width: 50px; height: 50px; align-items: center; justify-content: center; border-radius: 15px;
                          background: var(--bg-card-alt); color: var(--text-secondary); margin-bottom: 14px; }
.cm-ecra-pequeno h2 { font-size: 17px; margin: 0 0 8px; }
.cm-ecra-pequeno p { font-size: 13px; color: var(--text-secondary); margin: 0 0 10px; line-height: 1.6; }
.cm-ecra-pequeno .medida { font-size: 12px; color: var(--text-muted); margin-bottom: 18px; }
.cm-ecra-pequeno .accoes { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }

@media (max-width: 1080px) {
  .cm-duas { grid-template-columns: minmax(0, 1fr); }
  /* Deixa de ser uma coluna e passa a ser uma secção: lê-se a seguir, que
     é a ordem certa -- primeiro a decisão, depois a consequência. */
  .cm-lado { position: static; }
}
@media (max-width: 860px) {
  .cm-impacto-grelha { grid-template-columns: repeat(2, 1fr); }
  .cm-formatos { grid-template-columns: minmax(0, 1fr); }
  .cm-regra { flex-wrap: wrap; }
  .cm-regra .resumo { flex: 1 1 100%; white-space: normal; }
  /* No telemóvel o bloco do horário passa a duas linhas: a hora e o nome
     em cima, as acções em baixo à largura toda. Apertados na mesma linha,
     os três botões ficavam com 20px cada um. */
  .cm-bloco-accoes { margin-left: 0; flex: 1 1 100%; }
  .cm-bloco-accoes .btn-ghost { flex: 1; }
}

/* -------------------------------------------------------------------------
   O ASSISTENTE, POR DENTRO
   -------------------------------------------------------------------------
   O topo, as etapas e o cartão já viviam aqui. O CONTEÚDO de um passo --
   os grupos, as linhas com interruptor, os cartões de escolha, a linha de
   revisão e o veredicto do fim -- ficou durante meses dentro de
   activities-config.html, com nomes `.ac-`. Enquanto houve um assistente
   só, não se notou.

   Ao nascer o segundo (as competições, 24/9), notou-se logo: ou se copiava
   o bloco inteiro para a outra página -- e a partir daí os dois iam
   divergir --, ou se fazia isto. É isto.

   O que ficou em activities-config.html é o que é MESMO de uma atividade:
   a capa 16:9 e a zona de perigo. */

.wiz-cartao > h2 { font-size: 17px; margin: 0 0 4px; }
.wiz-cartao > .wiz-sub { font-size: 13px; color: var(--text-muted); margin: 0 0 18px; }
.wiz-grupo { border-top: 1px solid var(--border-subtle); margin-top: 18px; padding-top: 18px; }
.wiz-grupo:first-of-type { border-top: 0; margin-top: 0; padding-top: 0; }
.wiz-grupo h3 { font-size: 13px; font-weight: 700; margin: 0 0 12px; }

/* A letra pequena por baixo de um campo. NÃO é `.nota`, que neste tema é
   uma caixa com fundo e borda -- o nome batia certo, o resto não, e cada
   linha de ajuda aparecia dentro de um retângulo cinzento. */
.wiz-dica { font-size: 12px; color: var(--text-muted); margin: 6px 0 0; }
.wiz-erro { font-size: 12px; color: var(--danger); margin: 6px 0 0; }

/* Cartões grandes de escolha: um formato de corrida, um tipo de resultado. */
.wiz-escolhas { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.wiz-escolha { display: block; border: 1px solid var(--border-subtle); border-radius: 14px; background: var(--bg-card-alt); }
.wiz-escolha-int { display: flex; gap: 12px; align-items: flex-start; padding: 16px; min-height: 48px; cursor: pointer; }
.wiz-escolha input { width: 20px; height: 20px; margin: 2px 0 0; flex-shrink: 0; accent-color: var(--ok); }
.wiz-escolha .wiz-icone { width: 34px; height: 34px; border-radius: 9px; background: var(--bg-card); display: flex; align-items: center; justify-content: center; color: var(--text-secondary); flex-shrink: 0; }
/* O destaque segue a escolha marcada por quem desenha, e não um
   `:has(input:checked)` -- que também apanharia os sub-rádios lá dentro e
   podia acender dois cartões ao mesmo tempo. */
.wiz-escolha.escolhida .wiz-icone { color: var(--ok); }
.wiz-escolha.escolhida { border-color: var(--ok); background: color-mix(in srgb, var(--ok) 8%, var(--bg-card)); }
.wiz-escolha:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.wiz-escolha-txt { flex: 1; min-width: 0; }
.wiz-escolha-titulo { display: block; font-size: 14px; font-weight: 700; }
.wiz-escolha-nota { display: block; font-size: 12px; color: var(--text-muted); margin-top: 3px; }
.wiz-escolha-extra { border-top: 1px solid var(--border-subtle); padding: 12px 16px; display: none; }
.wiz-escolha.escolhida .wiz-escolha-extra { display: block; }

/* UMA ESCOLHA QUE PERTENCE À LINHA DE CIMA, e não ao cartão todo.
   `.wiz-grupo` normal traz um traço em cima e 18px de espaço: entre a
   linha de um módulo e a pergunta sobre ESSE módulo, isso lia-se como
   uma secção nova, sem ligação nenhuma ao interruptor que a fez
   aparecer. Recuada e encostada a uma barra, lê-se como o que é. */
.wiz-grupo-da-linha {
  border-top: 0; border-left: 2px solid var(--border-subtle);
  margin: 8px 0 0 22px; padding: 14px 0 2px 16px;
}
.wiz-grupo-da-linha + .wiz-linha { margin-top: 12px; }
@media (max-width: 640px) { .wiz-grupo-da-linha { margin-left: 0; padding-left: 12px; } }

/* Linhas com interruptor ou selo à direita. */
.wiz-linha {
  display: flex; align-items: center; gap: 14px; padding: 14px 16px; min-height: 48px;
  border: 1px solid var(--border-subtle); border-radius: 12px; background: var(--bg-card-alt);
}
.wiz-linha + .wiz-linha { margin-top: 10px; }
.wiz-linha.ligado { border-color: var(--ok); background: color-mix(in srgb, var(--ok) 7%, var(--bg-card)); }
.wiz-linha .wiz-icone { width: 34px; height: 34px; border-radius: 9px; background: var(--bg-card); display: flex; align-items: center; justify-content: center; color: var(--text-secondary); flex-shrink: 0; }
.wiz-linha .wiz-txt { flex: 1; min-width: 0; }
.wiz-linha .wiz-txt .nome { font-size: 14px; font-weight: 700; }
.wiz-linha .wiz-txt .nota { font-size: 12px; color: var(--text-muted); margin-top: 2px; }
/* O que fica encostado à direita da linha. Não se chama `.wiz-selo` porque
   esse nome já é do emblema "Rascunho" lá em cima, e duas coisas com o
   mesmo nome acabam a pintar-se uma à outra. */
.wiz-linha-fim { flex-shrink: 0; }

/* A revisão do último passo. */
.wiz-revisao-linha { display: flex; align-items: center; gap: 14px; padding: 14px 0; border-top: 1px solid var(--border-subtle); flex-wrap: wrap; }
.wiz-revisao-linha:first-of-type { border-top: 0; }
.wiz-revisao-linha .wiz-txt { flex: 1; min-width: 160px; }
.wiz-revisao-linha .wiz-txt .nome { font-size: 14px; font-weight: 700; }
.wiz-revisao-linha .wiz-txt .nota { font-size: 12px; color: var(--text-muted); margin-top: 2px; }

.wiz-veredicto { border-radius: 12px; padding: 14px 16px; display: flex; gap: 12px; align-items: flex-start; margin-bottom: 16px; }
.wiz-veredicto.ok { border: 1px solid var(--ok); background: color-mix(in srgb, var(--ok) 10%, transparent); }
.wiz-veredicto.falta { border: 1px solid var(--warn); background: color-mix(in srgb, var(--warn) 10%, transparent); }
.wiz-veredicto .titulo { font-size: 14px; font-weight: 700; }
.wiz-veredicto ul { margin: 6px 0 0; padding-left: 18px; font-size: 12px; color: var(--text-secondary); }

@media (max-width: 640px) {
  .wiz-escolhas { grid-template-columns: 1fr; }
}


/* Nota inline "módulo não contratado" dentro de um passo do assistente —
   mesmo padrão visual usado em displays.html/prizes.html para avisar que
   uma função depende de um módulo que este evento ainda não tem. */
.wiz-nota { font-size: 12px; color: var(--text-muted); background: var(--bg-card-alt); border-radius: 8px; padding: 10px 12px; margin: 10px 0 0; }
.wiz-nota strong { color: var(--text-primary); }

.nav { display: flex; flex-direction: column; gap: 4px; }
.nav-section { display: flex; flex-direction: column; gap: 4px; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border-subtle); }
.nav-section-label { padding: 2px 12px 4px; font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-muted); font-weight: 700; }
.ext-icon { margin-left: auto; color: var(--text-muted); font-size: 11px; }
.nav-item {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-radius: 10px;
  color: var(--text-secondary); font-size: 14px; font-weight: 500;
  cursor: pointer; border: 1px solid transparent; text-decoration: none;
}
.nav-item .tag {
  width: 24px; height: 20px; border-radius: 5px;
  background: var(--bg-card-alt); color: var(--text-muted);
  display: flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 700; flex-shrink: 0;
}
.nav-item.active { background: var(--bg-card); color: var(--text-primary); border-color: var(--border-subtle); }
.nav-item.active .tag { background: var(--accent); color: var(--accent-text); }
/* A identidade vive no fundo do menu, mas o menu e' tao alto quanto a
   pagina -- num evento com muitos modulos ficava a 1400px do topo, ou seja,
   so' se via depois de rolar tudo ate' ao fim. Com sticky fica encostada ao
   fundo do ECRA enquanto a barra lateral estiver a' vista, e assenta no seu
   lugar quando se chega mesmo ao fim.

   E' de proposito que nao se resolveu com uma barra lateral fixa e o menu a
   rolar por dentro: um segundo scroll dentro do menu e' pior do que o
   problema que resolve. Assim o menu continua a rolar com a pagina, como
   sempre, e so' este bloco acompanha.

   Precisa de fundo proprio: em sticky passa por cima dos itens do menu que
   ficarem atras. */
.footer-wrap {
  /* Espaco a serio por cima: encostada ao ultimo item do menu, a identidade
     lia-se como mais uma linha da lista em vez de um bloco a' parte. */
  margin-top: 22px;
  position: sticky;
  /* Assenta ACIMA da barra de contexto, quando ela existe -- senao ficava
     colada ao fundo do ecra e a barra desenhava-lhe por cima (a barra e'
     fixed, esta e' sticky: nao se empurram uma a' outra). A altura vem
     medida da propria barra, ver --context-bar-h em mountContextBar. Isto
     e' so' a base para o mobile (unica situacao em que este bloco ainda
     vive dentro da barra de baixo) -- no PC ha' uma regra propria mais
     abaixo que troca para position:fixed. */
  bottom: var(--context-bar-h, 0px);
  background: var(--bg-sidebar);
  padding-top: 4px;
  z-index: 2;
}
/* E o menu ganha espaco em baixo, para o ultimo item nao ficar por tras
   deste bloco quando se chega ao fim da pagina. */
body.has-context-bar .sidebar { padding-bottom: calc(var(--context-bar-h, 0px) + 8px); }

@media (min-width: 769px) {
  /* O MENU FICA QUIETO ENQUANTO A PAGINA ROLA.
     -------------------------------------------------------------------
     Estavam os dois presos ao mesmo rolamento: a barra lateral tinha a
     altura da pagina inteira, e numa listagem comprida ia-se embora por
     cima junto com o conteudo. Para trocar de pagina era preciso voltar
     ao topo primeiro (Tiago, 26/9).

     O comentario do .footer-wrap aqui em baixo dizia que isto nao se
     resolvia com uma barra fixa e o menu a rolar por dentro, porque um
     segundo rolamento e' pior do que o problema. Continua a ser verdade
     -- e e' por isso que aqui NAO se poe um rolamento proprio: poe-se
     `height: 100vh` com `overflow-y: auto`, que so' da' barra ao menu
     quando ele nao cabe mesmo no ecra. Num evento normal nunca aparece.

     `overscroll-behavior: contain` e' a outra metade: sem ele, chegar ao
     fim do menu continuava a empurrar a pagina, que e' exatamente a
     sensacao de "esta tudo ligado".

     `top: 0` com `position: sticky` e nao `fixed`: assim continua a ser
     uma coluna da grelha (ocupa o seu lugar, nao se sobrepoe ao
     conteudo) e o traco da direita cobre sempre o ecra todo. */
  .sidebar {
    position: sticky;
    top: 0;
    height: 100vh;
    /* O rolamento e' do .nav, nao da barra inteira: assim a marca fica
       em cima e a identidade em baixo, sempre a' vista, e so' a lista
       do meio e' que anda -- que e' a unica parte que pode nao caber. */
    overflow: hidden;
  }
  .sidebar > .nav {
    flex: 1 1 auto;
    /* Sem isto um filho de flex nunca encolhe abaixo do seu conteudo, e
       o `overflow` nao chega a ter o que fazer. */
    min-height: 0;
    overflow-y: auto;
    /* Chegar ao fim do menu nao pode continuar a empurrar a pagina --
       era exatamente essa a sensacao de "esta tudo ligado". */
    overscroll-behavior: contain;
  }

  /* No PC ja nao ha' barra de baixo nenhuma (ver .context-bar acima) --
     por isso a identidade e a escolha de evento/vista podem ficar MESMO
     presas ao fundo da coluna do menu, com position:fixed, em vez de
     sticky. Sticky so' "cola" depois de se rolar o suficiente para passar
     da sua posicao normal no fluxo -- com pouco conteudo (ex: dashboard da
     Administracao) isso nunca chega a acontecer, e o bloco fica a flutuar
     a meio da coluna em vez de encostado ao fundo, tal como foi reportado.
     Fixed nao depende de quanto (ou se) se rola. */
  /* A IDENTIDADE, EM BAIXO, SEM TRUQUES.
     Era `position: fixed` porque a barra lateral tinha a altura da
     pagina inteira: sticky so' "cola" depois de se rolar o suficiente, e
     num dashboard curto isso nunca acontecia -- o bloco ficava a flutuar
     a meio da coluna. Agora a barra tem a altura do ECRA e e' uma coluna
     de flex: o ultimo filho encosta ao fundo sozinho, sem depender de
     quanto (ou se) se rola.

     E deixa de ser preciso reservar-lhe espaco com padding: um bloco
     fixo passava POR CIMA do menu, e por isso o menu tinha de guardar
     111px em baixo -- o que sozinho ja' chegava para lhe dar uma barra
     de rolamento propria em quase todos os eventos. */
  .sidebar > .footer-wrap {
    position: static;
    flex: 0 0 auto;
    margin-top: 0;
    padding: 4px 0 0;
  }
  /* O menu reserva exatamente a altura do footer agora fixo -- medida em
     JS (ver mountSidebar em branding.js, --sidebar-footer-h) -- para o
     ultimo item da navegacao nunca ficar escondido atras dele. As duas
     variantes do seletor (com e sem has-context-bar) sao mesmo precisas:
     um Organizador/Promotor "a serio" (sem barra de contexto nenhuma, so'
     com a sua propria identidade fixa) cai na primeira; o Super Admin, que
     tem a classe posta pelo mountContextBar mesmo com a barra escondida no
     PC, precisa da segunda -- essa tem a MESMA especificidade da regra
     base la' em cima (body.has-context-bar .sidebar), por isso so' ganha
     por vir depois no ficheiro; um simples ".sidebar" sozinho perdia
     sempre para essa regra mais especifica. */
  .sidebar,
  body.has-context-bar .sidebar {
    padding-bottom: 16px;
  }
  /* No PC o proprio footer-wrap (fixo ca' em baixo) ja' leva a sua propria
     copia do selo logo a seguir aos seletores (ver renderFooter em
     branding.js) -- esta e' a copia de fora, pensada so' para o dropdown
     do menu em mobile (ver .sidebar > .footer-wrap mais abaixo, sempre
     escondido no PC). Sem isto aparecia duas vezes: uma reservada, presa
     ao fundo, e outra a flutuar a meio da coluna do menu (o proprio
     footer-wrap sai do fluxo normal com position:fixed, mas esta copia
     fica -- ficava exatamente onde o footer-wrap estaria se nao fosse
     fixo, escondida por baixo dele). */
  .sidebar > .powered-by { display: none; }
}
.sidebar-footer {
  width: 100%; display: flex; align-items: center; gap: 10px;
  /* Linha da cor da marca: e' o unico traco do menu que separa a navegacao
     de quem esta' a navegar. As outras separacoes sao cinzentas porque
     dividem seccoes da mesma lista; esta divide duas coisas diferentes. */
  padding-top: 16px; border-top: 1px solid var(--accent);
  background: none; border-left: none; border-right: none; border-bottom: none;
  color: inherit; font: inherit; text-align: left; cursor: pointer;
  text-decoration: none;
}
a.sidebar-footer { margin-top: auto; }
button.sidebar-footer:hover .name { color: var(--accent); }
.footer-menu {
  position: absolute; bottom: 100%; left: 0; right: 0; margin-bottom: 8px;
  background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 10px;
  padding: 6px; display: none; box-shadow: 0 10px 28px rgba(0,0,0,0.4); z-index: 20;
}
.footer-menu.show { display: block; }
.footer-menu-item {
  width: 100%; text-align: left; background: none; border: none;
  color: var(--text-secondary); font-size: 13px; padding: 9px 10px; border-radius: 8px; cursor: pointer;
}
.footer-menu-item:hover { background: var(--bg-card-alt); color: var(--text-primary); }
.avatar {
  width: 32px; height: 32px; border-radius: 50%;
  background: var(--bg-card-alt); color: var(--text-secondary);
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700; flex-shrink: 0;
}
.sidebar-footer .who .name { font-size: 13px; font-weight: 600; }
.sidebar-footer .who .role { font-size: 12px; color: var(--text-muted); }

/* "Powered by" — só na sidebar do backoffice (Super Admin/Organizador/
   Promotor com sessão iniciada), nunca nas páginas públicas (convite,
   boletim, portal, ecrã de display), que não têm sidebar. Discreto de
   propósito (opacidade reduzida) — é só uma assinatura, não é destaque. */
.powered-by {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  margin-top: 14px; padding-top: 12px; border-top: 1px dashed var(--border-subtle);
  opacity: 0.6;
}
.powered-by span { font-size: 10px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.05em; }
.powered-by img { height: 14px; width: auto; display: block; }

/* -------------------------------------------------------------------------
   Barra de contexto -- colada ao fundo, a atravessar o ecra todo.

   Leva os dois controlos com que o Super Admin salta entre contextos: QUE
   evento esta' a ver e EM QUE PAPEL. Estiveram no fundo do menu, mas ai'
   obrigavam a rolar o menu inteiro para lhes chegar. E nao sao navegacao --
   sao o contexto em que toda a navegacao acontece, por isso ficam por baixo
   de tudo, sempre no mesmo sitio, como a barra de estado de uma aplicacao.

   So' existe para o Super Admin (ver mountContextBar em branding.js).
   ------------------------------------------------------------------------- */
.context-bar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 45;
  background: var(--bg-sidebar);
  border-top: 1px solid var(--border-subtle);
  box-shadow: 0 -6px 24px rgba(0,0,0,0.35);
  padding: 8px 20px 6px;
}
/* Linha de cima: identidade a' esquerda, depois evento, depois "ver como" --
   pela ordem em que se pensa neles ("quem sou" -> "onde estou" -> "como
   estou a ver"). */
.context-bar-inner {
  display: flex; align-items: center; gap: 20px; flex-wrap: wrap;
}
/* Linha de baixo, centrada: de quem e' o sistema. */
.context-bar-credits {
  display: flex; align-items: center; justify-content: center; gap: 7px;
  margin-top: 6px; padding-top: 6px;
  border-top: 1px dashed var(--border-subtle);
  font-size: 10px; color: var(--text-muted);
  text-transform: uppercase; letter-spacing: 0.05em;
}
.context-bar-credits img { height: 13px; width: auto; display: block; opacity: 0.75; }

/* Os dois blocos partilham a classe .role-switcher (o seletor de evento
   reaproveita-a desde sempre -- ver renderEventSwitcher em branding.js). */
.context-bar .role-switcher {
  display: flex; align-items: center; gap: 8px;
  margin: 0; padding: 0; border: none; min-width: 0;
}
.context-bar label {
  margin: 0; font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-muted); font-weight: 700; white-space: nowrap;
}
.context-bar select {
  width: auto; min-width: 150px; max-width: 260px;
  padding: 6px 22px 6px 8px; font-size: 12px;
  background: var(--bg-card-alt); border: 1px solid var(--border-subtle);
  color: var(--text-secondary); border-radius: 8px;
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23a8a2c0' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 8px center;
}
.context-bar select option { background: var(--bg-card-alt); color: var(--text-secondary); }

/* So' existe mesmo em telemovel: no PC a escolha de evento/"ver como"
   volta a viver no proprio menu (ver .footer-wrap mais acima e
   renderFooter() em branding.js), fixa ao fundo dele -- e' o "voltamos ao
   menu como antes, mas com isto sempre visivel la' em baixo" pedido depois
   de a barra a atravessar o ecra todo no PC nao ter resultado bem. A
   funcao continua a montar-se sempre (mountContextBar) porque o mobile
   continua a precisar dela tal e qual como estava -- so' se esconde aqui. */
@media (min-width: 769px) {
  .context-bar { display: none; }
}

@media (max-width: 768px) {
  /* O conteudo da pagina reserva espaco em baixo, para nenhuma linha ficar
     escondida por tras da barra (ver a classe posta no body) -- so' faz
     sentido enquanto a barra existir mesmo, ou seja, em mobile. */
  body.has-context-bar .main { padding-bottom: calc(var(--context-bar-h, 0px) + 26px); }
  /* E o botao de voltar ao topo sobe, para nao se sentar em cima dela. */
  body.has-context-bar .back-to-top { bottom: calc(var(--context-bar-h, 0px) + 14px); }
}

@media (max-width: 680px) {
  .context-bar { padding: 7px 12px 5px; }
  .context-bar-inner { gap: 8px 10px; }
  /* Numa barra que vive no fundo de um telemovel, cada linha custa ecra. A
     identidade fica na sua (e' larga), mas os dois seletores dividem a linha
     seguinte, com o rotulo por cima em vez de ao lado -- assim continuam
     largos o suficiente para o dedo e a barra fica com pouco mais de metade
     da altura que teria com tudo empilhado. */
  .context-bar .footer-wrap { width: 100%; }
  .context-bar .role-switcher {
    flex: 1 1 0; min-width: 0;
    flex-direction: column; align-items: stretch; gap: 3px;
  }
  .context-bar select { width: 100%; min-width: 0; max-width: none; }
  .context-bar-credits { margin-top: 5px; padding-top: 5px; }
}

/* O QUE NUNCA VAI PARA O PAPEL
   ----------------------------
   Os relatorios que se imprimem escondem o que e' deles (o menu, os botoes
   da propria pagina). Estas duas nao sao de nenhuma pagina -- sao a
   moldura da aplicacao, pintada pelo branding.js em todas -- e por isso a
   regra vive aqui, uma vez, e nao repetida em cada pagina que venha a
   imprimir-se.

   A barra de contexto apanhou-nos no relatorio do evento (23/9): o papel
   e' mais estreito do que o ecra, a barra que so aparece em telemovel
   aparecia tambem na folha, e o cliente recebia um PDF com "A VER EVENTO:
   BOLT" e "VER COMO: Super Admin" no fundo. O mesmo acontecia no
   relatorio de credenciais, sem ninguem ter reparado.

   O botao de voltar ao topo e' fixo ao ecra: em papel sairia carimbado
   por cima do texto da primeira folha. */
@media print {
  .context-bar, .mobile-topbar, .mobile-tabbar, .back-to-top { display: none !important; }
}

/* Voltar ao topo -- so' aparece depois de se ter descido um ecra inteiro
   (ver mountBackToTop em shared/branding.js). Fica no canto, fora do
   caminho, e com tamanho de dedo em telemovel. */
.back-to-top {
  position: fixed; right: 20px; bottom: 20px; z-index: 50;
  width: 42px; height: 42px; border-radius: 50%;
  background: var(--bg-card); color: var(--text-secondary);
  border: 1px solid var(--border-subtle);
  box-shadow: 0 6px 20px rgba(0,0,0,0.35);
  font-size: 17px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  opacity: 0; pointer-events: none; transform: translateY(8px);
  transition: opacity 0.18s ease, transform 0.18s ease;
}
.back-to-top.is-visible { opacity: 1; pointer-events: auto; transform: none; }
.back-to-top:hover { color: var(--accent); border-color: var(--accent); }

/* Topbar */
.topbar { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; flex-wrap: wrap; gap: 12px; }
.topbar .label { font-size: 11px; letter-spacing: 0.08em; color: var(--text-muted); font-weight: 700; text-transform: uppercase; }
.topbar .event-name { font-size: 17px; font-weight: 700; margin-top: 2px; }

/* -------------------------------------------------------------------------
   O CABEÇALHO DE UMA PÁGINA -- um só, igual em toda a app
   -------------------------------------------------------------------------
   Havia três maneiras diferentes de escrever a mesma coisa: ".page-header"
   (um bloco, sem sítio para botões), ".ev-topo" (com sítio para botões) e
   a própria ".topbar" usada como título em meia dúzia de páginas -- que
   ainda por cima repetia a secção logo por cima do breadcrumb ("VISÃO
   GERAL / BOLT" e outra vez "VISÃO GERAL / Dashboard"). Quem anda pela
   app via cada página a apresentar-se de sua maneira.

   Agora é isto, e só isto:

     <div class="page-header">
       <div class="texto">
         <div class="crumb">SECÇÃO · PÁGINA</div>   onde estou (= menu)
         <h1>Título</h1>
         <p>uma linha a dizer para que serve</p>
       </div>
       <div class="ev-acoes"> …botões… </div>       opcional, à direita
     </div>

   Os botões ficam na MESMA LINHA do título, à direita -- nunca por cima do
   breadcrumb: "não quero botões por cima da localização da página" (Tiago,
   11/9). Um "voltar" não é um botão de página: vai numa linha própria por
   cima da primeira caixa (ver .voltar-linha).
   ------------------------------------------------------------------------- */
.page-header {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; margin-bottom: 24px;
}
.page-header > .texto,
.wiz-topo > .wiz-topo-texto { flex: 1; min-width: 240px; }
.page-header .crumb,
.wiz-topo .crumb { font-size: 11px; letter-spacing: 0.08em; color: var(--text-muted); font-weight: 700; text-transform: uppercase; }
.page-header h1,
.wiz-topo h1 { font-size: 34px; font-weight: 700; margin: 6px 0 8px; letter-spacing: -0.5px; }
.page-header p,
.wiz-topo .wiz-topo-texto p { font-size: 14px; color: var(--text-secondary); margin: 0; }
.page-header .crumb a,
.wiz-topo .crumb a { color: inherit; text-decoration: none; border-bottom: 1px dotted currentColor; }
.page-header .crumb a:hover,
.wiz-topo .crumb a:hover { color: var(--text-secondary); }

/* O "voltar" das fichas: uma linha só dele, por cima da primeira caixa. */
.voltar-linha { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin: -6px 0 14px; }
.voltar-linha .btn-ghost { display: inline-flex; align-items: center; }

@media (max-width: 720px) {
  .page-header h1, .wiz-topo h1 { font-size: 26px; }
  /* No telemóvel os botões passam para baixo do título, um por linha e
     todos da mesma largura -- ficavam cada um com a largura do seu texto,
     escadinha abaixo. */
  .page-header > .ev-acoes,
  .wiz-topo > .wiz-topo-accoes { width: 100%; }
  .page-header > .ev-acoes > .btn-accent,
  .page-header > .ev-acoes > .btn-ghost,
  .page-header > .ev-acoes > a,
  .page-header > .ev-acoes > button { flex: 1 1 100%; justify-content: center; }
}

/* Checkbox em forma de "pill" — usado em listas de módulos/postos que se
   ligam/desligam consoante o nível de acesso escolhido */
.pill-checkbox {
  display: inline-flex; align-items: center; gap: 8px;
  border: 1px solid var(--border-subtle); border-radius: 10px;
  padding: 9px 12px; font-size: 13px; color: var(--text-secondary);
  cursor: pointer; user-select: none; background: var(--bg-card-alt);
}
.pill-checkbox input { width: auto; margin: 0; }
.pill-checkbox.disabled { opacity: 0.4; pointer-events: none; }
.pill-row { display: flex; flex-wrap: wrap; gap: 10px; }
.pill-checkbox.pill-green:has(input:checked) { background: color-mix(in srgb, var(--ok) 14%, transparent); border-color: var(--ok); color: var(--ok); }

/* Linha de campo de contacto configurável (ver "Campos de contacto"/
   "Configuração do boletim" em convidados.html/invite.html): rótulo
   (.contact-field-name) + dois pill-checkbox (ou pill-checkbox + nota)
   lado a lado, agrupados dentro de .contact-field-options. Em ecrã
   largo cabe tudo numa linha só (rótulo + opções). No mobile é sempre
   rótulo numa linha, opções juntas na linha de baixo -- SEMPRE as
   duas linhas, mesmo quando o texto seria curto o suficiente para
   caber tudo numa linha só (ver .contact-field-name abaixo): variar
   entre uma e duas linhas consoante o campo (ex.: "Nome" cabia numa
   só, "Telemóvel" já não) dava um ar sem simetria nenhuma entre os
   campos -- agora todos os campos têm sempre a mesma forma. Correção
   anterior (antes deste comentário): os dois pill-checkbox eram
   filhos soltos deste flex e, ao não caberem os dois ao lado do
   rótulo, só o segundo caía sozinho para a linha de baixo, dando um
   ar de "partido" -- por isso vivem agrupados dentro de
   .contact-field-options, que cai inteiro como um bloco só. */
.contact-field-row { flex-wrap: wrap; row-gap: 8px; }
.contact-field-name { flex: 1; font-size: 13px; }
.contact-field-options { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; row-gap: 8px; }
@media (max-width: 768px) {
  /* flex-basis 100% obriga o rótulo a ocupar sempre a linha toda
     sozinho, empurrando .contact-field-options para a linha de baixo
     de forma garantida -- não depende de haver ou não espaço, ao
     contrário do resto do flex-wrap desta linha. */
  .contact-field-name { flex: 1 1 100%; }
  /* .contact-field-options, sem isto, só ocupava o espaço dos próprios
     pill-checkbox e parava aí -- sobrava espaço vazio à direita, o mesmo
     problema que a linha "Tipo"/"Obrigatória" tinha em "Adicionar
     formulário" (ver .question-type-row). Aqui também passa a ocupar a
     linha toda, e os pill-checkbox lá dentro esticam para se repartirem
     esse espaço. */
  .contact-field-options { flex: 1 1 100%; }
  /* "flex: 1 1 auto" (não "flex: 1", que ignorava o tamanho do próprio
     texto) -- parte do tamanho natural de cada pill e só reparte o que
     sobra depois dos dois caberem; com "flex: 1" simples, textos mais
     compridos como "Aparece no boletim" ficavam espremidos e quebravam
     para 2 linhas ao lado de "Obrigatório" numa só. */
  .contact-field-options .pill-checkbox { flex: 1 1 auto; justify-content: center; }
}
/* Em ecrã estreito os dois pill-checkbox deste grupo (ex: "Aparece no
   boletim/convite" + "Obrigatório") ficam ligeiramente mais compactos --
   só o suficiente para caberem lado a lado numa única linha, em vez de
   cada um ocupar a sua própria linha (o que, com o padding/gap normais
   do pill-checkbox, já não cabia num ecrã de telemóvel comum). Em ecrã
   largo mantém-se tudo como está (regra normal do .pill-checkbox). */
@media (max-width: 480px) {
  .contact-field-options .pill-checkbox { padding: 7px 8px; gap: 6px; font-size: 11.5px; }
  /* A nota "Sempre preenchido, não editável" (linha do Nome em
     convidados.html) é texto a mais para caber ao lado do pill-checkbox
     num telemóvel -- deixa-a quebrar em vez de forçar a largura toda
     numa linha só. */
  .contact-field-options > span { white-space: normal; }
}
.pill-checkbox.pill-red:has(input:checked) { background: color-mix(in srgb, var(--danger) 14%, transparent); border-color: var(--danger); color: var(--danger); }

/* Cartao "ligado": um modulo a' venda em Modulos e precos, um modulo
   escolhido para uma banca em Bancas e Zonas. Estava escrito em estilo em
   linha nas duas paginas, com a cor da marca -- passa para aqui, uma vez
   so', e para o verde de "escolhido/ligado", pela mesma razao dos outros:
   a cor da marca muda de evento para evento, e "ligado" tem de se ler igual
   em qualquer um. */
.panel.is-on {
  border-color: color-mix(in srgb, var(--ok) 45%, var(--border-subtle));
  background: color-mix(in srgb, var(--ok) 5%, var(--bg-card));
}
/* Caixa de escolher um modulo (ver "Modulos" em Criar/Gerir eventos).
   Estava copiada nas duas paginas, com a cor da marca no estado marcado --
   passa a viver aqui, uma vez so', e a usar o verde de "escolhido". */
.module-pick-card {
  display: flex; gap: 12px; align-items: flex-start;
  background: var(--bg-card-alt); border: 1px solid var(--border-subtle);
  border-radius: 12px; padding: 14px 16px; cursor: pointer;
  min-width: 0;
}
.module-pick-card:has(input:checked) {
  border-color: var(--ok);
  background: color-mix(in srgb, var(--ok) 10%, var(--bg-card-alt));
}
.module-pick-card input { margin-top: 3px; flex-shrink: 0; }
/* min-width: 0 nos dois: sem isto o texto nao parte e empurra a caixa para
   fora da grelha em ecra estreito -- era o que se via em telemovel. */
.module-pick-card > div { min-width: 0; }
.module-pick-card .name { font-weight: 700; font-size: 14px; overflow-wrap: anywhere; }
.module-pick-card .desc { font-size: 12px; color: var(--text-muted); margin-top: 2px; overflow-wrap: anywhere; }
.module-pick-group-title { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); margin-bottom: 8px; }

/* Etiquetas informativas pequenas (ex: módulos contratados por evento) */
.tag-chip {
  display: inline-block; font-size: 11px; color: var(--text-muted);
  background: var(--bg-card-alt); border: 1px solid var(--border-subtle);
  border-radius: 999px; padding: 2px 9px; margin: 3px 6px 0 0;
}
.topbar-right { display: flex; align-items: center; gap: 14px; }
.status-dot { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--text-secondary); }
.status-dot .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); }

/* Buttons */
/* inline-flex (em vez de inline-block, o normal do <button>) só para
   poderem ter um ícone antes do texto (ex: "+ Adicionar pergunta",
   "○ Pré-visualizar boletim") alinhado com a linha de base do texto --
   não muda nada visualmente nos botões só de texto, que continuam a
   maioria. Os pill (.btn-pill) são a família à parte para CTAs. */
.btn-accent {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  background: var(--accent); color: var(--accent-text);
  border: none; border-radius: 10px; padding: 9px 16px;
  font-size: 13px; font-weight: 700; cursor: pointer;
}
/* `hidden` tem de ganhar a qualquer `display` nosso -- os botões usam
   display:inline-flex e isso fazia com que esconder um botão com
   `elemento.hidden = true` não tivesse efeito nenhum (o "Remover" do
   logótipo aparecia mesmo sem logótipo). */
[hidden] { display: none !important; }

.btn-ghost {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  background: transparent; color: var(--text-secondary);
  border: 1px solid var(--border-subtle); border-radius: 10px; padding: 9px 16px;
  font-size: 13px; font-weight: 600; cursor: pointer;
}
.btn-accent svg, .btn-ghost svg { flex-shrink: 0; }
/* Botão desativado (ex: "Entrada"/"Saída" em checkin.html, o lado que não
   é para usar agora) -- sem isto um <button disabled> quase não se
   distingue do normal neste tema escuro. Mesma opacidade de
   .pill-checkbox.disabled, para os dois estados "desativado" da app
   lerem-se da mesma forma. */
.btn-ghost:disabled, .btn-accent:disabled { opacity: 0.35; cursor: not-allowed; }
/* Um campo de texto travado tem de PARECER travado. Sem isto, o campo da
   numeração (que trava depois de saírem credenciais) ficava igual a
   todos os outros, e só se percebia ao tentar escrever lá. */
input:disabled, select:disabled, textarea:disabled { opacity: 0.5; cursor: not-allowed; background: var(--bg-card-alt); }

/* -------------------------------------------------------------------------
   A ESCALA DOS BOTÕES

   Um critério por tipo, e as mesmas medidas em toda a app. Antes disto cada
   página escrevia a altura à mão -- min-height 40, 44, 46, 48 -- e o mesmo
   botão ficava com três tamanhos em três ecrãs. Num deles, dentro de uma
   coluna no telemóvel, ficou com 220px de altura, que foi o que deu por isto.

   Três tamanhos, e só três:

     .btn-sm    32px   dentro de uma linha de tabela ou de um cartão, ao
                       lado de texto. Nunca é a ação principal de um ecrã.
     (normal)   40px   o que se usa por omissão, em toda a parte.
     .btn-lg    48px   a ação que fecha um ecrã (guardar, criar, confirmar
                       numa folha) e os botões à largura toda no telemóvel.

   E uma regra que não é um tamanho: em ecrãs de toque o mínimo sobe para
   44px, seja qual for o tipo. Não é estética -- é o tamanho de um dedo. Um
   botão de 32px acerta-se com o rato e falha-se com o polegar.

   Escrever `style="min-height:..."` num botão é sair desta escala. Se um
   ecrã precisar de outra medida, é a escala que está errada.
   ------------------------------------------------------------------------- */
.btn-accent, .btn-ghost { min-height: 40px; }
.btn-sm { min-height: 32px; padding: 5px 12px; font-size: 12.5px; border-radius: 9px; }
.btn-lg { min-height: 48px; padding: 12px 20px; font-size: 14px; }
@media (pointer: coarse) {
  .btn-accent, .btn-ghost, .btn-sm { min-height: 44px; }
}

/* Linha de accoes de um painel -- onde vive o botao que grava.

   Fica sempre a' DIREITA, em todas as caixas da app: e' onde se procura a
   accao que fecha um formulario, e ter umas caixas a gravar a' esquerda e
   outras a' direita obriga a pensar em cada uma. Eventuais mensagens de
   estado ("Gravado.") ficam a' esquerda do botao, no caminho do olhar.

   A excepcao deliberada sao os passos de assistente (.wiz-nav), que tem
   "Voltar" a' esquerda e "Continuar" a' direita -- ai' os dois extremos
   querem dizer coisas diferentes. */
.form-actions {
  display: flex; align-items: center; justify-content: flex-end;
  gap: 10px; flex-wrap: wrap;
}
@media (max-width: 560px) {
  /* Em ecra estreito, botoes a toda a largura e empilhados: em linha ficavam
     estreitos de mais para o dedo. O principal fica em cima. */
  .form-actions { flex-direction: column-reverse; align-items: stretch; }
  .form-actions .btn-accent, .form-actions .btn-ghost { width: 100%; }
  .form-actions > span { text-align: center; }
}

/* Botao "pill" (cantos totalmente arredondados) + icone -- reservado para
   acoes de CONTEUDO tipo "Abrir"/"Partilhar" (ver invite.html), nunca
   para gravar/submeter (isso continua .btn-accent/.btn-ghost,
   retangulares). A forma + o icone bastam para nao se confundir com um
   botao de gravar mesmo indo a' toda a largura no mobile -- ver
   .invite-cta-row logo a seguir. */
.btn-pill {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; border: none; border-radius: 999px; padding: 13px 22px;
  font-size: 14px; font-weight: 700; cursor: pointer; text-decoration: none;
}
.btn-pill-accent { background: var(--accent); color: var(--accent-text); }
.btn-pill-ghost { background: transparent; color: var(--text-secondary); border: 1px solid var(--border-subtle); }
.btn-pill svg { flex-shrink: 0; }

/* Botões "Abrir boletim" / "Partilhar boletim" (invite.html): em mobile
   ficam empilhados a toda a largura (o principal em cima); em ecrã largo
   ficam lado a lado, cada um do tamanho do seu próprio texto. */
.invite-cta-row { display: flex; flex-direction: column; gap: 10px; }
@media (min-width: 769px) {
  .invite-cta-row { flex-direction: row; }
  .invite-cta-row .btn-pill { width: auto; }
}

/* "Enviar diretamente" (invite.html) -- cada canal é um bloco com ícone em
   cima e nome por baixo, em vez de só um botão de texto -- mais fácil de
   reconhecer à primeira vista, principalmente com os três lado a lado.
   Mesma grelha de 3 colunas em mobile e em PC (cabem bem palavras curtas
   como "E-mail"/"SMS"/"WhatsApp"). */
.channel-tile-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.channel-tile {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 14px 8px; border-radius: 12px;
  background: var(--bg-card-alt); border: 1px solid var(--border-subtle);
  color: var(--text-secondary); text-decoration: none;
  font-size: 12px; font-weight: 600; cursor: pointer;
}
.channel-tile svg { color: var(--accent); }
.channel-tile:hover { border-color: var(--accent); color: var(--text-primary); }

/* Inscrições (participants.html) -- reordenação só em mobile: "Adicionar
   participante" (botão de destaque) vem antes de "Importar ou exportar
   CSV" (ver #participantsContent flex column, ordens abaixo); no PC fica
   pela ordem normal do HTML (CSV primeiro). */
#participantsContent { display: flex; flex-direction: column; }
@media (max-width: 768px) {
  #guestStats { order: 0; }
  #addParticipantPanel { order: 1; }
  #csvImportPanel { order: 2; }
  #participantsContent > .panel:last-child { order: 3; }
}

/* .panel-head-cta -- só em mobile: o cabeçalho recolhível de "Adicionar
   participante" passa a um botão "pill" cheio, cor de destaque (mesma
   família visual do .btn-pill-accent do Boletim de Inscrição), com o
   ícone e o título só -- sem o rótulo pequeno por cima nem o chevron, que
   aqui não fazem falta nenhuma: é a ação mais importante da página, por
   isso fica com o peso todo em vez de parecer só mais um painel para
   abrir. Continua a abrir/fechar o formulário por baixo exatamente como
   antes (mesmo elemento, mesmo onclick) -- só o aspeto muda. No PC não
   sofre nada, fica um cabeçalho recolhível normal. */
@media (max-width: 768px) {
  /* .panel-head-cta sozinho tem a mesma especificidade que a regra base
     ".panel-head { ... justify-content: space-between; margin-bottom: 14px;
     gap: 10px; }" (uma classe cada) -- e como essa regra base vem DEPOIS
     no ficheiro (aplica-se sempre, não só em mobile), ela ganhava o
     empate e anulava o justify-content/gap/margin-bottom pretendidos
     aqui, fazendo o icone ficar colado a' esquerda e o texto a' direita
     em vez do grupo ficar junto e centrado como o "Abrir boletim". Juntar
     .panel-head-toggle (que este cabecalho tambem tem) sobe a
     especificidade e resolve, sem depender da ordem no ficheiro. */
  .panel-head-cta.panel-head-toggle {
    background: var(--accent); border-radius: 999px; padding: 13px 22px;
    justify-content: center; gap: 8px; margin-bottom: 0;
  }
  .panel-head-cta .label { display: none; }
  /* Especificidade (.panel-head + .panel-head-cta + :not(.panel-head-icon))
     tem de ser maior que ".panel-head > div:not(.panel-head-icon) { flex: 1;
     ... }" (a regra geral que mantem o titulo colado ao icone nos
     cabecalhos normais) -- senao essa regra geral ganha (como estava a
     acontecer) e a div do titulo fica esticada em vez de encolhida, o
     que desalinha o texto para a esquerda dentro do botao em vez de
     ficar centrado como o "Abrir boletim". */
  .panel-head.panel-head-cta > div:not(.panel-head-icon) { flex: none; min-width: 0; }
  .panel-head-cta.panel-head-toggle .title { color: var(--accent-text); font-size: 14px; font-weight: 700; margin: 0; text-align: center; }
  .panel-head-cta .panel-head-icon { background: transparent; border: none; color: var(--accent-text); width: auto; height: auto; }
  .panel-head-cta .panel-toggle { display: none; }
}

/* Lista de participantes em cartão -- só mobile (ver .data-table escondida
   abaixo); mesmos dados da tabela (linha renderGuestTable()), só que
   agrupados por participante em vez de por coluna -- mais fácil de ler
   sem ter de rolar uma tabela na horizontal num ecrã estreito. */
.guest-card-list { display: none; }
@media (max-width: 768px) {
  #guestTable, #inviteTable { display: none; }
  .guest-card-list { display: flex; flex-direction: column; gap: 10px; }
}
.guest-card { background: var(--bg-card-alt); border: 1px solid var(--border-subtle); border-radius: 12px; padding: 14px; }
.guest-card-top { display: flex; align-items: flex-start; gap: 12px; }
.guest-card-top input[type="checkbox"] { margin-top: 3px; flex-shrink: 0; }
.guest-card-info { min-width: 0; }
.guest-card-name { font-size: 14px; font-weight: 700; }
.guest-card-email { font-size: 12px; color: var(--text-muted); margin-top: 2px; overflow-wrap: anywhere; }
.guest-card-bottom { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border-subtle); }
.guest-card-stats { display: flex; align-items: center; gap: 16px; }
.guest-card-stat { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.guest-card-stat-label { font-size: 10px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; font-weight: 700; }
.guest-card-actions { display: flex; gap: 8px; flex-shrink: 0; }
.guest-card-actions .btn-ghost { padding: 6px 10px; font-size: 12px; text-decoration: none; }

/* Barra de pesquisa/ordenar/filtrar da lista (ver Inscrições/Convidados)
   -- pesquisa na sua caixa (com ícone), "Ordenar"/"Filtrar" como par de
   botões que só abrem os <select> reais de sempre (.sr-only, continuam a
   funcionar tal e qual -- ver showPicker() no participants.html), e o
   filtro de "Inscritos" atual como etiqueta removível por baixo -- fica
   sempre visível (mesmo em "todos"), para se ver de relance o que está a
   filtrar sem abrir nada. */
.list-toolbar { display: flex; flex-direction: column; gap: 10px; margin: 0 0 14px; }
/* Pesquisa + caixas de "Ordenar"/"Filtrar" -- só esta parte (nunca
   .list-toolbar inteira) é que passa a linha horizontal em computador
   (ver @media 769px abaixo); o painel de "Mais filtros" e a etiqueta
   removível ficam sempre por baixo, cada um na sua própria linha. */
.list-toolbar-main-row { display: flex; flex-direction: column; gap: 10px; }
.list-search {
  display: flex; align-items: center; gap: 10px;
  background: var(--bg-card-alt); border: 1px solid var(--border-subtle); border-radius: 12px;
  padding: 10px 14px; cursor: text;
}
.list-search svg { color: var(--text-secondary); flex-shrink: 0; }
/* O seletor ".list-search input[type=text]" (não só ".list-search input")
   é de propósito -- "input[type=text]" sozinho (ver mais abaixo no
   ficheiro, estilo geral de campos de formulário) tem a MESMA
   especificidade que ".list-search input", e por vir depois no ficheiro
   ganhava-lhe o fundo/borda a seguir: o campo de texto ficava com uma
   segunda caixa própria, coincidência de cor à parte (mascarava o
   problema, mas só por sorte -- deixou de mascarar quando a caixa exterior
   chegou a ser removida a título de teste). Com "[type=text]" aqui
   também, a especificidade sobe e este é que fica sempre a ganhar. */
.list-search input[type=text] { border: none; background: transparent; flex: 1; min-width: 0; font-size: 13px; color: var(--text-primary); padding: 0; font-family: inherit; }
.list-search input:focus { outline: none; }
.list-toolbar-row { display: flex; align-items: stretch; background: var(--bg-card-alt); border: 1px solid var(--border-subtle); border-radius: 12px; overflow: hidden; }
/* .toolbar-btn-wrap -- o <select> de sempre (escondido à vista, ver
   .toolbar-select-overlay) fica por cima do botão a ocupar a caixa toda,
   para o toque abrir sempre as opções nativas (ver comentário no HTML). */
.toolbar-btn-wrap { position: relative; flex: 1; display: flex; }
.toolbar-btn {
  flex: 1; display: flex; align-items: center; justify-content: center; gap: 8px;
  background: transparent; border: none; color: var(--text-primary);
  font-size: 13px; font-weight: 600; padding: 12px; cursor: pointer; font-family: inherit;
}
.toolbar-btn:hover { background: var(--bg-card); }
.toolbar-btn svg { color: var(--text-secondary); flex-shrink: 0; }
/* Conteúdo do botão que muda consoante o tamanho: em telemóvel mostra-se
   o ícone + palavra de ação ("Ordenar"/"Filtrar"); a partir de computador
   esconde-se isso e mostra-se antes o VALOR escolhido (.toolbar-value-text,
   preenchido por JS) + uma seta (.toolbar-chevron) a indicar que abre um
   menu -- ver initToolbarDropdown() em branding.js e o menu .toolbar-dropdown
   mais abaixo. */
.toolbar-btn-mobile-only { display: inline-flex; align-items: center; gap: 8px; }
.toolbar-value-text { display: none; }
.toolbar-chevron { display: none; }
.toolbar-select-overlay {
  position: absolute; inset: 0; width: 100%; height: 100%; z-index: 1;
  opacity: 0; border: none; margin: 0; padding: 0; cursor: pointer;
}
.toolbar-divider { width: 1px; background: var(--border-subtle); }
.toolbar-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; padding: 0 4px; border-radius: 999px;
  background: var(--accent); color: var(--accent-text); font-size: 11px; font-weight: 700;
}
/* Sem isto, "display:inline-flex" acima ganha ao "display:none" do
   atributo "hidden" nativo (mesma especificidade, esta regra é que vem
   depois) -- o badge ficava sempre visível, mesmo escondido por JS. */
.toolbar-badge[hidden] { display: none; }
.filter-chip-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.filter-chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent);
  border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
  border-radius: 999px; padding: 6px 6px 6px 14px; font-size: 12px; font-weight: 600;
}
.filter-chip button {
  background: transparent; border: none; color: inherit; cursor: pointer;
  display: flex; align-items: center; justify-content: center; width: 18px; height: 18px; border-radius: 50%; padding: 0;
}
.filter-chip button:hover { background: color-mix(in srgb, var(--accent) 20%, transparent); }

/* Versão "caixas clássicas" da barra acima, só a partir do ecrã de
   tablet/computador (mesmo limite de 769px já usado no resto do site) --
   em vez de "Ordenar"/"Filtrar" partilharem uma caixa só com um <select>
   escondido por cima (truque pensado para o dedo, ver comentário junto de
   .list-toolbar acima), cada filtro ganha a sua própria caixa, com uma
   etiqueta fixa ("Ordenar:", "Estado:") e o próprio <select> a servir de
   valor -- o género de barra de filtros de qualquer ecrã de gestão em
   computador. Em ecrã estreito nada disto se vê (.toolbar-box-label fica
   escondida, .toolbar-btn continua à vista) -- só muda a partir daqui.

   IMPORTANTE: só a .list-toolbar-main-row (pesquisa + caixas de
   filtro) é que vira uma linha horizontal em computador -- .list-toolbar
   em si NUNCA muda de coluna para linha (fica sempre a empilhar as suas
   secções: a linha principal, o painel de "Mais filtros" quando aberto,
   e a etiqueta removível), senão essas duas últimas entravam também na
   mesma linha a espalhar-se de qualquer maneira (era exactamente o que
   acontecia antes desta nota). */
.toolbar-box-label { display: none; }
@media (min-width: 769px) {
  .list-toolbar-main-row { flex-direction: row; flex-wrap: wrap; align-items: center; }
  .list-search { flex: 1 1 240px; max-width: 360px; }
  /* "display: contents" tira a própria .list-toolbar-row do layout (sem
     fundo/borda próprios) -- cada .toolbar-btn-wrap dentro passa a ser um
     filho direto de .list-toolbar-main-row, e por isso uma caixa à parte,
     já não uma barra só a dividir ao meio. */
  .list-toolbar-row { display: contents; }
  .toolbar-divider { display: none; }
  .toolbar-btn-wrap {
    flex: none; position: relative;
    background: var(--bg-card-alt); border: 1px solid var(--border-subtle); border-radius: 12px;
    padding: 0 8px 0 16px;
  }
  .toolbar-box-label { display: inline-block; font-size: 13px; font-weight: 600; color: var(--text-secondary); white-space: nowrap; padding: 12px 0; }
  /* O botão continua à vista em computador (deixa de se esconder) --
     mas troca de conteúdo: em vez do ícone + "Ordenar"/"Filtrar", mostra
     agora o valor escolhido (.toolbar-value-text) + uma seta, no lugar de
     onde antes estava o <select> a sério, visível. Esse <select> passa a
     ficar escondido (ver abaixo) -- deixou de fazer sentido mostrá-lo,
     porque abrir um <select> a sério dá o popup nativo do sistema
     operativo (fundo branco, nada a ver com o resto da app escura, ver
     captura enviada) -- em vez disso abre-se agora o menu próprio
     .toolbar-dropdown (ver initToolbarDropdown() em branding.js), com o
     mesmo estilo visual do resto da aplicação. */
  .toolbar-btn {
    display: flex; justify-content: flex-start; gap: 6px;
    padding: 12px 8px 12px 4px; font-weight: 700;
  }
  .toolbar-btn-mobile-only { display: none; }
  .toolbar-value-text { display: inline-block; }
  .toolbar-chevron { display: inline-flex; color: var(--text-secondary); flex-shrink: 0; margin-left: auto; }
  /* O <select> de sempre mantém-se no HTML (continua a guardar o valor a
     sério e a disparar "change" -- o resto do código nem sabe que este
     menu existe), só deixa de poder ser clicado diretamente: em
     computador quem abre o menu é sempre o botão ao lado. */
  .toolbar-select-overlay {
    position: absolute; opacity: 0; width: 1px; height: 1px; z-index: -1; pointer-events: none;
  }
  /* "Mais filtros" (ver .more-filters-panel abaixo) é um botão a sério,
     não um <select> escondido por baixo -- fica sempre à vista, também em
     computador (as outras caixas é que escondem o .toolbar-btn). */
  .toolbar-btn.more-filters-btn { display: flex; padding: 12px 16px; }
  .toolbar-btn-wrap.toolbar-btn-wrap-button { padding: 0; }
}
/* Menu próprio que substitui o popup nativo do <select> em computador
   (ver nota acima) -- mesmo fundo/borda/hover do resto da aplicação,
   posicionado mesmo por baixo da caixa (.toolbar-btn-wrap/.more-filters-box
   já ficam "position:relative" para isto se ancorar bem). Criado e
   preenchido por JS (initToolbarDropdown() em branding.js), não existe no
   HTML de origem. Só existe a partir de computador -- em telemóvel o
   próprio <select>, ainda por cima do botão, continua a abrir o seletor
   nativo do telemóvel (esse sim, já é o normal nesse tamanho). */
.toolbar-dropdown { display: none; }
@media (min-width: 769px) {
  .toolbar-dropdown {
    display: flex; flex-direction: column; gap: 2px;
    position: absolute; top: calc(100% + 6px); left: 0; z-index: 30;
    min-width: 100%; width: max-content; max-width: 280px; max-height: 280px; overflow-y: auto;
    background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 12px;
    padding: 6px; box-shadow: 0 16px 32px rgba(0,0,0,0.35);
  }
  .toolbar-dropdown[hidden] { display: none; }
  .toolbar-dropdown-option {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    background: transparent; border: none; border-radius: 8px; padding: 9px 10px;
    font-size: 13px; font-weight: 600; color: var(--text-primary); text-align: left;
    cursor: pointer; font-family: inherit; white-space: nowrap;
  }
  .toolbar-dropdown-option:hover, .toolbar-dropdown-option:focus-visible { background: var(--bg-card-alt); outline: none; }
  .toolbar-dropdown-option[aria-selected="true"] { color: var(--accent); }
  .toolbar-dropdown-option[aria-selected="true"]::after {
    content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); flex-shrink: 0;
  }
}

/* "Mais filtros" -- painel à parte para os filtros menos usados de uma
   lista (ex: "Evento" em Utilizadores, só na Visão Global), aberto/fechado
   pelo botão da barra principal (badge igual a .toolbar-badge quando algo
   lá dentro está ativo). Fica escondido por omissão (atributo "hidden"),
   sempre por baixo da linha principal (nunca ao lado, ver nota acima) --
   ao abrir, mostra os filtros extra cada um na sua própria caixa, na
   MESMA família visual das caixas "Ordenar"/"Estado" (etiqueta fixa +
   <select> à vista), para não parecer um formulário à parte. */
.more-filters-panel {
  display: flex; flex-wrap: wrap; gap: 10px;
  background: var(--bg-card-alt); border: 1px solid var(--border-subtle); border-radius: 12px;
  padding: 14px 16px;
}
.more-filters-panel[hidden] { display: none; }
/* .more-filters-box -- MESMO mecanismo de .toolbar-btn-wrap (etiqueta +
   botão + <select> escondido + menu .toolbar-dropdown, ver acima), só que
   com fundo/borda próprios em qualquer tamanho de ecrã (não está dentro
   de .list-toolbar-row, que é quem dava isso às outras caixas em
   telemóvel) -- por isso continua com o aspeto de caixa à parte tanto em
   telemóvel como em computador, tal como já acontecia antes. A etiqueta
   ("Evento:") também fica sempre à vista aqui (não só a partir de
   computador, ver a regra mais específica abaixo), porque esta caixa
   não faz parte do par "Ordenar/Filtrar" onde a etiqueta simples chega. */
.more-filters-box {
  position: relative; display: flex; align-items: center;
  flex: 1 1 180px; min-width: 160px;
  background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 12px;
}
.more-filters-box .toolbar-box-label { display: inline-block; padding: 10px 0 10px 14px; }
.more-filters-box .toolbar-btn { flex: 1; padding: 10px 12px 10px 4px; }
.more-filters-box .toolbar-btn-mobile-only { display: none; }
.more-filters-box .toolbar-value-text { display: inline-block; }
.more-filters-box .toolbar-chevron { display: inline-flex; color: var(--text-secondary); flex-shrink: 0; margin-left: auto; }

/* Largura máxima do CONTEÚDO em ecrãs muito largos (computador) -- só o
   .main (a área ao lado da barra lateral, essa continua sempre igual);
   sem isto, uma tabela/lista curta ficava esticada de ponta a ponta num
   monitor grande, com colunas a sobrar de espaço vazio no meio. Ecrãs
   normais de portátil (até ~1400px) não são afetados -- só monitores
   mesmo largos ganham margens dos dois lados, tal como a maioria das
   aplicações de gestão faz.
   O "width: 100%" (e não só max-width) é essencial aqui -- sem ele, o
   .main fica sem largura própria definida (só max-width + margin:auto),
   e isso fazia TODO o conteúdo lá dentro (painéis .panel normais e
   grelhas "auto-fit" como as do Dashboard, .stats/#presenceStats) encolher
   para a largura do próprio conteúdo em vez de esticar -- cada painel
   ficava centrado, sozinho, com um vazio à volta, e como cada página tem
   textos/conteúdo de tamanhos diferentes, cada uma ficava com uma largura
   visível diferente (exatamente o bug reportado, visto num monitor
   largo, ≥1400px). Com width:100% a largura de .main fica definida logo
   à partida (100% da coluna do grid .app, depois cortada a 1360px), e os
   filhos voltam todos a esticar até essa largura, iguais em qualquer
   página. */
@media (min-width: 1400px) {
  .main { width: 100%; max-width: 1360px; margin: 0 auto; }
}

/* Linha "Tipo" + "Obrigatória" de uma nova pergunta (invite.html/
   convidados.html) -- em ecrã estreito ficam juntos na linha de baixo do
   "Nova pergunta" (que já ocupa a linha toda sozinho, min-width maior que
   o ecrã), mas por omissão "Tipo" tem largura fixa e "Obrigatória" o
   tamanho do próprio texto, sobrando espaço vazio à direita. Aqui esticam
   os dois para preencherem a linha toda, tal como o resto dos botões desta
   área. */
.question-type-row { display: flex; gap: 10px; align-items: flex-end; }
@media (max-width: 560px) {
  .question-type-row { flex: 1 1 100%; }
  .question-type-row .field-group { flex: 1; min-width: 0; }
  .question-type-row .pill-checkbox { flex: 1; justify-content: center; }
}

/* Campos de ficheiro. O browser desenha aqui um botão cinzento de sistema
   que destoa de tudo o resto (via-se em Marca e em Tipos de letra).
   ::file-selector-button é a única parte de um <input type="file"> que se
   deixa vestir; o texto ao lado ("Nenhum ficheiro selecionado") é escrito
   pelo próprio browser, e desse só se pode mudar a cor -- daí ficar em
   text-muted, discreto, em vez de tentar competir com o botão.

   A maioria dos campos de ficheiro da app nem chega aqui: escondem o input
   e disparam-no a partir de um botão próprio (ver Participantes, Eventos,
   Brindes...). Isto trata dos que ficam à vista, e de qualquer outro que
   venha a aparecer sem se lembrar do padrão. */
input[type="file"] {
  font-family: inherit; font-size: 13px;
  color: var(--text-muted); max-width: 100%;
}
input[type="file"]::file-selector-button {
  font-family: inherit;
  background: transparent; color: var(--text-secondary);
  border: 1px solid var(--border-subtle); border-radius: 10px; padding: 9px 16px;
  margin-right: 10px;
  font-size: 13px; font-weight: 600; cursor: pointer;
}
input[type="file"]::file-selector-button:hover {
  border-color: var(--accent); color: var(--accent);
}
input[type="file"]:focus-visible::file-selector-button {
  outline: 2px solid var(--accent); outline-offset: 2px;
}

/* Par de textos "completo"/"curto" dentro do mesmo link (ver participant.html
   #backLink): em ecrãs estreitos não cabem os dois links da linha "Voltar" /
   "Ver área do participante" lado a lado com o texto todo, por isso troca-se
   para uma versão mais curta em vez de deixar quebrar para duas linhas. */
.link-text-short { display: none; }
@media (max-width: 560px) {
  .link-text-full { display: none; }
  .link-text-short { display: inline; }
}

/* Cards / panels */
.hero {
  background: var(--bg-card); border: 1px solid var(--border-subtle);
  border-radius: 16px; padding: 24px 26px;
  display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 16px;
  margin-bottom: 20px;
}
.hero .eyebrow { font-size: 11px; font-weight: 700; letter-spacing: 0.08em; color: var(--accent); text-transform: uppercase; }
.hero h1 { font-size: 26px; margin: 6px 0 4px; font-weight: 700; }
.hero .meta { font-size: 13px; color: var(--text-secondary); }
.hero-cta {
  display: flex; align-items: center; gap: 8px;
  background: var(--accent); color: var(--accent-text);
  border: none; border-radius: 12px; padding: 13px 20px;
  font-size: 14px; font-weight: 700; cursor: pointer;
}

.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 20px; }
.stat-card { background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 14px; padding: 18px; }
.stat-card .label { font-size: 12px; color: var(--text-muted); }
.stat-card .value { font-size: 30px; font-weight: 700; margin: 8px 0 6px; }
.stat-card .sub { font-size: 11px; color: var(--text-muted); margin-bottom: 10px; }
.stat-bar { height: 3px; border-radius: 2px; background: var(--border-subtle); overflow: hidden; }
.stat-bar > div { height: 100%; background: var(--accent); }

/* Tira compacta de estatísticas — para o topo das próprias páginas de
   listagem (Convidados, Inscrições), ao contrário dos cartões grandes
   (.stats/.stat-card acima), que ficam só no Dashboard (admin.html): aqui
   o objetivo da página é trabalhar a lista, não repetir em destaque o que
   já está no Dashboard a um clique. Uma linha só, com o essencial — o
   detalhe (ex: "3 por enviar") fica no title (tooltip ao passar o rato),
   nunca visível por omissão. Combinar sempre com a classe .panel (fundo/
   borda/padding vêm de lá). */
.stat-strip { display: flex; align-items: center; flex-wrap: wrap; row-gap: 10px; }
.stat-strip-item { display: flex; align-items: baseline; gap: 8px; padding-right: 22px; margin-right: 22px; border-right: 1px solid var(--border-subtle); }
.stat-strip-item:last-child { padding-right: 0; margin-right: 0; border-right: none; }
.stat-strip-item .value { font-size: 22px; font-weight: 700; }
.stat-strip-item .label { font-size: 12px; color: var(--text-muted); }

.panel { background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 16px; padding: 20px 22px; margin-bottom: 20px; }
/* Configuração -- distingue visualmente os painéis de definições/regras
   (aplicam-se ao evento ou ao sistema inteiro, mudam raramente -- ex:
   confirmação de identidade em Convidados, Marca, Modelos de email/SMS/
   WhatsApp, Reentrada/Oferta em Credenciais, Módulos e preços) dos de
   leitura e registo (listas, formulários de criar/editar um registo como
   convidado/prémio/banca/utilizador) -- só os primeiros ganham esta barra
   na cor de destaque do lado esquerdo, os segundos ficam normais. */
.panel-config { border-left: 3px solid var(--accent); }
.panel-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; flex-wrap: wrap; gap: 10px; }
/* A div do label+título -- com "justify-content: space-between" e o ícone
   (.panel-head-icon) inserido por decoratePanelHeadIcons, passam a ser 3
   itens em vez de 2, e o do meio (o título) ficava centrado no espaço
   sobrante em vez de colado ao ícone. Aqui cresce para ocupar esse espaço
   todo, ficando sempre à esquerda -- não muda nada nos cabeçalhos sem
   ícone (só 2 itens), onde já ficava assim. */
.panel-head > div:not(.panel-head-icon) { flex: 1; min-width: 0; }
.panel-head .label { font-size: 11px; letter-spacing: 0.08em; color: var(--text-muted); font-weight: 700; text-transform: uppercase; }
.panel-head .title { font-size: 16px; font-weight: 700; margin-top: 2px; }
.panel-head a.link { font-size: 12px; color: var(--accent); text-decoration: none; font-weight: 600; }

/* Cabeçalho de painel clicável para esconder/mostrar o corpo (ex: "Novo
   convite" e "Importar/exportar CSV" em Inscrições, que ficam escondidos
   por omissão para não atrapalhar quem só quer consultar a lista). */
.panel-head-toggle { cursor: pointer; user-select: none; }
.panel-toggle {
  flex-shrink: 0; width: 30px; height: 30px; border-radius: 8px;
  background: var(--bg-card-alt); border: 1px solid var(--border-subtle); color: var(--text-secondary);
  display: flex; align-items: center; justify-content: center; pointer-events: none;
}
.panel-head-toggle:hover .panel-toggle { color: var(--text-primary); }
.panel-toggle svg { transition: transform 0.2s ease; }
.panel-toggle.open svg { transform: rotate(180deg); }

/* Badge de icone a' esquerda do titulo de um cabecalho recolhivel (ver
   decoratePanelHeadIcons em branding.js) -- mesma familia visual do
   .panel-toggle (badge quadrado arredondado, bg-card-alt), mas na cor de
   destaque do evento, para se distinguir do chevron (esse fica neutro,
   e' so' a seta de abrir/fechar; o icone aqui diz o QUE e' o painel). */
.panel-head-icon {
  flex-shrink: 0; width: 34px; height: 34px; border-radius: 9px;
  background: var(--bg-card-alt); border: 1px solid var(--border-subtle); color: var(--accent);
  display: flex; align-items: center; justify-content: center;
}

.activity-row { display: flex; align-items: center; gap: 14px; padding: 13px 0; border-top: 1px solid var(--border-subtle); }
.activity-row:first-of-type { border-top: none; }
.activity-icon {
  width: 38px; height: 38px; border-radius: 10px;
  background: var(--bg-card-alt); color: var(--text-secondary);
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 700; flex-shrink: 0;
  overflow: hidden;
}
.activity-icon img { width: 100%; height: 100%; object-fit: cover; }
.activity-icon.lg { width: 56px; height: 56px; border-radius: 12px; font-size: 13px; }
.cover-upload {
  width: 100%; max-width: 320px; aspect-ratio: 16/9; border-radius: 12px;
  background: var(--bg-card-alt); border: 1px dashed var(--border-subtle);
  display: flex; align-items: center; justify-content: center;
  color: var(--text-muted); font-size: 12px; overflow: hidden; cursor: pointer;
  text-align: center; padding: 10px;
}
.cover-upload img { width: 100%; height: 100%; object-fit: cover; }
.activity-info { flex: 1; min-width: 120px; }
.activity-info .name { font-size: 14px; font-weight: 600; }
.activity-info .desc { font-size: 12px; color: var(--text-muted); margin-top: 1px; }
/* -------------------------------------------------------------------------
   Cartao de evento (Gerir eventos / Arquivo)

   Antes era uma so' linha com tudo la' dentro e flex-wrap a desenrascar --
   em telemovel os botoes e os estados perdiam-se no meio do texto, sem se
   perceber o que pertencia a que'. Passa a ter tres andares fixos, cada um
   com um assunto:

     1. o logotipo e o link publico de inscricao
     2. o que o evento E' (nome, local, datas, modulos) e em que estado esta'
     3. quanto custa e o que se pode fazer com ele

   Em cada andar, o conteudo fica a' esquerda e o que e' estado/accao a'
   direita. Abaixo de 680px os andares deixam de ser esquerda/direita e
   empilham, com os botoes em coluna e a ocupar a largura toda -- e' isso
   que os torna acertaveis com o dedo.
   ------------------------------------------------------------------------- */
.event-card { padding: 14px 0; border-top: 1px solid var(--border-subtle); }
.event-card:first-of-type { border-top: none; }
.event-card-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; }
.event-card-row + .event-card-row { margin-top: 12px; }
.event-card-row.top { align-items: center; }
.event-card-main { min-width: 0; flex: 1; }
.event-card-side { display: flex; align-items: center; gap: 8px; flex-shrink: 0; flex-wrap: wrap; justify-content: flex-end; }
.event-card-link {
  font-family: monospace; font-size: 11px; color: var(--text-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
.event-card-cost { font-size: 12px; color: var(--text-muted); min-width: 0; }

/* Modulos como siglas (as mesmas do menu). O nome inteiro aparece ao passar
   o rato -- e em telemovel ao tocar, que e' o que a linha .module-hint
   mostra, ja' que la' nao ha' rato para "passar por cima". */
.module-icons { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 7px; }
.module-icon {
  width: 27px; height: 22px; border-radius: 6px;
  background: var(--bg-card-alt); color: var(--text-muted);
  border: 1px solid var(--border-subtle);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 700; flex-shrink: 0;
  cursor: pointer; user-select: none; padding: 0;
}
.module-icon:hover, .module-icon:focus-visible, .module-icon.is-active {
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  border-color: var(--accent); color: var(--accent); outline: none;
}
.module-hint { font-size: 11px; color: var(--text-muted); margin-top: 5px; min-height: 15px; }

@media (max-width: 680px) {
  .event-card-row { flex-direction: column; align-items: stretch; }
  .event-card-row.top { flex-direction: row; align-items: center; }
  .event-card-side { justify-content: flex-start; }
  /* Botoes em coluna e a toda a largura -- em linha ficavam estreitos de
     mais para acertar com o dedo. */
  .event-card-side.actions { flex-direction: column; align-items: stretch; width: 100%; }
  .event-card-side.actions .btn-ghost, .event-card-side.actions .btn-accent { width: 100%; }
}

.activity-count { text-align: right; font-size: 13px; }
.activity-count .num { font-weight: 700; }
.activity-count .lbl { font-size: 11px; color: var(--text-muted); }
.badge { font-size: 11px; font-weight: 700; padding: 4px 10px; border-radius: 999px; background: color-mix(in srgb, var(--accent) 16%, transparent); color: var(--accent); white-space: nowrap; }
.badge-muted { background: var(--bg-card-alt); color: var(--text-muted); }
.badge-warn { background: color-mix(in srgb, var(--warn) 16%, transparent); color: var(--warn); }
.badge-danger { background: color-mix(in srgb, var(--danger) 16%, transparent); color: var(--danger); }
/* Ligado/escolhido (Ativo, Selecionado). O .badge normal fica com a cor da
   marca e continua a servir para o resto (Publicado, Confirmado...) -- isto
   e' so' para o estado ligado/desligado. */
.badge-ok { background: color-mix(in srgb, var(--ok) 16%, transparent); color: var(--ok); }
/* Variante compacta de .badge/.badge-warn — só um ícone (sem texto), para
   colunas de estado binário (feito/por fazer) em listas apertadas, ex. QR e
   Email em participants.html. Mantém a mesma cor de fundo consoante o
   estado; o texto original passa a "title" (tooltip ao passar o rato) e a
   .sr-only (leitores de ecrã), nunca desaparece de vez. */
.badge-icon { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; padding: 0; }
.badge-icon svg { width: 14px; height: 14px; }
/* Quando o badge-ícone é mesmo um <button> (ex: Entrada/Saída em
   participants.html, que abre os detalhes ao tocar) -- limpa o
   aspeto por omissão do botão, mantém só a "pill" do badge. */
button.badge-icon { border: none; cursor: pointer; font: inherit; }

/* Texto só para leitores de ecrã — visível ao teclado/tecnologia de apoio,
   removido do layout visual (ex. dentro de .badge-icon acima). */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }

/* Table */
table.data-table { width: 100%; border-collapse: collapse; font-size: 13px; }
/* Tabelas largas rolam DENTRO deste recipiente, em vez de empurrarem a
   pagina inteira para o lado. Uma tabela nao encolhe abaixo da largura das
   suas colunas -- por isso "max-width: 100%" nao resolve nada aqui, so'
   esconde o problema: continuava a alargar o documento e a app inteira
   deslizava. O recipiente e' posto por wrapWideTables() em branding.js, para
   nao ser preciso mexer no HTML das 11 paginas que tem tabelas. */
.table-scroll { display: block; position: relative; width: 100%; max-width: 100%; overflow-x: auto; }
/* Com um menu aberto, o recipiente deixa de cortar.
   `overflow-x: auto` não se consegue combinar com `overflow-y: visible`: o
   CSS transforma o outro eixo em `auto` também. Resultado, visto a 18/9 na
   lista de ecrãs: ao abrir o menu dos três pontos ele era desenhado DENTRO
   desta caixa, ficava cortado por baixo da última linha, e aparecia uma
   barra de deslocamento vertical que não era de ninguém. Carregava-se nos
   três pontos e "não acontecia nada".
   Enquanto o menu está aberto a caixa não corta -- e o deslocamento
   horizontal não faz falta nesse instante. */
.table-scroll.com-menu-aberto { overflow: visible; }

.data-table th { text-align: left; font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.05em; font-weight: 700; padding: 0 10px 10px; }
.data-table td { padding: 12px 10px; border-top: 1px solid var(--border-subtle); }
.data-table tr:first-child td { border-top: none; }
.data-table td.muted { color: var(--text-muted); }
/* Grelha de informação só de leitura (ex: participant.html — ficha
   completa do participante) — mesma linguagem visual de .field-group,
   mas sem inputs, só rótulo + valor. */
.info-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 18px 24px; }
.info-item .info-label { font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.05em; font-weight: 700; margin-bottom: 6px; }
.info-item .info-value { font-size: 14px; color: var(--text-primary); }

/* Par data+hora ao lado de um badge (ex: "Aceite em ...", QR/Email — ver
   participant.html) — data numa linha, hora (HH:MM, 24h) por baixo, em vez
   do timestamp ISO em bruto numa única linha comprida e mal alinhada. */
.dt-stack { display: inline-flex; flex-direction: column; gap: 1px; line-height: 1.3; }
.dt-stack .dt-date, .dt-stack .dt-time { font-size: 11px; color: var(--text-muted); }

/* Forms */
.field-group { display: flex; flex-direction: column; gap: 8px; }
.field-group label { font-size: 12px; color: var(--text-secondary); font-weight: 600; }
/* `input:not([type])` está aqui porque estes são seletores de ATRIBUTO, e
   um <input> escrito sem type nenhum comporta-se como texto mas não
   corresponde a "input[type=text]". Ficava com o cinzento de fábrica do
   Chrome (rgb(59,59,59)) no meio de um ecrã escuro -- foi o que apareceu
   no assistente de Atividades (11/9): a Descrição, que é um textarea,
   certa; o Nome e a Capacidade, que são inputs sem type, cinzentos.
   Corrigir aqui e não nos oito inputs em causa é o que impede o próximo:
   o erro não é de quem escreveu o HTML, é do seletor ser exigente.

   E aconteceu outra vez, a 14/9, com os campos de hora: a lista dizia
   text/email/tel/date/number/password/search, e `time` não estava lá.
   Escrever mais um nome na lista era repetir o erro que o parágrafo acima
   descreve -- por isso a lista passou ao contrário: veste-se TODOS os
   campos de escrever, e tiram-se os que têm aspeto próprio (caixas de
   seleção, cores, ficheiros, botões). O próximo tipo de campo que
   aparecer já nasce vestido.

   O `:where()` à volta dos `:not()` não é enfeite: cada `:not([type=x])`
   conta como um seletor de atributo, e dez deles fazem desta a regra mais
   FORTE da folha inteira. Passava a ganhar a regras escritas de propósito
   para a contrariar -- a caixa de procura das listas, que é sem moldura
   nem enchimento; a caixa do código dos ecrãs públicos, que é a 16px para
   se ler de longe; o campo com o botão do olho, que abre espaço à direita.
   Nenhuma dava erro: ficavam simplesmente com o aspeto de um campo
   qualquer. `:where()` vale zero, e assim esta volta a ser o que devia
   ser -- o fundo por cima do qual as outras escrevem. */
input:where(:not([type=checkbox]):not([type=radio]):not([type=color]):not([type=file]):not([type=range]):not([type=submit]):not([type=button]):not([type=reset]):not([type=image]):not([type=hidden])),
select, textarea {
  background: var(--bg-card-alt); border: 1px solid var(--border-subtle);
  border-radius: 8px; color: var(--text-primary); padding: 10px 12px; font-size: 13px;
  font-family: inherit;
}
/* O relógio e o calendário que o PRÓPRIO browser desenha dentro do campo.
   `color-scheme: dark` já os devia escurecer sozinho, mas o Chrome desenha
   o ícone a preto por cima de um fundo escuro -- fica um borrão. Inverte-se
   e baixa-se a opacidade, para ficar da cor do texto secundário à volta. */
input::-webkit-calendar-picker-indicator {
  filter: invert(1); opacity: 0.55; cursor: pointer;
}
input::-webkit-calendar-picker-indicator:hover { opacity: 1; }

/* O relógio do campo de hora -- o NOSSO. (Ver shared/escolher-hora.js: o
   do browser abre uma janela que é dele, e essa não se veste.) O painel
   fica preso à caixa do campo, por isso a caixa é que manda no
   posicionamento. */
.hora-wrap { position: relative; display: flex; align-items: center; width: 100%; }
.hora-wrap > input { flex: 1; min-width: 0; padding-right: 34px; }
.hora-abrir {
  position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
  background: none; border: none; padding: 6px; margin: 0; cursor: pointer;
  color: var(--text-muted); display: flex; align-items: center; border-radius: 6px;
}
.hora-abrir:hover { color: var(--text-primary); background: var(--bg-card); }
.hora-painel {
  position: absolute; z-index: 60; top: calc(100% + 6px); left: 0;
  background: var(--bg-card); border: 1px solid var(--border-subtle);
  border-radius: 10px; box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
  padding: 8px; min-width: 150px;
}
.hora-painel[hidden] { display: none; }
/* Nos campos do fundo de um formulário a lista abria fora do ecrã. */
.hora-painel.para-cima { top: auto; bottom: calc(100% + 6px); }
.hora-colunas { display: flex; gap: 6px; }
.hora-coluna {
  max-height: 188px; overflow-y: auto; display: flex; flex-direction: column;
  gap: 2px; flex: 1; scrollbar-width: thin;
}
.hora-opcao {
  background: none; border: none; border-radius: 6px; color: var(--text-secondary);
  font-family: inherit; font-size: 13px; padding: 6px 10px; cursor: pointer;
  text-align: center; line-height: 1.2;
}
.hora-opcao:hover { background: var(--bg-card-alt); color: var(--text-primary); }
.hora-opcao[aria-selected="true"] { background: var(--accent); color: var(--accent-text); font-weight: 700; }
.hora-rodape {
  display: flex; justify-content: flex-end; margin-top: 6px;
  border-top: 1px solid var(--border-subtle); padding-top: 6px;
}
.hora-limpar {
  background: none; border: none; color: var(--text-muted); font-family: inherit;
  font-size: 12px; cursor: pointer; padding: 4px 8px; border-radius: 6px;
}
.hora-limpar:hover { color: var(--danger); background: var(--bg-card-alt); }

/* E o calendário -- também o nosso. (Ver shared/escolher-data.js.) */
.data-wrap { position: relative; display: flex; align-items: center; width: 100%; }
.data-wrap > input { flex: 1; min-width: 0; padding-right: 34px; cursor: pointer; }
.data-abrir {
  position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
  background: none; border: none; padding: 6px; margin: 0; cursor: pointer;
  color: var(--text-muted); display: flex; align-items: center; border-radius: 6px;
}
.data-abrir:hover { color: var(--text-primary); background: var(--bg-card); }
.data-painel {
  position: absolute; z-index: 60; top: calc(100% + 6px); left: 0;
  background: var(--bg-card); border: 1px solid var(--border-subtle);
  border-radius: 10px; box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
  padding: 10px; width: 252px;
}
.data-painel[hidden] { display: none; }
.data-painel.para-cima { top: auto; bottom: calc(100% + 6px); }
.data-cabeca { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.data-mes { font-size: 13px; font-weight: 700; color: var(--text-primary); }
.data-passo {
  background: none; border: none; color: var(--text-secondary); cursor: pointer;
  font-size: 18px; line-height: 1; padding: 2px 8px; border-radius: 6px;
}
.data-passo:hover { background: var(--bg-card-alt); color: var(--text-primary); }
.data-semana, .data-grelha { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.data-semana span {
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--text-muted); text-align: center; padding-bottom: 4px;
}
.data-dia {
  background: none; border: none; border-radius: 6px; color: var(--text-secondary);
  font-family: inherit; font-size: 12px; padding: 6px 0; cursor: pointer; text-align: center;
}
.data-vazio { visibility: hidden; }
.data-dia:hover:not(:disabled) { background: var(--bg-card-alt); color: var(--text-primary); }
.data-dia:disabled { opacity: 0.3; cursor: not-allowed; }
/* Hoje marca-se com um ponto e não só com cor -- ao lado do dia escolhido,
   duas cores parecidas não se distinguem a olho. */
.data-dia.data-e-hoje { color: var(--text-primary); font-weight: 700; }
.data-dia[aria-selected="true"] { background: var(--accent); color: var(--accent-text); font-weight: 700; }
.data-rodape {
  display: flex; justify-content: space-between; margin-top: 8px;
  border-top: 1px solid var(--border-subtle); padding-top: 6px;
}
.data-hoje, .data-limpar {
  background: none; border: none; color: var(--text-muted); font-family: inherit;
  font-size: 12px; cursor: pointer; padding: 4px 8px; border-radius: 6px;
}
.data-hoje:hover { color: var(--accent); background: var(--bg-card-alt); }
.data-limpar:hover { color: var(--danger); background: var(--bg-card-alt); }

input[type=color] { width: 40px; height: 34px; border-radius: 8px; border: 1px solid var(--border-subtle); background: transparent; cursor: pointer; padding: 2px; }
.password-field-wrap { position: relative; display: flex; width: 100%; }
.password-field-wrap input[type=text], .password-field-wrap input[type=password] { width: 100%; padding-right: 38px; }
.password-toggle-btn {
  position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
  background: none; border: none; padding: 6px; margin: 0; cursor: pointer;
  color: var(--text-muted); display: flex; align-items: center; justify-content: center;
  border-radius: 6px;
}
.password-toggle-btn:hover { color: var(--text-primary); background: var(--bg-card); }

.swatches { display: flex; gap: 6px; margin-left: 4px; }
.swatch { width: 22px; height: 22px; border-radius: 6px; cursor: pointer; border: 1px solid var(--border-subtle); }

/* Campo de resultado tipo "tempo" (Min:Seg.Mil) em 3 caixas separadas, em
   vez de um único campo de texto livre (ex: "1:42.318") — mais fácil de ler
   e preencher no telemóvel/tablet, sobretudo por quem está de pé numa banca
   (ver Checkpoint/checkin.html). Atividades de pontuação continuam com um
   único campo numérico (ver .time-input-group ao lado de input#...Value). */
.time-input-group { display: flex; align-items: flex-end; gap: 8px; }
.time-input-group .time-field { flex: 1 1 0; max-width: 92px; }
.time-input-group .time-field span { display: block; font-size: 10px; letter-spacing: 0.06em; color: var(--text-muted); font-weight: 700; text-transform: uppercase; margin-bottom: 5px; }
.time-input-group .time-sep { padding-bottom: 11px; font-size: 20px; font-weight: 700; color: var(--text-muted); }
.time-box { width: 100%; text-align: center; font-size: 22px; font-weight: 700; padding: 11px 4px; }

/* Confirmação explícita ao retificar um resultado já registado — caixa com
   checkbox obrigatório antes de aceitar a retificação, em vez de um
   confirm() nativo do browser (pouco claro/incómodo no telemóvel ou
   tablet que o Promotor normalmente usa numa banca). */
.confirm-box {
  display: flex; align-items: flex-start; gap: 10px; cursor: pointer; user-select: none;
  background: var(--bg-card-alt); border: 1px solid color-mix(in srgb, var(--warn) 35%, transparent);
  border-radius: 10px; padding: 12px 14px;
}
.confirm-box input { width: auto; margin: 3px 0 0; flex-shrink: 0; }
.confirm-box strong { font-size: 13px; }
.confirm-box p { font-size: 12px; color: var(--text-muted); margin: 4px 0 0; }

/* Guest-facing (no sidebar) */
.guest-page { min-height: 100vh; display: flex; align-items: flex-start; justify-content: center; padding: 48px 20px; }
.guest-card { width: 100%; max-width: 480px; background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 16px; padding: 32px; }
.guest-brand { display: flex; align-items: center; gap: 10px; margin-bottom: 24px; }
/* ---------------------------------------------------------------------
   O TEXTO LEGAL DO BOLETIM
   ---------------------------------------------------------------------
   Era uma caixa cinzenta com `textContent` lá dentro: os termos de um
   concurso -- quarenta linhas vindas de um Word, com títulos, alíneas e
   datas -- chegavam ao ecrã como UM parágrafo de 900 palavras. Ninguém
   lê aquilo, e a caixa "Li e aceito" por baixo passa a ser uma mentira
   educada.

   Agora tem forma (ver shared/texto-legal.js) e uma altura: o texto está
   TODO lá, rola dentro da caixa, e há um botão para o abrir por inteiro.
   Nada é cortado nem escondido -- quem aceita tem de poder ler tudo, e o
   que se resolve aqui é o tamanho que a coisa ocupa no formulário, não o
   acesso ao texto. */
.gdpr-note { font-size: 12px; color: var(--text-muted); background: var(--bg-card-alt); border-radius: 10px; padding: 12px 14px; margin-top: 6px; line-height: 1.5; }
.gdpr-caixa { background: var(--bg-card-alt); border: 1px solid var(--border-subtle); border-radius: 12px; margin-top: 6px; overflow: hidden; }
.gdpr-caixa .cabeca { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
                      padding: 10px 14px; border-bottom: 1px solid var(--border-subtle); }
.gdpr-caixa .cabeca .quanto { flex: 1; min-width: 120px; font-size: 11.5px; color: var(--text-muted); }
.gdpr-caixa .cabeca button { background: none; border: 0; padding: 4px 8px; border-radius: 8px; cursor: pointer;
                             font-size: 12px; font-weight: 700; color: var(--text-secondary); }
.gdpr-caixa .cabeca button:hover { color: var(--text-primary); background: var(--bg-card); }
.gdpr-caixa .cabeca button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* A altura fechada mostra o princípio e diz, pela barra de deslocamento,
   que há mais. Um texto cortado sem sinal nenhum é o que faz alguém
   aceitar sem saber que faltava metade. */
.gdpr-corpo { max-height: 240px; overflow-y: auto; padding: 4px 14px 12px;
              font-size: 12.5px; color: var(--text-secondary); line-height: 1.6; }
.gdpr-corpo.aberto { max-height: none; overflow-y: visible; }
.gdpr-corpo h4 { font-size: 13px; font-weight: 700; color: var(--text-primary); margin: 16px 0 6px; }
.gdpr-corpo h4:first-child { margin-top: 8px; }
.gdpr-corpo p { margin: 0 0 10px; }
.gdpr-corpo ul { margin: 0 0 12px; padding-left: 18px; }
.gdpr-corpo li { margin-bottom: 4px; }
.gdpr-corpo strong { color: var(--text-primary); }
.gdpr-corpo > :last-child { margin-bottom: 0; }

/* Ecrã cheio do código QR (guest-portal.html) — mesmo padrão de cartão de
   embarque/passe de app de telemóvel: fundo escuro sólido, cartão claro ao
   centro só com o QR e o essencial, para ler bem mesmo com o ecrã no
   máximo de brilho. Sempre fundo/texto próprios (não var(--bg-card) etc.)
   porque tem de ficar sempre escuro por trás e sempre claro no cartão,
   mesmo em tema claro — é para ler à entrada, não para combinar com o
   resto da app. */
.qr-overlay {
  position: fixed; inset: 0; background: #05060a;
  display: flex; align-items: center; justify-content: center;
  z-index: 1000; padding: 20px;
  opacity: 0; pointer-events: none; transition: opacity 0.18s ease;
}
.qr-overlay.open { opacity: 1; pointer-events: auto; }
.qr-card {
  width: 100%; max-width: 340px; background: #ffffff; color: #0b0d12;
  border-radius: 20px; padding: 28px 24px 24px; text-align: center;
  transform: scale(0.96); transition: transform 0.18s ease;
}
.qr-overlay.open .qr-card { transform: scale(1); }
.qr-card canvas { width: 100%; height: auto; max-width: 260px; image-rendering: pixelated; }
.qr-close {
  position: absolute; top: 18px; right: 18px; width: 38px; height: 38px; border-radius: 50%;
  background: rgba(255,255,255,0.1); border: none; color: #fff; font-size: 18px; line-height: 1;
  cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.qr-close:hover { background: rgba(255,255,255,0.18); }

/* Overlay de transição entre papéis (evita o "flash" de conteúdo trocado
   durante o reload completo de página — ver branding.js) */
.role-transition-overlay {
  position: fixed; inset: 0; background: var(--bg-page);
  z-index: 9999; opacity: 1; transition: opacity 0.12s ease;
}
.role-transition-overlay.hide { opacity: 0; pointer-events: none; }

/* Linha da marca no topo da sidebar + sino de notificações (só Super
   Admin — ver renderNotificationBell em branding.js) lado a lado. */
.sidebar-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 6px; }
.notif-bell {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: 9px; margin-top: 2px;
  text-decoration: none; color: var(--accent); flex-shrink: 0;
}
.notif-bell:hover { background: var(--bg-card-alt); }
.notif-badge {
  position: absolute; top: -4px; right: -4px; min-width: 16px; height: 16px; padding: 0 3px;
  border-radius: 999px; background: var(--danger); color: #fff; font-size: 10px; font-weight: 700;
  line-height: 16px; text-align: center;
}

/* Popup de confirmação (toast) — ver showToast/queueToast em branding.js.
   Aparece a meio-baixo do ecrã e desaparece sozinho; não bloqueia nada,
   por isso não precisa de overlay nem de botão para fechar. */
.toast {
  position: fixed; left: 50%; bottom: 28px; transform: translateX(-50%) translateY(6px);
  display: flex; align-items: center; gap: 10px;
  background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 12px;
  padding: 12px 18px; box-shadow: 0 12px 32px rgba(0,0,0,0.45);
  font-size: 13px; font-weight: 600; color: var(--text-primary);
  z-index: 600; opacity: 0; pointer-events: none;
  transition: opacity 0.25s ease, transform 0.25s ease;
  max-width: calc(100vw - 40px);
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast-icon {
  flex-shrink: 0; width: 20px; height: 20px; border-radius: 50%;
  background: #4ADE80; color: #06210f; font-size: 12px; font-weight: 800;
  display: flex; align-items: center; justify-content: center;
}

/* Popup modal genérico (ex: pedido de módulo em falta — ver
   openModuleRequestPopup em branding.js). Fecha ao clicar fora. */
/* Acima da folha (520), e não abaixo.
   Uma confirmação aberta DE DENTRO de uma folha ficava por trás dela: via-
   se o escurecido e não se via a pergunta, e o botão não se conseguia
   carregar. Descoberto a 14/9 ao pôr um "Cancelar envio" numa folha -- e
   o botão de confirmar era impossível de tocar. Uma pergunta é sempre a
   coisa mais recente no ecrã: fica por cima do que a fez aparecer. */
.modal-overlay {
  position: fixed; inset: 0; background: rgba(6,4,14,0.6);
  display: flex; align-items: center; justify-content: center; z-index: 540; padding: 20px;
}
.modal-box { background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 14px; padding: 24px; max-width: 420px; width: 100%; }
.modal-title { font-size: 16px; font-weight: 700; margin-bottom: 10px; }
.modal-text { font-size: 13px; color: var(--text-secondary); line-height: 1.5; margin: 0 0 20px; }
.modal-actions { display: flex; gap: 10px; justify-content: flex-end; flex-wrap: wrap; }

/* =========================================================================
   FOLHA — a mesma caixa de diálogo no portátil e no telemóvel
   =========================================================================
   No ecrã largo é uma caixa ao centro; no telemóvel sobe do fundo, com a
   pega em cima e a acabar na safe area. É a MESMA coisa e o mesmo código:
   um modal ao centro num telemóvel fica preso entre o teclado virtual e o
   topo, e uma bottom sheet num monitor de 27 polegadas é uma tira a
   atravessar o ecrã. Ver abrirFolha() em shared/branding.js -- que trata
   também do foco, do Escape e do anúncio para leitores de ecrã.

   Os controlos têm 48px de altura mínima: isto é usado de pé, com o
   telemóvel numa mão e a fila à espera. */
.folha-fundo {
  position: fixed; inset: 0; background: rgba(6,4,14,0.6); z-index: 520;
  display: flex; align-items: center; justify-content: center; padding: 20px;
}
.folha {
  background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 16px;
  width: 100%; max-width: 560px; max-height: min(88vh, 900px); overflow-y: auto;
  padding: 22px;
}
/* Duas colunas lado a lado (ex: os dois QR de "Partilhar classificações")
   não cabem nos 560px de uma folha normal -- e encolher os QR até caberem
   dava dois códigos que a câmara já não lê à distância a que se lê um
   cartaz. */
.folha-larga { max-width: 860px; }
.folha-pega { display: none; }
.folha-topo { display: flex; align-items: flex-start; gap: 14px; margin-bottom: 18px; }
.folha-icone {
  width: 44px; height: 44px; border-radius: 12px; flex-shrink: 0;
  background: var(--bg-card-alt); border: 1px solid var(--border-subtle);
  display: flex; align-items: center; justify-content: center; color: var(--accent);
}
.folha-titulos { flex: 1; min-width: 0; }
.folha-titulo { font-size: 18px; font-weight: 800; }
.folha-sub { font-size: 13px; color: var(--text-muted); margin-top: 2px; }
.folha-fechar {
  background: none; border: 1px solid var(--border-subtle); border-radius: 10px;
  /* 48px como tudo o resto aqui dentro: isto é usado de pé, com o
     telemóvel numa mão. */
  width: 48px; height: 48px; color: var(--text-secondary); cursor: pointer; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
}
.folha-fechar:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.folha-nota {
  display: flex; gap: 12px; align-items: flex-start; font-size: 13px; color: var(--text-secondary);
  background: var(--bg-card-alt); border: 1px solid var(--border-subtle); border-radius: 12px;
  padding: 12px 14px; margin-top: 12px;
}
.folha-nota.aviso { border-color: color-mix(in srgb, var(--warn) 45%, transparent); color: var(--warn); }
.folha-nota.erro { border-color: color-mix(in srgb, var(--danger) 45%, transparent); color: var(--danger); }
.folha-nota.ok { border-color: color-mix(in srgb, var(--ok) 45%, transparent); color: var(--ok); }
.folha-nota strong { color: inherit; }
/* "Mostrar mais" no fim de uma lista longa. Ocupa a largura toda porque
   é o fim da lista e não uma ação ao lado das outras -- e porque num
   telemóvel um alvo estreito no fim de 120 linhas não se acerta. */
.in-mostrar-mais {
  display: block; width: 100%; padding: 14px; min-height: 48px;
  background: var(--bg-card-alt); border: 1px dashed var(--border-subtle);
  border-radius: 12px; color: var(--text-secondary); font-family: inherit;
  font-size: 13px; cursor: pointer; margin-top: 8px;
}
.in-mostrar-mais:hover { color: var(--text-primary); border-color: var(--accent); }

.folha-accoes { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 20px; }
/* 48px é o tamanho .btn-lg da escala: a ação que fecha uma folha é a
   ação que fecha um ecrã. Fica aqui para não ter de se escrever a classe
   em cada folha. */
.folha-accoes .btn-accent, .folha-accoes .btn-ghost { min-height: 48px; }
.folha-accoes .principal { margin-left: auto; }

@media (max-width: 720px) {
  .folha-fundo { align-items: flex-end; padding: 0; }
  .folha {
    max-width: none; border-radius: 20px 20px 0 0; border-bottom: 0;
    max-height: 92vh; padding: 8px 18px calc(18px + env(safe-area-inset-bottom, 0px));
  }
  /* A pega diz "isto sobe do fundo e volta a descer" sem ninguém explicar. */
  .folha-pega { display: block; width: 46px; height: 5px; border-radius: 3px; background: var(--border-subtle); margin: 6px auto 14px; }
  .folha-accoes { flex-direction: column-reverse; }
  .folha-accoes .btn-accent, .folha-accoes .btn-ghost { width: 100%; justify-content: center; }
  .folha-accoes .principal { margin-left: 0; }
}

/* =========================================================================
   RESUMO DE UMA LISTA — a faixa de números por cima dos separadores
   ========================================================================= */
.lista-resumo {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  border: 1px solid var(--border-subtle); border-radius: 16px; background: var(--bg-card);
  margin-bottom: 18px; overflow: hidden;
}
.lista-metrica { display: flex; align-items: center; gap: 14px; padding: 18px 20px; border-left: 1px solid var(--border-subtle); }
.lista-metrica:first-child { border-left: 0; }
.lista-metrica .icone {
  width: 44px; height: 44px; border-radius: 12px; flex-shrink: 0;
  background: var(--bg-card-alt); display: flex; align-items: center; justify-content: center; color: var(--text-secondary);
}
.lista-metrica .valor { font-size: 26px; font-weight: 800; line-height: 1; }
.lista-metrica .nome { font-size: 13px; color: var(--text-muted); margin-top: 4px; }
.lista-metrica.aviso .icone { color: var(--warn); background: color-mix(in srgb, var(--warn) 14%, transparent); }
.lista-metrica.perigo .icone { color: var(--danger); background: color-mix(in srgb, var(--danger) 14%, transparent); }
.lista-metrica.bom .icone { color: var(--ok); background: color-mix(in srgb, var(--ok) 14%, transparent); }
@media (max-width: 900px) {
  .lista-metrica { border-left: 0; border-top: 1px solid var(--border-subtle); }
  .lista-metrica:first-child { border-top: 0; }
}

/* Scanner */
.scanner-frame {
  aspect-ratio: 4/3; max-width: 420px; border-radius: 16px;
  background: var(--bg-card-alt); border: 1px dashed var(--border-subtle);
  display: flex; align-items: center; justify-content: center; flex-direction: column; gap: 10px;
  color: var(--text-muted); font-size: 13px;
}

/* Identificação em Checkpoint (pesquisa manual + câmara/QR lado a lado —
   ver #scannerPanelBody em checkin.html). Em telemóvel/tablet vertical, os
   240px fixos da coluna da câmara já não cabem confortavelmente ao lado da
   pesquisa — empilha-se numa coluna só, pesquisa primeiro (a forma mais
   usada sem câmara real neste protótipo). */
.scanner-id-grid { display: grid; grid-template-columns: 1fr 240px; gap: 24px; align-items: start; }
@media (max-width: 640px) {
  .scanner-id-grid { grid-template-columns: 1fr; }
}

/* -------------------------------------------------------------------------
   Checkpoint — o ecrã que se usa em pé, ao sol, com uma mão e fila à espera
   -------------------------------------------------------------------------
   Coluna única, sempre: a leitura do QR é o centro da página e nada lhe
   deve ficar ao lado a disputar a atenção. Antes a pesquisa manual e a
   câmara partilhavam a linha (.scanner-id-grid) e, no ecrã largo, a câmara
   ficava numa coluna de 240 px -- pequena de mais para a coisa mais
   importante que ali se faz. Agora são dois modos do mesmo cartão.
   ------------------------------------------------------------------------- */
.cp-coluna { max-width: 620px; margin: 0 auto; }

/* Ponto de leitura: uma linha compacta. Escolhe-se uma vez ao início do
   turno; quem tem de estar à vista, sem scroll nenhum, é o leitor. */
/* O ponto de leitura vive no cabeçalho, ao lado do estado da ligação --
   o mesmo sítio e o mesmo aspeto do seletor de atividade em
   Classificações. Escolhe-se uma vez por turno; o que ali se usa dezenas
   de vezes é o leitor, e era ele que estava a pagar este espaço. */
.page-header .ev-acoes select { min-height: 44px; font-weight: 700; max-width: 260px; }
.cp-ponto-nota { font-size: 12px; color: var(--text-muted); margin: -6px 0 14px; line-height: 1.5; }
.cp-ponto-nota:empty { display: none; }

/* Barras de deslocamento no tema, também nos browsers que só entendem a
   versão -webkit- (é o caso do Chrome em Android, que é o que está nos
   tablets do evento). */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--border-subtle); border-radius: 8px;
  border: 2px solid transparent; background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--text-muted); background-clip: padding-box; }
::-webkit-scrollbar-corner { background: transparent; }

/* Escolher entre ler o QR e pesquisar. Dois botões grandes, com ícone e
   texto -- nunca só o ícone (ver acessibilidade: uma ação importante não
   se explica por um desenho). */
.cp-modos {
  display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
  padding: 5px; border-radius: 14px; background: var(--bg-card-alt);
  border: 1px solid var(--border-subtle); margin-bottom: 16px;
}
.cp-modos button {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 48px; padding: 10px 12px; border-radius: 10px;
  border: 1px solid transparent; background: none; color: var(--text-secondary);
  font: inherit; font-weight: 700; font-size: 14px; cursor: pointer;
}
.cp-modos button[aria-pressed="true"] {
  background: color-mix(in srgb, var(--ok) 14%, transparent);
  border-color: color-mix(in srgb, var(--ok) 55%, transparent);
  color: var(--ok);
}
.cp-modos button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Área da câmara: o maior elemento da página. Em telemóvel ocupa a largura
   toda; em ecrã largo fica quadrada, que é a forma que melhor enquadra um
   QR sem obrigar a afastar o telemóvel do participante. */
.cp-camara {
  position: relative; width: 100%; aspect-ratio: 1 / 1; max-height: 62vh;
  border-radius: 16px; overflow: hidden;
  background: #05060a; border: 1px solid var(--border-subtle);
  display: flex; align-items: center; justify-content: center;
}
.cp-camara video { width: 100%; height: 100%; object-fit: cover; }
.cp-camara-vazia {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 12px; padding: 24px;
  text-align: center; color: var(--text-secondary); font-size: 14px; line-height: 1.5;
}
/* Os quatro cantos do enquadramento. Não são decoração: são o que diz a
   quem está a segurar o telemóvel onde tem de pôr o QR. */
.cp-cantos { position: absolute; inset: 14px; pointer-events: none; }
.cp-cantos span {
  position: absolute; width: 34px; height: 34px;
  border: 3px solid var(--ok); border-radius: 4px;
}
.cp-cantos span:nth-child(1) { top: 0; left: 0; border-right: 0; border-bottom: 0; }
.cp-cantos span:nth-child(2) { top: 0; right: 0; border-left: 0; border-bottom: 0; }
.cp-cantos span:nth-child(3) { bottom: 0; left: 0; border-right: 0; border-top: 0; }
.cp-cantos span:nth-child(4) { bottom: 0; right: 0; border-left: 0; border-top: 0; }
/* Linha de leitura -- discreta, e parada quando a câmara está parada
   (animações longas num ecrã que se usa horas seguidas cansam). */
.cp-linha {
  position: absolute; left: 14px; right: 14px; height: 2px;
  background: linear-gradient(90deg, transparent, var(--ok), transparent);
  animation: cp-varrer 2.6s ease-in-out infinite;
}
@keyframes cp-varrer {
  0%, 100% { top: 20%; opacity: 0.35; }
  50% { top: 80%; opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .cp-linha { animation: none; top: 50%; }
}

/* =========================================================================
   O LEITOR EM ECRÃ INTEIRO
   =========================================================================
   Com a câmara ligada, a página deixa de rolar e o leitor toma conta do
   ecrã. Isto não é enfeite: num tablet de 8-9" a câmara ficava maior do
   que o ecrã, os botões "Parar"/"Luz" caíam abaixo da dobra, e o dedo
   pousado na imagem a tentar enquadrar o QR arrastava a página. Ou seja,
   o gesto natural de usar um leitor era exactamente o gesto que o
   estragava.
   ========================================================================= */
body.cp-a-ler { overflow: hidden; }
/* A sidebar e o resto da página ficam por baixo -- o leitor é uma coisa de
   cada vez, e enquanto dura não há mais nada para ver. */
body.cp-a-ler #modoQr {
  position: fixed; inset: 0; z-index: 300;
  display: flex; flex-direction: column; gap: 0;
  background: var(--bg-page, #0b0d14);
  padding: 0 0 env(safe-area-inset-bottom);
  overscroll-behavior: contain;
}
/* Uma tira no topo a dizer ONDE se está a ler. Num turno de horas, com
   vários pontos de leitura no mesmo evento, é a única coisa que impede
   alguém de registar meia fila no sítio errado. */
.cp-leitor-topo {
  display: none; align-items: center; justify-content: space-between; gap: 12px;
  padding: calc(10px + env(safe-area-inset-top)) 16px 10px;
  border-bottom: 1px solid var(--border-subtle); background: var(--bg-card);
  /* Encostada ao topo, e fora da conta da centragem: senão o conteúdo
     centrava-se com ela dentro e a tira ficava a boiar a meio do ecrã. */
  position: absolute; top: 0; left: 0; right: 0;
}
body.cp-a-ler .cp-leitor-topo { display: flex; }
.cp-leitor-topo .onde { min-width: 0; }
.cp-leitor-topo .etiqueta {
  font-size: 10px; font-weight: 700; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--text-muted);
}
.cp-leitor-topo .nome {
  font-size: 15px; font-weight: 700; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
/* Um botão-fantasma num canto, sobre uma tira escura, com o tablet a ser
   segurado pelo outro lado: era pouco. Passa a ter contorno e peso -- é a
   saída do ecrã inteiro, e tem de se ver que é. */
.cp-leitor-topo button {
  min-height: 48px; min-width: 88px; flex-shrink: 0;
  border: 1px solid var(--border-subtle); background: var(--bg-card-alt);
  color: var(--text-primary); font-weight: 700;
}

body.cp-a-ler .cp-camara {
  /* Sempre INTEIRA no ecrã, com margem para os botões. Antes era
     `aspect-ratio: 3/4` com `max-height: none`, o que num tablet dava uma
     imagem mais alta do que a janela. */
  width: min(88vw, 60vh, 520px); height: min(88vw, 60vh, 520px);
  aspect-ratio: auto; max-height: none;
  margin: 0 auto; border-radius: 18px; border: 1px solid var(--border-subtle);
  flex-shrink: 0;
  /* O dedo pousado na imagem a enquadrar o QR não pode arrastar nada. */
  touch-action: none;
}
/* Fica o essencial: a câmara, os botões dela, e a saída para a pesquisa
   manual -- que NÃO é um extra. Quando um QR não lê (ecrã riscado, sol a
   bater, telemóvel sem bateria), procurar o nome é como o evento continua,
   e esconder isso obrigava a sair do leitor primeiro. */
body.cp-a-ler #modoQr > *:not(.cp-camara):not(.cp-camara-botoes):not(.cp-leitor-topo):not(#irParaPesquisaBtn) { display: none; }

/* -------------------------------------------------------------------------
   E COM A CÂMARA PARADA, NÃO HÁ CÂMARA NENHUMA PARA VER
   -------------------------------------------------------------------------
   O retângulo preto só existe para se tornar o leitor em ecrã inteiro.
   Parado, era uma janela morta de meio ecrã a dizer "toque em Ligar
   câmara" -- empurrava para baixo o ponto de leitura e os botões, que é
   exactamente o que obrigava a rolar. Agora encolhe a uma linha: o que
   fica à vista é a ação (Ligar câmara) e o que se pode mudar antes de
   ler (o ponto de leitura, no cabeçalho).
   ------------------------------------------------------------------------- */
body:not(.cp-a-ler) .cp-camara {
  aspect-ratio: auto; height: auto; min-height: 0; max-height: none;
  background: var(--bg-card-alt); border-radius: 12px;
  /* Anula a sangria que a câmara tem em telemóvel (ver o @media abaixo):
     aí ela saía das margens do cartão para ganhar largura, e uma linha de
     texto não precisa disso. */
  width: 100%; margin-left: 0; border-left: 1px solid var(--border-subtle);
  border-right: 1px solid var(--border-subtle);
}
body:not(.cp-a-ler) .cp-camara-vazia {
  position: static; inset: auto; padding: 16px; gap: 10px;
  flex-direction: row; text-align: left; font-size: 13px;
}
body:not(.cp-a-ler) .cp-camara-vazia svg { width: 22px; height: 22px; flex-shrink: 0; }
/* A ação fica com o peso todo: é o que ali se toca dezenas de vezes. */
body:not(.cp-a-ler) .cp-camara-botoes { margin-top: 14px; }
body:not(.cp-a-ler) .cp-camara-botoes #scanBtn { flex: 1; min-height: 54px; font-size: 15px; }
/* Tudo junto e centrado, em vez de a câmara no meio e os botões a boiar. */
/* O conteúdo ao centro, com espaço reservado em cima para a tira. */
/* As margens laterais vivem aqui, no contentor: o botão da pesquisa traz
   width:100% no próprio elemento, e um `width` posto por CSS perdia para
   ele -- ficava colado às bordas do ecrã. */
body.cp-a-ler #modoQr {
  justify-content: center; align-items: center;
  padding: 76px 16px calc(16px + env(safe-area-inset-bottom));
}
body.cp-a-ler .cp-camara-botoes {
  margin: 18px 0 0; padding: 0; width: 100%;
  max-width: 520px; flex-shrink: 0;
}
body.cp-a-ler .cp-camara-botoes button { flex: 1; min-height: 54px; }
body.cp-a-ler #irParaPesquisaBtn {
  margin: 10px 0 0; max-width: 520px; min-height: 50px; flex-shrink: 0;
}

.cp-camara-botoes { display: flex; gap: 10px; justify-content: center; margin-top: 12px; flex-wrap: wrap; }
.cp-camara-botoes button { min-height: 48px; display: inline-flex; align-items: center; gap: 8px; }
.cp-ajuda { font-size: 12px; color: var(--text-muted); margin: 12px 0 0; text-align: center; line-height: 1.5; }

/* Pesquisa manual */
.cp-resultado {
  display: block; width: 100%; text-align: left; background: none; font: inherit; color: inherit;
  border: 0; border-top: 1px solid var(--border-subtle); padding: 14px 14px; cursor: pointer;
  min-height: 48px;
}
.cp-resultado:first-child { border-top: 0; }
.cp-resultado:hover, .cp-resultado:focus-visible { background: var(--bg-card-alt); }
.cp-resultado:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.cp-resultado .nome { font-size: 14px; font-weight: 700; }
.cp-resultado .meta { font-size: 12px; color: var(--text-muted); margin-top: 3px; }
.cp-resultado .passe { font-size: 11px; color: var(--text-muted); font-family: monospace; margin-top: 3px; }

/* Ficha do participante */
.cp-ficha-topo { display: flex; align-items: center; gap: 14px; margin-bottom: 18px; }
.cp-ficha-icone {
  width: 56px; height: 56px; border-radius: 14px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--ok) 16%, transparent); color: var(--ok);
}
.cp-ficha-nome { font-size: 24px; font-weight: 800; line-height: 1.15; overflow-wrap: anywhere; }
.cp-ficha-etiqueta { font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-muted); font-weight: 700; }

/* Contactos: uma linha por dado, e uma linha que não existe não ocupa
   espaço -- num ecrã pequeno cada linha vazia empurra o botão para fora. */
.cp-dados { display: flex; flex-direction: column; gap: 12px; margin-bottom: 16px; }
.cp-dado { display: flex; align-items: center; gap: 12px; }
.cp-dado svg { flex-shrink: 0; color: var(--text-secondary); }
.cp-dado .rotulo { font-size: 11px; color: var(--text-muted); }
.cp-dado .valor { font-size: 14px; font-weight: 600; overflow-wrap: anywhere; }

/* A atividade a que este ponto de leitura está ligado */
.cp-atividade {
  display: flex; align-items: center; gap: 12px; justify-content: space-between;
  padding: 14px; border-radius: 12px; margin-bottom: 16px;
  background: color-mix(in srgb, var(--ok) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--ok) 35%, transparent);
}
.cp-atividade .rotulo { font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-muted); font-weight: 700; }
.cp-atividade .nome { font-size: 16px; font-weight: 700; margin-top: 2px; }

/* A lista de espera, no checkpoint. Tem a forma da caixa da atividade,
   mas não a cor: o verde ali quer dizer "é isto que se vai registar", e
   numa atividade com lista o que acontece à chegada não é um registo --
   é uma pessoa a entrar numa fila. */
.cp-fila {
  display: flex; align-items: center; gap: 12px; justify-content: space-between;
  padding: 14px; border-radius: 12px; margin-bottom: 16px;
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
}
.cp-fila .rotulo { font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-muted); font-weight: 700; }
.cp-fila .nome { font-size: 16px; font-weight: 700; margin-top: 2px; }
.cp-fila .sub { font-size: 12px; color: var(--text-secondary); margin-top: 3px; }

.cp-titulo-registo { font-size: 20px; font-weight: 800; margin: 0 0 14px; }

/* Em telemóvel a ação principal fica agarrada ao fundo enquanto a ficha
   estiver aberta -- é o gesto que se repete dezenas de vezes seguidas e
   não pode obrigar a rolar. O espaçador por baixo garante que ela nunca
   tapa o fim do conteúdo (mesmo padrão de .wiz-nav-movel). */
.cp-espaco-accao { display: none; }
@media (max-width: 720px) {
  .cp-accoes-fixas {
    position: fixed; left: 0; right: 0; bottom: var(--context-bar-h, 0px); z-index: 44;
    display: flex; flex-direction: column; gap: 10px;
    padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
    background: var(--bg-card); border-top: 1px solid var(--border-subtle);
  }
  .cp-accoes-fixas button { min-height: 52px; width: 100%; }
  .cp-espaco-accao { display: block; height: 132px; }
  /* A câmara sai das margens do cartão: é o elemento que tem de ocupar
     tudo o que houver, e 22 px de cada lado num ecrã de 390 é um quinto
     da largura desperdiçado precisamente onde ela faz falta. */
  .cp-camara {
    aspect-ratio: 3 / 4; max-height: none;
    width: calc(100% + 44px); margin-left: -22px; border-radius: 0;
    border-left: 0; border-right: 0;
  }
  .cp-ficha-nome { font-size: 21px; }
}

/* Anúncio para leitores de ecrã e aviso curto de estado (QR detetado,
   erro, resultado guardado) -- visível para todos, não só para quem usa
   leitor de ecrã: em pé e com pressa, uma linha de texto vale mais do que
   uma cor a mudar. */
.cp-anuncio {
  display: none; align-items: center; gap: 10px; margin-top: 14px;
  padding: 12px 14px; border-radius: 12px; font-size: 13px; font-weight: 600; line-height: 1.45;
}
.cp-anuncio.mostrar { display: flex; }
.cp-anuncio.info { background: var(--bg-card-alt); color: var(--text-secondary); }
.cp-anuncio.ok { background: color-mix(in srgb, var(--ok) 12%, transparent); color: var(--ok); border: 1px solid color-mix(in srgb, var(--ok) 35%, transparent); }
.cp-anuncio.erro { background: color-mix(in srgb, var(--danger) 12%, transparent); color: var(--danger); border: 1px solid color-mix(in srgb, var(--danger) 35%, transparent); }

/* Estado da ligação no topo -- deixa de ser um "Online" escrito à mão. */
.status-dot.offline { color: var(--warn); }
.status-dot.offline .dot { background: var(--warn); }

/* Convite (ver invite.html): QR à esquerda, link/partilha à direita. Em
   telemóvel, os 212px fixos do QR mais a largura mínima da coluna de
   partilha (o link + os botões "Enviar por ..." não encolhem bem lado a
   lado) já não cabem juntos — empilha-se numa coluna só, QR primeiro (o
   que se mostra a alguém, ou se aponta a câmara) e o resto da informação
   (link, copiar, partilhar, abrir boletim) por baixo. */
/* Escondido por omissão (ecrã largo) -- a media query "max-width: 680px"
   logo a seguir é que o mostra em mobile. Tem de vir ANTES de .invite-grid
   (a regra de fora do @media com a mesma especificidade que vier depois
   ganha sempre, senão o "display:flex" lá dentro nunca chegava a fazer
   efeito). */
.invite-qr-toggle { display: none; }

.invite-grid { display: grid; grid-template-columns: 212px 1fr; gap: 28px; align-items: start; }
@media (max-width: 680px) {
  .invite-grid { grid-template-columns: 1fr; justify-items: center; text-align: center; }
  .invite-grid > div:last-child { text-align: left; width: 100%; max-width: 360px; }

  /* Em mobile o QR passa para o fim (depois dos botões/link/canais) e deixa
     de aparecer logo aberto -- fica só o botão "Mostrar código QR", que abre
     o mesmo ecrã cheio (.qr-overlay) usado em Inscrições: assim quem
     mostra o telemóvel a alguém para ler o código não deixa também à vista
     o resto do que lá está. No PC mantém-se como sempre esteve (QR já
     visível à esquerda). */
  .invite-qr-col { order: 2; width: 100%; max-width: 360px; }
  .invite-content-col { order: 1; }
  .invite-qr-inline { display: none; }
  .invite-qr-toggle { display: flex; }
}

/* Botão "Mostrar código QR" (só mobile, ver acima) -- mesma "caixa" visual
   das outras linhas desta página (Link de inscrição, canais), com um
   ícone à esquerda e chevron à direita a convidar ao toque. */
.qr-reveal-btn {
  align-items: center; gap: 12px; width: 100%;
  background: var(--bg-card-alt); border: 1px solid var(--border-subtle); border-radius: 12px;
  padding: 14px 16px; color: var(--text-primary); font-size: 14px; font-weight: 600;
  cursor: pointer; text-align: left; font-family: inherit;
}
.qr-reveal-btn svg:first-child { color: var(--accent); flex-shrink: 0; }
.qr-reveal-btn .qr-reveal-chevron { margin-left: auto; color: var(--text-secondary); flex-shrink: 0; display: flex; }
/* -------------------------------------------------------------------
   Mobile (telemóvel): o menu esquerdo (.sidebar) fica escondido por
   omissão. Em vez de uma gaveta lateral, abre como um dropdown ancorado
   a uma barra fixa no topo, através do botão de 3 pontos (⋮) — o mesmo
   padrão do menu de Definições do WhatsApp (não desliza da esquerda,
   expande para baixo a partir do botão). Ver mountMobileTopbar() em
   shared/branding.js — só existe nas páginas com sidebar (app interna);
   páginas públicas (login, boletim de convidado...) já são "mobile
   first" (.guest-page) e não precisam disto.
   ------------------------------------------------------------------- */
.mobile-topbar { display: none; }

@media (max-width: 768px) {
  .app { grid-template-columns: minmax(0, 1fr); }

  /* Grelhas de duas colunas passam a uma so'. Duas colunas num telemovel
     dao caixas com 150px uteis -- o texto nao cabe e sai por fora, que era
     o que se via em "Modulos e precos" e nos modulos de Criar evento.
     Apanha as declaradas em linha nas paginas (repeat(2, 1fr) e 1fr 1fr),
     por isso precisa do !important: o estilo em linha ganha sempre. */
  [style*="grid-template-columns:repeat(2"],
  [style*="grid-template-columns: repeat(2"],
  [style*="grid-template-columns:1fr 1fr"],
  [style*="grid-template-columns: 1fr 1fr"] { grid-template-columns: 1fr !important; }

  /* Linhas de lista com botoes a' direita (ex: eventos no Dashboard): os
     botoes caiam para fora em vez de mudar de linha. */
  .activity-row { flex-wrap: wrap; }

  .mobile-topbar {
    display: flex; align-items: center; justify-content: space-between;
    position: fixed; top: 0; left: 0; right: 0; height: 56px;
    padding: 0 16px; background: var(--bg-sidebar);
    border-bottom: 1px solid var(--border-subtle);
    z-index: 60;
  }
  .mobile-topbar-brand { display: flex; align-items: center; gap: 8px; text-decoration: none; min-width: 0; }
  .mobile-topbar-brand .brand-logo { width: 28px; height: 28px; font-size: 13px; }
  .mobile-topbar-brand .brand-name { font-size: 15px; font-weight: 700; color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* "Só logótipo" na barra fixa do topo (mobile) — mesmo modificador que no
     resto da app, só que com uma altura menor para caber na barra de 56px. */
  .mobile-topbar-brand.brand-logo-only .brand-name { display: none; }
  .mobile-topbar-brand.brand-logo-only .brand-logo { width: auto; height: 36px; background: none; border-radius: 0; }
  .mobile-topbar-brand.brand-logo-only .brand-logo img { width: auto; height: 100%; object-fit: contain; }
  /* Identidade na barra do topo, ao lado dos tres pontinhos -- e' onde se
     procura uma conta, e em telemovel o menu esta' fechado quase sempre, por
     isso la' dentro ficaria escondida. A do menu fica oculta nesta largura
     (ver .sidebar > .footer-wrap abaixo) para nao haver duas. */
  .mobile-topbar-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
  /* Em ecrã inteiro não há barra do browser a comer altura -- o espaço que
     ela deixava livre volta para o conteúdo. O botão fica com o ícone
     trocado (ver mostrarEstadoDoEcraInteiro) para se perceber que se sai
     por onde se entrou. */
  #ecraInteiroBtn[aria-pressed="true"] { color: var(--accent); }
  body.em-ecra-inteiro .main { padding-top: 68px; }
  .topbar-user { position: relative; }
  #topbarAvatar {
    width: 34px; height: 34px; padding: 0; cursor: pointer;
    border: 1px solid var(--border-subtle); font: inherit;
    font-size: 12px; font-weight: 700;
  }
  #topbarAvatar:hover, #topbarAvatar[aria-expanded="true"] {
    color: var(--accent); border-color: var(--accent);
  }
  /* Abre para BAIXO -- esta' no topo do ecra, ao contrario do menu do fundo
     da barra lateral, que abre para cima. */
  #topbarUserMenu {
    top: 100%; bottom: auto; left: auto; right: 0;
    margin-top: 8px; margin-bottom: 0; min-width: 190px;
  }
  .topbar-user-who { padding: 8px 10px 10px; border-bottom: 1px solid var(--border-subtle); margin-bottom: 6px; }
  .topbar-user-who .name { font-size: 13px; font-weight: 600; color: var(--text-primary); }
  .topbar-user-who .role { font-size: 12px; color: var(--text-muted); }

  .mobile-menu-toggle {
    width: 36px; height: 36px; border-radius: 10px; flex-shrink: 0;
    background: var(--bg-card-alt); border: 1px solid var(--border-subtle);
    color: var(--text-primary); font-size: 20px; line-height: 1;
    display: flex; align-items: center; justify-content: center; cursor: pointer;
  }
  .mobile-menu-toggle:hover, .mobile-menu-toggle[aria-expanded="true"] { color: var(--accent); border-color: var(--accent); }

  .main { padding-top: 76px; }


  .sidebar {
    position: fixed; top: 64px; left: 12px; right: 12px;
    border: 1px solid var(--border-subtle); border-radius: 14px;
    box-shadow: 0 16px 40px rgba(0,0,0,0.45);
    max-height: 0; opacity: 0; pointer-events: none; overflow: hidden;
    transition: max-height 0.18s ease, opacity 0.15s ease;
    z-index: 55;
  }
  .sidebar.mobile-open {
    max-height: calc(100vh - 84px); opacity: 1; pointer-events: auto; overflow-y: auto;
  }
  /* A marca e a identidade ja' aparecem na barra fixa do topo -- dentro do
     dropdown ficariam duplicadas. */
  .sidebar > .brand { display: none; }
  .sidebar > .footer-wrap { display: none; }
  /* O Super Admin ja' ve' "Powered by" na barra de contexto (.context-bar,
     so' mobile) -- sem isto, o mesmo selo aparecia outra vez aqui dentro
     do dropdown do menu (ver .powered-by em mountSidebar, branding.js).
     Organizador/Promotor nao tem barra de contexto nenhuma (sem a classe
     body.has-context-bar), por isso continuam a ve-lo aqui, tal como
     sempre foi. */
  body.has-context-bar .sidebar > .powered-by { display: none; }

  .stats { grid-template-columns: repeat(2, 1fr); }
}

/* -------------------------------------------------------------------
   Barra de separadores fixa no fundo, só em telemóvel e só para o
   Promotor (ver mountMobileTabbar() em shared/branding.js) — fica
   sempre visível para alternar entre as poucas páginas que usa mais,
   sem precisar de abrir o dropdown do topo de cada vez. body ganha a
   classe "has-mobile-tabbar" só quando há mesmo itens para mostrar.
   ------------------------------------------------------------------- */
.mobile-tabbar { display: none; }

@media (max-width: 768px) {
  body.has-mobile-tabbar .mobile-tabbar {
    display: flex;
    /* Assenta em cima da barra de contexto quando ela existe (Super Admin a
       ver como Promotor): as duas estavam coladas ao fundo e sobrepunham-se.
       A altura vem medida da propria barra -- ver --context-bar-h em
       mountContextBar. Sem barra nenhuma, o fallback poe isto no fundo, como
       sempre foi para um Promotor a serio. */
    position: fixed; bottom: var(--context-bar-h, 0px); left: 0; right: 0;
    background: var(--bg-sidebar); border-top: 1px solid var(--border-subtle);
    padding: 6px 4px calc(6px + env(safe-area-inset-bottom, 0px));
    z-index: 60;
  }
  /* Com três ou quatro separadores em vez de seis, há espaço -- e num
     tablet de 9,7" ao alto (768px) isso são ~190px cada um. O que estava
     aqui foi desenhado para caber seis: rótulo de 10px e um selo de 26x20,
     que num braço esticado não se lê. */
  .mobile-tab-item {
    flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 4px;
    padding: 8px 4px; border-radius: 12px; text-decoration: none;
    color: var(--text-muted); font-size: 12px; font-weight: 600;
  }
  .mobile-tab-tag {
    width: 34px; height: 26px; border-radius: 8px; flex-shrink: 0;
    background: var(--bg-card-alt); color: var(--text-muted);
    display: flex; align-items: center; justify-content: center;
    font-size: 12px; font-weight: 700;
  }
  .mobile-tab-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
  .mobile-tab-item.active { color: var(--text-primary); }
  .mobile-tab-item.active .mobile-tab-tag { background: var(--accent); color: var(--accent-text); }

  body.has-mobile-tabbar .main { padding-bottom: 88px; }
  /* Com as duas barras (Super Admin a ver como Promotor), reserva-se a
     altura das duas -- senao as ultimas linhas da pagina ficavam por baixo
     delas, sem forma de as ler. */
  body.has-mobile-tabbar.has-context-bar .main { padding-bottom: calc(var(--context-bar-h, 0px) + 100px); }
  body.has-mobile-tabbar.has-context-bar .back-to-top { bottom: calc(var(--context-bar-h, 0px) + 92px); }

  /* -----------------------------------------------------------------
     A BARRA FICA, COM A CÂMARA LIGADA
     -----------------------------------------------------------------
     O leitor é `position: fixed; inset: 0` com z-index 300, e tapava a
     barra por inteiro. A única saída passava a ser o "Fechar" da tira do
     topo -- um alvo só, num canto, com a mão a segurar o tablet do outro
     lado. "Às vezes fica difícil de fechar" (Tiago, 16/9).
     Devolver a barra dá uma segunda saída sempre no mesmo sítio, e deixa
     saltar do leitor para a Lista de espera sem fechar coisa nenhuma. */
  body.cp-a-ler.has-mobile-tabbar .mobile-tabbar { z-index: 320; }
  /* E o leitor encolhe o que precisa para não ficar nada por baixo dela. */
  body.cp-a-ler.has-mobile-tabbar #modoQr { padding-bottom: 84px; }
}

/* ------------------------------------------------------------------------
   Dashboard único (admin.html) -- indicadores principais, "Precisa de
   atenção" e barras de "Estado do evento". Pedido do Tiago (9/9): juntar
   Início + Estatísticas numa só página; estas classes são específicas
   deste ecrã (o resto da app continua a usar .stat-card/.stats para os
   painéis por módulo mais abaixo no Dashboard e nas outras páginas).
   ------------------------------------------------------------------------ */
.kpi-box { background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 16px; padding: 18px 22px; margin-bottom: 20px; }
.kpi-grid { display: grid; grid-template-columns: repeat(4, 1fr); }
.kpi-item { display: flex; align-items: center; gap: 12px; padding: 6px 18px; min-width: 0; }
.kpi-item:not(:first-child) { border-left: 1px solid var(--border-subtle); }
.kpi-icon {
  width: 40px; height: 40px; border-radius: 11px; flex-shrink: 0;
  background: var(--bg-card-alt); color: var(--text-secondary);
  display: flex; align-items: center; justify-content: center;
}
.kpi-item.is-alert .kpi-icon { background: color-mix(in srgb, var(--warn) 18%, transparent); color: var(--warn); }
.kpi-value { font-size: 22px; font-weight: 700; line-height: 1.15; }
.kpi-item.is-alert .kpi-value { color: var(--warn); }
.kpi-label { font-size: 12px; color: var(--text-muted); margin-top: 1px; }
.kpi-sub { font-size: 11px; color: var(--text-muted); }
@media (max-width: 680px) {
  .kpi-grid { grid-template-columns: repeat(2, 1fr); row-gap: 18px; }
  .kpi-item:nth-child(2n+1) { border-left: none; }
  .kpi-item:nth-child(n+3) { border-top: 1px solid var(--border-subtle); padding-top: 16px; }
}

.attention-panel { background: var(--bg-card); border: 1px solid var(--border-subtle); border-left: 3px solid var(--warn); border-radius: 16px; padding: 20px 22px; margin-bottom: 20px; }
.attention-panel.is-ok { border-left-color: var(--ok); }
.attention-head { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 16px; }
.attention-head .icon-box {
  width: 36px; height: 36px; border-radius: 10px; flex-shrink: 0;
  background: color-mix(in srgb, var(--warn) 18%, transparent); color: var(--warn);
  display: flex; align-items: center; justify-content: center;
}
.attention-panel.is-ok .attention-head .icon-box { background: color-mix(in srgb, var(--ok) 18%, transparent); color: var(--ok); }
.attention-head h3 { margin: 0; font-size: 15px; font-weight: 700; }
.attention-head p { margin: 2px 0 0; font-size: 12px; color: var(--text-secondary); }
.attention-row { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 12px; background: var(--bg-card-alt); margin-bottom: 10px; flex-wrap: wrap; }
.attention-row:last-child { margin-bottom: 0; }
.attention-row.is-done { background: color-mix(in srgb, var(--ok) 12%, var(--bg-card-alt)); }
.attention-row .icon-box {
  width: 32px; height: 32px; border-radius: 9px; flex-shrink: 0;
  background: var(--bg-card); color: var(--text-secondary);
  display: flex; align-items: center; justify-content: center;
}
.attention-row.is-done .icon-box { background: color-mix(in srgb, var(--ok) 22%, transparent); color: var(--ok); }
.attention-row .info { flex: 1; min-width: 160px; }
.attention-row .info .title { font-size: 13px; font-weight: 600; }
.attention-row .info .sub { font-size: 11px; color: var(--text-muted); margin-top: 1px; }
.attention-row .action { flex-shrink: 0; }
.attention-row .done-badge {
  width: 26px; height: 26px; border-radius: 50%; flex-shrink: 0;
  background: color-mix(in srgb, var(--ok) 22%, transparent); color: var(--ok);
  display: flex; align-items: center; justify-content: center;
}

.eventstate-row { display: flex; align-items: center; gap: 14px; margin-bottom: 14px; }
.eventstate-row:last-child { margin-bottom: 0; }
.eventstate-label { width: 150px; flex-shrink: 0; font-size: 13px; color: var(--text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.eventstate-bar { flex: 1; height: 9px; background: var(--bg-card-alt); border-radius: 5px; overflow: hidden; min-width: 40px; }
.eventstate-bar > div { height: 100%; border-radius: 5px; }
.eventstate-value { width: 48px; flex-shrink: 0; text-align: right; font-size: 13px; font-weight: 600; }
.eventstate-pct { width: 44px; flex-shrink: 0; text-align: right; font-size: 12px; font-weight: 600; }
@media (max-width: 560px) {
  .eventstate-label { width: 92px; font-size: 12px; }
  .eventstate-value { width: 40px; }
  .eventstate-pct { width: 38px; }
}

.compact-stat-row { display: flex; align-items: center; gap: 22px; flex-wrap: wrap; }
.compact-stat-row .item { display: flex; flex-direction: column; }
/* Um item pode ter o ícone à esquerda e o par valor/rótulo à direita --
   esse par empilha-se sempre, senão o número e o rótulo saíam colados. */
.compact-stat-row .item > div { display: flex; flex-direction: column; }
.compact-stat-row .item .value { font-size: 18px; font-weight: 700; }
.compact-stat-row .item .label { font-size: 11px; color: var(--text-muted); margin-top: 1px; }

/* =========================================================================
   Configurar evento — assistente de 5 etapas (event-config.html)
   Uma coluna só, do princípio ao fim: o formulário é longo e a leitura em
   coluna única é o que aguenta desktop, tablet e telemóvel sem casos
   especiais. As excepções a "sem scroll horizontal" são deliberadas e
   estão marcadas onde acontecem (a fila de cores predefinidas).
   ========================================================================= */
/* A largura do assistente -- a mesma nos dois, para as caixas não terem
   uma medida em Eventos e outra em Atividades. */
.wiz-wrap { max-width: 1060px; margin: 0 auto; }

/* O cabeçalho, as etapas e a navegação do assistente estão todos em
   .wiz-* no topo deste ficheiro -- são a mesma moldura em Eventos e em
   Atividades. Daqui para baixo é só o que as ETAPAS do evento têm de
   próprio (campos, upload de marca, revisão). */

/* Corpo das etapas */
.cfg-etapa[hidden] { display: none; }
.cfg-grupo + .cfg-grupo,
/* o primeiro grupo depois da lista de revisão (etapa 5) precisa da
   mesma separação -- sem isto ficava colado à última linha. */
#cfgRevisaoLinhas + .cfg-grupo { margin-top: 26px; padding-top: 22px; border-top: 1px solid var(--border-subtle); }
.cfg-grupo-titulo { font-size: 15px; font-weight: 700; margin: 0 0 2px; }
.cfg-grupo-sub { font-size: 12px; color: var(--text-muted); margin: 0 0 16px; }
.cfg-campos { display: flex; flex-direction: column; gap: 16px; }
/* Só as datas partilham linha no ecrã largo — o resto ocupa a linha toda. */
.cfg-par { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.cfg-campo label { display: block; font-size: 12px; font-weight: 700; margin-bottom: 6px; }
.cfg-campo .opcional { color: var(--text-muted); font-weight: 500; }
/* A AJUDA, ESTEJA ONDE ESTIVER DENTRO DA ETAPA.
   Isto era `.cfg-grupo > .ajuda` -- filho direto --, e bastava a ajuda
   nascer dentro de um `<div>` qualquer do grupo para ficar sem estilo
   nenhum: letra do corpo da página, branca, do tamanho de um título. No
   passo Conteúdos, "1 escolhida." aparecia maior do que o campo a que se
   referia. */
.cfg-campo .ajuda, .cfg-grupo .ajuda, .cfg-etapa .ajuda { font-size: 11px; color: var(--text-muted); margin: 6px 0 0; }
/* Mesma razão da regra grande lá em cima: a lista de tipos era exigente e
   deixava o campo de hora com a largura do browser, mais estreito do que o
   do lado. Aqui vestem-se todos os campos de escrever do assistente. */
.cfg-campo input:not([type=checkbox]):not([type=radio]):not([type=color]), .cfg-campo textarea, .cfg-campo select { width: 100%; }
.cfg-com-espelho { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 0.85fr); gap: 12px; align-items: start; }
.cfg-espelho { display: flex; align-items: center; gap: 8px; min-height: 44px; padding: 10px 14px; border-radius: 10px; background: var(--bg-card-alt); border: 1px solid var(--border-subtle); font-size: 13px; color: var(--text-secondary); overflow-wrap: anywhere; }
.cfg-espelho svg { flex-shrink: 0; color: var(--text-muted); }
.cfg-erro { display: block; font-size: 12px; color: var(--danger); margin-top: 6px; }
.cfg-campo.tem-erro input, .cfg-campo.tem-erro textarea { border-color: var(--danger); }

/* Etapa 2 — logótipo */
.cfg-upload { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; padding: 18px; border: 1.5px dashed var(--border-subtle); border-radius: 14px; background: var(--bg-card-alt); }
.cfg-upload.a-arrastar { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, var(--bg-card-alt)); }
.cfg-upload-figura { width: 116px; height: 116px; border-radius: 12px; background: var(--bg-card); border: 1px solid var(--border-subtle); display: flex; align-items: center; justify-content: center; overflow: hidden; flex-shrink: 0; }
/* contain: o logótipo nunca é cortado nem esticado. */
.cfg-upload-figura img { width: 100%; height: 100%; object-fit: contain; }
.cfg-upload-figura .inicial { font-size: 34px; font-weight: 800; color: var(--text-muted); }
.cfg-upload-info { flex: 1; min-width: 200px; }
.cfg-upload-info .ficheiro { font-size: 14px; font-weight: 700; overflow-wrap: anywhere; }
.cfg-upload-info .meta { font-size: 12px; color: var(--text-muted); margin-top: 4px; }
.cfg-upload-info .carregada { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--ok); margin-top: 6px; }
.cfg-upload-botoes { display: flex; gap: 10px; flex-wrap: wrap; }

/* Etapa 2 — cor */
.cfg-cor { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.cfg-cor input[type="color"] { width: 62px; height: 44px; padding: 0; border-radius: 10px; border: 1px solid var(--border-subtle); background: none; cursor: pointer; }
.cfg-cor input[type="text"] { width: 132px; }
/* Única fila que pode deslizar na horizontal no telemóvel — de propósito. */
.cfg-swatches { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 2px; }
.cfg-swatch { width: 40px; height: 40px; border-radius: 10px; border: 2px solid transparent; cursor: pointer; flex-shrink: 0; padding: 0; }
.cfg-swatch[aria-pressed="true"] { border-color: var(--text-primary); }
.cfg-swatch:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.cfg-contraste { display: inline-flex; align-items: center; gap: 7px; font-size: 12px; font-weight: 600; }
.cfg-contraste.ok { color: var(--ok); }
.cfg-contraste.chumbou { color: var(--warn); }

/* Etapa 2 — apresentação da marca e outras escolhas em cartão */
.cfg-opcoes { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
/* O cartão escolhido veste-se da COR DO EVENTO, não de verde.
   O verde desta aplicação quer dizer uma coisa: correu bem -- guardado,
   concluído, publicado, ligação viva. Escolher uma opção não é nada
   disso: é uma escolha, e enquanto o verde a marcava ficavam dois
   significados na mesma cor e o olho deixava de saber qual era qual.

   A borda passa a DOIS píxeis, e isso não é enfeite: é o que faz a
   escolha continuar a ver-se quando a cor do evento tem pouco contraste
   com o fundo. Uma cor pálida some-se; uma borda com o dobro da
   espessura vê-se pela forma, mesmo sem cor nenhuma. Por isso o cartão
   escolhido tem sempre três sinais -- espessura, tom de fundo e o ponto
   do rádio -- e nenhum deles depende sozinho da cor que o evento
   escolheu. */
.cfg-opcao { display: flex; align-items: flex-start; gap: 11px; padding: 15px 16px; border: 1px solid var(--border-subtle); border-radius: 12px; background: var(--bg-card-alt); cursor: pointer; }
.cfg-opcao:has(input:checked) { border: 2px solid var(--accent); padding: 14px 15px; background: color-mix(in srgb, var(--accent) 12%, var(--bg-card-alt)); }
.cfg-opcao:has(input:checked) input[type="radio"],
.cfg-opcao:has(input:checked) input[type="checkbox"] { background: var(--accent); border-color: var(--accent); }
.cfg-opcao:has(input:checked) input[type="radio"]::before,
.cfg-opcao:has(input:checked) input[type="checkbox"]::before { background: var(--accent-text, #06120b); }
.cfg-opcao:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; }
.cfg-opcao input { margin-top: 3px; flex-shrink: 0; }
.cfg-opcao .titulo { font-size: 14px; font-weight: 700; }
.cfg-opcao .desc { font-size: 12px; color: var(--text-muted); margin-top: 3px; }

/* Etapa 2 — pré-visualização (componentes reais, não uma imagem) */
.cfg-preview-topo { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
.cfg-preview-modos { display: inline-flex; gap: 6px; background: var(--bg-card-alt); padding: 4px; border-radius: 10px; }
.cfg-preview-modos button { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 700; padding: 7px 13px; border-radius: 7px; border: 0; background: none; color: var(--text-muted); cursor: pointer; }
.cfg-preview-modos button[aria-pressed="true"] { background: var(--accent); color: var(--accent-text); }
.cfg-palco { border: 1px solid var(--border-subtle); border-radius: 14px; padding: 18px; background: var(--bg-card-alt); }
.cfg-palco.modo-mobile { max-width: 380px; margin: 0 auto; }
.cfg-palco-cartao { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.cfg-palco.modo-mobile .cfg-palco-cartao { flex-direction: column; align-items: flex-start; }
.cfg-palco-logo { width: 76px; height: 76px; border-radius: 12px; background: var(--bg-card); border: 1px solid var(--border-subtle); display: flex; align-items: center; justify-content: center; overflow: hidden; flex-shrink: 0; }
.cfg-palco-logo img { width: 100%; height: 100%; object-fit: contain; }
.cfg-palco-logo .inicial { font-size: 26px; font-weight: 800; }
.cfg-palco-info { flex: 1; min-width: 0; }
.cfg-palco-info .nome { font-size: 21px; font-weight: 800; overflow-wrap: anywhere; }
.cfg-palco-info .meta { display: flex; gap: 14px; flex-wrap: wrap; font-size: 13px; color: var(--text-secondary); margin-top: 6px; }
.cfg-palco-info .meta span { display: inline-flex; align-items: center; gap: 6px; }
.cfg-palco-cta { border: 0; border-radius: 10px; padding: 12px 20px; font-size: 14px; font-weight: 700; cursor: default; }

/* Etapa 3 — módulos em lista vertical */
.mod-resumo { display: flex; gap: 22px; flex-wrap: wrap; padding: 16px 18px; border: 1px solid var(--border-subtle); border-radius: 12px; background: var(--bg-card-alt); margin-bottom: 16px; }
.mod-resumo .bloco { display: flex; align-items: center; gap: 10px; }
.mod-resumo .valor { font-size: 17px; font-weight: 800; }
.mod-resumo .rotulo { font-size: 11px; color: var(--text-muted); }
.mod-resumo .total .valor { color: var(--accent); }
.mod-ferramentas { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 18px; }
.mod-ferramentas input[type="search"] { flex: 1; min-width: 200px; }
.mod-filtros { display: inline-flex; gap: 6px; flex-wrap: wrap; }
.mod-filtro { font-size: 12px; font-weight: 700; padding: 9px 15px; border-radius: 999px; border: 1px solid var(--border-subtle); background: none; color: var(--text-secondary); cursor: pointer; }
.mod-filtro[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
.mod-grupo + .mod-grupo { margin-top: 22px; }
.mod-grupo-cabeca { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 9px; }
.mod-grupo-cabeca .titulo { font-size: 13px; font-weight: 800; }
.mod-grupo-cabeca .conta { font-size: 11px; color: var(--text-muted); }
.mod-linha { display: flex; align-items: center; gap: 14px; padding: 14px 16px; border: 1px solid var(--border-subtle); border-radius: 12px; background: var(--bg-card-alt); }
.mod-linha + .mod-linha { margin-top: 8px; }
.mod-linha.is-on { border-color: color-mix(in srgb, var(--ok) 55%, transparent); background: color-mix(in srgb, var(--ok) 7%, var(--bg-card-alt)); }
.mod-linha .icone { width: 34px; height: 34px; border-radius: 9px; background: var(--bg-card); display: flex; align-items: center; justify-content: center; color: var(--text-secondary); flex-shrink: 0; }
.mod-linha.is-on .icone { color: var(--ok); }
.mod-linha .corpo { flex: 1; min-width: 0; }
.mod-linha .nome { font-size: 14px; font-weight: 700; overflow-wrap: anywhere; }
.mod-linha .desc { font-size: 12px; color: var(--text-muted); margin-top: 2px; overflow-wrap: anywhere; }
.mod-linha .preco { font-size: 12px; font-weight: 700; color: var(--text-secondary); white-space: nowrap; padding: 5px 11px; border-radius: 999px; border: 1px solid var(--border-subtle); }
.mod-linha .dependencia { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; color: var(--text-muted); white-space: nowrap; }
/* Um ajuste que pertence a UM módulo vive dentro do cartão dele -- um
   limite de e-mails perdido no fim da página não se liga a nada. Encosta
   à linha de cima (sem margem, cantos de cima direitos) para se ler como
   a mesma peça. */
.mod-ajuste { margin-top: -8px; padding: 10px 16px 12px 64px; border: 1px solid color-mix(in srgb, var(--ok) 55%, transparent); border-top: 0; border-radius: 0 0 12px 12px; background: color-mix(in srgb, var(--ok) 7%, var(--bg-card-alt)); }
.mod-linha.tem-ajuste { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
.mod-ajuste button { font-size: 12.5px; }
.mod-ajuste button strong { color: var(--text-primary); }
@media (max-width: 600px) { .mod-ajuste { padding-left: 16px; } }
.mod-vazio { font-size: 13px; color: var(--text-muted); padding: 18px; text-align: center; }

/* Etapa 5 — revisão */
.rev-cabecalho { display: flex; align-items: flex-start; gap: 13px; padding: 16px 18px; border-radius: 12px; margin-bottom: 16px; border: 1px solid; }
.rev-cabecalho.tudo-bem { border-color: color-mix(in srgb, var(--ok) 55%, transparent); background: color-mix(in srgb, var(--ok) 8%, transparent); }
.rev-cabecalho.tem-erros { border-color: color-mix(in srgb, var(--danger) 55%, transparent); background: color-mix(in srgb, var(--danger) 8%, transparent); }
.rev-cabecalho .titulo { font-size: 14px; font-weight: 700; }
.rev-cabecalho .sub { font-size: 12px; color: var(--text-muted); margin-top: 3px; }
.rev-cabecalho ul { margin: 8px 0 0; padding-left: 18px; font-size: 12px; color: var(--text-secondary); }
.rev-linha, .lista-linha { display: flex; align-items: center; gap: 14px; padding: 14px 16px; border: 1px solid var(--border-subtle); border-radius: 12px; background: var(--bg-card-alt); }
.rev-linha + .rev-linha, .lista-linha + .lista-linha { margin-top: 8px; }
.lista-linha .icone img { width: 100%; height: 100%; object-fit: contain; border-radius: 8px; }
.rev-linha .icone, .lista-linha .icone { width: 38px; height: 38px; border-radius: 10px; background: var(--bg-card); display: flex; align-items: center; justify-content: center; color: var(--text-secondary); flex-shrink: 0; }
.rev-linha .corpo, .lista-linha .corpo { flex: 1; min-width: 0; }
.rev-linha .titulo, .lista-linha .titulo { font-size: 14px; font-weight: 700; }
.rev-linha .resumo, .lista-linha .resumo { font-size: 12px; color: var(--text-muted); margin-top: 3px; overflow-wrap: anywhere; }
.rev-selo { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 700; padding: 6px 12px; border-radius: 999px; white-space: nowrap; }
.rev-selo.completo { color: var(--ok); background: color-mix(in srgb, var(--ok) 14%, transparent); }
.rev-selo.aviso { color: var(--warn); background: color-mix(in srgb, var(--warn) 14%, transparent); }
.rev-selo.incompleto { color: var(--danger); background: color-mix(in srgb, var(--danger) 14%, transparent); }
.rev-publicacao { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; padding: 15px 0; }
.rev-publicacao + .rev-publicacao { border-top: 1px solid var(--border-subtle); }
.rev-publicacao .titulo { font-size: 14px; font-weight: 700; }
.rev-publicacao .desc { font-size: 12px; color: var(--text-muted); margin-top: 3px; }
/* Marca um interruptor cujo valor ainda não foi aplicado -- estes dois são
   os únicos campos da configuração que NÃO se guardam sozinhos (ver o
   comentário junto de publicacaoPendente em event-config.js). */
.rev-por-aplicar {
  display: inline-block; margin-left: 8px; padding: 2px 8px; border-radius: 999px;
  font-size: 10px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: var(--warn); border: 1px solid color-mix(in srgb, var(--warn) 45%, transparent);
  background: color-mix(in srgb, var(--warn) 12%, transparent); vertical-align: middle;
}
.rev-publicacao .desc.vai-mudar { color: var(--warn); }

/* Navegação entre etapas */

@media (max-width: 900px) {
  .cfg-opcoes { grid-template-columns: 1fr; }
  .cfg-com-espelho { grid-template-columns: 1fr; }
}

@media (max-width: 1080px) {
  .wiz-passos { display: none; }
  .wiz-passos-mini { display: block; background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 14px; padding: 14px 16px; margin-bottom: 16px; }
  .wiz-passos-mini .passo-de { font-size: 12px; font-weight: 700; color: var(--text-muted); }
  .wiz-passos-mini .nome-etapa { font-size: 17px; font-weight: 800; margin: 2px 0 12px; }
  .wiz-marcadores { display: flex; align-items: center; }
  .wiz-marcador { width: 32px; height: 32px; border-radius: 50%; border: 1.5px solid var(--border-subtle); color: var(--text-muted); display: inline-flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; flex-shrink: 0; background: none; padding: 0; }
  .wiz-marcador.is-atual { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }
  .wiz-marcador.is-feito { background: color-mix(in srgb, var(--ok) 18%, transparent); border-color: var(--ok); color: var(--ok); }
  .wiz-marcador.tem-falta { border-color: var(--warn); color: var(--warn); background: color-mix(in srgb, var(--warn) 14%, transparent); }
  .wiz-marcador-linha { flex: 1; height: 2px; background: var(--border-subtle); margin: 0 6px; }
  .wiz-marcador-linha.is-feito { background: var(--ok); }
}

@media (max-width: 720px) {
  .cfg-par { grid-template-columns: 1fr; }
  /* A navegação passa para uma barra fixa em baixo. O espaço que ela ocupa
     é reservado no fim do conteúdo (ver .wiz-espaco-barra), para nunca
     tapar o último campo nem a pré-visualização. */
  .wiz-nav { display: none; }
  /* Assenta EM CIMA da barra de contexto (a do seletor de evento/"ver
     como", ver .context-bar), que também é fixa em baixo e já lá estava --
     sem isto ficavam uma por cima da outra e o seletor de evento roubava
     os cliques ao botão "Seguinte". A altura dela é publicada em
     --context-bar-h por mountContextBar() em shared/branding.js. */
  .wiz-nav-movel {
    display: flex; gap: 10px; position: fixed; left: 0; right: 0; z-index: 44;
    bottom: var(--context-bar-h, 0px);
    padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
    background: var(--bg-card); border-top: 1px solid var(--border-subtle);
  }
  /* Onde há barra de separadores do telemóvel (as páginas com secções, ver
     .mobile-tabbar), esta assenta por cima dela -- senão ficavam uma em
     cima da outra e o separador roubava os cliques ao "Seguinte". */
  body.has-mobile-tabbar .wiz-nav-movel { bottom: calc(var(--context-bar-h, 0px) + 64px); }
  .wiz-nav-movel button, .wiz-nav-movel a { min-height: 48px; display: inline-flex; align-items: center; justify-content: center; }
  /* Três botões numa barra estreita: "Seguinte" fica com o espaço que
     sobrar e os outros dois só com o que o texto precisa. */
  .wiz-nav-movel .principal { flex: 1; }
  .wiz-nav-movel .secundario { flex: 0 0 auto; padding-left: 12px; padding-right: 12px; }
  /* Espaço reservado no fim do conteúdo para as duas barras fixas -- é
     isto que garante que o último campo e a pré-visualização nunca ficam
     tapados. */
  .wiz-espaco-barra { height: calc(84px + var(--context-bar-h, 0px) + env(safe-area-inset-bottom)); }
  body.has-mobile-tabbar .wiz-espaco-barra { height: calc(148px + var(--context-bar-h, 0px) + env(safe-area-inset-bottom)); }
  .cfg-upload { flex-direction: column; align-items: stretch; }
  .cfg-upload-figura { width: 100%; height: 150px; }
  .cfg-upload-botoes button { flex: 1; min-height: 44px; }
  .mod-linha { flex-wrap: wrap; }
  .mod-linha .preco { order: 3; }
  /* No telemóvel a linha parte-se em dois andares: ícone + texto em cima,
     estado e ações em baixo. Sem dar largura mínima ao texto, ele era
     espremido pelos botões até ficar uma letra por linha. */
  .rev-linha, .lista-linha { flex-wrap: wrap; row-gap: 12px; }
  .rev-linha .corpo, .lista-linha .corpo { flex: 1 1 calc(100% - 56px); min-width: 150px; }
  .rev-linha .rev-selo, .lista-linha .rev-selo, .lista-linha .badge { order: 3; }
  .rev-linha .btn-ghost, .lista-linha .btn-ghost, .lista-linha a.btn-ghost { order: 4; flex: 1; min-height: 44px; justify-content: center; }
}

/* =========================================================================
   Lista de eventos (events.html) — separadores, ferramentas e cartões.
   Cartão horizontal e compacto no ecrã largo, vertical no telemóvel, com
   as mesmas quatro zonas em ambos: quem é, em que estado está, como vai a
   configuração, e o que fazer a seguir.
   ========================================================================= */
.ev-wrap { max-width: 1180px; }
/* .ev-topo era o cabeçalho de metade das páginas -- passou a ser
   .page-header, que é o mesmo com outro nome (ver lá em cima). Fica só
   como atalho para não partir nada que ainda o use. */
.ev-topo { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-bottom: 24px; }
.ev-topo .texto { flex: 1; min-width: 240px; }

/* Separadores: a única fila que pode deslizar na horizontal no telemóvel. */
.ev-separadores { display: flex; gap: 4px; border-bottom: 1px solid var(--border-subtle); margin-bottom: 18px; overflow-x: auto; }
.ev-separador { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; background: none; border: 0; border-bottom: 2px solid transparent; padding: 12px 14px; font-size: 14px; font-weight: 700; color: var(--text-muted); cursor: pointer; }
.ev-separador[aria-selected="true"] { color: var(--text-primary); border-bottom-color: var(--accent); }
.ev-separador .conta { font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 999px; background: var(--bg-card-alt); color: var(--text-secondary); }
.ev-separador[aria-selected="true"] .conta { background: var(--accent); color: var(--accent-text); }
.ev-separador:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* Separadores que são PÁGINAS (8/10, o Troféu): links, com a página aberta
   marcada como as outras marcam o separador escolhido. */
a.ev-separador { text-decoration: none; }
a.ev-separador:hover { color: var(--text-primary); }
.ev-separador[aria-current="page"] { color: var(--text-primary); border-bottom-color: var(--accent); }

.ev-ferramentas { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 14px; }
.ev-ferramentas .procura { flex: 1; min-width: 220px; }
.ev-ferramentas select { min-width: 150px; }

/* No telemóvel esta moldura usa-se de pé, com uma mão: os separadores e os
   campos de filtro passam a ter altura de dedo. Ficavam nos 37-42px, que
   se acertam por sorte -- e são precisamente os controlos que se usam a
   correr, a olhar para uma fila. Vale para todas as listas (Eventos,
   Atividades, Inscrições, Convidados), que partilham esta moldura. */
@media (max-width: 900px) {
  .ev-separador { min-height: 48px; padding: 12px 14px; }
  .ev-ferramentas input, .ev-ferramentas select { min-height: 48px; }
}
.ev-contagem { font-size: 13px; font-weight: 700; color: var(--text-secondary); margin: 0 0 12px; }

/* Cartão */
/* Grelha: a ordem no HTML é a de leitura no telemóvel (identidade,
   configuração, métricas, ações); aqui, no ecrã largo, as ações sobem
   para a direita da primeira linha sem mudar essa ordem. */
.ev-cartao {
  border: 1px solid var(--border-subtle); border-radius: 14px; background: var(--bg-card); padding: 18px 20px;
  display: grid; gap: 0 14px; align-items: start;
  grid-template-columns: minmax(0, 1fr) auto auto;
  grid-template-areas:
    "topo     acoes    menu"
    "config   config   config"
    "metricas metricas metricas";
}
.ev-cartao-topo { grid-area: topo; display: flex; align-items: flex-start; gap: 16px; }
.ev-cartao > .ev-menu-conteiner { grid-area: menu; }
.ev-cartao > .ev-acoes { grid-area: acoes; }
.ev-cartao > .ev-config { grid-area: config; }
.ev-cartao > .ev-metricas { grid-area: metricas; }
.ev-cartao + .ev-cartao { margin-top: 12px; }
.ev-logo { width: 62px; height: 62px; border-radius: 12px; background: var(--bg-card-alt); border: 1px solid var(--border-subtle); display: flex; align-items: center; justify-content: center; overflow: hidden; flex-shrink: 0; }
.ev-logo img { width: 100%; height: 100%; object-fit: contain; }
.ev-logo .inicial { font-size: 22px; font-weight: 800; letter-spacing: 0.02em; }
.ev-identidade { flex: 1; min-width: 0; }
.ev-identidade .nome { font-size: 17px; font-weight: 800; overflow-wrap: anywhere; }
.ev-meta { display: flex; gap: 16px; flex-wrap: wrap; margin-top: 6px; font-size: 13px; color: var(--text-secondary); }
.ev-meta span { display: inline-flex; align-items: center; gap: 6px; }
.ev-meta .em-falta { color: var(--warn); }
.ev-selos { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.ev-acoes { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; flex-shrink: 0; }
/* Sem altura própria: vale a escala (40px, 44px ao toque). Tinha 44px
   fixos e ficava mais alto do que o mesmo botão noutra página. */

/* Configuração e métricas */
.ev-config { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 14px; font-size: 13px; }
.ev-config .completa { display: inline-flex; align-items: center; gap: 7px; color: var(--ok); font-weight: 600; }
.ev-config .passos { color: var(--text-secondary); font-weight: 600; }
.ev-barra { flex: 1; min-width: 120px; max-width: 240px; height: 8px; border-radius: 4px; background: var(--bg-card-alt); overflow: hidden; }
.ev-barra > div { height: 100%; border-radius: 4px; background: var(--accent); }
.ev-metricas { display: flex; gap: 20px; flex-wrap: wrap; align-items: center; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border-subtle); font-size: 13px; color: var(--text-secondary); }
.ev-metricas .metrica { display: inline-flex; align-items: center; gap: 7px; }
.ev-metricas .metrica strong { color: var(--text-primary); font-weight: 700; }
.ev-metricas .preco { margin-left: auto; font-size: 12px; color: var(--text-muted); }

/* Menu de ações (um por evento) */
/* =====================================================================
   O ECRÃ PÚBLICO (display.html)

   Página autónoma, sem sidebar nem login -- pensada para ficar num
   browser/TV/Chromecast/tablet ligado o dia inteiro. Estas regras viviam
   dentro do próprio display.html; vieram para aqui porque a
   pré-visualização do editor (etapa Template) carrega esta folha e tem
   de desenhar EXACTAMENTE o mesmo. Uma pré-visualização com CSS próprio
   é uma pré-visualização que mente no dia em que o ecrã mudar.
   ===================================================================== */
  /* Página autónoma, sem sidebar nem login — pensada para ficar num
   browser/TV/Chromecast/tablet ligado o dia inteiro. Layout a preto,
   letras grandes, sem elementos de gestão. */
/* Sem padding: as bandas de publicidade vão de bordo a bordo (o padding
   vive agora no `.kiosk-util`, ver mais abaixo). Uma faixa com margem à
   volta não mede os 1920 que o patrocinador comprou. */
/* `height` e não só `min-height`: as bandas de publicidade medem-se em
   PERCENTAGEM da altura do ecrã, e uma percentagem contra uma altura
   automática não é nada -- a faixa encolhia até ao tamanho da imagem que
   lá estava dentro. Com um GIF de 1×1 no ensaio, os 18% deram 1,8%.
   O conteúdo é que passa a rolar quando não cabe (ver .kiosk-util): numa
   televisão nada rola, e num telemóvel rola o conteúdo em vez de as
   faixas se desfazerem. */
.kiosk { min-height: 100vh; height: 100vh; display: flex; flex-direction: column; box-sizing: border-box; }
.kiosk-header { display: flex; align-items: center; gap: 16px; margin-bottom: clamp(16px, 3vw, 32px); }
/* "Só logótipo", no ecrã público -- a MESMA opção do evento que já manda no
   resto da aplicação (events-create.html, etapa Imagem), aplicada aqui
   também. Um logótipo que já diz "Dia da Mobilidade 2026" seguido do nome
   do evento escrito ao lado é a mesma coisa dita duas vezes, e numa
   televisão isso vê-se de longe (18/9).
   O nome sai; o subtítulo FICA -- esse diz o que aquele ecrã está a
   mostrar ("Classificação"), que é outra informação. E o logótipo cresce,
   porque passou a ser ele a dizer de quem é o evento. */
.kiosk-header.brand-logo-only .kiosk-title { display: none; }
.kiosk-header.brand-logo-only .kiosk-logo:has(img) { height: clamp(52px, 7vw, 92px); max-width: min(42vw, 420px); }
.kiosk-logo { width: 56px; height: 56px; border-radius: 14px; background: var(--accent); color: var(--accent-text); display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 22px; overflow: hidden; flex-shrink: 0; }
/* Um logótipo NÃO é uma fotografia de perfil. Com `cover` dentro de um
   quadrado de 56px, o logótipo do evento aparecia cortado dos dois lados --
   visto na BOLT a 18/9: lia-se "Mobi" e meia palavra do "powered by".
   Com imagem, a caixa deixa de ser quadrada e passa a acompanhar a forma do
   logótipo (é para isso que ele foi desenhado), sem a cor de fundo por trás
   -- que num logótipo com fundo próprio era uma moldura a mais. */
.kiosk-logo img { width: auto; max-width: 100%; height: 100%; object-fit: contain; }
.kiosk-logo:has(img) { width: auto; max-width: 200px; background: none; border-radius: 0; }
.kiosk-title { font-size: clamp(20px, 3vw, 32px); font-weight: 800; }
.kiosk-sub { color: var(--text-secondary); font-size: clamp(12px, 1.4vw, 15px); }
.kiosk-clock { margin-left: auto; font-size: clamp(16px, 2vw, 24px); color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.kiosk-body { flex: 1; display: grid; gap: clamp(14px, 2vw, 24px); grid-template-columns: 1fr; }
.kiosk-body.has-ad { grid-template-columns: 2fr 1fr; }
@media (max-width: 860px) { .kiosk-body.has-ad { grid-template-columns: 1fr; } }
.rank-card { background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 16px; padding: clamp(14px, 2vw, 22px); }
.rank-card h2 { margin: 0 0 4px; font-size: clamp(16px, 1.8vw, 22px); }
.rank-card .rank-meta { color: var(--text-muted); font-size: clamp(11px, 1.1vw, 13px); margin-bottom: 12px; }
table.rank-table { width: 100%; border-collapse: collapse; font-size: clamp(13px, 1.5vw, 18px); }
table.rank-table th { text-align: left; color: var(--text-muted); font-size: 0.6em; text-transform: uppercase; letter-spacing: 0.05em; padding: 0 8px 8px; }
table.rank-table td { padding: 8px; border-top: 1px solid var(--border-subtle); }
table.rank-table tr:first-child td { border-top: none; }
.pos-badge { display: inline-flex; width: 1.8em; height: 1.8em; align-items: center; justify-content: center; border-radius: 50%; background: color-mix(in srgb, var(--accent) 16%, transparent); color: var(--accent); font-weight: 800; font-size: 0.8em; }
.pos-badge.gold { background: var(--accent); color: var(--accent-text); }
.ad-card { background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 16px; overflow: hidden; display: flex; align-items: center; justify-content: center; min-height: 220px; }
.ad-card img, .ad-card video, .ad-card iframe { width: 100%; height: 100%; object-fit: cover; border: 0; display: block; }
.social-row { display: flex; flex-wrap: wrap; gap: 10px; margin-top: clamp(14px, 2vw, 24px); }
.social-pill { background: var(--bg-card-alt); border: 1px solid var(--border-subtle); color: var(--text-primary); text-decoration: none; padding: 10px 18px; border-radius: 999px; font-size: clamp(12px, 1.3vw, 15px); font-weight: 600; }
.kiosk-footnote { margin-top: 16px; text-align: center; color: var(--text-muted); font-size: 11px; opacity: 0.7; }
.gate { min-height: 100vh; display: flex; align-items: center; justify-content: center; }
.gate-box { background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 16px; padding: 32px; width: min(360px, 90vw); text-align: center; }
.gate-box input { width: 100%; box-sizing: border-box; margin: 14px 0; text-align: center; font-size: 16px; }
.empty-state { min-height: 100vh; display: flex; align-items: center; justify-content: center; text-align: center; padding: 24px; color: var(--text-secondary); }

/* ---------------------------------------------------------------------
   A COMPOSIÇÃO DE UM ECRÃ PÚBLICO (ver shared/ecras-templates.js)

   Estas regras vivem aqui, e não dentro do display.html, por uma razão:
   a pré-visualização do editor carrega este mesmo ficheiro. Uma
   pré-visualização com CSS próprio é uma pré-visualização que mente no
   dia em que o ecrã mudar.

   O `.kiosk-cartoes` é a coluna de conteúdo; `.has-ad` diz que há uma
   coluna de publicidade ao lado.
   --------------------------------------------------------------------- */
/* ---------------------------------------------------------------------
   AS BANDAS DE PUBLICIDADE (ver shared/ecras-zonas.js)

   A publicidade saiu de dentro da composição: passou a ser uma escolha à
   parte, e por isso qualquer composição pode ter banner em cima, em
   baixo, ao lado, ou nada. As medidas vêm do modelo em variáveis CSS --
   o mesmo cálculo que mede as zonas para o patrocinador --, e não há
   aqui nenhum número escrito à mão que possa discordar dele.

   As bandas vão de bordo a bordo: o padding saiu do `.kiosk` para o
   `.kiosk-util`. Uma faixa de patrocinador com uma margem à volta não é
   1920 de largura, e era 1920 que ele tinha comprado.
   --------------------------------------------------------------------- */
.kiosk-pub { background: var(--bg-card-alt); overflow: hidden; display: flex;
             align-items: center; justify-content: center; flex-shrink: 0; }
.kiosk-pub img, .kiosk-pub video, .kiosk-pub iframe { width: 100%; height: 100%; object-fit: cover; border: 0; display: block; }
.kiosk-pub-cima { height: var(--pub-cima, 0%); }
.kiosk-pub-baixo { height: var(--pub-baixo, 0%); }
.kiosk-pub-esq { width: var(--pub-esq, 0%); }
.kiosk-pub-dir { width: var(--pub-dir, 0%); }
.kiosk-faixa-de-topo { display: flex; flex-shrink: 0; height: var(--pub-cima, 0%); }
.kiosk-meio { flex: 1; display: flex; min-height: 0; }
.kiosk-util { flex: 1; display: flex; flex-direction: column; min-width: 0; min-height: 0; overflow: auto;
              padding: clamp(14px, 2.2vw, 34px); box-sizing: border-box; }

/* A marca quando fica DENTRO da faixa do banner. Ocupa a parte reservada
   e o banner começa depois dela -- não há sobreposição nenhuma, que é o
   que a especificação manda e o que evita um logótipo em cima de arte
   comprada. */
.kiosk-marca-no-banner { width: var(--marca-no-banner, 22%); flex-shrink: 0; display: flex;
                         align-items: center; gap: 10px; padding: 0 clamp(10px, 1.4vw, 22px);
                         box-sizing: border-box; background: var(--bg-card); }
.kiosk-marca-no-banner .kiosk-logo { width: auto; max-height: 70%; }

/* A marca reposicionada: uma linha discreta ao pé do conteúdo, e não uma
   faixa própria. Uma faixa era devolver ao conteúdo com uma mão o que o
   banner lhe tinha tirado com a outra. */
.kiosk-marca-compacta, .kiosk-so-relogio { display: flex; align-items: center; gap: 10px; margin-bottom: clamp(8px, 1.2vw, 16px); flex-shrink: 0; }
/* "Só logótipo" vale onde a marca estiver, e não só no cabeçalho de
   sempre: um logótipo que já diz "OpenBet" seguido de "OpenBet" escrito
   ao lado é a mesma coisa dita duas vezes, e numa televisão vê-se de
   longe. A marca passou a poder estar numa tira compacta ou dentro da
   faixa do banner -- e nesses dois sítios o nome continuava a aparecer. */
.kiosk-marca-compacta.brand-logo-only .nome,
.kiosk-marca-no-banner.brand-logo-only .kiosk-title { display: none; }
.kiosk-marca-compacta.brand-logo-only .kiosk-logo:has(img) { width: auto; max-width: 150px; }
/* O relógio sozinho, quando a marca não está aqui. Classe PRÓPRIA e não a
   da marca: com o mesmo nome, ninguém -- nem um teste -- conseguia
   distinguir "a marca está junto ao conteúdo" de "está só o relógio", e
   é essa a diferença que a configuração da identidade decide. */
.kiosk-so-relogio { justify-content: flex-end; }
.kiosk-marca-compacta .kiosk-logo { width: 34px; height: 34px; border-radius: 9px; font-size: 14px; }
.kiosk-marca-compacta .kiosk-logo:has(img) { width: auto; max-width: 120px; height: 34px; }
.kiosk-marca-compacta .nome { font-size: clamp(12px, 1.3vw, 16px); font-weight: 700; color: var(--text-secondary); }
.kiosk-marca-compacta .kiosk-clock { margin-left: auto; font-size: clamp(13px, 1.5vw, 18px); }

.kiosk-cartoes { display: flex; flex-direction: column; gap: 16px; min-width: 0; }

/* ---------------------------------------------------------------------
   UMA ZONA DE CONTEÚDO
   ---------------------------------------------------------------------
   O conteúdo deixou de ser dois interruptores para o ecrã inteiro e passou
   a ser uma escolha POR ZONA (ver ecras-conteudos.js). Cada zona é uma
   destas caixas, e é o `.kiosk-cartoes` acima que as põe lado a lado ou
   uma debaixo da outra, consoante a composição.

   `min-height: 0` e `min-width: 0` não são arrumação: sem eles, uma zona
   de vídeo dentro de uma grelha cresce até ao tamanho natural do vídeo e
   empurra a outra coluna para fora do ecrã -- e no recinto isso é meia
   classificação cortada pela borda da televisão. */
.kiosk-zona {
  display: flex; flex-direction: column; gap: clamp(8px, 1.2vw, 14px);
  min-width: 0; min-height: 0;
}
.kiosk-zona > .rank-card { flex: 0 1 auto; min-height: 0; }

/* Uma zona de imagem, de vídeo, de YouTube ou de página enche a zona
   toda. `overflow: hidden` com o raio da caixa: um vídeo de proporção
   diferente da zona ficava com os cantos por fora do arredondado. */
.kiosk-media {
  flex: 1; min-height: 0; min-width: 0;
  background: var(--bg-card-alt); border: 1px solid var(--border-subtle);
  border-radius: 16px; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.kiosk-media > img, .kiosk-media > video, .kiosk-media > iframe {
  width: 100%; height: 100%; display: block; border: 0;
}

/* Um complemento: a tira fina no rodapé de uma zona que já mostra outra
   coisa (os brindes entregues, a informação do evento). NÃO é um painel
   encolhido -- é uma linha, e o que cabe numa linha é a última entrega. */
.kiosk-tira {
  flex: 0 0 auto;
  background: var(--bg-card-alt); border: 1px solid var(--border-subtle);
  border-radius: 999px; padding: clamp(6px, 0.9vw, 10px) clamp(12px, 1.6vw, 20px);
  font-size: clamp(11px, 1.2vw, 15px); color: var(--text-secondary);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.kiosk-tira strong { color: var(--text-primary); }

/* O texto de uma zona de informação: quebras de linha respeitadas, e a
   medida a crescer com o ecrã como todo o resto desta página. */
.kiosk-info-texto {
  font-size: clamp(13px, 1.5vw, 19px); line-height: 1.55;
  color: var(--text-secondary); margin-top: clamp(6px, 1vw, 12px);
}

/* As redes sociais deixaram de ser uma linha do ecrã inteiro no fim da
   página: são um complemento DE UMA ZONA. Dentro de uma zona a margem de
   cima já vem do `gap`, e a que a regra geral põe deixava um palmo de
   vazio entre a classificação e as contas. */
.kiosk-zona .social-row { margin-top: 0; }

/* Quadro: o de sempre -- uma prova debaixo da outra. */
.kiosk-body[data-template="quadro"] .kiosk-cartoes { flex-direction: column; }

/* Duas colunas: as provas lado a lado, com o mesmo espaço para cada uma. */
.kiosk-body[data-template="duas-colunas"] .kiosk-cartoes {
  display: grid; grid-template-columns: 1fr 1fr; align-content: start;
}
@media (max-width: 860px) {
  .kiosk-body[data-template="duas-colunas"] .kiosk-cartoes { grid-template-columns: 1fr; }
}

/* ---------------------------------------------------------------------
   AS DUAS COLUNAS QUE CONTINUAM UMA A OUTRA
   ---------------------------------------------------------------------
   Mesma prova, e a coluna da direita a continuar a da esquerda (ver
   colunasQueContinuam, em ecras-conteudos.js): é uma classificação só.
   A caixa ocupa as duas colunas da composição; dentro dela, ou um cartão
   com a largura toda (ninguém ainda nos lugares da direita), ou o título
   uma vez e as duas tabelas lado a lado. */
.kiosk-zona-juntas { grid-column: 1 / -1; }
.rank-cabeca { display: flex; align-items: flex-start; justify-content: space-between; gap: clamp(12px, 2vw, 32px); }
.rank-cabeca > div:first-child { min-width: 0; }
/* O intervalo de lugares: discreto, como as legendas das colunas. */
.rank-intervalo {
  color: var(--text-muted); font-size: clamp(10px, 1vw, 13px); font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em; white-space: nowrap;
}
.rank-cabeca > .rank-intervalo { padding-top: 0.5em; }
.rank-colunas { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(16px, 2.6vw, 48px); align-items: start; }
.rank-coluna { min-width: 0; }
.rank-coluna > .rank-intervalo { margin-bottom: 6px; }
/* As duas metades com as mesmas medidas, linha a linha: largura fixa por
   coluna (a da direita tem o cabeçalho, invisível, só para isto) e nomes
   numa linha só -- um nome comprido a partir em duas desalinhava tudo. Só
   o NOME leva reticências: um resultado cortado é um resultado errado. */
.rank-colunas table.rank-table { table-layout: fixed; }
.rank-colunas table.rank-table th[data-coluna="posicao"] { width: 14%; }
.rank-colunas table.rank-table th[data-coluna="resultado"],
.rank-colunas table.rank-table th[data-coluna="diferenca"],
.rank-colunas table.rank-table th[data-coluna="tentativas"] { width: 20%; }
.rank-colunas table.rank-table td { white-space: nowrap; }
.rank-colunas table.rank-table td:nth-child(2) { overflow: hidden; text-overflow: ellipsis; }
.rank-cabecalho-repetido { visibility: hidden; }
@media (max-width: 860px) {
  .rank-colunas { grid-template-columns: 1fr; }
  .rank-cabecalho-repetido { display: none; }
}

/* «Sem ligação», por cima do que está na TV (ECR-11): o conteúdo fica, e
   isto só diz que pode estar desatualizado. Discreto, num canto, e fora
   do #root -- redesenhar o ecrã não o apaga nem o duplica. */
.tv-sem-ligacao {
  position: fixed; left: clamp(10px, 1.4vw, 24px); bottom: clamp(10px, 1.4vw, 24px); z-index: 60;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 12px; border-radius: 999px;
  background: color-mix(in srgb, var(--bg-card) 88%, transparent); border: 1px solid var(--border-subtle);
  color: var(--text-secondary); font-size: clamp(11px, 1vw, 14px); font-weight: 600;
}
.tv-sem-ligacao::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--warning, #F59E0B); }

/* A janela de verificação da gestão: diz-se, num canto, para ninguém a
   pôr numa TV a pensar que conta. */
.tv-verificacao {
  position: fixed; right: clamp(10px, 1.4vw, 24px); bottom: clamp(10px, 1.4vw, 24px); z-index: 60;
  padding: 6px 12px; border-radius: 999px;
  background: color-mix(in srgb, var(--bg-card) 88%, transparent); border: 1px dashed var(--border-subtle);
  color: var(--text-muted); font-size: clamp(11px, 1vw, 13px); font-weight: 600;
}

/* Foco: uma coisa só, a encher o ecrã. */
.kiosk-body[data-template="foco"] .kiosk-cartoes { display: flex; }
.kiosk-body[data-template="foco"] .kiosk-cartoes > * { flex: 1; display: flex; flex-direction: column; justify-content: center; }
.kiosk-body[data-template="foco"] table.rank-table { font-size: clamp(16px, 2.4vw, 30px); }

/* Faixa: cabeçalho encolhido e os cartões em linha, para um ecrã muito
   mais largo do que alto (uma barra por cima de uma porta, um 32:9). */
.kiosk[data-template="faixa"] .kiosk-util { padding: clamp(8px, 1.2vw, 18px); }
.kiosk[data-template="faixa"] .kiosk-header { margin-bottom: clamp(8px, 1vw, 14px); gap: 10px; }
.kiosk[data-template="faixa"] .kiosk-logo { width: 36px; height: 36px; border-radius: 10px; font-size: 15px; }
.kiosk[data-template="faixa"] .kiosk-logo:has(img) { width: auto; max-width: 130px; }
.kiosk[data-template="faixa"] .kiosk-header.brand-logo-only .kiosk-logo:has(img) { height: 36px; max-width: 180px; }
.kiosk[data-template="faixa"] .kiosk-title { font-size: clamp(15px, 1.6vw, 22px); }
.kiosk[data-template="faixa"] .kiosk-sub { font-size: clamp(10px, 1vw, 12px); }
.kiosk[data-template="faixa"] .kiosk-footnote { display: none; }
.kiosk-body[data-template="faixa"] .kiosk-cartoes {
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: clamp(8px, 1.2vw, 16px);
}
.kiosk-body[data-template="faixa"] .rank-card { padding: clamp(8px, 1.2vw, 14px); }

/* ---------------------------------------------------------------------
   UM CARTÃO POR ZONA, NO PASSO CONTEÚDOS
   ---------------------------------------------------------------------
   O conteúdo deixou de ser três interruptores para o ecrã inteiro e passou
   a ser uma escolha por zona. Cada zona é um cartão, e o cartão tem três
   partes pela ordem em que se decidem: o que a zona É, como se configura, e
   o que ela leva ALÉM disso. */
/* ---------------------------------------------------------------------
   A CONFIGURAÇÃO DO SERVIDOR DE JOGO: sessões, perfis e avançado
   ---------------------------------------------------------------------
   Existe desde 26/9, quando ficou claro que o pass2, ao reescrever o
   server_cfg.ini, tinha de modelar tudo o que lá vive -- senão apagava-o. */
.esj-bloco {
  margin-top: 18px; padding-top: 16px;
  border-top: 1px solid var(--border-subtle);
}
.esj-bloco-titulo { font-size: 13px; font-weight: 700; margin-bottom: 4px; }
.esj-bloco-sub { font-size: 12px; color: var(--text-muted); margin: 0 0 12px; line-height: 1.5; }

/* Uma sessão: o interruptor e, à direita, quanto dura. A medida só aparece
   quando ela está ligada -- perguntar a duração de uma sessão que não se
   corre é uma pergunta sem resposta certa. */
.esj-sessao {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 10px 0; border-bottom: 1px dashed var(--border-subtle);
}
.esj-sessao:last-child { border-bottom: 0; }
.esj-sessao .medida { display: flex; align-items: center; gap: 8px; margin-left: auto; }
.esj-sessao .medida select { min-width: 110px; }
.esj-sessao .medida input { width: 86px; }
.esj-sessao .medida .unidade { font-size: 12px; color: var(--text-muted); min-width: 42px; }
.esj-sessao:not(.is-ligada) .toggle-label { color: var(--text-muted); }

/* Os perfis: dois cartões a carregar, não um select. A descrição de cada um
   é o que faz a escolha ser informada -- "Público" sozinho não diz nada a
   quem nunca montou um destes. */
.esj-perfis { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 10px; }
.esj-perfil {
  text-align: left; padding: 12px 14px; border-radius: 12px; cursor: pointer;
  border: 1px solid var(--border-subtle); background: var(--bg-card-alt);
  display: flex; flex-direction: column; gap: 4px;
}
.esj-perfil strong { font-size: 13px; }
.esj-perfil span { font-size: 12px; color: var(--text-muted); line-height: 1.45; }
.esj-perfil:hover { border-color: var(--accent); }
.esj-perfil.is-escolhido { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }

/* "alterado à mão", ao lado do título: um perfil que mente sobre o que está
   lá dentro é pior do que não haver perfil nenhum. */
.esj-alterado {
  font-size: 11px; font-weight: 600; color: var(--warning, #F59E0B);
  border: 1px solid currentColor; border-radius: 999px; padding: 1px 8px; margin-left: 6px;
}

/* O avançado fechado: quem precisa dele abre-o, quem não precisa não o vê.
   Vinte interruptores à vista é outra maneira de falhar. */
.esj-avancado > summary {
  cursor: pointer; font-size: 13px; font-weight: 700; margin-bottom: 4px;
  list-style: none;
}
.esj-avancado > summary::-webkit-details-marker { display: none; }
.esj-avancado > summary::before { content: "▸ "; color: var(--text-muted); }
.esj-avancado[open] > summary::before { content: "▾ "; }
.esj-avancado .esj-bloco-titulo { margin-top: 16px; }

/* PORQUE É QUE O SERVIDOR DE JOGO CAIU, quando ele o disse antes de morrer.
   Âmbar e não vermelho: é informação sobre uma coisa que já aconteceu, não
   um alarme a pedir acção agora -- e o estado do servidor, ao lado, já diz
   que ele está em baixo. Ver porqueCaiu, em servidores-de-jogo.js. */
.sv-caiu {
  display: flex; align-items: flex-start; gap: 6px; margin-top: 4px;
  font-size: 12px; line-height: 1.45; color: var(--warning, #F59E0B);
  /* O texto vem do servidor de jogo e pode ser uma linha de despejo de
     memória do Go: quebra-se onde for preciso, senão estica a linha e
     empurra os botões para fora do cartão. */
  overflow-wrap: anywhere;
}
.sv-caiu svg { flex-shrink: 0; margin-top: 2px; }

/* CADA ZONA É UM CARTÃO.
   Levava `.panel-config`, que é só uma barra de 3px do lado esquerdo. Num
   painel que JÁ é de configuração, essa barra não distinguia nada: ficava
   um risco colorido ao lado de um título solto, sem caixa à volta, e as
   zonas encostavam-se umas às outras sem se ver onde acabava uma. Uma
   caixa fechada diz o que a barra queria dizer. */
.ed-zona-conteudo {
  margin-top: 14px; padding: 16px;
  border: 1px solid var(--border-subtle); border-radius: 12px;
  background: var(--bg-card-alt);
}
.ed-zona-conteudo:first-child { margin-top: 0; }
/* Sem isto, a regra geral `.cfg-grupo + .cfg-grupo` metia ainda um traço
   separador ENTRE dois cartões que já têm contorno. */
.cfg-grupo + .ed-zona-conteudo { margin-top: 14px; padding-top: 16px; border-top: 1px solid var(--border-subtle); }

/* A escolha das provas: o cabeçalho, a conta e os dois botões na mesma
   linha. Estavam em três linhas seguidas -- um subtítulo, dois botões e,
   por baixo das pastilhas, uma frase a dizer quantas estavam escolhidas. */
.ed-zona-provas-cabeca {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  margin-bottom: 10px;
}
.ed-zona-provas-cabeca .botoes { margin-left: auto; display: flex; gap: 8px; flex-wrap: wrap; }
.ed-zona-cabeca { display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap; }

/* A configuração e os complementos separados por uma linha: sem ela, os
   interruptores do "além disso" leem-se como se fossem mais campos do
   tipo escolhido -- e "Mostrar redes sociais" dentro da configuração das
   classificações é uma pergunta sobre outra coisa. */
.ed-zona-config:not(:empty) { margin-top: 12px; }
.ed-zona-complementos {
  margin-top: 16px; padding-top: 14px;
  border-top: 1px solid var(--border-subtle);
}

/* AS ARTES DE PUBLICIDADE DE UMA ZONA.
   Este bloco inteiro não existia. A marcação estava escrita -- `.ed-arte`,
   `.ed-arte-ordem`, `.amostra`, `.segundos`, `.lista`, `.vazia` -- e
   nenhuma dessas classes tinha regra em lado nenhum. Um `<div>` sem regra
   é uma linha de texto: o nome da arte, o número dos segundos, o "s" e as
   duas setas saíam todos na mesma mancha, colados, e a miniatura não
   tinha medida. Passo 4 do editor de ecrãs, à vista de quem o abrisse. */
.ed-zona-artes {
  margin-top: 14px; padding: 16px;
  border: 1px solid var(--border-subtle); border-radius: 12px;
  background: var(--bg-card-alt);
}
.ed-zona-artes:first-child { margin-top: 0; }
.ed-zona-artes > .cabeca {
  display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap;
  margin-bottom: 12px;
}
.ed-zona-artes > .cabeca > div { flex: 1; min-width: 0; }
.ed-zona-artes > .cabeca .nome { font-size: 14px; font-weight: 700; }
.ed-zona-artes > .cabeca .medida { font-size: 12px; color: var(--text-muted); margin-top: 2px; }
.ed-zona-artes > .lista { display: flex; flex-direction: column; gap: 10px; }
.ed-zona-artes > .vazia { font-size: 12px; color: var(--text-muted); margin: 0; }

/* Uma arte, no passo Conteúdos: miniatura, nome, e o botão de a tirar. */
.ed-arte {
  display: flex; align-items: flex-start; gap: 12px; padding: 12px;
  border: 1px solid var(--border-subtle); border-radius: 10px; background: var(--bg-card);
}
.ed-arte > .amostra {
  width: 76px; height: 48px; flex-shrink: 0; overflow: hidden;
  border-radius: 8px; border: 1px solid var(--border-subtle); background: var(--bg-card-alt);
  display: flex; align-items: center; justify-content: center;
}
.ed-arte > .amostra img { width: 100%; height: 100%; object-fit: contain; display: block; }
.ed-arte > .amostra .video { font-size: 11px; color: var(--text-muted); }
.ed-arte > .corpo { flex: 1; min-width: 0; }
.ed-arte > .corpo > .titulo { width: 100%; }
.ed-arte > .corpo > .meta {
  font-size: 12px; color: var(--text-muted); margin-top: 4px; overflow-wrap: anywhere;
}
.ed-arte-identidade {
  display: flex; align-items: flex-start; gap: 8px; margin-top: 10px;
  font-size: 12px; cursor: pointer;
}
.ed-arte-identidade input { width: 16px; height: 16px; margin: 1px 0 0; flex-shrink: 0; accent-color: var(--ok); }

/* Uma arte na ORDEM por que passa (passo Programação). A mesma arte, sem
   miniatura: aqui só interessa em que lugar está e quantos segundos fica. */
.ed-arte-ordem {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  border: 1px solid var(--border-subtle); border-radius: 10px; background: var(--bg-card);
}
.ed-arte-ordem > .posicao {
  width: 24px; height: 24px; flex-shrink: 0; border-radius: 7px;
  background: var(--bg-card-alt); color: var(--text-secondary);
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.ed-arte-ordem > .nome { flex: 1; min-width: 0; font-size: 13px; overflow-wrap: anywhere; }
.ed-arte-ordem > .segundos { display: flex; align-items: center; gap: 5px; flex-shrink: 0; }
.ed-arte-ordem > .segundos input { width: 64px; text-align: right; font-variant-numeric: tabular-nums; }
.ed-arte-ordem > .segundos span { font-size: 12px; color: var(--text-muted); }

/* O rótulo de um campo que não é um <label> (porque o campo a seguir não
   é um controlo só). Vestia-se de nada: letra do corpo, a fazer-se passar
   por um título. */
.rotulo-campo { display: block; font-size: 12px; font-weight: 700; margin-bottom: 6px; }

/* O botão de tirar uma coisa. Vivia no <style> do servidor.html e já era
   usado em dois ecrãs -- no editor de ecrãs saía cinzento como os outros,
   e "Remover" ao lado de "Trocar a imagem" sem nada que os distinga é um
   clique que ninguém pode desfazer. */
.sv-perigo, .sv-perigo:hover { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 45%, transparent); }

/* CADA INTERRUPTOR NA SUA LINHA, com a ajuda dele por baixo.
   `.toggle-switch` é `inline-flex`: dois seguidos partilhavam a linha, e
   a ajuda que vinha a seguir aparecia debaixo dos DOIS. "Só em provas de
   tempo" lia-se como se fosse também sobre a coluna do resultado. */
.ed-zona-interruptor + .ed-zona-interruptor { margin-top: 12px; }
.ed-zona-interruptor .ajuda { margin-left: 52px; }

/* A amostra da imagem de uma zona. Medida contida de propósito: é para
   confirmar QUAL é a imagem, e não para a ver -- para isso está a
   pré-visualização ao lado, com a medida a sério da zona. */
.ed-zona-amostra {
  max-width: 260px; aspect-ratio: 16 / 9; margin-bottom: 10px;
  border: 1px solid var(--border-subtle); border-radius: 10px;
  background: var(--bg-card-alt); overflow: hidden;
}
.ed-zona-amostra img { width: 100%; height: 100%; object-fit: contain; display: block; }

/* O cartão para onde a pré-visualização acabou de apontar. Um piscar curto
   e nada mais: sem ele, quem clica numa zona que já estava à vista não vê
   nada acontecer e clica outra vez. */
.ed-zona-apontada { box-shadow: 0 0 0 2px var(--accent); }
@media (prefers-reduced-motion: no-preference) {
  .ed-zona-apontada { transition: box-shadow .2s; }
}

/* ---------------------------------------------------------------------
   AS ZONAS CLICÁVEIS DA PRÉ-VISUALIZAÇÃO
   ---------------------------------------------------------------------
   Por cima do iframe, uma caixa transparente por zona de conteúdo: clicar
   nela abre a configuração dessa zona. A alternativa era procurar o cartão
   certo numa lista de quatro -- e quem está a olhar para a televisão já
   está a apontar para a zona que quer mudar. */
.ed-previa-cliques { position: absolute; inset: 0; }
.ed-previa-zona {
  position: absolute; border: 0; padding: 0; cursor: pointer;
  background: transparent; border-radius: 8px;
  outline: 1px dashed transparent; outline-offset: -3px;
  transition: background .12s, outline-color .12s;
}
.ed-previa-zona:hover, .ed-previa-zona:focus-visible {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  outline-color: var(--accent);
}
.ed-previa-zona .rotulo {
  position: absolute; left: 6px; top: 6px; opacity: 0;
  background: var(--accent); color: var(--accent-text, #fff);
  font-size: 11px; font-weight: 700; padding: 3px 8px; border-radius: 999px;
  pointer-events: none; transition: opacity .12s; white-space: nowrap;
}
.ed-previa-zona:hover .rotulo, .ed-previa-zona:focus-visible .rotulo { opacity: 1; }

/* A caixa da pré-visualização do editor: o iframe vai com o tamanho a
   sério do formato escolhido e encolhe-se por transformação, para as
   medidas em `vw` lá dentro contarem a largura CERTA. */
.ed-previa-caixa { position: relative; overflow: hidden; border: 1px solid var(--border-subtle); border-radius: 12px; background: var(--bg-card-alt); }
.ed-previa-caixa iframe { border: 0; display: block; transform-origin: top left; background: var(--bg-page, #0b0f19); }

/* ---------------------------------------------------------------------
   O EDITOR DE ECRÃ A DUAS COLUNAS
   ---------------------------------------------------------------------
   Campos à esquerda, pré-visualização FIXA à direita.

   A razão é a que se sentia a configurar: a pré-visualização estava no fim
   da etapa, por baixo de tudo. Mudava-se o template ou desligava-se o
   relógio e era preciso descer para ver, subir para mexer outra vez. Numa
   etapa comprida (a do Conteúdo, com a rotação) são dois ecrãs de
   distância entre a decisão e o que ela faz -- e uma pré-visualização que
   obriga a ir buscá-la deixa de ser usada.

   É a mesma ideia do `.cm-duas` das Competições, e não a mesma regra de
   propósito: o corte é noutro sítio (aqui a coluna do lado tem uma medida
   mínima, porque um ecrã de televisão encolhido para menos de 340px
   deixa de se ler) e um prefixo é de uma área só (ver
   nomes-de-classe-nao-se-repetem.test.js).

   A classe liga-se e desliga-se em JavaScript, e só nas etapas que têm
   pré-visualização: nas outras (a papelada e a revisão) uma coluna de
   1400px daria linhas de texto largas demais para se lerem.
   O número 1200 tem de ser o mesmo que EcrasRascunho.LARGURA_PARA_PREVIA_AO_LADO,
   senão o aviso de largura mente. */
.wiz-wrap.ed-lado-a-lado { max-width: 1460px; }
.ed-lado-a-lado .ed-duas { display: grid; grid-template-columns: minmax(0, 1fr) minmax(340px, 0.6fr); column-gap: 18px; align-items: start; }
.ed-lado-a-lado .ed-duas > .wiz-cartao { grid-column: 1; margin-bottom: 0; }
.ed-lado-a-lado .ed-duas > .ed-lado { grid-column: 2; position: sticky; top: 14px; margin-top: 0; }

/* A pré-visualização é uma CAIXA IRMÃ do assistente, não uma caixa dentro
   dele -- é por isso que a grelha está no `.ed-duas` e não no
   `.wiz-cartao`.

   Foi o engano da primeira versão: pus as duas colunas DENTRO do cartão do
   assistente. Dar-lhe fundo próprio não chegou, e não podia chegar: uma
   caixa desenhada dentro de outra lê-se como parte dela, por mais contraste
   que tenha. O que separa duas coisas é serem duas, não serem de cores
   diferentes.

   Por isso veste-se como o cartão ao lado -- mesmo fundo, mesma borda,
   mesmo canto -- e fica a par dele. É a mesma disposição do quadro das
   Competições (.cm-duas/.cm-lado). */
.ed-lado { background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 16px; padding: 22px; margin-top: 16px; }
/* Dentro da caixa, o título já é o da caixa: não leva a risca de separação
   que os grupos do assistente levam entre si. */
.ed-lado > .cfg-grupo-titulo { margin-top: 0; }

/* ---------------------------------------------------------------------
   A GALERIA DE TEMPLATES
   ---------------------------------------------------------------------
   Era uma lista de opções com três linhas de texto cada. Escolher uma
   composição por descrição escrita é escolher às cegas: "duas provas lado
   a lado" e "uma coisa só a ocupar o ecrã" são a mesma quantidade de
   palavras e desenhos completamente diferentes.

   A miniatura é desenhada a partir das ZONAS declaradas no template (ver
   ecras-templates.js) -- não é um .png, por isso não pode ficar
   desactualizada no dia em que o template mudar. */
.ed-galeria { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 12px; }
.ed-modelo { display: flex; gap: 14px; align-items: flex-start; padding: 14px; cursor: pointer;
             border: 1px solid var(--border-subtle); border-radius: 12px; background: var(--bg-card-alt); }
.ed-modelo input { position: absolute; opacity: 0; pointer-events: none; }
.ed-modelo:hover { border-color: color-mix(in srgb, var(--accent) 40%, var(--border-subtle)); }
.ed-modelo.is-escolhido { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, var(--bg-card-alt)); }
.ed-modelo:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; }
.ed-modelo .miniatura { flex-shrink: 0; color: var(--text-secondary); line-height: 0; }
.ed-modelo.is-escolhido .miniatura { color: var(--accent); }
.ed-modelo .corpo { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.ed-modelo .titulo { font-size: 13.5px; font-weight: 700; }
.ed-modelo .desc { font-size: 12px; color: var(--text-secondary); line-height: 1.45; }
.ed-modelo .zonas { font-size: 11.5px; color: var(--text-muted); margin-top: 2px; }
/* Um template que não serve a orientação escolhida não desaparece da
   galeria -- desaparecer sem explicação é pior do que ficar marcado. */
.ed-modelo.nao-serve { opacity: 0.62; }
.ed-modelo .selo { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
                   color: var(--warn); border: 1px solid color-mix(in srgb, var(--warn) 45%, transparent);
                   border-radius: 6px; padding: 1px 5px; margin-left: 4px; white-space: nowrap; }

/* As zonas, com as medidas que se mandam a quem faz a arte. */
.ed-zonas { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 10px; }
.ed-zona { padding: 12px 14px; border: 1px solid var(--border-subtle); border-radius: 10px; background: var(--bg-card-alt); }
/* Um diagrama minúsculo a dizer ONDE fica esta zona. Sem ele, "Lateral
   esquerda 384 × 950" obriga a montar o ecrã de cabeça para se perceber
   de que lado é -- e quem lê isto está a escrever um email a um
   patrocinador, não a decorar a configuração. */
.ed-zona-mapa { display: block; margin-bottom: 8px; color: var(--text-muted); }
.ed-zona[data-tipo="publicidade"] .ed-zona-mapa { color: var(--accent); }
/* A área reservada à marca dentro da faixa do banner. Âmbar porque é uma
   condição do que se vai pedir, e não uma medida a mais. */
.ed-zona-segura { margin-top: 8px; font-size: 11.5px; line-height: 1.45; color: var(--warn); }

/* A galeria das estruturas publicitárias: os mesmos cartões da
   composição, e de propósito -- são duas escolhas do mesmo tipo, feitas
   uma a seguir à outra, e dois desenhos diferentes fariam parecer que
   uma delas é mais importante. */
.ed-estruturas .ed-modelo .miniatura { color: var(--accent); }

/* Quanto do ecrã é do patrocinador. Vive por baixo da pré-visualização,
   que é onde se está a olhar quando se muda uma estrutura. */
.ed-ocupacao { margin-top: 12px; padding: 12px 14px; border: 1px solid var(--border-subtle);
               border-radius: 10px; background: var(--bg-card-alt); }
.ed-ocupacao .numeros { font-size: 13px; font-weight: 700; }
.ed-ocupacao .zonas { font-size: 11.5px; color: var(--text-muted); margin-top: 3px; }
.ed-ocupacao .barra { margin-top: 10px; height: 6px; border-radius: 999px; background: var(--bg-card); overflow: hidden; }
.ed-ocupacao .barra > span { display: block; height: 100%; background: var(--accent); border-radius: 999px; }
/* Acima de 30% a barra fica âmbar. Não bloqueia nada -- há eventos em
   que o patrocinador comprou metade da televisão --, mas quem está a
   configurar vê a conta que costuma fazer de cabeça e errar. */
.ed-ocupacao.is-aviso .barra > span { background: var(--warn); }
.ed-ocupacao.is-aviso .numeros { color: var(--warn); }
.ed-ocupacao .avisos { margin: 10px 0 0; padding-left: 18px; font-size: 11.5px; line-height: 1.5; color: var(--text-secondary); }
.ed-ocupacao .avisos li + li { margin-top: 5px; }

/* O formato da pré-visualização: uma etiqueta e não três botões. Os três
   botões faziam parecer que o formato do ecrã se escolhia ali -- e
   escolhe-se em cima, na orientação e na resolução. */
/* Uma opção que não cabe NESTA RESOLUÇÃO. Fica à vista e desactivada,
   porque há uma coisa a fazer: mudar a resolução. As que não servem a
   ORIENTAÇÃO nem chegam a ser desenhadas -- ver desenharComposicoes. */
.ed-modelo.nao-serve { opacity: 0.55; cursor: not-allowed; }
.ed-modelo.nao-serve:hover { border-color: var(--border-subtle); }
/* O caminho para a desbloquear, dentro do próprio cartão. O botão tem de
   receber o clique sem que o `<label>` à volta escolha a opção que ainda
   não cabe -- por isso `position:relative` e um z-index acima do input. */
.ed-modelo .ed-desbloqueia { display: block; margin-top: 6px; font-size: 11.5px; line-height: 1.5;
                             color: var(--text-muted); }
.ed-modelo .ed-desbloqueia .link-inline { position: relative; z-index: 2; margin-top: 3px;
                                          display: inline-block; cursor: pointer; pointer-events: auto; }

/* A nota de que a composição mudou sozinha. Discreta de propósito: não é
   um erro, é uma coisa que já foi resolvida e que se diz por delicadeza.
   Por isso não é âmbar nem vermelha. */
.ed-nota { display: flex; align-items: center; gap: 8px; margin-top: 12px; padding: 9px 12px;
           border-radius: 10px; background: var(--bg-card-alt); border: 1px solid var(--border-subtle);
           font-size: 12.5px; color: var(--text-secondary); }
.ed-nota svg { color: var(--text-muted); flex-shrink: 0; }

/* As duas colunas de classificação: se repetem, se continuam, e o atalho
   para continuar. O aviso é âmbar porque a TV vai mostrar o mesmo duas
   vezes -- não trava a publicação, mas não pode passar despercebido. */
.ed-colunas { margin-top: 14px; padding: 12px 14px; border-radius: 10px; background: var(--bg-card-alt);
              border: 1px solid var(--border-subtle); font-size: 13px; color: var(--text-secondary); }
.ed-colunas.is-aviso { border-color: var(--warn); }
.ed-colunas.is-aviso .ed-colunas-frase strong { color: var(--warn); }
.ed-colunas-frase { margin: 0; line-height: 1.5; }
.ed-colunas .btn-sm { margin-top: 10px; }

/* ==================== ELEMENTOS FIXOS NO ECRÃ ====================
   Duas perguntas independentes -- o logótipo e o relógio --, cada uma com
   dois botões que são UM campo. Segmentado e não interruptor: "Mostrar" e
   "Não mostrar" ditos por palavras lêem-se de relance, e um interruptor
   obriga a saber se ligado quer dizer sim. */
.ed-fixos { padding-top: 18px; border-top: 1px solid var(--border-subtle); }
.ed-fixos-titulo { font-size: 13px; font-weight: 700; margin: 0 0 3px; }
.ed-fixos-sub { font-size: 12.5px; color: var(--text-muted); margin: 0 0 14px; line-height: 1.5; }
.ed-fixos-grelha { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 18px; }
.ed-fixo .rotulo { display: block; font-size: 12px; font-weight: 700; margin-bottom: 7px; }
.ed-fixo .ajuda { margin-top: 7px; }
.ed-segmento { display: flex; gap: 8px; }
.ed-seg { flex: 1 1 0; padding: 10px 12px; border-radius: 10px; font-size: 13px; font-weight: 700;
          background: var(--bg-card-alt); border: 1px solid var(--border-subtle);
          color: var(--text-secondary); cursor: pointer; text-align: center; }
.ed-seg:hover { border-color: color-mix(in srgb, var(--accent) 45%, transparent); }
/* A seleção leva a cor do EVENTO, e não verde: verde nesta aplicação quer
   dizer "correu bem", e escolher uma opção não é uma validação. */
.ed-seg.is-ligado { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }

/* ==================== O CARTÃO DO LOGÓTIPO ====================
   Dois estados que se distinguem de relance: com ficheiro, o que dele se
   sabe; sem ficheiro, o convite. Era uma caixa só, com uma figura redonda
   e duas linhas que diziam o mesmo nos dois casos. */
.ed-logo-cartao { display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
                  padding: 14px; border-radius: 12px; background: var(--bg-card-alt);
                  border: 1px solid var(--border-subtle); }
.ed-logo-cartao .figura { width: 84px; height: 84px; border-radius: 10px; background: var(--bg-card);
                          border: 1px solid var(--border-subtle); display: flex; align-items: center;
                          justify-content: center; overflow: hidden; flex-shrink: 0; padding: 8px; }
/* `contain` e nunca `cover`: um logótipo esticado ou cortado é um logótipo
   estragado, e o cartão tem de mostrar exactamente o que a televisão põe. */
.ed-logo-cartao .figura img { max-width: 100%; max-height: 100%; object-fit: contain; }
.ed-logo-cartao .corpo { flex: 1 1 200px; min-width: 0; }
.ed-logo-cartao .ficheiro { font-size: 13px; font-weight: 700; word-break: break-all; }
.ed-logo-cartao .meta { font-size: 12px; color: var(--text-muted); margin-top: 3px; font-variant-numeric: tabular-nums; }
.ed-logo-cartao .selos { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
/* "Em utilização" é uma validação a sério -- este ficheiro é o que está a
   ser mostrado --, e por isso leva verde. A origem é informação, e leva
   cinzento. */
.ed-logo-cartao .selo-uso { font-size: 11px; font-weight: 700; padding: 2px 9px; border-radius: 999px;
                            background: color-mix(in srgb, var(--ok) 16%, transparent); color: var(--ok); }
.ed-logo-cartao .selo-origem { font-size: 11px; font-weight: 700; padding: 2px 9px; border-radius: 999px;
                               background: var(--bg-card); border: 1px solid var(--border-subtle); color: var(--text-muted); }
.ed-logo-cartao .accoes { display: flex; gap: 8px; flex-wrap: wrap; }

.ed-logo-vazio { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; padding: 22px 18px;
                 border: 1.5px dashed var(--border-subtle); border-radius: 14px; background: var(--bg-card-alt); }
.ed-logo-vazio .icone { color: var(--text-muted); flex-shrink: 0; }
.ed-logo-vazio .texto { flex: 1 1 220px; min-width: 0; }
.ed-logo-vazio .texto strong { display: block; font-size: 13.5px; margin-bottom: 4px; }
.ed-logo-vazio .texto span { font-size: 12px; color: var(--text-muted); line-height: 1.5; }

/* A tira de largar fica POR BAIXO e discreta: com ficheiro carregado, o
   cartão é para ler, e uma caixa tracejada à volta do que já está feito
   lê-se como se faltasse alguma coisa. */
.ed-largar { display: flex; align-items: center; justify-content: center; gap: 7px; margin-top: 8px;
             padding: 9px; border: 1px dashed var(--border-subtle); border-radius: 10px;
             font-size: 12px; color: var(--text-muted); }
.cfg-campo.a-arrastar .ed-largar,
.cfg-campo.a-arrastar .ed-logo-vazio { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, var(--bg-card-alt)); }
.cfg-campo:focus { outline: none; }

/* O logótipo desligado: um resumo de uma linha, sem a gestão do ficheiro.
   O ficheiro não se apagou -- e é isso que a frase diz. */
.ed-logo-resumo { display: flex; align-items: flex-start; gap: 9px; padding: 12px 14px; border-radius: 10px;
                  background: var(--bg-card-alt); border: 1px solid var(--border-subtle);
                  font-size: 12.5px; color: var(--text-secondary); line-height: 1.5; }
.ed-logo-resumo svg { color: var(--text-muted); flex-shrink: 0; margin-top: 1px; }

/* A leitura do ficheiro, e SÓ enquanto ela está mesmo a acontecer. */
.ed-logo-cartao.a-carregar .ed-logo-progresso { flex: 1 1 200px; }
.ed-logo-cartao .barra { height: 6px; border-radius: 999px; background: var(--bg-card); overflow: hidden; margin: 8px 0 5px; }
.ed-logo-cartao .barra span { display: block; height: 100%; background: var(--accent); transition: width 0.12s linear; }


/* Uma zona que não existe nesta configuração: sem medidas, e com o nome
   esbatido -- as medidas seriam tomadas por um ficheiro a mandar fazer. */
.ed-zona[data-estado="nao-utilizada"] { opacity: 0.6; }

.ed-formato-atual { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 700;
                    padding: 6px 12px; border-radius: 999px; background: var(--bg-card-alt);
                    border: 1px solid var(--border-subtle); color: var(--text-secondary); }
.ed-formato-atual.is-simulado { border-color: color-mix(in srgb, var(--warn) 45%, transparent); }
.ed-formato-atual em { font-style: normal; color: var(--warn); font-weight: 600; }

/* Uma banda de publicidade ainda sem arte. Diz o que ali vai estar, em
   vez de ficar um retângulo vazio que se lê como um erro de desenho. */
.kiosk-pub-vazia { font-size: clamp(10px, 1.1vw, 14px); font-weight: 700; letter-spacing: 0.08em;
                   text-transform: uppercase; color: var(--accent); opacity: 0.85; }

/* Um botão que se lê como uma ligação, para uma ação secundária dentro
   de um campo ("usar resolução personalizada"). */
.link-inline { background: none; border: 0; padding: 0; margin-top: 6px; font-size: 12px;
               color: var(--accent); cursor: pointer; text-decoration: underline; font-family: inherit; }
.ed-zona .nome { font-size: 13px; font-weight: 700; }
.ed-zona .tipo { font-size: 11.5px; color: var(--text-muted); margin-top: 2px; line-height: 1.4; }
.ed-zona .medida { font-size: 12.5px; color: var(--text-secondary); margin-top: 8px;
                   font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.ed-zona .medida span { display: block; font-family: inherit; font-size: 11px; color: var(--text-muted); margin-top: 2px; }

/* O endereço público de um ecrã já publicado: mostra-se, copia-se, e
   mudá-lo é uma ação à parte. */
.ed-endereco { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 10px 14px;
               border: 1px solid var(--border-subtle); border-radius: 10px; background: var(--bg-card-alt); }
.ed-endereco .link { flex: 1; min-width: 180px; font-size: 12.5px; color: var(--text-secondary); overflow-wrap: anywhere;
                     font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.ed-endereco .selo { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
                     color: var(--ok); border: 1px solid color-mix(in srgb, var(--ok) 45%, transparent);
                     border-radius: 6px; padding: 1px 6px; white-space: nowrap; }

/* A palavra-passe: o campo e os dois botões na mesma linha. */
.ed-pwd { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.ed-pwd input { flex: 1; min-width: 180px; }

/* O aviso de arte fraca -- laranja, porque é um aviso e não um erro: o
   ficheiro grava-se na mesma, fica é mau numa televisão. */
.ed-aviso-arte { display: flex; align-items: flex-start; gap: 7px; margin-top: 8px; font-size: 12px;
                 color: var(--warn); line-height: 1.45; }
.ed-aviso-arte svg { flex-shrink: 0; margin-top: 1px; }

/* A identidade escolhida, em pequeno. */
.ed-identidade { margin-top: 16px; }
.ed-identidade-cartao { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; padding: 14px;
                        border: 1px solid var(--border-subtle); border-left: 3px solid var(--accent);
                        border-radius: 12px; background: var(--bg-card-alt); }
.ed-identidade-cartao .marca { width: 46px; height: 46px; border-radius: 12px; overflow: hidden; flex-shrink: 0;
                               color: #1a1530; display: flex; align-items: center; justify-content: center; font-weight: 800; }
/* `contain` e nunca `cover`: `cover` CORTA, e um logótipo de 640×180 num
   quadrado ficava com as pontas de fora — lia-se "penB" onde está escrito
   "OpenBet". Um logótipo cortado é um logótipo estragado, e este cartão
   existe para mostrar exactamente o que a televisão vai pôr. */
.ed-identidade-cartao .marca img { width: 100%; height: 100%; object-fit: contain; padding: 5px; }
.ed-identidade-cartao .texto { flex: 1; min-width: 150px; }
.ed-identidade-cartao .nome { font-size: 14px; font-weight: 700; }
.ed-identidade-cartao .onde { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
                              font-size: 12px; color: var(--text-muted); margin-top: 5px; }
.ed-selo-marca { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
                 color: var(--text-secondary); border: 1px solid var(--border-subtle);
                 border-radius: 6px; padding: 1px 6px; white-space: nowrap; }
.ed-identidade-cartao .cores { display: inline-flex; align-items: center; gap: 6px;
                               font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 11.5px; }
.ed-identidade-cartao .ponto { width: 13px; height: 13px; border-radius: 4px; display: inline-block;
                               border: 1px solid var(--border-subtle); margin-left: 6px; }
.ed-identidade-cartao .ponto:first-child { margin-left: 0; }

/* O resumo da última etapa: o que o ecrã É, antes do que mudou. */
.ed-resumo { display: flex; flex-direction: column; gap: 8px; margin-bottom: 20px; }
.ed-resumo .linha { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; padding: 11px 14px;
                    border: 1px solid var(--border-subtle); border-radius: 10px; background: var(--bg-card-alt); }
.ed-resumo .campo { font-size: 12px; font-weight: 700; color: var(--text-muted); min-width: 108px;
                    text-transform: uppercase; letter-spacing: 0.04em; }
.ed-resumo .valor { flex: 1; min-width: 180px; font-size: 13px; color: var(--text-secondary); line-height: 1.5; }

/* O conselho de largura. Uma linha dispensável, nunca uma caixa por cima:
   o editor FUNCIONA em coluna única, e quem está a arrumar isto no
   portátil pequeno da véspera tem de poder continuar sem carregar em nada.
   Sem cor de alarme de propósito -- não há nada de errado. */
.ed-conselho { display: flex; align-items: flex-start; gap: 12px; padding: 12px 14px; margin-bottom: 18px;
               border: 1px solid var(--border-subtle); border-left: 3px solid var(--text-muted);
               border-radius: 12px; background: var(--bg-card-alt); }
.ed-conselho .texto { flex: 1; min-width: 0; font-size: 12.5px; color: var(--text-secondary); line-height: 1.55; }
.ed-conselho .texto strong { color: var(--text-primary); }
.ed-conselho .fechar { flex-shrink: 0; background: none; border: 0; color: var(--text-muted); cursor: pointer;
                       font-size: 12px; font-weight: 700; padding: 2px 6px; border-radius: 8px; }
.ed-conselho .fechar:hover { color: var(--text-primary); background: var(--bg-card); }
.ed-conselho .fechar:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

@media (max-width: 1200px) {
  .wiz-wrap.ed-lado-a-lado { max-width: 1060px; }
  .ed-lado-a-lado .ed-duas { display: block; }
  .ed-lado-a-lado .ed-duas > .wiz-cartao { margin-bottom: 16px; }
  .ed-lado-a-lado .ed-duas > .ed-lado { position: static; margin-top: 0; }
}

.ev-menu-conteiner { position: relative; }
.ev-menu-botao { width: 44px; height: 44px; border-radius: 10px; border: 1px solid var(--border-subtle); background: none; color: var(--text-secondary); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; }
.ev-menu-botao:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.ev-menu { position: absolute; right: 0; top: calc(100% + 6px); z-index: 30; min-width: 210px; background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 12px; box-shadow: 0 18px 40px rgba(0,0,0,0.45); padding: 6px; }
/* Um item deste menu tanto pode ser uma ação (button) como um sítio para
   onde ir (a) -- e os dois têm de ser indistinguíveis a olho. */
.ev-menu button, .ev-menu a { display: flex; align-items: center; gap: 10px; width: 100%; background: none; border: 0; border-radius: 8px; padding: 11px 12px; font-size: 13px; font-weight: 600; color: var(--text-secondary); cursor: pointer; text-align: left; text-decoration: none; }
.ev-menu button:hover, .ev-menu button:focus-visible,
.ev-menu a:hover, .ev-menu a:focus-visible { background: var(--bg-card-alt); color: var(--text-primary); outline: none; }
.ev-menu button.perigo { color: var(--danger); }
.ev-menu hr { border: 0; border-top: 1px solid var(--border-subtle); margin: 5px 4px; }

/* Estados da página */
.ev-vazio { text-align: center; padding: 46px 20px; }
.ev-vazio .icone { color: var(--text-muted); margin-bottom: 12px; }
.ev-vazio h3 { font-size: 16px; margin: 0 0 6px; }
.ev-vazio p { font-size: 13px; color: var(--text-muted); margin: 0 0 18px; }
.ev-esqueleto { border: 1px solid var(--border-subtle); border-radius: 14px; background: var(--bg-card); padding: 18px 20px; }
.ev-esqueleto + .ev-esqueleto { margin-top: 12px; }
.ev-esqueleto .barra { height: 12px; border-radius: 6px; background: var(--bg-card-alt); animation: evPulsar 1.2s ease-in-out infinite; }
.ev-esqueleto .barra + .barra { margin-top: 10px; }
@keyframes evPulsar { 0%, 100% { opacity: 0.45; } 50% { opacity: 0.85; } }
@media (prefers-reduced-motion: reduce) { .ev-esqueleto .barra { animation: none; } }

@media (max-width: 860px) {
  /* Cartão vertical: identidade, estados, configuração, métricas, ações --
     por esta ordem, que é a ordem em que se lê. */
  .ev-cartao {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "topo     menu"
      "config   config"
      "metricas metricas"
      "acoes    acoes";
  }
  .ev-cartao-topo { flex-wrap: wrap; }
  .ev-acoes { width: 100%; margin-top: 14px; }
  .ev-acoes .principal { flex: 1; }

  /* O botão de três pontos é o mais pequeno do cartão -- no telemóvel
     acompanha os outros, senão é o único difícil de acertar com o dedo. */
  .ev-menu-botao { width: 48px; height: 48px; }
  .ev-metricas { gap: 12px 20px; }
  .ev-metricas .preco { margin-left: 0; width: 100%; }
  .ev-ferramentas select, .ev-ferramentas .procura { flex: 1 1 100%; min-width: 0; }
  .ev-barra { max-width: none; }
}

/* -------------------------------------------------------------------------
   A folha de "Enviar / Reenviar convite" (shared/convite-envio.js)
   -------------------------------------------------------------------------
   Vive aqui, e não na página, porque a MESMA caixa abre em dois sítios: a
   lista de Convidados e a ficha de um convidado. Estilos duplicados nas
   duas páginas era como se acabava com a caixa a mudar de forma consoante
   o sítio de onde foi aberta. Os alvos de toque ficam nos 48px do resto do
   projeto -- esta caixa usa-se muito no telemóvel. */
.cv-campo-email { margin-top: 4px; }
.cv-campo-email input { width: 100%; min-height: 48px; }
.cv-escolha { display: flex; gap: 12px; align-items: flex-start; padding: 14px; border: 1px solid var(--border-subtle); border-radius: 12px; cursor: pointer; min-height: 48px; }
.cv-escolha + .cv-escolha { margin-top: 10px; }
.cv-escolha.escolhida { border-color: var(--ok); background: color-mix(in srgb, var(--ok) 8%, var(--bg-card)); }
.cv-escolha input { width: 20px; height: 20px; margin-top: 2px; accent-color: var(--ok); flex-shrink: 0; }
.cv-escolha .nome { font-size: 14px; font-weight: 700; }
.cv-escolha .nota { font-size: 12px; color: var(--text-muted); margin-top: 3px; }
.cv-avatar { border-radius: 50%; flex-shrink: 0; color: #fff; display: flex; align-items: center; justify-content: center; font-weight: 800; }
.cv-guardar { display: flex; gap: 10px; align-items: flex-start; margin-top: 14px; cursor: pointer; min-height: 44px; }
.cv-guardar input { width: 20px; height: 20px; margin-top: 1px; accent-color: var(--accent); flex-shrink: 0; }
.cv-erro { font-size: 12px; color: var(--danger); margin: 6px 0 0; }
.cv-link-pessoal {
  display: flex; gap: 10px; align-items: center; margin-top: 14px; padding: 12px 14px;
  border: 1px solid var(--border-subtle); border-radius: 12px; background: var(--bg-card-alt);
}
.cv-link-pessoal code { font-size: 12px; overflow-wrap: anywhere; color: var(--text-secondary); flex: 1; }

/* -------------------------------------------------------------------------
   A faixa contextual (shared/tira.js)
   -------------------------------------------------------------------------
   Uma linha discreta no fim de uma página que diz em que estado está uma
   coisa que vive NOUTRO ecrã, e leva lá. É a mesma em Convidados, no
   Boletim de Inscrição e em Classificações -- e é uma só porque, escrita
   três vezes, era assim que ficava diferente em cada sítio: numa com o
   resumo, noutra sem; numa com o estado, noutra sem.

   O que esta faixa NUNCA faz é editar seja o que for. Mostra e leva.

   No telemóvel a faixa inteira passa a ser o alvo (.tira-toque, por cima
   de tudo, com o chevron a dizê-lo): dois botões pequenos lado a lado numa
   linha estreita acertam-se por sorte, e as ações vivem na página de
   destino, que é para onde isto leva. */
.tira {
  position: relative;
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  border: 1px solid var(--border-subtle); border-radius: 14px;
  background: var(--bg-card); padding: 14px 16px; margin-bottom: 16px;
}
.tira .icone {
  width: 40px; height: 40px; border-radius: 11px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent);
}
.tira .texto { flex: 1; min-width: 180px; }
.tira .titulo { font-size: 14px; font-weight: 700; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.tira .nota { font-size: 12px; color: var(--text-muted); margin-top: 3px; }
.tira .accoes { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.tira .accoes .btn-ghost { min-height: 44px; display: inline-flex; align-items: center; }
.tira .divisor { width: 1px; align-self: stretch; margin: 4px 0; background: var(--border-subtle); }
/* Fica por cima da faixa toda, mas abaixo dos botões -- no computador não
   se nota, no telemóvel é ele que recebe o toque. */
.tira .tira-toque { position: absolute; inset: 0; border-radius: 14px; display: none; background: none; border: 0; padding: 0; width: 100%; cursor: pointer; }
.tira .accoes, .tira .chevron { position: relative; }
.tira .chevron { display: none; color: var(--text-muted); }
.tira .tira-toque:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

@media (max-width: 720px) {
  .tira { gap: 12px; min-height: 64px; flex-wrap: nowrap; }
  .tira .tira-toque { display: block; }
  .tira .accoes { display: none; }
  .tira .nota { display: none; }
  .tira .chevron { display: flex; align-items: center; }
  .tira .texto { min-width: 0; }
}

/* -------------------------------------------------------------------------
   Partilhar classificações (shared/partilhar-classificacoes.js)
   -------------------------------------------------------------------------
   Dois cartões: o QR do evento inteiro e o QR desta atividade. Lado a lado
   no computador, empilhados no telemóvel -- nunca encolhidos até caberem,
   porque um QR pequeno deixa de se ler à distância a que se lê um cartaz,
   que é exactamente onde este vai parar.

   O QR fica sempre sobre branco: nenhuma câmara garante a leitura de um
   código invertido, e o tema desta app é escuro. */
.pc-cartoes { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.pc-cartao {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  border: 1px solid var(--border-subtle); border-radius: 14px;
  background: var(--bg-card-alt); padding: 16px;
}
.pc-cartao.escolhido { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }
.pc-cartao .pc-icone {
  width: 40px; height: 40px; border-radius: 11px; margin-bottom: 12px;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent);
}
.pc-cartao .pc-tipo { font-size: 10px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-muted); }
.pc-cartao .pc-nome { font-size: 16px; font-weight: 800; margin-top: 4px; overflow-wrap: anywhere; }
.pc-cartao .pc-desc { font-size: 12px; color: var(--text-muted); margin: 6px 0 14px; }
.pc-qr {
  background: #fff; border-radius: 12px; padding: 10px; width: 190px; max-width: 100%;
  display: flex; align-items: center; justify-content: center;
}
.pc-qr canvas, .pc-qr svg { width: 100%; height: auto; display: block; }
.pc-marca { margin: 12px 0 10px; }
.pc-ligacao {
  width: 100%; font-size: 12px; overflow-wrap: anywhere; color: var(--text-secondary);
  background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 10px; padding: 9px 10px;
}
.pc-accoes { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; margin-top: 10px; width: 100%; }
.pc-accoes .btn-ghost { flex: 1; min-width: 108px; min-height: 44px; display: inline-flex; align-items: center; justify-content: center; gap: 6px; }
.pc-alternativa { font-size: 11px; color: var(--text-muted); margin-top: 8px; }
.pc-alternativa button {
  /* Discreto à vista, mas com a mesma área de toque de tudo o resto: um
     link de 20px de altura falha-se com o polegar, e isto é usado de pé. */
  background: none; border: none; padding: 12px 6px; min-height: 44px; font: inherit; color: var(--accent);
  text-decoration: underline; cursor: pointer;
}
.pc-nota { display: flex; gap: 10px; align-items: flex-start; font-size: 12px; color: var(--text-muted); margin-top: 16px; }
.pc-escolha { display: flex; gap: 8px; flex-wrap: wrap; width: 100%; }
.pc-escolha .btn-ghost, .pc-escolha .btn-accent { min-height: 48px; flex: 1; min-width: 150px; }

@media (max-width: 720px) {
  .pc-cartoes { grid-template-columns: 1fr; }
  .pc-accoes .btn-ghost { flex: 1 1 100%; }
}

/* -------------------------------------------------------------------------
   Classificações (rankings.html)
   ------------------------------------------------------------------------- */
.rk-barra { display: flex; gap: 10px; justify-content: flex-end; align-items: center; flex-wrap: wrap; margin: -6px 0 16px; }
.rk-barra .btn-ghost { min-height: 44px; display: inline-flex; align-items: center; gap: 8px; }
.rk-conta { font-size: 12px; color: var(--text-muted); margin-right: auto; }

/* A posição: um número redondo, com medalha nos três primeiros. É o que
   toda a gente procura primeiro numa classificação, e um "1º" em texto
   corrido não se distingue de um "11º" ao passar os olhos. */
.rk-pos {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 999px; font-size: 13px; font-weight: 800;
  background: var(--bg-card-alt); color: var(--text-secondary);
}
.rk-pos.ouro { background: #E8B923; color: #241c00; }
.rk-pos.prata { background: #C7CBD4; color: #1b1d22; }
.rk-pos.bronze { background: #C87F45; color: #200f03; }
.rk-valor { font-variant-numeric: tabular-nums; font-weight: 700; }

@media (max-width: 720px) {
  .rk-barra { justify-content: stretch; }
  .rk-barra .btn-ghost { flex: 1; min-width: 140px; justify-content: center; }
  .rk-conta { flex-basis: 100%; margin-right: 0; }
}

/* -------------------------------------------------------------------------
   Páginas públicas de classificações (/r/<evento> e /r/<evento>/<atividade>)
   -------------------------------------------------------------------------
   Lidas de pé, num pavilhão, a um braço de distância, por quem acabou de
   apontar a câmara a um cartaz. Daí o texto grande, os alvos largos e o
   pódio a saltar à vista -- e daí não haver aqui um único botão de
   administração. Quem abre isto não é da organização. */
.pb-pagina { max-width: 760px; margin: 0 auto; padding: 22px 16px 40px; }
.pb-topo { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: 18px; }
.pb-topo [data-marca] { flex: 1; min-width: 0; display: flex; align-items: center; }
.pb-topo [data-marca] img { max-height: 44px; max-width: 190px; object-fit: contain; }
.pb-nome-evento { font-size: 18px; font-weight: 800; letter-spacing: 0.02em; overflow-wrap: anywhere; }
.pb-titulo { font-size: 34px; font-weight: 800; margin: 6px 0 4px; line-height: 1.1; }
.pb-sub { font-size: 14px; color: var(--text-muted); margin: 0 0 18px; }

/* O estado da ligação. Três tons, três coisas diferentes -- e com a rede
   em baixo nunca se diz "atualizado" (ver estadoDaAtualizacao). */
.pb-estado { display: inline-flex; align-items: center; gap: 8px; font-size: 12px; color: var(--text-secondary); flex-wrap: wrap; }
.pb-ponto { width: 8px; height: 8px; border-radius: 999px; background: var(--text-muted); }
.pb-ponto.ligado { background: var(--ok); }
.pb-ponto.perdido { background: var(--warn); }
.pb-tentar { background: none; border: 1px solid var(--border-subtle); border-radius: 999px; color: var(--text-primary); font: inherit; font-size: 12px; padding: 6px 12px; min-height: 36px; cursor: pointer; }
.pb-tentar:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.pb-procura { width: 100%; margin-bottom: 14px; }
.pb-procura input { width: 100%; min-height: 48px; font-size: 15px; }

/* A única fila que pode deslizar na horizontal -- e desliza de propósito:
   um evento com dez atividades não cabe em nenhuma largura de telemóvel. */
.pb-separadores { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 4px; margin-bottom: 18px; scrollbar-width: thin; }
.pb-separador {
  flex-shrink: 0; display: inline-flex; align-items: center; gap: 8px; min-height: 48px;
  padding: 10px 16px; border-radius: 12px; border: 1px solid var(--border-subtle);
  background: var(--bg-card); color: var(--text-secondary); font: inherit; font-size: 13px; font-weight: 700; cursor: pointer;
}
.pb-separador[aria-selected="true"] { border-color: var(--accent); color: var(--text-primary); background: color-mix(in srgb, var(--accent) 12%, var(--bg-card)); }
.pb-separador:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.pb-cartao { border: 1px solid var(--border-subtle); border-radius: 16px; background: var(--bg-card); padding: 18px; margin-bottom: 14px; }
.pb-cartao-topo { display: flex; align-items: flex-start; gap: 14px; margin-bottom: 12px; }
.pb-cartao-icone {
  width: 44px; height: 44px; border-radius: 12px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent);
}
.pb-cartao-nome { font-size: 19px; font-weight: 800; overflow-wrap: anywhere; }
.pb-cartao-regra { font-size: 13px; color: var(--text-muted); margin-top: 2px; }

/* A classificação é uma lista ordenada a sério: é o que um leitor de ecrã
   precisa de ouvir, e é o que dá cartões no telemóvel sem uma tabela a
   fugir para fora do ecrã. */
.pb-cabecalho, .pb-linha { display: grid; grid-template-columns: 44px 1fr auto 68px; gap: 12px; align-items: center; }
.pb-cabecalho { font-size: 10px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-muted); padding: 0 4px 8px; }
.pb-lista { list-style: none; margin: 0; padding: 0; }
.pb-linha { padding: 12px 4px; border-top: 1px solid var(--border-subtle); }
.pb-lista > li:first-child .pb-linha { border-top: 0; }
.pb-nome { font-size: 16px; font-weight: 700; overflow-wrap: anywhere; }
.pb-valor { font-size: 18px; font-weight: 800; font-variant-numeric: tabular-nums; }
.pb-tentativas { font-size: 12px; color: var(--text-muted); text-align: right; }
.pb-pos {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 999px; font-size: 15px; font-weight: 800;
  background: var(--bg-card-alt); color: var(--text-secondary);
}
.pb-pos.ouro { background: #E8B923; color: #241c00; }
.pb-pos.prata { background: #C7CBD4; color: #1b1d22; }
.pb-pos.bronze { background: #C87F45; color: #200f03; }

.pb-ver-tudo {
  display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%;
  min-height: 48px; margin-top: 14px; border: 1px solid var(--border-subtle); border-radius: 12px;
  background: none; color: var(--text-primary); font: inherit; font-size: 14px; font-weight: 700; text-decoration: none; cursor: pointer;
}
.pb-ver-tudo:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.pb-vazio { font-size: 14px; color: var(--text-muted); padding: 18px 4px; margin: 0; }
.pb-sobre { border-top: 1px solid var(--border-subtle); margin-top: 20px; padding-top: 16px; font-size: 13px; color: var(--text-secondary); }
.pb-sobre .rotulo { font-size: 10px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-muted); margin-bottom: 6px; }
.pb-voltar { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; font-size: 13px; color: var(--text-secondary); text-decoration: none; }
.pb-rodape { text-align: center; font-size: 11px; color: var(--text-muted); margin-top: 30px; }
.pb-rodape a { color: inherit; }

@media (max-width: 560px) {
  .pb-titulo { font-size: 28px; }
  /* A tabela passa a cartão: posição e nome em cima, resultado por baixo,
     em grande. Nada desliza para fora do ecrã. */
  .pb-cabecalho { display: none; }
  .pb-linha { grid-template-columns: 40px 1fr; grid-template-areas: "pos nome" ". valor"; row-gap: 4px; padding: 14px 4px; }
  .pb-linha > .pb-pos { grid-area: pos; }
  .pb-linha > .pb-nome { grid-area: nome; }
  .pb-linha > .pb-valor { grid-area: valor; }
  .pb-linha > .pb-tentativas { display: none; }
  .pb-linha[data-com-tentativas] { grid-template-areas: "pos nome" ". valor" ". tentativas"; }
  .pb-linha[data-com-tentativas] > .pb-tentativas { display: block; grid-area: tentativas; text-align: left; }
}

/* =========================================================================
   UTILIZADORES E ACESSOS
   =========================================================================
   Uma tabela em computador, um cartão por pessoa em telemóvel -- e UMA só
   marcação de HTML para os dois. A alternativa (desenhar a lista duas
   vezes e esconder uma com CSS) é como se chega a dois ecrãs que mostram
   coisas diferentes sobre a mesma pessoa, que é exatamente o problema que
   esta área tinha.

   Por isso a tabela é mesmo um <table> com <th> a sério: em computador é
   uma tabela, e em telemóvel as células passam a linhas de um cartão, cada
   uma com o seu rótulo (ver [data-rotulo] mais abaixo). Um leitor de ecrã
   continua a ter cabeçalhos nos dois tamanhos.
   ========================================================================= */
/* A mesma tabela das Inscrições (.in-tabela), com as mesmas medidas: é a
   mesma pessoa a ler as duas listas no mesmo dia.
   As LARGURAS MÍNIMAS por coluna não são enfeite. Sem elas, ao estreitar a
   janela o navegador espremia a coluna do nome até uma letra por linha --
   "Cat / arin / a Silv / a". Com elas, a tabela deixa de encolher e passa a
   rolar dentro do seu contentor (.table-scroll), que é o que as Inscrições
   já faziam. */
.ac-tabela { width: 100%; border-collapse: collapse; }
.ac-tabela th {
  text-align: left; font-size: 11px; letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--text-muted); font-weight: 700; padding: 0 12px 12px; white-space: nowrap;
}
.ac-tabela td { padding: 14px 12px; border-top: 1px solid var(--border-subtle); vertical-align: middle; }
.ac-tabela tbody tr:hover { background: color-mix(in srgb, var(--accent) 4%, transparent); }
.ac-tabela tbody tr[data-selecionada="1"] { background: color-mix(in srgb, var(--accent) 8%, transparent); }
.ac-tabela .ac-sel { width: 40px; }
.ac-tabela .ac-col-papel { min-width: 180px; }
.ac-tabela .ac-col-estado { min-width: 92px; }
.ac-tabela .ac-col-acesso { min-width: 210px; }
.ac-tabela .ac-accoes { text-align: right; white-space: nowrap; }

/* Quem é. Iniciais quando não há foto -- e o nome nunca fica cortado a
   meio de uma palavra num nome comprido. */
/* 210px é a mesma medida do .in-quem das Inscrições -- chega para dois
   nomes próprios lado a lado antes de a linha quebrar. */
.ac-pessoa { display: flex; align-items: center; gap: 12px; min-width: 210px; }
.ac-avatar {
  width: 42px; height: 42px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--accent) 18%, var(--bg-card-alt));
  color: var(--text-primary); font-size: 14px; font-weight: 800; letter-spacing: 0.02em;
}
.ac-pessoa > div { min-width: 0; }
/* Quebra entre palavras, e não a meio delas: `anywhere` era o que deixava
   partir "Catarina" em quatro linhas de uma letra. */
.ac-pessoa .nome { font-size: 14px; font-weight: 700; overflow-wrap: break-word; }
.ac-pessoa .contacto { font-size: 12px; color: var(--text-muted); margin-top: 2px; overflow-wrap: break-word; }
.ac-pessoa .contacto.em-falta { color: var(--warn); }

/* Papel e responsabilidade. Duas etiquetas no máximo -- a lista mostrava
   um chip por cada módulo contratado, e uma linha de oito chips não se lê
   nem diz nada de útil sobre a pessoa. */
.ac-etiquetas { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
.ac-papel {
  font-size: 11px; font-weight: 700; padding: 5px 12px; border-radius: 999px;
  background: color-mix(in srgb, var(--accent-2, #7c6cf5) 20%, transparent);
  color: color-mix(in srgb, var(--accent-2, #7c6cf5) 92%, var(--text-primary));
  white-space: nowrap;
}
.ac-papel-organizador { background: color-mix(in srgb, #7c6cf5 22%, transparent); color: #b9b0ff; }
.ac-papel-promotor { background: color-mix(in srgb, #6d7ea8 24%, transparent); color: #c3ceea; }
.ac-marca {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11px; font-weight: 700; padding: 5px 10px; border-radius: 999px;
  background: var(--bg-card-alt); color: var(--text-secondary); white-space: nowrap;
}
.ac-marca svg { width: 13px; height: 13px; flex-shrink: 0; }
.ac-marca-responsavel { background: color-mix(in srgb, var(--ok) 16%, transparent); color: var(--ok); }
.ac-marca-falta { background: color-mix(in srgb, var(--warn) 14%, transparent); color: var(--warn); }

/* O código. Mascarado por omissão -- o valor a sério nunca está escrito no
   HTML antes de alguém carregar em "Revelar" (ver revelarCodigo nas
   páginas): assim uma fotografia do ecrã, ou uma gravação de sessão, não
   apanha códigos de entrada de ninguém. */
.ac-codigo { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ac-codigo-valor {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 13px; letter-spacing: 0.08em;
  background: var(--bg-card-alt); border: 1px solid var(--border-subtle); border-radius: 10px;
  padding: 8px 12px; min-height: 38px; display: inline-flex; align-items: center;
}
.ac-codigo-valor.revelado { border-color: color-mix(in srgb, var(--ok) 55%, transparent); color: var(--ok); }
.ac-codigo-botao {
  min-height: 38px; min-width: 38px; display: inline-flex; align-items: center; justify-content: center;
  border-radius: 10px; border: 1px solid var(--border-subtle); background: none;
  color: var(--text-secondary); cursor: pointer;
}
.ac-codigo-botao:hover { color: var(--text-primary); background: var(--bg-card-alt); }
.ac-codigo-botao:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.ac-codigo-botao:disabled { opacity: 0.35; cursor: not-allowed; }
.ac-sem-codigo { font-size: 12px; color: var(--text-muted); }

/* O estado da entrega, com palavras. Nunca só a cor: um estado que só
   existe como cor não existe para quem não a distingue. */
.ac-entrega {
  display: inline-flex; align-items: center; gap: 6px; margin-top: 8px;
  font-size: 11px; font-weight: 700; padding: 5px 10px; border-radius: 999px; white-space: nowrap;
}
.ac-entrega svg { width: 13px; height: 13px; flex-shrink: 0; }
.ac-entrega-bom { background: color-mix(in srgb, var(--ok) 14%, transparent); color: var(--ok); }
.ac-entrega-aviso { background: color-mix(in srgb, var(--warn) 14%, transparent); color: var(--warn); }
.ac-entrega-neutro { background: var(--bg-card-alt); color: var(--text-muted); }

/* Os separadores e a barra de filtros são os das outras listas
   (.ev-separadores / .ev-ferramentas, mais acima neste ficheiro) -- eram
   aqui pastilhas e uma barra própria, e a mesma pessoa que passa de
   Inscrições para Utilizadores no mesmo dia tinha de reaprender o ecrã. */

/* Barra que aparece só quando há alguém escolhido, como nas Inscrições. */
.ac-barra-sel {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  border: 1px solid var(--accent); border-radius: 12px; padding: 12px 16px; margin-bottom: 14px;
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.ac-barra-sel .conta { font-size: 14px; font-weight: 700; }
.ac-barra-sel .direita { margin-left: auto; display: flex; gap: 10px; flex-wrap: wrap; }

/* A caixa informativa das bancas, no fim da lista. */
.ac-nota {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  background: var(--bg-card); border: 1px solid var(--border-subtle);
  border-radius: 14px; padding: 16px 18px; margin-top: 4px;
}
.ac-nota-icone {
  width: 40px; height: 40px; border-radius: 11px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-card-alt); color: var(--text-secondary);
}
.ac-nota p { margin: 0; font-size: 13px; color: var(--text-secondary); flex: 1 1 240px; }
.ac-nota a { color: var(--accent); font-weight: 600; text-decoration: none; font-size: 13px; white-space: nowrap; }

/* Cartões de escolha do papel -- em criação e em edição, os mesmos. Um
   <select> com "Promotor/Organizador" não diz o que cada um é, e a
   diferença entre os dois decide o acesso de uma pessoa ao evento todo. */
.ac-papeis { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 14px; }
.ac-papel-cartao {
  display: flex; align-items: flex-start; gap: 14px; cursor: pointer;
  border: 1px solid var(--border-subtle); border-radius: 14px; padding: 18px;
  background: var(--bg-card-alt);
}
.ac-papel-cartao:has(input:checked) {
  border-color: var(--ok); background: color-mix(in srgb, var(--ok) 10%, transparent);
}
.ac-papel-cartao:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; }
.ac-papel-cartao input { width: 20px; height: 20px; margin: 2px 0 0; flex-shrink: 0; accent-color: var(--ok); }
.ac-papel-cartao .icone { color: var(--text-secondary); flex-shrink: 0; margin-top: 1px; }
.ac-papel-cartao:has(input:checked) .icone { color: var(--ok); }
.ac-papel-cartao .nome { font-size: 15px; font-weight: 700; }
.ac-papel-cartao .desc { font-size: 12.5px; color: var(--text-muted); margin-top: 4px; line-height: 1.5; }
.ac-papel-cartao.desligado { opacity: 0.5; cursor: not-allowed; }

/* Zona de perigo -- fechada, no fim, longe de "Guardar alterações". */
.ac-perigo {
  border: 1px solid color-mix(in srgb, var(--danger) 32%, transparent);
  background: color-mix(in srgb, var(--danger) 6%, transparent);
  border-radius: 16px; margin-bottom: 20px; overflow: hidden;
}
.ac-perigo-topo {
  display: flex; align-items: center; gap: 14px; width: 100%;
  padding: 18px 20px; background: none; border: 0; color: inherit; font: inherit;
  cursor: pointer; text-align: left;
}
.ac-perigo-topo .titulo { font-size: 15px; font-weight: 700; color: var(--danger); }
.ac-perigo-topo .sub { font-size: 12.5px; color: var(--text-muted); margin-top: 3px; }
.ac-perigo-topo .icone { color: var(--danger); flex-shrink: 0; }
.ac-perigo-topo .seta { margin-left: auto; color: var(--text-muted); transition: transform 0.2s ease; }
.ac-perigo-topo[aria-expanded="true"] .seta { transform: rotate(180deg); }
.ac-perigo-corpo { padding: 0 20px 20px; }

/* Estados vazios -- um por motivo. "Nenhum resultado" e "ainda não há
   ninguém" pedem coisas diferentes a quem está a olhar. */
.ac-vazio { text-align: center; padding: 44px 20px; }
.ac-vazio-icone {
  width: 56px; height: 56px; border-radius: 16px; margin: 0 auto 16px;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-card-alt); color: var(--text-muted);
}
.ac-vazio h3 { font-size: 16px; font-weight: 700; margin: 0 0 8px; }
.ac-vazio p { font-size: 13.5px; color: var(--text-muted); margin: 0 auto 18px; max-width: 420px; line-height: 1.6; }

/* Os campos da ficha, em pares rótulo/valor. */
.ac-ficha-topo { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.ac-ficha-avatar {
  width: 68px; height: 68px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--accent) 18%, var(--bg-card-alt));
  font-size: 20px; font-weight: 700;
}
.ac-ficha-nome { font-size: 24px; font-weight: 800; line-height: 1.15; overflow-wrap: anywhere; }
.ac-ficha-marcas { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
.ac-ficha-dados { display: grid; gap: 12px; align-content: start; min-width: 220px; }
.ac-ficha-dado { display: flex; align-items: baseline; gap: 10px; font-size: 13px; }
.ac-ficha-dado .rotulo { color: var(--text-muted); display: inline-flex; align-items: center; gap: 8px; min-width: 108px; }
.ac-ficha-dado .rotulo svg { width: 15px; height: 15px; color: var(--text-muted); }
.ac-ficha-dado .valor { font-weight: 600; overflow-wrap: anywhere; }
.ac-ficha-dado .valor.em-falta { color: var(--warn); font-weight: 500; }

/* Módulos autorizados, na ficha: só leitura, com um visto por módulo. */
.ac-modulos { display: flex; flex-wrap: wrap; gap: 10px; }
.ac-modulo {
  display: inline-flex; align-items: center; gap: 9px;
  border: 1px solid var(--border-subtle); border-radius: 11px; padding: 11px 14px;
  font-size: 13px; font-weight: 600; background: var(--bg-card-alt);
}
.ac-modulo svg.icone { width: 15px; height: 15px; color: var(--text-muted); }
.ac-modulo .visto { color: var(--ok); display: inline-flex; }
.ac-modulo .visto svg { width: 16px; height: 16px; }

/* Cartões no telemóvel -- a mesma informação, sem tabela a rolar para o
   lado, e as mesmas medidas dos cartões das Inscrições (.in-cartao).
   São a MESMA informação da tabela, montada pelas mesmas funções: o que
   não pode acontecer é a tabela e o cartão dizerem coisas diferentes sobre
   a mesma pessoa. */
.ac-cartoes { display: none; }
.ac-cartao { border: 1px solid var(--border-subtle); border-radius: 14px; background: var(--bg-card); padding: 16px; }
.ac-cartao + .ac-cartao { margin-top: 12px; }
.ac-cartao-topo { display: flex; align-items: center; gap: 12px; }
.ac-cartao-topo .ac-pessoa { flex: 1; min-width: 0; }
.ac-cartao-linhas { margin-top: 14px; display: grid; gap: 12px; }
.ac-cartao-accoes { display: flex; gap: 10px; margin-top: 16px; }
.ac-cartao-accoes .btn-accent, .ac-cartao-accoes .btn-ghost { flex: 1; min-height: 48px; justify-content: center; }

@media (max-width: 900px) {
  .ac-tabela-conteiner { display: none; }
  .ac-cartoes { display: block; }
}

@media (max-width: 768px) {
  .ac-ficha-dados { width: 100%; }
  .ac-papeis { grid-template-columns: 1fr; }
}


/* As caixas de seleção e os rádios com a cor do tema. `accent-color` só
   pinta o estado LIGADO; desligadas, continuavam a ser o quadrado cinzento
   do sistema operativo, num ecrã todo escuro. Foi uma das coisas que o
   Tiago apanhou: "alguns scrolls e checkbox parecem ainda estar cinzentas,
   sem ter a configuração do tema". */
input[type="checkbox"], input[type="radio"] {
  appearance: none; -webkit-appearance: none;
  width: 19px; height: 19px; flex-shrink: 0; margin: 0;
  border: 1.5px solid var(--border-strong, var(--border-subtle));
  background: var(--bg-card-alt); cursor: pointer;
  display: inline-grid; place-content: center;
  transition: border-color 0.12s ease, background 0.12s ease;
}
input[type="checkbox"] { border-radius: 6px; }
input[type="radio"] { border-radius: 50%; }
input[type="checkbox"]:hover:not(:disabled),
input[type="radio"]:hover:not(:disabled) { border-color: var(--ok); }
input[type="checkbox"]::before {
  content: ""; width: 11px; height: 11px; transform: scale(0);
  transition: transform 0.1s ease-in-out; background: var(--accent-text, #06120b);
  clip-path: polygon(14% 44%, 0 65%, 43% 100%, 100% 20%, 82% 6%, 41% 68%);
}
input[type="radio"]::before {
  content: ""; width: 9px; height: 9px; border-radius: 50%;
  transform: scale(0); transition: transform 0.1s ease-in-out; background: var(--accent-text, #06120b);
}
input[type="checkbox"]:checked, input[type="radio"]:checked { background: var(--ok); border-color: var(--ok); }
input[type="checkbox"]:checked::before, input[type="radio"]:checked::before { transform: scale(1); }
input[type="checkbox"]:focus-visible, input[type="radio"]:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
input[type="checkbox"]:disabled, input[type="radio"]:disabled { opacity: 0.4; cursor: not-allowed; }
/* Os cartões de papel trazem o seu próprio tamanho maior (alvo de dedo). */
.ac-papel-cartao input[type="radio"] { width: 20px; height: 20px; }


/* A ação de um cartão (Editar permissões, Gerir distribuição, Tornar
   responsável) vive no cabeçalho do cartão. Em computador fica à direita
   do título; em telemóvel desce para a sua própria linha, a toda a
   largura -- espremida ao lado do título, deixava a descrição do cartão
   numa coluna de três palavras por linha. */
.ac-accao-cartao { flex-shrink: 0; }
@media (max-width: 768px) {
  .ac-accao-cartao { flex: 1 1 100%; margin-top: 12px; }
  .ac-accao-cartao > .btn-ghost,
  .ac-accao-cartao > .btn-accent { width: 100%; justify-content: center; min-height: 48px; }
}


/* O cartão do código de acesso.
   Era uma grelha de três colunas com blocos soltos -- o código, o estado e
   os botões lado a lado, cada um com a sua nota por baixo, e nada a dizer
   o que pertencia a quê. Lia-se como três avisos a competir pela atenção.
   Passa a ter três zonas com sentido: O QUE É (o código), EM QUE PÉ ESTÁ
   (a entrega) e O QUE SE PODE FAZER (as ações, numa linha só, em baixo). */
.ac-cod-grelha {
  display: grid; gap: 18px 28px;
  grid-template-columns: minmax(240px, 1fr) minmax(220px, 1fr);
  align-items: start;
}
.ac-cod-zona .rotulo {
  font-size: 11px; letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--text-muted); font-weight: 700; margin-bottom: 10px;
}
.ac-cod-zona .nota { font-size: 12px; color: var(--text-muted); margin: 10px 0 0; line-height: 1.5; }
/* As ações ocupam a linha toda, por baixo, separadas por um traço: são o
   que se FAZ, e não mais uma informação a ler. */
.ac-cod-accoes {
  grid-column: 1 / -1; display: flex; gap: 12px; flex-wrap: wrap;
  border-top: 1px solid var(--border-subtle); padding-top: 18px;
}
.ac-cod-accoes .btn-ghost, .ac-cod-accoes .btn-accent { flex: 1 1 220px; justify-content: center; }
.ac-cod-motivo { grid-column: 1 / -1; font-size: 12px; color: var(--text-muted); margin: -6px 0 0; line-height: 1.5; }
/* Um aviso que impede tudo o resto ocupa a largura toda -- não é uma
   coluna ao lado das outras. */
.ac-cod-impedido {
  grid-column: 1 / -1; display: flex; align-items: flex-start; gap: 11px;
  font-size: 13px; color: var(--warn); line-height: 1.55; margin: 0;
}
.ac-cod-impedido svg { flex-shrink: 0; margin-top: 2px; }
@media (max-width: 700px) {
  .ac-cod-grelha { grid-template-columns: 1fr; }
  .ac-cod-accoes { flex-direction: column; }
  /* Em coluna, o flex-basis passa a ser ALTURA: os 220px que faziam duas
     colunas lado a lado davam dois botões de 220px de alto, um por cima do
     outro. Aqui cada um vale o seu conteúdo, e a altura vem da escala. */
  .ac-cod-accoes .btn-ghost, .ac-cod-accoes .btn-accent { flex: 0 0 auto; }
}

/* Uma escolha dentro de uma folha: a caixa inteira é clicável, e não só os
   14 pixels do quadrado. Numa folha aberta no telemóvel, acertar no
   quadrado é a diferença entre escolher e voltar a tentar. */
.ac-opcao {
  display: flex; align-items: flex-start; gap: 12px; cursor: pointer;
  background: var(--bg-card-alt); border: 1px solid var(--border-subtle);
  border-radius: 12px; padding: 13px 14px; font-size: 13px; line-height: 1.5;
}
.ac-opcao:hover { border-color: var(--border); }
.ac-opcao input { margin-top: 2px; flex-shrink: 0; }
.ac-opcao .muted { font-size: 12.5px; color: var(--text-muted); }
.ac-opcao:has(input:checked) { border-color: color-mix(in srgb, var(--accent) 45%, transparent); }

/* O sinal de "o código desta pessoa já funcionou", ao lado do nome. Um
   sinal, e não uma etiqueta com palavras: cabe numa linha estreita, não
   compete com o nome, e não se confunde com ter entrado no evento. */
.ac-confirmado {
  display: inline-flex; vertical-align: middle; margin-left: 6px;
  color: var(--ok); flex-shrink: 0;
}

/* -------------------------------------------------------------------------
   BANCAS E ZONAS — a lista de postos e o editor em três etapas

   A lista segue a moldura das outras (faixa de números, painel, tabela que
   vira cartões no telemóvel). O editor é a novidade: três etapas, uma só
   barra de ações no fim, e um resumo que se atualiza enquanto se mexe.
   ------------------------------------------------------------------------- */

/* ------------------------------------------------------------- a lista */
.po-tabela { width: 100%; border-collapse: collapse; font-size: 13px; }
.po-tabela th {
  text-align: left; font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-muted); font-weight: 700; padding: 0 14px 10px; white-space: nowrap;
}
.po-tabela td { padding: 14px; border-top: 1px solid var(--border-subtle); vertical-align: middle; }
.po-tabela tbody tr:hover { background: var(--bg-card-alt); }
.po-col-ambito { min-width: 140px; }
.po-col-equipa { min-width: 160px; }
.po-col-accoes { width: 1%; white-space: nowrap; text-align: right; }

.po-quem { display: flex; align-items: center; gap: 12px; min-width: 200px; }
.po-quem .nome { font-size: 13.5px; font-weight: 700; overflow-wrap: break-word; }
.po-quem .sub { font-size: 12px; color: var(--text-muted); margin-top: 2px; overflow-wrap: break-word; }
.po-quem .sub.em-falta { color: var(--warn); }
.po-sigla {
  width: 40px; height: 40px; border-radius: 11px; flex-shrink: 0;
  background: color-mix(in srgb, var(--accent) 14%, var(--bg-card));
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700; color: var(--text-secondary);
}
.po-ambito { display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--text-secondary); }
.po-ambito.em-falta { color: var(--warn); }
.po-chips { display: flex; flex-wrap: wrap; gap: 7px; }
.po-chip {
  font-size: 12px; border-radius: 999px; padding: 5px 11px;
  background: var(--bg-card); border: 1px solid var(--border-subtle); color: var(--text-secondary);
}
.po-chip-falta { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 40%, transparent); }
.po-equipa { display: inline-flex; align-items: center; gap: 7px; font-size: 12px; font-weight: 700; border-radius: 999px; padding: 6px 11px; }
.po-equipa-bom { color: var(--ok); background: color-mix(in srgb, var(--ok) 12%, transparent); }
.po-equipa-falta { color: var(--warn); background: color-mix(in srgb, var(--warn) 12%, transparent); }

.po-cartoes { display: none; }
.po-cartao {
  border: 1px solid var(--border-subtle); border-radius: 14px;
  background: var(--bg-card-alt); padding: 14px; margin-bottom: 12px;
  display: grid; gap: 12px;
}
.po-cartao-topo { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.po-cartao-fim { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }

/* ------------------------------------------------------------ o editor */
.po-estado { display: inline-flex; align-items: center; gap: 8px; font-size: 12.5px; font-weight: 700; border-radius: 999px; padding: 8px 14px; }
.po-estado-bom { color: var(--ok); background: color-mix(in srgb, var(--ok) 12%, transparent); }
.po-estado-aviso { color: var(--warn); background: color-mix(in srgb, var(--warn) 12%, transparent); }

/* As três etapas. O número vira um visto quando a etapa está feita e um
   aviso quando falta lá alguma coisa -- é assim que se aponta ao sítio do
   erro sem obrigar a percorrer as três. */
.po-etapas {
  display: flex; align-items: center; gap: 0; list-style: none;
  margin: 0 0 22px; padding: 0 0 20px; border-bottom: 1px solid var(--border-subtle);
}
.po-etapa { flex: 1; display: flex; align-items: center; }
.po-etapa:not(:last-child)::after {
  content: ""; flex: 1; height: 1px; background: var(--border-subtle); margin: 0 10px;
}
.po-etapa.feita:not(:last-child)::after, .po-etapa.atual:not(:last-child)::after { background: color-mix(in srgb, var(--ok) 45%, transparent); }
.po-etapa > button {
  display: inline-flex; align-items: center; gap: 10px; cursor: pointer;
  background: none; border: 0; color: var(--text-muted); font: inherit; font-size: 13.5px; padding: 4px;
}
.po-etapa-numero {
  width: 30px; height: 30px; border-radius: 50%; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1.5px solid var(--border); font-size: 12.5px; font-weight: 700;
}
.po-etapa.atual > button { color: var(--text-primary); font-weight: 700; }
.po-etapa.atual .po-etapa-numero { border-color: var(--accent); color: var(--accent); }
.po-etapa.feita .po-etapa-numero { border-color: var(--ok); color: var(--ok); }
.po-etapa.com-problema .po-etapa-numero { border-color: var(--warn); color: var(--warn); }
.po-etapa.com-problema > button { color: var(--warn); }
.po-etapa-marca { display: inline-flex; color: var(--ok); flex-shrink: 0; margin-left: -3px; }
.po-etapa.com-problema .po-etapa-marca { color: var(--warn); }

.po-h2 { font-size: 19px; margin: 0; }
.po-nota { font-size: 12.5px; color: var(--text-muted); margin: 5px 0 0; line-height: 1.55; }
.po-etapa-corpo { padding-bottom: 4px; }

/* Os módulos, como cartões que se ligam e desligam. */
.po-modulos { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 14px; margin-top: 18px; }
.po-modulo {
  display: flex; align-items: flex-start; gap: 13px; text-align: left; cursor: pointer;
  background: var(--bg-card-alt); border: 1px solid var(--border-subtle);
  border-radius: 14px; padding: 15px; font: inherit; color: inherit;
}
.po-modulo:hover { border-color: var(--border); }
.po-modulo.ligado { border-color: color-mix(in srgb, var(--ok) 55%, transparent); background: color-mix(in srgb, var(--ok) 6%, transparent); }
.po-modulo-icone {
  width: 38px; height: 38px; border-radius: 11px; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--bg-card); color: var(--text-secondary);
}
.po-modulo.ligado .po-modulo-icone { color: var(--ok); background: color-mix(in srgb, var(--ok) 14%, transparent); }
.po-modulo-texto { flex: 1; min-width: 0; }
.po-modulo-texto .nome { display: block; font-size: 14px; font-weight: 700; }
.po-modulo-texto .desc { display: block; font-size: 12.5px; color: var(--text-muted); margin-top: 3px; line-height: 1.5; }
.po-modulo-estado {
  display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0;
  font-size: 11.5px; font-weight: 700; color: var(--text-muted);
}
.po-modulo.ligado .po-modulo-estado { color: var(--ok); }

/* Um bloco de configuração do âmbito. Só aparece quando a função que o
   exige está ligada -- um bloco a dizer "Sem opções disponíveis" é uma
   pergunta a que ninguém tem de responder. */
.po-bloco {
  display: flex; gap: 14px; margin-top: 18px;
  background: var(--bg-card-alt); border: 1px solid var(--border-subtle);
  border-radius: 14px; padding: 16px;
}
.po-bloco-icone {
  width: 40px; height: 40px; border-radius: 11px; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--bg-card); color: var(--accent);
}
.po-bloco-corpo { flex: 1; min-width: 0; }
.po-bloco-corpo h3 { font-size: 15px; margin: 0; }

.po-ativas { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; margin-top: 18px; background: var(--bg-card-alt); border: 1px solid var(--border-subtle); border-radius: 12px; padding: 13px 15px; }
.po-ativas-rotulo { font-size: 13px; font-weight: 700; margin-right: 4px; }

.po-escolhas { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 12px; margin-top: 12px; }
.po-escolha {
  display: flex; align-items: flex-start; gap: 11px; text-align: left; cursor: pointer;
  background: var(--bg-card); border: 1px solid var(--border-subtle);
  border-radius: 12px; padding: 13px; font: inherit; color: inherit;
}
.po-escolha:hover:not(:disabled) { border-color: var(--border); }
.po-escolha.marcada { border-color: color-mix(in srgb, var(--ok) 55%, transparent); background: color-mix(in srgb, var(--ok) 7%, transparent); }
.po-escolha.impedida, .po-escolha:disabled { opacity: 0.45; cursor: not-allowed; }
.po-escolha-icone { color: var(--text-muted); flex-shrink: 0; display: inline-flex; margin-top: 1px; }
.po-escolha.marcada .po-escolha-icone { color: var(--ok); }
.po-escolha-texto { flex: 1; min-width: 0; }
.po-escolha-texto .nome { display: block; font-size: 13.5px; font-weight: 700; }
.po-escolha-texto .desc { display: block; font-size: 12px; color: var(--text-muted); margin-top: 3px; line-height: 1.5; }
.po-escolha-marca { color: var(--ok); flex-shrink: 0; display: inline-flex; }

.po-resumo {
  display: flex; gap: 22px; flex-wrap: wrap; align-items: flex-start;
  margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--border-subtle);
}
.po-resumo-titulo { min-width: 200px; flex: 0 1 240px; }
.po-resumo-titulo h3 { font-size: 14.5px; margin: 0; }
.po-resumo-linhas { flex: 1; display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 14px; }
.po-resumo-linha { display: flex; align-items: flex-start; gap: 10px; }
.po-resumo-linha .marca {
  width: 24px; height: 24px; border-radius: 7px; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--ok) 18%, transparent); color: var(--ok);
}
.po-resumo-linha.em-falta .marca { background: color-mix(in srgb, var(--warn) 18%, transparent); color: var(--warn); }
.po-resumo-linha .nome { font-size: 13px; font-weight: 700; color: var(--ok); }
.po-resumo-linha.em-falta .nome { color: var(--warn); }
.po-resumo-linha .detalhe { font-size: 12px; color: var(--text-muted); margin-top: 2px; }

/* Uma barra de ações só, no fim. Nunca um "Guardar" dentro de cada bloco:
   dois sítios para gravar é como alguém grava metade. */
.po-barra {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-top: 18px; padding-top: 4px;
}
.po-barra-esq, .po-barra-dir { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.po-barra-dir { margin-left: auto; }
.po-gravacao { font-size: 12.5px; color: var(--text-muted); }
.po-gravacao-bom { color: var(--ok); }
.po-gravacao-aviso { color: var(--warn); }
.po-gravacao-erro { color: var(--danger); }
.po-apagar { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 40%, transparent); }
.po-apagar-confirmar { background: var(--danger); color: #fff; }
.po-consequencia {
  display: flex; align-items: flex-start; gap: 10px;
  background: var(--bg-card-alt); border-radius: 10px; padding: 12px 13px;
  font-size: 12.5px; line-height: 1.55;
}
.po-consequencia > span:first-child { flex-shrink: 0; display: inline-flex; margin-top: 1px; color: var(--text-muted); }

@media (max-width: 900px) {
  /* A pesquisa e o estado vivem no cabeçalho do painel; num telemóvel
     passam para baixo do título, à largura toda -- espremidos ao lado
     dele, o campo de pesquisa ficava com meia palavra visível. */
  .panel-head > .ev-ferramentas { width: 100%; margin-top: 12px; }
  .panel-head > .ev-ferramentas .field-group { flex: 1 1 100%; }
  /* A tabela vira cartões: cinco colunas num telemóvel só se leem com
     scroll horizontal, e isso é pior do que qualquer alternativa. */
  .po-tabela-conteiner { display: none; }
  .po-cartoes { display: block; }
  .po-etapas { padding-bottom: 16px; margin-bottom: 18px; }
  .po-etapa-nome { display: none; }
  .po-etapa > button { padding: 0; }
  .po-resumo { flex-direction: column; gap: 14px; }
  .po-barra { flex-direction: column; align-items: stretch; }
  .po-barra-esq, .po-barra-dir { margin-left: 0; }
  .po-barra-esq .btn-ghost, .po-barra-dir .btn-ghost, .po-barra-dir .btn-accent { flex: 1; justify-content: center; }
  .po-barra-dir { flex-direction: column-reverse; }
  .po-barra-dir .btn-accent, .po-barra-dir .btn-ghost { width: 100%; }
}

/* -------------------------------------------------------------------------
   PROMOTORES — a ficha de atribuição

   Tudo o que um promotor precisa fica numa ficha só: onde trabalha, o que
   o posto lhe dá, o que ele vai poder fazer, e o botão de guardar. Antes
   estava em três cartões seguidos que repetiam as mesmas bancas e os
   mesmos nomes, e obrigavam a comparar o que estava em cima com o que
   estava em baixo.
   ------------------------------------------------------------------------- */
.pr-atalho { margin: -14px 0 18px; font-size: 13px; }
.pr-atalho a { color: var(--accent); font-weight: 600; text-decoration: none; }
.pr-atalho a:hover { text-decoration: underline; }
.pr-sub-titulo { font-size: 12.5px; color: var(--text-muted); margin-top: 4px; font-weight: 500; }
.pr-nota {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  font-size: 12.5px; color: var(--text-muted); margin: 16px 0 0; line-height: 1.55;
}
.pr-nota span { display: inline-flex; color: var(--accent); flex-shrink: 0; }

.pr-linha {
  border: 1px solid var(--border-subtle); border-radius: 14px;
  background: var(--bg-card-alt); margin-bottom: 12px; overflow: hidden;
}
.pr-linha:last-child { margin-bottom: 0; }
.pr-linha-suja { border-color: color-mix(in srgb, var(--warn) 45%, transparent); }

/* O cabeçalho é um <button>: o que está lá dentro tem de ser <span>, e por
   isso cada um leva display próprio -- sem isso caíam todos na mesma linha
   e as etiquetas subiam para cima do nome no telemóvel. */
.pr-cab {
  display: flex; align-items: center; gap: 14px; width: 100%;
  padding: 14px 16px; background: none; border: 0; color: inherit;
  text-align: left; cursor: pointer; font: inherit;
}
.pr-cab:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.pr-avatar {
  width: 42px; height: 42px; border-radius: 11px; flex-shrink: 0;
  background: var(--bg-card); display: inline-flex; align-items: center; justify-content: center;
  font-size: 13px; font-weight: 700; color: var(--text-secondary);
}
.pr-quem { flex: 1; min-width: 0; display: block; }
.pr-nome { display: block; font-size: 14.5px; font-weight: 700; overflow-wrap: anywhere; }
.pr-papel { display: block; font-size: 12px; color: var(--text-muted); margin-top: 2px; overflow-wrap: anywhere; }
.pr-estado {
  display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0;
  font-size: 12px; font-weight: 700; border-radius: 999px; padding: 5px 11px;
}
.pr-estado svg { flex-shrink: 0; }
.pr-estado-bom { color: var(--ok); background: color-mix(in srgb, var(--ok) 12%, transparent); }
.pr-estado-aviso { color: var(--warn); background: color-mix(in srgb, var(--warn) 12%, transparent); }
.pr-estado-perigo { color: var(--danger); background: color-mix(in srgb, var(--danger) 12%, transparent); }
.pr-postos { flex-shrink: 0; font-size: 12.5px; color: var(--text-muted); }
.pr-seta { display: inline-flex; color: var(--text-muted); flex-shrink: 0; }
.pr-cab[aria-expanded="true"] .pr-seta { transform: rotate(180deg); }

.pr-corpo { padding: 4px 16px 16px; border-top: 1px solid var(--border-subtle); }
.pr-colunas { display: grid; grid-template-columns: minmax(240px, 1fr) minmax(260px, 1fr); gap: 20px 28px; padding-top: 16px; }
.pr-coluna-titulo { font-size: 13.5px; font-weight: 700; }
.pr-coluna-nota { font-size: 12px; color: var(--text-muted); margin: 4px 0 12px; line-height: 1.5; }
.pr-vazio-mini { font-size: 12.5px; color: var(--text-muted); margin: 8px 0 0; line-height: 1.55; }

/* Um posto escolhido. A borda verde diz "está atribuído" -- é o único
   verde desta ficha que não é um acesso. */
.pr-posto {
  display: flex; align-items: center; gap: 12px; margin-bottom: 10px;
  border: 1px solid color-mix(in srgb, var(--ok) 45%, transparent);
  background: color-mix(in srgb, var(--ok) 6%, transparent);
  border-radius: 12px; padding: 11px 12px;
}
.pr-posto-mau {
  border-color: color-mix(in srgb, var(--danger) 45%, transparent);
  background: color-mix(in srgb, var(--danger) 6%, transparent);
}
.pr-posto-sigla {
  width: 36px; height: 36px; border-radius: 10px; flex-shrink: 0;
  background: var(--bg-card); display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700; color: var(--text-secondary);
}
.pr-posto-quem, .pr-escolher-quem { flex: 1; min-width: 0; display: block; }
.pr-posto-nome { display: block; font-size: 13.5px; font-weight: 700; overflow-wrap: anywhere; }
.pr-posto-tipo { display: block; font-size: 12px; color: var(--text-muted); margin-top: 2px; overflow-wrap: anywhere; }
.pr-posto-tirar {
  flex-shrink: 0; width: 34px; height: 34px; border-radius: 9px; cursor: pointer;
  background: none; border: 1px solid transparent; color: var(--text-muted);
  display: inline-flex; align-items: center; justify-content: center;
}
.pr-posto-tirar:hover { border-color: var(--border-subtle); color: var(--danger); }

.pr-adicionar {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; min-height: 44px; cursor: pointer;
  background: none; border: 1px dashed var(--border); border-radius: 12px;
  color: var(--text-secondary); font: inherit; font-size: 13px; font-weight: 600;
}
.pr-adicionar:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.pr-adicionar:disabled { opacity: 0.4; cursor: not-allowed; }

.pr-herdados { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
.pr-herdados-rotulo { font-size: 12.5px; color: var(--text-secondary); font-weight: 600; }
.pr-modulo {
  font-size: 12px; border-radius: 999px; padding: 5px 11px;
  background: var(--bg-card); border: 1px solid var(--border-subtle); color: var(--text-secondary);
}
.pr-modulo-vazio { color: var(--text-muted); font-style: italic; }

/* O posto por configurar. Diz o que falta, onde se resolve, e que não é
   aqui -- a alternativa era um seletor de atividade nesta página, que
   seria uma segunda porta para o que já se faz em Bancas e Zonas. */
.pr-aviso-posto {
  display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap;
  border: 1px solid color-mix(in srgb, var(--warn) 50%, transparent);
  background: color-mix(in srgb, var(--warn) 7%, transparent);
  border-radius: 12px; padding: 13px 14px; margin-top: 10px;
}
.pr-aviso-icone { color: var(--warn); display: inline-flex; flex-shrink: 0; margin-top: 1px; }
.pr-aviso-texto { flex: 1; min-width: 180px; }
.pr-aviso-texto .titulo { font-size: 13px; font-weight: 700; color: var(--warn); }
.pr-aviso-texto p { font-size: 12.5px; color: var(--text-secondary); margin: 5px 0 0; line-height: 1.55; }
.pr-aviso-texto .nota { font-size: 12px; color: var(--warn); margin-top: 7px; }
.pr-aviso-accao { flex-shrink: 0; white-space: nowrap; }

/* Os acessos efetivos, à largura toda: é o resumo do que fica, e não mais
   uma coluna a competir com as outras duas. */
.pr-efetivos {
  margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--border-subtle);
}
.pr-efetivos-topo { margin-bottom: 12px; }
.pr-efetivos-grelha { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; }
.pr-efetivo {
  display: flex; align-items: flex-start; gap: 11px;
  background: var(--bg-card); border: 1px solid var(--border-subtle);
  border-radius: 12px; padding: 12px 13px;
}
.pr-efetivo .nome { font-size: 13px; font-weight: 700; }
.pr-efetivo .detalhe { font-size: 12px; color: var(--text-muted); margin-top: 3px; }
.pr-efetivo-marca {
  width: 24px; height: 24px; border-radius: 7px; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
}
.pr-efetivo-disponivel .nome { color: var(--ok); }
.pr-efetivo-disponivel .pr-efetivo-marca { background: color-mix(in srgb, var(--ok) 18%, transparent); color: var(--ok); }
.pr-efetivo-pendente .nome { color: var(--warn); }
.pr-efetivo-pendente .pr-efetivo-marca { background: color-mix(in srgb, var(--warn) 18%, transparent); color: var(--warn); }

.pr-accoes { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--border-subtle); }
.pr-accoes-nota {
  display: flex; align-items: flex-start; gap: 9px;
  font-size: 12.5px; color: var(--warn); margin: 0 0 12px; line-height: 1.55;
}
.pr-accoes-nota svg { flex-shrink: 0; margin-top: 1px; }
.pr-accoes-botoes { display: flex; gap: 12px; justify-content: flex-end; flex-wrap: wrap; }

/* A folha de escolher um posto. */
.pr-escolher { display: grid; gap: 10px; max-height: 52vh; overflow: auto; }
.pr-escolher-item {
  display: flex; align-items: center; gap: 12px; width: 100%; text-align: left; cursor: pointer;
  background: var(--bg-card-alt); border: 1px solid var(--border-subtle);
  border-radius: 12px; padding: 12px 13px; font: inherit; color: inherit;
}
.pr-escolher-item:hover { border-color: var(--accent); }
.pr-escolher-aviso {
  display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0;
  font-size: 11.5px; font-weight: 700; color: var(--warn);
}

@media (max-width: 860px) {
  /* No telemóvel as duas colunas empilham, e o aviso do posto fica logo
     por baixo do posto a que se refere. */
  .pr-colunas { grid-template-columns: 1fr; }
  .pr-cab { flex-wrap: wrap; row-gap: 8px; }
  .pr-quem { flex-basis: calc(100% - 56px); }
  .pr-estado, .pr-postos { margin-left: 56px; }
  .pr-seta { margin-left: auto; }
  .pr-accoes-botoes { flex-direction: column-reverse; }
  .pr-accoes-botoes .btn-ghost, .pr-accoes-botoes .btn-accent { width: 100%; }
  .pr-aviso-accao { width: 100%; }
}

/* O registo de entradas de uma pessoa (ficha do utilizador). Uma linha por
   entrada: quando em cima, o resto por baixo -- num telemóvel, quando e
   "de que aparelho" na mesma linha não cabem sem cortar um dos dois. */
.ac-entradas-resumo {
  display: flex; flex-wrap: wrap; gap: 10px 26px;
  font-size: 13px; color: var(--text-secondary);
  padding-bottom: 14px; margin-bottom: 4px;
  border-bottom: 1px solid var(--border-subtle);
}
.ac-entradas { display: grid; gap: 2px; }
.ac-entrada { padding: 11px 0; border-bottom: 1px solid var(--border-subtle); }
.ac-entrada:last-child { border-bottom: none; }
.ac-entrada-quando { font-size: 13.5px; display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.ac-entrada-marca {
  font-size: 10.5px; letter-spacing: 0.05em; text-transform: uppercase; font-weight: 700;
  color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent);
  border-radius: 999px; padding: 2px 8px;
}
.ac-entrada-detalhe {
  display: flex; flex-wrap: wrap; gap: 4px 16px;
  font-size: 12px; color: var(--text-muted); margin-top: 4px;
}
.ac-entrada-ip { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

/* ==========================================================================
   E-MAILS (Gestão > E-mails)
   ==========================================================================
   Mesma moldura de lista das outras páginas (.ev-wrap, .page-header,
   .lista-resumo, .ev-separadores, .ev-ferramentas, .ev-contagem) -- aqui
   está só o que esta página tem de próprio: a faixa dos limites, a tabela
   dos modelos e os cartões em que ela se transforma no telemóvel. */

/* Quatro números num telemóvel são quatro linhas a ocupar um ecrã inteiro.
   Duas colunas dizem o mesmo num relance. */
@media (max-width: 900px) {
  .lista-resumo.duas-colunas { grid-template-columns: 1fr 1fr; }
  .lista-resumo.duas-colunas .lista-metrica { border-left: 1px solid var(--border-subtle); }
  .lista-resumo.duas-colunas .lista-metrica:nth-child(odd) { border-left: 0; }
  .lista-resumo.duas-colunas .lista-metrica:nth-child(-n+2) { border-top: 0; }
  .lista-resumo.duas-colunas .lista-metrica { gap: 10px; padding: 14px; }
  .lista-resumo.duas-colunas .lista-metrica .icone { width: 36px; height: 36px; }
  .lista-resumo.duas-colunas .lista-metrica .valor { font-size: 21px; }
}
/* Um número que leva a algum lado tem de o dar a perceber. */
a.em-metrica-link { text-decoration: none; color: inherit; transition: background 0.15s ease; }
a.em-metrica-link:hover { background: var(--bg-card-alt); }
a.em-metrica-link:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* A faixa dos limites: o que se precisa de saber de relance fica à vista;
   a configuração e a explicação do plano abrem só a pedido. */
.em-limite { padding: 16px 20px; }
.em-limite-faixa { display: flex; align-items: center; gap: 22px; flex-wrap: wrap; }
.em-limite-icone {
  width: 40px; height: 40px; border-radius: 12px; flex-shrink: 0;
  background: var(--bg-card-alt); display: flex; align-items: center; justify-content: center; color: var(--text-secondary);
}
.em-limite-item { display: flex; flex-direction: column; gap: 3px; min-width: 120px; }
.em-limite-item .rotulo { font-size: 12px; color: var(--text-muted); }
.em-limite-item .valor { font-size: 15px; font-weight: 700; }
.em-limite-faixa .btn-ghost { margin-left: auto; }
.em-limite-barra { height: 4px; border-radius: 999px; background: var(--bg-card-alt); margin-top: 14px; overflow: hidden; }
.em-limite-barra > div { height: 100%; background: var(--accent); border-radius: 999px; transition: width 0.3s ease; }
.em-limite-barra > div.cheio { background: var(--warn); }
.em-limite-config { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--border-subtle); }
.em-limite-nota { font-size: 12px; color: var(--text-muted); margin: 0 0 14px; line-height: 1.6; }
@media (max-width: 700px) {
  .em-limite-faixa { gap: 14px; }
  .em-limite-faixa .btn-ghost { margin-left: 0; width: 100%; justify-content: center; }
  .em-limite-item { min-width: calc(50% - 7px); }
}

/* A lista dos modelos */
.em-subtitulo { font-size: 12px; color: var(--text-muted); margin-top: 4px; }
.em-tabela { width: 100%; border-collapse: collapse; font-size: 13px; }
.em-tabela th {
  text-align: left; font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-muted); font-weight: 700; padding: 0 14px 10px; white-space: nowrap;
}
.em-tabela td { padding: 14px; border-top: 1px solid var(--border-subtle); vertical-align: middle; }
.em-tabela tbody tr:hover { background: var(--bg-card-alt); }
.em-col-uso { min-width: 110px; }
.em-col-conteudo { min-width: 120px; }
.em-col-accoes { width: 1%; white-space: nowrap; text-align: right; }

.em-quem { display: flex; align-items: center; gap: 12px; min-width: 220px; }
.em-quem .nome { font-size: 13.5px; font-weight: 700; }
.em-quem .assunto { font-size: 12px; color: var(--text-muted); margin-top: 3px; overflow-wrap: anywhere; }
.em-iniciais {
  width: 38px; height: 38px; border-radius: 10px; flex-shrink: 0;
  background: var(--bg-card-alt); color: var(--text-secondary);
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 800; letter-spacing: 0.04em;
}
/* As duas ações ficam na mesma linha: partidas em duas, a coluna passava
   a ter o dobro da altura da linha e a tabela ganhava buracos. */
.em-accoes { display: flex; gap: 8px; justify-content: flex-end; flex-wrap: nowrap; }
.em-accoes .btn-ghost { gap: 6px; }

/* O estado, com a mesma linguagem do resto: verde é o que está a
   funcionar, cinzento é o que existe mas não está em uso. */
.em-estado { display: inline-flex; align-items: center; gap: 7px; font-size: 13px; font-weight: 600; white-space: nowrap; }
.em-estado .ponto { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.em-estado.ativo { color: var(--ok); }
.em-estado.ativo .ponto { background: var(--ok); }
.em-estado.inativo { color: var(--text-muted); }
.em-estado.inativo .ponto { background: var(--text-muted); }

/* No telemóvel, cartões em vez de cinco colunas */
.em-cartoes { display: none; }
.em-cartao { border: 1px solid var(--border-subtle); border-radius: 14px; padding: 16px; display: grid; gap: 12px; }
.em-cartao + .em-cartao { margin-top: 10px; }
.em-cartao-meta { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.em-cartao .em-uso { font-size: 12px; color: var(--text-secondary); }
.em-cartao .em-accoes { justify-content: flex-start; flex-wrap: wrap; }
@media (max-width: 820px) {
  .em-tabela-conteiner { display: none; }
  .em-cartoes { display: block; }
}

/* O editor de um modelo: uma vista própria, como o editor de um posto. */
.em-editor { display: grid; gap: 14px; }

/* ==========================================================================
   ECRÃS PÚBLICOS — a central (Divulgação > Ecrãs públicos)
   ==========================================================================
   Mesma moldura das outras listas (.ev-wrap, .page-header, .lista-resumo,
   .ev-separadores, .ev-ferramentas, .ev-contagem, .ev-menu) -- aqui está
   só o que esta página tem de próprio: a tabela dos ecrãs, a linha de um
   dispositivo, e os estados. */

.ec-subtitulo { font-size: 12px; color: var(--text-muted); margin-top: 4px; }
.ec-tabela { width: 100%; border-collapse: collapse; font-size: 13px; }
.ec-tabela th {
  text-align: left; font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-muted); font-weight: 700; padding: 0 14px 10px; white-space: nowrap;
}
.ec-tabela td { padding: 14px; border-top: 1px solid var(--border-subtle); vertical-align: middle; }
.ec-tabela tbody tr:hover { background: var(--bg-card-alt); }
.ec-col-conteudo { min-width: 160px; }
.ec-col-dispositivos { min-width: 170px; }
.ec-col-accoes { width: 1%; white-space: nowrap; text-align: right; }

.ec-quem { display: flex; align-items: center; gap: 12px; min-width: 210px; }
.ec-quem .nome { font-size: 13.5px; font-weight: 700; overflow-wrap: anywhere; }
.ec-quem .desc { font-size: 12px; color: var(--text-muted); margin-top: 3px; overflow-wrap: anywhere; }
.ec-icone {
  width: 38px; height: 38px; border-radius: 10px; flex-shrink: 0;
  background: var(--bg-card-alt); color: var(--text-secondary);
  display: flex; align-items: center; justify-content: center;
}
/* As duas ações ficam na mesma linha: partidas em duas, a coluna passava
   a ter o dobro da altura da linha. */
.ec-accoes { display: flex; gap: 8px; justify-content: flex-end; align-items: center; flex-wrap: nowrap; }
.ec-accoes .btn-ghost { gap: 6px; text-decoration: none; }

/* Os estados. Verde é o que está a dar; âmbar é o que precisa de alguém;
   cinzento é o que existe mas não está em uso. Vermelho fica reservado
   para erro a sério -- um ecrã desligado de propósito não é um erro. */
.ec-estado { display: inline-flex; align-items: center; gap: 7px; font-size: 13px; font-weight: 600; white-space: nowrap; }
.ec-estado .ponto { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.ec-estado.ativo { color: var(--ok); }
.ec-estado.ativo .ponto { background: var(--ok); }
.ec-estado.atencao { color: var(--warn); }
.ec-estado.atencao .ponto { background: var(--warn); }
.ec-estado.inativo, .ec-estado.rascunho { color: var(--text-muted); }
.ec-estado.inativo .ponto, .ec-estado.rascunho .ponto { background: var(--text-muted); }

.ec-ligado, .ec-desligado { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; font-weight: 600; white-space: nowrap; }
.ec-ligado { color: var(--ok); }
.ec-desligado { color: var(--warn); }

/* ---------------------------------------------------------------------
   «MOSTRAR NA TV» (mostrar-na-tv.js)
   ---------------------------------------------------------------------
   Um diálogo de ler: o estado, as duas formas de pôr o ecrã na TV, e os
   aparelhos. Nada a mais largo do que a folha -- o endereço rola dentro
   do próprio campo, nunca a página (a 390 px também). */
.mtv { display: flex; flex-direction: column; gap: 18px; min-width: 0; }
.mtv section { min-width: 0; }
.mtv .mtv-h { margin: 0 0 8px; font-size: 13px; font-weight: 700; color: var(--text-primary); }
.mtv p { margin: 0 0 8px; font-size: 13px; color: var(--text-secondary); }
.mtv-estado { background: var(--bg-card-alt); border: 1px solid var(--border-subtle); border-radius: 12px; padding: 14px; }
.mtv-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.mtv-chip { display: inline-flex; align-items: center; padding: 3px 10px; border-radius: 999px; font-size: 12px; font-weight: 700; border: 1px solid var(--border-subtle); }
.mtv-chip.bom { color: var(--ok); }
.mtv-chip.aviso { color: var(--warn); }
.mtv .mtv-resumo { color: var(--text-primary); }
.mtv .mtv-nota { font-size: 12px; color: var(--text-muted); }
.mtv .mtv-aviso { color: var(--warn); font-weight: 600; }
.mtv-endereco { display: flex; flex-direction: column; gap: 6px; margin: 4px 0 8px; min-width: 0; }
.mtv-endereco label { font-size: 12px; color: var(--text-muted); font-weight: 600; }
.mtv-endereco input { width: 100%; min-width: 0; box-sizing: border-box; font-family: var(--font-mono, ui-monospace, monospace); font-size: 13px; }
.mtv-linha-accoes { display: flex; flex-wrap: wrap; gap: 8px; margin: 6px 0; }
.mtv-linha-accoes .btn-ghost { text-decoration: none; }
.mtv-notas, .mtv-passos { margin: 6px 0 0; padding-left: 20px; font-size: 13px; color: var(--text-secondary); }
.mtv-notas li, .mtv-passos li { margin: 3px 0; }
.mtv-detalhes summary { cursor: pointer; font-size: 13px; font-weight: 600; color: var(--accent); }
.mtv-aparelhos { list-style: none; margin: 0 0 6px; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.mtv-aparelho {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px;
  padding: 8px 10px; border: 1px solid var(--border-subtle); border-radius: 10px;
}
.mtv-aparelho-nome { font-weight: 600; font-size: 13px; color: var(--text-primary); flex: 1 1 140px; min-width: 0; overflow-wrap: anywhere; }
.mtv-aparelho-nome.sem-nome { color: var(--text-muted); font-style: italic; }
.folha-accoes a.btn-ghost { text-decoration: none; }
/* O diálogo rola por dentro; o rodapé fica sempre à vista. */
.folha.mtv-folha { display: flex; flex-direction: column; overflow: hidden; }
.folha.mtv-folha > [data-folha-corpo] { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
.folha.mtv-folha > .folha-topo, .folha.mtv-folha > .folha-accoes, .folha.mtv-folha > [data-folha-anuncio] { flex-shrink: 0; }
.folha.mtv-folha > .folha-accoes { padding-top: 12px; border-top: 1px solid var(--border-subtle); }
/* Um botão que ainda não pode agir, mas diz porquê quando se carrega. */
[data-mostrar-tv][aria-disabled="true"], #edVerBtn[aria-disabled="true"], [data-mtv-gerar][aria-disabled="true"] { opacity: 0.6; }
/* O código curto: grande, para se ler de pé ao lado da TV e passar para o
   comando sem enganos. Gasto ou expirado, fica riscado e apagado. */
.mtv-tv-endereco { color: var(--text-primary); font-family: var(--font-mono, ui-monospace, monospace); }
.mtv-codigo { margin: 6px 0 10px; }
.mtv .mtv-codigo-numero {
  margin: 4px 0 6px; font-family: var(--font-mono, ui-monospace, monospace);
  font-size: clamp(30px, 6vw, 42px); font-weight: 800; letter-spacing: 0.08em;
  color: var(--text-primary); font-variant-numeric: tabular-nums;
}
.mtv .mtv-codigo-numero.gasto { color: var(--text-muted); text-decoration: line-through; opacity: 0.6; }

/* pass2.pt/tv (tv.html): lê-se a 3-5 m e usa-se só com o comando. */
.tvc { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 24px; box-sizing: border-box; }
.tvc-caixa { width: min(760px, 94vw); text-align: center; background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 24px; padding: clamp(24px, 4vw, 48px); box-sizing: border-box; }
.tvc-marca { font-weight: 800; letter-spacing: 0.02em; color: var(--accent); font-size: clamp(18px, 2.2vw, 26px); margin: 0 0 8px; }
.tvc-titulo { margin: 0 0 12px; font-size: clamp(26px, 3.6vw, 44px); font-weight: 800; color: var(--text-primary); }
.tvc-instrucao { margin: 0 0 24px; font-size: clamp(16px, 2vw, 24px); color: var(--text-secondary); }
.tvc-campo {
  display: block; width: 100%; box-sizing: border-box; margin: 0 0 16px; padding: 14px 16px;
  font-family: var(--font-mono, ui-monospace, monospace); font-size: clamp(40px, 7vw, 84px); font-weight: 800;
  letter-spacing: 0.12em; text-align: center; font-variant-numeric: tabular-nums;
  background: var(--bg-input, var(--bg-card-alt)); color: var(--text-primary);
  border: 3px solid var(--border-subtle); border-radius: 16px;
}
.tvc-campo:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 6px color-mix(in srgb, var(--accent) 30%, transparent); }
.tvc-campo[readonly] { opacity: 0.7; }
.tvc-botao { width: 100%; font-size: clamp(18px, 2.4vw, 28px); padding: 14px 20px; border-radius: 14px; }
.tvc-botao:focus-visible, .tvc-ultimo:focus-visible { outline: 4px solid var(--accent); outline-offset: 4px; }
.tvc-botao[aria-disabled="true"] { opacity: 0.6; }
.tvc-mensagem { min-height: 1.4em; margin: 16px 0 0; font-size: clamp(16px, 2vw, 24px); font-weight: 600; color: var(--text-secondary); }
.tvc-mensagem.erro { color: var(--danger); }
.tvc-ultimo-bloco { margin-top: 28px; padding-top: 20px; border-top: 1px solid var(--border-subtle); }
.tvc-ultimo { width: 100%; font-size: clamp(16px, 2vw, 22px); padding: 12px 18px; border-radius: 14px; }
.tvc-rodape { margin: 20px 0 0; color: var(--text-muted); font-size: clamp(12px, 1.4vw, 16px); }
.ec-por-publicar {
  display: inline-flex; align-items: center; gap: 6px; margin-top: 6px;
  font-size: 11.5px; font-weight: 600; color: var(--warn);
  background: color-mix(in srgb, var(--warn) 12%, transparent);
  border-radius: 999px; padding: 3px 9px;
}

/* Um dispositivo é uma linha, não uma tabela: são poucos campos e todos
   cabem de lado. */
.ec-dispositivo {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 14px 0; border-top: 1px solid var(--border-subtle);
}
.ec-dispositivo:first-child { border-top: 0; }
.ec-disp-texto { flex: 1; min-width: 180px; }
.ec-disp-texto .nome { font-size: 13.5px; font-weight: 700; }
.ec-disp-texto .desc { font-size: 12px; color: var(--text-muted); margin-top: 3px; }

/* No telemóvel, cartões em vez de cinco colunas */
.ec-cartoes { display: none; }
.ec-cartao { border: 1px solid var(--border-subtle); border-radius: 14px; padding: 16px; display: grid; gap: 12px; }
.ec-cartao + .ec-cartao { margin-top: 10px; }
.ec-cartao-meta { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.ec-cartao .ec-accoes { justify-content: flex-start; flex-wrap: wrap; }
@media (max-width: 900px) {
  .ec-tabela-conteiner { display: none; }
  .ec-cartoes { display: block; }
}

/* -------------------------------------------------------------------------
   AS CAIXAS DE UMA ESTACAO (ver frontend/estacoes.js).

   Tres coisas que se repetem nas caixas do ecra do monitor, dos tempos e
   da instalacao do leitor -- e que estavam a ser desenhadas com `style="
   "` a' mao dentro do HTML de cada uma, cada vez um bocadinho diferente.
   ------------------------------------------------------------------------- */

/* UM VALOR PARA COPIAR: um endereco, um segredo. So' de leitura, a poder
   partir-se em varias linhas (em muitos sitios ainda e' escrito a' mao
   noutra maquina) e com o botao de copiar ao lado. */
.es-valor { display: flex; align-items: stretch; gap: 8px; margin-top: 8px; }
.es-valor input {
  flex: 1; min-width: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12.5px; padding: 10px 12px;
  background: var(--bg-card-alt); border: 1px solid var(--border-subtle); border-radius: 8px;
  color: var(--text-primary);
}
.es-valor input:read-only { cursor: text; }
.es-valor .btn-ghost { flex-shrink: 0; }

/* OS PASSOS de uma instalacao. Numerados porque sao mesmo uma ordem: sem
   os ficheiros no PC certo, confirmar a ligacao nao confirma nada. */
.es-passos { list-style: none; margin: 0; padding: 0; counter-reset: passo; }
.es-passo {
  position: relative; padding: 0 0 18px 38px; counter-increment: passo;
}
.es-passo::before {
  content: counter(passo);
  position: absolute; left: 0; top: 0;
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--bg-card-alt); border: 1px solid var(--border-subtle);
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700; color: var(--text-secondary);
}
/* O traco que liga um passo ao seguinte -- nao no ultimo, que nao liga a
   lado nenhum. */
.es-passo:not(:last-child)::after {
  content: ""; position: absolute; left: 13px; top: 30px; bottom: 6px;
  width: 1px; background: var(--border-subtle);
}
.es-passo .titulo { font-size: 13.5px; font-weight: 700; margin-bottom: 4px; }
.es-passo .nota { font-size: 12px; color: var(--text-muted); line-height: 1.5; }
.es-passo .accoes { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.es-passo.feito::before {
  background: color-mix(in srgb, var(--ok) 18%, transparent);
  border-color: var(--ok); color: var(--ok);
}

/* A SECCAO DISCRETA no fim de uma caixa: "Seguranca e acesso".
   Discreta de proposito -- o que esta' la' dentro apaga o que esta' feito,
   e nao pode ter o mesmo peso que a acao que a pessoa veio fazer. */
.es-discreta {
  margin-top: 22px; padding-top: 16px; border-top: 1px solid var(--border-subtle);
}
.es-discreta > .titulo {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-muted); margin-bottom: 8px;
}
.es-discreta .nota { font-size: 12px; color: var(--text-muted); line-height: 1.5; margin: 0 0 10px; }
.es-discreta .accoes { display: flex; gap: 8px; flex-wrap: wrap; }

/* As linhas de um estado: rotulo a' esquerda, valor a' direita. */
.es-factos { display: flex; flex-direction: column; gap: 0; }
.es-facto {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  padding: 9px 0; border-bottom: 1px solid var(--border-subtle); font-size: 13px;
}
.es-facto:last-child { border-bottom: 0; }
.es-facto > .rotulo { color: var(--text-muted); flex-shrink: 0; }
.es-facto > .valor { text-align: right; overflow-wrap: anywhere; }
.es-facto > .valor.alarme { color: var(--danger); font-weight: 600; }
.es-facto > .valor.bom { color: var(--ok); font-weight: 600; }

.es-facto > .valor.aviso { color: var(--warn); font-weight: 600; }

/* O ATALHO DO ECRA no PC do simulador (caixa "Ecra de ..."): a escolha do
   monitor e o botao na mesma linha, porque sao uma coisa so'. */
.es-atalho { margin-top: 18px; }
.es-atalho .nota { font-size: 12px; color: var(--text-muted); line-height: 1.5; margin: 4px 0 10px; }
.es-atalho .linha { display: flex; gap: 8px; flex-wrap: wrap; align-items: stretch; }
.es-atalho select { flex: 1 1 220px; min-width: 0; }
.es-atalho .es-passos { list-style: decimal outside; margin: 0 0 12px; padding-left: 20px; font-size: 12px; color: var(--text-secondary); line-height: 1.55; }
.es-atalho .es-passos li + li { margin-top: 4px; }
.es-atalho .es-atalho-rodape { margin: 10px 0 0; }

/* O DIAGNOSTICO de uma estacao (estacoes.js, diagnosticoDaEstacao).
   O estado a' esquerda, o que esta' mal e o que fazer a' direita; os
   identificadores por inteiro recolhidos em baixo, para quem ajuda de
   fora. Numa janela estreita, uma coluna so', pela mesma ordem. */
.es-diag { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 28px; align-items: start; }
@media (max-width: 720px) { .es-diag { grid-template-columns: minmax(0, 1fr); gap: 18px; } }
.es-diag-titulo {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-muted); margin: 0 0 8px;
}
.es-diag-titulo:not(:first-child) { margin-top: 18px; }
.es-avisos { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.es-avisos li {
  display: flex; gap: 10px; align-items: flex-start; padding: 10px 12px; border-radius: 8px;
  font-size: 12.5px; line-height: 1.55; color: var(--text-secondary);
  background: var(--bg-card-alt); border: 1px solid var(--border-subtle);
}
.es-avisos .ponto, .es-tudo-bem .ponto {
  width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; margin-top: 6px; background: var(--text-muted);
}
.es-avisos li.tom-erro { border-color: color-mix(in srgb, var(--danger) 40%, transparent); }
.es-avisos li.tom-erro .ponto { background: var(--danger); }
.es-avisos li.tom-aviso { border-color: color-mix(in srgb, var(--warn) 40%, transparent); }
.es-avisos li.tom-aviso .ponto { background: var(--warn); }
.es-tudo-bem { display: flex; gap: 10px; align-items: flex-start; margin: 0; font-size: 13px; color: var(--text-secondary); }
.es-tudo-bem .ponto { background: var(--ok); }
.es-recomendadas { display: flex; flex-wrap: wrap; gap: 8px; }
.es-tecnicos { margin-top: 22px; padding-top: 14px; border-top: 1px solid var(--border-subtle); }
.es-tecnicos > summary {
  cursor: pointer; list-style: none; font-size: 12.5px; font-weight: 600; color: var(--text-secondary);
  border-radius: 6px; width: fit-content; padding: 2px 4px; margin-left: -4px;
}
.es-tecnicos > summary::-webkit-details-marker { display: none; }
.es-tecnicos > summary::before { content: "▸ "; color: var(--text-muted); }
.es-tecnicos[open] > summary::before { content: "▾ "; }
.es-tecnicos > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.es-tecnicos dl {
  display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 6px 16px;
  margin: 12px 0 0; font-size: 12px;
}
.es-tecnicos dt { color: var(--text-muted); }
.es-tecnicos dd {
  margin: 0; overflow-wrap: anywhere; color: var(--text-secondary);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
@media (max-width: 520px) { .es-tecnicos dl { grid-template-columns: minmax(0, 1fr); gap: 2px; } .es-tecnicos dd { margin-bottom: 8px; } }

/* -------------------------------------------------------------------------
   O MENU DOS TRÊS PONTOS DE UMA LINHA (ver shared/menu-de-linha.js).

   Um "⋮" numa linha abre sempre isto, em qualquer lista da aplicação.
   Está no tema e não numa página de propósito: a segunda cópia já tinha
   nascido diferente, e é essa a avaria que estas regras fecham.
   ------------------------------------------------------------------------- */
.ml-menu { position: relative; }
.ml-btn {
  width: 40px; height: 40px; border-radius: 10px; border: 1px solid var(--border-subtle);
  background: none; color: var(--text-secondary); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.ml-btn:hover { color: var(--text-primary); border-color: color-mix(in srgb, var(--accent) 40%, var(--border-subtle)); }
/* O botao tem de mostrar o foco: quem navega por teclado precisa de ver
   onde esta antes de carregar. */
.ml-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.ml-lista {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 40;
  min-width: 248px; max-width: min(320px, calc(100vw - 16px));
  background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 12px;
  box-shadow: 0 12px 32px rgba(0,0,0,0.4); padding: 6px; display: none;
  /* Num ecra baixo a lista ganha rolamento proprio (a altura vem medida
     em JS, ver posicionar) em vez de ficar com metade de fora. */
  overflow-y: auto; overscroll-behavior: contain;
}
.ml-menu[data-aberto="1"] .ml-lista { display: block; }
.ml-lista .ml-item {
  display: flex; align-items: flex-start; gap: 10px; width: 100%; min-height: 44px; padding: 9px 12px;
  background: none; border: 0; border-radius: 8px; color: var(--text-primary);
  font: inherit; font-size: 13.5px; text-align: left; text-decoration: none; cursor: pointer;
}
.ml-lista .ml-item:hover { background: var(--bg-card-alt); }
/* O mesmo destaque para o rato e para o teclado: um menu onde so' o rato
   ve' onde esta' e' um menu que so' o rato usa. */
.ml-lista .ml-item:focus { background: var(--bg-card-alt); outline: none; }
.ml-lista .ml-item:focus-visible { box-shadow: inset 0 0 0 2px var(--accent); }
.ml-lista .ml-icone { flex-shrink: 0; width: 18px; height: 18px; margin-top: 1px; color: var(--text-muted); }
.ml-lista .ml-item:hover .ml-icone, .ml-lista .ml-item:focus .ml-icone { color: var(--text-secondary); }
.ml-txt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.ml-rotulo { line-height: 1.25; }
.ml-nota { font-size: 11.5px; color: var(--text-muted); line-height: 1.3; }
.ml-estado { display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px; color: var(--text-muted); }
.ml-estado .ponto { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex-shrink: 0; }
.ml-estado.tom-bom { color: var(--ok); }
.ml-estado.tom-aviso { color: var(--warn); }
.ml-estado.tom-erro { color: var(--danger); }

/* Os grupos. Letra pequena e maiuscula: e' uma etiqueta, nao um item --
   e nao e' focavel, para as setas nao pararem nela. */
.ml-seccao {
  padding: 10px 12px 4px; font-size: 10.5px; font-weight: 700; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--text-muted);
}
.ml-lista > .ml-seccao:first-child { padding-top: 4px; }
.ml-traco { height: 1px; margin: 6px 8px; background: var(--border-subtle); }

.ml-lista .perigo { color: var(--danger); }
.ml-lista .perigo .ml-icone { color: var(--danger); }
/* Uma acao que nao se pode fazer fica A' VISTA, cinzenta, com a razao por
   baixo. Escondida, a pergunta "e o servidor associado?" ficava sem
   resposta nenhuma. */
.ml-lista .desativado { cursor: default; opacity: 0.55; }
.ml-lista .desativado:hover { background: none; }
