/* ═══════════════════════════════════════════════════════════════════════════
   Conector Ame — Estúdio Ame
   Design system do mockup estático. CSS puro, sem framework, sem build.
   Fonte da verdade: docs/ARQUITETURA.md §7 (7.1 direção, 7.2 tokens,
   7.3 branding, 7.4 componentes, 7.5 acessibilidade, 7.6 motion, 7.7 anti-padrões).

   Direção: Papel & Tinta. Canvas creme, folha branca, profundidade por hairline
   e não por sombra. A cor de ação é tinta. O accent é escasso e significa algo.

   Este arquivo é a ÚNICA folha de estilo do mockup. Nenhuma página redefine token.
   Abre em file:// — zero requisição externa, fonte = stack de sistema.

   ── ESTRATÉGIA DE BREAKPOINT: MOBILE-FIRST DE VERDADE ──────────────────────
   Tudo que está FORA de media query é o CELULAR. Projetado para 360px, testado
   em 390px. O que é maior entra por `min-width` e só adiciona:

     base            360px+   uma coluna, shell empilhado, ritmo curto
     sm   ≥  640px            celular grande / retrato pequeno
     md   ≥  900px            tablet — o PRIMEIRO layout de duas colunas
     lg   ≥ 1200px            desktop, layout completo
     xl   ≥ 1600px            desktop largo, a quinta coluna do inbox

   `max-width` é PROIBIDO neste arquivo (exceto `@media print`): resolver
   responsividade sobrescrevendo desktop é desktop-first disfarçado, e produz
   exatamente o mobile-espremido que o produto não pode ter. Se você precisa de
   `max-width` para consertar o celular, o defeito está na regra base.

   Armadilhas de celular já resolvidas aqui, e que nenhuma página precisa
   reimplementar:
     · `100dvh` com `100vh` de fallback — a barra do Safari mente sobre `vh`
     · `env(safe-area-inset-*)` em tudo que encosta na borda (mockbar, composer,
       toast, rodapé de painel)
     · controle de formulário ≥16px sob ponteiro grosso — abaixo disso o Safari
       dá zoom ao focar e a tela nunca mais volta
     · alvo de toque ≥44×44 por área invisível (`::after`), sem inflar a densidade
     · `:hover` sempre dentro de `@media (hover: hover)`; NADA existe só no hover
     · o `<body>` nunca rola na horizontal — conteúdo largo rola em si mesmo
   ═══════════════════════════════════════════════════════════════════════════ */


/* ═══ 0 · RESET ═════════════════════════════════════════════════════════════ */

*, *::before, *::after { box-sizing: border-box; }

html, body, div, span, h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, code, em, img, small, strong, sub, sup, b, i, ol, ul, li, fieldset,
form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, figure, figcaption, footer, header, main, nav, section, time {
  margin: 0;
  padding: 0;
  border: 0;
  font: inherit;
  vertical-align: baseline;
}

ol, ul { list-style: none; }
table { border-collapse: collapse; border-spacing: 0; }
img, svg, video, canvas { display: block; max-width: 100%; }
button, input, select, textarea { font: inherit; color: inherit; background: none; border: 0; }
button { cursor: pointer; }
a { color: inherit; text-decoration: none; }
[hidden] { display: none !important; }


/* ═══ 1 · TOKENS · TEMA CLARO ═══════════════════════════════════════════════ */

:root {
  color-scheme: light;

  /* ── Marca. Sobrescrita pelo SERVIDOR, por organização, em style no <html>.
        No mockup: <html style="--brand-h:168; --brand-c:0.075">.  §7.3
        O cliente escolhe hue e croma; a LIGHTNESS é propriedade do produto,
        e é por isso que o contraste é garantido por construção. ── */
  --brand-h: 168;      /* pinho — o default do Estúdio Ame */
  --brand-c: 0.075;    /* cap duro de produto: 0.020 – 0.110 */

  /* ── Superfícies: papel quente. O canvas NUNCA é #fff. ── */
  --canvas:          oklch(0.968 0.005 85);
  --surface-1:       oklch(1     0     0);     /* a folha de trabalho */
  --surface-2:       oklch(0.945 0.006 80);    /* hover, bolha recebida, coluna quieta */
  --surface-3:       oklch(0.913 0.008 80);    /* active, fundo de avatar */
  --hairline:        oklch(0.891 0.009 78);
  --hairline-strong: oklch(0.825 0.012 78);    /* borda de controle */

  /* ── Tinta: 4 níveis. A hierarquia inteira do produto vive aqui. ── */
  --ink:        oklch(0.204 0.003 60);   /* 14.9:1 sobre canvas */
  --ink-muted:  oklch(0.436 0.008 75);   /*  7.4:1 */
  --ink-subtle: oklch(0.594 0.010 78);   /*  4.6:1 — piso AA de texto normal */
  --ink-faint:  oklch(0.712 0.011 78);   /*  3.1:1 — SÓ placeholder, disabled, ícone decorativo */

  /* ── Marca derivada: lightness FIXA. ── */
  --brand:       oklch(0.44  var(--brand-c) var(--brand-h));
  --brand-hover: oklch(0.375 var(--brand-c) var(--brand-h));
  --brand-soft:  oklch(0.955 calc(var(--brand-c) * 0.30) var(--brand-h));
  --brand-line:  oklch(0.880 calc(var(--brand-c) * 0.45) var(--brand-h));
  --on-brand:    oklch(0.995 0 0);

  /* ── Ação = tinta. NUNCA a marca. Contraste constante entre organizações. ── */
  --action:       var(--ink);
  --action-hover: oklch(0.300 0.004 60);
  --action-active: oklch(0.300 0.004 60);
  --on-action:    oklch(0.995 0 0);

  /* ── Semânticas ── */
  --danger:       oklch(0.505 0.185 27);
  --danger-strong: oklch(0.445 0.180 27);   /* hover do botão danger */
  --danger-soft:  oklch(0.962 0.018 27);
  --danger-line:  oklch(0.505 0.185 27 / 0.25);
  --warning-line: oklch(0.550 0.145 55 / 0.25);
  --warning:      oklch(0.550 0.145 55);
  --warning-soft: oklch(0.965 0.035 80);
  --success:      oklch(0.510 0.128 155);
  --success-soft: oklch(0.960 0.030 155);
  --info:         oklch(0.490 0.185 260);
  --info-soft:    oklch(0.958 0.025 260);

  /* ── Automação. Plum de croma BAIXO — não é o violeta de template. ── */
  --bot:      oklch(0.460 0.085 305);
  --bot-soft: oklch(0.958 0.020 305);

  /* ── Foco: TINTA, não a marca. Auditado uma vez, não uma vez por cliente. ── */
  --focus: var(--ink);
  --scrim: oklch(0.204 0.003 60 / 0.32);

  /* ── Estados da conversa. Nenhum deles pinta fundo de linha (§7.7).
        Todos aparecem como ícone + rótulo, com texto acessível junto. ── */
  --state-unassigned:       var(--ink-muted);
  --state-ai:               var(--bot);
  --state-awaiting-agent:   var(--warning);
  --state-agent:            var(--ink);
  --state-awaiting-contact: var(--ink-subtle);
  --state-snoozed:          var(--ink-faint);
  --state-resolved:         var(--success);
  --state-sla-risk:         var(--warning);
  --state-sla-breached:     var(--danger);
  --state-window-closing:   var(--warning);
  --state-window-closed:    var(--danger);
  --state-read:             var(--brand);   /* o ÚNICO status de entrega com cor */

  /* ── Elevação: 2 níveis, acromáticos, uso NOMINAL.
        raised  → popover, dropdown
        overlay → modal, drawer, toast, card em arraste
        Card, painel, coluna e linha de lista: box-shadow NONE. ── */
  --elev-raised:  0 1px 2px oklch(0.204 0.003 60 / .06),
                  0 1px 1px oklch(0.204 0.003 60 / .04);
  --elev-overlay: 0 8px 24px -4px oklch(0.204 0.003 60 / .12),
                  0 2px  6px -2px oklch(0.204 0.003 60 / .06);

  /* ── Densidade: 2 modos. Default comfortable. <html data-density="condensed"> ── */
  --row-h: 76px;
  --table-row-h: 52px;

  /* ── Tipografia. Stack de sistema (mockup file://, zero requisição).
        As font-features descaracterizam a UI default: 1 alternativo,
        6/9 abertos, zero cortado — obrigatório num painel cheio de IDs. ── */
  --font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, "SF Mono", "Cascadia Mono", "Segoe UI Mono",
               Menlo, Consolas, monospace;

  /* ── Escala tipográfica. Peso NUNCA passa de 600. O papel de "display"
        é feito por tamanho e tracking óptico, não por segunda família.

        A escala é MOBILE-FIRST: os três degraus de display saem de um tamanho
        de celular e crescem por `clamp()` com limites explícitos — o mínimo é
        o valor de 360px, o máximo é o valor de desktop. O termo do meio sempre
        carrega um componente em `rem`, e é isso que mantém o zoom do navegador
        funcionando (uma escala só em `vw` congela o texto e reprova em 1.4.4).

        Abaixo de `--text-title` a escala é FIXA: 18/16/14/13/12/11 são medidas
        de interface, não de composição. Encolher o corpo no celular só piora a
        legibilidade justamente onde a tela está mais perto do olho.

        Entrelinha e tracking também invertem: texto pequeno pede entrelinha
        mais folgada e tracking menos negativo. Os valores apertados de desktop
        entram nos degraus `md`/`lg` logo abaixo (§1.1).                    ── */
  --text-display-lg: clamp(2rem,     1.35rem + 2.90vw, 2.75rem);  /* 32 → 44 */
  --lh-display-lg: 1.16;  --ls-display-lg: -0.018em;  --fw-display-lg: 560;
  --text-display-md: clamp(1.5rem,   1.15rem + 1.55vw, 2rem);     /* 24 → 32 */
  --lh-display-md: 1.20;  --ls-display-md: -0.014em;  --fw-display-md: 560;
  --text-headline:   clamp(1.25rem,  1.10rem + 0.65vw, 1.5rem);   /* 20 → 24 */
  --lh-headline:   1.28;  --ls-headline:   -0.011em;  --fw-headline:   560;
  --text-title:      1.125rem;  --lh-title:      1.30;  --ls-title:      -0.011em;  --fw-title:      550;
  --text-body-lg:    1rem;      --lh-body-lg:    1.55;  --ls-body-lg:    -0.003em;  --fw-body-lg:    400;
  --text-body:       0.875rem;  --lh-body:       1.50;  --ls-body:       0;         --fw-body:       400;
  --fw-body-strong:  550;                                                            /* não-lido, nome */
  --text-label:      0.8125rem; --lh-label:      1.35;  --ls-label:      0;         --fw-label:      500;
  --text-caption:    0.75rem;   --lh-caption:    1.40;  --ls-caption:    0.006em;   --fw-caption:    400;
  --text-micro:      0.6875rem; --lh-micro:      1.30;  --ls-micro:      0.012em;   --fw-micro:      500;
  --text-mono-sm:    0.75rem;   --lh-mono-sm:    1.50;

  /* ── Tipografia de CONTROLE. Separada do corpo por um motivo só: qualquer
        <input>, <select> ou <textarea> abaixo de 16px faz o Safari do iOS dar
        zoom ao receber foco — e o zoom não volta sozinho. No celular o campo
        é 16px; a densidade de 14px do painel volta no `md` com ponteiro fino
        (§1.1). Rótulo, hint e erro continuam na escala normal.            ── */
  --text-control: 1rem;
  --control-h:    44px;   /* .input / .select / .textarea — alvo de toque */
  --control-h-sm: 36px;   /* .input--sm / .select--sm */

  /* ── Espaçamento: base 4px. Não existe valor arbitrário. ── */
  --sp-0:  0px;
  --sp-1:  4px;
  --sp-2:  8px;
  --sp-3:  12px;
  --sp-4:  16px;
  --sp-5:  20px;
  --sp-6:  24px;
  --sp-8:  32px;
  --sp-10: 40px;
  --sp-12: 48px;
  --sp-16: 64px;
  --sp-20: 80px;

  /* ── Ritmo de espaçamento RESPONSIVO. A escala `--sp-*` acima é absoluta e
        nunca muda: `.p-4` é 16px em qualquer tela, e é isso que faz dela um
        contrato. O que muda com a largura é o ritmo de LAYOUT — a margem da
        página, a respiração entre seções, o padding de painel.

        No celular o espaçamento generoso do desktop não é elegante, é
        desperdício: 24px de cada lado num viewport de 360 consomem 13% da
        largura útil e espremem a linha de texto. Estes três tokens sobem em
        degraus (§1.1); todo componente de layout consome eles em vez de
        cravar `--sp-6`.                                                   ── */
  --gutter:    var(--sp-4);    /* margem lateral da página      16 → 20 → 24 */
  --section-y: var(--sp-10);   /* respiração entre seções  40 → 48 → 64 → 80 */
  --pane-pad:  var(--sp-3);    /* padding interno de painel/coluna   12 → 16 */

  /* ── Chrome do mockup. A barra é mais alta no toque (o link precisa caber
        num alvo de 44px honesto) e mais fina no desktop. Todo mundo que
        precisa compensar a barra lê `--mockbar-offset`, que já inclui o
        notch — nenhuma página, e nenhuma outra regra, escreve "36px". ── */
  --mockbar-h: 44px;
  --mockbar-offset: calc(var(--mockbar-h) + env(safe-area-inset-top, 0px));

  /* ── Raios: 4 valores + pill. Pill SÓ em avatar, badge e barra de não-lido. ── */
  --radius-xs: 4px;   /* checkbox, chip de status */
  --radius-sm: 6px;   /* botão */
  --radius-md: 8px;   /* input, card de kanban, miniatura de mídia */
  --radius-lg: 12px;  /* bolha, modal, drawer */
  --radius-pill: 9999px;

  /* ── Motion: 4 durações, 2 easings. Orçamento fechado (§7.6). ── */
  --dur-instant: 80ms;
  --dur-fast:    120ms;
  --dur-base:    160ms;
  --dur-slow:    240ms;
  --ease-standard: cubic-bezier(.2, 0, 0, 1);
  --ease-out:      cubic-bezier(.16, 1, .3, 1);

  /* ── Geometria do shell. Token porque quatro telas dependem dela.

        No CELULAR não existe "coluna de 340px": existe UMA coluna, a largura
        da tela. Por isso a base é `auto` — o shell empilha rail, filas, lista,
        conversa e ficha como documento contínuo, e NADA fica escondido. As
        larguras fixas só nascem no `md`, quando há tela para elas (§1.1).
        `--spacing-readcol` é a exceção: é um MÁXIMO (medida de leitura), não
        uma largura, então continua valendo em qualquer viewport.         ── */
  --spacing-rail:     auto;
  --spacing-sidebar:  auto;
  --spacing-convlist: auto;
  --spacing-context:  auto;
  --spacing-readcol:  680px;
}

[data-density="condensed"] { --row-h: 56px; --table-row-h: 40px; }


/* ═══ 1.1 · ESCALA RESPONSIVA DOS TOKENS ════════════════════════════════════
   O único lugar do arquivo onde token muda de valor. Tudo por `min-width`:
   cada degrau ADICIONA, nenhum desfaz o anterior. Uma página que queira saber
   "quanto vale --gutter aqui" olha esta tabela e nada mais.              ═══ */

@media (min-width: 640px) {
  :root {
    --gutter:    var(--sp-5);
    --section-y: var(--sp-12);
    --pane-pad:  var(--sp-4);
  }
}

@media (min-width: 900px) {
  :root {
    --gutter:    var(--sp-6);
    --section-y: var(--sp-16);

    /* O tracking apertado e a entrelinha curta são de composição grande:
       só fazem sentido quando o display já cresceu. */
    --lh-display-md: 1.14;  --ls-display-md: -0.022em;
    --lh-headline:   1.22;  --ls-headline:   -0.017em;

    /* O shell ganha colunas — aqui as larguras deixam de ser `auto`. */
    --spacing-rail:     56px;
    --spacing-sidebar:  232px;
    --spacing-convlist: 300px;
    --spacing-context:  288px;
  }
}

@media (min-width: 1200px) {
  :root {
    --section-y: var(--sp-20);
    --lh-display-lg: 1.08;  --ls-display-lg: -0.025em;
    --spacing-sidebar:  260px;
    --spacing-convlist: 340px;
    --spacing-context:  320px;
  }
}

/* A barra do mockup afina quando deixa de ser alvo de dedo — mesmo critério
   dos controles: o que decide é o PONTEIRO, não a largura. Num tablet largo
   a barra continua com 44px, e é isso que faz o alvo invisível de 44px do
   `.mockbar__link` caber dentro dela em vez de vazar para o conteúdo. */
@media (min-width: 900px) and (pointer: fine) {
  :root { --mockbar-h: 36px; }
}

/* Densidade de controle: 14px e 36px de altura são medida de PONTEIRO FINO.
   Um tablet grande continua com ponteiro grosso e continua com 16px/44px —
   o critério é o dedo, não a largura da tela, e é por isso que a consulta
   combina as duas coisas em vez de confiar só no breakpoint. */
@media (min-width: 900px) and (pointer: fine) {
  :root {
    --text-control: var(--text-body);
    --control-h:    36px;
    --control-h-sm: 32px;
  }
}


/* ═══ 2 · TOKENS · TEMA ESCURO ══════════════════════════════════════════════
   Dark é ATRIBUTO, nunca media query: o toggle precisa vencer a preferência
   do SO nas duas direções, e o data-theme já vem pintado no primeiro byte —
   por isso não há FOUC. No mockup, <html data-theme="light"> é escrito no
   próprio arquivo e o toggle troca o atributo.                           ═══ */

:root[data-theme="dark"] {
  color-scheme: dark;

  --canvas:          oklch(0.150 0.003 75);
  --surface-1:       oklch(0.192 0.004 75);
  --surface-2:       oklch(0.228 0.004 75);
  --surface-3:       oklch(0.265 0.005 75);
  --hairline:        oklch(0.282 0.005 75);
  --hairline-strong: oklch(0.352 0.006 75);

  --ink:        oklch(0.960 0.004 85);
  --ink-muted:  oklch(0.768 0.008 80);
  --ink-subtle: oklch(0.630 0.008 78);
  --ink-faint:  oklch(0.482 0.007 78);

  --brand:       oklch(0.760 var(--brand-c) var(--brand-h));
  --brand-hover: oklch(0.815 var(--brand-c) var(--brand-h));
  --brand-soft:  oklch(0.290 calc(var(--brand-c) * 0.55) var(--brand-h));
  --brand-line:  oklch(0.380 calc(var(--brand-c) * 0.60) var(--brand-h));
  --on-brand:    oklch(0.150 0.003 75);

  --action:        oklch(0.960 0.004 85);
  --action-hover:  oklch(0.880 0.005 82);
  --action-active: oklch(0.880 0.005 82);
  --on-action:     oklch(0.150 0.003 75);

  --danger:  oklch(0.700 0.160 27);   --danger-soft:  oklch(0.265 0.055 27);
  --danger-strong: oklch(0.760 0.155 27);
  --danger-line:   oklch(0.700 0.160 27 / 0.30);
  --warning-line:  oklch(0.760 0.130 65 / 0.30);
  --warning: oklch(0.760 0.130 65);   --warning-soft: oklch(0.270 0.050 65);
  --success: oklch(0.720 0.130 155);  --success-soft: oklch(0.262 0.048 155);
  --info:    oklch(0.700 0.140 260);  --info-soft:    oklch(0.265 0.055 260);
  --bot:     oklch(0.735 0.090 305);  --bot-soft:     oklch(0.268 0.045 305);

  --focus: oklch(0.960 0.004 85);
  --scrim: oklch(0.080 0.002 75 / 0.58);

  --elev-raised:  0 1px 2px oklch(0 0 0 / .55);
  --elev-overlay: 0 8px 24px -4px oklch(0 0 0 / .62),
                  0 2px  6px -2px oklch(0 0 0 / .40);
}


/* ═══ 3 · BASE ══════════════════════════════════════════════════════════════ */

html {
  font-family: var(--font-sans);
  font-feature-settings: 'cv01', 'cv03', 'cv04', 'ss03', 'zero';
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

body {
  background: var(--canvas);
  color: var(--ink);
  font-size: var(--text-body);
  line-height: var(--lh-body);
  font-weight: var(--fw-body);
  /* 100vh MENTE no iOS: a barra do navegador entra na conta e o rodapé fica
     debaixo dela. `dvh` é a medida honesta; `vh` fica como fallback antes. */
  min-height: 100vh;
  min-height: 100dvh;
  /* O body NUNCA rola na horizontal. `clip` e não `hidden` de propósito:
     `hidden` cria um contexto de rolagem e quebra todo `position: sticky`
     de dentro (o índice das páginas legais, o <thead> da tabela). Conteúdo
     largo — tabela, kanban, trilho, barra do mockup — rola dentro de si. */
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 { text-wrap: balance; }
p, li          { text-wrap: pretty; }

strong, b { font-weight: 600; }   /* teto absoluto do sistema. 700 é erro de build. */
em, i     { font-style: italic; }
code, pre, samp, kbd { font-family: var(--font-mono); }

/* Números tabulares onde há comparação. */
time, output, [data-numeric], [data-counter],
td[data-kind="numeric"], td[data-kind="currency"] { font-variant-numeric: tabular-nums; }

/* Marcas e identificadores nunca são traduzidos pelo Chrome. */
[translate="no"] { unicode-bidi: isolate; }

::selection { background: var(--brand-soft); color: var(--ink); }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--hairline-strong);
  border-radius: var(--radius-pill);
  border: 3px solid transparent;
  background-clip: content-box;
}

/* <select> nativo precisa de cor explícita: sem isto, o Windows em dark mode
   renderiza o popup do sistema em branco sobre branco. */
select, option { background-color: var(--surface-1); color: var(--ink); }

::placeholder { color: var(--ink-faint); opacity: 1; }


/* ═══ 4 · ACESSIBILIDADE (§7.5) ═════════════════════════════════════════════ */

/* UMA regra de foco, global, sem exceção. `outline: none` sem substituto é
   falha de build. O raio vai em :where() para especificidade 0 — assim o raio
   próprio do componente (pill do avatar, lg da bolha) sempre vence. */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}
:where(:focus-visible) { border-radius: var(--radius-xs); }

/* Dentro de lista e tabela o offset positivo é cortado pelo overflow. */
[data-focus-inset]:focus-visible { outline-offset: -2px; }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: fixed;
  top: 0;
  left: max(var(--sp-2), env(safe-area-inset-left, 0px));
  z-index: 200;
  transform: translateY(-200%);
  background: var(--surface-1);
  color: var(--ink);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius-sm);
  padding: var(--sp-2) var(--sp-4);
  font-size: var(--text-label);
  font-weight: var(--fw-label);
  box-shadow: var(--elev-overlay);
}
/* Sai de fora da tela (top:0 + -200%) e desce para BAIXO da barra do mockup —
   o offset já inclui o notch. Sem transição: foco é instantâneo (§7.6). */
.skip-link:focus-visible {
  transform: translateY(calc(var(--mockbar-offset) + var(--sp-2)));
}

/* Alvos de toque ≥ 44×44 CSS sob ponteiro grosso, sem inflar a densidade no
   desktop: o alvo cresce por ::after, o layout visual continua em 32px.
   `.rail-item`, `.menu-item` e `.doc-toc__link` entraram na lista — os três
   são navegação primária e nenhum deles chegava a 44px de altura no celular. */
@media (pointer: coarse) {
  .btn, .icon-btn, .badge__remove, .tab, .conv__action, .msg__action,
  .toast__close, .rail-item {
    position: relative;
  }
  .btn::after, .icon-btn::after, .badge__remove::after, .tab::after,
  .conv__action::after, .msg__action::after, .toast__close::after,
  .rail-item::after {
    content: "";
    position: absolute;
    inset: 50% auto auto 50%;
    width: 44px; height: 44px;
    transform: translate(-50%, -50%);
  }
  /* Item de lista larga: o alvo cresce em altura, não num quadrado de 44.
     Em `.check` e `.switch` o rótulo inteiro já é o alvo — basta a altura. */
  .menu-item, .doc-toc__link, .nav-item, .check, .switch { min-height: 44px; }
}

/* Reduzir movimento não é acelerar animação — é escolher outra representação.
   A regra global zera durações; os três casos que trocam de FORMA estão
   marcados adiante (skeleton, entrada de mensagem, auto-scroll). */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}


/* ═══ 5 · TIPOGRAFIA — UTILITÁRIOS ══════════════════════════════════════════ */

.t-display-lg { font-size: var(--text-display-lg); line-height: var(--lh-display-lg); letter-spacing: var(--ls-display-lg); font-weight: var(--fw-display-lg); }
.t-display-md { font-size: var(--text-display-md); line-height: var(--lh-display-md); letter-spacing: var(--ls-display-md); font-weight: var(--fw-display-md); }
.t-headline   { font-size: var(--text-headline);   line-height: var(--lh-headline);   letter-spacing: var(--ls-headline);   font-weight: var(--fw-headline); }
.t-title      { font-size: var(--text-title);      line-height: var(--lh-title);      letter-spacing: var(--ls-title);      font-weight: var(--fw-title); }
.t-body-lg    { font-size: var(--text-body-lg);    line-height: var(--lh-body-lg);    letter-spacing: var(--ls-body-lg);    font-weight: var(--fw-body-lg); }
.t-body       { font-size: var(--text-body);       line-height: var(--lh-body);       font-weight: var(--fw-body); }
.t-body-strong{ font-size: var(--text-body);       line-height: var(--lh-body);       font-weight: var(--fw-body-strong); }
.t-label      { font-size: var(--text-label);      line-height: var(--lh-label);      font-weight: var(--fw-label); }
.t-caption    { font-size: var(--text-caption);    line-height: var(--lh-caption);    letter-spacing: var(--ls-caption);    font-weight: var(--fw-caption); }
.t-micro      { font-size: var(--text-micro);      line-height: var(--lh-micro);      letter-spacing: var(--ls-micro);      font-weight: var(--fw-micro); }
.t-mono       { font-family: var(--font-mono); font-size: var(--text-mono-sm); line-height: var(--lh-mono-sm); }

.c-ink        { color: var(--ink); }
.c-ink-muted  { color: var(--ink-muted); }
.c-ink-subtle { color: var(--ink-subtle); }
.c-ink-faint  { color: var(--ink-faint); }
.c-brand      { color: var(--brand); }
.c-danger     { color: var(--danger); }
.c-warning    { color: var(--warning); }
.c-success    { color: var(--success); }
.c-info       { color: var(--info); }
.c-bot        { color: var(--bot); }

.num      { font-variant-numeric: tabular-nums; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.clamp-1  { display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; min-width: 0; }
.clamp-2  { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; min-width: 0; }

.link {
  color: var(--brand);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  transition: color var(--dur-fast) var(--ease-standard);
}
@media (hover: hover) {
  .link:hover { color: var(--brand-hover); }
}

.kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 var(--sp-1);
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  color: var(--ink-muted);
  background: var(--surface-2);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-xs);
}


/* ═══ 6 · ÍCONES ════════════════════════════════════════════════════════════
   SVG inline, traço 1.5px, currentColor. Emoji como ícone é erro de build.  */

.icon {
  width: 16px; height: 16px;
  flex: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  fill: none;
}
.icon--12 { width: 12px; height: 12px; }
.icon--14 { width: 14px; height: 14px; }
.icon--18 { width: 18px; height: 18px; }
.icon--20 { width: 20px; height: 20px; }
.icon--24 { width: 24px; height: 24px; }
.icon--32 { width: 32px; height: 32px; }


/* ═══ 7 · LAYOUT — SHELL E PRIMITIVAS DE COMPOSIÇÃO ═════════════════════════
   O app não empilha cartões brancos sobre fundo cinza: é um documento
   contínuo dividido por linhas de 1px. Card dentro de card é erro.

   ── O SHELL É MOBILE-FIRST, E ISSO MUDA O QUE ELE É ────────────────────────
   No celular o shell NÃO é um grid de colunas com scroll interno: é um
   documento que rola. Uma coluna, altura automática, e as peças empilhadas na
   ordem do DOM — trilho (deitado, rolando na horizontal), filas, lista de
   conversas, conversa, ficha do contato.

   Isso é deliberado e é a diferença entre um mockup navegável e um mockup
   quebrado: a alternativa clássica — esconder colunas com `display: none` e
   mostrar só a thread — tornaria a fila e a ficha INALCANÇÁVEIS num arquivo
   estático, que não tem rota nem estado para trazê-las de volta. Empilhado,
   o cliente vê tudo rolando o dedo.

   A partir do `md` o shell vira o grid de colunas de verdade, travado na
   altura da viewport, e cada coluna volta a ter a sua própria rolagem.    ═══ */

.app-shell {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  min-height: calc(100vh - var(--mockbar-offset));
  min-height: calc(100dvh - var(--mockbar-offset));
  background: var(--canvas);
}
/* Todas as variantes nascem em uma coluna. Cada uma ganha as suas no §7.1. */
.app-shell--inbox,
.app-shell--no-context,
.app-shell--crm,
.app-shell--dev { grid-template-columns: minmax(0, 1fr); }

/* ── Trilho ── deitado no celular, em pé a partir do `md`. Rola na horizontal
   dentro de si mesmo; nunca empurra a página. */
.rail {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--sp-1);
  padding: var(--sp-2) var(--pane-pad);
  padding-left: max(var(--pane-pad), env(safe-area-inset-left, 0px));
  padding-right: max(var(--pane-pad), env(safe-area-inset-right, 0px));
  background: var(--canvas);
  border-bottom: 1px solid var(--hairline);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.rail::-webkit-scrollbar { display: none; }
/* Deitado o espaçador vira separação mínima entre os destinos e a conta;
   em pé ele volta a empurrar a conta para o rodapé do trilho. */
.rail__spacer { flex: 1; min-width: var(--sp-4); }

.sidebar {
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--canvas);
  border-bottom: 1px solid var(--hairline);
}
.sidebar__section { padding: var(--sp-3) var(--pane-pad) var(--sp-2); }
.sidebar__title {
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  color: var(--ink-subtle);
  padding: 0 var(--sp-2) var(--sp-2);
}

/* No celular a coluna é uma FAIXA do documento: largura cheia, altura do
   conteúdo, separada da seguinte por hairline embaixo em vez de à direita. */
.pane {
  display: flex;
  flex-direction: column;
  min-width: 0;
  background: var(--surface-1);
  border-bottom: 1px solid var(--hairline);
}
.pane:last-child { border-bottom: 0; }
.pane--canvas { background: var(--canvas); }
.pane--scroll { overflow-y: auto; }

.pane__header {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 52px;
  padding: var(--sp-2) var(--pane-pad);
  border-bottom: 1px solid var(--hairline);
  background: var(--surface-1);
  flex: none;
  flex-wrap: wrap;   /* no celular o cabeçalho quebra em vez de espremer */
}
.pane__body { min-width: 0; }
.pane__footer {
  flex: none;
  padding: var(--sp-3) var(--pane-pad);
  /* Barra de ação colada no rodapé: a barra de gestos do iPhone não pode
     comer o botão de enviar. */
  padding-bottom: calc(var(--sp-3) + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--hairline);
}

.page-header {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--pane-pad) var(--sp-3);
  border-bottom: 1px solid var(--hairline);
}
.page-header__title { font-size: var(--text-headline); line-height: var(--lh-headline); letter-spacing: var(--ls-headline); font-weight: var(--fw-headline); }
.page-header__sub   { font-size: var(--text-body); color: var(--ink-subtle); margin-top: var(--sp-1); }
.page-header__actions { display: flex; align-items: center; gap: var(--sp-2); flex: none; }

.filter-bar {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
  padding: var(--sp-2) var(--pane-pad);
  border-bottom: 1px solid var(--hairline);
  background: var(--surface-1);
}
/* No celular o espaçador não empurra nada: a barra já quebrou em linhas. */
.filter-bar__spacer { flex: 0 0 100%; }

.panel {
  background: var(--surface-1);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  box-shadow: none;      /* profundidade é hairline, não sombra */
}
.panel__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  flex-wrap: wrap;
  padding: var(--sp-3) var(--pane-pad);
  border-bottom: 1px solid var(--hairline);
}
.panel__body   { padding: var(--pane-pad); }
.panel__footer { padding: var(--sp-3) var(--pane-pad); border-top: 1px solid var(--hairline); }

.stack   { display: flex; flex-direction: column; gap: var(--sp-3); }
.stack-1 { display: flex; flex-direction: column; gap: var(--sp-1); }
.stack-2 { display: flex; flex-direction: column; gap: var(--sp-2); }
.stack-4 { display: flex; flex-direction: column; gap: var(--sp-4); }
.stack-6 { display: flex; flex-direction: column; gap: var(--sp-6); }

.row    { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.row-3  { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.row-4  { display: flex; align-items: center; gap: var(--sp-4); min-width: 0; }
.row--between { justify-content: space-between; }
.row--wrap    { flex-wrap: wrap; }
.spacer { flex: 1; min-width: 0; }

.divider  { height: 1px; background: var(--hairline); border: 0; }
.divider--v { width: 1px; align-self: stretch; background: var(--hairline); }

.readcol { max-width: var(--spacing-readcol); margin-inline: auto; width: 100%; }

/* Item de navegação do rail e da sidebar. */
.nav-item {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  width: 100%;
  min-height: 32px;
  padding: 0 var(--sp-2);
  border-radius: var(--radius-sm);
  color: var(--ink-muted);
  font-size: var(--text-body);
  transition: background-color var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard);
}
@media (hover: hover) {
  .nav-item:hover { background: var(--surface-2); color: var(--ink); }
}
.nav-item[aria-current="page"],
.nav-item[aria-current="true"] { background: var(--surface-2); color: var(--ink); font-weight: var(--fw-body-strong); }
.nav-item[aria-current="page"] .icon { color: var(--brand); }
.nav-item__count { margin-left: auto; font-size: var(--text-micro); color: var(--ink-subtle); font-variant-numeric: tabular-nums; }

/* 40px na base porque no celular o trilho é a navegação primária e é tocado
   com o polegar; 36px volta no `md`, onde é mira de mouse (§7.1). */
.rail-item {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px; height: 40px;
  flex: none;
  border-radius: var(--radius-sm);
  color: var(--ink-muted);
  transition: background-color var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard);
}
@media (hover: hover) {
  .rail-item:hover { background: var(--surface-2); color: var(--ink); }
}
.rail-item[aria-current="page"] { background: var(--surface-3); color: var(--ink); }

/* Abas. NÃO viram contêiner de rolagem: o sublinhado da aba ativa fica em
   `bottom: -1px` para cobrir a hairline da própria `.tabs`, e um `overflow-x`
   aqui recortaria exatamente esse 1px (além de gerar rolagem vertical de 1px).
   Quem quebra linha é a faixa que hospeda as abas — `.crm-tabbar` tem
   `flex-wrap` no celular. O rótulo é que não pode quebrar. */
.tabs {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  flex-wrap: wrap;
  border-bottom: 1px solid var(--hairline);
  min-width: 0;
}
.tab {
  position: relative;
  flex: none;
  padding: var(--sp-2) var(--sp-3);
  font-size: var(--text-label);
  font-weight: var(--fw-label);
  color: var(--ink-subtle);
  white-space: nowrap;
  transition: color var(--dur-fast) var(--ease-standard);
}
@media (hover: hover) {
  .tab:hover { color: var(--ink); }
}
.tab[aria-selected="true"] { color: var(--ink); }
.tab[aria-selected="true"]::before {
  content: "";
  position: absolute;
  left: var(--sp-2); right: var(--sp-2); bottom: -1px;
  height: 2px;
  background: var(--brand);
  border-radius: var(--radius-pill);
}


/* ═══ 7.1 · O SHELL GANHA COLUNAS ═══════════════════════════════════════════
   Aqui, e só aqui, o documento empilhado da §7 vira o grid travado na altura
   da viewport. Cada degrau ACRESCENTA uma coluna, da mais essencial para a
   menos — o inverso exato do arquivo antigo, que começava com cinco colunas e
   ia arrancando pedaço com `max-width`.

     md  ≥  900  trilho + lista  + conversa          (3 colunas)
     lg  ≥ 1200  trilho + filas  + lista + conversa  (4 colunas)
     xl  ≥ 1600  + ficha do contato                  (5 colunas)

   A conversa (`.pane--canvas`) nunca sai. As colunas que ainda não couberam
   não somem do produto — elas estão logo abaixo, empilhadas, em qualquer
   viewport menor que o degrau.                                          ═══ */

@media (min-width: 900px) {
  .app-shell {
    grid-template-columns: var(--spacing-rail) var(--spacing-sidebar) minmax(0, 1fr);
    height: calc(100vh - var(--mockbar-offset));
    height: calc(100dvh - var(--mockbar-offset));
    min-height: 0;
    overflow: hidden;
  }

  .rail {
    flex-direction: column;
    padding: var(--sp-3) 0;
    border-right: 1px solid var(--hairline);
    border-bottom: 0;
    overflow: hidden;
  }
  .rail-item { width: 36px; height: 36px; }
  .rail__spacer { min-width: 0; }

  .sidebar {
    border-right: 1px solid var(--hairline);
    border-bottom: 0;
    overflow-y: auto;
  }

  .pane {
    min-height: 0;
    border-right: 1px solid var(--hairline);
    border-bottom: 0;
    overflow: hidden;
  }
  .pane:last-child { border-right: 0; }
  .pane__header { flex-wrap: nowrap; padding-block: 0; }
  .pane__body   { flex: 1; min-height: 0; overflow-y: auto; }

  .page-header {
    flex-direction: row;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--sp-4);
    padding: var(--sp-6) var(--sp-6) var(--sp-4);
  }
  .filter-bar__spacer { flex: 1 1 auto; }

  /* Inbox e CRM: trilho + trabalho. Filas e ficha entram no lg / xl. */
  .app-shell--inbox,
  .app-shell--no-context {
    grid-template-columns: var(--spacing-rail) var(--spacing-convlist) minmax(0, 1fr);
  }
  .app-shell--inbox    > .sidebar,
  .app-shell--no-context > .sidebar,
  .app-shell--inbox    > .pane:last-child { display: none; }

  .app-shell--crm { grid-template-columns: var(--spacing-rail) minmax(0, 1fr); }
  .app-shell--crm > .sidebar,
  .app-shell--crm > .pane:last-child { display: none; }

  /* O painel do Estúdio Ame continua documento até o lg: é dele a tela mais
     densa do mockup (tabela de organizações, cofre, filas) e 612px de coluna
     de trabalho não servem a nenhuma delas. */
  .app-shell--dev {
    grid-template-columns: minmax(0, 1fr);
    height: auto;
    min-height: calc(100vh - var(--mockbar-offset));
    min-height: calc(100dvh - var(--mockbar-offset));
    overflow: visible;
  }
  .app-shell--dev > .rail {
    flex-direction: row;
    padding: var(--sp-2) var(--pane-pad);
    border-right: 0;
    border-bottom: 1px solid var(--hairline);
    overflow-x: auto;
  }
  .app-shell--dev > .sidebar { border-right: 0; border-bottom: 1px solid var(--hairline); overflow: visible; }
  .app-shell--dev > .pane { border-right: 0; overflow: visible; }
  .app-shell--dev .pane__body { overflow: visible; }
}

@media (min-width: 1200px) {
  .app-shell--inbox,
  .app-shell--no-context {
    grid-template-columns:
      var(--spacing-rail) var(--spacing-sidebar) var(--spacing-convlist) minmax(0, 1fr);
  }
  .app-shell--inbox      > .sidebar,
  .app-shell--no-context > .sidebar { display: flex; }

  .app-shell--crm { grid-template-columns: var(--spacing-rail) var(--spacing-sidebar) minmax(0, 1fr); }
  .app-shell--crm > .sidebar { display: flex; }

  .app-shell--dev {
    grid-template-columns: var(--spacing-rail) var(--spacing-sidebar) minmax(0, 1fr);
    height: calc(100vh - var(--mockbar-offset));
    height: calc(100dvh - var(--mockbar-offset));
    min-height: 0;
    overflow: hidden;
  }
  .app-shell--dev > .rail { flex-direction: column; padding: var(--sp-3) 0; border-right: 1px solid var(--hairline); border-bottom: 0; overflow: hidden; }
  .app-shell--dev > .sidebar { border-right: 1px solid var(--hairline); border-bottom: 0; overflow-y: auto; }
  .app-shell--dev > .pane { overflow: hidden; }
  .app-shell--dev .pane__body { overflow-y: auto; }
}

@media (min-width: 1600px) {
  .app-shell--inbox {
    grid-template-columns:
      var(--spacing-rail) var(--spacing-sidebar) var(--spacing-convlist)
      minmax(0, 1fr) var(--spacing-context);
  }
  .app-shell--inbox > .pane:last-child { display: flex; }

  .app-shell--crm {
    grid-template-columns:
      var(--spacing-rail) var(--spacing-sidebar) minmax(0, 1fr)
      calc(var(--spacing-context) + var(--sp-10));
  }
  .app-shell--crm > .pane:last-child { display: flex; }

  /* Recolher a ficha (o botão da inbox) devolve as 4 colunas. Vem DEPOIS de
     `--inbox` de propósito: mesma especificidade, ordem decide. */
  .app-shell--no-context {
    grid-template-columns:
      var(--spacing-rail) var(--spacing-sidebar) var(--spacing-convlist) minmax(0, 1fr);
  }
  .app-shell--no-context > .pane:last-child { display: none; }
}


/* ═══ 8 · BUTTON (§7.4) ═════════════════════════════════════════════════════
   variantes primary | secondary | ghost | danger | link
   tamanhos   sm 28 / md 32 / lg 40
   `disabled` nativo é BANIDO: ele remove o elemento da ordem de foco no meio
   da interação. Use aria-disabled="true" e aria-busy="true".               */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  height: 32px;
  padding: 0 var(--sp-3);
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  font-size: var(--text-label);
  line-height: 1;
  font-weight: var(--fw-label);
  white-space: nowrap;
  user-select: none;
  transition: background-color var(--dur-fast) var(--ease-standard),
              border-color var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard);
}
/* Foco é sempre instantâneo — nunca entra na transição. */
.btn:focus-visible { transition: none; border-radius: var(--radius-sm); }

.btn--sm { height: 28px; padding: 0 var(--sp-2); font-size: var(--text-caption); gap: var(--sp-1); }
.btn--md { height: 32px; }
.btn--lg { height: 40px; padding: 0 var(--sp-4); font-size: var(--text-body); }

.btn--primary   { background: var(--action); color: var(--on-action); }
.btn--primary:active { background: var(--action-active); }

.btn--secondary { background: var(--surface-1); color: var(--ink); border-color: var(--hairline-strong); }
.btn--secondary:active { background: var(--surface-3); }

.btn--ghost     { background: transparent; color: var(--ink-muted); }
.btn--ghost:active { background: var(--surface-3); color: var(--ink); }

.btn--danger    { background: var(--danger); color: oklch(0.995 0 0); }
.btn--danger:active { background: var(--danger-strong); }

.btn--link {
  background: transparent;
  color: var(--ink);
  height: auto;
  padding: 0;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

/* `:active` fica fora: no toque ele É o feedback de pressão. `:hover` não
   existe em dedo — no celular vira estado grudado depois do tap. */
@media (hover: hover) {
  .btn--primary:hover   { background: var(--action-hover); }
  .btn--secondary:hover { background: var(--surface-2); }
  .btn--ghost:hover     { background: var(--surface-2); color: var(--ink); }
  .btn--danger:hover    { background: var(--danger-strong); }
  .btn--link:hover      { color: var(--ink-muted); }
}

.btn--block { width: 100%; }

.btn[aria-disabled="true"] {
  opacity: .45;
  cursor: not-allowed;
  pointer-events: none;
}
/* loading: o RÓTULO PERMANECE. Não vira "…". */
.btn[aria-busy="true"] { cursor: progress; }
.btn[aria-busy="true"] .btn__spinner { display: block; }
.btn__spinner {
  display: none;
  width: 16px; height: 16px;
  flex: none;
  border-radius: var(--radius-pill);
  border: 1.5px solid currentColor;
  border-top-color: transparent;
  transform-origin: 50% 50%;
  animation: ame-spin 700ms linear infinite;
  opacity: .85;
}
@keyframes ame-spin { to { transform: rotate(360deg); } }

/* IconButton: nunca existe sem nome acessível (aria-label obrigatório). */
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px; height: 32px;
  flex: none;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  color: var(--ink-muted);
  transition: background-color var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard),
              border-color var(--dur-fast) var(--ease-standard);
}
.icon-btn:active { background: var(--surface-3); }
.icon-btn:focus-visible { transition: none; border-radius: var(--radius-sm); }
.icon-btn--sm { width: 28px; height: 28px; }
.icon-btn--lg { width: 40px; height: 40px; }
.icon-btn--bordered { border-color: var(--hairline-strong); background: var(--surface-1); }
.icon-btn[aria-disabled="true"] { opacity: .45; cursor: not-allowed; pointer-events: none; }
.icon-btn[aria-pressed="true"] { background: var(--surface-3); color: var(--ink); }
@media (hover: hover) {
  .icon-btn:hover { background: var(--surface-2); color: var(--ink); }
  .icon-btn--danger:hover { color: var(--danger); background: var(--danger-soft); }
}

/* Grupo segmentado (ex.: densidade, período). */
.btn-group { display: inline-flex; border: 1px solid var(--hairline-strong); border-radius: var(--radius-sm); overflow: hidden; }
.btn-group > .btn { border-radius: 0; border: 0; border-right: 1px solid var(--hairline-strong); }
.btn-group > .btn:last-child { border-right: 0; }
.btn-group > .btn[aria-pressed="true"] { background: var(--surface-3); color: var(--ink); }


/* ═══ 9 · INPUT / TEXTAREA (§7.4) ═══════════════════════════════════════════ */

.field { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; }

.label {
  font-size: var(--text-label);
  line-height: var(--lh-label);
  font-weight: var(--fw-label);
  color: var(--ink);
}
.label__optional { color: var(--ink-subtle); font-weight: var(--fw-body); }

/* `--text-control` é 16px no celular e 14px no desktop com ponteiro fino.
   NÃO é preciosismo: abaixo de 16px o Safari do iOS dá zoom no campo ao
   receber foco, o layout sai do lugar e não volta. `--control-h` segue o
   mesmo critério — 44px de alvo no dedo, 36px de densidade no mouse. */
.input, .textarea {
  width: 100%;
  height: var(--control-h);
  padding: 0 var(--sp-3);
  background: var(--surface-1);
  color: var(--ink);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius-md);
  font-size: var(--text-control);
  line-height: var(--lh-body);
  transition: border-color var(--dur-fast) var(--ease-standard),
              background-color var(--dur-fast) var(--ease-standard);
}
.input--sm { height: var(--control-h-sm); padding: 0 var(--sp-2); }
.input--md { height: var(--control-h); }

.textarea {
  height: auto;
  min-height: 72px;
  padding: var(--sp-2) var(--sp-3);
  resize: vertical;
}

@media (hover: hover) {
  .input:hover, .textarea:hover { border-color: var(--ink-faint); }
}

/* focus: a borda funciona como parte do anel → offset 0. */
.input:focus-visible, .textarea:focus-visible {
  border-color: var(--brand);
  outline: 2px solid var(--focus);
  outline-offset: 0;
  border-radius: var(--radius-md);
  transition: none;
}

.input[aria-disabled="true"], .textarea[aria-disabled="true"],
.input[readonly][data-disabled], .textarea[readonly][data-disabled] {
  background: var(--surface-2);
  color: var(--ink-faint);
  cursor: not-allowed;
}

.input[aria-invalid="true"], .textarea[aria-invalid="true"] { border-color: var(--danger); }
.input[aria-invalid="true"]:focus-visible,
.textarea[aria-invalid="true"]:focus-visible { border-color: var(--danger); }

/* Wrapper para addon (ícone à esquerda, spinner/erro à direita). */
.input-wrap { position: relative; display: flex; align-items: center; min-width: 0; }
.input-wrap > .input { padding-left: var(--sp-3); padding-right: var(--sp-3); }
.input-wrap--lead  > .input { padding-left: var(--sp-8); }
.input-wrap--trail > .input { padding-right: var(--sp-8); }
/* Centragem explícita: a altura do campo muda com o ponteiro (44 ↔ 36) e um
   addon que dependa da posição estática do flex desalinha no meio do caminho. */
.input-addon {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  color: var(--ink-faint);
  pointer-events: none;
}
.input-addon--lead  { left: var(--sp-3); }
.input-addon--trail { right: var(--sp-3); }
.input-addon--danger { color: var(--danger); }
.input-addon--action { pointer-events: auto; }
/* loading: o campo CONTINUA editável. */
.input-spinner {
  width: 14px; height: 14px;
  border-radius: var(--radius-pill);
  border: 1.5px solid var(--ink-faint);
  border-top-color: transparent;
  transform-origin: 50% 50%;
  animation: ame-spin 700ms linear infinite;
}

.field-hint  { font-size: var(--text-caption); line-height: var(--lh-caption); color: var(--ink-subtle); }
.field-error { font-size: var(--text-caption); line-height: var(--lh-caption); color: var(--danger); display: flex; align-items: center; gap: var(--sp-1); }

/* Checkbox e radio: um único alvo compartilhado com o rótulo, sem zona morta. */
.check {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  min-height: 24px;
  padding: var(--sp-1) 0;
  cursor: pointer;
  font-size: var(--text-body);
}
.check input[type="checkbox"],
.check input[type="radio"] {
  appearance: none;
  width: 16px; height: 16px;
  flex: none;
  margin-top: 2px;
  background: var(--surface-1);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius-xs);
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-standard),
              border-color var(--dur-fast) var(--ease-standard);
}
.check input[type="radio"] { border-radius: var(--radius-pill); }
.check input:checked {
  background: var(--action);
  border-color: var(--action);
}
/* Check desenhado com borda rotacionada — zero imagem, zero gradiente. */
.check input[type="checkbox"] { position: relative; }
.check input[type="checkbox"]:checked::after {
  content: "";
  position: absolute;
  left: 4.5px; top: 1px;
  width: 4px; height: 8px;
  border: 1.5px solid var(--on-action);
  border-top: 0;
  border-left: 0;
  transform: rotate(42deg);
  transform-origin: 50% 50%;
}
.check input[type="radio"]:checked { box-shadow: inset 0 0 0 3px var(--surface-1); }
.check input:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

/* Switch. */
.switch { display: inline-flex; align-items: center; gap: var(--sp-2); cursor: pointer; }
.switch input { appearance: none; width: 34px; height: 20px; border-radius: var(--radius-pill); background: var(--surface-3); border: 1px solid var(--hairline-strong); position: relative; cursor: pointer; transition: background-color var(--dur-fast) var(--ease-standard), border-color var(--dur-fast) var(--ease-standard); }
.switch input::after { content: ""; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: var(--radius-pill); background: var(--surface-1); transition: transform var(--dur-fast) var(--ease-standard); }
.switch input:checked { background: var(--action); border-color: var(--action); }
.switch input:checked::after { transform: translateX(14px); background: var(--on-action); }
.switch input:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }


/* ═══ 10 · SELECT (§7.4) ════════════════════════════════════════════════════
   Nativo. Um <select> reimplementado em <div> é a forma mais eficiente de
   perder teclado, leitor de tela e o seletor nativo do Android.            */

.select-wrap { position: relative; display: flex; align-items: center; min-width: 0; }
.select {
  appearance: none;
  width: 100%;
  height: var(--control-h);
  padding: 0 var(--sp-8) 0 var(--sp-3);
  background-color: var(--surface-1);
  color: var(--ink);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius-md);
  font-size: var(--text-control);
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease-standard);
}
.select--sm { height: var(--control-h-sm); }
@media (hover: hover) {
  .select:hover { border-color: var(--ink-faint); }
}
.select:focus-visible {
  border-color: var(--brand);
  outline: 2px solid var(--focus);
  outline-offset: 0;
  border-radius: var(--radius-md);
  transition: none;
}
.select[aria-disabled="true"] { background-color: var(--surface-2); color: var(--ink-faint); cursor: not-allowed; }
.select:has(option[value=""]:checked) { color: var(--ink-faint); }
.select-wrap__chevron {
  position: absolute;
  right: var(--sp-3);
  top: 50%;
  transform: translateY(-50%);
  color: var(--ink-subtle);
  pointer-events: none;
}


/* ═══ 11 · BADGE / TAG (§7.4) ═══════════════════════════════════════════════
   tone: neutral | brand | success | warning | danger | info | bot
   variant: soft (default) | outline | solid
   Paleta FECHADA. Hex livre não existe neste produto.
   Máx. 3 badges visíveis por linha — o resto vai num +N que abre popover.  */

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: 2px var(--sp-2);
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  white-space: nowrap;
  --badge-fg: var(--ink-muted);
  --badge-bg: var(--surface-2);
  --badge-line: var(--hairline-strong);
  color: var(--badge-fg);
  background: var(--badge-bg);
}
.badge .icon { width: 12px; height: 12px; }

.badge--neutral { --badge-fg: var(--ink-muted);  --badge-bg: var(--surface-2);   --badge-line: var(--hairline-strong); }
.badge--brand   { --badge-fg: var(--brand);      --badge-bg: var(--brand-soft);  --badge-line: var(--brand-line); }
.badge--success { --badge-fg: var(--success);    --badge-bg: var(--success-soft);--badge-line: var(--success); }
.badge--warning { --badge-fg: var(--warning);    --badge-bg: var(--warning-soft);--badge-line: var(--warning); }
.badge--danger  { --badge-fg: var(--danger);     --badge-bg: var(--danger-soft); --badge-line: var(--danger); }
.badge--info    { --badge-fg: var(--info);       --badge-bg: var(--info-soft);   --badge-line: var(--info); }
.badge--bot     { --badge-fg: var(--bot);        --badge-bg: var(--bot-soft);    --badge-line: var(--bot); }

.badge--soft    { background: var(--badge-bg); color: var(--badge-fg); border-color: transparent; }
.badge--outline { background: transparent; color: var(--badge-fg); border-color: var(--badge-line); }
.badge--solid   { background: var(--badge-fg); color: var(--surface-1); border-color: transparent; }

/* hover só quando é clicável ou removível — e só onde hover existe. */
@media (hover: hover) {
  a.badge:hover, button.badge:hover, .badge--interactive:hover {
    filter: brightness(0.96);
  }
  :root[data-theme="dark"] a.badge:hover,
  :root[data-theme="dark"] button.badge:hover,
  :root[data-theme="dark"] .badge--interactive:hover { filter: brightness(1.12); }
}

.badge[aria-disabled="true"] { opacity: .5; }
.badge[aria-disabled="true"] .badge__remove { display: none; }

.badge__remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px; height: 14px;
  margin-right: -2px;
  border-radius: var(--radius-pill);
  color: currentColor;
  opacity: .7;
}
@media (hover: hover) { .badge__remove:hover { opacity: 1; } }
.badge__remove:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; border-radius: var(--radius-pill); }

/* Tags de conversa — oito hues nomeados, o vocabulário do seed da CostaVet.
   Mesmo contrato da marca: lightness travada, croma baixo, contraste por
   construção nos dois temas. */
.tag { --tag-c: 0.062; --tag-h: 255;
  --badge-fg: oklch(0.44 var(--tag-c) var(--tag-h));
  --badge-bg: oklch(0.955 calc(var(--tag-c) * 0.34) var(--tag-h));
  --badge-line: oklch(0.880 calc(var(--tag-c) * 0.50) var(--tag-h));
}
:root[data-theme="dark"] .tag {
  --badge-fg: oklch(0.775 var(--tag-c) var(--tag-h));
  --badge-bg: oklch(0.288 calc(var(--tag-c) * 0.60) var(--tag-h));
  --badge-line: oklch(0.380 calc(var(--tag-c) * 0.65) var(--tag-h));
}
.tag--slate { --tag-c: 0.028; --tag-h: 255; }
.tag--pine  { --tag-c: 0.070; --tag-h: 168; }
.tag--ocean { --tag-c: 0.070; --tag-h: 232; }
.tag--plum  { --tag-c: 0.068; --tag-h: 305; }
.tag--clay  { --tag-c: 0.066; --tag-h: 40;  }
.tag--amber { --tag-c: 0.072; --tag-h: 75;  }
.tag--moss  { --tag-c: 0.062; --tag-h: 140; }
.tag--rose  { --tag-c: 0.070; --tag-h: 10;  }

/* Ponto de estado: ícone-mínimo que SEMPRE vem acompanhado de rótulo textual. */
.dot { width: 6px; height: 6px; border-radius: var(--radius-pill); flex: none; background: currentColor; }
.dot--8 { width: 8px; height: 8px; }

.state { display: inline-flex; align-items: center; gap: var(--sp-1); font-size: var(--text-micro); line-height: var(--lh-micro); letter-spacing: var(--ls-micro); font-weight: var(--fw-micro); white-space: nowrap; }
.state--unassigned       { color: var(--state-unassigned); }
.state--ai               { color: var(--state-ai); }
.state--awaiting-agent   { color: var(--state-awaiting-agent); }
.state--agent            { color: var(--state-agent); }
.state--awaiting-contact { color: var(--state-awaiting-contact); }
.state--snoozed          { color: var(--state-snoozed); }
.state--resolved         { color: var(--state-resolved); }
.state--sla-risk         { color: var(--state-sla-risk); }
.state--sla-breached     { color: var(--state-sla-breached); }
.state--window-closing   { color: var(--state-window-closing); }
.state--window-closed    { color: var(--state-window-closed); }


/* ═══ 12 · AVATAR (§7.4) ════════════════════════════════════════════════════
   Iniciais determinísticas. Nunca foto remota, nunca ícone de imagem quebrada.
   A cor vem do nome via --av-h no style inline (0–359).                    */

.avatar {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px; height: 32px;
  flex: none;
  border-radius: var(--radius-pill);
  background: var(--surface-3);
  color: var(--ink-muted);
  font-size: var(--text-micro);
  line-height: 1;
  font-weight: var(--fw-micro);
  letter-spacing: 0.01em;
  overflow: hidden;
  user-select: none;
}
.avatar--20 { width: 20px; height: 20px; font-size: 9px; }
.avatar--24 { width: 24px; height: 24px; font-size: 10px; }
.avatar--32 { width: 32px; height: 32px; }
.avatar--40 { width: 40px; height: 40px; font-size: var(--text-caption); }
.avatar--64 { width: 64px; height: 64px; font-size: var(--text-body-lg); font-weight: var(--fw-title); }

/* Cor derivada do nome: <span class="avatar avatar--hued" style="--av-h:212"> */
.avatar--hued {
  background: oklch(0.930 0.030 var(--av-h, 255));
  color: oklch(0.400 0.070 var(--av-h, 255));
}
:root[data-theme="dark"] .avatar--hued {
  background: oklch(0.300 0.035 var(--av-h, 255));
  color: oklch(0.830 0.060 var(--av-h, 255));
}

.avatar img { width: 100%; height: 100%; object-fit: cover; }
.avatar .icon { color: var(--ink-faint); }

/* agent="ai": anel de 1.5px em --bot + glifo IA. NÃO preenche de cor. */
.avatar--ai { overflow: visible; box-shadow: 0 0 0 1.5px var(--bot); }
.avatar--ai::after {
  content: "IA";
  position: absolute;
  right: -3px; bottom: -3px;
  padding: 0 2px;
  font-size: 8px;
  line-height: 10px;
  font-weight: 550;
  color: var(--bot);
  background: var(--surface-1);
  border-radius: var(--radius-xs);
}

/* Interativo (botão de atribuição). */
@media (hover: hover) {
  button.avatar:hover, .avatar--button:hover { box-shadow: 0 0 0 1px var(--hairline-strong); }
}
button.avatar:focus-visible, .avatar--button:focus-visible { border-radius: var(--radius-pill); }

.avatar-group { display: inline-flex; align-items: center; }
.avatar-group > .avatar { margin-left: -6px; box-shadow: 0 0 0 2px var(--surface-1); }
.avatar-group > .avatar:first-child { margin-left: 0; }


/* ═══ 13 · BOLHA DE MENSAGEM (§7.4) ═════════════════════════════════════════
   A thread é uma <ol> comum com aria-label — NUNCA uma live region.
   Cor na thread existe em exatamente quatro exceções: nota interna,
   falha de entrega, fita de IA e o check de "lido".                        */

.thread {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--pane-pad);
  content-visibility: auto;
  contain-intrinsic-size: auto 600px;
}
@media (min-width: 900px) {
  .thread { padding: var(--sp-6) var(--sp-4); }
}

/* No celular a bolha é mais larga que no desktop — 85% contra 78%. Não é
   capricho: 78% de 360px deixa a linha com ~34 caracteres, e aí a mensagem
   vira uma coluna estreita e alta. Os 15% que sobram continuam sendo o recuo
   que diferencia enviada de recebida; ele só respira mais quando há tela. */
.msg {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  max-width: 85%;
  align-self: flex-start;
}
@media (min-width: 900px) {
  .msg { max-width: 78%; }
}
.msg--out, .msg--ai, .msg--note { align-self: flex-end; align-items: flex-end; }

.msg__bubble {
  position: relative;
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-lg);
  border: 1px solid transparent;
  font-size: var(--text-body);
  line-height: var(--lh-body);
  color: var(--ink);
  overflow-wrap: anywhere;
}
.msg__bubble p + p { margin-top: var(--sp-2); }

/* recebida: surface-2, sem borda, canto inferior esquerdo em 4px */
.msg--in  .msg__bubble { background: var(--surface-2); border-bottom-left-radius: var(--radius-xs); }

/* enviada: surface-1 + hairline-strong, canto inferior direito 4px. NUNCA colorida */
.msg--out .msg__bubble { background: var(--surface-1); border-color: var(--hairline-strong); border-bottom-right-radius: var(--radius-xs); }

/* IA: = enviada + fita de 2px em --bot na borda inicial */
.msg--ai  .msg__bubble {
  background: var(--surface-1);
  border-color: var(--hairline-strong);
  border-bottom-right-radius: var(--radius-xs);
  border-inline-start: 2px solid var(--bot);
}

/* nota interna: warning-soft + borda warning translúcida */
.msg--note .msg__bubble {
  background: var(--warning-soft);
  border-color: var(--warning-line);
  border-bottom-right-radius: var(--radius-xs);
}

/* sistema: sem bolha, texto centralizado */
.msg--system {
  align-self: center;
  align-items: center;
  max-width: 100%;
  font-size: var(--text-caption);
  line-height: var(--lh-caption);
  letter-spacing: var(--ls-caption);
  color: var(--ink-faint);
  text-align: center;
  padding: var(--sp-1) 0;
}

/* envio otimista: opacidade .55 → 1 ao confirmar */
.msg--queued .msg__bubble { opacity: .55; transition: opacity var(--dur-fast) var(--ease-standard); }

/* falha */
.msg--failed .msg__bubble { border-color: var(--danger); }
.msg__failure {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  font-size: var(--text-caption);
  line-height: var(--lh-caption);
  color: var(--danger);
}

.msg__label {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  color: var(--ink-subtle);
}
.msg__label--ai   { color: var(--bot); }
.msg__label--note { color: var(--warning); }

.msg__meta {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

/* Status de entrega — cada ícone é aria-hidden e vem com um .sr-only. */
.msg__status { display: inline-flex; align-items: center; gap: 2px; color: var(--ink-faint); }
.msg__status--queued    { color: var(--ink-faint); }
.msg__status--sent      { color: var(--ink-faint); }
.msg__status--delivered { color: var(--ink-faint); }
.msg__status--read      { color: var(--state-read); }
.msg__status--failed    { color: var(--danger); }

/* Barra de ações da bolha. NADA aqui pode depender de hover: no toque não há
   hover, e uma ação que só aparece ao passar o mouse simplesmente não existe
   no celular. Por isso a BASE é uma fileira discreta, estática e sempre
   visível, embaixo da bolha. A barra flutuante revelada em 120ms é o degrau
   de cima — só entra onde existe ponteiro que passa por cima. */
.msg__actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--sp-1);
  margin-top: var(--sp-1);
}
.msg__action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px; height: 28px;
  border-radius: var(--radius-xs);
  color: var(--ink-muted);
}

@media (hover: hover) and (min-width: 900px) {
  .msg__actions {
    position: absolute;
    top: -14px;
    inset-inline-end: var(--sp-2);
    gap: var(--sp-2);
    margin-top: 0;
    padding: 2px;
    background: var(--surface-1);
    border: 1px solid var(--hairline);
    border-radius: var(--radius-sm);
    box-shadow: var(--elev-raised);
    opacity: 0;
    transition: opacity var(--dur-fast) var(--ease-standard);
  }
  .msg:hover .msg__actions,
  .msg:focus-within .msg__actions { opacity: 1; }
  .msg__action { width: 24px; height: 24px; }
  .msg__action:hover { background: var(--surface-2); color: var(--ink); }
}

/* bolha focável pelas setas ↑/↓ dentro da thread */
.msg__bubble:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; border-radius: var(--radius-lg); }

/* separador de dia */
.thread__day {
  align-self: center;
  padding: var(--sp-1) var(--sp-2);
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  color: var(--ink-subtle);
  background: var(--surface-2);
  border-radius: var(--radius-pill);
}

/* mensagem chegando: opacity 0→1 + translateY 4px→0, 160ms out.
   Com reduced-motion perde o translateY e fica só em opacity. */
.msg--enter { animation: ame-msg-in var(--dur-base) var(--ease-out) both; }
@keyframes ame-msg-in {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .msg--enter { animation: none; opacity: 1; transform: none; }
}

/* indicador de digitação: 3 pontos de 4px, translateY(-3px) escalonado, 1.2s */
.typing { display: inline-flex; align-items: center; gap: 3px; padding: var(--sp-2) var(--sp-3); background: var(--surface-2); border-radius: var(--radius-lg); border-bottom-left-radius: var(--radius-xs); align-self: flex-start; }
.typing span { width: 4px; height: 4px; border-radius: var(--radius-pill); background: var(--ink-faint); transform-origin: 50% 50%; animation: ame-typing 1.2s var(--ease-standard) infinite; }
.typing span:nth-child(2) { animation-delay: .15s; }
.typing span:nth-child(3) { animation-delay: .30s; }
@keyframes ame-typing {
  0%, 60%, 100% { transform: translateY(0); }
  30%           { transform: translateY(-3px); }
}
@media (prefers-reduced-motion: reduce) { .typing span { animation: none; } }

/* Composer — :focus-within destaca o bloco inteiro. */
.composer {
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius-md);
  background: var(--surface-1);
  transition: border-color var(--dur-fast) var(--ease-standard);
}
.composer:focus-within { border-color: var(--brand); outline: 2px solid var(--focus); outline-offset: 0; }
.composer__input {
  width: 100%;
  min-height: 56px;
  max-height: 200px;
  padding: var(--sp-3);
  background: transparent;
  border: 0;
  resize: none;
  /* 16px no celular: é o campo mais tocado do produto e o que mais sofreria
     com o zoom automático do Safari no meio de um atendimento. */
  font-size: var(--text-control);
  line-height: var(--lh-body);
  color: var(--ink);
}
.composer__input:focus-visible { outline: none; }   /* substituto: o anel do :focus-within acima */
.composer__bar { display: flex; align-items: center; gap: var(--sp-1); padding: var(--sp-1) var(--sp-2) var(--sp-2); }
.composer--note { background: var(--warning-soft); border-color: var(--warning-line); }


/* ═══ 14 · ITEM DA LISTA DE CONVERSAS (§7.4) ════════════════════════════════
   <a> real: ⌘+clique e clique do meio funcionam.
   O fundo da linha NUNCA muda de cor por estado de leitura: não-lido é peso
   tipográfico + ponto de 6px, jamais fundo colorido.                       */

.conv-list { display: flex; flex-direction: column; }

.conv {
  position: relative;
  display: grid;
  grid-template-columns: 8px 32px 1fr auto;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--row-h);
  padding: var(--sp-2) var(--pane-pad);
  background: var(--surface-1);
  border-bottom: 1px solid var(--hairline);
  transition: background-color var(--dur-fast) var(--ease-standard);
}
@media (hover: hover) { .conv:hover { background: var(--surface-2); } }
.conv[aria-current="true"] { background: var(--surface-2); }
/* barra de 2px em linha de lista comunicando SELEÇÃO — não é o
   border-left: 4px decorativo em card, que é o anti-padrão banido. */
.conv[aria-current="true"]::before {
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 2px;
  background: var(--brand);
}

.conv__flag { display: flex; align-items: center; justify-content: center; }
.conv__unread { width: 6px; height: 6px; border-radius: var(--radius-pill); background: var(--brand); }

.conv__main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.conv__top  { display: flex; align-items: baseline; gap: var(--sp-2); min-width: 0; }
.conv__name { font-size: var(--text-body); line-height: var(--lh-body); color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.conv--unread .conv__name { font-weight: var(--fw-body-strong); }
.conv__time { margin-left: auto; flex: none; font-size: var(--text-micro); line-height: var(--lh-micro); letter-spacing: var(--ls-micro); font-weight: var(--fw-micro); color: var(--ink-subtle); font-variant-numeric: tabular-nums; }
.conv__preview {
  font-size: var(--text-caption);
  line-height: var(--lh-caption);
  letter-spacing: var(--ls-caption);
  color: var(--ink-subtle);
  display: -webkit-box;
  -webkit-line-clamp: 1;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-width: 0;
}
.conv__meta { display: flex; align-items: center; gap: var(--sp-1); min-width: 0; }
.conv__side { display: flex; flex-direction: column; align-items: flex-end; gap: var(--sp-1); flex: none; }
.conv__action { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; border-radius: var(--radius-xs); color: var(--ink-faint); }
@media (hover: hover) { .conv__action:hover { background: var(--surface-3); color: var(--ink); } }

.conv-error {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--pane-pad);
  background: var(--danger-soft);
  color: var(--danger);
  font-size: var(--text-caption);
  border-bottom: 1px solid var(--hairline);
}


/* ═══ 15 · CARD DO KANBAN (§7.4) ════════════════════════════════════════════
   Rolagem horizontal INTENCIONAL: `scroll-snap` prende cada coluna na borda
   esquerda, e no celular a coluna deixa um naco da seguinte à mostra — é o
   que conta ao dedo que existe mais funil à direita. `overscroll-behavior-x:
   contain` impede que o gesto vaze para a navegação de "voltar" do
   navegador no meio do arraste.                                          ═══ */

.kanban {
  display: flex;
  gap: var(--sp-3);
  align-items: flex-start;
  padding: var(--pane-pad);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-padding-left: var(--pane-pad);
  height: auto;
}
@media (min-width: 900px) {
  .kanban { padding: var(--sp-4); height: 100%; }
}

.kcol {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  width: min(300px, 84vw);
  flex: none;
  scroll-snap-align: start;
}
@media (min-width: 900px) {
  .kcol { width: 300px; max-height: 100%; }
}
.kcol__head { display: flex; align-items: center; gap: var(--sp-2); padding: 0 var(--sp-1) var(--sp-1); }
.kcol__title { font-size: var(--text-label); font-weight: var(--fw-label); color: var(--ink); }
.kcol__count { font-size: var(--text-micro); color: var(--ink-subtle); font-variant-numeric: tabular-nums; }
.kcol__body { display: flex; flex-direction: column; gap: var(--sp-2); overflow-y: auto; padding-bottom: var(--sp-2); }
.kcol--quiet .kcol__body { background: var(--surface-2); border-radius: var(--radius-md); padding: var(--sp-2); }

.kcard {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-3);
  background: var(--surface-1);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  box-shadow: none;
  text-align: left;
  transition: border-color var(--dur-fast) var(--ease-standard);
}
@media (hover: hover) {
  .kcard:hover { border-color: var(--hairline-strong); cursor: grab; }
}
.kcard:focus-visible { border-radius: var(--radius-md); }
.kcard__title { font-size: var(--text-body); font-weight: var(--fw-body-strong); color: var(--ink); }
.kcard__value { font-size: var(--text-body); color: var(--ink-muted); font-variant-numeric: tabular-nums; }
.kcard__foot  { display: flex; align-items: center; gap: var(--sp-2); }
.kcard[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }

.kcard--dragging {
  box-shadow: var(--elev-overlay);
  transform: rotate(1.5deg);
  transform-origin: 50% 50%;
  user-select: none;
  cursor: grabbing;
  transition: box-shadow var(--dur-fast) var(--ease-standard),
              transform var(--dur-fast) var(--ease-standard);
}

.kcard__error {
  margin: calc(var(--sp-3) * -1) calc(var(--sp-3) * -1) 0;
  padding: var(--sp-1) var(--sp-3);
  background: var(--danger-soft);
  color: var(--danger);
  font-size: var(--text-micro);
  border-radius: var(--radius-md) var(--radius-md) 0 0;
}

.kcol__empty {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 88px;
  padding: var(--sp-4);
  border: 1px dashed var(--hairline);
  border-radius: var(--radius-md);
  font-size: var(--text-caption);
  color: var(--ink-faint);
  text-align: center;
}


/* ═══ 16 · MODAL / DRAWER (§7.4) ════════════════════════════════════════════ */

.scrim {
  position: fixed;
  inset: 0;
  background: var(--scrim);
  z-index: 100;
  animation: ame-fade var(--dur-slow) var(--ease-out) both;
}
@keyframes ame-fade { from { opacity: 0; } to { opacity: 1; } }

.modal-layer {
  position: fixed;
  inset: 0;
  z-index: 101;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Colado nas bordas: respeita notch e barra de gestos. No celular a
     moldura é fina — 24px de cada lado num viewport de 360 sobrariam 312px
     de diálogo, e aí o formulário de dentro é que paga. */
  padding: var(--sp-3);
  padding-top: max(var(--sp-3), env(safe-area-inset-top, 0px));
  padding-bottom: max(var(--sp-3), env(safe-area-inset-bottom, 0px));
  pointer-events: none;
}
@media (min-width: 640px) {
  .modal-layer { padding: var(--sp-6); }
}

.modal {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 640px;
  max-height: calc(100vh - var(--sp-8));
  max-height: calc(100dvh - var(--sp-8));
  background: var(--surface-1);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--elev-overlay);
  overflow: hidden;
  overscroll-behavior: contain;
  pointer-events: auto;
  animation: ame-modal-in var(--dur-slow) var(--ease-out) both;
}
.modal--sm { max-width: 480px; }
.modal--md { max-width: 640px; }
.modal--lg { max-width: 840px; }
@keyframes ame-modal-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

.modal__header {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--modal-pad, var(--sp-4));
  border-bottom: 1px solid var(--hairline);
  flex: none;
}
.modal__title { font-size: var(--text-title); line-height: var(--lh-title); letter-spacing: var(--ls-title); font-weight: var(--fw-title); }
.modal__desc  { font-size: var(--text-body); color: var(--ink-subtle); margin-top: var(--sp-1); }
.modal__body  { padding: var(--modal-pad, var(--sp-4)); overflow-y: auto; flex: 1; min-height: 0; overscroll-behavior: contain; }
.modal__footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--modal-pad, var(--sp-4));
  border-top: 1px solid var(--hairline);
  flex: none;
}
/* Só a partir do `sm` a moldura interna do diálogo abre para 20px. */
@media (min-width: 640px) { .modal { --modal-pad: var(--sp-5); } }
.modal__error {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  margin: 0 var(--modal-pad, var(--sp-4)) var(--sp-4);
  padding: var(--sp-2) var(--sp-3);
  background: var(--danger-soft);
  color: var(--danger);
  border-radius: var(--radius-sm);
  font-size: var(--text-caption);
}

/* Drawer: mesma linguagem, ancorado à direita. */
.drawer {
  position: fixed;
  top: 0; right: 0; bottom: 0;
  z-index: 101;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 480px;
  background: var(--surface-1);
  border-left: 1px solid var(--hairline);
  box-shadow: var(--elev-overlay);
  overscroll-behavior: contain;
  animation: ame-drawer-in var(--dur-slow) var(--ease-out) both;
}
.drawer--md { max-width: 640px; }
.drawer--lg { max-width: 840px; }
@keyframes ame-drawer-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Popover / dropdown — o único outro uso de sombra, e é a raised. */
.popover {
  position: absolute;
  z-index: 90;
  min-width: 200px;
  padding: var(--sp-1);
  background: var(--surface-1);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  box-shadow: var(--elev-raised);
}
.menu-item {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  width: 100%;
  min-height: 32px;
  padding: 0 var(--sp-2);
  border-radius: var(--radius-xs);
  font-size: var(--text-body);
  color: var(--ink);
  text-align: left;
  transition: background-color var(--dur-fast) var(--ease-standard);
}
.menu-item--danger { color: var(--danger); }
@media (hover: hover) {
  .menu-item:hover { background: var(--surface-2); }
  .menu-item--danger:hover { background: var(--danger-soft); }
}
.menu-sep { height: 1px; margin: var(--sp-1) 0; background: var(--hairline); }


/* ═══ 17 · TOAST (§7.4) ═════════════════════════════════════════════════════
   Região aria-live="polite"; tone danger é assertive e PERSISTENTE.
   Toda ação destrutiva vem com desfazer de 5 segundos.                     */

/* No celular o aviso ocupa a largura do rodapé — uma caixa de 380px alinhada
   à direita num viewport de 360 seria a mesma coisa com sobra desperdiçada.
   A barra de gestos do iPhone entra na conta pelo `env()`. */
.toast-region {
  position: fixed;
  left: max(var(--sp-3), env(safe-area-inset-left, 0px));
  right: max(var(--sp-3), env(safe-area-inset-right, 0px));
  bottom: calc(var(--sp-3) + env(safe-area-inset-bottom, 0px));
  z-index: 120;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
@media (min-width: 640px) {
  .toast-region {
    left: auto;
    right: var(--sp-4);
    bottom: calc(var(--sp-4) + env(safe-area-inset-bottom, 0px));
    width: min(380px, calc(100vw - var(--sp-8)));
  }
}

.toast {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  padding: var(--sp-3);
  background: var(--surface-1);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  box-shadow: var(--elev-overlay);
  animation: ame-toast-in var(--dur-base) var(--ease-out) both;
}
@keyframes ame-toast-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
.toast--leaving { animation: ame-fade var(--dur-fast) var(--ease-standard) reverse both; }

.toast__icon    { color: var(--ink-muted); margin-top: 1px; }
.toast--success .toast__icon { color: var(--success); }
.toast--warning .toast__icon { color: var(--warning); }
.toast--danger  .toast__icon { color: var(--danger); }
.toast--info    .toast__icon { color: var(--info); }

.toast__main    { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.toast__title   { font-size: var(--text-body); font-weight: var(--fw-body-strong); color: var(--ink); }
.toast__desc    { font-size: var(--text-caption); line-height: var(--lh-caption); color: var(--ink-subtle); }
.toast__actions { display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-1); }
.toast__close   { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; flex: none; border-radius: var(--radius-xs); color: var(--ink-faint); }
@media (hover: hover) { .toast__close:hover { background: var(--surface-2); color: var(--ink); } }
.toast__spinner { width: 16px; height: 16px; flex: none; margin-top: 1px; border-radius: var(--radius-pill); border: 1.5px solid var(--ink-faint); border-top-color: transparent; transform-origin: 50% 50%; animation: ame-spin 700ms linear infinite; }


/* ═══ 18 · TABELA (CRM) (§7.4) ══════════════════════════════════════════════
   CRM é tabela densa, nunca grade de cards. Sem zebra striping.           */

/* A tabela é larga por natureza e NÃO pode empurrar o <body> na horizontal:
   ela rola dentro do próprio invólucro, e o gesto não vaza para a página. */
.table-wrap {
  width: 100%;
  overflow-x: auto;
  overscroll-behavior-x: contain;
}

.table { width: 100%; font-size: var(--text-body); }
.table thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--surface-1);
  border-bottom: 1px solid var(--hairline);
  padding: var(--sp-2) var(--sp-3);
  text-align: left;
  font-size: var(--text-label);
  line-height: var(--lh-label);
  font-weight: var(--fw-label);
  color: var(--ink-subtle);
  white-space: nowrap;
}
.table tbody tr {
  height: var(--table-row-h);
  border-bottom: 1px solid var(--hairline);
  transition: background-color var(--dur-fast) var(--ease-standard);
}
@media (hover: hover) { .table tbody tr:hover { background: var(--surface-2); } }
.table tbody td { padding: 0 var(--sp-3); color: var(--ink); vertical-align: middle; }

.table tbody tr[aria-selected="true"] { background: var(--surface-2); }
.table tbody tr[aria-selected="true"] td:first-child { box-shadow: inset 2px 0 0 0 var(--brand); }
.table tbody tr[data-archived] { opacity: .55; }
.table tbody tr[data-error] td:first-child { box-shadow: inset 2px 0 0 0 var(--danger); }

.table th[data-kind="numeric"], .table td[data-kind="numeric"],
.table th[data-kind="currency"], .table td[data-kind="currency"] {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.table td[data-kind="actions"] { text-align: right; white-space: nowrap; width: 1%; }

.table--long tbody tr { content-visibility: auto; contain-intrinsic-size: auto var(--table-row-h); }

.th-sort { display: inline-flex; align-items: center; gap: var(--sp-1); color: inherit; font: inherit; }
@media (hover: hover) { .th-sort:hover { color: var(--ink); } }


/* ═══ 19 · EMPTY STATE (§7.4) ═══════════════════════════════════════════════
   Duas partes de instrução para uma de personalidade. Ícone SVG 32px,
   traço 1.5, em ink-faint. Emoji como ícone é erro de build.              */

.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-2);
  max-width: 420px;
  margin: var(--sp-10) auto;
  padding: 0 var(--gutter);
  text-align: center;
}
@media (min-width: 900px) { .empty { margin: var(--sp-16) auto; } }
.empty__icon  { color: var(--ink-faint); margin-bottom: var(--sp-1); }
.empty__title { font-size: var(--text-title); line-height: var(--lh-title); letter-spacing: var(--ls-title); font-weight: var(--fw-title); color: var(--ink); }
.empty__desc  { font-size: var(--text-body); line-height: var(--lh-body); color: var(--ink-subtle); }
.empty__actions { display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-3); }

.empty--achievement .empty__icon { color: var(--success); }   /* inbox zero, SEM CTA */
.empty--neutral     .empty__icon { color: var(--ink-faint); }
.empty--error       .empty__icon { color: var(--danger); }

/* onboarding: 3 passos VERTICAIS separados por hairline.
   Nunca 3 cards lado a lado, nunca círculos numerados coloridos. */
.empty--onboarding { max-width: 480px; text-align: left; align-items: stretch; }
.empty--onboarding .empty__icon,
.empty--onboarding .empty__title,
.empty--onboarding .empty__desc { text-align: left; }
.steps { display: flex; flex-direction: column; margin-top: var(--sp-3); border-top: 1px solid var(--hairline); }
.step {
  display: grid;
  grid-template-columns: 20px 1fr;
  gap: var(--sp-3);
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--hairline);
}
.step__n    { font-size: var(--text-micro); font-weight: var(--fw-micro); color: var(--ink-faint); font-variant-numeric: tabular-nums; padding-top: 3px; }
.step__title{ font-size: var(--text-body); font-weight: var(--fw-body-strong); color: var(--ink); }
.step__desc { font-size: var(--text-caption); line-height: var(--lh-caption); color: var(--ink-subtle); margin-top: 2px; }

/* Callout — instrução ou aviso dentro do fluxo. */
.callout {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  padding: var(--sp-3);
  border-radius: var(--radius-md);
  border: 1px solid var(--hairline);
  background: var(--surface-2);
  font-size: var(--text-caption);
  line-height: var(--lh-caption);
  color: var(--ink-muted);
}
.callout__icon { color: var(--ink-subtle); margin-top: 1px; }
.callout--info    { background: var(--info-soft);    border-color: transparent; color: var(--info); }
.callout--warning { background: var(--warning-soft); border-color: transparent; color: var(--warning); }
.callout--danger  { background: var(--danger-soft);  border-color: transparent; color: var(--danger); }
.callout--success { background: var(--success-soft); border-color: transparent; color: var(--success); }
.callout--bot     { background: var(--bot-soft);     border-color: transparent; color: var(--bot); }
.callout--info .callout__icon,
.callout--warning .callout__icon,
.callout--danger .callout__icon,
.callout--success .callout__icon,
.callout--bot .callout__icon { color: currentColor; }


/* ═══ 20 · SKELETON (§7.4) ══════════════════════════════════════════════════
   Reproduz a GEOMETRIA EXATA do conteúdo final. Spinner centralizado no lugar
   de uma lista é proibido. Bloco aria-hidden + um único sr-only por região.
   Com reduced-motion: opacidade fixa em .8, sem pulso — outra representação,
   não uma animação mais rápida.                                            */

.skel {
  display: block;
  background: var(--surface-2);
  border-radius: var(--radius-xs);
  animation: ame-skel 1.6s ease-in-out infinite;
}
@keyframes ame-skel { 0%, 100% { opacity: .6; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .skel { animation: none; opacity: .8; }
}

.skel--text   { height: 10px; border-radius: var(--radius-pill); }
.skel--line   { height: 14px; border-radius: var(--radius-xs); }
.skel--pill   { height: 16px; width: 64px; border-radius: var(--radius-pill); }
.skel--circle { border-radius: var(--radius-pill); }
.skel--bubble { height: 40px; border-radius: var(--radius-lg); }
.skel--20 { width: 20px; height: 20px; }
.skel--24 { width: 24px; height: 24px; }
.skel--32 { width: 32px; height: 32px; }
.skel--40 { width: 40px; height: 40px; }
.skel--64 { width: 64px; height: 64px; }
.skel-w-38 { width: 38%; } .skel-w-45 { width: 45%; } .skel-w-55 { width: 55%; }
.skel-w-60 { width: 60%; } .skel-w-62 { width: 62%; } .skel-w-70 { width: 70%; }
.skel-w-85 { width: 85%; } .skel-w-100 { width: 100%; }

/* Geometria pronta da linha de conversa: círculo 32 + barras 60% e 85%. */
.skel-conv {
  display: grid;
  grid-template-columns: 8px 32px 1fr;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--row-h);
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--hairline);
}
.skel-conv__main { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }


/* ═══ 21 · MÍDIA E ANEXOS ═══════════════════════════════════════════════════ */

.thumb {
  border-radius: var(--radius-md);
  border: 1px solid var(--hairline);
  background: var(--surface-2);
  overflow: hidden;
}
.attach {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  background: var(--surface-1);
  font-size: var(--text-caption);
  color: var(--ink-muted);
}
.waveform { display: flex; align-items: center; gap: 2px; height: 20px; }
.waveform i { display: block; width: 2px; border-radius: var(--radius-pill); background: var(--ink-faint); }


/* ═══ 22 · UTILITÁRIOS DE ESPAÇO (uso pontual) ══════════════════════════════ */

.p-2 { padding: var(--sp-2); } .p-3 { padding: var(--sp-3); }
.p-4 { padding: var(--sp-4); } .p-6 { padding: var(--sp-6); }
.px-3 { padding-inline: var(--sp-3); } .px-4 { padding-inline: var(--sp-4); }
.py-2 { padding-block: var(--sp-2); } .py-3 { padding-block: var(--sp-3); }
.mt-1 { margin-top: var(--sp-1); } .mt-2 { margin-top: var(--sp-2); }
.mt-3 { margin-top: var(--sp-3); } .mt-4 { margin-top: var(--sp-4); }
.mt-6 { margin-top: var(--sp-6); }
.grow { flex: 1; min-width: 0; } .none { flex: none; }
.hide { display: none; }


/* ═══ 23 · BARRA DE NAVEGAÇÃO DO MOCKUP ═════════════════════════════════════
   Chrome do mockup, NÃO faz parte do produto: barra fina fixa que torna as
   telas navegáveis sem servidor. Fica fora de qualquer landmark do app e é
   idêntica em todas as páginas.

   ── OITO LINKS EM 360px ────────────────────────────────────────────────────
   Não cabem, e a saída NÃO pode ser um hambúrguer: esta barra é o que torna
   o mockup demonstrável — se ela vira um ícone, a apresentação morre no
   primeiro clique. Então a barra resolve assim, em três movimentos:

     1. o RÓTULO ("Mockup — Conector Ame") some abaixo do `md`. É decoração:
        a barra já se anuncia por `aria-label`, e no celular cada pixel dele
        estaria roubando espaço da navegação, que é a função.
     2. os LINKS rolam na horizontal dentro de `.mockbar__nav`, com snap
        discreto e sem barra de rolagem visível. Nenhum link é escondido —
        o corte no link parcialmente visível à direita é o próprio convite a
        arrastar, e não há gradiente de fade (§7.7 proíbe).
     3. a barra é mais ALTA no toque (44px) que no mouse (36px), porque um
        alvo de 24px de altura não é tocável. `--mockbar-h` cuida disso.

   O offset é automático: `body:has(.mockbar)` ganha o padding do topo, e
   `--mockbar-offset` (barra + notch) é o que o `.app-shell`, o `.site-nav`,
   o `.doc-toc` e o `.skip-link` leem. NENHUMA página compensa nada, e a
   string "36px" não aparece mais em lugar nenhum do arquivo.             */

.mockbar {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 150;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  height: var(--mockbar-offset);
  padding-top: env(safe-area-inset-top, 0px);
  padding-left: max(var(--sp-2), env(safe-area-inset-left, 0px));
  padding-right: max(var(--sp-2), env(safe-area-inset-right, 0px));
  background: var(--surface-2);
  border-bottom: 1px solid var(--hairline);
}
body:has(.mockbar) { padding-top: var(--mockbar-offset); }

/* Decoração. No celular a barra é 100% navegação. */
.mockbar__label {
  display: none;
  flex: none;
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  color: var(--ink-subtle);
}

/* `align-self: stretch` não é cosmético: sem ele o contêiner de rolagem teria
   a altura do link (28px) e recortaria pela metade o alvo invisível de 44px
   do `.mockbar__link` — o toque voltaria a 28px, que é o problema que o alvo
   existe para resolver. Esticado, o alvo cabe inteiro dentro da barra. */
.mockbar__nav {
  display: flex;
  align-items: center;
  align-self: stretch;
  gap: var(--sp-1);
  flex: 1 1 auto;
  min-width: 0;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
}
.mockbar__nav::-webkit-scrollbar { display: none; }

/* Sem rótulo à esquerda o espaçador não tem o que empurrar: some, e a
   navegação fica com a largura inteira. Volta a existir no `md`. */
.mockbar__spacer { display: none; }

.mockbar__link {
  display: inline-flex;
  align-items: center;
  flex: none;
  height: 28px;
  padding-inline: var(--sp-2);
  border-radius: var(--radius-xs);
  white-space: nowrap;
  text-decoration: none;
  color: var(--ink-muted);
  font-size: var(--text-caption);
  line-height: var(--lh-caption);
  scroll-snap-align: start;
  transition: background-color var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard);
}
.mockbar__link[aria-current="page"] { background: var(--surface-3); color: var(--ink); }
.mockbar__link:focus-visible { transition: none; }
@media (hover: hover) {
  .mockbar__link:hover { background: var(--surface-3); color: var(--ink); }
}

/* O alvo cobre a altura inteira da barra sem engordar o retângulo pintado. */
@media (pointer: coarse) {
  .mockbar__link { position: relative; }
  .mockbar__link::after {
    content: '';
    position: absolute;
    inset: 50% 0 auto 0;
    height: 44px;
    transform: translateY(-50%);
  }
}

@media (min-width: 900px) {
  .mockbar {
    gap: var(--sp-4);
    padding-left: var(--sp-3);
    padding-right: var(--sp-3);
  }
  .mockbar__label  { display: block; }
  .mockbar__nav    { flex: 0 1 auto; }
  .mockbar__spacer { display: block; flex: 1; }
  .mockbar__link   { height: 24px; }
}


/* ═══ 24 · PÁGINAS LEGAIS (privacidade · termos · exclusão de dados) ═════════
   Rota de leitura, não rota de operação: medida de linha curta, corpo em
   16px/1.55, índice lateral fixo. A tipografia é escopada em `.doc` porque
   um texto jurídico tem centenas de <p> e <li> — encher de classe utilitária
   seria ruído sem ganho. Nada aqui anima na entrada (§7.6).             ═══ */

/* Uma coluna no celular; o índice vira uma caixa estática antes do texto.
   Duas colunas só no `md`, que é onde 232px de índice deixam de comer a
   medida de leitura. */
.doc-page {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-6);
  align-items: start;
  max-width: 1040px;
  margin-inline: auto;
  padding: var(--sp-6) var(--gutter) var(--section-y);
  /* Página de leitura em paisagem no iPhone: o notch não come a primeira
     letra de cada linha, e a barra de gestos não come a última do rodapé. */
  padding-left: max(var(--gutter), env(safe-area-inset-left, 0px));
  padding-right: max(var(--gutter), env(safe-area-inset-right, 0px));
  padding-bottom: calc(var(--section-y) + env(safe-area-inset-bottom, 0px));
}
@media (min-width: 900px) {
  .doc-page {
    grid-template-columns: 232px minmax(0, 1fr);
    gap: var(--sp-10);
    padding-top: var(--sp-10);
  }
}

/* Índice. Caixa estática no celular; sticky abaixo da barra do mockup no `md`. */
.doc-toc {
  min-width: 0;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  background: var(--surface-1);
  padding: var(--sp-3);
}
@media (min-width: 900px) {
  .doc-toc {
    position: sticky;
    top: calc(var(--mockbar-offset) + var(--sp-6));
    border: 0;
    border-radius: 0;
    background: none;
    padding: 0;
  }
}
.doc-toc__title {
  font-size: var(--text-label);
  line-height: var(--lh-label);
  font-weight: var(--fw-label);
  color: var(--ink-subtle);
  padding-inline: var(--sp-2);
  margin-bottom: var(--sp-2);
}
.doc-toc__list { list-style: none; display: flex; flex-direction: column; gap: 1px; }
.doc-toc__link {
  display: block;
  padding: 5px var(--sp-2);
  border-left: 1px solid var(--hairline);
  color: var(--ink-muted);
  font-size: var(--text-caption);
  line-height: 1.45;
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease-standard),
              border-color var(--dur-fast) var(--ease-standard);
}
@media (hover: hover) {
  .doc-toc__link:hover { color: var(--ink); border-left-color: var(--hairline-strong); }
}
.doc-toc__link[aria-current="true"] {
  color: var(--ink);
  border-left-color: var(--brand);
  font-weight: var(--fw-body-strong);
}
.doc-toc__link:focus-visible { transition: none; }


/* ═══ 24.1 · SUMÁRIO RECOLHÍVEL — privacidade · termos · exclusão de dados ═══
   Catorze itens de índice no topo de um celular não são navegação, são uma
   parede: empurram o primeiro parágrafo para fora da tela e obrigam a rolar
   antes de começar a ler. No celular o índice vira um `<details>` fechado —
   uma linha de 44px que abre no toque. Do `md` para cima o gatilho volta a ser
   apenas o rótulo da §24 e o índice é de novo a coluna fixa.

   Por que o `open` é escrito pelo script da página e não por CSS: nos motores
   atuais o conteúdo de um `<details>` fechado é ocultado por
   `::details-content { content-visibility: hidden }`, e `display` num filho não
   desfaz isso. Forçar por CSS daria um índice invisível no desktop — o pior
   defeito possível numa página de 14 seções.
   A proposta comercial usa a mesma `.doc-toc` sem este modificador e continua
   sendo a caixa estática de sempre.                                       ═══ */

.doc-toc--collapse > details { min-width: 0; }

.doc-toc__summary {
  display: flex;             /* já remove o triângulo na maioria dos motores */
  align-items: center;
  gap: var(--sp-2);
  min-height: 44px;          /* alvo de toque honesto, não área invisível */
  padding-inline: var(--sp-2);
  cursor: pointer;
  list-style: none;          /* Firefox */
  color: var(--ink-muted);
}
.doc-toc__summary::-webkit-details-marker { display: none; }   /* Safari */
.doc-toc__summary:focus-visible { border-radius: var(--radius-sm); }

/* Dentro do resumo quem carrega padding e margem é o próprio <summary>. */
.doc-toc--collapse .doc-toc__title { padding-inline: 0; margin-bottom: 0; }

/* Sem transição: o orçamento de motion da §20 é fechado e não inclui seta de
   disclosure. O giro é troca de estado, não animação. */
.doc-toc__chevron { margin-left: auto; color: var(--ink-faint); }
[open] > .doc-toc__summary .doc-toc__chevron { transform: rotate(180deg); }

.doc-toc--collapse .doc-toc__list { margin-top: var(--sp-2); }

@media (min-width: 900px) {
  /* Coluna fixa de novo: o resumo perde a função de gatilho e passa a ser só
     o rótulo. `pointer-events: none` impede fechar por clique; o script
     reabre por segurança se alguém acionar pelo teclado. */
  .doc-toc__summary {
    min-height: 0;
    margin-bottom: var(--sp-2);
    cursor: default;
    pointer-events: none;
  }
  .doc-toc__chevron { display: none; }
  .doc-toc--collapse .doc-toc__list { margin-top: 0; }
}

/* No dedo o item do índice é navegação primária: a §4 já garante os 44px de
   altura, aqui o rótulo passa a ficar centrado neles em vez de encostado no
   topo. O mesmo vale para os links do rodapé do documento. */
@media (pointer: coarse) {
  .doc-toc__link { display: flex; align-items: center; }
  .doc-foot a { display: inline-flex; align-items: center; min-height: 44px; }
}

/* Coluna de leitura. */
.doc { max-width: var(--spacing-readcol); min-width: 0; }

/* ── Escada tipográfica das páginas legais ──────────────────────────────────
   Texto longo é onde a tipografia de celular aparece. Duas correções, ambas
   escopadas em `--legal` para não mexer na proposta comercial, que usa a mesma
   `.doc` com outra finalidade:

   1. medida de linha — 680px com corpo de 16px dá ~78 caracteres, acima do
      confortável; 640px fecha em ~72. No celular quem manda é o gutter;
   2. hierarquia — na escala base o `h3` (14px) é MENOR que o corpo do
      documento (16px), e um subtítulo menor que o parágrafo que ele abre
      inverte a hierarquia justamente na tela onde ela mais importa. A escada
      passa a ser 24/20/18/16 em 360px e 32/24/18/16 no desktop.

   O seletor é filho direto de `.doc-section` de propósito: o `h3` que titula
   um `.panel` (o formulário de exclusão) continua com a tipografia do
   sistema.                                                              ── */
.doc--legal { max-width: 640px; }
.doc--legal .doc-section > h2 {
  font-size: var(--text-headline);
  line-height: var(--lh-headline);
  letter-spacing: var(--ls-headline);
  font-weight: var(--fw-headline);
}
.doc--legal .doc-section > h3 {
  font-size: var(--text-title);
  line-height: var(--lh-title);
  letter-spacing: var(--ls-title);
  font-weight: var(--fw-title);
  margin-top: var(--sp-6);
}

.doc__eyebrow {
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  color: var(--ink-subtle);
}
.doc__lead {
  font-size: var(--text-body-lg);
  line-height: var(--lh-body-lg);
  color: var(--ink-muted);
  margin-top: var(--sp-3);
}
.doc__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-4);
  margin-top: var(--sp-4);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--hairline);
  font-size: var(--text-caption);
  color: var(--ink-subtle);
}

.doc-section { padding-top: var(--sp-6); scroll-margin-top: calc(var(--mockbar-offset) + var(--sp-4)); }
@media (min-width: 900px) {
  .doc-section { padding-top: var(--sp-8); scroll-margin-top: calc(var(--mockbar-offset) + var(--sp-6)); }
}
.doc-section + .doc-section { border-top: 1px solid var(--hairline); }

.doc h2 {
  font-size: var(--text-title);
  line-height: var(--lh-title);
  letter-spacing: var(--ls-title);
  font-weight: var(--fw-title);
  margin-bottom: var(--sp-3);
}
.doc h3 {
  font-size: var(--text-body);
  line-height: var(--lh-body);
  font-weight: var(--fw-body-strong);
  margin-top: var(--sp-5);
  margin-bottom: var(--sp-2);
}
.doc h2 .doc__num, .doc h3 .doc__num {
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
  margin-right: var(--sp-2);
}
/* Escopo em filho direto da seção: o texto corrido cresce para 16px, mas
   callout, formulário, tabela e .steps mantêm a tipografia do sistema. */
.doc-section > p:not(.callout),
.doc-section > ul > li,
.doc-section > ol:not(.steps) > li {
  font-size: var(--text-body-lg);
  line-height: var(--lh-body-lg);
  letter-spacing: var(--ls-body-lg);
  color: var(--ink);
}
.doc-section > p + p { margin-top: var(--sp-3); }
.doc-section > ul,
.doc-section > ol:not(.steps) { margin-top: var(--sp-3); padding-left: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-2); }
.doc-section > ul { list-style: none; }
.doc-section > ul > li { position: relative; }
.doc-section > ul > li::before {
  content: '';
  position: absolute;
  left: calc(var(--sp-4) * -1);
  top: 0.68em;
  width: 5px; height: 1px;
  background: var(--ink-faint);
}
.doc-section > ol:not(.steps) { list-style: decimal; }
.doc-section > ol:not(.steps) > li::marker { color: var(--ink-subtle); font-size: var(--text-body); }
.doc a:not(.btn):not(.doc-toc__link) {
  color: var(--brand);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
@media (hover: hover) {
  .doc a:not(.btn):not(.doc-toc__link):hover { color: var(--brand-hover); }
}
.doc > * + .callout, .doc .callout { margin-top: var(--sp-3); }
.doc .table-wrap, .doc .panel { margin-top: var(--sp-4); }

/* Definição: termo curto + explicação. Usada em "o que coletamos". */
.doc-dl { margin-top: var(--sp-4); display: flex; flex-direction: column; }
.doc-dl > div {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-1);
  padding-block: var(--sp-3);
  border-top: 1px solid var(--hairline);
}
@media (min-width: 640px) {
  .doc-dl > div { grid-template-columns: 200px minmax(0, 1fr); gap: var(--sp-4); }
}
.doc-dl > div:last-child { border-bottom: 1px solid var(--hairline); }
.doc-dl dt { font-size: var(--text-body); font-weight: var(--fw-body-strong); color: var(--ink); }
.doc-dl dd { font-size: var(--text-body); line-height: var(--lh-body); color: var(--ink-muted); }

/* Trecho que o jurídico ainda precisa preencher. Honesto: a minuta mostra
   onde está o buraco em vez de fingir que já tem CNPJ. */
.doc-pend {
  background: var(--warning-soft);
  color: var(--ink);
  border-bottom: 1px dashed var(--warning);
  padding-inline: 2px;
  border-radius: var(--radius-xs);
}

/* Rodapé das páginas legais: irmãs do documento. */
.doc-foot {
  margin-top: var(--sp-10);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--hairline);
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-4);
  font-size: var(--text-caption);
  color: var(--ink-subtle);
}


/* ═══ 25 · LANDING PÚBLICA (index.html) ═════════════════════════════════════
   Editorial, não brochura de SaaS: medida de leitura curta, tudo alinhado à
   esquerda, seções separadas por hairline, módulos em FOLHA DE ESPECIFICAÇÃO
   (linha com ícone ao lado do nome) e não em grade de cards ícone-no-topo.
   Sem gradiente, sem glow, sem pill acima do H1, sem hero centralizado.
   A barra de mockup é a `.mockbar` da §23 — esta seção não a redefine.     */

/* `--gutter` já é 16 no celular e 24 no `md`: a margem lateral da landing é a
   mesma da rota de leitura e da proposta, e sobe junto. */
.site-wrap {
  width: 100%;
  max-width: 1120px;
  margin-inline: auto;
  padding-left: max(var(--gutter), env(safe-area-inset-left, 0px));
  padding-right: max(var(--gutter), env(safe-area-inset-right, 0px));
}

.site-nav {
  position: sticky;
  top: var(--mockbar-offset);   /* logo abaixo da .mockbar (§23) */
  z-index: 50;
  background: var(--canvas);
  border-bottom: 1px solid var(--hairline);
}
.site-nav__inner {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
  min-height: 56px;
  padding-block: var(--sp-2);
}
@media (min-width: 900px) {
  .site-nav__inner { gap: var(--sp-4); flex-wrap: nowrap; min-height: 64px; padding-block: 0; }
}

.wordmark {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--text-title);
  line-height: var(--lh-title);
  letter-spacing: var(--ls-title);
  font-weight: var(--fw-title);
  color: var(--ink);
}
.wordmark__mark { color: var(--brand); }
.wordmark__sub {
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  color: var(--ink-subtle);
  padding-left: var(--sp-2);
  margin-left: var(--sp-1);
  border-left: 1px solid var(--hairline);
}

.lp-section { padding-block: var(--section-y); border-top: 1px solid var(--hairline); }
.lp-section__head { max-width: 62ch; }

/* Kicker editorial: texto curto + régua de 1px. Nunca uma pill. */
.lp-kicker {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  color: var(--ink-subtle);
  margin-bottom: var(--sp-4);
}
.lp-kicker::after { content: ""; flex: 1; height: 1px; background: var(--hairline); }

/* ── Hero: alinhado à esquerda, medida curta, dois botões e nada mais. ── */
.lp-hero { padding-block: var(--sp-10) var(--sp-8); }
.lp-hero__title { max-width: 20ch; color: var(--ink); }
.lp-hero__lede  { max-width: 56ch; color: var(--ink-muted); margin-top: var(--sp-4); }
/* Botão de largura cheia é a forma certa no celular: alvo grande, empilhado,
   sem dois botões disputando 360px. Voltam a ser inline no `sm`. */
.lp-hero__actions { display: flex; flex-direction: column; align-items: stretch; gap: var(--sp-3); margin-top: var(--sp-6); }
@media (min-width: 640px) {
  .lp-hero__actions { flex-direction: row; align-items: center; flex-wrap: wrap; }
}
@media (min-width: 900px) {
  .lp-hero { padding-block: var(--sp-16) var(--sp-12); }
  .lp-hero__lede { margin-top: var(--sp-5); }
  .lp-hero__actions { margin-top: var(--sp-8); }
}

.lp-facts {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  margin-top: var(--sp-8);
  border-block: 1px solid var(--hairline);
}
.lp-fact { padding: var(--sp-4) 0; }
.lp-fact + .lp-fact { border-top: 1px solid var(--hairline); }
.lp-fact__lead { color: var(--ink); }
.lp-fact__desc { color: var(--ink-subtle); margin-top: var(--sp-1); }
@media (min-width: 640px) {
  .lp-facts { grid-template-columns: repeat(3, minmax(0, 1fr)); margin-top: var(--sp-12); }
  .lp-fact { padding: var(--sp-5) var(--sp-5) var(--sp-5) 0; }
  .lp-fact + .lp-fact { padding-left: var(--sp-5); border-top: 0; border-left: 1px solid var(--hairline); }
}

/* ── Prova visual: recorte da inbox, construído em HTML/CSS. ── */
.lp-proof { margin: 0; }
.lp-proof__frame {
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius-lg);
  background: var(--surface-1);
  overflow: hidden;
}
.lp-proof__bar {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  height: 44px;
  padding: 0 var(--sp-3);
  background: var(--canvas);
  border-bottom: 1px solid var(--hairline);
}
.lp-proof__cols { display: grid; grid-template-columns: minmax(0, 1fr); }
.lp-proof__col { display: flex; flex-direction: column; min-width: 0; border-bottom: 1px solid var(--hairline); }
.lp-proof__col:last-child { border-bottom: 0; background: var(--canvas); }
@media (min-width: 1200px) {
  .lp-proof__cols { grid-template-columns: 330px minmax(0, 1fr); }
  .lp-proof__col { border-bottom: 0; border-right: 1px solid var(--hairline); }
  .lp-proof__col:last-child { border-right: 0; }
}
.lp-proof__head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  height: 40px;
  flex: none;
  padding: 0 var(--sp-3);
  border-bottom: 1px solid var(--hairline);
  overflow: hidden;
}
.lp-proof__meta { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* O recorte é literal: altura travada e overflow cortado — a sexta conversa
   aparece pela metade porque a fila continua abaixo dela. */
.lp-proof__crop { height: 300px; overflow: hidden; }
@media (min-width: 1200px) { .lp-proof__crop { height: 470px; } }
.lp-proof__foot { flex: none; padding: var(--sp-3); border-top: 1px solid var(--hairline); background: var(--surface-1); }
.lp-proof__caption { margin-top: var(--sp-3); font-size: var(--text-caption); line-height: var(--lh-caption); color: var(--ink-subtle); }

/* ── Módulos: folha de especificação. Linha, não card. ── */
.lp-modules { margin-top: var(--sp-8); border-top: 1px solid var(--hairline); }
/* Celular: numeral à esquerda, tudo o mais numa coluna só. A folha de
   especificação de quatro colunas só abre no `lg`, onde há largura para as
   quatro terem sentido. */
.lp-module {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr);
  gap: var(--sp-3) var(--sp-4);
  align-items: start;
  padding-block: var(--sp-5);
  border-bottom: 1px solid var(--hairline);
}
.lp-module__name,
.lp-module__body,
.lp-module__art { grid-column: 2; }
.lp-module__art { margin-top: var(--sp-2); }
@media (min-width: 1200px) {
  .lp-modules { margin-top: var(--sp-10); }
  .lp-module {
    grid-template-columns: 24px minmax(0, 260px) minmax(0, 1fr) 190px;
    gap: var(--sp-6);
    padding-block: var(--sp-6);
  }
  .lp-module__name,
  .lp-module__body,
  .lp-module__art { grid-column: auto; }
  .lp-module__art { margin-top: 0; }
}
.lp-module__n { font-size: var(--text-micro); font-weight: var(--fw-micro); color: var(--ink-faint); font-variant-numeric: tabular-nums; padding-top: 4px; }
.lp-module__name { display: flex; align-items: center; gap: var(--sp-2); color: var(--ink); }
.lp-module__name .icon { color: var(--brand); }
.lp-module__body { min-width: 0; }
.lp-module__desc { color: var(--ink-muted); max-width: 60ch; }
.lp-module__notes { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4); margin-top: var(--sp-3); }
.lp-module__note { display: inline-flex; align-items: center; gap: var(--sp-1); font-size: var(--text-caption); color: var(--ink-subtle); }
.lp-module__note .icon { color: var(--ink-faint); }

/* ── Seção da IA: duas colunas de garantias, separadas por hairline. ── */
.lp-split { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-6); margin-top: var(--sp-6); }
@media (min-width: 900px) {
  .lp-split { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-8); margin-top: var(--sp-8); }
}
.lp-col__title { display: flex; align-items: center; gap: var(--sp-2); color: var(--ink); padding-bottom: var(--sp-3); border-bottom: 1px solid var(--hairline); }
.lp-ticks { display: flex; flex-direction: column; }
.lp-tick { display: grid; grid-template-columns: 16px minmax(0, 1fr); gap: var(--sp-3); padding-block: var(--sp-3); border-bottom: 1px solid var(--hairline); font-size: var(--text-body); line-height: var(--lh-body); color: var(--ink-muted); }
.lp-tick .icon { margin-top: 3px; }
.lp-tick strong { color: var(--ink); font-weight: var(--fw-body-strong); }

/* ── Rodapé: exigência de aprovação da Meta. Os links legais são texto
      visível e nomeado, nunca ícone e nunca só na linha de baixo. ── */
.site-footer {
  border-top: 1px solid var(--hairline);
  background: var(--surface-1);
  padding-block: var(--sp-10) var(--sp-6);
  padding-bottom: calc(var(--sp-6) + env(safe-area-inset-bottom, 0px));
}
.site-footer__grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-6); }
@media (min-width: 640px) {
  .site-footer__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1200px) {
  .site-footer { padding-block: var(--sp-12) var(--sp-6); }
  .site-footer__grid { grid-template-columns: 1.5fr repeat(3, minmax(0, 1fr)); gap: var(--sp-8); }
}
.footer-col__title {
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  color: var(--ink-subtle);
  margin-bottom: var(--sp-3);
}
.site-footer__about { max-width: 44ch; }
.footer-nav { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-2); }
.footer-link {
  font-size: var(--text-body);
  line-height: var(--lh-body);
  color: var(--ink-muted);
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  transition: color var(--dur-fast) var(--ease-standard);
}
@media (hover: hover) {
  .footer-link:hover { color: var(--ink); text-decoration: underline; }
}
.site-footer__bottom {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-4);
  margin-top: var(--sp-8);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--hairline);
  font-size: var(--text-caption);
  line-height: var(--lh-caption);
  color: var(--ink-subtle);
}
@media (min-width: 1200px) { .site-footer__bottom { margin-top: var(--sp-10); } }


/* ── 27.1 · ARTE SVG DA LANDING ─────────────────────────────────────────────
   Desenhada à mão e embutida no HTML: file://, zero requisição, nenhuma
   imagem — nem remota, nem data-URI. Toda cor sai de TOKEN, e é por isso que
   a MESMA arte serve tema claro e escuro sem segunda versão (um PNG não faz
   isso). `var()` não é aceito em atributo de apresentação de SVG e a §0
   proíbe `style` inline, então cada cor abaixo precisa ser uma classe.
   Traço 1.5 com `non-scaling-stroke`: a hairline continua com 1,5px quando a
   peça encolhe no celular, em vez de sumir.                                */

.art {
  display: block;
  width: 100%;
  height: auto;
  fill: none;
  stroke: none;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.art * { vector-effect: non-scaling-stroke; }

/* Papel: as superfícies opacas. A profundidade vem da SOBREPOSIÇÃO delas —
   nunca de sombra, igual ao resto do produto. */
.art-paper          { fill: var(--surface-1); stroke: var(--hairline-strong); }
.art-paper--hair    { fill: var(--surface-1); stroke: var(--hairline); }
.art-paper--quiet   { fill: var(--surface-2); stroke: none; }
/* bolha recebida: surface-2 + hairline, a mesma leitura de `.msg--in` */
.art-paper--msg     { fill: var(--surface-2); stroke: var(--hairline-strong); }

/* Filetes e trilho. */
.art-hair { stroke: var(--hairline); }
.art-rail { stroke: var(--hairline-strong); stroke-dasharray: 1 6; }

/* Barras de conteúdo — o "texto" dentro das peças, em três valores. */
.art-bar          { fill: var(--hairline); }
.art-bar--strong  { fill: var(--hairline-strong); }
.art-bar--ink     { fill: var(--ink-faint); }

/* O caminho da mensagem. Sem ponta de seta: a direção é contada pela
   composição e pelo terminal, não por um diagrama de caixa e flecha. */
.art-flow     { stroke: var(--ink-muted); }
.art-flow--ai { stroke: var(--bot); stroke-dasharray: 5 4; }

/* Glifos de traço (pessoa, agente). */
.art-glyph     { stroke: var(--ink-muted); }
.art-glyph--ai { stroke: var(--bot); }

/* Portas do conector e terminais. A marca é ACENTO: aparece só aqui e no
   glifo do produto, nunca preenchendo superfície. */
.art-port         { fill: var(--surface-1); stroke: var(--hairline-strong); }
.art-dot          { fill: var(--ink-muted); }
.art-dot--brand   { fill: var(--brand); }
.art-dot--ai      { fill: var(--bot); }
.art-dot--warning { fill: var(--warning); }

/* Glifo do produto dentro do conector. */
.art-mark        { fill: var(--brand-soft); stroke: var(--brand-line); }
.art-mark__glyph { stroke: var(--brand); }

/* Bloco da IA: `bot-soft` + traço TRACEJADO — a mesma convenção de
   "ainda não é real" do `.shadow-ai` (§31.2). */
.art-ai { fill: var(--bot-soft); stroke: var(--bot); stroke-dasharray: 4 3; }

/* Barra de 2px de linha selecionada (a convenção do `.conv`) e o visto de
   verificação concluída. */
.art-sel { fill: var(--brand); }
.art-ok  { stroke: var(--success); }

/* Rótulo dentro da arte. No celular a peça é estreita demais para ele passar
   de ~8px de tela, então ele NASCE oculto e só aparece do `sm` para cima —
   o significado nunca depende dele: mora no <title>/<desc> do SVG. */
.art-label {
  display: none;
  fill: var(--ink-subtle);
  font-size: var(--text-label);     /* 13 unidades do viewBox, não 13px de tela */
  font-weight: var(--fw-label);
  letter-spacing: var(--ls-label);
}
@media (min-width: 640px) { .art-label { display: block; } }

/* Detalhe fino da arte — as barras de "texto" de 4 a 6 unidades do viewBox.
   A peça do hero mede 480 unidades de largura e no celular ela cabe em ~330px:
   escala de 0,68, em que uma barra de 5 unidades vira uma marca de 3px. Isso
   não é informação, é sujeira cinza em volta do que importa.

   Por isso o detalhe NASCE oculto e entra no `sm`, que é exatamente onde a
   peça atinge a escala 1:1 (`.lp-hero__art` trava em 480px, e de ~500px de
   viewport para cima a arte já não encolhe mais). É o mesmo degrau do
   `.art-label`, e não por acaso: os dois falham pelo mesmo motivo.

   O que fica no celular é a ESTRUTURA inteira — aparelho, mensagem chegando,
   conector, três destinos com os seus glifos. Nenhum passo do caminho some,
   nenhum quadro fica vazio: cada destino conserva a sua barra de título. */
.art-fine { display: none; }
@media (min-width: 640px) { .art-fine { display: block; } }

/* O único movimento da página: um ponto que percorre a entrada e, logo
   depois, as três saídas. 5,4 s de ciclo — quase tudo é pausa. */
.art-pulse { fill: var(--brand); }
.art-pulse--ai { fill: var(--bot); }

/* Hero: a arte COMPÕE com o texto, lado a lado. O texto continua alinhado à
   esquerda (§7.7 proíbe hero centralizado); os fatos seguem largura cheia. */
.lp-hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-8);
  align-items: center;
}
.lp-hero__content { min-width: 0; }
.lp-hero__art { min-width: 0; max-width: 480px; }
@media (min-width: 1200px) {
  .lp-hero__grid { grid-template-columns: minmax(0, 1fr) 480px; gap: var(--sp-12); }
  .lp-hero__art { max-width: none; }
}

/* Peça pequena da folha de especificação: a quarta coluna de `.lp-module`. */
.lp-module__art { align-self: start; max-width: 190px; }

/* Reduzir movimento é escolher outra representação: aqui a representação
   sem movimento é a arte parada, sem o ponto. */
@media (prefers-reduced-motion: reduce) {
  .art-pulse { display: none; }
}


/* ═══ 28 · TELA crm.html ════════════════════════════════════════════════════
   Barra de métricas, medidor de participação, blocos da ficha do cliente e
   renderização genérica de custom record (as propriedades da CostaVet). ═══ */

/* O grid de colunas do CRM mora na §7.1, junto com o dos outros shells —
   um lugar só para a geometria de todas as telas. */

/* Barra de métricas — banda de células separadas por hairline.
   Nenhum valor anima (§7.6).

   Quatro células lado a lado em 360px dariam ~80px cada: número truncado e
   rótulo em três linhas. Então a banda EMPILHA na base, vira 2×2 no `sm` e
   só abre nas quatro colunas no `lg`. O hairline muda de eixo junto — é a
   mesma banda, não outro componente. */
.metrics {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  background: var(--surface-1);
  border-bottom: 1px solid var(--hairline);
  flex: none;
}
.metric {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  min-width: 0;
  padding: var(--sp-3) var(--pane-pad);
  border-bottom: 1px solid var(--hairline);
}
.metric:last-child { border-bottom: 0; }

@media (min-width: 640px) {
  .metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .metric { border-right: 1px solid var(--hairline); }
  .metric:nth-child(2n) { border-right: 0; }
  .metric:nth-child(n + 3) { border-bottom: 0; }
}
@media (min-width: 1200px) {
  .metrics { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .metric { border-right: 1px solid var(--hairline); border-bottom: 0; }
  .metric:last-child { border-right: 0; }
}

/* Medidor de participação: uma barra de 6px, segmentos em tinta e o da IA
   em --bot. O flex-grow de cada segmento É o número do seed — assim o
   mockup não precisa de style inline nem de classe de largura arbitrária. */
.meter {
  display: flex;
  height: 6px;
  border-radius: var(--radius-pill);
  overflow: hidden;
  background: var(--surface-3);
}
.meter__seg { height: 100%; }
.meter__seg--ai    { flex: 412; background: var(--bot); }
.meter__seg--ana   { flex: 268; background: var(--ink); }
.meter__seg--bruno { flex: 214; background: var(--ink-muted); }
.meter__seg--helena{ flex: 179; background: var(--ink-faint); }

/* Faixa que hospeda as abas + as ações da visão. */
.crm-tabbar {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
  flex: none;
  padding: var(--sp-1) var(--pane-pad);
  background: var(--surface-1);
  border-bottom: 1px solid var(--hairline);
}
.crm-tabbar .tabs { border-bottom: 0; min-width: 0; }
@media (min-width: 900px) {
  .crm-tabbar { gap: var(--sp-4); flex-wrap: nowrap; padding: 0 var(--sp-4); }
}

/* Painel do funil: canvas creme sob os cards, rolagem só na horizontal. */
.crm-kanban {
  display: flex;
  flex-direction: column;
  background: var(--canvas);
}
@media (min-width: 900px) { .crm-kanban { overflow: hidden; } }

/* Seção da ficha lateral — separada por hairline, nunca card dentro de card. */
.pane-section {
  padding: var(--pane-pad);
  border-top: 1px solid var(--hairline);
}
.pane-section:first-child { border-top: 0; }
.pane-section__head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-bottom: var(--sp-3);
}
.pane-section__title {
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  color: var(--ink-subtle);
}

/* Pares rótulo/valor da ficha. <dl> em grid de duas colunas. */
.props {
  display: grid;
  grid-template-columns: minmax(88px, 104px) minmax(0, 1fr);
  gap: var(--sp-2) var(--sp-3);
  margin: 0;
}
.props > dt {
  font-size: var(--text-caption);
  line-height: var(--lh-caption);
  color: var(--ink-subtle);
  margin: 0;
}
.props > dd {
  font-size: var(--text-body);
  line-height: var(--lh-body);
  color: var(--ink);
  margin: 0;
  min-width: 0;
}

/* Custom record (pet). Renderização genérica: cabeçalho com o title_field e
   os campos preenchidos em .props. Campo vazio não vira linha com "—". */
.record { padding-block: var(--sp-3); border-top: 1px solid var(--hairline); }
.record:first-of-type { border-top: 0; padding-top: 0; }
.record__head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-bottom: var(--sp-2);
  min-width: 0;
}
.record__title {
  font-size: var(--text-body);
  line-height: var(--lh-body);
  font-weight: var(--fw-body-strong);
  color: var(--ink);
}
.record .props { gap: var(--sp-1) var(--sp-3); }

/* Painel de contatos. No celular o painel inteiro faz parte do documento e a
   tabela rola só na horizontal, dentro de si. A partir do `md` a barra de
   filtros trava e só a tabela rola — nos dois eixos, na própria caixa. */
.crm-list { display: flex; flex-direction: column; }
.crm-list > .table-wrap { flex: none; overflow-x: auto; }
@media (min-width: 900px) {
  .crm-list { overflow: hidden; }
  .crm-list > .table-wrap { flex: 1; min-height: 0; overflow: auto; }
}

/* Âncora de popover: o .popover é absolute e precisa de contexto posicionado. */
.pop-anchor { position: relative; display: inline-flex; }
.pop-anchor > .popover { top: calc(100% + var(--sp-1)); left: 0; }


/* ═══ 28.1 · crm.html NO CELULAR ════════════════════════════════════════════
   O CRM é a tela mais densa do produto e a que mais sofre em 360px. Ela não
   encolhe: ela é TRADUZIDA. Quatro traduções, e nenhuma delas é "a mesma
   coisa espremida".

   1. A banda de métricas ROLA na horizontal (`.metrics--scroll`). Empilhada,
      quatro números empurrariam a tabela 400px abaixo da dobra; espremida em
      quatro colunas de 80px, cada valor truncaria. Rolando, cada métrica tem
      a largura que o número pede e a seguinte aparece pela metade.
   2. A tabela de contatos vira LISTA DE CARTÕES (`.crm-cards`) com os cinco
      campos que decidem a visita — razão social, município, porte do plantel,
      vendedor e última compra. **Não é a tabela rolando de lado**: é outro
      layout do mesmo dado. Do `md` para cima a tabela volta e a lista sai.
   3. O funil já rola com snap (§15); aqui entra só o INDICADOR DE POSIÇÃO
      entre os oito estágios (`.kanban-pos`), porque uma coluna por vez sem
      indicador não conta quantas faltam.
   4. A ficha do cliente vira FOLHA (`.sheet`) presa ao rodapé, com uma alça
      que a abre. Coluna lateral de 320px não existe em 360px de tela, e
      empilhada no fim do documento a ficha ficaria a dez rolagens de distância
      da linha que a abriu.

   Tudo entra por `min-width`: o que está fora de media query aqui é o celular,
   e o `md` devolve a tabela, a banda em grade e a coluna lateral.        ═══ */

/* ── 1 · Banda de métricas que rola ────────────────────────────────────────
   Modificador, não redefinição: `dev.html` usa a mesma `.metrics` e continua
   empilhando 1 → 2 → 4. Nada aqui vaza para lá. */
.metrics--scroll {
  display: flex;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-padding-left: var(--pane-pad);
  scrollbar-width: none;
}
.metrics--scroll::-webkit-scrollbar { display: none; }
.metrics--scroll > .metric {
  flex: 0 0 78%;
  scroll-snap-align: start;
  border-bottom: 0;
  border-right: 1px solid var(--hairline);
}
.metrics--scroll > .metric:last-child { border-right: 0; }

/* Do `sm` para cima a banda volta a ser a grade da §28 — e as hairlines
   voltam a ser as dela. As regras abaixo só desfazem o que o modo rolagem
   tinha mudado; a geometria continua vindo de `.metrics`. */
@media (min-width: 640px) {
  .metrics--scroll { display: grid; overflow-x: visible; scroll-snap-type: none; }
  .metrics--scroll > .metric { flex: none; }
  .metrics--scroll > .metric:nth-child(-n + 2) { border-bottom: 1px solid var(--hairline); }
  .metrics--scroll > .metric:nth-child(2n) { border-right: 0; }
}
@media (min-width: 1200px) {
  .metrics--scroll > .metric:nth-child(-n + 2) { border-bottom: 0; }
  .metrics--scroll > .metric:nth-child(2n) { border-right: 1px solid var(--hairline); }
  .metrics--scroll > .metric:last-child { border-right: 0; }
}

/* As três ações do cabeçalho (período, exportar, novo cliente) somam mais que
   360px e o `.btn-group` respondia encolhendo até cortar "Trimestre" dentro do
   próprio botão. Elas quebram linha; nenhuma encolhe. */
.app-shell--crm .page-header__actions { flex-wrap: wrap; }
.app-shell--crm .page-header__actions > * { flex: none; }

/* ── 2 · Lista de cartões de contato ──────────────────────────────────────
   Mesma linha da tabela, outro objeto: avatar + razão social na primeira
   faixa, ação à direita, e os quatro pares rótulo/valor numa `.props` de
   largura cheia. Os estados são os MESMOS atributos da `<tr>` (§18) — quem
   sabe ler a tabela sabe ler o cartão. */
.crm-cards { display: flex; flex-direction: column; }

.crm-card {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--sp-2) var(--sp-3);
  padding: var(--sp-3) var(--pane-pad);
  border-bottom: 1px solid var(--hairline);
  transition: background-color var(--dur-fast) var(--ease-standard);
}
@media (hover: hover) {
  .crm-card:hover { background: var(--surface-2); }
}
.crm-card__head { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; }
.crm-card__action { justify-self: end; align-self: start; }
.crm-card__facts { grid-column: 1 / -1; }
.crm-card .props { gap: var(--sp-1) var(--sp-3); }

.crm-card[aria-current="true"] { background: var(--surface-2); box-shadow: inset 2px 0 0 0 var(--brand); }
.crm-card[data-error]    { box-shadow: inset 2px 0 0 0 var(--danger); }
.crm-card[data-archived] { opacity: .55; }

/* A troca. Nada é escondido "por a tela ser pequena": o mesmo dado existe nos
   dois layouts e só um deles está montado de cada vez. */
.crm-list > .crm-cards,
.crm-list > .crm-cards__foot { display: flex; }
.crm-list > .table-wrap { display: none; }
@media (min-width: 900px) {
  .crm-list > .crm-cards,
  .crm-list > .crm-cards__foot { display: none; }
  .crm-list > .table-wrap { display: block; }
}

/* ── 3 · Indicador de posição do funil ────────────────────────────────────
   Oito marcas, uma por estágio, e o nome do estágio em foco. É leitura de
   rolagem, não controle: `aria-hidden`, porque cada coluna já tem `<h2>` e o
   leitor de tela navega por eles. Nada anima (§7.6). */
.kanban-pos {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex: none;
  padding: var(--sp-2) var(--pane-pad) 0;
}
.kanban-pos__label {
  font-size: var(--text-label);
  line-height: var(--lh-label);
  font-weight: var(--fw-label);
  color: var(--ink);
  min-width: 0;
}
.kanban-pos__ticks { display: flex; align-items: center; gap: 3px; flex: none; }
.kanban-pos__ticks > i { width: 10px; height: 3px; border-radius: var(--radius-pill); background: var(--hairline-strong); }
.kanban-pos__ticks > i[data-current] { width: 18px; background: var(--brand); }
.kanban-pos__n {
  flex: none;
  font-size: var(--text-micro);
  color: var(--ink-subtle);
  font-variant-numeric: tabular-nums;
}

/* O funil ganhou um irmão acima dele. Sem isto, `height: 100%` (§15) somaria à
   barra de filtros e ao indicador e o `overflow: hidden` do painel cortaria o
   pé da última coluna a partir do `md`. */
@media (min-width: 900px) {
  .crm-kanban > .kanban { flex: 1; min-height: 0; height: auto; }
}

/* ── 4 · Ficha do cliente como folha (bottom sheet) ───────────────────────
   Presa ao rodapé, recolhida por padrão numa alça de 56px que diz de quem é a
   ficha. Aberta, para em 86dvh — o contexto de trás continua visível, que é o
   que separa folha de modal. `env(safe-area-inset-bottom)` porque a barra de
   gestos do iPhone passa exatamente por cima da alça. */
.sheet {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 80;              /* abaixo da .mockbar (150) e do modal (101) */
  max-height: 86vh;
  max-height: 86dvh;
  overflow: hidden;
  border-top: 1px solid var(--hairline-strong);
  border-bottom: 0;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  box-shadow: var(--elev-overlay);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
.sheet > .pane__body { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
/* A alça É o cabeçalho da folha: repetir "Ficha do cliente" logo abaixo dela,
   com um botão de fixar que no celular não tem lado nenhum para fixar, era
   dizer a mesma coisa duas vezes. O `.pane__header` volta no `md`. */
.sheet > .pane__header { display: none; }
.sheet[data-open="false"] > .pane__body,
.sheet[data-open="false"] > .pane__footer { display: none; }

.sheet__handle {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  min-height: 56px;
  flex: none;
  padding: var(--sp-4) var(--pane-pad) var(--sp-2);
  background: var(--surface-1);
  border-radius: inherit;
  text-align: left;
  color: var(--ink);
}
.sheet__grip {
  position: absolute;
  top: 8px;
  left: 50%;
  transform: translateX(-50%);
  width: 36px;
  height: 4px;
  border-radius: var(--radius-pill);
  background: var(--hairline-strong);
}
.sheet__handle-main { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; }
.sheet__chevron { flex: none; margin-left: auto; color: var(--ink-subtle); }
.sheet[data-open="true"] .sheet__chevron { transform: rotate(180deg); }

/* A folha ocupa o rodapé da viewport: o documento reserva a altura da alça
   para que a última linha da lista não fique embaixo dela. */
.app-shell:has(> .sheet) { padding-bottom: calc(64px + env(safe-area-inset-bottom, 0px)); }

/* Do `md` para cima não há folha nenhuma: volta a ser a coluna da §7.1. */
@media (min-width: 900px) {
  .app-shell:has(> .sheet) { padding-bottom: 0; }
  .sheet {
    position: static;
    max-height: none;
    z-index: auto;
    border-top: 0;
    border-radius: 0;
    box-shadow: none;
    padding-bottom: 0;
  }
  .sheet__handle { display: none; }
  .sheet > .pane__header { display: flex; }
  .sheet[data-open="false"] > .pane__body,
  .sheet[data-open="false"] > .pane__footer { display: block; }
}


/* ═══ 26 · TELA /entrar (login e convite) ═══════════════════════════════════
   Duas colunas: a folha de trabalho à esquerda (surface-1, onde se digita) e
   o papel do canvas à direita (a marca). A divisa entre elas é UM hairline —
   nunca um card branco flutuando no meio da tela. A coluna de formulário tem
   medida fixa (--auth-col) para que rótulo, campo, botão e rodapé legal
   fiquem no mesmo eixo vertical.

   ── No celular ──────────────────────────────────────────────────────────────
   Uma coluna só, com o formulário PRIMEIRO — no DOM, no foco e na tela — e o
   painel de marca reduzido a uma faixa curta depois dele. E, principalmente,
   SEM altura mínima de viewport: `min-height: 100dvh` numa coluna centrada
   verticalmente é o que empurra o rodapé legal (privacidade, termos, exclusão)
   para um segundo scroll inteiro. No celular a coluna tem a altura do que ela
   contém, e os três links ficam logo abaixo do último bloco do formulário.
   A altura cheia e a centragem vertical voltam no `md`, onde há tela para
   elas.                                                                 ═══ */

.auth {
  --auth-col: 380px;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 900px) {
  .auth {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    min-height: calc(100vh - var(--mockbar-offset));
    min-height: calc(100dvh - var(--mockbar-offset));
  }
  /* A variante de convite é mais alta que a viewport por natureza: não force. */
  .auth--invite { min-height: 0; }
}

/* ── Coluna do formulário ── */
.auth__form {
  display: flex;
  flex-direction: column;
  min-width: 0;
  background: var(--surface-1);
  padding: var(--sp-6) var(--gutter);
  padding-left: max(var(--gutter), env(safe-area-inset-left, 0px));
  padding-right: max(var(--gutter), env(safe-area-inset-right, 0px));
}
@media (min-width: 900px) {
  .auth__form {
    padding: var(--sp-12) var(--sp-10);
    border-right: 1px solid var(--hairline);
  }
}
/* `justify-content: center` só entra quando há sobra de altura para centrar —
   no celular a coluna já tem a altura do conteúdo e centrar não faz nada além
   de custar uma regra a mais para depurar. */
.auth__inner {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--sp-6);
  width: 100%;
  max-width: var(--auth-col);
  margin-inline: auto;
}
@media (min-width: 900px) {
  .auth__inner { justify-content: center; }
}

/* O submit é a última coisa que se toca antes de entrar: no dedo ele tem 44px
   de altura de verdade, não 40px com área invisível em volta. */
@media (pointer: coarse) {
  .auth__inner .btn--lg { height: 44px; }
}

/* Lockup da organização (wordmark do tenant, §8 `wordmark`). */
.auth__org { display: flex; align-items: center; gap: var(--sp-3); }
.auth__glyph {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px; height: 32px;
  flex: none;
  border-radius: var(--radius-md);
  border: 1px solid var(--brand-line);
  background: var(--brand-soft);
  color: var(--brand);
}
.auth__glyph--40 { width: 40px; height: 40px; }

/* Linha rótulo + link auxiliar ("Senha" · "Esqueci minha senha"). */
.auth__labelrow { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); }
/* "Esqueci minha senha" é o caminho de saída de quem errou a senha às 9h05:
   no dedo ele não pode ser um alvo de 12px. A linha inteira passa a ter 44px
   e o link estica dentro dela — sem margem negativa e sem valor fora da escala. */
@media (pointer: coarse) {
  .auth__labelrow { align-items: center; min-height: 44px; }
  .auth__labelrow .link { display: inline-flex; align-items: center; align-self: stretch; }
}

/* Campo de senha com botão de revelar. O botão fica DENTRO do input-wrap;
   o padding à direita abre espaço para ele sem cobrir o texto digitado.
   Centrado explicitamente porque a altura do campo muda com o ponteiro. */
.pw-field .input { padding-right: var(--sp-10); }
.pw-field .icon-btn {
  position: absolute;
  right: var(--sp-1);
  top: 50%;
  transform: translateY(-50%);
}

/* Rodapé legal: mesma medida da coluna, ancorado embaixo. Privacidade, termos
   e exclusão de dados são exigência de App Review da Meta e não podem depender
   de o cliente descobrir que ainda há página abaixo do painel de marca — por
   isso vivem AQUI, dentro da coluna do formulário, e não no fim do documento. */
.auth__legal {
  width: 100%;
  max-width: var(--auth-col);
  margin: var(--sp-6) auto 0;
  padding-top: var(--sp-4);
  border-top: 1px solid var(--hairline);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1) var(--sp-4);
  font-size: var(--text-caption);
  line-height: var(--lh-caption);
  color: var(--ink-subtle);
}
@media (min-width: 900px) {
  .auth__legal { margin-top: var(--sp-8); }
}
/* No celular o espaçador quebra a linha em vez de empurrar: os três links
   ficam numa faixa e o copyright na seguinte, sem órfão pendurado na borda. */
.auth__legal .spacer { flex: 0 0 100%; }
@media (min-width: 900px) {
  .auth__legal .spacer { flex: 1 1 0; }
}
/* Três links de 12px lado a lado não são tocáveis: no dedo cada um vira uma
   faixa de 44px de altura. É a última coisa que a Meta checa no App Review e a
   primeira que o cliente tenta abrir do celular. */
@media (pointer: coarse) {
  .auth__legal a { display: inline-flex; align-items: center; min-height: 44px; }
}

/* ── Coluna da marca ──
   No celular ela não é uma coluna, é uma FAIXA CURTA depois do formulário:
   ritmo apertado, nada de `flex: 1` esticando o discurso pela altura da tela.
   Nada é escondido — quem rola mais um dedo lê a mesma promessa que o desktop
   mostra ao lado. Esconder por `display: none` num arquivo estático tornaria
   o conteúdo inalcançável, e é justamente o que o resto do sistema evita. */
.auth__aside {
  display: flex;
  flex-direction: column;
  min-width: 0;
  gap: var(--sp-4);
  background: var(--canvas);
  border-top: 1px solid var(--hairline);
  padding: var(--sp-6) var(--gutter);
  padding-left: max(var(--gutter), env(safe-area-inset-left, 0px));
  padding-right: max(var(--gutter), env(safe-area-inset-right, 0px));
  padding-bottom: calc(var(--sp-6) + env(safe-area-inset-bottom, 0px));
}
@media (min-width: 900px) {
  .auth__aside {
    gap: var(--sp-6);
    border-top: 0;
    padding: var(--sp-12) var(--sp-10);
    padding-bottom: var(--sp-12);
  }
}
.auth__mark { display: flex; align-items: center; gap: var(--sp-3); flex: none; }
.auth__pitch {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
@media (min-width: 900px) {
  .auth__pitch { flex: 1; justify-content: center; gap: var(--sp-4); padding-block: var(--sp-6); }
}
.auth__phrase { max-width: 20ch; }        /* usa .t-display-md */
.auth__sub    { max-width: 46ch; }        /* usa .t-body-lg */

/* Fatos da organização: dl de duas colunas, separada por hairline.
   dl/dt/dd não estão no reset (§0) — zerados aqui. */
.auth__facts { flex: none; border-top: 1px solid var(--hairline); margin: 0; }
.auth__facts > div {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-1);
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--hairline);
}
@media (min-width: 640px) {
  .auth__facts > div { grid-template-columns: 136px minmax(0, 1fr); gap: var(--sp-3); }
}
.auth__facts dt { margin: 0; font-size: var(--text-caption); line-height: var(--lh-caption); color: var(--ink-subtle); }
.auth__facts dd { margin: 0; font-size: var(--text-caption); line-height: var(--lh-caption); color: var(--ink-muted); }

/* Lista de pessoas já na organização (variante de convite). */
.auth__people { display: flex; flex-direction: column; }
.auth__people > li {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-2) 0;
  border-bottom: 1px solid var(--hairline);
}
.auth__people > li:first-child { border-top: 1px solid var(--hairline); }

/* Anotação de mockup entre variantes da mesma tela. Chrome do mockup:
   deliberadamente NÃO se parece com o produto. */
.mock-note {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-3);
  padding: var(--sp-2) var(--gutter);
  background: var(--canvas);
  border-block: 1px solid var(--hairline-strong);
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  color: var(--ink-subtle);
}
.mock-note .t-mono { margin-left: auto; color: var(--ink-faint); }

/* Variante do topo de `dev.html`: a tela é do Estúdio Ame, não da CostaVet, e
   isso precisa estar dito em letra na primeira linha — não sugerido por cor.
   Fica em `warning-soft` porque é aviso de contexto, e continua sendo chrome
   do mockup: deliberadamente não se parece com o produto. */
.mock-note--interna {
  align-items: flex-start;
  padding-block: var(--sp-3);
  background: var(--warning-soft);
  border-block-color: var(--warning-line);
  color: var(--ink);
}
.mock-note--interna .icon { color: var(--warning); flex: none; margin-top: 1px; }
.mock-note--interna strong { font-weight: 600; }
.mock-note--interna > span:not(.t-mono) { flex: 1; min-width: 12rem; }


/* ═══ 29 · TELA: PAINEL DO DESENVOLVEDOR (dev.html) ══════════════════════════
   Área do Estúdio Ame, não do cliente. Mesma linguagem de Papel & Tinta, com
   um grão levemente mais técnico: identificador, chave, fila e latência vivem
   em mono. Nada aqui é card sobre card — o painel continua sendo folha branca
   dividida por hairline. O gráfico de filas é CSS puro, sem SVG e sem lib.
   Único style inline novo autorizado por esta seção: `--qv` em .qbar__seg,
   porque largura proporcional a dado não pode virar classe.            ═══ */

/* Coluna de leitura do painel: densa, mas não infinita. */
.dev-main {
  max-width: 1160px;
  margin-inline: auto;
  padding: var(--sp-4) var(--gutter) var(--sp-12);
}
@media (min-width: 1200px) {
  .dev-main { padding: var(--sp-6) var(--sp-6) var(--sp-16); }
}

/* Painel cujo conteúdo encosta na borda (tabela, faixa de métricas). */
.panel--flush { overflow: hidden; }
.panel--flush > .table-wrap { border-radius: inherit; }

/* O shell do painel (documento na base, colunas no `lg`) mora na §7.1, junto
   com o dos outros shells.

   A faixa de métricas do topo é a `.metrics` / `.metric` da §28 (crm.html),
   reaproveitada sem uma linha nova: mesma banda, mesmos degraus de
   1 → 2 → 4 colunas, mesmos utilitários tipográficos dentro. Duas definições
   da mesma classe em arquivo compartilhado seria a última a vencer — ou
   seja, um bug. Não existe aqui nenhuma regra `.app-shell--dev .metrics`. */

/* ── Lista chave/valor de credencial. <dl> em grade, separada por hairline. ── */
/* <dl>, <dt> e <dd> não estão na lista do reset da §0 e o <dd> nasce com
   margin-inline-start: 40px — dentro de um grid isso desloca a coluna
   inteira. Zerado aqui, no único lugar que usa <dl> em grade. */
.kv { display: grid; grid-template-columns: minmax(0, 1fr); margin: 0; }
.kv > dt,
.kv > dd {
  margin: 0;
  padding: var(--sp-2) 0;
  min-width: 0;
}
.kv > dt {
  font-size: var(--text-label);
  line-height: var(--lh-label);
  font-weight: var(--fw-label);
  color: var(--ink-subtle);
  border-top: 1px solid var(--hairline);
  padding-bottom: 2px;
}
.kv > dd { font-size: var(--text-body); color: var(--ink); padding-top: 0; }
.kv > *:nth-child(1), .kv > *:nth-child(2) { border-top: 0; padding-top: 0; }
@media (min-width: 640px) {
  .kv { grid-template-columns: minmax(150px, 210px) minmax(0, 1fr); }
  .kv > dt { padding-right: var(--sp-4); padding-bottom: var(--sp-2); }
  .kv > dd { border-top: 1px solid var(--hairline); padding-top: var(--sp-2); }
  .kv > *:nth-child(1), .kv > *:nth-child(2) { border-top: 0; padding-top: 0; }
}

/* ── Cápsula mono: identificador, URL, chave mascarada. ── */
.mono-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  max-width: 100%;
  padding: 2px var(--sp-2);
  background: var(--surface-2);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  line-height: 20px;
  color: var(--ink);
  overflow-wrap: anywhere;
}
.mono-chip--key { background: var(--surface-1); border-color: var(--hairline-strong); }

/* ── Cofre de segredos. Uma chave por linha, valor sempre mascarado.
      Não existe variante "revelada": o produto não tem rota de leitura. ── */
.secret-list { display: flex; flex-direction: column; }
.secret {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: center;
  gap: var(--sp-2) var(--sp-4);
  padding: var(--sp-3) 0;
  border-top: 1px solid var(--hairline);
}
@media (min-width: 640px) {
  .secret { grid-template-columns: minmax(0, 1fr) auto; }
}
.secret:first-child { border-top: 0; padding-top: 0; }
.secret[data-revoked] { opacity: .55; }
.secret__main { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; }
.secret__ref {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  color: var(--ink-muted);
}
.secret__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 2px var(--sp-3);
  font-size: var(--text-caption);
  line-height: var(--lh-caption);
  color: var(--ink-subtle);
}
.secret__actions { display: flex; align-items: center; gap: var(--sp-2); flex: none; justify-content: flex-start; }
@media (min-width: 640px) { .secret__actions { justify-content: flex-end; } }

/* ── Gráfico de filas. Barra empilhada, três séries, escala compartilhada.
      Largura de cada segmento vem de --qv no style inline (dado, não estilo).
      min-width garante que 1 job continue visível ao lado de 47.        ── */
.qchart { display: flex; flex-direction: column; }
.qrow {
  display: grid;
  grid-template-columns: 104px minmax(0, 1fr);
  align-items: center;
  gap: var(--sp-2) var(--sp-3);
  min-height: 32px;
  border-top: 1px solid var(--hairline);
}
@media (min-width: 900px) {
  .qrow { grid-template-columns: 116px minmax(80px, 1fr) 156px; gap: var(--sp-3); }
}
.qrow:first-child, .qrow--head { border-top: 0; }
.qrow--head { min-height: 24px; }
.qrow__name {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
}
.qbar {
  display: flex;
  gap: 2px;
  height: 10px;
  background: var(--surface-2);
  border-radius: var(--radius-xs);
  overflow: hidden;
}
.qbar--inline { width: 84px; height: 6px; display: inline-flex; vertical-align: middle; }
.qbar__seg { width: var(--qv, 0%); min-width: 3px; border-radius: 2px; }
.qbar__seg--pending { background: var(--ink-faint); }
.qbar__seg--running { background: var(--brand); }
.qbar__seg--failed  { background: var(--danger); }
.qbar__seg--warning { background: var(--warning); }
/* No celular os três números descem para a linha de baixo e ficam alinhados à
   esquerda, embaixo da barra que eles descrevem. */
.qrow__nums {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: repeat(3, minmax(0, 88px));
  justify-content: start;
  gap: var(--sp-2);
  padding-bottom: var(--sp-2);
}
@media (min-width: 900px) {
  .qrow__nums {
    grid-column: auto;
    grid-template-columns: repeat(3, 1fr);
    justify-content: stretch;
    padding-bottom: 0;
  }
}
.qnum {
  text-align: left;
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  font-variant-numeric: tabular-nums;
  color: var(--ink-muted);
}
.qnum--zero { color: var(--ink-faint); }
.qnum--failed { color: var(--danger); }
.qlegend { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4); }
.qlegend__key {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  color: var(--ink-subtle);
}
.qlegend__swatch { width: 10px; height: 10px; border-radius: 2px; flex: none; }
@media (min-width: 900px) { .qnum { text-align: right; } }

/* ── Grade de campos de configuração. `auto-fit` + `minmax` já é responsivo
      por construção: uma coluna no celular, quantas couberem depois. O
      mínimo desce para 0 na base porque 216px não cabem em 360 menos a
      moldura do painel. ── */
.field-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-4);
}
@media (min-width: 640px) {
  .field-grid { grid-template-columns: repeat(auto-fit, minmax(216px, 1fr)); }
}


/* ═══ 27 · INBOX — JANELA DE 24 H · SUGESTÃO EM SOMBRA · ÁUDIO · FICHA ═══════
   Tudo o que a tela de chat precisa e que não é bolha nem linha de lista.
   Nada aqui redefine token: só compõe os que já existem.                  ═══ */

/* ── 25.1 Contador da janela de 24 h ────────────────────────────────────────
   A regra da Cloud API do WhatsApp: passadas 24 h da última mensagem do
   contato, só sai template aprovado. O atendente precisa VER o relógio, não
   descobrir no erro de envio. 12 marcas = 2 h cada; as gastas ficam em
   ink-faint e as restantes assumem a cor do estado. O número nunca anima
   (§7.6): um contador que pulsa numa fila de atendimento produz ansiedade. */

.window-meter {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  flex: none;
  padding: 3px var(--sp-2);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-sm);
  background: var(--surface-1);
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  color: var(--ink-muted);
}
.window-meter__label { color: var(--ink-subtle); }
.window-meter__value { color: currentColor; font-variant-numeric: tabular-nums; }
.window-meter__ticks { display: flex; align-items: center; gap: 2px; }
.window-meter__ticks i {
  display: block;
  width: 3px; height: 10px;
  border-radius: 1px;
  background: var(--hairline-strong);
}

/* > 6 h restantes */
.window-meter--calm { color: var(--ink-muted); }
.window-meter--calm .window-meter__ticks i:nth-child(-n+5) { background: var(--ink-faint); }

/* fechando — 3 h 42 min de 24 h: 10 das 12 marcas já gastas */
.window-meter--closing {
  color: var(--state-window-closing);
  border-color: var(--warning-line);
  background: var(--warning-soft);
}
.window-meter--closing .window-meter__ticks i { background: var(--warning-line); }
.window-meter--closing .window-meter__ticks i:nth-child(-n+10) { background: var(--ink-faint); }
.window-meter--closing .window-meter__ticks i:nth-last-child(-n+2) { background: var(--warning); }

/* fechada — só template aprovado */
.window-meter--closed {
  color: var(--state-window-closed);
  border-color: var(--danger-line);
  background: var(--danger-soft);
}
.window-meter--closed .window-meter__ticks i { background: var(--ink-faint); }


/* ── 25.2 Sugestão da IA em modo sombra ─────────────────────────────────────
   A IA redige, o humano aprova. Precisa ser IMPOSSÍVEL confundir com algo já
   enviado, e a distinção não pode depender de cor: fica FORA da <ol> de
   mensagens (mora na área do composer), o traço é tracejado — a convenção de
   "ainda não é real" — e o rótulo diz em letra o que o desenho sugere.     */

.shadow-ai {
  --shadow-ai-line: oklch(0.460 0.085 305 / .45);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-3);
  background: var(--bot-soft);
  border: 1px dashed var(--shadow-ai-line);
  border-radius: var(--radius-md);
}
:root[data-theme="dark"] .shadow-ai { --shadow-ai-line: oklch(0.735 0.090 305 / .45); }

.shadow-ai__head { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.shadow-ai__label {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  color: var(--bot);
}
.shadow-ai__body {
  font-size: var(--text-body);
  line-height: var(--lh-body);
  color: var(--ink);
}
.shadow-ai__body p + p { margin-top: var(--sp-2); }

/* De onde a IA tirou o que escreveu. Sem fonte, o atendente não tem como
   aprovar com responsabilidade — e "confiança de 92%" seria número inventado. */
.shadow-ai__cite {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  padding-top: var(--sp-2);
  border-top: 1px dashed var(--shadow-ai-line);
  font-size: var(--text-caption);
  line-height: var(--lh-caption);
  letter-spacing: var(--ls-caption);
  color: var(--ink-subtle);
}
.shadow-ai__cite .icon { flex: none; margin-top: 2px; }
.shadow-ai__actions { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }


/* ── 25.3 Áudio com waveform ────────────────────────────────────────────────
   Alturas por nth-child: envelope de fala desenhado à mão, sem style inline e
   sem repetição visível. `--played` marca o trecho já ouvido em ink-muted
   contra ink-faint — diferença de VALOR, não de cor, e por isso legível em
   monocromático e nos dois temas.                                          */

/* `min-width` em vez de largura: numa bolha de 92% de 360px o player não pode
   exigir 232px e empurrar a bolha para fora da tela. */
.audio-msg { display: flex; align-items: center; gap: var(--sp-2); min-width: min(232px, 100%); }
.audio-msg__play {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px; height: 28px;
  flex: none;
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius-pill);
  background: var(--surface-1);
  color: var(--ink);
  transition: background-color var(--dur-fast) var(--ease-standard);
}
@media (hover: hover) { .audio-msg__play:hover { background: var(--surface-3); } }
.audio-msg__play:focus-visible { transition: none; }
.audio-msg .waveform { flex: 1; min-width: 0; }
.audio-msg__time {
  flex: none;
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  color: var(--ink-subtle);
  font-variant-numeric: tabular-nums;
}

.audio-msg__transcript {
  margin-top: var(--sp-2);
  padding-top: var(--sp-2);
  border-top: 1px solid var(--hairline);
  font-size: var(--text-caption);
  line-height: var(--lh-caption);
  letter-spacing: var(--ls-caption);
  color: var(--ink-muted);
}
.audio-msg__transcript-label {
  display: block;
  margin-bottom: 2px;
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  color: var(--ink-faint);
}

/* Envelope de fala de 34 barras. Agrupado por altura para não virar 34 regras. */
.waveform i { height: 6px; }
.waveform i:nth-child(1),  .waveform i:nth-child(18), .waveform i:nth-child(34) { height: 4px; }
.waveform i:nth-child(12), .waveform i:nth-child(29) { height: 5px; }
.waveform i:nth-child(6),  .waveform i:nth-child(23), .waveform i:nth-child(33) { height: 6px; }
.waveform i:nth-child(2),  .waveform i:nth-child(17) { height: 7px; }
.waveform i:nth-child(11), .waveform i:nth-child(24) { height: 8px; }
.waveform i:nth-child(7),  .waveform i:nth-child(19), .waveform i:nth-child(28) { height: 9px; }
.waveform i:nth-child(13), .waveform i:nth-child(32) { height: 10px; }
.waveform i:nth-child(5),  .waveform i:nth-child(30) { height: 11px; }
.waveform i:nth-child(3),  .waveform i:nth-child(22) { height: 12px; }
.waveform i:nth-child(16), .waveform i:nth-child(25) { height: 13px; }
.waveform i:nth-child(8),  .waveform i:nth-child(27) { height: 14px; }
.waveform i:nth-child(10), .waveform i:nth-child(20) { height: 15px; }
.waveform i:nth-child(4),  .waveform i:nth-child(31) { height: 16px; }
.waveform i:nth-child(14), .waveform i:nth-child(26) { height: 17px; }
.waveform i:nth-child(21) { height: 18px; }
.waveform i:nth-child(9)  { height: 19px; }
.waveform i:nth-child(15) { height: 20px; }
.waveform--played i:nth-child(-n+12) { background: var(--ink-muted); }


/* ── 25.4 Ficha do contato (coluna de contexto, recolhível) ─────────────────
   A coluna NÃO é um cartão: é folha dividida por hairline, igual ao resto do
   app. Recolher troca `.app-shell--inbox` por `.app-shell--no-context` e põe
   `hidden` no <aside> — o mesmo grid de 4 colunas que as outras telas usam. */

@media (min-width: 900px) {
  .app-shell--no-context > .pane--canvas { border-right: 0; }
}

.ficha__section { padding: var(--pane-pad); border-bottom: 1px solid var(--hairline); }
.ficha__section:last-child { border-bottom: 0; }
.ficha__title {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-bottom: var(--sp-3);
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  color: var(--ink-subtle);
}

/* Par rótulo/valor da ficha. Rótulo curto à esquerda, valor quebrando. */
.datalist { display: flex; flex-direction: column; gap: var(--sp-2); }
.datalist > div {
  display: grid;
  grid-template-columns: 88px minmax(0, 1fr);
  gap: var(--sp-2);
  align-items: baseline;
}
.datalist dt { font-size: var(--text-caption); line-height: var(--lh-caption); color: var(--ink-subtle); }
.datalist dd { font-size: var(--text-body); line-height: var(--lh-body); color: var(--ink); min-width: 0; overflow-wrap: anywhere; }

/* Plantel/propriedade: entidade N:1 do contato (custom record type), não
   campo customizado. O NOME da classe é genérico de propósito: o mecanismo
   serve a qualquer custom record de qualquer tenant (ARQUITETURA.md §8.1). */
.plantel {
  padding: var(--sp-3);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  background: var(--canvas);
}
.plantel + .plantel { margin-top: var(--sp-2); }
.plantel__head { display: flex; align-items: center; gap: var(--sp-2); }
.plantel__name { font-size: var(--text-body); line-height: var(--lh-body); font-weight: var(--fw-body-strong); color: var(--ink); }
.plantel__sub {
  margin-top: var(--sp-1);
  font-size: var(--text-caption);
  line-height: var(--lh-caption);
  letter-spacing: var(--ls-caption);
  color: var(--ink-subtle);
}
.plantel__facts {
  margin-top: var(--sp-2);
  padding-top: var(--sp-2);
  border-top: 1px solid var(--hairline);
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}
.plantel__facts > div { display: flex; align-items: baseline; gap: var(--sp-2); }
.plantel__facts dt { font-size: var(--text-caption); color: var(--ink-subtle); flex: none; }
.plantel__facts dd {
  margin-left: auto;
  font-size: var(--text-caption);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* Linha do tempo da aba Atividade da ficha. */
.tl { display: flex; flex-direction: column; }
.tl__item {
  position: relative;
  padding: 0 0 var(--sp-4) var(--sp-4);
  border-left: 1px solid var(--hairline);
}
.tl__item:last-child { border-left-color: transparent; padding-bottom: 0; }
.tl__item::before {
  content: '';
  position: absolute;
  left: -3px; top: 5px;
  width: 5px; height: 5px;
  border-radius: var(--radius-pill);
  background: var(--ink-faint);
}
.tl__when {
  display: block;
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}
.tl__what { font-size: var(--text-caption); line-height: var(--lh-caption); color: var(--ink-muted); margin-top: 2px; }


/* ── 25.5 Contador de fila em tom de alerta ─────────────────────────────────
   Só onde o número É o alerta (SLA, janela). A cor acompanha o rótulo textual
   da fila — nenhuma informação vive só na cor.                             */
.nav-item__count--alert  { color: var(--warning); }
.nav-item__count--danger { color: var(--danger); }


/* ── 25.6 (removida) ────────────────────────────────────────────────────────
   Aqui vivia a "degradação do shell de 5 colunas": três blocos `max-width`
   arrancando coluna por coluna até sobrar trilho + conversa. Era o coração do
   desenho desktop-first — e o motivo de a fila e a ficha SUMIREM do mockup no
   celular, sem rota que as trouxesse de volta.

   A construção agora é a inversa e mora na §7.1: o celular é a base (tudo
   empilhado, nada escondido) e cada breakpoint ACRESCENTA uma coluna. Não
   existe mais nenhuma regra neste arquivo que esconda conteúdo por ser
   pequeno demais.                                                          */

/* Rodapé de tabela (total do extrato). Completa a §18, que só previa thead e
   tbody: sem isto o <tfoot> herda padding zero e o total encosta na borda. */
.table tfoot td {
  padding: var(--sp-2) var(--sp-3);
  border-top: 1px solid var(--hairline-strong);
  color: var(--ink);
  vertical-align: middle;
}


/* ═══ 28 · TELA proposta.html (proposta comercial) ══════════════════════════
   Documento de apresentação, não brochura. Reaproveita a rota de leitura da
   §23 (.doc-page / .doc-toc / .doc) e acrescenta quatro objetos que não
   existem em nenhuma outra tela: a CAPA, a FOLHA DE MÓDULOS, o QUADRO DE
   FASES agrupadas em marcos e a LISTA DE PENDÊNCIAS do cliente.
   Tudo alinhado à esquerda, hairline no lugar de sombra, zero cor decorativa.
   O bloco @media print no fim é o que faz o botão "Salvar em PDF" valer.   */

/* ── 28.1 Capa ──────────────────────────────────────────────────────────────
   Banda de largura total acima da rota de leitura. Não é hero centralizado:
   é folha de rosto de documento — lockup, título, chamada e ficha técnica. */
.prop-cover {
  background: var(--surface-1);
  border-bottom: 1px solid var(--hairline);
}
/* A capa encosta nas duas bordas da tela: em paisagem, num aparelho com
   recorte, `--gutter` sozinho deixaria o título passar por baixo do notch. */
.prop-cover__inner {
  max-width: 1040px;
  margin-inline: auto;
  padding: var(--sp-6) var(--gutter) var(--sp-6);
  padding-left: max(var(--gutter), env(safe-area-inset-left, 0px));
  padding-right: max(var(--gutter), env(safe-area-inset-right, 0px));
}
@media (min-width: 900px) {
  .prop-cover__inner {
    padding: var(--sp-10) var(--sp-6) var(--sp-8);
    padding-left: max(var(--sp-6), env(safe-area-inset-left, 0px));
    padding-right: max(var(--sp-6), env(safe-area-inset-right, 0px));
  }
}
.prop-cover__top {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  flex-wrap: wrap;
  padding-bottom: var(--sp-6);
  border-bottom: 1px solid var(--hairline);
}
@media (min-width: 900px) { .prop-cover__top { padding-bottom: var(--sp-8); } }
/* A arte da capa COMPÕE com o texto, lado a lado — o título continua alinhado
   à esquerda e a folha de rosto não vira hero centralizado (§7.7). Só do `xl`
   para cima: abaixo disso a coluna de texto precisa da largura inteira, e a
   arte desce para baixo dela em vez de espremer as duas.

   O que ela desenha é o argumento do próprio título — as 168 horas da semana,
   35 preenchidas e 133 vazias — então ela leva `role="img"` + `aria-label`,
   não `aria-hidden`: aqui a figura carrega informação que o texto ao lado
   resume, mas não enumera.                                                  */
.prop-cover__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-6);
  align-items: center;
}
@media (min-width: 1200px) {
  .prop-cover__grid { grid-template-columns: minmax(0, 1fr) 480px; gap: var(--sp-12); }
}
.prop-cover__main { min-width: 0; }
.prop-cover__art  { min-width: 0; max-width: 480px; }

.prop-cover__title { max-width: 22ch; margin-top: var(--sp-2); color: var(--ink); }
.prop-cover__for {
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
  flex-wrap: wrap;
  margin-top: var(--sp-3);
  font-size: var(--text-body-lg);
  line-height: var(--lh-body-lg);
  color: var(--ink-muted);
}
.prop-cover__for strong { color: var(--ink); font-weight: var(--fw-body-strong); }
.prop-cover__lead { max-width: 62ch; }
.prop-cover__actions {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--sp-3);
  margin-top: var(--sp-6);
}
@media (min-width: 640px) {
  .prop-cover__actions { flex-direction: row; align-items: center; flex-wrap: wrap; margin-top: var(--sp-8); }
}

/* Ficha técnica da capa: quatro células cortadas por hairline vertical.
   É <dl>, porque é literalmente par termo/valor. */
.prop-meta {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  margin-top: var(--sp-6);
  border-top: 1px solid var(--hairline);
}
.prop-meta > div { padding: var(--sp-3) 0 0; min-width: 0; }
.prop-meta > div + div { padding-top: var(--sp-3); border-top: 1px solid var(--hairline); }
@media (min-width: 640px) {
  .prop-meta { grid-template-columns: repeat(2, minmax(0, 1fr)); margin-top: var(--sp-8); }
  .prop-meta > div { padding: var(--sp-4) var(--sp-4) 0 0; }
  .prop-meta > div + div { padding-left: var(--sp-4); border-top: 0; border-left: 1px solid var(--hairline); }
  .prop-meta > div:nth-child(3) { border-left: 0; }
}
@media (min-width: 900px) {
  .prop-meta { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .prop-meta > div:nth-child(3) { border-left: 1px solid var(--hairline); }
}
.prop-meta dt {
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  color: var(--ink-subtle);
}
.prop-meta dd {
  font-size: var(--text-body);
  line-height: var(--lh-body);
  color: var(--ink);
  margin-top: var(--sp-1);
}

/* ── 28.2 O problema hoje ───────────────────────────────────────────────────
   Linha de sintoma: o que acontece à esquerda, o que custa à direita.
   Nunca card, nunca ícone-no-topo.                                         */
.prop-pains { margin-top: var(--sp-4); border-top: 1px solid var(--hairline); }
.prop-pain {
  display: grid;
  grid-template-columns: 16px minmax(0, 1fr);
  gap: var(--sp-2) var(--sp-4);
  align-items: start;
  padding-block: var(--sp-4);
  border-bottom: 1px solid var(--hairline);
}
.prop-pain__cost { grid-column: 2; }
@media (min-width: 900px) {
  .prop-pain { grid-template-columns: 16px minmax(0, 1fr) minmax(0, 240px); gap: var(--sp-3) var(--sp-5); }
  .prop-pain__cost { grid-column: auto; }
}
.prop-pain > .icon { color: var(--ink-faint); margin-top: 3px; }
.prop-pain__what { font-size: var(--text-body); line-height: var(--lh-body); color: var(--ink); }
.prop-pain__cost { font-size: var(--text-caption); line-height: var(--lh-caption); color: var(--ink-subtle); }

/* ── 28.3 Folha de módulos ──────────────────────────────────────────────────
   Mesma lógica de especificação da landing, mas com a terceira linha que a
   landing não tem: o que a recepção deixa de fazer à mão.                  */
.prop-mods { margin-top: var(--sp-4); border-top: 1px solid var(--hairline); }
.prop-mod {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr);
  gap: var(--sp-2) var(--sp-4);
  padding-block: var(--sp-5);
  border-bottom: 1px solid var(--hairline);
}
.prop-mod__n {
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
  padding-top: 3px;
}
.prop-mod__name { display: flex; align-items: center; gap: var(--sp-2); color: var(--ink); }
.prop-mod__name .icon { color: var(--brand); flex: none; }
/* Nome do módulo e título do marco são <h3> dentro de .doc: precisam vencer a
   escala de leitura da §23, que rebaixa h3 para 14px. Especificidade, não
   !important, e nenhum token redefinido.                                    */
.doc .prop-mod__name,
.doc .prop-plan__title,
.doc .prop-marco__title {
  font-size: var(--text-title);
  line-height: var(--lh-title);
  letter-spacing: var(--ls-title);
  font-weight: var(--fw-title);
  margin-top: 0;
  margin-bottom: 0;
}
.doc .prop-marco__title,
.doc .prop-plan__title { margin-top: var(--sp-2); }
.prop-mod__desc {
  font-size: var(--text-body);
  line-height: var(--lh-body);
  color: var(--ink-muted);
  max-width: 60ch;
  margin-top: var(--sp-2);
}
.prop-mod__gain {
  display: flex;
  gap: var(--sp-2);
  margin-top: var(--sp-3);
  font-size: var(--text-caption);
  line-height: var(--lh-caption);
  color: var(--ink-subtle);
}
.prop-mod__gain .icon { color: var(--brand); flex: none; margin-top: 1px; }

/* ── 28.4 Fases agrupadas em marcos ─────────────────────────────────────────
   O marco é o que interessa ao dono da distribuidora; a fase é como se chega lá.
   O marco abre com um rótulo em tinta da marca e fecha com o ganho em uma
   frase. As fases penduram num filete vertical de 1px — linha do tempo sem
   bolinha, sem gradiente e sem ícone decorativo.                           */
.prop-marco { margin-top: var(--sp-6); }
.prop-marco + .prop-marco { margin-top: var(--sp-10); }
.prop-marco__head { padding-bottom: var(--sp-3); border-bottom: 1px solid var(--hairline-strong); }
.prop-marco__label {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  color: var(--brand);
}
.prop-marco__title { margin-top: var(--sp-2); color: var(--ink); }
.prop-marco__gain {
  font-size: var(--text-body);
  line-height: var(--lh-body);
  color: var(--ink-muted);
  margin-top: var(--sp-2);
  max-width: 58ch;
}
.prop-marco__list { list-style: none; margin-top: var(--sp-2); }

.prop-phase {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr);
  gap: var(--sp-3);
  align-items: start;
  padding: var(--sp-4) 0 var(--sp-4) var(--sp-3);
  border-left: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
}
@media (min-width: 900px) {
  .prop-phase {
    grid-template-columns: 28px minmax(0, 1fr);
    gap: var(--sp-4);
    padding: var(--sp-5) 0 var(--sp-5) var(--sp-4);
  }
}
.prop-phase__n {
  font-size: var(--text-caption);
  line-height: var(--lh-caption);
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
  padding-top: 2px;
}
.prop-phase__main { min-width: 0; }
.prop-phase__title { color: var(--ink); }
.prop-phase__gain {
  font-size: var(--text-body);
  line-height: var(--lh-body);
  color: var(--ink-muted);
  margin-top: var(--sp-2);
  max-width: 58ch;
}
.prop-phase__foot {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-4);
  margin-top: var(--sp-3);
  font-size: var(--text-caption);
  line-height: var(--lh-caption);
  color: var(--ink-subtle);
}

/* ── 28.5 Pendências do cliente ─────────────────────────────────────────────
   Uma linha por item, com o estado em .badge. Não é checkbox: a CostaVet não
   marca nada aqui, é um retrato do que falta.

   No celular o estado NÃO divide a linha com o título. "Verificação da empresa
   no Facebook Business" ao lado de "Caminho crítico" deixaria ~190px para o
   título, que quebraria em quatro linhas contra uma pill de uma. Empilhado, o
   título usa a largura inteira e o estado vem logo abaixo, alinhado à
   esquerda como todo o resto do documento. A linha de duas colunas volta no
   `sm`, onde há largura para as duas coisas.                               */
.prop-todos { margin-top: var(--sp-4); border-top: 1px solid var(--hairline); }
.prop-todo {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-2);
  align-items: start;
  padding-block: var(--sp-4);
  border-bottom: 1px solid var(--hairline);
}
.prop-todo > .badge { justify-self: start; }
@media (min-width: 640px) {
  .prop-todo {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--sp-2) var(--sp-4);
  }
  .prop-todo > .badge { justify-self: end; }
}
.prop-todo__title { display: flex; align-items: center; gap: var(--sp-2); color: var(--ink); }
.prop-todo__title .icon { color: var(--ink-faint); flex: none; }
.prop-todo__desc {
  grid-column: 1 / -1;
  font-size: var(--text-caption);
  line-height: var(--lh-caption);
  color: var(--ink-subtle);
  max-width: 62ch;
}


/* ── 28.6 Planos ────────────────────────────────────────────────────────────
   Os três planos são a primeira decisão que o leitor toma, e por isso são a
   §1 do documento. NÃO é a grade de preço de três colunas que toda página de
   SaaS usa: dentro de `.doc` sobram ~680px de medida, e três colunas ali dão
   ~210px cada — o valor, que é justamente o que o dono da distribuidora veio
   ler, sairia espremido entre duas quebras de linha.

   Então plano é LINHA, como a `.prop-pain` da §28.2 e a `.prop-mod` da §28.3:
   ilustração à esquerda, tudo o mais numa coluna de texto que usa a largura
   inteira. Empilha na ordem em que se lê, cresce sem reflow e imprime sem
   nenhuma regra especial.

   A escada é o argumento: cada plano contém o anterior. O `__inherits` é o
   que diz isso em uma linha, no lugar de repetir a lista inteira três vezes.
                                                                            */
.prop-plans { margin-top: var(--sp-4); border-top: 1px solid var(--hairline); }
.prop-plan {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-4);
  align-items: start;
  padding-block: var(--sp-6);
  border-bottom: 1px solid var(--hairline);
}
/* Do `md` para cima a arte vira quarta coluna, como na `.lp-module` da §25.
   Abaixo disso ela desce para baixo do texto e trava em 190px: esticada na
   largura do celular ela viraria ilustração decorativa de meia tela, que é
   exatamente o que a §7.7 não quer. */
@media (min-width: 900px) {
  .prop-plan { grid-template-columns: minmax(0, 1fr) 190px; gap: var(--sp-6); }
}

/* A arte reaproveita o vocabulário `.art-*` da §27.1 sem uma classe nova:
   mesma paleta de tokens, mesmo traço 1.5 `non-scaling-stroke`, mesma regra
   de que a marca é ACENTO e nunca preenche superfície. É `aria-hidden` — o
   que ela desenha já está escrito ao lado, e narrá-la seria repetir. */
.prop-plan__art { align-self: start; justify-self: start; width: 100%; max-width: 190px; }

.prop-plan__label {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  text-transform: uppercase;
  color: var(--brand);
}
.prop-plan__title { margin-top: var(--sp-2); color: var(--ink); }
.prop-plan__gain {
  margin-top: var(--sp-2);
  font-size: var(--text-body);
  line-height: var(--lh-body);
  color: var(--ink-muted);
  max-width: 62ch;
}

/* O valor é o único número grande do documento. Fica na escala de display
   pequena, no mesmo `.num` tabular do resto, com o "/mês" em corpo normal —
   sem cor, sem caixa, sem selo de "mais popular". */
.prop-plan__price {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  flex-wrap: wrap;
  margin-top: var(--sp-4);
  color: var(--ink);
}
.prop-plan__amount {
  font-size: var(--text-display-md);
  line-height: 1.15;
  letter-spacing: -0.015em;
  font-weight: 550;
}
.prop-plan__per { font-size: var(--text-body); line-height: var(--lh-body); color: var(--ink-subtle); }

/* A cota é o que o valor compra, então mora colada nele — não no meio da
   lista de recursos. Fica em `--ink`, não em `--ink-subtle`: é número de
   contrato, e o leitor vai voltar nele. */
.prop-plan__quota {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  flex-wrap: wrap;
  margin-top: var(--sp-2);
  font-size: var(--text-body);
  line-height: var(--lh-body);
  color: var(--ink);
}
.prop-plan__quota .num { font-weight: var(--fw-body-strong); }
.prop-plan__quota span:last-child { color: var(--ink-subtle); }

/* A alternativa anual anda junto do preço mensal, não numa tabela à parte:
   é a mesma decisão, tomada no mesmo instante. É o ÚNICO bloco com fundo de
   marca no documento inteiro, e usa o trio já estabelecido em `.auth__glyph`
   e `.badge--brand` — `brand-soft` de fundo, `brand-line` de borda, `brand`
   no texto. A marca continua sem preencher superfície em nenhum outro lugar:
   um destaque que se repete deixa de ser destaque.

   Contraste conferido nos dois temas: no claro `--brand` (L .44) sobre
   `--brand-soft` (L .955); no escuro (L .76) sobre (L .29).                */
.prop-plan__annual {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-2);
  margin-top: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--brand-line);
  border-radius: var(--radius-md);
  background: var(--brand-soft);
  max-width: 62ch;
}
.prop-plan__annual-tag {
  flex: none;
  font-size: var(--text-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  font-weight: var(--fw-micro);
  text-transform: uppercase;
  color: var(--brand);
}
.prop-plan__annual-amount {
  font-size: var(--text-title);
  line-height: var(--lh-title);
  letter-spacing: var(--ls-title);
  font-weight: var(--fw-title);
  color: var(--brand);
}
.prop-plan__annual-vista {
  font-size: var(--text-body);
  line-height: var(--lh-body);
  color: var(--ink-muted);
}
/* A justificativa quebra para a linha inteira: ela é leitura de apoio, e
   espremida ao lado do valor viraria uma coluna de duas palavras. */
.prop-plan__annual-note {
  flex-basis: 100%;
  font-size: var(--text-caption);
  line-height: var(--lh-caption);
  color: var(--ink-muted);
}

.prop-plan__inherits {
  margin-top: var(--sp-3);
  font-size: var(--text-caption);
  line-height: var(--lh-caption);
  color: var(--ink-subtle);
}
.prop-plan__list { list-style: none; margin-top: var(--sp-3); display: grid; gap: var(--sp-2); }
.prop-plan__list li {
  display: grid;
  grid-template-columns: 16px minmax(0, 1fr);
  gap: var(--sp-2);
  align-items: start;
  font-size: var(--text-body);
  line-height: var(--lh-body);
  color: var(--ink);
  max-width: 62ch;
}
.prop-plan__list .icon { color: var(--brand); margin-top: 4px; }

/* O que o plano NÃO faz vem junto, na mesma linha de leitura e no mesmo
   tamanho da nota de rodapé das fases. Omitir isso é o que transforma
   proposta em surpresa na implantação. */
.prop-plan__limit {
  margin-top: var(--sp-3);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--hairline);
  font-size: var(--text-caption);
  line-height: var(--lh-caption);
  color: var(--ink-subtle);
  max-width: 62ch;
}
.prop-plan__limit strong { color: var(--ink-muted); font-weight: var(--fw-body-strong); }


/* ── 28.7 Impressão ─────────────────────────────────────────────────────────
   O botão troca o tema para claro antes de chamar window.print() e devolve
   depois (evento afterprint) — por isso aqui não há remapeamento de token,
   só layout: cai para uma coluna, some o chrome do mockup e nada quebra no
   meio de uma fase.                                                        */
@media print {
  @page { margin: 16mm 14mm; }

  .mockbar,
  .doc-toc,
  .prop-noprint { display: none !important; }

  body:has(.mockbar) { padding-top: 0; }
  .mock-note, .mock-note--interna { display: none !important; }

  .prop-cover { background: none; }
  .prop-cover__inner { max-width: none; padding: 0 0 var(--sp-6); }

  .doc-page { display: block; max-width: none; padding: 0; }
  .doc { max-width: none; }

  /* No papel não existe rolagem: um contêiner com `overflow-x: auto` só faz
     RECORTAR o que passa da largura da folha. */
  .table-wrap { overflow: visible; }
  /* `position: sticky` no <thead> repete ou empilha o cabeçalho de forma
     imprevisível na paginação. No papel ele volta a ser cabeçalho comum. */
  .table thead th { position: static; }

  .doc-section { padding-top: var(--sp-6); }
  .doc h2,
  .doc h3,
  .prop-marco__head { break-after: avoid; }

  /* O navegador descarta fundo na impressão por padrão. Este é o único bloco
     do documento em que a cor CARREGA informação comercial — sem o fundo, a
     alternativa anual vira mais um parágrafo no PDF que o cliente assina. */
  .prop-plan__annual { print-color-adjust: exact; -webkit-print-color-adjust: exact; }

  .prop-phase,
  .prop-plan,
  .prop-mod,
  .prop-todo,
  .prop-pain,
  .callout,
  .doc-dl > div,
  .table-wrap,
  .doc-foot { break-inside: avoid; }
}


/* ═══ 30 · inbox.html NO CELULAR — NAVEGAÇÃO EM CAMADAS ═════════════════════
   Três colunas não cabem em 360px. Empilhá-las funciona para LER o mockup,
   mas não para trabalhar nele: o atendente rolaria meia tela de filas antes
   de alcançar a conversa, e outra meia para voltar. No celular a inbox vira
   NAVEGAÇÃO EM CAMADAS — o mesmo gesto do WhatsApp, que é o aplicativo que o
   comercial da CostaVet já tem na mão:

     camada 1 · FILA      trilho + filas + lista de conversas (tela inicial)
     camada 2 · CONVERSA  thread em tela cheia, com voltar no cabeçalho
     folha    · FICHA     ficha do cliente subindo de baixo, sobre a conversa

   O estado mora num atributo do shell — `data-vista="fila" | "conversa"` — e
   a troca é um `setAttribute`. Nada fica inalcançável: o que saiu de vista
   volta por um botão nomeado, não por rolagem às cegas.

   Do `md` para cima o mecanismo MORRE e volta a valer, intacto, o grid da
   §7.1 (md = lista + conversa · lg = + filas · xl = + ficha). Como
   `max-width` é proibido, quem desfaz a camada é o próprio degrau
   `min-width`: são os blocos de reposição no fim desta seção. Eles repetem o
   que a §7.1 já diz, com a mesma especificidade — a ordem no arquivo é que
   decide, e esta seção é a última.                                      ═══ */

/* ── A camada ativa é a viewport, e só ela ────────────────────────────────
   `100dvh` com `100vh` antes: no iOS a barra do navegador entra na conta do
   `vh` e o composer acabaria embaixo dela. */
.app-shell--inbox[data-vista] {
  display: flex;
  flex-direction: column;
  height: calc(100vh - var(--mockbar-offset));
  height: calc(100dvh - var(--mockbar-offset));
  min-height: 0;
  overflow: hidden;
}

/* ── Camada 1 · FILA ──────────────────────────────────────────────────────
   Trilho, filas e lista rolam JUNTOS, como um documento: as filas continuam
   ali, a um polegar de distância, em vez de trancadas atrás de um menu. */
.app-shell--inbox[data-vista="fila"] {
  overflow-y: auto;
  overscroll-behavior-y: contain;
}
.app-shell--inbox[data-vista="fila"] > .rail,
.app-shell--inbox[data-vista="fila"] > .sidebar,
.app-shell--inbox[data-vista="fila"] > .inbox-lista { flex: none; }
.app-shell--inbox[data-vista="fila"] > .pane--canvas { display: none; }

/* O cabeçalho da fila trava no topo enquanto as conversas passam por baixo:
   o nome da fila e o contador não somem no meio da rolagem. */
.app-shell--inbox[data-vista="fila"] > .inbox-lista > .pane__header {
  position: sticky;
  top: 0;
  z-index: 2;
}

/* ── Camada 2 · CONVERSA ──────────────────────────────────────────────────
   Cabeçalho fixo, thread rolando no meio, composer preso na base. A área
   rolável é exatamente `100dvh − cabeçalho − barra de ações − rodapé`, e
   quem faz essa conta é o flex, não um `calc()` que envelhece. */
.app-shell--inbox[data-vista="conversa"] > .rail,
.app-shell--inbox[data-vista="conversa"] > .sidebar,
.app-shell--inbox[data-vista="conversa"] > .inbox-lista { display: none; }
.app-shell--inbox[data-vista="conversa"] > .pane--canvas {
  flex: 1;
  min-height: 0;
  overflow: hidden;
}
.app-shell--inbox[data-vista="conversa"] > .pane--canvas > .pane__header,
.app-shell--inbox[data-vista="conversa"] > .pane--canvas > .filter-bar { flex: none; }
.app-shell--inbox[data-vista="conversa"] > .pane--canvas > .pane__body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior-y: contain;
}

/* O rodapé da conversa carrega a sugestão da IA E o composer. Numa tela de
   640px a sugestão sozinha comeria metade — então é o RODAPÉ que rola, até
   a metade da viewport, e o composer fica preso na base dele. É por isso que
   o `sticky` abaixo é real e não decorativo. */
.app-shell--inbox[data-vista="conversa"] > .pane--canvas > .pane__footer {
  max-height: 52vh;
  max-height: 52dvh;
  overflow-y: auto;
  overscroll-behavior-y: contain;
  padding-bottom: 0;      /* quem encosta na borda agora é o dock */
}

/* Dock do composer: a última coisa antes da barra de gestos do iPhone.
   O `textarea` já lê `--text-control` (16px no dedo) — abaixo disso o Safari
   daria zoom ao focar e não voltaria mais. */
.composer-dock {
  position: sticky;
  bottom: 0;
  z-index: 1;
  padding-top: var(--sp-2);
  padding-bottom: max(var(--sp-1), env(safe-area-inset-bottom, 0px));
  background: var(--canvas);
}

/* Voltar para a fila. Existe só enquanto a lista não está do lado. */
.inbox-voltar { flex: none; }

/* Menu de transbordo do cabeçalho da conversa: "assumir" e "resolver" ficam
   na tela, "transferir" e "adiar" vão para cá. Ancorado à direita porque no
   celular o gatilho fica na borda direita e um popover de 200px alinhado à
   esquerda sairia da tela. */
.inbox-acoes > .popover { left: auto; right: 0; }

/* ── Folha da ficha do cliente ────────────────────────────────────────────
   Sobe de baixo sobre a conversa, com a mesma linguagem do drawer da §16:
   folha branca, hairline, elevação de overlay, 240ms de translateY 8px.
   Nunca cobre a tela toda — os 18% de conversa que sobram acima são o que
   diz ao dedo que a folha se fecha. */
.app-shell--inbox[data-vista] > .inbox-sheet { display: none; }
.app-shell--inbox[data-vista] > .inbox-sheet.is-open {
  display: flex;
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 101;
  max-height: 82vh;
  max-height: 82dvh;
  border-top: 1px solid var(--hairline-strong);
  border-bottom: 0;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  box-shadow: var(--elev-overlay);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  overflow: hidden;
  overscroll-behavior: contain;
  animation: ame-sheet-in var(--dur-slow) var(--ease-out) both;
}
@keyframes ame-sheet-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .app-shell--inbox[data-vista] > .inbox-sheet.is-open { animation: none; }
}
.inbox-sheet.is-open > .pane__body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior-y: contain;
}

/* Puxador. Decorativo e insuficiente sozinho — quem fecha a folha é o botão
   nomeado do cabeçalho, o scrim e o Esc. */
.inbox-sheet__grip {
  display: block;
  flex: none;
  width: 36px;
  height: 4px;
  margin: var(--sp-2) auto 0;
  border-radius: var(--radius-pill);
  background: var(--hairline-strong);
}

/* ── Do `md` para cima a camada morre ─────────────────────────────────────
   Nenhuma regra nova de layout aqui: cada linha repõe o que a §7.1 já dizia
   antes de a base virar celular. */
@media (min-width: 900px) {
  .app-shell--inbox[data-vista] {
    display: grid;
    overflow: hidden;
  }
  .app-shell--inbox[data-vista] > .rail,
  .app-shell--inbox[data-vista] > .inbox-lista,
  .app-shell--inbox[data-vista] > .pane--canvas { display: flex; }
  .app-shell--inbox[data-vista] > .sidebar { display: none; }

  .app-shell--inbox[data-vista] > .inbox-lista > .pane__header { position: static; }

  .app-shell--inbox[data-vista] > .pane--canvas > .pane__footer {
    max-height: none;
    overflow: visible;
    padding-bottom: calc(var(--sp-3) + env(safe-area-inset-bottom, 0px));
  }
  .composer-dock { position: static; padding: 0; background: none; }

  /* A folha volta a ser coluna: nenhum resquício de sobreposição. */
  .app-shell--inbox[data-vista] > .inbox-sheet,
  .app-shell--inbox[data-vista] > .inbox-sheet.is-open {
    display: none;
    position: static;
    max-height: none;
    border-top: 0;
    border-radius: 0;
    box-shadow: none;
    padding-bottom: 0;
    animation: none;
  }

  .inbox-voltar,
  .inbox-sheet__grip { display: none; }
  .inbox-acoes > .popover { left: 0; right: auto; }
}

@media (min-width: 1200px) {
  .app-shell--inbox[data-vista] > .sidebar { display: flex; }
}

@media (min-width: 1600px) {
  .app-shell--inbox[data-vista] > .inbox-sheet,
  .app-shell--inbox[data-vista] > .inbox-sheet.is-open { display: flex; }
  /* Recolher a ficha continua sendo prerrogativa do botão, como na §7.1. */
  .app-shell--inbox[data-vista].app-shell--no-context > .inbox-sheet,
  .app-shell--inbox[data-vista].app-shell--no-context > .inbox-sheet.is-open { display: none; }
}
