/**
 * JigPhish 2.0 Admin Design System — Core Components (Fase 3)
 * ============================================================================
 * Extraído dos padrões comprovados nas 5 Reference Implementations (Fase 1/2):
 * redesign/reference/{app-shell,template-library,management-list,detail,dashboard}.html
 *
 * Cada seção abaixo cita de qual Reference o padrão foi extraído. Componentes
 * sem Reference literal (Dropdown/Menu, Modal, EmptyState, Skeleton) foram
 * pedidos nominalmente pelo dono do produto na Fase 3 — generalizados a
 * partir de padrões JÁ comprovados (scrim+painel do Drawer, superfície de
 * card, tokens de elevação/movimento existentes), não inventados soltos.
 *
 * OWNERSHIP — mesma regra de tokens.css:
 * ----------------------------------------------------------------------------
 *   - NÃO estende nenhum CSS legado (jig-platform.css, loophish-*.css, etc.).
 *   - NÃO é carregado pelo Student Portal nem por /addins/** — confirme antes
 *     de linkar este arquivo em qualquer página nova (ver tokens.css e
 *     redesign/fronteiras-seguranca.html §07 para a lista do Student Portal;
 *     /addins/** é read-only e nunca recebe este asset).
 *   - Todo seletor usa o prefixo `.jx-*`. Nenhuma classe sem prefixo.
 *   - Depende de `tokens.css` (deve ser carregado ANTES deste arquivo).
 *
 * ESCOPO (Fase 3 — Core Components, PRODUCT_REDESIGN_BRIEF.md §28):
 * ----------------------------------------------------------------------------
 * Biblioteca de componentes reais e reutilizáveis. Nenhuma página de produção
 * usa este arquivo ainda — ver redesign/components/index.html (galeria viva)
 * e redesign/archetypes/*.html (Fase 4) para o uso real, ambos fora de /in/.
 *
 * Comportamento interativo (Dropdown, Modal, Drawer, Tabs, seleção de tabela)
 * está em in/js/admin2/components.js — namespace `window.JX`.
 */

/* ============================================================================
 * 0. BASE — reset mínimo escopado a componentes .jx-*
 * ========================================================================= */
.jx-btn, .jx-icon-btn, .jx-chip, .jx-tab, .jx-menu-item, .jx-modal-close,
.jx-dropdown-trigger, .jx-chip-remove, .jx-pagination-nav-btn {
  font-family: var(--jx-font-ui);
  -webkit-font-smoothing: antialiased;
  box-sizing: border-box;
}
.jx-btn *, .jx-icon-btn *, .jx-chip *, .jx-tab * { box-sizing: border-box; }

/* Foco visível consistente em todo componente interativo — nunca remover
   outline sem substituir por um indicador de foco equivalente. */
.jx-btn:focus-visible, .jx-icon-btn:focus-visible, .jx-chip:focus-visible,
.jx-tab:focus-visible, .jx-menu-item:focus-visible, .jx-modal-close:focus-visible,
.jx-dropdown-trigger:focus-visible, .jx-checkbox:focus-visible,
.jx-template-card:focus-visible, .jx-metric-card-filterable:focus-visible,
.jx-search input:focus-visible, .jx-pagination-nav-btn:focus-visible {
  outline: 2px solid var(--jx-accent);
  outline-offset: 2px;
}

/* ============================================================================
 * 1. BUTTON — extraído de todas as 5 References (.jx-btn-primary/secondary)
 * ========================================================================= */
.jx-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--jx-space-2);
  height: var(--jx-control-h);
  padding: 0 var(--jx-space-4);
  border-radius: var(--jx-radius-sm);
  font: 600 14px/1 var(--jx-font-ui);
  border: 1px solid transparent;
  cursor: pointer;
  transition: background var(--jx-motion-fast) var(--jx-motion-ease),
              border-color var(--jx-motion-fast) var(--jx-motion-ease),
              color var(--jx-motion-fast) var(--jx-motion-ease);
  white-space: nowrap;
  position: relative;
}
.jx-btn svg { flex: none; width: 16px; height: 16px; }

.jx-btn-primary   { background: var(--jx-accent); color: #fff; }
.jx-btn-primary:hover   { background: var(--jx-accent-strong); }
.jx-btn-primary:active  { background: var(--jx-accent-strong); }

.jx-btn-secondary { background: var(--jx-surface); color: var(--jx-ink); border-color: var(--jx-line-strong); }
.jx-btn-secondary:hover { background: var(--jx-surface-2); border-color: var(--jx-muted); }

.jx-btn-ghost     { background: transparent; color: var(--jx-ink-soft); }
.jx-btn-ghost:hover { background: var(--jx-surface-2); color: var(--jx-ink); }

.jx-btn-danger    { background: var(--jx-danger); color: #fff; }
.jx-btn-danger:hover { filter: brightness(0.92); }

.jx-btn-sm { height: var(--jx-control-h-dense); padding: 0 var(--jx-space-3); font-size: 13px; }
.jx-btn-lg { height: 42px; padding: 0 var(--jx-space-5); font-size: 15px; }

.jx-btn:disabled, .jx-btn[aria-disabled="true"] {
  opacity: .5; cursor: not-allowed; pointer-events: none;
}

/* Estado de carregamento: texto fica invisível (não removido — evita CLS),
   um spinner sobrepõe via ::after. Marcar com is-loading + aria-busy. */
.jx-btn.is-loading { color: transparent !important; pointer-events: none; }
.jx-btn.is-loading svg { visibility: hidden; }
.jx-btn.is-loading::after {
  content: ""; position: absolute; width: 16px; height: 16px;
  border-radius: 50%; border: 2px solid rgba(255,255,255,.4);
  border-top-color: #fff; animation: jx-spin .7s linear infinite;
}
.jx-btn-secondary.is-loading::after, .jx-btn-ghost.is-loading::after {
  border-color: rgba(16,21,42,.18); border-top-color: var(--jx-ink);
}
@keyframes jx-spin { to { transform: rotate(360deg); } }

/* ============================================================================
 * 2. ICONBUTTON — extraído de Reference 3 (.jx-icon-btn em ações de linha)
 *    e Reference 2/4 (botão de favoritar no hover, fechar do drawer)
 * ========================================================================= */
.jx-icon-btn {
  width: 28px; height: 28px;
  border: 1px solid var(--jx-line);
  border-radius: var(--jx-radius-xs);
  background: var(--jx-surface);
  color: var(--jx-muted);
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: color var(--jx-motion-fast) var(--jx-motion-ease),
              border-color var(--jx-motion-fast) var(--jx-motion-ease),
              background var(--jx-motion-fast) var(--jx-motion-ease);
}
.jx-icon-btn svg { width: 14px; height: 14px; }
.jx-icon-btn:hover { color: var(--jx-ink); border-color: var(--jx-line-strong); }
.jx-icon-btn:disabled { opacity: .4; cursor: not-allowed; }

.jx-icon-btn-ghost { border-color: transparent; background: transparent; }
.jx-icon-btn-ghost:hover { background: var(--jx-surface-2); }

.jx-icon-btn-sm { width: 24px; height: 24px; }
.jx-icon-btn-sm svg { width: 12px; height: 12px; }
.jx-icon-btn-lg { width: 36px; height: 36px; }
.jx-icon-btn-lg svg { width: 18px; height: 18px; }

/* ============================================================================
 * 3. PAGEHEADER — extraído (idêntico) das 5 References (.jx-pageheader)
 * ========================================================================= */
.jx-pageheader {
  background: var(--jx-surface);
  border-bottom: 1px solid var(--jx-line);
  padding: var(--jx-space-6) var(--jx-space-8) var(--jx-space-5);
  flex: none;
}
.jx-breadcrumb {
  font: 600 12px var(--jx-font-ui); color: var(--jx-muted);
  margin-bottom: var(--jx-space-3);
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
}
.jx-breadcrumb a { color: var(--jx-muted); text-decoration: none; }
.jx-breadcrumb a:hover { color: var(--jx-ink-soft); text-decoration: underline; }

.jx-pageheader-row {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: var(--jx-space-4); flex-wrap: wrap;
}
.jx-pageheader-titleblock h1 {
  font: 700 25px var(--jx-font-display); color: var(--jx-ink); margin: 0 0 5px;
  display: flex; align-items: center; gap: 10px;
}
.jx-pageheader-desc { color: var(--jx-muted); font-size: 13.5px; margin: 0; }
.jx-pageheader-actions { display: flex; gap: var(--jx-space-2); flex: none; }

/* Responsivo: ações empilham abaixo do título em telas estreitas */
@media (max-width: 640px) {
  .jx-pageheader-row { flex-direction: column; align-items: stretch; }
  .jx-pageheader-actions { justify-content: flex-end; }
}

/* ============================================================================
 * 4. TOOLBAR / FILTERBAR — extraído de Reference 2 e 3 (.jx-toolbar)
 * ========================================================================= */
.jx-toolbar {
  display: flex; justify-content: space-between; align-items: center;
  gap: var(--jx-space-3); flex-wrap: wrap; margin-bottom: var(--jx-space-4);
}
.jx-toolbar-group { display: flex; gap: var(--jx-space-3); align-items: center; flex-wrap: wrap; }
/* STAGING FIX (2026-09-10, ampliado 2026-09-10): .jx-select é width:100% por
   padrão (correto dentro de um .jx-field de form, onde o container já limita
   a largura) — mas .jx-toolbar/.jx-toolbar-group são flex sem nenhum
   container limitando cada filho, e width:100% num item flex vira o
   flex-basis dele: cada <select> tentava ocupar a linha inteira e (com
   flex-wrap:wrap) quebrava pra sua própria linha — os "botões de filtro"
   gigantescos reportados em várias páginas. Primeira correção só cobriu
   `.jx-toolbar-group .jx-select`; achado real depois (QuestionBank ainda
   quebrado) — várias páginas (QuestionBank, ClientList, ClientOnboarding,
   ClientBranding, Reoffenders) usam `.jx-select` como filho DIRETO de
   `.jx-toolbar`, sem o wrapper `-group`, e sofrem o mesmo bug. Regra
   ampliada para `.jx-toolbar .jx-select` (cobre os dois casos — um select
   dentro de `.jx-toolbar-group` também está dentro de `.jx-toolbar`).
   Escopado só a selects dentro de toolbar/filtro; forms continuam
   width:100% normalmente. */
.jx-toolbar .jx-select { width: auto; min-width: 160px; max-width: 240px; flex: 0 1 auto; }

/* ============================================================================
 * 5. SEARCHFIELD — extraído de Reference 2 e 3 (.jx-search)
 * ========================================================================= */
.jx-search {
  display: flex; align-items: center; gap: var(--jx-space-2);
  height: 36px; padding: 0 var(--jx-space-3);
  border: 1px solid var(--jx-line); border-radius: var(--jx-radius-sm);
  width: 280px; max-width: 100%; color: var(--jx-muted);
  background: var(--jx-surface);
  transition: border-color var(--jx-motion-fast) var(--jx-motion-ease);
}
.jx-search:focus-within { border-color: var(--jx-accent); }
.jx-search svg { flex: none; width: 15px; height: 15px; }
.jx-search input {
  /* STAGING FIX (2026-09-10): "campo de pesquisa parece campo dentro de
     campo" reportado ao vivo em várias páginas (ex.: TrainingModules).
     input[type=search] recebe estilo NATIVO do browser/SO em cima do
     nosso CSS (Safari/WebKit em particular renderiza sua própria "cápsula"
     arredondada com sombra interna para type=search, independente de
     border:none/background:none no elemento — appearance é uma camada de
     renderização separada do box model) — o resultado visual é exatamente
     uma caixa dentro de outra caixa: o .jx-search (nosso wrapper, única
     superfície pretendida) por fora, e o chrome nativo do input por
     dentro. appearance:none remove essa segunda camada; o wrapper
     continua sendo a única superfície visual, como já documentado no
     comentário desta seção. */
  appearance: none; -webkit-appearance: none;
  border: none; outline: none; font: 14px var(--jx-font-ui); width: 100%;
  color: var(--jx-ink-soft); background: none; box-sizing: border-box;
  /* STAGING FIX (2026-09-10): causa raiz real do "campo dentro de campo" —
     NÃO é chrome nativo de type=search (o reset acima já cobre isso).
     css/jig-platform.css (carregado via z_menu.php, presente em praticamente
     toda página admin) tem uma regra !important para input[type="search"]
     que forca min-height:38px, border-radius:var(--jp-radius-sm) (6px) e
     background/border próprios — mas o wrapper .jx-search tem height:36px
     fixo e border-radius:var(--jx-radius-sm) (8px). Por serem !important,
     essas regras vencem o reset acima independente da ordem de carregamento
     no <head>, fazendo o <input> renderizar como uma caixa mais alta e com
     cantos diferentes "vazando" de dentro do wrapper — o efeito visual de
     duas caixas aninhadas. Repetimos aqui com !important só nas propriedades
     que o jig-platform.css força, para nao depender de reescrever/remover
     aquele arquivo legado (ainda em uso por outras telas). */
  min-height: 0 !important;
  height: 100% !important;
  background-color: transparent !important;
  border-color: transparent !important;
  border-radius: 0 !important;
  box-shadow: none !important;
}
.jx-search input::placeholder { color: var(--jx-muted); }
/* Remove os decoradores nativos de type=search (ícone de lupa/"x" do
   WebKit) — já temos os nossos próprios (svg + .jx-search-clear). */
.jx-search input::-webkit-search-decoration,
.jx-search input::-webkit-search-cancel-button,
.jx-search input::-webkit-search-results-button,
.jx-search input::-webkit-search-results-decoration { -webkit-appearance: none; appearance: none; }
.jx-search-clear {
  flex: none; border: none; background: none; cursor: pointer;
  color: var(--jx-muted); display: none; padding: 2px;
}
.jx-search.has-value .jx-search-clear { display: flex; }
.jx-search-clear:hover { color: var(--jx-ink); }

/* ============================================================================
 * 6. FILTERCHIP — extraído de Reference 2 e 3 (.jx-chip)
 * ========================================================================= */
.jx-chip {
  display: inline-flex; align-items: center; gap: 6px;
  height: 32px; padding: 0 var(--jx-space-3);
  border: 1px solid var(--jx-line-strong); border-radius: var(--jx-radius-sm);
  font: 500 12.5px var(--jx-font-ui); color: var(--jx-ink-soft);
  cursor: pointer; background: var(--jx-surface);
  transition: border-color var(--jx-motion-fast) var(--jx-motion-ease),
              background var(--jx-motion-fast) var(--jx-motion-ease),
              color var(--jx-motion-fast) var(--jx-motion-ease);
}
.jx-chip svg { width: 12px; height: 12px; flex: none; }
.jx-chip:hover { border-color: var(--jx-muted); }
.jx-chip.is-active { background: var(--jx-accent-tint); color: var(--jx-accent-strong); border-color: transparent; }

/* Variante removível (tag de filtro aplicado, com × para limpar) */
.jx-chip-removable { padding-right: 6px; }
.jx-chip-remove {
  flex: none; width: 16px; height: 16px; border: none; border-radius: 50%;
  background: rgba(16,21,42,.08); color: inherit; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; line-height: 1; margin-left: 2px;
}
.jx-chip-remove:hover { background: rgba(16,21,42,.16); }

/* Tabs por segmento (variante "pill" usada como sub-filtro dentro de Toolbar,
   distinta do componente Tabs de navegação de conteúdo — ver §18) */
.jx-tabs-inline { display: flex; gap: var(--jx-space-2); }
.jx-tabs-inline .jx-tab-pill {
  font: 600 13px var(--jx-font-ui); color: var(--jx-muted);
  padding: 6px 12px; border-radius: 100px; cursor: pointer; border: 1px solid transparent;
  background: none;
}
.jx-tabs-inline .jx-tab-pill.is-active { background: var(--jx-accent-tint); color: var(--jx-accent-strong); }

/* ============================================================================
 * 7. BADGE / STATUSBADGE — extraído de Reference 3 (.jx-badge) e
 *    Reference 2 (.jx-pill, tag compacta de metadado)
 * ========================================================================= */
.jx-badge {
  display: inline-flex; align-items: center; gap: 5px;
  font: 600 11.5px var(--jx-font-ui); padding: 3px 10px; border-radius: 100px;
  white-space: nowrap;
}
.jx-badge .jx-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }

.jx-badge-success { background: var(--jx-success-tint); color: var(--jx-success); }
.jx-badge-warning { background: var(--jx-warning-tint); color: var(--jx-warning); }
.jx-badge-danger  { background: var(--jx-danger-tint);  color: var(--jx-danger); }
.jx-badge-info    { background: var(--jx-info-tint);    color: var(--jx-info); }
.jx-badge-neutral { background: var(--jx-surface-2); color: var(--jx-ink-soft); border: 1px solid var(--jx-line); }
.jx-badge-muted   { background: #F2F2F5; color: var(--jx-muted); }

/* Tag compacta (metadado de card — categoria, idioma) */
.jx-pill {
  display: inline-flex; align-items: center;
  font: 600 10.5px var(--jx-font-ui); background: var(--jx-surface-2);
  color: var(--jx-ink-soft); border: 1px solid var(--jx-line);
  border-radius: 5px; padding: 2px 7px; white-space: nowrap;
}

/* ============================================================================
 * 8. DATATABLE — extraído de Reference 3 (tabela + densidade + seleção)
 * ========================================================================= */
.jx-table-wrap {
  background: var(--jx-surface); border: 1px solid var(--jx-line);
  border-radius: var(--jx-radius); overflow: hidden;
}
/* Tabelas largas nunca vazam do corpo da página — rolagem própria */
.jx-table-scroll { overflow-x: auto; }
.jx-table { width: 100%; border-collapse: collapse; min-width: 640px; }
.jx-table thead th {
  text-align: left; font: 700 11px var(--jx-font-ui); text-transform: uppercase;
  letter-spacing: .05em; color: var(--jx-muted); padding: var(--jx-space-3) var(--jx-space-4);
  border-bottom: 1px solid var(--jx-line); background: var(--jx-surface-2);
  white-space: nowrap;
}
.jx-table th[data-sortable] { cursor: pointer; user-select: none; }
.jx-table th[data-sortable]:hover { color: var(--jx-ink-soft); }
.jx-table th[data-sortable] .jx-sort-icon { display: inline-block; width: 10px; height: 10px; margin-left: 3px; opacity: .5; }
.jx-table th[aria-sort="ascending"] .jx-sort-icon,
.jx-table th[aria-sort="descending"] .jx-sort-icon { opacity: 1; color: var(--jx-accent); }

.jx-table tbody td {
  padding: var(--jx-row-py, 14px) var(--jx-space-4); border-bottom: 1px solid var(--jx-line);
  font-size: 13.5px; color: var(--jx-ink-soft); vertical-align: middle;
}
.jx-table tbody tr:last-child td { border-bottom: none; }
.jx-table tbody tr:hover { background: var(--jx-surface-2); }
.jx-table tbody tr.is-selected { background: var(--jx-accent-tint); }
.jx-table-wrap.is-compact .jx-table { --jx-row-py: 8px; }
.jx-table-wrap.is-compact .jx-table tbody td { font-size: 13px; }

.jx-table-check { width: 36px; }
.jx-checkbox { width: 16px; height: 16px; accent-color: var(--jx-accent); cursor: pointer; }

.jx-table-name { font-weight: 600; color: var(--jx-ink); }
.jx-table-sub  { font-size: 12px; color: var(--jx-muted); margin-top: 1px; }

/* Ações de linha só aparecem no hover — reduz ruído visual constante */
.jx-table-row-actions {
  display: flex; gap: 4px; justify-content: flex-end; opacity: 0;
  transition: opacity var(--jx-motion-fast) var(--jx-motion-ease);
}
.jx-table tbody tr:hover .jx-table-row-actions,
.jx-table tbody tr:focus-within .jx-table-row-actions { opacity: 1; }

/* Barra de risco/progresso inline (leitura rápida em varredura) */
.jx-table-metric { display: flex; align-items: center; gap: 8px; }
.jx-table-metric-bar { width: 64px; height: 6px; border-radius: 3px; background: var(--jx-surface-2); overflow: hidden; flex: none; }
.jx-table-metric-fill { height: 100%; border-radius: 3px; }
.jx-table-metric-val { font: 600 12px var(--jx-font-mono); color: var(--jx-ink); width: 32px; }

/* Toggle de densidade — controla .is-compact acima via JS (JX.DataTable) */
.jx-density-toggle { display: flex; border: 1px solid var(--jx-line-strong); border-radius: var(--jx-radius-sm); overflow: hidden; }
.jx-density-toggle button {
  border: none; background: var(--jx-surface); width: 32px; height: 32px; cursor: pointer;
  color: var(--jx-muted); display: flex; align-items: center; justify-content: center;
}
.jx-density-toggle button.is-active { background: var(--jx-accent-tint); color: var(--jx-accent-strong); }
.jx-density-toggle button svg { width: 14px; height: 14px; }

/* Barra de ação contextual flutuante — extraída de Reference 3, acompanha
   seleção múltipla de linhas da DataTable (não é toolbar fixa no topo). */
.jx-context-bar {
  position: fixed; left: 50%; bottom: 28px; transform: translate(-50%, 120%);
  background: var(--jx-shell-ink); color: #fff; border-radius: var(--jx-radius);
  box-shadow: var(--jx-shadow-floating); display: flex; align-items: center;
  gap: var(--jx-space-4); padding: var(--jx-space-3) var(--jx-space-4);
  transition: transform var(--jx-motion-base) var(--jx-motion-ease); z-index: 40;
}
.jx-context-bar.is-open { transform: translate(-50%, 0); }
.jx-context-bar .jx-context-count { font: 600 13.5px var(--jx-font-ui); }
.jx-context-bar .jx-context-sep { width: 1px; height: 20px; background: rgba(255,255,255,.18); }
.jx-context-bar button.jx-btn-ghost { background: none; border: none; color: #D7DCE8; font: 600 13px var(--jx-font-ui); }
.jx-context-bar button.jx-btn-ghost:hover { color: #fff; background: none; }
.jx-context-bar button.jx-context-danger:hover { color: #FF8A80; }

/* ============================================================================
 * 9. PAGINATION — extraído de Reference 3 (.jx-pagination)
 * ========================================================================= */
.jx-pagination {
  display: flex; justify-content: space-between; align-items: center;
  padding: var(--jx-space-3) var(--jx-space-4); border-top: 1px solid var(--jx-line);
  font-size: 12.5px; color: var(--jx-muted); flex-wrap: wrap; gap: var(--jx-space-2);
}
.jx-pagination-controls { display: flex; align-items: center; gap: var(--jx-space-2); }
.jx-pagination-page { font: 600 12.5px var(--jx-font-mono); color: var(--jx-ink-soft); }
/* STAGING FIX (2026-09-10): mesma causa-raiz do fix de .jx-toolbar-group acima —
   .jx-select é width:100% por padrão, e dentro do .jx-pagination-controls (flex
   nowrap, sem container limitando os filhos) isso faz o <select> de page-size
   disputar espaço com os irmãos; o flex-shrink resultante espreme o
   .jx-pagination-page ("1 / 3") até seu min-content, que quebra nos espaços —
   um número por linha (reportado em TrainingModules, único consumidor hoje de
   .jx-pagination-controls). Escopado só a select dentro de paginação. */
.jx-pagination-controls .jx-select { width: auto; flex: 0 0 auto; }

/* ============================================================================
 * 10. DROPDOWN / MENU — generalizado do padrão de scrim+painel flutuante
 *     (mesma elevação/movimento do Drawer) + affordance já visível em todas
 *     as References (botão + chevron do seletor de tenant e dos FilterChips)
 * ========================================================================= */
.jx-dropdown { position: relative; display: inline-block; }
.jx-dropdown-trigger {
  display: flex; align-items: center; gap: var(--jx-space-2); height: 32px;
  padding: 0 var(--jx-space-3); border: 1px solid var(--jx-line);
  border-radius: var(--jx-radius-sm); font: 600 13.5px var(--jx-font-ui);
  color: var(--jx-ink); background: var(--jx-surface); cursor: pointer;
}
.jx-dropdown-trigger:hover { border-color: var(--jx-line-strong); }
.jx-dropdown-trigger svg { width: 12px; height: 12px; flex: none; transition: transform var(--jx-motion-fast) var(--jx-motion-ease); }
.jx-dropdown[data-open="true"] .jx-dropdown-trigger svg { transform: rotate(180deg); }

.jx-menu {
  position: absolute; top: calc(100% + 6px); left: 0; min-width: 200px;
  background: var(--jx-surface); border: 1px solid var(--jx-line);
  border-radius: var(--jx-radius-sm); box-shadow: var(--jx-shadow-floating);
  padding: var(--jx-space-2); z-index: 50;
  opacity: 0; transform: translateY(-4px); pointer-events: none;
  transition: opacity var(--jx-motion-fast) var(--jx-motion-ease),
              transform var(--jx-motion-fast) var(--jx-motion-ease);
}
.jx-dropdown[data-open="true"] .jx-menu { opacity: 1; transform: translateY(0); pointer-events: auto; }
.jx-menu[data-align="right"] { left: auto; right: 0; }

.jx-menu-item {
  display: flex; align-items: center; gap: var(--jx-space-2); width: 100%;
  height: 34px; padding: 0 var(--jx-space-2); border: none; background: none;
  border-radius: var(--jx-radius-xs); font: 500 13.5px var(--jx-font-ui);
  color: var(--jx-ink-soft); cursor: pointer; text-align: left;
}
.jx-menu-item svg { width: 15px; height: 15px; flex: none; color: var(--jx-muted); }
.jx-menu-item:hover, .jx-menu-item.is-focused { background: var(--jx-surface-2); color: var(--jx-ink); }
.jx-menu-item-danger { color: var(--jx-danger); }
.jx-menu-item-danger svg { color: var(--jx-danger); }
.jx-menu-item-danger:hover { background: var(--jx-danger-tint); }
.jx-menu-divider { height: 1px; background: var(--jx-line); margin: var(--jx-space-2) 4px; }

/* ============================================================================
 * 11. MODAL / DIALOG — generalizado do padrão scrim+painel do Drawer
 *     (centralizado em vez de ancorado à borda; mesmos tokens de elevação)
 * ========================================================================= */
.jx-scrim {
  position: fixed; inset: 0; background: rgba(16, 21, 42, .32);
  opacity: 0; pointer-events: none; transition: opacity var(--jx-motion-base) var(--jx-motion-ease);
  z-index: 60;
}
.jx-scrim.is-open { opacity: 1; pointer-events: auto; }

.jx-modal {
  /* Tamanhos (staging fix 2026-09-10 — 3 páginas reportaram modal cortando
     conteúdo/gerando scroll: MailCmpDashboard e WebMailCmpDashboard's
     ModalCampaignList, TrainingModules' trmod_modal — todas já usando
     .jx-modal-lg, então a causa raiz é o próprio size system estar pequeno
     demais, não as páginas individualmente). Só a largura (width) muda por
     tier — max-width/max-height continuam aqui na base e valem para todos os
     tiers, então nenhum tier pode nunca ultrapassar a viewport.
       SM      ~440px   confirmação curta
       DEFAULT ~680px   forms simples
       LG      ~900px   forms/configuração complexa, tabela de seleção
       XL      ~1180px/90vw  preview/editor/tabelas grandes (ver .jx-modal-xl) */
  position: fixed; top: 50%; left: 50%; width: 680px; max-width: calc(100vw - 32px);
  max-height: calc(100vh - 64px); transform: translate(-50%, -46%); opacity: 0;
  background: var(--jx-surface); border-radius: var(--jx-radius-lg);
  /* z-index 1062 (staging fix 2026-09-10 — antes 62): modais compridos (perto
     do max-height acima) centralizam com o topo a só ~32px da viewport — e
     css/jig-platform.css (carregado por z_menu.php em praticamente toda
     página admin) tem .jp-global-topbar (a barra superior fixa) com
     z-index:998 e .jp-scroll-top com z-index:1000. Como esses dois números
     são MAIORES que o 62 do Admin2, a topbar antiga pintava por cima do
     cabeçalho do modal (título + botão fechar) — não um bug de tamanho, era
     empilhamento: o modal continuava exatamente do tamanho/posição certos,
     só ficava com a parte de cima escondida atrás da topbar. Reproduzido:
     print real mostrando o modal "Novo módulo" (TrainingModules) e o de
     nova organização (client onboarding) começando direto nos campos do
     formulário, sem cabeçalho visível. +1000 para garantir folga de todo o
     scroll do shell antigo (998/1000), mantendo modal(1062) > drawer(1061)
     conforme já documentado. */
  box-shadow: var(--jx-shadow-floating); z-index: 1062; display: none;
  flex-direction: column; pointer-events: none;
  transition: opacity var(--jx-motion-base) var(--jx-motion-ease),
              transform var(--jx-motion-base) var(--jx-motion-ease);
}
.jx-modal.is-open { display: flex; opacity: 1; transform: translate(-50%, -50%); pointer-events: auto; }
.jx-modal-sm { width: 440px; }
.jx-modal-lg { width: 900px; }
/* XL: preview/editor/tabelas grandes. Só `width` (nunca max-width) — o
   max-width:calc(100vw - 32px) da base .jx-modal continua sendo o limite
   real em viewports estreitos, min() aqui é só o teto superior em telas
   largas. */
.jx-modal-xl { width: min(1180px, 90vw); }

.jx-modal-head {
  display: flex; justify-content: space-between; align-items: flex-start;
  padding: var(--jx-space-5) var(--jx-space-6); border-bottom: 1px solid var(--jx-line); flex: none;
}
.jx-modal-title { font: 700 18px var(--jx-font-display); color: var(--jx-ink); margin: 0; }
.jx-modal-close { background: none; border: none; cursor: pointer; color: var(--jx-muted); padding: 4px; border-radius: var(--jx-radius-xs); }
.jx-modal-close:hover { color: var(--jx-ink); background: var(--jx-surface-2); }
.jx-modal-body { padding: var(--jx-space-6); overflow-y: auto; flex: 1; font-size: 13.5px; color: var(--jx-ink-soft); }
.jx-modal-foot { display: flex; justify-content: flex-end; gap: var(--jx-space-2); padding: var(--jx-space-5) var(--jx-space-6); border-top: 1px solid var(--jx-line); flex: none; }

@media (max-width: 560px) {
  .jx-modal, .jx-modal-sm, .jx-modal-lg, .jx-modal-xl { width: calc(100vw - 24px); }
}

/* ============================================================================
 * 12. DRAWER — extraído (idêntico) de Reference 2 (.jx-drawer)
 * ========================================================================= */
.jx-drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: 460px; max-width: 92vw;
  background: var(--jx-surface); box-shadow: var(--jx-shadow-floating);
  transform: translateX(100%); transition: transform var(--jx-motion-base) var(--jx-motion-ease);
  /* z-index 1061 (staging fix 2026-09-10 — mesmo motivo do .jx-modal acima):
     o Drawer é top:0, exatamente a faixa que .jp-global-topbar (z-index:998
     em jig-platform.css) cobre — sem essa correção o topo do Drawer (seu
     próprio cabeçalho/botão fechar) ficava escondido atrás da topbar antiga. */
  z-index: 1061; display: flex; flex-direction: column;
}
.jx-drawer.is-open { transform: translateX(0); }
.jx-drawer-sm { width: 360px; }
.jx-drawer-lg { width: 560px; }

.jx-drawer-preview { height: 220px; background: linear-gradient(135deg, var(--jx-surface-2), #E4E8EF); flex: none; }
.jx-drawer-head {
  padding: var(--jx-space-5) var(--jx-space-6); border-bottom: 1px solid var(--jx-line);
  display: flex; justify-content: space-between; align-items: flex-start; flex: none;
}
.jx-drawer-close { background: none; border: none; cursor: pointer; color: var(--jx-muted); padding: 4px; border-radius: var(--jx-radius-xs); }
.jx-drawer-close:hover { color: var(--jx-ink); background: var(--jx-surface-2); }
.jx-drawer-body { padding: var(--jx-space-6); overflow-y: auto; flex: 1; }
.jx-drawer-foot { padding: var(--jx-space-5) var(--jx-space-6); border-top: 1px solid var(--jx-line); display: flex; gap: var(--jx-space-2); flex: none; }

.jx-kv { display: flex; justify-content: space-between; padding: var(--jx-space-2) 0; border-bottom: 1px solid var(--jx-line); font-size: 13.5px; }
.jx-kv span:first-child { color: var(--jx-muted); }
.jx-kv span:last-child { color: var(--jx-ink); font-weight: 600; }

/* ============================================================================
 * 13. METRICCARD — extraído de Reference 5 (.jx-metric) e Reference 3
 *     (.jx-status-block, variante clicável/filtrável do mesmo componente)
 * ========================================================================= */
.jx-metric-card {
  background: var(--jx-surface); border: 1px solid var(--jx-line);
  border-radius: var(--jx-radius); padding: var(--jx-space-4) var(--jx-space-5);
}
.jx-metric-card-label { font: 600 12px var(--jx-font-ui); color: var(--jx-muted); margin-bottom: var(--jx-space-2); }
.jx-metric-card-value { font: 700 30px var(--jx-font-mono); color: var(--jx-ink); line-height: 1; }
.jx-metric-card-trend { display: flex; align-items: center; gap: 4px; font: 600 12px var(--jx-font-ui); margin-top: var(--jx-space-2); }
.jx-metric-card-trend svg { width: 12px; height: 12px; }
.jx-trend-up-bad, .jx-trend-down-bad { color: var(--jx-danger); }
.jx-trend-up-good, .jx-trend-down-good { color: var(--jx-success); }

/* Variante compacta e clicável — usada como filtro (Reference 3) */
.jx-metric-card-filterable {
  cursor: pointer; text-align: left; width: 100%;
  transition: border-color var(--jx-motion-fast) var(--jx-motion-ease), box-shadow var(--jx-motion-fast) var(--jx-motion-ease);
}
.jx-metric-card-filterable:hover { box-shadow: var(--jx-shadow-floating); }
.jx-metric-card-filterable.is-active { border-color: var(--jx-accent); box-shadow: 0 0 0 1px var(--jx-accent) inset; }
.jx-metric-card-filterable .jx-metric-card-value { font-size: 26px; }
.jx-metric-card-filterable .jx-metric-card-label { display: flex; align-items: center; gap: 6px; margin-top: 2px; margin-bottom: 0; }

/* ============================================================================
 * 14. EMPTYSTATE — sem Reference literal (nenhuma tela vazia foi mockada);
 *     generalizado a partir da superfície de card + tokens existentes.
 * ========================================================================= */
.jx-empty {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  padding: var(--jx-space-14) var(--jx-space-6);
  color: var(--jx-muted);
}
.jx-empty-icon {
  width: 56px; height: 56px; border-radius: 50%; background: var(--jx-surface-2);
  display: flex; align-items: center; justify-content: center; margin-bottom: var(--jx-space-4);
  color: var(--jx-muted);
}
.jx-empty-icon svg { width: 26px; height: 26px; }
.jx-empty-title { font: 700 16px var(--jx-font-display); color: var(--jx-ink); margin: 0 0 6px; }
.jx-empty-desc { font-size: 13.5px; max-width: 360px; margin: 0 0 var(--jx-space-5); }

/* ============================================================================
 * 15. SKELETON / LOADING — sem Reference literal (References usam dados
 *     estáticos); generalizado com o tom de --jx-surface-2 já usado como
 *     "rebaixado" no sistema, para não introduzir cor nova.
 * ========================================================================= */
.jx-skeleton {
  display: block; border-radius: var(--jx-radius-xs);
  background: linear-gradient(90deg, var(--jx-surface-2) 25%, #ECEEF3 37%, var(--jx-surface-2) 63%);
  background-size: 400% 100%;
  animation: jx-skeleton-shimmer 1.4s ease-in-out infinite;
}
.jx-skeleton-circle { border-radius: 50%; }
.jx-skeleton-text { height: 12px; margin-bottom: 6px; }
.jx-skeleton-text:last-child { margin-bottom: 0; width: 70%; }
@keyframes jx-skeleton-shimmer { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }

/* ============================================================================
 * 16. TEMPLATECARD — extraído de Reference 2 (.jx-card do Template Library)
 * ========================================================================= */
.jx-template-card {
  background: var(--jx-surface); border: 1px solid var(--jx-line);
  border-radius: var(--jx-radius); overflow: hidden; cursor: pointer;
  position: relative;
  transition: box-shadow var(--jx-motion-fast) var(--jx-motion-ease), border-color var(--jx-motion-fast) var(--jx-motion-ease);
}
.jx-template-card:hover, .jx-template-card:focus-visible { box-shadow: var(--jx-shadow-floating); border-color: var(--jx-line-strong); }
.jx-template-card:hover .jx-template-card-hover { opacity: 1; }

.jx-template-card-thumb { height: 150px; background: linear-gradient(135deg, var(--jx-surface-2), #E4E8EF); position: relative; }
.jx-template-card-thumb.is-rail { height: 100px; }
.jx-template-card-thumb .jx-template-card-badge {
  position: absolute; top: 8px; left: 8px; font: 600 10px var(--jx-font-ui);
  background: rgba(16,21,42,.72); color: #fff; padding: 2px 8px; border-radius: 100px;
}

/* Preview do card é SEMPRE estático/não-executável (imagem/gradiente), nunca
   HTML ativo do template armazenado — arquitetura de confiança compartilhada
   com o Security Track (Contexto B / Admin Preview, ver
   redesign/fronteiras-seguranca.html §10). Não renderizar srcdoc aqui. */
.jx-template-card-hover {
  position: absolute; inset: 0; background: rgba(16,21,42,.06); opacity: 0;
  transition: opacity var(--jx-motion-fast) var(--jx-motion-ease);
  display: flex; align-items: flex-end; justify-content: flex-end; padding: var(--jx-space-2);
}
.jx-template-card-body { padding: var(--jx-space-3) var(--jx-space-4) var(--jx-space-4); }
.jx-template-card-name { font: 600 14px var(--jx-font-ui); color: var(--jx-ink); margin-bottom: 6px; }
.jx-template-card-pills { display: flex; gap: 6px; flex-wrap: wrap; }

/* ============================================================================
 * 17. LIBRARYGRID — extraído de Reference 2 (.jx-grid)
 * ========================================================================= */
.jx-library-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: var(--jx-space-5); }
.jx-library-rail { display: flex; gap: var(--jx-space-4); overflow-x: auto; padding-bottom: var(--jx-space-2); scroll-snap-type: x proximity; }
.jx-library-rail .jx-template-card { flex: none; width: 220px; scroll-snap-align: start; }
.jx-library-rail-label { font: 700 11px var(--jx-font-ui); text-transform: uppercase; letter-spacing: .06em; color: var(--jx-muted); margin-bottom: var(--jx-space-3); }

/* ============================================================================
 * 18. TABS — extraído de Reference 2 e 4 (.jx-tab / .jx-tabs, navegação de
 *     conteúdo — distinto do jx-tab-pill de sub-filtro, ver §6)
 * ========================================================================= */
.jx-tabs { display: flex; gap: var(--jx-space-5); border-bottom: 1px solid var(--jx-line); }
.jx-tab {
  font: 600 13.5px var(--jx-font-ui); color: var(--jx-muted); padding: 0 0 var(--jx-space-3);
  cursor: pointer; border: none; background: none; border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.jx-tab.is-active { color: var(--jx-accent-strong); border-color: var(--jx-accent); }
.jx-tab:hover:not(.is-active) { color: var(--jx-ink-soft); }
.jx-tabpanel:focus { outline: none; }

/* ============================================================================
 * Redução de movimento — desliga toda transição/animação de componente
 * ========================================================================= */
@media (prefers-reduced-motion: reduce) {
  .jx-btn, .jx-icon-btn, .jx-chip, .jx-dropdown-trigger svg, .jx-menu, .jx-scrim,
  .jx-modal, .jx-drawer, .jx-table-row-actions, .jx-context-bar, .jx-metric-card-filterable,
  .jx-template-card, .jx-search, .jx-skeleton, .jx-btn.is-loading::after {
    transition: none !important; animation: none !important;
  }
}

/* ServerTable (Wave 2, 2026-09-07) — overlay states over the jx-table-wrap. */
.jx-server-table { position: relative; }
.jx-server-table-overlay {
  position: absolute; left: 0; right: 0; top: 44px; bottom: 48px;
  display: flex; align-items: center; justify-content: center; text-align: center;
  color: var(--jx-muted); font-size: 14px; background: color-mix(in srgb, var(--jx-surface) 78%, transparent);
  padding: var(--jx-space-6);
}
.jx-server-table-overlay.is-error { color: var(--jx-danger); }
.jx-pagination-info { color: var(--jx-muted); font-size: 13px; }
.jx-mono { font-family: var(--jx-font-mono); font-size: 12px; color: var(--jx-muted); }
/* Invalid field state (Wave 2) */
.jx-input.is-invalid, .jx-select.is-invalid { border-color: var(--jx-danger); box-shadow: 0 0 0 3px var(--jx-danger-tint, rgba(220,38,38,.12)); }

/* SelectSearch (Wave 2, 2026-09-08) — searchable select adapter over native <select>. */
.jx-selectsearch { position: relative; display: inline-block; width: 100%; }
.jx-selectsearch-btn { display: flex; align-items: center; justify-content: space-between; gap: 8px; width: 100%; min-height: 38px; padding: 8px 12px; background: var(--jx-surface); border: 1px solid var(--jx-line-strong); border-radius: var(--jx-radius); color: var(--jx-ink); font: inherit; cursor: pointer; text-align: left; }
.jx-selectsearch-btn.is-invalid { border-color: var(--jx-danger); box-shadow: 0 0 0 3px var(--jx-danger-tint, rgba(220,38,38,.12)); }
.jx-selectsearch-btn:focus-visible { outline: 2px solid var(--jx-accent); outline-offset: 1px; }
.jx-selectsearch-val { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.jx-selectsearch-val.is-placeholder { color: var(--jx-muted); }
.jx-selectsearch-panel { position: absolute; z-index: 50; left: 0; right: 0; top: calc(100% + 4px); background: var(--jx-surface); border: 1px solid var(--jx-line-strong); border-radius: var(--jx-radius); box-shadow: var(--jx-shadow-3, 0 12px 28px rgba(15,23,42,.14)); overflow: hidden; }
.jx-selectsearch-search { padding: 8px; border-bottom: 1px solid var(--jx-line); }
.jx-selectsearch-search input { width: 100%; padding: 7px 10px; border: 1px solid var(--jx-line-strong); border-radius: var(--jx-radius-sm, 6px); font: inherit; background: var(--jx-bg); }
.jx-selectsearch-list { max-height: 260px; overflow-y: auto; padding: 4px; }
.jx-selectsearch-item { display: block; width: 100%; text-align: left; padding: 8px 10px; border: 0; background: none; border-radius: var(--jx-radius-sm, 6px); font: inherit; color: var(--jx-ink); cursor: pointer; }
.jx-selectsearch-item:hover { background: var(--jx-hover, rgba(0,0,0,.04)); }
.jx-selectsearch-item[aria-selected="true"] { background: var(--jx-accent-tint, rgba(0,0,0,.06)); font-weight: 600; }
.jx-selectsearch-empty { padding: 12px; text-align: center; color: var(--jx-muted); }

/* ============================================================================
 * 19. FORM / FIELD / PANEL / SWITCH (2026-09-08) — promoted from the
 *     Create/Edit and Settings archetypes' local "convenção de formulário"
 *     (redesign/archetypes/create-edit.html, settings.html) into the shared
 *     library. Fase 3 deliberately left Input/Select out of Core Components
 *     ("não estavam na lista de prioridades") and each archetype re-declared
 *     an identical local copy instead. Several production pages already
 *     using these classes (MailSender.php create/edit, MailCampaignList.php,
 *     QRCampaigns.php, PhishingDomains.php) never copied that local CSS —
 *     only MailTemplate.php did — so their fields/panels/toggles were
 *     rendering with ZERO jx-* styling (bare native controls). Same rule as
 *     everywhere else in the library: extracted unchanged from the archetype
 *     that defined it, not reinvented. Fixes those pages retroactively by
 *     being additive-only (no page markup/JS touched); MailConfig (Wave 2)
 *     is the first page written to consume it directly instead of
 *     re-declaring it locally.
 * ========================================================================= */
.jx-panel { background: var(--jx-surface); border: 1px solid var(--jx-line); border-radius: var(--jx-radius); padding: var(--jx-space-5) var(--jx-space-6); margin-bottom: var(--jx-space-5); }
.jx-panel h3 { font-size: 15px; margin-bottom: 2px; }
.jx-panel-desc { font-size: 12.5px; color: var(--jx-muted); margin-bottom: var(--jx-space-5); }

.jx-field { margin-bottom: var(--jx-space-4); }
.jx-field:last-child { margin-bottom: 0; }
.jx-field-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--jx-space-4); }
.jx-field label { display: block; font: 600 12.5px var(--jx-font-ui); color: var(--jx-ink); margin-bottom: 6px; }
.jx-field-hint { font-size: 12px; color: var(--jx-muted); margin-top: 4px; }
@media (max-width: 640px) { .jx-field-row { grid-template-columns: 1fr; } }

.jx-input, .jx-textarea, .jx-select {
  /* STAGING FIX (2026-09-10): faltava box-sizing:border-box aqui — width:100%
     + padding horizontal + borda em content-box (padrão do browser p/ input/
     select/textarea) faz o elemento renderizar MAIS LARGO que o container
     (100% do pai + padding + borda), estourando pra fora dele. Silencioso na
     maioria dos forms admin (containers largos, overflow não chamava
     atenção), mas bem visível no card de login (.jx-auth-card, ~400px) —
     "inputs saindo da div do formulário" reportado ao vivo. Corrige em todo
     lugar que usa .jx-input/.jx-textarea/.jx-select, não só no login. */
  box-sizing: border-box;
  width: 100%; height: var(--jx-control-h); border: 1px solid var(--jx-line); border-radius: var(--jx-radius-sm);
  padding: 0 var(--jx-space-3); font: 14px var(--jx-font-ui); color: var(--jx-ink-soft); background: var(--jx-surface);
}
/* STAGING FIX (2026-09-10): mesmo conflito do .jx-search input (ver comentário
   acima) — jig-platform.css (carregado via z_menu.php em toda página admin)
   força com !important border-radius/border-color/background-color/
   min-height em input[type=search] (agrupado com type=text/email/password/
   number/...). .jx-input não tinha nenhum !important próprio, então um
   <input class="jx-input" type="search"> (SPLogs.php, CorporateGamification.php
   busca do ranking, OperationsDashboard.php) renderizava com os tokens do
   design system ANTIGO (--jp-*) em vez do atual (--jx-*) — raio de borda e
   altura mínima diferentes do resto da página. Escopado só a type=search
   (não input[type=text] em geral) para não expandir o escopo desta correção
   além do que foi reportado/confirmado. */
.jx-input[type="search"] {
  min-height: 0 !important;
  height: var(--jx-control-h) !important;
  border-radius: var(--jx-radius-sm) !important;
  border-color: var(--jx-line) !important;
  background-color: var(--jx-surface) !important;
}
.jx-input:focus, .jx-textarea:focus, .jx-select:focus { outline: 2px solid var(--jx-accent); outline-offset: 1px; border-color: var(--jx-accent); }
.jx-input:disabled, .jx-textarea:disabled, .jx-select:disabled { background: var(--jx-surface-2); color: var(--jx-muted); cursor: not-allowed; }
.jx-textarea { height: auto; padding: var(--jx-space-3); min-height: 88px; resize: vertical; }

.jx-toggle-row { display: flex; justify-content: space-between; align-items: center; gap: var(--jx-space-4); padding: var(--jx-space-3) 0; border-bottom: 1px solid var(--jx-line); }
.jx-toggle-row:last-child { border-bottom: none; }
.jx-toggle-label { font: 600 13.5px var(--jx-font-ui); color: var(--jx-ink); }
.jx-toggle-desc { font-size: 12px; color: var(--jx-muted); margin-top: 2px; }
.jx-switch { position: relative; width: 38px; height: 22px; flex: none; }
.jx-switch input { opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; position: absolute; z-index: 1; }
.jx-switch input:disabled { cursor: not-allowed; }
.jx-switch-track { position: absolute; inset: 0; background: var(--jx-line-strong); border-radius: 100px; transition: background var(--jx-motion-fast) var(--jx-motion-ease); }
.jx-switch-track::after { content: ""; position: absolute; width: 18px; height: 18px; border-radius: 50%; background: #fff; top: 2px; left: 2px; transition: transform var(--jx-motion-fast) var(--jx-motion-ease); box-shadow: 0 1px 2px rgba(16,21,42,.3); }
.jx-switch input:checked + .jx-switch-track { background: var(--jx-accent); }
.jx-switch input:checked + .jx-switch-track::after { transform: translateX(16px); }
.jx-switch input:disabled + .jx-switch-track { opacity: .55; }

/* Rodapé de ações do formulário — ecoa as ações do PageHeader para não
   depender de rolagem de volta ao topo (mesma decisão do Create/Edit
   archetype: deliberadamente não-sticky). */
.jx-form-footer { background: var(--jx-surface); border: 1px solid var(--jx-line); border-radius: var(--jx-radius); padding: var(--jx-space-4) var(--jx-space-5); display: flex; justify-content: flex-end; align-items: center; gap: var(--jx-space-2); }

/* ============================================================================
 * TOAST — notificação não-bloqueante (JX.Toast, js/admin2/components.js).
 * Adicionado na Wave 9 (2026-09-09): várias páginas já rebuiltadas neste
 * projeto (CorporateGamification.php/CertificateTemplateSettings.php/
 * ReportsExecutive.php) tinham removido jQuery mas continuavam chamando
 * `window.toastr` — o `toastr.min.js` deste repo é o build clássico
 * (CodeSeven/toastr), que EXIGE jQuery internamente (`window.toastr =
 * factory(window.jQuery)`); sem jQuery carregado, `toastr.success(...)`
 * lança uma exceção em runtime em vez de mostrar a notificação. Confirmado
 * via teste direto do arquivo real (Node, sem jQuery): lança
 * "Cannot read properties of undefined". Este componente substitui esse
 * uso — vanilla, zero dependência de jQuery, mesmo contrato de chamada
 * (`.success(msg)`/`.error(msg)`/`.warning(msg)`/`.info(msg)`) para manter
 * o diff de retrofit pequeno.
 * ========================================================================= */
.jx-toast-stack {
  position: fixed; right: var(--jx-space-5); bottom: var(--jx-space-5); z-index: 10030;
  display: flex; flex-direction: column-reverse; gap: var(--jx-space-2);
  max-width: min(380px, calc(100vw - 2 * var(--jx-space-5))); pointer-events: none;
}
.jx-toast {
  pointer-events: auto; display: flex; align-items: flex-start; gap: var(--jx-space-2);
  background: var(--jx-shell-ink); color: #fff; border-radius: var(--jx-radius-sm);
  padding: var(--jx-space-3) var(--jx-space-4); box-shadow: var(--jx-shadow-floating);
  font: 500 13.5px var(--jx-font-ui); border-left: 3px solid var(--jx-accent-ink);
  opacity: 0; transform: translateY(6px); transition: opacity var(--jx-motion-base) var(--jx-motion-ease), transform var(--jx-motion-base) var(--jx-motion-ease);
}
.jx-toast.is-visible { opacity: 1; transform: translateY(0); }
.jx-toast-success { border-left-color: var(--jx-success); }
.jx-toast-warning { border-left-color: var(--jx-warning); }
.jx-toast-error   { border-left-color: var(--jx-danger); }
.jx-toast-msg { flex: 1; min-width: 0; word-break: break-word; }
.jx-toast-close { flex: none; background: none; border: none; color: rgba(255,255,255,.7); cursor: pointer; font-size: 15px; line-height: 1; padding: 2px; }
.jx-toast-close:hover { color: #fff; }
