
/* ============================================================================
   OctoRender Web — folha unica. Substitui integralmente o ESTILO anterior.

   TRES REGRAS QUE EXPLICAM CADA LINHA DAQUI:
   1. Matiz e vocabulario de SINAL, nunca decoracao. Link nao e azul; foco e
      branco; hover nao tinge. Hierarquia se faz com luminancia, peso e caixa.
   2. Onde ha pixel de render na tela (.palco, .thumb), o chrome e ZERO: sem
      raio, sem borda, sem padding, sem crop. Onde nao ha, pode haver caixa,
      tinta de excecao e numero grande.
   3. Estado de render nao pulsa: o mural fica aberto o dia inteiro em visao periferica.
      Excecao decorativa pedida em 2026-09-12: mini polvo da marca, pausavel e fora das
      telas de julgamento. Nao representa atividade ou sanidade real da farm.
   ========================================================================== */

/* ------------------------------------------------------------- 1. tokens */
/* A CAMADA DE TOKENS E O CONTRATO DOS COMPONENTES (redesign E02, 2026-09-05).

   Dois temas, um bloco cada. Componente NENHUM sabe em que tema esta: ele so usa nomes
   semanticos (`--bg-surface`, `--text-primary`, `--sanity-empty`...). Trocar de tema e trocar o
   valor de `data-theme` na tag `<html>` -- ou num container qualquer, que e como a tela /estilo
   mostra os dois lado a lado.

   O QUE E IGUAL NOS DOIS TEMAS, DE PROPOSITO: tudo que encosta em pixel de render (palco,
   letterbox, xadrez, texto sobre imagem) e as quatro matizes de sinal como PREENCHIMENTO. A
   neutralidade R=G=B ali e o que permite julgar cor; as matizes sao o vocabulario que a equipe ja
   aprendeu. O que muda por tema e o texto SOBRE o sinal e a tinta suave em volta dele.

   Os nomes antigos (`--f0`, `--tx`, `--linha`, `--vazio`...) continuam existindo como ALIASES
   declarados junto de cada tema, para que as ~1.000 linhas de componente abaixo funcionem nos
   dois temas sem reescrita nesta entrega. A migracao componente a componente para os nomes
   semanticos e trabalho das entregas de tela; um alias nao e divida, e uma ponte com nome. */

:root, [data-theme="sala-escura"]{
  color-scheme: dark;

  /* Sala escura: TV de parede, madrugada, sala de render. Grafite neutro, sem sombra -- a
     elevacao e por borda e por 4-6 pontos de luminancia. */
  --bg-page:#0c0c0c;
  --bg-surface:#151515;
  --bg-raised:#1d1d1d;
  --bg-sunken:#080808;
  --border:#262626;
  --border-strong:#3a3a3a;
  --text-primary:#ececec;
  --text-strong:#ffffff;
  --text-secondary:#b4b4b4;
  --text-tertiary:#8c8c8c;      /* 5,6:1 sobre --bg-surface: passa AA em 11px */
  --text-inverse:#0c0c0c;
  --accent:#ececec;             /* controle ativo em VIDEO REVERSO, o idioma que a equipe ja le */
  --accent-text:#0c0c0c;
  --focus-ring:#ffffff;
  --focus-halo:rgba(0,0,0,.85);
  --shadow-1:none;
  --shadow-2:none;
  --shadow-pop:0 .65rem 2rem rgba(0,0,0,.8);
  --overlay:rgba(0,0,0,.6);        /* fundo de dialogo modal */
  --bg-page-fundo:radial-gradient(1200px 700px at 18% -12%, #171717 0%, #0c0c0c 60%);
  --shadow-ink:#000000;         /* sombra de texto/controle sobre imagem */
  --stripe-gap:#000000;         /* o vao das hachuras de worker offline/stalled */

  /* sinal: preenchimento igual nos dois temas; texto sobre o sinal e tinta por tema */
  --sanity-empty:#e5484d;   --sanity-empty-on:#ffffff;   --sanity-empty-ink:#1f1011;
  --sanity-empty-text:#ff8a8f;   --sanity-empty-on-ink:#ffd9d7;
  --sanity-suspect:#f5a524; --sanity-suspect-on:#000000; --sanity-suspect-ink:#1e1608;
  --sanity-suspect-text:#f5a524; --sanity-suspect-on-ink:#ffe3b0;
  --sanity-ok:#3fb950;      --sanity-ok-on:#000000;      --sanity-ok-ink:#0f1a12;
  --sanity-ok-text:#5ccb6c;
  --sanity-element:#3b82f6; --sanity-element-on:#ffffff; --sanity-element-ink:#0e1626;
  --sanity-element-text:#8ab6ff; --sanity-element-line:#2b4c7e;
  --sanity-unrated:#767676;
  --danger:#e5484d; --danger-text:#ffd9d7; --danger-ink:#1f1011;
  --badge-ring:#000000;
}

[data-theme="mesa-de-luz"]{
  color-scheme: light;

  /* Mesa de luz: o vidro leitoso do laboratorio, os frames como cromos por cima. Papel neutro,
     texto grafite, superficies brancas com UMA sombra suave, linhas finas escuras. Controle ativo
     em TINTA (grafite cheio) em vez de video reverso claro. */
  --bg-page:#f4f4f4;
  --bg-surface:#ffffff;
  --bg-raised:#fafafa;
  --bg-sunken:#e8e8e8;
  --border:#d9d9d9;
  --border-strong:#bdbdbd;
  --text-primary:#141414;
  --text-strong:#000000;
  --text-secondary:#4a4a4a;
  --text-tertiary:#6b6b6b;      /* 5,7:1 sobre --bg-surface */
  --text-inverse:#ffffff;
  --accent:#141414;
  --accent-text:#ffffff;
  --focus-ring:#141414;
  --focus-halo:rgba(255,255,255,.9);
  --shadow-1:0 1px 2px rgba(0,0,0,.06);
  --shadow-2:0 4px 16px rgba(0,0,0,.10);
  --shadow-pop:0 .65rem 2rem rgba(0,0,0,.18);
  --overlay:rgba(20,20,20,.45);
  --bg-page-fundo:radial-gradient(1200px 700px at 18% -12%, #ffffff 0%, #f4f4f4 60%);
  --shadow-ink:#000000;
  --stripe-gap:#ffffff;

  --sanity-empty:#e5484d;   --sanity-empty-on:#ffffff;   --sanity-empty-ink:#fdecec;
  --sanity-empty-text:#b3261e;   --sanity-empty-on-ink:#7a1a14;
  --sanity-suspect:#f5a524; --sanity-suspect-on:#000000; --sanity-suspect-ink:#fff3dc;
  --sanity-suspect-text:#8a5300; --sanity-suspect-on-ink:#5c3700;
  --sanity-ok:#3fb950;      --sanity-ok-on:#000000;      --sanity-ok-ink:#e9f7ec;
  --sanity-ok-text:#1f7a34;
  --sanity-element:#3b82f6; --sanity-element-on:#ffffff; --sanity-element-ink:#e8f0fe;
  --sanity-element-text:#1d4ed8; --sanity-element-line:#9db8f0;
  --sanity-unrated:#767676;
  --danger:#e5484d; --danger-text:#b3261e; --danger-ink:#fdecec;
  --badge-ring:#ffffff;
}

/* O QUE NAO MUDA COM O TEMA, e os aliases legados -- declarados em `:root` E em todo container com
   `data-theme`, porque custom property resolve `var()` NO ELEMENTO ONDE E DECLARADA: um alias
   declarado so em `:root` congelaria o valor do tema da pagina e ignoraria o container. */
:root, [data-theme]{
  /* PALCO -- fundos de julgamento, neutros fixos. 18% e a carta cinza da fotografia; o xadrez e
     de MEIO-TOM porque xadrez escuro esconde franja escura no alpha. */
  --stage-gray:#767676;
  --stage-checker-a:#6e6e6e;
  --stage-checker-b:#8a8a8a;
  --stage-black:#000000;
  --stage-white:#ffffff;
  --letterbox:#0c0c0c;          /* nunca preto puro: faixa != pixel preto da imagem */
  --over-image-text:#ffffff;    /* rotulo sobre thumb: sempre branco com sombra preta */
  --over-image-shadow:#000000;
  --guide-line:rgba(245,165,36,.55);
  --guide-safe:rgba(233,233,228,.5);

  /* estados de job e de worker, por nome */
  --job-queued:var(--text-tertiary);
  --job-rendering:var(--sanity-ok);
  --job-done:var(--sanity-ok);
  --job-failed:var(--sanity-empty);
  --job-paused:var(--sanity-suspect);
  --job-cancelled:var(--text-tertiary);
  --worker-idle:var(--text-tertiary);
  --worker-busy:var(--sanity-ok);
  --worker-offline:var(--sanity-empty);
  --worker-maintenance:var(--sanity-suspect);
  --worker-stalled:var(--sanity-suspect);

  /* tipografia: duas familias, tres papeis. Sem fonte externa (CSP, LAN sem internet). */
  --font-ui: "Segoe UI Variable Text", "Segoe UI", system-ui, -apple-system, Roboto,
             "Noto Sans", Arial, sans-serif;
  --font-display: "Segoe UI Variable Display", "Segoe UI", system-ui, -apple-system, Roboto,
                  "Noto Sans", Arial, sans-serif;
  --font-data: "Cascadia Mono", "Cascadia Code", Consolas, "DejaVu Sans Mono", ui-monospace,
               "SF Mono", Menlo, monospace;
  --fs-1:11px; --fs-2:12px; --fs-3:13px; --fs-4:14px; --fs-5:16px; --fs-6:20px; --fs-7:26px;
  --fs-display: clamp(1.6rem, 1rem + 2vw, 2.6rem);
  --lh-tight:1.2; --lh-normal:1.45; --lh-loose:1.6;
  --track-caps:.06em;

  /* espaco (base 4), raio, movimento */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:24px; --sp-6:32px; --sp-7:48px;
  --r-0:0; --r-1:2px; --r-2:4px; --r-3:8px;
  --dur-1:120ms; --dur-2:200ms; --dur-3:320ms;
  --ease-out:cubic-bezier(.2,.8,.2,1);
  --ease-in-out:cubic-bezier(.4,0,.2,1);

  /* larguras */
  --kpi: clamp(1.7rem, 3.4vw, 3.2rem);
  --col-card: clamp(260px, 21vw, 420px);
  --col-thumb: clamp(180px, 15vw, 300px);
  --cell:10px;

  /* ALIASES LEGADOS -> semanticos (ponte para as ~1.000 linhas de componente abaixo) */
  --f0:var(--bg-page);
  --f1:var(--bg-surface);
  --f2:var(--bg-raised);
  --linha:var(--border);
  --linha-forte:var(--border-strong);
  --tx:var(--text-primary);
  --tx2:var(--text-secondary);
  --tx3:var(--text-tertiary);
  --vazio:var(--sanity-empty);
  --suspeito:var(--sanity-suspect);
  --ok:var(--sanity-ok);
  --elemento:var(--sanity-element);
  --nao-avaliado:var(--sanity-unrated);
  --t-vazio:var(--sanity-empty-ink);
  --t-suspeito:var(--sanity-suspect-ink);
  --palco-cinza:var(--stage-gray);
  --xadrez-a:var(--stage-checker-a);
  --xadrez-b:var(--stage-checker-b);
  --ui:var(--font-ui);
  --mono:var(--font-data);
}

/* Densidade (E11): `compacta` para o operador em monitor grande, `confortavel` (padrao) para
   quem julga imagem. So tokens mudam; componente nenhum sabe da densidade. */
[data-densidade="compacta"]{
  --fs-3:12px; --fs-4:13px; --fs-5:15px; --fs-7:22px;
  --sp-2:6px; --sp-3:9px; --sp-4:12px; --sp-5:18px;
  --col-card: clamp(220px, 16vw, 320px);
  --col-thumb: clamp(140px, 12vw, 240px);
}
[data-densidade="compacta"] .card .corpo{ padding:.4rem .55rem .5rem }
[data-densidade="compacta"] .fila td, [data-densidade="compacta"] .fila th{ padding:.2rem .5rem }
[data-densidade="compacta"] main{ padding:var(--sp-3) var(--sp-4) }

/* Movimento de conteudo e pontual. Excecao pedida em 2026-09-12: mascote da marca, discreto,
   pausavel e so no trilho expandido. Ambos desligam para quem pediu menos movimento. */
@media (prefers-reduced-motion: reduce){
  :root, [data-theme]{ --dur-1:0ms; --dur-2:0ms; --dur-3:0ms }
}
/* A troca de tema faz UMA transicao de cor, e so enquanto a classe existir (o JS a poe e tira). */
html.tema-transicao, html.tema-transicao *, html.tema-transicao *::before, html.tema-transicao *::after{
  transition: background-color var(--dur-2) var(--ease-in-out), color var(--dur-2) var(--ease-in-out),
              border-color var(--dur-2) var(--ease-in-out), box-shadow var(--dur-2) var(--ease-in-out) !important }
/* Imagem e palco nunca transicionam: julgar cor com fade no meio seria julgar outra imagem. */
html.tema-transicao img, html.tema-transicao .palco, html.tema-transicao .thumb{ transition:none !important }

/* --------------------------------------------------------------- 2. base */
*{ box-sizing:border-box }
body{ margin:0; background:var(--f0); color:var(--tx);
      font:var(--fs-3)/var(--lh-normal) var(--font-ui);
      /* tabular em TODA a pagina: com digito proporcional, cada meta refresh
         de 10 s muda a largura de tempo_task/progresso e a linha dança. */
      font-variant-numeric:tabular-nums;
      -webkit-font-smoothing:antialiased }

/* Sem matiz no link, o SUBLINHADO passa a ser a unica pista de que e link:
   obrigatorio em prosa, dispensavel em card/thumb/celula (o alvo e a caixa). */
a{ color:var(--tx); text-decoration:none }
a:hover{ text-decoration:underline; text-decoration-color:var(--tx3) }
p a, .explica a, .prosa a{ text-decoration:underline;
  text-decoration-color:var(--linha-forte); text-underline-offset:2px }

/* Foco BRANCO, nao azul: azul pertence ao ELEMENTO. O halo preto garante o
   anel tambem sobre o palco branco. */
:focus-visible{ outline:2px solid var(--focus-ring); outline-offset:2px;
                box-shadow:0 0 0 4px var(--focus-halo) }

/* HIERARQUIA (redesign E03): titulo de tela e `<h1>` em display; `<h2>` e secao; `<h3>` e
   rotulo de bloco. Tres degraus de TAMANHO, nao tres caixas altas. */
h1{ font:600 var(--fs-7)/var(--lh-tight) var(--font-display); letter-spacing:-.01em;
    margin:var(--sp-2) 0 var(--sp-1); color:var(--text-strong) }
h1 .rot, h1 small{ font:500 var(--fs-1)/1.4 var(--font-ui); letter-spacing:var(--track-caps);
    text-transform:uppercase; color:var(--text-tertiary); margin-left:var(--sp-2);
    vertical-align:middle }
h1 .ident, h1 code{ font:var(--fs-3)/1 var(--font-data); color:var(--text-tertiary);
    font-weight:400; margin-left:var(--sp-2); vertical-align:middle }
h2{ font:600 var(--fs-5)/var(--lh-tight) var(--font-display); margin:var(--sp-4) 0 var(--sp-2) }
h3{ font:600 var(--fs-1)/1.3 var(--font-ui); letter-spacing:var(--track-caps);
    text-transform:uppercase; color:var(--tx2); margin:1.2rem 0 .4rem }
code{ font:11px/1.4 var(--mono); color:var(--tx2) }
.mono{ font-family:var(--mono) }
.meta{ color:var(--tx2); font-size:12px }
.fraco{ color:var(--tx3) }
/* micro-rotulo de instrumento: o UNICO lugar com letter-spacing largo */
/* Linha de PROPOSITO de cada tela (pedido do usuario em 2026-08-20: "em cada menu, qual o
   proposito dele e o que ele faz, para ser auto explicativo"). Uma frase, logo sob o titulo,
   sempre com a mesma cara — quem aprendeu a le-la numa tela sabe onde procura-la em todas. */
.proposito{ color:var(--tx3); font-size:var(--fs-2); margin:0 0 var(--sp-4); max-width:78ch }
body.viewport .proposito{ max-width:none; white-space:nowrap; overflow:hidden;
  text-overflow:ellipsis; margin-bottom:var(--sp-2) }
.proposito b{ color:var(--tx2) }

.rot{ font:600 var(--fs-1)/1.4 var(--font-ui); letter-spacing:var(--track-caps);
      text-transform:uppercase; color:var(--tx3) }
.alerta-num{ color:var(--vazio); font-weight:700 }
/* Desfecho do ultimo clique no card do worker (2026-09-10). Classes PROPRIAS, e nao `.aten`/
   `.ruim`: aquelas so existem qualificadas (`.explica.aten`, `.prog .ruim`), entao num
   `<p class="meta aten">` elas nao pintam nada -- a recusa sairia com a mesma cara do sucesso,
   que e a armadilha da feature invisivel de novo. */
.acao-ok{ color:var(--ok); font-weight:600 }
/* GRUPO "FORA DO AR": LISTA, e nao tabela nem card (2026-09-10).

   Duas tentativas anteriores fracassaram por motivos opostos, e o registro importa porque o
   proximo palpite seria repetir uma delas. Em 07/09 o grupo virou TABELA (`.tabular`), com o
   argumento de que 30 hosts se comparam melhor em colunas: dentro da `<details>` estreita a
   tabela some para a direita em vez de comparar. Em 10/09 virou o rack de CARDS da lista de
   cima: cada host desligado passou a ocupar um cartao inteiro com sete campos que ninguem le
   num host que nao esta trabalhando -- 20 hosts viraram tres paginas de cartao.

   O que estes hosts precisam responder e so "quem esta fora": uma LINHA por host, com nome,
   estado e a capacidade em texto corrido. Reaproveita as mesmas `<tr>`; o que muda e o
   arranjo. Classe PROPRIA (`lista-workers`) e nao um `:not()` a mais em `.workers`, para nao
   mexer nas regras da lista de cima -- que continua sendo cards, e esta certa assim. */
.lista-workers{ display:block; margin:.4rem 0 .8rem }
.lista-workers thead{ position:absolute; width:1px; height:1px; overflow:hidden;
  clip:rect(0 0 0 0) }
.lista-workers tbody{ display:block }
.lista-workers tr{ display:flex; flex-wrap:wrap; align-items:baseline; gap:.15rem .8rem;
  padding:.3rem .1rem; border-bottom:1px solid var(--linha) }
.lista-workers tr:last-child{ border-bottom:0 }
.lista-workers tr:hover{ background:var(--f1) }
.lista-workers td{ display:inline-block; border:0; padding:0; min-width:0;
  color:var(--tx2); font-size:var(--fs-2) }
.lista-workers td[data-col="worker"]{ font:600 var(--fs-3)/1.3 var(--font-ui); color:var(--tx);
  min-width:11rem }
/* Rotulo SO onde o valor e ambiguo: `84.5/84.5 GiB` sozinho nao diz se e RAM ou VRAM, mas
   `32/32 cores` ja se explica e `192.0.2.21` tambem. Prefixar tudo gastaria a largura que
   esta lista existe para economizar. */
.lista-workers td[data-col="ram"]::before, .lista-workers td[data-col="vram"]::before{
  content:attr(data-col) " "; color:var(--tx3); font-size:var(--fs-1);
  text-transform:uppercase; letter-spacing:var(--track-caps) }
/* Colunas que so fazem sentido em host que TRABALHA somem: host fora do ar nao tem frame,
   job nem progresso, e tres celulas vazias por linha viram ruido. */
.lista-workers td[data-col="frame"], .lista-workers td[data-col="job"],
.lista-workers td[data-col="progresso"]{ display:none }
.lista-workers td[data-col="ip"]{ font-family:var(--mono); font-size:var(--fs-1) }
/* TAGS NA MESMA LINHA, truncadas. Medido em 2026-09-10 na bancada: com `flex:1 1 100%` elas
   quebravam para uma linha inteira de 1086 px e cada host passava a ocupar 75 px -- duas
   linhas por host, que e card disfarcado de lista. Truncar mantem a informacao ao alcance
   (o `title` traz a lista inteira) sem gastar uma linha por host. */
.lista-workers td[data-col="tags"]{ flex:1 1 8rem; min-width:0; color:var(--tx3);
  font-size:var(--fs-1); white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
.acao-aten{ color:var(--suspeito); font-weight:600 }
.acao-ruim{ color:var(--vazio); font-weight:700 }
.atencao-num{ color:var(--suspeito); font-weight:700 }
.nada-num{ color:var(--nao-avaliado); font-weight:700 }

/* ------------------------------------------------------------- 3. header */
/* O SHELL (redesign E11). Ate 1023px: barra no topo, menu atras de um botao. A partir de 1024px:
   um TRILHO LATERAL fixo com a marca, a busca (paleta), o menu com icones, o pulso da farm ao
   vivo e, no pe, preferencias e sessao. O conteudo ganha a largura inteira ao lado -- a folha de
   contato e o produto -- e o trilho encolhe para icones nas telas de julgamento e no modo TV. */
header{ display:grid; grid-template-columns:auto 1fr auto; align-items:center;
  gap:var(--sp-4); min-height:44px; padding:0 var(--sp-4); background:var(--f1);
  border-bottom:1px solid var(--linha); position:sticky; top:0; z-index:5;
  font:500 var(--fs-2)/1 var(--font-ui); box-shadow:var(--shadow-1) }
.marca{ display:flex; align-items:center; gap:.55rem; color:var(--text-strong);
        font:600 var(--fs-4)/1 var(--font-display); letter-spacing:-.01em }
.marca:hover{ text-decoration:none }
.marca svg{ display:block; flex:none; color:var(--text-strong) }
.marca-area{ position:relative; display:block; width:max-content; max-width:100% }
.marca .marca-polvo, .marca-pausa, .marca-animacao{ display:none }
.nav-toggle{ display:none; appearance:none; border:1px solid var(--border-strong);
  background:var(--bg-sunken); color:var(--text-secondary); border-radius:var(--r-2);
  font:500 var(--fs-2)/1 var(--font-ui); padding:.4rem .7rem; cursor:pointer; min-height:32px }
.nav-toggle[aria-expanded="true"]{ background:var(--accent); color:var(--accent-text) }
.identidade-instancia{ display:flex; align-items:center; gap:.55rem; min-width:0 }
.ambiente-instancia,.ambiente-login{ display:block; padding:.2rem .45rem;
  border:1px solid var(--suspeito); border-radius:var(--r-1); color:var(--sanity-suspect-text);
  font:600 var(--fs-1)/1.3 var(--font-ui); letter-spacing:var(--track-caps); text-transform:uppercase }
.ambiente-instancia{ max-width:40ch; overflow:hidden; text-overflow:ellipsis;
  white-space:nowrap; flex:none }
.ambiente-login{ margin:1rem auto; width:max-content; max-width:calc(100% - 2rem);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap }

/* a busca-comando: parece um campo, e um botao que abre a paleta */
.paleta-abrir{ display:none; align-items:center; gap:.5rem; width:100%; min-height:34px;
  padding:0 .6rem; border:1px solid var(--border-strong); border-radius:var(--r-2);
  background:var(--bg-sunken); color:var(--text-tertiary); font:var(--fs-2)/1 var(--font-ui);
  cursor:text; text-align:left }
.paleta-abrir span{ flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.paleta-abrir:hover{ border-color:var(--text-tertiary); color:var(--text-secondary) }
.paleta-abrir kbd{ font-size:9px }

/* menu: itens com icone + rotulo; o `<a>` e o alvo inteiro pelo ::after */
header nav{ display:flex; gap:var(--sp-1); align-items:stretch; min-width:0 }
header nav .item{ position:relative; display:flex; align-items:center; gap:.55rem;
  padding:0 .65rem; height:44px; color:var(--tx2); border-radius:0; white-space:nowrap;
  box-shadow:inset 0 -2px 0 transparent }
header nav .item svg{ flex:none; opacity:.8 }
header nav .item a{ color:inherit; text-decoration:none }
header nav .item a::after{ content:""; position:absolute; inset:0 }
header nav .item:hover{ color:var(--tx); background:var(--bg-raised) }
header nav .item[data-ativo]{ color:var(--text-strong); box-shadow:inset 0 -2px 0 var(--accent) }
header nav .item[data-ativo] svg{ opacity:1 }
.nav-grupo{ position:relative; display:flex; align-items:stretch }
.nav-grupo > summary{ list-style:none; cursor:pointer; color:var(--tx2); padding:0 .65rem;
  display:flex; align-items:center; gap:.4em; height:44px; white-space:nowrap }
.nav-grupo > summary::-webkit-details-marker{ display:none }
.nav-grupo > summary::after{ content:""; width:5px; height:5px; margin-top:-2px;
  border-right:1.5px solid currentColor; border-bottom:1.5px solid currentColor;
  transform:rotate(45deg); opacity:.7 }
.nav-grupo > summary:hover{ color:var(--tx); background:var(--bg-raised) }
.nav-grupo[data-ativo] > summary{ color:var(--text-strong); box-shadow:inset 0 -2px 0 var(--accent) }
.nav-lista{ position:absolute; top:100%; left:0; z-index:30; min-width:14rem;
  display:flex; flex-direction:column; padding:var(--sp-1); margin-top:1px;
  background:var(--bg-surface); border:1px solid var(--border-strong); border-radius:var(--r-2);
  box-shadow:var(--shadow-pop) }
.nav-lista .item{ height:auto; padding:.5rem .6rem; border-radius:var(--r-1); box-shadow:none }
.nav-lista .item[data-ativo]{ background:var(--accent); color:var(--accent-text); box-shadow:none }

/* pulso da farm */
.pulso{ display:none }
.trilho-colapsar{ display:none }
.pulso-link{ display:flex; flex-direction:column; gap:.4rem; padding:.6rem .65rem;
  border-radius:var(--r-2); background:var(--bg-sunken); color:var(--text-secondary);
  text-decoration:none; font-size:var(--fs-1) }
.pulso-link:hover{ text-decoration:none; background:var(--bg-raised) }
.pulso-num b{ color:var(--text-strong); font-family:var(--font-data) }
.celulas-workers.mini{ gap:2px }
.celulas-workers.mini i{ width:9px; height:9px; border-radius:2px }

/* trilha de estado global — presente nas 7 telas, alimentada SO por cache */
.trilha-area{ display:flex; align-items:center; gap:.7rem }
.trilha{ display:flex; align-items:center; gap:.35rem; text-transform:none;
         letter-spacing:0 }
.preferencias{ display:flex; align-items:center; gap:.4rem }
.chip{ display:inline-flex; align-items:center; gap:.4em; white-space:nowrap;
  padding:.25rem .55rem; border:1px solid var(--linha-forte); border-radius:var(--r-2);
  color:var(--tx3); font:var(--fs-1)/1.4 var(--font-ui); min-height:26px }
.chip:hover{ color:var(--tx); text-decoration:none; background:var(--f2) }
.chip b{ color:var(--tx); font:600 var(--fs-2)/1 var(--font-data) }
.chip[data-nv="aten"]{ border-color:var(--suspeito); color:var(--sanity-suspect-text) }
.chip[data-nv="aten"] b{ color:var(--sanity-suspect-text) }
.chip[data-nv="crit"]{ border-color:var(--vazio); background:var(--t-vazio);
                       color:var(--sanity-empty-on-ink) }
.chip[data-nv="crit"] b{ color:var(--text-strong) }
.pulso-ponto{ width:7px; height:7px; border-radius:50%; background:var(--ok); flex:none }
.pulso-ponto[data-velho="1"]{ background:var(--suspeito) }
.pulso-ponto[data-velho="2"]{ background:var(--vazio) }
.pulso[data-velho="1"], .pulso[data-velho="2"]{ }

/* ---------------------------------------------------- 3b. trilho lateral (>= 1024px) */
@media (min-width: 1024px){
  body{ display:grid; grid-template-columns:var(--rail) minmax(0, 1fr);
        grid-template-rows:minmax(0, 1fr) auto; min-height:100vh; --rail:232px }
  header{ grid-row:1 / 3; grid-column:1; position:sticky; top:0; height:100vh; overflow-y:auto;
    display:flex; flex-direction:column; align-items:stretch; gap:var(--sp-2);
    padding:var(--sp-3) var(--sp-3); border-right:1px solid var(--border); border-bottom:0;
    box-shadow:none; z-index:5; scrollbar-width:none }
  /* Sem barra de rolagem visivel (pedido do usuario, 2026-09-06): o trilho cabe na altura da tela
     em qualquer papel; se um dia nao couber, continua rolando, so nao mostra a barra. */
  header::-webkit-scrollbar{ display:none }
  main{ grid-column:2; grid-row:1 }
  footer{ grid-column:2; grid-row:2 }
  .identidade-instancia{ flex-direction:column; align-items:flex-start; gap:var(--sp-2);
    padding:0 .35rem }
  .marca{ font-size:var(--fs-5) }
  .marca svg{ width:30px; height:14px }
  .ambiente-instancia{ max-width:100% }
  .paleta-abrir{ display:flex }
  header nav{ flex-direction:column; gap:2px }
  header nav .item{ height:32px; border-radius:var(--r-2); padding:0 .6rem; box-shadow:none }
  header nav .item[data-ativo]{ background:var(--accent); color:var(--accent-text); box-shadow:none }
  header nav .item[data-ativo]:hover{ background:var(--accent); color:var(--accent-text) }
  .nav-grupo{ flex-direction:column; margin-top:var(--sp-2) }
  /* O titulo do grupo e CLICAVEL e recolhe/abre a secao (pedido do usuario, 2026-09-06). Ate
     entao tinha `pointer-events:none`, e um clique fora do menu recolhia os grupos sem que nada
     conseguisse abri-los de novo ate a proxima navegacao. Nascem abertos; o chevron diz o estado. */
  .nav-grupo > summary{ height:auto; padding:.5rem .6rem .2rem; cursor:pointer;
    font:600 var(--fs-1)/1.3 var(--font-ui); letter-spacing:var(--track-caps);
    text-transform:uppercase; color:var(--text-tertiary); pointer-events:auto;
    box-shadow:none; background:transparent; border-radius:var(--r-1) }
  .nav-grupo > summary:hover{ color:var(--text-secondary); background:transparent }
  .nav-grupo > summary::after{ display:inline-block; margin-left:auto; margin-top:0;
    transform:rotate(45deg); transition:transform var(--dur-1) var(--ease-out) }
  .nav-grupo:not([open]) > summary::after{ transform:rotate(-45deg) }
  .nav-grupo[data-ativo] > summary{ color:var(--text-tertiary); box-shadow:none }
  .nav-lista{ position:static; box-shadow:none; border:0; padding:0; margin:0; min-width:0;
    background:transparent; gap:2px }
  .nav-lista .item{ height:32px; padding:0 .6rem; border-radius:var(--r-2) }
  .pulso{ display:block; margin-top:auto }
  .trilha-area{ flex-direction:column; align-items:stretch; gap:var(--sp-2) }
  .trilha{ flex-direction:column; align-items:stretch }
  .chip{ justify-content:center }
  .preferencias{ flex-direction:column; align-items:stretch }
  .tema-seletor{ display:flex } .tema-seletor button{ flex:1; justify-content:center }
  .sessao{ justify-content:space-between; padding:0 .35rem }

  /* telas de julgamento e TV: o trilho encolhe para icones, o palco fica com o resto.
     `body.rail-compacto` (2026-09-06) e o MESMO trilho de icones, mas por escolha da pessoa, em
     qualquer tela: o botao no topo do trilho alterna e a preferencia fica no perfil/cookie. */
  body.viewport, body.tv, body.rail-compacto{ --rail:64px }
  body.rail-compacto header{ padding:var(--sp-3) var(--sp-2); gap:var(--sp-2) }
  body.rail-compacto .marca span, body.rail-compacto .paleta-abrir,
  body.rail-compacto .ambiente-instancia, body.rail-compacto .nav-grupo > summary,
  body.rail-compacto .pulso-num, body.rail-compacto .preferencias,
  body.rail-compacto .sessao .mono, body.rail-compacto .chip .fraco{ display:none }
  body.rail-compacto header nav .item a{ font-size:0; line-height:0 }
  body.rail-compacto header nav .item{ justify-content:center; padding:0 }
  body.rail-compacto .chip{ padding:.25rem .3rem; font-size:0 }
  body.rail-compacto .chip b{ font-size:var(--fs-1) }
  body.rail-compacto .chip b + b::before{ content:"/"; opacity:.5; margin:0 .1em }
  body.rail-compacto .pulso-link{ padding:.4rem }
  body.rail-compacto .nav-grupo{ margin-top:var(--sp-1) }
  body.rail-compacto .nav-grupo:not([open]) > .nav-lista{ display:flex }
  /* o botao de recolher/expandir: so existe no trilho lateral */
  .trilho-colapsar{ display:flex; align-items:center; justify-content:center; align-self:flex-end;
    width:28px; height:28px; margin:-.2rem 0 0; border:1px solid var(--border);
    border-radius:var(--r-2); background:var(--bg-surface); color:var(--text-tertiary);
    cursor:pointer; font:600 16px/1 var(--font-ui); padding:0 }
  .trilho-colapsar:hover{ color:var(--text-strong); border-color:var(--border-strong) }
  .trilho-colapsar .exp{ display:none }
  body.rail-compacto .trilho-colapsar{ align-self:center; margin:0 }
  body.rail-compacto .trilho-colapsar .rec{ display:none }
  body.rail-compacto .trilho-colapsar .exp{ display:inline }
  body.viewport .trilho-colapsar, body.tv .trilho-colapsar{ display:none }
  body.viewport header, body.tv header{ padding:var(--sp-3) var(--sp-2); gap:var(--sp-2) }
  body.viewport .marca span, body.tv .marca span,
  body.viewport .paleta-abrir, body.tv .paleta-abrir,
  body.viewport .ambiente-instancia, body.tv .ambiente-instancia,
  body.viewport .nav-grupo > summary, body.tv .nav-grupo > summary,
  body.viewport .pulso-num, body.tv .pulso-num,
  body.viewport .preferencias, body.tv .preferencias,
  body.viewport .sessao .mono, body.tv .sessao .mono,
  body.viewport .chip .fraco, body.tv .chip .fraco{ display:none }
  body.viewport header nav .item a, body.tv header nav .item a{ font-size:0; line-height:0 }
  body.viewport header nav .item, body.tv header nav .item{ justify-content:center; padding:0 }
  body.viewport .chip, body.tv .chip{ padding:.25rem .3rem; font-size:0 }
  body.viewport .chip b, body.tv .chip b{ font-size:var(--fs-1) }
  /* no chip compacto so sobram os numeros: um separador visivel entre eles ("47 / 57") */
  body.viewport .chip b + b::before, body.tv .chip b + b::before{ content:"/"; opacity:.5;
    margin:0 .25em; font-weight:400 }
  body.viewport .pulso-link, body.tv .pulso-link{ padding:.4rem }
  /* `html body.viewport` (0,1,2) vence a regra base `body.viewport{display:flex}` (0,1,1) que vem
     depois na folha: sem isso o trilho virava uma faixa horizontal e o palco caia abaixo da dobra. */
  html body.viewport{ display:grid; height:auto; overflow:visible }
  html body.viewport main{ height:100vh; min-height:0; display:flex; flex-direction:column;
    padding:0; overflow:hidden }
  body.viewport .palco{ flex:1; min-height:120px }
  body.viewport footer{ display:none }
}

/* Mascote da marca: decoracao, nunca telemetria. So no trilho expandido; sem custo visual
   no player, TV ou celular. O checkbox nativo pausa inclusive sem JavaScript. */
@media (min-width:1024px){
  /* A folga fixa desce desenho, marca e pausa juntos, inclusive na densidade compacta.
     Nao depender do espaco do botao de recolher: a animacao precisa respirar no topo. */
  .marca-area{ padding-top:16px; margin-top:24px }
  .marca{ position:relative }
  .marca .marca-polvo{ display:block; position:absolute; left:0; top:-52px; width:136px;
    height:54px; pointer-events:none; overflow:visible }
  .polvo-braco{ transform-box:view-box; transform-origin:59px 25px }
  .polvo-b1{ transform-origin:53px 21px }
  .polvo-b6{ transform-origin:69px 22px }
  .polvo-cabeca{ transform-box:view-box; transform-origin:59px 24px }
  .polvo-olhos{ transform-box:fill-box; transform-origin:center }
  .marca-animacao{ position:absolute; right:-24px; top:-31px; width:24px; height:24px;
    align-items:center; justify-content:center; border-radius:var(--r-1);
    color:var(--text-tertiary); cursor:pointer; z-index:1 }
  .marca-animacao:hover{ color:var(--text-strong); background:var(--bg-raised) }
  .marca-pausa{ position:absolute; top:-31px; right:-24px; width:24px; height:24px;
    margin:0; opacity:0; z-index:2; cursor:pointer }
  .marca-pausa:focus-visible + .marca-animacao{ outline:2px solid var(--text-strong);
    outline-offset:2px }
  .marca-pausa:hover + .marca-animacao{ color:var(--text-strong); background:var(--bg-raised) }
  .marca-retomar{ display:none }
  .marca-pausa:checked + .marca-animacao .marca-pausar{ display:none }
  .marca-pausa:checked + .marca-animacao .marca-retomar{ display:block }
  .marca-pausa:checked ~ .marca .marca-polvo *{ animation-play-state:paused }
  body.rail-compacto .marca, body.viewport .marca, body.tv .marca{ padding-top:0 }
  body.rail-compacto .marca-area, body.viewport .marca-area, body.tv .marca-area{
    padding-top:0; margin-top:0 }
  body.rail-compacto .marca-polvo, body.viewport .marca-polvo, body.tv .marca-polvo,
  body.rail-compacto .marca-pausa, body.viewport .marca-pausa, body.tv .marca-pausa,
  body.rail-compacto .marca-animacao, body.viewport .marca-animacao,
  body.tv .marca-animacao{ display:none }
  body.rail-compacto .marca-polvo *, body.viewport .marca-polvo *,
  body.tv .marca-polvo *{ animation:none }
}
@media (min-width:1024px) and (prefers-reduced-motion:no-preference){
  .marca-pausa{ display:block }
  .marca-animacao{ display:flex }
  .polvo-braco{ animation:octo-tentaculo 6s ease-in-out infinite }
  .polvo-b2, .polvo-b5{ animation-delay:-2s }
  .polvo-b3{ animation-delay:-4s }
  .polvo-b4{ animation-delay:-6s }
  .polvo-b1{ animation:octo-operar 3.6s ease-in-out infinite }
  .polvo-b6{ animation:octo-cafe 6s ease-in-out infinite }
  .polvo-cabeca{ animation:octo-respirar 6s ease-in-out infinite }
  .polvo-olhos{ animation:octo-piscar 11s ease-in-out infinite }
}
@keyframes octo-tentaculo{
  0%, 100%{ transform:rotate(-3deg) }
  35%{ transform:rotate(4deg) translateY(-1px) }
  65%{ transform:rotate(-1deg) translateY(1px) }
}
@keyframes octo-operar{ 0%, 65%, 100%{ transform:rotate(0) }
  20%, 45%{ transform:rotate(-8deg) translateY(1px) }
  30%, 55%{ transform:rotate(3deg) translateY(-1px) } }
@keyframes octo-cafe{ 0%, 70%, 100%{ transform:rotate(0) }
  30%, 45%{ transform:rotate(-7deg) translateY(-1px) } }
@keyframes octo-respirar{ 0%, 100%{ transform:translateY(0) rotate(0) }
  50%{ transform:translateY(-1.5px) rotate(-2deg) } }
@keyframes octo-piscar{ 0%, 43%, 47%, 100%{ transform:scaleY(1) }
  45%{ transform:scaleY(.12) } }

/* ------------------------------------------------------------- 4. layout */
/* max-width sai do main: num ultrawide 3440 o portal jogava 1940 px fora, e a
   folha de contato E o produto. A medida de leitura fica so na PROSA. */
main{ padding:.9rem 1rem; max-width:none; margin:0 }
.prosa, .explica, p.meta, p, footer{ max-width:80ch }
.rolagem{ overflow-x:auto }        /* envolve .fila em janela estreita */
/* Log de frame. `pre` puro estoura a largura da pagina: as linhas do Blender passam de 200
   colunas e a barra de rolagem HORIZONTAL do documento inteiro aparece, empurrando o menu. O
   scroll fica DENTRO da caixa, e a altura e limitada porque um log de 400 KB numa pagina sem teto
   transforma a barra lateral do navegador em algo inutilizavel.
   `max-width:none` cancela o `80ch` que `.prosa, ..., p` impoe a esta arvore: aqui a largura
   nao e legibilidade de texto corrido, e sim coluna de log. */
pre.log{ max-width:none; max-height:70vh; overflow:auto; margin:.7rem 0;
  padding:.6rem .8rem; background:var(--f1); border:1px solid var(--linha);
  border-radius:var(--r-2); font:11px/1.45 var(--mono); white-space:pre; tab-size:4 }
/* Caminho do depot na linha de origem da ficha do job. Ele nao tem ponto de quebra -- nem `_`
   nem `/` sao um --, entao o `<code>` saia pela borda e a pagina INTEIRA ganhava rolagem
   horizontal. Medido em 2026-09-22 na bancada: `scrollWidth` de 809 px com a janela a 477 e a
   375 px, e esse `<code>` era o unico elemento alem da borda. A quebra e so de desenho: o texto
   selecionado e copiado continua sendo o caminho inteiro, sem espaco nem quebra de linha.
   `anywhere`, e nao `break-word`, porque so ele reduz a largura MINIMA da caixa: aqui o `<p>` e
   bloco e os dois dao o mesmo, mas dentro de flex, grid ou tabela so ele segura. */
.caminho-depot{ overflow-wrap:anywhere }
footer{ color:var(--tx3); font:var(--fs-1)/1.6 var(--font-ui); padding:1rem }

/* ------------------------------------------- 5. blocos de estado e aviso */
/* UM bloco, ordenado por severidade. Quatro faixas coloridas fixas viram papel
   de parede: em duas semanas ninguem enxerga mais a vermelha. */
.estado{ display:grid; gap:1px; background:var(--linha);
  border:1px solid var(--linha); border-radius:var(--r-2); overflow:hidden;
  margin-bottom:1rem }
.estado > *{ display:flex; align-items:center; gap:.8rem; padding:.6rem .9rem;
  background:var(--f1); color:var(--tx) }
.estado > a:hover{ background:var(--f2); text-decoration:none }
.estado .n{ font:300 1.9rem/1 var(--ui); min-width:2.5ch; text-align:right }
.estado .sev-crit{ background:var(--t-vazio);
                   box-shadow:inset 3px 0 0 var(--vazio) }
.estado .sev-crit .n{ color:var(--vazio) }
.estado .sev-aten{ background:var(--t-suspeito);
                   box-shadow:inset 3px 0 0 var(--suspeito) }
.estado .sev-aten .n{ color:var(--suspeito) }
.estado .sev-ok{ color:var(--tx2) }
/* Nem alerta nem verde: nao ha defeito MEDIDO, e tambem nao houve medicao. Sem tinta de excecao
   (nao e urgencia) e sem o ponto verde (nao e liberacao). */
.estado .sev-nada{ color:var(--tx2) }
.estado .sev-nada .n{ color:var(--nao-avaliado) }
/* Nota de escopo: mesma caixa das faixas, sem numero grande e sem tinta. Ela nao e um alerta —
   e a legenda de quem sao os alertas de cima. Tinta aqui competiria com o que ela explica. */
.estado .sev-nota{ color:var(--tx3); font-size:12px; padding-top:.45rem;
  padding-bottom:.45rem }
.estado .sev-ok .ponto{ width:.6em; height:.6em; border-radius:50%;
                        background:var(--ok); flex:none }

.aviso-velho{ background:var(--t-suspeito); color:var(--sanity-suspect-on-ink);
  box-shadow:inset 3px 0 0 var(--suspeito); padding:.55rem .9rem;
  border-radius:var(--r-2); margin-bottom:1rem; font-size:12px }
.explica{ margin:.7rem 0; padding:.55rem .85rem; background:var(--f1);
  border-left:3px solid var(--linha-forte); color:var(--tx2); font-size:12px }
.explica b{ color:var(--tx) }
.explica.crit{ border-left-color:var(--vazio) }
.explica.aten{ border-left-color:var(--suspeito) }
/* Verbos de revisao da tela do job (aprovar + retake) lado a lado quando cabem (2026-09-06). */
.verbos-revisao{ display:grid; grid-template-columns:repeat(auto-fit, minmax(22rem, 1fr));
  gap:var(--sp-3); align-items:start; margin:.7rem 0 }
.verbos-revisao > .explica{ margin:0; height:100% }
/* Cartoes de explicacao em grade (Tags): tres cartoes curtos em vez de um bloco vertical. */
.explica-grid{ display:grid; grid-template-columns:repeat(auto-fit, minmax(17rem, 1fr));
  gap:var(--sp-3); margin:.7rem 0 }
.explica-grid > .explica{ margin:0; height:100% }
/* Par de avisos do mesmo assunto, lado a lado. `align-items:start` para o card curto nao esticar
   ate a altura do longo — barra colorida gigante ao lado de duas linhas de texto le como se o
   aviso curto fosse o mais grave. A base de 34ch e o ponto em que a frase ainda respira; abaixo
   disso o `flex-wrap` empilha, que e melhor que espremer. O `max-width:80ch` que `.explica`
   herda da regra de prosa e neutralizado nos filhos: aqui quem limita a largura e a coluna. */
.explica-par{ display:flex; flex-wrap:wrap; gap:.7rem; align-items:start; margin:.7rem 0 }
.explica-par > .explica{ flex:1 1 34ch; min-width:0; max-width:none; margin:0 }

.busca{ width:100%; max-width:420px; background:var(--f0); color:var(--tx);
  border:1px solid var(--linha-forte); border-radius:var(--r-2); padding:.45rem .7rem;
  margin-bottom:.9rem; font:var(--fs-3)/1.4 var(--font-ui) }
.busca::placeholder{ color:var(--tx3) }

/* ------------------------------------------------------- 5b. paginacao */
/* POR QUE ISTO TEM CAIXA PROPRIA. A barra nasceu como <p class='meta'>, e no mural
   ela caia depois de cinco paragrafos de aviso com a MESMA classe — sexto texto
   cinza seguido. Estava no HTML e ninguem achava. Controle e aviso nao podem
   compartilhar aparencia: um se le, o outro se clica. */
.pag{ display:flex; flex-wrap:wrap; align-items:center; gap:.2rem .3rem;
  background:var(--f1); border:1px solid var(--linha);
  border-radius:var(--r-2); padding:.45rem .7rem; margin:.9rem 0;
  font:var(--fs-2)/1.5 var(--font-ui) }
.pag .cont{ color:var(--tx3); margin-left:auto; font-family:var(--font-data) }
.pag .cont b{ color:var(--tx2); font-weight:600 }

/* ------------------------------------------ 5c. barra de comando e avisos */
/* MESMA LICAO DA .pag, generalizada. O mural tinha, entre a busca e os cards, ate
   CINCO paragrafos `.meta` seguidos: legenda da tira, jobs de teste escondidos,
   jobs escondidos pelo admin, cobertura nao medida e resultado da busca. Cinco textos
   cinza indistinguiveis, e o olho aprende a pular a regiao inteira — a mesma
   habituacao que deixou 22 previews brancos um mes no depot.

   A separacao agora e por FUNCAO, nao por ordem de codigo: o que se CLICA mora na
   `.comando` (busca, recorte, tamanho de pagina); o que se LE mora na `.avisos`,
   uma caixa so, rotulada, com uma linha por aviso. Nenhum numero foi removido —
   corte silencioso continua sendo o defeito mais caro deste projeto. O que muda e
   que agora se ve que sao avisos, e quantos. */
.comando{ background:var(--f1); border:1px solid var(--linha); border-radius:var(--r-2);
  margin:.9rem 0 }
.comando > * + *{ border-top:1px solid var(--linha) }
/* A .pag dentro da .comando perde a CAIXA (ela ja esta numa), mas nao o divisor de linha.
   ⚠️ `border:0` liso zerava tambem o `border-top` que `.comando > * + *` acabou de por, e como
   esta regra vem depois ela vencia: a linha da paginacao ficava colada na de recorte sem
   separacao, enquanto a de busca tinha a dela. Assimetria que ninguem consegue nomear olhando,
   so sentir. Zerar os tres lados que sobram, e nao o de cima. */
.comando .pag{ border-right:0; border-bottom:0; border-left:0;
  border-radius:0; margin:0; background:transparent }
.comando .buscaform{ display:flex; flex-wrap:wrap; align-items:center; gap:.4rem;
  padding:.45rem .7rem }
/* ⚠️ MESMO VOCABULARIO DAS OUTRAS DUAS LINHAS. Quando as opcoes perderam a borda, a busca e o
   botao ficaram sendo os UNICOS elementos com moldura dentro da caixa — e `--linha-forte`
   (#3d3d3d) sobre `--f1` e mais forte que a borda da propria caixa (`--linha`, #2a2a2a). O
   resultado era o campo de busca gritando mais que o conteudo, que e o oposto do que se quer.
   Agora ele e um chip recuado como os outros: `--f0` afundado, sem linha, e a atencao so vem
   quando ele recebe foco. */
.comando .busca{ margin:0; flex:1 1 320px; background:var(--f0); border:0;
  border-radius:var(--r-1); padding:.35rem .6rem }
.comando .busca:focus{ outline:1px solid var(--linha-forte); outline-offset:0 }
.comando .buscaform button{ background:var(--f0); color:var(--tx2);
  border:0; border-radius:var(--r-1); padding:.4rem .8rem;
  font:500 var(--fs-2)/1.4 var(--font-ui); cursor:pointer }
.comando .buscaform button:hover{ background:var(--f2); color:var(--tx) }
#escopo-filtro{ flex-basis:100%; margin:0 }
#escopo-filtro:empty{ display:none }

/* Recorte por show/shot. Mesmo vocabulario da .pag de proposito: sao dois
   controles do mesmo tipo (recorte anunciado sobre o parque), e dar aparencia
   diferente a cada um obrigaria a aprender dois. */
.recorte{ display:flex; flex-wrap:wrap; align-items:center; gap:.2rem .3rem;
  padding:.45rem .7rem; font:var(--fs-2)/1.5 var(--font-ui) }

/* `.vista` e a TERCEIRA familia da mesma linha de controle, e existe por uma distincao que nao e
   de aparencia: `.recorte` e `.pag` decidem QUAL DADO aparece (quais linhas, quantas por pagina) e
   `.vista` decide COMO a tela se apresenta (quais colunas, com que frequencia recarrega). Nenhum
   controle `.vista` esconde job — e por isso o seletor de colunas nao e um `.recorte`, ainda que se
   pareca com um: chamar de recorte o que nao recorta faria a tela prometer um filtro que ela nao e.
   A separacao tambem serve de ancora: quem procura "a barra de recorte da /farm" continua achando
   uma so. A aparencia e compartilhada nas regras abaixo, porque tres controles na mesma coluna com
   tres caras diferentes obrigariam a aprender tres. */
.vista{ display:flex; flex-wrap:wrap; align-items:center; gap:.2rem .3rem;
  padding:.45rem .7rem; font:var(--fs-2)/1.5 var(--font-ui) }

/* ---------------------------------------------------------------------------------------
   ⚠️ AS DUAS LINHAS COMPARTILHAM O VOCABULARIO A PARTIR DAQUI, e isso e o conserto principal.
   O usuario chamou a regiao de "brega e bruto" em 2026-08-19, e ao olhar o print o defeito
   nao era gosto: era medida.

   O QUE ESTAVA ERRADO, item por item:

   1. TRES NIVEIS DE MOLDURA EMPILHADOS. A `.comando` tem borda; dentro dela cada linha; dentro
      da linha, CADA opcao tinha `border:1px` + `border-radius:var(--r-2)` propria. Numa barra de seis
      facetas o olho recebia oito retangulos aninhados, todos do mesmo peso. Densidade sem
      hierarquia le como amadorismo mesmo quando cada regra, isolada, e defensavel.
   2. O SELECIONADO NAO SALTAVA. `b.opt` diferia de `a.opt` por `--f2` (#1c1c1c) contra
      transparente sobre `--f1` (#141414): 8 pontos de luminancia em 255, a 12px. Na pratica
      `todos` e `50` pareciam iguais aos vizinhos, e o controle nao respondia a pergunta que
      existe para responder — "onde eu estou?".
   3. AS DUAS LINHAS NAO ALINHAVAM. `.recorte .rot` tinha `min-width:4ch` e `.pag .rot` nao tinha
      largura nenhuma. Como "JOB" e curto e "POR PAGINA" e longo, as opcoes de cada linha
      comecavam em x diferentes. Era o desalinhamento mais visivel do print, e o mais barato de
      consertar: uma largura de gutter comum.
   4. DOIS SEPARADORES PARA O MESMO TRABALHO. A `.pag` juntava as opcoes com `·` E cada opcao
      tinha borda. A borda ja separa; o ponto virava sujeira.
   5. `align-items:baseline` com chips de alturas diferentes deixava a linha bamba.

   A DIRECAO. Chip RECUADO em vez de chip com borda: a opcao usa `--f0` (o fundo da pagina)
   sobre a barra em `--f1`, entao ela parece afundada na barra em vez de desenhada por cima.
   Zero linha nova, e continua obviamente clicavel. O selecionado vai para VIDEO REVERSO — que
   e o idioma do terminal para "item selecionado", nao enfeite de dashboard, e coerente com a
   identidade monoespacada do portal. --------------------------------------------------------- */

/* Gutter comum: os rotulos das linhas de controle ocupam a mesma coluna e as opcoes comecam no
   mesmo x. `5.2rem` cabe "POR PAGINA" (o mais longo, ~64px a 10.5px mono) com folga.
   ⚠️ ESCOPADO EM `.recorte`/`.pag` E NAO EM `.comando`, e a diferenca importa: as mesmas duas
   classes sao usadas FORA da caixa de comando — `_barra_layers` na pagina do job e os controles
   da tela de alertas. Escopar no container deixaria justamente essas telas com o desalinhamento
   que esta regra existe para consertar, e ninguem olharia porque o mural estaria certo.

   ⚠️ `min-width` E `nowrap`, NAO `width`. Medido em /alertas: o rotulo la e "jobs por pagina"
   (15 caracteres, ~94px a 10.5px mono) e com `width:5.2rem` ele QUEBRAVA em duas linhas dentro
   do gutter, deixando aquela faixa 14px mais alta que as vizinhas — o mesmo tipo de rag que esta
   reforma existe para tirar. E o "jobs" nao pode ser cortado: em /alertas a paginacao conta JOBS
   e nao alertas, e um "50" sem essa palavra le como 50 frames com problema.
   Com `min-width` o rotulo curto preenche o gutter e o longo estica; como o alinhamento so
   precisa valer DENTRO de uma tela, e as duas barras de /alertas tem o mesmo rotulo, as duas
   continuam alinhadas entre si. */
.recorte > .rot, .pag > .rot, .vista > .rot{ flex:none; min-width:5.2rem; white-space:nowrap;
  color:var(--tx3); text-transform:uppercase; letter-spacing:var(--track-caps); font-size:var(--fs-1) }

.recorte .opt, .pag .opt, .vista .opt{ background:var(--f0); border:0; border-radius:var(--r-1);
  padding:.3rem .6rem; text-decoration:none; color:var(--tx2); white-space:nowrap;
  min-height:26px; display:inline-flex; align-items:center; gap:.35em }
.recorte a.opt:hover, .pag a.opt:hover, .vista a.opt:hover{ background:var(--f2); color:var(--tx) }
/* VIDEO REVERSO no selecionado. E o unico contraste que sobrevive a 12px num tema escuro. */
.recorte b.opt, .pag b.opt, .vista b.opt{ background:var(--tx); color:var(--f0); font-weight:600 }

/* A contagem e APOIO, nao rotulo: recua um degrau de cor e um de tamanho. */
.recorte .opt .n{ color:var(--tx3); font:var(--fs-1)/1 var(--font-data) }
.recorte b.opt .n, .pag b.opt .n{ color:var(--f0); opacity:.55 }

/* O `show` e a NUMERACAO do projeto (`11806`), curta por construcao — nao ha o que truncar. O
   `max-width` fica como rede: o balde "(sem job)" e um valor declarado sem depot ainda passam
   por aqui e nada garante que sejam curtos. */
.recorte .opt{ max-width:22rem; overflow:hidden; text-overflow:ellipsis }
/* O aviso de corte e TEXTO e nao pode parecer chip: sem fundo, sem padding de alvo. */
.recorte .resto, .vista .resto{ color:var(--tx3); font-size:11px; padding-left:.35rem }

/* ---------------------------------------------------------------------------------------
   A UNICA barra de recorte com chips `<button>` e a da /farm (`_barra_show_farm`), e o motivo
   esta la: nao ha URL para onde ir — o recorte acontece sobre a tabela que ja esta na pagina.
   Tres regras, e nenhuma e gosto:

   1. `font:inherit`. Botao NAO herda fonte do container por regra de UA. Sem esta linha a barra
      sairia em fonte de sistema no meio de uma tela monoespacada — exatamente o rag que a
      reforma de 19/08 acima existe para tirar, e que ninguem veria num teste de substring.
   2. O selecionado nao pode ser `<b class="opt">` como no mural: la o servidor sabe qual esta
      ativo (vem na URL), aqui o estado vive no cliente. O video reverso vem de `aria-pressed`,
      que ja e o atributo que o leitor de tela le — um estado visual sem par acessivel seria
      duas verdades diferentes na mesma barra.
   3. O `:hover` e escopado em `[aria-pressed="false"]`. Sem isso ele apagaria o video reverso do
      chip ATIVO ao passar o mouse, e "onde eu estou?" — a unica pergunta que este controle
      existe para responder — ficaria sem resposta justo enquanto se aponta para ele. */
.recorte button.opt, .vista button.opt{ font:inherit; cursor:pointer }
.recorte button.opt[aria-pressed="false"]:hover,
.vista button.opt[aria-pressed="false"]:hover{ background:var(--f2); color:var(--tx) }
.recorte button.opt[aria-pressed="true"],
.vista button.opt[aria-pressed="true"]{ background:var(--tx); color:var(--f0); font-weight:600 }
.recorte button.opt[aria-pressed="true"] .n{ color:var(--f0); opacity:.55 }
/* O `·` da .pag some: ele separava opcoes que ja tem respiro proprio. O da .cont fica, porque
   la ele separa FRASES ("mostrando 1-50 de 62 · pagina 1 de 2") e nao controles. */
.pag > .sep{ display:none }
.pag .sep{ color:var(--linha-forte) }

.avisos{ background:var(--f1); border:1px solid var(--linha); border-radius:var(--r-2);
  padding:.5rem .7rem .55rem; margin:.9rem 0; font-size:var(--fs-2) }
.avisos > .rot{ display:block; margin-bottom:.25rem }
.avisos p{ margin:.2rem 0; color:var(--tx2); max-width:none }
.avisos p b{ color:var(--tx) }
/* A legenda da tira e a unica linha PERMANENTE da caixa: ela nao noticia nada,
   so explica o que a cor significa. Fica no fim e mais apagada que os avisos de
   verdade, para nao competir com eles. */
.avisos p.legenda{ color:var(--tx3); border-top:1px solid var(--linha);
  margin-top:.45rem; padding-top:.4rem }

/* ---------------------------------------------- 5d. triagem de alerta */
/* A acao fica JUNTO do que ela afeta, logo abaixo das miniaturas do job. Caixa discreta e sem
   tinta de excecao: triar nao e emergencia, e um controle vermelho ao lado de miniaturas vermelhas
   competiria com o proprio alerta que se esta lendo. */
.triagem{ display:flex; flex-wrap:wrap; align-items:center; gap:.45rem;
  background:var(--f1); border:1px solid var(--linha); border-radius:var(--r-2);
  padding:.4rem .7rem; margin:.35rem 0 1.1rem; font:var(--fs-2)/1.5 var(--font-ui) }
.triagem select, .triagem input{ background:var(--f0); color:var(--tx);
  border:1px solid var(--linha-forte); border-radius:var(--r-2); padding:.35rem .5rem;
  font:var(--fs-2)/1.4 var(--font-ui) }
.triagem input{ flex:1 1 16rem; min-width:0 }
.triagem button{ background:var(--f2); color:var(--tx);
  border:1px solid var(--linha-forte); border-radius:var(--r-2); padding:.4rem .8rem;
  font:500 var(--fs-2)/1.4 var(--font-ui); cursor:pointer; min-height:30px }
.triagem button:hover{ border-color:var(--tx2) }
.triagem .fraco{ flex-basis:100%; font-size:11px }
/* Coluna de acoes de tabela (jobs escondidos do mural, alertas triados). */
td.acoes{ display:flex; flex-wrap:wrap; gap:.35rem; align-items:center }
td.acoes form{ display:flex; gap:.3rem; align-items:center }
td.acoes input{ background:var(--f0); color:var(--tx); border:1px solid var(--linha-forte);
  border-radius:var(--r-2); padding:.3rem .5rem; font:var(--fs-2)/1.4 var(--font-ui); width:9rem }
/* O `select` de papel entrou em 2026-09-02 e precisa da MESMA moldura do input -- sem esta regra
   ele herda o widget do sistema operacional, que no tema escuro sai branco no meio da linha.
   `width:auto` de proposito: os 9rem do input deixariam o dropdown maior que o conteudo dele. */
td.acoes select{ background:var(--f0); color:var(--tx); border:1px solid var(--linha-forte);
  border-radius:var(--r-2); padding:.3rem .4rem; font:var(--fs-2)/1.4 var(--font-ui); width:auto;
  cursor:pointer }
/* Botoes de acao em linha de tabela (pausar/retomar/matar na farm, verbos de usuario): pilula
   compacta com o mesmo vocabulario do resto (2026-09-06, "os botoes ali estao bem feios"). O
   `perigo` continua vermelho por `button.perigo`, abaixo. */
td.acoes button{ background:var(--bg-surface); color:var(--text-secondary);
  border:1px solid var(--border-strong); border-radius:999px; padding:.25rem .8rem;
  font:600 var(--fs-1)/1.3 var(--font-ui); letter-spacing:.01em; cursor:pointer; min-height:28px;
  transition:color var(--dur-1) var(--ease-out), border-color var(--dur-1) var(--ease-out),
             background var(--dur-1) var(--ease-out) }
td.acoes button:hover{ color:var(--text-strong); border-color:var(--text-tertiary);
  background:var(--bg-raised) }
td.acoes button.btn{ color:var(--accent-text); background:var(--accent); border-color:var(--accent) }
td.acoes button.btn:hover{ filter:brightness(1.08) }
/* T042: quatro grupos SEMANTICOS. nth-child ficou defasado ao acrescentar ultimo acesso,
   e td.acoes flex desmontava a celula da tabela. Flex/grid vivem DENTRO das celulas. */
.tabela-usuarios{ margin-top:1.4rem }
/* `max-width` e nao so `width:100%`: em monitor largo a tabela esticava para ~1600px e cada
   celula virava um vao com uma palavra no meio. O conteudo desta tela (nome, tres datas, um
   campo curto e dois controles) nao cresce com a tela, entao a tabela nao deve crescer junto.
   68rem foi MEDIDO, nao escolhido: com `table-layout:auto` o conteudo desta tela pede 945px
   (217/255/217/255 por coluna) mais 26px de padding em cada uma, ou seja ~1050px. Em 62rem o
   nome de usuario longo passou a quebrar no MEIO da palavra -- apertar mais que o conteudo
   troca um vao feio por um nome ilegivel. */
.tabela-usuarios table{ table-layout:fixed; width:100%; max-width:68rem; min-width:0 }
.tabela-usuarios .usuario-conta{ width:24% }
.tabela-usuarios .usuario-atividade{ width:27% }
.tabela-usuarios .usuario-apelidos{ width:22% }
.tabela-usuarios .usuario-acoes{ width:27% }
.tabela-usuarios .fila th{ padding:.65rem .8rem }
.tabela-usuarios .fila td{ padding:1rem .8rem; vertical-align:top; overflow-wrap:anywhere }
.usuario-conta > strong{ display:block; color:var(--tx); font-size:var(--fs-3) }
.usuario-selos{ display:flex; flex-wrap:wrap; gap:.3rem; margin:.4rem 0 }
.usuario-papel-selo{ border:1px solid var(--linha-forte); border-radius:4px;
  padding:.05rem .4rem; font-size:var(--fs-1); color:var(--tx2) }
.usuario-estado{ font-size:var(--fs-2); line-height:1.6; max-width:25rem }
.usuario-estado[data-estado="ativo"]::before{ content:""; display:inline-block;
  width:6px; height:6px; border-radius:50%; background:var(--ok); margin-right:.4rem }
.usuario-atividade dl{ margin:0; display:grid; grid-template-columns:max-content minmax(0,1fr);
  gap:.35rem .8rem; font-size:var(--fs-2); line-height:1.6; font-variant-numeric:tabular-nums }
.usuario-atividade dt{ color:var(--tx3) }
.usuario-atividade dd{ margin:0; color:var(--tx2) }
.tabela-usuarios form{ margin:0 }
.tabela-usuarios form.apelidos, .usuario-papel{ display:flex; align-items:center; gap:.4rem }
/* O campo guarda uma lista curta de apelidos, quase sempre um so. Ocupar a coluna inteira dava
   a impressao de que se espera um texto longo -- e o `salvar` ao lado ficava longe do que salva. */
.tabela-usuarios form.apelidos{ max-width:20rem }
.tabela-usuarios input.busca{ flex:1 1 0; min-width:0; width:100%; margin:0 }
.tabela-usuarios button, .tabela-usuarios select, .usuario-convite input,
.usuario-convite select, .usuario-convite button{ box-sizing:border-box; min-height:34px;
  padding:.4rem .65rem; border:1px solid var(--linha-forte); border-radius:var(--r-2);
  background:var(--f1); color:var(--tx); font:var(--fs-2)/1.4 var(--font-ui) }
.tabela-usuarios input.busca{ box-sizing:border-box; min-height:34px;
  padding:.4rem .65rem; font:var(--fs-2)/1.4 var(--font-ui) }
.tabela-usuarios button, .usuario-convite button{ cursor:pointer; flex-shrink:0;
  white-space:nowrap; font-weight:600 }
.tabela-usuarios button:hover, .usuario-convite button:hover{ background:var(--f2);
  border-color:var(--tx2) }
.usuario-papel select{ flex:1 1 auto; min-width:0; max-width:11rem }
.usuario-acoes-grupo{ display:flex; flex-direction:column; align-items:flex-start; gap:.65rem }
.usuario-acoes-grupo > .opt{ padding:0; min-height:0; text-decoration:underline;
  text-underline-offset:3px; background:none; border:0 }
.usuario-acesso{ width:100% }
.usuario-acesso summary{ width:fit-content; font-size:var(--fs-2); color:var(--tx2);
  cursor:pointer; padding:.25rem 0; min-height:28px; box-sizing:border-box }
.usuario-acesso-botoes{ display:flex; flex-wrap:wrap; gap:.45rem; padding:.6rem 0 .2rem }
.tabela-usuarios button.perigo{ border-color:var(--danger); color:var(--danger-text) }
.usuario-convite{ margin-top:1.8rem; padding:1.2rem; background:var(--f1);
  border:1px solid var(--linha); border-radius:var(--r-2); max-width:56rem }
.usuario-convite h3{ margin:0 0 .4rem }
.usuario-convite-form{ display:flex; flex-wrap:wrap; align-items:flex-end; gap:.8rem;
  margin:1rem 0 }
.usuario-convite-form > div{ flex:1 1 12rem; min-width:0 }
.usuario-convite label{ display:block; color:var(--tx2); font-size:var(--fs-2);
  margin-bottom:.4rem }
.usuario-convite input, .usuario-convite select{ width:100%; background:var(--f0) }
@media(max-width:1100px){
  .tabela-usuarios thead{ position:absolute; width:1px; height:1px; overflow:hidden;
    clip-path:inset(50%); white-space:nowrap }
  .tabela-usuarios table, .tabela-usuarios tbody{ display:block }
  .tabela-usuarios .usuario-linha{ display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr);
    gap:1rem 1.4rem; border:1px solid var(--linha); border-radius:var(--r-2);
    padding:1rem; margin-bottom:.8rem }
  .tabela-usuarios .fila td{ display:block; width:auto; min-width:0; border:0; padding:0 }
  .usuario-apelidos::before, .usuario-acoes::before{ content:attr(data-label); display:block;
    margin-bottom:.55rem; text-transform:uppercase; font-size:var(--fs-1); color:var(--tx3) }
}
@media(max-width:600px){
  .tabela-usuarios .usuario-linha{ grid-template-columns:minmax(0,1fr) }
  .usuario-atividade dl{ grid-template-columns:7rem minmax(0,1fr) }
  .usuario-papel{ width:100% }
  .usuario-convite-form{ flex-direction:column; align-items:stretch }
  .usuario-convite-form > div{ flex:auto }
}
/* Identidade de job sempre explicita e selecionavel; nome nao e chave unica. */
.job-ref{ display:inline-flex; align-items:baseline; gap:.4rem; max-width:100%;
  box-sizing:border-box; padding:.2rem .45rem; margin:.3rem 0;
  border:1px solid var(--linha-forte); border-radius:var(--r-2); background:var(--f1);
  vertical-align:middle; font:500 var(--fs-1)/1.5 var(--font-ui); color:var(--tx2);
  text-transform:none; letter-spacing:normal; white-space:normal; text-indent:0 }
.job-ref > span{ flex-shrink:0 }
.job-ref code{ min-width:0; padding:0; background:none; border:0; border-radius:0;
  color:var(--tx); font:600 var(--fs-2)/1.5 var(--font-data); overflow-wrap:anywhere;
  user-select:all; -webkit-user-select:all }
td > .job-ref, .card .job-ref, .ativo .nome > .job-ref{ display:flex; width:fit-content }
/* ⚠️ DENTRO DE TABELA O ID NAO QUEBRA. O `overflow-wrap:anywhere` do `code` existe para card e
   telefone, onde a largura e do tamanho da tela; numa coluna estreita de tabela ele partia um id
   de dez caracteres em tres linhas (`f358`/`ad81`/`9e`), que alem de feio e ilegivel como
   identidade. A tabela ja vive dentro de `.rolagem`, entao alargar a coluna e o custo certo --
   truncar seria pior, porque dois renders homonimos so se distinguem pelo id inteiro.
   ⚠️ SELETOR DESCENDENTE, e nao filho direto: em /resolvidos o `.job-ref` vem dentro de um `<a>`,
   entao `td > .job-ref` nao casa. Foi assim que a primeira tentativa desta correcao nao pegou --
   o `white-space` computado continuou `normal` e o id passou a quebrar LETRA A LETRA. */
td .job-ref{ white-space:nowrap }
td .job-ref code{ overflow-wrap:normal; word-break:normal }
/* Contrapeso do nowrap acima em /resolvidos: a coluna do job cresceu ~50px e, com
   `table-layout:auto`, quem pagou foi a observacao -- caiu para 143px e empilhou o texto em dez
   linhas. O caminho de preview passa de 60 caracteres e tomava 540px sozinho; limita-lo devolve
   a largura a coluna que carrega a frase escrita por uma pessoa. */
.triados-arquivo{ max-width:26rem; overflow-wrap:anywhere }
.barra .job-ref{ flex-shrink:0; margin:0 }
/* PERIGO tem a matiz do `vazio`, e e o unico lugar fora de sanidade que a usa. E deliberado: a
   equipe ja aprendeu que vermelho aqui significa "isto destroi"; inventar uma quinta matiz para
   acao destrutiva seria pedir para aprender de novo o que ja se sabe. Contorno, e nao preenchido —
   o botao nao pode gritar mais que a faixa de alerta do topo. */
button.perigo{ border-color:var(--danger); color:var(--danger-text) }
/* Acoes de job na fila da /farm. Empilhadas e nao lado a lado: a coluna e estreita (a tabela tem
   sete outras) e dois botoes em linha espremeriam o rotulo ate `pau...`. Empilhado cada um fica
   legivel, e `matar` ganha distancia do `pausar` — que numa fila que reordena sozinha nao e
   detalhe estetico. */
.acoes-job{ display:flex; flex-direction:column; gap:.3rem; align-items:stretch; min-width:6.5rem }
.acoes-job form{ margin:0 }
/* Os dois verbos da fila com a MESMA pilula da coluna de acoes (`td.acoes button`, acima): antes
   `pausar` herdava o `.btn` transparente e saia como texto solto ao lado de um `matar` contornado
   (2026-09-06, "os botoes ali estao bem feios"). O vermelho do `perigo` continua sendo a unica
   diferenca entre eles. */
.acoes-job button, .acoes-job button.btn{ width:100%; justify-content:center;
  background:var(--bg-surface); color:var(--text-secondary); border:1px solid var(--border-strong);
  border-radius:999px; padding:.25rem .8rem; font:600 var(--fs-1)/1.3 var(--font-ui);
  letter-spacing:.01em; min-height:28px; cursor:pointer;
  transition:color var(--dur-1) var(--ease-out), border-color var(--dur-1) var(--ease-out),
             background var(--dur-1) var(--ease-out) }
.acoes-job button.btn:hover{ color:var(--text-strong); border-color:var(--text-tertiary);
  background:var(--bg-raised) }
.acoes-job button.perigo{ border-color:var(--danger); color:var(--danger-text) }
/* O par positivo do `perigo`, de 2026-09-15. Ativar e desativar saiam como DUAS pilulas cinzas
   identicas, e o pedido do usuario foi "acender" os dois: agora a cor separa o verbo que poe o
   host na fila do que o tira dela, sem depender de ler o rotulo. */
.acoes-job button.acao{ border-color:var(--accent); color:var(--accent) }
.acoes-job button.acao:hover{ background:var(--accent); color:var(--accent-text);
  border-color:var(--accent) }
/* Travado no clique (`data-trava`): o botao para de convidar e diz que ja foi. Sem isto o
   `disabled` herdaria a cor acesa e continuaria parecendo clicavel. */
.acoes-job button[disabled]{ opacity:.55; cursor:progress; border-color:var(--border-strong);
  color:var(--text-tertiary); background:var(--bg-surface) }
.acoes-job button[disabled]:hover{ background:var(--bg-surface); color:var(--text-tertiary);
  border-color:var(--border-strong) }
button.perigo:hover{ background:var(--t-vazio); border-color:var(--vazio) }

/* --------------------------------------------- MANUAL DE USO (/manual, 2026-09-06)
   Leitura longa numa tela feita para varredura: indice fixo a esquerda em tela larga, corpo com
   largura de leitura, e as FIGURAS sao componentes reais do portal (tira, trilho, badges, detalhe
   de capacidade) dentro de uma moldura -- por isso herdam tema e densidade sem regra propria. */
.manual{ display:grid; grid-template-columns:14rem minmax(0,1fr); gap:var(--sp-6);
  align-items:start; margin-top:var(--sp-4) }
.manual-indice{ position:sticky; top:var(--sp-4); font:var(--fs-2)/1.5 var(--font-ui) }
.manual-indice ol{ margin:0; padding:0 0 0 1.4rem }
.manual-indice li{ margin:.15rem 0 }
.manual-indice a{ color:var(--tx2); text-decoration:none }
.manual-indice a:hover{ color:var(--tx); text-decoration:underline }
.manual-conteudo{ min-width:0; max-width:64rem; font:var(--fs-3)/1.6 var(--font-ui) }
.manual-conteudo p, .manual-conteudo li{ max-width:70ch }
.manual-secao{ margin:0 0 var(--sp-7); padding-top:var(--sp-2); scroll-margin-top:var(--sp-4) }
.manual-secao h2{ margin:0 0 var(--sp-3); padding-bottom:var(--sp-2);
  border-bottom:1px solid var(--linha) }
.manual-secao h3{ margin:var(--sp-5) 0 var(--sp-2); font-size:var(--fs-4) }
.manual-papel{ display:inline-block; vertical-align:middle; margin-left:.6rem; padding:.1rem .55rem;
  border-radius:999px; background:var(--f2); color:var(--tx2);
  font:600 var(--fs-1)/1.5 var(--font-ui); letter-spacing:.02em; text-transform:uppercase }
.manual-ui{ color:var(--tx); font-weight:600 }
.manual-figura{ margin:var(--sp-3) 0 var(--sp-4); padding:var(--sp-3);
  border:1px solid var(--linha); border-radius:var(--r-2); background:var(--f1) }
.manual-figura-corpo{ overflow-x:auto }
.manual-figura figcaption{ margin-top:var(--sp-2); color:var(--tx2);
  font:var(--fs-2)/1.45 var(--font-ui) }
.manual-nota{ margin:var(--sp-3) 0; padding:.6rem .85rem; border-radius:var(--r-2);
  background:var(--f1); border-left:3px solid var(--accent); max-width:70ch }
.manual-nota[data-tipo="atencao"]{ border-left-color:var(--danger) }
.manual-passos li{ margin:.35rem 0 }
.manual-tabela{ margin:var(--sp-3) 0 }
.manual-tabela td, .manual-tabela th{ vertical-align:top }
.manual-faq td:first-child{ font-weight:600; width:30% }
.manual-sim{ color:var(--ok); font-weight:600 }
.manual-nao{ color:var(--tx3) }
/* O fluxo de ponta a ponta: seis passos em grade, numerados; sem seta desenhada porque a ordem de
   leitura ja e a ordem dos numeros e uma seta viraria ruido em tela estreita. */
.manual-fluxo{ list-style:none; margin:0; padding:0; display:grid; gap:var(--sp-2);
  grid-template-columns:repeat(auto-fit, minmax(10.5rem, 1fr)) }
.manual-fluxo li{ display:flex; flex-direction:column; gap:.2rem; padding:.6rem .7rem;
  background:var(--f0); border:1px solid var(--linha); border-radius:var(--r-2);
  font:var(--fs-2)/1.45 var(--font-ui) }
.manual-fluxo-n{ font:700 var(--fs-1)/1 var(--mono); color:var(--accent) }
.manual-cards{ max-width:19rem }
.manual-capa-falsa{ display:block; aspect-ratio:16/9;
  background:linear-gradient(135deg, var(--f2), var(--f0)) }
.manual-glossario dt{ font-weight:600; margin-top:.55rem }
.manual-glossario dd{ margin:0; color:var(--tx2) }
.manual-topo{ margin-top:var(--sp-3); font-size:var(--fs-1) }
.manual-topo a{ color:var(--tx3) }
@media (max-width:60rem){
  .manual{ grid-template-columns:1fr }
  .manual-indice{ position:static }
}

/* --------------------------------------------- 6. cards (mural e worker) */
.cards{ display:grid; gap:.7rem;
  grid-template-columns:repeat(auto-fill, minmax(var(--col-card), 1fr)) }
.card{ position:relative; background:var(--f1); border:1px solid var(--linha);
  border-radius:var(--r-2); overflow:hidden; display:flex; flex-direction:column }
/* estado do job = regua de 3 px no TOPO (nao borda esquerda: a capa encosta
   no topo e a regua vira a moldura de estado dela) */
.card[data-sev="vazio"]{ box-shadow:inset 0 3px 0 var(--vazio) }
.card[data-sev="suspeito"]{ box-shadow:inset 0 3px 0 var(--suspeito) }
/* Job em que NADA pode ser medido. Regua cinza, e nao ausencia de regua: ausencia e o que o card
   verde ja e, e era exatamente isso que estava errado — um job sem nenhuma medida ficava
   indistinguivel de um job avaliado e aprovado. (Ate 08/09 a causa comum era job 100% passe
   tecnico; passe passou a ter veredito, e sobrou o job sem metrica no manifesto.) */
.card[data-sev="nao_avaliado"]{ box-shadow:inset 0 3px 0 var(--nao-avaliado) }
.card .capa{ display:block; background:var(--letterbox); border-bottom:1px solid var(--border) }
/* contain tambem aqui: `cover` e `contain` só divergem quando recortar
   mentiria (elemento quadrado, saida vertical). Logo contain custa zero. */
.card .capa img{ display:block; width:100%; aspect-ratio:16/9;
  object-fit:contain; background:var(--letterbox) }
.card .corpo{ padding:.55rem .7rem .65rem }
.card h3{ margin:0 0 .15rem; font:600 var(--fs-4)/1.3 var(--font-display); letter-spacing:0;
  text-transform:none; color:var(--tx) }
.card .ident{ display:block; font:var(--fs-1)/1.5 var(--font-data); color:var(--tx3);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
.card .meta{ color:var(--tx2); font-size:var(--fs-2) }

/* tira de sanidade: proporcao vazio/suspeito/passe/ok legivel de canto de olho.
   min-width nos segmentos de alerta -> 1 vazio em 300 NAO desaparece. */
.tira{ display:flex; height:5px; margin:.5rem 0 .4rem; background:var(--linha) }
.tira i{ display:block; min-width:2px }
.tira i[data-s="vazio"]{ background:var(--vazio); min-width:4px }
.tira i[data-s="suspeito"]{ background:var(--suspeito); min-width:4px }
/* Era `--linha-forte` (#3d3d3d): a 5 px de altura sobre `--f1` o segmento praticamente
   desaparecia, entao um job {ok: 14, nao_avaliado: 106} desenhava uma tira que parecia vazia com
   um risco verde — a leitura oposta da proporcao real. */
.tira i[data-s="nao_avaliado"]{ background:var(--nao-avaliado) }
.tira i[data-s="ok"]{ background:var(--ok); opacity:.55 }

/* worker: problema tem TEXTURA, nao so matiz — sobrevive a TV descalibrada e
   fora de eixo, onde vermelho e ambar convergem. */
.card[data-st]{ box-shadow:inset 3px 0 0 var(--tx3) }
.card[data-st="rendering"]{ box-shadow:inset 3px 0 0 var(--ok) }
.card[data-st="stalled"]{ box-shadow:inset 3px 0 0 var(--suspeito) }
.card[data-st="offline"]{ box-shadow:inset 3px 0 0 var(--vazio) }
.card[data-st="stalled"]::before, .card[data-st="offline"]::before{
  content:""; position:absolute; inset:0 0 auto 0; height:5px;
  background:repeating-linear-gradient(45deg, var(--suspeito) 0 7px,
                                       var(--stripe-gap) 7px 14px) }
.card[data-st="offline"]::before{
  background:repeating-linear-gradient(45deg, var(--vazio) 0 7px,
                                       var(--stripe-gap) 7px 14px) }
.card[data-st="stalled"], .card[data-st="offline"]{ padding-top:2px }
.card .capa-worker{ display:block; margin:.4rem 0 0 }
/* Capacidade do host. `line-height` folgado porque a linha quebra em host com muitas tags, e
   apertado ela vira um bloco ilegivel no card estreito. */
.card .capacidade{ margin-top:.25rem; line-height:1.5 }
/* Tag de host: retangulo discreto, NAO colorido por significado. Pintar `windows` de verde faria
   a tela julgar elegibilidade, e o limiar que decide isso vive no `crion`, fora daqui. */
/* Lista de definicao da capacidade: rotulo estreito a esquerda, valor a direita. `grid` em vez
   de `float` porque a tag e a unica celula que pode quebrar em varias linhas. */
.capdl{ display:grid; grid-template-columns:max-content 1fr; gap:.15rem .6rem;
  margin:.4rem 0 .3rem }
.capdl dt{ color:var(--tx2); font-size:11px; text-transform:uppercase; letter-spacing:.04em }
.capdl dd{ margin:0; font-size:12px }
/* Tabela de workers. A miniatura fica pequena e com altura fixa: numa tabela de 31 linhas, thumb
   de tamanho livre faria cada linha ter uma altura diferente e destruiria a varredura vertical,
   que e a razao de ser da tabela. */
/* Gaveta dos workers. O `summary` e a barra de resumo: quando fechada, ela E o painel, entao
   carrega os numeros que respondem "preciso abrir?" sem abrir.
   NAO herda `.gaveta`: aquela classe e do painel lateral e traz `max-height:38vh; overflow:auto`,
   que espremia as 31 linhas numa caixa rolante de 250px DENTRO da pagina -- duas barras de
   rolagem aninhadas e a tabela transbordando por cima do que vinha depois. Medido em
   2026-09-01: a gaveta media 250px com um filho de 1705px. */
.gaveta-workers > summary{ cursor:pointer; list-style:none; font-size:15px; font-weight:600;
  margin:1.1rem 0 .5rem; padding:.25rem 0 }
.gaveta-workers > summary::-webkit-details-marker{ display:none }
.gaveta-workers > summary::before{ content:"\25B8"; display:inline-block; width:1em; opacity:.6 }
.gaveta-workers[open] > summary::before{ content:"\25BE" }
.workers td{ vertical-align:middle }
/* Detalhe de frame morto, na coluna `erros` da fila. FECHADO por padrao e SEM marcador nativo,
   como as outras gavetas desta arvore: a /farm fica o dia inteiro numa TV de parede, onde cada
   linha que cresce empurra as outras para fora do enquadramento. O triangulo `::before` e o mesmo
   idioma da `.gaveta-workers`, para o olho reconhecer "isto abre" sem legenda. */
.falha-det{ margin-top:.3rem }
.falha-det > summary{ cursor:pointer; list-style:none; font-size:11px; color:var(--tx2) }
.falha-det > summary::-webkit-details-marker{ display:none }
.falha-det > summary::before{ content:"\25B8"; display:inline-block; width:1em; opacity:.6 }
.falha-det[open] > summary::before{ content:"\25BE" }
.falha-lista{ margin:.3rem 0 0; padding-left:1rem; font-size:11px; line-height:1.5 }
.falha-lista code{ font-size:11px }
.workers .capa-worker{ display:block; width:64px }
.workers .capa-worker img{ display:block; width:64px; height:36px; object-fit:cover;
  background:var(--letterbox); border-radius:var(--r-1) }
.workers td[data-col="frame"]{ width:64px; padding-top:.2rem; padding-bottom:.2rem }
.workers td[data-col="tags"]{ line-height:1.6; min-width:9rem }
/* Tela de tags do admin. A barra de orcamento e informacao, nao enfeite: ela mostra o quanto do
   teto de `host.str_tags` no Cuebot ja foi gasto, e e a unica pista visual de que existe um teto.
   O numero vive em `crion_tags.LIMITE_STR_TAGS` (128 ate 2026-09-09, 256 depois do ALTER) e NAO
   e escrito aqui: comentario que repete valor de infra vira o proximo a mentir. */
.tagsadm td{ vertical-align:middle }
.tagsadm td[data-col="tags"]{ line-height:2 }
.orc{ display:flex; align-items:center; gap:.4rem; white-space:nowrap; font-size:11px }
.orc .barra{ display:inline-block; width:76px; height:7px; background:var(--f2);
  border-radius:var(--r-2); overflow:hidden }
.orc .preench{ display:block; height:7px }
.orc .preench.ok{ background:var(--ok) }
.orc .preench.suspeito{ background:var(--suspeito) }
.orc .preench.vazio{ background:var(--vazio) }
.orc .num{ font:11px/1 var(--mono) }
/* Tag do Cuebot: visivelmente diferente da manual, e SEM botao de remover. O operador
   precisa ver que ela existe e que nao sai por aqui; esconde-la faria ele procurar por que
   a soma nao bate. */
.tagsadm .tag-host .x{ background:none; border:0; color:inherit; cursor:pointer;
  padding:0 0 0 .2rem; font-size:12px; line-height:1; opacity:.6 }
.tagsadm .fixa{ opacity:.45; font-style:italic; background:transparent;
  border:1px dashed var(--linha) }
.tagsadm .tag-host .x:hover{ opacity:1; color:var(--alerta) }
.tagsadm .add{ display:inline-block; margin-left:.4rem; white-space:nowrap }
/* Nome do worker NAO quebra. `rqd-replica-01` partido em tres linhas foi o que mais inflou a
   linha na largura estreita -- e o nome e justamente a coluna que se le em varredura vertical.
   Preferimos a rolagem horizontal, que a tabela ja tem, a uma coluna de altura variavel. */
.workers td[data-col="worker"]{ white-space:nowrap }
.workers td[data-col="ip"]{ white-space:nowrap }
.workers td[data-col="job"] a{ white-space:nowrap }
/* ⚠️ MAS NO CARD O `nowrap` ESTOURA A CAIXA. Em tabela ele esta certo -- coluna estreita com
   nome quebrado em duas linhas desalinha a grade inteira. No layout de CARD a largura e do
   cartao, e o nome de job desta farm passa de 70 caracteres
   (`overwatch_blizzard_prison_break1_prison_break-sh0670-admin_assembly_sc03_sh0670`) sem um
   unico espaco: o `_` nao e ponto de quebra, entao o texto saia por cima do cartao vizinho.
   Visto pelo usuario em 2026-09-11, na tela da farm com tres workers.
   `anywhere` e nao `break-word` porque so ele quebra token sem espaco nenhum. */
.workers:not(.tabular) td[data-col="job"] a{ white-space:normal; overflow-wrap:anywhere }
/* Painel colapsado. `summary` com cursor e marcador discreto: ele e clicavel e precisa parecer.
   `list-style` nativo some no Safari, entao o triangulo vem do `::before`. */
.eleg-painel{ padding:.5rem .7rem }
.eleg-painel > summary{ cursor:pointer; list-style:none; font-size:12px; color:var(--tx2) }
.eleg-painel > summary::-webkit-details-marker{ display:none }
.eleg-painel > summary::before{ content:"\25B8"; display:inline-block; width:1em; opacity:.6 }
.eleg-painel[open] > summary::before{ content:"\25BE" }
.eleg-painel[open] > summary{ margin-bottom:.3rem }
/* Tabela de elegibilidade: numeros a esquerda, barra proporcional a direita. A barra nao e
   enfeite — ela mostra o degrau (duas faixas com a mesma largura = subir o limiar nao custa
   maquina) mais rapido que a leitura dos numeros. */
.eleg table{ border-collapse:collapse; margin:.4rem 0 .3rem; width:100% }
.eleg td{ padding:.1rem .5rem .1rem 0; font-size:12px; white-space:nowrap }
.eleg td:first-child{ color:var(--tx2) }
.barra-eleg{ width:40%; min-width:60px }
.barra-eleg span{ display:block; height:6px; background:var(--tx2); opacity:.55; border-radius:var(--r-1) }
.tag-host{ display:inline-block; padding:0 .25rem; margin:0 .1rem .1rem 0; border-radius:var(--r-1);
  background:var(--bg-raised); color:var(--tx2); font-size:10.5px; letter-spacing:.02em }
.card .capa-worker img{ display:block; width:100%; aspect-ratio:16/9;
  object-fit:contain; background:var(--letterbox) }

/* ------------------------------------ 7. folha de contato (grade + thumb) */
/* Sem borda, sem raio, sem fundo no container: os 2 px de gap mostram a
   pagina e viram o fio da folha de contato. Container com background vazava
   um bloco cinza nas celulas vazias da ultima linha. */
.grade{ display:grid; gap:2px; align-content:start;
  grid-template-columns:repeat(auto-fill, minmax(var(--col-thumb), 1fr)) }
/* CARTAO DE FRAME MENOR NA TRIAGEM (spec 010), e SO na triagem.

   Pedido do usuario: "da p diminuir o tamanho dos cards dos frames". O `--col-thumb` global vale
   para o mural e para a ficha do shot, onde a thumb grande E o produto — encolher la tiraria a
   capacidade de julgar o frame olhando. Aqui a pergunta e outra: quantos frames alertados cabem na
   tela de uma vez, para a pessoa decidir sobre o conjunto sem rolar.

   `--col-thumb-triagem` corta ~40% da largura minima, o que dobra a densidade por linha sem tocar
   na proporcao 16/9 nem no rotulo — a informacao que sustenta a decisao (numero do frame, tons,
   badge de sanidade) continua inteira, so mais compacta. */
.alertas .grade{
  --col-thumb-triagem: clamp(110px, 9vw, 180px);
  grid-template-columns:repeat(auto-fill, minmax(var(--col-thumb-triagem), 1fr)) }
.incidente-job{ border:1px solid var(--border); border-radius:6px; padding:1rem;
  margin:1rem 0; overflow-wrap:anywhere }
.incidente-job h3{ margin:0 0 .7rem }
.incidentes-job{ list-style:none; padding:0; margin:.6rem 0 }
.incidentes-job li{ padding:.55rem 0; border-bottom:1px solid var(--border) }
.incidentes-job li:last-child{ border-bottom:0 }
.incidente-job details{ margin-top:.7rem }
.incidente-job summary{ cursor:pointer; padding:.45rem 0 }
/* A caixa fica sobre a thumb, no canto: fora dela a caixa criaria uma faixa propria e devolveria
   em altura o que a coluna economizou. `z-index` porque a thumb tem `position:relative`. */
.cartao-frame{ position:relative; display:block }
.cartao-frame .sel-frame{ position:absolute; top:3px; left:3px; z-index:2;
  width:14px; height:14px; cursor:pointer;
  accent-color:var(--tx2); filter:drop-shadow(0 1px 2px var(--shadow-ink)) }
.thumb{ position:relative; display:block; background:var(--letterbox);
  border:0; border-radius:0; overflow:hidden }
/* NUNCA cover: cortar o frame esconde exatamente onde o defeito pode estar —
   e em elemento com alpha, o corte tira a borda que se esta conferindo. */
.thumb img{ display:block; width:100%; aspect-ratio:16/9;
  object-fit:contain; background:var(--letterbox) }
.thumb[data-tipo="elemento"] img{ background:
  repeating-conic-gradient(var(--xadrez-a) 0% 25%, var(--xadrez-b) 0% 50%)
  0 0/12px 12px }
.thumb .rotulo{ position:absolute; inset:auto 0 0 0; display:flex;
  align-items:center; gap:.35em; padding:.2rem .4rem;
  font:10px/1.5 var(--mono); color:var(--over-image-text);
  text-shadow:0 1px 2px var(--over-image-shadow), 0 0 3px var(--over-image-shadow);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
.thumb .rotulo .detalhe{ opacity:0; transition:none }
.thumb:hover .rotulo .detalhe, .thumb:focus-visible .rotulo .detalhe{ opacity:1 }
/* alerta nunca se esconde atras de hover */
.thumb[data-s="vazio"] .rotulo .detalhe,
.thumb[data-s="suspeito"] .rotulo .detalhe{ opacity:1 }

/* O estado marca o THUMB INTEIRO, nao so o rotulo: e o que faz um frame vazio
   saltar de uma folha de 60 imagens sem ninguem ler rotulo nenhum.
   outline (nao box-shadow inset) porque outline pinta ACIMA do <img>. */
.thumb[data-s="vazio"]{ outline:2px solid var(--vazio); outline-offset:-2px }
.thumb[data-s="suspeito"]{ outline:2px solid var(--suspeito); outline-offset:-2px }
.thumb[data-s="vazio"]::after{ content:""; position:absolute; top:0; right:0;
  border:11px solid transparent;
  border-top-color:var(--vazio); border-right-color:var(--vazio) }
.thumb[data-s="suspeito"]::after{ content:""; position:absolute; top:0; right:0;
  border:8px solid transparent;
  border-top-color:var(--suspeito); border-right-color:var(--suspeito) }
/* TERCEIRO DEGRAU DO CANTO, 2026-08-19. Pedido do usuario: "os frames ja validados como OK
   poderiam aparecer verdes, assim como os vazios aparecem com contorno vermelho".

   O pedido literal — anel verde em todo thumb ok — contraria a regra 2 desta folha ("onde ha pixel
   de render, o chrome e ZERO") de um jeito concreto: `outline-offset:-2px` desenha PARA DENTRO,
   sobre o `<img>`, e um anel de 2 px cobre ~4,4% da area do quadro. No frame vazio isso e barato
   (nao ha nada para julgar ali); no frame OK, e justamente o que se esta julgando.

   Entao o vocabulario foi fechado pelos DOIS lados, e o resultado atende o pedido melhor que ele:
     canto 11 px vermelho = vazio  >  canto 8 px ambar = suspeito  >  canto 5 px cinza = nao
     avaliado  >  sem canto, com fio verde = avaliado e OK
   O gradiente de tamanho que ja existia (11 > 8) ganha o terceiro degrau, e "sem marca" deixa de
   ser ambiguo entre "passou" e "ninguem olhou" — que era o que impedia a leitura de relance. */
.thumb[data-s="nao_avaliado"]::after, .thumb[data-s="desconhecido"]::after{
  content:""; position:absolute; top:0; right:0; border:5px solid transparent;
  border-top-color:var(--nao-avaliado); border-right-color:var(--nao-avaliado) }
/* E o verde que o usuario pediu, com `outline-offset:0`: o fio e desenhado IMEDIATAMENTE FORA da
   caixa do `<a>`, dentro do vao da grade (`gap`), entao NENHUM pixel de render e coberto. 1 px, e
   nao 2: verde e o estado mais comum da folha, e a marca do que esta certo nao pode competir com
   a marca do que esta errado. */
.thumb[data-s="ok"]{ outline:1px solid var(--ok); outline-offset:0 }

/* ------------------------------------------- 8. badges: sanidade e estado */
/* Quatro canais redundantes (cor + palavra + forma + moldura no thumb): o par
   vermelho/ambar e justamente o que a deuteranopia colapsa, e isso e ~1 em 12
   artistas homens. A PALAVRA nunca e substituida pelo glifo, so acompanhada —
   se a fonte nao tiver o glifo, nada de informacao se perde. */
.badge{ display:inline-flex; align-items:center; gap:.3em;
  padding:.1em .45em; border-radius:var(--r-1); font:700 var(--fs-1)/1.6 var(--font-ui);
  letter-spacing:.04em; text-transform:uppercase; vertical-align:middle }
.badge::before{ font-family:var(--mono) }
.badge[data-s="vazio"]{ background:var(--vazio); color:var(--sanity-empty-on);
  box-shadow:0 0 0 1px var(--badge-ring) }
.badge[data-s="vazio"]::before{ content:"\25A0" }          /* quadrado cheio */
.badge[data-s="suspeito"]{ background:var(--suspeito); color:var(--sanity-suspect-on) }
.badge[data-s="suspeito"]::before{ content:"\25B2" }       /* triangulo */
.badge[data-s="nao_avaliado"]{ background:transparent; color:var(--nao-avaliado);
  box-shadow:inset 0 0 0 1px var(--linha-forte) }
.badge[data-s="nao_avaliado"]::before{ content:"\00B7" }   /* ponto medio */
.badge[data-s="elemento"]{ background:transparent; color:var(--sanity-element-text);
  box-shadow:inset 0 0 0 1px var(--sanity-element-line) }
.badge[data-s="elemento"]::before{ content:"\25CB" }       /* circulo vazado */
.badge[data-s="desconhecido"]{ background:transparent; color:var(--tx3);
  box-shadow:inset 0 0 0 1px var(--linha-forte) }

/* estado de worker / de job na fila: vocabulario SEPARADO do de sanidade */
/* Badge de estado (fila, workers, ocultos): pilula com PONTO colorido e tinta suave, em vez do
   bloco solido em caixa alta (2026-09-07, "a coluna Status" da farm). O ponto carrega a cor; o
   texto fica legivel nos dois temas porque usa o `-text` de cada semaforo. */
.st{ display:inline-flex; align-items:center; gap:.45em; padding:.12em .65em .12em .55em;
  border-radius:999px; font:600 var(--fs-1)/1.6 var(--font-ui); letter-spacing:.02em;
  text-transform:none; color:var(--tx2); background:var(--f2); white-space:nowrap }
.st::before{ content:""; width:.5em; height:.5em; border-radius:50%; background:currentColor;
  flex:none; opacity:.85 }
.st[data-st="rendering"]{ color:var(--sanity-ok-text);
  background:color-mix(in srgb, var(--ok) 16%, transparent) }
.st[data-st="stalled"]{ color:var(--sanity-suspect-text);
  background:color-mix(in srgb, var(--suspeito) 18%, transparent) }
.st[data-st="offline"], .st[data-st="expurgado"]{ color:var(--sanity-empty-text);
  background:color-mix(in srgb, var(--vazio) 14%, transparent) }
.st[data-st="paused"]{ color:var(--tx) }
/* RF2 (2026-09-07, "um pin verde do estilo online no card dos workers"): host de pe e livre e
   ONLINE, e o ponto diz isso em verde; `rendering` ja era verde. `disabled`/`desconhecido` seguem
   na tinta neutra — nao se afirma disponibilidade que o poller nao mediu. */
.st[data-st="idle"], .st[data-st="concluido"]{ color:var(--sanity-ok-text);
  background:color-mix(in srgb, var(--ok) 12%, transparent) }
.card[data-st="idle"]{ box-shadow:inset 3px 0 0 var(--ok) }
/* Tela do job: "renderizando agora: frame 1004 em OCTPG-680 (3min)". Dado vivo, fonte de dados. */
.rodando-agora{ font-family:var(--font-data); font-size:var(--fs-1) }
/* Fase do crion (sync de assets, copia para os workers): trabalho em andamento, nem verde nem
   cinza. Usa a tinta de "suspeito" (ambar) porque e o semaforo de "olhe, mas nao e erro". */
.st[data-st="sync"]{ color:var(--sanity-suspect-text);
  background:color-mix(in srgb, var(--suspeito) 16%, transparent) }
/* 2026-09-21: `sync-falhou` NAO e ambar. Depois da migracao v4 o layer so despacha para o host que
   carrega a tag do workspace, e a tag so aparece quando o sync do Perforce termina — sync que
   falhou nos tres workers nao e "olhe, mas nao e erro", e um job que nunca vai sair da fila.
   Tinta de vazio (vermelha), a mesma de `offline`, porque a consequencia e a mesma: nada acontece. */
.st[data-st="sync-falhou"]{ color:var(--sanity-empty-text);
  background:color-mix(in srgb, var(--vazio) 16%, transparent) }
/* Linha do tempo do job: lista compacta, fonte de dados, dentro do bloco vivo. */
.tempo{ margin:.5rem 0 0 }
/* GAVETA QUE SE ANUNCIA COMO GAVETA (2026-09-08). O usuario achou a lista de tempo por frame e
   disse: *"deviamos deixar mais explicito que alguns textos sao gavetas, pois eles ficam meio
   escondidos e dificil de perceber que aquilo expande"*. Estava certo — o `summary` era texto
   secundario, do mesmo tom do resto do bloco, e a unica pista era o triangulo nativo do
   navegador, que em `.explica` some no meio da prosa.
   Tres sinais somados, porque um só não basta em tela de painel: (1) chip com borda e fundo, que
   diz "isto e um controle"; (2) chevron proprio que GIRA ao abrir, dando o estado; (3) cor de
   acento no hover/foco. `list-style:none` remove o marcador nativo para o chevron nao duplicar. */
.tempo > summary{ cursor:pointer; list-style:none; display:inline-flex; align-items:center;
  gap:.4em; padding:.2em .7em .2em .55em; border:1px solid var(--linha); border-radius:999px;
  background:var(--f2); color:var(--tx); font:600 var(--fs-1)/1.6 var(--font-ui);
  transition:color .12s, border-color .12s, background .12s }
.tempo > summary::-webkit-details-marker{ display:none }
.tempo > summary::before{ content:""; width:.42em; height:.42em; flex:none;
  border-right:2px solid currentColor; border-bottom:2px solid currentColor;
  transform:rotate(-45deg); transition:transform .12s }
.tempo[open] > summary::before{ transform:rotate(45deg) }
.tempo > summary:hover, .tempo > summary:focus-visible{ color:var(--accent);
  border-color:var(--accent); background:color-mix(in srgb, var(--accent) 10%, transparent) }
.tempo[open] > summary{ margin-bottom:.35rem }
.tempo ul{ margin:.3rem 0 0; padding-left:1.2em; font:var(--fs-1)/1.7 var(--font-data) }
.tempo li{ list-style:"› " }
/* O mesmo tratamento nas gavetas que ja existiam e sofriam do mesmo problema. Elas mantem o
   proprio layout (a dos workers e uma barra de resumo, nao um chip), e ganham so a cor de acento
   no hover — o sinal que faltava para parecer clicavel. */
.gaveta-workers > summary:hover, .gaveta-workers > summary:focus-visible,
.falha-det > summary:hover, .falha-det > summary:focus-visible{ color:var(--accent) }
/* Remocao em lote da fila: pilula de perigo alinhada a direita, mesmo idioma dos verbos por linha. */
#loteFila{ display:flex; justify-content:flex-end; margin:.5rem 0 .2rem }
#loteFila button{ background:var(--bg-surface); color:var(--danger-text); border:1px solid var(--danger);
  border-radius:999px; padding:.3rem .95rem; font:600 var(--fs-1)/1.3 var(--font-ui);
  letter-spacing:.01em; cursor:pointer; min-height:30px }
#loteFila button:hover{ background:var(--t-vazio) }

/* -------------------------------------------- 9. palco e modo julgamento */
/* Fora do modo viewport (fallback), o palco continua sendo um bloco. */
.palco{ margin-top:.6rem; display:grid; place-items:center; overflow:hidden;
  position:relative }  /* ancora dos overlays: guias e onion posicionam contra o palco */
/* `min-width:0; min-height:0` NAO e decoracao — sem eles a imagem nasce CORTADA. `.palco` e
   `display:grid`, e item de grid tem tamanho minimo automatico igual ao tamanho intrinseco do
   conteudo; esse MIN vence o `max-height:100%`, entao a imagem renderizava na altura natural
   dentro de um palco menor e o `overflow:hidden` do palco comia o excedente sem barra de rolagem
   nenhuma. Medido em 2026-08-19: palco 900x144 com derivada 320x180 desenhava 320x180 (36 px
   cortados embaixo) e passou a desenhar 257x144, que e o contain correto. */
.palco img{ max-width:100%; max-height:100%; width:auto; height:auto;
  min-width:0; min-height:0;
            object-fit:contain; cursor:zoom-in }
.palco.preto{ background:var(--stage-black) }
.palco.cinza{ background:var(--palco-cinza) }   /* 18% — carta cinza, neutra */
.palco.branco{ background:var(--stage-white) }
.palco.xadrez{ background:
  repeating-conic-gradient(var(--xadrez-a) 0% 25%, var(--xadrez-b) 0% 50%)
  0 0/24px 24px }
/* Ampliado: o palco rola e a imagem sai do limite. `grab` porque o arraste faz pan — a mao
   e a affordance que todo software de review usa, e sem ela ninguem descobre o pan. */
.palco.zoom{ place-items:start; overflow:auto; cursor:grab }
.palco.zoom:active{ cursor:grabbing }
.palco.zoom img{ max-width:none; max-height:none; cursor:inherit }
.palco.comp-palco{ isolation:isolate }
.palco .comp-layer{ grid-area:1/1; position:relative; pointer-events:none;
  mix-blend-mode:normal }
.comp-controle{ position:relative }
.comp-controle>summary{ list-style:none }
.comp-controle>summary::-webkit-details-marker{ display:none }
/* LARGURA: 31rem era o teto ate 2026-08-19, e ele foi pedido para crescer — *"expandir o tamanho
   dessa caixa e deixar o caminho completo aparecer"*. 46rem cabe o nome de camada mais longo do
   piloto sem reticencia, e o `calc(100vw - 1rem)` continua impedindo que a caixa passe da tela em
   monitor estreito. Junto com a remocao do prefixo comum, o caminho completo passa a caber. */
.comp-painel{ position:absolute; z-index:20; top:calc(100% + .45rem); left:0;
  width:min(46rem,calc(100vw - 1rem)); max-height:min(65vh,32rem); overflow:auto;
  padding:.55rem; background:var(--f1); border:1px solid var(--linha-forte);
  border-radius:var(--r-2); box-shadow:var(--shadow-pop); font:var(--fs-1)/1.25 var(--font-ui) }
.comp-cabecalho{ display:flex; align-items:center; gap:.45rem; margin-bottom:.45rem }
.comp-cabecalho .rot{ flex:1 }
.comp-lista{ display:flex; flex-direction:column; gap:.25rem }
/* O NOME DA CAMADA — ate 2026-08-19 `.comp-nome` era o unico filho de `.comp-linha` SEM regra
   nenhuma de CSS. A trilha dele e `1fr` (funcao flexivel: recebe a sobra, nunca cresce para caber),
   o painel tem teto de 31rem, e o caminho `04_Outputs/03_RenderPreview/png/Scene_05/sh1830` nao
   tem ponto de quebra que o navegador aceite. Resultado medido: caixa de 202 px com 303 px de
   texto pintado por cima do slider de opacidade — 94 px de invasao, ilegivel.

   ⚠️ E POR QUE NAO E SO `text-overflow:ellipsis`: a reticencia corta pela DIREITA, e a direita e
   exatamente onde mora o token que distingue as linhas (o sufixo de papel, beauty contra o
   tecnico). Com o corte simples, duas camadas da mesma pasta ficam VISUALMENTE IDENTICAS —
   sumiria um defeito de legibilidade e nasceria um de ambiguidade, no caso para o qual este
   painel existe.

   Entao a linha e partida em duas: a PASTA encolhe e ganha reticencia, a CAUDA (shot + papel)
   nunca e truncada. `title` continua com o caminho inteiro no hover. */
.comp-nome{ min-width:0; display:flex; align-items:baseline; white-space:nowrap; gap:.15em;
  font-family:var(--font-data) }
.comp-nome .pasta{ overflow:hidden; text-overflow:ellipsis; color:var(--tx3) }
.comp-nome .cauda{ flex:none }
.comp-linha{ display:grid; grid-template-columns:auto minmax(7rem,1fr) 5.5rem 3rem auto auto auto;
  align-items:center; gap:.3rem; padding:.28rem; border:1px solid var(--linha) }
.comp-linha[data-ativa="false"]{ color:var(--tx3) }
.comp-linha input[type="range"]{ width:100%; accent-color:var(--accent) }
.comp-linha output{ text-align:right; color:var(--tx2) }
.comp-linha .btn{ padding:.24rem .35rem }
.comp-linha .btn:disabled{ opacity:.35; cursor:not-allowed }
.comp-nota{ display:block; margin-top:.45rem; color:var(--tx3); line-height:1.35 }
.comp-aviso{ color:var(--suspeito) }
.download-aviso{ color:var(--tx2) }
.download-aviso.erro{ color:var(--vazio) }
.player .btn:disabled{ opacity:.45; cursor:progress }
.barra .nivel{ min-width:3.4em; text-align:right; color:var(--text-strong); font-weight:700 }
/* Veredito de sanidade sobre a imagem, fora da .barra: nao pode recuar com o chrome, porque e
   o unico sinal de severidade da tela de julgamento. */
.veredito{ position:absolute; top:calc(36px + 2.4rem); right:1rem; z-index:4;
           display:flex; gap:.3rem }
.scrub .pista{ overflow:visible }   /* cabeca e marca do ULTIMO frame nao podem ser cortadas */
.scrub .cadencia{ overflow:hidden }

/* /frame e /player deixam de ser documento e viram viewport: a derivada de
   1920 aparece 1:1 quando cabe (antes era reamostrada para ~1470) e o fundo
   escolhido vai ate a borda da tela — condicao para julgar densidade e ruido.
   min-height:0 nos filhos flex e obrigatorio, senao o palco vaza a viewport. */
body.viewport{ height:100vh; overflow:hidden; display:flex;
               flex-direction:column }
body.viewport main{ flex:1; min-height:0; display:flex; flex-direction:column;
                    padding:0; max-width:none; margin:0 }
/* Com o trilho lateral (>=1024px) o body e grid e o `main` e a celula da direita; ver 3b. */
body.viewport .palco{ flex:1; min-height:120px; margin:0; padding:0; border:0;
                      border-radius:0 }
body.viewport .aviso-velho{ margin:0; border-radius:0; max-width:none }

/* -------------------------------------- 10. barra de ferramentas e teclas */
.barra{ display:flex; align-items:center; gap:.4rem; flex-wrap:wrap;
  padding:.3rem .55rem; background:var(--f1);
  border-bottom:1px solid var(--linha); font:var(--fs-1)/1 var(--font-ui);
  transition:opacity var(--dur-1) linear }
.barra .nivel, .barra .atual, .barra .mono, .barra output{ font-family:var(--font-data) }
.barra .grupo{ display:flex; align-items:center; gap:.3rem }
.barra .sep{ width:1px; align-self:stretch; background:var(--linha);
             margin:0 .15rem }
.barra .espaco{ flex:1 }
.barra .atalhos{ color:var(--tx3) }
.barra .atual{ color:var(--text-strong); font-weight:700 }
.btn{ background:transparent; color:var(--tx2); border:1px solid transparent;
  border-radius:var(--r-2); padding:.3rem .5rem; font:inherit; cursor:pointer;
  display:inline-flex; align-items:center; gap:.3em }
.btn:hover{ background:var(--f2); color:var(--tx); text-decoration:none }
.btn[aria-pressed="true"]{ background:var(--accent); color:var(--accent-text) }
.btn[aria-disabled="true"]{ color:var(--tx3); cursor:default }
kbd{ font:700 9px/1 var(--mono); color:var(--tx2); background:var(--bg-sunken);
  border:1px solid var(--linha-forte); border-bottom-width:2px;
  border-radius:var(--r-2); padding:.25em .35em }

/* O chrome recua depois de 2,5 s sem mouse: durante o julgamento, a unica
   coisa com contraste alto na tela e o frame.
   ARMADILHA: opacity cria grupo de composicao — filho NAO desfaz a opacidade
   do ancestral. Por isso a .trilha (estado global, inclusive alerta) fica FORA
   da regra de dim, em vez de "ser reposta" com opacity:1 la dentro. */
body.limpo .marca, body.limpo header nav, body.limpo .barra,
body.limpo footer{ opacity:.28 }
body.limpo .barra:hover, body.limpo .barra:focus-within,
body.limpo header:hover .marca, body.limpo header:hover nav,
body.limpo footer:hover{ opacity:1 }

/* Canvas de anotacao (Onda 3): acima da imagem e da vista de canal, abaixo das guias. So
   captura ponteiro no modo desenho — fora dele o clique atravessa para o conta-gotas. */
.anotacao-canvas{ position:absolute; pointer-events:none; z-index:10 }
.anotacao-canvas.desenhando{ pointer-events:auto; cursor:crosshair }

/* Vista de canal isolado (Onda 3): copia a caixa da imagem, acima dela e abaixo das guias. */
.canal-vista{ position:absolute; pointer-events:none; z-index:8 }
#histCanvas{ background:var(--f0); border:1px solid var(--linha); display:block;
  margin:.4rem 0; width:256px; height:96px }

/* Guias de enquadramento (Onda 3): overlay sincronizado a caixa da imagem. As linhas usam %
   da caixa, entao valem em qualquer zoom/resolucao. O modo escolhe o que aparece; nada e
   clicavel (pointer-events none) — e uma regua, nao um controle. */
.guias{ position:absolute; pointer-events:none; z-index:15 }
.guias > div{ position:absolute; display:none }
.guias .gv{ top:0; bottom:0; width:0; border-left:1px solid var(--guide-line) }
.guias .gh{ left:0; right:0; height:0; border-top:1px solid var(--guide-line) }
.guias .g-centro.gv{ border-left-style:dashed }
.guias .g-centro.gh{ border-top-style:dashed }
.guias .g-safe{ border:1px dashed var(--guide-safe) }
.guias .g-titulo{ border-style:dotted }
.guias[data-modo="grade"] .g-linha, .guias[data-modo="grade"] .g-centro{ display:block }
.guias[data-modo="safe"] .g-safe{ display:block }

/* Onion skin (Onda 3): o frame ANTERIOR sobreposto ao atual — fantasma para deslocamento,
   diferenca para ruido/flicker de baixa amplitude. So no modo de camada unica. */
.onion{ position:absolute; pointer-events:none; z-index:5 }
.onion[data-modo="fantasma"]{ opacity:.35 }
.onion[data-modo="diferenca"]{ opacity:1; mix-blend-mode:difference }

/* Wipe do modo VS: mesmo vocabulario da barra, controle deslizante largo. */
.vs-controle{ display:flex; align-items:center; gap:.6rem; padding:.4rem .9rem;
  background:var(--f1); border-bottom:1px solid var(--linha); font:var(--fs-2)/1.4 var(--font-ui) }
.vs-controle input[type="range"]{ flex:1 1 240px; max-width:420px }
.vs-controle #vsRotulo{ color:var(--tx2) }

/* --------------------------------------------- 11. scrub unico (/player) */
/* Uma pista, nao duas. A tira antiga usava flex:1 por frame: com 300 frames
   cada tick tinha ~4 px e com 800+ virava sub-pixel — a marca do frame vazio
   podia DESAPARECER, que e a falha que o portal existe para impedir. */
.scrub{ position:relative; height:34px; background:var(--f1);
  border-top:1px solid var(--linha); flex:none }
.scrub .pista{ position:absolute; inset:9px 10px; background:var(--bg-sunken);
  border-radius:var(--r-1); overflow:hidden }
.scrub .cadencia{ position:absolute; inset:0; background:
  repeating-linear-gradient(90deg, var(--linha) 0 1px,
                            transparent 1px var(--passo, 10%)) }
.scrub .marcas span{ position:absolute; top:0; bottom:0; width:3px;
                     min-width:3px; margin-left:-1px }
.scrub .marcas span[data-s="vazio"]{ background:var(--vazio);
  box-shadow:0 0 0 1px var(--bg-sunken) }
.scrub .marcas span[data-s="suspeito"]{ background:var(--suspeito) }
/* Frame AUSENTE: vazado, nao cheio — ausencia nao e um estado de sanidade, e a falta de um. */
.scrub .marcas span[data-s="ausente"]{ background:transparent;
  border:1px dashed var(--tx3); width:4px }
/* ANOMALIA temporal: observacao (ambar vazado), deliberadamente mais fraca que vazio/suspeito —
   ela pede um olhar, nao afirma veredito. */
.scrub .marcas span[data-s="anomalia"]{ background:transparent;
  border:1px dashed var(--suspeito); width:4px; opacity:.8 }
.scrub .cabeca{ position:absolute; top:-3px; bottom:-3px; width:2px;
  background:var(--text-strong); box-shadow:0 0 0 1px var(--shadow-ink) }
/* o range invisivel por cima: UMA area de arraste para a barra inteira, e o
   teclado continua funcionando porque o input segue focavel */
.scrub input[type="range"]{ position:absolute; inset:0; width:100%; height:100%;
  margin:0; opacity:0; cursor:ew-resize }
.scrub:focus-within .pista{ outline:1px solid var(--tx2) }
.player{ display:flex; align-items:center; gap:.5rem; padding:.35rem .55rem;
  background:var(--f1); border-top:1px solid var(--linha);
  font:var(--fs-1)/1 var(--font-ui); flex:none }
.player select, .barra select{ background:var(--f0); color:var(--tx);
  border:1px solid var(--linha-forte); border-radius:var(--r-2); padding:.3rem .35rem;
  font:var(--fs-1)/1 var(--font-ui) }

/* ------------------------------------------- 12. gaveta e tabela de dados */
.gaveta{ border-top:1px solid var(--linha); background:var(--f1); flex:none;
         max-height:38vh; overflow:auto }
.gaveta > summary{ cursor:pointer; padding:.4rem .6rem; list-style:none;
                   position:sticky; top:0; background:var(--f1) }
.gaveta > summary::-webkit-details-marker{ display:none }
.gaveta > summary::before{ content:"\25B8"; color:var(--tx3);
                           margin-right:.45em }
.gaveta[open] > summary::before{ content:"\25BE" }
.metricas{ border-collapse:collapse; width:100%; margin:0;
           font:11px/1.6 var(--mono) }
.metricas td{ border:0; border-bottom:1px solid var(--linha);
              padding:.22rem .6rem }
.metricas td:first-child{ color:var(--tx3); width:18rem; font:600 var(--fs-1)/1.6 var(--font-ui);
  letter-spacing:var(--track-caps); text-transform:uppercase }
.metricas tr:hover td{ background:var(--f2) }

/* Caixa de rolagem das tabelas largas. A classe era usada em DUAS tabelas (`concluidosFarm` e
   `workersFarm`) e NAO tinha regra nenhuma -- o wrapper foi escrito pretendendo rolagem propria e
   nunca ganhou o CSS. Sem ela, a tabela de 747px dentro de uma coluna de 625px empurrava a PAGINA
   INTEIRA para 763px de largura: o cabecalho, o placar e a busca saiam de eixo junto, e a barra
   horizontal aparecia no rodape da janela em vez de na tabela. Medido em 2026-09-01. */
.tabela-rolavel{ overflow-x:auto; max-width:100% }
.fila{ border-collapse:collapse; width:100%; margin:.4rem 0 1.2rem;
       font:var(--fs-2)/1.6 var(--font-ui) }
/* Dado numerico e identificador em mono; prosa e nome em sans. A coluna diz o que e. */
.fila td[data-col="frames"], .fila td[data-col="erros"], .fila td[data-col="prioridade"],
.fila td[data-col="progresso"], .fila td[data-col="inicio"], .fila td[data-col="ip"],
.fila td[data-col="cores"], .fila td[data-col="ram"], .fila td[data-col="vram"],
.fila code, .fila .num, .prog-num{ font-family:var(--font-data) }
/* Barra de progresso em CSS puro: largura em %, sem SVG e sem JS. A faixa de falha e
   PROPORCIONAL e ancorada na direita — falha escondida atras de um "12/24" e o tipo de
   silencio que este projeto persegue. min-width garante 1 falha em 300 visivel. */
.prog{ display:inline-block; position:relative; width:8rem; height:7px; vertical-align:middle;
       background:var(--f0); box-shadow:inset 0 0 0 1px var(--linha) }
.prog i{ position:absolute; top:0; bottom:0; left:0; display:block }
.prog .feito{ background:var(--ok); opacity:.8 }
.prog .ruim{ background:var(--vazio); min-width:2px; left:auto; right:0 }
.prog-num{ margin-left:.45rem; color:var(--tx2) }
.fila th{ text-align:left; color:var(--tx3); font:600 var(--fs-1)/1.6 var(--font-ui);
  letter-spacing:var(--track-caps); text-transform:uppercase; padding:.35rem .6rem;
  background:var(--f2); border-bottom:1px solid var(--linha) }
.fila td{ padding:.3rem .6rem; border-bottom:1px solid var(--linha) }
.fila tr:hover td{ background:var(--f1) }

/* --------------------------------------------------- 13. placar e modo TV */
.placar{ display:flex; gap:1px; background:var(--linha);
  border:1px solid var(--linha); border-radius:var(--r-2); overflow:hidden;
  margin:0 0 1rem }
.placar .celula{ flex:1; background:var(--f1); padding:.6rem .8rem }
.placar b{ display:block; color:var(--text-strong); font:300 var(--kpi)/1 var(--font-display);
  font-variant-numeric:tabular-nums }
.placar .alerta b{ color:var(--vazio) }
.placar .atencao b{ color:var(--suspeito) }

/* TV a 4 m: 13 px e um badge de 10 px sao ilegiveis. `?tv=1` e GET puro — sem
   cookie, sem estado no servidor, sem preferencia persistida. */
/* TUDO em `em` aqui, nao `rem`: `rem` e relativo ao root (16px fixo), entao os overrides
   ignoravam o `font-size:20px` do body e o modo TV quase nao aumentava nada. */
body.tv{ font-size:20px }
/* O header NAO some: ele carrega a `.trilha`, que e o unico canal de alerta de frame
   vazio/suspeito — esconde-la faria a tela de parede omitir exatamente o que ela existe para
   gritar. Só o rodape sai (e informacao de manutencao, nao de operacao). */
body.tv footer{ display:none }
body.tv header{ height:auto; padding:.5em .8em; font-size:.7em }
body.tv .chip{ font-size:1em; padding:.3em .6em }
body.tv .chip b{ font-size:1.15em }
body.tv main{ padding:1em }
body.tv .placar b{ font-size:clamp(3em, 7vw, 8em) }
body.tv .cards{ grid-template-columns:repeat(auto-fill, minmax(24em, 1fr)) }
body.tv .fila{ font-size:.9em }
body.tv .fila td, body.tv .fila th{ padding:.5em .8em; font-size:.85em }
body.tv .rot{ font-size:.7em }
body.tv .meta{ color:var(--text-secondary); font-size:.8em }   /* contraste a 4 m != a 60 cm */
body.tv .card h3{ font-size:1.05em }
/* .st e .badge fixam 10px na regra base; sem override eles ficavam ilegiveis na TV. */
body.tv .st, body.tv .badge{ font-size:.6em }
body.tv .prog{ width:14em; height:.5em }
body.tv .sair-tv{ display:inline-block }
.sair-tv{ display:none }

/* ------------------------------------------------ 15. login e formularios */
/* A tela de login e a UNICA tela-formulario: centrada, sem nav (nao ha para
   onde navegar sem sessao), mesmo vocabulario visual do resto. */
.login{ max-width:22rem; margin:12vh auto 0; padding:1.2rem 1.4rem;
  background:var(--f1); border:1px solid var(--linha); border-radius:var(--r-2) }
.login h2{ margin-top:0; display:flex; align-items:center; gap:.5rem; font-size:var(--fs-6) }
.login-rodape{ display:flex; justify-content:center; margin-top:var(--sp-4) }
.login label{ display:block; margin:.7rem 0 .2rem; font:600 var(--fs-1)/1.4 var(--font-ui);
  letter-spacing:var(--track-caps); text-transform:uppercase; color:var(--tx3) }
.login input{ width:100%; background:var(--f0); color:var(--tx);
  border:1px solid var(--linha-forte); border-radius:var(--r-2); padding:.45rem .6rem;
  font:13px/1.4 var(--ui) }
.login button{ margin-top:1rem; width:100%; background:var(--f2); color:var(--text-strong);
  border:1px solid var(--linha-forte); border-radius:var(--r-2); padding:.5rem;
  font:600 12px/1.4 var(--ui); cursor:pointer }
.login button:hover{ background:var(--linha-forte) }
.login .erro{ margin-top:.8rem; padding:.5rem .7rem; background:var(--t-vazio);
  box-shadow:inset 3px 0 0 var(--vazio); color:var(--sanity-empty-on-ink); font-size:12px }
.login .nota{ margin-top:.8rem; color:var(--tx3); font-size:11px }
/* quem esta logado, no header; o logout e um form de um botao */
.sessao{ display:inline-flex; align-items:center; gap:.5rem; font:var(--fs-2)/1 var(--font-ui) }
.sessao .mono{ font-family:var(--font-ui); font-weight:600; color:var(--tx) }
.sessao form{ display:inline; margin:0 }
.sessao .papel{ color:var(--tx3); font-weight:400 }
.btn-sair{ background:none; border:1px solid var(--linha-forte); border-radius:var(--r-2);
  color:var(--tx3); font:500 var(--fs-1)/1.4 var(--font-ui); padding:.3rem .6rem; cursor:pointer;
  min-height:26px }
.btn-sair:hover{ color:var(--tx); background:var(--f2) }

/* -------------------------------------------------------- 16. job reports */
.reports{ width:100%; border-collapse:collapse; font:var(--fs-2)/1.45 var(--font-ui) }
.reports th,.reports td{ padding:.45rem .55rem; border-bottom:1px solid var(--linha);
  text-align:left; vertical-align:top }
.reports th{ color:var(--tx3); text-transform:uppercase; letter-spacing:var(--track-caps);
  font:600 var(--fs-1)/1.4 var(--font-ui) }
.reports tr[data-tipo="error"]{ box-shadow:inset 3px 0 0 var(--vazio) }
.report-log{ max-height:70vh; overflow:auto; padding:.8rem; background:var(--bg-sunken);
  border:1px solid var(--linha); color:var(--tx); white-space:pre-wrap; overflow-wrap:anywhere;
  font:11px/1.45 var(--mono) }
.report-busca{ display:flex; gap:.5rem; margin:.8rem 0 }
.report-busca input{ min-width:min(32rem,70vw); background:var(--f0); color:var(--tx);
  border:1px solid var(--linha-forte); padding:.4rem .55rem; font:12px/1.4 var(--mono) }
.report-busca button{ background:var(--f2); color:var(--tx); border:1px solid var(--linha-forte);
  padding:.4rem .7rem; cursor:pointer }
.report-nav{ display:flex; gap:1rem; margin:.8rem 0; font:var(--fs-2)/1.4 var(--font-ui) }

/* -------------------------------------------------------- 14. responsivo */
@media (max-width: 1023px){
  header{ grid-template-columns:auto 1fr; height:auto; padding:.35rem var(--sp-3) }
  .identidade-instancia{ grid-column:1 / -1; justify-content:space-between; gap:var(--sp-2) }
  .ambiente-instancia{ max-width:min(50vw,40ch) }
  .nav-toggle{ display:inline-flex; align-items:center; margin-left:auto }
  /* Com JS o menu nasce fechado atras do botao; sem JS ele continua visivel (nada some). */
  html.js header nav{ display:none }
  html.js header.nav-aberta nav{ display:flex }
  header nav{ grid-column:1 / -1; flex-direction:column; align-items:stretch; gap:0;
    padding:var(--sp-1) 0 var(--sp-2); border-top:1px solid var(--border) }
  header nav .item, .nav-grupo > summary{ height:40px; padding:0 var(--sp-2); box-shadow:none }
  header nav .item[data-ativo]{ box-shadow:inset 3px 0 0 var(--accent) }
  .nav-grupo{ flex-direction:column }
  .nav-grupo > summary{ pointer-events:auto; cursor:pointer }
  .nav-lista{ position:static; box-shadow:none; border:0; padding:0 0 0 var(--sp-4); margin:0 }
  .trilha-area{ grid-column:1 / -1; padding-bottom:.35rem; flex-wrap:wrap }
  .trilha{ flex-wrap:wrap }
  .placar{ flex-wrap:wrap }
  .placar .celula{ min-width:45% }
}
@media (max-width: 700px){
  /* Toque (E08): alvos de 36px nas barras de julgamento; as dicas de tecla saem, nao ha teclado. */
  .barra .btn, .player .btn, .barra select, .player select{ min-height:36px; padding:.45rem .6rem }
  .barra .atalhos, .barra kbd, .player kbd{ display:none }
  .ambiente-instancia{ max-width:min(58vw,36ch) }
  .comp-painel{ position:fixed; inset:4.5rem .5rem auto .5rem; width:auto;
    max-height:calc(100dvh - 6rem) }
  .comp-cabecalho{ flex-wrap:wrap }
  .comp-cabecalho strong{ flex-basis:100% }
  .comp-linha{ grid-template-columns:auto minmax(0,1fr) auto auto auto auto;
    grid-template-rows:auto auto }
  .comp-linha .comp-opacidade{ grid-column:2 / -1; grid-row:2 }
  .comp-linha .btn{ min-width:24px; min-height:24px }
}
/* ------------------------------------------------- 16b. trilho de frames (E04) */
/* O elemento-assinatura. Celulas flexiveis com largura minima: 1 frame ruim em 300 continua
   visivel (regra herdada da tira). Nada aqui anima; renderizando e FORMA (meio-cheia). */
.trilho{ display:flex; gap:1px; height:8px; margin:.5rem 0 .4rem; align-items:stretch;
  overflow:hidden; border-radius:1px }
.trilho > *{ flex:1 1 0; min-width:2px; display:block; background:var(--bg-sunken);
  border-radius:1px; box-shadow:inset 0 0 0 1px var(--border) }
.trilho.grande{ height:14px; gap:2px; margin:var(--sp-2) 0 }
.trilho.grande > *{ min-width:3px; border-radius:2px }
.trilho a{ cursor:pointer }
.trilho a:hover, .trilho a:focus-visible{ outline:2px solid var(--focus-ring); outline-offset:1px;
  z-index:1; position:relative }
.trilho [data-e="ok"]{ background:var(--sanity-ok); box-shadow:none }
.trilho [data-e="pronto"]{ background:var(--sanity-ok); opacity:.72; box-shadow:none }
.trilho [data-e="vazio"]{ background:var(--sanity-empty); min-width:4px; box-shadow:none }
.trilho [data-e="suspeito"]{ background:var(--sanity-suspect); min-width:4px; box-shadow:none }
.trilho [data-e="nao_avaliado"]{ background:var(--sanity-unrated); box-shadow:none }
.trilho [data-e="aguardando"]{ background:transparent }
.trilho [data-e="renderizando"]{ box-shadow:none;
  background:linear-gradient(135deg, var(--sanity-ok) 0 50%, var(--bg-sunken) 50% 100%) }
.trilho [data-e="pausado"]{ box-shadow:none;
  background:repeating-linear-gradient(90deg, var(--sanity-suspect) 0 2px, transparent 2px 4px) }
.trilho [data-e="falhou"]{ min-width:4px; box-shadow:none;
  background:linear-gradient(45deg, transparent 40%, var(--sanity-empty-on) 40% 60%, transparent 60%),
             linear-gradient(-45deg, transparent 40%, var(--sanity-empty-on) 40% 60%, transparent 60%),
             var(--sanity-empty) }
.prog-num{ margin-left:.45rem; color:var(--tx2); font-family:var(--font-data); white-space:nowrap }
td .trilho{ display:inline-flex; width:8rem; vertical-align:middle; margin:0 }

/* ------------------------------------------------- 16g. formulario guiado (E09) */
.formulario-guiado{ margin:.5rem 0; max-width:42rem }
.formulario-guiado output{ display:block; min-height:1.2em; margin-top:.25rem;
  font-size:var(--fs-2); color:var(--text-tertiary) }
.formulario-guiado output[data-ok="1"]{ color:var(--sanity-ok-text) }
.formulario-guiado output[data-ok="0"]{ color:var(--sanity-empty-text) }
.formulario-guiado input[type="range"]{ width:100%; accent-color:var(--accent); padding:0;
  border:0; background:transparent }
.formulario-guiado .trilho{ margin:.35rem 0 0 }
/* E14: o que a farm vai receber, derivado da cena e corrigivel */
.formulario-guiado fieldset{ border:1px solid var(--border); border-radius:var(--r-2);
  padding:.5rem .8rem .7rem; margin:.6rem 0 0; min-width:0 }
.formulario-guiado legend{ padding:0 .35rem; font:600 var(--fs-1)/1.4 var(--font-ui);
  letter-spacing:var(--track-caps); text-transform:uppercase; color:var(--text-tertiary) }
.campos-derivados{ display:grid; grid-template-columns:repeat(auto-fit, minmax(11rem, 1fr));
  gap:.2rem .8rem }
.campos-derivados label{ margin-top:.3rem }
.campos-derivados label small{ font-weight:400; color:var(--text-tertiary) }
.formulario-guiado .modos{ display:flex; flex-wrap:wrap; gap:.3rem 1rem }
.formulario-guiado .opcao{ display:inline-flex; align-items:center; gap:.4rem; margin-top:.5rem;
  font-weight:400; text-transform:none; letter-spacing:0; font-size:var(--fs-3); cursor:pointer }
.formulario-guiado .opcao input{ width:auto; margin:0; accent-color:var(--accent) }
.formulario-guiado #projeto-derivado{ display:inline; font-family:var(--font-data);
  color:var(--text-secondary) }

/* ------------------------------------------------- 16f. pagina do job (E07) */
.trilho-job{ margin:var(--sp-2) 0 var(--sp-3) }
.trilho-job .trilho{ height:16px; gap:2px }
.trilho-job .trilho > *{ min-width:3px; border-radius:2px }
.trilho-job .meta{ margin:.3rem 0 0 }
.diagnostico{ margin:var(--sp-4) 0; border:1px solid var(--border); border-radius:var(--r-2);
  background:var(--bg-surface) }
.diagnostico > summary{ cursor:pointer; list-style:none; padding:.6rem .9rem;
  font:600 var(--fs-3)/1.4 var(--font-ui); display:flex; align-items:center; gap:.5rem }
.diagnostico > summary::-webkit-details-marker{ display:none }
.diagnostico > summary::before{ content:""; width:6px; height:6px; flex:none;
  border-right:1.5px solid currentColor; border-bottom:1.5px solid currentColor;
  transform:rotate(-45deg); opacity:.7 }
.diagnostico[open] > summary::before{ transform:rotate(45deg) }
.diagnostico-corpo{ padding:0 .9rem .6rem }
.diagnostico-corpo .explica{ margin:.5rem 0 }
.eta{ font-family:var(--font-data); color:var(--text-secondary) }

/* ------------------------------------------------- 16e. a farm agora (E06) */
.subtitulo{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-2);
  margin:-.1rem 0 var(--sp-2); color:var(--text-tertiary); font-size:var(--fs-2) }
.subtitulo .rot{ color:var(--text-tertiary) }
.agora{ display:flex; flex-direction:column; gap:var(--sp-2); padding:var(--sp-3) var(--sp-4);
  margin:0 0 var(--sp-4); background:var(--bg-surface); border:1px solid var(--border);
  border-radius:var(--r-2); box-shadow:var(--shadow-1) }
/* Uma celula por worker. Cinco estados, cinco FORMAS -- nao so cor: cheia (ocupado), vazada
   (ocioso), hachurada (offline), tracejada (manutencao), com ponto (travado). */
.celulas-workers{ display:flex; flex-wrap:wrap; gap:3px }
.celulas-workers i{ display:block; width:14px; height:14px; border-radius:3px;
  background:transparent; box-shadow:inset 0 0 0 1.5px var(--border-strong) }
.celulas-workers i[data-w="ocupado"]{ background:var(--worker-busy); box-shadow:none }
.celulas-workers i[data-w="offline"]{ box-shadow:none;
  background:repeating-linear-gradient(45deg, var(--worker-offline) 0 3px, var(--stripe-gap) 3px 6px) }
.celulas-workers i[data-w="manutencao"]{ box-shadow:inset 0 0 0 1.5px var(--worker-maintenance);
  background:repeating-linear-gradient(90deg, var(--worker-maintenance) 0 2px, transparent 2px 4px) }
.celulas-workers i[data-w="stalled"]{ background:var(--worker-stalled); box-shadow:none;
  background-image:radial-gradient(circle, var(--stripe-gap) 0 2px, transparent 2.5px) }
.agora-frase{ margin:0; max-width:none; font-size:var(--fs-3); color:var(--text-secondary) }
.agora-frase b{ color:var(--text-strong); font-family:var(--font-data) }
.agora-frase b.alerta-num{ color:var(--sanity-empty-text) }
body.tv .celulas-workers i{ width:1.1em; height:1.1em }
body.tv .agora-frase{ font-size:1.3em }
.bloqueio{ display:inline-flex; align-items:baseline; gap:.3em; color:var(--text-tertiary);
  white-space:nowrap; cursor:help }
.bloqueio small{ font-size:var(--fs-1) }

/* ------------------------------------------------- 16d. meus jobs ativos (E05) */
.ativos{ margin:0 0 var(--sp-4) }
.ativos h2{ display:flex; align-items:baseline; gap:var(--sp-2); margin:0 0 var(--sp-2) }
.lista-ativos{ list-style:none; margin:0; padding:0; display:grid; gap:var(--sp-1) }
.ativo{ display:grid; grid-template-columns:minmax(12rem,1fr) minmax(10rem,2fr) auto;
  gap:var(--sp-3); align-items:center; padding:.5rem .8rem; background:var(--bg-surface);
  border:1px solid var(--border); border-radius:var(--r-2); box-shadow:var(--shadow-1) }
.ativo .nome{ display:flex; flex-direction:column; gap:.1rem; min-width:0 }
.ativo .nome a{ font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.ativo .nome small{ color:var(--text-tertiary); font-size:var(--fs-1) }
.ativo .progresso{ display:flex; align-items:center; gap:var(--sp-2); min-width:0 }
.ativo .progresso .trilho{ margin:0; flex:1 1 auto; height:10px }
.ativo .eta{ font:var(--fs-2)/1.3 var(--font-data); color:var(--text-secondary);
  white-space:nowrap; text-align:right }
.ativos .meta{ margin:.4rem 0 0 }
@media (max-width: 700px){
  .ativo{ grid-template-columns:1fr; gap:var(--sp-1) }
  .ativo .eta{ text-align:left }
}

/* ------------------------------------------------- 16c. aviso de acao e estado vazio (E04) */
.aviso-status{ display:flex; align-items:center; gap:.6rem; margin:0 0 var(--sp-3);
  padding:.55rem .9rem; border-radius:var(--r-2); background:var(--sanity-ok-ink);
  color:var(--text-primary); box-shadow:inset 3px 0 0 var(--sanity-ok); font-size:var(--fs-2);
  max-width:80ch }
.aviso-status::before{ content:"\2713"; color:var(--sanity-ok-text); font-weight:700 }
.aviso-status[data-nv="aten"]{ background:var(--sanity-suspect-ink);
  box-shadow:inset 3px 0 0 var(--sanity-suspect) }
.aviso-status[data-nv="aten"]::before{ content:"!"; color:var(--sanity-suspect-text) }
.vazio-estado{ padding:var(--sp-5); border:1px dashed var(--border-strong); border-radius:var(--r-2);
  color:var(--text-secondary); max-width:60ch; margin:var(--sp-4) 0 }
.vazio-estado h2{ margin:0 0 var(--sp-1); font-size:var(--fs-4); color:var(--text-primary) }
.vazio-estado p{ margin:0; max-width:none }
.vazio-estado .acao{ display:inline-block; margin-top:var(--sp-3); padding:.45rem .85rem;
  background:var(--accent); color:var(--accent-text); border-radius:var(--r-2);
  font-weight:600; text-decoration:none }
.vazio-estado .acao:hover{ text-decoration:none; opacity:.9 }

/* ------------------------------------------------- 16i. acabamento (E11) */
/* Profundidade neutra: um gradiente radial R=G=B no fundo da pagina. Continua neutro (nenhum
   matiz), mas a pagina deixa de ser uma chapa plana -- e o primeiro sinal de "produto". */
body{ background:var(--bg-page-fundo) fixed, var(--bg-page) }
@media (min-width: 1024px){
  main{ padding:var(--sp-5) var(--sp-6) var(--sp-7) }
  h1{ font-size:clamp(26px, 1.4rem + .8vw, 34px) }
}
/* cards do mural: galeria. Raio maior, sombra do tema, elevacao no hover, e a ENTRADA
   ORQUESTRADA -- os cards aparecem em cascata, uma vez, como buckets chegando. Depois disso
   nada se move sozinho (regra 3). */
@keyframes octo-entrar{ from{ opacity:0; transform:translateY(8px) } to{ opacity:1; transform:none } }
.cards{ gap:var(--sp-3) }
.card{ border-radius:var(--r-3); box-shadow:var(--shadow-1);
  transition:transform var(--dur-1) var(--ease-out), box-shadow var(--dur-1) var(--ease-out),
             border-color var(--dur-1) var(--ease-out) }
.card:hover{ transform:translateY(-2px); box-shadow:var(--shadow-2); border-color:var(--border-strong) }
.cards .card{ animation:octo-entrar var(--dur-3) var(--ease-out) both }
.cards .card:nth-child(2){ animation-delay:35ms } .cards .card:nth-child(3){ animation-delay:70ms }
.cards .card:nth-child(4){ animation-delay:105ms } .cards .card:nth-child(5){ animation-delay:140ms }
.cards .card:nth-child(6){ animation-delay:175ms } .cards .card:nth-child(7){ animation-delay:210ms }
.cards .card:nth-child(8){ animation-delay:245ms } .cards .card:nth-child(n+9){ animation-delay:280ms }
@media (prefers-reduced-motion: reduce){ .cards .card{ animation:none } }
.card .capa{ position:relative; border-bottom:0 }
.card .capa img{ transition:opacity var(--dur-2) var(--ease-out) }
.card .corpo{ padding:.7rem .85rem .8rem }
.card h3{ font-size:var(--fs-4) }
.card .trilho{ height:10px; margin:.55rem 0 .5rem; border-radius:3px }
/* faixa de estado do mural: tres celulas lado a lado, numero em display, rotulo abaixo */
.estado{ display:flex; flex-wrap:wrap; gap:1px; border-radius:var(--r-3) }
.estado > *{ flex:1 1 220px; flex-direction:column; align-items:flex-start; gap:.15rem;
  padding:var(--sp-3) var(--sp-4) }
.estado .n{ font:600 var(--fs-7)/1 var(--font-display); min-width:0; text-align:left;
  letter-spacing:-.02em }
.estado .sev-nota{ flex:1 1 100%; flex-direction:row; padding-top:.5rem; padding-bottom:.55rem }
/* botoes: um vocabulario. Raio 6, altura minima 32, foco herdado do global */
.btn, .triagem button, td.acoes button, .comando .buscaform button, .controles button,
.login button, .report-busca button, .tema-seletor button{ border-radius:6px }
.triagem button, td.acoes button, .comando .buscaform button, .report-busca button{ min-height:32px }
/* caixas de comando e avisos com o mesmo raio dos cards */
.comando, .avisos, .agora, .ativo, .diagnostico, .vazio-estado, .aviso-status, .explica,
.pag, .triagem, .login{ border-radius:var(--r-3) }
.comando .pag{ border-radius:0 }
/* rack de workers (>=1024px): a tabela continua no DOM -- cabecalho, linhas e celulas com
   data-col -- e vira uma grade de tiles por CSS. O leitor de tela e os testes leem a tabela;
   o olho le uma parede de racks. */
/* `.workers.tabular` fica TABELA mesmo em tela larga: e o grupo "fora do ar", onde o que se quer
   e varrer 30 linhas e comparar colunas, nao ler um tile por host (pedido do usuario, 2026-09-07). */
@media (min-width: 1024px){
  .workers:not(.tabular){ display:block; margin:.4rem 0 1.2rem }
  .workers:not(.tabular) thead{ position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0) }
  .workers:not(.tabular) tbody{ display:grid; grid-template-columns:repeat(auto-fill, minmax(240px, 1fr));
    gap:var(--sp-2) }
  .workers:not(.tabular) tr{ display:grid; grid-template-columns:1fr 1fr; gap:.2rem .7rem; padding:.65rem .8rem;
    background:var(--bg-surface); border:1px solid var(--border); border-radius:var(--r-3);
    align-content:start; box-shadow:var(--shadow-1) }
  .workers:not(.tabular) tr:hover td{ background:transparent }
  .workers:not(.tabular) td{ border:0; padding:0; display:block; min-width:0; vertical-align:top }
  .workers:not(.tabular) td::before{ content:attr(data-col); display:block; font:600 var(--fs-1)/1.4 var(--font-ui);
    letter-spacing:var(--track-caps); text-transform:uppercase; color:var(--text-tertiary) }
  .workers:not(.tabular) td[data-col="worker"]{ grid-column:1 / -1; font:600 var(--fs-4)/1.3 var(--font-display);
    white-space:normal }
  .workers:not(.tabular) td[data-col="worker"]::before, .workers:not(.tabular) td[data-col="estado"]::before,
  .workers:not(.tabular) td[data-col="frame"]::before, .workers:not(.tabular) td[data-col="tags"]::before{ display:none }
  .workers:not(.tabular) td[data-col="estado"]{ grid-column:1 / -1 }
  .workers:not(.tabular) td[data-col="frame"]{ grid-column:1 / -1; width:auto; padding:.2rem 0 }
  .workers:not(.tabular) td[data-col="frame"] .capa-worker, .workers:not(.tabular) td[data-col="frame"] .capa-worker img{
    width:100%; height:auto; aspect-ratio:16/9; object-fit:contain; border-radius:var(--r-2) }
  .workers:not(.tabular) td[data-col="tags"]{ grid-column:1 / -1; padding-top:.2rem }
  .workers:not(.tabular) td[hidden]{ display:none }
  .fila#filaFarm td .trilho, .fila#concluidosFarm td .trilho{ width:12rem }
}
/* login: heroi com o trilho e o cartao com sombra do tema */
.tela-login main{ display:flex; flex-direction:column; align-items:center; padding:0 var(--sp-4) }
.login-heroi{ width:min(22rem, 100%); margin:14vh auto 0 }
.login-heroi .trilho{ height:12px; gap:3px; margin:0 }
.login-heroi .trilho > *{ border-radius:3px }
@keyframes octo-acender{ from{ opacity:0; transform:scaleY(.3) } to{ opacity:1; transform:none } }
.login-heroi .trilho > *{ animation:octo-acender var(--dur-3) var(--ease-out) both }
.login-heroi .trilho > :nth-child(n+2){ animation-delay:40ms } .login-heroi .trilho > :nth-child(n+4){ animation-delay:90ms }
.login-heroi .trilho > :nth-child(n+7){ animation-delay:150ms } .login-heroi .trilho > :nth-child(n+11){ animation-delay:220ms }
.login-heroi .trilho > :nth-child(n+15){ animation-delay:300ms } .login-heroi .trilho > :nth-child(n+18){ animation-delay:380ms }
@media (prefers-reduced-motion: reduce){ .login-heroi .trilho > *{ animation:none } }
.tela-login .login{ margin-top:var(--sp-4); box-shadow:var(--shadow-2); width:min(22rem, 100%) }

/* ------------------------------------------------- 16h. paleta de comandos (E11) */
.paleta{ border:1px solid var(--border-strong); border-radius:var(--r-3); padding:0;
  width:min(640px, calc(100vw - 2rem)); background:var(--bg-surface); color:var(--text-primary);
  box-shadow:var(--shadow-pop); margin:10vh auto }
.paleta::backdrop{ background:var(--overlay); backdrop-filter:blur(2px) }
.paleta-form{ display:flex; flex-direction:column }
#paleta-busca{ width:100%; border:0; border-bottom:1px solid var(--border); background:transparent;
  color:var(--text-primary); font:var(--fs-5)/1.4 var(--font-ui); padding:.9rem 1rem; outline:0 }
#paleta-busca::placeholder{ color:var(--text-tertiary) }
.paleta-lista{ list-style:none; margin:0; padding:var(--sp-1); max-height:50vh; overflow:auto }
.paleta-lista li{ display:flex; flex-wrap:wrap; align-items:center; gap:.4rem .7rem; padding:.55rem .8rem;
  border-radius:var(--r-2); cursor:pointer; color:var(--text-secondary) }
.paleta-lista li[aria-selected="true"]{ background:var(--accent); color:var(--accent-text) }
.paleta-lista li .rot{ margin-left:auto; color:inherit; opacity:.7 }
.paleta-lista li .nome{ color:inherit; font-weight:600; min-width:0;
  flex:1 1 60%; overflow-wrap:anywhere }
.paleta-lista li .sub{ font:var(--fs-1)/1.5 var(--font-data); opacity:.85;
  order:2; flex-basis:100%; overflow-wrap:anywhere }
.paleta-lista li .badge{ margin-left:.2rem }
.paleta-lista .vazio{ color:var(--text-tertiary); cursor:default }
.paleta-dica{ margin:0; padding:.5rem 1rem .7rem; border-top:1px solid var(--border) }
.paleta-dica kbd{ margin:0 .1em }

/* ------------------------------------------------- 17. seletor de tema (E02) */
/* Controle segmentado de dois estados, sempre visivel no header. `<form>` para funcionar sem JS
   (o POST recarrega com o tema novo); o JS intercepta e troca na hora. */
.tema-seletor{ display:inline-flex; align-items:stretch; gap:0; margin:0;
  border:1px solid var(--border-strong); border-radius:var(--r-2); overflow:hidden;
  background:var(--bg-sunken) }
.tema-seletor button{ appearance:none; display:inline-flex; align-items:center; gap:.35em;
  border:0; background:transparent; color:var(--text-tertiary); cursor:pointer;
  padding:.3rem .55rem; font:500 var(--fs-1)/1 var(--font-ui); letter-spacing:0;
  text-transform:none; min-height:26px }
.tema-seletor button svg{ display:block; width:12px; height:12px }
.tema-seletor button:hover{ color:var(--text-primary); background:var(--bg-raised) }
.tema-seletor button[aria-pressed="true"]{ background:var(--accent); color:var(--accent-text) }
.tema-seletor button:focus-visible{ outline-offset:-2px }
.login .tema-seletor{ margin-top:1rem }
.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 }

/* ------------------------------------------------- 18. amostra de tokens (/estilo) */
.amostras{ display:grid; gap:var(--sp-4); grid-template-columns:repeat(auto-fit, minmax(340px, 1fr));
  align-items:start }
.amostra{ background:var(--bg-page); color:var(--text-primary); border:1px solid var(--border);
  border-radius:var(--r-3); padding:var(--sp-4); font:var(--fs-3)/var(--lh-normal) var(--font-ui) }
.amostra h2{ font:600 var(--fs-6)/var(--lh-tight) var(--font-display); margin:0 0 var(--sp-2) }
.amostra h3{ font:600 var(--fs-1)/var(--lh-normal) var(--font-ui); letter-spacing:var(--track-caps);
  text-transform:uppercase; color:var(--text-tertiary); margin:var(--sp-5) 0 var(--sp-2) }
.amostra .painel{ background:var(--bg-surface); border:1px solid var(--border);
  border-radius:var(--r-2); padding:var(--sp-3); box-shadow:var(--shadow-1) }
.cores{ display:grid; grid-template-columns:repeat(auto-fill, minmax(96px, 1fr)); gap:var(--sp-2) }
.cores .cor{ border-radius:var(--r-2); border:1px solid var(--border); overflow:hidden;
  font:var(--fs-1)/1.35 var(--font-data) }
.cores .cor i{ display:block; height:34px }
.cores .cor span{ display:block; padding:.3rem .4rem; color:var(--text-secondary);
  background:var(--bg-surface); word-break:break-all }
.escala p{ margin:.15rem 0 }
.escala .d{ font:600 var(--fs-display)/var(--lh-tight) var(--font-display); letter-spacing:-.01em }
.escala .t6{ font:600 var(--fs-6)/var(--lh-tight) var(--font-display) }
.escala .t5{ font:500 var(--fs-5)/var(--lh-normal) var(--font-ui) }
.escala .t4{ font:400 var(--fs-4)/var(--lh-normal) var(--font-ui) }
.escala .t3{ font:400 var(--fs-3)/var(--lh-normal) var(--font-ui) }
.escala .t2{ font:400 var(--fs-2)/var(--lh-normal) var(--font-ui); color:var(--text-secondary) }
.escala .t1{ font:400 var(--fs-1)/var(--lh-normal) var(--font-ui); color:var(--text-tertiary) }
.escala .dado{ font:var(--fs-3)/var(--lh-normal) var(--font-data); font-variant-numeric:tabular-nums }
.espacos{ display:flex; align-items:flex-end; gap:var(--sp-2) }
.espacos i{ display:block; background:var(--accent); opacity:.7; width:var(--sp-3) }
.linha-badges{ display:flex; flex-wrap:wrap; gap:var(--sp-2); align-items:center }
.controles{ display:flex; flex-wrap:wrap; gap:var(--sp-2); align-items:center }
.controles button, .controles .btn{ font:500 var(--fs-2)/1 var(--font-ui); text-transform:none;
  letter-spacing:0; padding:.45rem .8rem; border-radius:var(--r-2); cursor:pointer;
  border:1px solid var(--border-strong); background:var(--bg-surface); color:var(--text-primary) }
.controles button:hover{ background:var(--bg-raised) }
.controles button.primario{ background:var(--accent); color:var(--accent-text); border-color:var(--accent) }
.controles button.perigo{ border-color:var(--danger); color:var(--danger-text) }
.controles button.perigo:hover{ background:var(--danger-ink) }
.controles button:disabled{ opacity:.45; cursor:not-allowed }
.controles input{ font:var(--fs-3)/1.4 var(--font-ui); padding:.4rem .6rem; border-radius:var(--r-2);
  border:1px solid var(--border-strong); background:var(--bg-sunken); color:var(--text-primary) }
.contraste{ font:var(--fs-1)/1.4 var(--font-data); color:var(--text-tertiary) }
