/* ============================================================================
   Design system v3 — componentes.
   ============================================================================
   Companheiro de tokens.css (que só declara variáveis e primitivas). Aqui
   moram as classes que as telas escrevem.

   Regras que valem para o arquivo inteiro:
     - ZERO !important. Se precisou, a especificidade está errada. A única
       exceção autorizada do sistema vive em compat.css, que é temporário.
     - ZERO hex de status. Semântico sai de --ds-ok / --ds-bad / --ds-warn, e
       os tints saem de color-mix sobre eles. Assim trocar o tema muda um
       lugar só.
     - Dado numérico SEMPRE em var(--ds-mono) + tabular-nums. Valor que dança
       de largura entre linhas é o que faz tabela financeira parecer amadora.
     - Âmbar é acento (botão, item ativo, tag), nunca faixa de fundo. NÃO usar
       --hover-bg (#fefbf3) nem --amber-light (#fff8eb) como preenchimento.
   ========================================================================== */


/* ── toast: fallback sem SweetAlert2 ──────────────────────────────────────
   O aviso padrão do sistema é o toast do SweetAlert2 (tematizado em
   css/design/swal.css). showToast() em main.js delega para ele.

   Este bloco só entra em ação quando window.Swal não existe — o que acontece
   quando a tela sobrescreveu {% block js %} sem {{ block.super }} e perdeu os
   vendors. Sem ele, essa tela ficaria muda. Mesmo acabamento, para não
   destoar. Ver tasks/lessons.md, "Swal is not defined só naquela tela".
   ========================================================================== */
.ds-toast-container {
  position: fixed;
  /* Abaixo do header: ele é fixed/top:0 com 56px e z-index 997. Sem o recuo,
     o aviso cobre o sino, o saldo e o menu de perfil — justamente o que a
     pessoa pode querer usar logo depois da ação que gerou o aviso. */
  top: calc(var(--header-h, 56px) + var(--ds-2));
  right: var(--ds-3);
  z-index: 1060;
  display: flex;
  flex-direction: column;
  gap: var(--ds-2);
  max-width: min(380px, calc(100vw - 2 * var(--ds-3)));
  pointer-events: none;   /* o container não bloqueia clique na página */
}

.ds-toast {
  pointer-events: auto;   /* mas o toast em si é clicável (fechar) */
  display: flex;
  align-items: flex-start;
  gap: var(--ds-2);
  padding: var(--ds-3) var(--ds-4);
  background: var(--ds-surface);
  color: var(--ds-text);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-lg);
  box-shadow: var(--ds-shadow-pop);
  font-size: 13px;
  font-weight: 600;
  animation: ds-toast-in .18s ease-out;
}

/* Cor + ícone, nunca cor sozinha: quem não distingue verde de vermelho
   continua sabendo o que aconteceu. */
.ds-toast-ico { font-size: 16px; line-height: 1.3; flex: none; }
.ds-toast-success .ds-toast-ico { color: var(--ds-ok); }
.ds-toast-error   .ds-toast-ico { color: var(--ds-bad); }
.ds-toast-warning .ds-toast-ico { color: var(--ds-warn); }
.ds-toast-info    .ds-toast-ico { color: var(--ds-text-dim); }

.ds-toast-msg { flex: 1; min-width: 0; overflow-wrap: anywhere; font-weight: 600; }

.ds-toast-close {
  flex: none;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  color: var(--ds-text-faint);
  font-size: 12px;
  line-height: 1.4;
}
.ds-toast-close:hover { color: var(--ds-text); }
.ds-toast-close:focus-visible {
  outline: 2px solid var(--ds-brand);
  outline-offset: 2px;
  border-radius: 3px;
}

.ds-toast.leaving { animation: ds-toast-out .18s ease-in forwards; }

@keyframes ds-toast-in  { from { opacity: 0; transform: translateX(12px); } }
@keyframes ds-toast-out { to   { opacity: 0; transform: translateX(12px); } }

@media (prefers-reduced-motion: reduce) {
  .ds-toast, .ds-toast.leaving { animation: none; }
}

@media (max-width: 767px) {
  /* No celular o header continua fixo; o toast ocupa a largura menos as
     margens em vez de uma coluna estreita no canto. */
  .ds-toast-container { left: var(--ds-3); max-width: none; }
}


/* ── cabeçalho de página ──────────────────────────────────────────────────
   Substitui v2-page-header (19 telas), partes-page-header (3) e .pagetitle (2).
   ========================================================================== */
.ds-page-header {
  display: flex; align-items: flex-start; gap: var(--ds-4);
  margin-bottom: var(--ds-5);
}
.ds-page-title {
  font-size: var(--ds-fs-6); font-weight: 750;
  letter-spacing: -.012em; color: var(--ds-text); margin: 0;
}
.ds-page-desc {
  font-size: var(--ds-fs-2); color: var(--ds-text-dim); margin: 2px 0 0;
}
.ds-page-actions {
  margin-left: auto; display: flex; align-items: center;
  gap: var(--ds-2); flex: none;
}
@media (max-width: 767px) {
  .ds-page-header { flex-direction: column; gap: var(--ds-3); }
  .ds-page-actions { margin-left: 0; width: 100%; flex-wrap: wrap; }
}


/* ── barra de ferramentas ─────────────────────────────────────────────────
   Substitui o ícone de busca posicionado por style="position:absolute" inline,
   idêntico em entity.html, entity_curation.html e user/list.html.
   ========================================================================== */
.ds-toolbar {
  display: flex; align-items: center; gap: var(--ds-2);
  flex-wrap: wrap; margin-bottom: var(--ds-3);
}
.ds-toolbar-sp { flex: 1; }
.ds-search { position: relative; flex: 1 1 240px; min-width: 200px; }
.ds-search input {
  width: 100%; padding: 7px 11px 7px 32px;
  font-size: var(--ds-fs-3); color: var(--ds-text);
  background: var(--ds-surface);
  border: 1px solid var(--ds-border-field); border-radius: var(--ds-radius);
}
.ds-search-ico {
  position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
  color: var(--ds-text-faint); pointer-events: none; line-height: 1;
}


/* ── tabela ───────────────────────────────────────────────────────────────
   Substitui v2-table-card, partes-table-card, cmp-table-wrap, bv2-listwrap e
   pipe-table-wrap — cinco grafias do mesmo componente.
   ========================================================================== */
.ds-table-card {
  background: var(--ds-surface); border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-lg); box-shadow: var(--ds-shadow);
  overflow: hidden;
}
/* O scroll horizontal mora AQUI, nunca no body: tabela larga que empurra a
   página inteira de lado é o defeito mais comum em tela de dado denso. */
.ds-table-wrap { overflow-x: auto; }
.ds-table { width: 100%; border-collapse: collapse; }
.ds-table th {
  position: sticky; top: 0; z-index: 2;
  background: var(--ds-surface-2); text-align: left; white-space: nowrap;
  padding: 9px 14px;
  font-size: var(--ds-fs-1); font-weight: 800; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ds-text-dim);
  border-bottom: 1px solid var(--ds-border);
}
.ds-table td {
  padding: 9px 14px; font-size: var(--ds-fs-3); color: var(--ds-text);
  border-bottom: 1px solid var(--ds-border); vertical-align: top;
}
.ds-table tbody tr:last-child td { border-bottom: 0; }
/* Hover neutro: uma regra serve os dois temas. NÃO usar --hover-bg (#fefbf3)
   nem --amber-light (#fff8eb) — âmbar é acento, não preenchimento de linha. */
.ds-table tbody tr:hover td {
  background: color-mix(in srgb, var(--ds-text) 3%, transparent);
}
/* Sem tabular-nums o número dança de largura entre linhas, e é isso que faz
   tabela financeira parecer amadora. */
.ds-table td.num, .ds-table th.num {
  text-align: right;
  font-family: var(--ds-mono); font-variant-numeric: tabular-nums;
}
.ds-table td.mono {
  font-family: var(--ds-mono); font-variant-numeric: tabular-nums;
}
.ds-table tr.selected td {
  background: color-mix(in srgb, var(--ds-brand) 10%, transparent);
}


/* ── estado vazio ─────────────────────────────────────────────────────────
   Substitui v2-empty-state, ps-empty-block, bv2-lane-empty, nv2-empty-inline,
   em-empty e cmp-empty. Seis telas de tabela hoje não têm nenhum.
   ========================================================================== */
.ds-empty { text-align: center; padding: var(--ds-6) var(--ds-4); }
.ds-empty-ico {
  width: 38px; height: 38px; margin: 0 auto var(--ds-3);
  border-radius: 50%; background: var(--ds-surface-2);
  border: 1px solid var(--ds-border);
  display: grid; place-items: center;
  color: var(--ds-text-faint); font-size: 17px;
}
.ds-empty-title {
  font-size: var(--ds-fs-4); font-weight: 650; color: var(--ds-text);
}
.ds-empty-desc {
  font-size: var(--ds-fs-2); color: var(--ds-text-dim);
  margin: var(--ds-1) auto var(--ds-3); max-width: 46ch;
}


/* ── skeleton ─────────────────────────────────────────────────────────────
   Substitui nv2-skel-block, v2-skeleton e sk-bar. Vai no HTML, não injetado
   por JS: o primeiro paint já tem estrutura. Larguras por classe, não por
   style="width:…" repetido dezenas de vezes no template.
   ========================================================================== */
.ds-skel {
  background: var(--ds-surface-2); border-radius: 4px;
  height: 10px; position: relative; overflow: hidden;
}
.ds-skel::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent,
    color-mix(in srgb, var(--ds-text) 7%, transparent), transparent);
  animation: ds-shimmer 1.5s infinite;
}
@keyframes ds-shimmer { to { transform: translateX(100%); } }
.ds-skel-stack { display: flex; flex-direction: column; gap: var(--ds-2); }
.ds-skel-25 { width: 25%; } .ds-skel-40 { width: 40%; }
.ds-skel-55 { width: 55%; } .ds-skel-70 { width: 70%; }
.ds-skel-85 { width: 85%; } .ds-skel-100 { width: 100%; }
.ds-skel-lg { height: 16px; }
@media (prefers-reduced-motion: reduce) { .ds-skel::after { animation: none; } }


/* ── filtros ──────────────────────────────────────────────────────────────
   Substitui partes-filter-card, hoje copiado LITERAL (com os mesmos IDs) em
   6 telas: lead/list, lead/search, lead/search_parts, partes/list,
   process/list e direito_creditorio.
   ========================================================================== */
.ds-filters {
  background: var(--ds-surface); border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-lg); box-shadow: var(--ds-shadow);
  margin-bottom: var(--ds-4);
}
.ds-filters-head {
  display: flex; align-items: center; gap: var(--ds-2);
  padding: var(--ds-3) var(--ds-4); cursor: pointer;
  border-bottom: 1px solid var(--ds-border);
  background: none; border-left: 0; border-right: 0; border-top: 0;
  width: 100%; text-align: left;
}
.ds-filters-head[aria-expanded="false"] { border-bottom-color: transparent; }
.ds-filters-title {
  font-size: var(--ds-fs-1); font-weight: 800; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ds-text-dim);
}
.ds-filters-count {
  font-family: var(--ds-mono); font-variant-numeric: tabular-nums;
  font-size: var(--ds-fs-2); color: var(--ds-text-dim); margin-left: auto;
}
/* Colapso por linha de grid (1fr → 0fr) e não por max-height: max-height
   precisa de um número mágico, e o número escolhido lá atrás (800px) CORTAVA
   o painel de advogados quando a grade quebrava em mais linhas. Grid anima
   até a altura real do conteúdo, qualquer que seja.

   Este bloco morava duplicado em css/common/listagem.css e css/lead/listagem.css
   — dois agentes resolveram o mesmo problema em arquivos separados porque
   nenhum podia editar o do outro. As classes são do partial
   includes/_ds_filters.html, que é componente; o lugar delas é aqui. */
.ds-filters-body {
  display: grid;
  grid-template-rows: 1fr;
  padding: var(--ds-4);
  opacity: 1;
  transition: grid-template-rows .3s cubic-bezier(.4, 0, .2, 1),
              padding .3s cubic-bezier(.4, 0, .2, 1),
              opacity .2s ease;
}
.ds-filters-body.collapsed {
  grid-template-rows: 0fr;
  opacity: 0;
  padding-top: 0;
  padding-bottom: 0;
}
/* min-height:0 é o que deixa a linha encolher abaixo do conteúdo; sem ele o
   0fr não faz nada. O padding fica no pai, senão sobraria uma faixa com o
   painel fechado. */
.ds-filters-inner { min-height: 0; overflow: hidden; }
/* Fechado, o cabeçalho vira a última linha do cartão e a divisória dele
   ficaria solta acima da borda. Cobre os dois jeitos de marcar o estado:
   atributo (acessível) e classe (o que os JS antigos alternam). */
.ds-filters-head[aria-expanded="false"],
.ds-filters:has(> .ds-filters-body.collapsed) .ds-filters-head {
  border-bottom-color: transparent;
}
.ds-filters-chev {
  color: var(--ds-text-faint); font-size: 13px;
  margin-left: var(--ds-1); transition: transform .2s ease;
}
.ds-filters-chev.collapsed { transform: rotate(180deg); }

.ds-filters-grid {
  display: grid; gap: var(--ds-3);
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}
.ds-filters-grid + .ds-filters-grid { margin-top: var(--ds-3); }
.ds-filters-sep {
  height: 1px; background: var(--ds-border); margin: var(--ds-4) 0;
}
/* Campo de duas colunas: um intervalo "de / até" em 190px fica ilegível.
   Abaixo de 560px a grade pode ter uma coluna só, e aí `span 2` criaria uma
   coluna implícita que estoura a largura — `1 / -1` nunca estoura. */
.ds-field-2 { grid-column: span 2; }
.ds-field-3 { grid-column: span 3; }
@media (max-width: 560px) {
  .ds-field-2, .ds-field-3 { grid-column: 1 / -1; }
}
/* Par "de / até" dentro de um .ds-field. */
.ds-field-range { display: flex; align-items: center; gap: var(--ds-2); }
.ds-field-range input { flex: 1; min-width: 0; }
.ds-field-range > span {
  flex: none; font-size: var(--ds-fs-2); color: var(--ds-text-faint);
}

.ds-filters-bar {
  display: flex; align-items: center; gap: var(--ds-2); flex-wrap: wrap;
  margin-top: var(--ds-4); padding-top: var(--ds-3);
  border-top: 1px solid var(--ds-border);
}
/* Barra de chips: o JS alterna .has-chips conforme houver filtro ativo, por
   isso a visibilidade mora em classe e não em atributo. */
.ds-filters-chipbar {
  display: none;
  padding: var(--ds-2) var(--ds-4);
  border-top: 1px solid var(--ds-border);
}
.ds-filters-chipbar.has-chips { display: block; }
.ds-filters-chipbar .ds-chips { align-items: center; gap: var(--ds-2); }
.ds-chips { display: flex; flex-wrap: wrap; gap: var(--ds-1); }

@media (prefers-reduced-motion: reduce) {
  .ds-filters-body, .ds-filters-chev { transition: none; }
}


/* ── KPI ──────────────────────────────────────────────────────────────────
   Substitui v2-kpi-card, pipe-kpi, evo-stat, sig-summary e rpt-kpi.
   ========================================================================== */
.ds-kpis {
  display: grid; gap: var(--ds-3); margin-bottom: var(--ds-5);
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
}
.ds-kpi {
  background: var(--ds-surface); border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius); padding: var(--ds-3) var(--ds-4);
}
.ds-kpi-title {
  font-size: var(--ds-fs-1); font-weight: 800; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ds-text-dim);
}
.ds-kpi-value {
  font-family: var(--ds-mono); font-variant-numeric: tabular-nums;
  font-size: var(--ds-fs-7); font-weight: 700;
  letter-spacing: -.02em; line-height: 1.1; margin-top: var(--ds-1);
  color: var(--ds-text);
}
/* Variantes semânticas por classe — nunca style="color:#16a34a" no template,
   que é o que pipeline/index.html faz hoje. */
.ds-kpi-value.ok  { color: var(--ds-ok); }
.ds-kpi-value.bad { color: var(--ds-bad); }
.ds-kpi-sub {
  font-size: var(--ds-fs-2); color: var(--ds-text-faint); margin-top: 2px;
}


/* ── formulário ───────────────────────────────────────────────────────────
   Substitui os controles espalhados entre style.css, access.css e inline.
   ========================================================================== */
.ds-form-grid {
  display: grid; gap: var(--ds-4);
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}
.ds-field-wide { grid-column: 1 / -1; }
.ds-field { display: flex; flex-direction: column; gap: var(--ds-1); }
.ds-field > label {
  font-size: var(--ds-fs-1); font-weight: 800; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ds-text-dim);
}
.ds-field input, .ds-field select, .ds-field textarea {
  font-size: var(--ds-fs-3); color: var(--ds-text);
  background: var(--ds-surface);
  border: 1px solid var(--ds-border-field); border-radius: var(--ds-radius);
  padding: 7px 10px;
}
.ds-field input:focus-visible,
.ds-field select:focus-visible,
.ds-field textarea:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--ds-brand) 65%, transparent);
  outline-offset: 1px; border-color: var(--ds-brand);
}
/* Ajuda PERSISTENTE abaixo do campo, não placeholder: placeholder some
   quando a pessoa começa a digitar, que é justo quando ela precisa da dica. */
.ds-field-help { font-size: var(--ds-fs-2); color: var(--ds-text-faint); }
/* Erro: cor + ícone + texto. Cor sozinha não comunica para quem não
   distingue vermelho. */
.ds-field-error {
  display: flex; align-items: flex-start; gap: 5px;
  font-size: var(--ds-fs-2); color: var(--ds-bad); font-weight: 600;
}
.ds-field.has-error input,
.ds-field.has-error select,
.ds-field.has-error textarea { border-color: var(--ds-bad); }
.ds-field.has-error input:focus-visible,
.ds-field.has-error select:focus-visible,
.ds-field.has-error textarea:focus-visible {
  outline-color: color-mix(in srgb, var(--ds-bad) 65%, transparent);
}
.ds-field-req { color: var(--ds-bad); margin-left: 2px; }
/* Somente-leitura ≠ desabilitado: um é submetido, o outro não. */
.ds-field input[readonly], .ds-field textarea[readonly] {
  background: var(--ds-surface-2); color: var(--ds-text-dim);
  border-color: var(--ds-border);
}
.ds-field input:disabled, .ds-field select:disabled, .ds-field textarea:disabled {
  opacity: .45; cursor: not-allowed;
}

/* switch âmbar — equivalente ao .v2-switch de access.css, sobre os tokens */
.ds-switch {
  position: relative; display: inline-block;
  width: 36px; height: 20px; flex: none;
}
.ds-switch input {
  position: absolute; opacity: 0; width: 100%; height: 100%;
  margin: 0; cursor: pointer;
}
.ds-switch-track {
  position: absolute; inset: 0; border-radius: 999px;
  background: var(--ds-surface-2); border: 1px solid var(--ds-border-field);
  transition: background .15s, border-color .15s; pointer-events: none;
}
.ds-switch-track::after {
  content: ""; position: absolute; left: 2px; top: 50%;
  width: 14px; height: 14px; border-radius: 50%;
  transform: translateY(-50%); background: var(--ds-text-faint);
  transition: transform .15s, background .15s;
}
.ds-switch input:checked + .ds-switch-track {
  background: var(--ds-brand); border-color: var(--ds-brand);
}
.ds-switch input:checked + .ds-switch-track::after {
  transform: translate(16px, -50%); background: var(--ds-on-brand);
}
.ds-switch input:focus-visible + .ds-switch-track {
  outline: 2px solid var(--ds-brand); outline-offset: 2px;
}
.ds-switch-row {
  display: flex; align-items: center; gap: var(--ds-3);
  padding: var(--ds-2) 0; border-bottom: 1px solid var(--ds-border);
}
.ds-switch-row:last-child { border-bottom: 0; }
.ds-switch-row-text { flex: 1; min-width: 0; }
.ds-switch-row-title {
  font-size: var(--ds-fs-3); font-weight: 600; color: var(--ds-text);
  display: block; cursor: pointer;
}
.ds-switch-row-desc { font-size: var(--ds-fs-2); color: var(--ds-text-dim); }
@media (prefers-reduced-motion: reduce) {
  .ds-switch-track, .ds-switch-track::after { transition: none; }
}


/* ── abas ─────────────────────────────────────────────────────────────────
   Unifica as abas ad-hoc ps-tab (person-search, company-search) com as abas
   Bootstrap de process/detail. Serve nos dois casos: o estado ativo é .active,
   que é o que o Bootstrap já aplica sozinho.
   ========================================================================== */
.ds-tabs {
  display: flex; gap: var(--ds-1); border-bottom: 1px solid var(--ds-border);
  margin-bottom: var(--ds-4); overflow-x: auto;
}
.ds-tab {
  padding: 9px var(--ds-3); white-space: nowrap; cursor: pointer;
  font-size: var(--ds-fs-3); font-weight: 600; color: var(--ds-text-dim);
  background: none; border: 0; border-bottom: 2px solid transparent;
  transition: color .12s, border-color .12s;
}
.ds-tab:hover { color: var(--ds-text); }
.ds-tab.active {
  color: var(--ds-text); font-weight: 700; border-bottom-color: var(--ds-brand);
}
.ds-tab:focus-visible { outline: 2px solid var(--ds-brand); outline-offset: -2px; }
.ds-tab-badge {
  margin-left: 5px; font-family: var(--ds-mono); font-size: 10px;
  font-weight: 700; padding: 1px 5px; border-radius: 999px;
  background: var(--ds-idle-soft); color: var(--ds-idle);
}


/* ── modal ────────────────────────────────────────────────────────────────
   Substitui em-* e os modais Bootstrap crus. O JS continua o do Bootstrap
   (data-bs-toggle="modal") — aqui é só a pele.
   ========================================================================== */
.ds-modal .modal-content {
  background: var(--ds-surface); border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-lg); box-shadow: var(--ds-shadow-pop);
}
.ds-modal .modal-header {
  padding: var(--ds-3) var(--ds-4);
  border-bottom: 1px solid var(--ds-border);
  background: var(--ds-surface-2);
  border-radius: var(--ds-radius-lg) var(--ds-radius-lg) 0 0;
}
.ds-modal .modal-title {
  font-size: var(--ds-fs-4); font-weight: 700; color: var(--ds-text); margin: 0;
}
.ds-modal .modal-body { padding: var(--ds-4); font-size: var(--ds-fs-3); }
.ds-modal .modal-footer {
  padding: var(--ds-3) var(--ds-4); border-top: 1px solid var(--ds-border);
  display: flex; justify-content: flex-end; gap: var(--ds-2);
}
/* O X do Bootstrap é uma imagem preta embutida: no escuro ele some. */
[data-theme="dark"] .ds-modal .btn-close {
  filter: invert(1) grayscale(100%) brightness(200%);
}


/* ── drawer ───────────────────────────────────────────────────────────────
   Substitui partes-drawer, duplicado em lawyer, person-search e
   company-search.
   ========================================================================== */
.ds-drawer-overlay {
  position: fixed; inset: 0; z-index: 1050;
  background: rgba(0, 0, 0, .5);
  opacity: 0; visibility: hidden; transition: opacity .2s, visibility .2s;
}
.ds-drawer-overlay.open { opacity: 1; visibility: visible; }
.ds-drawer {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 1051;
  width: min(460px, 100vw);
  background: var(--ds-surface); border-left: 1px solid var(--ds-border);
  box-shadow: var(--ds-shadow-pop);
  display: flex; flex-direction: column;
  transform: translateX(100%); transition: transform .22s ease-out;
}
.ds-drawer.open { transform: translateX(0); }
.ds-drawer-head {
  display: flex; align-items: center; gap: var(--ds-2);
  padding: var(--ds-4); border-bottom: 1px solid var(--ds-border);
}
.ds-drawer-title {
  font-size: var(--ds-fs-4); font-weight: 700; color: var(--ds-text);
}
.ds-drawer-body { flex: 1; overflow-y: auto; padding: var(--ds-4); }
.ds-drawer-foot {
  padding: var(--ds-3) var(--ds-4); border-top: 1px solid var(--ds-border);
  display: flex; gap: var(--ds-2); justify-content: flex-end;
}
@media (prefers-reduced-motion: reduce) {
  .ds-drawer, .ds-drawer-overlay { transition: none; }
}


/* ── wizard ───────────────────────────────────────────────────────────────
   Substitui os passos duplicados entre marketing/campaigns.html e
   marketing/lead-prospection.html — hoje campaigns carrega o CSS E o JS de
   lead-prospection, e ainda assim repete o markup.
   ========================================================================== */
.ds-wizard-steps {
  display: flex; align-items: center; gap: var(--ds-2);
  margin-bottom: var(--ds-5); overflow-x: auto; padding-bottom: var(--ds-1);
}
.ds-wizard-step {
  display: flex; align-items: center; gap: var(--ds-2);
  white-space: nowrap; font-size: var(--ds-fs-2); color: var(--ds-text-faint);
}
.ds-wizard-num {
  width: 22px; height: 22px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  font-family: var(--ds-mono); font-size: var(--ds-fs-1); font-weight: 700;
  background: var(--ds-surface-2); border: 1px solid var(--ds-border);
  color: var(--ds-text-faint);
}
.ds-wizard-step.on { color: var(--ds-text); font-weight: 650; }
.ds-wizard-step.on .ds-wizard-num {
  background: var(--ds-brand); border-color: var(--ds-brand);
  color: var(--ds-on-brand);
}
.ds-wizard-step.done .ds-wizard-num {
  background: var(--ds-ok); border-color: var(--ds-ok); color: #fff;
}
.ds-wizard-sep {
  flex: 1 1 20px; min-width: 16px; height: 1px; background: var(--ds-border);
}
.ds-wizard-pane[hidden] { display: none; }


/* ── checkbox e radio ─────────────────────────────────────────────────────
   Sem aparência explícita, o navegador desenha o controle nativo e o resultado
   depende do `color-scheme`: no tema claro sai uma caixinha discreta, no
   escuro sai um contorno que praticamente some contra a superfície. O
   "Lembrar de mim" do login ficava invisível no dark.

   Aqui a caixa é desenhada por nós, com os mesmos tokens de borda dos outros
   campos (`--ds-border-field`, 3:1) — mesma aparência nos dois temas e em
   qualquer engine. Marcado é âmbar com o check em `--ds-on-brand`: branco
   sobre âmbar daria 2.08:1 e o check sumiria, que é exatamente o defeito que
   o SVG embutido do Bootstrap tem.
   ========================================================================== */
input[type="checkbox"].ds-check,
input[type="radio"].ds-check,
.ds-field input[type="checkbox"],
.ds-field input[type="radio"],
.ds-switch-row > input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  width: 16px; height: 16px; flex: none; margin: 0;
  background: var(--ds-surface);
  border: 1px solid var(--ds-border-field);
  border-radius: 3px;
  cursor: pointer;
  transition: background .12s, border-color .12s;
}
input[type="radio"].ds-check,
.ds-field input[type="radio"] { border-radius: 50%; }

/* A marca vai em `background-image`, NÃO em ::before.
   `<input>` é elemento substituído e não renderiza pseudo-elemento de forma
   confiável — com ::before o "V" saía desenhado fora da caixa. É por isso que
   o próprio Bootstrap usa background-image aqui.

   O `%23141824` é `--ds-on-brand` escrito à mão: data URI não interpola
   `var()`. Se o token mudar, muda aqui junto. Escuro sobre âmbar dá 8.51:1 —
   o SVG do Bootstrap usa branco, que dá 2.08:1 e faz o "V" sumir. */
input[type="checkbox"].ds-check:checked,
input[type="radio"].ds-check:checked,
.ds-field input[type="checkbox"]:checked,
.ds-field input[type="radio"]:checked,
.ds-switch-row > input[type="checkbox"]:checked {
  background-color: var(--ds-brand);
  border-color: var(--ds-brand);
  background-repeat: no-repeat;
  background-position: center;
  background-size: 10px 10px;
}
input[type="checkbox"].ds-check:checked,
.ds-field input[type="checkbox"]:checked,
.ds-switch-row > input[type="checkbox"]:checked {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23141824' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M3 8.5l3.2 3.2L13 5'/%3E%3C/svg%3E");
}
input[type="radio"].ds-check:checked,
.ds-field input[type="radio"]:checked {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='4' fill='%23141824'/%3E%3C/svg%3E");
  background-size: 12px 12px;
}

input[type="checkbox"].ds-check:focus-visible,
input[type="radio"].ds-check:focus-visible,
.ds-field input[type="checkbox"]:focus-visible,
.ds-field input[type="radio"]:focus-visible {
  outline: 2px solid var(--ds-brand); outline-offset: 2px;
}
input[type="checkbox"].ds-check:disabled,
input[type="radio"].ds-check:disabled {
  opacity: .45; cursor: not-allowed;
}
@media (prefers-reduced-motion: reduce) {
  input[type="checkbox"].ds-check, input[type="radio"].ds-check { transition: none; }
}




/* ── botão que é <a>: o hover global de link rouba a cor ──────────────────
   `style.css` tem `a:hover { color: #b86200 }` com especificidade (0,1,1), e a
   cor declarada em `.ds-btn` é (0,1,0) — o link vence. Resultado: os 56
   `<a class="ds-btn">` do sistema ficavam com texto âmbar ao passar o mouse, e
   no primário isso é âmbar-escuro sobre âmbar: **2.11:1**, o mesmo defeito que
   o --ds-on-brand tinha resolvido, voltando por outra porta.

   `.ds-btn:hover` é (0,2,0) e vence (0,1,1) sem !important. Declarar a cor no
   hover de cada variante é o que fecha a porta — não basta declarar no estado
   normal, porque quem sobrescreve é o :hover do link. */
.ds-btn:hover,
.ds-btn:focus,
.ds-btn:active { color: var(--ds-text); }
.ds-btn-primary:hover,
.ds-btn-primary:focus,
.ds-btn-primary:active { color: var(--ds-on-brand); }
.ds-btn-ok:hover, .ds-btn-ok:focus, .ds-btn-ok:active,
.ds-btn-bad:hover, .ds-btn-bad:focus, .ds-btn-bad:active { color: #fff; }
.ds-btn-ghost:hover,
.ds-btn-ghost:focus { color: var(--ds-text); }


/* ── botões e pills: variantes que faltavam em tokens.css ────────────────── */
.ds-btn-ghost {
  background: transparent; border-color: transparent; color: var(--ds-text-dim);
}
.ds-btn-ghost:hover { color: var(--ds-text); background: var(--ds-surface-2); }
.ds-btn-sm { padding: 5px 10px; font-size: var(--ds-fs-2); }
/* Botão desabilitado já apareceu ilegível (âmbar desbotado com texto branco).
   Com --ds-on-brand escuro o texto continua legível a 45% de opacidade. */
.ds-btn:disabled, .ds-btn[aria-disabled="true"] {
  opacity: .45; cursor: not-allowed;
}
.ds-pill-warn {
  color: var(--ds-warn-ink);
  background: color-mix(in srgb, var(--ds-warn) 14%, transparent);
}
.ds-pill-brand {
  color: var(--ds-brand-ink);
  background: color-mix(in srgb, var(--ds-brand) 14%, transparent);
}


/* ── lançador do chat de suporte ──────────────────────────────────────────
   O lançador do Freshchat é um iframe de outro domínio, com fundo branco no
   documento dele: no tema escuro virava um quadrado branco no canto.

   Duas tentativas antes desta: esconder o lançador e abrir por um botão
   nosso (quebra o estado interno do widget — clique duplo, abertura
   sozinha) e cobrir com um elemento posicionado por JS (cai no lugar errado
   quando o widget se move). E recortar o iframe com clip-path deixava um
   anel laranja: a borda recortada é do próprio iframe, que tem camada de
   composição própria — nada por baixo cobre.

   O que funciona: o iframe fica INVISÍVEL (opacity 0 não tira o clique, que
   continua sendo dele) e a nossa cara é um ::after do #fc_frame, que é uma
   DIV. Sempre alinhado, sem JS, sem coordenada.

   A regra não pede a classe `.fc-widget-normal`: ela chega um pouco depois
   da div, e nessa fresta o quadrado branco piscava na tela. Ao abrir, o
   widget acrescenta `.fc-open` — aí saímos da frente e a conversa aparece. */
/* Antes de virar lançador, o widget aparece por uns 300ms como uma caixa de
   1500x150 SEM classe: é o quadrado branco que piscava na tela (e, com a
   regra pegando essa fase, o nosso botão chegava a ser desenhado no canto
   dela). Enquanto não é o lançador, não mostramos nada. */
#fc_frame:not(.fc-widget-normal):not(.fc-open) { visibility: hidden; }
#fc_frame.fc-widget-normal:not(.fc-open) > iframe { opacity: 0; }
#fc_frame.fc-widget-normal:not(.fc-open)::after {
  content: "\f249";                    /* bi-chat-dots-fill */
  font-family: "bootstrap-icons";
  font-size: 22px; line-height: 1;
  position: absolute;
  /* a bolha deles é 60px centrada em (34.5, 38.5) do iframe de 70x75 */
  left: 4.5px; top: 8.5px;
  width: 60px; height: 60px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1px solid var(--ds-border);
  background: var(--ds-surface);
  color: var(--ds-text-dim);
  /* sombra curta: a --ds-shadow-pop tem 28px de desfoque e, no tema claro,
     virava um halo em volta do botão — parecia borrado */
  box-shadow: 0 3px 10px rgba(0, 0, 0, .14);
  pointer-events: none;                /* o clique é do widget, não nosso */
}

/* A CONVERSA aberta é branca por tema do Freshchat — o card inteiro, não só
   a moldura em volta. Por dentro do iframe não se mexe (documento de outro
   domínio), mas o iframe como CAIXA aceita filtro: a inversão escurece corpo,
   moldura e barra de resposta de uma vez, e o hue-rotate devolve o matiz das
   cores (o laranja continua laranja).

   O preço, escolhido com o time: o cabeçalho preto deles vira branco e o logo
   inverte junto; imagem enviada no chat aparece com as cores trocadas. Só no
   tema escuro — no claro a conversa já nasce certa e o filtro sairia do ar. */
[data-theme="dark"] #fc_frame.fc-open {
  filter: invert(1) hue-rotate(180deg);
}


/* ── `hidden` tem que ganhar de qualquer display daqui ────────────────────
   O navegador esconde `[hidden]` pela folha DELE, e folha de autor sempre
   vence folha do navegador. Como quase todo componente deste arquivo declara
   `display: flex` ou `grid`, o atributo `hidden` parava de funcionar — uma
   `.ds-field-error` marcada como hidden aparecia como alerta vazio na tela.

   Eu vinha remendando caso a caso (`.ds-filters-body[hidden]`,
   `.ds-wizard-pane[hidden]`), o que só resolve onde alguém lembrou. Esta
   regra, no fim do arquivo, cobre os componentes atuais e os futuros com a
   mesma especificidade (0,1,0) — vence por ordem, sem `!important`.

   Se uma tela precisar sobrepor isto, que use uma classe própria com
   especificidade maior; não mexa aqui. */
[hidden] { display: none; }
