/* ============================================================================
 * components.css — Biblioteca de componentes Conversattiva
 * Classes com prefixo `.cv-` para evitar colisão com Tailwind utilities.
 * Depende de tokens.css + base.css + um theme-*.css.
 *
 * IMPORTANTE: se um componente que você precisa NÃO está aqui, adicione aqui
 * antes de rolar próprio na tela. Ver AGENTS.md.
 * ============================================================================ */

/* ══════════════════════════════════════════════════════════════════════════
 * BUTTON — `.cv-btn` + variantes
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: 0 var(--space-4);
  height: var(--touch-target);              /* 44px MOBILE-FIRST (WCAG target) */
  border-radius: var(--radius-md);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  letter-spacing: -0.005em;
  line-height: 1;
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  transition: background-color var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-fast) var(--ease-out),
              transform var(--duration-fast) var(--ease-out);
  border: 1px solid transparent;
  white-space: nowrap;
}
.cv-btn:disabled, .cv-btn[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}
.cv-btn:active:not(:disabled) { transform: translateY(0.5px); }

/* Sizes — mobile-first. --sm continua 36px mas nunca abaixo do touch target
   em contexto interativo primário. Use --sm apenas em ações secundárias
   (Cancelar, Ver mais) ou em toolbars densas de desktop. */
.cv-btn--sm { height: 36px; padding: 0 var(--space-3); font-size: var(--text-xs); border-radius: var(--radius-sm); }
.cv-btn--lg { height: 52px; padding: 0 var(--space-6); font-size: var(--text-md); border-radius: var(--radius-md); }
.cv-btn--xl { height: 60px; padding: 0 var(--space-8); font-size: var(--text-lg); border-radius: var(--radius-lg); }
.cv-btn--icon { padding: 0; width: var(--touch-target); }
.cv-btn--icon.cv-btn--sm { width: 36px; }
.cv-btn--icon.cv-btn--lg { width: 52px; }
.cv-btn--block { width: 100%; }

/* Desktop enhancement: em telas grandes botões podem ser mais compactos por default,
   já que mouse tem precisão maior que dedo. */
@media (min-width: 1024px) {
  .cv-btn { height: 40px; }
  .cv-btn--icon { width: 40px; }
}

/* Variants */
.cv-btn--primary {
  background: var(--brand-500);
  color: var(--text-on-brand);
  border-color: var(--brand-500);
  box-shadow: var(--shadow-brand-sm);
}
.cv-btn--primary:hover:not(:disabled) { background: var(--brand-600); border-color: var(--brand-600); box-shadow: var(--shadow-brand-md); }
.cv-btn--primary:focus-visible { box-shadow: var(--focus-ring); }

/* Primary gradient — usar em CTAs de destaque (login, capa de slide) */
.cv-btn--primary-gradient {
  background: var(--brand-gradient);
  color: var(--text-on-brand);
  border-color: transparent;
  box-shadow: var(--shadow-brand-sm);
}
.cv-btn--primary-gradient:hover:not(:disabled) {
  box-shadow: var(--shadow-brand-md);
}

.cv-btn--secondary {
  background: var(--surface-raised);
  color: var(--text-primary);
  border-color: var(--border-default);
}
.cv-btn--secondary:hover:not(:disabled) {
  background: var(--interactive-hover);
  border-color: var(--border-strong);
}

.cv-btn--ghost {
  background: transparent;
  color: var(--text-secondary);
  border-color: transparent;
}
.cv-btn--ghost:hover:not(:disabled) {
  background: var(--interactive-hover);
  color: var(--text-primary);
}

.cv-btn--danger {
  background: var(--danger-600);
  color: var(--neutral-0);
  border-color: var(--danger-600);
}
.cv-btn--danger:hover:not(:disabled) { background: var(--danger-700); border-color: var(--danger-700); }

.cv-btn--link {
  background: transparent;
  color: var(--text-link);
  border-color: transparent;
  padding: 0;
  height: auto;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
.cv-btn--link:hover:not(:disabled) { color: var(--text-link-hover); }

/* ══════════════════════════════════════════════════════════════════════════
 * INPUT / SELECT / TEXTAREA
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-1-5);
}
.cv-label {
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--text-secondary);
  letter-spacing: var(--tracking-wide);
}
.cv-input,
.cv-select,
.cv-textarea {
  width: 100%;
  padding: 0 var(--space-3);
  height: var(--touch-target);          /* 44px MOBILE-FIRST */
  background: var(--surface-raised);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  font-family: var(--font-sans);
  font-size: 16px;                      /* iOS: <16 causa auto-zoom no focus */
  color: var(--text-primary);
  transition: border-color var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-fast) var(--ease-out),
              background-color var(--duration-fast) var(--ease-out);
}
.cv-textarea { height: auto; min-height: 120px; padding: var(--space-3); resize: vertical; }
@media (min-width: 1024px) {
  /* Desktop: pode diminuir levemente (mouse não zooma) */
  .cv-input, .cv-select, .cv-textarea { height: 40px; font-size: var(--text-sm); }
  .cv-textarea { height: auto; min-height: 96px; }
}
.cv-input::placeholder, .cv-textarea::placeholder { color: var(--text-quaternary); }
.cv-input:hover, .cv-select:hover, .cv-textarea:hover { border-color: var(--border-strong); }
.cv-input:focus, .cv-select:focus, .cv-textarea:focus {
  outline: none;
  border-color: var(--brand-500);
  box-shadow: var(--focus-ring);
}
.cv-input:disabled, .cv-select:disabled, .cv-textarea:disabled {
  background: var(--surface-sunken);
  color: var(--text-quaternary);
  cursor: not-allowed;
}
.cv-input--error, .cv-select--error, .cv-textarea--error {
  border-color: var(--danger-500);
}
.cv-input--error:focus, .cv-select--error:focus, .cv-textarea--error:focus {
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--danger-500) 25%, transparent);
}

.cv-help  { font-size: var(--text-xs); color: var(--text-tertiary); }
.cv-error { font-size: var(--text-xs); color: var(--danger-600); font-weight: var(--weight-medium); }

/* Select — reset appearance + arrow via SVG background */
.cv-select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: var(--space-8);
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%236b7280' stroke-width='2'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M19 9l-7 7-7-7'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-3) center;
  background-size: 16px;
}

/* Input group — input com ícone à esquerda */
.cv-input-group { position: relative; }
.cv-input-group .cv-input { padding-left: 38px; }
.cv-input-group__icon {
  position: absolute; left: var(--space-3); top: 50%; transform: translateY(-50%);
  color: var(--text-tertiary); pointer-events: none;
  width: 16px; height: 16px;
}

/* Input addon — prefixo joined ao input (moeda, unidade). Diferente de
 * .cv-input-group (ícone flutuante dentro do input): aqui o prefixo é uma
 * célula própria, com sua própria borda, soldada ao input. */
.cv-input-addon-group { display: flex; align-items: stretch; max-width: 200px; }
.cv-input-addon-group__prefix {
  display: flex; align-items: center;
  padding: 0 var(--space-3);
  border: 1px solid var(--border-default); border-right: 0;
  border-radius: var(--radius-md) 0 0 var(--radius-md);
  background: var(--surface-sunken);
  color: var(--text-tertiary);
  font-size: var(--text-sm); font-weight: var(--weight-medium);
}
.cv-input-addon-group .cv-input {
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  text-align: right;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* ══════════════════════════════════════════════════════════════════════════
 * BADGE / CHIP — status/label pequenos
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  height: 20px;
  border-radius: var(--radius-xs);
  font-size: var(--text-2xs);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  line-height: 1;
  background: var(--surface-sunken);
  color: var(--text-secondary);
  border: 1px solid transparent;
}
.cv-badge--brand    { background: var(--brand-100);    color: var(--brand-800); }
.cv-badge--success  { background: var(--success-100);  color: var(--success-700); }
.cv-badge--warning  { background: var(--warning-100);  color: var(--warning-800); }
.cv-badge--danger   { background: var(--danger-100);   color: var(--danger-700); }
.cv-badge--info     { background: var(--info-100);     color: var(--info-700); }
.cv-badge--magenta  { background: var(--accent-magenta-100); color: var(--accent-magenta-800); }
.cv-badge--purple   { background: var(--accent-purple-100);  color: var(--accent-purple-800); }
.cv-badge--gold     { background: var(--accent-gold-100);    color: var(--warning-800); }
.cv-badge--outline  { background: transparent; border-color: var(--border-default); color: var(--text-secondary); }

/* Chip — badge maior, sem uppercase, para tags/filtros */
.cv-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1-5);
  padding: var(--space-1) var(--space-3);
  height: 28px;
  border-radius: var(--radius-full);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  background: var(--surface-sunken);
  color: var(--text-secondary);
  border: 1px solid var(--border-subtle);
  transition: all var(--duration-fast) var(--ease-out);
}
.cv-chip--active { background: var(--interactive-selected); color: var(--brand-700); border-color: var(--brand-500); }
.cv-chip--closable { padding-right: var(--space-1); }
.cv-chip__close { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; border-radius: var(--radius-full); opacity: 0.6; }
.cv-chip__close:hover { opacity: 1; background: color-mix(in oklab, currentColor 15%, transparent); }

/* Status dot (para linhas de tabela, sidebar) */
.cv-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-full);
  background: var(--neutral-400);
  flex-shrink: 0;
}
.cv-dot--brand   { background: var(--brand-500); box-shadow: 0 0 0 3px color-mix(in oklab, var(--brand-500) 20%, transparent); }
.cv-dot--success { background: var(--success-500); }
.cv-dot--warning { background: var(--warning-500); }
.cv-dot--danger  { background: var(--danger-500); }
.cv-dot--muted   { background: var(--neutral-400); }
/* Issue #104 r3: campaign status "finished" per mockup 4's annotated mapping —
   a distinctly darker/blue tone, kept visually apart from "draft" (--muted). */
.cv-dot--info    { background: var(--info-700); }

/* ══════════════════════════════════════════════════════════════════════════
 * CARD — superfícies elevadas
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-card {
  background: var(--surface-raised);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-xl);
  padding: var(--space-6);
  transition: border-color var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-fast) var(--ease-out);
}
.cv-card--hover:hover { border-color: var(--border-strong); box-shadow: var(--shadow-md); }
.cv-card--flat     { box-shadow: none; }
.cv-card--raised   { box-shadow: var(--shadow-sm); }
.cv-card--elevated { box-shadow: var(--shadow-lg); }
.cv-card--brand {
  background: var(--brand-gradient);
  color: var(--text-on-brand);
  border-color: transparent;
}
.cv-card--outline { background: transparent; }
.cv-card--compact { padding: var(--space-4); border-radius: var(--radius-lg); }
/* Accent-left — setting/config cards that need a "this is the active one"
 * marker without the full --brand gradient treatment (e.g. platform-wide
 * settings vs. "em breve" placeholders on the same page). */
.cv-card--accent-brand { border-left: 4px solid var(--brand-500); }
/* Muted — placeholder/disabled-looking cards ("em breve"). Content stays
 * readable (no pointer-events:none — a card can still hold a real, if
 * inert, link/copy) but visually recedes behind active cards. */
.cv-card--muted { opacity: 0.6; }

.cv-card__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--space-4); gap: var(--space-4); }
.cv-card__title  { font-family: var(--font-sans); font-size: var(--text-md); font-weight: var(--weight-semibold); color: var(--text-primary); letter-spacing: -0.01em; }
.cv-card__subtitle { font-size: var(--text-sm); color: var(--text-tertiary); margin-top: 2px; }
.cv-card__actions { display: flex; align-items: center; gap: var(--space-2); }
.cv-card__footer { margin-top: var(--space-4); padding-top: var(--space-4); border-top: 1px solid var(--border-subtle); }

/* ══════════════════════════════════════════════════════════════════════════
 * STAT — números de impacto (KPI, capa de slide, hero de dashboard)
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-stat {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.cv-stat__eyebrow {
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
  color: var(--text-tertiary);
}
.cv-stat__value {
  font-family: var(--font-display);
  font-size: var(--text-6xl);
  font-weight: var(--weight-regular);
  line-height: 0.95;
  letter-spacing: var(--tracking-tighter);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.cv-stat__value--sm { font-size: var(--text-4xl); }
.cv-stat__value--xl { font-size: var(--text-8xl); }
.cv-stat__unit { font-family: var(--font-sans); font-size: 0.4em; color: var(--text-tertiary); font-weight: var(--weight-regular); margin-left: 4px; letter-spacing: 0; }
.cv-stat__delta {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
}
.cv-stat__delta--up   { color: var(--success-600); }
.cv-stat__delta--down { color: var(--danger-600); }
.cv-stat__caption { font-size: var(--text-sm); color: var(--text-tertiary); }

/* ══════════════════════════════════════════════════════════════════════════
 * TABLE — data tables editoriais. MOBILE-FIRST: por padrão a tabela é uma
 * lista de "cards" empilhados (cada tr vira bloco). Em md+ vira grid tabular.
 * Para converter, o markup deve incluir `data-label` em cada <td>:
 *   <td data-label="UF">SP</td>
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}

/* MOBILE — cada tr vira bloco tipo card */
.cv-table thead { display: none; }
.cv-table tr {
  display: block;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border-subtle);
}
.cv-table tr:last-child { border-bottom: 0; }
.cv-table td {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-1) 0;
  border: 0;
}
.cv-table td::before {
  content: attr(data-label);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wider);
  color: var(--text-tertiary);
  flex-shrink: 0;
}
.cv-table td:first-child {
  font-family: var(--font-display);
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
  padding-bottom: var(--space-2);
  margin-bottom: var(--space-2);
  border-bottom: 1px solid var(--border-subtle);
  justify-content: flex-start;
}
.cv-table td:first-child::before { display: none; }

/* Desktop — vira tabela normal a partir de 768px */
@media (min-width: 768px) {
  .cv-table thead { display: table-header-group; }
  .cv-table thead th {
    text-align: left;
    padding: var(--space-3) var(--space-4);
    font-size: var(--text-xs);
    font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-wider);
    text-transform: uppercase;
    color: var(--text-tertiary);
    border-bottom: 1px solid var(--border-subtle);
    background: var(--surface-canvas);
    position: sticky; top: 0;
  }
  .cv-table tr { display: table-row; padding: 0; }
  .cv-table tbody td {
    display: table-cell;
    padding: var(--space-4);
    border-bottom: 1px solid var(--border-subtle);
    vertical-align: middle;
  }
  .cv-table tbody td::before { display: none; }
  .cv-table tbody td:first-child {
    font-family: var(--font-sans);
    font-size: var(--text-sm);
    font-weight: var(--weight-regular);
    padding-bottom: var(--space-4);
    margin-bottom: 0;
    border-bottom: 1px solid var(--border-subtle);
  }
  .cv-table tbody tr { transition: background-color var(--duration-fast) var(--ease-out); }
  .cv-table tbody tr:hover { background: var(--interactive-hover); }
  .cv-table tbody tr:last-child td { border-bottom: 0; }
  .cv-table--compact tbody td, .cv-table--compact thead th { padding: var(--space-2) var(--space-3); }
  .cv-table--striped tbody tr:nth-child(even) { background: color-mix(in oklab, var(--surface-sunken) 40%, transparent); }
  .cv-table__num { text-align: right; font-variant-numeric: tabular-nums; }
}

/* ══════════════════════════════════════════════════════════════════════════
 * TABS
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-tabs {
  display: flex;
  gap: 0;
  border-bottom: 1px solid var(--border-subtle);
}
.cv-tab {
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--text-tertiary);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out);
  cursor: pointer;
  background: transparent;
}
.cv-tab:hover { color: var(--text-primary); }
.cv-tab[aria-selected="true"], .cv-tab.is-active {
  color: var(--text-primary);
  border-bottom-color: var(--brand-500);
}

/* ══════════════════════════════════════════════════════════════════════════
 * AVATAR
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px; height: 32px;
  border-radius: var(--radius-full);
  background: var(--surface-sunken);
  color: var(--text-secondary);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: -0.01em;
  overflow: hidden;
  flex-shrink: 0;
  border: 1px solid var(--border-subtle);
}
.cv-avatar img { width: 100%; height: 100%; object-fit: cover; }
.cv-avatar--xs { width: 20px; height: 20px; font-size: 9px; }
.cv-avatar--sm { width: 24px; height: 24px; font-size: 10px; }
.cv-avatar--lg { width: 40px; height: 40px; font-size: var(--text-sm); }
.cv-avatar--xl { width: 56px; height: 56px; font-size: var(--text-lg); }
.cv-avatar--brand { background: var(--brand-gradient); color: var(--text-on-brand); border-color: transparent; }
.cv-avatar-group { display: inline-flex; }
.cv-avatar-group .cv-avatar + .cv-avatar { margin-left: -8px; box-shadow: 0 0 0 2px var(--surface-canvas); }

/* ══════════════════════════════════════════════════════════════════════════
 * NAVIGATION — sidebar item, breadcrumb
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-nav-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--text-secondary);
  transition: background-color var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out);
  cursor: pointer;
}
.cv-nav-item:hover { background: var(--interactive-hover); color: var(--text-primary); }
.cv-nav-item[aria-current="page"], .cv-nav-item.is-active {
  background: var(--interactive-selected);
  color: var(--brand-700);
  font-weight: var(--weight-semibold);
}
.cv-nav-item__icon { width: 18px; height: 18px; flex-shrink: 0; color: currentColor; opacity: 0.8; }
.cv-nav-item__label { flex: 1; }
.cv-nav-item__badge { margin-left: auto; }

.cv-nav-group {
  display: flex; flex-direction: column; gap: var(--space-1);
  padding: var(--space-2) 0;
}
.cv-nav-group__label {
  padding: var(--space-1) var(--space-3);
  font-size: var(--text-2xs);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
  color: var(--text-quaternary);
}

.cv-breadcrumb {
  display: flex; align-items: center; gap: var(--space-2);
  font-size: var(--text-sm); color: var(--text-tertiary);
}
.cv-breadcrumb__sep { color: var(--text-quaternary); }
.cv-breadcrumb a { color: var(--text-tertiary); }
.cv-breadcrumb a:hover { color: var(--text-primary); }
.cv-breadcrumb__current { color: var(--text-primary); font-weight: var(--weight-medium); }

/* ══════════════════════════════════════════════════════════════════════════
 * APP SHELL — MOBILE-FIRST
 * Mobile (default): topbar + main + bottom-nav (single column).
 * Desktop (>= 1024px): sidebar 260px + topbar + main (bottom-nav some).
 * Sidebar em mobile é um drawer overlay controlado por .cv-drawer.
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-app-shell {
  display: grid;
  /* Issue #94 — `1fr` alone carries an implicit `minmax(auto, 1fr)`: the
     track grows to fit its widest descendant's content (min-content) instead
     of clamping to the viewport. Any unconstrained content ANYWHERE inside
     .cv-main (e.g. a fixed max-width empty-state paragraph, an untruncated
     org name) widened the whole column — and since .cv-topbar/.cv-main/
     .cv-bottom-nav all share this one column, EVERY area reported the same
     inflated width, even ones with no oversized content of their own.
     `minmax(0, 1fr)` is the standard CSS Grid fix: clamps the track to the
     available space so overflow is contained (and clipped via the existing
     `overflow-x: clip` on body/.cv-main) instead of propagating outward. */
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: var(--topbar-h-mobile) 1fr var(--bottom-nav-h);
  grid-template-areas: "topbar" "main" "bottom-nav";
  min-height: 100dvh;   /* dvh evita "pulo" quando barra do browser mobile aparece */
}
.cv-topbar {
  grid-area: topbar;
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-3);
  padding: 0 var(--space-4);
  padding-top: var(--safe-top);
  background: var(--surface-raised);
  border-bottom: 1px solid var(--border-subtle);
  position: sticky; top: 0; z-index: var(--z-sticky);
  /* Fix mobile overflow: sem isso o org-name pill (`white-space: nowrap`
     em `.org-trigger__title`) forçava o topbar a exceder o viewport em
     ~150-280px em iPhone SE/13 Pro/Pixel 7 portrait. `min-width: 0` no
     próprio topbar + no scope-pill-wrapper filho permite que a ellipsis
     truncation do title efetivamente entre em ação. `max-width: 100vw`
     é o cinto-e-suspensório contra qualquer outro nowrap que aparecer. */
  min-width: 0;
  max-width: 100vw;
  overflow: hidden;
}
/* Flex items têm automatic minimum size (min-width: auto): sem `min-width: 0`
   estes filhos diretos do topbar se recusam a encolher abaixo da largura
   intrínseca do conteúdo nowrap, e a ellipsis do title nunca entra em ação.
   `overflow: hidden` faz o clipping do que ainda exceder. */
.cv-topbar > .cv-menu,
.cv-topbar > .scope-pill-wrapper {
  min-width: 0;
  overflow: hidden;
}
.cv-topbar__title {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cv-sidebar {
  /* Mobile: escondida — vira drawer (.cv-drawer) */
  display: none;
  grid-area: sidebar;
  padding: var(--space-4) var(--space-3);
  background: var(--surface-raised);
  border-right: 1px solid var(--border-subtle);
  flex-direction: column; gap: var(--space-2);
  overflow-y: auto;
}
.cv-main {
  grid-area: main;
  padding: var(--space-4);
  padding-bottom: calc(var(--space-4) + var(--safe-bottom));
  overflow-x: clip;
  overflow-y: visible;
}

/* Desktop: sidebar aparece, bottom-nav some, main tem mais respiro */
@media (min-width: 1024px) {
  .cv-app-shell {
    grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
    grid-template-rows: var(--topbar-h-desktop) 1fr;
    grid-template-areas: "sidebar topbar" "sidebar main";
  }
  .cv-topbar { padding: 0 var(--space-6); }
  .cv-sidebar { display: flex; }
  .cv-main { padding: var(--space-8) var(--space-10); padding-bottom: var(--space-8); }
  .cv-app-shell .cv-bottom-nav { display: none; }
  .cv-app-shell .cv-hamburger { display: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
 * HAMBURGER — só visível em mobile, abre drawer
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-hamburger {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--touch-target); height: var(--touch-target);
  border-radius: var(--radius-md);
  color: var(--text-primary);
  background: transparent;
  border: none;
  cursor: pointer;
  flex-shrink: 0;
  -webkit-tap-highlight-color: transparent;
  transition: background-color var(--duration-fast) var(--ease-out);
}
.cv-hamburger:hover, .cv-hamburger:active { background: var(--interactive-hover); }

/* ══════════════════════════════════════════════════════════════════════════
 * BOTTOM NAV — mobile primária. Máx 5 itens. Some em desktop.
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-bottom-nav {
  grid-area: bottom-nav;
  display: flex;
  align-items: stretch;
  background: var(--surface-raised);
  border-top: 1px solid var(--border-subtle);
  padding-bottom: var(--safe-bottom);
  position: sticky; bottom: 0; z-index: var(--z-sticky);
}
.cv-bottom-nav__item {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px;
  min-height: var(--bottom-nav-h);
  padding: var(--space-1) var(--space-1);
  font-family: var(--font-sans);
  font-size: 10px;
  font-weight: var(--weight-medium);
  letter-spacing: 0.02em;
  color: var(--text-tertiary);
  text-decoration: none;
  background: transparent;
  border: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color var(--duration-fast) var(--ease-out);
  position: relative;
}
.cv-bottom-nav__item[aria-current="page"],
.cv-bottom-nav__item.is-active { color: var(--brand-600); }
.cv-bottom-nav__item[aria-current="page"]::before,
.cv-bottom-nav__item.is-active::before {
  content: '';
  position: absolute; top: 0; left: 50%;
  width: 32px; height: 2px;
  background: var(--brand-500);
  border-radius: 0 0 var(--radius-full) var(--radius-full);
  transform: translateX(-50%);
}
.cv-bottom-nav__icon { width: 22px; height: 22px; display: block; }

/* ══════════════════════════════════════════════════════════════════════════
 * DRAWER — sidebar mobile em overlay. Também usado para modais tipo bottom sheet.
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-drawer-backdrop {
  position: fixed; inset: 0;
  background: color-mix(in oklab, var(--neutral-950) 45%, transparent);
  backdrop-filter: blur(2px);
  z-index: var(--z-overlay);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--duration-base) var(--ease-out);
}
.cv-drawer-backdrop[data-open="true"] {
  opacity: 1;
  pointer-events: auto;
}
.cv-drawer {
  position: fixed; top: 0; bottom: 0; left: 0;
  width: min(85vw, 320px);
  background: var(--surface-raised);
  border-right: 1px solid var(--border-subtle);
  z-index: calc(var(--z-overlay) + 1);
  transform: translateX(-100%);
  transition: transform var(--duration-slow) var(--ease-out);
  display: flex; flex-direction: column;
  padding-top: var(--safe-top);
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
.cv-drawer[data-open="true"] { transform: translateX(0); }
.cv-drawer--right {
  left: auto; right: 0;
  border-right: none;
  border-left: 1px solid var(--border-subtle);
  transform: translateX(100%);
}
.cv-drawer--right[data-open="true"] { transform: translateX(0); }

/* Bottom sheet — variante drawer que sobe do rodapé em mobile */
.cv-sheet {
  position: fixed; left: 0; right: 0; bottom: 0;
  max-height: 90dvh;
  background: var(--surface-overlay);
  border-radius: var(--radius-2xl) var(--radius-2xl) 0 0;
  z-index: calc(var(--z-overlay) + 1);
  transform: translateY(100%);
  transition: transform var(--duration-slow) var(--ease-out);
  display: flex; flex-direction: column;
  padding-bottom: var(--safe-bottom);
  overflow: hidden;
  box-shadow: var(--shadow-2xl);
}
.cv-sheet[data-open="true"] { transform: translateY(0); }
.cv-sheet__handle {
  align-self: center;
  width: 40px; height: 4px;
  background: var(--border-strong);
  border-radius: var(--radius-full);
  margin: var(--space-2) 0 var(--space-1);
  flex-shrink: 0;
}
.cv-sheet__body { flex: 1; overflow-y: auto; padding: var(--space-4); }
.cv-sheet__footer { padding: var(--space-3) var(--space-4); border-top: 1px solid var(--border-subtle); display: flex; gap: var(--space-2); }

/* ═══════════════════════════════════════════════════════════════════════════
 * ACTION SHEET — variante especializada de .cv-sheet para lista de ações
 * disparadas por tap num card/row no mobile. Substitui row-action button clusters
 * (Editar/Copiar/Remover) que ficam apertados no mobile. Estrutura:
 *
 *   <div class="cv-sheet cv-action-sheet" data-open="true">
 *     <div class="cv-sheet__handle"></div>
 *     <header class="cv-action-sheet__header"> ... contexto (avatar + nome + meta) ... </header>
 *     <nav class="cv-action-sheet__list">
 *       <button class="cv-action-sheet__item cv-action-sheet__item--primary">
 *         <svg class="cv-action-sheet__icon">…</svg> Editar
 *       </button>
 *       <button class="cv-action-sheet__item">…</button>
 *       <button class="cv-action-sheet__item cv-action-sheet__item--danger">…</button>
 *     </nav>
 *     <footer class="cv-sheet__footer">
 *       <button class="cv-btn cv-btn--secondary cv-btn--block">Cancelar</button>
 *     </footer>
 *   </div>
 *
 * Regras:
 * - Primeiro item (ação mais comum) leva `--primary` — background teal tint + border-left brand.
 * - Ação destrutiva (Remover/Excluir) leva `--danger` — cor vermelha + hairline no topo.
 * - Mínimo 48px por item (thumb target > 44px baseline).
 * ═══════════════════════════════════════════════════════════════════════════ */
.cv-action-sheet__header {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border-subtle);
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-shrink: 0;
}
.cv-action-sheet__list {
  display: flex;
  flex-direction: column;
  padding: var(--space-1) 0;
  overflow-y: auto;
}
.cv-action-sheet__item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  min-height: 48px;
  color: var(--text-primary);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  font-family: inherit;
  background: transparent;
  border: none;
  border-left: 3px solid transparent;
  text-align: left;
  cursor: pointer;
  width: 100%;
}
.cv-action-sheet__item:hover:not(:disabled) { background: var(--interactive-hover, var(--surface-subtle)); }
.cv-action-sheet__item:disabled { opacity: 0.5; cursor: not-allowed; }
.cv-action-sheet__icon {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  color: var(--brand-600);
}
.cv-action-sheet__item--primary {
  background: color-mix(in srgb, var(--brand-500) 8%, transparent);
  border-left-color: var(--brand-500);
  color: var(--brand-700);
  font-weight: var(--weight-semibold);
}
.cv-action-sheet__item--primary:hover:not(:disabled) {
  background: color-mix(in srgb, var(--brand-500) 14%, transparent);
}
.cv-action-sheet__item--danger {
  color: var(--danger-700, var(--danger-600));
  border-top: 1px solid var(--border-subtle);
  margin-top: var(--space-1);
}
.cv-action-sheet__item--danger .cv-action-sheet__icon { color: currentColor; }
.cv-action-sheet__item--danger:hover:not(:disabled) {
  background: color-mix(in srgb, var(--danger-500) 8%, transparent);
}

/* Brand mark (usar no sidebar topo). Padrão: passar <img src="…/assets/logo.png">
   como filho. Placeholder textual (letra "C" etc.) segue funcionando via
   `.cv-brand__mark--placeholder`. */
.cv-brand {
  display: inline-flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2);
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: var(--weight-regular);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
}
.cv-brand__mark {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px;
  border-radius: var(--radius-md);
  overflow: hidden;
  flex-shrink: 0;
}
.cv-brand__mark img,
.cv-brand__mark svg {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
/* Placeholder textual — usar SÓ quando não há logo (ex.: docs/dev) */
.cv-brand__mark--placeholder {
  background: var(--brand-gradient);
  color: var(--text-on-brand);
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: var(--weight-regular);
}

/* ══════════════════════════════════════════════════════════════════════════
 * PAGE HEADER — MOBILE-FIRST: título empilhado sobre ações; desktop em linha.
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-page-header {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-bottom: var(--space-6);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--border-subtle);
}
.cv-page-header__title h1 {
  font-size: var(--text-3xl);
  letter-spacing: var(--tracking-tight);
  line-height: 1.05;
  margin-top: var(--space-1);
}
.cv-page-header__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

@media (min-width: 768px) {
  .cv-page-header {
    flex-direction: row;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--space-6);
    margin-bottom: var(--space-8);
    padding-bottom: var(--space-6);
  }
  .cv-page-header__title h1 {
    font-size: var(--text-5xl);
    letter-spacing: var(--tracking-tighter);
    line-height: 1;
    margin-top: var(--space-2);
  }
  .cv-page-header__actions { flex-wrap: nowrap; }
}

/* ══════════════════════════════════════════════════════════════════════════
 * MODAL / DIALOG — MOBILE-FIRST: em mobile vira bottom-sheet full-width
 * ancorado no rodapé (mais fácil de alcançar com polegar). Em md+ centraliza.
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-modal-backdrop {
  position: fixed; inset: 0;
  background: color-mix(in oklab, var(--neutral-950) 55%, transparent);
  backdrop-filter: blur(4px);
  z-index: var(--z-overlay);
  display: flex;
  align-items: flex-end;              /* mobile: colado no rodapé */
  justify-content: center;
  padding: 0;
}
.cv-modal {
  background: var(--surface-overlay);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-2xl) var(--radius-2xl) 0 0;   /* só topo em mobile */
  box-shadow: var(--shadow-2xl);
  width: 100%;
  max-height: 90dvh;
  padding-bottom: var(--safe-bottom);
  overflow: hidden;
  display: flex; flex-direction: column;
}
.cv-modal--lg, .cv-modal--xl {
  /* em mobile ignora largura fixa e ocupa 100% */
  max-width: none;
}
.cv-modal__header {
  padding: var(--space-4) var(--space-4);
  border-bottom: 1px solid var(--border-subtle);
  display: flex; align-items: center; justify-content: space-between;
}
.cv-modal__title { font-family: var(--font-display); font-size: var(--text-xl); letter-spacing: var(--tracking-tight); }
.cv-modal__body { padding: var(--space-4); overflow-y: auto; }
.cv-modal__footer {
  padding: var(--space-3) var(--space-4);
  border-top: 1px solid var(--border-subtle);
  display: flex; align-items: center; justify-content: flex-end;
  gap: var(--space-2);
  background: var(--surface-canvas);
}
.cv-modal__footer .cv-btn { flex: 1; }  /* mobile: botões ocupam largura toda */

@media (min-width: 768px) {
  .cv-modal-backdrop { align-items: center; padding: var(--space-6); }
  .cv-modal {
    border-radius: var(--radius-2xl);
    max-width: 560px;
    max-height: 85vh;
    padding-bottom: 0;
  }
  .cv-modal--lg { max-width: 800px; }
  .cv-modal--xl { max-width: 1000px; }
  .cv-modal__header, .cv-modal__body { padding: var(--space-6); }
  .cv-modal__footer { padding: var(--space-4) var(--space-6); }
  .cv-modal__footer .cv-btn { flex: 0 0 auto; }
  .cv-modal__title { font-size: var(--text-2xl); }
}

/* ══════════════════════════════════════════════════════════════════════════
 * CALLOUT / ALERT
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-callout {
  display: flex;
  gap: var(--space-3);
  padding: var(--space-4);
  border-radius: var(--radius-lg);
  background: var(--surface-sunken);
  border-left: 3px solid var(--border-strong);
  font-size: var(--text-sm);
  color: var(--text-secondary);
}
.cv-callout__title { font-weight: var(--weight-semibold); color: var(--text-primary); margin-bottom: 2px; }
.cv-callout__icon { flex-shrink: 0; width: 18px; height: 18px; margin-top: 2px; color: var(--text-tertiary); }
.cv-callout--info    { background: var(--info-50);    border-left-color: var(--info-500);    color: var(--info-700); }
.cv-callout--info .cv-callout__icon { color: var(--info-600); }
.cv-callout--info .cv-callout__title { color: var(--info-700); }
.cv-callout--success { background: var(--success-50); border-left-color: var(--success-500); color: var(--success-700); }
.cv-callout--success .cv-callout__icon, .cv-callout--success .cv-callout__title { color: var(--success-700); }
.cv-callout--warning { background: var(--warning-50); border-left-color: var(--warning-500); color: var(--warning-800); }
.cv-callout--warning .cv-callout__icon, .cv-callout--warning .cv-callout__title { color: var(--warning-800); }
.cv-callout--danger  { background: var(--danger-50);  border-left-color: var(--danger-500);  color: var(--danger-700); }
.cv-callout--danger .cv-callout__icon, .cv-callout--danger .cv-callout__title { color: var(--danger-700); }

/* ══════════════════════════════════════════════════════════════════════════
 * TOAST — confirmação transiente pós-ação (salvar, remover...). MOBILE-FIRST:
 * full-width acima da safe-area em mobile; vira card ancorado ao canto em
 * desktop. Não é modal — não bloqueia interação, some sozinho.
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-toast-region {
  position: fixed;
  left: var(--space-4);
  right: var(--space-4);
  bottom: calc(var(--space-4) + env(safe-area-inset-bottom));
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  pointer-events: none;
}
@media (min-width: 768px) {
  .cv-toast-region { left: auto; right: var(--space-6); bottom: var(--space-6); width: 360px; }
}
.cv-toast {
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-lg);
  background: var(--surface-raised);
  border: 1px solid var(--border-default);
  border-left: 3px solid var(--border-strong);
  box-shadow: var(--shadow-lg);
  font-size: var(--text-sm);
  color: var(--text-primary);
}
.cv-toast--success { border-left-color: var(--success-500); }
.cv-toast--danger  { border-left-color: var(--danger-500); }
.cv-toast__icon { flex-shrink: 0; width: 18px; height: 18px; margin-top: 1px; }
.cv-toast--success .cv-toast__icon { color: var(--success-600); }
.cv-toast--danger  .cv-toast__icon { color: var(--danger-600); }

/* Vue <TransitionGroup name="cv-toast"> hook classes */
.cv-toast-enter-active, .cv-toast-leave-active {
  transition: opacity var(--duration-fast) var(--ease-out), transform var(--duration-fast) var(--ease-out);
}
.cv-toast-enter-from, .cv-toast-leave-to { opacity: 0; transform: translateY(8px); }

/* ══════════════════════════════════════════════════════════════════════════
 * EMPTY STATE — quando não há dados. Editorial, não "genérico ilustração 3D"
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-empty {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  padding: var(--space-16) var(--space-6);
  gap: var(--space-3);
  color: var(--text-tertiary);
}
.cv-empty__title { font-family: var(--font-display); font-size: var(--text-3xl); color: var(--text-primary); font-weight: var(--weight-regular); letter-spacing: var(--tracking-tight); }
.cv-empty__body  { max-width: 42ch; font-size: var(--text-sm); }
.cv-empty__actions { margin-top: var(--space-4); display: flex; gap: var(--space-2); }

/* ══════════════════════════════════════════════════════════════════════════
 * SKELETON — loading state
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-skeleton {
  display: block;
  background: linear-gradient(90deg, var(--surface-sunken) 25%, var(--interactive-hover) 50%, var(--surface-sunken) 75%);
  background-size: 200% 100%;
  animation: cv-shimmer 1.4s var(--ease-in-out) infinite;
  border-radius: var(--radius-sm);
  height: 12px;
}
@keyframes cv-shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* ══════════════════════════════════════════════════════════════════════════
 * KBD — atalho de teclado
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-kbd {
  display: inline-flex; align-items: center;
  padding: 2px 6px;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: var(--weight-medium);
  color: var(--text-secondary);
  background: var(--surface-raised);
  border: 1px solid var(--border-default);
  border-bottom-width: 2px;
  border-radius: var(--radius-sm);
  line-height: 1;
}

/* ══════════════════════════════════════════════════════════════════════════
 * DIVIDER com label (editorial "OU" — usar login/onboarding)
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-divider {
  display: flex; align-items: center; gap: var(--space-3);
  color: var(--text-tertiary);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
}
.cv-divider::before, .cv-divider::after {
  content: ""; flex: 1; height: 1px; background: var(--border-subtle);
}

/* ══════════════════════════════════════════════════════════════════════════
 * STAGE — utilitários para modo Apresentação (slides). Assume desktop/telão.
 * Em mobile ainda funciona (padding reduzido) mas não é o caso primário.
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-slide {
  min-height: 100dvh;
  padding: var(--space-8) var(--space-4);
  display: flex; flex-direction: column;
  gap: var(--space-6);
}
@media (min-width: 768px) {
  .cv-slide { padding: var(--space-12) var(--space-10); gap: var(--space-8); }
}
@media (min-width: 1280px) {
  .cv-slide { padding: var(--space-16) var(--space-20); }
}
.cv-slide__eyebrow {
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
  color: var(--brand-300);
  font-weight: var(--weight-semibold);
  /* HARD RULE (Luke 2026-08-14): título de slide sempre centralizado horizontalmente.
     Aplica no eyebrow também pra manter o par visual coeso. */
  text-align: center;
}
.cv-slide__title {
  font-family: var(--font-display);
  /* Carousel stage: cap at --text-4xl (36px) so the title never exceeds
     ~10% of slide height at 1600×900. The original hero clamp (up to 96px)
     was designed for full-page standalone slides, not embedded carousel
     slots — bug A (title takes ~25% of screen). */
  font-size: var(--text-4xl);
  line-height: 0.95;
  letter-spacing: var(--tracking-tighter);
  text-wrap: balance;
  /* .cv-slide surfaces are always dark (--brand-950), regardless of the
     page's data-theme — unlike __subtitle (--brand-300, theme-independent)
     and __date (--text-tertiary), __title had no explicit color and fell
     back to the global h1{color:var(--text-primary)} rule in base.css,
     which is near-black under data-theme="app" (#23). */
  color: var(--text-on-brand);
  /* HARD RULE (Luke 2026-08-14): título centralizado + v-align top. Alguns
     slides ainda vertical-centralizavam o conteúdo (justify-content: center
     no __inner) — override por slide em cima, mas o texto do título fica
     sempre center. */
  text-align: center;
}
.cv-slide__title em { font-style: italic; }

/* Subtítulo italic serif — usado sob .cv-slide__title (padrão capa PDF cliente). */
.cv-slide__subtitle {
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(var(--text-xl), 3vw, var(--text-3xl));
  line-height: 1.2;
  color: var(--brand-300);
  margin-top: var(--space-2);
  text-wrap: balance;
}

/* Data / meta caption em capas de slide. */
.cv-slide__date {
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  color: var(--text-tertiary);
  letter-spacing: 0.02em;
  margin-top: var(--space-4);
}

/* Footer discreto co-brand — obrigatório em cada slide (regra R6 do brief cliente). */
.cv-slide__footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-family: var(--font-sans);
  font-size: var(--text-2xs);
  color: var(--text-tertiary);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding-top: var(--space-3);
  border-top: 1px solid var(--border-subtle);
  margin-top: auto;
}

/* Logo do cliente (configurável por org, aparece em capa e em preview branding).
   Aspect-ratio livre, contido (não deformado), com drop-shadow discreto. */
.cv-client-logo {
  display: flex;
  align-items: center;
  justify-content: center;
  max-width: min(70vw, 520px);
  max-height: 40vh;
}
.cv-client-logo img,
.cv-client-logo svg {
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: drop-shadow(var(--shadow-md));
}
/* Placeholder quando org ainda não subiu logo — mostra nome da org em serif. */
.cv-client-logo--placeholder {
  padding: var(--space-6) var(--space-8);
  border: 2px dashed var(--border-subtle);
  border-radius: var(--radius-lg);
  text-align: center;
  color: var(--text-tertiary);
  font-size: var(--text-sm);
  max-width: 320px;
  aspect-ratio: unset;
}
.cv-client-logo--placeholder strong {
  display: block;
  font-size: var(--text-lg);
  color: var(--text-primary);
  margin-bottom: var(--space-1);
  font-family: var(--font-display);
}

/* Grid assimétrico — MOBILE-FIRST empilhado; assimetria só em md+ */
.cv-asymm {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-6);
}
@media (min-width: 768px) {
  .cv-asymm { grid-template-columns: 5fr 7fr; gap: var(--space-12); }
  .cv-asymm--reverse { grid-template-columns: 7fr 5fr; }
}

/* ══════════════════════════════════════════════════════════════════════════
 * GRID responsivo genérico — usar em vez de custom grids ad-hoc.
 * MOBILE: 1 col; md+: auto-fit conforme min tamanho.
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-grid { display: grid; grid-template-columns: 1fr; gap: var(--space-4); }
.cv-grid--sm  { grid-template-columns: repeat(auto-fill, minmax(min(100%, 220px), 1fr)); }
.cv-grid--md  { grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr)); }
.cv-grid--lg  { grid-template-columns: repeat(auto-fill, minmax(min(100%, 380px), 1fr)); }
.cv-grid--xl  { grid-template-columns: repeat(auto-fill, minmax(min(100%, 460px), 1fr)); }

/* Stat row — mobile 2 cols, md+ 4 cols */
.cv-stat-row {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-3);
}
@media (min-width: 768px) {
  .cv-stat-row { grid-template-columns: repeat(4, 1fr); gap: var(--space-4); }
}

/* Utility: só em mobile / só em desktop (accessible - display none is ok pra UX chunks).
   `!important` porque são utilities e precisam vencer especificidade de qualquer componente
   com regra `display: ...` (ex: .cv-menu { display: inline-block }). */
.cv-only-mobile  { display: initial !important; }
.cv-only-desktop { display: none !important; }
@media (min-width: 1024px) {
  .cv-only-mobile  { display: none !important; }
  .cv-only-desktop { display: initial !important; }
}

/* Utility "hairline" — border 1px que respeita tema */
.cv-hairline { border: 1px solid var(--border-subtle); }
.cv-hairline-t { border-top: 1px solid var(--border-subtle); }
.cv-hairline-b { border-bottom: 1px solid var(--border-subtle); }

/* ══════════════════════════════════════════════════════════════════════════
 * MENU / DROPDOWN / LISTBOX — `.cv-menu`
 *
 * Menu flutuante padronizado. Trigger (botão/avatar) + panel com options.
 * MOBILE-FIRST: em mobile o panel colapsa em bottom sheet (mesma mecânica
 * de `.cv-sheet`). Desktop @768px+: panel vira card flutuante ancorado ao
 * trigger.
 *
 * ARIA: trigger com aria-expanded + aria-haspopup="menu"; panel role=menu
 * (ou role=listbox se seleção mutually-exclusive); items role=menuitem
 * (ou role=option com aria-selected). Focus trap enquanto data-open="true".
 *
 * Search server-side opcional: adicionar modifier `.cv-menu--searchable`.
 * O input `.cv-menu__search-input` emite `input` events; o parent debounce
 * (~250ms) e faz fetch async. Enquanto carrega: `data-loading="true"` no
 * panel mostra skeleton overlay. Zero resultados: renderizar
 * `.cv-menu__state--empty` no lugar dos items.
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-menu { position: relative; display: inline-block; }

/* Trigger — pode ser qualquer botão; a classe só normaliza cursor + focus */
.cv-menu__trigger {
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.cv-menu__trigger[aria-expanded="true"] { background: var(--interactive-selected); }

/* PANEL — MOBILE: bottom sheet
   Reusa transform + shadow do cv-sheet mas com id próprio pra não conflitar. */
.cv-menu__panel {
  position: fixed; left: 0; right: 0; bottom: 0;
  max-height: 85dvh;
  background: var(--surface-overlay);
  border-radius: var(--radius-2xl) var(--radius-2xl) 0 0;
  z-index: calc(var(--z-overlay) + 1);
  transform: translateY(100%);
  transition: transform var(--duration-slow) var(--ease-out);
  display: flex; flex-direction: column;
  padding-bottom: var(--safe-bottom);
  overflow: hidden;
  box-shadow: var(--shadow-2xl);
  visibility: hidden;
}
.cv-menu__panel[data-open="true"] {
  transform: translateY(0);
  visibility: visible;
}

/* Handle "puxador" no topo do sheet mobile — só visível em mobile */
.cv-menu__handle {
  align-self: center;
  width: 40px; height: 4px;
  background: var(--border-strong);
  border-radius: var(--radius-full);
  margin: var(--space-2) 0 var(--space-1);
  flex-shrink: 0;
}

/* Search — opcional, ativado pelo modifier .cv-menu--searchable */
.cv-menu__search {
  position: relative;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border-subtle);
  flex-shrink: 0;
}
.cv-menu__search-icon {
  position: absolute; left: calc(var(--space-4) + var(--space-3));
  top: 50%; transform: translateY(-50%);
  width: 16px; height: 16px;
  color: var(--text-tertiary);
  pointer-events: none;
}
.cv-menu__search-input {
  width: 100%;
  height: var(--touch-target);
  padding: 0 var(--space-3) 0 calc(var(--space-3) + 16px + var(--space-2));
  font-size: var(--text-sm);
  font-family: var(--font-sans);
  color: var(--text-primary);
  background: var(--surface-sunken);
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  outline: none;
  -webkit-appearance: none;
  appearance: none;
}
.cv-menu__search-input:focus {
  border-color: var(--brand-500);
  background: var(--surface-overlay);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--brand-500) 15%, transparent);
}
.cv-menu__search-input::-webkit-search-cancel-button { display: none; }

/* Label de seção — opcional, aparece acima de um grupo de items */
.cv-menu__label {
  padding: var(--space-3) var(--space-4) var(--space-1);
  font-family: var(--font-sans);
  font-size: var(--text-2xs);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
  color: var(--text-tertiary);
  flex-shrink: 0;
}

/* Lista dos items — scrollável se estourar */
.cv-menu__list {
  list-style: none;
  padding: var(--space-1);
  margin: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  flex: 1;
  position: relative;
}

/* Item — botão full-width em grid 3-col: icon | label | badge/check.
   Grid garante que badge e label nunca disputem espaço na mesma coluna. */
.cv-menu__item {
  display: grid;
  grid-template-columns: 28px 1fr auto;
  column-gap: var(--space-3);
  align-items: center;
  width: 100%;
  min-height: var(--touch-target);
  padding: var(--space-2) var(--space-3);
  background: transparent;
  border: 0;
  border-radius: var(--radius-md);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  color: var(--text-primary);
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background-color var(--duration-fast) var(--ease-out);
}
.cv-menu__item:hover:not(:disabled) { background: var(--interactive-hover); }
.cv-menu__item:active:not(:disabled) { background: var(--interactive-pressed); }
.cv-menu__item[aria-selected="true"],
.cv-menu__item[aria-current="true"] {
  background: var(--interactive-selected);
  font-weight: var(--weight-semibold);
}
.cv-menu__item:disabled,
.cv-menu__item[aria-disabled="true"] {
  opacity: 0.4; cursor: not-allowed; pointer-events: none;
}
.cv-menu__item:focus-visible {
  outline: 2px solid var(--brand-500);
  outline-offset: -2px;
}

.cv-menu__item-icon {
  width: 28px; height: 28px;
  border-radius: var(--radius-sm);
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-display);
  font-size: 13px; font-weight: var(--weight-semibold);
  color: var(--text-on-brand);
  flex-shrink: 0;
  background: var(--surface-sunken); /* default; override inline pra cores por-item */
  overflow: hidden;
}
.cv-menu__item-icon svg { width: 16px; height: 16px; color: var(--text-secondary); }
.cv-menu__item-label {
  /* Grid column 2 (1fr) — no flex: 1 needed */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cv-menu__item-caption {
  display: block;
  font-size: var(--text-xs);
  color: var(--text-tertiary);
  font-weight: var(--weight-regular);
  margin-top: 2px;
}
.cv-menu__item-check {
  width: 16px; height: 16px;
  color: var(--brand-600);
  flex-shrink: 0;
}
.cv-menu__item-badge {
  font-size: var(--text-2xs);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 3px var(--space-2);
  border-radius: var(--radius-full);
  background: var(--brand-gradient);
  color: var(--text-on-brand);
  font-weight: var(--weight-semibold);
  flex-shrink: 0;
}

/* Item variante "escape-scope" — separado + destacado (ex: super_admin cross-org) */
.cv-menu__item--emphasis {
  color: var(--text-secondary);
  font-style: italic;
}
.cv-menu__item--emphasis .cv-menu__item-icon {
  background: var(--surface-canvas);
  border: 1px dashed var(--border-default);
}

/* Separator */
.cv-menu__separator {
  height: 1px;
  background: var(--border-subtle);
  margin: var(--space-1) var(--space-2);
  border: 0;
  flex-shrink: 0;
}

/* Footer opcional — CTAs (ex: "+ Adicionar organização") */
.cv-menu__footer {
  padding: var(--space-2) var(--space-3);
  border-top: 1px solid var(--border-subtle);
  flex-shrink: 0;
  background: var(--surface-canvas);
}

/* States: loading (overlay skeleton) + empty (mensagem inline) */
.cv-menu__state {
  padding: var(--space-6) var(--space-4);
  text-align: center;
  color: var(--text-tertiary);
  font-size: var(--text-sm);
}
.cv-menu__state--empty { font-style: italic; }
.cv-menu__panel[data-loading="true"] .cv-menu__list > * { opacity: 0.4; pointer-events: none; }
.cv-menu__panel[data-loading="true"] .cv-menu__list::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(90deg,
    color-mix(in oklab, var(--surface-overlay) 60%, transparent) 25%,
    color-mix(in oklab, var(--interactive-hover) 60%, transparent) 50%,
    color-mix(in oklab, var(--surface-overlay) 60%, transparent) 75%);
  background-size: 200% 100%;
  animation: cv-shimmer 1.4s var(--ease-in-out) infinite;
  border-radius: var(--radius-md);
  pointer-events: none;
}

/* Backdrop opcional (dim + click-to-close). Uso: montar irmão do panel. */
.cv-menu-backdrop {
  position: fixed; inset: 0;
  background: color-mix(in oklab, var(--neutral-950) 45%, transparent);
  backdrop-filter: blur(2px);
  z-index: var(--z-overlay);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--duration-base) var(--ease-out);
}
.cv-menu-backdrop[data-open="true"] {
  opacity: 1;
  pointer-events: auto;
}

/* Desktop @768px+ — panel vira floating card ancorado ao trigger.
   position: fixed escapa o overflow-y: auto da .cv-sidebar (que causava
   clipping). top/left são calculados via getBoundingClientRect() no
   OrganizationSwitcher.vue e injetados como inline style. */
@media (min-width: 768px) {
  .cv-menu__panel {
    position: fixed;
    top: 0;      /* fallback; sobreescrito por inline style via JS */
    left: 0;     /* fallback; sobreescrito por inline style via JS */
    right: auto; bottom: auto;
    width: 280px;
    max-height: 420px;
    transform: none;
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    z-index: var(--z-dropdown);
    padding-bottom: 0;
  }
  .cv-menu--wide .cv-menu__panel { width: 360px; }
  .cv-menu__handle { display: none; }
  /* Backdrop de menu não aparece em desktop; click-outside via JS resolve */
  .cv-menu-backdrop { display: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
 * SWITCH / TOGGLE — `.cv-switch`
 *
 * Toggle acessível pra settings (radar auto_enabled, alerts on/off).
 * Estrutura: <label class="cv-switch"><input type="checkbox">
 *   <span class="cv-switch__track"><span class="cv-switch__thumb"/></span>
 *   <span class="cv-switch__label">Texto</span></label>
 *
 * ARIA: usa <input type="checkbox"> nativo (screen readers reconhecem
 * out-of-the-box). Touch target 44px garantido via padding do label.
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-switch {
  display: inline-flex; align-items: center; gap: var(--space-3);
  min-height: var(--touch-target);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
}
.cv-switch__input {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.cv-switch__track {
  position: relative;
  width: 44px; height: 24px;
  background: var(--border-strong);
  border-radius: 999px;
  transition: background-color var(--duration-fast) var(--ease-out);
  flex-shrink: 0;
}
.cv-switch__thumb {
  position: absolute;
  top: 2px; left: 2px;
  width: 20px; height: 20px;
  background: var(--surface-overlay);
  border-radius: 999px;
  box-shadow: var(--shadow-sm);
  transition: transform var(--duration-base) var(--ease-out);
}
.cv-switch__input:checked + .cv-switch__track {
  background: var(--brand-500);
}
.cv-switch__input:checked + .cv-switch__track .cv-switch__thumb {
  transform: translateX(20px);
}
.cv-switch__input:focus-visible + .cv-switch__track {
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--brand-500) 30%, transparent);
}
.cv-switch__input:disabled + .cv-switch__track {
  opacity: 0.4; cursor: not-allowed;
}
.cv-switch__label {
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  color: var(--text-primary);
  line-height: 1.4;
}
.cv-switch__label small {
  display: block;
  font-size: var(--text-xs);
  color: var(--text-tertiary);
  margin-top: 2px;
}

/* ══════════════════════════════════════════════════════════════════════════
 * CHART wrapper — `.cv-chart`
 *
 * Container responsivo pra Chart.js. Preserva aspect-ratio + tem min-height
 * mobile pra evitar squish. Chart.js é instanciado em <canvas> child via
 * client-side (Vue component `<CvChart type="donut">`).
 *
 * MOBILE-FIRST: min-height fixa garante legibilidade em telas pequenas.
 * ══════════════════════════════════════════════════════════════════════════ */
.cv-chart {
  position: relative;
  width: 100%;
  min-height: 200px;
  padding: var(--space-3);
  background: var(--surface-overlay);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  display: flex; flex-direction: column;
  gap: var(--space-2);
}
.cv-chart__title {
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-2);
}
.cv-chart__caption {
  font-size: var(--text-xs);
  color: var(--text-tertiary);
}
.cv-chart__canvas {
  width: 100% !important;   /* Chart.js seta inline styles; forçar responsividade */
  height: auto !important;
  display: block;
}
.cv-chart__legend {
  display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-3);
  font-size: var(--text-xs);
  color: var(--text-secondary);
  margin-top: var(--space-2);
}
.cv-chart__legend-dot {
  display: inline-block;
  width: 8px; height: 8px;
  border-radius: 999px;
  margin-right: var(--space-1);
  vertical-align: middle;
}

/* Aspect-ratio variants — usa aspect-ratio moderno (95%+ browsers) */
.cv-chart--donut { aspect-ratio: 1 / 1; }
.cv-chart--bar   { aspect-ratio: 16 / 10; }
.cv-chart--spark { aspect-ratio: 4 / 1; min-height: 60px; padding: var(--space-2); border: 0; }

@media (min-width: 768px) {
  .cv-chart { min-height: 260px; padding: var(--space-4); }
  .cv-chart--spark { min-height: 60px; padding: var(--space-2); }
}

/* Ex-hotfix Ricardo demo 2026-08-10 removido: causava divergência windowed
 * vs fullscreen (min-height:788px + aspect-ratio:auto + justify-content:center
 * no bottombar sem width:100% no nav). Substituído pela pipeline única
 * transform:scale no CarouselShell (Luke DRY 2026-08-13). */
