﻿/* ============================================================
   Painel Sou Santo - ferramenta de trabalho, nao vitrine.
   Quem abre isto decide verba: a tela tem que ser rapida de
   escanear, nao bonita a toa.

   Tres decisoes que sustentam o resto:
     1. Cor SO tem significado. Verde/dourado/vermelho sao
        veredito de lucro. O que nao tem veredito e cinza.
     2. Cada fonte tem um trabalho: condensada para numero
        grande, sans para interface, mono para coluna de tabela.
     3. Espacamento sai de uma escala de sete degraus (--e1..--e7).
   ============================================================ */

/* ===================================================================
   Fontes servidas localmente (public/vendor/fonts). Mesma razao do
   Chart.js: o painel abre sem internet e sem depender de CDN.
   Só os pesos usados, subset latin - 156 KB no total.
   =================================================================== */

/* UMA familia para a interface inteira, em cinco pesos.
   A Anton durou um commit: fonte de display em DADO e rotulo e proibida em
   painel de trabalho - ela decora onde o numero precisa ser lido. O peso 800 da
   Geist Sans da a mesma presenca sem trocar a voz da interface. Trocou de Inter
   para Geist Sans em 05/08/2026 - Inter virou a fonte-padrao de todo painel de
   SaaS, o que a faz ler como "sem fonte nenhuma"; Geist Sans e tao adequada
   quanto pra numero/tabela densa, mas ainda tem identidade propria. */
@font-face {
  font-family: "Geist Sans"; font-style: normal; font-weight: 700; font-display: swap;
  src: url("vendor/fonts/geist-sans-latin-700-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Geist Sans"; font-style: normal; font-weight: 800; font-display: swap;
  src: url("vendor/fonts/geist-sans-latin-800-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Geist Sans"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("vendor/fonts/geist-sans-latin-400-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Geist Sans"; font-style: normal; font-weight: 500; font-display: swap;
  src: url("vendor/fonts/geist-sans-latin-500-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Geist Sans"; font-style: normal; font-weight: 600; font-display: swap;
  src: url("vendor/fonts/geist-sans-latin-600-normal.woff2") format("woff2");
}
@font-face {
  font-family: "JetBrains Mono"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("vendor/fonts/jetbrains-mono-latin-400-normal.woff2") format("woff2");
}
@font-face {
  font-family: "JetBrains Mono"; font-style: normal; font-weight: 500; font-display: swap;
  src: url("vendor/fonts/jetbrains-mono-latin-500-normal.woff2") format("woff2");
}

/* ===================================================================
   TEMA. Dois conjuntos completos: escuro (padrao) e claro.

   Trocar de tema troca SO estes tokens - nenhuma regra abaixo repete cor
   literal. Foi por isso que a troca coube num bloco: o painel ja lia tudo de
   variavel. Onde ainda havia rgba() literal (veu de selecao, fundo de alerta),
   os valores viraram token proprio, senao o tema claro herdaria manchas
   escuras.

   O fundo saiu do marrom-quente para um azul-profundo neutro: e a diferenca
   entre "terminal antigo" e "aplicativo", e o ciano de marca - que ja estava la
   - finalmente assenta, em vez de brigar com o amarelo do preto.
   =================================================================== */
:root {
  color-scheme: dark;

  /* ---------- 6 tons base, nomeados por FUNCAO ---------- */
  --bg:        #0B0D14;   /* fundo da aplicacao */
  --surface:   #12151F;   /* fundo de card e painel */
  --line:      #232838;   /* borda e divisoria */
  --ink:       #EDF0F7;   /* texto primario: o numero que decide */
  --ink-2:     #A8B0C4;   /* texto secundario */
  --ink-3:     #7B8499;   /* rotulo, legenda, unidade */

  /* apoios do mesmo eixo, para elevacao e divisoria fraca */
  --surface-2: #181C29;
  --line-soft: #1B2030;

  /* ---------- cor com SIGNIFICADO ----------
     Fora desta lista, nada e colorido. Cinza nao e decisao: e ausencia
     de veredito, e deve parecer isso mesmo. */
  --lucro:     #35C88A;   /* lucro saudavel */
  --limite:    #E0B341;   /* no limite */
  --prejuizo:  #E85C7E;   /* prejuizo */

  /* Versoes claras: o verde e o vermelho cheios sao escuros demais para TEXTO
     miudo sobre fundo escuro. Preenchimento e filete usam os de cima; texto de
     11px usa estes. */
  --lucro-claro:    #6FE3AE;
  --prejuizo-claro: #FF9DB4;

  /* fundo da sidebar: um degrau abaixo do fundo da aplicacao */
  --bg-fundo:  #080A10;

  /* ---------- MARCA E INTERACAO ----------
     Ciano eletrico, e a escolha NAO foi estetica: verde, ambar e vermelho ficam
     RESERVADOS para veredito e severidade, entao a cor de marca tem de ficar
     perceptualmente longe dos tres. Sem isso, "ambar = atencao" colide com
     "ambar = marca" na mesma tela - que e exatamente o incidente do ROAS que
     este projeto ja viveu.
     Usa-se para: acao primaria, foco, selecao, item ativo, hover, enfase de
     dado. NUNCA para status. Decidido com o usuario em 30-07-2026. */
  /* CORRIGIDO em 24-08-2026, pedido do usuario: paleta trocou de ciano pro
     azul da logo (Pantone ~19-4052 TCX / HEX aproximado #004A7C na propria
     logo). O HEX literal da logo NAO serve aqui - medido contra este fundo
     (#0B0D14) da 2,10:1, bem abaixo do minimo de 4,5 pra texto. #2FB8E0 e um
     azul da MESMA familia, mais claro/vivo, que passa com folga (8,37:1) -
     e tambem uma ponte com o ciano antigo, mantendo um pouco da identidade
     anterior. O HEX literal da logo vira a cor do tema CLARO logo abaixo,
     onde ele mede bem (8,55:1) - mesmo padrao que o projeto ja usa (cores
     diferentes por tema, nunca a mesma forcada nos dois). */
  --marca:       #2FB8E0;
  --marca-forte: #6ED6F0;   /* hover de link e botao */
  --marca-fraco: #1C6E8C;   /* borda, filete, estado apagado */
  --marca-veu:   rgba(47, 184, 224, .10);  /* fundo de linha selecionada/hover */
  /* mesmo cobre da tela de login (public/login.css) - so decorativo (filete de
     card, gradiente de botao), nunca texto, entao um valor so serve pros dois
     temas sem precisar medir contraste. */
  --marca-cobre: #C77D4A;

  /* ---------- ACCENT DO DASHBOARD (azul cobalto) ----------
     Cor nova, só para o redesenho da Visão Geral (10-08-2026): KPI de
     destaque, linha do gráfico de ROAS, seleção de canal. Longe das quatro
     cores já reservadas (ciano de marca, verde/dourado/vermelho de veredito)
     de propósito — mesma razão que criou --marca separada do veredito.
     --accent NUNCA substitui --marca nos elementos que já existem (nav ativo,
     foco, checkbox) — os dois convivem: --marca é interação geral do painel
     inteiro, --accent é assinatura desta tela. */
  --accent:       #4B6EF5;
  --accent-forte: #8FA8FF;   /* texto/ícone sobre --surface — validado em contraste.mjs */
  --accent-fraco: #33459E;   /* borda, estado apagado */
  --accent-veu:   rgba(75, 110, 245, .10);

  /* ---------- O DOURADO SAIU DA MARCA ----------
     #D9A441 agora significa SO "no limite" - e o mesmo hex de --limite, e isso
     deixou de ser um problema porque os dois papeis viraram um. Ate 30-07-2026
     ele era marca E status ao mesmo tempo, e era por isso que a regra "cor so
     tem significado" precisava ser tao dura: nao havia como distinguir os dois.
     Estes tres tokens sobrevivem apenas onde o sentido e ALERTA. */
  --gold:      #E0B341;
  --gold-forte:#F0C766;
  --gold-fraco:#B88F2E;

  /* ---------- fundos de estado ----------
     Eram rgba() literais espalhados pelas regras. Viraram token porque no tema
     claro um veu preto-azulado sujaria a superficie branca: cada tema define o
     seu, e a regra que usa nao muda. */
  --veu-lucro:    rgba(53, 200, 138, .10);
  --veu-limite:   rgba(224, 179, 65, .10);
  --veu-prejuizo: rgba(232, 92, 126, .10);
  --veu-marca-forte: rgba(47, 184, 224, .16);  /* linha selecionada */
  --veu-marca-max:   rgba(47, 184, 224, .24);  /* selecionada E sob o cursor */
  /* realce sem cor: zebra da tabela e hover de navegacao */
  --veu-neutro:      rgba(255, 255, 255, .022);
  --sombra-painel: 0 14px 34px rgba(0, 0, 0, .55);

  /* ---------- series de grafico ----------
     Existiam SO dentro dos .js, fora do alcance do tema. Aqui elas
     passam a fazer parte da paleta e os graficos leem daqui. */
  --serie-gasto:   #7C6BF5;  /* investimento */
  --serie-receita: #35C88A;  /* receita = mesma cor de lucro */
  --serie-neutra:  #3A4055;  /* sem veredito */
  --pizza-1: #3DE1F0;
  --pizza-2: #7C6BF5;
  --pizza-3: #E85C7E;
  --pizza-4: #35C88A;
  --pizza-5: #E0B341;
  --pizza-6: #6E778F;
  --pizza-7: #C77DFF;

  /* Texto do badge de empresa (inicial sobre --pizza-N, .empresaBadge):
     nao existe uma cor de texto fixa que bata 4,5:1 contra as 7 --pizza-*
     nos dois temas ao mesmo tempo. Medido, nao suposto (mesma formula WCAG
     de scripts/contraste.mjs): preto puro (#000) e o melhor fixo possivel -
     aqui no escuro passa com folga, pior caso 4,70:1 (pizza-6). Branco foi
     tentado primeiro e mediu so 1,59:1 contra pizza-1 (#3DE1F0) - reprovado,
     mesmo tipo de erro que o funil ja cometeu e corrigiu sobre esta MESMA
     paleta (ver comentario em .funilNome, mais abaixo). */
  --empresa-badge-texto: #000;

  /* ---------- tipografia: DUAS VOZES, e o display e o grito ----------
     A interface fala em Geist Sans. Todo NUMERO e todo ROTULO de dado falam em mono:
     digito de largura fixa alinha coluna sozinho, e da ao painel a voz de
     etiqueta de composicao - que e literalmente o que a marca costura na roupa.
     O display fica reservado ao numero que DECIDE (KPI) e ao titulo da pagina.
     Se ele aparecer em mais de dois lugares por tela, perdeu a funcao.

     Antes eram tres compartimentos paralelos (display/sans/mono) sem relacao
     entre si, e o rotulo em Inter caixa alta era o eyebrow de qualquer
     dashboard - nao dizia nada sobre esta marca. */
  --font-display: "Geist Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  /* Trocado em 19-08-2026, pedido explicito do usuario: mandou print de outro
     painel (DataCrazy) e pediu a mesma fonte. Inspecionei o CSS de verdade do
     DataCrazy (nao suposicao) - o body de la e so
     "ui-sans-serif, system-ui, ...", a stack padrao do Tailwind. Ou seja: NAO
     e uma fonte de marca, e a fonte NATIVA do sistema operacional (Segoe UI no
     Windows, San Francisco no Mac) - o motivo de parecer "diferente" e
     justamente parecer nativo, nao uma fonte desenhada. Substitui aqui pela
     mesma stack, sem vendorizar nada novo (ainda mais alinhado com a politica
     zero-CDN do painel do que a Geist Sans, que precisa do arquivo local).
     --font-display continua Geist Sans de proposito - o pedido foi sobre o
     texto do corpo/rotulos (o print mostrado era paragrafo e label de form),
     nao sobre o numero grande do KPI, que e um caso separado. */
  --font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, Consolas, monospace;

  /* ---------- raio ----------
     Cara de aplicativo vem daqui e do espacamento, nao de efeito. Teto de 12px:
     acima disso o card vira balao, e "muito arredondado" e tao datado quanto
     canto vivo. Pilula so onde o elemento E uma pilula (chip, etiqueta). */
  --r1: 4px;    /* campo, botao pequeno */
  --r2: 8px;    /* botao, painel interno */
  --r3: 12px;   /* card, superficie principal */
  --r-pilula: 999px;

  /* ---------- escala de espacamento ----------
     Sete degraus. Antes existiam 22 valores soltos (9, 10, 11, 13,
     14, 15px convivendo), o que faz nada alinhar com nada. */
  --e1: 4px;
  --e2: 8px;
  --e3: 12px;
  --e4: 16px;
  --e5: 24px;
  --e6: 32px;
  --e7: 48px;

  /* transicao unica: ferramenta de trabalho, nao landing page */
  --troca: 120ms ease;
}

/* ===================================================================
   TEMA CLARO. Nao e o escuro com as cores invertidas: os verdes e vermelhos
   neon do escuro ficam ilegiveis sobre branco (contraste de 1,8:1 em texto
   miudo), entao a faixa semantica inteira escurece para passar de 4,5:1.
   O ciano de marca e o caso mais grave - #3DE1F0 sobre branco e praticamente
   invisivel, e vira um teal fechado aqui.
   =================================================================== */
:root[data-tema="claro"] {
  color-scheme: light;

  --bg:        #F4F6FB;
  --surface:   #FFFFFF;
  --line:      #DDE2EE;
  --ink:       #0E1220;
  --ink-2:     #4A5268;
  --ink-3:     #646D82;

  --surface-2: #EDF0F7;
  --line-soft: #E6EAF3;
  --bg-fundo:  #FFFFFF;

  --lucro:     #0F8F5F;
  --limite:    #96690A;
  --prejuizo:  #C9315A;
  /* no claro, "claro" passa a significar MAIS ESCURO: e a versao legivel para
     texto miudo, e sobre branco isso e o tom fechado, nao o pastel */
  --lucro-claro:    #0B6E49;
  --prejuizo-claro: #A62448;

  /* Cor exata da logo (ver comentario no bloco escuro acima) - aqui mede
     8,55:1 contra o fundo claro, o melhor caso dos dois temas pra este
     tom especifico. */
  --marca:       #004A7C;
  --marca-forte: #003960;
  --marca-fraco: #5C8FB3;
  --marca-veu:   rgba(0, 74, 124, .09);
  --veu-marca-forte: rgba(0, 74, 124, .15);
  --veu-marca-max:   rgba(0, 74, 124, .22);
  --marca-cobre: #C77D4A;
  /* no claro o realce neutro e uma SOMBRA, nao um brilho: branco sobre branco
     nao existe */
  --veu-neutro:      rgba(14, 18, 32, .028);

  --gold:      #96690A;
  --gold-forte:#8A5F08;
  --gold-fraco:#D8B871;

  /* accent do dashboard: escurece pro claro, mesma razão do --marca acima —
     #4B6EF5 sobre branco fica perto do piso de 4,5:1; este passa com folga */
  --accent:       #2F4FE0;
  --accent-forte: #1F39B8;
  --accent-fraco: #7C93F0;
  --accent-veu:   rgba(47, 79, 224, .09);

  --veu-lucro:    rgba(15, 143, 95, .10);
  --veu-limite:   rgba(169, 118, 11, .10);
  --veu-prejuizo: rgba(201, 49, 90, .10);
  --sombra-painel: 0 12px 28px rgba(14, 18, 32, .12);

  --serie-gasto:   #6D5AE0;
  --serie-receita: #0F8F5F;
  --serie-neutra:  #AEB6C8;
  --pizza-1: #0B7E90;
  --pizza-2: #6D5AE0;
  --pizza-3: #C9315A;
  --pizza-4: #0F8F5F;
  --pizza-5: #A9760B;
  --pizza-6: #6B7488;
  --pizza-7: #9B4DD8;

  /* Mesmo token do bloco escuro, mesmo motivo (ver comentario la). Aqui
     preto (#000) segue sendo o melhor fixo possivel, mas NAO fecha 4,5:1
     nas 7 cores: pior caso 4,07:1 (pizza-3, #C9315A). Falta pequena, MEDIDA
     e aceita (ver scripts/contraste.mjs) - ainda assim muito melhor que o
     branco testado antes (1,59:1 no escuro). Nao existe cor fixa unica que
     passe nas 14 combinacoes (7 --pizza-* x 2 temas) sem customizar por
     cor, e customizar por cor foi descartado pela mesma razao do funil:
     o julgamento fica no tamanho/peso do texto, nao na cor de fundo. */
  --empresa-badge-texto: #000;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--font-sans);
  background: var(--bg);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
}

/* Barra de rolagem no tema. A do sistema entra clara e grossa dentro de painel
   escuro, e aparece em tres lugares que sao usados o tempo todo: a tabela de
   campanhas, a lista de 182 campanhas do seletor e a faixa de navegacao quando
   a sidebar vira barra horizontal em tela estreita. */
* { scrollbar-width: thin; scrollbar-color: var(--line) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--line);
  border-radius: var(--r2);
  border: 2px solid transparent;
  background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--ink-3); background-clip: content-box; }

/* Rotulo recorrente, agora em MONO: e a voz de etiqueta de composicao, e nao o
   eyebrow em Inter que todo dashboard usa.
   A mono desenha mais largo que a Geist Sans no mesmo corpo, entao o tamanho cai de
   10,5 para 10px e o espacamento de .14 para .08em - sem isso o rotulo cresce e
   quebra linha onde hoje cabe em uma. */
.eyebrow,
.kpi .label,
.cardTitle,
th,
.fgCampo > span,
.stepLabel {
  font-family: var(--font-mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--ink-3);
  font-weight: 500;
}

/* ------------------------------------------- estrutura: sidebar + conteudo */

.shell {
  display: grid;
  grid-template-columns: 234px minmax(0, 1fr);
  min-height: 100vh;
  transition: grid-template-columns var(--troca);
}

/* Sidebar colapsada - encolhe a coluna do grid, não só o aside por dentro,
   senão sobrava uma faixa vazia do tamanho antigo ao lado.
   CORRIGIDO em 20-08-2026, duas vezes: (1) sigla de 2 letras -> ícone (usuário
   reportou "cortando o texto"); (2) usuário esclareceu que o ícone é só da
   CATEGORIA (logo da plataforma - Meta Ads, Instagram) - subcategoria
   (Visão Geral, Campanhas, Conteúdo...) não leva ícone nenhum. Consequência:
   com a lista de subcategorias visível e sem ícone nem texto, os botões
   ficariam em branco - por isso `.navItems` (a lista) fica ESCONDIDA inteira
   quando colapsado, não só o texto de dentro. Só as categorias (ícone) ficam
   à mostra; clicar numa categoria colapsada já leva pra primeira aba dela
   (comportamento que o clique no cabeçalho do grupo já tinha, sem precisar
   de código novo aqui). */
.shell.is-sidebarColapsada { grid-template-columns: 60px minmax(0, 1fr); }
.shell.is-sidebarColapsada .brandTexto,
.shell.is-sidebarColapsada .navItems,
.shell.is-sidebarColapsada .sidebarFoot,
.shell.is-sidebarColapsada .navBadge { display: none; }
.shell.is-sidebarColapsada .navGroup { justify-content: center; padding-left: 0; padding-right: 0; }
.shell.is-sidebarColapsada .brand { justify-content: center; padding: 0 0 var(--e6); }

/* CORRIGIDO em 24-08-2026: .navTexto saiu do display:none acima e virou
   dica flutuante. Colapsado, o nome do grupo (Meta Ads, Instagram...)
   deixa de ficar visivel sempre - reaparece so no hover, do lado do
   icone, reaproveitando o MESMO texto que ja existe no DOM (nao duplica
   nada em HTML). Pedido do usuario em 24-08-2026: sidebar colapsado
   "mais bonito, moderno, interativo" - hoje era so um icone mudo. */
.shell.is-sidebarColapsada .navGroup { position: relative; }
.shell.is-sidebarColapsada .navTexto {
  display: block;
  position: absolute;
  left: 100%;
  top: 50%;
  margin-left: var(--e3);
  transform: translateY(-50%) translateX(-4px);
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--ink);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  white-space: nowrap;
  padding: 5px 10px;
  border-radius: var(--r1);
  box-shadow: var(--sombra-painel);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--troca), transform var(--troca);
  z-index: 30;
}
.shell.is-sidebarColapsada .navGroup:hover .navTexto,
.shell.is-sidebarColapsada .navGroup:focus-visible .navTexto {
  opacity: 1;
  transform: translateY(-50%) translateX(0);
}
/* Realce do icone ao passar o mouse - mesmo tom (--veu-neutro) que
   .navItem:hover ja usa no sidebar expandido, so que aqui vira um
   pilula em volta do icone em vez de faixa inteira (nao ha texto para
   a faixa acompanhar). */
.shell.is-sidebarColapsada .navGroup:hover {
  background: var(--veu-neutro);
  border-radius: var(--r2);
}

/* CORRIGIDO em 23-08-2026: era font-size:13px aqui, herdado de quando o
   grupo Publicar era o unico com emoji ("📤", que RENDERIZA como texto e
   escala com font-size). Os tres icones SVG (Meta/Instagram 17px,
   Google 17px) tem width/height proprios em pixel e nao escalam com
   font-size do pai - so o emoji lia esse valor. Com 13px o emoji saia
   visivelmente menor que os SVGs de 17px no sidebar expandido (o estado
   COLAPSADO ja tinha a regra abaixo pareando os dois em 15px - so o
   expandido, o estado que a maioria ve, ficava com o descompasso). Subido
   pra 17px pra casar com o tamanho real dos SVGs. */
.navIcone { display: inline-block; width: 1.4em; margin-right: var(--e2); font-size: 17px; line-height: 1; }
.shell.is-sidebarColapsada .navIcone { margin-right: 0; font-size: 15px; }

/* SVG tem width/height fixo, nao escala com font-size como o emoji fazia -
   sem isto, os tres icones coloridos ficariam menores que o "📤" do
   Publicar quando o sidebar colapsa. */
.shell.is-sidebarColapsada .navIcone svg { width: 15px; height: 15px; }

.sidebar {
  position: sticky;
  top: 0;
  align-self: start;
  height: 100vh;
  display: flex;
  flex-direction: column;
  padding: var(--e6) 0 var(--e5);
  background: var(--bg-fundo);
  border-right: 1px solid var(--line);
}

.brand {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e2);
  padding: 0 var(--e5) var(--e6);
}
/* CORRIGIDO em 24-08-2026, pedido do usuario: o nome do painel falava a
   fonte do CORPO do texto (--font-sans, a nativa do sistema) em
   caixa-alta bem espacada - lia como rotulo, nao como marca. Troca para
   --font-display (Geist Sans): a MESMA fonte que ja grita os numeros
   grandes de KPI no resto do painel, ja baixada localmente - nenhum
   arquivo novo, nenhuma dependencia de CDN. "Hub" ganha a cor de marca
   pra puxar o olho sem virar arco-iris (decidido com mockup, opcao C). */
.brandNome {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 21px;
  letter-spacing: -.01em;
  color: var(--ink);
}
.brandAccent { color: var(--marca-forte); }

.sidebarColapsar {
  flex: none;
  width: 22px; height: 22px;
  display: flex; align-items: center; justify-content: center;
  background: none; border: 1px solid var(--line); border-radius: var(--r1);
  color: var(--ink-3); cursor: pointer; font-size: 11px;
  font-family: var(--font-mono); font-weight: 400; letter-spacing: 0;
  text-transform: none;
}
.sidebarColapsar:hover { border-color: var(--marca); color: var(--marca); }
/* "painel de trafego pago" e legenda da marca, nao grito: sai do display e vai
   para a mono, junto com os outros rotulos - e fica um degrau abaixo do nome da
   marca, que e quem manda naquele canto. Seletor de CLASSE, nao mais ".brand
   span": desde 24-08-2026 o nome tambem e feito de spans (.brandNome/
   .brandAccent), e ".brand span" pegaria os tres sem distincao. */
.brand .brandRotulo {
  display: block;
  font-family: var(--font-mono);
  font-weight: 400;
  font-size: 11px;
  letter-spacing: .02em;
  text-transform: none;
  color: var(--ink-3);
  margin-top: var(--e1);
}

/* ------------------------------------------------- trocador de empresa
   Entre .brand e <nav>, sempre visivel (diferente da barra de filtro Meta
   Ads, que some nas abas organicas) - decidido com mockup no companheiro
   visual em 21-08-2026, opcao "trocador compacto" (estilo Notion/Linear).
   So aparece com 2+ empresas - ver empresaSwitch em app.js. */
.empresaSwitch {
  position: relative;
  padding: 0 var(--e5) var(--e5);
}
.empresaSwitchBtn {
  width: 100%;
  display: flex;
  align-items: center;
  gap: var(--e3);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r1);
  padding: var(--e3);
  cursor: pointer;
  color: var(--ink);
  font-family: var(--font-sans);
  text-align: left;
}
.empresaSwitchBtn:hover { border-color: var(--marca); }
.empresaBadge {
  flex: none;
  width: 26px; height: 26px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 800;
  /* CORRIGIDO em 23-08-2026: o branco+sombra que estava aqui nunca foi
     medido contra o tema ESCURO (o padrao/primario do painel) - branco
     sobre --pizza-1 (#3DE1F0, ciano vivo) mede 1,59:1, bem abaixo do
     minimo de 4,5:1. E o mesmo incidente que o funil ja viveu e resolveu
     sobre esta mesma paleta --pizza-* (ver comentario em .funilNome, mais
     abaixo): texto escuro fixo e a solucao que funciona, nao branco com
     contorno. --empresa-badge-texto (definido nos dois blocos de :root,
     junto dos tokens --pizza-*) e #000, o melhor fixo unico medido: passa
     nas 7 cores do escuro (pior caso 4,70:1) e chega perto nas 7 do claro
     (pior caso 4,07:1, falta pequena e aceita - ver scripts/contraste.mjs).
     Sombra removida de proposito: nao ajuda texto preto sobre estes
     fundos, so o branco precisava dela. */
  color: var(--empresa-badge-texto);
}
.empresaInfo { flex: 1; min-width: 0; }
.empresaNome {
  display: block;
  font-size: 13px;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.empresaRotulo {
  display: block;
  font-size: 10px;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: .05em;
}
.empresaChev { flex: none; color: var(--ink-3); font-size: 10px; }

.empresaLista {
  position: absolute;
  left: var(--e5);
  right: var(--e5);
  top: 100%;
  margin-top: var(--e2);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r1);
  padding: var(--e2);
  z-index: 20;
  box-shadow: var(--sombra-painel);
}
.empresaLista[hidden] { display: none; }
.empresaItem {
  width: 100%;
  display: flex;
  align-items: center;
  gap: var(--e3);
  padding: var(--e2) var(--e3);
  border-radius: var(--r1);
  background: none;
  border: none;
  cursor: pointer;
  color: var(--ink-2);
  font-family: var(--font-sans);
  font-size: 12.5px;
  text-align: left;
}
.empresaItem:hover { background: var(--veu-neutro); }
.empresaItem.is-ativo { color: var(--marca-forte); background: var(--marca-veu); }
.empresaItemDot {
  flex: none;
  width: 16px;
  height: 16px;
  border-radius: 50%;
}

/* colapsado: so o badge fica, nome/legenda/seta somem - mesma logica que
   .navTexto ja usa no resto do sidebar */
.shell.is-sidebarColapsada .empresaInfo,
.shell.is-sidebarColapsada .empresaChev { display: none; }
.shell.is-sidebarColapsada .empresaSwitchBtn { justify-content: center; padding: var(--e2); }
.shell.is-sidebarColapsada .empresaLista { left: 100%; top: 0; margin-top: 0; margin-left: var(--e2); width: 200px; }
/* Defensivo: .empresaSwitch tem padding horizontal proprio (var(--e5)) que
   nenhuma regra zerava aqui, ao contrario de .navGroup e .brand (acima),
   que ja zeram o deles no colapso. Sem efeito pratico hoje - ha um bug
   separado, pre-existente e fora de escopo, na transicao CSS do colapso
   que impede este estado de terminar visualmente - mas e barato de
   corrigir agora, antes que o outro bug seja resolvido e revele este. */
.shell.is-sidebarColapsada .empresaSwitch { padding-left: 0; padding-right: 0; }

.nav { display: flex; flex-direction: column; }

.navItem {
  background: none;
  border: none;
  border-left: 2px solid transparent;
  text-align: left;
  padding: var(--e3) var(--e5);
  color: var(--ink-3);
  font-family: inherit;
  font-size: 13.5px;
  cursor: pointer;
  transition: color var(--troca), background var(--troca), border-color var(--troca);
}
.navItem:hover { color: var(--ink-2); background: var(--veu-neutro); }
/* Selo de contagem: quantos itens pedem atencao AGORA (grupos tecnico +
   prejuizo do planoDeAcao) - padrao generico de contador de navegacao, nao a
   marca de ninguem. So aparece quando ha algo urgente; contador zerado nao
   e noticia, e ficar de fora e mais silencioso que mostrar "0". */
.navItem--comBadge { display: flex; align-items: center; justify-content: space-between; gap: var(--e2); }
.navBadge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: var(--r-pilula);
  background: var(--prejuizo);
  color: var(--bg);
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  flex: none;
}
.navBadge[hidden] { display: none; }
.navItem.active {
  color: var(--ink);
  border-left-color: var(--marca);
  background: var(--marca-veu);
  font-weight: 600;
}

.sidebarFoot {
  margin-top: auto;
  padding: var(--e4) var(--e5) 0;
  border-top: 1px solid var(--line-soft);
  font-size: 11px;
  line-height: 1.5;
  color: var(--ink-3);
}

.sidebarSair {
  width: 100%; margin-top: var(--e3); background: none; border: 1px solid var(--line);
  border-radius: var(--r1); color: var(--ink-3); font-family: var(--font-sans); font-size: 12px;
  font-weight: 600; padding: var(--e2) var(--e3); cursor: pointer; transition: border-color var(--troca), color var(--troca);
}
.sidebarSair:hover { border-color: var(--marca); color: var(--marca); }

.content { min-width: 0; display: flex; flex-direction: column; }

.topbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--e5);
  padding: var(--e5) var(--e6);
  border-bottom: 1px solid var(--line);
}
/* O titulo da pagina e interface, nao cartaz: mesma familia do resto, forte no
   peso e apertado no tracking. E como um aplicativo nomeia a tela em que voce
   esta - sem trocar de voz para fazer isso. */
.pageTitle { font-family: var(--font-sans); font-size: 20px; font-weight: 700; letter-spacing: -.02em; }
.novaBtn { padding: var(--e3) var(--e4); white-space: nowrap; }

.topbarAcoes { display: flex; align-items: center; gap: var(--e3); }

/* Alternador de tema: so o icone. Quadrado de 34px porque o alvo de clique nao
   pode encolher junto com o desenho - 17px de icone com 34px de area e o
   minimo confortavel para o mouse.
   O SVG herda `currentColor`, entao o icone segue a cor do botao em cada tema e
   no hover, sem regra separada.

   O seletor leva `button` de proposito. O botao e `class="ghostBtn temaBtn"`, e
   `.ghostBtn` mora la embaixo (linha ~1419): com a MESMA especificidade, quem
   vence e quem vem depois no arquivo, entao o `padding: var(--e2) var(--e4)`
   dele engolia o `padding: 0` daqui. Com `border-box` num quadrado de 34px isso
   deixava 0,4px de area de conteudo e o icone da lua desaparecia - o botao
   continuava clicavel e completamente invisivel. `button.temaBtn` vence por
   especificidade, e nao por posicao no arquivo. */
button.temaBtn {
  width: 34px;
  height: 34px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--r2);
  color: var(--ink-3);
}
.temaBtn:hover { color: var(--marca); border-color: var(--marca); }
.temaBtn svg { display: block; }

/* 1180px era a medida de uma pilha de blocos de largura cheia, onde mais
   largura só esticaria linha de texto. Com a Visão Geral em grade de 12
   colunas a largura virou informação: a 1180px a coluna do funil fica com
   280px e o nome da etapa quebra em três linhas. 1400px dá 325px à mesma
   coluna e uma coluna a mais de tabela nas outras abas. O teto continua
   existindo — sem ele, em monitor largo a tabela vira uma linha de 2.000px
   que ninguém acompanha da esquerda para a direita. */
main { max-width: 1400px; width: 100%; padding: var(--e6) var(--e6) var(--e7); }
.tabPanel { display: none; }
/* Sem animacao ao trocar de aba: quem usa isto troca de aba dezenas de vezes
   por dia, e um fade de 250ms vira 250ms de espera toda vez. */
.tabPanel.active { display: block; }

/* ---------- foco visivel em TUDO que recebe teclado ----------
   Regra unica, no lugar de cada componente inventar a sua. `focus-visible`
   e nao `focus`: quem clica com o mouse nao ve contorno, quem navega por
   Tab ve sempre - que e exatamente quem precisa. */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--marca);
  outline-offset: 2px;
  border-radius: 2px;
}

/* checkbox tambem responde: e o controle mais clicado da tabela */
input[type="checkbox"] {
  accent-color: var(--marca);
  cursor: pointer;
  transition: transform var(--troca);
}
input[type="checkbox"]:hover { transform: scale(1.15); }
input[type="checkbox"]:active { transform: scale(.94); transition: none; }

/* ---------- microinteracao de CLIQUE ----------

   O hover diz "da para clicar". O clique precisa dizer "recebi" - e ate aqui
   nao dizia nada: o painel tinha 20 regras de :hover e nenhuma de :active.

   Isso e um problema concreto, nao enfeite. Criar campanha leva segundos entre
   o clique e a primeira etapa acender; sem confirmacao de toque, a reacao
   natural e clicar de novo. Ali, clicar de novo e uma campanha duplicada na
   conta de producao.

   Por que isto nao viola a regra de motion:
   a regra proibe animacao no caminho de interacao repetida porque ela COBRA
   ESPERA. Aqui nao ha espera nenhuma - `transition: none` na ida faz o estado
   valer no mesmo quadro do clique. A volta usa --troca, que e o dedo saindo.
   Um deslocamento de 1px: o suficiente para o olho registrar, pouco o bastante
   para nao mexer o layout em volta. */
button:active,
.primaryBtn:active,
.ghostBtn:active,
.delBtn:active,
.navItem:active,
.fgSeletor:active,
.sugestao:active,
.chipX:active {
  transform: translateY(1px);
  transition: none;
}

/* O botao primario tambem escurece: em fundo claro de marca, 1px sozinho quase
   nao aparece. */
button[type="submit"]:active,
.primaryBtn:active { filter: brightness(.92); }

/* Linha de tabela e item de lista nao se deslocam - arrastariam o texto das
   colunas vizinhas. Respondem pelo fundo, no mesmo quadro. */
tbody tr:active td,
.fgItem:active,
.diagCard summary:active {
  background: var(--marca-veu);
  transition: none;
}

/* Quem pediu menos movimento nao perde a resposta ao clique - ela nao e
   movimento decorativo, e confirmacao. Mas o deslocamento sai. */
@media (prefers-reduced-motion: reduce) {
  button:active, .primaryBtn:active, .ghostBtn:active, .delBtn:active,
  .navItem:active, .fgSeletor:active, .sugestao:active, .chipX:active,
  input[type="checkbox"]:active {
    transform: none;
  }
}

/* ------------------------------------------------------------ KPIs */

/* CARDS, nao celulas divididas por filete.
   Ate aqui os KPIs eram uma faixa unica cortada por linhas verticais - lia como
   cabecalho de tabela. Como card, cada indicador vira um objeto proprio: e o
   que separa "planilha" de "aplicativo", e foi o pedido.

   `auto-fit` com minmax resolve as duas grades sem media query: a de 5 e a de 8
   indicadores se reorganizam pelo espaco que sobra, e nunca fica um card orfao
   esticado numa fileira sozinho. */
.kpiGrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: var(--e3);
  margin-bottom: var(--e6);
}

.kpiGrid--wide { grid-template-columns: repeat(auto-fit, minmax(178px, 1fr)); }
.kpiGrid--canal { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* MEDIDO: o .kpi comum usa clamp(22px,2.3vw,32px), calibrado pra grade de 8
   colunas de largura cheia. Este bloco e 2 colunas dentro de 1/3 da grade
   (span 4) - card de ~155px, bem mais estreito. Nesse contexto o mesmo teto
   de 32px vazava 44px pra fora do card com "R$ 6.324,06". Teto proprio,
   medido pra esta largura (~130px de area util). */
.kpiGrid--canal .kpi .value { font-size: clamp(15px, 1.5vw, 20px); }

/* -------------------------------------------------- faixa de KPI primaria
   Os 5 indicadores que decidem verba, acima da grade detalhada existente
   (que continua intacta, mais abaixo). Reaproveita .kpi inteiro - so o
   modificador --hero muda tamanho. O badge de meta usa .vBadge, o MESMO
   componente da etiqueta de veredito na tabela de campanhas: e o elemento de
   assinatura do painel, e "acima/abaixo da meta" e a mesma pergunta que
   "saudavel/prejuizo", so que contra um alvo em vez de contra R$ 0. */
.kpiGrid--hero {
  grid-template-columns: repeat(5, minmax(0, 1fr));
  margin-bottom: var(--e4);
}
/* Cards hero: layout PRÓPRIO, não o grid de 3 faixas do .kpi comum. A
   diferença estrutural é real - o badge de meta saiu de "linha 3 abaixo do
   valor" para dentro do cabeçalho, ao lado do rótulo (pedido do usuário,
   referência de layout). Com o badge fora do fluxo vertical, as 3 faixas
   empilhadas do .kpi genérico não fazem mais sentido aqui.
   Alinhado à ESQUERDA, não centralizado: mais denso, lê como painel de
   trabalho, não como cartão de destaque isolado. */
.kpi--hero {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 6px;
  min-height: 96px;
  padding: var(--e3) var(--e4);
  text-align: left;
  border-color: var(--accent-fraco);
}
.kpi--hero:hover { border-color: var(--accent); }
.kpiHeroTop {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e2);
}
/* label herda .kpi .label (mono, caixa alta) mas sem a reserva de 2 linhas
   nem a centralizacao - aqui ela divide a faixa com o pill, nunca quebra. */
.kpi--hero .label { min-height: 0; padding-bottom: 0; justify-content: flex-start; white-space: nowrap; }
.kpi--hero .value {
  /* MEDIDO, nao chutado (ver CLAUDE.md: e o mesmo cuidado que a grade de 8
     colunas ja tinha). Teto de 40px vazava por 5px em 1200px de largura, com
     "R$ 1.966,05" - a mesma regra de "o teto tem de caber no PIOR caso" que já
     rege .kpi .value comum. Piso e vw recalculados para o pior caso desta
     grade (5 colunas, valor de 11-12 caracteres): clamp(18px, 2.2vw, 28px)
     cabe com folga onde 40px vazava. Ainda maior que a grade pequena (32px de
     teto) até 1400px de largura, mas sem repetir o vazamento.
     accent so aqui: e o unico lugar da faixa hero onde a cor nao e veredito -
     ROAS e Investimento nao tem lado bom/ruim fixo por cor, entao herdam
     --ink como os demais .kpi; so o CONTORNO do card e o accent. */
  font-size: clamp(18px, 2.2vw, 28px);
}

/* Pilula compacta de meta - NAO reaproveita .vBadge (a etiqueta de composicao
   tem min-width de 128px e canto chanfrado, pensada pra celula de tabela;
   aqui o espaco é uma faixa de cabeçalho ao lado de um rótulo curto, um
   contexto diferente o bastante pra pedir componente proprio, nao uma
   variante espremida do chanfro). Mesmas cores de veredito (--lucro/--prejuizo
   via os tokens -claro e veu-, já validados em contraste.mjs), forma nova. */
.metaPill {
  display: inline-flex;
  align-items: center;
  padding: 2px var(--e2);
  border-radius: var(--r-pilula);
  border: 1px solid transparent;
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  white-space: nowrap;
  flex: none;
}
.metaPill.good { color: var(--lucro-claro); background: var(--veu-lucro); border-color: color-mix(in srgb, var(--lucro) 35%, transparent); }
.metaPill.bad  { color: var(--prejuizo-claro); background: var(--veu-prejuizo); border-color: color-mix(in srgb, var(--prejuizo) 35%, transparent); }
/* Quebra PROPRIA da faixa hero, mais cedo que os 1180px do resto da grade:
   5 colunas de numero grande ficam apertadas antes das 8 colunas da grade
   pequena apertarem - medido, o vazamento comecava logo abaixo de 1360px. */
@media (max-width: 1360px) { .kpiGrid--hero { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 780px)  { .kpiGrid--hero { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* O card: fundo proprio, borda de 1px e raio da escala. Sem sombra junto da
   borda - os dois na mesma caixa e o "ghost card", que faz tudo flutuar sem
   motivo. A separacao aqui vem do fundo, nao de um filete. */
.kpi {
  display: grid;
  /* Tres faixas independentes: rotulo, valor, e o que vier depois (seta de
     variacao, sparkline, nota). Grid em vez de flex+justify-content:flex-end
     de proposito - o valor (faixa 2) so depende da altura da faixa 1 (rotulo),
     nunca do que sobra na faixa 3. Com flex+flex-end, um card com seta+
     sparkline empurrava o valor pra cima enquanto o vizinho sem esses dois
     deixava o valor cair ate o fundo - a mesma fileira parava de alinhar
     (achado real, 05/08/2026: Gasto Total e Receita Gerada lado a lado, com
     e sem sparkline, o numero de um ficava visivelmente mais alto que o outro). */
  grid-template-rows: auto auto 1fr;
  min-height: 116px;
  padding: var(--e4) var(--e4) var(--e4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r3);
  transition: border-color var(--troca), background var(--troca);
  /* Conteudo centralizado no card - pedido do usuario em 31-07-2026. E
     `text-align`, e nao `align-items: center`, de proposito: com `align-items` o
     SVG da sparkline deixaria de ser um item esticado e encolheria para a
     largura do conteudo. `text-align` move so o texto, e a sparkline segue com
     os seus `width: 100%`. */
  text-align: center;
}
/* o card inteiro responde ao cursor: e o alvo, mesmo sem ser clicavel */
.kpi:hover { border-color: var(--marca-fraco); background: var(--surface-2); }

/* --- os tres degraus da hierarquia ---
   1. ROTULO: miudo, caixa alta, cinza. Diz o que e, nao chama atencao.
   2. VALOR: condensado, grande, claro. E o que a pessoa veio ler.
   3. LEGENDA: miuda, cinza. Contexto de quem quer conferir a conta.
   Tamanho, peso E cor mudam entre os tres - so tamanho nao separa o bastante. */

/* O rotulo ocupa a faixa 1 do grid do .kpi (acima). min-height reserva sempre
   o espaco de DUAS linhas (10px/1.3 = 13px cada + os 12px de padding-bottom),
   mesmo quando o rotulo deste card cabe numa linha so - e o que garante que a
   faixa 2 (o valor) comece na mesma altura em toda a fileira, mesmo com
   "Negócios fechados no período" (2 linhas) ao lado de "ROAS geral" (1 linha). */
.kpi .label {
  display: flex;
  align-items: flex-start;
  /* O rotulo e um flex container, entao o `text-align: center` do card nao o
     alcanca - quem centraliza o texto de um item flex e o `justify-content`. */
  justify-content: center;
  min-height: 38px;
  padding-bottom: var(--e3);
  /* acompanha o token de rotulo em mono (10px/.08em): manter 10,5/.14 aqui
     criaria uma variante de rotulo sozinha, exatamente o que a regra evita */
  font-size: 10px;
  line-height: 1.3;
  letter-spacing: .08em;
  color: var(--ink-3);
}

.kpi .value {
  font-family: var(--font-display);
  /* Escala fluida: valores longos (R$ 7.516,87) nao quebram linha em coluna
     estreita. `white-space: nowrap` faz o numero VAZAR em vez de quebrar, entao
     o teto tem de caber no pior caso, nao no caso comum. */
  font-size: clamp(22px, 2.3vw, 32px);
  line-height: 1;
  /* 800: a presenca vem do PESO, nao de uma fonte de cartaz. Numero de painel e
     dado - fonte de display em dado decora onde precisa ser lido. */
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  /* negativo de leve junta os digitos num bloco so, que e como o olho le um
     valor. Piso de -.04em existe para as letras nunca se tocarem. */
  letter-spacing: -.02em;
  white-space: nowrap;
  color: var(--ink);
}
/* O primeiro card deixou de ser maior que os outros. Na grade de celulas ele
   abria a faixa e o destaque fazia sentido; em cards de tamanho igual, um
   numero maior so desalinha a fileira. O destaque de "lucro real" continua
   existindo - pela COR (.pos/.neg), que e o que importa ali. */
.kpi .value.pos { color: var(--lucro); }
.kpi .value.neg { color: var(--prejuizo); }

/* A SETA DE VARIAÇÃO vs. o período anterior.
   NÃO É PINTADA, e a divergência da referência é deliberada. Lá a cor vem da
   DIREÇÃO (verde para cima, laranja para baixo), o que faz "CPC subiu 31%"
   chegar em verde — um custo que aumentou anunciado como notícia boa. Pintar
   por "isso é bom ou ruim" exigiria a faixa semântica, reservada aqui ao
   veredito de lucro: teríamos duas escalas de cor dizendo coisas diferentes na
   mesma tela, que é exatamente o incidente do ROAS.
   A direção fica no glifo — que também é o que resolve para quem não distingue
   verde de vermelho. */
.kpiVar {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  margin-top: var(--e1);
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
  white-space: nowrap;
  cursor: help;   /* o title diz contra qual janela está comparando */
}
.kpiVar i { font-style: normal; font-size: 11px; }

/* Nota sob o valor: diz sobre QUAL base o número foi calculado, para ninguém
   tentar refazer a conta com o total errado. */
.kpiNota {
  display: block;
  margin-top: var(--e2);
  font-size: 10.5px;
  line-height: 1.4;
  color: var(--ink-3);
}

/* ------------------------------------------------ saude das campanhas
   Resumo visual no topo, contagem por grupo do MESMO planoDeAcao() que a aba
   Recomendacoes usa - a regra de negocio mora so em diagnostico.js, aqui e so
   desenho. Pilula, nao .vBadge: o .vBadge (etiqueta de composicao, canto
   chanfrado) e a assinatura de veredito POR CAMPANHA numa tabela; isto e um
   resumo agregado, um nivel acima - reaproveitar a MESMA forma aqui diluiria
   o que faz o chanfro significar "esta e a etiqueta de uma campanha". */
.saudeFaixa {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e3);
  margin-bottom: var(--e4);
}
.saudeChip {
  display: inline-flex;
  align-items: center;
  gap: var(--e2);
  padding: var(--e2) var(--e4);
  border-radius: var(--r-pilula);
  border: 1px solid transparent;
  font-size: 12.5px;
  font-family: inherit;
  cursor: pointer;
  transition: filter .12s ease, transform .12s ease;
}
/* Vira <button> em 19-08-2026 para abrir a campanha ao clicar - antes era
   <span>, so leitura. cursor:pointer + leve destaque no hover/foco avisam
   que agora e clicavel, sem mudar a aparencia em repouso. */
.saudeChip:hover { filter: brightness(1.15); }
.saudeChip:active { transform: scale(.97); }
.saudeChip:focus-visible { outline: 2px solid var(--marca); outline-offset: 2px; }
.saudeChip b {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  font-size: 13px;
}
.saudeChip.good { color: var(--lucro-claro); background: var(--veu-lucro); border-color: color-mix(in srgb, var(--lucro) 35%, transparent); }
.saudeChip.mid  { color: var(--limite); background: var(--veu-limite); border-color: color-mix(in srgb, var(--limite) 35%, transparent); }
.saudeChip.bad  { color: var(--prejuizo-claro); background: var(--veu-prejuizo); border-color: color-mix(in srgb, var(--prejuizo) 35%, transparent); }
.saudeChip.neutro { color: var(--ink-3); background: var(--surface-2); border-color: var(--line); }

/* ------------------------------------------------------------ blocos */

/* --e7 entre blocos contra --e3 entre titulo e conteudo: e a proporcao que
   agrupa. Antes os dois eram parecidos (--e6 e --e4) e a pagina lia como uma
   lista de coisas do mesmo peso, nao como blocos com hierarquia interna. */
/* Superficie unificada com .vgBloco em 19-08-2026 - pedido do usuario:
   "use fonte e layout da visao geral para TODO o painel". Antes .card so
   tinha margem, sem fundo/borda/raio/padding proprios - por isso toda aba
   fora da Visao Geral (Campanhas, Recomendacoes, Publicar, etc.) lia "chapada",
   sem moldura, com o titulo colado na borda da pagina. Mesmos valores que
   .vgBloco ja usa, pro painel inteiro ter UMA superficie de card, nao duas. */
.card {
  position: relative;
  margin-bottom: var(--e7);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r3);
  padding: var(--e4);
}
/* Mesmo filete azul->cobre do topo de .loginCard (public/login.css) - a
   assinatura visual do login chega no resto do painel. Raio proprio nos
   dois cantos de cima em vez de `overflow:hidden` no .card: esta classe e
   usada em dezenas de lugares, alguns com dropdown/tooltip que precisa
   vazar a moldura - `overflow:hidden` no pai cortaria isso. */
.card::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0; height: 2px;
  border-radius: var(--r3) var(--r3) 0 0;
  background: linear-gradient(90deg, var(--marca), var(--marca-cobre));
}
/* .panelBox por si so tambem e uma superficie (fundo+borda) - dentro de um
   .card ela dobraria a moldura (card dentro de card). So os 5 lugares que
   usam grafico dentro de card precisam disto; .panelBox fora de .card (nao
   existe hoje, mas se existir) continua com a moldura propria dele. */
.card > .panelBox { background: none; border: none; padding: 0; }
/* O bloco do Instagram na Visao Geral nasce com `hidden` e so aparece quando a
   credencial existe. A regra e explicita porque e a armadilha documentada: no
   dia em que `.card` ganhar um `display`, ele venceria o `[hidden]` da folha do
   navegador e o bloco apareceria vazio em quem nao usa Instagram. */
.card[hidden] { display: none; }

/* A regua sob o titulo e NEUTRA, e essa foi a mudanca mais visivel da passada
   de 30-07-2026. Ela era `--gold`, e o dourado aparecia 5 ou 6 vezes por tela em
   reguas de titulo: onde tudo e marcado, nada esta marcado. A regra do dourado
   ("como marca so aparece em filete/borda") permitia pela letra, mas a diluicao
   gastava o recurso que precisa estar livre para carregar estado de verdade
   quando o Motor de Decisao chegar.
   `margin-bottom` caiu de --e4 para --e3 de proposito: o titulo pertence ao
   conteudo dele, e antes tinha a MESMA distancia que separa um card do outro -
   com espacamento uniforme nada agrupa, e a tela le como lista em vez de
   hierarquia. Menos espaco dentro do grupo, mais entre grupos (ver .card). */
.cardTitle {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--e4);
  padding-bottom: var(--e3);
  margin-bottom: var(--e3);
  border-bottom: 1px solid var(--line);
}
.cardTitle .note {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
  font-size: 11.5px;
  color: var(--ink-3);
}

/* A superficie que da cara de aplicativo: r3 no painel principal, e a borda
   fazendo o trabalho sozinha. Sem sombra larga junto da borda - os dois na
   mesma caixa e o "ghost card", que faz o painel parecer flutuar sem motivo. */
.panelBox {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r3);
  padding: var(--e5) var(--e5);
}

.chartWrap { position: relative; height: 300px; }
.chartWrap--pizza { height: 260px; }

/* ===================== A VISÃO GERAL CABE EM UMA TELA =====================
   Ela era uma PILHA: nove blocos de largura cheia, cada um separado do
   seguinte por 48px iguais. Medido, dava 3.556px de altura em 1440×900 —
   quase quatro telas para a decisão que ele toma de manhã, e o espaçamento
   uniforme não agrupava nada (tudo equidistante = nada relacionado).

   Agora é uma GRADE 2D de 12 colunas em três faixas, no formato da
   referência da Meta. A leitura passou a ter uma ordem espacial, e não só
   vertical:
     1. INDICADORES — o placar, largura cheia.
     2. O PERÍODO, lido de três formas complementares e lado a lado: quando
        gastou (série), o que a verba comprou (entrega) e onde perdeu (funil).
        Lado a lado é o ponto: as três respondem à mesma pergunta e antes
        estavam a 1.200px de distância uma da outra.
     3. O DETALHE ACIONÁVEL — a tabela leva 8 das 12 colunas porque é ela que
        responde "o que eu pauso hoje"; o resto acompanha.

   Grid e não flex porque isto é 2D de verdade: linhas E colunas precisam de
   controle coordenado. */
.visaoGrade {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  /* Ritmo: --e3 (12px) DENTRO da grade contra --e7 (48px) que separava os
     blocos antes. Junto o que se compara, e o respiro fica entre a grade e o
     resto da página, não entre dois gráficos que se leem juntos. */
  gap: var(--e3);
  /* `stretch`, e não `start`: os blocos de uma mesma faixa terminam na mesma
     linha, e a faixa se lê como uma faixa. Com `start` cada bloco parava na
     altura do próprio conteúdo e a fileira ficava serrilhada — três molduras
     de alturas diferentes, que é o "enquadramento" que ele apontou. O custo é
     sobrar espaço dentro do bloco mais curto, e sobra alinhada é melhor que
     borda desalinhada. */
  align-items: stretch;
}
/* O canvas some quando não há o que desenhar. Regra explícita porque é a
   armadilha documentada: no dia em que `.chartWrap` ganhar um `display`, ele
   venceria o `[hidden]` da folha do navegador. */
.chartWrap[hidden] { display: none; }
/* `minmax(0, 1fr)` na coluna resolve o track; isto resolve o ITEM. Sem os
   dois, um canvas já desenhado impede a célula de encolher e empurra a página
   inteira - a armadilha documentada da .cardsRow. */
.visaoGrade > * { min-width: 0; }

/* O bloco É a superfície. Antes eram DOIS elementos - `.card` (só margem) por
   fora e `.panelBox` (fundo e borda) por dentro - e nem todo bloco tinha os
   dois, então metade da tela tinha moldura e a outra metade não. Um elemento
   só, mesma moldura em todos. */
.vgBloco {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r3);
  padding: var(--e4);
  min-width: 0;
  /* Coluna flex para o CONTEÚDO acompanhar a altura do bloco. Com altura fixa
     de gráfico dentro de um bloco esticado, sobrava um vão de 110px embaixo do
     desenho — a moldura alinhava com a vizinha e o conteúdo não. O título é
     fixo; o corpo cresce. */
  display: flex;
  flex-direction: column;
}
.vgBloco > .cardTitle { flex: none; }
.vgBloco > :last-child { flex: 1 1 auto; min-height: 0; }
/* Os indicadores não levam moldura: eles JÁ são cards. Moldura em volta de
   card é card dentro de card, que nunca está certo. */
.vgKpis,
.vgKpisPrimarios {
  background: none;
  border: none;
  padding: 0;
}
.vgKpis .kpiGrid,
.vgKpisPrimarios .kpiGrid { margin-bottom: 0; }

/* As três faixas, e a razão de cada largura:
   PLACAR    kpis 12    — os oito numa linha só, como na referência. Em duas
                          linhas eles custavam 274px e a fileira de baixo já
                          não se comparava com a de cima.
   O PERÍODO serie 6 · tiles 6 — as duas leituras do mesmo período, lado a lado.
   O DETALHE campanhas 8 · funil 4 — a tabela responde "o que eu pauso"; o funil
                          precisa das 4 colunas porque com 3 o nome da etapa
                          quebrava em três linhas e a faixa ia a 580px.
   CONTEXTO  contas 4 · semana 4 · instagram 4 — o que se consulta, não o que
                          se decide. */
.vgKpisPrimarios { grid-column: span 12; }
.vgRoas      { grid-column: span 12; }
.vgKpis      { grid-column: span 12; }
.vgSerie     { grid-column: span 6; }
.vgTiles     { grid-column: span 6; }
/* REVERTIDO em 19-08-2026, mesmo dia: span 12 (linha própria) deixou o funil
   "grande e desproporcional" contra os cards vizinhos, no feedback direto do
   usuário depois de ver o resultado ao vivo. Voltou pra 8/4 (mesma régua
   original, "com 3 colunas o nome da etapa quebrava em três linhas" - 4 é o
   mínimo funcional). O jeito de caber o conteúdo do redesenho (3 cards +
   números grandes) numa coluna estreita não é mais espaço - é ESCALA menor
   (ver .funilResumoCard/.funilValor/.funilTaxaFinal, ajustados junto). */
.vgCampanhas { grid-column: span 8; }
.vgFunil     { grid-column: span 4; }
.vgCanal     { grid-column: span 4; }
.vgContas    { grid-column: span 4; }
.vgSemana    { grid-column: span 4; }
.vgDistrib   { grid-column: span 4; }
.vgInstagram { grid-column: span 4; }
.vgBloco[hidden] { display: none; }

/* Oito numa linha. O `auto-fit`/`minmax(178px)` da pilha caía para sete e
   jogava um card sozinho para a linha de baixo — e card sozinho numa fileira
   não se compara com nada, que é a única coisa que uma fileira de KPI faz. */
.vgKpis .kpiGrid { grid-template-columns: repeat(8, minmax(0, 1fr)); }

/* E O NÚMERO PRECISA ENCOLHER JUNTO. O card caiu de ~190px para ~167px, e a
   escala da pilha (teto de 32px) com `white-space: nowrap` faz o número VAZAR
   em vez de quebrar — "R$ 2.363,18" saía por cima da borda do card vizinho.
   O teto tem de caber no PIOR caso, não no caso comum: o pior caso aqui é
   receita na casa dos milhares com centavos. */
/* Teto reduzido de 21 para 19px em 10-08-2026: MEDIDO a 1280px de largura -
   "R$ 4.513,67" vazava 3px pra fora do card com o teto antigo. Achado ao
   remover 2 cards desta grade (Lucro Real e Receita, que foram pra faixa
   hero) - a contagem de colunas e fixa em 8 (linha acima), entao a largura
   por card nao mudou; o vazamento so nao tinha sido medido nesta largura
   exata antes. */
.vgKpis .kpi .value { font-size: clamp(14px, 1.2vw, 19px); }
.vgKpis .kpi .label { font-size: 9.5px; }
.vgKpis .kpiNota { font-size: 9.5px; line-height: 1.3; }

/* Densidade da grade: as alturas de gráfico da pilha (300px e 260px) foram
   escolhidas para largura cheia. Numa célula de 1/3 da largura elas viram
   caixas vazias. */
/* O gráfico OCUPA o bloco em vez de ter altura própria. A linha do grid já é
   dimensionada pelo bloco mais alto da faixa, então altura fixa aqui só deixava
   espaço morto embaixo do desenho. `min-height` existe porque Chart.js precisa
   de um contêiner com altura definida, e um piso evita o gráfico de 40px numa
   faixa curta. */
.visaoGrade .chartWrap { flex: 1 1 auto; height: auto; min-height: 168px; }
.graficoAcoes { display: flex; align-items: center; gap: var(--e3); }
/* Controle segmentado, para trocar a metrica do grafico de evolucao.
   O selecionado NAO enche de --accent solido: essa combinacao (fundo accent +
   texto var(--surface)) reprova contraste no tema escuro (4,21:1, falta pouco
   pra 4,5 - medido em contraste.mjs ao testar o botao Sincronizar). Em vez
   disso o segmento ativo "levanta" com --surface (mais claro que o fundo do
   grupo) e o texto vai em --accent-forte, o MESMO par ja validado em
   accent-forte/surface (7,99:1 escuro, 8,99:1 claro). */
.tabGroup { display: inline-flex; gap: 2px; background: var(--surface-2); padding: 2px; border-radius: var(--r2); }
.tabBtn {
  background: none;
  border: none;
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .03em;
  text-transform: uppercase;
  padding: 3px var(--e3);
  border-radius: var(--r1);
  cursor: pointer;
  transition: background var(--troca), color var(--troca);
}
.tabBtn:hover { color: var(--ink-2); }
.tabBtn.active { background: var(--surface); color: var(--accent-forte); }

/* mais alto que o padrao da grade: e o grafico de destaque da tela. Mesma
   especificidade da regra acima (.visaoGrade + 1 classe) - vem DEPOIS no
   arquivo de proposito, pra vencer no empate. Um seletor .chartWrap--roas
   sozinho perdia sempre, porque .visaoGrade .chartWrap tem uma classe a mais. */
.visaoGrade .chartWrap--roas { min-height: 220px; }

/* O CANVAS SAI DO FLUXO, e isso é obrigatório aqui. Num contêiner flex sem
   altura definida existe um laço: o Chart.js dimensiona o canvas pelo
   contêiner, o canvas entra na altura do contêiner, o contêiner cresce, e o
   Chart.js redimensiona de novo — medido, a faixa de contexto engordou de 298
   para 370px sozinha. Com o canvas absoluto ele deixa de contribuir para a
   altura: o contêiner recebe a altura do flex, e o desenho preenche. */
.visaoGrade .chartWrap > canvas { position: absolute; inset: 0; }

/* O estado vazio centraliza no espaço que sobra, em vez de ficar grudado no
   topo com 200px de nada embaixo. */
#diarioVazio {
  display: grid;
  place-items: center;
  text-align: center;
  padding: var(--e5) var(--e4);
}
#diarioVazio[hidden] { display: none; }
.visaoGrade .cardTitle { padding-bottom: var(--e2); margin-bottom: var(--e3); }
/* O KPI encolhe: 116px de altura mínima existiam numa página que já era longa
   demais. O rótulo continua ancorado em cima e o número na base. */
.visaoGrade .kpi { min-height: 92px; padding: var(--e3); }
.visaoGrade .metrica { padding: var(--e2); }
.visaoGrade .metricaValor { font-size: 18px; }
/* 3×3 fixo, como na referência. `auto-fit` com piso de 150px caía para duas
   colunas nesta célula, e nove métricas em cinco linhas faziam o bloco ter o
   dobro da altura do vizinho. */
.visaoGrade .metricasGrade { grid-template-columns: repeat(3, minmax(0, 1fr)); }

/* A metodologia recolhida. `summary` é o controle: cursor, foco e alvo de
   clique decentes, sem inventar um botão para algo que o HTML já resolve. */
.funilResumo p { margin: 0 0 var(--e2); }
.funilMetodo summary {
  cursor: pointer;
  color: var(--ink-3);
  font-size: 11.5px;
  padding: var(--e1) 0;
}
.funilMetodo summary:hover { color: var(--marca); }
.funilMetodo p { margin-top: var(--e2); }
/* A tabela rola DENTRO do bloco, na vertical também: 10 linhas soltas numa
   faixa de grade voltariam a esticar a página, que é o problema que isto
   resolve. O teto é 430px porque é o que o funil, ao lado, já custa à linha —
   abaixo disso sobraria espaço vazio embaixo da tabela, e acima disso a página
   cresceria. */
.visaoGrade #overviewCampanhas .tableWrap { max-height: 430px; overflow: auto; }

/* O NOME TRUNCA PARA O VEREDITO CABER. Com o nome livre, as nove colunas
   somavam mais que a célula e a tabela rolava na horizontal — escondendo
   justamente a etiqueta de lucro, que é a coluna pela qual esta tabela existe.
   Nome de campanha é reconhecível pelo começo (`[Tráfego][site]06/02/26`), e o
   nome inteiro continua no `title`. Vale só aqui: na aba Campanhas, onde há
   largura, o nome segue inteiro em duas linhas. */
.visaoGrade #overviewCampanhas td.name > span {
  display: block;
  max-width: 150px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Tipografia de RESUMO, um degrau abaixo da aba Campanhas: aqui são nove
   colunas em 887px. A aba completa continua no tamanho normal, porque lá a
   tabela é o conteúdo principal e tem a largura inteira. */
.visaoGrade #overviewCampanhas td,
.visaoGrade #overviewCampanhas th {
  padding: var(--e1) var(--e2);
  font-size: 11.5px;
}
.visaoGrade #overviewCampanhas thead th {
  position: sticky;
  top: 0;
  z-index: 1;   /* acima das linhas que rolam por baixo, e só isso */
  background: var(--surface);
}

/* Uma quebra só, e ela é ESTRUTURAL (a grade recompõe), não fluida: produto se
   comporta por breakpoint, não por tipografia que escorre. */
@media (max-width: 1180px) {
  .vgSerie     { grid-column: span 12; }
  .vgTiles     { grid-column: span 7; }
  .vgFunil     { grid-column: span 5; }
  .vgCampanhas { grid-column: span 12; }
  .vgSemana,
  .vgContas,
  .vgDistrib,
  .vgCanal,
  .vgInstagram { grid-column: span 6; }
  /* A fileira de oito tem de relaxar junto: medido a 1025px, oito colunas
     davam 110px por card e o número voltava a vazar por cima da borda. Quatro
     e quatro continuam comparáveis entre si — o que não pode é um card
     sozinho numa linha. */
  .vgKpis .kpiGrid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
@media (max-width: 780px) {
  .visaoGrade > * { grid-column: span 12; }
  .vgKpis .kpiGrid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .visaoGrade .metricasGrade { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* dois graficos lado a lado na Visao Geral.
   `minmax(0, ...)` e obrigatorio: o padrao de um track de grid e `min-width:
   auto`, entao o canvas ja desenhado impedia a coluna de encolher. Ao diminuir
   a janela o grafico continuava no tamanho antigo e empurrava a PAGINA INTEIRA
   para o lado - 112px de rolagem horizontal em 1280px. Mesmo motivo do
   `min-width: 0` em .content. */
/* UM lugar possui o espacamento desta fileira: o `gap` do grid entre as colunas,
   e o margin-bottom da propria fileira para o bloco seguinte.
   Antes os cards filhos tinham `margin-bottom: --e6` POR CIMA do `gap: --e6`, e
   em tela estreita - onde a fileira quebra em uma coluna - os dois somavam 64px
   entre os dois graficos, o dobro do resto da pagina. */
.cardsRow {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: var(--e6);
  margin-bottom: var(--e7);
}
.cardsRow .card { margin-bottom: 0; }

/* ------------------------------------------------------------------ funil */
/* REDESENHO 19-08-2026 (pedido do usuário: "SaaS moderno, premium, fácil de
   entender em poucos segundos"). O que NÃO mudou, de propósito: a forma de
   trapézio (pedida em 31-07-2026), o preenchimento neutro (--serie-neutra, a
   faixa mede volume, não tem veredito - "incidente do ROAS" de novo se fosse
   colorida), a escala logarítmica com piso de 45%, a animação scaleX de
   revelação, e a regra de contraste que fixa o texto sobre a faixa em --ink
   (medida em scripts/contraste.mjs - --ink-2/--ink-3 reprovam ali). O que
   mudou é hierarquia: números muito maiores, 3 cards de resumo no topo, selo
   de queda com DOIS indicadores nunca misturados, e dois blocos novos
   (gargalo, taxa final) que já existiam como texto corrido e viraram cards. */

/* ESCALA REDUZIDA em 19-08-2026, mesmo dia: o funil voltou a dividir linha
   com Campanhas (span 4/12, ver .vgFunil acima) depois do usuário achar a
   versão de largura cheia "grande e desproporcional" - então a escala interna
   (números, cards, respiro) encolheu pra caber numa coluna estreita sem
   perder a estrutura do redesenho (3 cards, cores por etapa, indicadores
   separados). Não é o mesmo número em espaço menor - é hierarquia recalibrada
   pro tamanho real do card, igual o resto do painel já faz. */
.funil {
  display: flex;
  flex-direction: column;
  gap: var(--e2);
}

/* Os 3 cards de resumo empilham, não ficam lado a lado - 3 colunas numa
   coluna de ~380px deixava "Cliques no link → View Content" espremido a
   126px de largura. Empilhado, cada um usa a largura toda do card. */
.funilResumoCards {
  display: flex;
  flex-direction: column;
  gap: var(--e2);
  margin-bottom: var(--e4);
}
.funilResumoCard {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--e2);
  padding: var(--e2) var(--e3);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r1);
}
.funilResumoRotulo {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.funilResumoValor {
  font-family: var(--font-mono);
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -.01em;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  text-align: right;
}
/* "Maior gargalo" é nome de etapa, não número - Geist Sans, não mono, menor
   ainda pra caber "Cliques no link → View Content" numa linha de card estreito. */
.funilResumoValor--texto {
  font-family: var(--font-sans);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0;
  text-align: right;
  line-height: 1.3;
}
/* Cor de veredito SÓ aqui, no card "Maior gargalo" - é o único dos 3 que
   carrega um julgamento (os outros dois são fato). Mesma paleta severidade
   leve/média/grave que o selo de queda já usava. */
.funilResumoCard.is-media { border-color: var(--limite); }
.funilResumoCard.is-media .funilResumoValor--texto { color: var(--limite); }
.funilResumoCard.is-grave { border-color: var(--prejuizo); }
.funilResumoCard.is-grave .funilResumoValor--texto { color: var(--prejuizo); }

.funilEtapa { position: relative; }

/* REVISÃO 19-08-2026, mesmo dia: preenchimento neutro trocado por cor
   categórica (--pizza-1.."5), a pedido do usuário depois de ver o resultado
   ("muito feio e estranho") e mandar uma referência bem mais colorida.
   Isto NÃO reabre o "incidente do ROAS": aquela regra proíbe cor de VEREDITO
   fora do papel 1 (lucro/limite/prejuízo teria significado "impressões estão
   ruins"). --pizza-* é o papel 3 do sistema, CATEGÓRICO por definição ("nem
   marca nem status") - a mesma família já usada nas roscas de distribuição.
   Cada etapa vira uma cor de identidade, não um julgamento; o julgamento
   (leve/média/grave) continua vivendo só no selo de queda, como antes. */
.funilForma {
  position: absolute;
  inset: 0;
  clip-path: polygon(
    calc(50% - var(--topo) / 2) 0,
    calc(50% + var(--topo) / 2) 0,
    calc(50% + var(--base) / 2) 100%,
    calc(50% - var(--base) / 2) 100%
  );
}
.funilEtapa:nth-child(1) .funilForma { background: var(--pizza-1); }
.funilEtapa:nth-child(2) .funilForma { background: var(--pizza-2); }
.funilEtapa:nth-child(3) .funilForma { background: var(--pizza-3); }
.funilEtapa:nth-child(4) .funilForma { background: var(--pizza-4); }
.funilEtapa:nth-child(5) .funilForma { background: var(--pizza-5); }

/* Nome, valor e conversão no centro da faixa - mais espaço vertical que
   antes (números grandes precisam de respiro, não só de tamanho). */
.funilConteudo {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  min-height: 64px;
  padding: var(--e2) var(--e3);
}
/* Texto ESCURO fixo, não --ink, não branco: com 5 cores de fundo diferentes
   (--pizza-1.."5), não existe um único par ink/fundo pra testar contra
   scripts/contraste.mjs como antes (fundo único --serie-neutra). Testei
   branco primeiro (mesmo raciocínio da referência do usuário) e MEDI contraste
   real contra as 5: reprovou feio no pizza-1/ciano (1,59:1) e no pizza-5/ouro
   (1,96:1) - cores claras de mais pra texto branco por cima, mesmo com sombra.
   Escuro fixo (#10131c) passa em TODAS as 5, com folga (4,66:1 a 11,68:1) -
   e bate com a própria referência, que também usa texto escuro sobre as
   faixas mais claras. Hierarquia continua vindo de tamanho e peso. */
.funilNome {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: #10131c;
  /* SEM opacity aqui, de propósito: opacity mistura com o fundo e derrubaria
     o contraste medido acima (era assim que o --ink-3/--ink-2 antigos
     reprovavam sobre --serie-neutra) - texto pequeno (10,5px) precisa do
     contraste cheio, não de um recuo visual que a opacidade daria. */
}
/* O número principal continua o maior texto da etapa (peso 800, hierarquia
   por tamanho E peso) - só recalibrado pra caber numa coluna de ~380px em
   vez dos 42px que cabiam em largura cheia. 24px ainda é maior que o rótulo
   (9,5px) e a conversão (11px) por uma margem clara, sem estourar o card. */
.funilValor {
  font-family: var(--font-mono);
  font-weight: 800;
  font-size: 24px;
  line-height: 1.05;
  letter-spacing: -.01em;
  font-variant-numeric: tabular-nums;
  color: #10131c;
  white-space: nowrap;
}
/* Aqui SIM cabe opacity: é a menor prioridade das três linhas (nome > valor >
   conversão), e mesmo a 78% de opacidade contra a cor mais clara (pizza-1,
   ciano) o par ainda passa de 3:1 - suficiente pra texto de apoio pequeno,
   que não é o critério de 4,5:1 do texto principal. */
.funilConversao {
  font-size: 10.5px;
  font-variant-numeric: tabular-nums;
  color: #10131c;
  opacity: .78;
  white-space: nowrap;
}

@keyframes funilEncher {
  from { transform: scaleX(0); }
}
.funilForma {
  transform-origin: center;
  animation: funilEncher 420ms cubic-bezier(.22, 1, .36, 1) both;
}
.funilEtapa:nth-child(2) .funilForma { animation-delay: 60ms; }
.funilEtapa:nth-child(3) .funilForma { animation-delay: 120ms; }
.funilEtapa:nth-child(4) .funilForma { animation-delay: 180ms; }
.funilEtapa:nth-child(5) .funilForma { animation-delay: 240ms; }

@media (prefers-reduced-motion: reduce) {
  .funilForma { animation: none; }
}

/* O selo de queda pousa na costura entre trapézios, igual antes - só o
   CONTEÚDO interno mudou, de "fato e veredito na mesma linha" pra duas
   linhas próprias, cada uma sua própria cor/peso. Pedido explícito do brief:
   nunca escrever "↓ -98,7% dentro do esperado" no mesmo texto. */
.funilQueda {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  padding: var(--e1) var(--e3);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r1);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* Linha 1: o FATO (queda real). Peso forte, cor neutra - é dado, não juízo. */
.funilQuedaFato { font-size: 12px; font-weight: 700; color: var(--ink); }
.funilQuedaFato .seta { color: var(--ink-3); font-weight: 400; }
/* Linha 2: o VEREDITO (contra o esperado da etapa). Menor, e É onde mora a
   cor semântica - leve/média/grave, mesma paleta que sempre existiu aqui. */
.funilQuedaVeredito { font-size: 10px; letter-spacing: .02em; }
.funilQueda.leve  .funilQuedaVeredito { color: var(--lucro); }
.funilQueda.media .funilQuedaVeredito { color: var(--limite); }
.funilQueda.grave .funilQuedaVeredito { color: var(--prejuizo); }

/* Card "Principal gargalo" - era um parágrafo de texto corrido, virou card
   com checklist. A cor da borda segue a MESMA severidade do selo daquela
   etapa (leve/média/grave) - não é uma paleta nova. */
.funilGargaloCard {
  margin-top: var(--e4);
  padding: var(--e3);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-left: 3px solid var(--line);
  border-radius: var(--r2);
}
.funilGargaloCard.is-media { border-left-color: var(--limite); }
.funilGargaloCard.is-grave { border-left-color: var(--prejuizo); }
.funilGargaloCard.is-leve  { border-left-color: var(--lucro); }
.funilGargaloTitulo {
  font-weight: 700;
  font-size: 13px;
  margin-bottom: var(--e2);
}
.funilGargaloEtapas {
  margin: 0 0 var(--e2);
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink-2);
}
.funilGargaloTexto { margin: 0 0 var(--e3); font-size: 12.5px; color: var(--ink-2); line-height: 1.6; }
.funilGargaloTexto strong { color: var(--ink); }
.funilGargaloInvestigar ul {
  margin: var(--e2) 0 0;
  padding-left: var(--e4);
  font-size: 12px;
  color: var(--ink-3);
  line-height: 1.8;
}

/* Taxa de conversão final - o número que fecha a história, em linguagem
   simples logo abaixo ("45 compras a partir de X impressões"), pedido
   explícito do brief pra evitar termo técnico aqui. */
.funilTaxaFinal {
  margin-top: var(--e4);
  padding-top: var(--e4);
  border-top: 1px solid var(--line);
  text-align: center;
}
.funilTaxaFinal b {
  display: block;
  font-family: var(--font-mono);
  font-size: 22px;
  font-weight: 800;
  color: var(--ink);
  margin: var(--e1) 0;
}
.funilTaxaFinal .note { margin: 0; }

/* ------------------------------------------------- alerta da Visao Geral */

.alertBanner {
  display: flex;
  gap: var(--e4);
  align-items: flex-start;
  border: 1px solid var(--prejuizo);
  border-left-width: 3px;
  border-radius: var(--r1);
  background: var(--veu-prejuizo);
  padding: var(--e4) var(--e5);
  margin-bottom: var(--e5);
}
.alertBanner.laranja {
  border-color: var(--limite);
  background: var(--veu-limite);
}
.alertBanner .icone { font-size: 15px; line-height: 1.4; flex: none; }
.alertBanner .title { font-weight: 700; font-size: 13px; margin-bottom: var(--e2); color: var(--prejuizo-claro); }
.alertBanner.laranja .title { color: var(--limite); }
.alertBanner .msg { font-size: 12.5px; color: var(--ink-2); line-height: 1.6; }
.alertBanner .causa { display: block; margin-top: var(--e2); color: var(--ink-3); font-size: 12px; }

/* ------------------------------------------------------------ tabela */

.tableWrap { max-height: 460px; overflow: auto; }

table { width: 100%; border-collapse: collapse; font-size: 13px; }

/* Cabecalho fixo LEVANTADO da superficie das linhas: era --bg, o mesmo fundo da
   pagina, e com 182 linhas rolando por baixo ele nao se separava do conteudo.
   --surface-2 mais o filete de 2px em --marca-fraco dao a borda que diz "daqui
   para cima e cabecalho, e ele nao rola". */
th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--surface-2);
  text-align: left;
  padding: var(--e3) var(--e3) var(--e3) var(--e2);
  border-bottom: 2px solid var(--marca-fraco);
  white-space: nowrap;
}
/* Valor numerico de tabela em mono: digito de largura fixa alinha a virgula
   sozinho, e comparar uma coluna de R$ vira leitura de silhueta em vez de
   leitura de numero. E o unico lugar onde a mono aparece. */
th.num { text-align: right; }
td.num {
  text-align: right;
  font-family: var(--font-mono);
  /* 12px, nao 11.5px: mono ja e mais estreita que a sans, e 11,5 numa coluna de
     R$ com 182 linhas cansa. Meio pixel aqui nao muda a densidade e muda a
     leitura. */
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.01em;
  color: var(--ink-2);
}
th.pick, td.pick { width: 34px; text-align: center; padding-right: 0; }

td {
  padding: var(--e2) var(--e3) var(--e2) var(--e2);
  border-bottom: 1px solid var(--line-soft);
  white-space: nowrap;
  color: var(--ink-2);
}
/* A coluna do nome e a ancora: peso 600 contra as numericas em --ink-2, entao o
   olho vai nome -> numero e nao numero -> nome. Antes era peso 500 e a diferenca
   nao sustentava a hierarquia. */
td.name {
  color: var(--ink);
  white-space: normal;
  min-width: 196px;
  font-weight: 600;
  border-right: 1px solid var(--line-soft);
}

/* ZEBRA MUITO SUTIL. Com 182 linhas e 12 colunas, perder a linha no meio do
   caminho e o erro de leitura mais comum, e ela custa 1,5% de branco. Vem antes
   das regras de hover e selecao de proposito: as duas tem de vencer. */
tbody tr:nth-child(even) td { background: var(--veu-neutro); }

/* A linha inteira reage: com 12 colunas, saber em qual linha o olho esta e
   metade do trabalho de ler a tabela.
   Veu de --marca em vez de --surface: o hover agora se ve de longe, que era o
   pedido. E o filete de 2px na primeira celula marca onde a linha comeca. */
tbody tr { transition: background var(--troca); }
tbody tr:hover td { background: var(--marca-veu); }
tbody tr:hover td.name { color: var(--ink); box-shadow: inset 2px 0 0 var(--marca-fraco); }

/* Selecionada e MAIS forte que hover, senao passar o mouse por cima apagava a
   selecao visualmente. Era veu ambar, que agora significa "no limite" e nao pode
   mais ser usado para selecao. */
tbody tr.picked td { background: var(--veu-marca-forte); }
tbody tr.picked td.name { box-shadow: inset 2px 0 0 var(--marca); }
tbody tr.picked:hover td { background: var(--veu-marca-max); }

/* ROAS sem cor, de proposito. Ele era pintado pelas suas proprias faixas
   (>=1,5 verde / >=0,8 dourado / abaixo vermelho), o que punha duas cores
   contraditorias na MESMA linha: "1.25x" em dourado ao lado da etiqueta
   PREJUIZO em vermelho. ROAS ignora o custo do produto e o veredito nao - so
   um dos dois pode mandar na cor, e e o do lucro. O numero continua na tabela.
   Para reverter: devolver `roasClasse(r.roasReal)` a classe da celula em
   report.js e recriar as tres regras de cor aqui. */
.roas { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-weight: 500; }

/* badge de lucro real na tabela de campanhas */
/* ---------- ETIQUETA DE COMPOSICAO: o elemento de assinatura ----------

   O veredito de lucro e o dado mais importante do painel, e a marca vende
   roupa - entao ele veste a etiqueta costurada na gola.

   Filete de 3px na cor do veredito + canto chanfrado. Nada alem disso: sem
   textura, sem pontilhado imitando costura, sem icone. A COR continua fazendo
   todo o trabalho de leitura rapida; a etiqueta e so a moldura.

   Se em uso o chanfro atrapalhar a leitura, basta tirar o clip-path: o filete
   sozinho ja resolve. */
/* EMPILHADA, nao em linha: rotulo em cima, valor embaixo - que e como uma
   etiqueta de gola e escrita de verdade. E resolve um problema concreto: em
   linha unica ela ocupava 217px e empurrava a coluna de veredito para fora da
   tela, escondendo justamente o dado mais importante do painel. */
/* Fluxo de texto normal, nao flex: o rotulo, o valor e o sufixo "/venda" sao
   tres nos separados no HTML, e em flex-column cada um virava uma linha - o
   "/venda" ficava sozinho embaixo, em caixa alta, chamando mais atencao que o
   numero. Como texto corrido com largura maxima, eles se acomodam sozinhos. */
.vBadge {
  display: inline-block;
  /* 136px, nao 116: o caso "gasto sem venda" escreve o total mais "sem venda",
     e a 116px ele quebrava numa terceira linha - a linha da tabela ia a 60px
     enquanto as vizinhas ficavam em 49px e o olho perdia a base de comparacao.
     Bem longe dos 217px que um dia empurraram a coluna de lucro para fora. */
  max-width: 136px;
  /* O min-width existe por causa da Analise Mensal: com 11 colunas a celula
     espreme a etiqueta ate o minimo, e sem piso "R$ -103,77 sem venda" quebrava
     em tres linhas - a linha ia a 60px enquanto a vizinha ficava em 49px.
     128px e o menor valor que zera a terceira linha em 1280px (medido: 5 de 10
     etiquetas quebravam a 118px, nenhuma a 128px). Custo: a tabela mensal rola
     10px a mais DENTRO do .tableWrap, e a pagina continua sem estourar. */
  min-width: 128px;
  white-space: normal;
  font-size: 9px;
  font-weight: 600;
  line-height: 1.15;
  text-transform: uppercase;
  letter-spacing: .07em;
  padding: 3px var(--e2) 4px 6px;
  border: 1px solid var(--line);
  border-left-width: 3px;
  border-left-color: var(--ink-3);
  background: var(--surface-2);
  color: var(--ink-3);
  /* canto superior direito cortado: o corte da etiqueta */
  clip-path: polygon(0 0, calc(100% - 5px) 0, 100% 5px, 100% 100%, 0 100%);
}

/* o valor em mono, para as etiquetas alinharem entre linhas da tabela */
.vBadge b {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 10.5px;
  line-height: 1.3;
  letter-spacing: -.03em;
  text-transform: none;
  white-space: nowrap;     /* o numero nunca se parte */
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}

/* A unidade ("/venda") e legenda, nao dado: sem caixa alta, menor e cinza.
   Como texto solto ela herdava o uppercase e a cor do veredito, e "R$ -18,45"
   e "/VENDA" chegavam ao olho com o mesmo peso - metade da tinta gasta na
   unidade em vez do numero. */
.vBadge i {
  font-style: normal;
  font-size: 8.5px;
  font-weight: 500;
  letter-spacing: .02em;
  text-transform: none;
  white-space: nowrap;
  color: var(--ink-3);
}

.vBadge.good { color: var(--lucro-claro); border-color: color-mix(in srgb, var(--lucro) 40%, transparent);  border-left-color: var(--lucro);    background: var(--veu-lucro); }
.vBadge.mid  { color: var(--limite); border-color: color-mix(in srgb, var(--limite) 40%, transparent); border-left-color: var(--limite); background: var(--veu-limite); }
.vBadge.bad  { color: var(--prejuizo-claro); border-color: color-mix(in srgb, var(--prejuizo) 40%, transparent);  border-left-color: var(--prejuizo); background: var(--veu-prejuizo); }

.statusDot {
  display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  margin-right: var(--e2); vertical-align: middle; background: var(--ink-3);
}
.statusDot.ACTIVE { background: var(--lucro); }
.statusDot.PAUSED { background: var(--ink-3); }

.emptyRow { color: var(--ink-3); font-style: italic; padding: var(--e5) var(--e3); }

/* Marca de aviso ao lado do nome da campanha: nome repetido na Meta, ou
   conversão vindo de duas fontes ao mesmo tempo. O texto todo fica no title. */
.marcaAviso {
  display: inline-block;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .06em;
  padding: 2px var(--e2);
  border-radius: 2px;
  vertical-align: middle;
  cursor: help;
  background: var(--line);
  color: var(--ink-2);
  white-space: nowrap;
}
.marcaAviso.alerta { background: var(--veu-prejuizo); color: var(--prejuizo); }

/* As abas de conta e os quatro blocos ".filters" por aba sairam: viraram o
   filtro global do topo (.filtroGlobal, mais abaixo). Um controle por coisa, em
   um lugar so, valendo para todas as abas DE TRAFEGO PAGO.
   A aba Instagram tem filtro proprio (.igFiltros) e e a excecao declarada: ela
   le outra API, em outro host, onde conta de anuncio e campanha nao existem.
   Levar periodo de organico para o filtro global vazaria para paramsDeConsulta()
   e para as oito abas de Meta Ads. Registrado no CLAUDE.md em 29/07/2026. */

/* coluna Conta: só aparece quando faz diferença ("Todos" com 2+ contas) */
.colConta { display: none; }
table.mostrarConta .colConta { display: table-cell; }

.selectionBar {
  display: flex;
  align-items: center;
  gap: var(--e4);
  flex-wrap: wrap;
  font-size: 12.5px;
  color: var(--ink-2);
  padding: var(--e3) 0 0;
}
.selectionBar strong { color: var(--marca); font-variant-numeric: tabular-nums; }

/* ------------------------------------------------- filtro global (topo) */

/* Fica grudado no topo porque vale para todas as abas: ao rolar uma tabela
   longa, saber qual periodo esta ativo continua importando. */
.filtroGlobal {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--bg);
  border-bottom: 1px solid var(--line);
  padding: var(--e4) var(--e6) var(--e3);
}
.filtroGlobal[hidden] { display: none; }

.fgLinha {
  display: flex;
  gap: var(--e4);
  align-items: flex-end;
  flex-wrap: wrap;
  max-width: 1180px;
}
.fgLinha .spacer { flex: 1; }

.fgCampo { display: flex; flex-direction: column; gap: var(--e2); position: relative; }
/* `display` de classe vence o [hidden] da folha do navegador: sem esta regra o
   bloco de datas ficaria visivel mesmo com o atributo hidden aplicado. */
.fgCampo[hidden] { display: none; }
.fgCampo > span {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: .14em;
  color: var(--ink-3);
  font-weight: 600;
}
/* `select` saiu daqui de propósito: ele é governado por uma regra `select` única
   lá embaixo ("controles de filtro em forma de botão"), que vale nas três
   marcações do painel. Se voltar a ser listado aqui, o atalho `background`
   apaga a `background-image` da seta — e como `.fgCampo select` tem
   especificidade maior que `select`, ela some sem erro nenhum. */
.fgCampo input[type="search"],
.fgCampo input[type="date"] {
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--ink);
  padding: var(--e2) var(--e3);
  border-radius: var(--r1);
  font-size: 13px;
  font-family: inherit;
  min-width: 150px;
}
/* Piso de largura dos controles do filtro, onde eles ficam lado a lado e
   larguras diferentes desalinham a fileira. Fica AQUI, e não junto da regra
   `select` do fim do arquivo, porque a media query de ≤900px logo abaixo
   precisa vencer por ordem para a barra encolher em tela estreita. Em Criar
   Campanha o piso não se aplica: quebraria a grade `auto-fit`. */
.fgCampo select,
.igFiltros select { min-width: 150px; }

.fgCampo select:focus,
.fgCampo input:focus { outline: 1px solid var(--marca); outline-offset: -1px; }
.fgBusca input { min-width: 158px; }

.fgDatasCampos { display: flex; gap: var(--e2); }
.fgDatasCampos input[type="date"] { min-width: 132px; }
/* o icone nativo do date vem escuro sobre fundo escuro */
.fgCampo input[type="date"]::-webkit-calendar-picker-indicator {
  filter: invert(.75) sepia(.4) saturate(3) hue-rotate(1deg);
  cursor: pointer;
}

/* ------- seletor de campanhas (multi-select) ------- */

.fgSeletor {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e3);
  min-width: 156px;
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--ink-2);
  padding: var(--e2) var(--e3);
  border-radius: var(--r1);
  font-size: 13px;
  font-family: inherit;
  cursor: pointer;
  text-align: left;
}
.fgSeletor:hover { border-color: var(--ink-3); }
.fgSeletor.ativo { border-color: var(--marca); color: var(--ink); }
.fgSeta { color: var(--ink-3); font-size: 10px; }

.fgPainel {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 30;
  width: 340px;
  max-width: 78vw;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r1);
  padding: var(--e3);
  box-shadow: var(--sombra-painel);
}
.fgPainel[hidden] { display: none; }
.fgPainel input[type="search"] {
  width: 100%;
  background: var(--bg);
  border: 1px solid var(--line);
  color: var(--ink);
  padding: var(--e2) var(--e3);
  border-radius: var(--r1);
  font-size: 12.5px;
  font-family: inherit;
}
.fgPainelAcoes {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--e2) var(--e1) var(--e2);
}
.fgPainelInfo { font-size: 10.5px; color: var(--ink-3); font-variant-numeric: tabular-nums; }

.fgLista { max-height: 274px; overflow-y: auto; }
.fgItem {
  display: flex;
  align-items: center;
  gap: var(--e3);
  padding: var(--e2) var(--e1);
  border-radius: 2px;
  cursor: pointer;
  font-size: 12.5px;
  color: var(--ink-2);
}
.fgItem:hover { background: var(--line-soft); }
.fgItem.marcado { color: var(--ink); }
.fgItem input { accent-color: var(--marca); flex: none; }
.fgItemNome {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.fgItem .statusDot { margin: 0; flex: none; }
.fgVazio { padding: var(--e3) var(--e1); font-size: 12px; color: var(--ink-3); font-style: italic; }

/* ------- linha de contexto e aviso de truncamento ------- */

.fgResumo { max-width: 1180px; }
.fgResumoLinha {
  padding-top: var(--e3);
  font-size: 11.5px;
  color: var(--ink-3);
}
.fgResumoLinha strong { color: var(--ink-2); font-weight: 600; }

.fgAviso {
  margin-top: var(--e3);
  padding: var(--e3) var(--e3);
  border-left: 2px solid var(--limite);
  background: var(--veu-limite);
  font-size: 11.5px;
  line-height: 1.55;
  color: var(--ink-2);
}
.fgAviso strong { color: var(--limite); }

/* resumo por aba, no lugar dos blocos de filtro que cada uma tinha */
.abaResumo {
  display: flex;
  /* space-between, nao flex-end: o horario de sincronizacao mora a esquerda
     (informacao de estado, lida primeiro) e as exportacoes seguem a direita
     (acao, como sempre foram). */
  justify-content: space-between;
  align-items: center;
  gap: var(--e3);
  min-height: 16px;
  margin-bottom: var(--e3);
  flex-wrap: wrap;
}
.abaResumo .note { font-size: 11.5px; color: var(--ink-3); }
.abaResumoAcoes { display: flex; align-items: center; gap: var(--e3); }

.syncInfo { display: flex; align-items: center; gap: var(--e2); }
/* ponto solido, sem pulso: e leitura de estado ("dado atual"), nao alerta -
   animar isso repetiria o erro que a regra de motion do painel ja evita
   (movimento decorativo, cobrado toda vez que a tela e olhada). */
.syncPonto {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent); flex: none;
}
.ghostBtn--accent { border-color: var(--accent-fraco); color: var(--accent-forte); }
.ghostBtn--accent:hover { border-color: var(--accent); background: var(--accent-veu); }
.ghostBtn--accent:disabled { opacity: .5; cursor: not-allowed; border-color: var(--line); color: var(--ink-3); background: none; }

@media (max-width: 900px) {
  .filtroGlobal { padding: var(--e3) var(--e5) var(--e3); position: static; }
  .fgCampo select,
  .fgCampo input[type="search"] { min-width: 0; width: 100%; }
  .fgCampo, .fgBusca { flex: 1 1 168px; }
}

.linkBtn {
  background: none; border: none; padding: 0;
  color: var(--ink-2); font-family: inherit; font-size: 12.5px;
  cursor: pointer; border-bottom: 1px solid var(--line);
}
.linkBtn { transition: color var(--troca), border-color var(--troca); }
.linkBtn:hover { color: var(--marca-forte); border-bottom-color: var(--marca); }

input[type="checkbox"] { width: 14px; height: 14px; }

/* ------------------------------------------------------------ estados */

.skeleton {
  background: linear-gradient(90deg, var(--surface) 25%, var(--surface-2) 50%, var(--surface) 75%);
  background-size: 200% 100%;
  animation: shimmer 1.3s infinite linear;
  border-radius: var(--r1);
}
@keyframes shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
/* Quem pede menos movimento no sistema recebe menos movimento. O esqueleto
   perde o brilho e as transicoes de hover somem - o painel continua inteiro. */
@media (prefers-reduced-motion: reduce) {
  .skeleton { animation: none; }
  * { transition: none !important; }
}

.skelLine { height: 11px; margin-bottom: var(--e3); }
.skelValue { height: 30px; width: 78%; margin-top: var(--e1); }

.errorBox {
  border: 1px solid var(--prejuizo);
  border-left-width: 3px;
  border-radius: var(--r1);
  background: var(--veu-prejuizo);
  padding: var(--e4) var(--e5);
  margin-bottom: var(--e5);
}
.errorBox .title { font-weight: 700; font-size: 13px; margin-bottom: var(--e2); color: var(--prejuizo-claro); }
.errorBox .msg { font-size: 12.5px; color: var(--ink-2); line-height: 1.55; word-break: break-word; }
.errorBox .hint { font-size: 12px; color: var(--ink-3); margin-top: var(--e3); line-height: 1.5; }
.errorBox button { margin-top: var(--e4); }

.badge {
  display: inline-block;
  font-size: 11.5px;
  padding: var(--e2) var(--e4);
  border-radius: var(--r-pilula);
  border: 1px solid transparent;
}
.badge.ok   { background: var(--veu-lucro);  color: var(--lucro-claro); border-color: color-mix(in srgb, var(--lucro) 40%, transparent); }
.badge.warn { background: var(--veu-limite); color: var(--limite); border-color: color-mix(in srgb, var(--limite) 40%, transparent); }

/* ------------------------------------------- plano de acao / recomendacoes */

/* cor por grupo de prioridade, usada no plano e na bolinha dos cards */
.grupo-tecnico   { --acento: var(--prejuizo); }
.grupo-prejuizo  { --acento: var(--prejuizo); }
.grupo-reativar  { --acento: var(--limite); }
.grupo-escalar   { --acento: var(--lucro); }
.grupo-observar  { --acento: var(--ink-3); }
.grupo-sem-dados { --acento: var(--line); }

.plano { list-style: none; margin: 0; padding: 0; counter-reset: passo; }

.planoItem {
  display: flex;
  gap: var(--e4);
  align-items: flex-start;
  /* e4 -> e5: e4 deixava pouco ar entre itens empilhados (achado real,
     05/08/2026) - a lista e uma sequencia de blocos com titulo+descricao+tags
     cada um, nao uma linha de tabela, e precisa do mesmo respiro que um card
     teria. */
  padding: var(--e5) 0;
  border-bottom: 1px solid var(--line-soft);
}
.planoItem:first-child { padding-top: 0; }
.planoItem:last-child { border-bottom: none; padding-bottom: 0; }

.planoNum {
  flex: none;
  width: 26px; height: 26px;
  border-radius: 50%;
  border: 1px solid var(--acento, var(--line));
  color: var(--acento, var(--ink-2));
  display: grid; place-items: center;
  font-size: 12px; font-weight: 700;
  font-variant-numeric: tabular-nums;
  /* Centraliza o circulo contra a PRIMEIRA LINHA do titulo (14px/~1,5 = 21px
     de caixa), nao contra o bloco inteiro do item - com align-items:flex-start
     no pai, os 26px do circulo comecavam 2-3px acima da caixa de texto e
     liam como levemente desalinhado. */
  margin-top: -2px;
}

.planoCorpo { min-width: 0; }
.planoTitulo {
  display: flex; align-items: baseline; gap: var(--e3); flex-wrap: wrap;
  font-size: 14px; font-weight: 700; color: var(--ink); margin-bottom: var(--e3);
}
.planoQtd {
  font-size: 10.5px; font-weight: 600; text-transform: uppercase; letter-spacing: .1em;
  color: var(--acento, var(--ink-3));
}
.planoPorque { font-size: 12.5px; color: var(--ink-2); line-height: 1.6; }
/* e3 -> e4: as tags sao METADADO da recomendacao, nao continuacao do
   paragrafo - precisam ler como um grupo proprio, nao grudadas no texto. */
.planoNomes { display: flex; gap: var(--e2); flex-wrap: wrap; margin-top: var(--e4); }

.chip {
  font-size: 11px;
  padding: var(--e1) var(--e3);
  border-radius: var(--r1);
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--ink-2);
  max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chip.mais { color: var(--ink-3); border-style: dashed; }

/* .chipLink: os chips de campanha do Plano de Acao viraram <button> em
   19-08-2026 para abrir a campanha em Campanhas ao clicar. Modificador em
   vez de mudar .chip direto porque a maioria dos .chip do painel (severidade
   da auditoria, etc.) continua so leitura, sem acao nenhuma. */
.chipLink { font-family: inherit; cursor: pointer; transition: background .12s ease, color .12s ease; }
.chipLink:hover { background: var(--marca-veu); color: var(--marca); border-color: color-mix(in srgb, var(--marca) 40%, transparent); }
.chipLink:focus-visible { outline: 2px solid var(--marca); outline-offset: 2px; }

/* ---------------------------------------------------- cards por campanha */

.diagCard {
  border: 1px solid var(--line);
  border-left: 2px solid var(--acento, var(--line));
  border-radius: var(--r1);
  background: var(--surface);
  margin-bottom: var(--e2);
}
.diagCard summary {
  display: flex; align-items: center; gap: var(--e3);
  padding: var(--e3) var(--e4);
  cursor: pointer;
  list-style: none;
  font-size: 13px;
}
.diagCard summary::-webkit-details-marker { display: none; }
.diagCard summary:hover { background: var(--surface-2); }
.diagCard[open] summary { border-bottom: 1px solid var(--line-soft); }

.diagPonto {
  flex: none; width: 7px; height: 7px; border-radius: 50%;
  background: var(--acento, var(--ink-3));
}
.diagNome { flex: 1; min-width: 0; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.diagVeredito { font-size: 11.5px; color: var(--acento, var(--ink-3)); white-space: nowrap; }
.diagGasto {
  font-family: var(--font-mono); font-weight: 500; font-size: 12.5px;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums; color: var(--ink-2); white-space: nowrap;
}

.diagCorpo { padding: var(--e4) var(--e4) var(--e4); }
.diagMotivo { margin: 0 0 var(--e3); font-size: 12.5px; color: var(--ink-2); line-height: 1.6; }

.diagNumeros {
  display: flex; flex-wrap: wrap; gap: var(--e2) var(--e5);
  padding: var(--e3) 0; margin-bottom: var(--e3);
  border-top: 1px solid var(--line-soft); border-bottom: 1px solid var(--line-soft);
  font-size: 12px; color: var(--ink-2); font-variant-numeric: tabular-nums;
}
.diagNumeros b {
  font-weight: 600; font-size: 10px; text-transform: uppercase; letter-spacing: .1em;
  color: var(--ink-3); margin-right: var(--e2);
}

.diagAcoesTitulo {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .14em;
  color: var(--marca); font-weight: 600; margin-bottom: var(--e2);
}
.diagAcoes { margin: 0; padding-left: var(--e5); font-size: 12.5px; color: var(--ink-2); line-height: 1.7; }
.diagAcoes li { margin-bottom: var(--e1); }

/* ------------------------------------------------------------ formularios */

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

/* Rotulo de formulario fala a MESMA lingua dos outros rotulos do painel
   (KPI, cabecalho de tabela, filtro do topo): caixa alta miuda e cinza. Na aba
   Vendas dava para ver os dois idiomas na mesma tela - "CONTA" no filtro do
   topo e "Nome do cliente" logo abaixo. */
label { display: flex; flex-direction: column; font-size: 12.5px; color: var(--ink-2); gap: var(--e2); }

/* `form label`, nao `label`: os itens do seletor de campanhas tambem sao
   <label>, e a caixa alta cairia sobre os 182 nomes de campanha da lista. */
form label {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .12em;
  color: var(--ink-3);
}

/* O `display: flex` acima VENCE o [hidden] da folha do navegador - a mesma
   armadilha do .fgCampo. Sem esta regra, o campo de raio ficava visivel mesmo
   com o atributo aplicado, e o JS "escondia" algo que continuava na tela. */
label[hidden] { display: none; }

/* Nota explicativa dentro do rotulo: e frase, nao rotulo. Sem o reset ela
   herdava a caixa alta e virava "A META ACEITA DE 17 A 80 KM." gritando ao
   lado do campo. */
form label .hint {
  text-transform: none;
  letter-spacing: normal;
  font-weight: 400;
  font-size: 11px;
}
/* O controle NAO herda a caixa alta: text-transform desce para o campo e
   deixaria o que a pessoa digita - e o placeholder - em maiuscula. */
form label input, form label select, form label textarea {
  text-transform: none;
  letter-spacing: normal;
  font-weight: 400;
}

input, select, textarea {
  /* --surface, nao --bg: com o fundo do campo igual ao da pagina, o campo
     desaparecia e so uma borda de 1px dizia onde clicar. Os campos do filtro
     global ja usavam --surface, entao a mesma tela tinha campo visivel em cima
     e campo invisivel embaixo. */
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--ink);
  padding: var(--e3) var(--e3);
  border-radius: var(--r1);
  font-size: 13.5px;
  font-family: inherit;
  transition: border-color var(--troca);
}
input:hover, select:hover, textarea:hover { border-color: var(--ink-3); }
input:focus, select:focus, textarea:focus { outline: 1px solid var(--marca); outline-offset: -1px; }
textarea { resize: vertical; min-height: 74px; line-height: 1.5; }
::placeholder { color: var(--ink-3); opacity: .75; }

button[type="submit"], .primaryBtn {
  background: linear-gradient(90deg, var(--marca), var(--marca-cobre));
  color: var(--surface);
  border: none;
  border-radius: var(--r1);
  padding: var(--e3);
  font-weight: 700;
  font-family: inherit;
  cursor: pointer;
  font-size: 13.5px;
  letter-spacing: .02em;
  transition: filter var(--troca);
}
button[type="submit"]:disabled, .primaryBtn:disabled { opacity: .45; cursor: not-allowed; }
/* Mesmo brilho de hover do botao do login (public/login.css) - o escurecer no
   :active ja existe mais abaixo neste arquivo, so faltava o par claro. */
button[type="submit"]:hover:not(:disabled), .primaryBtn:hover:not(:disabled) { filter: brightness(1.08); }

.ghostBtn {
  background: none;
  border: 1px solid var(--line);
  color: var(--ink-2);
  border-radius: var(--r1);
  padding: var(--e2) var(--e4);
  font-family: inherit;
  font-size: 12.5px;
  cursor: pointer;
}
.ghostBtn { transition: border-color var(--troca), color var(--troca); }
.ghostBtn:hover { border-color: var(--marca); color: var(--marca); }

.hint { font-size: 12px; color: var(--ink-3); margin-top: var(--e4); line-height: 1.6; }

.delBtn {
  background: none; border: 1px solid var(--line); color: var(--ink-3);
  padding: var(--e1) var(--e3); border-radius: var(--r1); font-size: 11px; cursor: pointer; font-family: inherit;
}
.delBtn:hover { border-color: var(--prejuizo); color: var(--prejuizo); }

.formGrid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--e4); }
.formGrid .full { grid-column: 1 / -1; }

/* Formulario de registro (Leads e Vendas). Eram sete campos curtos empilhados
   numa coluna de 520px: o historico - que e o que a pessoa vem ver - nascia
   abaixo da dobra, com 65% da tela vazia ao lado. Auto-fit resolve os tres
   tamanhos sem media query: 3-4 colunas no monitor, 2 no notebook, 1 no
   celular. `align-items: end` mantem os campos alinhados pela base quando um
   rotulo quebra em duas linhas e o vizinho nao. */
.formRegistro {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(178px, 1fr));
  gap: var(--e4);
  align-items: end;
}
.formRegistro .full { grid-column: 1 / -1; }

/* botao do registro nao ocupa a linha inteira: a acao e curta, o alvo tambem */
.formRegistro + button[type="submit"] {
  align-self: flex-start;
  padding-left: var(--e6);
  padding-right: var(--e6);
}

fieldset {
  border: none;
  border-top: 1px solid var(--line);
  padding: var(--e5) 0 0;
  margin: var(--e2) 0 0;
  display: flex;
  flex-direction: column;
  gap: var(--e4);
}
/* Um degrau acima do rotulo de campo: com os dois em 10.5px, "CAMPANHA" (secao)
   e "NOME DA CAMPANHA" (campo) chegavam ao olho no mesmo nivel. A cor ja
   separava; o tamanho confirma. */
legend {
  padding: 0 var(--e3) 0 0;
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: .16em;
  color: var(--marca);
  font-weight: 600;
}

/* ------------------------------------------------------- criar anuncio */

.twoCol { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 380px); gap: var(--e6); align-items: start; }

.dropZone {
  border: 1px dashed var(--line);
  border-radius: var(--r2);
  padding: var(--e5);
  text-align: center;
  cursor: pointer;
  transition: border-color .15s, background .15s;
  background: var(--surface);
}
.dropZone:hover, .dropZone.dragging { border-color: var(--marca); background: var(--surface-2); }
.dropZone .big { font-size: 13px; color: var(--ink-2); margin-bottom: var(--e2); }
.dropZone .small { font-size: 11.5px; color: var(--ink-3); }
.dropZone input[type="file"] { display: none; }
.mediaPreview { margin-top: var(--e4); }
/* miniatura, nao heroi: sem o teto de altura um criativo 1080x1080 empurrava
   todo o resto do formulario para fora da tela */
.mediaPreview img, .mediaPreview video {
  max-width: 100%;
  max-height: 260px;
  width: auto;
  border-radius: var(--r1);
  display: block;
  border: 1px solid var(--line);
}

/* -------------------------------------------------- busca de segmentacao ----
   Campo com sugestoes da Meta (interesses e cidades). O painel e ancorado no
   proprio campo, entao o <label> precisa ser o contexto de posicionamento. */

.buscaCampo { position: relative; }

/* Nota logo abaixo de um campo de busca. Fica FORA do <label> porque o painel
   de sugestoes e ancorado nele: dentro, o painel abriria depois do texto, com
   um vao entre o campo e a lista. O gap do form ja separa, entao ela sobe. */
.notaCampo { margin-top: calc(var(--e4) * -1 + var(--e1)); }

.sugestoes {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 40;
  margin-top: var(--e1);
  max-height: 260px;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r1);
  box-shadow: var(--sombra-painel);
}
.sugestoes[hidden] { display: none; }

.sugestao {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  border-bottom: 1px solid var(--line-soft);
  padding: var(--e2) var(--e3);
  cursor: pointer;
  font-family: inherit;
  color: var(--ink-2);
  transition: background var(--troca);
}
.sugestao:last-child { border-bottom: none; }
.sugestao:hover { background: var(--surface-2); color: var(--ink); }

.sugNome { display: block; font-size: 12.5px; text-transform: none; letter-spacing: normal; }
/* alcance e caminho: contexto para escolher entre homonimos, sem competir */
.sugMeta {
  display: block;
  margin-top: 2px;
  font-size: 10.5px;
  color: var(--ink-3);
  text-transform: none;
  letter-spacing: normal;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sugestaoVazia {
  padding: var(--e3);
  font-size: 12px;
  color: var(--ink-3);
  font-style: italic;
}

/* interesses e cidade escolhidos */
.chips { display: flex; flex-wrap: wrap; gap: var(--e2); }
.chips:not(:empty) { margin-top: var(--e2); }
.chips[hidden] { display: none; }

.chipRemovivel {
  display: inline-flex;
  align-items: center;
  gap: var(--e2);
  max-width: 100%;
  text-transform: none;
  letter-spacing: normal;
  font-weight: 400;
}
.chipX {
  background: none;
  border: none;
  color: var(--ink-3);
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
  padding: 0 2px;
  font-family: inherit;
  transition: color var(--troca);
}
.chipX:hover { color: var(--prejuizo); }

/* faixa de idade: dois campos que se leem como um intervalo */
.faixaIdade { display: flex; align-items: center; gap: var(--e2); }
.faixaIdade input { width: 100%; min-width: 0; }
.faixaIdade .ate {
  flex: none;
  font-size: 11px;
  color: var(--ink-3);
  text-transform: none;
  letter-spacing: normal;
}

.steps { list-style: none; margin: 0; padding: 0; font-size: 12.5px; }
.steps li {
  display: flex; gap: var(--e3); align-items: flex-start;
  padding: var(--e3) 0; border-bottom: 1px solid var(--line-soft); color: var(--ink-3);
}
.steps li:last-child { border-bottom: none; }
.steps .mark { width: 15px; flex: none; text-align: center; font-weight: 700; }
.steps li.doing { color: var(--ink); }
.steps li.done  { color: var(--ink-2); }
.steps li.done .mark  { color: var(--lucro); }
.steps li.fail  { color: var(--prejuizo-claro); }
.steps li.fail .mark { color: var(--prejuizo); }
.steps .detail { display: block; font-size: 11.5px; color: var(--ink-3); margin-top: var(--e1); word-break: break-all; }

.previewFrame {
  border: 1px solid var(--line);
  border-radius: var(--r2);
  overflow: hidden;
  background: #fff;
  margin-top: var(--e4);
}
.previewFrame iframe { display: block; border: none; width: 100%; min-height: 620px; }

.resultBox {
  border: 1px solid var(--lucro);
  border-left-width: 3px;
  border-radius: var(--r1);
  background: var(--veu-lucro);
  padding: var(--e4) var(--e5);
  font-size: 12.5px;
  line-height: 1.6;
}
.resultBox .title { font-weight: 700; color: var(--lucro-claro); margin-bottom: var(--e2); font-size: 13px; }
.resultBox code { font-family: var(--font-mono); font-size: 11.5px; color: var(--ink-2); }

/* ------------------------------------------------------------ responsivo */

@media (max-width: 900px) {
  /* a sidebar deixa de ser coluna e vira uma faixa de navegacao rolavel no topo */
  .shell { grid-template-columns: 1fr; }
  .sidebar {
    position: static;
    height: auto;
    flex-direction: row;
    align-items: center;
    gap: var(--e1);
    padding: var(--e4) 0;
    overflow-x: auto;
    border-right: none;
    border-bottom: 1px solid var(--line);
  }
  .brand { padding: 0 var(--e5) 0; flex: none; }
  .brand span { display: none; }
  /* Colapso e feature de tela larga (a sidebar vertical); em telas estreitas
     ela ja vira faixa horizontal por conta propria, entao o botao some e o
     grid volta ao normal - sem isso a coluna de 60px do colapso desktop
     brigaria com o layout em linha do celular. */
  .sidebarColapsar { display: none; }
  .shell.is-sidebarColapsada { grid-template-columns: 234px minmax(0, 1fr); }
  .shell.is-sidebarColapsada .navTexto { display: inline; }
  /* Colapso salvo no localStorage de uma sessao desktop nao pode deixar o
     celular sem menu - aqui nao tem botao pra descolapsar (ver acima), entao
     .navItems precisa voltar sozinho, senao a pessoa fica sem nenhuma
     subcategoria alcancavel. */
  .shell.is-sidebarColapsada .navItems { display: flex; }
  .nav { flex-direction: row; gap: var(--e1); }
  .navItem {
    border-left: none;
    border-bottom: 2px solid transparent;
    padding: var(--e2) var(--e4);
    white-space: nowrap;
  }
  .navItem.active { border-left-color: transparent; border-bottom-color: var(--marca); }
  .sidebarFoot { display: none; }

  .cardsRow { grid-template-columns: 1fr; }
  /* Os KPIs nao precisam mais de regra por breakpoint: `auto-fit` com minmax ja
     reorganiza os cards sozinho. As regras de filete que moravam aqui sairam
     junto com os filetes - o card se separa pelo fundo. */
  .twoCol, .formGrid { grid-template-columns: 1fr; }
  .topbar { padding: var(--e4) var(--e5); }
  main { padding: var(--e5) var(--e5) var(--e7); }
}
@media (max-width: 520px) {
  /* Em tela de celular o minmax ainda tentaria dois cards por fileira num
     espaco onde o numero nao cabe: aqui a coluna passa a ser uma so. */
  .kpiGrid, .kpiGrid--wide { grid-template-columns: 1fr; }
}

/* ================= Instagram (organico) ================= */

/* Cabecalho de grupo da sidebar: separa Meta Ads de Instagram, que sao fontes
   de dado diferentes e nao se cruzam em nenhuma tela. E um BOTAO, nao um
   rotulo - clicar abre o grupo e leva para a primeira funcao dele.
   Segue a regra do rotulo: caixa alta miuda e cinza. */
.navGroup {
  display: flex;
  align-items: center;
  gap: var(--e2);
  width: 100%;
  background: none;
  border: none;
  text-align: left;
  cursor: pointer;
  font-family: var(--font-sans);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--ink-3);
  /* 24px a esquerda, igual ao .brand e alinhado ao texto do .navItem (24px de
     padding + 2px de border-left). Com 16px, "META ADS" ficava 10px a esquerda
     dos nomes das abas que ele encabeca - visivel em todas as oito. */
  padding: var(--e5) var(--e4) var(--e1) var(--e5);
  transition: color var(--troca);
}
.navGroup:first-child { padding-top: var(--e2); }
.navGroup:hover { color: var(--ink-2); }
.navGroup[aria-expanded="true"] { color: var(--ink-2); }

/* Seta desenhada em CSS, nao caractere: "▸" depende de a fonte ter o glifo, e a
   Geist Sans vendorizada (subset latin) nao tem - cairia num fallback do sistema, que renderiza
   diferente em cada maquina. Sem transicao: a regra do projeto e nao animar
   alem de hover, e a troca de aba ja teve um fade removido de proposito. */
.navGroup::after {
  content: "";
  margin-left: auto;
  width: 0;
  height: 0;
  border-left: 4px solid currentColor;
  border-top: 3px solid transparent;
  border-bottom: 3px solid transparent;
}
.navGroup[aria-expanded="true"]::after {
  border-left: 3px solid transparent;
  border-right: 3px solid transparent;
  border-top: 4px solid currentColor;
  border-bottom: none;
}

/* display explicito sobrescreve o display:none que [hidden] traz da folha do
   navegador - sem esta linha, o grupo "fechado" continuaria aparecendo. */
.navItems { display: flex; flex-direction: column; }
.navItems[hidden] { display: none; }

/* Migalha no topo: "Meta Ads > Visao Geral". O grupo entra menor e em cinza,
   com o separador desenhado no ::after - assim o nome da ABA continua sendo o
   que o olho pega primeiro, e o grupo funciona como contexto, nao como titulo.
   Sem o degrau de tamanho, os dois chegariam ao olho no mesmo nivel. */
.pageTitleGrupo {
  font-size: 13px;
  color: var(--ink-3);
  letter-spacing: .02em;
}
.pageTitleGrupo::after {
  content: "›";
  margin: 0 var(--e2);
  color: var(--line);
}

/* Em tela estreita a sidebar ja vira faixa horizontal rolavel. A sanfona
   continua valendo e ate ajuda: com um grupo fechado sobra menos coisa para
   rolar de lado. So o eixo muda, e o cabecalho perde o width:100% que o
   empurraria para uma linha inteira. */
@media (max-width: 900px) {
  .nav { align-items: center; }
  /* sem `border-bottom` reservado: ele espelhava o indicador de ativo do
     .navItem, mas .navGroup nunca recebe .active (irPara so alterna a classe nos
     itens). Os 2px so engordavam a faixa horizontal. */
  .navGroup {
    width: auto;
    padding: var(--e2) var(--e3);
    white-space: nowrap;
  }
  .navGroup:first-child { padding-top: var(--e2); }
  /* REGRESSAO CORRIGIDA: o gap vinha de `.nav` quando os .navItem eram filhos
     diretos dele. Ao entrarem em .navItems, os oito botoes de Meta Ads passaram a
     ficar colados na faixa horizontal. */
  .navItems { flex-direction: row; gap: var(--e1); }
}

/* Filtro proprio da aba. Nao e a barra global: periodo aqui vale so para o
   organico. Campo usa --surface, nunca --bg - com o fundo igual ao da pagina
   sobra so uma borda de 1px dizendo onde clicar. */
.igFiltros {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--e3);
  margin-bottom: var(--e6);
}
/* Mesma armadilha do .navItems, e caí nela duas vezes: `display` de classe vence
   o `display:none` que [hidden] traz da folha do navegador. Sem esta linha, a
   barra de saida aparecia SEMPRE - inclusive com a aba funcionando, oferecendo
   "Tentar de novo" para quem nao tinha nada a repetir. */
.igFiltros[hidden] { display: none; }
/* Mesmos valores do token de rotulo da casa (ver a lista de seletores no inicio
   do arquivo): 10,5px / uppercase / .14em / 600 / --ink-3. A primeira versao
   usava .06em e nao declarava font-weight, criando uma quarta variante de rotulo
   no painel - a regra do CLAUDE.md e "o rotulo", nao "algo miudo e cinza". */
.igFiltros label {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: .14em;
  font-weight: 600;
  color: var(--ink-3);
}

/* NAO existe `.igFiltros select` aqui, de proposito.
   A versao anterior redeclarava background, border, radius e font-family - todos
   identicos ao global `input, select, textarea`, que NAO e escopado e ja pega
   estes campos. Pior: o shorthand `border` tinha a mesma especificidade de
   `select:hover { border-color }` e vinha depois no arquivo, entao MATAVA o hover
   nos tres unicos selects do painel. E o `font-size: 12.5px` criava um terceiro
   tamanho de select (13,5px global, 13px no filtro global, 12,5px aqui).
   Deixar o global agir resolve os tres problemas e remove a duplicacao. */

/* .note SOLTA nao tinha estilo nenhum. Ate agora a classe so existia dentro de
   .cardTitle e de .abaResumo, e as duas regras sao aninhadas - um <p class="note">
   fora desses contextos herdava tamanho e cor de corpo de texto, virando um
   paragrafo comum onde era para ser nota miuda e cinza. Aconteceu justamente na
   instrucao de configuracao, que e a primeira tela de quem ainda nao tem token.
   ESCOPADA EM `p.note`, e a correcao veio de um code review. A versao anterior
   usava `.note` puro e o comentario afirmava que "nada muda nas abas antigas".
   Era falso: nem `.cardTitle .note` nem `.abaResumo .note` declaram
   `line-height`, e o `body` tambem nao - entao o 1.5 daqui cascateava para os
   15 `<span class="note">` que ja existiam, engordando a caixa de linha de
   ~13,8px para 17,25px no cabecalho de quase todo card do painel.
   Os alvos legitimos desta regra sao todos `<p>`; os pre-existentes, todos
   `<span>`. O seletor de elemento separa os dois sem depender de especificidade. */
p.note {
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--ink-3);
}
p.note code {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-2);
}

/* Estes sao os PRIMEIROS links em tabela do projeto - nenhuma outra aba abre
   conteudo externo. Sem regra propria, o navegador pinta azul (#0000EE) e roxo
   de visitado, duas cores que nao existem nesta paleta e gritam no painel
   escuro. O link herda a cor do texto e usa --gold-forte no hover, que ja e o
   token de "hover de link".
   O sublinhado fica em REPOUSO, nao so no hover: sem ele, a celula de hora do
   story era um horario nu, indistinguivel de texto comum - e em toque nao existe
   hover para revelar. O idioma do projeto para isso ja existia em .linkBtn, que
   mantem filete em repouso e so troca a cor no hover. */
#tab-instagram a {
  color: inherit;
  text-decoration: underline;
  /* --ink-3, nao --line. Com --line (#2A271F sobre #0F0E0C) o contraste era
     1,29:1 - o sublinhado existia no CSS e nao existia no olho, entao o link
     seguia indistinguivel de texto ate o hover, que e exatamente o que este
     tratamento existe para evitar em tela de toque. */
  text-decoration-color: var(--ink-3);
  text-underline-offset: 3px;
}
#tab-instagram a:hover { color: var(--marca-forte); text-decoration-color: currentColor; }

/* Demografia: lista simples, sem cor de veredito. Esta aba nao tem veredito de
   lucro, entao nada aqui pode ser verde ou vermelho. */
.demoBloco { margin-bottom: var(--e5); }
.demoBloco:last-child { margin-bottom: 0; }
.demoTitulo {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--ink-3);
  margin-bottom: var(--e2);
}
.demoLinha {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: var(--e2) 0;
  border-bottom: 1px solid var(--line-soft);
}
.demoLinha:last-child { border-bottom: none; }
.demoLinha .num { font-family: var(--font-mono); color: var(--ink-2); font-size: 12.5px; }

/* "Melhores horários pra postar" - mesmo rótulo de seção do .demoTitulo, mas
   lista ordenada (ranking), não barra proporcional. */
.horariosBloco { margin-bottom: var(--e5); }
.horariosBloco:last-child { margin-bottom: 0; }
.horariosLista {
  list-style: decimal inside;
  margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: var(--e2);
}
.horariosLista li { padding: var(--e1) 0; border-bottom: 1px solid var(--line-soft); }
.horariosLista li:last-child { border-bottom: none; }
.horariosLista .note { display: block; margin-top: 2px; }

/* ===================== sub-aba Publicar (Instagram) =====================
   Nenhum token novo: tudo sai da escala --e1..--e7, dos raios --r1..--r3 e da
   paleta aprovada. Cor semantica so aparece em ESTADO, e nunca sozinha - vem
   sempre com icone ou rotulo, porque ~8% dos homens nao distinguem verde de
   vermelho e esta e a tela que diz se o post saiu. */

.zonaUpload {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--e1);
  padding: var(--e6) var(--e4);
  border: 1px dashed var(--line);
  border-radius: var(--r3);
  background: var(--surface);
  cursor: pointer;
  text-align: center;
}
.zonaUpload:hover, .zonaUpload.is-sobre {
  border-color: var(--marca);
  background: var(--marca-veu);
}
.zonaUpload strong { font-size: 13px; }

.linhasPub { display: flex; flex-direction: column; gap: var(--e2); margin-top: var(--e3); }

.linhaPub {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto;
  gap: var(--e3);
  align-items: start;
  padding: var(--e3);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r2);
}
.linhaPub.is-selecionada { border-color: var(--marca); }
.linhaSel { display: flex; align-items: center; padding-top: var(--e1); }

.linhaMinis { display: flex; gap: var(--e1); flex-wrap: wrap; max-width: 200px; }
.mini {
  width: 44px; height: 44px;
  border-radius: var(--r1);
  background: var(--bg) center/cover no-repeat;
  border: 1px solid var(--line-soft);
  flex: none;
}

.linhaCorpo { display: flex; flex-direction: column; gap: var(--e1); min-width: 0; }

/* Substituiu .chipFormato em 20-08-2026 - pedido do usuario: um botao so que
   CICLAVA por feed/feed+story/story (clique escondido, sem mostrar as outras
   opcoes) nao era "nitido nem claro". Agora sao duas pecas separadas: o
   formato (foto/reels/carrossel) e so informativo, detectado do arquivo, sem
   como clicar nele; o destino e dois botoes independentes, sempre os DOIS
   visiveis, o ativo com preenchimento solido - a mesma logica visual dos
   filtros de formato da fila (.filtroFormato), pra nao inventar um terceiro
   padrao de "selecionado" no mesmo painel. */
.destinoLinha { display: flex; align-items: center; gap: var(--e3); flex-wrap: wrap; }
.destinoFormato {
  display: inline-flex; align-items: center; gap: var(--e1);
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.destinoBotoes { display: inline-flex; gap: var(--e1); }
.destinoBtn {
  background: var(--surface-2);
  color: var(--ink-2);
  border: 1px solid var(--line);
  border-radius: var(--r-pilula);
  font-size: 11.5px;
  font-weight: 600;
  padding: var(--e1) var(--e3);
  cursor: pointer;
}
.destinoBtn:hover { border-color: var(--marca-fraco); }
.destinoBtn.is-ativo {
  background: var(--marca);
  color: var(--surface);
  border-color: var(--marca);
}
/* Rede ainda nao conectada (ex.: Google Meu Negócio antes do OAuth) - opaco
   e sem cursor de clique, mas o texto continua legivel: e informativo ("isto
   vai existir"), nao um controle escondido. */
.destinoBtn:disabled { cursor: not-allowed; opacity: .55; }
.destinoBtn:disabled:hover { border-color: var(--line); }
.destinoBtn.is-ativo:disabled { opacity: .85; }

.linhaLegenda {
  background: var(--surface);   /* nunca --bg: campo com o fundo da pagina some */
  border: 1px solid var(--line);
  border-radius: var(--r1);
  color: inherit;
  font-family: inherit;
  font-size: 12.5px;
  padding: var(--e2);
  resize: vertical;
  text-transform: none;
  width: 100%;
}
.linhaLegenda:focus { outline: none; border-color: var(--marca); }
.linhaLegenda:disabled { opacity: .5; cursor: not-allowed; }

.linhaBlocos { display: flex; gap: var(--e1); align-items: center; flex-wrap: wrap; }
.chipBloco {
  background: none;
  border: 1px solid var(--line);
  border-radius: var(--r1);
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 10px;
  padding: 2px var(--e1);
  cursor: pointer;
}
.chipBloco:hover { border-color: var(--marca); color: var(--marca); }
.linhaContador { font-family: var(--font-mono); font-size: 10px; margin-left: auto; }
.linhaContador.is-erro, .linhaAviso.is-erro { color: var(--prejuizo); }
.linhaAviso { margin: 0; font-size: 11px; }

/* "Quando" virou RODAPE da linha, nao coluna espremida na direita. Marcar
   horario e uma decisao do mesmo peso que escrever a legenda; empurrada para o
   canto ela lia como metadado e o alvo de clique ficava pequeno demais. */
.linhaQuando {
  display: flex; align-items: center; gap: var(--e2); flex-wrap: wrap;
  padding-top: var(--e2); margin-top: var(--e1);
  border-top: 1px dashed var(--line-soft);
}
.quandoRotulo {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--ink-3);
}
.quandoResumo { font-size: 11.5px; }
.linhaQuando .linkBtn { font-size: 11px; }

/* Marcação (pessoa/localização) - mesmo rodapé tracejado do "Quando", uma
   decisão a mais sobre o mesmo post, não uma seção separada. */
.linhaMarcacao {
  display: flex; gap: var(--e4); flex-wrap: wrap;
  padding-top: var(--e2); margin-top: var(--e1);
  border-top: 1px dashed var(--line-soft);
}
.linhaMarcacaoCampo { display: flex; flex-direction: column; gap: var(--e1); flex: 1 1 220px; }
.linhaChips {
  display: flex; gap: var(--e1); flex-wrap: wrap; align-items: center;
}
.linhaChips .chip button {
  background: none; border: none; color: inherit; cursor: pointer;
  font-size: 10px; padding: 0 0 0 var(--e1); line-height: 1;
}
.linhaMarcacaoInput {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r1);
  color: inherit; font-family: inherit; font-size: 12px;
  padding: var(--e1) var(--e2); min-width: 160px; flex: 1;
}
.linhaMarcacaoInput:focus { outline: none; border-color: var(--marca); }

/* Escrever na foto - editor inline (aparece dentro da própria linha, não
   modal), mesmo espírito da edição de fila: o resto da mesa continua visível
   por cima/embaixo, só essa linha cresce. */
.editorFoto {
  margin-top: var(--e3);
  padding-top: var(--e3);
  border-top: 1px dashed var(--line-soft);
}
.editorFotoTopo {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: var(--e2); font-size: 12.5px; font-weight: 600;
}
.editorFotoAcoes { display: flex; gap: var(--e2); }
.editorFotoCorpo { display: flex; gap: var(--e4); flex-wrap: wrap; }
.editorFotoTela {
  max-width: 420px; flex: 1 1 320px;
  border: 1px solid var(--line); border-radius: var(--r1); overflow: hidden;
  background: var(--bg);
  position: relative; /* ancora a .previaLocal (guia de posicao, nao gravada) */
}
.editorFotoTela canvas { display: block; width: 100%; height: auto; cursor: crosshair; }

/* Guia de localização: um elemento HTML por CIMA do canvas, NUNCA desenhado
   nele - por isso nunca entra no canvas.toBlob() nem duplica com a etiqueta
   oficial do Instagram na publicação real (esse foi o problema do adesivo
   removido em 20-08-2026, gravado nos pixels). É só orientação visual pra
   decidir tamanho/posição antes de publicar - a etiqueta de verdade continua
   vindo 100% do Instagram, no estilo dele, sem nenhum controle nosso. */
.previaLocal {
  position: absolute;
  transform: translate(-50%, -50%);
  display: flex; align-items: center; gap: 4px;
  background: rgba(255,255,255,.92);
  color: #10131c;
  border-radius: var(--r-pilula);
  padding: 5px 10px;
  font-size: 12px;
  font-weight: 700;
  white-space: nowrap;
  cursor: grab;
  user-select: none;
  box-shadow: 0 2px 8px rgba(0,0,0,.35);
}
.previaLocal:active { cursor: grabbing; }
.previaLocalTag {
  position: absolute; top: -10px; left: 50%; transform: translateX(-50%);
  background: var(--marca); color: var(--surface);
  font-family: var(--font-mono); font-size: 8px; letter-spacing: .06em; text-transform: uppercase;
  padding: 1px 5px; border-radius: var(--r-pilula); white-space: nowrap;
}
/* Story: o canvas fica alto (1080x1920) - limitar a largura mantem a altura
   dentro de algo razoavel sem esticar a linha da mesa de montagem. Cursor
   "grab" porque o gesto principal aqui e arrastar a FOTO, nao criar texto. */
.editorFotoTela.is-story { max-width: 260px; }
.editorFotoTela.is-story canvas { cursor: grab; }
.editorFotoTela.is-story canvas:active { cursor: grabbing; }
.editorFotoPainel { flex: 1 1 220px; min-width: 220px; }
.editorFotoEnquadre {
  display: flex; flex-direction: column; gap: var(--e2);
  padding-bottom: var(--e3); margin-bottom: var(--e3);
  border-bottom: 1px dashed var(--line-soft);
}
.editorFotoLista { display: flex; gap: var(--e1); flex-wrap: wrap; align-items: center; margin-bottom: var(--e3); }
.editorFotoCampos { display: flex; flex-direction: column; gap: var(--e2); }
.editorFotoCampo { display: flex; flex-direction: column; gap: var(--e1); }
.editorFotoCampo input[type="text"], .editorFotoCampo select {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r1);
  color: inherit; font-family: inherit; font-size: 12.5px; padding: var(--e1) var(--e2);
}
.editorFotoCores { display: flex; gap: var(--e1); align-items: center; }
.editorFotoCor {
  width: 22px; height: 22px; border-radius: 50%; border: 2px solid var(--line);
  cursor: pointer; padding: 0;
}
.editorFotoCor.is-ativo { border-color: var(--marca); }
.editorFotoCores input[type="color"] {
  width: 22px; height: 22px; border: none; border-radius: 50%; overflow: hidden;
  padding: 0; background: none; cursor: pointer;
}

.linhaRemover {
  background: none; border: none; color: var(--ink-3);
  cursor: pointer; font-size: 14px; padding: var(--e1); line-height: 1;
}
.linhaRemover:hover { color: var(--prejuizo); }

.pubAcoes {
  display: flex; justify-content: space-between; align-items: center;
  gap: var(--e3); margin-top: var(--e4); flex-wrap: wrap;
}
.pubAcoesEsq, .pubAcoesDir { display: flex; gap: var(--e2); align-items: center; }

/* :active e confirmacao, nao enfeite: sem resposta ao toque a reacao natural e
   clicar de novo, e aqui isso significa POST DUPLICADO no perfil. Sem espera na
   ida - o estado vale no mesmo quadro do clique. */
.pubAcoesDir button:active { transform: translateY(1px); transition: none; }
.pubAcoesDir button { transition: background var(--troca), border-color var(--troca); }

.filaGrupo {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .08em;
  color: var(--ink-3);
  margin: var(--e3) 0 var(--e1);
}
.filaGrupo:first-child { margin-top: 0; }

.filaItem {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto auto;
  gap: var(--e3);
  align-items: center;
  padding: var(--e2) var(--e3);
  border: 1px solid var(--line);
  border-left-width: 3px;
  border-radius: var(--r2);
  margin-bottom: var(--e1);
}
.filaItem.is-atrasado { border-left-color: var(--limite); }
.filaItem.is-erro { border-left-color: var(--prejuizo); }
.filaItem.is-publicado { border-left-color: var(--lucro); }
.filaItem.is-publicando, .filaItem.is-preparando { border-left-color: var(--marca); }

.filaHora { font-family: var(--font-mono); font-size: 13px; font-weight: 800; }
.filaFormato {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--ink-3);
}
.filaLegenda { color: var(--ink-2); font-size: 12.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Coluna 4 do grid (a mesma que .filaEstado ocupava sozinho antes do selo do
   TikTok existir) - .filaEstado e .filaEstadoTikTok (quando presente) ficam os
   dois AQUI DENTRO, empilhados por flex, em vez de serem dois filhos diretos
   de .filaItem. CORRIGIDO na revisao final: antes o selo do TikTok era um 6o
   filho solto do grid de 5 colunas (auto auto minmax(0,1fr) auto auto) sem
   grid-column proprio - o auto-placement empurrava .filaBotoes (que esperava a
   5a coluna) pra uma 2a linha, desalinhando os botoes de acao de todo item SEM
   tiktokResultado ao lado. Com o wrapper, .filaItem sempre tem exatamente 5
   filhos diretos de novo, tiktokResultado presente ou nao. */
.filaEstadoCol { display: flex; flex-direction: column; gap: 2px; }
.filaEstado { font-family: var(--font-mono); font-size: 10.5px; color: var(--ink-3); }
.is-atrasado .filaEstado { color: var(--limite); }
.is-erro .filaEstado { color: var(--prejuizo); }
.is-publicado .filaEstado { color: var(--lucro); }
/* Selo do TikTok: classe COMPOSTA no mesmo elemento (filaEstadoTikTok.is-erro),
   nao um ancestral com is-erro/is-publicado - as regras acima sao seletoras de
   DESCENDENTE (".is-erro .filaEstado") e nunca alcancam esta marcacao, entao
   sem regra propria a cor herdava do item.estado (Instagram) do PAI ".filaItem",
   nao do tiktokResultado.estado - achado real da revisao, corrigido aqui. Sem
   regra para o estado transitorio "…" (nem publicado nem erro): a cor padrao
   herdada de .filaEstado (--ink-3, neutra) ja serve, e um terceiro estado que
   dura pouco nao precisa de destaque proprio. */
.filaEstadoTikTok.is-erro { color: var(--prejuizo); }
.filaEstadoTikTok.is-publicado { color: var(--lucro); }
.filaBotoes { display: flex; gap: var(--e1); }
.filaBotoes button:active { transform: translateY(1px); transition: none; }
.filaMotivo, .filaLink { grid-column: 1 / -1; margin: var(--e1) 0 0; font-size: 11px; }
.filaMotivo { color: var(--prejuizo); }

@media (max-width: 900px) {
  .linhaPub, .filaItem { grid-template-columns: auto minmax(0, 1fr); }
  .linhaQuando, .filaBotoes { grid-column: 1 / -1; }
}

/* Sem token, o conteudo inteiro sai da tela. CLASSE e nao [hidden] de
   proposito - ver o comentario em mostrarConteudo() (public/instagram.js). */
#igConteudo.is-semToken { display: none; }

/* ===================== seletor de dia e hora ===================== */
/* position: fixed e nao absolute: a mesa de montagem rola dentro de um
   container, e um popover absoluto seria cortado pelo overflow dele. */
.selData {
  position: fixed;
  z-index: 60;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r3);
  box-shadow: var(--sombra-painel);
  overflow: hidden;
}
.selCorpo { display: flex; gap: 0; }
.selCal { padding: var(--e3); }
.selCabecalho {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e2); margin-bottom: var(--e2);
}
.selCabecalho strong { font-size: 12.5px; }
.selNav {
  background: none; border: 1px solid var(--line); border-radius: var(--r1);
  color: var(--ink-2); cursor: pointer; width: 24px; height: 24px; line-height: 1;
}
.selNav:hover { border-color: var(--marca); color: var(--marca); }
.selSemana, .selGrade { display: grid; grid-template-columns: repeat(7, 30px); gap: 2px; }
.selSemana span {
  font-family: var(--font-mono); font-size: 9.5px; color: var(--ink-3);
  text-align: center; padding-bottom: var(--e1);
}
.selDia {
  position: relative;
  background: none; border: 1px solid transparent; border-radius: var(--r1);
  color: inherit; cursor: pointer; height: 30px;
  font-family: var(--font-mono); font-size: 12px;
}
.selDia.is-vazio { visibility: hidden; }
.selDia:hover:not(:disabled) { border-color: var(--marca); }
.selDia.is-hoje { font-weight: 800; }
.selDia.is-escolhido { background: var(--marca); color: var(--bg); border-color: var(--marca); }
.selDia.is-passado { color: var(--ink-3); opacity: .4; cursor: not-allowed; }
.selPonto {
  position: absolute; bottom: 3px; left: 50%; transform: translateX(-50%);
  width: 3px; height: 3px; border-radius: 50%; background: var(--marca);
}
.selDia.is-escolhido .selPonto { background: var(--bg); }
.selDia.is-cheio { color: var(--limite); }

.selHoras {
  display: flex; flex-direction: column; gap: var(--e1);
  padding: var(--e3); border-left: 1px solid var(--line-soft);
  min-width: 92px;
}
.selHora {
  background: none; border: 1px solid var(--line); border-radius: var(--r1);
  color: inherit; cursor: pointer; font-family: var(--font-mono); font-size: 11.5px;
  padding: var(--e1) var(--e2); text-align: center;
}
.selHora:hover { border-color: var(--marca); color: var(--marca); }
.selHora.is-escolhido { background: var(--marca); color: var(--bg); border-color: var(--marca); }
.selHoraLivre { display: flex; flex-direction: column; gap: 2px; margin-top: var(--e1); }
.selHoraLivre span {
  font-family: var(--font-mono); font-size: 9.5px; color: var(--ink-3);
  letter-spacing: .08em; text-transform: uppercase;
}
.selHoraLivre input {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r1);
  color: inherit; font-family: var(--font-mono); font-size: 11.5px;
  padding: var(--e1); text-transform: none; width: 100%;
}
.selRodape {
  display: flex; align-items: center; justify-content: space-between; gap: var(--e3);
  padding: var(--e2) var(--e3); border-top: 1px solid var(--line-soft);
  background: var(--bg);
}
.selResumo { font-size: 11.5px; color: var(--ink-2); }
.selResumo.is-erro { color: var(--prejuizo); }
.selRodapeBotoes { display: flex; gap: var(--e1); }
.selRodapeBotoes button:active { transform: translateY(1px); transition: none; }

.botaoQuando {
  display: inline-flex; align-items: center; gap: var(--e1);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r1);
  color: var(--ink-3); cursor: pointer;
  font-family: var(--font-mono); font-size: 12.5px;
  /* alvo de toque decente: a decisao precisa parecer uma decisao */
  padding: var(--e2) var(--e3); text-align: left; white-space: nowrap;
}
.botaoQuando i { font-style: normal; opacity: .7; }
.botaoQuando:hover { border-color: var(--marca); color: var(--marca); }
.botaoQuando.is-marcado { color: inherit; border-color: var(--marca-fraco); }
.botaoQuando:active { transform: translateY(1px); transition: none; }

/* ===================== filtros e calendário da fila ===================== */
.filaFiltros {
  display: flex; flex-wrap: wrap; gap: var(--e3);
  padding-bottom: var(--e3); margin-bottom: var(--e3);
  border-bottom: 1px solid var(--line-soft);
}
.filtroGrupo { display: flex; gap: var(--e1); flex-wrap: wrap; }
.filtroVisao { margin-left: auto; }
.chipFiltro {
  background: none; border: 1px solid var(--line); border-radius: var(--r1);
  color: var(--ink-3); cursor: pointer;
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .04em;
  padding: var(--e1) var(--e2); text-transform: none;
  transition: border-color var(--troca), color var(--troca);
}
.chipFiltro:hover { border-color: var(--marca); color: var(--marca); }
.chipFiltro.is-ativo { background: var(--marca-veu); border-color: var(--marca); color: var(--marca); }
.chipFiltro i { font-style: normal; opacity: .65; }

.calendario { display: flex; flex-direction: column; gap: var(--e2); }
.calCabecalho strong { font-size: 13px; }
.calSemana { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: var(--e1); }
.calSemana span {
  font-family: var(--font-mono); font-size: 9.5px; color: var(--ink-3);
  letter-spacing: .08em; text-transform: uppercase;
}
.calGrade { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: var(--e1); }
.calDia {
  min-height: 76px; padding: var(--e1);
  border: 1px solid var(--line-soft); border-radius: var(--r1);
  display: flex; flex-direction: column; gap: 2px;
}
.calDia.is-vazio { border-color: transparent; }
.calDia.is-hoje { border-color: var(--marca); }
.calNumero { font-family: var(--font-mono); font-size: 10.5px; color: var(--ink-3); }
.calDia.is-hoje .calNumero { color: var(--marca); font-weight: 800; }
.calPosts { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.calPost {
  display: flex; align-items: center; gap: 3px;
  background: var(--marca-veu); border: none; border-radius: var(--r1);
  color: var(--ink-2); cursor: pointer;
  font-family: var(--font-mono); font-size: 9.5px;
  padding: 2px 4px; text-align: left; min-width: 0;
}
.calPost:hover { background: var(--marca-fraco); }
.calPost i { font-style: normal; }
.calPost span { overflow: hidden; text-overflow: ellipsis; }
.calPost.is-atrasado { background: color-mix(in srgb, var(--limite) 18%, transparent); }
.calPost.is-erro { background: color-mix(in srgb, var(--prejuizo) 18%, transparent); }
.calPost.is-publicado { background: color-mix(in srgb, var(--lucro) 16%, transparent); }
.calLegenda { display: flex; gap: var(--e3); flex-wrap: wrap; font-size: 10.5px; }
.calLegenda i { font-style: normal; }

.filaItem.is-apontado { border-color: var(--marca); background: var(--marca-veu); }

@media (max-width: 900px) {
  .selCorpo { flex-direction: column; }
  .selHoras { flex-direction: row; flex-wrap: wrap; border-left: none; border-top: 1px solid var(--line-soft); }
  .calDia { min-height: 56px; }
  .filtroVisao { margin-left: 0; }
}

/* ===================== demografia: minimizável e com barra ===================== */
/* <details> nativo: minimizar sem uma linha de JS, com teclado e leitor de tela
   funcionando de graca. */
details.demoBloco > summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: var(--e1);
}
details.demoBloco > summary::-webkit-details-marker { display: none; }
details.demoBloco > summary::before {
  content: "▾";
  font-size: 9px;
  color: var(--ink-3);
  transition: transform var(--troca);
}
details.demoBloco:not([open]) > summary::before { transform: rotate(-90deg); }
details.demoBloco:not([open]) { padding-bottom: var(--e2); }
details.demoBloco > summary:hover::before { color: var(--marca); }

/* Barra proporcional: a coluna de numeros sozinha exige comparar digito a
   digito. Cor de SERIE, nunca semantica - demografia nao tem veredito. */
.demoLinha { display: grid; grid-template-columns: minmax(90px, 1fr) minmax(60px, 2fr) auto; gap: var(--e3); align-items: center; }
.demoChave { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.demoBarra { display: block; height: 6px; border-radius: 3px; background: var(--line-soft); overflow: hidden; }
.demoBarra i { display: block; height: 100%; background: var(--serie-gasto, var(--marca)); border-radius: 3px; }
.demoPct {
  display: inline-block; min-width: 38px; text-align: right;
  font-style: normal; color: var(--ink-3); font-size: 10.5px; margin-left: var(--e2);
}

@media (max-width: 700px) {
  .demoLinha { grid-template-columns: minmax(80px, 1fr) auto; }
  .demoBarra { display: none; }
}

/* Linha de tendência dentro do KPI. Cor de SÉRIE, nunca semântica: ela mostra a
   forma do período, não um veredito. Pintar de vermelho uma queda faria a mesma
   tela dar dois sinais sobre o mesmo número — o incidente do ROAS de novo. */
.kpiTend {
  display: block;
  width: 100%;
  height: 22px;
  margin-top: var(--e2);
  overflow: visible;
}
.kpiTend polyline {
  fill: none;
  stroke: var(--serie-gasto, var(--marca));
  stroke-width: 1.5;
  stroke-linejoin: round;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;   /* não engorda ao esticar na largura */
  opacity: .75;
}

/* ===================== dobra: card e bloco que minimizam ===================== */
/* O affordance estava fraco demais: um "▾" cinza de 9px não diz "clique aqui".
   Agora o marcador é um botão de verdade — quadrado, com borda, girando ao
   abrir — e a faixa inteira do título responde ao passar o mouse. */
details.cardDobra > summary {
  cursor: pointer;
  list-style: none;
}
details.cardDobra > summary::-webkit-details-marker { display: none; }
details.cardDobra > summary::after {
  content: "▾";
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border: 1px solid var(--line);
  border-radius: var(--r1);
  font-size: 9px;
  color: var(--ink-3);
  transition: transform var(--troca), color var(--troca), border-color var(--troca);
}
details.cardDobra:not([open]) > summary::after { transform: rotate(-90deg); }
details.cardDobra > summary:hover::after { color: var(--marca); border-color: var(--marca); }
details.cardDobra:not([open]) { padding-bottom: var(--e4); }

/* O mesmo tratamento nos recortes internos, um degrau menor. */
details.demoBloco > summary::before {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border: 1px solid var(--line);
  border-radius: var(--r1);
  font-size: 8px;
}
details.demoBloco > summary:hover::before { border-color: var(--marca); }

/* ===================== KPIs centralizados ===================== */
/* Com nove cards numa tela larga sobra espaço à direita e a fileira encosta na
   esquerda. `justify-content: center` distribui a sobra dos dois lados sem
   esticar card nenhum — cards de tamanhos diferentes desalinhariam os números,
   que é o que permite comparar de relance. */
.kpiGrid { justify-content: center; }

/* ===================== edição inline na fila ===================== */
/* Inline e não modal: a fila é uma lista de decisões rápidas, e um modal para
   trocar um horário esconde o resto da agenda justamente na hora de decidir
   onde encaixar o post. */
.filaEdicao {
  grid-column: 1 / -1;
  display: flex;
  flex-direction: column;
  gap: var(--e2);
  margin-top: var(--e2);
  padding-top: var(--e2);
  border-top: 1px dashed var(--line-soft);
}
.filaEdicaoCampo { display: flex; flex-direction: column; gap: var(--e1); }
.filaEdicaoCampo span {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--ink-3);
}
.filaEdicaoCampo textarea {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r1);
  color: inherit; font-family: inherit; font-size: 12.5px;
  padding: var(--e2); resize: vertical; text-transform: none; width: 100%;
}
.filaEdicaoCampo textarea:focus { outline: none; border-color: var(--marca); }
.filaEdicaoLinha { display: flex; align-items: center; gap: var(--e2); flex-wrap: wrap; }
.filaEdicaoBotoes { display: flex; gap: var(--e1); margin-left: auto; }
.filaEdicaoBotoes button:active { transform: translateY(1px); transition: none; }

/* Publicado no calendário: o ✓ diz o que a cor sozinha não pode dizer. */
.calPost b { font-weight: 800; margin-left: auto; opacity: .8; }

/* ===================== controles de filtro em forma de botão =====================
   O pedido do usuário, a partir de uma referência de painel da Meta: os
   seletores devem parecer BOTÕES, não campos de formulário cru. Vale para todo
   o painel — Meta Ads e Instagram.

   A REGRA MIRA `select`, NÃO O ELEMENTO QUE O ENVOLVE, e isso é medido, não
   preferência. Os selects do painel têm TRÊS marcações diferentes:
     1. filtro global  — `<label class="fgCampo"><span>Conta</span><select>`
     2. Instagram      — `<div class="igFiltros"><label for=…>…</label><select>`,
                          o label é IRMÃO do select, não pai
     3. Criar Campanha — `<label>Objetivo <select name="objective">`, sem classe
   Escrevendo `.fgCampo select, .igFiltros select` só o caso 1 ganhava a seta: no
   caso 2 não existe label envolvendo o select, e o caso 3 ficava de fora inteiro
   — com `appearance: none` aplicado e nenhuma seta, o controle vira uma caixa
   que não diz que abre.

   A seta é desenhada com DOIS GRADIENTES no próprio select, e não com um
   `::after` no pai. Assim ela não depende de haver um pai que abrace só o
   select, e continua **dentro do tema**: um SVG em data-URI fixaria a cor no
   arquivo e a seta ficaria escura no tema escuro. */
select {
  appearance: none;
  -webkit-appearance: none;
  background-color: var(--surface);
  background-image:
    linear-gradient(45deg, transparent 50%, var(--ink-3) 50%),
    linear-gradient(135deg, var(--ink-3) 50%, transparent 50%);
  background-position: right 14px center, right 10px center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  border: 1px solid var(--line);
  border-radius: var(--r2);
  color: var(--ink);
  cursor: pointer;
  font-family: inherit;
  font-size: 13px;
  /* o recuo à direita reserva a faixa da seta, para o texto não passar por baixo */
  padding: var(--e2) var(--e5) var(--e2) var(--e3);
  transition: border-color var(--troca), background-color var(--troca);
}
select:hover { border-color: var(--marca); }

/* O piso de largura NÃO mora aqui — mora junto dos campos do filtro global, lá
   em cima. Aqui embaixo ele venceria por ordem a media query de ≤900px que faz
   `min-width: 0; width: 100%`, e a barra pararia de encolher em tela estreita. */

/* Busca e datas acompanham a mesma forma, senão a barra fica com dois
   vocabulários de controle lado a lado. */
.fgCampo input[type="search"],
.fgCampo input[type="date"] {
  border-radius: var(--r2);
  padding: var(--e2) var(--e3);
}
.fgSeletor { border-radius: var(--r2); }

/* ===================== o número do KPI ganha a voz da referência =====================
   Os números grandes saem da mono e passam à Geist Sans em peso 800. A mono CONTINUA
   nas tabelas, onde dígito de largura fixa é o que alinha a coluna — ali ela
   trabalha, aqui ela era só sotaque.

   `font-variant-numeric: tabular-nums` mantém os dígitos com a mesma largura
   dentro da Geist Sans, então a fileira de KPIs continua alinhada. */
.kpi .value {
  font-family: var(--font-sans);
  font-variant-numeric: tabular-nums;
  font-weight: 800;
  letter-spacing: -.02em;
}

/* ===================== métricas de entrega e engajamento =====================
   Formato compacto da referência: rótulo miúdo, número grande, proporção
   embaixo. NENHUMA é pintada — na referência elas têm fundo colorido por
   decoração, e aqui vermelho significa prejuízo. */
.metricasGrade {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--e1);
}
.metrica {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--e3);
  border-radius: var(--r2);
  background: var(--surface);
  border: 1px solid var(--line-soft);
  /* Acompanha os KPIs. Deixar so os de cima centralizados poria dois
     tratamentos de card na mesma tela, que e o problema que a passada de design
     resolveu nos formularios. */
  text-align: center;
}
.metricaRotulo {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-3);
  /* Duas linhas SEMPRE, mesmo quando o rotulo cabe em uma. E a mesma regra dos
     KPIs ("o rotulo e ancorado no topo e o valor na base"), pelo mesmo motivo:
     medido, "ENGAJAMENTO NA PUBLICACAO" quebrava em duas linhas e empurrava o
     numero 12px abaixo dos vizinhos - o olho perde a regua que usa para
     comparar a fileira. Reservar a segunda linha custa 13px e alinha todos. */
  line-height: 1.35;
  min-height: 2.7em;
}
.metricaValor {
  font-family: var(--font-sans);
  font-variant-numeric: tabular-nums;
  font-size: 21px;
  font-weight: 800;
  letter-spacing: -.02em;
}

/* ------------------------------------------------------- exportar em PDF ---
   Botao "Exportar PDF" da Visao Geral chama window.print() (public/exportar.js)
   depois de preencher #printRelatorio, que fica vazio e fora da tela o resto
   do tempo. Cores fixas em preto sobre branco, NUNCA var(--ink)/var(--surface):
   o tema padrao do painel e escuro, e herdar a paleta escura faria o relatorio
   sair com texto claro sobre fundo branco no papel - ilegivel. */
.printOnly { display: none; }

@media print {
  body > *:not(#printRelatorio) { display: none !important; }
  #printRelatorio {
    display: block !important;
    color: #000;
    background: #fff;
    font-family: var(--font-sans, sans-serif);
    padding: 24px;
  }
  #printRelatorio h1 { font-size: 18px; margin: 0 0 16px; }
  #printRelatorio h2 { font-size: 14px; margin: 24px 0 8px; }
  #printRelatorio table { width: 100%; border-collapse: collapse; margin-bottom: 12px; }
  #printRelatorio td {
    border: 1px solid #999;
    padding: 5px 10px;
    font-size: 12px;
    text-align: left;
    color: #000;
  }
}
.metricaNota { font-size: 10.5px; color: var(--ink-3); }

/* ================= Agentes IA (telas "Agentes" e "Organograma") =================
   Zero cor solta: tudo em token. Cor semântica (--lucro/--limite/--prejuizo)
   vale para STATUS DE DECISÃO; "rodando" é neutro de propósito — não é
   veredito, e pintá-lo gastaria a faixa semântica com estado transitório. */

.agArea { margin-bottom: var(--e6); }
.agAreaTitulo {
  font-family: var(--font-mono);
  font-size: 10px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-3); margin: 0 0 var(--e3);
}

.agCard { margin-bottom: var(--e3); }
.agCardApagado { opacity: .55; }
.agCardFocado { outline: 2px solid var(--marca); outline-offset: 2px; }

.agCabecalho { display: flex; align-items: center; gap: var(--e3); flex-wrap: wrap; }
.agCabecalho .cardTitle { margin: 0; }
.agCabecalho .agBtnRodar { margin-left: auto; }

.agEstado {
  font-family: var(--font-mono); font-size: 10px;
  letter-spacing: .08em; text-transform: uppercase;
  padding: 2px var(--e2); border-radius: var(--r1); border: 1px solid var(--line);
}
.agEstadoNeutro { color: var(--ink-3); }
.agEstadoBom { color: var(--lucro); border-color: var(--lucro); }
.agEstadoAtencao { color: var(--limite); border-color: var(--limite); }
.agEstadoRuim { color: var(--prejuizo); border-color: var(--prejuizo); }

/* Expansão INLINE, nunca modal — mesma decisão já tomada na fila de publicação:
   a lista de agentes é uma lista de decisões rápidas. */
.agCompor { margin-top: var(--e3); padding-top: var(--e3); border-top: 1px solid var(--line); }
.agCompor[hidden] { display: none; }
.agLabelPedido {
  display: block; font-family: var(--font-mono); font-size: 10px;
  letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3);
  margin-bottom: var(--e1);
}
.agPedidoCampo {
  width: 100%; background: var(--surface); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--r2);
  padding: var(--e2); font: inherit; text-transform: none; resize: vertical;
}
.agComporBotoes { display: flex; gap: var(--e2); margin-top: var(--e2); }
.agErroCompor { color: var(--prejuizo); margin: var(--e2) 0 0; }

.agExecs { list-style: none; margin: var(--e3) 0 0; padding: 0; }
.agExec { border-top: 1px solid var(--line); padding: var(--e3) 0; }
.agExecPendente { border-left: 3px solid var(--limite); padding-left: var(--e3); }
.agExecTopo { display: flex; gap: var(--e3); align-items: baseline; flex-wrap: wrap; }
.agExecQuando { font-family: var(--font-mono); font-size: 11px; color: var(--ink-2); }
.agExecEstado {
  font-family: var(--font-mono); font-size: 10px;
  letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3);
}
.agPedidoEco { color: var(--ink-2); margin: var(--e2) 0; }
.agErro { color: var(--prejuizo); margin: var(--e2) 0; }

.agVariacao { border: 1px solid var(--line); border-radius: var(--r2); padding: var(--e3); margin: var(--e2) 0; }
.agVariacao h5 { margin: 0 0 var(--e1); font-size: 15px; }
.agVariacao p { margin: 0 0 var(--e2); }
.agGancho {
  font-family: var(--font-mono); font-size: 10px;
  letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3);
}
.agCta { font-weight: 700; }
.agPrompt, .agJson {
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--r2);
  padding: var(--e2); overflow-x: auto; white-space: pre-wrap;
  font-family: var(--font-mono); font-size: 11.5px; color: var(--ink-2);
}

/* Esclarecimento é pergunta dirigida a você; aviso do parser é sinal de que
   algo foi barrado. Nenhum dos dois pode virar rodapé discreto. */
.agEsclarecimentos, .agAvisos {
  border-left: 3px solid var(--limite); padding: var(--e2) var(--e3);
  margin: var(--e2) 0; background: var(--surface);
}
.agEsclarecimentos ul, .agAvisos ul { margin: var(--e1) 0 0; padding-left: var(--e4); }
.agDecisao { display: flex; gap: var(--e2); margin-top: var(--e3); }

/* Contador de pendências: único do painel, e some quando zero. */
.navBadge {
  margin-left: var(--e2); padding: 1px var(--e2);
  border-radius: 999px; background: var(--limite); color: #10131c;
  font-family: var(--font-mono); font-size: 10px; font-weight: 700;
}
.navBadge[hidden] { display: none; }

/* ---------------------------- Organograma: leitura pura ------------------- */
.orgArvore { display: flex; flex-direction: column; align-items: center; gap: var(--e5); }
.orgCerebro {
  display: flex; flex-direction: column; align-items: center; gap: var(--e1);
  background: var(--surface); border: 1px solid var(--marca);
  border-radius: var(--r3); padding: var(--e3) var(--e5);
}
.orgCerebroTitulo { font-weight: 800; font-size: 18px; }
.orgAreas { display: flex; gap: var(--e5); flex-wrap: wrap; justify-content: center; width: 100%; }
.orgArea {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r3); padding: var(--e4); min-width: 260px;
}
.orgAreaTitulo {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--ink-3); margin: 0 0 var(--e3); text-align: center;
}
.orgAgentes { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--e2); }
.orgAgente {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: var(--e2);
  background: var(--bg); color: var(--ink); border: 1px solid var(--line);
  border-radius: var(--r2); padding: var(--e2) var(--e3); cursor: pointer;
  font: inherit; text-align: left;
}
.orgAgente:hover:not(:disabled) { border-color: var(--marca); }
.orgAgente:disabled { cursor: default; opacity: .5; }
.orgAgentePendente { border-color: var(--limite); }
.orgNome { font-weight: 600; }
.orgPend, .orgSelo {
  font-family: var(--font-mono); font-size: 10px;
  letter-spacing: .08em; text-transform: uppercase;
}
.orgPend { color: var(--limite); }
.orgSelo { color: var(--ink-3); }
.orgNota { text-align: center; margin-top: var(--e4); }

/* Rotulo do alvo quando a execucao tem mais de uma unidade aprovavel (o
   Otimizador tem uma acao de midia por alvo; Copywriter/Criativo tem uma so). */
.agAlvo {
  font-family: var(--font-mono); font-size: 10px;
  letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3);
  margin-right: var(--e2);
}

/* Resumo da cadeia diária, em Recomendações. Somente leitura: o único
   elemento clicável é um link que NAVEGA para "Agentes". */
.cadeiaNumeros { display: flex; gap: var(--e5); flex-wrap: wrap; margin-bottom: var(--e3); }
.cadeiaNumero { display: flex; flex-direction: column; gap: var(--e1); }
.cadeiaNumero .label {
  font-family: var(--font-mono); font-size: 10px;
  letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3);
}
.cadeiaNumero b { font-size: 26px; font-weight: 800; font-variant-numeric: tabular-nums; }
/* Pendência é status que espera a pessoa - faixa semântica de atenção. */
.cadeiaPendente b { color: var(--limite); }
.cadeiaFalhou { color: var(--prejuizo); }
.linkInline {
  background: none; border: none; padding: 0; font: inherit;
  color: var(--marca); cursor: pointer; text-decoration: underline;
}
.linkInline:hover { color: var(--marca-forte); }
