/* Camada canônica do Uni Design System no UniChat — UNICHAT-DEMO-02.
 *
 * Porta os componentes compartilhados da família Uni (`app-*`) já homologados visualmente pelo
 * proprietário em UniServiços CUT 07.1 e UniStock CUT 08. Antes deste corte o UniChat não tinha
 * NENHUMA classe `app-*`: cada tela inventava seu próprio botão e campo, e era por isso que o
 * produto não se parecia com os irmãos.
 *
 * Os tokens `--uni-*` são ALIASES dos `--crm-*` que já existiam (crm-theme.css), não uma paleta
 * nova: a cor de produto do UniChat continua sendo a dele (#1c7ed6), assim como UniServiços tem a
 * sua. O que é compartilhado é a linguagem — escala, raio, tipografia, anatomia dos componentes.
 */

:root {
    /* Papéis de cor — apontam para os tokens já existentes do UniChat. */
    --uni-color-primary: var(--crm-color-primary);
    --uni-color-primary-hover: var(--crm-color-primary-hover);
    --uni-color-primary-soft: var(--crm-color-primary-soft);
    /* UNICHAT-KANBAN-AGENDA-TAREFAS-VISUAL-ASSISTED-CONVERGENCE-01 — o par de TEXTO do pastel
       primário existia só na camada `--crm-*`, com os dois temas declarados (VL-46), e faltava o
       alias canônico. Sem ele, `var(--uni-color-primary-soft-text)` é declaração INVÁLIDA: o
       navegador a descarta e o texto herda a cor do pai. Mesmo caminho de `--uni-shadow-lg` e
       `--uni-z-tooltip`, criados pelos cortes anteriores pelo mesmo motivo. */
    --uni-color-primary-soft-text: var(--crm-color-primary-soft-text);
    --uni-color-on-primary: var(--crm-color-on-primary);
    /* Variante clara usada no degradê do CTA — o par escuro/claro cria o brilho. */
    --uni-color-primary-bright: #4dabf7;

    --uni-color-success: var(--crm-color-success);
    --uni-color-warning: var(--crm-color-warning);
    --uni-color-danger: var(--crm-color-danger);
    --uni-color-info: var(--crm-color-info);
    --uni-color-neutral: var(--crm-color-text-muted);

    --uni-color-success-soft: #e5f7ee;
    --uni-color-warning-soft: #fdf1e2;
    --uni-color-danger-soft: #fbe9e9;
    --uni-color-info-soft: #eaf2fb;
    --uni-color-neutral-soft: #eef1f5;

    --uni-color-app-bg: var(--crm-color-app-bg);
    --uni-color-surface: var(--crm-color-surface);
    --uni-color-border: var(--crm-color-border);
    --uni-color-border-strong: var(--crm-color-border-strong);
    --uni-color-text: var(--crm-color-text);
    --uni-color-text-muted: var(--crm-color-text-muted);
    --uni-color-text-subtle: #94a0b4;
    /* C-03 PROMOVIDO A REGRA GERAL (decisão do proprietário, 2026-09-07), na forma emendada por
       VL-44: o âmbar vale FORA de campos de entrada — botão, aba, linha de lista, ação de linha,
       switch, menu. Dentro do campo quem realça é a borda na cor do produto mais o halo, porque
       um anel retangular por fora do campo cria dois indicadores concorrentes e ignora o raio do
       controle. Segunda prova em /contatos e em Usuários/Permissões, sem contraexemplo. */
    --uni-color-focus-ring: #b45309;

    --uni-color-shell-bg: var(--crm-color-sidebar-bg);
    --uni-color-shell-bg-hover: var(--crm-color-sidebar-bg-hover);

    /* Tipografia canônica da família Uni. */
    --uni-font-family: Inter, "Segoe UI", Roboto, Arial, sans-serif;
    /* UNICHAT-VISUAL-SYSTEM-ASSISTED-CONVERGENCE-01 / VL-01, decisao VG-05: A.
       Degrau de micro-label (11px). Uso RESTRITO a cabecalho de coluna, texto de badge, rotulo
       de acao por icone e metadado de segunda linha. Proibido em conteudo primario, titulo,
       corpo ou valor de campo - ver foundations.md. */
    --uni-font-size-2xs: 0.6875rem;
    --uni-font-size-xs: 0.75rem;
    --uni-font-size-sm: 0.8125rem;
    --uni-font-size-md: 0.875rem;
    --uni-font-size-lg: 1rem;
    --uni-font-size-xl: 1.25rem;
    --uni-font-size-2xl: 1.75rem;

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

    /* UNICHAT-MOBILE-UX-CONFORMANCE-01 (Phase B) — escala canônica de z-index
       (foundations.md do Uni DS). Componentes novos usam SOMENTE estes tokens;
       os valores legados fora da escala estão registrados em DESIGN_GAPS G31. */
    --uni-z-sticky: 10;
    --uni-z-nav: 30;
    --uni-z-dropdown: 40;
    --uni-z-backdrop: 50;
    --uni-z-modal: 51;
    --uni-z-toast: 60;
    /* UNICHAT-CONFIGURACOES-VISUAL-ASSISTED-CONVERGENCE-01 — VL-09 declara a escala terminando em
       "tooltip 70", mas o token nunca existiu. Quem escrevesse `z-index: var(--uni-z-tooltip)`
       recebia uma declaração INVÁLIDA, que o navegador descarta em silêncio: o elemento ficava sem
       camada nenhuma e sumia atrás do conteúdo. Foi o que aconteceu com o popover do (i), medido na
       revisão. Token fantasma não avisa — só o resultado na tela denuncia. */
    --uni-z-tooltip: 70;
    /* CUT 5F (Workstream C) — camadas do shell nomeadas (mesmos valores que já estavam soltos em
       crm-shell.css) e o tour como camada própria. Escala completa e regras de convivência em
       docs/design-system/UNI_LAYERING_AUTHORITY_01.md. */
    --uni-z-sidebar: 50;
    --uni-z-sidebar-menu-backdrop: 55;
    --uni-z-sidebar-menu: 60;
    --uni-z-tour: 70;
    --uni-z-media-viewer: 80;

    --uni-radius-xs: var(--crm-radius-xs);
    --uni-radius-sm: var(--crm-radius-sm);
    --uni-radius-md: var(--crm-radius-md);
    --uni-radius-lg: var(--crm-radius-lg);
    --uni-radius-xl: var(--crm-radius-xl);
    --uni-radius-pill: 999px;

    --uni-shadow-sm: var(--crm-shadow-sm);
    --uni-shadow-md: var(--crm-shadow-md);
    /* UNICHAT-VISUAL-SYSTEM-ASSISTED-CONVERGENCE-01 / VL-08. Terceiro nivel de elevacao, para
       modal e drawer. O valor ja existia em --crm-shadow-lg (com variante escura); faltava o
       alias na camada canonica --uni-*. */
    --uni-shadow-lg: var(--crm-shadow-lg);
}

/* Os papéis "-soft" são os únicos tokens de cor desta família que não derivam de --crm-color-*:
   são pastéis fixos, pensados para o tema claro. No escuro, o neutro é superfície de verdade
   (cabeçalho de tabela, badge neutro, hover de opção), então ele precisa do par escuro — sem ele
   o cabeçalho da tabela de destinatários fica com fundo claro dentro do tema escuro. */
:root[data-crm-theme="dark"] {
    --uni-color-neutral-soft: #222b3a;

    /* C-03, par escuro. Promovido junto com o token claro: `#b45309` sobre fundo escuro fica
       abaixo do contraste mínimo, então o escuro usa o degrau claro do mesmo âmbar. Era um
       override de `.crm-contacts-page`; agora vale para todo o app, como VL-46 exige de todo
       token de cor semântica. */
    --uni-color-focus-ring: #f59e0b;

    /* Revisão do proprietário (2026-09-07): "o badge de sucesso não está legal no dark theme;
       talvez seja problema de todos os badges". Estava — e valia para TODO alerta e TODO badge
       do app, porque os quatro pastéis semânticos só tinham versão clara. Fundo claro com texto
       claro no tema escuro é ilegível, não é questão de gosto.

       Fundo: tinta da própria cor sobre a superfície escura, preservando a leitura semântica.
       Texto/ícone: a cor precisa CLAREAR no escuro — #1a9c5e sobre fundo escuro fica abaixo do
       mínimo. Os pares abaixo passam em AA contra o fundo correspondente. */
    --uni-color-success-soft: color-mix(in srgb, #1a9c5e 20%, #0f1420);
    --uni-color-warning-soft: color-mix(in srgb, #e2932e 20%, #0f1420);
    --uni-color-danger-soft:  color-mix(in srgb, #e14848 20%, #0f1420);
    --uni-color-info-soft:    color-mix(in srgb, #4d8fd6 20%, #0f1420);

    --uni-color-success: #4ec98a;
    --uni-color-warning: #f0ab4d;
    --uni-color-danger:  #f87171;
    --uni-color-info:    #74aae4;
}

/* Tipografia da família Uni em todo o app. Carregado depois de app.css de propósito: aquele fixa
   "Segoe UI" no body, o que fazia o UniChat destoar dos irmãos mesmo com o resto igual. */
body {
    font-family: var(--uni-font-family);
}

/* ---------- Botão ---------- */

.app-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    align-self: flex-start;
    gap: var(--uni-space-2);
    border-radius: var(--uni-radius-pill);
    border: 1px solid transparent;
    font-family: var(--uni-font-family);
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
    text-decoration: none;
    transition: background-color 0.12s ease, border-color 0.12s ease, color 0.12s ease, opacity 0.12s ease;
}

.app-button-md {
    min-height: 42px;
    padding: 0 var(--uni-space-5);
    font-size: var(--uni-font-size-md);
}

.app-button-sm {
    min-height: 34px;
    padding: 0 var(--uni-space-4);
    font-size: var(--uni-font-size-sm);
}

/* UNICHAT-VISUAL-SYSTEM-ASSISTED-CONVERGENCE-01 / C-01 - conformidade aberta de UI-03A: o degrau
   `lg` (48px) foi aprovado pelo proprietario e nunca existiu no CSS. Aditivo: nenhuma superficie
   consome hoje, entao nada muda ate alguem pedir Size="Lg". */
.app-button-lg {
    min-height: 48px;
    padding: 0 var(--uni-space-6);
    font-size: var(--uni-font-size-md);
}

.app-button-primary {
    background: var(--uni-color-primary);
    border-color: var(--uni-color-primary);
    color: var(--uni-color-on-primary);
}

.app-button-primary:hover:not(:disabled) {
    background: var(--uni-color-primary-hover);
    border-color: var(--uni-color-primary-hover);
}

.app-button-secondary {
    background: var(--uni-color-surface);
    border-color: color-mix(in srgb, var(--uni-color-primary) 30%, var(--uni-color-border));
    color: var(--uni-color-primary);
}

.app-button-secondary:hover:not(:disabled) {
    background: var(--uni-color-primary-soft);
}

.app-button-ghost {
    background: transparent;
    border-color: transparent;
    color: var(--uni-color-text-muted);
}

.app-button-ghost:hover:not(:disabled) {
    background: var(--uni-color-neutral-soft);
    color: var(--uni-color-text);
}

.app-button-danger {
    background: var(--uni-color-surface);
    border-color: color-mix(in srgb, var(--uni-color-danger) 45%, var(--uni-color-border));
    color: var(--uni-color-danger);
}

.app-button-danger:hover:not(:disabled) {
    background: var(--uni-color-danger-soft);
}

.app-button:focus-visible {
    outline: 2px solid var(--uni-color-focus-ring);
    outline-offset: 2px;
}

.app-button:disabled {
    opacity: 0.55;
    cursor: not-allowed;
}

/* Ação canônica Uni: o chrome clicável é circular e o rótulo permanece visível fora do círculo. */
.app-icon-action {
    min-width: 62px;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--uni-color-text-muted);
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    gap: var(--uni-space-1);
    font-family: var(--uni-font-family);
    font-size: var(--uni-font-size-xs);
    font-weight: 600;
    line-height: 1.2;
    text-align: center;
    cursor: pointer;
}

.app-icon-action-circle {
    width: 42px;
    height: 42px;
    border: 1px solid color-mix(in srgb, var(--uni-color-primary) 32%, var(--uni-color-border));
    border-radius: 50%;
    background: var(--uni-color-surface);
    color: var(--uni-color-primary);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background-color 0.12s ease, border-color 0.12s ease, color 0.12s ease, transform 0.12s ease;
}

.app-icon-action-circle .crm-icon {
    width: 19px;
    height: 19px;
}

.app-icon-action-label {
    max-width: 92px;
    color: currentColor;
    overflow-wrap: anywhere;
}

.app-icon-action:hover:not(:disabled) .app-icon-action-circle {
    border-color: var(--uni-color-primary);
    background: var(--uni-color-primary-soft);
    transform: translateY(-1px);
}

.app-icon-action:focus-visible {
    outline: none;
}

.app-icon-action:focus-visible .app-icon-action-circle {
    outline: 2px solid var(--uni-color-focus-ring);
    outline-offset: 2px;
}

.app-icon-action-primary .app-icon-action-circle {
    border-color: var(--uni-color-primary);
    background: var(--uni-color-primary);
    color: var(--uni-color-on-primary);
}

.app-icon-action-primary:hover:not(:disabled) .app-icon-action-circle {
    background: var(--uni-color-primary-hover);
    color: var(--uni-color-on-primary);
}

.app-icon-action-danger {
    color: var(--uni-color-danger);
}

.app-icon-action-danger .app-icon-action-circle {
    border-color: color-mix(in srgb, var(--uni-color-danger) 55%, var(--uni-color-border));
    color: var(--uni-color-danger);
}

.app-icon-action-danger:hover:not(:disabled) .app-icon-action-circle {
    border-color: var(--uni-color-danger);
    background: var(--uni-color-danger-soft);
}

.app-icon-action:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* ---------- Campo de formulário ---------- */

.app-field-label {
    font-size: var(--uni-font-size-sm);
    font-weight: 500;
    color: var(--uni-color-text);
}

/* C-06 PROMOVIDO A REGRA GERAL (decisão do proprietário, 2026-09-07): controle de 42px e raio
   `md`, pareando com a altura do botão (VL-10). Era override sob o escopo `.crm-contacts-page`,
   provado em duas superfícies independentes sem contraexemplo. */
.app-control {
    width: 100%;
    height: 42px;
    padding: 0 var(--uni-space-3);
    border: 1px solid var(--uni-color-border-strong);
    border-radius: var(--uni-radius-md);
    background: var(--uni-color-surface);
    color: var(--uni-color-text);
    font-family: var(--uni-font-family);
    font-size: var(--uni-font-size-md);
}

/* VL-44 — campo de entrada NÃO usa o anel âmbar: borda na cor do produto + halo de 3px a 22%,
   acompanhando o raio do próprio controle. */
.app-control:focus {
    outline: none;
    border-color: var(--uni-color-primary);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--uni-color-primary) 22%, transparent);
}

.app-control::placeholder {
    color: var(--uni-color-text-subtle);
}

/* UNICHAT-CONFIGURACOES-VISUAL-ASSISTED-CONVERGENCE-01 — o campo de várias linhas não tinha ficha
   canônica: `/contatos` resolvia com `class="app-control"` mais um `style` inline de altura e
   padding, que é valor local (proibição 3) repetido em cada uso. A variante existe aqui para que a
   altura venha do `rows` e o padding vertical exista de verdade, mantendo borda, raio, tipografia e
   o foco de VL-44 idênticos ao controle de uma linha. */
.app-control-textarea {
    height: auto;
    min-height: 84px;
    padding: var(--uni-space-3);
    line-height: 1.45;
    resize: vertical;
}

/* ---------- Ficha de campo de formulário (C-09, promovida) ----------
   Revisão do proprietário (2026-09-08), sobre o modal "Nova conversa": *"garanta o gap correto em
   cada campo do formulário"* e *"tem certeza que esse modal está seguindo padrão de tipografia,
   espaçamento, aparência?"*.

   A anatomia rótulo-acima-do-controle já estava resolvida e ACEITA em `/contatos`
   (`.crm-contacts-field`), mas presa à folha daquela superfície — usá-la aqui seria a proibição 1
   (classe emprestada). Por §15, a peça é promovida ao canônico com a MESMA geometria em vez de
   reescrita: `/contatos` migra quando reentrar no programa, sem mudança visual. */

.uni-field {
    display: flex;
    flex-direction: column;
    gap: var(--uni-space-2);
    min-width: 0;
}

/* O rótulo é o primeiro span; ajuda/erro dentro do campo têm a própria ficha (abaixo). */
.uni-field > span:not(.uni-field-hint):not(.uni-field-error) {
    color: var(--uni-color-text);
    font-size: var(--uni-font-size-sm);
    font-weight: 500;
    user-select: none;
}

.uni-field-hint,
.uni-field-error {
    margin: 0;
    font-size: var(--uni-font-size-xs);
    line-height: 1.4;
}

.uni-field-hint { color: var(--uni-color-text-muted); }
.uni-field-error { color: var(--uni-color-danger); }

/* Checkbox é a exceção: o rótulo fica ao lado, não acima — quem decide é a caixa. */
.uni-field-check {
    display: flex;
    align-items: center;
    gap: var(--uni-space-2);
    font-size: var(--uni-font-size-sm);
    color: var(--uni-color-text);
}

.uni-field-check input[type="checkbox"] {
    width: 16px;
    height: 16px;
    margin: 0;
    accent-color: var(--uni-color-primary);
}

/* Duas colunas quando cabem; uma quando não cabem. Mesma escada de VL-05. */
/* =====================================================================================
   Espaço reservado para o resultado de uma ação dentro de modal (F-06, decisão do Owner:
   o tamanho do modal NÃO muda com o conteúdo). O modal de formulário renderiza este slot
   sempre — vazio ou com um UniInlineNotice (uma linha, 36px) — e por isso tem a mesma altura
   antes e depois de um erro ou sucesso. Nunca usar UniSectionAlert (duas linhas, padding de
   seção) como feedback dentro de modal: ele empurra o rodapé.
   ===================================================================================== */
.uni-modal-feedback {
    display: flex;
    flex-direction: column;
    justify-content: center;
    /* Altura FIXA (não mínima): o aviso vive dentro de 36px e nunca empurra o rodapé — nem por
       arredondamento de zoom/DPR, nem por texto que quebraria linha (fica em uma linha, com reticências
       e o texto inteiro no title). */
    height: 36px;
    flex: 0 0 36px;
    overflow: hidden;
}

.uni-modal-feedback .uni-inline-notice {
    height: 36px;
    min-height: 0;
    box-sizing: border-box;
}

/* Campo de senha com olho (UniPasswordInput) — mesma anatomia do login, cores da superfície clara. */
.uni-password-field {
    position: relative;
    display: flex;
    min-width: 0;
}

.uni-password-field .app-control {
    flex: 1 1 auto;
    min-width: 0;
    padding-right: 2.75rem;
}

.uni-password-toggle {
    position: absolute;
    right: 6px;
    top: 50%;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: var(--uni-radius-sm);
    background: transparent;
    color: var(--uni-color-text-muted);
    cursor: pointer;
    transition: color 0.15s ease, background-color 0.15s ease;
}

.uni-password-toggle:hover,
.uni-password-toggle:focus-visible {
    background: color-mix(in srgb, var(--uni-color-primary) 10%, transparent);
    color: var(--uni-color-primary);
}

.uni-password-toggle:focus-visible {
    outline: 2px solid var(--uni-color-primary);
    outline-offset: 1px;
}

.uni-password-toggle:disabled {
    cursor: not-allowed;
    opacity: 0.5;
}

.uni-password-toggle .icon-eye-off { display: none; }
.uni-password-toggle.is-visible .icon-eye { display: none; }
.uni-password-toggle.is-visible .icon-eye-off { display: inline-flex; }

.uni-field-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: var(--uni-space-4);
}

/* =====================================================================================
   FORM GRID ALIGNMENT CONTRACT — UNICHAT-CUT-6 (decisão do Owner, 2026-09-18)
   docs/design-system/uni/forms.md › "Grade de campos: alinhamento dos controles".

   Em grade de duas ou mais colunas, os CONTROLES de uma mesma linha lógica começam na mesma
   altura mesmo quando os rótulos têm alturas diferentes (um rótulo de duas linhas não empurra
   só o seu campo para baixo). A grade garante isso pela ESTRUTURA, não por margem: cada campo é
   um subgrid de três trilhos do pai — rótulo / controle / ajuda-ou-erro — e o trilho do rótulo
   é o mesmo para todos os campos daquela linha (mede pelo mais alto). Rótulo curto assenta no pé
   do trilho (align-self: end) e mantém o gap fixo até o controle. O trilho de ajuda fica vazio
   (0px, sem gap próprio) quando não há ajuda/erro: erro aparece sem deslocar a linha seguinte
   além do próprio texto, e nada reserva espaço permanente.
   Continua correto quando o texto do rótulo muda; sem margin-top por campo, sem offsets.
   ===================================================================================== */
.uni-field-grid > .uni-field {
    display: grid;
    grid-template-rows: subgrid;
    grid-row: span 3;
    row-gap: 0;
    align-content: start;
}

.uni-field-grid > .uni-field > span:first-child,
.uni-field-grid > .uni-field > .app-field-label:first-child {
    grid-row: 1;
    align-self: end;
    padding-bottom: var(--uni-space-2);
}

.uni-field-grid > .uni-field > .uni-field-hint,
.uni-field-grid > .uni-field > .uni-field-error {
    grid-row: 3;
    margin-top: var(--uni-space-1);
}

/* Campo que ocupa a linha inteira (textarea, título longo): mesma regra de rótulo/controle. */
.uni-field--wide { grid-column: 1 / -1; }

/* Largura reduzida: uma coluna, determinística — a grade não se comprime até cortar rótulo. */
@media (max-width: 767px) {
    .uni-field-grid { grid-template-columns: 1fr; }
}

/* ---------- Busca (VL-14) — promovida ao canônico ----------
   UNICHAT-CONFIGURACOES-VISUAL-ASSISTED-CONVERGENCE-01.

   VL-14 é regra GERAL ("toda busca do UniChat, em qualquer superfície"), mas a única
   implementação que a cumpria vivia em `crm-contacts.css` como `.crm-contacts-search`. Usá-la em
   Configurações seria a proibição 1 (classe emprestada) e reescrevê-la seria o antipadrão que o
   §15 nomeia. Segue o mesmo caminho de C-09: a peça sobe ao canônico com a GEOMETRIA IDÊNTICA à
   já aceita, e as superfícies homologadas migram quando reentrarem — sem mudança visual, porque
   os valores são os mesmos. */

.uni-search {
    display: flex;
    align-items: center;
    gap: var(--uni-space-2);
    flex: 1 1 auto;
    min-width: 0;
    height: 42px;
    min-height: 42px;
    padding: 0 var(--uni-space-4);
    border: 1px solid var(--uni-color-border);
    border-radius: var(--uni-radius-pill);
    background: var(--uni-color-surface);
    color: var(--uni-color-text);
    transition: border-color 0.14s ease, box-shadow 0.14s ease;
}

/* VL-14(a) + VL-44: realce de foco do container, na forma homologada pelo aceite de Contatos. */
.uni-search:focus-within {
    border-color: var(--uni-color-primary);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--uni-color-primary) 22%, transparent);
}

.uni-search .crm-icon {
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    color: var(--uni-color-text-muted);
}

.uni-search input {
    flex: 1 1 auto;
    min-width: 0;
    height: 100%;
    border: 0;
    background: transparent;
    color: inherit;
    font-family: var(--uni-font-family);
    font-size: var(--uni-font-size-md);
    /* Permitido só porque o container carrega o indicador de foco acima (VL-14). */
    outline: none;
}

.uni-search input::placeholder { color: var(--uni-color-text-subtle); }
.uni-search input::-webkit-search-cancel-button { display: none; }

.uni-search-clear {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--uni-color-text-muted);
    cursor: pointer;
}

.uni-search-clear:hover { background: var(--uni-color-neutral-soft); color: var(--uni-color-text); }
.uni-search-clear:focus-visible { outline: 2px solid var(--uni-color-focus-ring); outline-offset: 2px; }
.uni-search-clear .crm-icon { width: 16px; height: 16px; }

/* ---------- (i) informativo do rótulo de campo ----------
   UNICHAT-CONFIGURACOES-VISUAL-ASSISTED-CONVERGENCE-01, decisão do proprietário: rótulo curto mais
   um "(i)" que abre a explicação, em vez de tentar informar o campo inteiro no título. O rótulo
   longo quebrava em duas linhas e desalinhava a grade toda.

   Fica na camada canônica porque a decisão do proprietário foi explícita em adotá-lo como padrão
   ("podemos adotar isso"), não só em Configurações. */

.uni-field-info {
    position: relative;
    display: inline-flex;
    align-items: center;
}

.uni-field-info-trigger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--uni-color-text-subtle);
    cursor: pointer;
    transition: color 0.12s ease, background-color 0.12s ease;
}

.uni-field-info-trigger:hover,
.uni-field-info.is-open .uni-field-info-trigger {
    background: var(--uni-color-primary-soft);
    color: var(--uni-color-primary);
}

/* VL-24 — fora de campo de entrada, o realce de foco é o anel âmbar. */
.uni-field-info-trigger:focus-visible {
    outline: 2px solid var(--uni-color-focus-ring);
    outline-offset: 2px;
}

.uni-field-info-trigger .crm-icon {
    width: 14px;
    height: 14px;
}

/* UNICHAT-PARALLEL-VISUAL-AUTHORITY-AND-WEB-RECONCILIATION-01 — OD-C da Visão geral e a regra
   G do Planner: o glifo continua com 18px, mas o alvo precisa de 44×44 no toque.

   Aqui a separação entre geometria pintada e área interativa FUNCIONA, ao contrário das abas:
   `.uni-field-info` é `position: relative` e vive solto na linha do rótulo, sem contêiner que
   recorte por overflow. O pseudo-elemento é filho do próprio <button>, então o toque nele
   aciona o botão sem handler novo e sem mudar uma única propriedade visível.

   Só no toque, de propósito. No desktop um alvo invisível de 44px cobriria o fim do rótulo à
   esquerda, e o ponteiro fino não precisa dele. `(pointer: coarse)` entra ao lado do
   breakpoint para alcançar a tela sensível ao toque que não é estreita. */
.uni-field-info-trigger { position: relative; }

@media (max-width: 1023px), (pointer: coarse) {
    .uni-field-info-trigger::after {
        content: "";
        position: absolute;
        top: 50%;
        left: 50%;
        width: 44px;
        height: 44px;
        transform: translate(-50%, -50%);
    }
}

/* VL-30 — o backdrop fecha ao clicar fora e ao rolar a página. */
.uni-field-info-backdrop {
    position: fixed;
    inset: 0;
    z-index: var(--uni-z-dropdown);
}

/* VL-30 — `position: fixed` para nunca ser recortado pelo overflow do container; a posição real
   quem decide é `uniUx.anchor`. VL-08 — flutuante sobre fundo claro leva borda E sombra. */
.uni-field-info-panel {
    position: fixed;
    z-index: var(--uni-z-tooltip);
    display: flex;
    flex-direction: column;
    gap: var(--uni-space-1);
    width: max-content;
    max-width: 280px;
    /* `uniUx.anchor` aplica um teto de altura calibrado para DROPDOWN DE OPÇÕES (300px) mais rolagem
       interna. Num popover de duas frases isso cortava o título e escondia o começo do texto —
       visto na captura da revisão. Aqui o conteúdo é sempre curto: sem teto e sem rolagem. A
       direção (abrir para cima quando não cabe embaixo) continua sendo decidida pela função. */
    max-height: none !important;
    overflow: visible !important;
    padding: var(--uni-space-3) var(--uni-space-4);
    border: 1px solid var(--uni-color-border);
    border-radius: var(--uni-radius-md);
    background: var(--uni-color-surface);
    box-shadow: var(--uni-shadow-md);
    text-align: left;
    white-space: normal;
}

.uni-field-info-panel strong {
    color: var(--uni-color-text);
    font-size: var(--uni-font-size-sm);
    font-weight: 600;
}

.uni-field-info-panel span {
    color: var(--uni-color-text-muted);
    font-size: var(--uni-font-size-sm);
    font-weight: 400;
    line-height: 1.45;
}

/* UNICHAT-CUT-6T — ação opcional no fim do painel do (i): botão pequeno, alinhado à esquerda, com respiro. */
.uni-field-info-panel .uni-field-info-action {
    align-self: flex-start;
    margin-top: var(--uni-space-2);
    text-decoration: none;
}

/* Rótulo com o (i) ao lado: o texto e o ícone ficam na mesma linha de base, e o rótulo continua
   sendo o `> span` que `.uni-field` já estiliza. */
.uni-field > span.uni-field-label-row {
    display: inline-flex;
    align-items: center;
    gap: var(--uni-space-2);
}

/* ---------- Badge de status ---------- */

.app-badge {
    display: inline-flex;
    align-items: center;
    gap: var(--uni-space-1);
    padding: 2px var(--uni-space-3);
    border-radius: var(--uni-radius-pill);
    font-size: var(--uni-font-size-xs);
    font-weight: 600;
    white-space: nowrap;
}

.app-badge-neutral { background: var(--uni-color-neutral-soft); color: var(--uni-color-neutral); }
.app-badge-info    { background: var(--uni-color-info-soft);    color: var(--uni-color-info); }
.app-badge-success { background: var(--uni-color-success-soft); color: var(--uni-color-success); }
.app-badge-warning { background: var(--uni-color-warning-soft); color: var(--uni-color-warning); }
.app-badge-danger  { background: var(--uni-color-danger-soft);  color: var(--uni-color-danger); }

/* UNICHAT-MVP-UX-PRODUCT-EXPERIENCE-COMPLETION-01 (Fase A) — breadcrumb curto de "volta" para
   páginas que passaram a ser subárea de outra (Base de Conhecimento -> Atendente de IA;
   Templates Oficiais -> Campanhas). */
.uni-breadcrumb {
    display: inline-block;
    margin-bottom: 4px;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--crm-color-text-muted, #667085);
    text-decoration: none;
}
.uni-breadcrumb:hover { color: var(--crm-color-primary, #1c7ed6); }

/* ============================================================================
   UNICHAT-MOBILE-UX-CONFORMANCE-01 (Phase B) — primitivos de composição mobile.
   Autoridade: docs/design-system/uni/mobile-composition-contract.md (seções F–P),
   extraída do UniCursos homologado. Breakpoints canônicos: 767 / 1023 / 1024.
   ============================================================================ */

/* ---------- Visibilidade por shell (contrato B/C) ---------- */
.uni-desktop-only { display: revert; }
.uni-mobile-only { display: none !important; }

@media (max-width: 1023px) {
    .uni-desktop-only { display: none !important; }
    .uni-mobile-only { display: revert !important; }
}

/* ---------- Lista cardificada (contrato J) ----------
   Equivalente do .responsive-row-card do UniCursos. Uso: lista de cards no
   mobile que substitui a tabela desktop (dual rendering) — cada card com
   pares label/valor e ações no rodapé. */
.uni-row-card-list {
    display: grid;
    min-width: 0;
    gap: var(--uni-space-3);
}

.uni-row-card {
    display: grid;
    gap: var(--uni-space-3);
    min-width: 0;
    max-width: 100%;
    border: 1px solid var(--uni-color-border);
    border-radius: var(--uni-radius-md);
    padding: var(--uni-space-4);
    background: var(--uni-color-surface);
}

.uni-row-card__field {
    display: grid;
    min-width: 0;
    gap: var(--uni-space-1);
}

.uni-row-card__label {
    color: var(--uni-color-text-muted);
    font-size: var(--uni-font-size-xs);
    font-weight: 800;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.uni-row-card__value {
    min-width: 0;
    overflow-wrap: anywhere;
    font-size: var(--uni-font-size-md);
    color: var(--uni-color-text);
}

.uni-row-card__value small,
.uni-row-card__meta {
    display: block;
    color: var(--uni-color-text-muted);
    font-size: var(--uni-font-size-xs);
    font-weight: 400;
}

.uni-row-card__title {
    min-width: 0;
    font-size: 14px;
    font-weight: 600;
    color: var(--uni-color-text);
    overflow-wrap: anywhere;
}

.uni-row-card__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--uni-space-2);
    padding-top: var(--uni-space-3);
    border-top: 1px solid var(--uni-color-border);
}

/* ---------- Cardificação transitória de <table> (contrato P) ----------
   Para tabelas reais existentes que ainda não migraram para uni-row-card:
   aplica label via data-label. Registrada como transição técnica, não como
   arquitetura final (contrato P). Cardifica no shell mobile/tablet (<=1023,
   como as listas administrativas do UniCursos); no tablet a grade interna do
   card usa 2 colunas quando há espaço (768–1023), 1 coluna no mobile. */
@media (max-width: 1023px) {
    .uni-table-cardify { min-width: 0 !important; width: 100%; border-collapse: separate; border-spacing: 0; }
    .uni-table-cardify thead { display: none; }
    .uni-table-cardify tbody { display: grid; gap: var(--uni-space-3); }
    .uni-table-cardify tr {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: var(--uni-space-2) var(--uni-space-4);
        border: 1px solid var(--uni-color-border);
        border-radius: var(--uni-radius-md);
        padding: var(--uni-space-4);
        background: var(--uni-color-surface);
    }
    .uni-table-cardify td {
        display: block;
        min-width: 0;
        padding: 0;
        border: 0;
        overflow-wrap: anywhere;
        white-space: normal;
    }
    /* Identidade (1ª célula) e ações (última) atravessam o card inteiro. */
    .uni-table-cardify td:first-child,
    .uni-table-cardify td:last-child {
        grid-column: 1 / -1;
    }
    .uni-table-cardify td[data-label]::before {
        content: attr(data-label);
        display: block;
        margin-bottom: 2px;
        color: var(--uni-color-text-muted);
        font-size: var(--uni-font-size-xs);
        font-weight: 800;
        letter-spacing: 0.04em;
        text-transform: uppercase;
    }
    .uni-table-cardify td:empty { display: none; }
}

@media (max-width: 767px) {
    .uni-table-cardify tr {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* ---------- Form stack (contrato M) ---------- */
@media (max-width: 767px) {
    .uni-form-stack,
    .uni-filter-stack {
        display: flex;
        flex-direction: column;
        align-items: stretch;
        gap: var(--uni-space-3);
    }

    .uni-form-stack input:not([type="checkbox"]):not([type="radio"]),
    .uni-form-stack select,
    .uni-form-stack textarea,
    .uni-filter-stack input:not([type="checkbox"]):not([type="radio"]),
    .uni-filter-stack select {
        width: 100%;
        min-width: 0;
        max-width: 100%;
        box-sizing: border-box;
    }
}

/* ---------- Stack de botões (contrato L) ---------- */
@media (max-width: 767px) {
    .uni-button-stack {
        display: flex;
        flex-direction: column;
        align-items: stretch;
        gap: var(--uni-space-2);
    }

    .uni-button-stack > * {
        width: 100%;
        justify-content: center;
    }
}

/* ---------- Faixa de tabs/chips com scroll próprio (contrato N) ----------
   Scroll horizontal SOMENTE dentro da faixa; a página nunca rola lateralmente. */
.uni-tabs-scroll {
    display: flex;
    min-width: 0;
    max-width: 100%;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-behavior: smooth;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
    overscroll-behavior-inline: contain;
    -webkit-overflow-scrolling: touch;
}

.uni-tabs-scroll > * {
    flex: 0 0 auto;
    scroll-snap-align: start;
}


/* ============================================================================
   SCROLL ELEGANTE (app-wide) — UNICHAT-MOBILE-UX-ARCHITECTURE-01 (Phase B / B8)

   Regra do app: nenhuma barra de rolagem grossa do sistema. As barras são finas,
   arredondadas e INVISÍVEIS em repouso; aparecem quando o elemento é rolado
   (classe .uni-scrolling, aplicada por uni-ux.js) ou quando o ponteiro está sobre
   ele. Vale para rolagem vertical e horizontal, em qualquer elemento.
   ============================================================================ */

:root {
    --uni-scroll-size: 10px;
    --uni-scroll-thumb: rgba(100, 116, 139, 0.34);
    --uni-scroll-thumb-strong: rgba(100, 116, 139, 0.58);
}

:root[data-crm-theme="dark"] {
    --uni-scroll-thumb: rgba(226, 232, 240, 0.24);
    --uni-scroll-thumb-strong: rgba(226, 232, 240, 0.44);
}

*::-webkit-scrollbar {
    width: var(--uni-scroll-size);
    height: var(--uni-scroll-size);
}

*::-webkit-scrollbar-track,
*::-webkit-scrollbar-corner {
    background: transparent;
}

*::-webkit-scrollbar-thumb {
    background-color: transparent;
    border: 3px solid transparent;
    border-radius: 999px;
    background-clip: padding-box;
    transition: background-color 160ms ease;
}

*:hover::-webkit-scrollbar-thumb,
.uni-scrolling::-webkit-scrollbar-thumb {
    background-color: var(--uni-scroll-thumb);
}

*::-webkit-scrollbar-thumb:hover,
*::-webkit-scrollbar-thumb:active {
    background-color: var(--uni-scroll-thumb-strong);
}

/* Firefox (sem pseudo-elementos de scrollbar): fino e discreto. */
@supports not selector(::-webkit-scrollbar) {
    * {
        scrollbar-width: thin;
        scrollbar-color: var(--uni-scroll-thumb) transparent;
    }
}

/* Faixas horizontais de chips/abas/etapas: sem barra alguma. */
.uni-tabs-scroll::-webkit-scrollbar,
.uni-edge-scroll::-webkit-scrollbar {
    width: 0;
    height: 0;
}

.uni-tabs-scroll,
.uni-edge-scroll {
    scrollbar-width: none;
}

/* ============================================================================
   UNICHAT-UX-PRODUCT-ATENDIMENTO-OMNICHANNEL-05 — Fase 1, Fundação Design System.
   D-02 (botões), D-03 (UniModal/UniDrawer), D-04/F-02/F-03 (toast + alerta de seção),
   D-43 (UniSelect/UniCombobox). Reusa os tokens --uni-* já existentes acima; nenhuma
   paleta nova.
   ============================================================================ */

/* ---------- UniButton: spinner (fecha G21) ---------- */
.app-button-spinner {
    width: 15px;
    height: 15px;
    border: 2px solid color-mix(in srgb, currentColor 30%, transparent);
    border-top-color: currentColor;
    border-radius: 50%;
    animation: uni-spin 0.7s linear infinite;
}

@keyframes uni-spin {
    to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    .app-button-spinner { animation-duration: 1.6s; }
}

/* ---------- UniModal (D-03: decisão / formulário pequeno) ---------- */
.uni-modal-backdrop {
    position: fixed;
    inset: 0;
    z-index: var(--uni-z-modal);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--uni-space-4);
    background: rgba(15, 23, 42, 0.46);
}

.uni-modal {
    display: flex;
    flex-direction: column;
    width: 100%;
    max-height: min(720px, 92vh);
    background: var(--uni-color-surface);
    border-radius: var(--uni-radius-lg);
    box-shadow: var(--uni-shadow-md);
    outline: none;
}

.uni-modal-sm { max-width: 420px; }
.uni-modal-md { max-width: 640px; }
.uni-modal-lg { max-width: 900px; }
/* INSTAGRAM-EXPERIENCE-FIDELITY-POLISH-01 — degrau XL (Caixa de comentários com a aba Publicações). */
.uni-modal-xl { max-width: 1120px; }
.uni-modal-header-actions { display: inline-flex; align-items: center; gap: var(--uni-space-2); flex: 0 0 auto; margin-left: auto; }

.uni-modal-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--uni-space-3);
    padding: var(--uni-space-5) var(--uni-space-5) var(--uni-space-3);
    border-bottom: 1px solid var(--uni-color-border);
}

.uni-modal-title-row { display: flex; align-items: center; gap: var(--uni-space-2); min-width: 0; }
.uni-modal-title-actions { display: inline-flex; align-items: center; gap: 2px; flex: 0 0 auto; }
.uni-modal-icon-button {
    display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border: 0;
    border-radius: var(--uni-radius-pill); background: transparent; color: var(--uni-color-text-muted); cursor: pointer; padding: 0;
}
.uni-modal-icon-button .crm-icon { width: 18px; height: 18px; }
.uni-modal-icon-button:hover { background: var(--uni-color-neutral-soft); color: var(--uni-color-text); }
.uni-modal-icon-button.is-on { color: var(--uni-color-primary); }
.uni-modal-icon-button:focus-visible { outline: 2px solid var(--uni-color-focus-ring); outline-offset: 2px; }
.uni-modal-icon-button:disabled { opacity: .5; cursor: default; }

.uni-modal-header-titles h2 {
    margin: 0;
    font-size: var(--uni-font-size-lg);
    font-weight: 700;
    color: var(--uni-color-text);
}

.uni-modal-header-titles p {
    margin: 4px 0 0;
    font-size: var(--uni-font-size-sm);
    color: var(--uni-color-text-muted);
}

.uni-modal-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border: 0;
    border-radius: var(--uni-radius-pill);
    background: transparent;
    color: var(--uni-color-text-muted);
    cursor: pointer;
    flex: 0 0 auto;
}

.uni-modal-close:hover { background: var(--uni-color-neutral-soft); color: var(--uni-color-text); }
.uni-modal-close:focus-visible { outline: 2px solid var(--uni-color-focus-ring); outline-offset: 2px; }

/* FU-03 — faixa fixa do cabeçalho (stepper de assistente). Não rola com o corpo: a posição no
   fluxo é justamente o que o operador precisa ver enquanto preenche. */
.uni-modal-subheader {
    flex: 0 0 auto;
    padding: var(--uni-space-5) var(--uni-space-5) var(--uni-space-4);
    border-bottom: 1px solid var(--uni-color-border);
    background: var(--uni-color-surface);
}

.uni-modal-body {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: var(--uni-space-5);
}

.uni-modal-footer {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--uni-space-3);
    padding: var(--uni-space-4) var(--uni-space-5);
    border-top: 1px solid var(--uni-color-border);
}

@media (max-width: 767px) {
    .uni-modal-backdrop { padding: 0; align-items: flex-end; }
    .uni-modal { max-width: 100%; max-height: 92vh; border-radius: var(--uni-radius-lg) var(--uni-radius-lg) 0 0; }
    .uni-modal-footer { flex-direction: column-reverse; align-items: stretch; }
}

/* ---------- UniDrawer (D-03: detalhe que preserva a lista) — anatomia de KanbanDealDrawer ---------- */
.uni-drawer-backdrop {
    position: fixed;
    inset: 0;
    z-index: var(--uni-z-modal);
    display: flex;
    justify-content: flex-end;
    background: rgba(15, 23, 42, 0.4);
}

.uni-drawer {
    display: flex;
    flex-direction: column;
    width: min(440px, 100vw);
    max-width: 100vw;
    height: 100%;
    background: var(--uni-color-surface);
    box-shadow: var(--uni-shadow-md);
    outline: none;
}

.uni-drawer-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--uni-space-3);
    padding: var(--uni-space-5);
    border-bottom: 1px solid var(--uni-color-border);
}

.uni-drawer-eyebrow {
    display: block;
    font-size: var(--uni-font-size-xs);
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--uni-color-text-muted);
}

.uni-drawer-header h2 { margin: 2px 0 0; font-size: var(--uni-font-size-lg); font-weight: 700; color: var(--uni-color-text); }
.uni-drawer-header p { margin: 4px 0 0; font-size: var(--uni-font-size-sm); color: var(--uni-color-text-muted); }

.uni-drawer-header-actions {
    display: flex;
    align-items: center;
    gap: var(--uni-space-2);
    flex: 0 0 auto;
}

.uni-drawer-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border: 0;
    border-radius: var(--uni-radius-pill);
    background: transparent;
    color: var(--uni-color-text-muted);
    cursor: pointer;
}

.uni-drawer-close:hover { background: var(--uni-color-neutral-soft); color: var(--uni-color-text); }
.uni-drawer-close:focus-visible { outline: 2px solid var(--uni-color-focus-ring); outline-offset: 2px; }

.uni-drawer-body {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: var(--uni-space-5);
    display: flex;
    flex-direction: column;
    gap: var(--uni-space-5);
}

.uni-drawer-footer {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--uni-space-3);
    padding: var(--uni-space-4) var(--uni-space-5);
    border-top: 1px solid var(--uni-color-border);
}

/* <=1023: UniDetailHeader (app bar de página) assume o papel do header desktop (mesmo padrão do
   Kanban — G34); o drawer vira superfície de detalhe em tela cheia. */
@media (max-width: 1023px) {
    .uni-drawer-backdrop { justify-content: stretch; }
    .uni-drawer { width: 100%; }
}

/* ---------- UniTabs (D-02/D-07) — generaliza .crm-ticket-tabs ---------- */
/* VL-16, revisado pela revisao visual do proprietario (2026-09-07).
   A primeira tentativa deste corte trocou a aba "de sistema" (borda inferior de 2px) por pilulas
   soltas. O proprietario apontou a referencia certa: o SEGMENTED CONTROL do UniCursos (calendario
   e comunicacao), que e um trilho fechado com fundo proprio e a aba ativa preenchida.
   Duas correcoes que vieram junto:
   - `width: fit-content` -> o trilho passa a ter o tamanho do conteudo. Antes, `display:flex`
     dentro de um container em coluna esticava a barra pela largura toda e as abas ficavam
     "espremidas" numa faixa larga e vazia;
   - `margin-bottom` -> na pagina de Listas as abas encostavam no titulo da secao seguinte. */
.uni-tabs {
    display: inline-flex;
    align-items: center;
    align-self: flex-start;
    /* MEDIDO no navegador: sem isto o trilho renderiza com 8px de altura e as abas de 34px
       transbordam para fora dele. `.crm-page-container` é flex-column; como item flex, o trilho
       herda `flex-shrink: 1` e é espremido quando o conteúdo da página excede a altura. É o mesmo
       defeito que uni-mobile-ux.css já corrigia — mas só dentro da media query de mobile, e por
       isso o desktop continuava quebrado. */
    flex: 0 0 auto;
    width: fit-content;
    max-width: 100%;
    gap: var(--uni-space-1);
    padding: 3px;
    border: 1px solid var(--uni-color-border);
    border-radius: var(--uni-radius-pill);
    background: color-mix(in srgb, var(--uni-color-neutral-soft) 70%, var(--uni-color-surface));
}

/* UNICHAT-VISUAL-SYSTEM-ASSISTED-CONVERGENCE-01 / VL-16.
   A anatomia anterior era borda inferior de 2px - o padrao de aba "de sistema" que o contrato
   proibe, e que diverge da anatomia canonica registrada em components.md ("ativo com fundo
   primary-soft", generalizada de TicketTabs/ConversationSwitcher). O componente nasceu assim no
   corte reprovado visualmente. Corrigido para a anatomia canonica: pilula de 42px.
   Efeito colateral verificado antes de aplicar: a UNICA superficie que consome <UniTabs> hoje e
   CrmMyAccountDrawer, que o proprietario ja reprovou explicitamente - nao ha superficie aprovada
   mudando de aparencia em silencio. */
.uni-tab {
    display: inline-flex;
    align-items: center;
    gap: var(--uni-space-1);
    min-height: 34px;
    padding: 0 var(--uni-space-3);
    border: 0;
    border-radius: var(--uni-radius-pill);
    background: transparent;
    color: var(--uni-color-text-muted);
    font-family: var(--uni-font-family);
    font-size: var(--uni-font-size-sm);
    font-weight: 600;
    line-height: 1;
    white-space: nowrap;
    text-decoration: none;
    cursor: pointer;
    user-select: none;
    transition: background-color 0.14s ease, color 0.14s ease;
}

/* VL-24 mantida: selecionado e hover nao sao a mesma aparencia. O UniCursos usa o mesmo
   preenchimento para os dois, o que faz o hover mentir que a aba ja esta ativa. */
.uni-tab:hover:not(:disabled):not(.is-active) {
    background: var(--uni-color-surface);
    color: var(--uni-color-text);
}

.uni-tab.is-active {
    background: var(--uni-color-primary);
    color: var(--uni-color-on-primary);
}

.uni-tab:focus-visible { outline: 2px solid var(--uni-color-focus-ring); outline-offset: 2px; }
.uni-tab:disabled { opacity: 0.5; cursor: not-allowed; }

.uni-tab-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    border-radius: var(--uni-radius-pill);
    background: var(--uni-color-neutral-soft);
    color: var(--uni-color-text-muted);
    font-size: var(--uni-font-size-xs);
    font-weight: 700;
}

/* Aba ativa agora tem fundo preenchido: o contador precisa contrastar com ele, nao com a pagina. */
.uni-tab.is-active .uni-tab-count {
    background: color-mix(in srgb, var(--uni-color-on-primary) 26%, transparent);
    color: var(--uni-color-on-primary);
}

/* UNICHAT-PARALLEL-VISUAL-AUTHORITY-AND-WEB-RECONCILIATION-01 — metade de acessibilidade de
   CF-02. Por §0 acessibilidade está ACIMA deste contrato, então esta parte não espera decisão
   de estética: `.uni-tab` mede 34px, e D-38/VL-27 pedem 44px de alvo no toque.

   MEDIDO antes de escolher a abordagem: a tentativa de separar geometria pintada de área
   interativa — pseudo-elemento de 44px centrado na pílula de 34px — NÃO funciona aqui. O
   trilho é `.uni-tabs-scroll`, que carrega `overflow-y: hidden`; a caixa do pseudo-elemento
   é recortada na altura do trilho (40px de padding box) e o alvo real nunca chega a 44. Não
   há truque: para um alvo de 44px dentro de um trilho com borda, o trilho precisa ter 44px.

   Então a altura cresce de verdade, e SOMENTE no toque. O desktop fica exatamente como as
   oito superfícies aceitaram. E no mobile isto não estreia nada: é a mesma regra que a
   variante de 42px já aplicava, já vista e aceita pelo proprietário em Tarefas e no Kanban —
   está sendo estendida às demais abas, não inventada.

   `min-width` junto porque D-38 pede 44 nos DOIS eixos, e rótulo curto ("7d", "Mês") produz
   pílula de ~40px. Cresce a caixa real, não uma sobreposição: abas vizinhas continuam sem
   alvos que se cobrem. */
@media (max-width: 1023px) {
    .uni-tab {
        min-height: 44px;
        min-width: 44px;
        justify-content: center;
    }
}

/* ---------- UniSectionAlert (D-04/F-03) — status persistente de seção, 4 tons ---------- */
.uni-section-alert {
    display: flex;
    align-items: flex-start;
    gap: var(--uni-space-3);
    padding: var(--uni-space-4);
    border: 1px solid transparent;
    border-radius: var(--uni-radius-md);
    /* UNICHAT-CUT-6S (F-99) — espaçamento próprio: nunca grudado em busca/inputs/cabeçalhos. */
    margin-block: var(--uni-space-2) var(--uni-space-4);
}
.uni-section-alert:first-child { margin-top: 0; }

/* F-99 — "X" para fechar, alinhado ao topo do aviso; espaço para ele não colidir com o texto. */
.uni-section-alert-close {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    margin: -4px -6px -4px 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--uni-color-text-muted);
    cursor: pointer;
}
.uni-section-alert-close:hover { background: color-mix(in srgb, currentColor 10%, transparent); color: var(--uni-color-text); }
.uni-section-alert-close:focus-visible { outline: 2px solid var(--uni-color-primary); outline-offset: 1px; }
.uni-section-alert-close .crm-icon { width: 14px; height: 14px; }

.uni-section-alert-icon { flex: 0 0 auto; display: inline-flex; margin-top: 1px; }
.uni-section-alert-content { flex: 1 1 auto; min-width: 0; }
.uni-section-alert-title { margin: 0; font-size: var(--uni-font-size-md); font-weight: 700; color: var(--uni-color-text); }
.uni-section-alert-message { margin: 4px 0 0; font-size: var(--uni-font-size-sm); color: var(--uni-color-text-muted); }
.uni-section-alert-action { flex: 0 0 auto; }

.uni-section-alert-info { background: var(--uni-color-info-soft); border-color: color-mix(in srgb, var(--uni-color-info) 30%, transparent); }
.uni-section-alert-info .uni-section-alert-icon { color: var(--uni-color-info); }

.uni-section-alert-success { background: var(--uni-color-success-soft); border-color: color-mix(in srgb, var(--uni-color-success) 30%, transparent); }
.uni-section-alert-success .uni-section-alert-icon { color: var(--uni-color-success); }

.uni-section-alert-warning { background: var(--uni-color-warning-soft); border-color: color-mix(in srgb, var(--uni-color-warning) 35%, transparent); }
.uni-section-alert-warning .uni-section-alert-icon { color: var(--uni-color-warning); }

.uni-section-alert-danger { background: var(--uni-color-danger-soft); border-color: color-mix(in srgb, var(--uni-color-danger) 35%, transparent); }
.uni-section-alert-danger .uni-section-alert-icon { color: var(--uni-color-danger); }

/* ---------- UniSelect (D-43) — nativo estilizado, seta afastada da borda (picker-aprovado.png) ---------- */
.uni-select {
    position: relative;
    display: inline-flex;
    width: 100%;
}

/* C-06 promovido: select acompanha o campo — 42px e raio `md`. VL-10 pareia os três
   (input, select, combobox) com o botão de 42px. */
.uni-select-control {
    width: 100%;
    height: 42px;
    padding: 0 var(--uni-space-7) 0 var(--uni-space-3);
    border: 1px solid var(--uni-color-border-strong);
    border-radius: var(--uni-radius-md);
    background: var(--uni-color-surface);
    color: var(--uni-color-text);
    font-family: var(--uni-font-family);
    font-size: var(--uni-font-size-md);
    appearance: none;
    cursor: pointer;
}

/* VL-44 — campo usa o realce neon azul, nunca o anel âmbar. */
.uni-select-control:focus {
    outline: none;
    border-color: var(--uni-color-primary);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--uni-color-primary) 22%, transparent);
}

.uni-select-caret {
    position: absolute;
    top: 50%;
    right: var(--uni-space-3);
    transform: translateY(-50%);
    display: inline-flex;
    color: var(--uni-color-text-muted);
    pointer-events: none;
}

.uni-select.is-disabled .uni-select-control { opacity: 0.6; cursor: not-allowed; }

/* ---------- UniCombobox (D-43) — generaliza .aut-combo-* ---------- */
.uni-combobox { position: relative; width: 100%; }

.uni-combobox-control { position: relative; display: flex; align-items: center; }

/* C-06 promovido: combobox acompanha o campo — 42px e raio `md`. */
.uni-combobox-input {
    width: 100%;
    height: 42px;
    padding: 0 var(--uni-space-7) 0 var(--uni-space-3);
    border: 1px solid var(--uni-color-border-strong);
    border-radius: var(--uni-radius-md);
    background: var(--uni-color-surface);
    color: var(--uni-color-text);
    font-family: var(--uni-font-family);
    font-size: var(--uni-font-size-md);
}

/* VL-44 — campo usa o realce neon azul, nunca o anel âmbar. */
.uni-combobox-input:focus {
    outline: none;
    border-color: var(--uni-color-primary);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--uni-color-primary) 22%, transparent);
}

.uni-combobox-caret {
    position: absolute;
    right: var(--uni-space-3);
    display: inline-flex;
    color: var(--uni-color-text-muted);
    pointer-events: none;
}

.uni-combobox-dropdown {
    z-index: var(--uni-z-dropdown);
    overflow-y: auto;
    background: var(--uni-color-surface);
    border: 1px solid var(--uni-color-border);
    border-radius: var(--uni-radius-sm);
    box-shadow: var(--uni-shadow-md);
    padding: var(--uni-space-1);
}

.uni-combobox-group {
    padding: var(--uni-space-2) var(--uni-space-3) 4px;
    font-size: var(--uni-font-size-xs);
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--uni-color-text-subtle);
}

.uni-combobox-option {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    width: 100%;
    padding: var(--uni-space-2) var(--uni-space-3);
    border: 0;
    border-radius: var(--uni-radius-sm);
    background: transparent;
    color: var(--uni-color-text);
    font-family: var(--uni-font-family);
    font-size: var(--uni-font-size-md);
    text-align: left;
    cursor: pointer;
}

.uni-combobox-option:hover,
.uni-combobox-option.is-highlight { background: var(--uni-color-primary-soft); }
.uni-combobox-option.is-selected { color: var(--uni-color-primary); font-weight: 600; }

.uni-combobox-option-hint {
    font-size: var(--uni-font-size-xs);
    color: var(--uni-color-text-muted);
}

.uni-combobox-empty {
    padding: var(--uni-space-3);
    font-size: var(--uni-font-size-sm);
    color: var(--uni-color-text-muted);
}

.uni-combobox-error {
    margin: 4px 0 0;
    font-size: var(--uni-font-size-xs);
    color: var(--uni-color-danger);
}

.uni-combobox.is-disabled .uni-combobox-input { opacity: 0.6; cursor: not-allowed; }

/* ---------- UniToast (F-02, G4) ---------- */
.uni-toast-region {
    position: fixed;
    top: var(--uni-space-5);
    right: var(--uni-space-5);
    z-index: var(--uni-z-toast);
    display: flex;
    flex-direction: column;
    gap: var(--uni-space-2);
    width: min(360px, calc(100vw - 2 * var(--uni-space-5)));
    pointer-events: none;
}

.uni-toast {
    display: flex;
    align-items: flex-start;
    gap: var(--uni-space-2);
    padding: var(--uni-space-3) var(--uni-space-4);
    border-radius: var(--uni-radius-md);
    background: var(--uni-color-surface);
    border: 1px solid var(--uni-color-border);
    box-shadow: var(--uni-shadow-md);
    pointer-events: auto;
    animation: uni-toast-in 0.16s ease-out;
}

@keyframes uni-toast-in {
    from { opacity: 0; transform: translateY(-6px); }
    to { opacity: 1; transform: translateY(0); }
}

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

.uni-toast-icon { flex: 0 0 auto; margin-top: 1px; }
.uni-toast-success .uni-toast-icon { color: var(--uni-color-success); }
.uni-toast-error .uni-toast-icon { color: var(--uni-color-danger); }
.uni-toast-warning .uni-toast-icon { color: var(--uni-color-warning); }
.uni-toast-info .uni-toast-icon { color: var(--uni-color-info); }

.uni-toast-message {
    flex: 1 1 auto;
    margin: 0;
    font-size: var(--uni-font-size-sm);
    color: var(--uni-color-text);
}

.uni-toast-dismiss {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border: 0;
    border-radius: var(--uni-radius-pill);
    background: transparent;
    color: var(--uni-color-text-muted);
    cursor: pointer;
}

.uni-toast-dismiss:hover { background: var(--uni-color-neutral-soft); color: var(--uni-color-text); }
.uni-toast-dismiss:focus-visible { outline: 2px solid var(--uni-color-focus-ring); outline-offset: 2px; }

@media (max-width: 767px) {
    .uni-toast-region { left: var(--uni-space-3); right: var(--uni-space-3); top: var(--uni-space-3); width: auto; }
}

/* ============================================================================
   Lista canônica do UniChat (UniList)

   UNICHAT-VISUAL-SYSTEM-ASSISTED-CONVERGENCE-01 — revisão visual do proprietário (2026-09-07):
   "Observe a lista de 'Turmas cadastradas' do UniCursos. Ela está dentro de um card, olhe a fonte
   e tipografia do título e dos demais componentes, o column header, o botão de ação circular com
   rótulo. Copie o modelo da página /classes. Esse será o padrão do UniChat para listas."

   Modelo de origem medido em feature/unicursos-efam-finance-ops-02 @ f92ff5d8
   (ClassesPage.razor + .table-card/.courses-list-toolbar/.admin-table).

   A diferença estrutural em relação à tabela que este corte tinha entregue: a lista NÃO é uma
   tabela com linhas separadas por régua. É um card contendo linhas que são elas próprias cartões
   delimitados, separados por espaço. O respiro entre linhas é o que dá o acabamento.

   Valores adaptados à escada do UniChat (VL-01/VL-02): o modelo usa font-weight 650 e 0.82rem,
   ambos fora da escada — aqui viram 600 e `sm` (13px), que é o degrau equivalente.
   ============================================================================ */

.uni-list-card {
    display: flex;
    flex-direction: column;
    gap: var(--uni-space-5);
    padding: var(--uni-space-5);
    border: 1px solid var(--uni-color-border);
    border-radius: var(--uni-radius-lg);
    background: var(--uni-color-surface);
    box-shadow: var(--uni-shadow-sm);
}

.uni-list-head {
    display: flex;
    align-items: flex-start;
    gap: var(--uni-space-4);
    min-width: 0;
}

.uni-list-head-copy {
    display: grid;
    flex: 1 1 280px;
    gap: var(--uni-space-1);
    min-width: 0;
}

.uni-list-title {
    margin: 0;
    color: var(--uni-color-text);
    font-size: var(--uni-font-size-lg);
    font-weight: 600;
    line-height: 1.2;
}

.uni-list-subtitle {
    margin: 0;
    color: var(--uni-color-text-muted);
    font-size: var(--uni-font-size-sm);
    line-height: 1.45;
}

.uni-list-head-controls {
    display: flex;
    flex: 0 1 auto;
    align-items: center;
    justify-content: flex-end;
    gap: var(--uni-space-3);
    min-width: 0;
    margin-left: auto;
}

/* Ação circular com rótulo do modelo. VG-07 proíbe repetir este padrão em CADA LINHA de uma
   lista; aqui ele vive no cabeçalho do card, que é exatamente o uso que a decisão reserva. */
.uni-list-action {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    gap: var(--uni-space-2);
    border: 0;
    background: transparent;
    color: var(--uni-color-primary);
    font-family: var(--uni-font-family);
    font-size: var(--uni-font-size-sm);
    font-weight: 600;
    cursor: pointer;
    user-select: none;
}

.uni-list-action-circle {
    display: inline-grid;
    place-items: center;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background: var(--uni-color-primary);
    color: var(--uni-color-on-primary);
    transition: background-color 0.14s ease;
}

.uni-list-action:hover .uni-list-action-circle { background: var(--uni-color-primary-hover); }
.uni-list-action:focus-visible { outline: 2px solid var(--uni-color-focus-ring); outline-offset: 2px; border-radius: var(--uni-radius-sm); }
.uni-list-action .crm-icon { width: 16px; height: 16px; }

/* ---- Corpo da lista ---- */

.uni-list {
    display: grid;
    gap: var(--uni-space-2);
    min-width: 0;
}

.uni-list-row {
    display: grid;
    align-items: center;
    gap: var(--uni-space-3);
    min-width: 0;
    padding: var(--uni-space-3);
    border: 1px solid var(--uni-color-border);
    border-radius: var(--uni-radius-md);
    background: var(--uni-color-surface);
    color: var(--uni-color-text);
    font-size: var(--uni-font-size-md);
    transition: background-color 0.12s ease, border-color 0.12s ease;
}

.uni-list-row > * { min-width: 0; }

/* A última coluna é sempre a de ações — alinhada à direita, no cabeçalho e nas linhas. */
.uni-list-row > :last-child {
    justify-self: end;
    text-align: right;
}

.uni-list-row-head {
    padding: var(--uni-space-2) var(--uni-space-3);
    border-color: transparent;
    background: var(--uni-color-neutral-soft);
    color: var(--uni-color-text-muted);
    font-size: var(--uni-font-size-sm);
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    user-select: none;
}

.uni-list-row-link { cursor: pointer; }

.uni-list-row-link:hover {
    border-color: color-mix(in srgb, var(--uni-color-primary) 40%, var(--uni-color-border));
    background: color-mix(in srgb, var(--uni-color-primary-soft) 40%, var(--uni-color-surface));
}

.uni-list-row-link:focus-visible {
    outline: 2px solid var(--uni-color-focus-ring);
    outline-offset: 2px;
}

.uni-list-row strong,
.uni-list-row small {
    display: block;
    min-width: 0;
    overflow-wrap: anywhere;
}

.uni-list-row strong {
    color: var(--uni-color-text);
    font-size: var(--uni-font-size-md);
    font-weight: 600;
    line-height: 1.35;
}

.uni-list-row small {
    color: var(--uni-color-text-muted);
    font-size: var(--uni-font-size-sm);
    line-height: 1.4;
}

.uni-list-empty {
    padding: var(--uni-space-6);
    color: var(--uni-color-text-muted);
    font-size: var(--uni-font-size-md);
    text-align: center;
}

/* ≤767: o cabeçalho de coluna some e cada linha vira um cartão em pilha (VL-27). */
@media (max-width: 767px) {
    .uni-list-card { padding: var(--uni-space-4); gap: var(--uni-space-4); }
    .uni-list-head { flex-direction: column; }
    /* UNICHAT-CONFIGURACOES-VISUAL-ASSISTED-CONVERGENCE-01 — defeito medido no navegador a 390px:
       `.uni-list-head-copy` declara `flex: 1 1 280px` para o cabeçalho em LINHA, onde 280px é
       largura mínima. Ao virar coluna, o mesmo `flex-basis` passa a ser ALTURA, e o título ficava
       separado da descrição por um vão de ~280px. É a mesma família de armadilha do `flex-grow`
       herdado do contexto de linha já registrada no programa. Correção de defeito, não de
       composição: `/contatos` e `/usuarios` usam o mesmo cabeçalho e tinham o mesmo vão. */
    .uni-list-head-copy { flex: 0 0 auto; width: 100%; }
    .uni-list-head-controls { margin-left: 0; width: 100%; }
    .uni-list-row-head { display: none; }
    .uni-list-row { grid-template-columns: minmax(0, 1fr) !important; }
    .uni-list-row > :last-child { justify-self: start; text-align: left; }
}

/* Ação de linha com ícone circular e rótulo externo — padrão do UniCursos, pedido explícito do
   proprietário na revisão visual de 2026-09-07 ("devem ser botões circulares, com ícones internos,
   e rótulos externos. Padrão do UniCursos, deve ser aplicado também no UniChat").

   EMENDA A VG-07. A decisão VG-07 (2026-09-07) proibia repetir ícone+rótulo em cada linha de
   lista, medindo no UniCursos 167 usos de 68x68px que dobravam a altura da linha. O proprietário
   reviu essa restrição com a implementação na frente. A emenda preserva o motivo original ao
   limitar o número: UMA ação rotulada por linha, com o excedente no menu — o custo que VG-07
   nomeia (quebra em duas linhas com 3+ botões) não se materializa com uma só. */
.uni-row-action {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    min-width: 56px;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--uni-color-text-muted);
    font-family: var(--uni-font-family);
    font-size: var(--uni-font-size-2xs);
    font-weight: 600;
    line-height: 1.2;
    cursor: pointer;
    user-select: none;
}

.uni-row-action-circle {
    display: inline-grid;
    place-items: center;
    width: 32px;
    height: 32px;
    border: 1px solid var(--uni-color-border);
    border-radius: 50%;
    background: var(--uni-color-surface);
    color: var(--uni-color-text-muted);
    transition: background-color 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}

.uni-row-action:hover .uni-row-action-circle {
    border-color: var(--uni-color-primary);
    background: var(--uni-color-primary-soft);
    color: var(--uni-color-primary);
}

.uni-row-action:hover { color: var(--uni-color-primary); }

.uni-row-action:focus-visible {
    outline: 2px solid var(--uni-color-focus-ring);
    outline-offset: 2px;
    border-radius: var(--uni-radius-sm);
}

.uni-row-action .crm-icon { width: 16px; height: 16px; }

/* ============================================================================
   Tema escuro dos controles nativos — revisão do proprietário (2026-09-07)

   "Os checkbox continuam com fundo branco, mesmo com dark mode. Esse problema é geral no app.
   Se necessário criamos nosso próprio checkbox."

   Não é necessário criar componente. O que faltava é declarar o esquema de cor do documento:
   sem `color-scheme`, o navegador desenha TODO controle nativo — checkbox, radio, barra de
   rolagem, seletor de data, spinner numérico — com a paleta clara, independentemente do CSS do
   app. Uma linha por tema resolve a família inteira e continua valendo para qualquer controle
   nativo que apareça depois.

   Um componente próprio de checkbox resolveria só o checkbox, custaria manutenção e teria que
   reimplementar estado indeterminado, foco e acessibilidade que o nativo já entrega. */

:root {
    color-scheme: light;
}

:root[data-crm-theme="dark"] {
    color-scheme: dark;
}

/* A cor de marcação acompanha o produto em ambos os temas. */
input[type="checkbox"],
input[type="radio"] {
    accent-color: var(--uni-color-primary);
}

/* O popup do <select> é desenhado pelo navegador a partir das próprias <option>. Com
   `color-scheme: dark` o campo fechado já escurece, mas a <option> nasce com fundo transparente:
   o popup aberto herda o padrão do sistema e sai claro dentro do tema escuro. Declarar a cor na
   opção é o que fecha o caso — vale para qualquer <select> do app, não só os estilizados.

   Revisão do proprietário, 2026-09-07. */
:root[data-crm-theme="dark"] select option,
:root[data-crm-theme="dark"] select optgroup {
    background-color: var(--uni-color-surface);
    color: var(--uni-color-text);
}

:root[data-crm-theme="dark"] select optgroup {
    font-weight: 700;
}

/* ============================================================================
   UniSwitch — VL-41. Switch canônico do UniChat.

   Decisão do proprietário (CF-01): switch é o padrão para chaves.
   Revisão visual (2026-09-07): "a bolinha não está perfeitamente centralizada; chegue a um switch
   elegante e minimalista."

   Geometria, e por que ela centraliza de verdade: a primeira versão empilhava o polegar dentro do
   trilho com `margin`, e qualquer diferença de `line-height` ou `box-sizing` do contexto o
   deslocava. Aqui o polegar é ABSOLUTO dentro do trilho e ancorado em `top: 50%` com
   `translateY(-50%)` — o centro vertical passa a ser geométrico, não a soma de margens.

   Proporções: trilho 36×20, polegar 14, folga de 3px. O deslocamento ligado é exatamente
   36 − 14 − 3 − 3 = 16px, então a folga é idêntica dos dois lados nos dois estados.
   ============================================================================ */

.uni-switch-row {
    display: flex;
    align-items: flex-start;
    gap: var(--uni-space-3);
    padding: var(--uni-space-3) 0;
    color: var(--uni-color-text);
    font-size: var(--uni-font-size-md);
    cursor: pointer;
}

.uni-switch-row.is-disabled { cursor: not-allowed; }
.uni-switch-row.is-saving { cursor: progress; }

.uni-switch {
    position: relative;
    flex: 0 0 auto;
    display: block;
    width: 36px;
    height: 20px;
    /* Alinha o trilho com a primeira linha do rótulo (md/1.35 ≈ 19px). */
    margin-top: 1px;
}

/* O input real cobre o trilho, invisível: teclado, foco e leitor de tela vêm de graça. */
.uni-switch input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: inherit;
}

.uni-switch-track {
    display: block;
    width: 100%;
    height: 100%;
    border-radius: var(--uni-radius-pill);
    background: color-mix(in srgb, var(--uni-color-text-muted) 32%, transparent);
    transition: background-color 0.18s cubic-bezier(0.2, 0, 0.2, 1);
}

.uni-switch-thumb {
    position: absolute;
    top: 50%;
    left: 3px;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: #ffffff;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.22);
    transform: translateY(-50%);
    transition: transform 0.18s cubic-bezier(0.2, 0, 0.2, 1);
}

.uni-switch.is-on .uni-switch-track { background: var(--uni-color-primary); }
.uni-switch.is-on .uni-switch-thumb { transform: translate(16px, -50%); }

.uni-switch input:focus-visible ~ .uni-switch-track {
    outline: 2px solid var(--uni-color-focus-ring);
    outline-offset: 2px;
}

.uni-switch input:not(:disabled):active ~ .uni-switch-track { filter: brightness(0.96); }

/* Desligado e travado: apaga. Ligado e travado (o caso do Owner em D-46): precisa continuar
   lendo como ATIVO, só que sem convite ao clique — cor do produto dessaturada, não cinza. */
.uni-switch-row.is-disabled .uni-switch-track { opacity: 0.55; }
.uni-switch-row.is-disabled .uni-switch-thumb { box-shadow: none; }

.uni-switch-row.is-disabled .uni-switch.is-on .uni-switch-track {
    background: color-mix(in srgb, var(--uni-color-primary) 60%, var(--uni-color-text-muted));
    opacity: 0.7;
}

.uni-switch-text {
    display: grid;
    gap: 2px;
    min-width: 0;
}

.uni-switch-text strong {
    color: var(--uni-color-text);
    font-size: var(--uni-font-size-md);
    font-weight: 600;
    line-height: 1.35;
}

.uni-switch-text small {
    color: var(--uni-color-text-muted);
    font-size: var(--uni-font-size-sm);
    line-height: 1.4;
}

.uni-switch-row.is-disabled .uni-switch-text strong { color: var(--uni-color-text-muted); }

.uni-switch-error { color: var(--uni-color-danger) !important; font-weight: 600; }

.uni-switch-status {
    flex: 0 0 auto;
    margin-left: auto;
    align-self: flex-start;
    margin-top: 1px;
    color: var(--uni-color-text-muted);
    font-size: var(--uni-font-size-xs);
    white-space: nowrap;
}

/* Avatar de pessoa: mesmo círculo do contato, com ícone em vez de iniciais. */
.crm-users-avatar .crm-icon {
    width: 18px;
    height: 18px;
    color: #ffffff;
}

/* ============================================================================
   UniStepper — OS-01
   Promovido de `.cmp-stepper` (CSS scoped de CrmCampaignsPage), que por sua vez
   é o port do stepper do UniAssessor / LeadPhaseStepper. A anatomia é a mesma,
   apenas movida de escopo: Campanhas continua com a aparência que tinha.

   Semântica herdada e normativa (OS-02):
     preenchimento = PROGRESSO (nunca seleção); contorno/halo = FOCO da etapa.
   Os dois eixos são independentes — um nó concluído e em foco acumula ambos.
   ========================================================================== */
.uni-stepper {
    --st-r: 20px;
    --st-primary: var(--crm-color-primary);
    --st-inactive: var(--uni-color-neutral-soft);
    --st-fill-top: color-mix(in srgb, white 38%, var(--st-primary));
    --st-fill-bottom: color-mix(in srgb, black 8%, var(--st-primary));
    --st-ring: color-mix(in srgb, white 60%, var(--st-primary));
    --st-ease: cubic-bezier(0.45, 0, 0.55, 1);
    display: flex;
    align-items: flex-start;
    overflow: visible;
}

.uni-stepper-item {
    position: relative;
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.uni-stepper-rail {
    position: absolute;
    z-index: 0;
    left: -50%;
    right: 50%;
    top: calc(var(--st-r) * 0.85);
    height: calc(var(--st-r) * 0.3);
    border-radius: 999px;
    overflow: hidden;
    pointer-events: none;
    background: color-mix(in srgb, var(--crm-color-border) 82%, transparent);
    /* UNICHAT-CUT-6 (polish, 7A) — contorno SUTIL do trilho vazio: com nenhuma etapa concluída o
       trilho tinha só a cor da borda sobre a superfície e se perdia no fundo. Sombra interna de 1px
       com o token de borda forte, nos dois temas; o preenchimento (progresso) cobre o contorno. */
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crm-color-border-strong) 55%, transparent);
}

.uni-stepper-rail i {
    position: absolute;
    inset: 0;
    border-radius: 999px;
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform 480ms var(--st-ease);
}

.uni-stepper-rail i.nav { background: color-mix(in srgb, var(--st-primary) 26%, transparent); }
.uni-stepper-rail i.done { background: var(--st-primary); }
.uni-stepper-rail i.on { transform: scaleX(1); }

.uni-stepper-node {
    position: relative;
    z-index: 1;
    flex: 0 0 auto;
    width: calc(var(--st-r) * 2);
    height: calc(var(--st-r) * 2);
    display: grid;
    place-items: center;
    padding: 0;
    cursor: pointer;
    border-radius: 999px;
    /* UNICHAT-CUT-6 (polish, 7A) — o nó pendente tinha borda MAIS CLARA que o próprio preenchimento
       (white 38% sobre o neutro), e sobre a superfície do card o círculo perdia o desenho. Contorno
       fino com o token de borda forte: baixo contraste, mas define o círculo nos dois temas.
       Concluído/atual/adiado/aguardando continuam com as bordas próprias abaixo. */
    border: 1.5px solid var(--crm-color-border-strong);
    background: var(--st-inactive);
    color: var(--crm-color-text-muted);
    font-size: 12.5px;
    font-weight: 600;
    transition: background 480ms var(--st-ease), border-color 480ms var(--st-ease),
        box-shadow 480ms var(--st-ease), color 480ms var(--st-ease), transform 180ms var(--st-ease);
}

.uni-stepper-node span,
.uni-stepper-node .crm-icon,
.uni-stepper-check { position: relative; z-index: 2; }

.uni-stepper-check {
    width: calc(var(--st-r) * 0.95);
    height: calc(var(--st-r) * 0.95);
    fill: none;
    stroke: currentColor;
    stroke-width: 2.6;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.uni-stepper-node:not(:disabled):hover { transform: scale(1.06); }
.uni-stepper-node:disabled { cursor: default; opacity: .9; }

.uni-stepper-node.done {
    background: linear-gradient(180deg, var(--st-fill-top), var(--st-fill-bottom));
    border-color: color-mix(in srgb, var(--st-ring) 90%, transparent);
    color: #fff;
    box-shadow: 0 0 calc(var(--st-r) * 1.1) color-mix(in srgb, var(--st-primary) 55%, transparent);
}

.uni-stepper-node.started {
    background: color-mix(in srgb, var(--st-primary) 18%, var(--st-inactive));
    border-color: var(--st-primary);
    color: var(--crm-color-primary);
}

.uni-stepper-node.selected {
    box-shadow: 0 0 calc(var(--st-r) * 3) color-mix(in srgb, var(--st-primary) 55%, transparent);
    animation: uni-stepper-pulse 900ms ease-in-out infinite;
}

.uni-stepper-node.selected::after {
    content: "";
    position: absolute;
    z-index: 0;
    width: calc(var(--st-r) * 2.52);
    height: calc(var(--st-r) * 2.52);
    border-radius: 999px;
    border: calc(var(--st-r) * 0.16) solid color-mix(in srgb, var(--st-ring) 78%, transparent);
    filter: blur(calc(var(--st-r) * 0.45));
    pointer-events: none;
}

.uni-stepper-node.selected:not(.done):not(.started) {
    border-color: color-mix(in srgb, var(--st-primary) 45%, transparent);
    color: var(--crm-color-text);
}

/* OS-05 — adiado e "aguardando terceiro" são estados próprios, nem pendentes nem
   concluídos. VL-36 dá o tom: aguardando
   é sempre `warning`. A distinção entre os dois vem da FORMA — tracejado para o que a pessoa
   escolheu adiar, contínuo para o que depende de um terceiro. */
.uni-stepper-node.postponed {
    border-style: dashed;
    border-color: var(--crm-color-warning);
    color: var(--crm-color-warning);
}

.uni-stepper-node.awaiting {
    border-color: var(--crm-color-warning);
    color: var(--crm-color-warning);
}

@keyframes uni-stepper-pulse {
    0%, 100% { transform: scale(1); }
    50% { transform: scale(1.06); }
}

.uni-stepper-label {
    margin-top: 9px;
    padding: 0 4px;
    min-height: 16px;
    text-align: center;
    font-size: 11px;
    line-height: 1.25;
    color: var(--crm-color-text-muted);
    overflow-wrap: anywhere;
    transition: color 240ms var(--st-ease);
}

.uni-stepper-label.selected { color: var(--crm-color-text); font-weight: 600; }

@media (prefers-reduced-motion: reduce) {
    .uni-stepper-node.selected { animation: none; }
    .uni-stepper-rail i { transition: none; }
}

/* OS-10 — vertical em ≤767px, opt-in por `.uni-stepper-responsive`.
   Horizontal com quatro a seis nós num viewport estreito derruba o alvo de toque,
   e rolar o stepper esconde justamente o progresso que ele existe para mostrar.
   Campanhas (wizard de 3 etapas dentro de modal) não adota a variante. */
@media (max-width: 767px) {
    .uni-stepper.uni-stepper-responsive {
        flex-direction: column;
        align-items: stretch;
        /* O gap é o que sobra visível do trilho entre um nó e o seguinte. Com 4px a linha
           existe no DOM mas fica escondida atrás do nó, e a coluna perde a leitura de
           progressão que o stepper existe para dar. */
        gap: var(--uni-space-3);
    }

    .uni-stepper-responsive .uni-stepper-item {
        /* O alvo de toque (VL-27 / D-38) é maior que o nó, então o nó fica centrado e sobra uma
           folga em cima e embaixo. O trilho precisa saber dessa folga para encostar no nó
           anterior — daí ela ser um token derivado, não um número solto. */
        --st-touch: 44px;
        --st-vgap: var(--uni-space-3);
        --st-voffset: calc((var(--st-touch) - var(--st-r) * 2) / 2);
        flex: 0 0 auto;
        flex-direction: row;
        align-items: center;
        gap: var(--uni-space-3);
        min-height: var(--st-touch);
    }

    /* O trilho vertical liga o nó anterior a este: nasce um gap acima do item e desce até o meio
       dele, passando POR TRÁS do nó — que tem fundo próprio e z-index maior, e portanto recorta
       a linha exatamente na borda. Largura fina, altura é que preenche: o inverso do horizontal. */
    .uni-stepper-responsive .uni-stepper-rail {
        left: calc(var(--st-r) - (var(--st-r) * 0.15));
        right: auto;
        top: calc((var(--st-vgap) + var(--st-voffset)) * -1);
        bottom: auto;
        width: calc(var(--st-r) * 0.3);
        /* Do fim do nó anterior até o centro deste: a metade de baixo fica atrás do nó, que a
           recorta na borda. */
        height: calc(var(--st-vgap) + var(--st-voffset) * 2 + var(--st-r));
    }

    .uni-stepper-responsive .uni-stepper-rail i { transform: scaleY(0); transform-origin: top center; }
    .uni-stepper-responsive .uni-stepper-rail i.on { transform: scaleY(1); }

    .uni-stepper-responsive .uni-stepper-label {
        margin-top: 0;
        text-align: left;
        font-size: var(--uni-font-size-sm);
        flex: 1 1 auto;
    }
}

/* =====================================================================================
   UNICHAT-KANBAN-AGENDA-TAREFAS-VISUAL-ASSISTED-CONVERGENCE-01

   Barra de superfície + popover de filtros — PROMOÇÃO ao canônico, pelo mesmo caminho de
   C-09 (`.uni-field`) e de `.uni-search` (§22.1): a ficha já existia, mas presa a folhas de
   feature. `crm-contacts.css` tem `.crm-contacts-filters-panel` e `crm-chat.css` tem
   `.crm-ticket-filters-panel` — a MESMA anatomia escrita duas vezes. Esta é a terceira
   superfície que precisa dela; escrever uma terceira cópia é o que o §15 proíbe.

   Geometria IDÊNTICA à já aceita em /contatos: nada muda de aparência lá. As duas folhas de
   feature seguem intactas e migram quando aquelas superfícies reentrarem no programa.
   ===================================================================================== */

/* VL-21 — anatomia fixa: busca permanente (flex:1) · uma faixa de segmentação · Filtros (N) */
.uni-toolbar {
    display: flex;
    align-items: center;
    gap: var(--uni-space-3);
    margin-bottom: var(--uni-space-4);
}

.uni-toolbar > .uni-search { flex: 1 1 260px; min-width: 0; }

.uni-toolbar-segment { flex: 0 0 auto; min-width: 200px; }

.uni-filter-anchor { position: relative; flex: 0 0 auto; }

.uni-filter-panel {
    position: absolute;
    top: calc(100% + var(--uni-space-2));
    right: 0;
    z-index: var(--uni-z-dropdown);
    width: min(420px, calc(100vw - 32px));
    border: 1px solid var(--uni-color-border);
    border-radius: var(--uni-radius-lg);
    background: var(--uni-color-surface);
    box-shadow: var(--uni-shadow-md);
    /* VL-38: o PAINEL respeita a altura; o corpo rola por dentro e o rodapé fica preso ao pé. */
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.uni-filter-panel-body {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: var(--uni-space-4);
    min-height: 0;
    padding: var(--uni-space-5);
    overflow-y: auto;
}

.uni-filter-panel-footer {
    display: flex;
    justify-content: space-between;
    gap: var(--uni-space-3);
    padding: var(--uni-space-4) var(--uni-space-5);
    border-top: 1px solid var(--uni-color-border);
}

.uni-filter-group {
    display: flex;
    flex-direction: column;
    gap: var(--uni-space-2);
}

/* VL-03 — micro-label de cabeçalho de grupo. */
.uni-filter-group-title {
    margin: 0;
    color: var(--uni-color-text-muted);
    font-size: var(--uni-font-size-2xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    line-height: 1.2;
    text-transform: uppercase;
    user-select: none;
}

.uni-filter-backdrop {
    position: fixed;
    inset: 0;
    z-index: calc(var(--uni-z-dropdown) - 1);
    border: 0;
    background: transparent;
    cursor: default;
}

/* -------------------------------------------------------------------------------------
   ESCALA DE TAMANHO DA ABA — UNICHAT-PARALLEL-VISUAL-AUTHORITY-AND-WEB-RECONCILIATION-01,
   fechamento de CF-02 (aberta em Configurações §22.5 e reproposta em PAA-07).

   CF-02 pedia promover a geometria de VL-16 (42px) para TODA aba. A reconciliação mediu os
   consumidores antes de promover e encontrou o motivo pelo qual isso não pode ser feito:
   `.uni-tab` a 34px está OWNER VISUAL ACCEPTED em Contatos, Usuários, Configurações, Minha
   conta, Cargos e Visão geral; 42px está OWNER VISUAL ACCEPTED em Tarefas e no drawer do
   Kanban. Uma geometria única regride uma das duas listas — e as duas estão na lista de
   "não regredir" desta reconciliação.

   A leitura honesta é que o produto tem uma escala de DOIS degraus e não sabia disso. Aqui
   ela deixa de ser acidente e vira contrato: o degrau é escolhido por `Size` na primitive,
   não por uma classe emprestada. O nome `.uni-tabs-vl16` morreu de propósito — amarrar o
   seletor ao número de uma regra faz o CSS quebrar quando a numeração da authority muda.

   O alvo de toque NÃO mora mais aqui: subiu para a ficha base, porque é acessibilidade e
   vale para toda aba, não só para as desta variante.
   ------------------------------------------------------------------------------------- */
.uni-tabs-lg .uni-tab {
    min-height: 42px;
    padding: 0 var(--uni-space-4);
    font-size: var(--uni-font-size-md);
}

.uni-tabs-lg .uni-tab:not(.is-active) { font-weight: 500; }

/* MEDIDO no smoke de integração, e é o motivo desta regra existir em vez de confiar na ficha base:
   `.uni-tabs-lg .uni-tab` tem especificidade (0,2,0) e a regra de toque da ficha base tem (0,1,0).
   A base perde SEMPRE, media query nenhuma muda isso. Sem esta repetição a aba de modo de Tarefas
   voltava a 42px no celular — abaixo do piso de 44px que a superfície já tinha ACEITO, ou seja,
   regressão silenciosa introduzida pela própria unificação da escala.

   O degrau maior nunca pode ficar abaixo do piso do degrau menor. */
@media (max-width: 1023px) {
    .uni-tabs-lg .uni-tab { min-height: 44px; }
}

/* -------------------------------------------------------------------------------------
   UNICHAT-RESIDUAL-PRODUCT-SURFACE-VISUAL-COMPLETION-01 — página de sistema (RS-44)

   As duas páginas fora do produto autenticado (não encontrada e erro global) viviam em
   `.empty-page`, declarada em `app.css` sobre tokens `--app-*` legados e SEM fundo próprio:
   herdavam o que o `body` tivesse. Elas usam `MainLayout`, que não monta `CrmThemeProvider` —
   o que salva o tema escuro ali é o `crmTheme.boot()` do script, que carimba `data-crm-theme`
   no `<html>` antes de qualquer render. Logo: token resolve, literal não. Esta ficha é toda
   em token, e por isso tem par escuro sem escrever uma segunda regra.

   Estrutura conforme D-36/VL-22: ícone, título curto, uma frase, uma ação — e nada mais.
   ------------------------------------------------------------------------------------- */
.uni-system-page {
    display: grid;
    place-content: center;
    min-height: 100vh;
    min-height: 100dvh;
    padding: var(--uni-space-6) var(--uni-space-4);
    background: var(--uni-color-app-bg);
    color: var(--uni-color-text);
}

.uni-system-page-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--uni-space-3);
    width: min(100%, 460px);
    padding: var(--uni-space-6);
    border: 1px solid var(--uni-color-border);
    border-radius: var(--uni-radius-lg);
    background: var(--uni-color-surface);
    box-shadow: var(--uni-shadow-sm);
    text-align: center;
}

.uni-system-page-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: var(--uni-radius-md);
    background: var(--uni-color-neutral-soft);
    color: var(--uni-color-text-muted);
}

.uni-system-page-icon.is-danger {
    background: var(--uni-color-danger-soft);
    color: var(--uni-color-danger);
}

.uni-system-page-icon .crm-icon { width: 22px; height: 22px; }

.uni-system-page h1 {
    margin: 0;
    font-size: var(--uni-font-size-xl);
    font-weight: 700;
    line-height: 1.2;
    color: var(--uni-color-text);
}

.uni-system-page p {
    margin: 0;
    font-size: var(--uni-font-size-md);
    line-height: 1.45;
    color: var(--uni-color-text-muted);
}

/* O código de referência serve para a pessoa CITAR ao suporte: precisa ser selecionável e
   quebrar em telas estreitas, senão empurra a largura do cartão. */
.uni-system-page-ref {
    display: flex;
    flex-direction: column;
    gap: var(--uni-space-1);
    width: 100%;
    padding: var(--uni-space-2) var(--uni-space-3);
    border-radius: var(--uni-radius-md);
    background: var(--uni-color-neutral-soft);
}

.uni-system-page-ref > span {
    font-size: var(--uni-font-size-xs);
    font-weight: 600;
    color: var(--uni-color-text-muted);
}

.uni-system-page-ref code {
    font-size: var(--uni-font-size-sm);
    color: var(--uni-color-text);
    overflow-wrap: anywhere;
}

.uni-system-page .app-button { margin-top: var(--uni-space-2); }

/* -------------------------------------------------------------------------------------
   UNICHAT-RESIDUAL-PRODUCT-SURFACE-VISUAL-COMPLETION-01 — faixa de erro do circuito (RS-46)

   Migrada de `app.css`, onde tinha `background: #fee2e2` literal — cor clara fixa, sem par
   escuro, contra texto de perigo: exatamente o que VL-46 proíbe. E `z-index: 1000`, um número
   solto que não conversa com a escala `--uni-z-*` (VL-09): ficava ACIMA do modal (51) e do
   toast (60) sem que ninguém tivesse decidido isso. Agora usa o degrau de toast, que é onde
   um aviso não-bloqueante do viewport pertence.

   Os seletores são contrato do framework — ver o comentário em `BlazorErrorUi.razor`.
   ------------------------------------------------------------------------------------- */
#blazor-error-ui {
    display: none;
    position: fixed;
    right: var(--uni-space-4);
    bottom: var(--uni-space-4);
    z-index: var(--uni-z-toast);
    align-items: center;
    gap: var(--uni-space-2);
    max-width: min(420px, calc(100vw - var(--uni-space-6)));
    padding: var(--uni-space-3) var(--uni-space-4);
    border: 1px solid var(--uni-color-danger);
    border-radius: var(--uni-radius-md);
    background: var(--uni-color-danger-soft);
    color: var(--uni-color-danger);
    box-shadow: var(--uni-shadow-md);
    font-size: var(--uni-font-size-sm);
}

/* O framework mostra a faixa escrevendo `display: block` inline. Sem esta regra o `flex` do
   bloco acima seria perdido no momento em que ela aparece — que é o único momento em que
   importa. Medir isto exige derrubar o circuito, então fica declarado, não deduzido. */
#blazor-error-ui[style*="display: block"],
#blazor-error-ui[style*="display:block"] { display: flex !important; }

#blazor-error-ui .blazor-error-ui-copy { flex: 1 1 auto; }

#blazor-error-ui .reload {
    color: var(--uni-color-danger);
    font-weight: 700;
    text-decoration: underline;
    white-space: nowrap;
}

#blazor-error-ui .dismiss {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: var(--uni-radius-sm);
    color: inherit;
    cursor: pointer;
}

#blazor-error-ui .dismiss:hover { background: color-mix(in srgb, currentColor 14%, transparent); }
#blazor-error-ui .dismiss:focus-visible { outline: 2px solid var(--uni-color-focus-ring); outline-offset: 2px; }
#blazor-error-ui .dismiss .crm-icon { width: 16px; height: 16px; }

/* ============================================================================
   UNICHAT-WEB-MVP-PRE-PRODUCTION-CORRECTIONS-01 (D1) — UniFilePicker.
   O <input type=file> real vive DENTRO do gatilho, oculto por clip: continua na ordem de foco
   (Tab chega, Enter/Espaço abrem o seletor), sem `hidden` (sai do teclado) e sem `opacity:0`
   (rouba o scroll ao focar). O anel de foco é desenhado no gatilho via :focus-within.
   ============================================================================ */
.uni-file-picker {
    display: flex;
    flex-direction: column;
    gap: var(--uni-space-2);
    min-width: 0;
}

.uni-file-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--uni-space-3);
    min-width: 0;
}

.uni-file-trigger {
    position: relative;
    cursor: pointer;
    flex: 0 0 auto;
}

.uni-file-trigger:focus-within {
    outline: 2px solid var(--uni-color-focus-ring);
    outline-offset: 2px;
}

.uni-file-input {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
}

.uni-file-name {
    display: inline-flex;
    align-items: baseline;
    gap: 0;
    min-width: 0;
    max-width: 100%;
    font-size: var(--uni-font-size-sm);
    color: var(--uni-color-text);
}

.uni-file-name.is-empty { color: var(--uni-color-text-muted); }

.uni-file-name-text {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.uni-file-name-detail {
    flex: 0 0 auto;
    color: var(--uni-color-text-muted);
    white-space: nowrap;
}

.uni-file-error {
    margin: 0;
    font-size: var(--uni-font-size-xs);
    line-height: 1.4;
    color: var(--uni-color-danger);
}

.uni-file-picker.is-disabled .uni-file-trigger,
.uni-file-picker.is-busy .uni-file-trigger {
    opacity: 0.55;
    cursor: not-allowed;
}

/* ============================================================================
   UNICHAT-WEB-MVP-PRE-PRODUCTION-CORRECTIONS-01 (D2) — sobreposições resistentes a conteúdo longo.
   Medido em produção (Campanhas, 2026-09-11): um erro técnico de 800+ caracteres no UniNoticeModal
   crescia sem teto e sem quebra em tokens longos (URLs de stack trace). Regras: largura responsiva,
   altura limitada ao viewport, corpo rolável, cabeçalho e rodapé fixos, quebra de qualquer token.
   crm-knowledge.css (dono original do .uni-notice-*) carrega DEPOIS desta folha, então as regras
   aqui usam o ancestral .uni-notice-overlay para vencer por especificidade, não por ordem.
   ============================================================================ */
.uni-notice-overlay .uni-notice-modal {
    max-height: min(640px, calc(100vh - 32px));
    grid-template-rows: auto auto;
    align-items: start;
}

.uni-notice-overlay .uni-notice-content {
    min-height: 0;
    max-height: min(440px, calc(100vh - 200px));
    overflow-y: auto;
    overscroll-behavior: contain;
}

.uni-notice-overlay .uni-notice-modal h2,
.uni-notice-overlay .uni-notice-message,
.uni-notice-overlay .uni-notice-eyebrow {
    overflow-wrap: anywhere;
    word-break: break-word;
}

.uni-notice-overlay .uni-notice-message { white-space: pre-line; }

.uni-notice-actions { flex: 0 0 auto; }

.uni-modal { min-height: 0; }
.uni-modal-header,
.uni-modal-footer { flex: 0 0 auto; }
.uni-modal-body {
    min-height: 0;
    overscroll-behavior: contain;
    overflow-wrap: anywhere;
}
.uni-modal-header-titles { min-width: 0; }
.uni-modal-header-titles h2,
.uni-modal-header-titles p { overflow-wrap: anywhere; }

@media (max-width: 767px) {
    .uni-notice-overlay .uni-notice-modal { width: calc(100vw - 24px); max-height: calc(100vh - 24px); }
    .uni-notice-overlay .uni-notice-content { max-height: calc(100vh - 220px); }
}

/* CUT 5J — ficha de campo com caixa de seleção à esquerda e hint abaixo do rótulo (compartilhada). */
.uni-field-inline { display: grid; grid-template-columns: auto 1fr; column-gap: var(--uni-space-2); align-items: center; }
.uni-field-inline input[type="checkbox"] { grid-row: 1; }
.uni-field-inline > small { grid-column: 2; }

/* ---------- UniDisclosure (UNICHAT-CUT-6S, Owner R2: seção recolhível de detalhe) ----------
   Cabeçalho inteiro clicável (o botão cobre a linha via ::after); o (i) e as ações ficam acima dessa
   camada. Chevron vazado, 16px (compatível com a fonte), encostado à direita, gira 180° quando aberto.
   Nível "section": título md 600 com régua inferior; nível "sub": título sm 600, sem régua. */
.uni-disclosure { display: flex; flex-direction: column; min-width: 0; }

.uni-disclosure-head {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--uni-space-2);
    min-height: 36px;
}

.uni-disclosure--section > .uni-disclosure-head {
    padding: var(--uni-space-2) 0;
    border-bottom: 1px solid var(--uni-color-border);
}

.uni-disclosure--sub > .uni-disclosure-head {
    min-height: 32px;
    padding: var(--uni-space-1) 0;
}

.uni-disclosure-trigger {
    display: inline-flex;
    align-items: baseline;
    gap: var(--uni-space-2);
    min-width: 0;
    padding: 0;
    border: 0;
    background: transparent;
    font: inherit;
    color: var(--uni-color-text);
    text-align: left;
    cursor: pointer;
}

/* A linha inteira alterna a seção. */
.uni-disclosure-trigger::after { content: ""; position: absolute; inset: 0; }

.uni-disclosure-trigger:focus-visible { outline: none; }
.uni-disclosure-trigger:focus-visible::after { outline: 2px solid var(--uni-color-primary); outline-offset: 2px; border-radius: var(--uni-radius-sm); }

.uni-disclosure--section .uni-disclosure-title { font-size: var(--uni-font-size-md); font-weight: 600; line-height: 1.3; }
.uni-disclosure--sub .uni-disclosure-title { font-size: var(--uni-font-size-sm); font-weight: 600; line-height: 1.3; }

.uni-disclosure-meta {
    font-size: var(--uni-font-size-xs);
    font-weight: 500;
    color: var(--uni-color-text-muted);
    white-space: nowrap;
}

/* (i) e ações acima da camada clicável do botão. */
.uni-disclosure-head > .uni-field-info,
.uni-disclosure-actions { position: relative; z-index: 1; }
.uni-disclosure-actions { display: inline-flex; align-items: center; gap: var(--uni-space-2); margin-left: auto; }
.uni-disclosure-actions + .uni-disclosure-chevron { margin-left: 0; }

.uni-disclosure-chevron {
    pointer-events: none; /* Owner R3: a seta girada (transform) ficava acima da camada clicável e engolia o clique */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 16px;
    height: 16px;
    margin-left: auto;
    color: var(--uni-color-text-muted);
    transition: transform 140ms ease;
}

.uni-disclosure.is-open > .uni-disclosure-head > .uni-disclosure-chevron { transform: rotate(180deg); }
.uni-disclosure-head:hover .uni-disclosure-chevron { color: var(--uni-color-text); }

.uni-disclosure-body {
    display: flex;
    flex-direction: column;
    gap: var(--uni-space-3);
    min-width: 0;
}

.uni-disclosure--section > .uni-disclosure-body { padding-top: var(--uni-space-3); }
.uni-disclosure--sub > .uni-disclosure-body { padding-top: var(--uni-space-1); }

/* Subgrupos empilhados dentro de uma seção: régua fina entre eles. */
.uni-disclosure--section > .uni-disclosure-body > .uni-disclosure--sub + .uni-disclosure--sub {
    border-top: 1px solid var(--uni-color-border-subtle, var(--uni-color-border));
    padding-top: var(--uni-space-1);
}

/* ---------- UniBreadcrumb — trilha (UNICHAT-CUT-6T, decisão do proprietário 2026-09-21) ----------
   O separador é o chevron do CrmIcon, com a altura da fonte da trilha: o glifo "›" ficava menor que
   o texto e não lia como fluxo. Degraus anteriores são links; o atual é texto firme. */
.uni-breadcrumb { margin-bottom: var(--uni-space-4); font-size: var(--uni-font-size-sm); color: var(--crm-color-text-muted); }
.uni-breadcrumb ol { display: flex; flex-wrap: wrap; align-items: center; gap: var(--uni-space-1) 0; margin: 0; padding: 0; list-style: none; }
.uni-breadcrumb li { display: inline-flex; align-items: center; min-width: 0; }
.uni-breadcrumb a { color: var(--crm-color-primary); text-decoration: none; }
.uni-breadcrumb a:hover { text-decoration: underline; }
.uni-breadcrumb [aria-current="page"] { color: var(--crm-color-text); font-weight: 600; }
.uni-breadcrumb-sep { display: inline-flex; align-items: center; margin: 0 var(--uni-space-1); color: var(--crm-color-text-muted); opacity: .8; }
.uni-breadcrumb-sep .crm-icon { width: 1.15em; height: 1.15em; }

/* ================================================================================================
   UniProgressBar — UNICHAT-CUT-6U (F-113)

   Duas formas, um trilho. Determinada: o preenchimento vai a `width` e DESLIZA até lá (a
   suavização visual que o briefing pede). Indeterminada: um segmento atravessa o trilho em ciclo,
   sem nunca sugerir uma posição — porque não há posição a sugerir.

   Alturas, raios e cores saem dos tokens do sistema; nada aqui é valor solto.
   ================================================================================================ */
.uni-progress {
    position: relative;
    height: 6px;
    width: 100%;
    border-radius: var(--uni-radius-pill);
    overflow: hidden;
    background: color-mix(in srgb, var(--uni-color-border) 70%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--uni-color-border-strong) 45%, transparent);
}

.uni-progress-fill {
    display: block;
    height: 100%;
    border-radius: inherit;
    background: var(--crm-color-primary);
}

/* 600ms é o degrau em que um salto de 28% para 47% se lê como movimento e não como corte, sem virar
   uma barra preguiçosa que parece travada. `ease-out` porque o fim do movimento é o que se olha. */
.uni-progress.is-determinate .uni-progress-fill {
    width: 0;
    transition: width 600ms ease-out;
}

/* O segmento indeterminado tem largura própria e atravessa o trilho. Não há `width` animada aqui:
   animar `transform` mantém o movimento na thread de composição e não recalcula layout a cada
   quadro — numa tela que fica aberta minutos, é a diferença entre fluido e trêmulo. */
.uni-progress.is-indeterminate .uni-progress-fill {
    position: absolute;
    inset: 0 auto 0 0;
    width: 38%;
    animation: uni-progress-sweep 1.5s cubic-bezier(0.65, 0, 0.35, 1) infinite;
}

@keyframes uni-progress-sweep {
    0%   { transform: translateX(-100%); }
    100% { transform: translateX(363%); } /* 100/38 ≈ 2,63 trilhos + a própria largura */
}

/* Movimento reduzido: o indicador continua existindo (a pessoa precisa saber que há trabalho em
   curso), mas devagar e sem varredura — uma pulsação de opacidade no lugar do deslocamento. */
@media (prefers-reduced-motion: reduce) {
    .uni-progress.is-determinate .uni-progress-fill { transition-duration: 0ms; }
    .uni-progress.is-indeterminate .uni-progress-fill {
        position: static;
        width: 100%;
        animation: uni-progress-pulse 2.4s ease-in-out infinite;
    }
    @keyframes uni-progress-pulse { 50% { opacity: 0.35; } }
}
