/* ============================================================================
   JSF-CONNECTOR — Sistema de design "malha de sinal" (#332)
   Direção visual: trilhas de cobre + telemetria de sinal sobre a stack Django.
   Paleta cobre (--accent) + sinal (--signal), tipografia Bahnschrift (display)
   e monoespaçada (IDs/timestamps/status). Tokens abaixo são a fonte única de
   verdade das cores/tipografia; os seletores consomem via var(). Esboço de
   referência em docs/proposta-design-visual.html.
   Tema claro apenas (color-scheme: light) — o app tem muitos estilos inline
   herdados de telas antigas; um dark-mode global viria depois, quando esses
   estiverem todos tokenizados.
   ============================================================================ */
:root {
    --canvas:#F4F5F0; --panel:#FFFFFF; --panel-2:#FAFAF7;
    --text:#12201A; --text-muted:#5B6B64; --border:#DDE1D7; --border-strong:#C7CDC2;
    --sidebar-bg:#0A1512; --sidebar-fg:#C9D6CF; --sidebar-fg-dim:#71877C; --sidebar-border:#1B2C25;
    --accent:#B5651D; --accent-strong:#8F4E14; --accent-on-dark:#E39A57;
    --signal:#2FA99A; --signal-on-dark:#5EEAD4;
    --ok:#2F7A3C; --ok-bg:#E4F1E3;
    --warn:#96650F; --warn-bg:#F5EBD3;
    --err:#B33A3A; --err-bg:#F6E1E1;
    --info:#1A56DB; --info-bg:#E8F0FE;
    /* #348: cores por tipo de nó do editor de fluxo (antes hex solto no flow.css).
       Tons médios que funcionam sobre fundo claro e escuro; o #349 os reajusta
       no tema escuro. --node-accent é o realce interativo do editor (foco,
       botões auxiliares) alinhado ao "sinal" do design system. */
    --node-accent:#2FA99A; --node-accent-bg:#E4F5F2; --node-accent-border:#A9DED7;
    --node-trigger:#34A853; --node-api:#3B7DD8; --node-http:#9C27B0;
    --node-logic:#C79212; --node-delay:#00ACC1; --node-loop:#E4703A;
    --node-estado:#C2185B; /* #505: nó "Máquina de Estado" */
    --node-ia:#6A4CFF; /* #535: nó "IA / LLM" */
    --node-email:#1E88A8; /* #568: nó "E-mail" */
    --node-subfluxo:#5C6BC0; /* #598: nó "Subfluxo" */
    --shadow: 0 1px 2px rgba(16,32,26,.06), 0 8px 24px -12px rgba(16,32,26,.18);
    --radius-s:3px; --radius-m:5px;
    --font-display:"Bahnschrift","Arial Narrow","Segoe UI Semibold","Segoe UI",sans-serif;
    --font-body:-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue",Arial,sans-serif;
    --font-mono:"Cascadia Code","Cascadia Mono","SF Mono","JetBrains Mono","Fira Code",Consolas,"Roboto Mono",monospace;
    color-scheme: light;
}

/* ============================================================================
   #349 — Tema escuro
   Tokens escuros portados do mockup docs/proposta-design-visual.html. Dois
   gatilhos: (1) preferência do SO (prefers-color-scheme: dark) quando o usuário
   NÃO forçou um tema (:not([data-theme="light"])); (2) escolha explícita
   data-theme="dark" (toggle no header, persistido em localStorage e aplicado
   antes do paint por um script inline no <head> do base.html — sem flash).
   data-theme="light" força o claro mesmo com SO escuro. A sidebar/header
   permanecem escuros nos dois temas (já são a superfície mais escura).
   Os --node-* mantêm o matiz por tipo; só ajustamos os que precisavam de brilho.
   ============================================================================ */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --canvas:#0D1815; --panel:#122019; --panel-2:#0F1B17;
        --text:#E7EEE9; --text-muted:#8FA39A; --border:#22332B; --border-strong:#2E4238;
        --accent:#E39A57; --accent-strong:#F2AE6E;
        --signal:#5EEAD4;
        --ok:#6FCB7F; --ok-bg:#123821;
        --warn:#E8B339; --warn-bg:#3A2C0E;
        --err:#F1666B; --err-bg:#3B1414;
        --info:#7CA6F0; --info-bg:#16233F;
        --node-accent:#5EEAD4; --node-accent-bg:#12312C; --node-accent-border:#2C5A52;
        --node-api:#5B92E0; --node-logic:#E8B339;
        --shadow: 0 1px 2px rgba(0,0,0,.4), 0 12px 28px -14px rgba(0,0,0,.6);
        color-scheme: dark;
    }
}
:root[data-theme="dark"] {
    --canvas:#0D1815; --panel:#122019; --panel-2:#0F1B17;
    --text:#E7EEE9; --text-muted:#8FA39A; --border:#22332B; --border-strong:#2E4238;
    --accent:#E39A57; --accent-strong:#F2AE6E;
    --signal:#5EEAD4;
    --ok:#6FCB7F; --ok-bg:#123821;
    --warn:#E8B339; --warn-bg:#3A2C0E;
    --err:#F1666B; --err-bg:#3B1414;
    --info:#7CA6F0; --info-bg:#16233F;
    --node-accent:#5EEAD4; --node-accent-bg:#12312C; --node-accent-border:#2C5A52;
    --node-api:#5B92E0; --node-logic:#E8B339;
    --shadow: 0 1px 2px rgba(0,0,0,.4), 0 12px 28px -14px rgba(0,0,0,.6);
    color-scheme: dark;
}

/* ============================================================================
   #530 — Identificação visual de ambiente (selo no cabeçalho, base.html)
   Sandbox ganha um bloco de tokens PRÓPRIO (paleta laranja vibrante, distinta
   do --accent cobre padrão) sob o atributo [data-ambiente='sandbox'] setado
   no <html> por core.context_processors.ambiente_context -- mesmo mecanismo
   de variante clara/escura já usado pelo tema acima. Produção reaproveita o
   --info já existente (sem token novo). #537: 'local' ganhou o mesmo
   tratamento de Sandbox, com paleta rosa/roxo própria (--env-local/
   --env-local-fg) -- só 'production' segue sem bloco de tokens dedicado aqui
   (reaproveita --info).
   ============================================================================ */
html[data-ambiente="sandbox"] {
    --env-sandbox:#FF6A00; --env-sandbox-fg:#12201A;
}
@media (prefers-color-scheme: dark) {
    html[data-ambiente="sandbox"]:not([data-theme="light"]) {
        --env-sandbox:#FF9142; --env-sandbox-fg:#12201A;
    }
}
html[data-ambiente="sandbox"][data-theme="dark"] {
    --env-sandbox:#FF9142; --env-sandbox-fg:#12201A;
}

/* #537 — paleta rosa/roxo própria do ambiente 'local' (default de ENVIRONMENT
   quando ausente, #530), distinta de --accent/--env-sandbox/--info. Mesma
   estrutura clara/escura acima (SO via prefers-color-scheme + toggle explícito
   via data-theme="dark"). */
html[data-ambiente="local"] {
    --env-local:#9B2FBF; --env-local-fg:#FFFFFF;
}
@media (prefers-color-scheme: dark) {
    html[data-ambiente="local"]:not([data-theme="light"]) {
        --env-local:#D17EF0; --env-local-fg:#2B0A3D;
    }
}
html[data-ambiente="local"][data-theme="dark"] {
    --env-local:#D17EF0; --env-local-fg:#2B0A3D;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: var(--font-body); background: var(--canvas); color: var(--text); }

/* #306: skip-link -- fora da tela até receber foco por teclado (Tab), aí
   salta para o topo e fica visível o suficiente para ler e ativar (Enter). */
.skip-link {
    position: absolute; top: -3rem; left: .5rem; z-index: 1000;
    background: var(--sidebar-bg); color: #fff; padding: .65rem 1rem; border-radius: var(--radius-s);
    text-decoration: none; font-size: .9rem; transition: top .15s;
}
.skip-link:focus { top: .5rem; outline: 2px solid var(--signal); outline-offset: 2px; }
header { background: var(--sidebar-bg); color: #fff; padding: 1rem 2rem; display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid var(--sidebar-border); }
header .header-brand { display: flex; align-items: center; gap: 1rem; }
header .logo { height: 60px; width: auto; border-radius: 6px; }
header .company-name { font-family: var(--font-display); font-size: 1.25rem; font-weight: 700; letter-spacing: 0.04em; color: #fff; }
/* #530: selo de ambiente ao lado do nome da empresa -- header é sempre escuro
   (--sidebar-bg) nos dois temas, por isso as duas variantes usam fundo sólido
   (não o padrão --info-bg/tint, pensado para painéis claros). */
.env-badge { display: inline-block; margin-left: .7rem; padding: .15rem .6rem; border-radius: 999px; font-size: .68rem; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; vertical-align: middle; }
.env-badge-production { background: var(--info); color: #fff; }
.env-badge-sandbox { background: var(--env-sandbox); color: var(--env-sandbox-fg); }
.env-badge-local { background: var(--env-local); color: var(--env-local-fg); }
header nav a { color: #fff; text-decoration: none; }
main { padding: 0; }

/* #540: rodapé simples "Powered by JS Financial Systems" -- JSF-CONNECTOR tem
   identidade visual própria como produto (logo dedicado), mantendo o vínculo
   visível com a JSFS como mantenedora. */
.app-footer { padding: 1rem 2rem; text-align: center; border-top: 1px solid var(--border); }
.app-footer a { color: var(--text-muted); text-decoration: none; font-size: .8rem; }
.app-footer a:hover { text-decoration: underline; }

/* #647: versão do sistema (settings.APP_VERSION), ao lado do "Powered by" --
   discreta (mesmo tom apagado de .app-footer a), sem virar link. */
.app-footer-version { color: var(--text-muted); font-size: .8rem; margin-left: .5rem; }

/* Mensagens globais (django.contrib.messages) */
.messages-bar { padding: .5rem 2rem; }
.alert { padding: .65rem 1rem; border-radius: var(--radius-s); font-size: .9rem; margin-bottom: .4rem; }
.alert-error, .alert.error { background: var(--err-bg); color: var(--err); border: 1px solid var(--err); }
.alert-success, .alert.success { background: var(--ok-bg); color: var(--ok); border: 1px solid var(--ok); }
.alert-info, .alert.info { background: var(--info-bg); color: var(--info); border: 1px solid var(--info); }

/* Dashboard layout */
.dashboard-layout { display: flex; min-height: calc(100vh - 78px); }
.sidebar { width: 220px; background: var(--sidebar-bg); color: var(--sidebar-fg); padding: 1.25rem 0; flex-shrink: 0; border-right: 1px solid var(--sidebar-border); }
.sidebar-nav ul { list-style: none; }
.sidebar-nav ul li a, .sidebar-module { display: block; padding: 0.6rem 1.25rem; color: var(--sidebar-fg); text-decoration: none; font-size: 0.92rem; border-left: 3px solid transparent; transition: background 0.15s; }
.sidebar-module { cursor: default; font-family: var(--font-mono); font-size: 0.68rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--sidebar-fg-dim); }
.sidebar-nav ul li a:hover { background: #152720; color: #fff; }
.sidebar-nav ul li a.active { background: #17281F; color: #fff; border-left-color: var(--accent-on-dark); }
.sidebar-submenu { display: none; list-style: none; }
.sidebar-submenu.open { display: block; }
.sidebar-submenu li a { padding: 0.5rem 1.25rem 0.5rem 2.25rem; font-size: 0.86rem; color: var(--sidebar-fg); border-left: 3px solid transparent; }
.sidebar-submenu li a:hover { background: #152720; color: #fff; }
.sidebar-submenu li a.active { color: #fff; border-left-color: var(--accent-on-dark); background: #17281F; }
.dashboard-content { flex: 1; padding: 2rem; background: var(--canvas); }

.card { background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-m); padding: 1.5rem; margin-bottom: 1.5rem; box-shadow: var(--shadow); }
.card h3 { font-family: var(--font-display); font-weight: 700; letter-spacing: .01em; color: var(--text); margin-bottom: 1rem; }
.card p { margin-bottom: 0.4rem; }
.card-section { margin-top: 1.25rem; padding-top: 1rem; border-top: 1px solid var(--border); }
.card-section strong { display: block; margin-bottom: 0.6rem; color: var(--text); }
.user-table { width: 100%; border-collapse: collapse; font-size: 0.92rem; }
.user-table th { text-align: left; padding: 0.55rem 0.75rem; background: var(--panel-2); color: var(--text-muted); font-family: var(--font-mono); font-size: .72rem; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; border-bottom: 1px solid var(--border); }
.user-table th a { color: inherit; text-decoration: none; }
.user-table th a:hover { text-decoration: underline; }
.user-table td { padding: 0.55rem 0.75rem; border-top: 1px solid var(--border); }
/* #305: "Excluir" agora é um <button> real (não mais <a href="#">) --
   reset visual para continuar parecendo um link de ação inline na tabela. */
.btn-link-danger {
    background: none; border: none; padding: 0; margin-left: .75rem;
    color: var(--err); font: inherit; text-decoration: underline; cursor: pointer;
}
.btn-link-danger:hover { color: var(--accent-strong); }
.user-table tr:hover td { background: var(--panel-2); }
/* #351: classe compartilhada para ações inline coladas lado a lado
   (Editar/Histórico/Excluir em connections/conexao_config.html,
   Executar/Gatilhos/Histórico/Simular/Exportar em flow/lista.html) --
   substitui o antigo style="margin-left:.75rem" repetido nos templates.
   Mesmo espaçamento no desktop; alvo de toque maior em pointer:coarse (ver
   media query acima). */
.inline-action { margin-left: .75rem; }

.login-container { max-width: 400px; margin: 3rem auto; background: var(--panel); padding: 2rem; border: 1px solid var(--border); border-radius: var(--radius-m); box-shadow: var(--shadow); }
.login-container h2 { font-family: var(--font-display); font-weight: 700; margin-bottom: 1.5rem; color: var(--text); }
.form-group { margin-bottom: 1rem; }
.form-group label { display: block; margin-bottom: 0.4rem; font-weight: 500; }
.form-group input, .form-group select, .form-group textarea { width: 100%; padding: 0.6rem 0.8rem; border: 1px solid var(--border-strong); border-radius: var(--radius-s); font-size: 1rem; background: var(--panel); color: var(--text); }
/* #304: além da troca de cor da borda, um anel (box-shadow) reforça o
   indicador de foco -- mais visível em telas com brilho alto ou ao navegar
   rapidamente por Tab. outline permanece none só porque box-shadow já cobre
   o mesmo papel visual (evita anel duplicado). */
.form-group input:focus, .form-group select:focus, .form-group textarea:focus {
    outline: none;
    border-color: var(--signal);
    box-shadow: 0 0 0 3px rgba(47,169,154,.22);
}
.form-error { color: var(--err); margin-bottom: 1rem; font-size: 0.9rem; }
button[type="submit"] { width: 100%; padding: 0.75rem; background: var(--accent); color: #fff; border: none; border-radius: var(--radius-s); font-size: 1rem; cursor: pointer; margin-top: 0.5rem; }
button[type="submit"]:hover { background: var(--accent-strong); }

/* Header nav (usuário + logout) */
.header-nav { display: flex; align-items: center; gap: 1.25rem; }
.header-nav a { color: var(--sidebar-fg); font-size: 0.9rem; }
.header-nav a:hover { color: #fff; }
.header-nav .header-user { color: #fff; font-size: 0.9rem; font-weight: 600; }
.logout-form { margin: 0; }
.header-nav .logout-form button { width: auto; margin: 0; padding: 0.4rem 0.9rem; background: transparent; border: 1px solid rgba(255,255,255,0.35); color: #fff; border-radius: var(--radius-s); font-size: 0.85rem; cursor: pointer; }
.header-nav .logout-form button:hover { background: rgba(255,255,255,0.12); }

/* Login: logo no card */
.login-logo { display: block; height: 64px; width: auto; border-radius: 8px; margin: 0 auto 1rem; }
.login-container h2 { text-align: center; }

/* Landing pública */
.landing { max-width: 720px; margin: 4rem auto; text-align: center; padding: 0 1.5rem; }
.landing-logo { height: 96px; width: auto; border-radius: 10px; margin-bottom: 1.5rem; }
.landing h1 { font-family: var(--font-display); font-weight: 800; color: var(--text); font-size: 2.1rem; margin-bottom: 0.75rem; letter-spacing: 0.02em; }
.landing p { color: var(--text-muted); font-size: 1.05rem; margin-bottom: 2rem; line-height: 1.5; }
.btn-primary { display: inline-block; padding: 0.75rem 2rem; background: var(--accent); color: #fff; text-decoration: none; border-radius: var(--radius-m); font-size: 1rem; transition: background 0.15s; }
.btn-primary:hover { background: var(--accent-strong); }

/* Avisos */
.alert-warning { background: var(--warn-bg); border: 1px solid var(--warn); color: var(--warn); padding: 0.75rem 1rem; border-radius: var(--radius-m); margin-bottom: 1.25rem; font-size: 0.92rem; }
.alert-success { background: var(--ok-bg); border: 1px solid var(--ok); color: var(--ok); padding: 0.75rem 1rem; border-radius: var(--radius-m); margin-bottom: 1.25rem; font-size: 0.92rem; }
.alert-error { background: var(--err-bg); border: 1px solid var(--err); color: var(--err); padding: 0.75rem 1rem; border-radius: var(--radius-m); margin-bottom: 1.25rem; font-size: 0.92rem; }

/* Botão "Testar Conexão" (secundário) */
.testar-form { margin-top: 1rem; }
.testar-form .btn-test { width: auto; margin: 0; padding: 0.6rem 1.2rem; background: var(--signal); color: #fff; border: none; border-radius: var(--radius-s); font-size: 0.95rem; cursor: pointer; }
.testar-form .btn-test:hover { background: #26877b; }

/* Modal de confirmação */
.modal-overlay { display: none; position: fixed; inset: 0; background: rgba(10,21,18,0.55); z-index: 9999; align-items: center; justify-content: center; }
.modal-overlay.open { display: flex; }
.modal-box { background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-m); padding: 1.5rem; width: 420px; max-width: 95vw; box-shadow: var(--shadow); }
.btn-cancel { padding: 0.5rem 1.1rem; background: var(--panel-2); color: var(--text); border: 1px solid var(--border-strong); border-radius: var(--radius-s); font-size: 0.9rem; cursor: pointer; }
.btn-cancel:hover { background: var(--border); }
/* #422: .btn-danger fora de .modal-box (ex.: form "Cancelar execução" em
   executions/detalhe.html) não tinha nenhuma regra própria -- caía no estilo
   genérico de button[type="submit"] (azul), perdendo o destaque visual de
   ação potencialmente destrutiva. Mesma aparência do já usado dentro de
   .modal-box, só sem a dependência desse contexto. */
.btn-danger { width: auto; margin: 0; padding: 0.5rem 1.1rem; background: var(--err); color: #fff; border: none; border-radius: var(--radius-s); font-size: 0.9rem; cursor: pointer; }
.btn-danger:hover { background: #9a3030; }

/* ── Toast de feedback de ações assíncronas (#308) ── */
.jsf-toast-container {
    position: fixed; bottom: 1.25rem; right: 1.25rem; z-index: 10000;
    display: flex; flex-direction: column; gap: .5rem; max-width: 360px;
}
.jsf-toast {
    padding: .75rem 1rem; border-radius: var(--radius-m); font-size: .9rem; color: #fff;
    box-shadow: var(--shadow); animation: jsf-toast-entrar .15s ease-out;
}
.jsf-toast-saindo { opacity: 0; transform: translateY(6px); transition: opacity .2s, transform .2s; }
.jsf-toast-loading { background: var(--text-muted); }
.jsf-toast-info { background: var(--info); }
.jsf-toast-success { background: var(--ok); }
.jsf-toast-error { background: var(--err); }
@keyframes jsf-toast-entrar { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }

/* ── Busca global / command palette (Ctrl+K, #307) ── */
.header-search-btn {
    background: rgba(255,255,255,0.08); color: var(--sidebar-fg); border: 1px solid rgba(255,255,255,0.15);
    border-radius: var(--radius-s); padding: .35rem .7rem; font-size: .85rem; cursor: pointer;
    display: flex; align-items: center; gap: .4rem;
}
.header-search-btn:hover { background: rgba(255,255,255,0.15); color: #fff; }
.header-search-shortcut {
    font-family: var(--font-mono); font-size: .72rem; padding: .05rem .35rem; border-radius: 3px;
    background: rgba(255,255,255,0.12); color: var(--sidebar-fg-dim);
}
.jsf-search-overlay { align-items: flex-start; justify-content: center; padding-top: 10vh; }
.jsf-search-box { width: 600px; max-width: 92vw; padding: 0; overflow: hidden; }
.jsf-search-input {
    width: 100%; border: none; border-bottom: 1px solid var(--border); padding: 1rem 1.25rem;
    font-size: 1.05rem; outline: none; background: var(--panel); color: var(--text);
}
.jsf-search-resultados { list-style: none; max-height: 50vh; overflow-y: auto; }
.jsf-search-item {
    display: flex; align-items: baseline; gap: .6rem; padding: .7rem 1.25rem; cursor: pointer;
    border-left: 3px solid transparent;
}
.jsf-search-item.active, .jsf-search-item:hover { background: var(--panel-2); border-left-color: var(--accent); }
.jsf-search-tipo {
    font-family: var(--font-mono); font-size: .68rem; text-transform: uppercase; letter-spacing: .04em; color: var(--text-muted);
    background: var(--panel-2); border: 1px solid var(--border); padding: .1rem .45rem; border-radius: 3px; flex-shrink: 0;
}
.jsf-search-nome { font-weight: 500; color: var(--text); flex: 1; }
.jsf-search-subtitulo { font-size: .82rem; color: var(--text-muted); }
.jsf-search-vazio { padding: 1rem 1.25rem; color: var(--text-muted); font-size: .9rem; }

/* ── Paginação ── */
.pagination { display: flex; align-items: center; gap: .75rem; margin-top: 1rem; flex-wrap: wrap; }
.page-btn { padding: .4rem .9rem; background: var(--panel-2); border: 1px solid var(--border-strong); border-radius: var(--radius-s); text-decoration: none; color: var(--text); font-size: .88rem; }
.page-btn:hover { background: var(--border); }
.page-info { font-family: var(--font-mono); font-size: .82rem; color: var(--text-muted); }

/* Modal grande que hospeda criação/edição de fluxo num iframe */
.flow-modal-overlay { display: none; position: fixed; inset: 0; background: rgba(10,21,18,0.55); z-index: 1000; align-items: center; justify-content: center; }
.flow-modal-overlay.open { display: flex; }
.flow-modal-box { background: var(--panel); border-radius: var(--radius-m); overflow: hidden; width: 95vw; height: 92vh; max-width: 1400px; display: flex; flex-direction: column; box-shadow: 0 10px 40px rgba(10,21,18,0.3); }
.flow-modal-head { display: flex; align-items: center; justify-content: space-between; padding: 0.5rem 0.9rem; border-bottom: 1px solid var(--border); background: var(--panel-2); }
.flow-modal-head h3 { margin: 0; font-size: 0.95rem; }
.flow-modal-close { border: none; background: transparent; font-size: 1.5rem; line-height: 1; cursor: pointer; color: var(--text-muted); padding: 0 0.3rem; }
.flow-modal-close:hover { color: var(--err); }
.flow-modal-frame { flex: 1; border: 0; width: 100%; }

/* Conteúdo renderizado dentro do iframe do modal (sem header/sidebar) */
body.modal-embed { background: var(--panel); }
body.modal-embed main { min-height: 100vh; }
body.modal-embed .flow-editor { height: 100vh; }
.modal-form-wrap { padding: 1.5rem; }

/* Menu do usuário (header) — dropdown com empresas */
.user-menu { position: relative; }
.user-menu-toggle { background: transparent; border: none; color: #fff; font-size: 0.9rem; font-weight: 600; cursor: pointer; display: flex; align-items: center; gap: 0.35rem; padding: 0.3rem 0; }
.user-menu-toggle .caret { font-size: 0.7rem; color: var(--sidebar-fg); }
.user-menu-dropdown { display: none; position: absolute; right: 0; top: calc(100% + 0.5rem); min-width: 230px; max-height: 60vh; overflow-y: auto; background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-m); box-shadow: var(--shadow); padding: 0.4rem 0; z-index: 1000; }
.user-menu-dropdown.open { display: block; }
.user-menu-label { font-family: var(--font-mono); font-size: 0.64rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-muted); padding: 0.4rem 1rem 0.3rem; }
.user-menu-divider { height: 1px; background: var(--border); margin: 0.4rem 0; }
.user-menu-dropdown .user-menu-item { display: block; width: 100%; text-align: left; background: transparent; border: none; border-radius: 0; margin: 0; padding: 0.5rem 1rem; font-size: 0.88rem; color: var(--text); cursor: pointer; }
.user-menu-dropdown .user-menu-item:hover { background: var(--panel-2); }
.user-menu-dropdown .user-menu-item.active { color: var(--accent-strong); font-weight: 600; }

/* ── Central de notificações (sino no header, #313) ── */
.notif-bell { position: relative; font-size: 1.1rem; padding: 0.3rem 0.5rem; }
.notif-badge { position: absolute; top: -2px; right: -2px; background: var(--err); color: #fff; font-size: 0.65rem; font-weight: 700; min-width: 16px; height: 16px; border-radius: 8px; display: flex; align-items: center; justify-content: center; padding: 0 3px; line-height: 1; }
.notif-dropdown { min-width: 280px; }
.notif-item { border-left: 3px solid transparent; }
.notif-item.notif-nivel-erro { border-left-color: var(--err); }
.notif-item.notif-nivel-aviso { border-left-color: var(--warn); }

/* ── Dashboard: cabeçalho de seção ── */
.dash-section-title { font-family: var(--font-display); font-size: .95rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--text); margin-bottom: .75rem; display: flex; align-items: center; gap: .6rem; }
.dash-plan-badge { font-family: var(--font-mono); background: var(--panel); border: 1px solid var(--border-strong); color: var(--accent); font-size: .68rem; padding: 2px 8px; border-radius: 20px; text-transform: uppercase; letter-spacing: .04em; font-weight: 600; }
.dash-plan-link { margin-left: auto; font-size: .8rem; color: var(--accent); text-decoration: none; font-weight: 500; text-transform: none; letter-spacing: 0; }
.dash-plan-link:hover { text-decoration: underline; }

/* ── Dashboard: métricas de uso -> "stat tiles" (proposta malha de sinal) ── */
.dash-metrics { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; margin-bottom: 1.5rem; }
.metric-card { position: relative; background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-m); padding: 1.25rem; box-shadow: var(--shadow); display: flex; flex-direction: column; gap: .6rem; }
/* Corner tick: marca de canto (estilo trilha de PCB) do esboço. */
.metric-card::before {
    content: ""; position: absolute; top: 10px; right: 10px; width: 16px; height: 16px;
    border-top: 1px solid var(--border-strong); border-right: 1px solid var(--border-strong);
    pointer-events: none;
}
.metric-icon { font-size: 1.4rem; line-height: 1; }
.metric-body { flex: 1; }
.metric-label { font-family: var(--font-mono); font-size: .72rem; letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted); margin-bottom: .25rem; }
.metric-value { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: 1.7rem; font-weight: 600; color: var(--text); line-height: 1.1; }
/* #309: card de saúde de conexões no dashboard -- destaca em vermelho quando
   há conexões em falha (mesmo tom de .bar-danger abaixo). */
.metric-value-danger { color: var(--err); }
.metric-value-ok { color: var(--ok); }
.metric-limit { font-family: var(--font-mono); font-size: 1rem; font-weight: 400; color: var(--text-muted); }
.metric-bar { height: 6px; background: var(--border); border-radius: 3px; margin-top: .5rem; overflow: hidden; }
.metric-bar-fill { height: 100%; background: var(--ok); border-radius: 3px; transition: width .3s; }
.metric-bar-fill.bar-warn { background: var(--warn); }
.metric-bar-fill.bar-danger { background: var(--err); }
.metric-action { font-size: .8rem; color: var(--accent); text-decoration: none; align-self: flex-end; }
.metric-action:hover { text-decoration: underline; }

/* ── Dashboard: malha de conexões (#332) — hub central + nós dos fornecedores,
   sinal animado nas conexões saudáveis. Coordenadas vêm da view (core.views). ── */
.network-card { position: relative; background: var(--panel-2); border: 1px solid var(--border); border-radius: var(--radius-m); box-shadow: var(--shadow); padding: 1.25rem 1.25rem 0.5rem; margin-bottom: 1.5rem; }
.network-card svg { width: 100%; height: auto; display: block; overflow: visible; }
/* #506: modo "ver mapa completo" -- o SVG ganha largura real (view_w, maior
   que os 900px padrão) em vez de encolher para caber (width:100%), então o
   contêiner rola horizontalmente (mesmo princípio de "pan" sugerido na
   pendência) em vez de espremer todos os nós na mesma largura fixa. */
.network-card-expandida { overflow-x: auto; }
.network-card-expandida svg { width: auto; min-width: 100%; }
.net-line { fill: none; stroke: var(--border-strong); stroke-width: 1.4; }
.net-line.live { stroke: var(--signal); stroke-dasharray: 5 4; animation: net-flow 1.6s linear infinite; }
.net-line.pending { stroke: var(--border-strong); stroke-dasharray: 2 5; }
.net-node { fill: var(--panel); stroke: var(--border-strong); stroke-width: 1.4; }
.net-node.live { stroke: var(--signal); }
.net-hub { fill: var(--accent); stroke: none; }
.net-label { font-family: var(--font-mono); font-size: 10.5px; fill: var(--text-muted); }
.net-label.hub { fill: var(--text); font-weight: 700; font-size: 11px; }
@keyframes net-flow { to { stroke-dashoffset: -18; } }
@media (prefers-reduced-motion: reduce) { .net-line.live { animation: none; } }

/* #380/#381: nós "disponíveis" (fornecedor do catálogo ainda sem conexão) --
   tracejado com "+", clicável, leva ao wizard já pré-selecionado nesse
   fornecedor (ver wzSelectProvider em wizard.html). */
.net-node-add-link { cursor: pointer; }
.net-node-add { fill: var(--panel); stroke: var(--border-strong); stroke-width: 1.4; stroke-dasharray: 2 2; }
.net-node-add-plus { font-family: var(--font-mono); font-size: 9px; fill: var(--text-muted); pointer-events: none; }
.net-label-add { fill: var(--text-muted); }
.net-label-add-cta { fill: var(--accent); font-weight: 600; font-size: 9.5px; }
.net-node-add-link:hover .net-node-add,
.net-node-add-link:focus .net-node-add { stroke: var(--accent); fill: var(--accent); fill-opacity: .12; }
.net-node-add-link:hover .net-node-add-plus,
.net-node-add-link:hover .net-label-add,
.net-node-add-link:focus .net-node-add-plus,
.net-node-add-link:focus .net-label-add { fill: var(--accent); }

/* #454: nós com conexão em falha (ConexaoConfig.health_status='falha') --
   badge de alerta ("!" num círculo vermelho) colado no canto do nó + link
   clicável direto para editar a conexão específica que está falhando
   (mesmo padrão de affordance clicável do nó "+ Incluir" acima). */
.net-line.falha { stroke: var(--err); stroke-dasharray: 3 3; }
.net-node-falha-link { cursor: pointer; }
.net-node.falha { stroke: var(--err); fill: var(--err-bg); }
.net-node-badge { fill: var(--err); stroke: var(--panel-2); stroke-width: 1.2; }
.net-node-badge-mark { font-family: var(--font-mono); font-size: 7px; font-weight: 700; fill: #fff; pointer-events: none; }
.net-label-falha { fill: var(--err); font-weight: 600; }
.net-label-falha-cta { fill: var(--err); font-weight: 600; font-size: 9.5px; }
.net-node-falha-link:hover .net-node.falha,
.net-node-falha-link:focus .net-node.falha { fill-opacity: .35; }

.net-legend { display: flex; flex-wrap: wrap; gap: 1.1rem; padding: .5rem 0 .75rem; font-size: .78rem; color: var(--text-muted); }
.net-legend-item { display: inline-flex; align-items: center; gap: .4rem; }
.net-legend-dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; border: 1.4px solid var(--border-strong); background: var(--panel); }
.net-legend-dot.falha { border-color: var(--err); background: var(--err); }
.net-legend-dot.live { border-color: var(--signal); background: var(--signal); }
.net-legend-dot.add { border-style: dashed; }

/* ── Dashboard: checklist de onboarding (#166) ── */
.onboarding-checklist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .6rem; }
.onboarding-item { display: flex; align-items: center; gap: .75rem; padding: .5rem 0; }
.onboarding-check { flex: 0 0 auto; width: 24px; height: 24px; border-radius: 50%; background: var(--panel-2); border: 1px solid var(--border-strong); color: var(--text-muted); font-family: var(--font-mono); font-size: .78rem; font-weight: 700; display: flex; align-items: center; justify-content: center; }
.onboarding-item.done .onboarding-check { background: var(--ok-bg); border-color: var(--ok); color: var(--ok); }
.onboarding-text { flex: 1; color: var(--text); }
.onboarding-item.done .onboarding-text { color: var(--text-muted); text-decoration: line-through; }
.onboarding-cta { font-size: .85rem; color: var(--accent); text-decoration: none; font-weight: 500; white-space: nowrap; }
.onboarding-cta:hover { text-decoration: underline; }
.onboarding-tour-link { font-size: .82rem; color: var(--text-muted); text-decoration: none; }
.onboarding-tour-link:hover { color: var(--accent); text-decoration: underline; }

/* #354: tour guiado de onboarding (static/js/main.js, IIFE final). O
   "spotlight" é o próprio elemento posicionado sobre o alvo real (via
   getBoundingClientRect) com um box-shadow gigante -- não é uma div cobrindo
   a tela inteira, então o resto da página continua clicável (tour leve, não
   um modal bloqueante). */
.jsf-tour-spotlight {
    position: fixed; z-index: 9000; border-radius: var(--radius-m);
    box-shadow: 0 0 0 9999px rgba(0,0,0,.65);
    pointer-events: none;
    transition: top .2s ease, left .2s ease, width .2s ease, height .2s ease;
}
.jsf-tour-tip {
    position: fixed; z-index: 9001; width: 320px; max-width: calc(100vw - 24px);
    background: var(--panel); color: var(--text); border: 1px solid var(--border-strong);
    border-radius: var(--radius-m); box-shadow: var(--shadow); padding: 1rem 1.1rem;
}
.jsf-tour-tip-passo { font-family: var(--font-mono); font-size: .68rem; font-weight: 600; text-transform: uppercase; letter-spacing: .06em; color: var(--text-muted); margin-bottom: .3rem; }
.jsf-tour-tip-titulo { font-weight: 700; margin-bottom: .35rem; }
.jsf-tour-tip-texto { font-size: .88rem; color: var(--text-muted); line-height: 1.4; margin-bottom: .9rem; }
.jsf-tour-tip-acoes { display: flex; align-items: center; gap: .5rem; }
.jsf-tour-pular { background: none; border: none; padding: 0; color: var(--text-muted); text-decoration: underline; cursor: pointer; font-size: .82rem; }
.jsf-tour-pular:hover { color: var(--accent); }

/* Badges de status nas execuções recentes -> "pills" (proposta malha de sinal) */
.run-badge { display: inline-flex; align-items: center; gap: 5px; font-family: var(--font-mono); padding: 2px 8px; border-radius: 99px; font-size: .72rem; font-weight: 600; }
.run-badge::before { content: ""; width: 5px; height: 5px; border-radius: 50%; }
.badge-success { background: var(--ok-bg); color: var(--ok); }
.badge-success::before { background: var(--ok); }
.badge-error { background: var(--err-bg); color: var(--err); }
.badge-error::before { background: var(--err); }
.badge-running { background: var(--info-bg); color: var(--info); }
.badge-running::before { background: var(--info); }
.badge-queued { background: var(--panel-2); color: var(--text-muted); }
.badge-queued::before { background: var(--text-muted); }

/* ── Campo obrigatório (*) e dica de campo (?) ── */
.form-req { color: var(--err); font-style: normal; text-decoration: none; cursor: default; margin-left: 2px; font-weight: 700; }
/* #302: botão real (não mais <abbr title>) -- abre um popover ao
   toque/clique/foco+Enter (ver static/js/main.js), em vez de depender só de
   hover (que não existe em touch). Reset de aparência de botão nativo para
   manter o mesmo badge circular "?" de antes. */
.form-help {
    display: inline-flex; align-items: center; justify-content: center;
    width: 14px; height: 14px; border-radius: 50%;
    background: var(--signal); color: #fff;
    font: inherit; font-size: .67rem; font-style: normal; font-weight: 700;
    text-decoration: none; cursor: pointer; margin-left: 3px;
    border: 1px solid var(--signal); vertical-align: middle;
    padding: 0; appearance: none; -webkit-appearance: none; line-height: 1;
}
.form-help:hover, .form-help:focus-visible { background: #26877b; outline: none; }
.form-help:focus-visible { box-shadow: 0 0 0 2px rgba(47,169,154,.4); }
.form-help-pop {
    position: absolute; z-index: 2000;
    max-width: 260px;
    background: var(--sidebar-bg); color: #fff;
    font-size: .78rem; line-height: 1.35;
    padding: .5rem .65rem; border-radius: var(--radius-m);
    box-shadow: var(--shadow);
}

/* #351: alvos de toque abaixo de 44x44px (badge de ajuda, botão ƒx do editor
   de fluxo, setas de ordenação das tabelas, ações inline Editar/Histórico/
   Excluir). Só em pointer:coarse (dedo/touch) -- não altera nada no desktop
   (mouse = pointer:fine, fora desta media query). O badge/botão ganham uma
   área de toque invisível maior via ::after (sem inflar o tamanho visual);
   os links de ação inline (classe .inline-action, ver templates de
   connections/flow) e o botão "Excluir" (.btn-link-danger) ganham
   padding/min-height e mais espaçamento entre si, pois aqui são só texto e
   crescer a área de toque também cresce a área visível -- inevitável e aceito
   nesse caso (mesmo critério de #350, telas de toque já reorganizam o
   layout). */
@media (pointer: coarse) {
    .form-help { position: relative; }
    .form-help::after {
        content: ""; position: absolute;
        top: 50%; left: 50%; width: 44px; height: 44px;
        transform: translate(-50%, -50%);
    }
    .inline-action {
        display: inline-flex; align-items: center;
        min-height: 44px; padding: 0 .35rem; margin-left: 1rem;
    }
    .btn-link-danger {
        display: inline-flex; align-items: center;
        min-height: 44px; padding: 0 .35rem;
    }
    /* #453: o botão do menu suspenso de empresas (nome do usuário no header)
       só tinha padding vertical (.user-menu-toggle base, padding: .3rem 0) --
       em pointer:coarse a área de toque real ficava restrita à largura exata
       do texto do nome, colada na borda direita do header, fazendo o toque
       (especialmente perto da borda, comum em Chrome mobile) errar o alvo e
       o dropdown nunca abrir. Mesmo tratamento de alvo mínimo 44px do restante
       deste bloco; cobre também .notif-bell (mesma classe base). */
    .user-menu-toggle {
        min-height: 44px;
        padding: .3rem .5rem;
    }
}

/* ── #299: responsividade ── */
/* Botão ☰ que abre a sidebar como gaveta -- só existe visualmente abaixo do
   breakpoint (ver media query); acima disso a sidebar já fica sempre visível
   no fluxo normal do layout (.dashboard-layout). */
.sidebar-toggle-btn {
    display: none;
    background: transparent;
    border: 1px solid rgba(255,255,255,0.4);
    color: #fff;
    border-radius: var(--radius-s);
    padding: 0.3rem 0.65rem;
    font-size: 1.15rem;
    line-height: 1;
    cursor: pointer;
}
.sidebar-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(10,21,18,0.45);
    z-index: 1000;
}

/* ── #333: responsividade mobile (Chrome Android/iOS) ──
   Antes o único breakpoint era 960px (gaveta da sidebar). Adicionados dois
   ajustes finos abaixo: header/topbar em telas médias e o "aperto" de padding
   e tipografia nas telas realmente estreitas (<560px, celular em retrato). */

@media (max-width: 960px) {
    .sidebar-toggle-btn { display: inline-flex; align-items: center; justify-content: center; }

    /* Sidebar vira gaveta off-canvas; body.sidebar-open (JS no base.html)
       controla abrir/fechar. O overlay fecha ao clicar fora. */
    .dashboard-layout { position: relative; }
    .sidebar {
        position: fixed;
        top: 0; bottom: 0; left: -240px;
        width: 220px;
        z-index: 1001;
        overflow-y: auto;
        transition: left 0.2s ease;
    }
    body.sidebar-open .sidebar { left: 0; }
    body.sidebar-open .sidebar-overlay { display: block; }
    .dashboard-content { padding: 1rem; }

    /* Tabelas densas: rolagem horizontal em vez de espremer/quebrar colunas
       (ex.: listagem de Conexões com 10 colunas, conexao_config.html). */
    .user-table { display: block; overflow-x: auto; white-space: nowrap; }
}

/* Header/topbar: em telas médias o header pode ficar apertado com muitos
   itens de nav -- permite quebrar em duas linhas e reduz o padding lateral. */
@media (max-width: 760px) {
    header { padding: 0.75rem 1rem; flex-wrap: wrap; gap: .5rem; }
    header .logo { height: 44px; }
    header .company-name { font-size: 1.05rem; }
    .header-nav { gap: .75rem; flex-wrap: wrap; row-gap: .5rem; }
    /* Rótulo textual do botão de busca some em telas médias; o ícone 🔍 e o
       atalho Ctrl+K continuam (o modal abre por clique ou pelo atalho). */
    .header-search-btn { padding: .35rem .55rem; }
    .messages-bar { padding: .5rem 1rem; }
}

/* Telas estreitas de celular (retrato): aperta ainda mais e garante que
   modais, dropdowns e a busca global caibam na largura útil. */
@media (max-width: 560px) {
    .dashboard-content { padding: .85rem; }
    .card { padding: 1rem; }
    .dash-metrics { grid-template-columns: 1fr; gap: .75rem; }
    /* Dropdowns do header (empresas/notificações) não podem estourar a tela:
       ancoram na largura da viewport com uma pequena margem. */
    .user-menu-dropdown { position: fixed; right: .5rem; left: auto; min-width: 0; width: calc(100vw - 1rem); max-width: 320px; }
    .notif-dropdown { max-width: 320px; }
    /* Command palette ocupa quase toda a largura no celular. */
    .jsf-search-box { width: 96vw; }
    .jsf-search-overlay { padding-top: 6vh; }
    /* Busca do header vira só o ícone (economiza espaço na barra). */
    .header-search-btn .header-search-shortcut { display: none; }
    /* Toast não pode ocupar a tela inteira nem colar nas bordas. */
    .jsf-toast-container { left: .75rem; right: .75rem; max-width: none; }
    /* Modais de confirmação com padding menor. */
    .modal-box { padding: 1.1rem; }

    /* #350: tabelas marcadas com .table-cards viram cards empilhados no celular
       (retrato) em vez de rolagem horizontal de N colunas. Cada <td> vira uma
       linha rótulo→valor, usando o data-label do próprio td como rótulo.
       Tabelas sem .table-cards mantêm o overflow-x do breakpoint de 960px. */
    .user-table.table-cards { display: block; overflow-x: visible; white-space: normal; }
    .user-table.table-cards thead { display: none; }
    .user-table.table-cards tbody { display: block; }
    .user-table.table-cards tr { display: block; border: 1px solid var(--border); border-radius: var(--radius-m); margin-bottom: .75rem; padding: .35rem .75rem; background: var(--panel); }
    .user-table.table-cards td { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; padding: .4rem 0; border: none; border-top: 1px solid var(--border); text-align: right; }
    .user-table.table-cards tr td:first-child { border-top: none; }
    .user-table.table-cards td::before { content: attr(data-label); font-family: var(--font-mono); font-size: .68rem; font-weight: 600; text-transform: uppercase; letter-spacing: .05em; color: var(--text-muted); text-align: left; flex: 0 0 auto; }
    /* td sem data-label (coluna de ações) ocupa a linha inteira, sem rótulo. */
    .user-table.table-cards td:not([data-label]) { justify-content: flex-start; text-align: left; }
    .user-table.table-cards td:not([data-label])::before { content: none; }
    .user-table.table-cards tr:hover td { background: transparent; }
}

/* ============================================================================
   #347 — Camada de utilitários (migração de estilos inline → tokens)
   Classes utilitárias mínimas para substituir os padrões `style="..."` mais
   repetidos nos templates do front-end. Todas consomem os tokens de :root,
   então herdam automaticamente o tema (claro/escuro do #349). Objetivo: tirar
   cor/hex hardcoded de dentro do HTML — não é um framework utilitário completo.
   ============================================================================ */
/* Cabeçalho de página: título à esquerda + ação à direita, quebra no mobile. */
.u-page-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; margin-bottom: 1rem; }
.u-page-head h2 { margin: 0; }
/* #353: trilha de navegação (templates/core/_breadcrumb.html) -- telas
   profundas (detalhe de Fornecedor de API, detalhe de Execução, editar
   Conexão) só tinham o estado "active" da sidebar como orientação. */
.breadcrumb { margin-bottom: .75rem; font-size: .82rem; }
.breadcrumb-list { list-style: none; display: flex; flex-wrap: wrap; align-items: center; gap: .35rem; margin: 0; padding: 0; }
.breadcrumb-item { display: flex; align-items: center; gap: .35rem; color: var(--text-muted); }
.breadcrumb-item:not(:first-child)::before { content: "›"; color: var(--text-muted); }
.breadcrumb-item a { color: var(--text-muted); text-decoration: none; }
.breadcrumb-item a:hover { color: var(--accent); text-decoration: underline; }
.breadcrumb-item span[aria-current="page"] { color: var(--text); font-weight: 600; }

/* #360: views salvas (templates/core/_views_salvas.html) -- combinação de
   filtro/ordenação nomeada, para não refazer os mesmos filtros a cada
   visita numa listagem (Conexões, Execuções). */
.views-salvas-bar { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; margin-bottom: 1rem; }
.view-salva-chip { display: inline-flex; align-items: center; gap: .3rem; background: var(--panel-2); border: 1px solid var(--border); border-radius: 999px; padding: .25rem .4rem .25rem .75rem; font-size: .82rem; }
.view-salva-link { color: var(--text); text-decoration: none; }
.view-salva-link:hover { color: var(--accent); text-decoration: underline; }
.view-salva-excluir-form { display: inline-flex; margin: 0; }
.view-salva-excluir { background: none; border: none; padding: 0 .3rem; color: var(--text-muted); cursor: pointer; font-size: 1rem; line-height: 1; }
.view-salva-excluir:hover { color: var(--err); }
.view-salva-salvar-form { display: inline-flex; align-items: center; gap: .4rem; }
.view-salva-nome-input { padding: .35rem .6rem; border: 1px solid var(--border-strong); border-radius: var(--radius-s); font-size: .82rem; background: var(--panel); color: var(--text); width: 160px; }
.view-salva-salvar-btn { padding: .35rem .75rem; font-size: .82rem; }

/* Cores semânticas (sempre via token — nunca hex no template). */
.u-muted { color: var(--text-muted); }
.u-accent { color: var(--accent); }
.u-ok { color: var(--ok); }
.u-warn { color: var(--warn); }
.u-err { color: var(--err); }
.u-info { color: var(--info); }
/* Número-destaque de cartão de indicador (SaaS Admin: total de empresas, MRR).
   A cor vem de uma das classes semânticas acima (.u-info/.u-ok/...). */
.u-stat { font-family: var(--font-display); font-size: 2rem; font-weight: 700; line-height: 1.15; }
/* Tamanhos de fonte recorrentes. */
.u-text-sm { font-size: .88rem; }
.u-text-xs { font-size: .82rem; }
.u-fw-600 { font-weight: 600; }
/* Espaçamentos verticais recorrentes. */
.u-mt-1 { margin-top: .75rem; }
.u-mt-2 { margin-top: 1.5rem; }
.u-mb-1 { margin-bottom: 1rem; }
.u-mb-2 { margin-bottom: 1.5rem; }
/* Card "rente": sem padding e com overflow escondido (hospeda tabela full-bleed). */
.u-card-flush { padding: 0; overflow: hidden; }
/* Estado vazio centralizado de tabela/listagem. */
.u-empty { text-align: center; padding: 2rem 1rem; color: var(--text-muted); }
/* Linha flex genérica com gap. */
.u-row { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.u-row-gap-1 { gap: 1rem; }
/* Divisória "Webhooks" reutilizada em conexão/detalhe de fornecedor. */
.u-webhook-divider { margin: .7rem 0 .25rem; padding: .25rem .6rem; background: var(--warn-bg); border-left: 3px solid var(--warn); border-radius: var(--radius-s); font-size: .74rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--warn); }
/* Link "SaaS Admin" no header (destaque cobre que funciona sobre o header escuro). */
.header-nav a.header-saas { color: var(--accent-on-dark); }
.header-nav a.header-saas:hover { color: #fff; }
/* Item vazio de dropdown (ex.: "Nenhuma notificação"). */
.user-menu-dropdown .user-menu-item.is-empty { cursor: default; color: var(--text-muted); }
/* Card de aviso de trial no dashboard (faixa informativa à esquerda). */
.dash-trial { margin-bottom: 1rem; border-left: 3px solid var(--info); }
/* Rótulo de campo de filtro (listagens com filtro GET inline). */
.filter-label { display: block; font-size: .82rem; color: var(--text-muted); margin-bottom: .3rem; }
/* Botão/link secundário "outline" (Templates/Importar/Gerar IA na lista de fluxos). */
.btn-outline { display: inline-block; padding: .5rem 1.1rem; font-size: .9rem; border: 1px solid var(--border-strong); border-radius: var(--radius-s); color: var(--text); text-decoration: none; background: var(--panel); cursor: pointer; }
.btn-outline:hover { background: var(--panel-2); }

/* #433: Billing — Minha Assinatura. Estilos extraídos de style="..." inline
   (destoavam do padrão de classes centralizadas do resto do app) para as
   classes abaixo; cores/pesos/tamanhos genéricos usam as utilities .u-*
   já existentes (ver "Cores semânticas" acima). */
.billing-card { max-width: 600px; }
.billing-card-wide { max-width: 700px; }
.billing-section-title { margin-bottom: .75rem; }
.billing-pending { margin-bottom: 1rem; border-left: 3px solid var(--warn); }
.billing-pending-btn { padding: .4rem 1rem; font-size: .85rem; }
.billing-plan-price-note { font-size: .85rem; }
.billing-plan-list { margin: .5rem 0 0 1rem; font-size: .88rem; }
.billing-usage { margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--border); }
.billing-usage-row { display: flex; justify-content: space-between; font-size: .82rem; }
.billing-usage-warn { margin-top: .4rem; font-size: .8rem; }
.billing-status { margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--border); font-size: .88rem; }
.billing-history-table { margin-bottom: 1.5rem; }
.billing-history-subtitle { margin: 0 0 .5rem; font-size: .9rem; }
.billing-footer-note { margin-top: 2rem; font-size: .85rem; }
/* Grade comparativa de planos ("Alterar plano"). */
.plan-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; max-width: 700px; }
.plan-card { background: var(--panel); border: 1px solid var(--border-strong); border-radius: 8px; padding: 1rem; }
.plan-card.is-current { border-color: var(--info); }
.plan-card-name { font-weight: 600; }
.plan-card-price { font-size: .85rem; margin: .25rem 0 .75rem; }
.plan-card-features { list-style: none; margin: 0 0 .6rem; padding: 0; font-size: .78rem; }
.plan-card-current-badge { font-size: .8rem; font-weight: 500; }
.plan-card-consult-note { font-size: .78rem; margin-bottom: .5rem; }
.plan-card-btn { padding: .35rem .8rem; font-size: .82rem; }
/* #581: seletor de forma de pagamento (Pix/Cartão) no card de cada plano. */
.plan-card-forma-pagamento { border: 0; margin: 0 0 .5rem; padding: 0; display: flex; gap: .75rem; }
.plan-card-forma-pagamento-opcao { font-size: .78rem; display: flex; align-items: center; gap: .25rem; font-weight: 400; }

/* #536: tela "Saldo Pré-pago" (Grupo A + Consultoria). */
.saldo-prepago-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 1rem; margin-bottom: 1.5rem; }
.saldo-prepago-valor { font-size: 1.6rem; font-weight: 600; margin: 0 0 .75rem; }
.saldo-prepago-recarga-form { margin-bottom: 1rem; }
.saldo-prepago-recarga-linha { display: flex; gap: .5rem; margin-top: .25rem; }
.saldo-prepago-recarga-linha input[type="number"] { flex: 1; padding: .5rem; border: 1px solid var(--border-strong); border-radius: var(--radius-s); background: var(--panel); color: var(--text); }
.saldo-prepago-extrato { font-size: .82rem; }

/* #542: slot de anúncio (topo de toda página autenticada quando exibir_anuncio
   é True) -- placeholder deliberadamente neutro (borda tracejada, sem cor de
   marca) até o fornecedor/mecanismo real ser definido (item 1 de #542). */
.ad-slot { border: 1px dashed var(--border-strong); border-radius: var(--radius-s); padding: .6rem 1rem; margin-bottom: 1rem; text-align: center; }
.ad-slot-label { font-size: .78rem; color: var(--text-muted); }

/* ── Árvore de atributos do catálogo (compartilhada por fornecedor_api_detalhe
   e conexao_config_form) — antes ~30 estilos inline com cor hardcoded por tela;
   agora tokenizada, herda o tema. Seta (▶) e larguras seguem inline por serem
   layout puro. ── */
.attr-arrow { transition: transform .15s; }
.attr-grp-toggle { display: flex; align-items: center; gap: .5rem; padding: .75rem 1rem; cursor: pointer; background: var(--panel-2); user-select: none; }
.attr-grp-tec { color: var(--text-muted); }
.attr-count { margin-left: auto; color: var(--text-muted); font-size: .85rem; }
.attr-api-wrap { margin: .5rem 0; padding-left: .75rem; border-left: 3px solid var(--border-strong); }
.attr-api-wrap.is-webhook { border-left-color: var(--warn); }
.attr-api-toggle { display: flex; align-items: center; flex-wrap: wrap; gap: .4rem; padding: .4rem 0; cursor: pointer; user-select: none; }
.attr-api-count { margin-left: auto; color: var(--text-muted); font-size: .78rem; }
.attr-badge-webhook { padding: .05rem .4rem; background: var(--warn); color: #fff; border-radius: 3px; font-size: .65rem; }
.attr-badge-versao { padding: .05rem .4rem; background: var(--info-bg); border: 1px solid var(--info); border-radius: 3px; font-size: .7rem; color: var(--info); }
.attr-secao { padding: .25rem .5rem; background: var(--signal); color: #fff; border-radius: 3px; font-size: .78rem; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; }
.attr-secao-count { font-weight: 400; opacity: .85; }
.attr-secao-body { padding: .35rem 0 .05rem .6rem; margin-left: .25rem; border-left: 2px solid var(--border); }
.attr-tipo-toggle { display: flex; align-items: center; gap: .5rem; padding: .3rem .5rem; background: var(--panel-2); border: 1px solid var(--border); border-radius: 3px; cursor: pointer; user-select: none; }
.attr-tipo-nome { font-size: .82rem; }
.attr-tipo-count { font-size: .72rem; color: var(--text-muted); }
.attr-table { font-size: .82rem; }
.attr-has-children { color: var(--signal); font-size: .65rem; }
.attr-enum { font-size: .74rem; background: var(--panel-2); padding: .05rem .3rem; border-radius: 3px; margin: .1rem .05rem; display: inline-block; }
.attr-empty { color: var(--text-muted); font-size: .82rem; }
/* #349: chips de preenchimento sólido (seção e badge webhook) usam texto branco
   sobre --signal/--warn. No tema escuro esses tokens ficam claros, então o texto
   passa a ser escuro para manter contraste legível. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .attr-secao,
    :root:not([data-theme="light"]) .attr-badge-webhook { color: #12201A; }
}
:root[data-theme="dark"] .attr-secao,
:root[data-theme="dark"] .attr-badge-webhook { color: #12201A; }
/* #399: cor/badge por tipo de atributo — ponto colorido antes do rótulo do
   sub-grupo (query/path/header/body/response) para diferenciá-los visualmente
   além do badge de webhook. A cor vem de --attr-tipo-color, setada por
   data-tipo no .attr-tipo-toggle e herdada pelo ponto (.attr-tipo-dot).
   Mesmo mapeamento no admin (static/css/admin_forms.css) para consistência. */
.attr-tipo-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--attr-tipo-color, var(--text-muted)); flex-shrink: 0; }
.attr-tipo-toggle[data-tipo="query_parameters"]  { --attr-tipo-color: #3b82f6; }
.attr-tipo-toggle[data-tipo="path_parameters"]    { --attr-tipo-color: #8b5cf6; }
.attr-tipo-toggle[data-tipo="header"]             { --attr-tipo-color: #6b7280; }
.attr-tipo-toggle[data-tipo="request_body"]       { --attr-tipo-color: #10b981; }
.attr-tipo-toggle[data-tipo="request_parameter"]  { --attr-tipo-color: #10b981; }
.attr-tipo-toggle[data-tipo="response_code"]      { --attr-tipo-color: #f59e0b; }
.attr-tipo-toggle[data-tipo="response_body"]      { --attr-tipo-color: #f59e0b; }
/* Bloco <code> destacando uma URL (ex.: endpoint de webhook a cadastrar). */
.code-url { display: inline-block; margin-top: .35rem; padding: .35rem .6rem; background: var(--panel-2); border: 1px solid var(--border); border-radius: var(--radius-s); font-size: .85rem; word-break: break-all; }
/* #355: barra de ações em massa (listagens com seleção por checkbox). */
.bulk-toolbar { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; margin-bottom: 1rem; padding: .6rem .9rem; background: var(--panel-2); border: 1px solid var(--border-strong); border-radius: var(--radius-m); }
.bulk-toolbar[hidden] { display: none; }
.bulk-count { font-size: .9rem; color: var(--text); margin-right: auto; }
.bulk-toolbar .btn-test { margin: 0; }
/* #349: botão de alternância de tema no header (mesmo figurino dos botões do
   header escuro — busca/notificações). O ícone é trocado por JS (☀/🌙). */
.theme-toggle { background: rgba(255,255,255,0.08); color: var(--sidebar-fg); border: 1px solid rgba(255,255,255,0.15); border-radius: var(--radius-s); padding: .35rem .55rem; font-size: 1rem; line-height: 1; cursor: pointer; }
.theme-toggle:hover { background: rgba(255,255,255,0.15); color: #fff; }
