/* ═══════════════════════════════════════════════════════════════════
   FARMAR · ops console — folha única de estilo
   A identidade completa (marca, paletas, componentes) está em IDENTIDADE.md.
   Regra: nenhuma cor literal fora dos blocos de token abaixo.

   TRÊS EIXOS independentes, todos escritos no :root por js/aparencia.js, e
   nenhum deles toca uma única regra de componente:
     · data-theme    "dark" ou ausente (claro) — a rampa de superfície
     · data-paleta   indigo · violeta · ciano · azul · grafite — o matiz
     · data-efeitos  pleno · sobrio — gradiente, luz ambiente e movimento
   ═══════════════════════════════════════════════════════════════════ */

/* ── TOKENS ──────────────────────────────────────────────────────── */
:root{
  /* superfícies e texto — a rampa do ÍNDIGO, que é a paleta padrão.
     Trocar de paleta troca este bloco inteiro; ver a seção PALETAS. */
  --bg:#f7f8fb; --surface:#ffffff; --surface-2:#f1f3f8; --surface-3:#e8ebf3;
  --border:#e2e6ee; --border-strong:#cbd2e0;
  --text:#12141a; --text-2:#414755;
  /* --muted era #6b7280 e REPROVAVA no AA: 4,05:1 sobre --surface-3 (o hover do
     slot) e 4,35:1 sobre --surface-2 (o th). A tabela de contraste só tinha
     conferido --muted sobre --surface, que passava, e por isso os dois passaram
     batido. Escurecido até passar nos três fundos: 6,1:1 sobre --surface,
     5,5:1 sobre --surface-2, 5,1:1 sobre --surface-3. */
  --muted:#5b6270;
  /* marca. --accent-2 é a parada clara do gradiente: só a camada de efeitos usa */
  --accent:#4f46e5; --accent-2:#6366f1; --accent-hover:#4338ca;
  --accent-soft:#eef2ff; --accent-contrast:#ffffff;
  /* O logo tem cor própria: não muda com o TEMA, mas muda com a PALETA — um tile
     índigo num painel ciano parece colado de outro produto. */
  --mark-1:#818cf8; --mark-2:#4f46e5; --mark-fg:#ffffff;
  /* semânticos: par sólido (texto/ícone) + soft (fundo).
     COMPARTILHADOS por todas as paletas, e isso é regra de domínio e não
     economia: o pool inteiro se lê de relance pela cor do status, e essa leitura
     não pode mudar de significado quando se troca o matiz da interface.
     A única exceção é o Grafite, e o motivo está escrito lá embaixo. */
  --ok:#15803d;   --ok-soft:#dcfce7;
  --warn:#b45309; --warn-soft:#fef3c7;
  --bad:#be123c;  --bad-soft:#ffe4e6;
  --dead:#64748b; --dead-soft:#eef1f5;
  /* Branco fixo nos dois temas. O QR do MFA precisa de quiet zone clara para a
     câmera ler; era um style="background:#fff" inline no js/nuvem.js, que é
     exatamente o tipo de coisa que quebra no tema escuro. */
  --qr-bg:#ffffff;

  /* elevação — agora multiplicada por --k, como todo o resto do desenho.
     Antes as sombras eram os únicos px parados da folha: em --k:1.45 o painel
     crescia 45% e a elevação continuava do tamanho de uma tela de 1366. */
  --sh-1:0 calc(1px*var(--k)) calc(2px*var(--k)) rgba(16,20,40,.06);
  --sh-2:0 calc(1px*var(--k)) calc(2px*var(--k)) rgba(16,20,40,.05),
         0 calc(8px*var(--k)) calc(24px*var(--k)) rgba(16,20,40,.06);
  --sh-3:0 calc(12px*var(--k)) calc(32px*var(--k)) rgba(16,20,40,.14),
         0 calc(2px*var(--k)) calc(8px*var(--k)) rgba(16,20,40,.08);
  /* A elevação da barra inferior. Era a ÚNICA cor literal fora de token da folha
     (rgba(0,0,0,.12) chapado), e um bug de tema real: preto sobre #0b0d12 no
     escuro, onde a barra fixa perdia toda separação do que rolava por baixo. */
  --sh-barra:0 calc(-4px*var(--k)) calc(18px*var(--k)) rgba(16,20,40,.14);
  --scrim:rgba(8,10,18,.6);
  /* Luz vinda de cima nas superfícies, e a tinta do radial ambiente do fundo.
     As duas são da camada de efeitos: em data-efeitos="sobrio" viram nada. */
  --brilho-topo:inset 0 1px 0 rgba(255,255,255,.75);
  /* o brilho do botão de ação é o MESMO nos dois temas: ele não fica sobre uma
     superfície do tema, fica sobre o accent, que é sempre uma cor saturada */
  --brilho-acao:inset 0 1px 0 rgba(255,255,255,.22);
  --luz-1:rgba(79,70,229,.09); --luz-2:rgba(129,140,248,.07);
  --sh-glow:0 calc(2px*var(--k)) calc(12px*var(--k)) rgba(79,70,229,.32);

  /* não-cromáticos: idênticos nos dois temas.
     TUDO aqui é multiplicado por --k, o fator de escala que o js/escala.js grava no :root a
     partir da largura FÍSICA da tela (e não do viewport CSS, que o zoom do Chrome infla).
     Os números abaixo são a régua base, na escala 1; o desenho não muda, muda o tamanho dela.
     Só --r-pill e as bordas de 1px ficam de fora: pílula é sempre pílula, e hairline é hairline. */
  --k:1;
  --r-1:calc(6px*var(--k)); --r-2:calc(9px*var(--k)); --r-3:calc(12px*var(--k));
  --r-4:calc(16px*var(--k)); --r-pill:999px;
  --s-1:calc(4px*var(--k)); --s-2:calc(8px*var(--k)); --s-3:calc(12px*var(--k));
  --s-4:calc(16px*var(--k)); --s-5:calc(24px*var(--k)); --s-6:calc(32px*var(--k));
  --fs-xs:calc(11.5px*var(--k)); --fs-sm:calc(12.5px*var(--k)); --fs-md:calc(13.5px*var(--k));
  --fs-base:calc(15px*var(--k)); --fs-lg:calc(18px*var(--k)); --fs-xl:calc(26px*var(--k));
  --font-ui:system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  --mono:ui-monospace,"Cascadia Mono","Consolas",monospace;
  --tr:140ms; --ease:cubic-bezier(.4,0,.2,1);
  /* entrada de modal e de aba: mais longa que a troca de cor, e com saída
     desacelerada. Duas durações, não uma, porque 140ms num painel que desliza
     lê como engasgo e 220ms numa troca de cor lê como lentidão. */
  --tr-2:220ms; --ease-saida:cubic-bezier(.16,1,.3,1);
  /* anel de foco, num token só. Estava reescrito à mão em quatro lugares
     (button, a, input, .at-conta), e por isso já tinha divergido entre eles. */
  --anel:0 0 0 calc(3px*var(--k)) var(--accent-soft);
  --sidebar-w:calc(244px*var(--k)); --sidebar-rail:calc(72px*var(--k));
  --topbar-h:calc(60px*var(--k));
  /* teto de linha, não moldura: a 2560 com k=1.27 dá 2400px contra ~2250px de área útil, então
     quem vence é o min(...,100%) da .wrap e a coluna encosta nas bordas. O teto só volta a valer
     em 4K, onde uma linha de ponta a ponta seria longa demais para ler. */
  --wrap-max:calc(1890px*var(--k));

  /* ícones dos alertas (mask-image; a cor vem do nível) */
  --ico-warn:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z'/%3E%3Cpath d='M12 9v4'/%3E%3Cpath d='M12 17h.01'/%3E%3C/svg%3E");
  --ico-bad:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='m15 9-6 6'/%3E%3Cpath d='m9 9 6 6'/%3E%3C/svg%3E");
  --ico-info:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 11v5'/%3E%3Cpath d='M12 8h.01'/%3E%3C/svg%3E");
  /* caret da dobra do card de workspace — mesma técnica de máscara dos alertas */
  --ico-caret:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  /* ícone dos estados vazios — mesma técnica de máscara dos alertas */
  --ico-vazio:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 12h-6l-2 3h-4l-2-3H2'/%3E%3Cpath d='M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z'/%3E%3C/svg%3E");
}
:root[data-theme="dark"]{
  --bg:#0b0d12; --surface:#14161d; --surface-2:#1b1e27; --surface-3:#232733;
  --border:#262b36; --border-strong:#363c4a;
  --text:#e8eaf0; --text-2:#b6bcca; --muted:#8b93a5;
  --accent:#818cf8; --accent-2:#a5b4fc; --accent-hover:#a5b4fc;
  --accent-soft:#1e1f3d; --accent-contrast:#0b0d12;
  --ok:#4ade80;   --ok-soft:#10241a;
  --warn:#fbbf24; --warn-soft:#2a2110;
  --bad:#fb7185;  --bad-soft:#2c1319;
  --dead:#94a3b8; --dead-soft:#21252e;
  --sh-1:0 calc(1px*var(--k)) calc(2px*var(--k)) rgba(0,0,0,.4);
  --sh-2:0 calc(1px*var(--k)) calc(2px*var(--k)) rgba(0,0,0,.4),
         0 calc(8px*var(--k)) calc(24px*var(--k)) rgba(0,0,0,.35);
  --sh-3:0 calc(16px*var(--k)) calc(40px*var(--k)) rgba(0,0,0,.55),
         0 calc(2px*var(--k)) calc(8px*var(--k)) rgba(0,0,0,.4);
  /* No escuro, sombra preta sobre #0b0d12 não separa NADA — era exatamente esse
     o bug da barra inferior. A separação aqui tem que vir de uma linha clara, e
     a sombra só adiciona profundidade abaixo dela. */
  --sh-barra:0 calc(-1px*var(--k)) 0 var(--border-strong),
             0 calc(-8px*var(--k)) calc(20px*var(--k)) rgba(0,0,0,.6);
  --scrim:rgba(0,0,0,.66);
  --brilho-topo:inset 0 1px 0 rgba(255,255,255,.055);
  --luz-1:rgba(129,140,248,.10); --luz-2:rgba(79,70,229,.12);
  --sh-glow:0 calc(2px*var(--k)) calc(14px*var(--k)) rgba(79,70,229,.5);
}

/* ── PALETAS ─────────────────────────────────────────────────────────
   Um bloco por matiz, e nenhuma regra de componente sabe que elas existem.

   O bloco CLARO de cada paleta é [data-paleta=x] e não :root[data-paleta=x], e
   isso não é descuido: sem o :root ele vale para QUALQUER elemento, e é o que
   permite as amostras do modal de Aparência se pintarem sozinhas — cada chip
   leva data-paleta e usa var(--mark-1)/var(--surface) como qualquer outro
   componente. Sem isso os hex teriam que ser copiados para dentro do JS, que é
   exatamente a duplicata que este arquivo existe para não ter.
   O bloco ESCURO mantém o :root de propósito: ele precisa dos (0,3,0) de
   especificidade para vencer :root[data-theme="dark"], que tem (0,2,0).
   A especificidade resolve sozinha: :root[data-paleta] (0,2,0) vence :root
   (0,1,0), e :root[data-paleta][data-theme] (0,3,0) vence :root[data-theme]
   (0,2,0) — então cada paleta só precisa declarar o que muda.

   O que cada paleta redefine: a família do accent, a marca, a rampa de neutros
   e as tintas de luz. O que ela NÃO redefine são os semânticos (--ok/--warn/
   --bad/--dead), porque a cor do status é a informação mais importante da tela
   e não pode mudar de significado quando se troca o tema visual. A única
   exceção é o Grafite, lá embaixo, e ela é obrigatória.

   O --muted de cada paleta clara foi escolhido para passar 4,5:1 sobre o
   --surface-3 daquela paleta, que é o fundo mais claro em que ele aparece
   (o hover do slot). É o par que reprovava no índigo antigo. */

/* ── ÍNDIGO ── o padrão; os valores completos estão no :root lá em cima ──
   Este bloco existe só para as AMOSTRAS do modal de Aparência. O índigo mora no
   :root, então um chip data-paleta="indigo" dentro de um painel em grafite
   herdaria o grafite e mostraria a cor errada justamente na paleta padrão.
   Repete apenas os tokens que a amostra desenha, e nada mais. */
[data-paleta="indigo"]{
  --surface:#ffffff; --border:#e2e6ee;
  --accent:#4f46e5; --mark-1:#818cf8; --mark-2:#4f46e5;
}
[data-paleta="indigo"][data-theme="dark"]{
  --surface:#14161d; --border:#262b36; --accent:#818cf8;
}

/* ── VIOLETA ── primo do índigo, mais quente e mais saturado ───────── */
[data-paleta="violeta"]{
  --bg:#f9f7fc; --surface:#ffffff; --surface-2:#f4f1fa; --surface-3:#eae4f4;
  --border:#e7e0f1; --border-strong:#cec3e0;
  --text:#171320; --text-2:#4a4259; --muted:#635a75;
  --accent:#7c3aed; --accent-2:#9061f9; --accent-hover:#6d28d9;
  --accent-soft:#f3e9ff; --accent-contrast:#ffffff;
  --mark-1:#a78bfa; --mark-2:#7c3aed; --mark-fg:#ffffff;
  --luz-1:rgba(124,58,237,.09); --luz-2:rgba(167,139,250,.07);
  --sh-glow:0 calc(2px*var(--k)) calc(12px*var(--k)) rgba(124,58,237,.32);
}
[data-paleta="violeta"][data-theme="dark"]{
  --bg:#0d0a14; --surface:#17131f; --surface-2:#1e1929; --surface-3:#272134;
  --border:#2c2539; --border-strong:#3f3654;
  --text:#ece8f5; --text-2:#bdb5cd; --muted:#928aa6;
  --accent:#a78bfa; --accent-2:#c4b5fd; --accent-hover:#c4b5fd;
  --accent-soft:#2a1f45; --accent-contrast:#100a1c;
  --luz-1:rgba(167,139,250,.10); --luz-2:rgba(124,58,237,.12);
  --sh-glow:0 calc(2px*var(--k)) calc(14px*var(--k)) rgba(124,58,237,.5);
}

/* ── CIANO ── neutros gelo; o mais "console técnico" do conjunto ───── */
[data-paleta="ciano"]{
  --bg:#f4f8fa; --surface:#ffffff; --surface-2:#eaf2f5; --surface-3:#dde9ee;
  --border:#d9e6eb; --border-strong:#b9cdd5;
  --text:#0f171a; --text-2:#3a4a50; --muted:#4f6169;
  --accent:#0e7490; --accent-2:#1592b3; --accent-hover:#155e75;
  --accent-soft:#ddf3fa; --accent-contrast:#ffffff;
  --mark-1:#22d3ee; --mark-2:#0e7490; --mark-fg:#ffffff;
  --luz-1:rgba(14,116,144,.09); --luz-2:rgba(34,211,238,.07);
  --sh-glow:0 calc(2px*var(--k)) calc(12px*var(--k)) rgba(14,116,144,.3);
}
[data-paleta="ciano"][data-theme="dark"]{
  --bg:#070d10; --surface:#101a1e; --surface-2:#162227; --surface-3:#1f2d33;
  --border:#223037; --border-strong:#35474f;
  --text:#e4eef1; --text-2:#b0c2c8; --muted:#86999f;
  --accent:#22d3ee; --accent-2:#67e8f9; --accent-hover:#67e8f9;
  --accent-soft:#0a2b34; --accent-contrast:#04161b;
  --luz-1:rgba(34,211,238,.10); --luz-2:rgba(14,116,144,.14);
  --sh-glow:0 calc(2px*var(--k)) calc(14px*var(--k)) rgba(34,211,238,.28);
}

/* ── AZUL-AÇO ── o mais neutro; nunca briga com nada na tela ───────── */
[data-paleta="azul"]{
  --bg:#f6f8fc; --surface:#ffffff; --surface-2:#eff3fa; --surface-3:#e4ebf5;
  --border:#dfe6f1; --border-strong:#c4d0e2;
  --text:#10151c; --text-2:#3e4856; --muted:#5a6474;
  --accent:#2563eb; --accent-2:#3b82f6; --accent-hover:#1d4ed8;
  --accent-soft:#e8f0ff; --accent-contrast:#ffffff;
  --mark-1:#60a5fa; --mark-2:#2563eb; --mark-fg:#ffffff;
  --luz-1:rgba(37,99,235,.09); --luz-2:rgba(96,165,250,.07);
  --sh-glow:0 calc(2px*var(--k)) calc(12px*var(--k)) rgba(37,99,235,.32);
}
[data-paleta="azul"][data-theme="dark"]{
  --bg:#070b11; --surface:#11171f; --surface-2:#18202a; --surface-3:#202a36;
  --border:#232d3a; --border-strong:#34414f;
  --text:#e6ebf2; --text-2:#b3bdc9; --muted:#88929f;
  --accent:#60a5fa; --accent-2:#93c5fd; --accent-hover:#93c5fd;
  --accent-soft:#16243f; --accent-contrast:#06101c;
  --luz-1:rgba(96,165,250,.10); --luz-2:rgba(37,99,235,.14);
  --sh-glow:0 calc(2px*var(--k)) calc(14px*var(--k)) rgba(37,99,235,.5);
}

/* ── GRAFITE ── a tela sem cor, para o status ser a única cor que existe ──
   E aqui está a exceção do --dead, que não é preferência: com o accent
   quase-neutro, .pill.em_uso (accent, ardósia) e .pill.aposentada (--dead,
   também ardósia) ficariam INDISTINGUÍVEIS — dois status diferentes com a
   mesma aparência, que é justamente o que o painel existe para evitar.
   Só nesta paleta o --dead vira um taupe QUENTE, que se separa do accent frio
   por temperatura e não só por tom. Conferido: 5,0:1 no claro, 5,5:1 no escuro. */
[data-paleta="grafite"]{
  --bg:#f6f7f9; --surface:#ffffff; --surface-2:#eef0f3; --surface-3:#e3e6eb;
  --border:#dfe2e8; --border-strong:#c3c9d2;
  --text:#11141a; --text-2:#414652; --muted:#5a606c;
  --accent:#334155; --accent-2:#475569; --accent-hover:#1e293b;
  --accent-soft:#e9edf2; --accent-contrast:#ffffff;
  --mark-1:#64748b; --mark-2:#334155; --mark-fg:#ffffff;
  --dead:#6b6560;  --dead-soft:#f1eeeb;
  --luz-1:rgba(100,116,139,.06); --luz-2:rgba(148,163,184,.05);
  --sh-glow:0 calc(2px*var(--k)) calc(12px*var(--k)) rgba(51,65,85,.24);
}
[data-paleta="grafite"][data-theme="dark"]{
  --bg:#0a0c0f; --surface:#14171c; --surface-2:#1b1f26; --surface-3:#242931;
  --border:#262b33; --border-strong:#383e48;
  --text:#e7eaef; --text-2:#b4bac4; --muted:#89909b;
  --accent:#cbd5e1; --accent-2:#e2e8f0; --accent-hover:#e2e8f0;
  --accent-soft:#232932; --accent-contrast:#0d1016;
  --dead:#a89484;  --dead-soft:#262321;
  --luz-1:rgba(203,213,225,.05); --luz-2:rgba(148,163,184,.05);
  --sh-glow:0 calc(2px*var(--k)) calc(14px*var(--k)) rgba(203,213,225,.18);
}

/* ── BASE ────────────────────────────────────────────────────────── */
*{box-sizing:border-box}
/* A luz ambiente vai no BACKGROUND do body, e não num ::before posicionado, de
   propósito: pseudo-elemento com position:fixed criaria contexto de empilhamento
   e obrigaria .app, .mask e .trava a disputar z-index com ele. Como imagem de
   fundo com attachment:fixed, ela não participa do empilhamento de nada. */
body{margin:0;background-color:var(--bg);color:var(--text);
  background-image:
    radial-gradient(calc(1200px*var(--k)) calc(700px*var(--k)) at 8% -5%,  var(--luz-1), transparent 60%),
    radial-gradient(calc(1000px*var(--k)) calc(600px*var(--k)) at 100% 0%, var(--luz-2), transparent 55%);
  background-attachment:fixed;background-repeat:no-repeat;
  font:var(--fs-base)/1.5 var(--font-ui);-webkit-font-smoothing:antialiased;
  accent-color:var(--accent);caret-color:var(--accent)}
h1,h2,h3{margin:0;font-weight:650;letter-spacing:-.01em}
a{color:var(--accent)}
::selection{background:var(--accent-soft);color:var(--accent)}
/* Um anel de foco só, em token. Estava reescrito à mão aqui, no input, e de novo
   no .at-conta do ativo.css — e já tinha divergido entre os três. */
button:focus-visible,a:focus-visible,[role="button"]:focus-visible,
summary:focus-visible{outline:calc(2px*var(--k)) solid var(--accent);
  outline-offset:calc(2px*var(--k))}
.spacer{flex:1}

/* Scrollbar tokenizada. Sem isso a barra do Chrome entra com o cinza do sistema,
   que é a única superfície da tela que ignora tema e paleta — e num painel
   escuro ela aparece como uma faixa clara em pé ao lado do conteúdo. */
*{scrollbar-width:thin;scrollbar-color:var(--border-strong) transparent}
::-webkit-scrollbar{width:calc(10px*var(--k));height:calc(10px*var(--k))}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:var(--border-strong);border-radius:var(--r-pill);
  border:calc(2px*var(--k)) solid transparent;background-clip:content-box}
::-webkit-scrollbar-thumb:hover{background:var(--muted);background-clip:content-box}
::-webkit-scrollbar-corner{background:transparent}

/* ── SHELL ───────────────────────────────────────────────────────── */
.app{display:grid;grid-template-columns:var(--sidebar-w) 1fr;min-height:100vh}

/* A sidebar não é --surface chapada: um degradê de meio ponto, do topo para o
   rodapé, dá a ela o volume de uma coluna que sustenta a página em vez de uma
   faixa colada nela. É sutil de propósito — em captura de tela lado a lado a
   diferença quase não aparece; na tela, o painel para de parecer recortado. */
.sidebar{position:sticky;top:0;height:100vh;z-index:30;display:flex;flex-direction:column;
  background:linear-gradient(180deg,var(--surface),
    color-mix(in srgb,var(--surface) 88%,var(--bg)));
  border-right:1px solid var(--border)}
/* o clarão atrás da marca, no mesmo espírito do que o próprio tile já carrega */
.brand .mark{filter:drop-shadow(0 calc(2px*var(--k)) calc(8px*var(--k))
  color-mix(in srgb,var(--mark-2) 45%,transparent))}

.brand{display:flex;align-items:center;gap:calc(10px*var(--k));padding:calc(18px*var(--k)) var(--s-4) var(--s-4);
  border-bottom:1px solid var(--border)}
/* logo: var() não resolve em atributo de apresentação SVG, então as paradas
   do gradiente e o "F" são pintados por CSS */
.mark{flex:none;display:block}
.mark .s1{stop-color:var(--mark-1)}
.mark .s2{stop-color:var(--mark-2)}
.mark .fg{fill:var(--mark-fg)}
.brand-txt{display:flex;flex-direction:column;line-height:1.2;min-width:0}
.brand-txt b{font-size:calc(14.5px*var(--k));font-weight:700;letter-spacing:.14em}
.brand-txt i{font-size:calc(10.5px*var(--k));font-style:normal;color:var(--muted);letter-spacing:.07em}

/* navegação: mesmo contrato de sempre — .tabs button[data-tab] + #tab-<nome> + .on */
/* gap de 2px é mais apertado que --s-1 (4px) de propósito — itens de nav
   empilhados querem ler como uma lista, não como cartões soltos. Mas é px de
   desenho, então escala como todo o resto; era o único valor da folha fora
   simultaneamente da escala de espaço E do multiplicador. */
nav.tabs{display:flex;flex-direction:column;gap:calc(2px*var(--k));flex:1;
  padding:var(--s-2);overflow-y:auto}
nav.tabs button{position:relative;display:flex;align-items:center;gap:calc(10px*var(--k));width:100%;
  padding:calc(9px*var(--k)) calc(11px*var(--k));border:1px solid transparent;border-radius:var(--r-2);background:transparent;
  color:var(--muted);font-size:var(--fs-md);font-weight:550;text-align:left;
  transition:background var(--tr) var(--ease),color var(--tr) var(--ease)}
nav.tabs button svg{flex:none;width:calc(18px*var(--k));height:calc(18px*var(--k));fill:none;stroke:currentColor;
  stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
nav.tabs button:hover{background:var(--surface-2);color:var(--text);border-color:transparent}
/* Três sinais no item ativo, e nenhum deles é só cor: fundo, texto e a barra à
   esquerda. O fundo virou lavagem em gradiente — o accent-soft cheio deixava o
   item parecendo um botão apertado; esvaziando para a direita ele lê como
   destaque, e a barra ganha o peso de indicador. */
nav.tabs button.on{background:linear-gradient(90deg,var(--accent-soft),
    color-mix(in srgb,var(--accent-soft) 25%,transparent));
  color:var(--accent);font-weight:600}
nav.tabs button.on::before{content:"";position:absolute;left:calc(3px*var(--k));top:50%;
  transform:translateY(-50%);width:calc(3px*var(--k));height:calc(18px*var(--k));
  border-radius:var(--r-pill);background:var(--accent);
  box-shadow:0 0 calc(8px*var(--k)) color-mix(in srgb,var(--accent) 60%,transparent)}

.side-foot{margin-top:auto;display:flex;align-items:center;gap:var(--s-2);
  padding:var(--s-3);border-top:1px solid var(--border)}
.side-foot button{display:flex;align-items:center;gap:calc(7px*var(--k))}
.side-foot svg{flex:none;width:calc(15px*var(--k));height:calc(15px*var(--k));fill:none;stroke:currentColor;
  stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.ver{margin-left:auto;font-size:var(--fs-xs);color:var(--muted);font-family:var(--mono)}

.main{min-width:0;display:flex;flex-direction:column}
header.top{position:sticky;top:0;z-index:20;min-height:var(--topbar-h);
  display:flex;align-items:center;gap:var(--s-4);flex-wrap:wrap;
  padding:var(--s-3) var(--s-5);background:var(--surface);
  border-bottom:1px solid var(--border)}
header.top h1{font-size:var(--fs-lg);font-weight:650}
.wrap{width:100%;max-width:min(var(--wrap-max),100%);margin:0 auto;
  padding:var(--s-5) var(--s-5) calc(80px*var(--k))}

/* ── selo da nuvem, na topbar ─────────────────────────────────────
   Reusa o vocabulário das pills (mesmo ponto colorido, mesmas cores por estado) porque é a
   mesma informação do #pillNuvem lá no cartão — o que muda é só estar sempre à vista. Como é
   botão, ganha o cursor e o hover que uma pill não tem. */
.selo-nuvem{display:inline-flex;align-items:center;gap:calc(6px*var(--k));
  padding:calc(4px*var(--k)) calc(12px*var(--k));border-radius:var(--r-pill);
  border:1px solid transparent;font-size:var(--fs-xs);font-weight:600;white-space:nowrap;
  background:var(--surface-2);color:var(--muted);cursor:pointer;
  transition:border-color var(--tr) var(--ease)}
.selo-nuvem::before{content:"";flex:none;width:calc(7px*var(--k));height:calc(7px*var(--k));
  border-radius:50%;background:currentColor;
  box-shadow:0 0 calc(6px*var(--k)) color-mix(in srgb,currentColor 70%,transparent)}
.selo-nuvem:hover{border-color:currentColor}
.selo-nuvem.ok    {background:var(--ok-soft);     color:var(--ok)}
.selo-nuvem.indo  {background:var(--accent-soft); color:var(--accent)}
.selo-nuvem.atencao{background:var(--warn-soft);  color:var(--warn)}
.selo-nuvem.ruim  {background:var(--bad-soft);    color:var(--bad)}
/* pendência é o estado que não pode passar por acidente: pisca devagar, uma vez a cada 2s.
   Quem preferir a tela quieta desliga no sistema — e aí o selo continua colorido. */
.selo-nuvem.pendente{animation:selo-pulsa 2s var(--ease) infinite}
@keyframes selo-pulsa{0%,100%{opacity:1}50%{opacity:.55}}
@media (prefers-reduced-motion:reduce){.selo-nuvem.pendente{animation:none}}
/* em tela estreita some o texto e fica o ponto: a informação é a cor */
:root[data-estreito] .selo-nuvem{padding:calc(6px*var(--k));gap:0;font-size:0}

/* ── QUEM ESTÁ OPERANDO ──────────────────────────────────────────────
   Vizinho do selo da nuvem e deliberadamente DIFERENTE dele: o selo é
   semáforo (a cor é a informação), este é identidade (o nome é). Por isso
   não tem ponto colorido nem vocabulário de status — tem a inicial num
   disco, que é como a pessoa se reconhece numa lista.
   Deslogado ele fica tracejado: é a mesma gramática do .pill.falta do card
   de workspace incompleto — cadastro pela metade se sinaliza, não se
   esconde. E não pode ser discreto: enquanto ele diz "entrar", tudo que
   for criado nasce sem autor. */
.chip-membro{display:inline-flex;align-items:center;gap:calc(7px*var(--k));
  padding:calc(3px*var(--k)) calc(12px*var(--k)) calc(3px*var(--k)) calc(3px*var(--k));
  border-radius:var(--r-pill);border:1px solid var(--border);
  background:var(--surface-2);color:var(--text-2);
  font-size:var(--fs-xs);font-weight:600;white-space:nowrap;cursor:pointer;
  transition:border-color var(--tr) var(--ease),background var(--tr) var(--ease)}
.chip-membro:hover{border-color:var(--accent);background:var(--accent-soft);color:var(--accent)}
.chip-membro.fora{border-style:dashed;border-color:var(--warn);
  color:var(--warn);background:var(--warn-soft)}
.chip-membro.fora .avatar{background:var(--warn);color:var(--surface)}
.chip-membro.fora:hover{border-color:var(--warn);background:var(--warn-soft);
  border-style:solid}
/* em tela estreita fica só o disco da inicial — o nome cabe no title.
   O .avatar tem font-size próprio, então a inicial sobrevive ao font-size:0 */
:root[data-estreito] .chip-membro{padding:calc(3px*var(--k));gap:0;font-size:0}

/* ── CRONÔMETRO ──────────────────────────────────────────────────────
   Mesma família do selo da nuvem e do chip de membro: item de largura
   estável na topbar, nunca uma faixa que empurra o conteúdo. Três estados
   e cada um com uma cara diferente à distância, porque a pergunta que ele
   responde de relance é "está contando?" — não "quanto".
   O tempo é tabular-nums e min-width fixo: sem isso o chip muda de largura
   a cada segundo e a topbar inteira treme. */
.crono{display:none;align-items:center;gap:calc(7px*var(--k));
  padding:calc(4px*var(--k)) calc(12px*var(--k));
  border-radius:var(--r-pill);border:1px solid var(--border);
  background:var(--surface-2);color:var(--text-2);
  font-size:var(--fs-xs);font-weight:600;white-space:nowrap;cursor:pointer;
  transition:border-color var(--tr) var(--ease),background var(--tr) var(--ease)}
.crono.on{display:inline-flex}
.crono .t{font-variant-numeric:tabular-nums;font-weight:700;font-size:var(--fs-sm);
  min-width:calc(52px*var(--k));text-align:right}
.crono .alvo{overflow:hidden;text-overflow:ellipsis;max-width:calc(140px*var(--k))}
/* o ponto que pulsa: é ele que diz "está contando" de canto de olho */
.crono .luz{flex:none;width:calc(7px*var(--k));height:calc(7px*var(--k));border-radius:50%;
  background:var(--muted)}
.crono.rodando{border-color:var(--ok);background:var(--ok-soft);color:var(--ok)}
.crono.rodando .luz{background:var(--ok);animation:cronoPulso 2s var(--ease) infinite}
.crono.pausado{border-style:dashed;border-color:var(--warn);background:var(--warn-soft);
  color:var(--warn)}
.crono.pausado .luz{background:var(--warn)}
@keyframes cronoPulso{0%,100%{opacity:1}50%{opacity:.25}}
@media (prefers-reduced-motion:reduce){.crono.rodando .luz{animation:none}}
/* em tela estreita fica só a luz e o tempo — o alvo cabe no title */
:root[data-estreito] .crono .alvo{display:none}

/* ── AVATAR ──────────────────────────────────────────────────────────
   O disco de identidade do membro: foto quando há uma, inicial quando não.
   Um componente só, em três tamanhos, porque ele aparece em três lugares
   (chip da topbar, placar da Competição, card do Perfil) e uma cara que
   mudasse de um para o outro contaria duas histórias sobre a mesma pessoa.

   As oito cores NÃO seguem a paleta, e isso é deliberado: a paleta é a
   marca do painel, e esta cor é a identidade de uma PESSOA — se ela virasse
   ciano junto com o resto, dois membros ficariam do mesmo tom no dia em que
   alguém trocasse o tema. Por isso são oito matizes fixos, e o que o tema
   ajusta é só saturação e luz. São números de matiz e dois botões de
   acabamento, todos em bloco de token, e não cor literal espalhada.
   Quem escolhe qual dos oito é corDe(), em js/perfil.js: hash do email, para
   que as duas máquinas e os dois sócios desenhem o mesmo disco sem combinar. */
:root{
  --av-0:265; --av-1:200; --av-2:150; --av-3:25;
  --av-4:340; --av-5:95;  --av-6:220; --av-7:305;
  --av-s:52%; --av-l:42%; --av-fg:#ffffff}
:root[data-theme="dark"]{--av-s:58%; --av-l:62%; --av-fg:#0b0d12}
.avatar{flex:none;display:grid;place-items:center;overflow:hidden;
  width:calc(28px*var(--k));height:calc(28px*var(--k));border-radius:50%;
  background:var(--surface-3);color:var(--av-fg);
  font-size:calc(12px*var(--k));font-weight:700;
  text-transform:uppercase;letter-spacing:0;line-height:1}
.avatar img{width:100%;height:100%;object-fit:cover;display:block}
.avatar.p{width:calc(21px*var(--k));height:calc(21px*var(--k));font-size:calc(10px*var(--k))}
.avatar.g{width:calc(72px*var(--k));height:calc(72px*var(--k));font-size:calc(30px*var(--k))}
.avatar.c0{background:hsl(var(--av-0) var(--av-s) var(--av-l))}
.avatar.c1{background:hsl(var(--av-1) var(--av-s) var(--av-l))}
.avatar.c2{background:hsl(var(--av-2) var(--av-s) var(--av-l))}
.avatar.c3{background:hsl(var(--av-3) var(--av-s) var(--av-l))}
.avatar.c4{background:hsl(var(--av-4) var(--av-s) var(--av-l))}
.avatar.c5{background:hsl(var(--av-5) var(--av-s) var(--av-l))}
.avatar.c6{background:hsl(var(--av-6) var(--av-s) var(--av-l))}
.avatar.c7{background:hsl(var(--av-7) var(--av-s) var(--av-l))}
/* célula de membro do placar: o disco e o nome andam juntos */
.membro-cel{display:flex;align-items:center;gap:calc(9px*var(--k));min-width:0}
.membro-cel b{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.ws-now{display:flex;align-items:center;gap:calc(10px*var(--k));background:var(--surface-2);
  border:1px solid var(--border);border-radius:var(--r-pill);padding:calc(5px*var(--k)) calc(14px*var(--k));
  font-size:var(--fs-md)}
.ws-now b{font-size:var(--fs-md)}
.bar{width:calc(110px*var(--k));height:calc(6px*var(--k));border-radius:var(--r-pill);
  background:var(--border-strong);overflow:hidden;
  box-shadow:inset 0 1px 2px color-mix(in srgb,var(--text) 14%,transparent)}
/* a duração era 250ms literal, o único tempo da folha fora dos tokens — e ela é
   exatamente a entrada longa que --tr-2 já nomeia */
.bar>i{display:block;height:100%;
  background:linear-gradient(90deg,var(--accent),var(--accent-2));
  transition:width var(--tr-2) var(--ease)}
.bar.full>i{background:linear-gradient(90deg,var(--warn),color-mix(in srgb,var(--warn) 60%,var(--bad)))}

/* ── BOTÕES ──────────────────────────────────────────────────────────
   a.mini entra no MESMO seletor que button, e não numa cópia à mão da regra.
   Link externo precisa ser <a> de verdade — nova aba, botão do meio e "copiar
   endereço" do navegador só existem em link —, mas isso é motivo para ele ter
   a mesma aparência por herança, não por duplicata (que já tinha divergido:
   a cópia não transicionava a cor nem tinha estado de foco próprio). */
button,a.mini{font:inherit;font-size:var(--fs-md);cursor:pointer;border-radius:var(--r-2);
  border:1px solid var(--border-strong);background:var(--surface-2);color:var(--text);
  text-decoration:none;padding:calc(7px*var(--k)) calc(13px*var(--k));
  transition:background var(--tr) var(--ease),border-color var(--tr) var(--ease),
    color var(--tr) var(--ease),box-shadow var(--tr) var(--ease),
    transform var(--tr) var(--ease)}
button:hover,a.mini:hover{border-color:var(--accent);background:var(--surface-3)}
button:disabled{opacity:.5;cursor:not-allowed}
button:disabled:hover{border-color:var(--border-strong);background:var(--surface-2);
  transform:none;box-shadow:none}
/* A ação principal é o único elemento da tela que ganha gradiente E sombra
   tingida. É o que a faz destacar sem precisar crescer: numa .card-h cheia de
   botões secundários do mesmo tamanho, cor chapada some. */
button.primary{background:linear-gradient(180deg,var(--accent-2),var(--accent));
  border-color:var(--accent);color:var(--accent-contrast);font-weight:600;
  box-shadow:var(--sh-glow),var(--brilho-acao)}
button.primary:hover{background:linear-gradient(180deg,var(--accent),var(--accent-hover));
  border-color:var(--accent-hover);transform:translateY(calc(-1px*var(--k)))}
button.primary:active{transform:none}
button.ghost{background:transparent;border-color:transparent}
button.ghost:hover{background:var(--surface-2);border-color:var(--border)}
button.mini,a.mini{display:inline-flex;align-items:center;
  padding:calc(3px*var(--k)) calc(9px*var(--k));font-size:var(--fs-sm);
  border-radius:var(--r-1)}
button.danger{color:var(--bad)}
button.danger:hover{border-color:var(--bad);background:var(--bad-soft);color:var(--bad)}
/* Confirmação de cópia. copiarTexto() (js/util.js) troca o texto do botão por
   "copiado!" e põe esta classe pelo mesmo intervalo — o texto sozinho é fácil
   de perder de vista numa linha cheia de botões iguais. Só cor: mexer em
   tamanho aqui faria a linha dançar, que é o que o min-width do .px-copiar
   existe para impedir. */
button.copiado,button.copiado:hover{background:var(--ok-soft);border-color:var(--ok);
  color:var(--ok)}

/* ── O ALARME DE PROXY REPETIDO ──────────────────────────────────
   Vermelho, grande e no alto da .wrap, acima dos KPIs — aparece em todas as abas porque duas
   contas no mesmo IP é defeito do dado, não da tela que se está olhando.
   Ele NÃO é a volta da faixa de alertas do topo: aquilo empilhava uma barra por assunto e
   crescia; isto é um estado só, raro, e some inteiro quando não há colisão.
   O [hidden] segue o par da .kpis: sem a linha abaixo, o display:grid ganharia dele. */
.alarme{display:grid;gap:calc(10px*var(--k));margin:0 0 var(--s-5);
  background:var(--bad-soft);border:1px solid var(--bad);
  border-left:calc(4px*var(--k)) solid var(--bad);
  border-radius:var(--r-3);padding:var(--s-4);
  box-shadow:var(--sh-2);animation:alarme-pulso 2.4s var(--ease) infinite}
.alarme[hidden]{display:none}
@keyframes alarme-pulso{0%,100%{box-shadow:var(--sh-2)}
  50%{box-shadow:var(--sh-2),0 0 0 calc(4px*var(--k)) var(--bad-soft)}}
@media (prefers-reduced-motion:reduce){.alarme{animation:none}}
.alarme-t{display:grid;gap:calc(3px*var(--k))}
.alarme-t b{color:var(--bad);font-size:var(--fs-lg);letter-spacing:-.01em}
.alarme-t span{font-size:var(--fs-sm);color:var(--text-2)}
.alarme-l{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s-2);
  background:var(--surface);border:1px solid var(--border);border-radius:var(--r-2);
  padding:calc(8px*var(--k)) calc(10px*var(--k))}
.alarme-l .px{font-weight:600;color:var(--bad)}
.alarme-l .quem{display:flex;flex-wrap:wrap;align-items:center;gap:calc(6px*var(--k));flex:1 1 auto}
.alarme-l .quem .x{color:var(--muted);font-weight:600}
.alarme-l .autor{font-size:var(--fs-xs);color:var(--muted)}

/* ── ANOTAÇÕES DE BUGS ───────────────────────────────────────────
   Card por anotação, na gramática do .ws-card: cabeçalho com pills e ações, corpo com o
   texto. Resolvido fica esmaecido em vez de sumir — a lista de resolvidos é o histórico. */
.bug-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-3);
  padding:var(--s-4);margin-bottom:var(--s-3);box-shadow:var(--sh-1)}
.bug-card.feito{opacity:.62}
.bug-h{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s-2)}
.bug-h h3{margin:0;font-size:var(--fs-md);font-weight:600;flex:0 1 auto}
.bug-h .acts{margin-left:auto;display:flex;gap:calc(6px*var(--k));flex-wrap:wrap}
.bug-h .autor{font-size:var(--fs-xs);color:var(--muted)}
.bug-d{margin:calc(8px*var(--k)) 0 0;font-size:var(--fs-sm);color:var(--text-2);
  white-space:pre-wrap}

/* O cadastro de etapas do checklist (aba ck). Uma LINHA e não um card: o que se lê aqui é a
   ordem dos passos, e card com padding empurra o passo 8 para fora da tela — a lista inteira
   precisa caber de uma vez para se conferir a sequência. Desativado não some: fica apagado,
   como o .bug-card.feito, porque continua contando nas contas que já o marcaram. */
.et-linha{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s-2);
  background:var(--surface);border:1px solid var(--border);border-radius:var(--r-2);
  padding:calc(7px*var(--k)) calc(10px*var(--k));margin-bottom:calc(6px*var(--k))}
.et-linha.off{opacity:.55}
.et-n{flex:none;font-size:var(--fs-xs);color:var(--muted);font-variant-numeric:tabular-nums}
/* min-width:0 é o que deixa um passo longo encolher em vez de empurrar os botões para fora */
.et-txt{flex:1;min-width:calc(160px*var(--k));font-size:var(--fs-sm)}
.et-linha .acts{margin-left:auto;display:flex;gap:calc(6px*var(--k));flex-wrap:wrap}
.et-linha .autor{font-size:var(--fs-xs);color:var(--muted)}
/* as setas de reordenar: largura fixa pelo mesmo motivo do .at-enc na janelinha — ↑ e ↓ têm
   avanço diferente do resto e a linha de botões dançaria entre uma etapa e outra */
.et-seta{min-width:calc(26px*var(--k));justify-content:center}

/* A prévia do que a montagem em lote vai consumir, e as linhas do relatório dela. */
.lote-previa{display:grid;gap:calc(4px*var(--k));background:var(--surface-2);
  border:1px solid var(--border);border-radius:var(--r-2);padding:calc(10px*var(--k))}
.lote-l{display:flex;gap:var(--s-3);align-items:baseline;font-size:var(--fs-sm)}
.lote-l .rot{flex:none;width:calc(74px*var(--k));font-size:var(--fs-xs);
  text-transform:uppercase;letter-spacing:.04em;color:var(--muted)}
.lote-l.falta{color:var(--warn)}
/* O relatório do lote é a única tabela do painel que vive DENTRO de um modal, e o
   `table{min-width:820px}` global a fazia rolar na horizontal ali — escondendo justamente a
   coluna de empresa, que é metade do que se veio conferir. Seis colunas curtas cabem em bem
   menos, e a rolagem do .tbl-wrap continua de pé para telas estreitas. */
.tbl-lote{min-width:calc(700px*var(--k));font-size:var(--fs-sm)}
.tbl-lote th,.tbl-lote td{padding:calc(7px*var(--k)) calc(9px*var(--k));white-space:nowrap}
/* Os quatro interruptores de "o que este lote puxa do pool". Aceso = puxa, e o vocabulário do
   aceso é o mesmo do encaixe da janela do modo ativo (css/ativo.css): borda e fundo da cor de
   acento. Apagado NÃO é só um botão sem cor — o texto dele muda para "sem cartão", porque um
   estado invisível aqui gasta cartão de verdade, e cor sozinha é a informação que some primeiro
   em tela clara, em daltonismo e no modo sóbrio. */
.puxa-l button{min-width:calc(96px*var(--k));justify-content:center}
.puxa-l button.on{border-color:var(--accent);background:var(--accent-soft);color:var(--accent)}
.puxa-l button:not(.on){color:var(--muted)}

/* A tabela de ESCOLHER conta a conta, no mesmo modal. Ao contrário do relatório, aqui cada
   célula é um campo: o padding encolhe (o próprio input já tem o dele) e as três colunas de
   select ganham piso de largura, senão o <select> do Chrome se espreme até virar uma seta com
   o nome do proxy cortado — que é justamente o dado que se veio conferir antes de gravar. */
.tbl-escolha{min-width:calc(880px*var(--k));font-size:var(--fs-sm)}
.tbl-escolha th,.tbl-escolha td{padding:calc(4px*var(--k)) calc(6px*var(--k));white-space:nowrap}
.tbl-escolha td:first-child,.tbl-escolha td:nth-child(2){color:var(--muted)}
.tbl-escolha input,.tbl-escolha select{font-size:var(--fs-sm);
  padding:calc(5px*var(--k)) calc(7px*var(--k))}
.tbl-escolha td:nth-child(3){min-width:calc(190px*var(--k))}
.tbl-escolha td:nth-child(4),.tbl-escolha td:nth-child(5),
.tbl-escolha td:nth-child(6){min-width:calc(160px*var(--k))}

/* ── KPIs ────────────────────────────────────────────────────────── */
.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(calc(158px*var(--k)),1fr));
  gap:var(--s-3);margin:0 0 var(--s-5)}
/* A régua global mora FORA das sections, então ela some por [hidden] e não pela classe .on
   das abas — e o `display:grid` acima ganharia do [hidden] do navegador se esta linha não
   existisse. Quem liga e desliga é mostrarKpis(), em render.js: só vale na aba Workspaces. */
.kpis[hidden]{display:none}
.kpi{position:relative;overflow:hidden;background:var(--surface);
  border:1px solid var(--border);border-radius:var(--r-3);padding:calc(15px*var(--k)) var(--s-4);
  box-shadow:var(--sh-1),var(--brilho-topo);
  transition:transform var(--tr) var(--ease),box-shadow var(--tr) var(--ease)}
.kpi:hover{transform:translateY(calc(-1px*var(--k)));box-shadow:var(--sh-2),var(--brilho-topo)}
/* O filete é gradiente e não chapado: no degradê ele lê como luz sobre a cor do
   nível, e não como uma tarja colada em cima do tile. A parada transparente
   deixa o próprio --ok/--warn/--bad ditar o matiz — nenhum token novo por nível. */
.kpi::before{content:"";position:absolute;inset:0 0 auto 0;height:calc(3px*var(--k));
  background:var(--border-strong)}
.kpi.ok::before{background:linear-gradient(90deg,var(--ok),color-mix(in srgb,var(--ok) 55%,transparent))}
.kpi.warn::before{background:linear-gradient(90deg,var(--warn),color-mix(in srgb,var(--warn) 55%,transparent))}
.kpi.bad::before{background:linear-gradient(90deg,var(--bad),color-mix(in srgb,var(--bad) 55%,transparent))}
.kpi .n{font-size:var(--fs-xl);font-weight:700;line-height:1.1;letter-spacing:-.02em;
  font-variant-numeric:tabular-nums}
.kpi .l{font-size:var(--fs-sm);color:var(--muted);margin-top:calc(3px*var(--k))}
.kpi.ok .n{color:var(--ok)} .kpi.warn .n{color:var(--warn)} .kpi.bad .n{color:var(--bad)}

/* ── CARDS ───────────────────────────────────────────────────────── */
.card{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-4);
  padding:var(--s-4);margin-bottom:var(--s-3);box-shadow:var(--sh-2),var(--brilho-topo)}
.card-h{display:flex;align-items:center;gap:calc(10px*var(--k));margin-bottom:var(--s-3);flex-wrap:wrap}
.card-h h3{font-size:var(--fs-base)}
/* .hint dentro do cabeçalho não leva a margem de parágrafo: ali ele é um item do
   flex, ao lado do título. Era um style="margin:0" repetido em quatro renders. */
.card-h .hint,.ws-head .hint{margin:0}

/* ── ALERTAS ─────────────────────────────────────────────────────────
   Bloco <div class="alert nivel"><div>msg</div></div>. Não existe mais lista de alertas no
   topo da página: hoje ele só é usado DENTRO de modal e de painel de aba (importação em
   massa, aviso de proxy/cartão, análise, tela da chave de recuperação).
   O ícone entra por ::before como item do flex — sem tocar no JS. */
.alert{display:flex;gap:var(--s-3);align-items:flex-start;border-radius:var(--r-3);
  padding:calc(12px*var(--k)) var(--s-4);margin-bottom:calc(10px*var(--k));
  font-size:var(--fs-md);color:var(--text);
  border:1px solid transparent;border-left:calc(3px*var(--k)) solid transparent}
.alert::before{content:"";flex:none;width:calc(18px*var(--k));height:calc(18px*var(--k));margin-top:calc(2px*var(--k));
  background-color:currentColor;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  -webkit-mask-size:contain;mask-size:contain;-webkit-mask-position:center;mask-position:center}
.alert.warn{background:var(--warn-soft);border-left-color:var(--warn)}
.alert.warn::before{color:var(--warn);
  -webkit-mask-image:var(--ico-warn);mask-image:var(--ico-warn)}
.alert.bad{background:var(--bad-soft);border-left-color:var(--bad)}
.alert.bad::before{color:var(--bad);
  -webkit-mask-image:var(--ico-bad);mask-image:var(--ico-bad)}
.alert.info{background:var(--accent-soft);border-left-color:var(--accent)}
.alert.info::before{color:var(--accent);
  -webkit-mask-image:var(--ico-info);mask-image:var(--ico-info)}

/* ── PAINÉIS DE ABA ──────────────────────────────────────────────── */
.tab{display:none}
/* trocarAba() só liga a classe .on, então a entrada roda a cada troca sem JS.
   Deslocamento pequeno de propósito: a aba não "entra na tela", ela assenta —
   num painel consultado dezenas de vezes por dia, animação que se anuncia cansa. */
.tab.on{display:block;animation:aba-entra var(--tr-2) var(--ease-saida)}
@keyframes aba-entra{
  from{opacity:0;transform:translateY(calc(6px*var(--k)))}
  to{opacity:1;transform:none}}

/* ── TABELAS ─────────────────────────────────────────────────────── */
.tbl-wrap{overflow-x:auto;border:1px solid var(--border);border-radius:var(--r-3);
  background:var(--surface)}
table{width:100%;border-collapse:collapse;font-size:var(--fs-md);min-width:calc(820px*var(--k))}
th{text-align:left;font-size:var(--fs-xs);font-weight:600;text-transform:uppercase;
  letter-spacing:.06em;color:var(--muted);padding:calc(10px*var(--k)) calc(12px*var(--k));background:var(--surface-2);
  white-space:nowrap;border-bottom:1px solid var(--border)}
td{padding:calc(10px*var(--k)) calc(12px*var(--k));border-bottom:1px solid var(--border);vertical-align:middle}
tr:last-child td{border-bottom:0}
tbody tr{transition:background var(--tr) var(--ease)}
tbody tr:hover{background:var(--surface-3)}
/* A marca de linha ativa vai no box-shadow do primeiro td, e não num ::before do
   tr: com border-collapse:collapse o box-shadow do próprio <tr> não é desenhado
   de forma confiável. Mesmo vocabulário da barra do slot e do item de nav. */
tbody tr:hover td:first-child{box-shadow:inset calc(3px*var(--k)) 0 0 var(--accent)}
.mono{font-family:var(--mono);font-size:var(--fs-sm)}

/* ── PILLS ───────────────────────────────────────────────────────────
   Os nomes destas classes SÃO as strings de status do db, interpoladas
   direto pelo render. Podem ser restilizadas; nunca renomeadas. */
.pill{display:inline-flex;align-items:center;gap:calc(5px*var(--k));
  padding:calc(2px*var(--k)) calc(10px*var(--k)) calc(2px*var(--k)) calc(8px*var(--k));
  border-radius:var(--r-pill);font-size:var(--fs-xs);font-weight:600;
  white-space:nowrap;line-height:1.75;
  /* anel interno tirado da própria cor do estado: sem ele o fundo -soft é uma
     mancha sem contorno, e num card claro a pill some dentro da superfície */
  box-shadow:inset 0 0 0 1px color-mix(in srgb,currentColor 22%,transparent)}
.pill::before{content:"";flex:none;width:calc(6px*var(--k));height:calc(6px*var(--k));
  border-radius:50%;background:currentColor;
  box-shadow:0 0 calc(5px*var(--k)) color-mix(in srgb,currentColor 65%,transparent)}
.pill.livre      {background:var(--ok-soft);     color:var(--ok)}
.pill.em_uso     {background:var(--accent-soft); color:var(--accent)}
.pill.queimado   {background:var(--bad-soft);    color:var(--bad)}
/* A lixeira não é um desfecho como o queimado: é decisão pendente, então veste o vocabulário
   de atenção e não o de erro. Mesma família do .pill.falta e do bônus pendente. */
.pill.lixeira    {background:var(--warn-soft);   color:var(--warn)}
.pill.ativa      {background:var(--ok-soft);     color:var(--ok)}
.pill.em_revisao {background:var(--warn-soft);   color:var(--warn)}
.pill.banida     {background:var(--bad-soft);    color:var(--bad)}
.pill.aposentada {background:var(--dead-soft);   color:var(--dead)}
/* .falta não é status do db: marca o workspace com login pela metade */
.pill.falta      {background:var(--warn-soft);   color:var(--warn)}
/* bônus do Google Ads. Pendente é tarefa aberta (warn); pago é desfecho fechado (ok).
   .pago vem depois na cascata e tem especificidade maior, então sobrescreve sozinho. */
.pill.bonus      {background:var(--warn-soft);   color:var(--warn)}
.pill.bonus.pago {background:var(--ok-soft);     color:var(--ok)}
/* Vocabulário NEUTRO, para o que não é status do db.
   A nuvem e o cofre vestiam as classes de conta: "conflito de nuvem" pintava com
   .banida e "cofre não configurado" com .falta. Funcionava e mentia — a mesma
   classe passava a significar duas coisas, e restilizar o status de conta mexia
   sem querer no estado de rede. Estes cinco não são status de nada, são
   semáforo, e é isso que renderNuvem()/renderCofre() usam agora. */
.pill.neutro  {background:var(--dead-soft);   color:var(--dead)}
.pill.ok      {background:var(--ok-soft);     color:var(--ok)}
.pill.info    {background:var(--accent-soft); color:var(--accent)}
.pill.atencao {background:var(--warn-soft);   color:var(--warn)}
.pill.ruim    {background:var(--bad-soft);    color:var(--bad)}

/* ── VÍNCULO DE INSUMO QUE PERDEU A CONTA ────────────────────────
   A célula "Vinculado a" das três tabelas de pool quando a conta que usava aquele proxy,
   cartão ou empresa foi excluída. Empilhada de propósito: em linha, o navegador quebrava
   "WS-01 · Palestrino 03" no meio, e o dado que se veio ler — de onde o insumo veio — saía
   partido em duas linhas com o motivo colado. Quem monta é vinculoPool(), em js/util.js. */
.vinc-usado{display:grid;gap:var(--s-1);justify-items:start}

/* ── PESO (a régua de pontos da Competição) ──────────────────────
   Parece pill e NÃO é, de propósito. A pill é semáforo: a cor é a informação e o ponto na
   frente diz "isto é um estado". A régua de pontos é legenda — o que informa é o rótulo e o
   número —, e vestir .pill.neutro nela punha nove bolinhas de status numa linha que não
   descreve estado nenhum. Um chip neutro, sem ponto, e o peso em destaque. */
.peso{display:inline-flex;align-items:center;gap:calc(6px*var(--k));
  padding:calc(2px*var(--k)) calc(10px*var(--k));
  border-radius:var(--r-pill);font-size:var(--fs-xs);line-height:1.75;
  white-space:nowrap;color:var(--muted);background:var(--surface-2);
  box-shadow:inset 0 0 0 1px var(--border)}
.peso b{color:var(--text);font-variant-numeric:tabular-nums}

/* ── FORMULÁRIOS ─────────────────────────────────────────────────── */
label{display:block;font-size:var(--fs-sm);color:var(--muted);margin-bottom:calc(5px*var(--k));font-weight:550}
input,select,textarea{width:100%;font:inherit;font-size:var(--fs-md);
  padding:calc(8px*var(--k)) calc(11px*var(--k));
  border-radius:var(--r-2);border:1px solid var(--border-strong);background:var(--bg);
  color:var(--text);transition:border-color var(--tr) var(--ease),box-shadow var(--tr) var(--ease)}
input::placeholder,textarea::placeholder{color:var(--muted)}
input:focus,select:focus,textarea:focus{outline:none;border-color:var(--accent);
  box-shadow:var(--anel)}
textarea{resize:vertical;font-family:var(--mono);font-size:var(--fs-md)}
.grid{display:grid;gap:var(--s-3)}
.g2{grid-template-columns:1fr 1fr}
.g3{grid-template-columns:repeat(3,1fr)}
.row{display:flex;gap:var(--s-2);align-items:center;flex-wrap:wrap}
.hint{font-size:var(--fs-sm);color:var(--muted);margin-top:calc(6px*var(--k));line-height:1.55}
/* Dica que existe no markup para ser PREENCHIDA depois (o retorno da consulta de CNPJ, em
   blocoEmpresaModal) não pode reservar espaço enquanto está vazia. */
.hint:empty{display:none}
/* era .9em, o último font-size da folha fora da escala — e o único que encolhia
   junto com o contexto em vez de seguir a régua */
code{font-family:var(--mono);font-size:var(--fs-sm);background:var(--surface-2);
  border:1px solid var(--border);border-radius:var(--r-1);padding:calc(1px*var(--k)) calc(5px*var(--k))}

/* ── UTILITÁRIOS ─────────────────────────────────────────────────────
   O painel tinha 89 style="" inline entre o HTML e as strings de markup do JS,
   e ~34 deles eram só uma margem de topo. Inline style fura a escala (nenhum
   deles passava por --k), não responde a data-estreito e obrigava um !important
   no CSS responsivo para vencer os max-width dos campos de busca.
   Estes utilitários existem para que markup gerado não precise de style=". */
.mt-1{margin-top:var(--s-1)}
.mt-2{margin-top:var(--s-2)}
.mt-3{margin-top:var(--s-3)}
.mt-4{margin-top:var(--s-4)}
.flush{margin:0}
.flush-top{margin-top:0}
.txt-muted{color:var(--muted)}
.txt-bad{color:var(--bad)}
.txt-warn{color:var(--warn)}
.txt-accent{color:var(--accent)}
.forte{font-weight:600}
.nowrap{white-space:nowrap}
/* dígitos de largura fixa: sem isso o número dança entre um render e outro */
.num-tab{font-variant-numeric:tabular-nums}
.escondido{display:none}
.centro{justify-content:center}
.centro-txt{text-align:center}
.campo-curto{max-width:calc(140px*var(--k))}
/* a chave de recuperação: aparece UMA vez na vida do cofre e é copiada a mão de
   quem está lendo para um papel. Centralizada e um degrau maior que o corpo —
   é o único input do painel cujo trabalho é ser lido, não preenchido. */
.campo-chave{text-align:center;font-size:var(--fs-lg)}
/* campo que toma o resto da linha dentro de .row — eram sete style="flex:1;
   min-width:Npx" com três valores diferentes e nenhum motivo para divergirem */
.cresce{flex:1;min-width:calc(180px*var(--k))}
.cresce.curto{min-width:calc(140px*var(--k))}
.cresce.longo{min-width:calc(200px*var(--k))}
/* filtros e busca do cabeçalho de aba. Estes três substituem os max-width
   inline que existiam SÓ para serem anulados por um !important em tela
   estreita — agora o override não precisa de força nenhuma. */
.campo-num{max-width:calc(90px*var(--k))}
.campo-filtro{max-width:calc(170px*var(--k))}
/* o seletor de destino do lote: as opções são frases, não uma palavra, e cortadas no meio
   ("preencher as contas vaz…") elas deixam de responder à pergunta que fazem */
.campo-modo{max-width:calc(260px*var(--k))}
.campo-busca{max-width:calc(280px*var(--k))}
/* caixa do QR do MFA: fundo claro fixo, porque quem lê é uma câmera */
.qr-cx{max-width:calc(220px*var(--k));background:var(--qr-bg);padding:var(--s-2);
  border-radius:var(--r-2)}

/* ── MODAL DE APARÊNCIA ──────────────────────────────────────────────
   As amostras se pintam SOZINHAS: cada botão leva data-paleta e, por causa
   disso, resolve --surface/--border/--mark-* com os tokens daquela paleta.
   Nenhum hex é copiado para dentro do js/aparencia.js — trocar uma cor no bloco
   de tokens muda a amostra no mesmo movimento. */
.apar-grade{display:grid;grid-template-columns:repeat(auto-fit,minmax(calc(120px*var(--k)),1fr));
  gap:var(--s-2)}
.apar-op{display:flex;flex-direction:column;align-items:flex-start;gap:calc(6px*var(--k));
  padding:var(--s-2);border-radius:var(--r-2);text-align:left;width:100%}
.apar-op[aria-pressed="true"]{border-color:var(--accent);box-shadow:var(--anel)}
.apar-op b{font-size:var(--fs-md);font-weight:600}
.apar-op span{font-size:var(--fs-xs);color:var(--muted)}
/* a fita: a superfície da paleta com as três cores que a definem em cima dela */
.apar-fita{display:flex;align-items:center;gap:calc(4px*var(--k));width:100%;
  padding:calc(6px*var(--k));border-radius:var(--r-1);
  background:var(--surface);border:1px solid var(--border)}
.apar-fita i{display:block;height:calc(10px*var(--k));border-radius:var(--r-pill);flex:1}
.apar-fita i:nth-child(1){background:var(--mark-2)}
.apar-fita i:nth-child(2){background:var(--mark-1)}
/* o verde de status entra na amostra de propósito: é o que mostra que a cor de
   status NÃO muda junto com a paleta */
.apar-fita i:nth-child(3){background:var(--ok);flex:0 0 calc(14px*var(--k))}
.apar-linha{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap}
.apar-esc{min-width:calc(58px*var(--k));text-align:center;font-variant-numeric:tabular-nums}

/* ── WORKSPACES E SLOTS ──────────────────────────────────────────────
   .slot é compartilhado entre a lista de contas e a fila de emails. */
.ws-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-4);
  margin-bottom:var(--s-3);overflow:hidden;box-shadow:var(--sh-1),var(--brilho-topo)}
.ws-head{display:flex;align-items:center;gap:var(--s-3);padding:calc(12px*var(--k)) var(--s-4);
  background:var(--surface-2);border-bottom:1px solid var(--border);flex-wrap:wrap}
.ws-head h3{font-size:var(--fs-md)}
/* Dobra do card. Quadrado, fantasma e do tamanho do texto do cabeçalho: ele é o gesto mais
   repetido da aba e o menos importante de olhar. O caret entra por máscara, como no .alert e
   no .empty — nenhum <svg> novo no JS —, e a ROTAÇÃO é o estado: para baixo abre, para a
   direita (fechado) diz que há coisa escondida ali. Sai do aria-expanded, que o leitor de
   tela já lê; classe separada seria uma segunda verdade para manter em pé. */
.ws-dobra{flex:none;width:calc(24px*var(--k));height:calc(24px*var(--k));padding:0;
  background:transparent;border-color:transparent;color:var(--muted);
  display:grid;place-items:center}
.ws-dobra:hover{background:var(--surface-3);border-color:var(--border);color:var(--text)}
.ws-dobra::before{content:"";width:calc(16px*var(--k));height:calc(16px*var(--k));
  background-color:currentColor;transition:transform var(--tr) var(--ease);
  -webkit-mask:var(--ico-caret) no-repeat center/contain;
  mask:var(--ico-caret) no-repeat center/contain}
.ws-dobra[aria-expanded="false"]::before{transform:rotate(-90deg)}
/* fechado o cabeçalho é o card inteiro: sem a linha de baixo, ela não separa nada */
.ws-card.fechado .ws-head{border-bottom:0}
/* login do próprio workspace: mesma linha do slot, mas rebaixada — é cabeçalho, não conta */
.ws-meta{display:flex;align-items:center;gap:var(--s-3);padding:calc(8px*var(--k)) var(--s-4);
  background:var(--surface-2);border-bottom:1px solid var(--border);flex-wrap:wrap;
  font-size:var(--fs-sm)}
/* min-width, não width: "LOGIN" em caixa alta com letter-spacing passa dos 28px do .slot .num */
.ws-meta .rot{flex:none;min-width:calc(38px*var(--k));color:var(--muted);font-size:var(--fs-xs);
  text-transform:uppercase;letter-spacing:.06em}
.ws-meta .em{color:var(--text-2);min-width:calc(170px*var(--k))}
.ws-meta .px{font-family:var(--mono);color:var(--text-2);min-width:calc(150px*var(--k));
  max-width:34ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ws-meta .pf{color:var(--muted)}
/* .acts é o mesmo componente nos três lugares (cabeçalho do workspace, linha de
   login e slot) — era a mesma declaração escrita três vezes, em pontos
   distantes da folha, que é como duas delas divergem sem ninguém notar */
.ws-head .acts,.ws-meta .acts,.slot .acts{margin-left:auto;display:flex;
  gap:calc(6px*var(--k))}
.slot{position:relative;display:flex;align-items:center;gap:var(--s-3);
  padding:calc(10px*var(--k)) var(--s-4);
  border-bottom:1px solid var(--border);flex-wrap:wrap;
  transition:background var(--tr) var(--ease)}
.slot:last-child{border-bottom:0}
.slot:hover{background:var(--surface-3)}
/* barra de accent que CRESCE do centro no hover, em vez de só trocar o fundo.
   É o mesmo indicador do item de nav ativo e da linha de tabela — um único
   vocabulário de "esta é a linha em que estou". */
.slot::before{content:"";position:absolute;left:0;top:0;bottom:0;
  width:calc(3px*var(--k));background:var(--accent);
  transform:scaleY(0);transform-origin:center;
  transition:transform var(--tr) var(--ease)}
.slot:hover::before{transform:scaleY(1)}
.slot .num{flex:none;width:calc(28px*var(--k));color:var(--muted);font-size:var(--fs-sm);font-family:var(--mono)}
.slot .nome{font-weight:600;min-width:calc(130px*var(--k))}
.slot .em{color:var(--muted);font-size:var(--fs-sm);min-width:calc(170px*var(--k))}
/* gateway leva a sessão junto (host:porta · usuário) e estoura o slot: corta com reticências,
   o texto completo fica no title (e no botão de cópia ao lado). Cortar mais curto que 34ch
   esconderia a porta, que em gateway é o que distingue uma sessão da outra — todas as linhas
   ficariam iguais na tela. Entre ~1200 e ~1330px de janela o .acts desce para a segunda linha;
   é o flex-wrap fazendo o que já fazia, e abaixo de 1180 a sidebar vira rail e sobra espaço. */
.slot .px{font-family:var(--mono);font-size:var(--fs-sm);min-width:calc(150px*var(--k));color:var(--text-2);
  max-width:34ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* botão de cópia colado no proxy, no slot e na linha de login. O min-width reserva o espaço
   de "copiado!", que copiarTexto() escreve por cima do rótulo — sem ele a linha dança a cada clique */
.px-copiar{flex:none;min-width:calc(70px*var(--k))}
.slot.vazio{color:var(--muted);font-style:italic;font-size:var(--fs-md)}
/* slot vazio não é registro: não acende nem fundo nem barra */
.slot.vazio:hover{background:transparent}
.slot.vazio::before{content:none}
/* Site que a conta anuncia. É <a> de verdade — abrir em nova aba, botão do meio e "copiar
   endereço" do navegador só funcionam em link. Mesmo tratamento do proxy: trunca com
   reticências e o endereço inteiro fica no title e no botão de cópia ao lado. */
.slot a.site{font-family:var(--mono);font-size:var(--fs-sm);color:var(--accent);
  text-decoration:none;min-width:calc(120px*var(--k));max-width:26ch;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.slot a.site:hover{text-decoration:underline}
.slot .site.sem{font-size:var(--fs-sm);color:var(--muted);font-style:italic;
  min-width:calc(120px*var(--k))}
/* moldura da lista de membros da equipe. Era compartilhada com a lista da distribuição de
   sites, que era modal — hoje a distribuição é uma página inteira (.emp-lista, mais abaixo)
   e não cabe mais numa caixa de 300px. */
.equipe-lista{margin-top:var(--s-3);border:1px solid var(--border);
  border-radius:var(--r-3);max-height:calc(300px*var(--k));overflow-y:auto}
.equipe-lista .slot{padding:calc(8px*var(--k)) calc(10px*var(--k))}
/* checkbox de linha: sem isso o input herda o width:100% do formulário */
.chk{display:flex;align-items:center;gap:calc(6px*var(--k));margin:0;width:auto;
  color:var(--text-2);cursor:pointer}
.chk input{width:auto;flex:none;accent-color:var(--accent)}

/* CNPJ no slot, colado no site. Tabular porque é número que se compara de relance entre
   linhas, e truncado porque a razão social — que é o texto longo — mora no title. */
.slot .cnpj{font-family:var(--mono);font-size:var(--fs-sm);color:var(--text-2);
  font-variant-numeric:tabular-nums;min-width:calc(140px*var(--k))}

/* idade da conta no slot; "fria" = sem registro há mais de 7 dias */
.slot .idade{font-family:var(--mono);font-size:var(--fs-sm);color:var(--muted);
  min-width:calc(38px*var(--k));text-align:right}
.slot .idade.fria{color:var(--warn);font-weight:600}
/* quem criou a conta. Discreto de propósito: é contexto, não estado — a linha já tem duas
   pills disputando o olho. Trunca porque o apelido do email varia de 3 a 20 caracteres e é a
   única coluna do slot cujo tamanho não se controla. */
.slot .autor{font-size:var(--fs-xs);color:var(--muted);max-width:14ch;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ── SITES E EMPRESAS (aba própria) ──────────────────────────────────
   Quatro campos por conta numa linha só. É GRID e não flex — que é o que o .slot usa — porque
   aqui as colunas precisam ficar alinhadas ENTRE as linhas: com flex cada linha se acomoda
   sozinha, e no meio de cinquenta contas o olho perde qual campo é qual. É a mesma razão pela
   qual existe uma linha de cabeçalho, que o .slot nunca precisou ter. */
.emp-lote{padding:var(--s-4);margin-bottom:var(--s-3)}
.emp-lote textarea{font-size:var(--fs-sm)}

/* A moldura, a borda e a rolagem horizontal são do .tbl-wrap por fora — o mesmo par que as
   tabelas do painel já usam. O min-width aqui é o irmão do `table{min-width:820px*k}`: é a
   soma dos mínimos das sete colunas, e é ele que decide quando a rolagem começa em vez de a
   grade transbordar. */
.emp-lista{min-width:calc(1120px*var(--k))}
.emp-lista>:last-child{border-bottom:0}

/* dez colunas: #, conta, os SEIS campos de CAMPOS_EMP na ordem, o botão de buscar e as marcas.
   Mexeu em CAMPOS_EMP, mexe aqui — CSS não lê JS, e é o único ponto do par que não se atualiza
   sozinho. */
.emp-cab,.emp-linha{display:grid;
  grid-template-columns:calc(30px*var(--k)) minmax(calc(115px*var(--k)),1fr)
    calc(150px*var(--k)) minmax(calc(150px*var(--k)),1.3fr)
    minmax(calc(120px*var(--k)),1fr)
    calc(96px*var(--k)) minmax(calc(110px*var(--k)),1fr)
    minmax(calc(150px*var(--k)),1.2fr)
    auto minmax(calc(84px*var(--k)),auto);
  align-items:center;gap:calc(8px*var(--k));
  padding:calc(6px*var(--k)) var(--s-4);border-bottom:1px solid var(--border)}
.emp-cab{background:var(--surface-2);color:var(--muted);font-size:var(--fs-xs);
  text-transform:uppercase;letter-spacing:.06em}
.emp-linha:last-child{border-bottom:0}
.emp-linha:hover{background:var(--surface-3)}
.emp-linha .num{color:var(--muted);font-size:var(--fs-sm);font-family:var(--mono)}
.emp-linha .nome{font-weight:600;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.emp-linha input{width:100%;min-width:0;font-size:var(--fs-sm);
  padding:calc(5px*var(--k)) calc(8px*var(--k))}
/* Campo recusado: continua VISÍVEL com o que foi digitado, marcado, e fora do db. É o único
   jeito de mostrar o que estava errado — apagar o valor esconderia a causa. */
.emp-linha input.erro{border-color:var(--bad);background:var(--bad-soft);color:var(--bad)}
/* O PLACEHOLDER SOME QUANDO O CABEÇALHO JÁ DIZ O NOME DA COLUNA. Com uma conta ele ajudava;
   com dez, "loja.com.br" repetido dez vezes na mesma coluna vira uma parede de dado falso —
   e o olho tem que checar linha a linha o que é exemplo e o que é o site de verdade. A coluna
   já está rotulada em cima, uma vez, que é onde rótulo deve ficar.
   Em tela estreita a regra se inverte, e por isso o :not(): lá o cabeçalho some (a linha
   empilha) e o placeholder volta a ser a única coisa que diz qual campo é qual. */
:root:not([data-estreito]) .emp-linha input::placeholder,
:root:not([data-estreito]) .gt-linha input::placeholder{color:transparent}

/* o botão de buscar tem largura mínima porque ele troca de texto enquanto consulta ("…"),
   e a linha inteira dançaria a cada clique — o mesmo motivo do .px-copiar */
.emp-acao{min-width:calc(58px*var(--k));justify-self:start}
.emp-marcas{display:flex;flex-wrap:wrap;justify-content:flex-end;
  gap:calc(4px*var(--k));font-size:var(--fs-xs);text-align:right}

/* A faixa do workspace separa os grupos: sem ela a numeração recomeçaria em #01 no meio da
   lista sem dizer de quem é. NÃO é sticky, e não por esquecimento — o .tbl-wrap de fora é um
   contexto de rolagem, e dentro de um deles o position:sticky vertical não tem a que se
   grudar. Faixa grudada valeria menos que a lista não invadir a tela. */
.emp-grupo{display:flex;align-items:center;gap:var(--s-3);background:var(--surface-2);
  padding:calc(7px*var(--k)) var(--s-4);border-bottom:1px solid var(--border)}
.emp-grupo .nome{font-weight:600}
.emp-grupo .hint{margin-left:auto}

/* ── GESTÃO DE TRÁFEGO (aba própria) ─────────────────────────────────
   Irmã da aba Sites acima, e diferente dela num ponto que dita este bloco inteiro: lá UMA
   grade serve todas as linhas, porque as seis colunas respondem a mesma pergunta em toda
   conta. Aqui as fases pedem controles diferentes — "a subir" não tem o que medir, "encerrada"
   não tem o que subir —, e uma grade só poria três colunas de dinheiro vazias em toda linha da
   primeira faixa. É o mesmo motivo pelo qual o site saiu de CAMPOS_EMP.
   Então são TRÊS grades, e o alinhamento entre linhas continua valendo DENTRO de cada faixa,
   que é onde o olho compara. O .tbl-wrap é UM só, por fora das três: três contextos de rolagem
   horizontal fariam as faixas desalinharem no eixo x ao rolar. */
/* O min-width é a soma dos mínimos da fase mais larga (a "no ar", com dez colunas), e é ele
   que decide quando a rolagem começa em vez de a grade transbordar — o irmão do
   `.emp-lista{min-width:…}`. Ele foi apertado até a faixa mais larga caber numa janela comum:
   as colunas de dinheiro são as últimas da linha, e rolar para ver justamente o número que se
   veio digitar é o pior lugar possível para cortar. */
.gt-lista{min-width:calc(1080px*var(--k))}
.gt-lista>:last-child{border-bottom:0}

.gt-cab,.gt-linha{display:grid;align-items:center;gap:calc(8px*var(--k));
  padding:calc(6px*var(--k)) var(--s-4);border-bottom:1px solid var(--border)}
.gt-cab{background:var(--surface-2);color:var(--muted);font-size:var(--fs-xs);
  text-transform:uppercase;letter-spacing:.06em}
.gt-linha:hover{background:var(--surface-3)}

/* As colunas são hard-coded e NÃO derivam de COLUNAS_GT/CAMPOS_GT — CSS não lê JS, e agora são
   três grades em vez de uma: mexeu na tabela, mexe nas três. Mexer numa e esquecer as outras
   desalinha só uma faixa, que é o tipo de erro que passa semanas sem ser visto.

   NENHUMA COLUNA DE CONTEÚDO VARIÁVEL PODE SER `auto`, e isto é o oposto do que parece óbvio.
   Cada .gt-linha é um grid PRÓPRIO — não há uma tabela por trás —, então `auto` dimensiona pelo
   conteúdo DAQUELA linha: a coluna do bônus, que troca entre "Pagamos o bônus", "Marcar pago" e
   a pill de pago com o "desmarcar" ao lado, empurrava rodado/receita/vendas para posições
   diferentes em cada linha. O resultado era a lista desalinhada — exatamente o que esta grade
   existe para impedir, e por isso a aba tem cabeçalho.
   `auto` só sobra onde o conteúdo é sempre o mesmo (o botão "Subi o tráfego", o "desmarcar"). */
.gt-cab.gt-subir,.gt-linha.gt-subir{grid-template-columns:
  calc(100px*var(--k)) minmax(calc(136px*var(--k)),1fr)
  minmax(calc(190px*var(--k)),1.4fr) auto calc(160px*var(--k))}
.gt-cab.gt-noar,.gt-linha.gt-noar{grid-template-columns:
  calc(100px*var(--k)) minmax(calc(104px*var(--k)),1fr)
  minmax(calc(136px*var(--k)),1.1fr) calc(48px*var(--k)) calc(184px*var(--k))
  calc(84px*var(--k)) calc(84px*var(--k)) calc(62px*var(--k))
  calc(82px*var(--k)) calc(86px*var(--k))}
.gt-cab.gt-fim,.gt-linha.gt-fim{grid-template-columns:
  calc(100px*var(--k)) minmax(calc(104px*var(--k)),1fr)
  minmax(calc(136px*var(--k)),1fr) calc(104px*var(--k))
  calc(84px*var(--k)) calc(84px*var(--k)) calc(62px*var(--k)) calc(82px*var(--k))}

/* A faixa da fase. NÃO é sticky, e não por esquecimento: o .tbl-wrap de fora é um contexto de
   rolagem, e dentro de um deles o position:sticky vertical não tem a que se grudar. Mesma
   decisão, e mesma razão, do .emp-grupo logo acima. */
.gt-faixa{display:flex;align-items:center;gap:var(--s-3);background:var(--surface-2);
  padding:calc(7px*var(--k)) var(--s-4);border-bottom:1px solid var(--border)}
.gt-faixa .nome{font-weight:600}
.gt-faixa .hint{margin-left:auto}

/* o workspace e o slot juntos numa coluna: é o mesmo "WS-03 #04" do card de Workspaces, e é
   assim que se acha a conta lá depois de vê-la aqui */
.gt-num{color:var(--muted);font-size:var(--fs-sm);font-family:var(--mono);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gt-linha .nome{font-weight:600;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gt-linha select{width:100%;min-width:0;font-size:var(--fs-sm)}
/* Dinheiro é número que se compara ENTRE linhas: alinhado à direita e tabular, pela mesma
   razão do .slot .cnpj. */
.gt-linha input{width:100%;min-width:0;font-size:var(--fs-sm);
  padding:calc(5px*var(--k)) calc(8px*var(--k));
  text-align:right;font-variant-numeric:tabular-nums}
/* Campo recusado: continua VISÍVEL com o que foi digitado, marcado, e fora do db. É o único
   jeito de mostrar o que estava errado — apagar o valor esconderia a causa. */
.gt-linha input.erro{border-color:var(--bad);background:var(--bad-soft);color:var(--bad)}
/* três células que agrupam mais de um filho: o grid conta filhos DIRETOS, então cada uma
   precisa do próprio invólucro, senão o botão de dentro vira uma coluna solta */
.gt-bonus,.gt-acts{display:flex;align-items:center;gap:calc(6px*var(--k))}
/* pill que é célula direta (o status, em Encerradas) esticaria para encher a coluna: item de
   grid estica por padrão, e uma pill esticada deixa de parecer pill */
.gt-linha>.pill{justify-self:start}
.gt-roi{display:flex;justify-content:flex-start}
.gt-marcas{display:flex;flex-wrap:wrap;justify-content:flex-end;
  gap:calc(4px*var(--k));font-size:var(--fs-xs);text-align:right}
/* faixa de trabalho vazia é uma resposta ("nada esperando tráfego"), não um buraco */
.gt-grupo .empty{padding:var(--s-4);font-size:var(--fs-sm)}

/* ── MODAL ───────────────────────────────────────────────────────── */
.mask{position:fixed;inset:0;z-index:50;display:none;background:var(--scrim);
  align-items:flex-start;justify-content:center;padding:var(--s-6) var(--s-4);
  overflow-y:auto;-webkit-backdrop-filter:blur(calc(3px*var(--k)));
  backdrop-filter:blur(calc(3px*var(--k)))}
.mask.on{display:flex;animation:mask-entra var(--tr) var(--ease)}
.modal{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-4);
  width:100%;max-width:calc(620px*var(--k));overflow:hidden;
  box-shadow:var(--sh-3),var(--brilho-topo)}
/* Só para conteúdo de LEITURA em tabela — hoje o relatório da montagem em lote. Formulário
   continua nos 620px: campo largo demais é campo que se lê pior. */
.modal.largo{max-width:calc(940px*var(--k))}
/* A entrada é do MODAL, não da máscara: o scrim aparece junto e o painel sobe
   por baixo dele. modal() só liga a classe .on, então a animação roda sozinha a
   cada abertura sem uma linha de JS. */
.mask.on .modal{animation:modal-entra var(--tr-2) var(--ease-saida)}
@keyframes mask-entra{from{opacity:0}to{opacity:1}}
@keyframes modal-entra{
  from{opacity:0;transform:translateY(calc(10px*var(--k))) scale(.985)}
  to{opacity:1;transform:none}}
.modal-h{display:flex;align-items:center;gap:calc(10px*var(--k));padding:calc(14px*var(--k)) var(--s-5);
  background:var(--surface-2);border-bottom:1px solid var(--border)}
.modal-h h3{font-size:var(--fs-base);flex:1}
.modal-b{padding:var(--s-5)}
.modal-f{display:flex;gap:var(--s-2);flex-wrap:wrap;padding:calc(13px*var(--k)) var(--s-5);
  background:var(--surface-2);border-top:1px solid var(--border)}
.modal-f .spacer{flex:1}

/* ── TRAVA DO COFRE ──────────────────────────────────────────────────
   Acima do .mask (z-50): com o painel trancado, nada pode aparecer por cima — nem um modal
   que tenha ficado aberto antes de trancar. Fundo opaco, e não scrim: o conteúdo atrás não
   pode nem vazar por transparência. */
.trava{position:fixed;inset:0;z-index:60;display:none;background:var(--bg);
  place-items:center;padding:var(--s-5);overflow-y:auto}
.trava.on{display:grid}
/* …com UMA exceção, e ela é o que faz a trava ter saída: o modal aberto DE DENTRO dela sobe por
   cima. Sem isto, "Entrar na nuvem" e o código do autenticador abrem atrás de um fundo opaco —
   a tela parece congelada e não há como digitar nada. Vale só com o modal aberto, e mostrarTrava()
   fecha qualquer modal ao acender a trava: então o que aparecer aqui foi pedido de dentro dela. */
.trava.on ~ .mask.on{z-index:70}
/* A trava é a PRIMEIRA tela de toda abertura do painel — é ela, e não a lista de
   workspaces, que dá o tom do produto. Ganha a elevação de modal, a luz de cima
   e um clarão da marca atrás do tile; a animação de entrada é a mesma do modal,
   porque é o mesmo gesto (uma caixa que assenta sobre o fundo). */
.trava-cx{width:min(calc(400px*var(--k)),100%);background:var(--surface);
  border:1px solid var(--border);border-radius:var(--r-4);
  box-shadow:var(--sh-3),var(--brilho-topo);
  padding:var(--s-5);text-align:center;
  animation:modal-entra var(--tr-2) var(--ease-saida)}
.trava-cx .mark{margin:0 auto;
  filter:drop-shadow(0 calc(3px*var(--k)) calc(14px*var(--k))
    color-mix(in srgb,var(--mark-2) 55%,transparent))}
.trava-cx h2{margin:var(--s-3) 0 var(--s-1);font-size:var(--fs-lg)}
.trava-cx .hint{margin-top:0}
.trava-cx input{margin-top:var(--s-3);text-align:center}
.trava-cx .row{justify-content:space-between}
/* altura reservada: a mensagem de erro não pode empurrar o botão para baixo ao aparecer */
.trava-erro{color:var(--bad);min-height:1.4em;margin-bottom:0}

/* ── TIMELINE ────────────────────────────────────────────────────── */
.tl{border-left:calc(2px*var(--k)) solid var(--border);
  margin:calc(6px*var(--k)) 0 0 calc(7px*var(--k));padding-left:calc(16px*var(--k))}
.tl-item{position:relative;padding:calc(7px*var(--k)) 0}
.tl-item::before{content:"";position:absolute;
  left:calc(-23px*var(--k));top:calc(13px*var(--k));width:calc(9px*var(--k));height:calc(9px*var(--k));
  border-radius:50%;background:var(--muted);border:calc(2px*var(--k)) solid var(--surface)}
.tl-item.ban::before{background:var(--bad)}
.tl-item.criacao::before{background:var(--ok)}
/* aviso e verificacao eram EMITIDOS por contas.js/workspaces.js e não tinham
   regra aqui: caíam no ponto cinza no painel enquanto o ativo.css já os pintava.
   O mesmo evento aparecia de duas cores dependendo da janela em que se olhava. */
.tl-item.aviso::before{background:var(--warn)}
.tl-item.verificacao::before{background:var(--ok)}
.tl-d{font-size:var(--fs-xs);color:var(--muted);font-family:var(--mono)}
.tl-t{font-size:var(--fs-md)}

/* ── ESTADO VAZIO ────────────────────────────────────────────────────
   Era uma linha de texto cinza. Um painel de operação passa boa parte da vida
   com alguma lista vazia (fila zerada, sem cartão, sem snapshot), e cada uma
   delas é a primeira coisa que alguém vê ao abrir aquela aba pela primeira vez.
   O ícone entra por máscara, como no .alert — nenhum <svg> novo no JS. */
.empty{color:var(--muted);font-size:var(--fs-md);padding:var(--s-5);text-align:center}
.empty::before{content:"";display:block;width:calc(34px*var(--k));height:calc(34px*var(--k));
  margin:0 auto var(--s-3);background-color:currentColor;opacity:.4;
  -webkit-mask:var(--ico-vazio) no-repeat center/contain;
  mask:var(--ico-vazio) no-repeat center/contain}
/* como card, ele é um lugar à espera de conteúdo — borda tracejada e sem
   elevação, para não competir com os cards que têm dado dentro */
.card.empty{border-style:dashed;box-shadow:none;background:transparent;
  padding:var(--s-6) var(--s-5)}

/* ── PRIMEIROS PASSOS ────────────────────────────────────────────────
   O oposto do .card.empty: ali é um lugar esperando conteúdo, aqui é
   trabalho a fazer. Por isso tem borda de acento e elevação — ele deve
   ganhar o olho dos cards de workspace enquanto existir, e some sozinho
   quando a instalação termina (ver blocoPrimeirosPassos em render.js).
   Não é a faixa de alertas do topo de volta: é um só, mora dentro da
   aba, na coluna do conteúdo, e tem prazo de validade. */
.card.setup{border-color:var(--accent);
  box-shadow:var(--sh-2),inset calc(3px*var(--k)) 0 0 var(--accent)}
.card.setup>h3{font-size:var(--fs-lg);margin-bottom:var(--s-2)}
.card.setup .passos{list-style:none;margin:var(--s-4) 0 0;padding:0;
  display:flex;flex-direction:column;gap:var(--s-4)}
.card.setup .passos li{display:flex;gap:var(--s-3);align-items:flex-start}
.card.setup .passos .n{flex:none;display:grid;place-items:center;
  width:calc(26px*var(--k));height:calc(26px*var(--k));border-radius:50%;
  background:var(--accent);color:var(--accent-contrast);
  font-size:var(--fs-sm);font-weight:700;margin-top:calc(1px*var(--k))}
.card.setup .passos li.feito .n{background:var(--ok-soft);color:var(--ok);
  border:1px solid color-mix(in srgb,var(--ok) 35%,transparent)}
.card.setup .passos h4{font-size:var(--fs-base);margin:0 0 calc(2px*var(--k))}
.card.setup .passos li.feito h4{color:var(--muted);text-decoration:line-through;
  text-decoration-color:color-mix(in srgb,var(--muted) 50%,transparent)}
.card.setup .passos p{margin:0 0 var(--s-2);color:var(--text-2);font-size:var(--fs-md);
  max-width:78ch}
.card.setup .passos li.feito p{color:var(--muted)}

/* a URL ocupa o lugar do proxy no slot, e cabe mais: sem status, idade e Kit disputando
   a linha, dá para mostrar o endereço quase inteiro antes das reticências. */
#tab-lk .slot .px{flex:1;max-width:46ch}
#tab-lk .slot .em{flex:1 1 calc(200px*var(--k))}

/* tabelas da aba Análise ficam dentro de card, sem largura mínima de planilha */
#analise table{min-width:calc(520px*var(--k))}

/* ── LARGURA ─────────────────────────────────────────────────────────
   Estes eram três @media (max-width). Não podiam continuar sendo: media query só enxerga o
   px CSS, e o px CSS deixou de dizer o tamanho da janela desde que o painel passou a compensar
   o zoom. A 67%, uma janela de 1000px reais mede 1492px CSS e nunca viraria rail.

   Quem mede agora é aplicarLargura() em js/escala.js, sempre em px de tela, ligando atributos
   no :root. Os limites são os mesmos de antes — 1180 rail · 820 barra inferior · 560 estreito —
   e são cumulativos: abaixo de 820 o data-rail também está ligado.

   O quarto, data-largo (≥2100), é o que sobrou do antigo degrau de tela grande: a escala virou
   contínua no --k, mas truncar o gateway em 34ch quando sobra largura não é escala, é decisão
   de leitura. */
:root[data-rail] .app{grid-template-columns:var(--sidebar-rail) 1fr}
:root[data-rail] .brand{justify-content:center;
  padding:calc(18px*var(--k)) var(--s-2) var(--s-3)}
:root[data-rail] .brand-txt{display:none}
:root[data-rail] nav.tabs button{justify-content:center;padding:calc(11px*var(--k)) 0}
:root[data-rail] nav.tabs button span{display:none}
:root[data-rail] nav.tabs button.on::before{left:calc(2px*var(--k));height:calc(16px*var(--k))}
/* dois botões de ícone não cabem lado a lado num rail de 72px: no rail eles empilham */
:root[data-rail] .side-foot{flex-direction:column;justify-content:center;padding:var(--s-2)}
:root[data-rail] .side-foot button span{display:none}
:root[data-rail] .ver{display:none}
:root[data-rail] header.top{padding:var(--s-3) var(--s-4)}
:root[data-rail] .wrap{padding:var(--s-4) var(--s-4) calc(80px*var(--k))}

:root[data-barra] .app{grid-template-columns:1fr}
:root[data-barra] .sidebar{position:fixed;top:auto;left:0;right:0;bottom:0;height:auto;
  flex-direction:row;align-items:center;padding:0 var(--s-2);
  border-right:0;border-top:1px solid var(--border);box-shadow:var(--sh-barra)}
:root[data-barra] .brand{display:none}
:root[data-barra] nav.tabs{flex-direction:row;gap:var(--s-1);padding:var(--s-2) 0;overflow-x:auto}
:root[data-barra] nav.tabs button{flex:1;min-width:calc(54px*var(--k))}
:root[data-barra] nav.tabs button.on::before{left:50%;top:calc(2px*var(--k));
  transform:translateX(-50%);width:calc(16px*var(--k));height:calc(3px*var(--k))}
:root[data-barra] .side-foot{flex-direction:row;margin-top:0;padding:0 var(--s-1) 0 var(--s-2);
  border-top:0;border-left:1px solid var(--border)}
:root[data-barra] .wrap{padding-bottom:calc(100px*var(--k))}

:root[data-estreito] .kpis{grid-template-columns:1fr 1fr}
:root[data-estreito] header.top{gap:var(--s-2)}
:root[data-estreito] header.top h1{font-size:var(--fs-base)}
:root[data-estreito] .ws-now{width:100%;justify-content:space-between}
:root[data-estreito] .wrap{padding-left:var(--s-3);padding-right:var(--s-3)}
:root[data-estreito] .card-h{gap:var(--s-2)}
/* Os campos de busca/filtro tinham max-width INLINE no HTML, e por isso esta
   regra precisava de !important para vencê-los. Hoje eles usam .campo-busca /
   .campo-filtro, que são classes como qualquer outra: a cascata resolve. */
:root[data-estreito] .card-h input,
:root[data-estreito] .card-h select{max-width:none;flex:1 1 100%}
:root[data-estreito] .slot,
:root[data-estreito] .ws-meta{align-items:flex-start}
:root[data-estreito] .slot .acts,
:root[data-estreito] .ws-meta .acts{margin-left:0;width:100%}
/* Empilhado, o cabeçalho de colunas não descreve mais nada (cada campo fica sozinho na
   linha), então some — e o placeholder de cada input passa a ser quem diz o que ele é. */
:root[data-estreito] .emp-lista{min-width:0}
:root[data-estreito] .emp-cab{display:none}
:root[data-estreito] .emp-linha{grid-template-columns:calc(30px*var(--k)) 1fr}
:root[data-estreito] .emp-linha input{grid-column:2}
:root[data-estreito] .emp-acao{grid-column:2;justify-self:start}
:root[data-estreito] .emp-marcas{grid-column:2;justify-content:flex-start}
/* A aba Gestão de Tráfego colapsa igual, e com uma regra a menos: como as três grades já
   viram duas colunas aqui, basta jogar TODO filho direto para a segunda — o número fica na
   primeira, sozinho, como no .emp-linha. */
:root[data-estreito] .gt-lista{min-width:0}
:root[data-estreito] .gt-cab{display:none}
:root[data-estreito] .gt-cab.gt-subir,
:root[data-estreito] .gt-cab.gt-noar,
:root[data-estreito] .gt-cab.gt-fim,
:root[data-estreito] .gt-linha.gt-subir,
:root[data-estreito] .gt-linha.gt-noar,
:root[data-estreito] .gt-linha.gt-fim{grid-template-columns:calc(112px*var(--k)) 1fr}
:root[data-estreito] .gt-linha>*{grid-column:2}
:root[data-estreito] .gt-linha .gt-num{grid-column:1}
:root[data-estreito] .gt-marcas,
:root[data-estreito] .gt-roi{justify-content:flex-start}
:root[data-estreito] .g2,
:root[data-estreito] .g3{grid-template-columns:1fr}
:root[data-estreito] .modal-h,
:root[data-estreito] .modal-b,
:root[data-estreito] .modal-f{padding-left:var(--s-4);padding-right:var(--s-4)}

/* aqui sobra largura: o gateway (host:porta · usuário) para de ser truncado */
:root[data-largo] .slot .px,
:root[data-largo] .ws-meta .px{max-width:48ch}
:root[data-largo] .slot a.site{max-width:38ch}
:root[data-largo] #tab-lk .slot .px{max-width:66ch}

/* ── EFEITOS: O INTERRUPTOR ──────────────────────────────────────────
   O padrão é "pleno" — gradiente, luz ambiente, glow e movimento —, e é ele que
   está escrito nas regras acima. Este bloco é o caminho de volta.

   Ele existe porque o IDENTIDADE.md dizia, com razão para o painel que era:
   "ferramenta de operação, não produto de marketing… rápido de ler, não
   impressionante de ver". A doutrina mudou por pedido, mas apagá-la seria
   perder a opção — e quem opera oito horas seguidas pode querer a tela quieta.

   Repare que a MAIOR parte do desligamento é feita por TOKEN, não por regra:
   zerar --brilho-topo, --luz-* e --sh-glow apaga sozinho a luz de cima, o
   radial do fundo e todo halo. Só o que não cabe num token (gradiente,
   transform e keyframe) precisa de regra explícita aqui embaixo. */
:root[data-efeitos="sobrio"]{
  --brilho-topo:none; --brilho-acao:none; --sh-glow:none;
  --luz-1:transparent; --luz-2:transparent;
}
:root[data-efeitos="sobrio"] .sidebar{background:var(--surface)}
:root[data-efeitos="sobrio"] .brand .mark,
:root[data-efeitos="sobrio"] .trava-cx .mark{filter:none}
:root[data-efeitos="sobrio"] button.primary{background:var(--accent)}
:root[data-efeitos="sobrio"] button.primary:hover{background:var(--accent-hover);
  transform:none}
:root[data-efeitos="sobrio"] nav.tabs button.on{background:var(--accent-soft)}
:root[data-efeitos="sobrio"] nav.tabs button.on::before{box-shadow:none}
:root[data-efeitos="sobrio"] .kpi:hover{transform:none;box-shadow:var(--sh-1)}
:root[data-efeitos="sobrio"] .kpi.ok::before{background:var(--ok)}
:root[data-efeitos="sobrio"] .kpi.warn::before{background:var(--warn)}
:root[data-efeitos="sobrio"] .kpi.bad::before{background:var(--bad)}
:root[data-efeitos="sobrio"] .bar>i{background:var(--accent)}
:root[data-efeitos="sobrio"] .bar.full>i{background:var(--warn)}
:root[data-efeitos="sobrio"] .bar{box-shadow:none}
:root[data-efeitos="sobrio"] .slot::before{content:none}
:root[data-efeitos="sobrio"] tbody tr:hover td:first-child{box-shadow:none}
:root[data-efeitos="sobrio"] .pill{box-shadow:none}
:root[data-efeitos="sobrio"] .pill::before,
:root[data-efeitos="sobrio"] .selo-nuvem::before{box-shadow:none}
:root[data-efeitos="sobrio"] .card.empty{border-style:solid;background:var(--surface)}
:root[data-efeitos="sobrio"] .empty::before{display:none}
:root[data-efeitos="sobrio"] .mask.on,
:root[data-efeitos="sobrio"] .mask.on .modal,
:root[data-efeitos="sobrio"] .trava-cx,
:root[data-efeitos="sobrio"] .tab.on{animation:none}

@media (prefers-reduced-motion:reduce){
  *{transition-duration:.01ms !important;animation-duration:.01ms !important}
}
