/* ==========================================================================
   Canivete Suíço — base visual
   Tokens, tipografia, barra, botões, campos, cartões, rodapé e as peças
   reutilizáveis (aviso, diálogo, dica, esqueleto, girador, seletor, marcador).

   Este arquivo é compartilhado pelas três telas (index, hub e fups):
   nada aqui pode ser específico de uma página só.

   Regra da casa: nenhum controle nativo de navegador pode aparecer na tela.
   Barra de rolagem, seleção de texto, placeholder, autofill, setinhas,
   realce de toque, tooltip, spinner e diálogo são todos desenhados aqui.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   Todo valor de cor, raio e medida do vocabulário aprovado mora aqui.
   -------------------------------------------------------------------------- */
:root {
  /* Fundo e texto
     Os cinzas foram medidos contra o preto puro (razão de contraste WCAG).
     Nenhum token de texto pode ficar abaixo de 4,5:1: o app tem muito texto
     pequeno (0,78rem a 0,9rem) e é lido em tela de celular, na rua. */
  --fundo: #000000;
  --texto: #ffffff;            /* 21,0:1 */
  --texto-2: #a1a1a6;          /* 8,2:1  — secundário: apoio, rótulos, descrições */
  /* Os dois cinzas de baixo valem 6,4:1 e 5,2:1 sobre o preto. Precisam dessa
     folga porque também são lidos sobre o vidro dos menus (~#1c1c1e), onde a
     razão cai para 5,2:1 e 4,2:1 — com os valores antigos (#86868b/#77777c) o
     texto do menu de peças ficava em 4,7:1, rente demais ao mínimo.
     Este é o mesmo par das três telas: a de fups tinha um par só dela. */
  --texto-3: #8e8e94;          /* 6,4:1  — terciário: rodapé, contadores, recados */
  --texto-4: #7e7e84;          /* 5,2:1  — quaternário: reservado, estado vazio */
  --texto-invertido: #0c0c0d;  /* texto sobre o branco */

  /* Superfícies de vidro */
  --superficie: rgba(255, 255, 255, 0.05);
  --superficie-forte: rgba(255, 255, 255, 0.08);
  --superficie-hover: rgba(255, 255, 255, 0.10);
  --superficie-ativa: rgba(255, 255, 255, 0.14);
  --superficie-barra: rgba(30, 30, 30, 0.35);
  --superficie-apagada: rgba(255, 255, 255, 0.02);

  /* Equivalentes opacos das superfícies de vidro.
     Servem onde o navegador exige cor sólida: autofill do Chrome (que só
     aceita box-shadow), menus flutuantes e a caixa do diálogo. */
  --campo-solido: #0d0d0d;     /* = --superficie sobre o preto */
  --flutuante-solido: #161618;
  --dialogo-solido: #0f0f10;

  /* Bordas */
  --borda: rgba(255, 255, 255, 0.12);
  --borda-barra: rgba(255, 255, 255, 0.08);
  --borda-apagada: rgba(255, 255, 255, 0.07);
  --borda-contorno: rgba(255, 255, 255, 0.25);
  --borda-forte: rgba(255, 255, 255, 0.40);
  --borda-rodape: rgba(255, 255, 255, 0.06);

  /* Barra de rolagem desenhada */
  --rolagem: rgba(255, 255, 255, 0.18);
  --rolagem-forte: rgba(255, 255, 255, 0.34);

  /* Seleção de texto: branco do vocabulário, nunca o azul do sistema */
  --selecao: rgba(255, 255, 255, 0.85);

  /* Formas */
  --pilula: 980px;       /* tudo de uma linha é pílula */
  --raio-cartao: 22px;
  --raio-caixa: 16px;    /* avisos, menus e diálogos: texto longo não vira pílula */
  --raio-item: 12px;     /* item de lista dentro de um menu */
  --largura: 1180px;     /* largura útil das telas */

  /* Recuos
     --recuo é a coluna da página: é o padding lateral da .faixa E a margem
     lateral da .barra, para que a borda esquerda da barra caia exatamente
     na mesma linha do título e dos blocos.
     --respiro-topo é a distância padrão da barra até o começo do conteúdo,
     igual nas três telas. */
  --recuo: 20px;
  --respiro-topo: 60px;

  /* Sombras */
  --sombra-cartao: 0 8px 24px rgba(0, 0, 0, 0.4),
                   inset 0 1px 0 rgba(255, 255, 255, 0.1);
  --sombra-flutuante: 0 18px 40px rgba(0, 0, 0, 0.65);

  /* Movimento (some inteiro em prefers-reduced-motion) */
  --transicao: 0.16s ease;

  /* Brilho azul discreto do topo */
  --brilho: rgba(1, 111, 208, 0.2);
}

@media (max-width: 720px) {
  :root {
    --recuo: 16px;
    --respiro-topo: 40px;
  }
}

/* --------------------------------------------------------------------------
   2. Reinício e tipografia
   -------------------------------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  /* O retângulo cinza que Android e iOS pintam sobre o que se toca. */
  -webkit-tap-highlight-color: transparent;
}

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;   /* iOS/Android: 100vh é maior que a área útil com a barra de endereço */
  font-family: 'Poppins', system-ui, sans-serif;
  font-weight: 300;
  background: var(--fundo);
  color: var(--texto);
  -webkit-font-smoothing: antialiased;
  /* E-mail comprido, nome comprido, link colado: quebra em vez de estourar. */
  overflow-wrap: break-word;
}

a {
  color: var(--texto);
  text-decoration: none;
  transition: color var(--transicao), opacity var(--transicao);
}

/* Hover não é desbotar: sobre preto, baixar opacidade some com o texto.
   O padrão do app é clarear (cinza -> branco). */
a:hover {
  color: var(--texto);
}

a:active {
  color: rgba(255, 255, 255, 0.72);
}

/* Títulos: peso 400, nunca 700. A hierarquia vem do tamanho e do espaçamento. */
.titulo {
  margin: 0;
  font-size: 2.4rem;
  font-weight: 400;
  letter-spacing: -0.03em;
  line-height: 1.15;
}

.titulo--grande {
  font-size: 2.6rem;
}

.subtitulo {
  margin: 0;
  font-size: 0.98rem;
  font-weight: 300;
  line-height: 1.6;
  color: var(--texto-2);
}

/* 2.1 Seleção de texto
   ------------------------------------------------------------------ */
::selection {
  background: var(--selecao);
  color: var(--texto-invertido);
  text-shadow: none;
}

/* 2.2 Barra de rolagem — da página e de qualquer área rolável
   O polegar é uma pílula clara sobre trilho transparente. A borda
   transparente com background-clip afina o polegar sem afinar a área
   de clique.
   ------------------------------------------------------------------ */
* {
  scrollbar-width: thin;                              /* Firefox */
  scrollbar-color: var(--rolagem) transparent;        /* Firefox: polegar, trilho */
}

::-webkit-scrollbar {
  width: 12px;
  height: 12px;
}

::-webkit-scrollbar-track,
::-webkit-scrollbar-corner {
  background: transparent;
}

/* As setinhas das pontas do trilho, que algumas configurações do Windows e do
   Chrome ainda desenham. Não são nossas. */
::-webkit-scrollbar-button {
  display: none;
  width: 0;
  height: 0;
}

::-webkit-scrollbar-thumb {
  background: var(--rolagem);
  background-clip: padding-box;
  border: 3px solid transparent;
  border-radius: var(--pilula);
}

::-webkit-scrollbar-thumb:hover {
  background: var(--rolagem-forte);
  background-clip: padding-box;
}

/* Área rolável interna: some com a rolagem até precisar dela. */
.rolavel {
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* --------------------------------------------------------------------------
   3. Foco visível — acessibilidade, em tudo que recebe teclado
   -------------------------------------------------------------------------- */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
[tabindex]:focus-visible,
[contenteditable]:focus-visible {
  outline: 2px solid var(--texto);
  outline-offset: 3px;
}

button:focus-visible,
a.botao-contorno:focus-visible,
.botao-primario:focus-visible {
  outline-offset: 4px;
}

/* Atalho para o conteúdo, só aparece no Tab */
.pular-para-conteudo {
  position: absolute;
  top: 12px;
  left: 50%;
  transform: translate(-50%, -200%);
  z-index: 50;
  padding: 10px 22px;
  font-size: 0.85rem;
  font-weight: 400;
  color: var(--texto-invertido);
  background: var(--texto);
  border-radius: var(--pilula);
  transition: transform 0.15s ease, background-color var(--transicao);
}

.pular-para-conteudo:focus {
  transform: translate(-50%, 0);
}

.pular-para-conteudo:hover {
  color: var(--texto-invertido);
  background: #f1f1f2;
}

.pular-para-conteudo:active {
  color: var(--texto-invertido);
  background: #e2e2e4;
}

/* --------------------------------------------------------------------------
   4. Esqueleto da página
   -------------------------------------------------------------------------- */
.pagina {
  position: relative;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Segura o brilho decorativo; não é lugar de esconder conteúdo estourado:
     bloco que não cabe se resolve com min-width: 0 e .truncar. */
  overflow-x: hidden;
}

/* Brilho azul de fundo, decorativo.
   A largura é 100%, e não 100vw: 100vw conta a barra de rolagem vertical, e o
   brilho passava alguns pixels da tela — o bastante para a página rolar para o
   lado no celular. O editor tinha um remendo só dele para isto; agora vale
   para as três telas. */
.brilho {
  position: absolute;
  top: -300px;
  left: 50%;
  width: min(1000px, 100%);
  height: 560px;
  transform: translateX(-50%);
  background: radial-gradient(ellipse at center, var(--brilho), rgba(0, 0, 0, 0) 70%);
  pointer-events: none;
  z-index: 0;
}

.brilho--forte {
  top: -260px;
  width: min(900px, 100%);
  height: 520px;
}

/* Faixa de conteúdo, com a mesma largura útil em todas as telas */
.faixa {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: var(--largura);
  padding-left: var(--recuo);
  padding-right: var(--recuo);
}

/* Respiro padrão entre a barra e o começo do conteúdo. */
.respiro-topo {
  padding-top: var(--respiro-topo);
}

/* --------------------------------------------------------------------------
   5. Barra superior (vidro)
   A margem lateral é --recuo, igual ao padding da .faixa: a borda da barra
   nasce na mesma coluna do título. Dentro da pílula, o conteúdo respeita
   o mesmo --recuo, e nada mais soma padding por fora disso.
   -------------------------------------------------------------------------- */
.barra {
  position: relative;
  z-index: 3;
  /* Antes era width:100% + margem lateral: a soma passava da tela e a pílula
     era cortada rente à borda no celular. Descontar o recuo da largura mantém
     a barra dentro da tela e, acima de 1220px, com a borda exatamente na
     mesma coluna do conteúdo da .faixa. */
  width: calc(100% - var(--recuo) * 2);
  max-width: var(--largura);
  min-height: 60px;
  margin: 24px 0 0;
  padding: 8px 12px 8px var(--recuo);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  border-radius: var(--pilula);
  background: var(--superficie-barra);
  border: 1px solid var(--borda-barra);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
}

.barra__marca {
  display: flex;
  align-items: center;
  gap: 11px;
  min-width: 0;
  font-size: 0.95rem;
  font-weight: 500;
  letter-spacing: -0.01em;
}

.barra__voltar {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
  font-size: 0.9rem;
  font-weight: 300;
  color: var(--texto-2);
}

.barra__acoes {
  display: flex;
  align-items: center;
  gap: 16px;
  min-width: 0;
  flex-wrap: nowrap;
}

/* Nome de quem está logado: nunca quebra a pílula em duas fileiras.
   Nome comprido (ou e-mail inteiro) vira reticência. */
.barra__usuario {
  min-width: 0;
  max-width: 190px;
  font-size: 0.9rem;
  font-weight: 300;
  color: var(--texto-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   6. Botões e links de ação — tudo em pílula
   Todo elemento interativo tem os quatro estados desenhados:
   hover, active, disabled e focus-visible.
   -------------------------------------------------------------------------- */
button {
  font-family: inherit;
}

.botao-primario {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  height: 52px;
  padding: 0 28px;
  font-family: inherit;
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--texto-invertido);
  background: var(--texto);
  border: none;
  border-radius: var(--pilula);
  cursor: pointer;
  transition: background-color var(--transicao), transform var(--transicao),
              opacity var(--transicao);
}

.botao-primario:hover {
  background: #f1f1f2;
}

.botao-primario:active {
  background: #dededf;
  transform: scale(0.985);
}

/* Desabilitado é visivelmente diferente e não aceita clique.
   Só quando há trabalho em curso (aria-busy) o cursor vira de espera —
   antes isso valia para todo [disabled], e sobrava para botão que estava
   apenas sem nada a fazer. */
.botao-primario[disabled] {
  opacity: 0.42;
  background: var(--texto);
  transform: none;
  cursor: not-allowed;
}

.botao-primario[aria-busy='true'] {
  cursor: progress;
  opacity: 0.6;
}

.botao-primario--compacto {
  height: 42px;
  padding: 0 20px;
  font-size: 0.88rem;
}

.botao-contorno {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: inherit;
  font-size: 0.85rem;
  font-weight: 400;
  color: var(--texto);
  padding: 8px 20px;
  background: none;
  border: 1px solid var(--borda-contorno);
  border-radius: var(--pilula);
  cursor: pointer;
  transition: background-color var(--transicao), border-color var(--transicao),
              transform var(--transicao);
}

.botao-contorno:hover {
  color: var(--texto);
  background: var(--superficie-hover);
  border-color: var(--borda-forte);
}

.botao-contorno:active {
  background: var(--superficie-ativa);
  transform: scale(0.985);
}

.botao-contorno[disabled],
.botao-contorno[aria-disabled='true'] {
  color: var(--texto-3);
  background: none;
  border-color: var(--borda-apagada);
  transform: none;
  cursor: not-allowed;
}

/* Ocupado vem depois de desabilitado de propósito: enquanto a ação está em
   curso o cursor é de espera, não de proibido. */
.botao-contorno[aria-busy='true'] {
  color: var(--texto-2);
  border-color: var(--borda);
  cursor: progress;
}

/* Link discreto: clareia no hover, escurece no clique. */
.link-suave {
  font-size: 0.9rem;
  font-weight: 300;
  color: var(--texto-2);
  transition: color var(--transicao);
}

.link-suave:hover {
  color: var(--texto);
}

.link-suave:active {
  color: var(--texto-2);
}

/* --------------------------------------------------------------------------
   7. Formulário e campos
   -------------------------------------------------------------------------- */
.formulario {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.campo {
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.campo__rotulo {
  font-size: 0.8rem;
  font-weight: 300;
  color: var(--texto-2);
  /* 22px = o mesmo recuo interno do .campo__entrada: o rótulo nasce
     exatamente na coluna do texto digitado. */
  padding-left: 22px;
}

/* Envolve o campo quando há um botão nosso por dentro dele (ex.: mostrar senha) */
.campo__caixa {
  position: relative;
  display: flex;
  align-items: center;
}

.campo__caixa .campo__entrada {
  padding-right: 112px;
}

/* Botão nosso encostado na borda interna do campo (ex.: mostrar a senha,
   no lugar do olho que o Edge e o Chrome injetam). Usar junto de
   .botao-contorno para herdar hover, active, disabled e foco. */
.campo__acao {
  position: absolute;
  right: 6px;
  height: 40px;
  padding: 0 16px;
  font-size: 0.8rem;
}

.campo__entrada {
  height: 52px;
  width: 100%;
  padding: 0 22px;
  font-family: inherit;
  font-size: 0.95rem;
  font-weight: 300;
  color: var(--texto);
  background: var(--superficie);
  border: 1px solid var(--borda);
  border-radius: var(--pilula);
  /* Sem isto o Safari do iPhone desenha a sombra interna dele por baixo
     da nossa borda, e o campo fica com duas molduras. */
  -webkit-appearance: none;
  appearance: none;
  caret-color: var(--texto);
  transition: border-color var(--transicao), background-color var(--transicao);
}

.campo__entrada:hover {
  border-color: var(--borda-contorno);
}

.campo__entrada:focus {
  background: var(--superficie-forte);
  border-color: var(--borda-contorno);
}

.campo__entrada[disabled],
.campo__entrada[readonly] {
  color: var(--texto-3);
  background: var(--superficie-apagada);
  border-color: var(--borda-apagada);
  cursor: not-allowed;
}

/* Campo que o servidor recusou. Marcado por peso de borda, não por cor. */
.campo__entrada[aria-invalid='true'] {
  border-color: var(--texto);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.35);
}

/* 7.1 Placeholder
   opacity: 1 é obrigatório: o Firefox aplica opacidade própria e o cinza
   cairia abaixo do contraste mínimo.
   ------------------------------------------------------------------ */
::placeholder {
  color: var(--texto-3);
  font-weight: 300;
  opacity: 1;
}

/* 7.2 Autofill do Chrome
   O Chrome força fundo azul-claro com texto preto dentro do campo e só
   aceita ser convencido por box-shadow. A transição longuíssima segura o
   flash do fundo original no primeiro quadro.
   ------------------------------------------------------------------ */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active,
textarea:-webkit-autofill,
select:-webkit-autofill {
  -webkit-box-shadow: inset 0 0 0 1000px var(--campo-solido) !important;
  box-shadow: inset 0 0 0 1000px var(--campo-solido) !important;
  -webkit-text-fill-color: var(--texto) !important;
  caret-color: var(--texto);
  border-radius: inherit;
  transition: background-color 100000s ease 0s;
}

/* 7.3 Enxertos do navegador dentro do campo
   Chave do gerenciador de senhas (Chrome), olho de revelar (Edge),
   X de limpar, lupa da busca e setinhas do number. Nada disso é nosso.
   ------------------------------------------------------------------ */
input::-webkit-credentials-auto-fill-button,
input::-webkit-contacts-auto-fill-button,
input::-webkit-strong-password-auto-fill-button,
input::-webkit-caps-lock-indicator {
  visibility: hidden;
  display: none !important;
  width: 0;
  height: 0;
  margin: 0;
  pointer-events: none;
}

input::-ms-reveal,
input::-ms-clear {
  display: none;
}

input[type='search']::-webkit-search-cancel-button,
input[type='search']::-webkit-search-decoration,
input[type='search']::-webkit-search-results-button,
input[type='search']::-webkit-search-results-decoration {
  -webkit-appearance: none;
  appearance: none;
  display: none;
}

input[type='number'] {
  -moz-appearance: textfield;
  appearance: textfield;
}

input[type='number']::-webkit-inner-spin-button,
input[type='number']::-webkit-outer-spin-button {
  -webkit-appearance: none;
  appearance: none;
  margin: 0;
}

/* Área de texto: sem a alça de redimensionar e sem o contorno padrão. */
textarea {
  resize: none;
  -webkit-appearance: none;
  appearance: none;
}

/* Guarda-costas: se um <select> nativo entrar no app um dia, ele não
   aparece com a cara do sistema. O certo é usar .seletor (item 7.6). */
select {
  -webkit-appearance: none;
  appearance: none;
  font-family: inherit;
}

/* Entrada escondida com o teclado ainda alcançando ela.
   Usada por input[type=file], checkbox e radio: o visível é o nosso. */
.entrada-oculta {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  padding: 0;
  opacity: 0;
  pointer-events: none;
}

/* Só para leitor de tela (rótulos de apoio, contagens, avisos de estado). */
.so-leitor {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* 7.4 Recado discreto: erro de entrada, aviso de salvamento etc.
   O espaço fica reservado sempre — sem isso a tela pula quando o erro
   aparece e o botão foge do dedo.
   ------------------------------------------------------------------ */
.recado {
  margin: 0;
  min-height: 1.2em;
  text-align: center;
  font-size: 0.85rem;
  font-weight: 300;
  line-height: 1.5;
  color: var(--texto-2);
}

/* Área com altura reservada para um .aviso que vai e volta.
   Enquanto não há aviso, o espaço já é dele: nada se move quando chega. */
.area-aviso {
  min-height: 52px;
  display: flex;
  align-items: flex-start;
}

/* 7.5 Marcador: checkbox e radio desenhados
   Markup:
     <label class="marcador">
       <input class="entrada-oculta marcador__entrada" type="checkbox">
       <span class="marcador__caixa" aria-hidden="true"></span>
       <span class="marcador__texto">Rótulo</span>
     </label>
   Para radio, acrescente .marcador--redondo no <label> e type="radio".
   O input continua sendo o input: teclado, formulário e leitor de tela
   funcionam sozinhos — o que muda é só o desenho.
   ------------------------------------------------------------------ */
.marcador {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  position: relative;
  font-size: 0.9rem;
  font-weight: 300;
  color: var(--texto-2);
  cursor: pointer;
  user-select: none;
}

.marcador__caixa {
  position: relative;
  flex: none;
  width: 20px;
  height: 20px;
  display: grid;
  place-items: center;
  background: var(--superficie);
  border: 1px solid var(--borda-contorno);
  border-radius: 7px;
  transition: background-color var(--transicao), border-color var(--transicao);
}

.marcador--redondo .marcador__caixa {
  border-radius: 50%;
}

/* O tique, desenhado com duas bordas. */
.marcador__caixa::after {
  content: '';
  width: 10px;
  height: 5px;
  margin-top: -2px;
  border-left: 2px solid var(--texto-invertido);
  border-bottom: 2px solid var(--texto-invertido);
  border-radius: 1px;
  transform: rotate(-45deg) scale(0.6);
  opacity: 0;
  transition: opacity var(--transicao), transform var(--transicao);
}

.marcador--redondo .marcador__caixa::after {
  width: 8px;
  height: 8px;
  margin: 0;
  border: none;
  border-radius: 50%;
  background: var(--texto-invertido);
  transform: scale(0.4);
}

.marcador:hover .marcador__caixa {
  background: var(--superficie-hover);
  border-color: var(--borda-forte);
}

.marcador__entrada:checked + .marcador__caixa {
  background: var(--texto);
  border-color: var(--texto);
}

.marcador__entrada:checked + .marcador__caixa::after {
  opacity: 1;
  transform: rotate(-45deg) scale(1);
}

.marcador--redondo .marcador__entrada:checked + .marcador__caixa::after {
  transform: scale(1);
}

.marcador__entrada:focus-visible + .marcador__caixa {
  outline: 2px solid var(--texto);
  outline-offset: 3px;
}

.marcador__entrada:active + .marcador__caixa {
  background: var(--superficie-ativa);
}

.marcador:has(.marcador__entrada[disabled]) {
  color: var(--texto-4);
  cursor: not-allowed;
}

.marcador__entrada[disabled] + .marcador__caixa {
  background: var(--superficie-apagada);
  border-color: var(--borda-apagada);
}

/* 7.6 Seletor: o nosso <select>
   Markup (o gatilho é <button>, a lista é <ul role="listbox"> e cada
   opção é <li role="option"> — listbox e option precisam ser pai e filho
   diretos, senão o leitor de tela não anuncia a contagem):

     <div class="seletor">
       <button class="seletor__gatilho" type="button"
               aria-haspopup="listbox" aria-expanded="false"
               aria-controls="lista-x" id="gatilho-x">
         <span class="seletor__valor">Escolha</span>
       </button>
       <ul class="seletor__lista rolavel" id="lista-x" role="listbox"
           aria-labelledby="gatilho-x" tabindex="-1" hidden>
         <li class="seletor__opcao" role="option" aria-selected="false" id="op-1">Um</li>
       </ul>
     </div>

   Teclado obrigatório no JS de quem usar:
     Enter/Espaço/Seta abre · Setas movem (marcando .seletor__opcao--ativa e
     aria-activedescendant no gatilho) · Enter escolhe · Esc fecha e devolve
     o foco ao gatilho · Home/End vão para a primeira e a última ·
     Tab fecha sem escolher. Clique fora fecha.
   ------------------------------------------------------------------ */
.seletor {
  position: relative;
  display: inline-flex;
  flex-direction: column;
  min-width: 0;
}

.seletor__gatilho {
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  min-height: 44px;
  padding: 0 18px;
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 300;
  color: var(--texto);
  text-align: left;
  background: var(--superficie);
  border: 1px solid var(--borda);
  border-radius: var(--pilula);
  cursor: pointer;
  transition: background-color var(--transicao), border-color var(--transicao);
}

.seletor__valor {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A seta, desenhada: duas bordas giradas. */
.seletor__gatilho::after {
  content: '';
  flex: none;
  width: 7px;
  height: 7px;
  margin-top: -3px;
  border-right: 1.5px solid var(--texto-2);
  border-bottom: 1.5px solid var(--texto-2);
  transform: rotate(45deg);
  transition: transform var(--transicao);
}

.seletor__gatilho:hover {
  background: var(--superficie-hover);
  border-color: var(--borda-contorno);
}

.seletor__gatilho:active {
  background: var(--superficie-ativa);
}

.seletor__gatilho[aria-expanded='true'] {
  background: var(--superficie-forte);
  border-color: var(--borda-contorno);
}

.seletor__gatilho[aria-expanded='true']::after {
  margin-top: 3px;
  transform: rotate(-135deg);
}

.seletor__gatilho[disabled] {
  color: var(--texto-3);
  background: var(--superficie-apagada);
  border-color: var(--borda-apagada);
  cursor: not-allowed;
}

.seletor__lista {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 30;
  min-width: 100%;
  max-height: 280px;
  margin: 0;
  padding: 6px;
  list-style: none;
  background: var(--flutuante-solido);
  border: 1px solid var(--borda);
  border-radius: var(--raio-caixa);
  box-shadow: var(--sombra-flutuante);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
}

.seletor__lista[hidden] {
  display: none;
}

.seletor__opcao {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  font-size: 0.9rem;
  font-weight: 300;
  color: var(--texto-2);
  border-radius: var(--raio-item);
  cursor: pointer;
  transition: background-color var(--transicao), color var(--transicao);
}

.seletor__opcao:hover,
.seletor__opcao--ativa {
  color: var(--texto);
  background: var(--superficie-forte);
}

.seletor__opcao:active {
  background: var(--superficie-ativa);
}

.seletor__opcao[aria-selected='true'] {
  color: var(--texto);
}

/* Marca da opção escolhida: um tique desenhado, sem badge nem cor. */
.seletor__opcao[aria-selected='true']::after {
  content: '';
  flex: none;
  width: 9px;
  height: 5px;
  margin-left: auto;
  border-left: 1.5px solid var(--texto);
  border-bottom: 1.5px solid var(--texto);
  transform: rotate(-45deg);
}

/* Lista sem resultado nunca fecha calada: diz por que está vazia. */
.seletor__vazio {
  padding: 12px 14px;
  font-size: 0.85rem;
  font-weight: 300;
  line-height: 1.5;
  color: var(--texto-3);
}

/* 7.7 Arquivo: o input fica com .entrada-oculta e o botão é nosso.
   .arquivo__nome recebe o nome escolhido; vazio, mostra o texto de apoio.
   ------------------------------------------------------------------ */
.arquivo {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  min-width: 0;
}

.arquivo__nome {
  min-width: 0;
  flex: 1 1 140px;
  font-size: 0.85rem;
  font-weight: 300;
  color: var(--texto-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.arquivo__nome:empty::before {
  content: attr(data-vazio);
  color: var(--texto-3);
}

/* --------------------------------------------------------------------------
   8. Cartões
   -------------------------------------------------------------------------- */
.cartao {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 24px 26px;
  background: var(--superficie);
  border: 1px solid var(--borda);
  border-radius: var(--raio-cartao);
}

/* Cartão de ferramenta do hub: ativo, clicável, com sombra */
.cartao-ferramenta {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 60px;
  min-width: 0;
  min-height: 210px;
  padding: 28px 26px;
  background: var(--superficie-forte);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: var(--raio-cartao);
  box-shadow: var(--sombra-cartao);
  transition: background-color var(--transicao), border-color var(--transicao),
              transform var(--transicao);
}

a.cartao-ferramenta:hover {
  color: var(--texto);
  background: var(--superficie-hover);
  border-color: var(--borda-contorno);
  transform: translateY(-2px);
}

a.cartao-ferramenta:active {
  color: var(--texto);
  background: var(--superficie-ativa);
  transform: translateY(0) scale(0.995);
}

/* Cartão reservado: mesma forma, quase apagado. Não é clicável e o
   cursor precisa dizer isso. */
.cartao-ferramenta--reservado {
  background: var(--superficie-apagada);
  border-color: var(--borda-apagada);
  box-shadow: none;
  cursor: default;
  transform: none;
}

/* O ícone segue a cor do texto do cartão (currentColor no SVG), para o
   cartão reservado apagar sem precisar de um segundo hexadecimal solto. */
.cartao-ferramenta__icone {
  flex: none;
  color: var(--texto);
}

.cartao-ferramenta--reservado .cartao-ferramenta__icone {
  color: var(--texto-4);
}

.cartao-ferramenta__texto {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}

.cartao-ferramenta__nome {
  font-size: 1.12rem;
  font-weight: 500;
  letter-spacing: -0.015em;
}

.cartao-ferramenta__descricao {
  font-size: 0.88rem;
  font-weight: 300;
  line-height: 1.55;
  color: var(--texto-2);
}

.cartao-ferramenta__estado {
  display: inline-block;
  min-height: 1.2em;
  font-size: 0.82rem;
  font-weight: 300;
  color: var(--texto-3);
}

.cartao-ferramenta__estado--atencao {
  color: var(--texto-2);
}

.cartao-ferramenta--reservado .cartao-ferramenta__nome {
  color: var(--texto-3);
}

.cartao-ferramenta--reservado .cartao-ferramenta__descricao {
  color: var(--texto-4);
}

/* --------------------------------------------------------------------------
   9. Rodapé
   -------------------------------------------------------------------------- */
.rodape {
  position: relative;
  z-index: 2;
  width: 100%;
  margin-top: 48px;
  padding: 20px 24px 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  text-align: center;
  border-top: 1px solid var(--borda-rodape);
}

.rodape__icone {
  flex: none;
  color: var(--texto-3);
}

.rodape__texto {
  margin: 0;
  min-width: 0;
  font-size: 0.78rem;
  font-weight: 300;
  line-height: 1.6;
  color: var(--texto-3);
}

.rodape__destaque {
  display: inline-block;
  max-width: 100%;
  vertical-align: bottom;
  color: var(--texto-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   10. Peças reutilizáveis
   As três telas usam estas mesmas classes. Nada aqui depende de página.
   -------------------------------------------------------------------------- */

/* 10.1 Aviso — o lugar desenhado do erro, do sucesso e do alerta.
   Erro e sucesso NÃO se distinguem por cor (o vocabulário não tem cor de
   estado): o erro ganha um fio branco na lateral e texto em branco cheio;
   o sucesso, um fio apagado e texto secundário.
   Some e volta com o atributo [hidden] — nunca com :empty, que faz a
   tela pular. Onde ele vai e volta, envolva em .area-aviso.
   ------------------------------------------------------------------ */
.aviso {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  width: 100%;
  margin: 0;
  padding: 11px 16px;
  font-size: 0.85rem;
  font-weight: 300;
  line-height: 1.5;
  text-align: left;
  color: var(--texto-2);
  background: var(--superficie);
  border: 1px solid var(--borda);
  border-radius: var(--raio-caixa);
}

.aviso[hidden] {
  display: none;
}

.aviso--erro {
  color: var(--texto);
  background: var(--superficie-forte);
  border-color: var(--borda-contorno);
  box-shadow: inset 2px 0 0 0 var(--texto);
}

.aviso--ok {
  box-shadow: inset 2px 0 0 0 rgba(255, 255, 255, 0.35);
}

.aviso--atencao {
  color: var(--texto);
  box-shadow: inset 2px 0 0 0 var(--texto-2);
}

/* Variante de uma linha, em pílula, para caber dentro de uma barra. */
.aviso--linha {
  width: auto;
  padding: 7px 16px;
  border-radius: var(--pilula);
}

.aviso__texto {
  margin: 0;
  min-width: 0;
}

/* 10.2 Estado vazio — nenhuma lista pode ficar em branco sem explicação. */
.vazio {
  margin: 0;
  padding: 14px 16px;
  font-size: 0.85rem;
  font-weight: 300;
  line-height: 1.55;
  color: var(--texto-3);
  background: var(--superficie-apagada);
  border: 1px dashed var(--borda);
  border-radius: var(--raio-caixa);
}

.vazio--solto {
  padding: 4px 0;
  background: none;
  border: none;
}

/* 10.3 Esqueleto de carregamento — tela em branco nunca.
   O texto de apoio ("Carregando…") pode ficar dentro: ele some da vista
   (color: transparent) e continua sendo lido pelo leitor de tela.
   ------------------------------------------------------------------ */
.esqueleto {
  position: relative;
  display: inline-block;
  overflow: hidden;
  color: transparent !important;
  background: rgba(255, 255, 255, 0.06);
  border-radius: var(--pilula);
  user-select: none;
}

.esqueleto::after {
  content: '';
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg,
              rgba(255, 255, 255, 0) 0%,
              rgba(255, 255, 255, 0.09) 50%,
              rgba(255, 255, 255, 0) 100%);
  animation: esqueleto-brilho 1.4s ease-in-out infinite;
}

@keyframes esqueleto-brilho {
  to { transform: translateX(100%); }
}

.esqueleto--texto {
  min-height: 1em;
  width: 11em;
  max-width: 100%;
  vertical-align: middle;
}

.esqueleto--curto {
  width: 6em;
}

.esqueleto--linha {
  display: block;
  width: 100%;
  height: 12px;
}

.esqueleto--bloco {
  display: block;
  width: 100%;
  height: 64px;
  border-radius: var(--raio-caixa);
}

/* 10.4 Girador e barra de progresso — os nossos, nunca o do navegador. */
.girador {
  display: inline-block;
  flex: none;
  width: 16px;
  height: 16px;
  border: 2px solid rgba(255, 255, 255, 0.22);
  border-top-color: var(--texto);
  border-radius: 50%;
  animation: girar 0.7s linear infinite;
}

.girador--escuro {
  border-color: rgba(12, 12, 13, 0.25);
  border-top-color: var(--texto-invertido);
}

@keyframes girar {
  to { transform: rotate(360deg); }
}

.progresso {
  width: 100%;
  height: 4px;
  background: rgba(255, 255, 255, 0.10);
  border-radius: var(--pilula);
  overflow: hidden;
}

.progresso__barra {
  height: 100%;
  width: 0;
  background: var(--texto);
  border-radius: var(--pilula);
  transition: width 0.25s ease;
}

/* 10.5 Dica — a nossa tooltip, no lugar do atributo title.
   Uso: data-dica="texto" no elemento. O elemento PRECISA ter nome
   acessível próprio (texto visível ou aria-label): o ::after não é lido
   por leitor de tela. Não funciona em <input> (elemento substituído):
   nesse caso, envolva num <span data-dica>.
   ------------------------------------------------------------------ */
[data-dica] {
  position: relative;
}

[data-dica]::after {
  content: attr(data-dica);
  position: absolute;
  bottom: calc(100% + 9px);
  left: 50%;
  z-index: 40;
  width: max-content;
  max-width: 220px;
  padding: 7px 13px;
  font-size: 0.78rem;
  font-weight: 300;
  line-height: 1.45;
  color: var(--texto);
  text-align: center;
  white-space: normal;
  background: var(--flutuante-solido);
  border: 1px solid var(--borda);
  border-radius: var(--raio-item);
  box-shadow: var(--sombra-flutuante);
  opacity: 0;
  transform: translate(-50%, 4px);
  pointer-events: none;
  transition: opacity var(--transicao), transform var(--transicao);
}

[data-dica]:hover::after,
[data-dica]:focus-visible::after {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* Perto do topo da tela, a dica desce. */
[data-dica-lado='baixo']::after {
  bottom: auto;
  top: calc(100% + 9px);
  transform: translate(-50%, -4px);
}

[data-dica-lado='baixo']:hover::after,
[data-dica-lado='baixo']:focus-visible::after {
  transform: translate(-50%, 0);
}

/* 10.6 Diálogo — o substituto de alert(), confirm() e prompt().
   Markup:
     <div class="dialogo" id="x" role="dialog" aria-modal="true"
          aria-labelledby="x-titulo" aria-describedby="x-texto" hidden>
       <div class="dialogo__caixa">
         <h2 class="dialogo__titulo" id="x-titulo">Descartar as alterações?</h2>
         <p class="dialogo__texto" id="x-texto">O que você escreveu se perde.</p>
         <div class="dialogo__acoes">
           <button class="botao-contorno" type="button">Voltar</button>
           <button class="botao-primario botao-primario--compacto" type="button">Descartar</button>
         </div>
       </div>
     </div>

   Obrigações do JS de quem usar: guardar quem tinha o foco, focar o
   primeiro botão ao abrir, prender o Tab dentro da caixa, fechar no Esc
   e no clique no fundo, e devolver o foco ao abrir de onde veio.
   ------------------------------------------------------------------ */
.dialogo {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(0, 0, 0, 0.72);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.dialogo[hidden] {
  display: none;
}

.dialogo__caixa {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 100%;
  max-width: 420px;
  padding: 26px;
  background: var(--dialogo-solido);
  border: 1px solid var(--borda);
  border-radius: var(--raio-cartao);
  box-shadow: var(--sombra-flutuante);
}

.dialogo__titulo {
  margin: 0;
  font-size: 1.15rem;
  font-weight: 400;
  letter-spacing: -0.02em;
}

.dialogo__texto {
  margin: 0;
  font-size: 0.9rem;
  font-weight: 300;
  line-height: 1.6;
  color: var(--texto-2);
}

.dialogo__acoes {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 6px;
}

/* 10.7 Utilitários de texto que não cabe.
   .truncar exige min-width: 0 quando o pai é flex — já vem junto. */
.truncar {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.truncar-2 {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* 10.8 Arrastar: sem o realce azul de seleção enquanto se arrasta. */
.arrastando,
.arrastando * {
  user-select: none;
  cursor: grabbing;
}

/* --------------------------------------------------------------------------
   11. Ajustes de tela estreita
   -------------------------------------------------------------------------- */
@media (max-width: 720px) {
  .titulo {
    font-size: 1.9rem;
  }

  .titulo--grande {
    font-size: 2.1rem;
  }

  .barra {
    padding-right: 10px;
    border-radius: 28px;
  }

  .barra__acoes {
    gap: 12px;
  }

  .barra__usuario {
    max-width: 120px;
  }

  .rodape {
    padding: 18px var(--recuo) 22px;
  }

  .dialogo__caixa {
    padding: 22px;
  }

  .dialogo__acoes .botao-primario,
  .dialogo__acoes .botao-contorno {
    flex: 1 1 auto;
    justify-content: center;
  }
}

@media (max-width: 380px) {
  .barra__usuario {
    max-width: 92px;
  }
}

/* Quem prefere menos movimento não vê transição nenhuma. */
@media (prefers-reduced-motion: reduce) {
  * {
    transition: none !important;
    animation: none !important;
  }

  /* Sem animação, o brilho do esqueleto viraria uma faixa parada no lugar. */
  .esqueleto::after {
    display: none;
  }
}
