/* ---------- Design tokens ---------- */
:root {
  --color-bg: #f5f6f8;
  --color-surface: #ffffff;
  --color-border: #e1e4e8;
  --color-text: #1a1a1a;
  --color-text-muted: #616161;

  --color-primary: #0f6cbd;
  --color-primary-hover: #115ea3;

  /* Auditoria de UX (pós-U6) — estes cinco existiam SÓ no tema escuro.
     Enquanto o escuro era fixo em toda tela, ninguém notou: no claro eles
     ficavam indefinidos, e uma `var()` indefinida faz o navegador
     descartar a declaração inteira (uma borda vira `currentColor`, um
     brilho vira nada). Com o tema virando escolha da pessoa, o claro
     precisou deixar de ser um tema pela metade. */
  /* Ver theme-dark.css: o primário é cor de fundo (botão) E cor de texto
     (link). No claro os dois papéis cabem no mesmo tom; no escuro, não. */
  --color-primary-texto: #0f6cbd;
  /* Auditoria de contraste (pós-U6): #2b7fd4 dava 3.82:1 como texto sobre
     a superfície clara. Ele é usado como cor de texto de apoio na tela
     Sobre, então precisa passar o mínimo de leitura (agora 5.05:1). */
  --color-primary-2: #175a9c;
  /* Frente B (marca) — era `#d2691e` (laranja queimado). Usado só como
     borda decorativa na tela Sobre; passou a ciano para ficar na família
     da marca e parar de competir com `--color-warning`. */
  --color-accent: #0891b2;
  --color-surface-2: #f0f2f5;
  --shadow-glow-primary: 0 0 0 1px rgba(15, 108, 189, 0.35), 0 0 16px rgba(15, 108, 189, 0.15);
  --shadow-glow-success: 0 0 0 1px rgba(16, 124, 16, 0.35), 0 0 14px rgba(16, 124, 16, 0.14);

  /* Sprint UX-7 (ajuste fino) — cores de marca fixas, independentes de
     tema: usadas onde a identidade visual da plataforma precisa ser a
     mesma em toda página, dark ou light (sidebar, marca do topbar) —
     nunca `--color-primary`/`--color-accent`, que mudam com o tema (ou
     nem existem no tema light).

     Frente B (marca) — o par passou de roxo→laranja para índigo→ciano.
     O roxo/laranja vinha do ambiente do primeiro cliente e não era
     identidade própria; índigo e ciano são vizinhos no espectro, então o
     degradê deixa de atravessar o meio do círculo cromático (era o que
     produzia a faixa marrom no meio do gradiente em telas grandes). O
     laranja também disputava atenção com `--color-warning`, que é
     semântico — a marca não pode falar a língua de um estado. */
  --color-brand-1: #4f46e5;
  --color-brand-2: #06b6d4;
  /* Variante escura da marca, usada ATRÁS de texto branco (item ativo do
     menu, atalho de conteúdo, seletor de modo). Com o roxo ela existia
     por obrigação de contraste — o roxo anterior dava 4.23:1 e reprovava.
     Com o índigo ela deixa de ser obrigação (`--color-brand-1` dá 6.29:1)
     e passa a ser hierarquia: 9.93:1 separa o item ativo do resto do
     menu sem precisar de peso de fonte ou borda. */
  --color-brand-1-forte: #3730a3;
  /* A marca quando ela é TEXTO sobre a barra lateral escura — mesmo
     papel que `--color-primary-texto` cumpre para o primário. O índigo
     cheio dá 2.88:1 ali e some; estes dão 6.07:1 e 10.02:1. A barra
     lateral é escura nos dois temas, então estes dois valores servem
     aos dois. */
  --color-marca-texto-1: #818cf8;
  --color-marca-texto-2: #22d3ee;
  /* O mesmo degradê, mas sobre uma superfície que MUDA com o tema (o
     título da tela Sobre). Aqui, no claro: 6.29:1 e 5.36:1 — o ciano
     cheio daria 2.43:1 e sumiria no branco. O tema escuro sobrescreve. */
  --color-marca-titulo-1: #4f46e5;
  --color-marca-titulo-2: #0e7490;

  /* Ver `.btn--run`: o par de cor do botão de executar é declarado por
     tema, porque a mesma combinação não serve aos dois. */
  --color-run-bg: #0e6b0e;
  --color-run-text: #ffffff;

  /* No tema claro a barra é grafite azulado, não preto: o preto puro
     destoava da página clara. Rótulos de grupo em cinza liso e item ativo
     no azul dos botões, para a barra não competir com o conteúdo. O tema
     escuro devolve os valores anteriores (theme-dark.css). */
  --color-sidebar-bg: #283141;
  --color-sidebar-text: #dde1e7;
  --color-sidebar-rotulo-1: #aab3c2;
  --color-sidebar-rotulo-2: #aab3c2;
  --color-sidebar-ativo-bg: #0f6cbd;
  --color-sidebar-anel-1: #7a869a;
  --color-sidebar-anel-2: #7a869a;
  /* Auditoria de contraste (pós-U6): #7a7c85 dava 4.35:1 sobre o fundo da
     barra — logo abaixo do mínimo de leitura (4.5:1). É o cinza que nomeia
     os grupos do menu e as dicas de cada item, ou seja, exatamente o texto
     que orienta quem ainda não conhece a plataforma. Agora 5.83:1. */
  --color-sidebar-text-muted: #a3abb9;

  /* Auditoria de contraste (pós-U6): sobre o próprio fundo de estado,
     estes tons ficavam entre 4.18:1 e 4.69:1 — abaixo ou raspando o
     mínimo de leitura. São as cores que dizem "falhou", que é a
     informação que mais precisa ser lida numa tela cheia de linhas. */
  --color-success: #0e6b0e;
  --color-success-bg: #dff6dd;
  --color-error: #a4262c;
  --color-error-bg: #fde7e9;
  /* No claro, o vermelho é escuro e o par certo é texto branco (7.1:1). */
  --color-danger-bg: #a4262c;
  --color-danger-text: #ffffff;
  --color-warning: #7a5200;
  --color-warning-bg: #fff4ce;
  --color-info: #0f6cbd;
  --color-info-bg: #e5f2fb;

  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 14px;

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-8: 48px;

  --shadow-sm: 0 1px 2px rgba(20, 20, 20, 0.06);
  --shadow-md: 0 4px 14px rgba(20, 20, 20, 0.08);

  --font-sans: "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
  --font-mono: "Cascadia Code", ui-monospace, "SFMono-Regular", Consolas, monospace;

  /* Escala tipografica — decidida em docs/MODELO_VISUAL.md §1.1 (camada 2
     da skill `interface`) e trazida para o codigo aqui. Sao 6 tamanhos em
     7 papeis: 14px aparece duas vezes, mudando so o peso, porque "nome do
     item" e "texto corrido" tem o mesmo tamanho e hierarquias diferentes.

     O token nomeia o PAPEL, nunca o tamanho. `--fs-rotulo` continua sendo
     o rotulo mesmo que um dia ele deixe de ser 12px; `--fs-sm` obrigaria
     a reabrir cada uso para descobrir o que aquele texto e.

     Em rem, e nao px, porque o zoom de texto do navegador e o unico
     recurso de acessibilidade que nao depende de nos. Nada abaixo de
     0.75rem entra aqui: e o piso que `npm run audit:tokens` cobra. */
  --fs-metrica: 1.75rem;
  --fs-titulo-tela: 1.25rem;
  --fs-titulo-secao: 1rem;
  --fs-nome: 0.875rem;
  --fs-corpo: 0.875rem;
  --fs-apoio: 0.8125rem;
  --fs-rotulo: 0.75rem;

  --lh-metrica: 1.15;
  --lh-titulo: 1.3;
  --lh-nome: 1.4;
  --lh-corpo: 1.5;
  --lh-apoio: 1.45;

  --transition-fast: 150ms ease;
  --transition-base: 250ms cubic-bezier(0.4, 0, 0.2, 1);
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

/* ---------- Troca de tela sem corte seco ----------
 *
 * Cada tela da plataforma é um documento HTML próprio, e trocar de tela
 * é uma navegação de verdade — o navegador descarta uma página e pinta
 * outra. Entre as duas havia um corte: a tela antiga sumia, aparecia um
 * vazio, a nova entrava. Curto, mas visível toda vez.
 *
 * `navigation: auto` faz o navegador tirar uma foto da tela que sai,
 * outra da que entra, e dissolver uma na outra. É a mesma troca de
 * página de sempre — só deixa de ser um corte e passa a ser um
 * esmaecimento. Vale para as 26 telas de uma vez, porque a navegação é
 * entre documentos da mesma origem; nenhuma tela precisa declarar nada.
 *
 * A causa maior da piscada não era esta — eram 307 ms perdidos abrindo
 * a conexão, corrigidos em `app/backend/server.ts`. Esta regra é a
 * camada de cima: com a espera resolvida, ela é o que separa "rápido" de
 * "não dá para perceber".
 *
 * Onde não houver suporte, a regra é simplesmente ignorada e a
 * navegação continua como sempre foi — não há caminho a manter em pé
 * para os dois casos.
 */
@view-transition {
  navigation: auto;
}

/* O esmaecimento é curto de propósito: ele existe para esconder a troca,
   não para ser notado. Acima de ~200ms a transição deixa de disfarçar a
   navegação e passa a atrasá-la — que é o defeito oposto ao que ela
   veio corrigir. */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 140ms;
}

/* Quem pediu menos movimento ao sistema não recebe a dissolução. O
   bloco genérico acima zera `animation-duration` com `!important`, e
   isso já alcança os pseudo-elementos da transição — mas depender de um
   efeito colateral de uma regra escrita para outra coisa é frágil.
   Declarado aqui, é decisão. */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation: none !important;
  }
}

* {
  box-sizing: border-box;
}

/*
 * O atributo `hidden` precisa vencer QUALQUER `display` definido por
 * classe de autor — sem isso, uma regra como `.btn { display: inline-flex }`
 * empata em especificidade com o `[hidden] { display: none }` do
 * stylesheet do navegador, e o autor vence por ordem de cascata, fazendo
 * elementos "escondidos" continuarem visíveis (bug real encontrado nos
 * painéis de parâmetros/edição da Automações e nos botões de ação —
 * `hidden` era setado corretamente em JS mas não tinha efeito nenhum).
 * `hidden` é sempre uma instrução explícita de "não renderizar", nunca
 * deve perder para um seletor de classe.
 */
[hidden] {
  display: none !important;
}

/*
 * Perfil de interface — a segunda regra global de visibilidade, AO LADO
 * de `[hidden]` e nunca no lugar dela.
 *
 * `[hidden]` continua sendo o mecanismo de "não renderizar isto agora",
 * decidido por código de tela. Esta regra responde outra pergunta, que
 * nenhuma tela decide sozinha: **para quem esta tela está falando**. O
 * perfil vive num atributo do documento (`data-perfil`, escrito só por
 * density-boot.js/InterfaceDensity.js); cada trecho declara a que
 * audiência pertence (`data-densidade`).
 *
 * `!important` pelo mesmo motivo do `[hidden]`: sem ele, qualquer
 * `.classe { display: flex }` de autor empata em especificidade e vence
 * por ordem de cascata — um bloco técnico continuaria visível no modo
 * simples, que é a falha mais cara que este eixo pode ter.
 *
 * Um trecho sem `data-densidade` aparece nos dois modos. É o padrão, e
 * é o certo: marcar é a exceção deliberada, nunca a regra.
 */
[data-perfil="simples"] [data-densidade="tecnico"],
[data-perfil="tecnico"] [data-densidade="simples"] {
  display: none !important;
}

body {
  margin: 0;
  font-family: var(--font-sans);
  color: var(--color-text);
  background: var(--color-bg);
  font-size: 14px;
  line-height: 1.5;
}

h1, h2, h3 {
  margin: 0;
}

button {
  font-family: inherit;
}

/* ---------- App shell ---------- */

.app-shell {
  display: grid;
  grid-template-columns: 240px 1fr;
  min-height: 100vh;
  transition: grid-template-columns var(--transition-base);
}

/* Sprint UX-7 — colapso de sidebar (pedido explícito), viabilizado pela
   sidebar ter virado um componente único injetado por JS
   (`shared/Sidebar.js`) em vez de copiada por página — sem essa
   extração, esta classe teria que ser testada em ~10 lugares
   separadamente.

   Sprint UX-7 (ajuste fino 7) — achado real, confirmado pelo
   responsável do produto: a cada navegação, a sidebar nascia expandida
   (240px) e só recolhia depois que `shared/Sidebar.js` rodava
   (script deferred, executa depois do HTML inteiro parseado) —
   resultado: um "flash" de sidebar expandida animando para recolhida
   em toda troca de página, parecendo "abre e fecha". Corrigido com um
   script síncrono, primeiro filho do `<body>` (antes de qualquer
   outro script), que lê `localStorage` e marca `body.sidebar-collapsed`
   ANTES da primeira pintura — nenhuma transição chega a rodar porque o
   estado correto já existe desde o primeiro frame. `.sidebar-root`/
   `.sidebar__*` nem existem ainda nesse momento (só `shared/Sidebar.js`
   os cria depois), mas como é um seletor descendente de `body`, a
   regra passa a valer automaticamente assim que esses elementos forem
   inseridos — sem depender de ordem entre os dois scripts. */
body.sidebar-collapsed .app-shell {
  grid-template-columns: 64px 1fr;
}

.sidebar {
  background: var(--color-sidebar-bg);
  color: var(--color-sidebar-text);
  display: flex;
  flex-direction: column;
  /* Topo menor que a base: a primeira linha da marca precisa nascer na
     mesma altura do título da tela, à direita, e cada pixel de respiro
     aqui empurra a marca para baixo dele. Medido: 16px nos dois lados. */
  padding: var(--space-3) var(--space-3) var(--space-5);
  /* Sprint UX-7 — achado real da auditoria: sem `position: sticky`, a
     sidebar rolava junto com o conteúdo e sumia em qualquer tela com
     mais itens do que cabem numa viewport (Agendamentos, editor de
     Workflow com muitas etapas). `top: 0` + `max-height: 100vh` +
     `overflow-y: auto` prende a sidebar no topo da viewport durante
     toda a rolagem da página, com scroll próprio só se a navegação em
     si crescer além da tela — nunca depende de reescrever `.app-shell`
     como grid de altura fixa (ver DESIGN_SYSTEM.md §12). */
  position: sticky;
  top: 0;
  max-height: 100vh;
  overflow-y: auto;
}

/* ---------- Topo da barra lateral: marca, depois conta ----------
 *
 * A ordem é a hierarquia. Antes, o alto da barra era a foto do dono da
 * máquina e o nome dele, e a marca do produto ficava numa faixa
 * centralizada sobre o conteúdo — desconectada da navegação, ocupando
 * 40px de altura em toda tela para dizer o que a barra lateral deveria
 * estar dizendo. Numa reunião de hospital isso lê como ferramenta
 * pessoal, não como produto.
 *
 * Agora: a marca é a primeira coisa da barra, fixa em toda tela; o
 * avatar vem abaixo, menor, e significa "quem está usando" — o slot onde
 * entra o usuário autenticado quando houver autenticação. Enquanto não
 * houver, é um contorno: uma foto real seria a mesma para todo mundo que
 * abrisse o endereço, e diria de quem é o produto em vez de quem o opera.
 */
/* O lockup: ícone, sigla em destaque, descritor abaixo em corpo
   pequeno. A sigla é o nome do produto — é ela que alguém repete numa
   reunião —, e a linha de baixo diz o que ele é, não de quem ele é: o
   nome do autor sai da barra e fica só na tela Sobre, para que o
   produto não seja lido como ferramenta pessoal de alguém.

   `padding-top` menor que o dos lados de propósito: alinha a linha do
   `MIP` com a do título da tela, à direita. A marca e o título ficam na
   mesma altura, dizendo coisas diferentes — "em que sistema estou" e
   "onde estou". */
/* A marca é o caminho para a tela Sobre — é onde alguém clica para
   saber o que é o produto, e é o gesto que a web inteira já ensinou.
   Com ela cumprindo esse papel, a versão no rodapé voltou a ser só o
   número: dois links para a mesma tela na mesma coluna é escolha a mais
   sem decisão nova por trás. */
.sidebar__marca {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  padding: 0 var(--space-3) var(--space-3);
  text-decoration: none;
  border-radius: var(--radius-sm);
}

/* O alvo do clique se anuncia sem mover nada: o degradê é recortado no
   texto, então mudar cor no hover exigiria desligá-lo — o brilho de
   fundo diz a mesma coisa e mantém a marca intacta. */
.sidebar__marca:hover {
  background: rgba(255, 255, 255, 0.05);
}

.sidebar__marca:focus-visible {
  outline: 2px solid var(--color-marca-texto-2);
  outline-offset: 2px;
}

.sidebar__marca-logo {
  width: 30px;
  height: 30px;
  flex-shrink: 0;
  /* Encosta o ícone na linha de base da sigla, não no topo do bloco de
     duas linhas — senão ele flutua acima do texto. */
  margin-top: 1px;
}

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

/* Forte e permanente, sem virar título de tela: o título de uma tela é
   1.15rem/700, e a sigla fica abaixo disso em corpo — o peso e o
   espaçamento é que lhe dão presença. Quem responde "onde estou" é o
   título; a marca responde "em qual sistema estou", e não pode disputar
   essa leitura. */
.sidebar__marca-sigla {
  font-size: 1.02rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  line-height: 1.1;
  background: linear-gradient(100deg, var(--color-sidebar-rotulo-1), var(--color-sidebar-rotulo-2));
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}

/* O descritor também no degradê da marca, e não no cinza de apoio:
   ele é marca, não legenda. Em corpo pequeno o degradê continua legível
   porque os dois extremos são tons de texto (6.07:1 e 10.02:1 sobre a
   barra) — nunca o índigo e o ciano cheios, que servem de fundo.

   `overflow: hidden` não pode voltar aqui: com `background-clip: text` o
   recorte já é o próprio texto, e cortar a caixa apara a última letra do
   degradê. O descritor cabe na largura da barra — foi medido. */
.sidebar__marca-nome {
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.005em;
  line-height: 1.25;
  white-space: nowrap;
  background: linear-gradient(100deg, var(--color-sidebar-rotulo-1), var(--color-sidebar-rotulo-2));
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}

/* Separadores finos entre marca, conta e navegação. É a "separação
   visual leve" pedida: uma linha de 1px na própria cor da barra,
   clareada — nada de card, borda ou fundo, que engordariam a coluna. */
.sidebar__divisor {
  height: 1px;
  margin: 0 var(--space-3);
  background: rgba(255, 255, 255, 0.08);
  flex-shrink: 0;
}

.sidebar__conta {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3);
  margin-bottom: var(--space-2);
  min-width: 0;
}

/* Aro discreto de 1px nas cores da marca — o mesmo truque de duas
   camadas de `background` de antes (a de baixo, padding-box, pinta o
   miolo; a de cima, border-box, só aparece no anel), agora com anel
   fino: o avatar identifica quem está logado, não carrega a marca.

   Serve tanto ao contorno de hoje (um `<svg>`) quanto à foto de amanhã
   (um `<img>`) — o anel é do elemento, não do conteúdo. */
.sidebar__conta-avatar {
  display: block;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
  border: 1px solid transparent;
  background:
    linear-gradient(var(--color-sidebar-bg), var(--color-sidebar-bg)) padding-box,
    linear-gradient(135deg, var(--color-sidebar-anel-1), var(--color-sidebar-anel-2)) border-box;
}

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

.sidebar__conta-nome {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-sidebar-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  /* Vazias até /api/sessao responder, e com a altura de quando cheias: o
     bloco não pula quando o nome e o papel chegam (ADR-275). */
  min-height: 1.2em;
}

/* Sair e trocar a senha, à direita do nome (ADR-275). O texto ocupa o
   espaço que sobra, e o botão fica encostado na borda. */
.sidebar__conta-texto {
  flex: 1 1 auto;
}

.sidebar__conta-menu-btn {
  color: var(--color-sidebar-text-muted);
}

body.sidebar-collapsed .sidebar__conta-menu {
  display: none;
}

/* O papel de quem entrou, abaixo do nome (ADR-275). Altura do bloco
   inalterada: as duas linhas cabem nos 34px do avatar. */
.sidebar__conta-papel {
  font-size: var(--fs-rotulo);
  color: var(--color-sidebar-text-muted);
  min-height: 1.2em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sidebar__nav {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  /* Respiro entre o filete que fecha o bloco de conta e o primeiro
     rótulo de grupo. Sem ele, "OPERAÇÃO" encosta na linha e os dois
     viram uma coisa só — o filete deixa de separar e passa a sublinhar
     o rótulo errado. */
  padding-top: var(--space-3);
}

/* Sprint Navegação — grupos conceituais (Principal / Registro /
   Recursos / Sistema / Administração) em vez de lista plana de itens
   no mesmo nível. */
.sidebar__nav-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.sidebar__nav-group-label {
  padding: 0 var(--space-3);
  font-size: 0.66rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-sidebar-text-muted);
}

/*
 * Os nomes de seção no degradê da marca, para separá-los dos itens
 * clicáveis abaixo: com o mesmo cinza dos subitens, rótulo e item
 * disputavam a mesma leitura.
 *
 * O recorte é aplicado ao TEXTO, nunca ao contêiner. Dois dos três
 * grupos são `<button>` com o nome num `<span>` e o chevron num `<svg>`
 * ao lado — recortar o botão inteiro apaga os dois filhos, e foi
 * exatamente o que aconteceu na primeira tentativa: "CONSTRUÇÃO" e
 * "ADMINISTRAÇÃO" sumiram e sobraram as setas.
 */
span.sidebar__nav-group-label,
.sidebar__nav-group-toggle > span {
  background: linear-gradient(100deg, var(--color-sidebar-rotulo-1), var(--color-sidebar-rotulo-2));
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  width: fit-content;
}

body.sidebar-collapsed .sidebar__nav-group-label {
  display: none;
}

/* Sprint E6 — grupos secundários recolhíveis. Pedido do responsável do
   produto: o menu não deve nascer com tudo aberto e poluído. O cabeçalho
   do grupo vira um alvo clicável de largura inteira, com a seta girando
   para indicar o estado — nenhum controle novo a aprender. */
.sidebar__nav-group-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  background: none;
  border: 0;
  cursor: pointer;
  font: inherit;
  font-size: 0.66rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-sidebar-text-muted);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-sm);
  transition: color 120ms, background-color 120ms;
}

.sidebar__nav-group-toggle:hover {
  color: var(--color-sidebar-text);
  background: var(--color-sidebar-item-hover, rgba(255, 255, 255, 0.06));
}

.sidebar__nav-group-chevron {
  width: 14px;
  height: 14px;
  flex: none;
  transition: transform 140ms ease;
}

.sidebar__nav-group-toggle[aria-expanded="true"] .sidebar__nav-group-chevron {
  transform: rotate(90deg);
}

.sidebar__nav-group-items {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

/* Com a barra recolhida em ícones, esconder itens por grupo tiraria o
   acesso a telas inteiras sem nenhum rótulo para reabri-las — ali todos
   os itens continuam visíveis, como sempre. */
body.sidebar-collapsed .sidebar__nav-group-toggle {
  display: none;
}

body.sidebar-collapsed .sidebar__nav-group-items[hidden] {
  display: flex;
}

.sidebar__nav-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  color: var(--color-sidebar-text);
  text-decoration: none;
  font-size: 0.85rem;
  transition: background var(--transition-fast), color var(--transition-fast);
}

/* Só o grupo Principal é arrastável (ver Sidebar.js) — reusa
   `.drag-reorder__handle` (Sprint 56), só ajustando a cor para os
   tokens de texto da sidebar em vez dos tokens de conteúdo. */
/*
 * A alça de arrastar aparece no hover, não o tempo todo.
 *
 * Auditoria de arquitetura: ela ocupava ~20px de largura em TODOS os
 * itens, o tempo inteiro, para uma ação que quase ninguém faz — e era
 * justamente essa largura que faltava para "Inteligência Documental"
 * caber sem reticências. A função continua idêntica; o que muda é que
 * ela deixa de competir com o nome do item.
 *
 * `visibility` em vez de `display`, para o item não pular de posição
 * quando o mouse entra.
 */
.sidebar__drag-handle {
  color: var(--color-sidebar-text-muted);
  font-size: 0.8rem;
  width: 10px;
  margin-left: -6px;
  visibility: hidden;
}

.sidebar__nav-item:hover .sidebar__drag-handle,
.sidebar__drag-handle:focus-visible {
  visibility: visible;
}

.sidebar__drag-handle:hover {
  color: #fff;
}

body.sidebar-collapsed .sidebar__drag-handle {
  display: none;
}

.sidebar__nav-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

.sidebar__nav-label {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

body.sidebar-collapsed .sidebar__nav-label,
body.sidebar-collapsed .sidebar__marca-texto,
body.sidebar-collapsed .sidebar__conta-texto,
body.sidebar-collapsed .sidebar__conhecimento-label,
body.sidebar-collapsed .sidebar__versao {
  display: none;
}

body.sidebar-collapsed .sidebar__conhecimento {
  justify-content: center;
}

/* Recolhida, a coluna guarda só as duas silhuetas — o cubo e o avatar —
   uma sobre a outra, centradas. A ordem continua dizendo a mesma coisa
   que dizia expandida. */
body.sidebar-collapsed .sidebar__marca,
body.sidebar-collapsed .sidebar__conta {
  justify-content: center;
}

body.sidebar-collapsed .sidebar__nav-item,
body.sidebar-collapsed .sidebar__collapse-btn {
  justify-content: center;
}

body.sidebar-collapsed .sidebar__collapse-btn svg {
  transform: rotate(180deg);
}

.sidebar__nav-item:hover {
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
}

.sidebar__nav-item:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.sidebar__nav-item--active {
  /* Ver `--color-brand-1-forte`: o item ativo é o único do menu com texto
     branco sobre cor cheia, e no tema escuro o primário é o roxo da marca
     — o par caía para 4.23:1 justamente no item que diz onde a pessoa
     está. */
  background: var(--color-sidebar-ativo-bg);
  color: #fff;
}

.sidebar__nav-item--active:hover {
  background: var(--color-primary-hover);
}

.sidebar__nav-item--disabled {
  cursor: default;
  color: var(--color-sidebar-text-muted);
}

.sidebar__nav-item--disabled:hover {
  background: none;
  color: var(--color-sidebar-text-muted);
}

.sidebar__nav-item--disabled em {
  margin-left: auto;
  font-style: normal;
  font-size: 0.65rem;
  padding: 1px 6px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
}

.sidebar__collapse-btn {
  margin-top: auto;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  border: none;
  background: transparent;
  color: var(--color-sidebar-text-muted);
  font-size: 0.8rem;
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
}

.sidebar__collapse-btn:hover {
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
}

/*
 * "Recolher menu" no mesmo degradê dos nomes de seção: ele não é um
 * destino como os itens acima, é um comando sobre a própria barra — e
 * agora se lê como tal.
 *
 * No `<span>`, e não no botão, pelo mesmo motivo dos grupos: o botão
 * carrega o chevron ao lado, e recortar o contêiner apagaria os dois.
 * No hover a regra acima pinta o botão de branco; o `-webkit-text-fill`
 * do span venceria essa cor, então o degradê é desligado ali para o
 * hover continuar significando alguma coisa.
 */
.sidebar__collapse-btn > .sidebar__nav-label {
  background: linear-gradient(100deg, var(--color-sidebar-rotulo-1), var(--color-sidebar-rotulo-2));
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}

.sidebar__collapse-btn:hover > .sidebar__nav-label,
.sidebar__collapse-btn:focus-visible > .sidebar__nav-label {
  background: none;
  color: #fff;
  -webkit-text-fill-color: #fff;
}

.sidebar__collapse-btn svg {
  flex-shrink: 0;
  transition: transform var(--transition-fast);
}

.sidebar__footer {
  padding: var(--space-2) var(--space-2) 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

/* A Central de Conhecimento voltou a ter um lugar visível em toda tela,
   a pedido do responsável pelo projeto — mas no rodapé, ao lado da
   versão, e não como item de menu: é consulta, não trabalho. */
.sidebar__conhecimento {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) 0;
  font-size: 0.78rem;
  color: var(--color-sidebar-text);
  text-decoration: none;
}

.sidebar__conhecimento:hover,
.sidebar__conhecimento[aria-current="page"] {
  color: #fff;
}

.sidebar__versao {
  font-size: 0.7rem;
  color: var(--color-sidebar-text-muted);
}

/* ---------- Seletor de perfil de interface ----------
   Vive no rodapé do menu, e portanto em toda tela: a escolha de modo
   precisa ser desfazível de onde a pessoa estiver, não só de dentro de
   Configurações — uma preferência que só se troca numa tela específica
   é uma preferência que se troca uma vez e nunca mais. Cores próprias
   (e não `.segmented-control`) porque o fundo da barra lateral é fixo,
   independente do tema da página. */
.sidebar__perfil {
  padding: var(--space-2) var(--space-2) var(--space-1);
}

/* "MODO" é um nome de seção como "OPERAÇÃO" — segue a mesma regra, ou
   seria o único rótulo de seção em cinza numa barra em que todos os
   outros estão no degradê. */
.sidebar__perfil-label {
  display: block;
  font-size: 0.62rem;
  /* Mesmo peso de "OPERAÇÃO" e "CONSTRUÇÃO": num corpo deste tamanho, o
     degradê em peso normal deixa o traço fino demais para segurar duas
     cores, e o rótulo fica lavado. */
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin-bottom: var(--space-1);
  width: fit-content;
  background: linear-gradient(100deg, var(--color-sidebar-rotulo-1), var(--color-sidebar-rotulo-2));
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}

body.sidebar-collapsed .sidebar__perfil-label {
  display: none;
}

.perfil-switch {
  display: inline-flex;
  padding: 2px;
  border-radius: var(--radius-md);
  background: rgba(255, 255, 255, 0.06);
}

.perfil-switch__btn {
  font: inherit;
  font-size: 0.72rem;
  font-weight: 600;
  padding: 3px 10px;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-sidebar-text-muted);
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
}

.perfil-switch__btn:hover {
  color: #fff;
}

.perfil-switch__btn--ativo {
  background: var(--color-sidebar-ativo-bg);
  color: #fff;
}

.perfil-switch__btn:focus-visible {
  outline: 2px solid var(--color-brand-2);
  outline-offset: 1px;
}

/* Com o menu recolhido sobram 40px de conteúdo (64px de coluna menos o
   padding da barra): os dois rótulos empilham e encolhem, em vez de
   virarem iniciais — "S"/"T" seria críptico justamente para quem o modo
   simples atende. O clique continua inteiro nos dois estados. */
body.sidebar-collapsed .sidebar__perfil {
  padding-left: 0;
  padding-right: 0;
}

body.sidebar-collapsed .perfil-switch {
  flex-direction: column;
  width: 100%;
}

body.sidebar-collapsed .perfil-switch__btn {
  padding: 3px 2px;
  font-size: 0.58rem;
  overflow: hidden;
  white-space: nowrap;
}

/* Dentro de Configurações o seletor herda o tema da página, não o da
   barra lateral. */
.settings-section .perfil-switch {
  background: var(--color-surface-2);
  border: 1px solid var(--color-border);
}

.settings-section .perfil-switch__btn {
  color: var(--color-text-muted);
  font-size: 0.8rem;
  padding: 5px 16px;
}

.settings-section .perfil-switch__btn--ativo {
  background: var(--color-primary);
  color: #fff;
}

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

.topbar {
  /* Sprint 32 — achado real: `height` fixo (não `min-height`) quebrava
     o alinhamento vertical inteiro da barra quando o título da
     automação precisava de mais espaço do que cabia numa linha só (ex.:
     nome longo + os botões de ação do editor, que cresceram desde a
     Sprint 31) — o flexbox calculava uma "linha" mais alta que a caixa
     de 64px de fato renderizada, e os itens (inclusive botões) ficavam
     posicionados fora da área visível/clicável (`getBoundingClientRect().y`
     negativo, confirmado ao reproduzir). `min-height` deixa a barra
     crescer com segurança em vez de desalinhar por baixo dos panos. */
  min-height: 64px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 var(--space-6);
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  position: sticky;
  top: 0;
  z-index: 10;
}

/* A faixa de marca que ficava aqui (`.platform-bar`, Sprint UX-7) saiu.
   Ela nasceu para dar à marca um lugar próprio em toda tela, e cumpriu
   isso — mas ao preço de 40px de altura em 26 telas para repetir um
   nome desconectado da navegação, enquanto o alto da barra lateral era
   ocupado pela foto de uma pessoa. A marca foi para o topo da barra
   lateral (`.sidebar__marca`), que é onde a identidade de um produto
   fica, e a área de conteúdo passou a começar pelo título da tela. O
   link "Sobre" que morava no canto direito desta faixa virou a própria
   marca: ela é o alvo do clique para "o que é este produto". */

/* Subtítulo descritivo por tela (ex.: "Oracle, REST e SMTP..." em
   Conectores) — renomeado de `.topbar__brand` (Sprint UX-7) para não
   colidir com a marca persistente acima; eram dois conceitos diferentes
   competindo pelo mesmo nome de classe. */
.topbar__description {
  font-size: 0.82rem;
  color: var(--color-text-muted);
}

/* Papel: titulo de tela. */
.topbar__title {
  font-size: var(--fs-titulo-tela);
  font-weight: 600;
  line-height: var(--lh-titulo);
  /* Nunca quebra em várias linhas — trunca com reticências. Título
     completo continua disponível via `title` do próprio elemento (o
     navegador já mostra em tooltip nativo quando trunca). */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.content {
  padding: var(--space-5) var(--space-6);
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

/* ---------- Navegação em tela pequena (auditoria de UX pós-U6) ----------
   A regra que existia aqui era `.sidebar { display: none }`, escrita
   quando ninguém tinha aberto a plataforma num telefone: abaixo de 720px
   a interface ficava SEM NAVEGAÇÃO NENHUMA. Não era uma tela feia — era
   uma tela sem saída (medido pela auditoria da Sprint U6, em 375px).

   A barra lateral deixa de sumir e passa a deslizar por cima, com véu
   atrás e um botão de menu no cabeçalho da tela — ver MobileNav.js. */

.nav-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  margin-right: var(--space-2);
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: inherit;
  cursor: pointer;
}

.nav-toggle:hover {
  /* O botão saiu da barra escura de marca para o cabeçalho da tela, que
     acompanha o tema — um branco translúcido some no tema claro. */
  background: var(--color-surface-2);
}

.nav-toggle:focus-visible {
  outline: 2px solid var(--color-brand-2);
  outline-offset: 2px;
}

.nav-veu {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 190;
  background: rgba(0, 0, 0, 0.5);
}

/* O atalho para pular a navegação: invisível até receber foco, e o
   primeiro elemento tabulável da página. Sem ele, quem navega por
   teclado percorre os ~20 itens do menu a cada troca de tela. */
.skip-link {
  position: fixed;
  top: -100px;
  left: var(--space-3);
  z-index: 400;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-sm);
  background: var(--color-brand-1-forte);
  color: #fff;
  font-size: 0.85rem;
  font-weight: 600;
  text-decoration: none;
  transition: top var(--transition-fast);
}

.skip-link:focus {
  top: var(--space-3);
}

@media (max-width: 720px) {
  .app-shell {
    grid-template-columns: 1fr;
  }

  .nav-toggle {
    display: inline-flex;
  }

  .sidebar {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    width: 260px;
    max-height: 100vh;
    z-index: 200;
    transform: translateX(-100%);
    /* Fechada, a gaveta não recebe foco: ~20 itens de navegação fora da
       tela mas focáveis são piores do que gaveta nenhuma, porque o foco
       desaparece sem explicação para quem usa teclado ou leitor de tela. */
    visibility: hidden;
    transition: transform var(--transition-base), visibility var(--transition-base);
  }

  body.nav-aberta .sidebar {
    transform: none;
    visibility: visible;
  }

  body.nav-aberta .nav-veu {
    display: block;
  }

  /* Em tela pequena a gaveta é sempre larga: recolhê-la em ícones não
     economiza espaço nenhum, porque ela já não ocupa a coluna. */
  body.sidebar-collapsed .app-shell {
    grid-template-columns: 1fr;
  }

  body.sidebar-collapsed .sidebar {
    width: 260px;
  }

  body.sidebar-collapsed .sidebar__nav-label,
  body.sidebar-collapsed .sidebar__marca-texto,
  body.sidebar-collapsed .sidebar__conta-texto,
  body.sidebar-collapsed .sidebar__footer,
  body.sidebar-collapsed .sidebar__perfil-label {
    display: revert;
  }

  .content {
    padding: var(--space-4);
  }
}

/* ---------- Buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  border: none;
  border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-4);
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
  /* Um link com cara de botão (<a class="btn">) herdava o sublinhado. */
  text-decoration: none;
  transition: background var(--transition-fast), transform var(--transition-fast);
}

.btn:active {
  transform: scale(0.98);
}

.btn:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.btn--primary {
  background: var(--color-primary);
  color: #fff;
}

.btn--primary:hover {
  background: var(--color-primary-hover);
}

/* Identidade visual própria (verde), deliberadamente diferente de
   .btn--primary (ver DESIGN_SYSTEM.md) — usado por toda ação semântica
   de "Executar" na plataforma (Automações, Agendamentos, barra de
   lote). Movido para cá na Sprint UX-1: era duplicado só em
   automacoes.css, mas Agendamentos usava .btn--primary para a mesma
   ação, inconsistência não documentada encontrada na auditoria. */
/* Auditoria de contraste (pós-U6): o par era texto quase preto sobre
   `--color-success`. No tema escuro o verde é claro e o par dá 7.5:1; no
   claro o verde é escuro, e o mesmo par caía para 3.18:1 — escuro sobre
   escuro no botão mais importante da plataforma. Cada tema passa a ter o
   seu par, declarado junto. */
.btn--run {
  background: var(--color-run-bg);
  color: var(--color-run-text);
}

.btn--run svg {
  width: 14px;
  height: 14px;
}

.btn--run:hover {
  filter: brightness(1.08);
}

/* Variante compacta de qualquer `.btn` — consolidado aqui (Sprint
   UX-7, ajuste fino 3), antes só existia em workflow.css. */
.btn--small {
  padding: 4px 10px;
  font-size: 0.75rem;
}

/* Progressive disclosure genérico para formulários (Sprint UX-2) —
   mesmo padrão visual já usado pelo Builder (`step-edit__advanced`,
   Sprint 42) para separar campo essencial de campo técnico raramente
   ajustado, agora compartilhado por qualquer formulário da plataforma
   via <details>/<summary> nativos (sem JS extra). */
.form-advanced {
  margin-top: var(--space-1);
  padding-top: var(--space-2);
  border-top: 1px dashed var(--color-border);
  font-size: 0.8rem;
}

.form-advanced summary {
  cursor: pointer;
  user-select: none;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--color-text-muted);
}

.form-advanced[open] summary {
  margin-bottom: var(--space-2);
}

.form-advanced > *:not(summary) {
  margin-top: var(--space-2);
}

/* ---------- Modal (compartilhado — Sprint UX-3) ---------- */
/* Era duplicado byte-a-byte em agendamentos.css, arquivos.css,
   builder.css, conectores.css e workflow.css (achado da auditoria de
   UX). Consolidado aqui; cada página mantém só o que é genuinamente
   específico dela (ex.: `.modal__field textarea` com fonte monoespaçada
   em Agendamentos/Workflow). */
.modal {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.5);
}

/*
 * Botão desligado precisa parecer desligado.
 *
 * Achado em 2026-09-01, ao construir o Importador: `disabled` era
 * respeitado pelo navegador (o clique não acontecia) e invisível na
 * tela — o botão continuava azul, com cursor de mão. Quem lê a tela vê
 * uma ação disponível, clica, e nada acontece; a conclusão razoável é
 * que a plataforma travou.
 *
 * Vale para toda a fundação, e não só para o Importador: nenhuma tela
 * deve resolver isso por conta própria (DESIGN_SYSTEM §397).
 */
.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
}

.modal__panel {
  width: min(480px, calc(100vw - 48px));
  max-height: calc(100vh - 48px);
  overflow-y: auto;
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-md);
  padding: var(--space-5);
}

/* O painel largo, para o conteúdo que a pessoa lê enquanto ajusta: o relatório
   de importação de automação e o formulário de um estado do fluxo. A regra
   vivia só em workflow/workflow.css, e uma segunda tela precisando dela
   copiaria o componente em vez de usá-lo. */
.modal__panel--wide {
  width: min(720px, calc(100vw - 48px));
}

/* Variante para modais com mais campos (ex.: editor de etapa de
   Workflow, configurar automação) — consolidado aqui (Sprint UX-7,
   ajuste fino 3), antes só existia em workflow.css. */
.modal--wide .modal__panel {
  width: min(620px, calc(100vw - 48px));
}

.modal__title {
  margin: 0 0 var(--space-4);
  font-size: 1.1rem;
}

.modal__form {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.modal__field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 0.82rem;
  color: var(--color-text-muted);
}

.modal__field input,
.modal__field select,
.modal__field textarea {
  font: inherit;
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
  color: var(--color-text);
}

.modal__field--checkbox {
  flex-direction: row;
  align-items: center;
  gap: var(--space-2);
}

.modal__field--checkbox input {
  width: auto;
}

.modal__error {
  margin: 0;
  font-size: 0.8rem;
  color: var(--color-error);
  white-space: pre-wrap;
}

.modal__actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-3);
  margin-top: var(--space-2);
}

/* Card base (Sprint UX-3) — mesmas 8 propriedades visuais estavam
   duplicadas em `.automation-card`/`.builder-card`/`.schedule-card`/
   `.connector-card`. Cada página mantém só o que é genuinamente
   específico dela (transição de hover, cursor). Nomes de classe
   mantidos — zero mudança em JS/HTML, só a regra CSS base unificada. */
.automation-card,
.builder-card,
.schedule-card,
.connector-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-4);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}

/* Badge compacto (Sprint UX-3) — base idêntica que estava duplicada em
   agendamentos.css/builder.css/workflow.css (só a paleta de estados
   diverge por família, então fica em cada página). Nomes de classe
   mantidos (`schedule-status-badge`, `builder-status-badge`,
   `workflow-status-badge`) para não tocar em JS/HTML — só a regra CSS
   base foi unificada. Deliberadamente não fundido com `.status-badge`
   logo abaixo (usado por Cockpit/Automações/Histórico) — são dois
   estilos visuais diferentes (esse é maiúsculo/compacto, aquele tem
   ícone e caixa normal); fundir os dois seria redesenhar telas
   protegidas por Baseline, não só remover duplicação. */
.schedule-status-badge,
.builder-status-badge,
.workflow-status-badge {
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--color-surface-2);
  color: var(--color-text-muted);
}

/* ---------- Card menu "⋮" (Sprint UX-7) ----------
   Consolidado a partir de `.automation-card__menu-*` (única
   implementação existente até aqui) — nova base compartilhada para
   qualquer tela que precise do padrão "ação primária destacada + menu
   ⋮ para o resto" (Conectores, Workflows, Agendamentos). Automações
   mantém seus nomes de classe originais como alias, ver
   `automacoes.css`. */
.automation-card__menu-wrap,
.card-menu-wrap {
  position: relative;
  flex-shrink: 0;
}

.automation-card__menu-btn,
.card-menu-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-text-muted);
  cursor: pointer;
}

.automation-card__menu-btn:hover,
.automation-card__menu-btn[aria-expanded="true"],
.card-menu-btn:hover,
.card-menu-btn[aria-expanded="true"] {
  background: var(--color-surface-2);
  color: var(--color-text);
}

.automation-card__menu-btn svg,
.card-menu-btn svg {
  width: 16px;
  height: 16px;
}

.automation-card__menu,
.card-menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  z-index: 20;
  display: flex;
  flex-direction: column;
  min-width: 140px;
  padding: var(--space-1);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
}

.automation-card__menu-item,
.card-menu-item {
  display: block;
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: none;
  background: transparent;
  color: var(--color-text);
  font-size: 0.82rem;
  text-align: left;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.automation-card__menu-item:hover,
.card-menu-item:hover {
  background: var(--color-surface-2);
}

.automation-card__menu-item--danger,
.card-menu-item--danger {
  color: var(--color-error);
}

/* ---------- Segmented control (Sprint UX-7, ajuste fino 8) ----------
   Achado real: vivia em `shared/param-fields.css`, mas Builder/
   Conectores/Workflows não carregam esse arquivo — o toggle Cards/Lista
   dessas telas renderizava com o botão padrão do navegador (cinza
   claro, sem nada do nosso CSS aplicado). style.css é a única folha
   carregada por toda página, sem exceção — lar correto de qualquer
   componente verdadeiramente global (mesmo padrão de `.card-menu-*`
   acima). Usado pelo alternador "Cards | Lista" (toda tela de
   catálogo) e pelos toggles rápidos de execução (Fila/Paralelo,
   Interface/Headless). */
.segmented-control {
  display: inline-flex;
  padding: 2px;
  border-radius: var(--radius-md);
  background: var(--color-surface-2);
  border: 1px solid var(--color-border);
  flex-shrink: 0;
}

/* Papel: rotulo. */
.segmented-control__btn {
  font: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  padding: 5px 14px;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-text-muted);
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
}

.segmented-control__btn--active {
  background: var(--color-primary);
  color: #fff;
}

/* Variante compacta — cabe na linha de controles rápidos do card
   (Automações) e na barra de lote, onde o alternador Cards/Lista
   original (padding 5px/14px) ficaria grande demais. */
.segmented-control--quick .segmented-control__btn {
  padding: 3px 10px;
  font-size: 0.72rem;
}

/* ---------- Tag de tipo/categoria (Sprint UX-7, ajuste fino 8) ----------
   Consolida `.automation-card__category-badge`/`.builder-card__system-badge`/
   `.connector-card__kind-badge` (mesmas 8 propriedades, cinza neutro,
   repetidas em 3 arquivos) — pedido explícito: tag ganha uma corzinha
   (azul, `--color-info`) pra se diferenciar do status ao lado. Nomes de
   classe mantidos como alias, zero mudança de HTML/JS. */
.automation-card__category-badge,
.builder-card__system-badge,
.connector-card__kind-badge {
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--color-info);
  background: var(--color-info-bg);
  padding: 2px 9px;
  border-radius: 999px;
  white-space: nowrap;
}

/* ---------- Grid de itens (Sprint UX-7) ----------
   Consolida `automations-grid`/`connectors-grid`/`workflow-grid`/
   `schedule-grid` — mesma regra `repeat(auto-fill, minmax(...))`
   repetida 4x, variando só o mínimo de coluna. Nomes de classe mantidos
   por tela (zero mudança de HTML/JS); largura mínima ajustável via
   `--item-grid-min` quando uma tela precisar de um valor diferente do
   padrão. */
.automations-grid,
.connectors-grid,
.workflow-grid,
.schedule-grid,
.files-grid,
.item-grid {
  display: grid;
  /*
   * `min(…, 100%)` e não o valor cru: sem ele, a coluna mínima de 300px
   * continua valendo 300px numa janela de 390px COM a gaveta de
   * navegação por cima — e a grade fica mais larga que a tela, que é o
   * jeito clássico de a página inteira passar a rolar de lado no
   * telefone. Medido pela régua de contenção (`--estresse`): era o que
   * fazia seis telas rolarem 550px para o lado.
   */
  grid-template-columns: repeat(auto-fill, minmax(min(var(--item-grid-min, 300px), 100%), 1fr));
  gap: var(--space-4);
}

/* ---------- Empty state (Sprint UX-7) ----------
   Consolida `.automations-empty`/`.connectors-empty`/`.workflow-empty`/
   `.schedule-empty` (CSS quase idêntico repetido por tela). Nova classe
   genérica `.empty-state` para qualquer tela nova; as existentes
   ganham a mesma base sem precisar trocar de classe. */
.automations-empty,
.connectors-empty,
.workflow-empty,
.schedule-empty,
.empty-state {
  margin: 0;
  padding: var(--space-6) var(--space-4);
  text-align: center;
  color: var(--color-text-muted);
}

/* Papel: titulo de secao. */
.empty-state__title {
  margin: 0 0 var(--space-2);
  font-size: var(--fs-titulo-secao);
  font-weight: 600;
  line-height: var(--lh-nome);
  color: var(--color-text);
}

.empty-state__action {
  margin-top: var(--space-3);
}

/* ---------- Toolbar de catálogo (Sprint UX-7, ajuste fino 6) ----------
   Padrão único de "busca por nome + toggle Cards/Lista", pedido
   explícito para ser o mesmo em toda tela de catálogo (Automações,
   Conectores, Agendamentos, Workflows, Builder) — nunca um padrão por
   tela. `.catalog-search` generaliza `.automations-search` (única
   implementação existente até aqui). */
.catalog-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

.catalog-search {
  flex: 1 1 220px;
  min-width: 180px;
  font: inherit;
  font-size: 0.85rem;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
  color: var(--color-text);
}

.catalog-search:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 1px;
}

.catalog-toolbar .segmented-control {
  margin-left: auto;
}

/* ---------- Confirmação in-app (Sprint UX-7) ----------
   Consolidado a partir de 5 cópias idênticas (Automações, Workflows,
   Conectores, Builder, Arquivos) — `dashboard/ConfirmDialog.js` já era
   compartilhado, só o CSS estava duplicado por página. **Achado real**:
   Agendamentos usa `ConfirmDialog` (inclusive a nova confirmação de
   "Desativar", Sprint UX-7) mas nunca teve este CSS — o diálogo
   renderizava sem estilo nenhum nessa tela. Corrigido ao consolidar
   aqui: toda página que carrega `style.css` (todas) passa a ter o
   componente estilizado, sem precisar copiar de novo. */
.confirm-dialog {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.55);
}

.confirm-dialog__panel {
  width: min(420px, calc(100vw - 48px));
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  padding: var(--space-5);
}

.confirm-dialog__message {
  margin: 0 0 var(--space-4);
  color: var(--color-text);
  line-height: 1.5;
}

.confirm-dialog__actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-3);
}

/* ---------- Toast (Sprint UX-7) ----------
   Consolidado a partir de 4 cópias idênticas (Automações, Workflows,
   Builder, Agendamentos) — `dashboard/Toast.js` já era compartilhado,
   só o CSS estava duplicado por página. Conectores ganha o padrão pela
   primeira vez usando esta mesma base, sem precisar copiar de novo. */
.toast-stack {
  position: fixed;
  bottom: var(--space-5);
  right: var(--space-5);
  z-index: 80;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  max-width: min(360px, calc(100vw - 32px));
}

.toast {
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--color-border);
  box-shadow: var(--shadow-md);
  color: var(--color-text);
  font-size: 0.85rem;
  line-height: 1.4;
  cursor: pointer;
}

.toast--success {
  border-left-color: var(--color-success);
}

.toast--error {
  border-left-color: var(--color-error);
}

/* ---------- Status badge (compartilhado entre Cockpit e Automações) ---------- */

/* Papel: rotulo. */
.status-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-3);
  border-radius: 999px;
  font-size: var(--fs-rotulo);
  font-weight: 600;
  line-height: var(--lh-titulo);
  background: var(--color-border);
  color: var(--color-text-muted);
  white-space: nowrap;
  transition: background var(--transition-base), color var(--transition-base);
}

.status-badge__icon {
  width: 14px;
  height: 14px;
  display: inline-flex;
}

.status-badge__icon svg {
  width: 100%;
  height: 100%;
}

.status-badge--success {
  background: var(--color-success-bg);
  color: var(--color-success);
}

.status-badge--failure {
  background: var(--color-error-bg);
  color: var(--color-error);
}

.status-badge--running {
  background: var(--color-info-bg);
  color: var(--color-info);
  box-shadow: var(--shadow-glow-primary);
}

.status-badge--pending,
.status-badge--partial {
  background: var(--color-warning-bg);
  color: var(--color-warning);
}

.icon--spin {
  animation: spin 1s linear infinite;
}

@keyframes spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

/* ---------- Searchable select (Sprint 56 — melhora progressiva sobre <select>) ---------- */

.searchable-select {
  position: relative;
}

.searchable-select__input {
  width: 100%;
  font: inherit;
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
  color: var(--color-text);
}

.searchable-select__input:disabled {
  color: var(--color-text-muted);
  cursor: not-allowed;
}

.searchable-select__menu {
  position: absolute;
  z-index: 20;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  max-height: 220px;
  overflow-y: auto;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
  padding: var(--space-1);
}

.searchable-select__option {
  padding: var(--space-2);
  border-radius: var(--radius-sm);
  font-size: 0.85rem;
  cursor: pointer;
  color: var(--color-text);
}

.searchable-select__option:hover,
.searchable-select__option--active {
  background: var(--color-primary);
  color: #fff;
}

.searchable-select__empty {
  padding: var(--space-2);
  font-size: 0.85rem;
  color: var(--color-text-muted);
}

/* ---------- Drag reorder (Sprint 56 — mesmo padrão do Builder, Sprint 28 §16) ---------- */

.drag-reorder__handle {
  flex-shrink: 0;
  align-self: center;
  cursor: grab;
  color: var(--color-text-muted);
  font-size: 0.95rem;
  line-height: 1;
  user-select: none;
}

.drag-reorder__handle:hover {
  color: var(--color-text);
}

.drag-reorder--dragging {
  opacity: 0.5;
}

.drag-reorder--drop-target {
  border-color: var(--color-primary) !important;
  border-style: dashed !important;
}

/* ---------- Field picker (Sprint 56, Grupo F — "＋ campo") ---------- */

.field-picker {
  position: relative;
  display: inline-block;
}

.field-picker__trigger {
  font: inherit;
  font-size: 0.72rem;
  padding: 2px 8px;
  border: 1px dashed var(--color-border);
  border-radius: 999px;
  background: transparent;
  color: var(--color-text-muted);
  cursor: pointer;
}

.field-picker__trigger:hover {
  color: var(--color-primary-2);
  border-color: var(--color-primary-2);
}

.field-picker__menu {
  position: absolute;
  z-index: 20;
  top: calc(100% + 4px);
  left: 0;
  width: max(280px, 100%);
  max-height: 260px;
  display: flex;
  flex-direction: column;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
  padding: var(--space-1);
}

.field-picker__search {
  font: inherit;
  font-size: 0.8rem;
  padding: var(--space-2);
  margin-bottom: var(--space-1);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
  color: var(--color-text);
}

.field-picker__list {
  overflow-y: auto;
}

.field-picker__item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  width: 100%;
  padding: var(--space-2);
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.field-picker__item:hover {
  background: var(--color-primary);
}

.field-picker__item:hover .field-picker__item-path,
.field-picker__item:hover .field-picker__item-preview {
  color: #fff;
}

.field-picker__item-path {
  font-family: "Consolas", "Menlo", monospace;
  font-size: 0.78rem;
  color: var(--color-text);
}

.field-picker__item-preview {
  font-size: 0.72rem;
  color: var(--color-text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

.field-picker__empty {
  margin: 0;
  padding: var(--space-2);
  font-size: 0.8rem;
  color: var(--color-text-muted);
}


/* Sprint P1 — aviso visível quando MALACA_API_TOKEN não está
   configurado (ver shared/Sidebar.js). Bloco normal no topo do body,
   nunca fixed/sticky — evita conflito com o sidebar sticky, que já
   ancora em top:0 do viewport. */
.security-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-4);
  background: var(--color-warning-bg);
  color: var(--color-warning);
  font-size: 0.85rem;
  border-bottom: 1px solid var(--color-warning);
}

/* Sprint P1 — variante informativa: não ter IA configurada é uma escolha
   válida de instalação, não um problema de segurança. Mesmo componente,
   cor diferente — nunca um segundo banner com CSS próprio. */
.security-banner--info {
  background: var(--color-info-bg);
  color: var(--color-info);
  border-bottom-color: var(--color-info);
}

.security-banner code {
  background: rgba(0, 0, 0, 0.08);
  padding: 0.1em 0.4em;
  border-radius: 4px;
}

/* Botão de IA sem conector configurado (ver shared/systemStatus.js) —
   continua visível, para o recurso não sumir sem explicação, mas
   inoperante e com o motivo no title. */
[data-ai-unavailable] {
  opacity: 0.5;
  cursor: not-allowed;
}

.security-banner__link {
  color: inherit;
  font-weight: 700;
  text-decoration: underline;
  white-space: nowrap;
}

.security-banner__dismiss {
  flex: none;
  border: none;
  background: transparent;
  color: inherit;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  padding: var(--space-1);
}

/* Sprint P3 — assistente estruturado (ver shared/AssistantPanel.js). */
/* z-index 90 — acima de modais (50) e toasts (80): o assistente deve
   continuar acessível mesmo quando um modal está aberto. */
.assistant-toggle {
  position: fixed;
  right: var(--space-4);
  bottom: var(--space-4);
  z-index: 90;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 10px 16px;
  border-radius: 999px;
  border: none;
  background: var(--color-primary);
  color: #fff;
  font-weight: 600;
  font-size: 0.85rem;
  cursor: pointer;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.18);
}

.assistant-toggle:hover {
  background: var(--color-primary-hover);
}

/* Um ícone por estado, no mesmo botão e no mesmo lugar: a interrogação
   quando a ajuda está fechada, o X quando está aberta. Trocar o ícone
   (e não só o texto) é o que faz o botão ser lido como "a saída" de
   relance, sem mover a âncora — a referência espacial de quem está
   usando continua sendo o canto inferior direito. */
.assistant-toggle__icone--fechar {
  display: none;
}

.assistant-toggle--aberto .assistant-toggle__icone--ajuda {
  display: none;
}

.assistant-toggle--aberto .assistant-toggle__icone--fechar {
  display: block;
}

.assistant-panel {
  position: fixed;
  right: var(--space-4);
  top: 110px;
  bottom: calc(var(--space-4) + 52px);
  z-index: 90;
  width: min(380px, calc(100vw - 2 * var(--space-4)));
  display: flex;
  flex-direction: column;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg, 12px);
  box-shadow: 0 12px 36px rgba(0, 0, 0, 0.22);
  overflow: hidden;
}

.assistant-panel__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-3) var(--space-4);
  font-weight: 700;
  background: var(--color-primary);
  color: #fff;
  border-bottom: 1px solid var(--color-border);
  flex-shrink: 0;
}

.assistant-panel__close {
  border: none;
  background: transparent;
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
  color: rgba(255, 255, 255, 0.8);
}

/* Sprint E13 — regra MALACA AGENT/MALACA AI sempre visível, sem
   depender de hover (achado do responsável do produto: "hoje só fica
   claro se colocar o mouse em cima"). Ver AssistantPanel.js renderStatus(). */
.assistant-panel__status {
  margin: 0;
  padding: var(--space-2) var(--space-4);
  font-size: 0.72rem;
  line-height: 1.5;
  color: var(--color-text-muted);
  background: var(--color-bg);
  border-bottom: 1px solid var(--color-border);
  flex-shrink: 0;
}

.assistant-panel__status strong {
  color: var(--color-text);
}

.assistant-panel__status--warning {
  color: var(--color-warning);
  background: var(--color-warning-bg);
}

.assistant-panel__status-link {
  border: none;
  background: transparent;
  color: var(--color-primary-texto);
  font-size: 0.72rem;
  font-weight: 600;
  text-decoration: underline;
  cursor: pointer;
  padding: 0;
}

.assistant-panel__body {
  padding: var(--space-3) var(--space-4);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

/* Sprint E13 — fio de conversa: cada pergunta some no fio junto com a
   resposta, em vez de a resposta seguinte apagar a anterior. Ver
   AssistantPanel.js (`turns`, `renderThread`). */
.assistant-panel__thread {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.assistant-panel__turn {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.assistant-panel__turn + .assistant-panel__turn {
  padding-top: var(--space-3);
  border-top: 1px dashed var(--color-border);
}

.assistant-panel__turn-question {
  align-self: flex-end;
  max-width: 88%;
  margin: 0;
  padding: 6px 12px;
  border-radius: var(--radius-lg, 12px) var(--radius-lg, 12px) 2px var(--radius-lg, 12px);
  background: var(--color-primary);
  color: #fff;
  font-size: 0.82rem;
  line-height: 1.4;
  overflow-wrap: anywhere;
}

.assistant-panel__related {
  margin-top: var(--space-1);
}

.assistant-panel__hint {
  font-size: 0.78rem;
  color: var(--color-text-muted);
  margin: 0;
}

.assistant-panel__suggestions {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-height: 260px;
  overflow-y: auto;
}

/* Sprint Assist-Fix — a resposta agora vem sempre antes das sugestões
   no HTML; este botão substitui a lista quando ela está recolhida
   (depois de uma pergunta ser respondida), para a lista longa nunca
   mais empurrar a resposta para fora da vista. */
.assistant-panel__suggestions-toggle {
  align-self: flex-start;
  font-size: 0.78rem;
  color: var(--color-primary-texto);
  background: transparent;
  border: none;
  cursor: pointer;
  padding: 4px 0;
  text-decoration: underline;
}

.assistant-panel__suggestions button {
  width: 100%;
  text-align: left;
  padding: 8px 10px;
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
  background: var(--color-bg);
  color: var(--color-text);
  font-size: 0.82rem;
  cursor: pointer;
}

.assistant-panel__suggestions button:hover {
  border-color: var(--color-primary-texto);
}

.assistant-panel__form {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: var(--space-1);
}

/* ─── Sprint Onboarding-Data — exemplos educativos ──────────────────────────── */

/* Badge "Exemplo" sobreposto ao card */
.example-badge {
  display: inline-flex;
  align-items: center;
  padding: 2px 7px;
  border-radius: var(--radius-sm, 4px);
  border: 1px solid color-mix(in srgb, var(--color-primary) 35%, transparent);
  background: color-mix(in srgb, var(--color-primary) 10%, transparent);
  color: var(--color-primary-texto);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  pointer-events: none;
  flex-shrink: 0;
}

/* Linha com conteúdo + botão hint alinhados */
.example-hint-row {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1, 4px);
  flex-wrap: wrap;
}

/* Botão "?" de dica */
.hint-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 1px solid var(--color-muted, #888);
  background: none;
  color: var(--color-muted, #888);
  font-size: 10px;
  font-weight: 700;
  font-style: normal;
  line-height: 1;
  cursor: pointer;
  flex-shrink: 0;
  transition: border-color 0.15s, color 0.15s;
  padding: 0;
}
.hint-btn:hover {
  border-color: var(--color-primary-texto);
  color: var(--color-primary-texto);
}

/* Sprint U6 (auditoria de paridade de interface) — achado da própria
   auditoria: este botão zerava o contorno de foco e trocava por uma
   mudança de cor de borda. Para quem navega por teclado, "a borda ficou
   roxa" num botão de 20px é indistinguível de nada — o contorno é o
   único indicador que sobrevive a qualquer tema e a qualquer tamanho. */
.hint-btn:focus-visible {
  border-color: var(--color-primary-texto);
  color: var(--color-primary-texto);
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/* Popover de dica */
.hint-popover {
  position: fixed;
  z-index: 300;
  width: 280px;
  background: var(--color-surface);
  border: 1px solid var(--color-primary);
  border-radius: var(--radius);
  padding: var(--space-3, 12px);
  font-size: var(--fs-apoio);
  line-height: 1.5;
  color: var(--color-primary-texto);
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.18);
  pointer-events: none;
}

/* Nota de rodapé da grade de exemplos */
.example-grid-hint {
  grid-column: 1 / -1;
  text-align: center;
  font-size: var(--fs-apoio);
  color: var(--color-text-muted);
  padding: var(--space-4) var(--space-2);
  border-top: 1px solid var(--color-border);
  margin-top: var(--space-2);
}

/* Grade wrapper dos exemplos de automações */
.automation-examples-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--space-4);
  width: 100%;
}

/* Overlay do painel de detalhes do exemplo */
.example-detail-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
}

.example-detail {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg, 8px);
  width: 100%;
  max-width: 480px;
  max-height: 85vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.25);
}

.example-detail .modal__header {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--color-border);
}

.example-detail .modal__body {
  padding: var(--space-4) var(--space-5);
  flex: 1;
}

.example-detail .modal__footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--color-border);
}

.example-detail__intro {
  font-size: var(--fs-apoio);
  color: var(--color-text-muted);
  margin-bottom: var(--space-4);
  line-height: 1.6;
}

.example-detail__fields {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-1) var(--space-4);
  font-size: var(--fs-apoio);
  margin: 0;
}

.example-detail__fields dt {
  color: var(--color-text-muted);
  font-weight: 600;
  white-space: nowrap;
  padding: var(--space-1) 0;
}

.example-detail__fields dd {
  margin: 0;
  padding: var(--space-1) 0;
  color: var(--color-text);
  border-bottom: 1px solid var(--color-border);
}

.example-detail__fields dd:last-child,
.example-detail__fields dt:last-of-type {
  border-bottom: none;
}

.example-detail__note {
  color: var(--color-text-muted);
  font-size: 11px;
}

/* ---------- Simulação de execução em exemplos (ExampleCards.js) ---------- */

.example-sim__intro {
  color: var(--color-text-muted);
}

.example-sim {
  list-style: none;
  margin: var(--space-3) 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.example-sim__step {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 0.875rem;
  color: var(--color-text-muted);
  transition: color var(--transition-base);
}

.example-sim__step--done {
  color: var(--color-text);
}

.example-sim__icon {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  font-size: 0.75rem;
  background: var(--color-border);
  color: var(--color-text-muted);
}

.example-sim__icon--running {
  background: var(--color-info-bg);
  color: var(--color-info);
  box-shadow: var(--shadow-glow-primary);
}

.example-sim__icon--running {
  animation: spin 1s linear infinite;
}

.example-sim__icon--success {
  background: var(--color-success-bg);
  color: var(--color-success);
}

.example-sim__icon--failure {
  background: var(--color-error-bg);
  color: var(--color-error);
}

.example-sim__result {
  margin-top: var(--space-3);
  padding: var(--space-3);
  border-radius: var(--radius-md);
  border-left: 3px solid var(--color-border);
}

.example-sim__result--success {
  border-left-color: var(--color-success);
  background: var(--color-success-bg);
}

.example-sim__result--failure {
  border-left-color: var(--color-error);
  background: var(--color-error-bg);
}

.example-sim__result p {
  margin: var(--space-1) 0 0;
  color: var(--color-text-muted);
  font-size: 0.875rem;
}

/*
 * O par de cor do botão destrutivo é declarado por TEMA, pelo mesmo
 * motivo do `.btn--run`: a mesma combinação não serve aos dois.
 *
 * Achado da página viva do Design System, e ele só apareceu porque ela
 * existe: no tema escuro `--color-error` é um vermelho CLARO (#f87171,
 * escolhido para ser legível como texto), e texto branco sobre ele dava
 * **2.77:1** — bem abaixo do mínimo de leitura. Nenhuma régua tinha
 * pego porque nenhuma tela mostrava esse botão num estado visível: ele
 * vive dentro de menu e de diálogo.
 */
.btn--danger {
  background: var(--color-danger-bg, var(--color-error));
  color: var(--color-danger-text, #fff);
  border: none;
}
.btn--danger:hover {
  background: color-mix(in srgb, var(--color-error) 85%, black);
}

.assistant-panel__form textarea {
  width: 100%;
  padding: 8px 10px;
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
  font-size: 0.85rem;
  font-family: inherit;
  background: var(--color-bg);
  color: var(--color-text);
  resize: none;
  min-height: 88px;
  line-height: 1.5;
  box-sizing: border-box;
}

/* Ver o comentário de .hint-btn:focus-visible — mesmo achado, mesma
   correção: a borda mudando de cor não substitui o contorno de foco. */
.assistant-panel__form textarea:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 1px;
  border-color: var(--color-primary-texto);
}

.assistant-panel__form button {
  align-self: flex-end;
  padding: 8px 16px;
  border-radius: var(--radius-md);
  border: none;
  background: var(--color-primary);
  color: #fff;
  font-size: 0.82rem;
  cursor: pointer;
}

.assistant-panel__loading {
  font-size: 0.82rem;
  color: var(--color-text-muted);
}

.assistant-panel__answer {
  font-size: 0.86rem;
  line-height: 1.5;
  background: var(--color-info-bg);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
}

.assistant-panel__answer code {
  background: rgba(0, 0, 0, 0.12);
  padding: 0.1em 0.4em;
  border-radius: 4px;
  font-size: 0.92em;
}

.assistant-panel__answer--none {
  background: var(--color-warning-bg);
  color: var(--color-warning);
}

.assistant-panel__answer-lede {
  font-size: 0.82rem;
  color: var(--color-text-muted);
  margin: 0;
}

.assistant-panel__results {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.assistant-panel__result {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 8px 10px;
}

.assistant-panel__result a {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-primary-texto);
}

.assistant-panel__result p {
  margin: 4px 0 0;
  font-size: 0.78rem;
  color: var(--color-text-muted);
}

.assistant-panel__feedback {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.8rem;
  color: var(--color-text-muted);
}

.assistant-panel__feedback button {
  padding: 4px 10px;
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
  background: var(--color-bg);
  color: var(--color-text);
  cursor: pointer;
  font-size: 0.78rem;
}

/* Sprint Widget-KB — navegação hierárquica por tópico. */
.assistant-panel__breadcrumb {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0 0 var(--space-2);
  border-bottom: 1px solid var(--color-border);
  margin-bottom: var(--space-1);
}

.assistant-panel__back {
  border: none;
  background: transparent;
  color: var(--color-primary-texto);
  font-size: 0.8rem;
  font-weight: 600;
  cursor: pointer;
  padding: 0;
  white-space: nowrap;
}

.assistant-panel__back:hover {
  text-decoration: underline;
}

.assistant-panel__breadcrumb span {
  font-size: 0.78rem;
  color: var(--color-text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.assistant-panel__suggestion-topic {
  width: 100%;
  text-align: left;
  padding: 9px 10px;
  border-radius: var(--radius-md);
  border: 1px solid var(--color-primary);
  background: var(--color-bg);
  color: var(--color-primary-texto);
  font-size: 0.82rem;
  font-weight: 600;
  cursor: pointer;
}

.assistant-panel__suggestion-topic:hover {
  background: var(--color-info-bg);
}

.assistant-panel__doc-link {
  display: inline-block;
  margin-top: var(--space-2);
  font-size: 0.78rem;
  color: var(--color-primary-texto);
  text-decoration: none;
  font-weight: 500;
}

.assistant-panel__doc-link:hover {
  text-decoration: underline;
}

.assistant-panel__topic-page-link {
  list-style: none;
  padding: 0 0 var(--space-1);
}

/* Sprint P4 — escalonamento do assistente para IA (ver AssistantPanel.js). */
.assistant-panel__escalate {
  align-self: flex-start;
  padding: 6px 12px;
  border-radius: var(--radius-md);
  border: 1px solid var(--color-primary);
  background: transparent;
  color: var(--color-primary-texto);
  font-size: 0.8rem;
  font-weight: 600;
  cursor: pointer;
}

.assistant-panel__escalate:hover {
  background: var(--color-info-bg);
}

.assistant-panel__answer--ai {
  background: var(--color-success-bg);
}

/* Sprint Error-Reporting — botão de relato no rodapé do painel de ajuda */
.assistant-panel__footer {
  margin-top: var(--space-4);
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-border);
}

.assistant-panel__report-btn {
  width: 100%;
  background: transparent;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 6px var(--space-3);
  font-size: 0.78rem;
  color: var(--color-text-muted);
  cursor: pointer;
  text-align: center;
  transition: background var(--transition-fast), color var(--transition-fast);
}

.assistant-panel__report-btn:hover {
  background: var(--color-error-bg);
  color: var(--color-error);
  border-color: var(--color-error);
}

/* Botão ghost — variante secundária (Sprint Error-Reporting) */
.btn--ghost {
  background: transparent;
  color: var(--color-text-muted);
  border: 1px solid var(--color-border);
}

.btn--ghost:hover {
  background: var(--color-bg);
}

/* ---- Overlays genéricos de erros (modais) ---- */
.error-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2000;
  padding: var(--space-4);
}

.error-modal {
  background: var(--color-surface);
  color: var(--color-text);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  width: 100%;
  max-width: 520px;
  max-height: 90vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}

.error-modal__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--color-border);
  font-weight: 600;
  font-size: 0.95rem;
}

.error-modal__close {
  background: none;
  border: none;
  font-size: 1.3rem;
  line-height: 1;
  cursor: pointer;
  color: var(--color-text-muted);
  padding: 2px 6px;
  border-radius: var(--radius-sm);
}

.error-modal__close:hover {
  background: var(--color-bg);
  color: var(--color-text);
}

.error-modal__body {
  padding: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.error-modal__lead {
  margin: 0;
  font-size: 0.9rem;
  color: var(--color-text-muted);
}

.error-modal__footer {
  display: flex;
  gap: var(--space-3);
  justify-content: flex-end;
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--color-border);
}

/* Botões de escolha: IA vs. direto */
.error-choice-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3);
}

.error-choice-btn {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-1);
  padding: var(--space-4);
  background: var(--color-bg);
  color: var(--color-text);
  border: 2px solid var(--color-border);
  border-radius: var(--radius-md);
  cursor: pointer;
  text-align: left;
  font: inherit;
  transition: border-color var(--transition-fast), background var(--transition-fast);
}

.error-choice-btn:hover {
  border-color: var(--color-primary-texto);
  background: var(--color-info-bg);
}

.error-choice-btn--primary {
  border-color: var(--color-primary-texto);
  background: var(--color-info-bg);
}

.error-choice-btn__icon {
  opacity: 0.7;
}

.error-choice-btn__label {
  font-weight: 600;
  font-size: 0.88rem;
}

.error-choice-btn__hint {
  font-size: 0.75rem;
  color: var(--color-text-muted);
  line-height: 1.4;
}

/* Formulário de descrição */
.error-form__label {
  font-size: 0.85rem;
  font-weight: 500;
  display: block;
  margin-bottom: var(--space-2);
}

.error-form__textarea {
  width: 100%;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: var(--space-3);
  font-size: 0.88rem;
  font-family: inherit;
  resize: vertical;
  background: var(--color-bg);
  color: var(--color-text);
  box-sizing: border-box;
}

.error-form__textarea:focus {
  outline: 2px solid var(--color-primary);
  outline-offset: 1px;
}

.error-form__ai-block {
  background: var(--color-info-bg);
  border-left: 3px solid var(--color-primary);
  border-radius: var(--radius-sm);
  padding: var(--space-3) var(--space-4);
}

.error-form__ai-label {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-primary-texto);
  margin: 0 0 var(--space-1);
}

.error-form__ai-text {
  font-size: 0.85rem;
  color: var(--color-text);
  margin: 0;
  white-space: pre-wrap;
}

.error-form__screen-info {
  font-size: 0.78rem;
  color: var(--color-text-muted);
  margin: 0;
}

.error-form__submit-error {
  font-size: 0.82rem;
  color: var(--color-error);
  margin: 0;
}

/* Tela de sucesso */
.error-success {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  text-align: center;
  padding: var(--space-2) 0;
}

.error-success__icon {
  opacity: 0.9;
}

.error-success__msg {
  font-size: 0.95rem;
  font-weight: 500;
  margin: 0;
}

.error-success__id-box {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-4);
}

.error-success__id-label {
  font-size: 0.78rem;
  color: var(--color-text-muted);
}

.error-success__id-value {
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--color-text);
}

.error-success__hint {
  font-size: 0.78rem;
  color: var(--color-text-muted);
  margin: 0;
}

/* ---- Diálogo de diagnóstico por IA ---- */
.diagnosis-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  display: flex;
  align-items: stretch;
  justify-content: center;
  z-index: 2100;
}

.diagnosis-dialog {
  background: var(--color-surface);
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 640px;
  height: 100%;
}

.diagnosis-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--color-border);
  flex-shrink: 0;
}

.diagnosis-title {
  font-weight: 600;
  font-size: 0.95rem;
}

.diagnosis-skip {
  background: none;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 4px var(--space-3);
  font-size: 0.78rem;
  color: var(--color-text-muted);
  cursor: pointer;
}

.diagnosis-skip:hover {
  background: var(--color-bg);
  color: var(--color-text);
}

.diagnosis-chat {
  flex: 1;
  overflow-y: auto;
  padding: var(--space-4) var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.diagnosis-msg {
  display: flex;
}

.diagnosis-msg--user {
  justify-content: flex-end;
}

.diagnosis-msg--ai {
  justify-content: flex-start;
}

.diagnosis-msg__bubble {
  max-width: 80%;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  font-size: 0.88rem;
  line-height: 1.5;
}

.diagnosis-msg--ai .diagnosis-msg__bubble {
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-bottom-left-radius: 4px;
}

.diagnosis-msg--user .diagnosis-msg__bubble {
  background: var(--color-primary);
  color: #fff;
  border-bottom-right-radius: 4px;
}

/* Indicador de carregamento — três pontos animados */
.diagnosis-msg__bubble--loading {
  display: flex;
  gap: 4px;
  align-items: center;
  padding: var(--space-3) var(--space-4);
}

.diagnosis-msg__bubble--loading span {
  width: 7px;
  height: 7px;
  background: var(--color-text-muted);
  border-radius: 50%;
  animation: diag-dot-bounce 1.2s ease-in-out infinite;
}

.diagnosis-msg__bubble--loading span:nth-child(2) { animation-delay: 0.2s; }
.diagnosis-msg__bubble--loading span:nth-child(3) { animation-delay: 0.4s; }

@keyframes diag-dot-bounce {
  0%, 80%, 100% { transform: translateY(0); opacity: 0.4; }
  40% { transform: translateY(-5px); opacity: 1; }
}

/* Card de diagnóstico concluído */
.diagnosis-done-card {
  margin: var(--space-3) var(--space-5) var(--space-4);
  padding: var(--space-4);
  background: var(--color-success-bg);
  border: 1px solid var(--color-success);
  border-radius: var(--radius-md);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  flex-shrink: 0;
}

.diagnosis-done__label {
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-success);
  margin: 0;
}

.diagnosis-done__summary {
  font-size: 0.88rem;
  color: var(--color-text);
  margin: 0;
  white-space: pre-wrap;
}

.diagnosis-done__actions {
  display: flex;
  gap: var(--space-3);
}

/* Área de input do diálogo */
.diagnosis-input-area {
  display: flex;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-5) var(--space-4);
  border-top: 1px solid var(--color-border);
  flex-shrink: 0;
}

.diagnosis-input {
  flex: 1;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-3);
  font-size: 0.88rem;
  font-family: inherit;
  resize: none;
  background: var(--color-bg);
  color: var(--color-text);
}

.diagnosis-input:focus {
  outline: 2px solid var(--color-primary);
  outline-offset: 1px;
}

.diagnosis-send {
  align-self: flex-end;
  padding: var(--space-2) var(--space-4);
  background: var(--color-primary);
  color: #fff;
  border: none;
  border-radius: var(--radius-sm);
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}

.diagnosis-send:hover { background: var(--color-primary-hover); }
.diagnosis-send:disabled { opacity: 0.5; cursor: not-allowed; }

/* ---- Gate de administrador (Telemetria) ---- */
.admin-gate {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-6);
}

.admin-gate__card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  max-width: 420px;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
  text-align: center;
  box-shadow: var(--shadow-md);
}

.admin-gate__icon {
  opacity: 0.4;
}

.admin-gate__title {
  font-size: 1.05rem;
  font-weight: 700;
  margin: 0;
}

.admin-gate__desc {
  font-size: 0.85rem;
  color: var(--color-text-muted);
  margin: 0;
  line-height: 1.5;
}

.admin-gate__form {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  align-items: center;
}

.admin-gate__input {
  width: 100%;
  max-width: 240px;
  text-align: center;
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  font-size: 1rem;
  letter-spacing: 0.2em;
  background: var(--color-bg);
  color: var(--color-text);
  box-sizing: border-box;
}

.admin-gate__input:focus {
  outline: 2px solid var(--color-primary);
  outline-offset: 1px;
}

.admin-gate__error {
  font-size: 0.82rem;
  color: var(--color-error);
  margin: 0;
}

.admin-gate__actions {
  display: flex;
  gap: var(--space-3);
  flex-wrap: wrap;
  justify-content: center;
}

/* Ícone de cadeado na sidebar para itens admin */
.sidebar__admin-lock {
  display: inline-block;
  vertical-align: middle;
  margin-left: 4px;
  opacity: 0.5;
}

.sidebar__nav-item--admin {
  opacity: 0.75;
}

.sidebar__nav-item--admin:hover,
.sidebar__nav-item--admin.sidebar__nav-item--active {
  opacity: 1;
}

/* ---------- Arquivar (Sprint P1) ----------
   Item retirado da lista padrão sem nunca ser apagado. O toggle só
   existe quando há algo arquivado (ver shared/ArchivedToggle.js). */
.archived-toggle {
  display: inline-flex;
  align-items: center;
  flex: none;
  white-space: nowrap;
  margin: 0;
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-text-muted);
  cursor: pointer;
  font-size: 0.8125rem;
}

.archived-toggle:hover,
.archived-toggle[aria-pressed="true"] {
  color: var(--color-text);
  border-color: var(--color-primary-texto);
}

.builder-card--archived,
.workflow-card--archived {
  opacity: 0.55;
}

/* ---------- Assistente: esclarecimento e origem (Sprint P2) ----------
   Quando o catálogo tem candidatos plausíveis mas nenhum claramente
   melhor, o assistente devolve a pergunta em vez de escolher por conta
   própria (ver core/assist/AssistResolver.ts). */
.assistant-panel__clarify {
  list-style: none;
  margin: var(--space-2) 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.assistant-panel__clarify-option {
  width: 100%;
  text-align: left;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-text);
  cursor: pointer;
  font-size: 0.85rem;
  line-height: 1.4;
}

.assistant-panel__clarify-option:hover {
  border-color: var(--color-primary-texto);
  color: var(--color-primary-texto);
}

.assistant-panel__source {
  margin: var(--space-1) 0 0;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-muted);
  opacity: 0.75;
}

/* ---------- Explicação de cada item do menu (Sprint P6) ----------
   Decisão de nomenclatura (ADR-072): os nomes próprios — Cockpit,
   Builder, Workflows — ficam; o que faltava era alguém que chega saber
   o que cada um faz. A explicação some com o menu recolhido e nunca
   compete com o rótulo. */
.sidebar__nav-hint {
  display: block;
  margin-top: 1px;
  font-size: 0.6875rem;
  font-style: normal;
  line-height: 1.3;
  color: var(--color-sidebar-text-muted);
  opacity: 0.85;
}

/* Auditoria de contraste (pós-U6): a dica herdava o cinza do menu, e no
   item ativo esse cinza cai sobre o roxo cheio — 2.1:1, ilegível
   justamente no item que diz onde a pessoa está. */
.sidebar__nav-item--active .sidebar__nav-hint {
  opacity: 1;
  color: #e6e1fb;
}

.sidebar-collapsed .sidebar__nav-hint {
  display: none;
}


/* ---------- Faixa de boas-vindas por tela (Sprint E6) ----------
   Mesma aparência em todas as telas, sempre logo abaixo do título. O
   componente nasceu em Automações e agradou; o que faltava era ser um só,
   no mesmo lugar, em todo lugar. Ver app/frontend/shared/ScreenIntro.js. */
.screen-intro {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-5) var(--space-6) var(--space-4);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
  background: var(--color-info-bg, var(--color-surface-2));
  color: var(--color-text);
  font-size: 0.875rem;
  line-height: 1.5;
}

.screen-intro__text {
  flex: 1;
}

.screen-intro__text a {
  color: var(--color-primary-texto);
}

.screen-intro__dismiss {
  flex-shrink: 0;
  align-self: flex-start;
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-text-muted);
  cursor: pointer;
  font-size: 0.8125rem;
}

.screen-intro__dismiss:hover {
  color: var(--color-text);
  border-color: var(--color-primary-texto);
}

.settings-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  cursor: pointer;
  color: var(--color-text);
  font-size: 0.9375rem;
}

/* ---------- Descrição de cartão/linha (Sprint E8) ----------
   Um componente só para Builder, Workflows, Automações e Histórico: corta
   em N linhas com reticências, e o texto inteiro vai para a dica ao
   passar o mouse — só quando houve corte. Ver
   app/frontend/shared/CardDescription.js. */
.card-description {
  margin: 0;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: anywhere;
  font-size: 0.8rem;
  line-height: 1.45;
  color: var(--color-text-muted);
}

.card-description--clamp-1 { -webkit-line-clamp: 1; }
.card-description--clamp-2 { -webkit-line-clamp: 2; }
.card-description--clamp-3 { -webkit-line-clamp: 3; }

.card-description--empty {
  font-style: italic;
  opacity: 0.8;
}

/* ---------- MALACA AGENT / MALACA AI (Sprint E10) ----------
   O AGENT (guia, sem custo) responde primeiro; o AI fica sempre visível
   e em destaque no cabeçalho, e libera após 3 perguntas ou assim que o
   AGENT não souber. Ver AssistantPanel.js. */
.assistant-panel__brand {
  letter-spacing: 0.04em;
  font-weight: 500;
}

.assistant-panel__brand strong {
  font-weight: 800;
}

.assistant-panel__ai-btn {
  margin-left: auto;
  margin-right: var(--space-3);
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.7);
  background: linear-gradient(135deg, var(--color-brand-1), var(--color-brand-2));
  color: #fff;
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  cursor: pointer;
  box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.4);
  transition: box-shadow var(--transition-fast), opacity var(--transition-fast);
}

.assistant-panel__ai-btn:hover {
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.25);
}

.assistant-panel__ai-btn--locked {
  opacity: 0.75;
  background: rgba(255, 255, 255, 0.15);
}

.assistant-panel__ai-btn--active {
  background: #fff;
  color: var(--color-brand-1);
}

.assistant-panel__ai-count {
  font-weight: 600;
  opacity: 0.85;
}

.assistant-panel__ai-spark {
  font-size: 0.8rem;
}

.assistant-panel--ai .assistant-panel__header {
  background: linear-gradient(135deg, var(--color-brand-1), var(--color-brand-2));
}

.assistant-panel--ai .assistant-panel__form button[type="submit"] {
  background: linear-gradient(135deg, var(--color-brand-1), var(--color-brand-2));
}


/* =====================================================================
   FUNDAÇÃO DE TELA — os três componentes que toda tela usa
   =====================================================================

   ## Por que isto existe

   A auditoria de arquitetura mediu o estado da plataforma e encontrou o
   mesmo conceito reinventado tela a tela:

   - **21 classes diferentes** de "estado vazio" (`.automations-empty`,
     `.workflow-empty`, `.settings-empty`, `.telemetry-empty`, …);
   - **11 arquivos de estilo** definindo o próprio "cartão";
   - **6 variações** de cabeçalho de página;
   - `.topbar__actions` usado por 11 telas e definido em **uma só**
     (builder.css) — as outras 10 usavam uma classe sem estilo nenhum;
   - **8 de 17 telas sem nenhuma ação primária** na primeira dobra, e
     uma (Automações) com **nove** — que dá no mesmo: quando tudo é
     primário, nada é.

   Nada disso é feiura de tela: é ausência de fundação. Cada tela nova
   nascia decidindo de novo o que já tinha sido decidido, e por isso a
   plataforma parecia um conjunto de sistemas diferentes.

   ## A regra que estes componentes carregam

   > Toda tela tem UM cabeçalho, UMA ação primária e UM jeito de dizer
   > que não há nada para mostrar.

   Uma tela que precise de algo diferente disto está dizendo que é uma
   tela diferente do resto da plataforma — e essa é uma decisão de
   arquitetura, não de estilo.

   ------------------------------------------------------------------ */

/* ---------- 1. Cabeçalho de página ---------- */

/*
 * Responde as três perguntas de orientação de uma vez: onde estou
 * (título + trilha), o que esta área faz (uma linha, nunca um
 * parágrafo), e qual é a ação principal (um botão, à direita).
 */
.page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
  padding: var(--space-4) var(--space-6) var(--space-3);
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  position: sticky;
  top: 0;
  z-index: 10;
}

.page-header__identidade {
  min-width: 0;
  flex: 1 1 320px;
}

/* A trilha só aparece quando a tela tem um pai de verdade. Trilha de um
   nível só é enfeite: ela ocupa uma linha para dizer "você está onde
   você está". */
.page-header__trilha {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0 0 2px;
  font-size: 0.75rem;
  color: var(--color-text-muted);
}

.page-header__trilha a {
  color: inherit;
  text-decoration: none;
}

.page-header__trilha a:hover {
  color: var(--color-text);
  text-decoration: underline;
}

.page-header__titulo {
  margin: 0;
  font-size: 1.15rem;
  font-weight: 700;
  line-height: 1.3;
  overflow-wrap: anywhere;
}

/*
 * Uma linha, com teto de largura. O teto não é estética: é o que
 * impede o subtítulo de virar parágrafo na próxima sprint — quem
 * escrever demais vê o texto sobrar, e corta.
 */
.page-header__resumo {
  margin: 2px 0 0;
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--color-text-muted);
  max-width: 68ch;
}

.page-header__acoes {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
  flex-shrink: 0;
}

/* ---- abas do módulo, dentro do cabeçalho ---- */

/*
 * A navegação interna de um módulo é parte do cabeçalho, e não do
 * conteúdo que rola por baixo dele. Solta no corpo, ela ficava coberta
 * pelo cabeçalho grudado assim que a pessoa rolava 40px — e ficava
 * assim, cortada ao meio, o resto da sessão.
 */
.page-header--com-abas {
  padding-bottom: 0;
  row-gap: var(--space-2);
}

.page-header__abas-barra {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
  width: 100%;
  margin-top: var(--space-1);
}

.page-header__abas {
  display: flex;
  gap: var(--space-1);
  flex-wrap: wrap;
}

/*
 * Aba sublinhada, e não pílula: a pílula competia com o botão de ação
 * primária, que fica a poucos centímetros dela — dois elementos com
 * fundo cheio na mesma faixa, e nenhum dos dois lendo como "o
 * principal". A aba marca posição; o botão marca ação.
 */
.page-header__aba {
  padding: 8px 12px;
  border: none;
  border-bottom: 2px solid transparent;
  background: transparent;
  color: var(--color-text-muted);
  font-size: 0.85rem;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}

.page-header__aba:hover {
  color: var(--color-text);
}

.page-header__aba--ativa {
  color: var(--color-text);
  border-bottom-color: var(--color-primary);
}

.page-header__filtro {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
  padding-bottom: var(--space-2);
}

/* ---------- 2. Seção de conteúdo ---------- */

/*
 * O bloco padrão de qualquer tela. Substitui `.cortex-bloco`,
 * `.telemetry-panel`, `.settings-section` e as outras nove variantes do
 * mesmo cartão branco com borda.
 */
.secao {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
}

/* Variante sem moldura, para quando a seção é a própria tela e a
   borda só somaria um retângulo dentro de outro. */
.secao--nua {
  background: transparent;
  border: none;
  padding: 0;
}

.secao__cabecalho {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin-bottom: var(--space-3);
}

.secao__titulo {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 700;
}

.secao__resumo {
  margin: 2px 0 0;
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--color-text-muted);
  max-width: 68ch;
}

/* ---------- 3. Estado da tela ---------- */

/*
 * Um componente para todos os "não há o que mostrar agora" — ver
 * shared/Estado.js para os sete estados e a diferença entre eles.
 *
 * A diferença importa: "não aconteceu nada" e "não foi medido" e "deu
 * erro" são três fatos diferentes, e a plataforma dizia os três com o
 * mesmo cinza.
 */
.estado {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-5) var(--space-4);
  border-radius: var(--radius-md);
  max-width: 62ch;
}

.estado--centrado {
  align-items: center;
  text-align: center;
  margin: 0 auto;
  padding: var(--space-8) var(--space-4);
}

.estado__titulo {
  margin: 0;
  font-size: 1rem;
  font-weight: 700;
}

.estado__texto {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--color-text-muted);
}

.estado__acoes {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
  margin-top: var(--space-2);
}

/* Vazio e carregando são estados neutros: nada deu errado. */
.estado--vazio,
.estado--carregando {
  background: var(--color-surface-2);
}

/* Pendente é vizinho do vazio, e de propósito: um indicador que ainda
   não nasceu não é um problema. O que muda é o itálico, que diz
   "campo à espera" sem gritar. */
.estado--pendente {
  background: var(--color-surface-2);
}

.estado--pendente .estado__texto {
  font-style: italic;
}

.estado--erro {
  background: var(--color-error-bg);
  border: 1px solid var(--color-error);
}

.estado--erro .estado__titulo {
  color: var(--color-error);
}

.estado--aviso {
  background: var(--color-warning-bg);
  border-left: 4px solid var(--color-warning);
}

.estado--aviso .estado__titulo,
.estado--aviso .estado__texto {
  color: var(--color-warning);
}

.estado--desligado {
  background: var(--color-surface-2);
  opacity: 0.85;
}

/* ---------- 4. Indicador (KPI) ---------- */

/*
 * O cartão de número. Um só na plataforma inteira: Telemetria, o painel
 * de documentos e qualquer painel futuro usam este.
 */
.kpis {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--kpi-min, 210px), 1fr));
  gap: var(--space-3);
}

.kpi {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}

/* Papel: rotulo. */
.kpi__rotulo {
  margin: 0;
  font-size: var(--fs-rotulo);
  font-weight: 600;
  line-height: var(--lh-titulo);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
}

/* Papel: metrica. Numero grande, rotulo pequeno (UX_GUIDE secao 6b): e a
   unica coisa da plataforma que usa peso 700. */
.kpi__valor {
  margin: 0;
  font-size: var(--fs-metrica);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: var(--lh-metrica);
}

/* Papel: apoio. */
.kpi__apoio {
  margin: 0;
  font-size: var(--fs-apoio);
  line-height: var(--lh-apoio);
  color: var(--color-text-muted);
}

/*
 * O número que a pessoa veio ver.
 *
 * Um painel em que pedido, documento, item e taxa de automação tem todos
 * o mesmo corpo de letra nao tem hierarquia — e sem hierarquia quem olha
 * de relance nao leva nada. Aqui o numero cresce e o rotulo encolhe, que
 * e a proporcao de painel de gestao: numero grande, rotulo pequeno.
 *
 * `clamp` porque a mesma tela abre num monitor de recepcao e num
 * notebook: 2rem no estreito, 3rem no largo, sem quebra de linha no
 * meio de um numero.
 */
.kpi--destaque {
  padding: var(--space-4) var(--space-4) var(--space-3);
}

.kpi--destaque .kpi__valor {
  font-size: clamp(2rem, 4.2vw, 3rem);
  line-height: 1.05;
  letter-spacing: -0.02em;
}

.kpi--destaque .kpi__apoio {
  margin-top: 2px;
}

/* Pendente em destaque nao vira numero grande: "Ainda nao medido" em
   corpo 3rem gritaria a ausencia como se fosse resultado. */
.kpi--pendente.kpi--destaque .kpi__valor {
  font-size: 0.95rem;
}

/* O KPI sem medição herda a aparência do estado pendente — a mesma
   linguagem visual em toda a plataforma, e nunca um zero no lugar. */
.kpi--pendente {
  background: var(--color-surface-2);
}

.kpi--pendente .kpi__valor {
  font-size: 0.95rem;
  font-weight: 500;
  font-style: italic;
  color: var(--color-text-muted);
}

/* ---------- 5. Largura de leitura ---------- */

/*
 * Texto corrido em tela larga vira linha de 200 caracteres, que
 * ninguém lê. Toda prosa da plataforma respeita este teto.
 */
.prosa {
  max-width: 68ch;
}

@media (max-width: 720px) {
  .page-header {
    padding: var(--space-3) var(--space-4);
    position: static;
  }

  .page-header__acoes {
    width: 100%;
  }
}

/* =====================================================================
   CONTENÇÃO — texto nunca ultrapassa o componente
   =====================================================================

   Pedido direto do responsável pelo produto, virando premissa de
   layout: *"textos de cards não podem ultrapassar o tamanho dos
   componentes"*.

   ## A causa quase sempre é a mesma

   Um item de flex ou de grid tem `min-width: auto` por padrão, e
   `auto` significa "no mínimo o tamanho do meu conteúdo". Ou seja: uma
   palavra longa (um código, um caminho de arquivo, um nome de catálogo)
   **empurra a caixa** em vez de quebrar dentro dela. O cartão estica,
   estoura a grade, e a linha vaza para fora da borda.

   Corrigir isso caso a caso é o que a plataforma vinha fazendo — e é
   por isso que o defeito reaparecia em cada tela nova. A correção
   estrutural é declarar, uma vez, que **conteúdo cede antes da caixa**.

   ## As três regras

   1. Todo item de flex/grid pode encolher (`min-width: 0`).
   2. Toda palavra longa quebra dentro da caixa (`overflow-wrap`).
   3. O que precisa mesmo de largura (tabela, código) rola **dentro do
      próprio componente**, nunca empurrando a página.

   Garantido por `scripts/audit-vazamento.js`, que abre cada tela e
   falha nomeando o elemento que vazou.

   ------------------------------------------------------------------ */

/*
 * As duas regras estruturais, aplicadas ao conteúdo inteiro — e não a
 * uma lista de componentes.
 *
 * A régua de estresse (`node scripts/audit-vazamento.js --estresse`)
 * mediu **179 vazamentos** quando cada texto da plataforma foi trocado
 * por uma palavra longa. Nenhum deles era defeito de um componente
 * específico: eram todos a mesma coisa, o comportamento padrão do CSS.
 * Corrigir componente a componente é o que vinha sendo feito, e é por
 * isso que o defeito voltava em cada tela nova.
 *
 * `:where()` de propósito: especificidade zero. Estas regras são o
 * PISO da plataforma — qualquer componente que precise de outro
 * comportamento sobrescreve sem precisar de `!important` e sem brigar.
 *
 * 1. **Tudo pode encolher.** `min-width: 0` só muda algo em item de
 *    flex ou grid, onde o padrão (`auto`) significa "no mínimo o
 *    tamanho do meu conteúdo" — é ele que faz uma palavra empurrar a
 *    caixa em vez de quebrar dentro dela.
 * 2. **Toda palavra quebra antes de vazar.** `anywhere` e não
 *    `break-word`: só `anywhere` parte uma palavra única que sozinha já
 *    é maior que a caixa, que é exatamente o caso de um código de
 *    catálogo, um caminho de arquivo ou um endereço.
 */
.content :where(div, section, article, header, footer, aside, p, li, dt, dd, span, label, a, td, th, h1, h2, h3, h4, h5, h6) {
  min-width: 0;
}

.content :where(p, li, dt, dd, span, label, a, strong, em, small, code, h1, h2, h3, h4, h5, h6, td, th, summary, figcaption, blockquote) {
  overflow-wrap: anywhere;
}

/*
 * Botão fica de FORA da quebra em qualquer ponto — e isto é um achado
 * real, não precaução: com `anywhere`, "Ver relatório" numa coluna
 * estreita virou uma letra por linha, e a lista do Histórico ficou
 * ilegível. Rótulo de botão é curto por definição; se não cabe, o
 * problema é a largura da coluna, não a palavra.
 */
/*
 * `break-word` e não `anywhere`: ele quebra a palavra **só quando ela
 * sozinha não cabe**, e nunca no meio de um rótulo que teria onde
 * quebrar. `anywhere` produziu "Ver relatório" com uma letra por linha;
 * `keep-all` produziu "Pré-visualizar" saindo para fora do painel. Este
 * é o meio-termo que resolve os dois.
 */
.content .btn {
  overflow-wrap: break-word;
  /*
   * A regra global de contenção dá `min-width: 0` a tudo — correto para
   * caixas, errado para botão: "Pré-visualizar" foi comprimido a 34px
   * dentro de um flex e o texto passou a ser desenhado fora dele.
   * `fit-content` deixa o botão quebrar em duas linhas, mas nunca ficar
   * menor do que o rótulo precisa.
   */
  /*
   * `min(fit-content, 100%)` e não `fit-content` puro: o mínimo é o que
   * o rótulo precisa, MAS nunca maior do que o espaço disponível. Sem o
   * teto, um rótulo longo fazia o botão crescer para fora do cartão —
   * trocando a compressão por um vazamento.
   */
  min-width: fit-content;
}

/*
 * Nada dentro do conteúdo é mais largo que o espaço que tem.
 *
 * A régua de estresse mostrou o padrão: um `<span>` com `white-space:
 * nowrap` chegava a 576px dentro de um cartão de 340px, e o alternador
 * de visualização a 924px numa janela de 390px. Nos dois casos o
 * elemento não estava "quebrado" — ele estava obedecendo o CSS, que sem
 * teto deixa o conteúdo mandar na largura.
 */
.content :where(div, section, article, p, li, span, label, a, img, table, pre, h1, h2, h3, h4, h5, h6),
.content :where(select, input, textarea, button) {
  max-width: 100%;
}

/*
 * Popover ancorado NÃO entra na contenção acima.
 *
 * O teto de 100% é medido contra o ancorador — um botão de 24px —, não
 * contra a tela: o menu ⋮ do Histórico foi esmagado a 24px de largura e
 * as opções ("Rever no Cockpit"…) vazavam ilegíveis para fora
 * (achado do responsável, 2026-08-28). Elemento em posição absoluta não
 * empurra layout nenhum, então a contenção não protege nada aqui — e o
 * `width: max-content` devolve ao menu o tamanho do próprio conteúdo.
 */
.content :where(.card-menu, .automation-card__menu, .filter-popover__panel) {
  max-width: none;
  width: max-content;
}

/*
 * Tabela: as colunas dividem a largura disponível em vez de o conteúdo
 * mandar. `table-layout: fixed` + a quebra de palavra declarada acima
 * é o par que impede uma coluna com texto longo de esticar a tabela
 * para 655px numa janela de 390px — o que fazia o Histórico rolar de
 * lado no telefone.
 *
 * Quando uma tabela precisa MESMO de largura (muitas colunas), ela vai
 * dentro de um `.rola-x` e rola no próprio envelope, nunca na página.
 */
/*
 * `table-layout: fixed` reparte a largura igualmente entre as colunas,
 * ignorando o conteúdo. Isso é o certo no telefone (impede a tabela de
 * esticar e a página de rolar de lado) e é o ERRADO no monitor: ele
 * espremeu a coluna de ações do Histórico até os botões não caberem.
 *
 * Então ele vale só onde resolve alguma coisa.
 */
/*
 * Sem `width: 100%` aqui: forçá-la fez a tabela do Histórico repartir a
 * largura entre as colunas de conteúdo e espremer a de ações até 34px.
 * A largura de uma tabela é decisão da tela que a desenha; o que esta
 * regra garante é só que ela não passe da tela.
 */
@media (max-width: 720px) {
  .content table {
    table-layout: fixed;
  }
}

/* Coluna de ações: os botões ficam lado a lado e a coluna toma a
   largura que eles precisam, nunca o contrário. */
.content td:has(.btn),
.content th:has(.btn) {
  white-space: nowrap;
  width: 1%;
}

/*
 * O alternador de visualização quebra em duas linhas antes de empurrar
 * a tela. `flex-shrink: 0` fazia sentido quando ele tinha dois botões
 * curtos; com rótulos maiores, virou a peça mais larga do telefone.
 */
.content .segmented-control {
  flex-wrap: wrap;
  flex-shrink: 1;
}

/*
 * Selo, etiqueta e badge: rótulo curto por natureza, `white-space:
 * nowrap` por construção — e por isso o primeiro a estourar o cartão
 * quando o texto vem maior do que alguém imaginou.
 *
 * Aqui truncar é a decisão certa, e não quebrar em três linhas: um selo
 * é um sinal de relance. O teto é do cartão, não do selo.
 *
 * Regra de vizinhança: `[class*="badge"]` e `[class*="selo"]` cobrem as
 * dezoito variantes que a plataforma acumulou (status, tipo, ambiente,
 * confiança, execução) sem precisar listá-las — e sem que a próxima
 * precise se lembrar de entrar na lista.
 */
.content :where([class*="badge"], [class*="selo"], [class*="-tag"]) {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

/*
 * Botão com rótulo longo quebra em duas linhas em vez de esticar até
 * sair do cartão. Um botão largo demais é feio; um botão que empurra a
 * tela para fora é defeito.
 */
.content .btn {
  max-width: 100%;
}

/*
 * O envelope de rolagem: o que não cabe rola DENTRO do componente.
 * Uma tabela larga dentro dele nunca faz a página inteira rolar de
 * lado — que é o defeito que aparece primeiro no notebook, e some no
 * monitor grande de quem desenvolveu.
 */
.rola-x {
  overflow-x: auto;
  max-width: 100%;
}

/*
 * Truncar é uma decisão, não um acidente. Quem trunca declara — e o
 * texto inteiro fica no `title`. Sem esta classe, texto que não cabe
 * quebra a linha; nunca some sem avisar.
 */
.trunca {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

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

/* ---------- Correções da contenção: dois achados reais ---------- */

/*
 * **1. Coluna de ações de tabela.**
 *
 * Achado do responsável pelo produto: na lista do Histórico, "Ver
 * relatório" virou uma letra por linha. A causa foi a regra de
 * contenção recém-introduzida — `table-layout: fixed` repartia a
 * largura igualmente e a coluna de ações ficava com 34px.
 *
 * A coluna de ações toma a largura que os botões precisam. `width: 1%`
 * numa tabela significa "o mínimo que couber", e é o idioma consagrado
 * para isso.
 */
/*
 * A coluna de ações toma só a largura que precisa — e agora ela precisa
 * de pouco, porque as quatro ações viraram uma mais um menu. A versão
 * anterior desta regra (com `max-width: none` nos botões) fazia a coluna
 * transbordar por cima das vizinhas: era o defeito que a redução de
 * ações resolve na origem, em vez de contornar com largura.
 */
/*
 * Só CÉLULA DE TABELA. O seletor anterior era `[class$="__actions"]`, e
 * ele pegou as caixas de ação de todo cartão da plataforma — Conectores,
 * Arquivos, Agendamentos, Suítes, Configurações. `width: 1%` numa célula
 * significa "o mínimo que couber"; num `<div>` de cartão significa
 * literalmente 1%, e os botões passaram a ser desenhados fora da caixa.
 * Vinte e cinco colapsos, medidos pela régua depois de ela aprender a
 * enxergá-los.
 *
 * Terceira vez que uma regra global minha precisou de recorte nesta
 * frente. A regra sobre a regra continua valendo: contra-exemplo antes
 * de entrar.
 */
.content td[class$="__actions"] {
  white-space: nowrap;
  width: 1%;
}

/*
 * **2. Valor longo num painel de informação.**
 *
 * Achado do responsável pelo produto: um documento chega como texto
 * embutido (uma cadeia de centenas de milhares de caracteres) e, com a
 * quebra em qualquer ponto, ele passou a ocupar milhares de linhas —
 * "barra de rolagem quilométrica", e a tela do Cockpit ficou inutilizável.
 *
 * A quebra está certa (sem ela, a cadeia vazava para fora do painel). O
 * que faltava é o teto: **um valor que ninguém vai ler não pode ocupar
 * a tela inteira.** Ele rola dentro do próprio campo, e o texto completo
 * continua ali para quem precisar copiar.
 *
 * Vale para qualquer valor de painel — não só para este caso: o próximo
 * campo grande não vai precisar de correção nova.
 */
.content .info-panel__value,
.content .cortex-versoes dd,
.content dd {
  max-height: 7.5em;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/*
 * `.modal__actions` fora de um modal.
 *
 * Achado da régua de contenção: o painel de Atualizações reusa a caixa
 * de ações do modal dentro de uma seção comum. Ali ela não tem a
 * largura que o modal lhe dava, e a regra global de contenção
 * (`min-width: 0`) a comprimiu a 6px — os botões dentro dela passaram a
 * ser desenhados por fora do painel.
 *
 * O teto `min(fit-content, 100%)` é o mesmo dos botões: nunca menor que
 * o conteúdo, nunca maior que o espaço.
 */
.content .modal__actions {
  /* `min-width: min(fit-content, 100%)` foi descartado pelo navegador
     nesta combinação; o par explícito faz a mesma coisa e é suportado. */
  min-width: fit-content;
  max-width: 100%;
  flex-wrap: wrap;
}

/* ---------- Faixa de status (da faixa do Cockpit, 2026-09-25) ----------
 *
 * A cápsula de 52px do Cockpit ocioso (`.hero__faixa`): trilho, borda,
 * sombra interna e o ponto colorido com halo. Vive aqui para outra tela
 * usar a mesma peça em vez de copiar. O ponto recebe a cor pelo
 * modificador; `--brilho` passa o reflexo da barra de execução por cima,
 * para quem trabalha agora.
 */
.faixa-status {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  height: 52px;
  padding: 0 var(--space-5);
  border-radius: 999px;
  background: var(--color-surface-2);
  border: 1px solid var(--color-border);
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.35);
  font-size: var(--fs-corpo);
  color: var(--color-text-muted);
  white-space: nowrap;
  overflow: hidden;
}

.faixa-status__ponto {
  --faixa-cor: var(--color-text-muted);
  --faixa-halo: transparent;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--faixa-cor);
  box-shadow: 0 0 0 3px var(--faixa-halo);
  transition: background-color 240ms ease, box-shadow 240ms ease;
}

.faixa-status__ponto--ok { --faixa-cor: var(--color-success); --faixa-halo: var(--color-success-bg); }
.faixa-status__ponto--info { --faixa-cor: var(--color-info); --faixa-halo: var(--color-info-bg); }
.faixa-status__ponto--atencao { --faixa-cor: var(--color-warning); --faixa-halo: var(--color-warning-bg); }

.faixa-status--brilho::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.22), transparent);
  transform: translateX(-100%);
  animation: faixa-status-brilho 1.8s infinite;
}

@keyframes faixa-status-brilho {
  from { transform: translateX(-100%); }
  to { transform: translateX(100%); }
}

@media (prefers-reduced-motion: reduce) {
  .faixa-status--brilho::after { animation: none; opacity: 0; }
}

/* ---------- O cubo da marca, animado ----------
 *
 * Mesma peça da tela de carregamento (`carregando.html`), montada por
 * `shared/Cubo.js`. A aresta vem de `--cubo-aresta`, e todo o resto é
 * derivado dela: quem chama escolhe o tamanho, não seis medidas.
 *
 * As cores saem de `--color-brand-1`/`--color-brand-2`, como todo o
 * resto da marca — nunca escritas à mão (ver `tests/marca.test.ts`).
 */
.cubo-marca {
  --cubo-aresta: 58px;
  width: var(--cubo-aresta);
  height: var(--cubo-aresta);
  flex-shrink: 0;
  perspective: calc(var(--cubo-aresta) * 5.5);
}

.cubo-marca__corpo {
  width: 100%;
  height: 100%;
  position: relative;
  transform-style: preserve-3d;
  animation: cubo-marca-girar 14s ease-in-out infinite;
}

/* Gira transicionando entre os três eixos ao mesmo tempo: X, Y e Z
   variam juntos e fora de fase, então o cubo tumbla em vez de parecer
   preso a uma haste vertical. */
@keyframes cubo-marca-girar {
  0%   { transform: rotateX(-20deg) rotateY(0deg)   rotateZ(0deg); }
  20%  { transform: rotateX(35deg)  rotateY(80deg)  rotateZ(18deg); }
  40%  { transform: rotateX(-35deg) rotateY(160deg) rotateZ(-12deg); }
  60%  { transform: rotateX(25deg)  rotateY(230deg) rotateZ(20deg); }
  80%  { transform: rotateX(-15deg) rotateY(300deg) rotateZ(-18deg); }
  100% { transform: rotateX(-20deg) rotateY(360deg) rotateZ(0deg); }
}

/* Quem pediu ao sistema para reduzir movimento vê o cubo parado, numa
   pose de três quartos — a peça continua ali, o giro é que sai. */
@media (prefers-reduced-motion: reduce) {
  .cubo-marca__corpo {
    animation: none;
    transform: rotateX(-20deg) rotateY(35deg);
  }
}

/* As seis faces existem todas para o fundo nunca vazar por um lado
   vazio durante o giro. Cada uma é uma grade 3x3 de adesivos da mesma
   cor — é isso que faz reconhecer um cubo mágico, e não um cubo. */
.cubo-marca__face {
  position: absolute;
  width: var(--cubo-aresta);
  height: var(--cubo-aresta);
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 1fr);
  gap: calc(var(--cubo-aresta) / 29);
  padding: calc(var(--cubo-aresta) / 29);
  background: var(--color-sidebar-bg);
  border-radius: calc(var(--cubo-aresta) / 14.5);
}

.cubo-marca__adesivo {
  border-radius: 1px;
}

/* Regra BOY, o esquema padrão dos cubos vendidos: branco em cima, e as
   duas cores da marca nas faces vizinhas — nunca duas iguais dividindo
   uma aresta, só as opostas repetem. */
.cubo-marca__face--top .cubo-marca__adesivo,
.cubo-marca__face--bottom .cubo-marca__adesivo { background: #e7e9f3; }
.cubo-marca__face--front .cubo-marca__adesivo,
.cubo-marca__face--back .cubo-marca__adesivo { background: var(--color-brand-1); }
.cubo-marca__face--left .cubo-marca__adesivo,
.cubo-marca__face--right .cubo-marca__adesivo { background: var(--color-brand-2); }

.cubo-marca__face--top    { transform: rotateX(90deg)  translateZ(calc(var(--cubo-aresta) / 2)); }
.cubo-marca__face--bottom { transform: rotateX(-90deg) translateZ(calc(var(--cubo-aresta) / 2)); }
.cubo-marca__face--front  { transform: translateZ(calc(var(--cubo-aresta) / 2)); }
.cubo-marca__face--back   { transform: rotateY(180deg) translateZ(calc(var(--cubo-aresta) / 2)); }
.cubo-marca__face--right  { transform: rotateY(90deg)  translateZ(calc(var(--cubo-aresta) / 2)); }
.cubo-marca__face--left   { transform: rotateY(-90deg) translateZ(calc(var(--cubo-aresta) / 2)); }

/* ---------- Item de lista (padrão único, 2026-09-19) ----------
   Nasceu da lista de tipos do Document Intelligence, a que o responsável
   pelo produto apontou como a mais organizada. Um item é: ícone, nome,
   uma linha de apoio e no máximo um selo. O que não decide a leitura vai
   para o detalhe do item (modal ou tela), nunca para a linha. */
.list-item {
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  box-shadow: none;
  color: inherit;
  text-decoration: none;
  transition: border-color var(--transition-fast);
}

.list-item:hover,
.list-item:focus-visible {
  border-color: var(--color-primary);
}

.list-item__linha {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.list-item__icone {
  flex: none;
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--color-primary-texto);
  overflow: hidden;
}

.list-item__icone svg {
  width: 26px;
  height: 26px;
}

.list-item__icone img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: var(--radius-sm);
}

.list-item__corpo {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1 1 auto;
  min-width: 0;
}

/* Papel: nome. O peso vem para 600, que e o do papel: 700 e reservado a
   metrica, e dois pesos fortes na mesma linha nao hierarquizam nada. */
.list-item__nome {
  margin: 0;
  font-size: var(--fs-nome);
  font-weight: 600;
  line-height: var(--lh-nome);
  color: var(--color-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Nome e dica lado a lado, quando o detalhe do item vive numa dica em vez
   de uma linha de apoio (Histórico, Conectores, Arquivos). */
.list-item__corpo--com-dica {
  flex-direction: row;
  align-items: center;
  gap: var(--space-2);
}

/* Papel: apoio. */
.list-item__apoio {
  font-size: var(--fs-apoio);
  line-height: var(--lh-apoio);
  color: var(--color-text-muted);
}

/* ---------- Dica (2026-09-19) ----------
   Posição e comportamento seguem o padrão Tooltip do WAI-ARIA e o
   critério 1.4.13 da WCAG: fecha com Esc, permanece enquanto houver foco
   ou ponteiro, e aceita o ponteiro sem sumir. O gatilho fica colado ao
   rótulo que explica; o balão abre abaixo, alinhado à esquerda, e vira
   para cima quando não cabe. Ver app/frontend/shared/dica.js. */
.dica-wrap {
  position: relative;
  display: inline-flex;
  flex: none;
}

.dica {
  display: inline-flex;
  width: 15px;
  height: 15px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--color-text-muted);
  cursor: help;
}

/* Alvo de 25px, como manda o mínimo de área clicável, sem engordar o
   desenho. */
.dica::before {
  content: "";
  position: absolute;
  inset: -5px;
}

.dica svg {
  width: 100%;
  height: 100%;
}

.dica:hover,
.dica:focus-visible {
  color: var(--color-primary-texto);
}

.dica-balao {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  width: max-content;
  min-width: 160px;
  max-width: min(320px, calc(100vw - 2 * var(--space-4)));
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface-2);
  color: var(--color-text);
  box-shadow: var(--shadow-md);
  font-size: 13px;
  font-weight: 400;
  line-height: 1.45;
  white-space: normal;
  opacity: 0;
  visibility: hidden;
  /* Acima do botão flutuante de Ajuda (.assistant-toggle, 90): o balão de
     uma linha do fim da lista abre para baixo, cai em cima do botão e o
     motivo da falha fica ilegível no Histórico a 720px. O balão só existe
     enquanto a pessoa aponta o gatilho, então nada fica coberto depois. */
  z-index: 95;
  transition: opacity var(--transition-fast) 150ms, visibility 0s 300ms;
}

.dica-wrap[data-acima] .dica-balao {
  top: auto;
  bottom: calc(100% + 8px);
}

/* O balão vira para a esquerda quando o gatilho está perto da borda
   direita (shared/dica.js decide, medindo). Sem isso a página inteira
   rola de lado num telefone, com o balão ainda fechado. */
.dica-wrap[data-a-esquerda] .dica-balao {
  left: auto;
  right: 0;
}

.dica-wrap:hover .dica-balao,
.dica:focus-visible + .dica-balao,
.dica-balao:hover,
.dica-wrap[data-aberta="true"] .dica-balao {
  opacity: 1;
  visibility: visible;
  transition-delay: 300ms, 0s;
}

@media (prefers-reduced-motion: reduce) {
  .dica-balao {
    transition: none;
  }
}

/* O caminho de volta fica antes do título, e não depende do botão do
   navegador (2026-09-19). */
.topbar__voltar {
  margin-right: var(--space-3);
}

/* A lista de execuções também serve à tela de Atualizações, que não
   carrega o CSS do Histórico: o respiro entre itens mora aqui, senão os
   registros de lá ficavam colados. */
.history-list {
  display: grid;
  gap: var(--space-1);
}

/* O botão flutuante de Ajuda mora no canto de baixo, à direita, e cobria
   o menu do último item de toda lista. O espaço é reservado na lista, e
   não em cada tela, senão a próxima lista nasce com o mesmo defeito. */
.history-list,
.automations-grid,
.connectors-grid,
.files-grid,
.item-grid {
  padding-bottom: 4rem;
}
