/* =====================================================================
   PORTA DE PROJETOS — folha de estilo unica, sem build.
   Ordem das secoes fixada pela spec de UI (secao 2.4) — a cascata depende da
   ordem abaixo, por isso nenhuma secao deve ser movida nem intercalada.

   ESTE ARQUIVO E SERVIDO SEM LOGIN (esta na lista PUBLICOS do server.js, porque
   a tela de login precisa dele). Sem build e sem minificacao, os comentarios
   viajam crus para o navegador: nada aqui pode nomear a organizacao nem citar
   caminho de arquivo interno. Vale para todo comentario novo tambem.

   01 tokens
   02 reset leve + base
   03 utilitarios de tipo
   04 barra do topo
   05 primitivos
   06 biblioteca      (Task 9)
   07 login
   08 admin           (Task 10)
   09 estados         (Task 9 + Task 10 — .esqueleto segue sem dono, ver nota abaixo)
   10 responsivo      (Task 9 + Task 10)
   ===================================================================== */

/* =====================================================================
   01 TOKENS
   Bloco colado literalmente da spec de UI §2.1 — hex e tamanhos ja
   verificados par a par contra WCAG naquele documento. Nao alterar aqui
   sem alterar a spec primeiro.
   ===================================================================== */
:root {
  color-scheme: light;

  /* ---------- SUPERFÍCIES ---------- */
  --bg:            #F5F5F5;   /* papel da página */
  --card:          #FFFFFF;   /* card, linha de tabela, modal */
  --card-hover:    #FAFDE6;   /* lavado de verde-limão: hover de card e de linha */
  --sunken:        #EDEEE9;   /* fundo da placa, trilhos, áreas recuadas */
  --ink:           #0D0E10;   /* barra do topo, anel de foco, texto forte */
  --ink-2:         #17181C;   /* fim do gradiente da barra */
  --ink-campo:     #1B1C1E;   /* campo de busca dentro da barra preta */

  /* ---------- MARCA ---------- */
  --brand:         #E5FF51;   /* verde-limão: botão primário, régua da placa */
  --brand-700:     #D0E84A;   /* hover do botão primário */
  --brand-800:     #A3B53A;   /* active do botão primário */
  --brand-ink:     #5C6B14;   /* verde LEGÍVEL para texto e ícone (5.9:1 no branco) */
  --brand-halo:    rgba(229, 255, 81, .55); /* halo externo do anel de foco */

  /* ---------- TEXTO ---------- */
  --texto:         #0D0E10;   /* 19.9:1 no branco — nome do link, títulos */
  --texto-2:       #4D4E52;   /*  8.3:1 no branco — descrição, rótulos de campo */
  --texto-3:       #6A6B6E;   /*  5.3:1 no branco — host, placeholder, metadados */
  --texto-claro:   #FFFFFF;   /* sobre --ink e sobre --erro sólido */
  --texto-barra:   rgba(255, 255, 255, .78); /* nav secundária na barra preta */

  /* ---------- LINHAS ---------- */
  --fio:           #ECECED;   /* hairline entre linhas de tabela (decorativo) */
  --borda:         #D6D6D7;   /* borda de card e de painel (decorativa) */
  --borda-campo:   #8B8D91;   /* borda de input/select/checkbox — 3.3:1, WCAG 1.4.11 */

  /* ---------- SINAIS ---------- */
  --erro:          #E84A4C;   /* barra de 3px e borda do bloco de erro */
  --erro-tinta:    #8C2D2E;   /* TEXTO de erro (7.4:1 sobre --erro-fundo) */
  --erro-fundo:    #FFEEEE;
  --erro-borda:    #F3C9C9;
  --espera:        #B57C3A;   /* barra do bloco de bloqueio (429) */
  --espera-tinta:  #8C602D;   /* TEXTO do bloqueio (5.2:1 sobre --espera-fundo) */
  --espera-fundo:  #FFF7EE;
  --espera-borda:  #F2D9B8;
  --ok-tinta:      #336B22;   /* confirmação (6.2:1 sobre --ok-fundo) */
  --ok-fundo:      #F2FFEE;
  --ok-borda:      #BFE6CC;

  /* ---------- TIPOGRAFIA ---------- */
  /* Font stack do sistema: sem rede, sem FOUT, sem CDN. Justificativa em §2.2. */
  --f-ui:     "Segoe UI Variable Text", "Segoe UI", -apple-system,
              BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  --f-titulo: "Segoe UI Variable Display", "Segoe UI Semibold", "Segoe UI",
              -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  --f-mono:   "Cascadia Mono", "Cascadia Code", ui-monospace, SFMono-Regular,
              "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

  --t-rotulo:   0.6875rem; /* 11px — mono-caps: categoria, host, pill, monograma */
  --t-mini:     0.75rem;   /* 12px — metadados, ajuda de campo, ações da tabela */
  --t-tabela:   0.8125rem; /* 13px — linhas da /admin */
  --t-corpo:    0.875rem;  /* 14px — corpo de UI, descrição do card, inputs */
  --t-card:     1rem;      /* 16px — nome do link: o que se lê em 4 segundos */
  --t-h2:       1.25rem;   /* 20px — título de tela e de modal */
  --t-h1:       1.625rem;  /* 26px — título do login */
  --t-contador: 2rem;      /* 32px — contador mono do bloqueio 429 */

  --p-normal: 400;
  --p-medio:  500;
  --p-forte:  600;
  --p-bold:   700;

  --lh-apertado: 1.15;  /* monograma, contador */
  --lh-titulo:   1.25;  /* nome do link, títulos */
  --lh-corpo:    1.5;   /* descrição, parágrafos */

  --tk-rotulo: .12em;   /* mono-caps espaçados */
  --tk-titulo: -.015em; /* títulos e nome do link */

  /* ---------- ESPAÇAMENTO (base 4px) ---------- */
  --e1: 4px;  --e2: 8px;  --e3: 12px; --e4: 16px;
  --e5: 20px; --e6: 24px; --e8: 32px; --e10: 40px; --e12: 48px;

  --largura-max: 1320px;
  --altura-barra: 60px;

  /* ---------- RAIO (nomeado por papel, não por tamanho) ---------- */
  --r-campo:  10px;  /* input, select, textarea, placa, botão de ícone */
  --r-card:   12px;  /* card de link, painel, bloco de mensagem */
  --r-painel: 16px;  /* modal, cartão de login */
  --r-pill:   999px; /* botões e pills — sem exceção */

  /* ---------- SOMBRA (tingida de --ink, nunca preto puro) ---------- */
  --sombra-1:     0 1px 2px rgba(13, 14, 16, .05);
  --sombra-2:     0 1px 2px rgba(13, 14, 16, .05), 0 6px 18px rgba(13, 14, 16, .07);
  --sombra-modal: 0 24px 60px rgba(13, 14, 16, .22);
  --sombra-barra: 0 1px 0 rgba(13, 14, 16, .10), 0 6px 16px rgba(13, 14, 16, .06);

  /* ---------- FOCO ---------- */
  /* Anel preto sobre superfície clara; anel verde-limão sobre a barra preta.
     O anel inverte com a superfície porque verde-limão sobre branco é 1.1:1. */
  --foco-claro:  0 0 0 2px var(--card), 0 0 0 5px var(--ink), 0 0 0 9px var(--brand-halo);
  --foco-escuro: 0 0 0 2px var(--ink),  0 0 0 5px var(--brand), 0 0 0 9px rgba(229,255,81,.25);

  /* ---------- MOVIMENTO ---------- */
  --dur-1: 120ms;
  --dur-2: 180ms;
  --ease: cubic-bezier(.2, .7, .3, 1);
}

@media (prefers-reduced-motion: reduce) {
  :root { --dur-1: 0ms; --dur-2: 0ms; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* =====================================================================
   02 RESET LEVE + BASE
   ===================================================================== */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
}

/* Reset leve: zera as margens que o UA aplica por padrao, para o espaco
   entre elementos vir sempre do `gap` do pai (spec §2.4), nunca de uma
   margem de navegador que ninguem declarou. */
body, h1, h2, p, fieldset, legend {
  margin: 0;
}
button, input, select, textarea {
  font: inherit;
  color: inherit;
}
ul {
  list-style: none;
  padding: 0;
}

body {
  min-height: 100dvh;
  font-family: var(--f-ui);
  font-size: var(--t-corpo);
  color: var(--texto);
  /* Assinatura de fundo da casa (spec §3.1): glow verde-limão + grade de pontos
     sobre o papel. Aparece em toda tela — nas telas com grade de cards a maior
     parte fica coberta pelos cards; e a intencao (Step 8 do brief). */
  background:
    radial-gradient(820px 420px at 92% -80px, rgba(229,255,81,.14), transparent 65%),
    radial-gradient(rgba(13,14,16,.045) 1px, transparent 1.4px),
    var(--bg);
  background-size: auto, 26px 26px, auto;
  /* Um valor unico valia para as tres camadas, e o glow ficava grudado na
     viewport: lia como mancha na tela em vez de luz na pagina. Os pontos
     seguem `fixed` de proposito -- e o que faz a camada repetida no
     `.categoria-titulo` sticky casar sem costura. */
  background-attachment: scroll, fixed, scroll;
}

::selection {
  background: var(--brand);
  color: var(--ink);
}

/* Anel preto sobre superficie clara é o padrao global; dentro da barra preta
   os papeis se invertem (selector verbatim da spec de UI §6). Nunca outline
   none sem substituto, e nunca :focus sem -visible (mouse nao pinta anel). */
:focus-visible {
  outline: none;
  box-shadow: var(--foco-claro);
}
.barra :focus-visible {
  box-shadow: var(--foco-escuro);
}

/* Padrao .sr-only: clip-path, nunca display:none — display:none tira o texto
   da arvore de acessibilidade tambem, nao so da tela. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* =====================================================================
   03 UTILITÁRIOS DE TIPO
   ===================================================================== */
.mono {
  font-family: var(--f-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

.rotulo {
  font-family: var(--f-mono);
  font-size: var(--t-rotulo);
  font-weight: var(--p-bold);
  letter-spacing: var(--tk-rotulo);
  text-transform: uppercase;
  line-height: var(--lh-apertado);
}

.titulo-tela {
  font-family: var(--f-titulo);
  font-size: var(--t-h2);
  font-weight: var(--p-forte);
  letter-spacing: var(--tk-titulo);
  color: var(--texto);
  line-height: var(--lh-titulo);
}

/* =====================================================================
   04 BARRA DO TOPO
   Consumida pelas Tasks 9 e 10 (public/barra.js); as classes ja existem
   aqui para a cascata seguir a ordem fixada mesmo antes do HTML existir.
   ===================================================================== */
.barra {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: var(--e6);
  height: var(--altura-barra);
  padding: 0 var(--e8);
  background: linear-gradient(180deg, var(--ink), var(--ink-2));
  box-shadow: var(--sombra-barra);
}

.marca {
  display: flex;
  align-items: center;
  gap: var(--e2);
  flex: 0 0 auto;
  text-decoration: none;
  color: var(--texto-claro);
}
.marca-nomes {
  display: flex;
  flex-direction: column;
  line-height: var(--lh-apertado);
}
.marca-nome {
  font-family: var(--f-titulo);
  font-size: var(--t-corpo);
  font-weight: var(--p-forte);
  color: var(--texto-claro);
}
.marca-org {
  color: var(--brand);
}

.placa.placa-marca {
  /* Classe DOBRADA de proposito. `barra.js` monta class="placa placa-marca", e
     `.placa-marca` mora nesta secao (04), ~190 linhas ANTES de `.placa` (secao
     05). As duas empatam em especificidade, entao quem vencia era `.placa`, por
     ordem de fonte: a marca da barra renderizava 40x40, raio 10, fundo --sunken
     e texto --ink -- uma pastilha CLARA de 40px dentro da barra preta de 60px,
     e nao a placa de 28px com letra lima que a §4.2 desenha. Medido por
     getComputedStyle, nao deduzido. Dobrar a classe corrige sem mover secao. */
  width: 28px;
  height: 28px;
  border-radius: 8px;
  background: rgba(255, 255, 255, .07);
  color: var(--brand);
  font-size: 10px;
}
.placa.placa-marca::before {
  top: 4px;
  bottom: 4px;
  width: 2px;
}

.busca {
  position: relative;
  display: flex;
  align-items: center;
  flex: 1 1 auto;
  max-width: 420px;
}
.busca-campo {
  width: 100%;
  height: 40px;
  padding: 0 var(--e8) 0 var(--e3);
  /* Reconciliado na Task 9: rgba(255,255,255,.16) (estimativa da Task 8) media
     so 1.64:1 contra --ink-campo — abaixo do piso de 3:1 do WCAG 1.4.11 para
     borda funcional. --borda-campo (ja catalogado em §2.3 contra #FFFFFF) da
     5.13:1 aqui, contra #1B1C1E — reaproveita o token existente, sem inventar
     valor novo. */
  border: 1px solid var(--borda-campo);
  border-radius: var(--r-campo);
  background: var(--ink-campo);
  color: var(--texto-claro);
  font-family: var(--f-ui);
  font-size: var(--t-corpo);
}
.busca-campo::placeholder {
  color: rgba(255, 255, 255, .66);
}
.busca-dica {
  position: absolute;
  top: 50%;
  right: var(--e3);
  transform: translateY(-50%);
  color: var(--texto-barra);
  font-family: var(--f-mono);
  font-size: var(--t-mini);
}

.nav-barra {
  display: flex;
  align-items: center;
  gap: var(--e5);
  margin-left: auto;
}
.nav-item {
  display: inline-flex;
  align-items: center;
  height: 100%;
  color: var(--texto-barra);
  text-decoration: none;
  font-size: var(--t-corpo);
  font-weight: var(--p-medio);
  border-bottom: 2px solid transparent;
}
.nav-ativo {
  color: var(--texto-claro);
  border-bottom-color: var(--brand);
}
/* Reconciliado na Task 9: barra.js usa um <button> para "Sair" (precisa ser
   button, nao <a>, porque a acao e assincrona antes de navegar). .nav-item so
   zera border-bottom; um <button> sem isto herda o chrome do UA (fundo cinza,
   borda nos outros 3 lados). Zera so o que falta, sem depender da ordem das
   regras no arquivo. */
.nav-sair {
  background: none;
  border-width: 0 0 2px;
  border-style: solid;
  border-color: transparent;
  padding: 0;
  cursor: pointer;
}

/* =====================================================================
   05 PRIMITIVOS
   ===================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--e2);
  height: 44px;
  padding: 0 var(--e5);
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  font-family: var(--f-ui);
  font-size: var(--t-corpo);
  font-weight: var(--p-forte);
  cursor: pointer;
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease),
              border-color var(--dur-1) var(--ease), transform var(--dur-1) var(--ease);
}
.btn:disabled {
  cursor: not-allowed;
}

.btn-primario {
  background: var(--brand);
  color: var(--ink);
}
.btn-primario:hover {
  background: var(--brand-700);
}
.btn-primario:active {
  background: var(--brand-800);
}
.btn-primario:disabled {
  background: var(--sunken);
  color: var(--texto-3);
  border-color: var(--borda-campo);
}

.btn-secundario {
  background: transparent;
  color: var(--texto);
  border-color: var(--borda);
}
.btn-secundario:hover {
  background: var(--sunken);
}

/* Reconciliado na Task 10: confirmacao destrutiva inline (§3.3 admin) precisa
   de um botao SOLIDO de perigo, que a spec de UI nao desenha explicitamente.
   --erro (a cor de borda/barra de erro) so da 4.11:1 com texto branco — abaixo
   de 4.5:1 para texto normal. --erro-tinta (o par ja vetado em §2.3 para TEXTO
   de erro, 7.4:1 no fundo claro) da 8.3:1 com --texto-claro por cima: reusa um
   token ja calculado em vez de inventar hex novo, e passa AAA. */
.btn-perigo-solido {
  background: var(--erro-tinta);
  color: var(--texto-claro);
}
.btn-perigo-solido:hover {
  opacity: .88;
}

.pill {
  display: inline-flex;
  align-items: center;
  gap: var(--e1);
  padding: 2px 8px;
  border-radius: var(--r-pill);
  font-family: var(--f-mono);
  font-size: 10px;
  font-weight: var(--p-bold);
  letter-spacing: .1em;
  text-transform: uppercase;
  line-height: 1.4;
}

.campo-rotulo {
  display: block;
  font-family: var(--f-ui);
  font-size: var(--t-mini);
  font-weight: var(--p-forte);
  color: var(--texto-2);
}

.campo {
  display: block;
  width: 100%;
  height: 44px;
  padding: 0 var(--e3);
  border: 1px solid var(--borda-campo);
  border-radius: var(--r-campo);
  background: var(--card);
  color: var(--texto);
  font-family: var(--f-ui);
  font-size: var(--t-corpo);
}
.campo::placeholder {
  color: var(--texto-3);
}
.campo[aria-invalid="true"] {
  border-color: var(--erro);
}

/* A placa: elemento-assinatura do portal, em 4 escalas (spec §4.2). Bloco
   base colado literalmente; as variantes de tamanho ficam logo abaixo. */
.placa {
  position: relative;
  flex: 0 0 auto;
  width: 40px; height: 40px;
  border-radius: var(--r-campo);
  background: var(--sunken);
  overflow: hidden;
  display: grid; place-items: center;
  font-family: var(--f-mono);
  /* 12px e o valor da tabela da §4.2; o CSS herdou --t-rotulo (11px) por
     descuido. `.placa-g` (17px) e `.placa-p` (10px) declaram o proprio e vem
     depois nesta folha, entao nao mudam. */
  font-size: 0.75rem;
  font-weight: var(--p-bold);
  letter-spacing: .01em;
  color: var(--texto);
  /* --sunken sobre --card sao ~3% de luminancia: sem contorno a chapa lia como
     mancha, nao como objeto, e a "placa" virava um tique lima ao lado de duas
     letras cinzas. A placa e aria-hidden -- ornamento puro -- entao isto nao e
     borda funcional e o WCAG 1.4.11 nao se aplica. */
  box-shadow: inset 0 0 0 1px rgba(13, 14, 16, .07);
}
.placa::before {                 /* a régua: assinatura da casa, em dose de 3px */
  content: "";
  /* De ARESTA A ARESTA, nao recuada. A metafora declarada e "chapa com a aresta
     pintada"; com recuo de 6px em cima e embaixo o que se via era um traco curto
     flutuando ao lado do monograma. O `overflow: hidden` da .placa ja recorta a
     barra na curva do canto, e e esse recorte que faz a peca ler como placa --
     por isso o border-radius vai a zero aqui em vez de arredondar a ponta.
     A LARGURA fica nos 3px da tabela da spec §4.2: a recomendacao do agente de
     UI era 4px, mas ir a aresta ja aumenta a massa visual, e mudar as duas
     coisas de uma vez deixaria de ser conformidade e passaria a ser redesenho. */
  position: absolute; left: 0; top: 0; bottom: 0;
  width: 3px; border-radius: 0;
  background: var(--brand);
}
.campo[type="number"] { max-width: 6rem; }   /* 44px de altura por 2 digitos era desproporcional */
.placa-emoji { font-size: 19px; line-height: 1; }   /* emoji não usa a fonte mono */

.placa-g {
  width: 56px;
  height: 56px;
  border-radius: 14px;
  font-size: 17px;
}
.placa-g::before {  /* 4px na tabela da §4.2; aresta a aresta como a base */
  top: 0;
  bottom: 0;
  width: 4px;
}

.bloco-msg {
  display: flex;
  flex-direction: column;
  gap: var(--e1);
  position: relative;
  padding: var(--e3) var(--e4) var(--e3) calc(var(--e4) + var(--e1));
  border: 1px solid;
  border-radius: var(--r-card);
  font-size: var(--t-tabela); /* 13px — o valor que a spec de UI §3.1 anota para erro/espera */
  line-height: var(--lh-corpo);
}
.bloco-msg::before {
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 3px;
  border-radius: var(--r-card) 0 0 var(--r-card);
}
.bloco-erro {
  background: var(--erro-fundo);
  border-color: var(--erro-borda);
  color: var(--erro-tinta);
}
.bloco-erro::before { background: var(--erro); }

.bloco-espera {
  background: var(--espera-fundo);
  border-color: var(--espera-borda);
  color: var(--espera-tinta);
}
.bloco-espera::before { background: var(--espera); }

.bloco-ok {
  background: var(--ok-fundo);
  border-color: var(--ok-borda);
  color: var(--ok-tinta);
}
.bloco-ok::before { background: var(--ok-tinta); }

/* =====================================================================
   06 BIBLIOTECA
   Grade de cards por categoria (spec de UI §3.2 e §4). Cada categoria vira
   uma <section> com <h2> sticky, lendo --altura-barra — a mesma variavel que
   a secao 10 redefine em telas estreitas, entao o numero nunca se repete.
   ===================================================================== */
/* Reconciliado na Task 10: a /admin empilha h1 + .abas + .painel como irmaos
   diretos de .conteudo (a /login e a biblioteca so tem UM filho visivel — o
   h1 e o p de status ali sao .sr-only, fora do fluxo). display:flex + gap
   aqui e o que da esse espacamento sem violar a regra "gap do pai, nunca
   margin do filho" (§2.4); nao afeta as outras duas telas. */
.conteudo {
  display: flex;
  flex-direction: column;
  gap: var(--e6);
  max-width: var(--largura-max);
  margin: 0 auto;
  padding: var(--e8);
}

/* #lista e o container que app.js preenche com um .categoria por vez; o gap
   entre categorias vem daqui (regra §2.4: espaco entre irmaos vem do gap do
   pai, nunca de margin do filho). */
.lista {
  display: flex;
  flex-direction: column;
  gap: var(--e8);
}

.categoria {
  display: flex;
  flex-direction: column;
  gap: var(--e4);
}

.categoria-titulo {
  display: flex;
  align-items: center;
  gap: var(--e2);
  position: sticky;
  top: var(--altura-barra);
  z-index: 10;
  padding: var(--e2) 0;
  /* Repete a camada de pontos do body com o MESMO `fixed`: as duas se alinham no
     mesmo referencial e a costura desaparece. Sem isto, o fundo opaco apagava os
     pontos numa faixa que viajava com o scroll -- defeito que so aparece com
     links suficientes para rolar. */
  background:
    radial-gradient(rgba(13, 14, 16, .045) 1px, transparent 1.4px) 0 0 / 26px 26px fixed,
    var(--bg);
  color: var(--texto-3);
}
/* A pontuacao "····" e uma LINHA, nunca caracteres: flex:1 + border-bottom
   ocupa o resto da largura entre o nome da categoria e o contador (§3.2). */
.categoria-fio {
  flex: 1 1 auto;
  border-bottom: 1px dotted var(--borda);
}

.grade {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(252px, 1fr));
  align-items: stretch; /* cards da mesma fileira ficam com a mesma altura (§5.4) */
  gap: var(--e3);
}

/* Geometria e estados do card — bloco colado de §4.5, com height:100% somado:
   e o que faz o align-items:stretch da grade valer de fato dentro do <li>
   (senao o card fica na altura do proprio conteudo, nao na da fileira). */
.card {
  display: flex; flex-direction: column; gap: var(--e2);
  min-height: 148px;
  height: 100%;
  padding: var(--e4);
  background: var(--card);
  border: 1px solid var(--borda);
  border-radius: var(--r-card);
  box-shadow: var(--sombra-1);
  text-decoration: none;
  transition: background var(--dur-1) var(--ease),
              border-color var(--dur-1) var(--ease),
              box-shadow var(--dur-1) var(--ease),
              transform var(--dur-1) var(--ease);
}

.card-topo {
  display: flex;
  align-items: flex-start;
  gap: var(--e2);
}
/* A arvore de nos (§4.4) e sempre placa -> pill? -> seta, plana, sem wrapper.
   Para o pill (quando existe) e a seta ficarem colados no canto direito com a
   placa sozinha a esquerda, o elemento que vier logo apos a placa recebe este
   empurrao — app.js decide qual e (o pill quando ele existe, senao a propria
   seta). Modificador na mesma logica de .card.card-restrito (regra §2.4),
   so que aplicado via classList em vez de fixo na classe base. */
.card-ancora-direita {
  margin-left: auto;
}
/* "A seta desce 2px e fica ao lado" do pill (§4.6) — so quando o pill existe,
   porque so entao a seta perde o alinhamento com o topo da placa. */
.card-seta-desce {
  margin-top: 2px;
}

.card-seta {
  font-size: 13px; /* valor literal da tabela §4.4 — nenhum --t-* nomeia este papel */
  color: var(--texto-3);
  opacity: .45;
  transition: opacity var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}

.card-nome, .card-desc {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  overflow-wrap: anywhere;
  hyphens: auto;
}
.card-nome {
  font-family: var(--f-titulo);
  font-size: var(--t-card);
  font-weight: var(--p-forte);
  letter-spacing: var(--tk-titulo);
  color: var(--texto);
  line-height: var(--lh-titulo);
}
.card-desc {
  font-family: var(--f-ui);
  font-size: var(--t-corpo);
  color: var(--texto-2);
  line-height: var(--lh-corpo);
}

/* Host cola na base: com nome de 1 ou 2 linhas e descricao presente ou
   ausente, o endereco fica sempre no mesmo lugar em toda a fileira (§4.5).
   Font-family/tabular-nums vem de .mono (ja aplicada junto no HTML). */
.card-host {
  margin-top: auto;
  font-size: var(--t-rotulo);
  font-weight: var(--p-medio);
  letter-spacing: .02em;
  color: var(--texto-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Sinalizacao de somente_admin — colada literalmente de §4.6.
   Excecao DECLARADA a disciplina de classe unica da §2.4 (ruling do
   coordenador na revisao da Task 9): a §4.6 fornece este seletor descendente
   por escrito, e o caso e legitimo — um estado (.card-restrito) no elemento
   PAI precisa alcancar um filho (.placa) que nao tem estado proprio. Uma
   ponte via custom property trocaria um combinador simples por indirecao;
   nao vale a pena so para manter a regra literal. Nao remova. */
.card-restrito .placa::before { background: var(--ink); }
.pill-restrito {
  font-family: var(--f-mono); font-size: 10px; font-weight: var(--p-bold);
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--texto-claro); background: var(--ink);
  padding: 2px 8px; border-radius: var(--r-pill);
}

/* Toque nao fica com :hover grudado (ultima linha da tabela de estados, §4.5). */
@media (hover: hover) {
  .card:hover {
    background: var(--card-hover);
    border-color: #C9CFA8;
    box-shadow: var(--sombra-2);
    transform: translateY(-1px);
  }
  /* Excecao DECLARADA a disciplina de classe unica da §2.4 (mesmo ruling do
     coordenador citado acima em .card-restrito .placa::before): :hover no PAI
     precisa alcancar a seta, que nao tem estado proprio. Nao remova. */
  .card:hover .card-seta {
    opacity: 1;
    color: var(--brand-ink);
  }
}
/* Repete o :focus-visible global (secao 02) aqui, depois do :hover no arquivo,
   para o anel vencer por ordem de fonte quando as duas coincidem (mouse sobre
   um card com foco de teclado) — as duas regras empatam em especificidade. */
.card:focus-visible {
  outline: none;
  box-shadow: var(--foco-claro);
}
.card:active {
  transform: translateY(0);
  box-shadow: var(--sombra-1);
}

/* =====================================================================
   07 LOGIN
   ===================================================================== */
.login-wrapper {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--e4);
  min-height: 100dvh;
  /* O cartao fica no centro optico (~42% da altura), nao no centro geometrico.
     Antes era `padding-top: 12vh` fixo, que nao acompanha a viewport: medido
     38,1% em 804px de altura, fora dos 42% que este comentario prometia.
     Centrar com vies no rodape acerta em qualquer altura. `min-height`, nunca
     `height`: mantem o scroll em tela curta e em zoom 200%. 100vh nunca -- no
     iOS a barra de endereco corta o rodape. */
  padding: var(--e8) var(--e4) 19vh;
}

.login-cartao {
  display: flex;
  flex-direction: column;
  gap: var(--e4);
  width: 380px;
  max-width: 100%;
  padding: var(--e8);
  background: var(--card);
  border: 1px solid var(--borda);
  border-radius: var(--r-painel);
  box-shadow: var(--sombra-2);
}

.login-titulo {
  font-family: var(--f-titulo);
  font-size: var(--t-h1);
  font-weight: var(--p-forte);
  letter-spacing: var(--tk-titulo);
  color: var(--texto);
  line-height: var(--lh-titulo);
}

.login-sub {
  font-family: var(--f-ui);
  font-size: var(--t-corpo);
  color: var(--texto-2);
  line-height: var(--lh-corpo);
}

.login-form {
  display: flex;
  flex-direction: column;
  gap: var(--e2);
  width: 100%;
}

.login-btn {
  width: 100%;
}

.bloco-contador {
  font-size: var(--t-contador);
  font-weight: var(--p-bold);
  line-height: var(--lh-apertado);
}

.login-ajuda {
  font-family: var(--f-ui);
  font-size: var(--t-mini);
  color: var(--texto-2);
  text-align: center;
}

/* =====================================================================
   08 ADMIN (spec de UI §3.3, §4.6 para o pill "so admin" e §5.7 para o toast
   — este ultimo fica na secao 09 por ser o numero que a tabela de secoes de
   §2.4 atribui a ele; ver nota la).
   ===================================================================== */
.painel {
  display: flex;
  flex-direction: column;
  gap: var(--e4);
}

.abas {
  display: flex;
  gap: var(--e5);
  border-bottom: 1px solid var(--borda);
}
.aba {
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px; /* fica por cima do fio do .abas, sem dobrar a linha */
  padding: var(--e2) var(--e1) var(--e3);
  font-family: var(--f-ui);
  font-size: var(--t-corpo);
  font-weight: var(--p-medio);
  color: var(--texto-2);
  cursor: pointer;
}
.aba-ativa {
  color: var(--texto);
  border-bottom-color: var(--brand);
}

.ferramentas {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--e4);
}
.ferramentas-busca {
  flex: 0 1 320px;
}
/* Empurra a si mesma (e tudo que vem depois, aqui so o botao) para a ponta
   direita — a busca fica ancorada a esquerda sem precisar de mais nada. */
.ferramentas-arquivados {
  margin-left: auto;
}
.ferramentas-espaco {
  flex: 1 1 auto;
}

.grupo {
  display: flex;
  flex-direction: column;
  background: var(--card);
  border: 1px solid var(--borda);
  border-radius: var(--r-card);
  overflow: hidden;
}

.linha {
  display: flex;
  align-items: center;
  gap: var(--e3);
  min-height: 44px;
  padding: var(--e2) var(--e4);
  border-bottom: 1px solid var(--fio);
  transition: background var(--dur-1) var(--ease);
}
.linha:last-child {
  border-bottom: none;
}
@media (hover: hover) {
  .linha:hover {
    background: var(--card-hover);
  }
}

/* 32×32 · r 8 · regua 2px (spec §4.2, "Linha da /admin"): valores literais da
   tabela de escalas, como ja reconciliado na Task 8/9 para .placa-marca — nao
   ha token --r-8 no catalogo e forcar --r-campo (10px) mentiria o tamanho. */
.placa-p {
  width: 32px;
  height: 32px;
  border-radius: 8px;
  font-size: 10px;
}
.placa-p::before {
  top: 0;
  bottom: 0;
  width: 2px;
}

.linha-identidade {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1 1 auto;
  min-width: 0;
}
.linha-nome {
  font-family: var(--f-ui);
  font-size: var(--t-tabela);
  font-weight: var(--p-forte);
  color: var(--texto);
}
.linha-host {
  font-size: var(--t-rotulo);
  color: var(--texto-3);
}
.linha-host-riscado {
  text-decoration: line-through;
}
.linha-voce {
  font-family: var(--f-ui);
  font-weight: var(--p-normal);
  font-size: var(--t-mini);
  color: var(--texto-3);
}

.linha-visibilidade,
.linha-papel {
  flex: 0 0 96px;
}
.linha-todos {
  font-size: var(--t-tabela);
  color: var(--texto-2);
}
.linha-status {
  flex: 0 0 84px;
  font-size: var(--t-tabela);
  color: var(--texto-2);
}

/* Coluna de ordem discreta: sem borda ate hover/focus (spec §3.3), pensada
   para editar direto sem abrir o modal. */
.linha-ordem {
  flex: 0 0 56px;
  height: 32px;
  padding: 0 var(--e2);
  border: 1px solid transparent;
  border-radius: var(--r-campo);
  background: transparent;
  color: var(--texto-2);
  font-size: var(--t-tabela);
  text-align: center;
  transition: border-color var(--dur-1) var(--ease), background var(--dur-1) var(--ease);
}
.linha-ordem:hover,
.linha-ordem:focus-visible {
  border-color: var(--borda-campo);
  background: var(--card);
}

.linha-acoes {
  /* Era `0 0 168px`: os tres botoes de texto da aba Usuarios ("Definir senha",
     "Promover a admin", "Desativar") nao cabem em 168px, a coluna quebrava e a
     linha ficava 88px contra 49px da vizinha -- lia como bug, nao como decisao.
     O `flex: 1 1 100%` da media query de 900px continua vencendo no celular. */
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  align-items: center;
  gap: var(--e2);
}

.btn-icone {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: none;
  border-radius: var(--r-campo);
  background: none;
  color: var(--texto-2);
  font-size: var(--t-corpo);
  cursor: pointer;
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.btn-icone:hover {
  background: var(--sunken);
  color: var(--texto);
}
.btn-icone:disabled {
  color: var(--texto-3);
  opacity: .45;
  cursor: not-allowed;
}

.btn-texto {
  background: none;
  border: none;
  padding: 0;
  height: 32px;
  color: var(--texto-2);
  font-family: var(--f-ui);
  font-size: var(--t-mini);
  font-weight: var(--p-forte);
  cursor: pointer;
}
.btn-texto:hover {
  color: var(--texto);
  text-decoration: underline;
}
.btn-perigo {
  color: var(--erro-tinta);
}

/* Linha arquivada: opacidade + host riscado (a classe fica no proprio filho,
   ver .linha-host-riscado acima). */
.linha-arquivada {
  opacity: .55;
}

/* Realce de 600ms apos reordenar (spec §3.3/§6 "Movimento"). O bloco global de
   prefers-reduced-motion (secao 01) ja neutraliza animation-duration para
   TODO seletor — nao precisa de uma segunda regra aqui. */
.linha-realce {
  animation: destaque-linha 600ms var(--ease);
}
@keyframes destaque-linha {
  from { background: var(--card-hover); }
  to { background: transparent; }
}

/* Confirmacao destrutiva substitui o conteudo da linha (§3.3): o proprio
   .linha ja e flex com gap, entao pergunta + 2 botoes se alinham sem CSS
   extra alem do tingido de fundo. Escrita DEPOIS de .linha:hover no arquivo
   para vencer por ordem de fonte quando as duas coincidem (mesma tecnica
   ja usada em .card:focus-visible na secao 06). */
.linha-confirmando {
  background: var(--erro-fundo);
}
.linha-pergunta {
  color: var(--erro-tinta);
  font-size: var(--t-tabela);
}

.pill-admin {
  background: var(--brand);
  color: var(--ink);
}
.pill-equipe {
  background: var(--sunken);
  color: var(--texto-2);
}

/* Checkbox/radio nativos, so com a cor da casa no lugar do azul padrao do
   navegador — sem isso o unico controle azul da tela destoaria do resto
   da paleta (preto/verde-limao). */
.selecao {
  width: 16px;
  height: 16px;
  accent-color: var(--ink);
  cursor: pointer;
}
.checkbox,
.radio {
  display: inline-flex;
  align-items: center;
  gap: var(--e2);
  font-family: var(--f-ui);
  font-size: var(--t-corpo);
  color: var(--texto-2);
  cursor: pointer;
}

.modal {
  width: 520px;
  max-width: calc(100vw - 32px);
  max-height: calc(100vh - 64px);
  padding: 0;
  border: none;
  border-radius: var(--r-painel);
  background: var(--card);
  color: var(--texto);
  box-shadow: var(--sombra-modal);
}
/* Mesmo tingido de --ink usado nas sombras da casa (secao 01), aqui como
   veu por tras do modal — nao e um token a parte, e --ink com alpha. */
.modal::backdrop {
  background: rgba(13, 14, 16, .5);
}

.modal-form {
  display: flex;
  flex-direction: column;
  gap: var(--e4);
  padding: var(--e6);
  max-height: calc(100vh - 64px);
  overflow-y: auto;
}
.modal-topo {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.modal-titulo {
  font-family: var(--f-titulo);
  font-size: var(--t-h2);
  font-weight: var(--p-forte);
  letter-spacing: var(--tk-titulo);
  color: var(--texto);
}
/* .modal-campo tambem e usado num <fieldset> (visibilidade "Quem ve"): zera o
   chrome nativo de fieldset, inofensivo nos outros usos (que ja sao <div>). */
.modal-campo {
  display: flex;
  flex-direction: column;
  gap: var(--e1);
  border: 0;
  padding: 0;
}
.modal-linha {
  display: flex;
  gap: var(--e4);
  align-items: flex-end;
}
/* Modificador so do campo "Nome" dentro de .modal-linha: cresce para dividir
   a linha com a previa de largura fixa (§2.4 — classe unica, sem seletor
   descendente para diferenciar este .modal-campo dos demais). */
.modal-campo-cresce {
  flex: 1 1 auto;
}
.modal-previa {
  flex: 0 0 64px;
  display: flex;
  flex-direction: column;
  gap: var(--e1);
  align-items: flex-start;
}
.campo-ajuda {
  font-family: var(--f-ui);
  font-size: var(--t-mini);
  color: var(--texto-2);
}
.campo-ajuda-erro {
  color: var(--erro-tinta);
}
.modal-rodape {
  display: flex;
  justify-content: flex-end;
  gap: var(--e3);
  padding-top: var(--e2);
  border-top: 1px solid var(--borda);
}

/* =====================================================================
   09 ESTADOS
   .vazio cobre os dois estados vazios da biblioteca (banco recem-criado §5.1
   e busca sem resultado §5.2); .skip e o skip-link do topo da pagina.
   .toast implementado na Task 10 (unico consumidor: public/admin.js — a spec
   de UI §5.7 e explicita que e "so para confirmacao de acao na /admin").
   .esqueleto (carregamento, §5.6) segue SEM DONO: nem a Task 9 nem a Task 10
   o pediram em brief algum, e nenhuma das duas telas troca o "vazio" por um
   fantasma de carregamento — as duas so alternam aria-busy, sem nada visual
   (mesmo padrao das duas, decisao consistente; ver raciocinio completo no
   relatorio da Task 10). Se algum dia for feito, cabe aqui.
   ===================================================================== */
.vazio {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--e3);
  padding: var(--e8);
  background: var(--card);
  border: 1px dashed var(--borda-campo);
  border-radius: var(--r-card);
}
/* Variante com a placa "+" (banco vazio, §5.1): vira linha, placa a esquerda e
   texto empilhado ao lado — diferente do padrao acima (centralizado em
   coluna), que serve a busca sem resultado, sem placa nenhuma (§5.2). */
.vazio-com-icone {
  flex-direction: row;
  align-items: flex-start;
  text-align: left;
  gap: var(--e6);
}
.vazio-texto {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--e3);
}

.vazio-titulo {
  font-family: var(--f-titulo);
  font-size: var(--t-h2);
  font-weight: var(--p-forte);
  color: var(--texto);
  line-height: var(--lh-titulo);
}
.vazio-corpo {
  font-family: var(--f-ui);
  font-size: var(--t-corpo);
  color: var(--texto-2);
  line-height: var(--lh-corpo);
}

/* Toast (spec §5.7): fundo --card, barra esquerda 3px, --sombra-modal, some em
   4s (o tempo e controlado por admin.js). toast-erro e uma extensao pratica —
   a spec so descreve o "ok", mas admin.js tambem usa o mesmo componente para
   erro de acao (§ "Aviso sobre o codigo do brief" nao se aplica aqui, e uma
   decisao de implementacao, nao um bug do brief). */
.toast {
  position: fixed;
  right: var(--e6);
  bottom: var(--e6);
  z-index: 60;
  display: flex;
  align-items: center;
  gap: var(--e2);
  max-width: 360px;
  padding: var(--e3) var(--e4) var(--e3) calc(var(--e4) + var(--e1));
  border-radius: var(--r-card);
  background: var(--card);
  color: var(--texto);
  box-shadow: var(--sombra-modal);
  font-family: var(--f-ui);
  font-size: var(--t-corpo);

  /* Escondido por OPACITY, nunca por [hidden]/display:none/visibility:hidden —
     esses tres tiram o no da arvore de acessibilidade junto com a tela, e o
     role="status" so anuncia MUDANCA de conteudo numa regiao que ja esteja na
     arvore. Com display:none o texto era escrito fora da arvore e a regiao
     entrava nela ja pronta: nenhuma mudanca, nenhum anuncio, e toda confirmacao
     da /admin saia muda no leitor de tela (WCAG 4.1.3).
     pointer-events impede a caixa invisivel de roubar o clique do canto. */
  opacity: 0;
  pointer-events: none;
  transform: translateY(var(--e2));
  transition: opacity var(--dur-1) var(--ease), transform var(--dur-1) var(--ease);
}
.toast-visivel {
  opacity: 1;
  pointer-events: auto;
  transform: none;
}
.toast::before {
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 3px;
  border-radius: var(--r-card) 0 0 var(--r-card);
  background: var(--ok-tinta);
}
.toast-erro::before {
  background: var(--erro);
}
/* NAO volte a esconder o toast com o atributo `hidden`. Duas armadilhas, nesta
   ordem: (1) [hidden] e regra de USER AGENT, e o `display: flex` de autor acima
   vence qualquer regra de user-agent (a origem decide antes da especificidade),
   entao o toast apareceria mesmo com o atributo presente — foi o que se mediu no
   admin.html, onde a classe e o atributo conviviam desde o carregamento;
   (2) consertar isso com `.toast[hidden] { display: none }` funciona na tela e
   quebra o anuncio, porque tira a regiao live da arvore de acessibilidade. As
   duas juntas sao o motivo de o estado escondido morar em `opacity` la acima. */

/* Skip link: fora da tela ate receber foco de teclado. Nunca display:none —
   isso tiraria o link da arvore de tabulacao tambem, nao so da tela (§2, §6). */
.skip {
  position: absolute;
  top: var(--e2);
  left: -9999px;
  z-index: 100;
  padding: var(--e2) var(--e4);
  background: var(--ink);
  color: var(--texto-claro);
  border-radius: var(--r-campo);
  text-decoration: none;
  font-weight: var(--p-forte);
}
.skip:focus-visible {
  left: var(--e2);
}

/* =====================================================================
   10 RESPONSIVO
   Duas media queries, nesta ordem (900px primeiro, 560px depois: quando as
   duas se aplicam ao mesmo tempo, a de 560px precisa vir por ULTIMO no
   arquivo para vencer o empate de especificidade nas propriedades em comum,
   como .conteudo).
   ===================================================================== */
@media (max-width: 900px) {
  /* Atalho de teclado em tela sem teclado e affordance fantasma. O glifo ja e
     aria-hidden, entao sumir com ele nao tira nada de leitor de tela. */
  .busca-dica { display: none; }

  /* Redefinida SO aqui: .barra (altura) e .categoria-titulo (top do sticky)
     leem a MESMA variavel — o numero nunca se repete em dois lugares. */
  :root { --altura-barra: 104px; }

  .barra {
    flex-wrap: wrap;
    gap: var(--e2) var(--e4);
    padding: var(--e3) var(--e5);
  }
  /* Duas linhas: (marca + nav) na primeira, busca full-width na segunda —
     via `order`, sem mudar a ordem real do DOM que barra.js monta. */
  .marca { order: 1; }
  .nav-barra { order: 2; }
  .busca {
    order: 3;
    flex: 1 1 100%;
    max-width: none;
  }

  .conteudo { padding: var(--e5); }

  /* /admin (spec §3.3): a linha da tabela vira cartao empilhado — nome+host
     no topo (via order, a identidade ja e o primeiro filho no DOM tambem),
     metadados numa faixa e as acoes por ultimo, com alvo de toque de 44px. */
  .linha {
    flex-wrap: wrap;
    row-gap: var(--e2);
  }
  .linha-identidade { flex: 1 1 100%; order: 1; }
  .placa-p { order: 0; }
  .linha-visibilidade, .linha-papel, .linha-status, .linha-ordem { order: 2; }
  .linha-acoes { order: 3; flex: 1 1 100%; }
  /* Sem seletor descendente (§2.4): .btn-icone e .btn-texto so existem dentro
     da /admin (setas de ordem, acoes de linha, fechar do modal), entao crescer
     os dois direto, sem escopar em .linha-acoes, ja cobre exatamente o que
     precisa e nao pede uma exceçao. */
  .btn-icone,
  .btn-texto {
    min-height: 44px;
  }
}

@media (max-width: 560px) {
  .conteudo { padding: var(--e4); }
  /* Marca so com a PLACA. A regra anterior escondia so `.marca-org` (a segunda
     linha), apoiada no argumento de que "a parte que sobra tem de carregar o
     nome" -- verdadeiro sob o nome ANTERIOR do produto, cuja primeira linha era
     palavra inteira. A renomeacao de 17/08 quebrou a premissa sem ninguem
     notar: sobrava "Porta", que em portugues e outra palavra e le como
     truncamento.
     Uma placa sem legenda e uma marca; meia palavra e erro de digitacao.
     O <a> inteiro continua sendo lido por leitor de tela (§3.2). */
  .marca-nomes { display: none; }

  /* Refinamento do cartao de login (§3.1) que a Task 8 deixou pendente para
     esta secao. */
  .login-wrapper { padding-top: 8vh; }
  .login-cartao {
    width: 100%;
    border-radius: var(--r-card);
    padding: var(--e6);
  }

  /* /admin (spec §3.3): as abas viram largura total divididas em dois. */
  .aba { flex: 1 1 50%; text-align: center; }
}
