/* ===========================================================================
   App JC — web app (PWA). Design system canônico: docs/design/design-system-app-jc.md
   e o protótipo aprovado `prototipo-home-arcade-coral.html`.

   LEI 4 (nada de cor sem nome): nenhum hex fora do bloco `:root`. As únicas
   exceções nomeadas pelo design system são `#fff` (branco puro) — o fundo de
   moldura dos protótipos NÃO vem para cá, porque não é cor de produto.

   Verificação (deve listar só as linhas do :root e os #fff):
     grep -nE "#[0-9A-Fa-f]{3,6}" web/app.css
   =========================================================================== */

:root{
  /* Rampa unica, matiz 203 travada, degraus ancorados em CONTRASTE (ADR-0035).
     Os nomes de token do Arcade sobrevivem; so os valores mudam. */
  --navy-card:#07161E;   /* b950 - fundo do card da jornada, fase atual, aba ativa */
  --navy-deep:#09212F;   /* b900 - bloco interno "next up" */
  --navy:#0D3248;        /* b800 - texto principal */
  --navy-tint:#0D3248;   /* b800 - trilha incompleta, fase trancada (sobre o card) */
  --navy-line:#3B98D1;   /* b400 - borda de elemento trancado sobre o card */
  --navy-fade:#8BBEDD;   /* b300 - texto e icone secundario sobre o card */
  --blue-pale:#8BBEDD;   /* b300 - icone de destaque sobre navy-deep */
  --blue:#237BB2;        /* b500 - ACAO: nav ativa, avatar, link, sino */
  --blue-deep:#154B6D;   /* b700 - "dominio, pontos e links" (ADR-0035). O degrau
                            que carrega TEXTO sobre fundo claro: 9,30:1 no branco,
                            8,08:1 sobre --blue-light onde o b500 dava 4,01. */
  --blue-light:#E9F0F5;  /* b100 */
  /* "nao sabemos" (D62). Os 6 usos deste token vivem TODOS sobre fundo claro —
     nenhum sobre o card escuro — e no b300 o traco media 1,87:1 contra o --soft:
     a ausencia estava desenhada e ilegivel, que e' o mesmo que nao estar. O b600
     da 6,09:1 ali. Nao pode ser o b500: aquele degrau e' ACAO (ADR-0035), e uma
     ausencia pintada de acao convida a clicar no que nao existe. */
  --empty:#1D638F;       /* b600 */
  --track:#C9DDEA;       /* b200 - "ainda nao aconteceu" */
  --soft:#F5F8FA;        /* b50  - fundos neutros */
  /* Demanda: coral. Identico ao #FC5647 da Angi (matiz 4,9 x 5,0). */
  --accent-dark:#B3352A;--accent:#FF6153;--accent-light:#FFEBE8;
  --accent-solid:#D04539; /* preenchimento de botao - 4,57:1 com branco (ADR-0033) */
  --green:#1E9E66;--green-light:#E4F5EC;
  --green-dark:#167D51;   /* verde que carrega TEXTO - 5,14:1 (ADR-0033) */
  --ts:#5E6F87;           /* era #7C8AA5 = 3,48:1, reprovava (ADR-0033/0034) */
  --line:#E4EAF0;         /* borda de card */
  --field-line:#5E6F87;   /* borda de CAMPO - era 1,19:1, reprovava 1.4.11 */
  --sans:'Inter',system-ui,sans-serif;--display:'Manrope',system-ui,sans-serif;
  /* Largura fixa, um uso so: o codigo de pareamento. Pilha do SISTEMA, sem
     `@font-face` — zero byte novo. Porque: ADR-0177. */
  --mono:ui-monospace,'SF Mono',Menlo,Consolas,monospace;

  /* ── ESCALA DE TEXTO ────────────────────────────────────────────────────
     7 degraus. Antes eram **20 tamanhos distintos**, 5 deles em meio pixel
     (10,5 · 11,5 · 12,5 · 13,5 · 14,5) e dez espremidos entre 10,5 e 15.
     Passo de meio pixel está abaixo do limiar perceptual: ninguém lê "13,5
     contra 14" como hierarquia — lê como descuido. E como quase tudo vivia
     entre 11 e 14, nada dominava, e a hierarquia inteira sobrava para a cor.

     O PISO SUBIU de 10,5 para 12 de propósito: o comprador é dono de empresa
     de serviço, tipicamente 35-55 anos, lendo no sol, com a tela suja e uma
     mão só. Presbiopia começa aos 40, e `micro` é carimbo, nunca corpo.

     A migração foi conservadora: dos 84 tamanhos de texto, 63 mudaram, e o
     maior salto foi 3px — a maioria mexeu 0,5 ou 1px. */
  --t-micro:12px;   /* carimbo de tempo, rótulo de métrica */
  --t-meta:13px;    /* apoio, prévia, legenda */
  --t-body:15px;    /* corpo, campo, botão */
  --t-lead:17px;    /* saudação, entrada de bloco */
  --t-title:20px;   /* título de tela */
  --t-hero:24px;    /* número grande */
  --t-display:28px; /* o maior — hoje só o h1 do login */

  /* ── ESCALA DE ÍCONE ────────────────────────────────────────────────────
     PRÓPRIA, e não a de texto. Ícone e letra não crescem pelo mesmo motivo:
     casar as duas faria a lupa de um campo crescer junto com o rótulo dele,
     que não é a mesma decisão. Eram 10 tamanhos avulsos entre 13 e 26. */
  --i-sm:16px;   /* dentro de linha, ao lado de texto */
  --i-md:20px;   /* dentro de círculo, nav, ação */
  --i-lg:26px;   /* ilustração de estado vazio */

  /* ── ESCALA DE RAIO ─────────────────────────────────────────────────────
     Eram 7 valores (12·14·16·18·20·22·24) sem nenhuma regra dizendo quando
     usar qual — arredondamento no olho, componente a componente. A faixa
     20-24 do "arcade" (§5 do design system) continua; o que sai são os
     degraus intermediários que competiam sem hierarquia. */
  --r-sm:14px;    /* campo, linha, bloco interno */
  --r-md:20px;    /* tile, balão, card pequeno */
  --r-lg:24px;    /* card-herói (jornada, fase) */
  --r-pill:99px;  /* pill e círculo */

  /* ── COR COM ALFA ───────────────────────────────────────────────────────
     A Lei 4 diz "nada de cor sem nome", e `rgba(13,50,72,.06)` é uma cor sem
     nome que o lint de hex não pegava — o buraco fechou junto com estes dois
     tokens. Os dois são o MESMO navy e o MESMO branco do resto da paleta, só
     que translúcidos; escritos assim, trocar a paleta continua trocando tudo. */
  --sombra-coluna:rgba(13,50,72,.06);  /* --navy a 6% — a borda da coluna no desktop */
  --branco-fraco:rgba(255,255,255,.14); /* branco a 14% — chip sobre o card escuro */
  /* ── RAMPA DO PAINEL (2026-08-16) ────────────────────────────────────────
     A malha da referência aprovada tem tamanhos que a escala `--t-*` não tem
     (9 · 10 · 11 · 14 · 16 · 18) e faz hierarquia por PESO. Somar 5 degraus
     aos 7 de `--t-*` daria 12 tamanhos anônimos — a bagunça que o design
     system desfez. Então o painel tem rampa PRÓPRIA e NOMEADA, com trabalho
     definido em cada degrau. Duas rampas com nome se leem; doze degraus sem
     dono, não.
     🔴 Fura o piso de 12px, e isso é decisão da chefia com o render na mão:
     ela aprovou nesses tamanhos. Se parecer pequeno, sobe a rampa inteira. */
  --p-nano:11px;   /* legenda de gráfico, rodapé de métrica */
  --p-rot:11px;    /* rótulo de KPI (CAPS), subtítulo de cartão, chip */
  --p-lin:12px;    /* linha e valor de funil, delta do KPI */
  --p-tab:13px;    /* aba, status bar, avatar */
  --p-card:17px;   /* título de cartão */
  --p-med:20px;    /* número do trio de qualidade */
  --p-num:26px;    /* número do KPI */
  --p-tit:28px;    /* título da tela */
  --r-p:16px;      /* raio do cartão do painel — o degrau da referência */
  /* `--w` é preenchido inline por barra (`style="--w:91%"`); o default aqui
     existe para a barra nunca herdar lixo se o dado faltar. */
  --w:0%;
  --p-hair:rgba(13,50,72,.08);
  --p-sh:0 1px 3px rgba(13,50,72,.10), 0 1px 2px -1px rgba(13,50,72,.10);
  --p-ease:cubic-bezier(.4,0,.2,1);

  /* ── ESCALA DE ESPAÇO ───────────────────────────────────────────────────
     2026-08-17. Eram 26 valores em 250 usos, escolhidos no olho, e o
     `design-lint` não checava nenhum deles — a maior superfície do arquivo
     sem token E sem portão. 11·12·13 e 14·15·16 conviviam em 132 usos: um
     passo de 1px não produz hierarquia, produz textura de descuido. É o
     mesmo argumento da escala de texto (l. 46).

     Os degraus saem da MEDIÇÃO, não de uma régua 4/8/16 teórica. Isso
     importa em UM ponto que parece erro e não é: 15 e 16 ficaram os dois.
     São papéis diferentes que por acaso estão a 1px —
       16px é a MARGEM DE TELA  (22 dos 27 usos são `margin:0 16px`)
       15px é o RESPIRO DE CARD (11 dos 14 usos são `padding:N 15px`)
     Fundir os dois moveria todos os cards ou toda a margem da tela, e
     nenhum dos dois é melhoria. Por isso a margem tem nome próprio e não é
     degrau: ela nunca mudou em nenhum dos 22 lugares onde aparece. */
  --s-1:2px;      /* fio: ícone↔rótulo, 2ª linha de um par  (1·2·3  → 18 usos) */
  --s-2:4px;      /* aperto: interior vertical de pílula    (4·5    → 19) */
  --s-3:6px;      /* gap curto                              (6·7    → 24) */
  --s-4:9px;      /* interior horizontal de pílula          (8·9·10 → 37) */
  --s-5:12px;     /* o passo padrão: gap de linha, folga entre blocos (11·12·13 → 67) */
  --s-6:15px;     /* respiro interno de card                (14·15  → 40) */
  --s-7:20px;     /* cabeçalho de tela, respiro grande      (18·20·22 → 12) */
  --s-8:32px;     /* tela sem card: login, estado vazio     (32·34  → 2) */
  --s-gutter:16px;/* A MARGEM LATERAL DA TELA. Constante, não degrau. */

  /* ── MOVIMENTO ──────────────────────────────────────────────────────────
     Os números saem da decisão já escrita na l. 210-212: 180ms é percebido
     como RESPOSTA, e acima de ~250ms começa a ser percebido como espera. O
     que faltava era o degrau ABAIXO de 180 — o realce sob o dedo quer ~100ms,
     porque acima disso o dedo já saiu e o realce vira eco.

     São três tokens e não seis porque neste app NADA SAI DE CENA: o router
     substitui a tela inteira (`raiz.replaceWith`, router.js:185), então uma
     curva de saída nunca rodaria. Token que não roda é token que mente. */
  --mov-toque:.10s;  /* realce sob o dedo: :active */
  --mov:.18s;        /* o degrau canônico — o mesmo do @keyframes entrar */
  --ease:ease-out;   /* desacelera na chegada; nada acelera na saída aqui */

  /* ── CAMADA ─────────────────────────────────────────────────────────────
     Não havia `z-index` no app. A nav pill (l. 567) fica por cima hoje por
     ACIDENTE: é o último filho do template E é posicionada, então ganha nos
     dois desempates. No dia em que uma tela renderizar algo posicionado
     depois do `navPill(...)`, a pill some por baixo em silêncio — e num PWA
     `standalone` não há botão de voltar para escapar. */
  --z-base:0;   /* conteúdo da tela */
  --z-nav:10;   /* a barra de navegação fixa */

  /* ── SOMBRA ─────────────────────────────────────────────────────────────
     2026-08-17, decisão da Junia a partir do mockup. O app era plano de
     propósito: isto é desvio consciente, não descuido.

     É `--navy` translúcido, nunca preto — preto sobre paleta fria lê como
     sujeira. Dois degraus e não cinco: numa coluna de 420px, do nível 3 em
     diante ninguém distingue e só custa paint no Android de entrada.

     ⚠️ `rgba()` só é legal dentro do `:root` (design-lint l. 128-138).

     Reversível por uma linha: se ler mal no sol (nota de ICP, l. 53-55),
     `border:1px solid var(--line)` no lugar não mexe em mais nada. */
  --sombra-1:rgba(13,50,72,.07);  /* --navy a 7%  — apoio, contato com a página */
  --sombra-2:rgba(13,50,72,.13);  /* --navy a 13% — a peça que saltou do plano */
}

*{box-sizing:border-box;margin:0}

/* No celular o app ocupa a tela inteira; no desktop vira a coluna de 375px do
   protótipo, centrada sobre `soft`. É a mesma tela, não um layout novo. */
/* 🔴 O body NÃO é flex container (mudou 2026-08-10). Era `display:flex` +
   `justify-content:center`, e a centralização do app dependia disso — o que
   funciona até alguém injetar um elemento no `<body>`. Extensão de navegador
   faz exatamente isso: a injetada vira flex-item, divide a linha, e o app é
   EMPURRADO para o lado (medido em produção num notebook com barra de SEO —
   o app apareceu colado na direita, com a nav pill solta no meio da tela).
   Com `margin:0 auto` no próprio #app, a centralização não depende de mais
   ninguém e é imune a qualquer coisa que o navegador do cliente injete. */
body{
  background:var(--soft);
  font-family:var(--sans);
  color:var(--navy);
  min-height:100vh;
  min-height:100dvh;
  -webkit-font-smoothing:antialiased;
}
#app{
  width:100%;
  max-width:420px;
  margin:0 auto;
  background:#fff;
  min-height:100vh;
  min-height:100dvh;
  display:flex;
  flex-direction:column;
  /* espaço da barra de navegação fixa + safe area do iOS */
  padding-bottom:calc(84px + env(safe-area-inset-bottom));
}
#app.no-nav{padding-bottom:0}

/* No DESKTOP a coluna precisa ter BORDA.
   O app é branco sobre `--soft`, e os dois medem 1,07:1 entre si — ou seja, no
   monitor a coluna não tinha nenhum limite visível: lia como uma página que não
   terminou de carregar, não como "o app, no desktop". A hipótese de que boa
   parte do 'muito amador' veio daí é plausível justamente porque a revisão foi
   feita no monitor, não no celular.
   Só borda e sombra, de propósito: emoldurar a coluna como um aparelho exigiria
   limitar a ALTURA, e a nav pill é `position:fixed` no viewport (l. 446) — ela
   se descolaria da moldura e ficaria solta no meio da tela, que é exatamente o
   defeito que o comentário do `body` acima descreve. */
@media (min-width:900px){
  #app{
    border-left:1px solid var(--line);
    border-right:1px solid var(--line);
    box-shadow:0 0 40px var(--sombra-coluna);
  }
}

/* --- tipografia base ---------------------------------------------------- */
h1,h2,h3{font-family:var(--display);font-weight:600;color:var(--navy)}
button{font-family:var(--sans)}

/* --- utilitários de estado (D62: ausência tem cor própria) --------------- */
.empty{color:var(--empty)}

/* --- carregando --------------------------------------------------------- */
.loading{
  flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:var(--s-5);color:var(--ts);font-size:var(--t-meta);
}
.spinner{
  width:28px;height:28px;border-radius:50%;
  border:3px solid var(--track);border-top-color:var(--blue);
  animation:spin .8s linear infinite;
}
@keyframes spin{to{transform:rotate(360deg)}}

/* --- esqueleto de carregamento (consultoria 2026-08-12, decisão nº1) -------
   O spinner acima continua existindo para a espera DENTRO de uma tela já
   desenhada (a thread da inbox). O esqueleto serve o outro caso: a tela
   inteira ainda não existe, e um spinner centralizado no vazio não diz nada
   sobre o que vem.

   NENHUM token novo, de propósito. `--track` já significa "ainda não
   aconteceu" no design system, que é exatamente o que um esqueleto é; usá-lo
   aqui mantém o `contrast-lint` verde e não inventa um cinza paralelo.

   ⚠️ Estas classes NÃO carregam texto. Se algum dia carregarem, o par de cor
   precisa ir para a tabela do design system e passar pelo portão de contraste
   — `--track` sobre `--soft` é 1,4:1, ilegível de propósito: é forma, não
   informação. */
.sk{flex:1;padding:var(--s-gutter);display:flex;flex-direction:column;gap:var(--s-5)}
.sk i{display:block;background:var(--track);border-radius:var(--r-sm);height:14px}
.sk .bloco{height:96px;border-radius:var(--r-md)}
.sk .alto{height:150px;border-radius:var(--r-md)}
.sk .curto{width:45%}
.sk .medio{width:70%}
.sk .linha{display:flex;gap:var(--s-5);align-items:center;padding:var(--s-5) 0}
.sk .circulo{width:42px;height:42px;border-radius:50%;flex-shrink:0}
.sk .corpo{flex:1;display:flex;flex-direction:column;gap:var(--s-4)}
/* `flex:1` acima serve o `.corpo` DENTRO de `.linha` (horizontal), onde ele
   ocupa o resto da largura. Como filho direto de `.sk` (que é coluna), o mesmo
   `flex:1` faz cada par esticar em ALTURA e espalhar a ficha pela tela inteira
   — os pares ficavam a mais de 200px um do outro, nada parecido com a tela que
   estava por vir. Visto na captura; nenhum proof pegaria. */
.sk > .corpo{flex:none}
/* A pulsação que diz "está vindo" — sem ela o esqueleto lê como conteúdo
   quebrado, cinza e parado. É a diferença entre "carregando" e "vazio".

   É PULSAÇÃO e não o shimmer diagonal de sempre por duas razões medidas:
     1. shimmer precisa de um branco translúcido no gradiente, e cor sem nome
        fora do `:root` viola a lei 4 — o `design-lint` reprova, e reprovou;
     2. `opacity` é composited pelo GPU; `background-position` força repaint da
        caixa a cada quadro. Numa lista de esqueleto isso é a diferença entre
        liso e picotado no celular do cliente, que é o aparelho que importa. */
.sk i{animation:pulsar 1.4s ease-in-out infinite}
@keyframes pulsar{0%,100%{opacity:1}50%{opacity:.45}}

/* --- entrada da tela ------------------------------------------------------
   A troca de tela era um corte seco: o conteúdo aparecia inteiro, no mesmo
   quadro. Uma subida de 6px com fade dá ao olho a informação de que algo
   CHEGOU, em vez de a tela ter sempre estado ali. Curta de propósito — 180ms
   é percebido como resposta; acima de ~250ms começa a ser percebido como
   espera, e aí a animação passa a custar em vez de render. */
/* 🔴 SEM `transform` AQUI, E ISSO NÃO É ESCOLHA ESTÉTICA — 2026-08-19.
   Quem recebe `.entrando` é o `palco`, que É o `#app` (`router.js:192`), e a nav
   mora DENTRO dele (`${navPill(...)}` no template de cada tela). Pelo spec do
   CSS, ancestral com `transform` vira containing block dos descendentes
   `position:fixed` — durante os .18s da animação a nav deixava de se ancorar no
   viewport e passava a se ancorar no `#app`, que é mais alto que a tela. Ela ia
   parar no fim do conteúdo, fora de vista, A CADA navegação. Reportado como
   "o footer com as abinhas está sumindo".
   `opacity` sozinha não cria containing block, então a nav fica congelada — que
   é o que se espera de um app.
   ⚠️ Consequência: a entrada perdeu os 6px de deslize e virou fade puro. A
   ADR-0132 fixou `--mov` como o degrau de movimento e ele continua valendo em
   todo o resto; o que saiu foi o deslocamento DESTE keyframe. O conserto
   estrutural (tirar a nav de dentro do `#app`) devolveria os 6px, mexe em 6
   telas e fica registrado como opção, não feito aqui. */
@keyframes entrar{from{opacity:0}to{opacity:1}}
.entrando{animation:entrar var(--mov) var(--ease) both}

/* --- transição --------------------------------------------------------------
   Só nos nós que PERSISTEM entre estados. Item de lista (`.conv`, `.task`) fica
   fora: cada tela é reescrita por `innerHTML` (router.js), então dispararia
   sobre zero mudança hoje e viraria pisca-pisca no dia do render incremental.
   Três propriedades e só elas — `background-color`, `opacity`, `transform` são
   compostas na GPU; `all`, `height`, `box-shadow` e `filter` forçam layout ou
   repaint por quadro. Mesma razão do `.sk i` pulsar por `opacity`. */
.botao,.cta,.linha-acao,.tab,.reply,.nav a,.pulse .cta{
  transition:background-color var(--mov) var(--ease),opacity var(--mov) var(--ease),transform var(--mov-toque) var(--ease);
}
.botao:active,.cta:active,.linha-acao:active,.tab:active,.reply:active,.nav a:active,.pulse .cta:active{transform:scale(.98)}
/* Atrasar o indicador de foco é atrasar a informação de ONDE VOCÊ ESTÁ. */
.botao:focus-visible,.cta:focus-visible,.linha-acao:focus-visible,.tab:focus-visible,.reply:focus-visible,.nav a:focus-visible,.pulse .cta:focus-visible{transition:none}

/* Movimento reduzido não é "menos animação": é NENHUM movimento. O brilho e a
   subida saem inteiros; o esqueleto vira forma estática, que continua
   comunicando "ainda não chegou" sem nada se mexer. Quem liga essa preferência
   costuma fazê-lo por enjoo ou vertigem — meia dose não serve.
   ⚠️ O spinner contradizia a lei três linhas acima dela: só ficava mais LENTO
   (2,4s), girando por mais tempo na frente de quem pediu para nada girar. */
@media (prefers-reduced-motion:reduce){
  *{transition:none!important}
  .sk i{animation:none}
  .entrando{animation:none}
  .spinner{animation:none;opacity:.6}
}

/* --- erro (nunca vermelho: o design system não tem vermelho) ------------- */
.erro{
  margin:var(--s-5) var(--s-gutter);background:var(--accent-light);border-radius:var(--r-md);
  padding:var(--s-5) var(--s-6);display:flex;align-items:center;gap:var(--s-5);
}
.erro .ic{
  width:36px;height:36px;border-radius:50%;background:var(--accent);
  display:flex;align-items:center;justify-content:center;flex-shrink:0;
}
.erro .ic i{font-size:var(--i-md);color:#fff}
.erro p{font-size:var(--t-meta);color:var(--accent-dark);font-weight:500}

/* =========================================================================
   LOGIN — única tela sem referência canônica (as 5 do design são pós-login).
   Construída com as peças existentes: título Manrope navy, campo de borda
   `line`, CTA pill coral. Nenhum token novo foi inventado para ela.
   ========================================================================= */
.login{flex:1;display:flex;flex-direction:column;justify-content:center;padding:32px 24px;gap:22px}
/* O lockup: símbolo + nome. Manrope 600 com o mesmo aperto de letra dos
   títulos, e o nome alinhado ÓPTICAMENTE ao símbolo (o `align-items:center`
   basta porque o símbolo é circular — num logotipo com haste seria preciso
   compensar à mão). Fica acima do "Welcome back" e não substitui o título:
   a marca diz de quem é o app, o título diz o que fazer nesta tela. */
.login .lockup{display:flex;align-items:center;gap:11px;margin-bottom:2px}
.login .lockup span{font-family:var(--display);font-weight:600;font-size:var(--t-title);letter-spacing:-.3px;color:var(--navy)}
.login .marca{display:flex;flex-direction:column;gap:6px}
.login .marca h1{font-size:var(--t-display);letter-spacing:-.4px}
.login .marca p{font-size:var(--t-body);color:var(--ts)}
.login form{display:flex;flex-direction:column;gap:11px}
.campo{display:flex;flex-direction:column;gap:6px}
.campo label{font-size:var(--t-meta);font-weight:500;color:var(--ts)}
.campo input{
  font-family:var(--sans);font-size:var(--t-body);color:var(--navy);
  background:#fff;border:1px solid var(--field-line);border-radius:var(--r-sm);
  padding:14px 16px;width:100%;
}
.campo input:focus{outline:2px solid var(--blue);outline-offset:1px;border-color:var(--blue)}
.botao{
  background:var(--blue);color:#fff;font-size:var(--t-body);font-weight:500;
  padding:15px 18px;border-radius:var(--r-pill);border:0;width:100%;margin-top:4px;
}
.botao:disabled{opacity:.55}
.login .nota{font-size:var(--t-micro);color:var(--ts);text-align:center;line-height:1.5}
/* magic link como LINK de texto — ação secundária, não um 3º botão cheio */
.login .link-btn{
  background:none;border:0;color:var(--blue);font-size:var(--t-body);font-weight:500;
  padding:8px;width:100%;text-align:center;cursor:pointer;
}
.login .link-btn:disabled{opacity:.55}
/* Nota que vale para o arquivo inteiro: número de PR aqui vai SEM cerquilha —
   o design-lint lê a cerquilha seguida de 3 ou 6 dígitos como cor crua. */

/* =========================================================================
   CHROME COMPARTILHADO — header e nav pill (protótipo aprovado, verbatim)
   ========================================================================= */
.header{display:flex;align-items:center;justify-content:space-between;padding:20px 20px 12px}
.who{display:flex;align-items:center;gap:11px}
.avatar{
  width:46px;height:46px;border-radius:50%;background:var(--blue);color:#fff;
  display:flex;align-items:center;justify-content:center;
  font-family:var(--display);font-weight:600;font-size:var(--t-lead);
}
.hey{font-family:var(--display);font-weight:600;font-size:var(--t-lead);color:var(--navy)}
/* Telas irmãs abrem com o título da tela — a saudação é privilégio da home
   (nota de chrome 1 do design system). */
.titulo-tela{font-family:var(--display);font-weight:600;font-size:var(--t-title);color:var(--navy)}
/* Pontos ganhos sao RECOMPENSA, nao demanda: ninguem esta esperando o dono por
   causa deles. Pela ADR-0034 isso e' azul — e o b700 e' o degrau que a ADR-0035
   destina a "pontos". Coral aqui roubava a atencao do pulso de lead na mesma
   tela, que e' o unico lugar da home onde alguem esta mesmo esperando. */
.pts{display:flex;align-items:center;gap:4px;margin-top:1px;font-size:var(--t-meta);font-weight:500;color:var(--blue-deep)}
.pts i{color:var(--blue);font-size:var(--i-sm)}
/* `min-width:0` é o que faz o ellipsis valer: sem ele o filho flex adota
   `min-width:auto` e ESTICA até caber o nome inteiro, empurrando o selo para
   fora da linha em vez de cortar o nome. */
.quem{min-width:0}
/* O nome da EMPRESA — qual conta está aberta, não quem está usando. Uma linha
   sempre: razão social longa empilharia três alturas de texto no cabeçalho. */
.empresa{
  margin-top:1px;font-size:var(--t-micro);font-weight:500;color:var(--ts);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

/* ── O SELO DE FRESCOR (substituiu o sino) ──────────────────────────────────
   🚫 SEM ANIMAÇÃO: ponto pulsando numa tela que fica aberta é bateria, gatilho
   para quem tem enjoo de movimento, e em dois dias ninguém mais vê.
   🚫 SEM CORAL (ADR-0034): ninguém espera por um carimbo de tempo.

   O terceiro estado é o que importa: `sem` usa `--empty`, a cor de "não
   sabemos". O BFF leu o banco e não falou com o GHL, então o número pode estar
   velho — e isso não é "está tudo bem" nem é alarme. */
.vivo{
  display:flex;align-items:center;gap:var(--s-3);flex-shrink:0;
  font-size:var(--t-micro);font-weight:500;
  padding:var(--s-3) var(--s-4);border-radius:var(--r-pill);
  background:var(--soft);color:var(--ts);
}
.vivo b{width:7px;height:7px;border-radius:50%;background:currentColor;display:block;flex-shrink:0}
.vivo.fresco{background:var(--green-light);color:var(--green-dark)}
.vivo.sem{color:var(--empty)}

/* A FAIXA DE ABAS virou chrome (`faixaDeAbas`), então a regra de ALVO DE TOQUE
   mora aqui e não na tela que a inventou. O botão media 30px — abaixo do piso
   legal de 24 e longe dos 44 que funcionam para quem toca de pé, com a mão
   suja. `.tabs .tab` vence `.tab` por especificidade, então corrige a Inbox
   junto: alvo pequeno não é problema de uma tela só. */
.tabs .tab{min-height:44px;display:inline-flex;align-items:center;justify-content:center}

/* =========================================================================
   HOME — protótipo aprovado `prototipo-home-arcade-coral.html`, verbatim onde
   possível. As variantes do pulso de leads são a única adição, e existem
   porque o design system §4.2 define TRÊS humores e o protótipo desenhou um.
   ========================================================================= */
/* ── O PRIMITIVO DE CARD ───────────────────────────────────────────────────
   A superfície de card (fundo, raio, respiro) estava redesenhada em cada
   componente, e saíram CINCO respiros para a mesma ideia (12·13·14·15·16).
   Passa a ter um lugar só. Quem não herda declara o seu, e é a ORDEM que faz
   isso funcionar: este bloco vem antes, e especificidade igual dá a vitória a
   quem vem depois. Preço medido: `.conv` +4px, `.overall` +2, `.ag-linha` +6 —
   é a uniformização, não efeito colateral. */
.card,.conv,.overall,.ag-linha,.phase{background:#fff;border-radius:var(--r-md);padding:var(--s-6)}
.card{margin:0 var(--s-gutter) var(--s-5)}
.card.plano{background:var(--soft)}
.card.contorno{border:1px solid var(--line)}
/* A única peça que sai do plano: o card do lead esperando. Dois degraus — o
   curto encosta na página, o longo levanta (ADR-0132). */
.card.urgente{box-shadow:0 1px 2px var(--sombra-1),0 8px 20px var(--sombra-2)}
/* O pulso pinta a própria superfície e é filho único: herdar o respiro daria
   caixa dentro de caixa. O `overflow` conserta um defeito MEDIDO — `.pulse` não
   tem raio e raio de pai não recorta filho, então o coral vinha de canto reto
   dentro de um card de 20px. */
.card:has(.pulse){padding:0;overflow:hidden}

/* --- pulso de leads: 3 humores ------------------------------------------ */
.pulse{padding:13px 15px;display:flex;align-items:center;gap:11px}
.pulse .ic{
  width:40px;height:40px;border-radius:50%;display:flex;align-items:center;
  justify-content:center;flex-shrink:0;
}
.pulse .ic i{font-size:var(--i-md);color:#fff}
.pulse .txt{flex:1;min-width:0}
.pulse h3{font-size:var(--t-body);font-weight:500;color:var(--navy);font-family:var(--sans)}
.pulse p{font-size:var(--t-micro);font-weight:500}

/* esperando — coral PEDE, e é o único humor com botão */
.pulse.wait{background:var(--accent-light)}
.pulse.wait .ic{background:var(--accent)}
.pulse.wait p{color:var(--accent-dark)}
/* O botão do pulso é uma PÍLULA dentro de uma linha flex — o oposto do `.cta`
   genérico lá embaixo (linha ~236), que é o botão de largura total dos cards da
   Journey.
   ⚠️ `display`, `width` e `margin-top` PRECISAM estar declarados aqui. A regra
   `.cta` vence por não ter concorrente nessas três propriedades: especificidade
   maior só ganha no que ela declara. Sem estas linhas o botão herda
   `display:block;width:100%`, come a linha inteira, empurra o `.txt` para uma
   coluna de uma palavra por linha e ainda transborda o card.
   Foi exatamente o que aconteceu: `.pulse .cta` nasceu no bloco 2, o `.cta`
   genérico entrou no bloco 3 (`134cefc`) e quebrou o de cima sem tocar nele. */
/* AFORDANCIA x DEMANDA (ADR-0034): `.cta` serve dois papeis. Na jornada e
   'abrir tarefa' — ninguem esperando, entao AZUL (regra generica acima). Aqui,
   dentro do pulso, e 'reply'/'call' para um lead parado com relogio correndo:
   demanda, e por isso o unico .cta coral. */
.pulse .cta{
  display:inline-block;width:auto;margin-top:0;white-space:nowrap;
  background:var(--accent-solid);color:#fff;font-size:var(--t-meta);font-weight:500;
  padding:9px 18px;border-radius:var(--r-pill);border:0;text-decoration:none;flex-shrink:0;
}
/* ── PULSO DOMINANTE ───────────────────────────────────────────────────────
   Quando há lead esperando, este bloco vira o dono da tela. Não é "o mesmo
   card maior": ele se reorganiza — o ícone e o texto ficam em cima, o botão
   desce FULL-WIDTH com altura de dedo, e os contadores viram um rodapé.

   Antes, o bloco com relógio correndo e dinheiro em jogo era o MENOR da tela:
   título de 14px, botão de 34px encostado na margem, e o card preto da jornada
   (um to-do de setup) dominando logo abaixo. Saliência visual — tamanho ×
   contraste — é o que governa a primeira fixação; a ordem no DOM não governa
   nada. A ordem já estava certa desde sempre, o peso é que não existia.

   O botão em `--t-body` e 15px de padding dá 45px de altura: passa o mínimo
   obrigatório do WCAG (24px) e alcança a recomendação de 44px, que é a que
   importa para quem toca com a mão suja, de pé, entre um serviço e outro. */
.pulse.big{flex-direction:column;align-items:stretch;gap:13px;padding:16px 15px}
.pulse.big .topo{display:flex;align-items:center;gap:11px}
.pulse.big h3{font-family:var(--display);font-size:var(--t-lead);font-weight:600;line-height:1.25}
.pulse.big p{font-size:var(--t-meta);margin-top:3px}
.pulse.big .cta{
  display:block;width:100%;text-align:center;white-space:normal;
  font-size:var(--t-body);padding:15px 18px;
}
/* Contexto, não ação: desce para o rodapé e fica no tom de apoio do coral. */
.pulse.big .rodape{
  display:block;text-align:center;font-size:var(--t-micro);font-weight:500;
  color:var(--accent-dark);text-decoration:none;opacity:.85;
}
/* em dia — verde CONFIRMA */
.pulse.ok{background:var(--green-light)}
.pulse.ok .ic{background:var(--green)}
.pulse.ok p{color:var(--green-dark)}
/* convite — azul INFORMA */
.pulse.invite{background:var(--soft)}
.pulse.invite .ic{background:#fff}
.pulse.invite .ic i{color:var(--blue)}
.pulse.invite p{color:var(--ts)}

/* --- card da jornada ----------------------------------------------------- */
.journey{background:var(--navy-card);border-radius:var(--r-lg);padding:16px 17px;text-decoration:none;display:block}
/* ── JORNADA COLAPSADA ─────────────────────────────────────────────────────
   A contraparte do pulso dominante: com lead esperando, a trilha inteira vira
   uma linha. Continua sendo o mesmo link, com o próximo passo e o progresso
   escritos — só deixa de ser o objeto mais pesado da tela num momento em que
   a coisa mais importante é outra. */
.journey.slim{display:flex;align-items:center;gap:10px;padding:13px 15px;border-radius:var(--r-md)}
.journey.slim .l{display:flex;align-items:center;gap:9px;flex:1;min-width:0}
.journey.slim .l i{font-size:var(--i-sm);color:var(--blue-pale);flex-shrink:0}
.journey.slim .l span{font-size:var(--t-meta);font-weight:500;color:#fff;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.journey.slim em{font-size:var(--t-micro);font-weight:500;font-style:normal;color:var(--navy-fade);flex-shrink:0}
.journey.slim > i{font-size:var(--i-sm);color:var(--navy-fade);flex-shrink:0}
.jhead{display:flex;justify-content:space-between;align-items:center;margin-bottom:var(--s-5)}
.jhead span{font-family:var(--display);font-weight:600;font-size:var(--t-body);color:#fff}
.jhead em{background:#fff;color:var(--navy);font-size:var(--t-micro);font-weight:500;font-style:normal;padding:var(--s-2) var(--s-5);border-radius:var(--r-pill)}
.trail{display:flex;align-items:center;gap:var(--s-3);margin-bottom:var(--s-5)}
.node{
  width:30px;height:30px;border-radius:50%;display:flex;align-items:center;
  justify-content:center;border:2.5px solid #fff;flex-shrink:0;
}
.node.done{background:var(--green)}
.node.done i{font-size:var(--i-sm);color:#fff}
/* O no da fase ATUAL diz "voce pode fazer isto agora" — afordancia, nao demanda:
   ninguem do outro lado esta esperando. Azul pela ADR-0034. E o coral tambem
   reprovava: branco sobre --accent dava 2,96:1 num numero de 13px. */
.node.now{width:34px;height:34px;background:var(--blue);font-family:var(--display);font-weight:600;font-size:var(--t-meta);color:#fff}
.node.lock{background:var(--navy-tint);border-style:dashed;border-color:var(--navy-line)}
.node.lock i{font-size:var(--i-sm);color:var(--navy-fade)}
.seg{flex:1;height:5px;border-radius:var(--r-pill);background:var(--navy-tint)}
.seg.done{background:var(--green)}
.next{background:var(--navy-deep);border-radius:var(--r-sm);padding:var(--s-4) var(--s-6);display:flex;align-items:center;justify-content:space-between;gap:var(--s-4)}
.next .l{display:flex;align-items:center;gap:var(--s-4);min-width:0}
.next .l i{font-size:var(--i-sm);color:var(--blue-pale);flex-shrink:0}
.next span{font-size:var(--t-meta);font-weight:500;color:#fff;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.next em{background:var(--blue);color:#fff;font-size:var(--t-micro);font-weight:500;font-style:normal;padding:var(--s-2) var(--s-5);border-radius:var(--r-pill);flex-shrink:0}

/* --- métricas do mês ----------------------------------------------------- */
/* O grid dos 3 números virou uma linha DENTRO do link, para o rodapé "see this
   month's report ›" caber embaixo sem entrar na grade e virar um quarto card. */
.metrics{display:block;padding:0 var(--s-gutter) var(--s-6)}
.mrow{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s-4)}
/* A única pista de que a faixa é tocável — antes ela era um `<a>` com
   `text-decoration:none` e `color:inherit`, ou seja, um link sem nenhum sinal
   de link. Em `--blue` porque é AÇÃO (ADR-0034), e com chevron porque a seta é
   o que o polegar procura. */
.mver{display:flex;align-items:center;justify-content:flex-end;gap:var(--s-1);
  margin-top:var(--s-4);font-size:var(--t-meta);font-weight:500;color:var(--blue)}
.mver i{font-size:var(--i-sm)}
.m{background:var(--soft);border-radius:var(--r-md);padding:var(--s-5);text-align:center}
.m b{display:block;font-family:var(--display);font-weight:600;font-size:var(--t-hero);color:var(--navy);letter-spacing:-.5px}
.m span{font-size:var(--t-micro);font-weight:500;color:var(--ts)}
.m.ok{background:var(--green-light)}
.m.ok b{color:var(--green-dark)}
/* A ausência tem cor própria (D62): o traço não é um número apagado. */
.m b.empty{color:var(--empty)}

/* =========================================================================
   JOURNEY — `docs/design/tela-journey.html`, verbatim onde possível.
   Os nós (.node) são os MESMOS da home: um vocabulário só para a trilha.
   ========================================================================= */
.overall{margin:0 var(--s-gutter) var(--s-6);background:var(--soft)}
.orow{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:var(--s-4)}
.orow b{font-family:var(--display);font-weight:600;font-size:var(--t-body);color:var(--navy)}
.orow span{font-size:var(--t-micro);font-weight:500;color:var(--ts)}
.obar{height:7px;border-radius:var(--r-pill);background:var(--track);overflow:hidden}
.obar i{display:block;height:100%;border-radius:var(--r-pill);background:var(--green)}

.phase{margin:0 var(--s-gutter) var(--s-5);border-radius:var(--r-lg);overflow:hidden}
.phase.done{background:var(--green-light);padding:var(--s-5) var(--s-6);display:flex;align-items:center;gap:var(--s-5)}
.phase.done .ic{width:38px;height:38px;border-radius:50%;background:var(--green);display:flex;align-items:center;justify-content:center;flex-shrink:0}
.phase.done .ic i{font-size:var(--i-md);color:#fff}
.phase.done h3{font-size:var(--t-body);font-weight:500;color:var(--navy)}
.phase.done p{font-size:var(--t-micro);font-weight:500;color:var(--green-dark)}

/* Os `17px` ficam crus de propósito: não há degrau em 17 (a escala vai de 15 a
   20) e este padding é o MESMO do `.journey` — o mesmo card navy visto na Home,
   congelado nesta rodada. Mover só um desfaz o par. Mudam juntos. */
.phase.now{background:var(--navy-card);padding:16px 17px}
.phhead{display:flex;justify-content:space-between;align-items:center;margin-bottom:var(--s-6)}
.phhead span{font-family:var(--display);font-weight:600;font-size:var(--t-body);color:#fff}
.phhead em{background:#fff;color:var(--navy);font-size:var(--t-micro);font-weight:500;font-style:normal;padding:var(--s-2) var(--s-5);border-radius:var(--r-pill)}

.task{display:flex;gap:var(--s-5);position:relative}
.task .rail{display:flex;flex-direction:column;align-items:center;flex-shrink:0}
.vseg{width:5px;flex:1;min-height:14px;border-radius:var(--r-pill);background:var(--navy-tint);margin:var(--s-1) 0}
.vseg.done{background:var(--green)}
.tbody{flex:1;padding-bottom:var(--s-5);min-width:0}
.tbody.last{padding-bottom:0}
.trow{display:flex;align-items:center;justify-content:space-between;gap:var(--s-4)}
.tbody h4{font-size:var(--t-body);font-weight:500;color:#fff;padding-top:var(--s-3)}
.tbody h4.muted{color:var(--navy-fade)}
/* ⚠️ O 2º seletor NAO e' redundante, e a medicao provou: o card do quiz nao tem
   `.tbody`, entao a descricao caia FORA desta regra e herdava a cor do
   documento — medido em Chrome, 1,37:1 sobre o `--navy-card`, ou seja a frase
   que explica POR QUE pedimos cada resposta, invisivel. O lint de contraste nao
   pega esta classe (so mede pares da MESMA regra); quem pega e' o
   `trava-fluxo.proof.mjs`, no DOM renderizado. */
.tbody .desc,.phase.now>.desc{font-size:var(--t-micro);color:var(--navy-fade);margin-top:var(--s-2);line-height:1.45}
.chip{font-size:var(--t-micro);font-weight:500;font-style:normal;padding:var(--s-2) var(--s-5);border-radius:var(--r-pill);flex-shrink:0;margin-top:var(--s-2)}
.chip.won{background:var(--branco-fraco);color:var(--navy-fade)}
.chip.go{background:var(--blue);color:#fff}
.cta{display:block;width:100%;margin-top:var(--s-5);background:var(--blue);color:#fff;font-family:var(--sans);font-size:var(--t-body);font-weight:500;padding:var(--s-6);border-radius:var(--r-pill);border:0;text-align:center}
/* "em breve" — capacidade que ainda não existe. Nunca botão morto (D62). */
.embreve{margin-top:var(--s-5);display:flex;align-items:center;gap:var(--s-3);font-size:var(--t-micro);color:var(--navy-fade)}
.embreve i{font-size:var(--i-sm)}
/* pular: existe no motor (skippable), mas nunca compete com o coral */
.pular{margin-top:var(--s-4);background:none;border:0;color:var(--navy-fade);font-size:var(--t-meta);text-decoration:underline;padding:var(--s-1)}

.phase.lock{background:var(--soft);padding:var(--s-6)}
.lkhead{display:flex;align-items:center;gap:var(--s-5)}
.lkhead .ic{width:38px;height:38px;border-radius:50%;background:var(--track);display:flex;align-items:center;justify-content:center;flex-shrink:0}
.lkhead .ic i{font-size:var(--i-md);color:var(--ts)}
.lkhead h3{font-size:var(--t-body);font-weight:500;color:var(--navy)}
.lkhead p{font-size:var(--t-micro);font-weight:500;color:var(--ts)}

/* --- formulário da tarefa (dentro do card navy da fase atual) ------------- */
.tform{margin-top:var(--s-5);display:flex;flex-direction:column;gap:var(--s-4)}
/* `.rot` e' o rotulo do grupo sim/nao: dois botoes nao dividem um <label>, entao
   ali vai um <span> apontado por aria-labelledby. Mesma pinta do <label>. */
.tform label,.tform .rot{font-size:var(--t-meta);font-weight:500;color:var(--navy-fade);display:block;margin-bottom:var(--s-2)}
/* A lista É explícita, e a tentação de trocá-la por `input:not([type=file])
   :not([type=checkbox])` foi MEDIDA e recusada: cada `:not()` carrega a
   especificidade do argumento, então a versão com exclusões sobe de (0,2,1)
   para (0,3,1) e passa a VENCER `.tform .busca input{padding-left:36px}`
   (l. 762). O `padding` shorthand daqui apaga o `padding-left` de lá, e o texto
   da busca das 5.102 categorias entra DEBAIXO da lupa — medido em jsdom com o
   `app.css` real: 36px → 15px, com o campo comum imóvel nos dois casos como
   controle. Nenhum lint deste repo vê isso.
   ⚠️ Tipo novo de `<input>` no formulário da jornada TEM de ser somado aqui:
   fora da lista ele sai cru, caixa branca do navegador dentro do card navy —
   e no desktop nada denuncia, porque lá o teclado não muda. */
.tform input[type=text],.tform input[type=number],.tform input[type=tel],
.tform input[type=email],.tform input[type=url],.tform textarea,.tform select{
  font-family:var(--sans);font-size:var(--t-body);color:var(--navy);background:#fff;
  border:0;border-radius:var(--r-sm);padding:var(--s-5) var(--s-6);width:100%;
}
.tform textarea{min-height:78px;resize:vertical}
.tform input[type=file]{
  font-family:var(--sans);font-size:var(--t-meta);color:#fff;width:100%;
  background:var(--navy-deep);border:1px dashed var(--navy-line);
  border-radius:var(--r-sm);padding:var(--s-5) var(--s-6);
}
.tform input[type=file]::file-selector-button{
  font-family:var(--sans);font-size:var(--t-meta);font-weight:500;
  background:#fff;color:var(--navy);border:0;border-radius:var(--r-pill);
  padding:var(--s-3) var(--s-6);margin-right:var(--s-5);
}
.tform .sim-nao{display:flex;gap:var(--s-4)}
.tform .sim-nao button{
  flex:1;border:1.5px solid var(--navy-tint);background:none;color:#fff;
  font-family:var(--sans);font-size:var(--t-body);padding:var(--s-5);border-radius:var(--r-pill);
}
.tform .sim-nao button[aria-pressed=true]{background:#fff;color:var(--navy);border-color:#fff}
.tform .dica{font-size:var(--t-micro);color:var(--navy-fade);line-height:1.4}
/* "falta preencher" e' instrucao para o dono, nao um lead esperando: azul claro
   sobre o card escuro (ADR-0034). 9,20:1 contra o --navy-card. */
.tform .falta{color:var(--navy-fade);font-size:var(--t-micro);font-weight:500}

/* --- a recusa de UM campo, ao lado da caixa que a causou ------------------
   Mora dentro do `[data-campo]`, e não junto do `.falta` do formulário: com uma
   pergunta por vez a falta do quiz é sempre "responda esta", e a recusa de
   FORMA precisa apontar a caixa — "o telefone tem 10 dígitos" 200px abaixo do
   telefone é a mesma frase valendo menos. Mesmos tokens do `.falta`: é
   instrução para o dono, não alarme. */
.tform .recusa-campo{
  margin-top:var(--s-2);
  font-size:var(--t-micro);
  font-weight:500;
  color:var(--navy-fade);
  line-height:1.4;
}
/* O palpite seguro vira BOTÃO, nunca troca automática: adivinhar domínio de
   e-mail manda o acesso do cliente para a caixa de outra pessoa. 44px de alvo
   pelo mesmo piso de toque do resto (WCAG 2.2 AA §2.5.8) — aqui pelo padding,
   porque `min-height` numa caixa `inline` não vale. */
.tform .usar-sugestao{
  border:0;
  background:none;
  padding:var(--s-3) 0;
  font-family:var(--sans);
  font-size:var(--t-micro);
  font-weight:600;
  color:#fff;
  text-decoration:underline;
}
/* A caixa recusada se diz recusada por mais de UMA via: o texto ao lado e o anel
   na borda. Cor sozinha não serve a quem não a distingue (WCAG 1.4.1).
   🚫 O anel NÃO é coral, e o `contrast-lint` me reprovou por tentar: coral nesta
   casa significa ALGUÉM ESTÁ ESPERANDO (um lead, ADR-0034). Telefone com 4
   dígitos não é ninguém esperando — é instrução para o dono, exatamente como o
   `.falta` logo acima. Mesmo token dos dois, de propósito: a caixa e a frase que
   a explica falam com a mesma voz.
   🚫 E é `outline`, NÃO `box-shadow`: a catraca anti-slop limita o vocabulário
   de sombra a 5 formas distintas, e uma sexta entrou aqui na primeira tentativa.
   Não subi o teto — anel de ESTADO não é sombra: sombra diz elevação, e este
   traço diz "esta caixa foi recusada". `outline` é o que a casa já usa para
   marcar estado (`:focus-visible`), não desloca layout com `border:0` no campo,
   e some sozinho quando o foco entra — enquanto o cliente digita, quem manda é
   o anel de foco; a frase da recusa continua na tela do lado.
   ⚠️ Duas correções que vieram de um verificador em contexto limpo, e as duas
   eram o comentário mentindo:
   · `:not(:focus-visible)` é o que TORNA VERDADE a frase acima. Não existe
     regra de foco para `.tform input` (o `.campo input:focus` da l. 379 é do
     LOGIN), e declaração de autor vence a do navegador independentemente de
     especificidade — sem esta exclusão o anel de recusa ficava por cima do anel
     de foco e APAGAVA o foco enquanto o cliente digitava.
   · O token é `--field-line` e não `--navy-fade`: o anel encosta no INTERIOR
     BRANCO do campo, e ali `--navy-fade` mede 2,00:1 — abaixo dos 3:1 de
     1.4.11. `--field-line` dá 5,12:1 sobre branco, e é o token nomeado para
     borda de campo. O `contrast-lint` não pega este par por construção: ele só
     mede pares declarados na MESMA regra, e o fundo aqui vem do campo. */
.tform input[aria-invalid=true]:not(:focus-visible){outline:2px solid var(--field-line);outline-offset:0}

/* --- busca no catalogo do Google (trade principal e secundarios) ----------
   5.102 categorias: `select` nao serve no celular, entao e' busca com lista.
   Tudo dentro do card navy da fase atual, por isso os tokens sao os do card. */
.tform .busca{position:relative;display:flex;align-items:center}
.tform .busca i{position:absolute;left:13px;font-size:var(--i-sm);color:var(--navy-fade)}
.tform .busca input{padding-left:36px}
.tform .chips{display:flex;flex-wrap:wrap;gap:var(--s-3)}
.tform .chips:empty{display:none}
.tform .chip{
  display:inline-flex;align-items:center;gap:var(--s-2);
  background:var(--blue-light);color:var(--blue-deep);
  /* Sem respiro VERTICAL: o "x" dentro mede 44px (alvo de toque), e somar o
     padding daria uma pílula de 56. A altura do chip É o alvo. */
  font-size:var(--t-meta);font-weight:500;padding:0 var(--s-4) 0 var(--s-5);border-radius:var(--r-pill);
}
.tform .chip button{background:none;border:0;color:var(--blue-deep);display:flex;padding:var(--s-1);cursor:pointer}
.tform .chip button i{font-size:var(--i-sm)}
.tform .sugestoes{list-style:none;padding:0;margin:var(--s-3) 0 0;display:flex;flex-direction:column;gap:var(--s-1)}
.tform .sugestoes button{
  width:100%;text-align:left;background:#fff;border:0;border-radius:var(--r-sm);
  padding:var(--s-5);display:flex;flex-direction:column;gap:var(--s-1);cursor:pointer;
}
.tform .sugestoes .n{font-size:var(--t-body);color:var(--navy);font-weight:500}
.tform .sugestoes .via{font-size:var(--t-micro);color:var(--ts)}
.tform .sugestoes .vazio{font-size:var(--t-meta);color:var(--navy-fade);padding:var(--s-4) var(--s-1)}
.tform .servicos{display:flex;flex-direction:column;gap:var(--s-5)}
.tform .servicos .grupo{display:flex;flex-direction:column;gap:var(--s-2)}
.tform .serv{display:flex;align-items:center;gap:var(--s-4);font-size:var(--t-body);color:#fff;font-weight:400}
.tform .serv input{width:17px;height:17px;flex-shrink:0;accent-color:var(--blue)}

/* A opcao sob as SETAS, no combobox do catalogo. E' CONTORNO e nao fundo de
   proposito: trocar o fundo mexeria no par cor-de-texto x fundo ja medido
   (`--navy` sobre `#fff`), e o `contrast-lint` so mede pares da MESMA regra — o
   defeito passaria calado. `-2px` para ficar DENTRO do raio da linha. */
.tform .sugestoes button.ativo{outline:2px solid var(--blue);outline-offset:-2px}

/* =========================================================================
   QUIZ — uma pergunta por vez (ADR-0152).

   Tres regras, e nenhuma tem cor: o card REUSA `.phase.now` (o `--navy-card`
   para o qual todo o markup de `.tform` foi escrito) e a barra REUSA `.obar`.
   Reusar nao e' economia: card novo com fundo proprio exigiria remedir todos os
   pares de `.tform` contra ele, e o lint so mede pares da MESMA regra.

   🚫 SEM `transition`: o card NAO PERSISTE entre perguntas, e transicao em no
   que nasce nao dispara. Quem move e' `.entrando`.
   ========================================================================= */
.quiz .obar{margin:0 var(--s-gutter) var(--s-6)}
.quiz .phase.now{margin-bottom:0}
/* "voltar" e "pular" na mesma linha: os dois sao saidas laterais e tem o mesmo
   peso de link. Empilhados, ocupariam mais altura que a propria pergunta. */
.qacoes{display:flex;align-items:center;gap:var(--s-6);flex-wrap:wrap}

/* Volta para o Google, na tarefa do desvio. E' a saida de quem disse "nao
   tenho perfil" por engano — sem ela, aquela resposta e' irreversivel pela
   interface. Peso de LINK, nao de CTA: nao disputa com a acao principal da
   tarefa, so precisa existir e ser achavel. */
.reconectar{margin-top:var(--s-4);display:flex;flex-direction:column;gap:var(--s-3)}
.reconectar .link-btn{
  background:none;border:0;color:var(--blue-pale);font-size:var(--t-meta);font-weight:500;
  padding:var(--s-3) 0;text-align:left;cursor:pointer;
}
.reconectar .falta{color:var(--navy-fade);font-size:var(--t-micro);font-weight:500}

/* Barra inferior encostada, como na malha aprovada — a pílula flutuante saiu
   junto do rótulo: pílula + texto ficava alta demais e comia a tela. */
.nav{
/* BARRA, não pílula — corrigido em 2026-08-19 contra a REFERÊNCIA da chefia.
   O merge de 18/08 (PR 2403 × main) tinha escolhido a pílula flutuante de
   17/08 alegando a conta de altura. Os 5 prints da referência mostram barra
   branca full-width em TODAS as telas, e a ADR-0124 dá a nav como decisão
   dela — a escolha do merge contrariou as duas. Volta a barra.

   A conta de altura continua fechando, e com MAIS folga que a pílula: 52 de
   alvo + 6+6 de padding = 64, contra os 84px que o `#app` reserva. A pílula
   gastava 70 dos mesmos 84 (46+8+16 de margem); sem margem lateral e sem
   margem de baixo, a barra cabe melhor.

   `z-index` fica: entrou em 17/08 e a razão dele não tinha nada a ver com o
   formato — escreve a intenção de ficar por cima antes que alguém renderize
   um elemento posicionado depois do `navPill(...)` e a perca em silêncio. */
  position:fixed;bottom:0;left:0;right:0;margin:0 auto;z-index:var(--z-nav);
  width:min(100%,430px);
  display:flex;justify-content:space-around;background:#fff;
  border-top:1px solid var(--p-hair);
  padding:6px 4px calc(6px + env(safe-area-inset-bottom));
}
/* Ícone sobre rótulo, como a referência. O alvo é 52px — acima do mínimo de
   44 da WCAG 2.2 AA, e o ICP justifica a folga: dono de empresa de serviço,
   no celular, de pé, entre um serviço e outro. */
.nav a{
  flex:1;min-width:0;min-height:52px;border-radius:var(--r-sm);
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:3px;text-decoration:none;
}
.nav i{font-size:var(--i-md);color:var(--ts)}
.nav a span{font-size:var(--p-nano);font-weight:600;color:var(--ts);line-height:1}
/* Ativo é COR, não fundo: na referência o item aceso muda ícone e rótulo para
   a cor da marca e o fundo continua branco. Pastilha preenchida chamaria mais
   atenção que o conteúdo da tela. */
.nav a.on i,.nav a.on span{color:var(--blue)}

/* --- INBOX (bloco 4) ------------------------------------------------------ */
/* Cabeçalho próprio: a Inbox não usa `cabecalhoTela` porque troca os pontos
   pelo selo de espera — o que importa aqui é quantos aguardam resposta. */
.shead{display:flex;align-items:center;justify-content:space-between;padding:var(--s-7) var(--s-7) var(--s-6)}
.shead h1{font-family:var(--display);font-weight:600;font-size:var(--t-hero);color:var(--navy);letter-spacing:-.3px}
.waiting{display:flex;align-items:center;gap:var(--s-2);font-size:var(--t-meta);font-weight:500;color:var(--accent-dark);background:var(--accent-light);padding:var(--s-3) var(--s-5);border-radius:var(--r-pill)}
.waiting b{width:7px;height:7px;border-radius:50%;background:var(--accent);display:block}
.voltar{background:none;border:0;padding:0;color:var(--navy);display:flex;align-items:center}
.voltar i{font-size:var(--i-md)}

.tabs{display:flex;gap:var(--s-3);padding:0 var(--s-gutter) var(--s-6)}
/* `.idiomas` (profile.js:334) era a única classe que o app emitia sem NENHUMA
   regra: botões no cinza cru do navegador. Reusa a aba da Inbox — o que o
   comentário do profile.js já mandava — lendo o `aria-pressed` que já está no
   DOM. Sem classe nova, sem JS. */
.tab,.idiomas button{font-size:var(--t-meta);font-weight:500;color:var(--ts);background:var(--soft);padding:var(--s-3) var(--s-6);border-radius:var(--r-pill);border:0;font-family:var(--sans)}
.tab.on,.idiomas button[aria-pressed=true]{background:var(--navy-card);color:#fff}

.conv{margin:0 var(--s-gutter) var(--s-4);display:flex;align-items:center;gap:var(--s-5);border:1px solid var(--line)}
/* O coral é da não respondida, e só dela: é a única linha que pede ação. */
.conv.hot{background:var(--accent-light);border-color:var(--accent-light)}
.av{width:42px;height:42px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-family:var(--display);font-weight:600;font-size:var(--t-body);flex-shrink:0}
/* Iniciais no avatar sao TEXTO. O b500 sobre o b100 dava 4,01:1 — reprovava por
   pouco, e passou batido na medicao a mao. O b700 resolve com 8,08:1. */
.av.b{background:var(--blue-light);color:var(--blue-deep)}
/* Avatar da conversa quente: coral CERTO (o lead esta esperando), tom errado —
   branco sobre --accent dava 2,96:1. O --accent-solid e' o coral que carrega
   texto, 4,57:1, e ja e' o mesmo do botao de reply logo ao lado. */
.av.c{background:var(--accent-solid);color:#fff}
.av.g{background:var(--green-light);color:var(--green-dark)}
.ct{flex:1;min-width:0}
.cn{display:flex;align-items:center;gap:var(--s-3)}
.cn h3{font-size:var(--t-body);font-weight:500;color:var(--navy);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cn i{font-size:var(--i-sm);color:var(--ts);flex-shrink:0}
.cn i.done{color:var(--green-dark)}
.cp{font-size:var(--t-micro);color:var(--ts);margin-top:var(--s-1);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cp.hot{color:var(--accent-dark);font-weight:500}
/* Ligação e "sem prévia" em itálico: sinalizam que ali não houve texto. */
.cp.call{color:var(--navy-tint);font-style:italic}
.rt{display:flex;flex-direction:column;align-items:flex-end;gap:var(--s-3);flex-shrink:0}
.tm{font-size:var(--t-micro);color:var(--ts);font-weight:500}
.reply{background:var(--accent-solid);color:#fff;font-size:var(--t-meta);font-weight:500;padding:var(--s-4) var(--s-6);border-radius:var(--r-pill);border:0;font-family:var(--sans)}

/* Estado vazio de tela inteira. NOME PRÓPRIO de propósito: `.empty` já é a
   classe de COR da métrica ausente na Home (D62) — dar layout a ela quebraria
   os números da Home. */
.semnada{margin:var(--s-6) var(--s-gutter) 0;text-align:center;padding:var(--s-7)}
.semnada i{font-size:var(--i-lg);color:var(--empty)}
.semnada p{font-size:var(--t-micro);color:var(--ts);margin-top:var(--s-3)}
/* O "Try again" do estado SEM SINAL. Declara a CAIXA inteira, nao so a pintura:
   `.cta` generico e' `display:block;width:100%` (bloco 3), e a especificidade
   maior daqui so ganha no que ESTA regra declara — foi assim que o botao do
   pulso transbordou o card na D81. Virou regra da casa. */
.semnada .cta{display:inline-block;width:auto;margin-top:var(--s-5);padding:var(--s-4) var(--s-7);font-size:var(--t-meta)}

/* --- thread --------------------------------------------------------------- */
.thread{padding:0 var(--s-gutter) var(--s-4);display:flex;flex-direction:column;gap:var(--s-4)}
.msg{position:relative;display:flex;flex-direction:column;align-items:flex-start;gap:var(--s-1)}
.msg.saiu{align-items:flex-end}
.bolha{max-width:78%;padding:var(--s-4) var(--s-5);border-radius:var(--r-md);font-size:var(--t-meta);line-height:1.45;background:var(--soft);color:var(--navy);word-break:break-word}
.msg.saiu .bolha{background:var(--blue);color:#fff}
/* Mensagem sem conteúdo é nomeada, não sumida — e a cor diz que é ausência. */
.bolha.vazia{color:var(--ts);font-style:italic}
.msg.saiu .bolha.vazia{color:var(--blue-light)}
/* --- gramatica de conversa: bloco, cauda, tique, avatar ------------------- */
/* A CAUDA. So o ultimo balao do bloco desce um canto de --r-md (20) para
   --r-sm (14), e do lado de quem fala — e' o rabinho do WhatsApp sem desenhar
   rabinho, e e' o que faz cinco respostas seguidas lerem como UM bloco. Os dois
   raios ja existem na rampa (ADR-0033), nenhum valor novo. */
.msg.fim .bolha{border-bottom-left-radius:var(--r-sm)}
.msg.saiu.fim .bolha{border-bottom-left-radius:var(--r-md);border-bottom-right-radius:var(--r-sm)}
/* Continuacao do mesmo lado: o respiro cai de 9px (o gap da `.thread`) para
   4px. Margem NEGATIVA porque `gap` e' do container e nao se anula por filho;
   os dois numeros sao degraus da escala, nao px avulso. */
.msg.seq{margin-top:calc(var(--s-2) - var(--s-4))}
/* O AVATAR do contato. Absoluto de proposito: um wrapper por balao custaria um
   no de DOM em cada mensagem (500 no teto) so para posicionar um circulo que
   aparece uma vez por bloco. A calha e' o `padding-left` do lado de la, e ela
   fica reservada MESMO sem avatar (nome desconhecido): sem isso a thread
   saltaria de indentacao no instante em que o nome chegasse. Reusa
   `.av.b` — mesmo par ja medido da lista (8,08), zero cor nova. */
.msg:not(.saiu){padding-left:calc(28px + var(--s-3))}
.av.at{position:absolute;left:0;bottom:0;width:28px;height:28px;font-size:var(--t-micro)}
/* O TIQUE fica dentro do carimbo, na mesma linha. */
.msg .tm{display:inline-flex;align-items:center;gap:var(--s-2)}
/* Cor e fundo na MESMA regra, e o fundo declarado e' o do `body` (--soft) de
   verdade: e' o que deixa o par mensuravel pelo contrast-lint, mesma tecnica do
   `.diasep`. Zero coral — entrega e' descricao, nao demanda (ADR-0034).
   A ORDEM importa: o otimista carrega `saiu`+`enviando` e o incerto
   `saiu`+`incerto`, todos (0,3,0) — quem vem depois no arquivo ganha, por isso
   `saiu` primeiro e `incerto` por ultimo (bloco do compositor, abaixo). */
.msg.saiu .tm{color:var(--blue-deep);background:var(--soft)}
.msg.enviando .tm{color:var(--ts);background:var(--soft)}
/* Separador de dia. A PILL e' o que separa: `.thread` tem gap uniforme, entao
   texto solto no meio leria como mais uma linha de evento. `--ts` sobre
   `--soft` = 4,80 (piso 4,5). Cor e fundo na MESMA regra de proposito: e' o que
   deixa o par mensuravel pelo contrast-lint. Zero coral — separador e'
   descricao, nao demanda (ADR-0034). */
.diasep{align-self:center;font-size:var(--t-micro);font-weight:500;color:var(--ts);
  background:var(--soft);border-radius:var(--r-pill);padding:var(--s-2) var(--s-5)}
/* Ligação é evento no meio da conversa, não balão. */
.evento{display:flex;align-items:center;justify-content:center;gap:var(--s-3);font-size:var(--t-micro);color:var(--navy-tint);font-style:italic;padding:var(--s-2) 0}
.evento i{font-size:var(--i-sm)}
/* O play da gravacao. Azul e' AFORDANCIA (ADR-0034): "voce pode ouvir", nao
   "alguem esta esperando". Alvo de 28px porque ele mora dentro de uma linha de
   12px — sem tamanho proprio, o dedo erraria. */
.tocar{flex:none;width:28px;height:28px;display:flex;align-items:center;justify-content:center;
  border:0;border-radius:var(--r-pill);background:var(--blue-light);color:var(--blue-deep);cursor:pointer}
.tocar i{font-size:var(--i-sm)}
/* Baixando: o WAV inteiro vem antes do primeiro som, e numa ligacao longa isso
   demora. O botao precisa PARECER ocupado — sem isto o toque nao devolve nada
   por segundos e a pessoa toca de novo. */
.tocar.baixando{opacity:.55;cursor:progress}
.tocar.tocando{background:var(--blue);color:#fff}
/* Falhou (nao ha gravacao, ou nao consegui buscar): o botao SAI e vira frase.
   Cor de ausencia, e sem italico — a linha ja e' italica, e frase que some no
   fundo e' frase que nao foi lida. */
.evento .sem-gravacao{color:var(--empty);font-style:normal}

/* --- COMPOSITOR (a resposta pelo app) ------------------------------------- */
/* Substituiu o aviso de somente-leitura (`.somenteleitura`), removido junto com
   a linha que ele pintava — CSS de tela que nao existe mais so serve pra fazer
   a proxima pessoa procurar o markup. */
/* Substitui o aviso de so-leitura. Tudo que sai daqui vira SMS real no
   telefone do cliente do dono, entao o estado de envio precisa ser visivel:
   o balao otimista nasce esmaecido e so firma quando o servidor confirma. */
.compositor{display:flex;align-items:flex-end;gap:var(--s-4);margin:var(--s-5) var(--s-gutter) var(--s-6)}
.compositor textarea{flex:1;resize:none;min-height:42px;max-height:120px;padding:var(--s-5);
  border:1px solid var(--field-line);border-radius:var(--r-sm);background:#fff;color:var(--navy);
  font-family:var(--sans);font-size:var(--t-meta);line-height:1.45}
/* Azul, nao coral: ADR-0034 — coral e "alguem esta esperando", azul e "voce
   pode fazer". Escrever e responder sao afordancia, ninguem espera por elas. */
.compositor textarea:focus{outline:2px solid var(--blue);outline-offset:-1px}
.compositor textarea:disabled{opacity:.6}
.compositor button{flex:none;width:42px;height:42px;display:flex;align-items:center;justify-content:center;
  border:0;border-radius:var(--r-sm);background:var(--blue);color:#fff;cursor:pointer}
.compositor button:disabled{opacity:.5;cursor:default}
.compositor button i{font-size:var(--i-sm)}
/* O erro fala do que NAO aconteceu — por isso ocupa a linha inteira, abaixo
   da caixa, e nao um toast que some antes de ser lido. */
.compositor-erro{margin:-6px var(--s-gutter) var(--s-5);padding:var(--s-4) var(--s-5);border-radius:var(--r-sm);
  background:var(--soft);color:var(--navy);font-size:var(--t-micro)}
/* Balao ainda nao confirmado pelo servidor. */
.msg.enviando .bolha{opacity:.55}
/* O TERCEIRO estado: o envio falhou de um jeito que NAO prova que nada saiu
   (timeout, 5xx, conexao que caiu depois do POST). Nao pode parecer enviado
   nem sumir — as duas leituras erradas custam caro em direcoes opostas:
   sumir faz o dono reenviar (SMS duplicado), firmar deixa um cliente sem
   resposta. O tracejado e' "isto esta' em aberto", nao "isto falhou". */
.msg.incerto .bolha{opacity:.55;box-shadow:inset 0 0 0 1px var(--field-line)}
.msg.incerto .tm{color:var(--empty);background:var(--soft)}


/* --- RESULTS (bloco 5) ---------------------------------------------------- */
/* `.metrics` e `.m` são REUSADOS da Home: mesma forma de card, mesma classe
   `.empty` para a ausência (D62). Não se duplica aqui o que já existe lá.

   🐛 E era reuso PELA METADE: `.metrics{display:block}` e a grade de 3 colunas
   vive em `.mrow`, que a Home emite e a Results NÃO emitia — esta tela
   empilhava tiles de largura cheia enquanto o comentário dizia que as duas
   compartilhavam o primitivo. Pararam de compartilhar quando o `.mrow` foi
   extraído para caber o rodapé da Home. O `row-gap` é a única diferença: aqui
   são duas fileiras, lá é uma. */
.metrics .mrow{row-gap:var(--s-5)}

/* ── O COMPARATIVO ──────────────────────────────────────────────────────────
   A cor vem de `bom`, NUNCA de `direcao` (regra 4): o mockup que originou esta
   tela pintava "COST PER LEAD ↗ +80.7%" de VERDE. E a direção lê SEM COR, pelo
   triângulo do `::before` — ~8% dos homens têm daltonismo vermelho-verde.

   🚫 SEM CORAL, nem para o delta ruim: coral é "um humano está esperando"
   (ADR-0034), e gastá-lo num número faria o card do lead parado deixar de
   significar. Esta é tela de LEITURA, que confirma e nunca cobra (chrome 3);
   por isso "ruim" fica na cor normal do texto e quem diz a direção é a seta. */
.delta{
  display:block;margin-top:var(--s-1);font-style:normal;
  font-size:var(--t-micro);font-weight:500;color:var(--navy);
}
.delta.bom{color:var(--green-dark)}
.delta.sobe::before{content:"\25B2";margin-right:var(--s-1)}
.delta.desce::before{content:"\25BC";margin-right:var(--s-1)}

/* ── O GRÁFICO ──────────────────────────────────────────────────────────────
   As barras são conteúdo NÃO-TEXTUAL (WCAG 1.4.11, piso 3:1) e o `--blue` dá
   4,62:1 contra o branco. 🚫 NUNCA `--track` para dado real: 1,40:1, ilegível
   DE PROPÓSITO, porque ali ele significa "ainda não aconteceu".

   `width:100%` e altura fixa, nunca largura intrínseca — o `home-ui.proof`
   afirma `docScrollW <= docClientW`, e um SVG que traz a própria largura é a
   forma mais fácil de furar isso. */
.graf{margin:0 16px 14px}
.graf .barras{display:block;width:100%;height:48px}
.graf rect{fill:var(--blue)}
/* A tabela é o fallback acessível — `<details>` nativo dá teclado de graça. */
.graf summary{
  min-height:44px;display:flex;align-items:center;
  font-size:var(--t-meta);font-weight:500;color:var(--blue-deep);cursor:pointer;
}
.graf table{width:100%;border-collapse:collapse;font-size:var(--t-micro)}
.graf th,.graf td{text-align:left;padding:var(--s-3) 0;border-bottom:1px solid var(--line)}
.graf thead th{color:var(--ts);font-weight:500}
.graf tbody th{font-weight:500;color:var(--navy)}
.graf td{text-align:right;font-weight:500;color:var(--navy)}

.period{display:flex;align-items:center;gap:5px;font-size:var(--t-meta);font-weight:500;color:var(--navy);background:var(--soft);padding:7px 13px;border-radius:var(--r-pill)}
.sect{padding:0 16px;margin-bottom:8px;display:flex;align-items:center;justify-content:space-between}
.sect h2{font-family:var(--display);font-weight:600;font-size:var(--t-body);color:var(--navy)}
.src{font-size:var(--t-micro);font-weight:500;color:var(--ts);background:var(--soft);padding:4px 9px;border-radius:var(--r-pill)}

/* A linha de resposta. O verde é do estado `todos` — zero MEDIDO é conquista.
   Os estados `sem_leads`/`sem_dado` usam o cinza neutro: não houve o que
   responder, e pintar isso de verde seria parabenizar o cliente por nada. */
.row{margin:0 16px 14px;background:var(--green-light);border-radius:var(--r-md);padding:12px 15px;display:flex;align-items:center;gap:11px}
.row .ic{width:36px;height:36px;border-radius:50%;background:var(--green);display:flex;align-items:center;justify-content:center;flex-shrink:0}
.row .ic i{font-size:var(--i-md);color:#fff}
.row h3{font-size:var(--t-body);font-weight:500;color:var(--navy)}
.row.neutro{background:var(--soft)}
.row.neutro .ic{background:var(--empty)}
/* Sem resposta pendente NÃO é alarme: tela de leitura não pede ação (chrome 3).
   Azul informa; coral cobraria — e cobrança é papel da Home. */
.row:not(.ok):not(.neutro){background:var(--blue-light)}
.row:not(.ok):not(.neutro) .ic{background:var(--blue)}

/* O painel do Google. Borda tracejada porque a moldura também comunica
   ausência — é um lugar reservado, não um resultado. */
.nodata{margin:0 16px 9px;border:1px dashed var(--empty);border-radius:var(--r-md);padding:14px 15px}
.ngrid{display:grid;grid-template-columns:repeat(2,1fr);gap:11px}
.n{display:flex;flex-direction:column;gap:2px}
/* Cor por ESTADO, não fixa: o design assume tudo vazio, mas no dia em que o
   snapshot gravar as métricas o número precisa sair legível, não cinza-fantasma. */
.n b{font-family:var(--display);font-weight:600;font-size:var(--t-hero);color:var(--navy);letter-spacing:-.5px;line-height:1.1}
.n b.empty{color:var(--empty)}
.n span{font-size:var(--t-micro);font-weight:500;color:var(--ts)}

.connect{margin:0 16px 14px;background:var(--blue-light);border-radius:var(--r-md);padding:13px 15px;display:flex;align-items:center;gap:11px}
.connect .ic{width:38px;height:38px;border-radius:50%;background:#fff;display:flex;align-items:center;justify-content:center;flex-shrink:0}
.connect .ic i{font-size:var(--i-md);color:var(--blue)}
.connect h3{font-size:var(--t-meta);font-weight:500;color:var(--navy);line-height:1.35}
.connect p{font-size:var(--t-micro);color:var(--blue);font-weight:500;margin-top:2px}

/* A legenda que ensina a ler a tela: o traço é a única convenção que o cliente
   precisa aprender, e ela fica escrita em vez de subentendida. */
/* A folga da nav pill mora no `#app` (`padding-bottom:84px + safe-area`), não
   aqui. Este `margin-bottom` era 88px e só fazia sentido enquanto `.note` era o
   último elemento da tela — verdade na Results, FALSO no Profile (onde ela
   aparece no meio) e na Journey (onde ela abre a tela). Medido: ~106px de vão
   no meio do perfil, e 88px de branco entre "conectado com sucesso" e a barra
   de progresso. Folga de chrome dentro de componente de conteúdo vaza para
   todo lugar onde o componente for reusado. */
.note{margin:0 16px 14px;display:flex;align-items:flex-start;gap:7px;padding:11px 14px;background:var(--soft);border-radius:var(--r-sm);font-size:var(--t-micro);line-height:1.4;color:var(--ts)}
.note i{font-size:var(--i-sm);flex-shrink:0;margin-top:1px}
.note.aviso{margin-bottom:14px;background:var(--accent-light);color:var(--accent-dark)}

/* --- perfil e schedule (2026-08-11) --------------------------------------- */
/* Cores por TOKEN, nunca hex: a lei 4 do design system é verificada no CI. */
.secao{margin:0 var(--s-gutter) var(--s-7)}
/* Manrope 600, não Inter 700: só as faces de `fonts.css` existem no disco —
   Inter 400/500 e Manrope 500/600. Pedir Inter 700 fazia o browser SINTETIZAR
   o negrito (engorda o traço por transformação, sem desenho), e como as três
   regras do perfil pediam peso não servido, a tela inteira saía borrada ao
   lado de um "your profile" em Manrope 600 de verdade. */
.secao h3{font-family:var(--display);font-size:var(--t-meta);font-weight:600;color:var(--ts);margin:0 0 var(--s-4);letter-spacing:.02em}
/* O `gap:1px` não é degrau e não vira `--s-1`: com `overflow:hidden` e os
   `.dado` colados ele é o FIO DIVISOR, desenhado como gap. 2px engrossa. */
.campos{margin:0 0 var(--s-5);display:flex;flex-direction:column;gap:1px;border-radius:var(--r-sm);overflow:hidden}
/* `.dado`, não `.campo`: `.campo` já era o par label+input do LOGIN (l. 123).
   Como este bloco vem depois no arquivo com a mesma especificidade, ele vencia
   a cascata e injetava `background`, `padding` e `justify-content` nos campos
   de e-mail e senha — o caixote cinza de canto reto atrás dos labels do login,
   que ninguém desenhou. Dois componentes sem relação disputando um seletor sem
   escopo, na primeira tela que o cliente vê. */
.dado{display:flex;justify-content:space-between;align-items:baseline;gap:var(--s-5);background:var(--soft);padding:var(--s-5) var(--s-6)}
.dado dt{font-size:var(--t-micro);color:var(--ts);flex-shrink:0}
.dado dd{margin:0;font-size:var(--t-meta);font-weight:500;text-align:right;word-break:break-word}
/* `text-decoration:none` porque esta classe deixou de ser só de `<button>`: o
   Calendar e o WhatsApp de suporte são `<a>` de verdade (link abre em nova aba,
   aparece no teclado, é anunciado por leitor de tela), e sem esta linha eles
   apareciam sublinhados no meio de uma lista de itens que não são. */
.linha-acao{display:flex;align-items:center;gap:var(--s-5);width:100%;background:var(--soft);border:0;border-radius:var(--r-sm);
  padding:var(--s-6);margin-bottom:var(--s-4);font:inherit;font-size:var(--t-body);font-weight:500;color:inherit;text-align:left;
  text-decoration:none;cursor:pointer}
.linha-acao:disabled{opacity:.55;cursor:progress}
.linha-acao span{flex:1}
/* `--blue`, não `--blue-500`: esse token NUNCA existiu no `:root`. Custom
   property inválida numa propriedade herdada cai no valor do pai, então os dois
   ícones saíam em `--navy` — a mesma cor do texto ao lado — e perdiam a
   afordância azul que a ADR-0034 usa em todo o resto do app. Silencioso por
   construção: o lint procurava hex, e nome sem cor não é hex. */
.linha-acao i:first-child{font-size:var(--i-sm);color:var(--blue)}
.linha-acao i:last-child{font-size:var(--i-sm);color:var(--ts)}

/* --- codigo de pareamento (ADR-0177) ------------------------------------- */
.cod{font-family:var(--mono);font-size:var(--t-display);font-weight:500;letter-spacing:.06em;
  text-align:center;color:var(--navy);background:var(--soft);border-radius:var(--r-sm);
  padding:var(--s-6) var(--s-4);margin-bottom:var(--s-4);
  user-select:all;-webkit-user-select:all}
.cod-prazo{text-align:center;font-size:var(--t-meta);color:var(--ts);margin-bottom:var(--s-5)}

.vazio{text-align:center;padding:var(--s-8) var(--s-7)}
.vazio .ic-grande{width:56px;height:56px;margin:0 auto var(--s-6);border-radius:var(--r-md);background:var(--soft);
  display:flex;align-items:center;justify-content:center}
.vazio .ic-grande i{font-size:var(--i-lg);color:var(--blue)}
.vazio h3{font-size:var(--t-body);margin:0 0 var(--s-4);color:inherit;letter-spacing:0}
.vazio p{margin:0 0 var(--s-3);font-size:var(--t-meta);line-height:1.5;color:var(--ts)}
/* Sem `opacity`: a 80% o `--ts` compunha sobre o branco um cinza de 3,42:1, e
   nesse tamanho a regra exige 4,5:1. A frase que reprovava é justamente a que
   existe para tranquilizar quem pagou ("nothing for you to do") — desenhada e
   ilegível. O `contrast-lint` não alcança este caso por construção: ele lê
   pares de `color`+`background` na mesma regra, e aqui quem derruba o contraste
   é o alpha. Opacidade sobre texto é contraste que o portão não vê. */
.vazio p.sub{font-size:var(--t-micro);color:var(--ts)}
a.metrics{text-decoration:none;color:inherit}

/* --- schedule (bloco 2) ---------------------------------------------------
   Azul inteira, sem coral: pela ADR-0034 o coral significa "alguém está
   esperando", e compromisso marcado é hora combinada, não espera por resposta.
   Usar coral aqui gastaria o único sinal de urgência que o app tem. */
.ag-destaque{background:var(--blue-pale);border:1px solid var(--blue-light);border-radius:var(--r-md);padding:var(--s-6)}
.ag-quando{display:flex;align-items:baseline;gap:var(--s-4);margin-bottom:var(--s-2)}
.ag-dia{font-family:var(--display);font-weight:600;font-size:var(--t-meta);color:var(--blue-deep);letter-spacing:.02em}
.ag-hora{font-size:var(--t-micro);color:var(--ts);font-weight:500}
.ag-quem{font-size:var(--t-body);font-weight:500;color:var(--navy);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

.ag-linha{display:flex;gap:var(--s-5);align-items:flex-start;border:1px solid var(--line);margin-bottom:var(--s-4)}
/* O que já aconteceu continua na tela (a janela vai 7 dias para trás) mas
   recuado, para não competir com o que ainda vai acontecer. Recuo por COR e não
   por opacity: alpha sobre texto é contraste que o portão de contraste não vê
   — a lição já escrita no `.vazio p.sub` logo acima. */
.ag-linha.passou .ag-quem{color:var(--ts)}
.ag-hora-col{font-size:var(--t-micro);color:var(--ts);font-weight:500;flex-shrink:0;min-width:76px;padding-top:var(--s-1)}
.ag-corpo{flex:1;min-width:0}

.ag-meta{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s-3);margin-top:var(--s-3)}
.ag-selo{display:inline-flex;align-items:center;gap:var(--s-2);font-size:var(--t-micro);color:var(--ts);background:var(--soft);border-radius:var(--r-pill);padding:var(--s-1) var(--s-4)}
.ag-selo i{font-size:var(--i-sm)}
/* O selo da IA é o único com cor própria: é a entrega que o cliente paga, e a
   tela só o mostra quando `created_source` prova que foi ela. */
.ag-selo.ia{background:var(--blue-light);color:var(--blue-deep)}
.ag-conversa{display:inline-flex;align-items:center;gap:var(--s-2);font-family:var(--sans);font-size:var(--t-micro);font-weight:500;background:var(--blue);color:#fff;border:0;border-radius:var(--r-pill);padding:var(--s-2) var(--s-5)}
.ag-conversa i{font-size:var(--i-sm)}

/* =========================================================================
   PAINEL — a malha da referência aprovada (2026-08-16)
   =========================================================================
   A chefia aprovou a réplica de `docs/design/mockup-replica-figma.html` e
   mandou subir "sem perder o que fizemos lá". Então:

     · o que ENTRA  → a malha: cartão branco r16 sobre chão cinza, hairline +
       uma sombra, KPI 2×2, gráfico, funil com barra que cresce.
     · o que FICA   → o pulso de lead (a lei do coral, ADR-0034), a jornada, o
       traço de ausência (D62), os estados dirigidos por `humor`. Nada disso
       muda de comportamento; muda a moldura em volta.

   ── A RAMPA PRÓPRIA DO PAINEL ────────────────────────────────────────────
   A referência tem tamanhos que a nossa escala não tem (9 · 10 · 11 · 14 · 18),
   e a hierarquia dela é feita por PESO. Somar 5 degraus aos 7 de `--t-*` daria
   12 tamanhos anônimos — que é exatamente a bagunça que o design system
   desfez ("eram 20 tamanhos, 5 deles em meio pixel").

   Então o painel ganha rampa PRÓPRIA e NOMEADA, `--p-*`, com trabalho definido.
   Duas rampas com nome são legíveis; doze degraus sem dono não são.

   🔴 TRADE-OFF REGISTRADO, decisão da Junia: isto fura o piso de 12px que o
   design system fixou pensando no ICP — dono de empresa de serviço, 35-55 anos,
   lendo no sol. Ela viu o render nesses tamanhos e aprovou. Se depois parecer
   pequeno, sobe-se a rampa inteira um degrau sem tocar no layout.
   ========================================================================= */

/* o painel pinta o chão de cinza; o cartão é que é branco */
.painel{background:var(--soft)}

/* --- cabeçalho: empresa 11/600 sobre título 20/800 ----------------------- */
.p-hd{display:flex;align-items:flex-start;justify-content:space-between;padding:4px 16px 8px}
.p-hd .quem{margin:0;font-size:var(--p-lin);font-weight:600;color:var(--ts)}
.p-hd h1{margin:0;font-family:var(--sans);font-size:var(--p-tit);font-weight:800;
  color:var(--navy);letter-spacing:-.5px;line-height:32px}
.p-hd .dir{display:flex;gap:8px;align-items:center}
.p-hd .sino{width:32px;height:32px;border-radius:var(--r-pill);background:#fff;
  box-shadow:var(--p-sh);display:grid;place-items:center;color:var(--navy)}
.p-hd .sino i{font-size:var(--i-sm)}
.p-hd .av{width:32px;height:32px;border-radius:var(--r-pill);background:var(--blue);
  color:#fff;display:grid;place-items:center;font-size:var(--p-tab);font-weight:700}

/* --- chips de contexto --------------------------------------------------- */
.p-chips{display:flex;gap:8px;padding:0 16px;flex-wrap:wrap}
.p-chip{display:inline-flex;align-items:center;gap:4px;padding:6px 10px;border-radius:var(--r-sm);
  background:#fff;border:1px solid var(--p-hair);box-shadow:var(--p-sh);
  font-size:var(--p-rot);font-weight:600;color:var(--navy)}
.p-chip .pt{width:6px;height:6px;border-radius:var(--r-pill);background:var(--green)}
.p-chip i{font-size:var(--p-rot);color:var(--ts)}

/* --- KPI 2×2 ------------------------------------------------------------- */
/* A grade inteira é o link para os Resultados — mas link herda sublinhado e
   cor de link, e um KPI sublinhado lê como erro de renderização. Reset aqui, e
   a pista de que é tocável fica no próprio cartão, não numa linha embaixo. */
.p-kpis{display:grid;grid-template-columns:1fr 1fr;gap:10px;padding:12px 16px 0;
  text-decoration:none;color:inherit}
.p-kpis:hover .p-kpi{border-color:var(--track)}
.p-kpi{padding:14px;border-radius:var(--r-p);background:#fff;border:1px solid var(--p-hair);
  box-shadow:var(--p-sh)}
.p-kpi .rot{margin:0;font-size:var(--p-rot);font-weight:600;color:var(--ts);line-height:14px;
  text-transform:uppercase;letter-spacing:.04em}
.p-kpi .num{margin:4px 0 0;font-family:var(--sans);font-size:var(--p-num);font-weight:800;
  color:var(--navy);line-height:30px;letter-spacing:-.5px}
.p-kpi .num.empty{color:var(--empty)}
.p-kpi .dlt{display:flex;align-items:center;gap:2px;margin-top:4px;
  font-size:var(--p-lin);font-weight:700;line-height:16px}
.p-kpi .dlt.sobe{color:var(--green-dark)}
/* Delta que piorou é NEUTRO, não coral. Coral significa "alguém está
   esperando" (ADR-0034), e métrica caindo não é gente esperando — quem alarma
   é o pulso de lead, que já tem a tela inteira quando o caso é esse. O sinal
   e a seta carregam a direção; a cor não precisa gritar. */
.p-kpi .dlt.desce{color:var(--ts)}
.p-kpi .dlt.sem{color:var(--ts);font-weight:600}
.p-kpi .dlt i{font-size:var(--p-lin)}

/* --- cartão de painel ---------------------------------------------------- */
.p-card{margin:12px 16px 0;padding:16px;border-radius:var(--r-p);background:#fff;
  border:1px solid var(--p-hair);box-shadow:var(--p-sh)}
.p-card h3{margin:0;font-family:var(--sans);font-size:var(--p-card);font-weight:700;
  color:var(--navy);line-height:20px}
.p-card .sub{margin:0;font-size:var(--p-rot);font-weight:400;color:var(--ts);line-height:15px}

/* --- gráfico ------------------------------------------------------------- */
.p-graf{margin-top:8px}
.p-graf svg{display:block;width:100%;height:108px;overflow:visible}
.p-graf .eixo{font-size:var(--p-nano);font-weight:400;fill:var(--ts)}
.p-leg{display:flex;gap:12px;margin-top:8px;flex-wrap:wrap}
.p-leg span{display:inline-flex;align-items:center;gap:4px;font-size:var(--p-nano);
  font-weight:400;color:var(--ts)}
.p-leg i{width:8px;height:8px;border-radius:var(--r-pill);display:inline-block}

/* --- funil: a barra CRESCE (movimento medido na referência: width .4s) ---- */
.p-passo{margin-top:10px}
.p-passo .lin{display:flex;justify-content:space-between;align-items:center;gap:10px}
.p-passo .lin span{font-size:var(--p-lin);font-weight:400;color:var(--navy);line-height:17px}
.p-passo .lin b{font-family:var(--sans);font-size:var(--p-lin);font-weight:800;
  color:var(--navy);line-height:17px}
.p-passo .lin b.empty{color:var(--empty)}
.p-passo .barra{height:6px;border-radius:var(--r-pill);background:var(--track);
  margin-top:4px;overflow:hidden}
.p-passo .barra i{display:block;height:100%;border-radius:var(--r-pill);background:var(--blue);
  width:0;transition:width .4s ease}
.painel.anima .p-passo .barra i{width:var(--w)}
/* ausência: trilho hachurado, sem preenchimento. Nunca um zero. */
.p-passo.sem .barra{background:repeating-linear-gradient(135deg,var(--track) 0 4px,transparent 4px 8px)}
.p-passo.sem .lin span{color:var(--ts)}
@media (prefers-reduced-motion:reduce){
  .p-passo .barra i{transition:none;width:var(--w)}
}

/* --- trio de qualidade --------------------------------------------------- */
.p-trio{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-top:8px}
.p-trio .rot{margin:0;font-size:var(--p-rot);font-weight:600;color:var(--ts);line-height:15px}
.p-trio .num{margin:2px 0 0;font-family:var(--sans);font-size:var(--p-med);font-weight:800;
  color:var(--navy);line-height:20px}
.p-trio .num.destaque{color:var(--blue)}
.p-trio .num.empty{color:var(--empty)}
.p-trio .pe{margin:0;font-size:var(--p-nano);font-weight:400;color:var(--ts);line-height:14px}

/* --- abas do funil (malha aprovada) --------------------------------------
   Sublinhado no ativo, como na referência. Elas trocam painel de verdade —
   ver o listener em `screens/home.js`. */
.p-abas{display:flex;gap:16px;margin-bottom:8px}
.p-abas button{border:0;background:none;padding:0 0 4px;font-family:var(--sans);
  font-size:var(--p-tab);font-weight:600;color:var(--ts);cursor:pointer;
  border-bottom:2px solid transparent;transition:color .15s var(--p-ease)}
.p-abas button.on{color:var(--blue);border-bottom-color:var(--blue)}
/* --- schedule · a GRADE DE MÊS (v1.5) -------------------------------------
   Desenho e custo: `docs/calendario-v1.5-desenho.md`, opção B. O porquê mora
   lá; aqui fica só o que não dá para ler no CSS.

   Alvo de toque MEDIDO em Chrome real (`getBoundingClientRect`), coluna a
   375 px: célula 47,3×47,3 · seta 44×44 · "all days" 73,2×44. A 320 px a
   célula cai para 44×44 — `min-height` segura o piso e `aspect-ratio` obriga a
   largura a acompanhar, então ela encolhe quadrada em vez de virar uma tira.

   🔴 NENHUM recuo por `opacity`: alpha sobre texto é contraste que o
   `contrast-lint` não enxerga (a lição de `.vazio p.sub` e `.ag-linha.passou`).
   Os cinco estados da célula declaram cor E fundo NA MESMA REGRA de propósito —
   é a única forma de o portão medir. Medido: normal 13,4:1 · hoje 8,08:1 ·
   selecionado 18,38:1 · inerte 5,12:1 · fora do mês 4,80:1. */
.ag-aviso{display:flex;align-items:center;gap:8px;margin:0 16px 12px;padding:10px 13px;border-radius:var(--r-sm);font-size:var(--t-micro);background:var(--blue-light);color:var(--blue-deep)}
.ag-aviso i{font-size:var(--i-sm)}

.ag-nav{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:6px}
.ag-mes{font-family:var(--display);font-weight:600;font-size:var(--t-body);color:var(--navy);letter-spacing:.02em}
.ag-seta{display:flex;align-items:center;justify-content:center;width:44px;min-height:44px;border:0;border-radius:var(--r-pill);background:var(--soft);color:var(--blue-deep)}
.ag-seta i{font-size:var(--i-md)}
/* A seta travada continua VISÍVEL: ela É a borda da janela −7/+45. */
.ag-seta[disabled]{background:var(--soft);color:var(--ts)}

.ag-sem{display:grid;grid-template-columns:repeat(7,1fr);gap:2px;padding-bottom:4px;text-align:center;font-size:var(--t-micro);font-weight:500;background:#fff;color:var(--ts)}
.ag-grade{display:grid;grid-template-columns:repeat(7,1fr);gap:2px}
.ag-cel{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;aspect-ratio:1;min-height:44px;min-width:0;padding:0;border:0;border-radius:var(--r-sm);font-family:var(--sans);font-size:var(--t-meta);font-weight:500;background:#fff;color:var(--navy)}
/* Fora do mês: cinza cheio — "esta caixa completa a grade", sem competir. */
.ag-cel.fora{background:var(--soft);color:var(--ts)}
/* Fora de −7/+45: o servidor NÃO buscou aqui. Segue clicável e legível de
   propósito — quem tocar lê "nenhum compromisso neste dia" em vez de achar um
   botão morto (D62: "não buscamos" ≠ "não há nada"). */
.ag-cel.inerte{background:#fff;color:var(--ts)}
.ag-cel.hoje{background:var(--blue-light);color:var(--blue-deep)}
/* Selecionado = o mesmo par de `.tab.on`. Um significado, um desenho só. */
.ag-cel.sel{background:var(--navy-card);color:#fff}
/* Indicador não-textual (§1.4.11, piso 3:1). O `contrast-lint` não alcança este
   par — o fundo vem da célula, não desta regra — então vai medido à mão: azul
   sobre branco 4,62 · sobre `--blue-light` 4,01 · branco sobre `--navy-card` 18,38. */
.ag-ponto{width:5px;height:5px;border-radius:var(--r-pill);background:var(--blue)}
.ag-cel.sel .ag-ponto{background:#fff}

.ag-diahead{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:10px}
.ag-diahead h3{margin:0}
.ag-todos{min-height:44px;padding:0 14px;border:0;border-radius:var(--r-pill);font-family:var(--sans);font-size:var(--t-micro);font-weight:500;background:var(--soft);color:var(--blue-deep)}
.ag-diavazio{padding:16px;border-radius:var(--r-md);text-align:center;font-size:var(--t-meta);background:var(--soft);color:var(--ts)}

/* 42 células sem foco visível é armadilha de tabulação. Mesmo `outline` dos
   campos (`.campo input:focus`) — um significado, um desenho. */
.ag-cel:focus-visible,.ag-seta:focus-visible,.ag-todos:focus-visible{outline:2px solid var(--blue);outline-offset:1px}

/* =========================================================================
   CONVITE DE IDIOMA — o seletor da ADR-0018 no primeiro boot (js/i18n.js)

   Duas peças aqui: `.idiomas` (o seletor em si, compartilhado com a tela de
   Perfil, que já emite essa classe desde a ADR-0018 e até hoje a renderizava
   SEM UMA LINHA de CSS — três botões crus do navegador) e a caixa que o
   apresenta uma única vez.
   ========================================================================= */

/* `padding:0`/`border:0` desfazem a borda de janela de 1998 do UA stylesheet.
   Sem `box-shadow`: o véu já separa a caixa, e o único token de sombra de hoje
   (`--sombra-coluna`, 6%) não apareceria sobre ele — peso sem efeito. */
dialog.convite-idioma{
  padding:0;
  border:0;
  /* 🔴 `margin:auto` NÃO é redundante com o UA stylesheet: o reset global deste
     arquivo (`*{box-sizing:border-box;margin:0}`, l. 96) zera a margem de TUDO,
     inclusive a do `<dialog>` — e é ela que centra a caixa no top layer. Sem
     esta linha a caixa cola no topo da tela, com os cantos arredondados
     encostando na borda. Medido em Chrome 151. */
  margin:auto;
  width:min(100% - 32px,360px);
  border-radius:var(--r-lg);
  background:#fff;
  color:var(--navy);
}

/* 🚫 O véu vai no `::backdrop`, NUNCA `filter:blur()` no `#app`: `filter` num
   ancestral cria containing block para `position:fixed`, e a `.nav` é fixed —
   ela se descolaria da moldura e rolaria com o conteúdo.

   `currentColor` e não um token: `::backdrop` só passou a HERDAR do elemento de
   origem em 2024 (Chrome 122 · Safari 17.4 · Firefox 125). Antes disso `var(…)`
   não resolve e o véu sai TRANSPARENTE, calado, justo no aparelho velho. */
dialog.convite-idioma::backdrop{background:currentColor;opacity:.5}
@supports (backdrop-filter:blur(1px)){
  /* Com blur o véu pode ser mais leve: o ponto é o dono ver o app que ele
     comprou por trás enquanto confirma — a caixa é passagem, não parede. */
  dialog.convite-idioma::backdrop{backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);opacity:.32}
}

.convite-idioma form{display:flex;flex-direction:column;gap:14px;padding:22px 20px 18px}
.convite-idioma h2{font-family:var(--display);font-weight:600;font-size:var(--t-title);color:var(--navy)}
.convite-idioma p{font-size:var(--t-meta);color:var(--ts);line-height:1.45}
/* Duas classes de propósito: `.convite-nota` sozinha (0,1,0) PERDERIA para
   `.convite-idioma p` (0,1,1) e o tamanho voltaria ao de apoio. */
.convite-idioma .convite-nota{font-size:var(--t-micro)}

/* AZUL, nunca coral (ADR-0034): confirmar o idioma é uma porta que o dono abre
   quando quiser — não tem relógio correndo nem gente do outro lado esperando.
   44px de altura mínima: o alvo de toque de quem lê no sol, com uma mão. */
.convite-ok{
  min-height:44px;
  border:0;
  border-radius:var(--r-pill);
  background:var(--blue);
  color:#fff;
  font-family:var(--sans);
  font-size:var(--t-body);
  font-weight:500;
}

/* O seletor — MESMO markup nas duas casas (Perfil e convite), um só bloco.
   Nada de `text-transform`: cada rótulo tem `lang` próprio, e capitalização é
   regra de idioma. */
.idiomas{display:flex;flex-wrap:wrap;gap:8px}
.idiomas button{
  flex:1 1 auto;
  min-height:44px;
  padding:8px 14px;
  border:0;
  border-radius:var(--r-pill);
  font-family:var(--sans);
  font-size:var(--t-meta);
  font-weight:500;
  background:var(--soft);
  color:var(--ts);
}
/* Ativo = o mesmo par da aba ligada da Inbox (`.tab.on`). Não é coincidência:
   é o mesmo significado — "é este que está valendo" — e dois desenhos para um
   significado só ensinam o olho a duvidar dos dois. */
.idiomas button[aria-pressed="true"]{background:var(--navy-card);color:#fff}
/* --- alvos de toque (WCAG 2.2 AA §2.5.8) ------------------------------------
   Mediam 18-21px em Chrome real, abaixo do mínimo de 24 — e o piso que importa
   é 44: o comprador toca de pé, com a mão suja (mesma nota de ICP que levantou
   o piso da fonte). `min-height` + `inline-flex`: a caixa cresce, o peso visual
   de link não. Juntos e não espalhados porque é invariante — "todo alvo passa?"
   precisa de UM lugar para ser respondida.
   O quinto medido (`.idiomas button`, 21px) fica FORA desta lista e passa assim
   mesmo: o bloco CONVITE DE IDIOMA acima já o declara em `min-height:44px`. Ele
   é `flex:1 1 auto`, e repetir `inline-flex` aqui jogava o rótulo do botão
   esticado para a ESQUERDA — dentro de um container flex o `text-align:center`
   do UA deixa de centrar. Medido em Chrome real, coluna a 400px: com a linha
   antiga, folga 14px à esquerda contra 83,6px à direita; sem ela, 48,1/48,1.
   Altura 44 nos dois. Mesmo piso, escrito onde o botão é desenhado — e o
   layout do seletor (`display:flex`, `gap`) mora lá também, uma vez só. */
.voltar,.pular,.tform .chip button,.tform .serv{min-height:44px;display:inline-flex;align-items:center}
/* =========================================================================
   A TRAVA — o onboarding como `<dialog>` modal sobre a Home (js/trava.js)
   ========================================================================= */

/* `padding:0`/`border:0` desfazem o UA stylesheet do `<dialog>` (margem e borda
   de janela de 1998). Mesma largura máxima do `#app`: a caixa é a MESMA coluna
   do app, não uma janela de outra medida por cima dela. */
dialog.trava{
  padding:0;
  border:0;
  /* 🔴 `margin:auto` NÃO é redundante com o UA stylesheet — e a ausência dela
     aqui foi defeito no ar. O reset global deste arquivo (o seletor universal
     com `margin:0`, l. 180) zera a margem de TUDO, inclusive a do `<dialog>`,
     e é ela que centra a caixa no top layer. Sem esta linha o `<dialog>` modal
     (que o UA posiciona com `inset:0`) encosta no CANTO SUPERIOR ESQUERDO da
     tela, com os cantos arredondados na borda — foi exatamente o que a chefia
     viu ao ser segurada pelo portão em 19/08. `dialog.convite-idioma` (l. 1330)
     já carregava esta linha com esta mesma nota, medida em Chrome 151; a trava
     nasceu sem ela.
     🚫 Nenhum comentário DENTRO desta regra pode conter chave de fechamento: a
     sonda do `trava-fluxo.proof.mjs` lê o corpo da regra até a primeira que
     encontra, e uma chave no comentário corta a leitura no meio. Medido — o
     controle negativo do proof caiu por isso em 19/08. */
  margin:auto;
  width:min(100% - var(--s-7),420px);
  max-height:min(88dvh,760px);
  border-radius:var(--r-lg);
  background:#fff;
  color:var(--navy);
  display:flex;
  flex-direction:column;
  overflow:hidden;
  box-shadow:0 18px 48px var(--sombra-2);
}


/* 🚫 NÃO APAGUE ESTA REGRA ACHANDO QUE É REDUNDANTE COM O NAVEGADOR.
   Ela parece só repetir o que o UA stylesheet já faz (`dialog:not([open])
   {display:none}`) — e não repete: a regra logo acima declara `display:flex` em
   `dialog.trava` SEM condição, e CSS de autor vence CSS de UA. O `display:none`
   do navegador perde para a nossa própria linha, e a caixa FECHADA continua
   ocupando layout. A regra de cima é que criou a exceção; esta a desfaz.

   Ficou latente enquanto a trava só existia TRAVADA — ela nunca fechava por
   toque. O `×` e a abertura voluntária tornaram o caminho alcançável, e aí o
   defeito vira tela: medido em Chrome no app real, depois de fechar pelo `×` o
   `<dialog>` seguia com `display:flex`, `visibility:visible`, 420×157 e o texto
   do cabeçalho dentro — um cartão branco órfão no fim da Home, com frase de
   onboarding e sem nada explicando o que é.

   `:not([open])` aqui, e não mover o `display` para `dialog.trava[open]` lá em
   cima: `display` é a ÚNICA propriedade que briga com o UA, e movê-la partiria
   o box model da caixa em duas regras — quem for ler como ela desenha passaria
   a precisar das duas, e o `contrast-lint` deste repo mede pares declarados na
   MESMA regra. Assim a exceção fica isolada e visível.

   Provado em `trava-fluxo.proof.mjs` ("a caixa fechada pelo × NÃO ocupa
   layout"), com controle negativo que serve o CSS sem esta linha. */
dialog.trava:not([open]){display:none}

/* 🚫 O BLUR VAI NO `::backdrop`, NUNCA `filter:blur()` NO `#app`: `filter` num
   ancestral cria containing block para `position:fixed`, e a `.nav` é fixed —
   ela se descolaria da moldura e passaria a rolar com o conteúdo, que é a falha
   já escrita verbatim no comentário do `#app` no desktop (l. 190-200). E
   forçaria repaint de blur de página inteira por frame de rolagem.

   `background:currentColor` e não um token: `::backdrop` só passou a HERDAR do
   elemento de origem em 2024 (Chrome 122 · Safari 17.4 · Firefox 125). Antes
   disso ele não tem pai, `var(--navy-card)` não resolve e o véu sai
   TRANSPARENTE — falha muda, e justo no aparelho velho. `currentColor` serve os
   dois mundos: com herança é o `--navy` da caixa, sem ela é o preto inicial.
   (Pela Lei 4 o certo seria um `--veu-trava` no `:root`; ver o relatório.) */
dialog.trava::backdrop{background:currentColor;opacity:.55}
@supports (backdrop-filter:blur(1px)){
  /* Com blur o véu pode ser mais leve: o ponto é o cliente VER o app que
     comprou por trás enquanto responde. */
  dialog.trava::backdrop{backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);opacity:.34}
}

/* Cabeça CLARA, corpo com o card navy que a jornada já renderiza. Não é gosto:
   o markup dela é escrito para `--navy-card` (`.tbody h4` e `.tform .serv` são
   brancos) — num painel branco esses pares caem para 1:1, e o `contrast-lint`
   não pegaria nenhum, porque só mede pares declarados na mesma regra. */
.trava-head{
  padding:var(--s-7) var(--s-gutter) var(--s-5);
  background:#fff;
  color:var(--navy);
  border-bottom:1px solid var(--line);
  flex-shrink:0;
  position:relative;
}
/* A saída da abertura VOLUNTÁRIA (card da Home). Nasce `hidden` no HTML e só
   `abrir()` a revela, conferindo o modo — na trava do portão ela não existe,
   senão seria o botão de pular que o cabeçalho de `trava.js` diz não existir.
   44px pelo mesmo piso de toque do resto (WCAG 2.2 AA §2.5.8). `--ts` sobre
   branco = 5,12:1: sai do caminho do olho sem sair do alcance do dedo. */
.trava-fechar{
  position:absolute;
  top:var(--s-4);
  right:var(--s-4);
  width:44px;
  min-height:44px;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  border:0;
  border-radius:var(--r-pill);
  background:#fff;
  color:var(--ts);
}
.trava-fechar i{font-size:var(--i-md)}
.trava-fechar[hidden]{display:none}
.trava-head h1{font-family:var(--display);font-weight:600;font-size:var(--t-title);color:var(--navy)}
.trava-head p{margin-top:var(--s-2);font-size:var(--t-meta);color:var(--ts);line-height:1.45}
/* Classe DUPLA de propósito: `.trava-recusa` sozinha (0,1,0) PERDERIA para
   `.trava-head p` (0,1,1) e a cor voltaria ao cinza.
   🚫 `.trava-contador` saiu em 2026-08-17 junto com o `N of M answered` do
   cabeçalho da caixa: o quiz não mostra total nenhum. */
.trava-head .trava-recusa{font-weight:500;color:var(--blue-deep)}
/* O que ainda falta, na caixa TRAVADA. Duas classes pelo mesmo motivo da linha
   acima: `.trava-falta` sozinha (0,1,0) perderia para `.trava-head p` (0,1,1).
   Peso 500 e `--navy` (o texto principal, 12,6:1 sobre branco): é a frase que
   responde "por que estou preso?", e ela não pode ser mais fraca que o apoio
   cinza logo acima dela. */
.trava-head .trava-falta{font-weight:500;color:var(--navy)}
.trava-head .trava-falta:empty{display:none}

/* Região viva que nasce VAZIA e some quando não tem o que dizer. Escondê-la com
   `hidden` e só então pôr texto dentro é o jeito de um `role="status"` NÃO
   anunciar — o leitor precisa do nó já presente para ver a mudança. Vale também
   para as caixas de recusa da jornada, que trocaram `hidden` por texto vazio. */
[data-recusa]:empty,[data-falta]:empty,[data-erro-conectar]:empty{display:none}

/* `overscroll-behavior:contain`: sem isto, chegar ao fim da lista continua
   rolando a Home ATRÁS do véu — a página que a trava existe para segurar. */
.trava-corpo{
  flex:1;
  min-width:0;
  overflow-y:auto;
  overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;
  padding:var(--s-5) 0 var(--s-7);
  background:#fff;
  color:var(--navy);
}

/* `:has` é ignorado por quem não o suporta, e aí sobra o `overscroll-behavior`
   acima — degradação, não quebra. */
body:has(dialog.trava[open]){overflow:hidden}
