/* CRM Galwan — CSS único.
 *
 * A ordem de vitória é declarada aqui, na linha 1, e nunca depende de quem
 * escreveu depois. Sem isso, um arquivo mantido ao longo de muitas sessões
 * desenvolve guerra de especificidade e `!important`.
 *
 * Tokens extraídos do protótipo aprovado. Modo escuro está FORA de escopo por
 * decisão do Victor.
 */
@layer tokens, base, layout, componentes, utilitarios, estado;

/* As fontes, auto-hospedadas em app/static/fonts/.
 *
 * Ficam FORA das camadas de propósito: `@font-face` não participa da cascata, e
 * pô-lo numa camada só o esconderia de quem lê o arquivo procurando por ele.
 *
 * Subset `latin` apenas — o português cabe inteiro nele, e cirílico, grego e
 * vietnamita seriam peso morto. Cinco arquivos, 99 KB no total, copiados do
 * Google Fonts (OFL; as licenças estão ao lado dos .woff2).
 *
 * O Newsreader é pedido como `wght@600` e não com o eixo `opsz`: a variável com
 * tamanho óptico de 6 a 72 pesa 60 KB contra 23 KB da estática, e esta tela não
 * usa o eixo.
 *
 * `font-display: swap`: o texto aparece na hora com a fonte do sistema e troca
 * quando a própria chega. Em 4G a alternativa (`block`) é meio segundo de tela
 * sem texto nenhum — pior que a troca.
 */
@font-face {
  font-family: "Newsreader";
  src: url("/static/fonts/newsreader-600.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Sans";
  src: url("/static/fonts/plex-sans-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Sans";
  src: url("/static/fonts/plex-sans-600.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("/static/fonts/plex-mono-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("/static/fonts/plex-mono-600.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

@layer tokens {
  :root {
    /* Cor. Azul institucional da Galwan. */
    --paper: #eef1f5;
    --surface: #fff;
    --surface-2: #f5f7fa;
    --ink: #111e2e;
    --slate: #54657c;
    /* Escurecido em relação ao protótipo (#8494A9 dava ~3:1 sobre branco, e
     * estava na DATA de cada interação). Este dá ~4.6:1. */
    --slate-2: #6b7c93;
    --line: #dce2ea;
    --line-2: #c3cdd9;

    --blue: #1f4e8c;
    --blue-ink: #0d2543;
    --blue-soft: #e4edf8;

    --ok: #1c6a56;
    --ok-soft: #e0efea;
    --warn: #9c5416;
    --warn-soft: #f8ede1;
    --crit: #a03028;
    --crit-soft: #f8e7e5;

    /* Tipografia. Newsreader e IBM Plex auto-hospedados; ver @font-face acima. */
    --serif: "Newsreader", Georgia, "Times New Roman", serif;
    --sans: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    --mono: "IBM Plex Mono", ui-monospace, "Cascadia Mono", Consolas, monospace;

    /* Escala de tamanho: oito, não os 21 do protótipo. */
    --t-micro: 11px; /* piso: 9px do protótipo era ilegível no sol */
    --t-xs: 12px;
    --t-sm: 13px;
    --t: 15px;
    --t-md: 16px; /* PISO em input: abaixo disso o Safari do iOS dá zoom */
    --t-lg: 1.15rem;
    --t-xl: 1.4rem;

    /* Espaçamento: seis, não os 15 do protótipo. */
    --s1: 4px;
    --s2: 8px;
    --s3: 12px;
    --s4: 16px;
    --s5: 22px;
    --s6: 32px;

    --r-xs: 2px;
    --r: 4px;
    --r-lg: 12px;
    --r-pill: 999px;

    --tap: 44px; /* alvo de toque mínimo */
    --sh: 0 1px 2px rgba(17, 30, 46, 0.06), 0 8px 24px -12px rgba(17, 30, 46, 0.18);

    --z-abas: 30;
    --z-folha: 40;
    --z-detalhe: 50;
    --dur: 200ms;

    color-scheme: light;
  }
}

@layer base {
  *,
  *::before,
  *::after {
    box-sizing: border-box;
  }

  body {
    margin: 0;
    background: var(--paper);
    color: var(--ink);
    font: var(--t) / 1.5 var(--sans);
    -webkit-font-smoothing: antialiased;
  }

  /* Entrelinha de título, e não a 1.5 herdada do corpo: em 22px ela dava uma
   * caixa de 34px e o título flutuava 5px abaixo de onde a margem o punha. Um
   * valor aqui, e nenhum local — havia um 1.15 solto na ficha. */
  h1,
  h2,
  h3 {
    font-family: var(--serif);
    font-weight: 600;
    line-height: 1.2;
    letter-spacing: -0.01em;
    margin: 0;
  }
  h1 {
    font-size: var(--t-xl);
  }
  h2 {
    font-size: var(--t-lg);
  }

  a {
    color: var(--blue);
    text-decoration: none;
  }

  button,
  input,
  select,
  textarea {
    font: inherit;
    color: inherit;
  }

  /* Piso de 16px: abaixo disso o Safari do iOS dá zoom na página ao focar, e o
   * layout salta na mão do corretor. */
  input,
  select,
  textarea {
    font-size: var(--t-md);
  }

  /* Toda <details> deste sistema mostra para onde vai.
   *
   * Sem a seta, o único sinal de que há algo a abrir é o cursor virar mãozinha
   * — e no celular cursor não existe. O triângulo padrão do navegador sai
   * porque ele se desenha FORA da caixa do botão, e dentro de um retângulo
   * azul cheio isso parece defeito.
   *
   * Uma regra só, e não uma classe por lugar: toda gaveta se comporta igual, e
   * a próxima nasce certa sem ninguém lembrar de nada. */
  summary {
    list-style: none;
  }
  summary::-webkit-details-marker {
    display: none;
  }
  summary::after {
    content: "";
    flex: none;
    width: 0.38em;
    height: 0.38em;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    /* Aponta para baixo: o conteúdo abre embaixo. */
    transform: translateY(-0.12em) rotate(45deg);
    transition: transform var(--dur);
  }
  details[open] > summary::after {
    transform: translateY(0.1em) rotate(-135deg);
  }

  :focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
  }

  ::selection {
    background: var(--blue-soft);
  }
}

@layer layout {
  .app {
    min-height: 100dvh;
    display: grid;
    grid-template-areas: "topo" "conteudo" "abas";
    grid-template-rows: auto 1fr auto;
  }

  /* `min-width: 0`: como item do grid, a barra tem largura mínima automática
   * igual ao seu min-content, e esse mínimo é o que dimensiona a coluna. Com a
   * logo (179px que não encolhem) mais um nome comprido, a coluna passava de
   * 360px para 473px e a PÁGINA INTEIRA ganhava rolagem lateral — a marca
   * esticava a carteira e as abas junto. */
  .topbar {
    grid-area: topo;
    /* Contexto do painel do sino no celular: ele se ancora na barra inteira,
     * não no botão — ver `.sino-painel`. */
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--s3);
    min-width: 0;
    padding: var(--s4) var(--s4) var(--s3);
    background: var(--surface);
    border-bottom: 1px solid var(--line);
  }
  /* A altura manda e a largura sai da proporção. `flex-shrink: 0` porque a barra
   * é um flex: sem ele o nome longo e o botão Sair espremem a logo no celular,
   * e marca espremida é marca errada. */
  .brand {
    height: 1.5rem;
    width: auto;
    flex-shrink: 0;
  }
  /* `min-width: 0` e as reticências abaixo: sem eles o nome é um piso de
   * largura, e num celular de 360px "Maria Fernanda Albuquerque" empurrava a
   * barra a 376px — a página inteira ganhava rolagem lateral. Quem encolhe é o
   * nome, e não a marca: o usuário sabe qual é o próprio nome, e a barra fica
   * de uma linha em vez de três. */
  .who {
    margin-left: auto;
    text-align: right;
    line-height: 1.25;
    min-width: 0;
  }
  .who b {
    display: block;
    font-size: var(--t-sm);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .who span {
    display: block;
    white-space: nowrap;
    font-family: var(--mono);
    font-size: 10px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--slate-2);
  }

  /* O sino de avisos. `flex-shrink: 0` como a marca: quem encolhe na barra é o
   * nome, não o botão que existe para ser tocado.
   *
   * No celular ele NÃO é o contexto do painel (`position: static`): 22rem
   * ancorados à direita de um botão que fica no meio da barra saíam pela borda
   * esquerda da tela — e rolagem lateral não denuncia vazamento à esquerda. O
   * painel se ancora na barra (`.topbar`), de margem a margem. Acima de 45rem
   * volta a pendurar no botão. */
  .sino {
    position: static;
    flex-shrink: 0;
  }
  /* Com a marca, o sino e o Sair, sobravam 47px para o nome em 390px — virava
   * "Raf…". O corretor sabe o próprio nome; o sino ele precisa ver. Quem não
   * tem sino (gestor, administrativo) mantém o nome. */
  .topbar:has(.sino) .who {
    display: none;
  }
  /* Sem o nome, é o sino que empurra a si e ao Sair para a direita — era o
   * `margin-left: auto` do nome que fazia isso. */
  .topbar:has(.sino) .sino {
    margin-left: auto;
  }
  .sino-botao {
    list-style: none;
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: var(--tap);
    min-height: var(--tap);
    border-radius: var(--r);
    color: var(--slate);
    cursor: pointer;
  }
  /* Sem a seta do `summary::after` global: o sino já diz que abre pelo número
   * e pelo ícone, e a seta encostada no sino parecia parte do desenho. */
  .sino-botao::after {
    content: none;
  }
  .sino[open] > .sino-botao {
    background: var(--blue-soft);
    color: var(--blue);
  }
  .sino-n {
    position: absolute;
    top: 3px;
    right: 3px;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: var(--r-pill);
    background: var(--crit);
    color: #fff;
    font: 600 11px / 18px var(--mono);
    text-align: center;
  }
  /* Abre por cima do conteúdo, logo abaixo da barra, de margem a margem — o
   * contexto é a `.topbar`. Acima de 45rem, alinhado à direita do botão. */
  .sino-painel {
    position: absolute;
    left: var(--s4);
    right: var(--s4);
    top: calc(100% + var(--s1));
    z-index: var(--z-detalhe);
    padding: var(--s2);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r);
    box-shadow: 0 8px 24px rgb(0 0 0 / 0.12);
  }
  .sino-lista {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--s1);
  }
  .sino-item {
    display: flex;
    align-items: center;
    min-height: var(--tap);
    padding: var(--s2) var(--s3);
    border-left: 3px solid var(--line-2);
    border-radius: var(--r);
    color: var(--ink);
    font-size: var(--t-sm);
    text-decoration: none;
  }
  .sino-item:hover {
    background: var(--surface-2);
  }
  .sino-item[data-tom="crit"] {
    border-left-color: var(--crit);
  }
  .sino-item[data-tom="info"] {
    border-left-color: var(--blue);
  }
  .sino-painel .empty {
    padding: var(--s3);
  }

  .col {
    grid-area: conteudo;
    padding: var(--s4) var(--s4) var(--s6);
    max-width: 44rem;
    margin-inline: auto;
    width: 100%;
  }
  /* O painel inicial do Admin e de comparacao, nao de leitura: doze corretores
     com cinco numeros nao cabem em 44rem sem furar o piso de 11px. A largura
     nasce do conteudo e vale so ali. Esta tela nunca preenche #detalhe, entao
     nao se cruza com o mestre-detalhe logo abaixo. */
  .col:has(> .panorama) {
    max-width: 78rem;
  }

  /* Navegação por abas no rodapé: o dedo é o dispositivo de entrada.
   *
   * Grudada embaixo (decisão do Victor, 18/09/2026): em página longa ela rolava
   * junto e só voltava no fim. `sticky` mantém o espaço dela no grid, então o
   * conteúdo não fica escondido atrás. Abaixo da folha e da ficha de detalhe,
   * que são camadas por cima da tela inteira. */
  .tabs {
    grid-area: abas;
    position: sticky;
    bottom: 0;
    z-index: var(--z-abas);
    display: grid;
    grid-auto-flow: column;
    background: var(--surface);
    border-top: 1px solid var(--line);
    padding-bottom: env(safe-area-inset-bottom);
  }
  .tabs a {
    min-height: var(--tap);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    padding: var(--s2) 0;
    color: var(--slate);
    font-size: var(--t-micro);
    border-top: 2px solid transparent;
  }
  .tabs a[aria-current="page"] {
    color: var(--blue);
    border-top-color: var(--blue);
  }
  .tabs .ic {
    font-size: 17px;
    line-height: 1;
  }

  /* Escondida por padrão, e ANTES da media query: dentro da mesma camada, a
   * regra que vem depois vence com especificidade igual. Declarar o `none`
   * depois do `flex` deixava o desktop sem navegação nenhuma. */
  .topnav {
    display: none;
  }

  @media (min-width: 45rem) {
    .app {
      grid-template-areas: "topo" "conteudo";
      grid-template-rows: auto 1fr;
    }
    /* Acima de 720px o rodapé é vertical caro e o dedo não é a entrada: a
     * navegação sobe para o topo. */
    .tabs {
      display: none;
    }
    .topnav {
      display: flex;
      gap: var(--s1);
      margin-left: var(--s5);
    }
    .topnav a {
      padding: var(--s2) var(--s3);
      border-radius: var(--r);
      color: var(--slate);
      font-size: var(--t-sm);
    }
    .topnav a[aria-current="page"] {
      background: var(--blue-soft);
      color: var(--blue);
      font-weight: 600;
    }
    /* Com espaço, o painel do sino pendura no botão e o nome volta — e é o
     * nome que volta a empurrar para a direita. */
    .sino {
      position: relative;
    }
    .topbar:has(.sino) .sino {
      margin-left: 0;
    }
    .sino-painel {
      left: auto;
      right: 0;
      width: 22rem;
    }
    .topbar:has(.sino) .who {
      display: initial;
    }
  }
  /* O painel de detalhe — um só para os três breakpoints.
   *
   * Vazio ele some, e é o `:empty` que decide: assim a carteira sozinha não
   * precisa de uma classe a mais nem de um `if` no template. */
  .detalhe:empty {
    display: none;
  }

  /* Até o mestre-detalhe, a ficha é camada por cima. Abaixo de 1100px a tela
   * não comporta lista e ficha lado a lado sem espremer as duas. */
  .detalhe {
    position: fixed;
    inset: 0;
    z-index: var(--z-detalhe);
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--paper);
    padding: var(--s4);
    padding-bottom: calc(var(--s6) + env(safe-area-inset-bottom));
  }

  @media (min-width: 68.75rem) {
    /* Mestre-detalhe: a ficha nunca tira a lista da tela. A coluna só nasce
     * quando há ficha — com `#detalhe` vazio a carteira usa a largura inteira. */
    .app:has(#detalhe:not(:empty)) {
      grid-template-areas: "topo topo" "conteudo detalhe";
      grid-template-columns: minmax(0, 1fr) minmax(26rem, 34rem);
      height: 100dvh;
    }
    /* `100dvh` com rolagem por painel só aqui, e isso é deliberado: no celular
     * o documento tem um scroll único, que é o que o navegador otimiza — a
     * barra de endereço esconde e o teclado virtual não quebra o layout. */
    .app:has(#detalhe:not(:empty)) .col {
      overflow-y: auto;
    }
    .detalhe {
      position: static;
      grid-area: detalhe;
      background: var(--surface);
      border-left: 1px solid var(--line);
      padding-bottom: var(--s6);
    }
  }
}

@layer componentes {
  /* Um botão, variante por atributo. O protótipo tinha onze estilos. */
  .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--s1);
    min-height: var(--tap);
    padding: 0 var(--s3);
    border: 1px solid var(--line-2);
    border-radius: var(--r);
    background: var(--surface);
    font-weight: 600;
    font-size: var(--t-sm);
    cursor: pointer;
  }
  .btn[data-variante="primaria"] {
    background: var(--blue);
    border-color: var(--blue);
    color: #fff;
  }
  .btn[data-variante="fantasma"] {
    background: none;
    border-color: transparent;
    color: var(--blue);
  }
  /* Verde do WhatsApp, escurecido para dar contraste com texto branco: o
   * #25D366 da marca rende ~1.8:1 e reprova em qualquer leitura. */
  .btn[data-variante="wa"] {
    background: #0f7a3d;
    border-color: #0f7a3d;
    color: #fff;
  }
  .btn[data-variante="perigo"] {
    border-color: var(--crit);
    color: var(--crit);
  }
  .btn[data-largo] {
    width: 100%;
  }
  .btn:disabled {
    opacity: 0.45;
    cursor: default;
  }
  /* Enviando um formulário comum: ele não passa pelo htmx, e é o app.js que
   * marca o botão entre o toque e a resposta. Mesma opacidade do
   * `.htmx-request`, para a espera ter uma cara só. */
  .btn[aria-busy="true"] {
    opacity: 0.55;
    pointer-events: none;
  }

  /* Um rótulo micro, não as oito declarações do protótipo. */
  .eyebrow {
    font: 500 var(--t-micro) / 1.3 var(--mono);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--slate);
  }

  .fld {
    margin-bottom: var(--s3);
  }
  .fld label {
    display: block;
    margin-bottom: var(--s1);
  }
  .fld input {
    width: 100%;
    padding: var(--s3);
    border: 1px solid var(--line-2);
    border-radius: var(--r);
    background: var(--surface);
  }
  .fld[data-erro] input {
    border-color: var(--crit);
  }

  /* Mostrar a senha digitada.
   *
   * O padding à direita reserva o espaço do botão: sem ele, uma senha longa
   * corre por baixo do olho e fica ilegível justamente quando foi revelada. */
  .campo-olho {
    position: relative;
  }
  .campo-olho input {
    padding-right: 48px;
  }
  /* O Edge desenha o próprio olho dentro do campo de senha. Sem isto ficam dois
   * ícones lado a lado, e o nativo some quando o campo perde o foco — ou seja,
   * dois controles com aparência e comportamento diferentes para a mesma coisa. */
  .campo-olho input::-ms-reveal,
  .campo-olho input::-ms-clear {
    display: none;
  }
  .olho {
    position: absolute;
    right: 2px;
    top: 50%;
    transform: translateY(-50%);
    /* 44px é o piso de alvo de toque; o ícone tem 20px e o resto é área. */
    width: 44px;
    height: 44px;
    display: grid;
    place-items: center;
    border: 0;
    background: none;
    border-radius: var(--r);
    color: var(--slate-2);
    cursor: pointer;
  }
  .olho:hover {
    color: var(--slate);
    background: var(--line);
  }
  /* Anel para dentro: com o offset global de 2px o foco desenharia por cima da
   * borda do campo, e a soma dos dois vira uma moldura dupla no canto. */
  .olho:focus-visible {
    outline-offset: -2px;
  }
  /* Sem JS para trocar o ícone: o estado já está no aria-pressed, e duplicá-lo
   * numa classe é o começo dos dois estados que discordam. */
  .olho .olho-ocultar,
  .olho[aria-pressed="true"] .olho-ver {
    display: none;
  }
  .olho[aria-pressed="true"] .olho-ocultar {
    display: block;
  }
  .fld-erro {
    margin: var(--s1) 0 0;
    font-size: var(--t-sm);
    color: var(--crit);
  }

  .aviso {
    padding: var(--s3);
    border-radius: var(--r);
    font-size: var(--t-sm);
    margin-bottom: var(--s3);
  }
  .aviso[data-tom="erro"] {
    background: var(--crit-soft);
    color: var(--crit);
  }
  .aviso[data-tom="ok"] {
    background: var(--ok-soft);
    color: var(--ok);
  }

  /* --------------------------------------------------------------- entrada */

  /* A única tela sem o shell do sistema: não há navegação nem sessão ainda,
   * então ela tem o próprio layout de página.
   *
   * O desenho é uma prancheta: uma malha de 28px corre por baixo de tudo —
   * branca dentro do azul, grafite sobre o papel —, o cartão é a folha presa em
   * cima dela, e a régua no topo do cartão usa a mesma medida da malha. Nada
   * disso é imagem: são gradientes repetidos, sem nada para baixar.
   *
   * A faixa da marca tem a MESMA marcação e a MESMA aparência nos dois
   * tamanhos: no celular é a faixa azul do topo, a partir de 48rem é a parede
   * da esquerda. Isso mantém a logo (que é a versão branca) sempre sobre azul,
   * e é por isso que NENHUM texto desta tela fica em cima da malha de grafite
   * — o que tira a malha da conta de contraste em vez de apertá-la.
   *
   * A faixa é a primeira linha e o palco é a segunda, elástica: a faixa encosta
   * no topo da janela e o cartão se centra no que sobra. `min-height` e não
   * `height` — a linha elástica tem piso de conteúdo, então numa tela baixa (ou
   * com o teclado virtual aberto) a página cresce e rola em vez de cortar.
   */
  .entrada {
    /* O passo da malha e as duas tintas do papel, em um lugar só: são citados
     * oito vezes, e oito números soltos viram sete depois da primeira mudança.
     * A malha do papel é decoração pura — sem texto em cima dela, a opacidade é
     * escolha de olho e não teto de contraste. */
    --modulo: 28px;
    --papel-forte: rgba(17, 30, 46, 0.055);
    --papel-fino: rgba(17, 30, 46, 0.026);

    min-height: 100dvh;
    display: grid;
    grid-template-rows: auto 1fr;
    background-color: var(--paper);
    /* Linha forte a cada cinco módulos, como papel milimetrado de verdade. */
    background-image:
      repeating-linear-gradient(to right, var(--papel-forte) 0 1px, transparent 1px calc(var(--modulo) * 5)),
      repeating-linear-gradient(to bottom, var(--papel-forte) 0 1px, transparent 1px calc(var(--modulo) * 5)),
      repeating-linear-gradient(to right, var(--papel-fino) 0 1px, transparent 1px var(--modulo)),
      repeating-linear-gradient(to bottom, var(--papel-fino) 0 1px, transparent 1px var(--modulo));
  }

  /* A faixa azul, alinhada à esquerda nos dois tamanhos e com o mesmo recuo
   * lateral do palco: no celular a logo nasce exatamente na borda esquerda do
   * cartão que vem abaixo. Só a logo mora aqui — o ramo "Construtora e
   * Incorporadora" saiu por decisão do Victor (19/09/2026): a marca já diz
   * quem é, e a linha de mono em caixa alta competia com ela.
   *
   * As opacidades da malha branca são as que já estavam no arquivo. Sem texto
   * na faixa elas não entram em conta de contraste nenhuma; são escolha de
   * olho. */
  .entrada-marca {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--s2);
    /* `env(safe-area-inset-top)`: o `viewport-fit=cover` do base.html deixa a
     * página correr por baixo da barra de status, e sem isto o nome da empresa
     * fica atrás do relógio no iPhone. O azul pode passar por baixo; o texto,
     * não. */
    padding: calc(var(--s5) + env(safe-area-inset-top)) var(--s4) var(--s5);
    color: #fff;
    background-color: var(--blue-ink);
    background-image:
      radial-gradient(75% 55% at 15% 0%, rgba(31, 78, 140, 0.85), transparent 70%),
      repeating-linear-gradient(to right, rgba(255, 255, 255, 0.09) 0 1px, transparent 1px calc(var(--modulo) * 5)),
      repeating-linear-gradient(to bottom, rgba(255, 255, 255, 0.09) 0 1px, transparent 1px calc(var(--modulo) * 5)),
      repeating-linear-gradient(to right, rgba(255, 255, 255, 0.04) 0 1px, transparent 1px var(--modulo)),
      repeating-linear-gradient(to bottom, rgba(255, 255, 255, 0.04) 0 1px, transparent 1px var(--modulo));
  }
  /* A logo é o maior elemento da tela nos dois layouts. A proporção é 7,5 por
   * 1, então a altura vem da largura: 17rem no celular dão 36px de altura,
   * parecido com o "Galwan" em serifa que ela substituiu. `display: block`
   * tira a folga de linha que toda <img> inline carrega embaixo. */
  .entrada-logo {
    display: block;
    width: 100%;
    max-width: 17rem;
    height: auto;
  }
  .entrada-palco {
    display: grid;
    place-items: center;
    padding: var(--s6) var(--s4);
    padding-bottom: calc(var(--s6) + env(safe-area-inset-bottom));
  }
  /* `--pad` é o recuo do cartão em um lugar só: a régua do topo se estica entre
   * as mesmas duas margens, então ela continua alinhada quando o recuo cresce
   * no computador.
   *
   * Raio de 4px, borda `--line-2` e sombra curta em azul-tinta: é uma folha
   * presa na prancheta, não um balão. Sombra cinza sobre papel azulado suja o
   * branco do cartão. */
  .entrada-cartao {
    --pad: var(--s5);
    position: relative;
    width: min(25rem, 100%);
    padding: var(--pad);
    background: var(--surface);
    border: 1px solid var(--line-2);
    border-radius: var(--r);
    box-shadow:
      0 1px 1px rgba(13, 37, 67, 0.06),
      0 12px 24px -18px rgba(13, 37, 67, 0.5);
  }
  /* A régua de cotas: traço curto a cada meio módulo, traço longo a cada dois.
   * Mesma medida da malha do fundo — é o que faz o cartão parecer cotado sobre
   * a folha em vez de largado nela. Ornamento: nada para ler, nada para tocar. */
  .entrada-cartao::before {
    content: "";
    position: absolute;
    top: 0;
    left: var(--pad);
    right: var(--pad);
    height: 9px;
    background-image:
      repeating-linear-gradient(to right, var(--line-2) 0 1px, transparent 1px calc(var(--modulo) / 2)),
      repeating-linear-gradient(to right, var(--line-2) 0 1px, transparent 1px calc(var(--modulo) * 2));
    background-size: 100% 4px, 100% 9px;
    background-repeat: no-repeat;
    /* Centrada: a largura do cartão não é múltiplo do passo, e o que sobra
     * fica dividido entre as duas pontas em vez de acumulado na direita. */
    background-position: 50% 0;
  }
  /* Os 4px são a folga sob o traço mais longo da régua. */
  .entrada-titulo {
    margin: var(--s1) 0 var(--s5);
  }
  /* A faixa vermelha sozinha some no meio do cartão branco; a barra à esquerda
   * é o que faz a recusa ser vista antes de o corretor digitar de novo. Borda,
   * e não desenho de fundo: no alto contraste do Windows o fundo é trocado pelo
   * do sistema e a borda sobrevive. */
  .entrada-cartao .aviso {
    margin-bottom: var(--s4);
    border-left: 3px solid var(--crit);
  }

  .entrada-form .fld {
    margin-bottom: var(--s4);
  }
  /* O rótulo é a linha de uma prancha: índice, espaço, nome do campo. */
  .entrada-form .fld label {
    display: flex;
    align-items: baseline;
    gap: var(--s2);
    margin-bottom: var(--s2);
  }
  /* O índice se separa do rótulo pelo peso, e não por uma cor mais clara: fica
   * em `--slate` sobre branco, 5.95:1. */
  .entrada-num {
    font-weight: 600;
    letter-spacing: 0.06em;
  }
  /* 48px e não `--tap`: são dois campos e um botão na tela inteira, e o botão já
   * é 48. O campo cinza que branqueia ao foco é o sinal do toque, onde o anel
   * do sistema aparece e some junto com o teclado virtual. Sem halo por fora: o
   * anel global de 2px com recuo de 2px desenha por cima dele e vira moldura
   * tripla. */
  .entrada-form .fld input {
    min-height: 48px;
    background: var(--surface-2);
    transition:
      background var(--dur),
      border-color var(--dur);
  }
  .entrada-form .fld input:focus {
    background: var(--surface);
    border-color: var(--blue);
  }
  /* Em campo de texto o `:focus-visible` casa em TODO foco, não só no de
   * teclado, então o anel global (2px, recuo 2px) aparecia a cada toque ao lado
   * da borda azul: duas linhas da mesma cor com um fio branco entre elas. O
   * recuo de -1px põe o anel em cima da borda e vira uma moldura só, de 2px. */
  .entrada-form .fld input:focus-visible {
    outline-offset: -1px;
  }
  /* O Chrome pinta o campo preenchido pelo gerenciador com um lilás próprio por
   * cima de qualquer `background`; só a sombra interna vence. Em vez de apagar
   * o sinal, ele vira o azul da casa, com o texto em 14.23:1.
   *
   * 1000px de espalhamento e não 40: a sombra interna só cobre a caixa enquanto
   * o dobro do espalhamento passar da altura do campo. Com a fonte do navegador
   * aumentada o campo passa de 80px e o lilás reaparece no meio dele —
   * justamente para quem aumentou a fonte.
   *
   * `:focus` não mexe em `box-shadow`, então o foco nunca traz o lilás de
   * volta: as duas regras não disputam a mesma propriedade. */
  .entrada-form .fld input:-webkit-autofill {
    -webkit-text-fill-color: var(--ink);
    box-shadow: inset 0 0 0 1000px var(--blue-soft);
  }
  /* Regra separada: navegador que não conhece um dos dois seletores descartaria
   * a declaração inteira se os dois estivessem na mesma lista. */
  .entrada-form .fld input:autofill {
    background: var(--blue-soft);
  }

  .entrada-form .btn {
    margin-top: var(--s5);
    min-height: 48px;
    font-size: var(--t);
  }
  /* `:active` junto com `:hover`: no celular não existe hover, e sem isto o
   * botão não responde a nada entre o toque e a troca de página. */
  .entrada-form .btn[data-variante="primaria"]:hover,
  .entrada-form .btn[data-variante="primaria"]:active {
    background: var(--blue-ink);
    border-color: var(--blue-ink);
  }
  /* A saída de quem não consegue entrar: o link para pedir a redefinição por
   * e-mail, e nas telas do pedido, o caminho de volta ao login. */
  .entrada-ajuda {
    margin: var(--s4) 0 0;
    font-size: var(--t-sm);
    line-height: 1.4;
    color: var(--slate);
  }
  .entrada-ajuda a {
    color: var(--blue);
    text-decoration: underline;
    text-underline-offset: 2px;
  }
  /* O texto corrido do cartão (a confirmação do pedido, o link vencido): mesma
   * medida do formulário, para o cartão não mudar de largura entre as telas. */
  .entrada-texto {
    margin: 0 0 var(--s4);
    line-height: 1.5;
  }

  @media (min-width: 48rem) {
    /* 48rem (768px), e não 56: o tablet em pé (768 a 860px) recebia o celular
     * esticado — faixa de 108px com o lockup encolhido num canto e 360px de
     * papel vazio antes do cartão, que se centrava e desalinhava da marca.
     *
     * Proporção com teto: no ponto de virada os 38% dão 292px, sobrando 476
     * para o cartão de 400 mais o recuo; em 1440 o painel acompanha a janela
     * e em 2560 ele para em 34rem em vez de virar 1100px de azul com uma
     * palavra dentro. */
    .entrada {
      grid-template-columns: clamp(18rem, 38%, 34rem) minmax(0, 1fr);
      grid-template-rows: 1fr;
    }
    .entrada-marca {
      justify-content: center;
      gap: var(--s3);
      padding: var(--s6);
    }
    /* A margem de desenho que toda prancha tem. Só aqui: numa faixa de 110px no
     * celular ela viraria uma caixa em volta do logotipo. */
    .entrada-marca::before {
      content: "";
      position: absolute;
      inset: var(--s4);
      border: 1px solid rgba(255, 255, 255, 0.16);
      pointer-events: none;
    }
    /* 24rem dão 51px de altura, a presença do "Galwan" de 54px que estava aqui.
     * A parede tem no mínimo 288px menos 64 de recuo, e a logo encolhe junto. */
    .entrada-logo {
      max-width: 24rem;
    }
    .entrada-cartao {
      --pad: var(--s6);
    }
  }

  @media (prefers-reduced-motion: reduce) {
    .entrada-form .fld input {
      transition: none;
    }
  }

  /* Contador das 12h. Uma linha e uma barra fina — o protótipo tinha um card
   * que dizia a mesma proporção quatro vezes. */
  .duty {
    margin: 0 0 var(--s4);
  }
  .duty-line {
    display: flex;
    align-items: baseline;
    gap: var(--s3);
    margin: 0 0 7px;
  }
  .duty-txt {
    font-size: var(--t-sm);
    color: var(--slate);
    min-width: 0;
  }
  .duty-txt b {
    font-family: var(--mono);
    font-size: var(--t);
    font-weight: 600;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
  }
  .duty-t {
    margin-left: auto;
    flex: 0 0 auto;
    font-family: var(--mono);
    font-size: var(--t-micro);
    color: var(--warn);
    white-space: nowrap;
  }
  /* 600, e nao 500: era o unico uso do peso 500 no sistema inteiro, e sozinho
   * custaria mais um arquivo de fonte de ~22 KB para uma palavra. */
  .duty[data-ok] .duty-txt {
    color: var(--ok);
    font-weight: 600;
  }
  .duty[data-ok] .duty-t {
    display: none;
  }
  .bar {
    height: 3px;
    background: var(--line);
    border-radius: var(--r-xs);
    overflow: hidden;
  }
  .bar i {
    display: block;
    height: 100%;
    background: var(--blue);
    border-radius: var(--r-xs);
    transition: width 0.3s ease;
  }
  .duty[data-ok] .bar i {
    background: var(--ok);
  }

  /* Cartão de lead. Sempre <a>, para clique do meio e voltar funcionarem. */
  .leads {
    display: flex;
    flex-direction: column;
    gap: var(--s2);
  }
  .lead {
    display: grid;
    grid-template-columns: 3px 1fr auto;
    gap: var(--s3);
    align-items: center;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r);
    padding: var(--s3);
    color: inherit;
    min-height: var(--tap);
  }
  .lead:hover {
    border-color: var(--line-2);
  }
  .lead-sev {
    align-self: stretch;
    border-radius: var(--r-xs);
    background: var(--line-2);
  }
  .lead[data-sev="crit"] .lead-sev {
    background: var(--crit);
  }
  .lead[data-sev="warn"] .lead-sev {
    background: var(--warn);
  }
  .lead[data-sev="ok"] .lead-sev {
    background: var(--ok);
  }
  .lead-mid {
    min-width: 0;
  }
  .lead-nome {
    display: block;
    font-weight: 600;
    font-size: var(--t);
  }
  .lead-meta {
    display: block;
    font-size: var(--t-sm);
    color: var(--slate);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .lead-rt {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: var(--s1);
    text-align: right;
  }
  .lead-prazo {
    font-family: var(--mono);
    font-size: var(--t-sm);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
  }
  .lead[data-sev="crit"] .lead-prazo {
    color: var(--crit);
  }
  .lead[data-sev="warn"] .lead-prazo {
    color: var(--warn);
  }
  .lead[data-sev="ok"] .lead-prazo {
    color: var(--ok);
  }

  .chip {
    font: 500 var(--t-micro) / 1 var(--mono);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    padding: 4px 6px;
    border-radius: var(--r-xs);
    white-space: nowrap;
  }
  .chip[data-tom="todo"] {
    background: var(--warn-soft);
    color: var(--warn);
  }
  .chip[data-tom="done"] {
    background: var(--ok-soft);
    color: var(--ok);
  }
  .chip[data-tom="pause"] {
    background: var(--surface-2);
    color: var(--slate);
    border: 1px solid var(--line-2);
  }
  .chip[data-tom="pre"] {
    background: var(--blue-soft);
    color: var(--blue);
  }

  .grouplbl {
    font: 500 var(--t-micro) / 1.3 var(--mono);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--slate-2);
    margin: var(--s5) 0 var(--s2);
  }
  .grouplbl:first-child {
    margin-top: 0;
  }

  .empty {
    padding: var(--s6) var(--s1);
    text-align: center;
    color: var(--slate-2);
    font-size: var(--t-sm);
  }

  /* ---------------------------------------------------------- ficha do lead */

  /* Toda seção de primeiro nível da ficha é uma faixa: fio em cima, rótulo,
   * respiro fixo. Não depende do fundo, e é isso que a faz igual no papel do
   * celular e no branco da coluna — os cartões brancos de antes sumiam no
   * branco, e o cinza do núcleo sumia no papel. Os cartões que ficam dentro
   * (`.tl-item`, `.anexo`) são itens, não seções, e continuam como são.
   *
   * `.ficha > section` e não uma classe por seção: a próxima seção nasce certa
   * sem ninguém lembrar de nada. */
  .ficha > section {
    margin-top: var(--s5);
    padding-top: var(--s4);
    border-top: 1px solid var(--line-2);
  }
  /* O rótulo de seção fica ACIMA do rótulo de campo na hierarquia: em `--slate`
   * e 600, contra o `--slate-2` e 400 do `.grouplbl` solto — que, dentro da
   * ficha, ficava mais claro que o `.eyebrow` de cada campo. */
  .ficha > section > .grouplbl {
    color: var(--slate);
    font-weight: 600;
  }

  .ficha-topo {
    display: flex;
    align-items: flex-start;
    gap: var(--s3);
    margin-bottom: var(--s3);
  }
  .ficha-topo h2 {
    margin: var(--s1) 0 0;
    font-family: var(--serif);
    font-size: var(--t-xl);
  }
  .ficha-topo .chip {
    margin-left: auto;
    flex: none;
  }
  /* Fechar a ficha existe nos dois layouts, e isso corrige um engano meu: no
   * mestre-detalhe eu havia escondido a saída achando que "voltar" para uma
   * lista que nunca sai da tela era ruído. Voltar é mesmo; **fechar** não — com
   * a ficha aberta a carteira fica espremida numa coluna, e não havia como
   * devolver a largura inteira a ela. */
  .ficha-fechar {
    flex: none;
    display: grid;
    place-items: center;
    width: var(--tap);
    height: var(--tap);
    margin: -6px -6px 0 0;
    border-radius: var(--r);
    color: var(--slate-2);
    font-size: 26px;
    line-height: 1;
    text-decoration: none;
  }
  .ficha-fechar:hover {
    color: var(--ink);
    background: var(--line);
  }
  .ficha-estado {
    margin: 0 0 var(--s4);
    color: var(--slate);
    font-size: var(--t-sm);
  }

  /* Origem e interesse: dois fatos curtos, lado a lado. */
  .ficha-meta {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: center;
    gap: var(--s1) var(--s3);
    margin: 0 0 var(--s4);
  }
  .ficha-meta dt {
    font-family: var(--mono);
    font-size: var(--t-micro);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--slate-2);
  }
  .ficha-meta dd {
    margin: 0;
    font-size: var(--t-sm);
  }
  .ficha-meta select {
    padding: var(--s1) var(--s2);
    border: 1px solid var(--line-2);
    border-radius: var(--r);
    background: var(--surface);
    font-size: var(--t-sm);
  }

  .ficha-nucleo {
    display: grid;
    gap: var(--s2);
  }
  .pessoa summary {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--s1) var(--s3);
    min-height: var(--tap);
    padding: var(--s1) 0;
    cursor: pointer;
  }
  .pessoa > summary::after {
    margin-left: auto;
    color: var(--slate-2);
  }
  .pessoa[open] summary {
    margin-bottom: var(--s2);
  }
  .pessoa-corpo {
    display: grid;
    gap: var(--s2);
    padding: 0 0 var(--s3) var(--s3);
    border-left: 2px solid var(--line);
  }
  .pessoa-form {
    display: grid;
    gap: var(--s2);
  }
  .pessoa-form input {
    width: 100%;
    padding: var(--s2) var(--s3);
    border: 1px solid var(--line-2);
    border-radius: var(--r);
    background: var(--surface);
  }
  .pessoa-leitura {
    margin: 0;
    font-size: var(--t-sm);
    color: var(--slate);
  }
  /* Corrigir e remover na mesma linha do número: as duas nascem do mesmo
   * engano, e separá-las faria a tela escolher antes do corretor. */
  .tel-form {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s2);
  }
  /* O formulario de corrigir cresce; o de remover fica do tamanho do botao. */
  .tel-form > form:first-child {
    display: flex;
    flex: 1 1 14rem;
    gap: var(--s2);
  }
  .tel-form input {
    flex: 1 1 10rem;
    padding: var(--s2) var(--s3);
    border: 1px solid var(--line-2);
    border-radius: var(--r);
    background: var(--surface);
  }
  .pessoa-nome {
    font-weight: 600;
    font-size: var(--t-sm);
  }
  .tel {
    font-family: var(--mono);
    font-size: var(--t-xs);
    color: var(--slate);
  }
  .tel-vazio {
    font-style: italic;
  }

  /* Um número: link direto. Vários: a escolha vem antes do redirecionamento,
   * senão o corretor cai na conversa errada e só percebe depois de mandar. */
  .wa,
  .wa-lista {
    margin-top: var(--s2);
  }
  .wa-lista a {
    display: flex;
    align-items: center;
    gap: var(--s2);
    min-height: var(--tap);
    padding: 0 var(--s3);
    margin-top: var(--s1);
    border: 1px solid var(--line-2);
    border-radius: var(--r);
    background: var(--surface);
    font-size: var(--t-sm);
  }
  .wa-lista a span {
    margin-left: auto;
    color: var(--slate);
    font-family: var(--mono);
    font-size: var(--t-xs);
  }

  /* Fechados por padrão: são ações ocasionais, e abertos empurrariam a Timeline
   * para baixo da dobra em toda abertura de ficha. */
  .nucleo-add summary {
    display: inline-flex;
    align-items: center;
    /* A seta precisa de respiro: encostada no texto ela parece parte da
     * palavra, e foi assim que "+ pessoa no núcleo" ficou apertado. */
    gap: var(--s2);
    min-height: var(--tap);
    padding: 0 var(--s1);
    color: var(--blue);
    font-size: var(--t-sm);
    cursor: pointer;
  }
  .nucleo-pessoa {
    border-top: 1px dashed var(--line-2);
    padding-top: var(--s2);
  }
  .nucleo-add form {
    display: grid;
    gap: var(--s2);
    padding: var(--s2) 0;
  }
  /* Campos de TEXTO ocupam a largura; caixa de selecao, nao. Sem a exclusao, o
   * `width: 100%` pegava tambem o checkbox de `.caixa` — o quadradinho esticava
   * pela tela e o rotulo ia para a borda direita. */
  .nucleo-add input:not([type="checkbox"]):not([type="radio"]),
  .nucleo-add select {
    width: 100%;
    padding: var(--s2) var(--s3);
    border: 1px solid var(--line-2);
    border-radius: var(--r);
    background: var(--surface);
  }
  /* A pessoa é uma linha que quebra; o formulário aberto ocupa a largura toda,
   * senão ele fica espremido ao lado do telefone. */
  .pessoa > .nucleo-add[open] {
    flex-basis: 100%;
  }

  /* ---------------------------------------------------------------- roleta */

  /* A oferta vem antes de tudo e se destaca: é a única coisa da tela com prazo
   * correndo, e o corretor tem 30 minutos. */
  .oferta {
    padding: var(--s4);
    margin-bottom: var(--s5);
    background: var(--blue-soft);
    border: 1px solid var(--blue);
    border-radius: var(--r);
  }
  .oferta h2 {
    margin: var(--s1) 0 0;
    font-family: var(--serif);
    font-size: var(--t-lg);
  }
  .oferta-meta {
    margin: var(--s1) 0 var(--s3);
    font-size: var(--t-sm);
    color: var(--slate);
  }
  .oferta-prazo {
    margin: 0 0 var(--s4);
    font-family: var(--mono);
    font-size: var(--t-xl);
    color: var(--blue-ink);
  }
  .oferta-acoes {
    display: flex;
    gap: var(--s2);
  }
  .oferta-acoes form {
    flex: 1;
  }
  .oferta-acoes .btn {
    width: 100%;
  }

  .meu-estado {
    margin-bottom: var(--s5);
  }
  /* A resposta à pergunta com que o corretor abre a tela, em uma linha: o
   * número grande e a frase ao lado, na mesma base. */
  .vez {
    display: flex;
    align-items: baseline;
    gap: var(--s2);
    margin: 0 0 var(--s3);
    font-size: var(--t);
    font-weight: 600;
  }
  .vez-num {
    font-family: var(--serif);
    font-size: var(--t-xl);
    line-height: 1;
    color: var(--blue-ink);
  }

  .fila,
  .ordem {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--s1);
  }
  .fila-item,
  .ordem-item {
    display: flex;
    align-items: center;
    gap: var(--s3);
    min-height: var(--tap);
    padding: 0 var(--s3);
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: var(--surface);
  }
  /* Quem sou eu e quem é o próximo, sem depender de cor sozinha: os dois têm
   * texto no estado à direita. */
  .fila-item[data-eu] {
    border-color: var(--line-2);
    background: var(--surface-2);
  }
  .fila-item[data-proximo] {
    border-left: 3px solid var(--blue);
  }
  /* Pulado nesta volta: apagado E tracejado, porque a linha já diz o motivo à
   * direita e o traço distingue sem depender da cor. `--slate` e não
   * `--slate-2`: a 13px o segundo dá 4,26:1 sobre branco, abaixo dos 4,5:1. */
  .fila-item[data-pulado] {
    border-style: dashed;
  }
  .fila-item[data-pulado] .fila-nome {
    color: var(--slate);
  }
  /* Onde a varredura começa. Não é alvo de toque, então não tem os 44px. */
  .fila-ponteiro {
    font: 500 var(--t-micro) / 1.3 var(--mono);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--blue);
    padding: var(--s1) var(--s3) 0;
  }
  .fila-n {
    font-family: var(--mono);
    font-size: var(--t-micro);
    color: var(--slate-2);
  }
  .fila-nome {
    font-size: var(--t-sm);
  }
  .fila-estado {
    margin-left: auto;
    font-size: var(--t-xs);
    color: var(--slate);
  }
  .ordem-item .btn {
    min-height: 34px;
    padding: 0 var(--s2);
  }
  .ordem-item .fila-nome {
    flex: 1;
  }
  .ordem-tirar {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s2);
    margin-top: var(--s4);
  }

  /* ----------------------------------------------------------------- funil */

  .funil {
    list-style: none;
    margin: 0 0 var(--s5);
    padding: 0;
    display: grid;
    gap: var(--s1);
  }
  /* Sem barra: ela existia para comparar volume de relance, e isso só funciona
   * quando há volume. Com no máximo 10 leads por corretor espalhados em oito
   * etapas ela nunca disse nada que o número ao lado não dissesse — e no
   * administrativo uma das etapas é um arquivo que só cresce, então a barra
   * dela seria sempre cheia e as outras, sempre um risco. */
  .funil-etapa {
    display: grid;
    grid-template-columns: 1.5rem 1fr 2.5rem;
    align-items: center;
    gap: var(--s2);
    min-height: var(--tap);
    padding: 0 var(--s2);
    border-radius: var(--r);
    color: var(--ink);
  }
  .funil-etapa:hover {
    background: var(--surface-2);
  }
  .funil-etapa[aria-current="true"] {
    background: var(--blue-soft);
  }
  .funil-n {
    font-family: var(--mono);
    font-size: var(--t-micro);
    color: var(--slate-2);
  }
  .funil-nome {
    font-size: var(--t-sm);
  }
  .funil-total {
    text-align: right;
    font-size: var(--t-sm);
    font-weight: 600;
  }

  /* ---------------------------------------------------- painel do gestor */

  .painel-espera {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--s2);
  }
  .painel-destino {
    list-style: none;
    margin: 0;
    padding: 0;
  }

  /* O histórico é referência, não trabalho: linha fina, sem cartão. Com o mesmo
   * peso do bloco de cima, vinte entregas enterravam os leads parados — e são
   * eles que pedem ação. */
  .painel-hist {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 0 var(--s3);
    padding: var(--s2) var(--s1);
    border-bottom: 1px solid var(--line);
  }

  /* Nome e tempo na primeira linha, o resto embaixo: o gestor varre a coluna
   * da esquerda procurando quem está parado há mais tempo. Duas colunas, e não
   * uma tabela, porque nome de pessoa não tem largura previsível. */
  .painel-lead {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: var(--s1) var(--s3);
    padding: var(--s3);
    background: var(--surface);
    border: 1px solid var(--line);
    border-left: 3px solid var(--line-2);
    border-radius: var(--r);
  }
  .painel-lead[data-tom="crit"] {
    border-left-color: var(--crit);
  }
  .painel-lead[data-tom="ok"] {
    border-left-color: var(--ok);
  }
  .painel-nome {
    font-weight: 600;
    font-size: var(--t-sm);
  }
  .painel-tempo {
    font-size: var(--t-xs);
    color: var(--slate);
    text-align: right;
  }
  .painel-tel {
    font-size: var(--t-xs);
    color: var(--slate);
  }
  .painel-estado {
    grid-column: 1 / -1;
    font-size: var(--t-xs);
    color: var(--ink);
  }
  .painel-meta {
    grid-column: 1 / -1;
    font-size: var(--t-micro);
    color: var(--slate-2);
  }

  /* Debaixo das colunas do funil do Gestor, a nota precisa do respiro que ela
   * não tem no panorama: lá ela fecha um cartão, aqui ela separa a contagem da
   * lista. O espaço de cima já vem da margem da `.funil`. */
  .funil + .kpi-nota {
    margin: 0 0 var(--s4);
  }

  /* Os atos do funil do Gestor. Atravessam as duas colunas do cartão: ao lado
   * do nome, os três botões espremiam o telefone num celular de 390px. */
  .sdr-atos {
    grid-column: 1 / -1;
    display: flex;
    flex-wrap: wrap;
    align-items: start;
    gap: var(--s2);
    margin-top: var(--s1);
  }
  /* Aqui o descarte perde o respiro extra que ele tem na ficha do corretor:
   * lá é o irreversível que não divide linha com a rotina; aqui desqualificar
   * É a rotina — ~630 por mês. */
  .sdr-atos .descarte {
    margin-top: 0;
  }
  /* "opcional" dito no rótulo, e não descoberto depois de submeter vazio. */
  .fld-opcional {
    margin-left: var(--s2);
    text-transform: none;
    letter-spacing: 0;
    color: var(--slate-2);
    font-weight: 400;
  }
  /* Aberto, o descarte toma a linha inteira: o campo do motivo com a largura de
   * um botão é onde se digita "não serve" e acabou — e o motivo é o único dado
   * que sobra do lead descartado. */
  .sdr-atos .descarte[open] {
    flex: 1 1 100%;
  }

  /* --------------------------------------------------------- parâmetros */

  .parametros {
    display: grid;
    gap: var(--s4);
    margin: var(--s4) 0 var(--s5);
  }
  .parametros input {
    width: 100%;
    max-width: 14rem;
  }
  /* A consequência de cada prazo, embaixo do campo. Fato, não instrução — quem
   * lê é o Admin, e a decisão é dele. */
  .fld-nota {
    margin: var(--s1) 0 0;
    font-size: var(--t-xs);
    color: var(--slate);
  }
  .versoes {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--s2);
  }
  .versao {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: var(--s1) var(--s3);
    padding: var(--s3);
    background: var(--surface);
    border: 1px solid var(--line);
    border-left: 3px solid var(--line-2);
    border-radius: var(--r);
  }
  .versao:first-child {
    border-left-color: var(--blue);
  }
  .versao-desde {
    font-size: var(--t-xs);
    color: var(--slate);
  }
  .versao-autor {
    font-size: var(--t-xs);
    color: var(--slate);
    text-align: right;
  }
  .versao-valores {
    grid-column: 1 / -1;
    font-size: var(--t-sm);
    font-weight: 600;
  }
  .versao-nota {
    grid-column: 1 / -1;
    font-size: var(--t-xs);
    color: var(--ink);
  }

  /* ---------------------------------------------------- empreendimentos */

  .obra-novo {
    margin-bottom: var(--s4);
  }
  .obras {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--s2);
  }
  .obra {
    background: var(--surface);
    border: 1px solid var(--line);
    /* Faixa azul no que ainda vai lançar: é nele que há data a definir. */
    border-left: 3px solid var(--blue);
    border-radius: var(--r);
    /* O padding vive no `summary` e no formulário, não aqui: assim a área de
     * toque da linha vai de borda a borda em vez de parar antes. */
    overflow: hidden;
  }
  .obra[data-lancado] {
    border-left-color: var(--line-2);
  }
  .obra-editar > summary {
    display: flex;
    align-items: center;
    gap: var(--s2);
    padding: var(--s3);
    min-height: var(--tap);
    cursor: pointer;
  }
  /* A seta global sai SÓ aqui: o lápis já é o sinal de que a linha abre, e dois
   * marcadores na mesma linha viram sujeira. */
  .obra-editar > summary::after {
    content: none;
  }
  .obra-id {
    flex: 1;
    min-width: 0;
    display: grid;
    gap: 2px;
    font-size: var(--t-sm);
  }
  .obra-id b {
    /* Nome comprido encolhe com reticências em vez de empurrar o lápis para
     * fora da tela. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .obra-meta {
    font-size: var(--t-xs);
    color: var(--slate);
  }
  .obra-lapis {
    flex: none;
    color: var(--slate-2);
    transition: color var(--dur);
  }
  .obra-editar > summary:hover .obra-lapis,
  .obra-editar[open] .obra-lapis {
    color: var(--blue);
  }
  .obra-editar > form {
    display: grid;
    gap: var(--s2);
    padding: var(--s3);
    border-top: 1px solid var(--line);
    background: var(--surface-2);
  }
  .obra-editar input[type="text"],
  .obra-editar input[type="datetime-local"] {
    width: 100%;
    min-height: var(--tap);
    /* 16px é PISO: abaixo disso o Safari do iOS dá zoom ao focar. */
    font-size: var(--t-md);
    padding: 0 var(--s2);
    border: 1px solid var(--line-2);
    border-radius: var(--r);
    background: var(--surface);
    color: var(--ink);
  }

  /* --------------------------------------------- tela do Administrativo */

  .casos {
    list-style: none;
    margin: 0 0 var(--s4);
    padding: 0;
    display: grid;
    gap: var(--s2);
  }
  .caso {
    padding: var(--s3);
    background: var(--surface);
    border: 1px solid var(--line);
    border-left: 3px solid var(--blue);
    border-radius: var(--r);
  }
  .caso-cab {
    margin: 0;
    font-size: var(--t-sm);
  }
  .caso-meta {
    margin: var(--s1) 0 var(--s3);
    font-size: var(--t-xs);
    color: var(--slate);
  }
  .caso-acoes {
    display: grid;
    gap: var(--s2);
  }
  /* O aval do supervisor: aprovar em cima, reprovar como gaveta embaixo. */
  .aval {
    display: grid;
    gap: var(--s2);
  }
  /* Devolver e reprovar são a exceção, não o caminho normal: ficam como gaveta,
   * e abrir já pede o motivo — que é o ponto inteiro das duas. */
  .devolver > summary,
  .reprovar > summary {
    display: inline-flex;
    align-items: center;
    gap: var(--s2);
    min-height: var(--tap);
    padding: 0 var(--s1);
    color: var(--slate);
    font-size: var(--t-sm);
    cursor: pointer;
  }
  .devolver form,
  .reprovar form {
    display: grid;
    gap: var(--s2);
    padding-top: var(--s2);
  }
  .devolver input[type="text"],
  .reprovar input[type="text"] {
    width: 100%;
    min-height: var(--tap);
    /* 16px é PISO: abaixo disso o Safari do iOS dá zoom ao focar. */
    font-size: var(--t-md);
    padding: 0 var(--s2);
    border: 1px solid var(--line-2);
    border-radius: var(--r);
    background: var(--surface);
    color: var(--ink);
  }

  /* ------------------------------------------- telas do Gerente Comercial */

  /* Os atalhos de Outros: linha larga, alvo generoso, e a explicação embaixo do
   * nome — quem abre esta tela não usa estas telas todo dia e precisa lembrar o
   * que cada uma faz. */
  .atalhos {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--s2);
  }
  .atalhos a {
    display: grid;
    gap: var(--s1);
    padding: var(--s3);
    min-height: var(--tap);
    background: var(--surface);
    border: 1px solid var(--line);
    border-left: 3px solid var(--blue);
    border-radius: var(--r);
    text-decoration: none;
    color: var(--ink);
  }
  .atalhos a:hover {
    background: var(--surface-2);
  }
  .atalhos span {
    font-size: var(--t-xs);
    color: var(--slate);
  }

  /* ------------------------------------------------- administração ---- */

  /* Contas. A inativa perde o destaque e continua na lista: ela é registro de
   * quem esteve aqui, e some da lista quem some do histórico. */
  .usuarios,
  .atos,
  .saude {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--s2);
  }
  .usuario,
  .ato {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r);
  }
  .ato {
    padding: var(--s3);
  }
  .usuario[data-inativo] {
    background: var(--surface-2);
  }
  .ato-cab {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--s2);
    margin: 0;
    flex-wrap: wrap;
  }

  /* A conta abre em duas linhas: nome e papeis. E o que responde de relance
   * "quem existe e com que acesso"; o resto so aparece para quem vai agir.
   *
   * Areas nomeadas porque a seta de `details > summary` deste sistema e um
   * ::after — sem area propria ele cairia numa terceira celula do grid e
   * desceria para baixo dos papeis. */
  .conta > summary {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas:
      "nome seta"
      "papeis seta";
    align-items: center;
    column-gap: var(--s2);
    min-height: var(--tap);
    padding: var(--s2) var(--s3);
    cursor: pointer;
  }
  .conta > summary::after {
    grid-area: seta;
  }
  .conta-nome {
    grid-area: nome;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--s2);
  }
  .conta-papeis {
    grid-area: papeis;
    font-size: var(--t-xs);
    color: var(--slate);
  }
  .conta-corpo {
    padding: 0 var(--s3) var(--s3);
  }
  .usuario-meta,
  .ato-campos {
    margin: var(--s1) 0 0;
    font-size: var(--t-xs);
    color: var(--slate);
  }

  /* Gaveta e botao nao dividem linha: a gaveta cresce quando abre, e ao lado
   * dela o botao de um toque ficava torto. Os de um toque ficam juntos em
   * cima, as gavetas empilhadas embaixo. */
  .usuario-diretas {
    display: flex;
    gap: var(--s2);
    margin-top: var(--s3);
  }
  .usuario-diretas > form {
    flex: 1;
  }
  .usuario-atos {
    display: grid;
    gap: var(--s2);
    margin-top: var(--s3);
  }
  .usuario-atos > .perdao {
    margin-top: 0;
  }
  /* O conjunto de papeis usa `.caixa`, que ja existe e ja trata o tamanho do
   * quadradinho. Uma segunda classe para a mesma coisa foi o que produziu o
   * formulario torto. */
  .papeis {
    margin: 0;
    padding: 0;
    border: 0;
  }

  /* Auditoria. A escrita sem ator declarado é o alarme, e por isso é a única
   * linha com faixa. */
  .ato[data-sem-ator] {
    border-left: 3px solid var(--warn);
  }
  .ato-quando {
    font-size: var(--t-xs);
    color: var(--slate);
  }
  .ato-frase {
    margin: var(--s1) 0 0;
    font-size: var(--t-sm);
  }
  .ato-motivo {
    margin: var(--s1) 0 0;
    font-size: var(--t-xs);
    color: var(--slate);
    font-style: italic;
  }

  /* Saúde: cada sinal é um cartão, e a cor diz se exige ação. Cor nunca sozinha
   * — o valor e a nota dizem a mesma coisa em palavras. */
  .sinal {
    padding: var(--s3);
    background: var(--surface);
    border: 1px solid var(--line);
    border-left: 3px solid var(--line-2);
    border-radius: var(--r);
  }
  .sinal[data-tom='ok'] {
    border-left-color: var(--ok);
  }
  .sinal[data-tom='warn'] {
    border-left-color: var(--warn);
  }
  .sinal[data-tom='crit'] {
    border-left-color: var(--crit);
  }
  .sinal-titulo {
    margin: 0;
    font-size: var(--t-xs);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--slate);
  }
  .sinal-valor {
    margin: var(--s1) 0 0;
    font-size: var(--t-lg);
    font-weight: 600;
  }
  .sinal-nota {
    margin: var(--s1) 0 0;
    font-size: var(--t-xs);
    color: var(--slate);
  }

  /* O perdão em dois tempos: o botão abre, e só então o motivo aparece. Caixa
   * sempre aberta convida a digitar qualquer coisa e apertar, e a justificativa
   * é o que responde "por quê" numa disputa. */
  .perdao {
    margin-top: var(--s3);
  }
  .perdao > summary {
    display: inline-flex;
    align-items: center;
    gap: var(--s2);
    min-height: var(--tap);
    cursor: pointer;
  }
  .perdao form {
    display: grid;
    gap: var(--s2);
    padding-top: var(--s3);
  }
  .perdao input[type="text"] {
    width: 100%;
    min-height: var(--tap);
    /* 16px é PISO: abaixo disso o Safari do iOS dá zoom ao focar. */
    font-size: var(--t-md);
    padding: 0 var(--s2);
    border: 1px solid var(--line-2);
    border-radius: var(--r);
    background: var(--surface);
    color: var(--ink);
  }

  .feriados {
    list-style: none;
    margin: var(--s2) 0 0;
    padding: 0;
    display: grid;
    gap: var(--s1);
  }
  .feriado {
    display: flex;
    align-items: center;
    gap: var(--s2);
    padding: var(--s2) var(--s3);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r);
    font-size: var(--t-sm);
  }
  /* Feriado que já passou continua na lista como registro de por que aquele dia
   * não foi útil, mas sem o botão de tirar. */
  .feriado[data-passou] {
    background: var(--surface-2);
    color: var(--slate);
  }
  .feriado-nome {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--slate);
    font-size: var(--t-xs);
  }
  .feriado-tirar {
    width: var(--tap);
    height: var(--tap);
    margin: calc(var(--s2) * -1) calc(var(--s3) * -1) calc(var(--s2) * -1) 0;
    border: 0;
    background: none;
    color: var(--slate-2);
    font-size: var(--t-md);
    cursor: pointer;
  }
  .feriado-tirar:hover {
    color: var(--crit);
  }

  .punicoes,
  .nuc {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--s2);
  }
  .punicao,
  .nuc-pessoa {
    padding: var(--s3);
    background: var(--surface);
    border: 1px solid var(--line);
    border-left: 3px solid var(--warn);
    border-radius: var(--r);
  }
  /* Perdoada e desfeito perdem a faixa de urgência: continuam na lista como
   * registro, e não como coisa a fazer. */
  .punicao[data-perdoada],
  .nuc-pessoa[data-desfeito] {
    border-left-color: var(--line-2);
    background: var(--surface-2);
  }
  .nuc-pessoa {
    border-left-color: var(--line-2);
  }
  .punicao-cab,
  .nuc-cab {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--s2);
    margin: 0;
    font-size: var(--t-sm);
  }
  .punicao-dia,
  .nuc-tel {
    font-size: var(--t-xs);
    color: var(--slate-2);
  }
  .punicao-meta,
  .nuc-vinculo {
    margin: var(--s1) 0 0;
    font-size: var(--t-xs);
    color: var(--slate);
  }
  /* Desde quando a pessoa está na base: é o dado que arbitra "quem chegou
   * primeiro", então fica visível sem precisar abrir nada. */
  .nuc-desde {
    margin: var(--s1) 0 var(--s3);
    font-size: var(--t-xs);
    color: var(--slate);
  }
  /* Consulta de leads: o histórico de posse de uma negociação. A posse aberta
   * ganha a barra à esquerda, como a punição que ainda vale — é a linha que
   * responde "quem está atendendo agora". */
  .consulta-meta {
    margin: 0 0 var(--s1);
    font-size: var(--t-xs);
    color: var(--slate);
  }
  .posses {
    list-style: none;
    margin: 0 0 var(--s4);
    padding: 0;
    display: grid;
    gap: var(--s2);
  }
  .posse {
    padding: var(--s3);
    background: var(--surface-2);
    border: 1px solid var(--line);
    border-left: 3px solid var(--line-2);
    border-radius: var(--r);
  }
  .posse[data-aberta] {
    background: var(--surface);
    border-left-color: var(--blue);
  }
  .posse-cab {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--s2);
    margin: 0;
  }
  .posse-dia {
    font-size: var(--t-xs);
    color: var(--slate);
  }
  .posse-meta {
    margin: var(--s1) 0 0;
    font-size: var(--t-xs);
    color: var(--slate);
  }

  .punicao-perdao {
    margin: var(--s1) 0 0;
    font-size: var(--t-xs);
    color: var(--slate);
  }
  /* A justificativa é texto de gente: sem maiúscula, sem mono, do tamanho de
   * uma frase que se lê. É ela que responde "por quê" numa disputa. */
  .punicao-motivo,
  .vinculo-motivo {
    margin: var(--s1) 0 0;
    font-size: var(--t-sm);
    color: var(--ink);
  }
  .punicao-form,
  .vinculo-form {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s2);
  }
  .punicao-form input[type="text"],
  .vinculo-form input[type="text"] {
    flex: 1 1 11rem;
    min-width: 0;
    min-height: var(--tap);
    /* 16px é PISO: abaixo disso o Safari do iOS dá zoom ao focar. */
    font-size: var(--t-md);
    padding: 0 var(--s3);
    border: 1px solid var(--line-2);
    border-radius: var(--r);
    background: var(--surface);
    color: var(--ink);
  }

  /* --------------------------------------- vínculo e preferências do lead */

  /* O parentesco ao lado do nome, na lista fechada. Discreto: quem procura é o
   * nome e o telefone; o vínculo responde "quem é essa pessoa" de relance. */
  .pessoa-vinculo {
    font-size: var(--t-xs);
    color: var(--slate-2);
    white-space: nowrap;
  }

  .vinculo-form {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: var(--s1) var(--s2);
    align-items: center;
    margin-top: var(--s3);
  }
  .vinculo-form label {
    grid-column: 1 / -1;
  }
  .vinculo-form select {
    min-height: var(--tap);
    font-size: var(--t-md);
    padding: 0 var(--s2);
    border: 1px solid var(--line-2);
    border-radius: var(--r);
    background: var(--surface);
    color: var(--ink);
  }

  /* Sem cartão: é a última linha do Núcleo, e abre como a linha da pessoa. O
   * cartão branco de antes sumia no branco da coluna. */
  .prefs {
    margin-top: var(--s2);
  }
  .prefs > summary {
    cursor: pointer;
    min-height: var(--tap);
    display: flex;
    align-items: center;
    gap: var(--s2);
    font-size: var(--t-sm);
    font-weight: 600;
  }
  .prefs > summary::after {
    color: var(--slate-2);
  }
  /* A seta vai para a borda direita só quando não há resumo: com resumo, é ele
   * quem empurra (`margin-left: auto`), e dois `auto` na mesma linha dividiriam
   * o espaço ao meio. */
  .prefs > summary:not(:has(.prefs-resumo))::after {
    margin-left: auto;
  }
  .prefs[open] > summary {
    margin-bottom: var(--s2);
  }
  /* O resumo na gaveta fechada: sem ele, a única forma de saber se há algo
   * preenchido é abrir — e ninguém abre todo dia. */
  .prefs-resumo {
    margin-left: auto;
    font-weight: 400;
    font-size: var(--t-xs);
    color: var(--slate);
    text-align: right;
  }
  /* Duas colunas onde cabe, uma no celular. `min-width:0` porque item de grid
   * não encolhe abaixo do conteúdo sozinho, e o campo furaria a tela. */
  .prefs-linha {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    gap: var(--s3);
    margin-top: var(--s3);
  }
  .prefs-linha .fld {
    min-width: 0;
  }
  /* O `select` não estica sozinho dentro do grid: sem isto ele encolhia até o
   * texto e ficava do tamanho de metade do campo ao lado. */
  .prefs-linha select,
  .prefs-linha input {
    width: 100%;
    min-height: var(--tap);
    /* 16px é PISO: abaixo disso o Safari do iOS dá zoom ao focar. */
    font-size: var(--t-md);
    padding: 0 var(--s2);
    border: 1px solid var(--line-2);
    border-radius: var(--r);
    background: var(--surface);
    color: var(--ink);
  }
  .prefs-devs {
    margin: var(--s4) 0 var(--s3);
    padding: 0;
    border: 0;
    display: grid;
    gap: var(--s1);
  }

  /* ------------------------------------------------ busca e filtro da carteira */

  .filtros {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s2);
    margin-bottom: var(--s4);
  }
  /* A busca fica larga e o filtro acompanha o conteúdo; em tela estreita o
   * filtro cai para a linha de baixo em vez de espremer o campo. */
  .filtros .busca {
    position: relative;
    flex: 1 1 12rem;
    display: flex;
    align-items: center;
  }
  .busca-lupa {
    position: absolute;
    left: var(--s3);
    color: var(--slate-2);
    pointer-events: none;
  }
  .filtros .busca input {
    width: 100%;
    /* 16px é PISO: abaixo disso o Safari do iOS dá zoom ao focar, e o layout
     * salta na mão do corretor. */
    font-size: var(--t-md);
    min-height: var(--tap);
    padding: 0 var(--s3) 0 calc(var(--s3) * 2 + 18px);
    border: 1px solid var(--line-2);
    border-radius: var(--r);
    background: var(--surface);
    color: var(--ink);
  }
  .filtros .busca input:focus {
    border-color: var(--blue);
  }

  /* Os tres seletores numa linha que quebra: em 390px eles empilham em vez de
   * espremer, e `min-width: 0` porque item de grid nao encolhe abaixo do
   * conteudo sozinho — sem ele o select furaria a tela. */
  .filtro-linha {
    flex: 1 1 100%;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
    gap: var(--s2);
  }
  .filtro-linha .fld {
    min-width: 0;
  }
  /* Um seletor sozinho fica AO LADO da busca, e não numa linha só dele: uma
   * linha inteira para quatro palavras parece sobra de layout. Em tela estreita
   * ele cai para baixo e ocupa a largura toda, como os outros. */
  .filtros > .fld {
    flex: 1 1 14rem;
    min-width: 0;
    /* Sem a margem que `.fld` traz para formulário empilhado: aqui os itens
     * esticam na altura da linha, e a margem embaixo sobe o seletor — era o
     * que o deixava desalinhado com a busca ao lado. */
    margin-bottom: 0;
  }
  .filtro-linha select,
  .filtros > .fld select {
    width: 100%;
    min-height: var(--tap);
    /* 16px e PISO: abaixo disso o Safari do iOS da zoom ao focar. */
    font-size: var(--t-md);
    padding: 0 var(--s2);
    border: 1px solid var(--line-2);
    border-radius: var(--r);
    background: var(--surface);
    color: var(--ink);
  }

  .filtro-chip {
    min-height: var(--tap);
    display: inline-flex;
    align-items: center;
    gap: var(--s2);
    padding: 0 var(--s4);
    border: 1px solid var(--line-2);
    border-radius: var(--r-pill);
    background: var(--surface);
    color: var(--slate);
    font: 500 var(--t-sm) / 1 var(--sans);
    cursor: pointer;
  }
  .filtro-chip span {
    font-weight: 700;
    color: var(--ink);
  }
  /* Ligado é estado, não decoração: cor E a borda mais forte, porque cor
   * sozinha não serve a quem não a distingue. */
  .filtro-chip[aria-pressed="true"] {
    background: var(--blue);
    border-color: var(--blue-ink);
    color: #fff;
  }
  .filtro-chip[aria-pressed="true"] span {
    color: #fff;
  }

  /* A troca entre os dois funis. São links e não botões: cada funil é uma URL,
   * e o F5 e o botão voltar precisam devolver o funil em que se estava. */
  .funil-troca {
    display: flex;
    gap: var(--s2);
    margin-bottom: var(--s4);
  }
  .funil-troca a {
    flex: 1;
    min-height: var(--tap);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0 var(--s3);
    border: 1px solid var(--line-2);
    border-radius: var(--r-pill);
    background: var(--surface);
    color: var(--slate);
    font: 500 var(--t-sm) / 1 var(--sans);
    text-decoration: none;
  }
  /* Selecionado é estado, não decoração: cor E borda mais forte, porque cor
   * sozinha não serve a quem não a distingue. */
  .funil-troca a[aria-current="true"] {
    background: var(--blue);
    border-color: var(--blue-ink);
    color: #fff;
  }

  /* Mudança de etapa: contexto entre as conversas, não uma conversa. Fica sem
   * o cartão e em cinza, para a Timeline continuar sendo lida como a sequência
   * de contatos com o cliente — que é o que ela é. */
  .tl-item[data-stage] {
    background: none;
    border: 0;
    padding-left: 0;
  }
  .tl-item[data-stage] .tl-label,
  .tl-item[data-stage] .tl-autor {
    color: var(--slate);
    font-weight: 400;
  }

  /* ------------------------------------------------------------- anexos */

  .anexo-lista {
    list-style: none;
    margin: 0 0 var(--s2);
    padding: 0;
    display: grid;
    gap: var(--s1);
  }
  /* Uma coluna só, empilhada: o formulário de remover é uma gaveta como a do
   * perdão e a da devolução. Nada de `display: contents` para tirar o
   * `<details>` de uma grade — é frágil entre navegadores e já me custou uma
   * correção no lápis dos empreendimentos. */
  .anexo {
    display: grid;
    gap: 2px;
    padding: var(--s2) var(--s3);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r);
  }
  .anexo-nome {
    font-size: var(--t-sm);
    color: var(--blue-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .anexo-meta {
    font-size: var(--t-xs);
    color: var(--slate);
  }
  /* Remover é irreversível, e o vermelho é a cor reservada a isso na ficha —
   * em cinza ele parecia rotina. Texto e não caixa, porque a caixa vermelha é
   * do Descartar, que custa o lead inteiro. Alvo de 44px porque o corretor
   * mexe nisto no celular. */
  .anexo-tirar > summary {
    display: inline-flex;
    align-items: center;
    gap: var(--s2);
    min-height: var(--tap);
    color: var(--crit);
    font-size: var(--t-xs);
    cursor: pointer;
  }
  .anexo-tirar form {
    display: grid;
    gap: var(--s2);
    padding-bottom: var(--s2);
  }
  .anexo-tirar input[type="text"] {
    width: 100%;
    min-height: var(--tap);
    /* 16px é PISO: abaixo disso o Safari do iOS dá zoom ao focar. */
    font-size: var(--t-md);
    padding: 0 var(--s2);
    border: 1px solid var(--line-2);
    border-radius: var(--r);
    background: var(--surface);
    color: var(--ink);
  }

  /* ------------------------------------------------- histórico do núcleo */

  /* Fechado por padrão: aberto, ele empurraria Aceitar e Recusar para fora da
   * tela num celular, com 30 minutos correndo. A setinha diz que abre. */
  .hist {
    margin: var(--s3) 0;
    border-top: 1px solid var(--line);
    padding-top: var(--s2);
  }
  /* A seta é a do `summary::after` global, desenhada com borda. Esta regra já
   * tentou redesenhá-la com o caractere "▾" e saiu torta: a fonte não tem o
   * glifo e o navegador caiu num substituto. O comentário daquela regra avisa
   * exatamente isto — uma regra só, e toda gaveta se comporta igual. */
  .hist > summary {
    cursor: pointer;
    min-height: var(--tap);
    display: flex;
    align-items: center;
    gap: var(--s2);
    font-size: var(--t-sm);
    color: var(--slate);
  }
  .hist-lista {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--s3);
  }
  .hist-item {
    border-left: 2px solid var(--line-2);
    padding-left: var(--s3);
  }
  .hist-cab {
    display: flex;
    justify-content: space-between;
    gap: var(--s2);
    margin: 0;
    font-size: var(--t-sm);
  }
  .hist-quando {
    color: var(--slate-2);
    font-size: var(--t-xs);
    white-space: nowrap;
  }
  .hist-motivo,
  .hist-vazio {
    margin: 0 0 var(--s2);
    font-size: var(--t-micro);
    color: var(--slate-2);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-family: var(--mono);
  }
  .hist-motivo {
    margin-bottom: var(--s1);
  }
  /* Texto do corretor, não rótulo: sem maiúscula e sem mono, como a nota. */
  .hist-descarte {
    margin: 0 0 var(--s2);
    font-size: var(--t-xs);
    color: var(--ink);
  }
  .hist-tl {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--s2);
  }
  .hist-tl > li {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 0 var(--s2);
    font-size: var(--t-xs);
  }
  /* "Sem contato hoje" cumpre a obrigação das 12h e NÃO é contato com o
   * cliente. Com o mesmo peso, o histórico pareceria mais movimentado do que
   * foi — e é sobre isso que o corretor está decidindo. */
  .hist-tl > li[data-followup] {
    opacity: 0.65;
  }
  .hist-data {
    color: var(--slate-2);
    font-family: var(--mono);
  }
  .hist-tipo {
    font-weight: 600;
  }
  .hist-nota {
    grid-column: 2;
    color: var(--slate);
  }

  .paginacao {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--s2);
    margin-top: var(--s4);
  }
  /* O número da página no meio, mesmo quando só um dos botões existe: sem isto
   * ele gruda no botão único e some entre a primeira página e a última. */
  .paginacao-n {
    order: 1;
    flex: 1;
    text-align: center;
    font-size: var(--t-xs);
    color: var(--slate-2);
  }
  .paginacao a[rel="prev"] {
    order: 0;
  }
  .paginacao a[rel="next"] {
    order: 2;
  }

  /* -------------------------------------------------------------- situação */

  /* A seção espaça os próprios filhos, em vez de cada bloco trazer a própria
   * margem: assim o botão seguinte nasce com o respiro certo sem ninguém
   * lembrar. Foi o que faltou quando "Enviar ao administrativo" e "Devolver ao
   * corretor" entraram e ficaram colados na lista de etapas. */
  .situacao {
    display: grid;
    gap: var(--s4);
  }
  .etapas-lista {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s1);
    margin-top: var(--s2);
  }
  /* Cada etapa é um botão de submit com o próprio `value`: um clique, uma
   * mudança, sem select intermediário nem confirmação. */
  .etapa {
    display: inline-flex;
    align-items: center;
    gap: var(--s1);
    min-height: 34px;
    padding: 0 var(--s2);
    border: 1px solid var(--line-2);
    border-radius: var(--r-pill);
    background: var(--surface);
    color: var(--slate);
    font-size: var(--t-xs);
    cursor: pointer;
  }
  .etapa:hover:not(:disabled) {
    border-color: var(--blue);
    color: var(--blue);
  }
  .etapa[aria-current="step"] {
    background: var(--blue);
    border-color: var(--blue);
    color: #fff;
    opacity: 1;
    cursor: default;
  }
  .etapa-n {
    font-family: var(--mono);
    font-size: var(--t-micro);
    opacity: 0.7;
  }

  /* Descartar fica fechado: é irreversível e não deve estar a um toque de
   * distância de quem só queria mudar de etapa. */
  /* O <summary> é o botão. Descartar libera a posse em qualquer etapa e é
   * irreversível — em cinza miúdo ele não parecia o que é. */
  .descarte summary {
    gap: var(--s2);
  }
  /* Fecha a seção, com um respiro a mais que o das ações de rotina: o
   * irreversível não divide linha nem ritmo com o que se faz todo dia. */
  .descarte {
    margin-top: var(--s2);
    justify-self: start;
  }
  .descarte form {
    padding-top: var(--s2);
  }
  /* O nome é histórico: `.descarte` virou o botão que abre um formulário curto
   * ali mesmo, e o funil do Gestor o usa também para qualificar. Renomear
   * atravessaria a ficha do corretor, que não é assunto desta tela. */
  .descarte input[type="text"],
  .descarte textarea {
    width: 100%;
    padding: var(--s3);
    border: 1px solid var(--line-2);
    border-radius: var(--r);
    font: inherit;
  }
  .descarte textarea {
    resize: vertical;
  }

  /* ------------------------------------------------------------- registro */

  .registro select,
  .registro textarea {
    width: 100%;
    padding: var(--s3);
    border: 1px solid var(--line-2);
    border-radius: var(--r);
    background: var(--surface);
  }
  .registro textarea {
    resize: vertical;
  }
  /* O <summary> É o botão: um clique abre o formulário, sem um botão a mais
   * para a mesma ação. */
  .registro-novo[open] > summary {
    margin-bottom: var(--s3);
    /* Aberto, o botão vira neutro e o único primário da seção passa a ser
     * "Registrar": dois azuis cheios um em cima do outro disputavam o toque. */
    background: var(--surface);
    border-color: var(--line-2);
    color: inherit;
  }
  .registro-form {
    display: grid;
    gap: var(--s3);
  }

  /* O "sem contato hoje" é separado por uma linha, não só por espaço: ele não é
   * um nono tipo de interação, e na tela também não pode parecer um. */
  .registro-followup {
    margin-top: var(--s4);
    padding-top: var(--s3);
    border-top: 1px dashed var(--line-2);
  }

  /* ------------------------------------------------------- cadastro */

  .sonda {
    max-width: 22rem;
    margin-bottom: var(--s5);
  }
  /* A linha inteira é o alvo, não só o quadradinho de 13px do navegador. */
  .caixa {
    display: flex;
    align-items: center;
    gap: var(--s2);
    min-height: var(--tap);
    margin-bottom: var(--s3);
    cursor: pointer;
    font-size: var(--t-sm);
  }
  .caixa input {
    width: 18px;
    height: 18px;
    accent-color: var(--blue);
  }
  /* A lista de pré-lançamentos só aparece com a caixa marcada. Em CSS e não em
   * JavaScript porque o servidor decide pela caixa: o seletor escondido até
   * envia o valor, e ele é ignorado enquanto a caixa estiver desmarcada. */
  .caixa:has(input[name="pre_lancamento"]:not(:checked)) + .pre-opcoes {
    display: none;
  }
  .pre-opcoes select {
    width: 100%;
    min-height: var(--tap);
    /* 16px é PISO: abaixo disso o Safari do iOS dá zoom ao focar. */
    font-size: var(--t-md);
    padding: 0 var(--s2);
    border: 1px solid var(--line-2);
    border-radius: var(--r);
    background: var(--surface);
    color: var(--ink);
  }

  /* As três respostas se distinguem pela faixa à esquerda, não só pelo texto:
   * a decisão é lida de relance, no stand, com o cliente esperando. */
  .veredito {
    padding: var(--s4);
    background: var(--surface);
    border: 1px solid var(--line);
    border-left: 4px solid var(--slate-2);
    border-radius: var(--r);
    max-width: 30rem;
  }
  .veredito[data-outcome="new"] {
    border-left-color: var(--ok);
  }
  .veredito[data-outcome="free"] {
    border-left-color: var(--blue);
  }
  .veredito[data-outcome="blocked"] {
    border-left-color: var(--crit);
    background: var(--crit-soft);
  }
  .veredito h2 {
    margin: var(--s1) 0 var(--s2);
    font-family: var(--serif);
    font-size: var(--t-lg);
  }
  .veredito-txt {
    margin: 0 0 var(--s2);
    font-size: var(--t-sm);
  }
  .veredito form {
    margin-top: var(--s4);
  }

  /* ------------------------------------------------------------- timeline */

  .tl {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--s2);
  }
  .tl-item {
    padding: var(--s3);
    background: var(--surface);
    border: 1px solid var(--line);
    border-left: 3px solid var(--blue);
    border-radius: var(--r);
  }
  /* O acompanhamento é visualmente outra coisa. Se parecesse interação, sumiria
   * a distinção entre falei e não falei com o cliente — que é a regra inteira. */
  .tl-item[data-followup] {
    background: var(--surface-2);
    border-left-style: dashed;
    border-left-color: var(--line-2);
  }
  .tl-cab {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--s2);
  }
  .tl-label {
    font-weight: 600;
    font-size: var(--t-sm);
  }
  .tl-quando {
    margin-left: auto;
    font-family: var(--mono);
    font-size: var(--t-micro);
    color: var(--slate-2);
  }
  .tl-nota {
    margin: var(--s2) 0 0;
    font-size: var(--t-sm);
    white-space: pre-wrap;
  }
  .tl-pe {
    display: flex;
    align-items: center;
    gap: var(--s3);
    margin-top: var(--s2);
  }
  .tl-autor {
    font-size: var(--t-micro);
    color: var(--slate-2);
    text-transform: uppercase;
    letter-spacing: 0.06em;
  }
  .tl-editar {
    margin-left: auto;
    min-height: var(--tap);
    padding: 0 var(--s2);
    border: 0;
    background: none;
    color: var(--blue);
    font-size: var(--t-xs);
    cursor: pointer;
  }
  .tl-form {
    display: grid;
    gap: var(--s2);
    margin-top: var(--s2);
  }
  .tl-form textarea {
    width: 100%;
    padding: var(--s2);
    border: 1px solid var(--line-2);
    border-radius: var(--r);
  }

  /* A confirmação do sistema. */
  .dialogo {
    max-width: min(26rem, calc(100vw - 2 * var(--s4)));
    padding: var(--s5);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    background: var(--surface);
    color: var(--ink);
    box-shadow: var(--sh);
  }
  .dialogo::backdrop {
    background: rgba(17, 30, 46, 0.45);
  }
  .dialogo p {
    margin: 0 0 var(--s5);
    font-size: var(--t);
  }
  .dialogo-acoes {
    display: flex;
    justify-content: flex-end;
    gap: var(--s2);
  }

  /* Barra de progresso global. É o que faz o 4G suportável. */
  #progresso {
    position: fixed;
    inset: 0 auto auto 0;
    height: 2px;
    width: 0;
    background: var(--blue);
    z-index: 90;
    transition: width 0.2s ease;
  }
  #progresso[data-on] {
    width: 70%;
  }

  /* ------------------------------------------------ panorama do Administrador */

  /* Quatro cartoes, cada um uma pergunta. O cartao e o que separa as secoes:
     fundo branco sobre o papel, borda fina, cabecalho proprio. Sem ele a tela
     era uma coluna de rotulos que se lia como uma lista so. */
  .panorama {
    display: grid;
    gap: var(--s5);
  }
  .panorama-cab {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--s2) var(--s4);
  }
  .panorama-quando {
    margin: 0;
    font-size: var(--t-sm);
    color: var(--slate);
  }
  .panorama-corpo {
    display: grid;
    gap: var(--s5);
  }
  .panorama-pe {
    margin: 0;
    font: 500 var(--t-micro) / 1.3 var(--mono);
    color: var(--slate-2);
    text-align: right;
  }

  /* Os numeros do mes: um cartao por indicador, numero grande em serifa, e o
     delta contra o mesmo periodo do mes anterior — a cor segue o SENTIDO do
     numero, nao o sinal: perdido a menos e verde. */
  .kpis {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--s3);
  }
  .kpi {
    padding: var(--s4);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    min-width: 0;
  }
  .kpi-rotulo {
    margin: 0;
    font-size: var(--t-sm);
    color: var(--slate);
  }
  .kpi-valor {
    margin: var(--s1) 0 0;
    font-family: var(--serif);
    font-size: 2.2rem;
    font-weight: 600;
    line-height: 1.1;
    letter-spacing: -0.01em;
  }
  .kpi-nota {
    margin: var(--s2) 0 0;
    font-size: var(--t-xs);
    color: var(--slate);
  }
  .kpi-delta {
    font-family: var(--mono);
    font-weight: 600;
  }
  .kpi-delta[data-sentido="bom"] {
    color: var(--ok);
  }
  .kpi-delta[data-sentido="ruim"] {
    color: var(--crit);
  }

  .panorama-grade {
    display: grid;
    gap: var(--s4);
  }

  .cartao {
    padding: var(--s4);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    min-width: 0;
  }
  .cartao-cab {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--s1) var(--s3);
    margin-bottom: var(--s4);
    padding-bottom: var(--s3);
    border-bottom: 1px solid var(--line);
  }
  .cartao-cab h2 {
    font-size: var(--t-lg);
  }
  .cartao-periodo {
    margin: 0;
    font-size: var(--t-xs);
    color: var(--slate);
  }
  .cartao-sub {
    margin: var(--s5) 0 var(--s2);
    font: 500 var(--t-micro) / 1.3 var(--mono);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--slate-2);
  }
  .cartao-vazio {
    margin: 0;
    padding: var(--s4) 0;
    font-size: var(--t-sm);
    color: var(--slate-2);
  }
  .cartao-pe {
    margin: var(--s4) 0 0;
    font-size: var(--t-sm);
  }
  .cartao-pe a,
  .hoje-nota a {
    display: inline-flex;
    align-items: center;
    min-height: var(--tap);
  }

  /* Colunas dos ultimos dias: uma serie, uma cor, barra de no maximo 24px com
     a ponta arredondada e a base reta. Numero so no maior dia e no de hoje. */
  .colunas {
    list-style: none;
    margin: 0;
    /* O respiro em cima e o numero da barra mais alta: ele senta acima dela. */
    padding: 1.5em 0 0;
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    gap: var(--s1);
    height: 10rem;
    border-bottom: 1px solid var(--line);
  }
  .coluna {
    display: grid;
    grid-template-rows: minmax(0, 1fr) auto;
    justify-items: center;
    min-width: 0;
  }
  .coluna-barra {
    display: block;
    position: relative;
    align-self: end;
    width: 100%;
    max-width: 24px;
    min-height: 2px;
    background: var(--blue-soft);
    border-radius: var(--r) var(--r) 0 0;
  }
  /* Preso a barra, e nao ao topo do cartao: numero longe da coluna e numero
     que se le na coluna errada. */
  .coluna-n {
    position: absolute;
    bottom: 100%;
    left: 50%;
    transform: translateX(-50%);
    margin-bottom: 2px;
    font: 600 var(--t-micro) / 1.3 var(--mono);
    color: var(--slate);
    white-space: nowrap;
  }
  .coluna[data-destaque] .coluna-n {
    color: var(--ink);
  }
  .coluna[data-destaque] .coluna-barra {
    background: var(--blue);
  }
  .coluna-dia {
    padding-top: var(--s1);
    font: 500 var(--t-micro) / 1.3 var(--mono);
    color: var(--slate-2);
    min-height: 1.6em;
  }
  .coluna[data-destaque] .coluna-dia {
    color: var(--ink);
  }

  /* Barras horizontais com nome e numero: origem e etapa do funil. */
  .fatias {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--s2);
  }
  .fatia {
    display: grid;
    grid-template-columns: minmax(0, 9rem) minmax(0, 1fr) 2.5rem;
    align-items: center;
    gap: var(--s3);
    min-height: 1.5rem;
  }
  .fatia-nome {
    font-size: var(--t-sm);
    line-height: 1.2;
  }
  .fatia-trilho {
    display: block;
    height: 10px;
    background: var(--surface-2);
    border-radius: var(--r-xs);
    overflow: hidden;
  }
  .fatia-barra {
    display: block;
    height: 100%;
    background: var(--blue);
    border-radius: 0 var(--r) var(--r) 0;
  }
  .fatia-n {
    font: 600 var(--t-sm) / 1 var(--mono);
    text-align: right;
  }

  /* Hoje: dois blocos lado a lado. */
  .hoje {
    display: grid;
    gap: var(--s4);
  }
  .hoje-rotulo {
    margin: 0;
    font-size: var(--t-sm);
    color: var(--slate);
  }
  .hoje-valor {
    margin: var(--s1) 0 var(--s2);
    font-size: var(--t);
  }
  .hoje-valor b {
    font-family: var(--serif);
    font-size: var(--t-xl);
    font-weight: 600;
  }
  /* Os dois números do "Hoje" também abrem, e também têm 44px. */
  .hoje-valor a,
  .hoje-nota a {
    display: inline-flex;
    align-items: center;
    min-height: var(--tap);
  }
  .hoje-nota {
    margin: var(--s2) 0 0;
    font-size: var(--t-xs);
    color: var(--slate);
  }

  /* Um corretor por vez, ou todos: o seletor mora no cabecalho do cartao. */
  .equipe-seletor {
    display: flex;
    align-items: center;
    gap: var(--s2);
  }
  .equipe-seletor select {
    min-height: var(--tap);
    font-size: var(--t-md);
    padding: 0 var(--s2);
    border: 1px solid var(--line-2);
    border-radius: var(--r);
    background: var(--surface);
    color: var(--ink);
  }

  /* A ficha de um corretor: os mesmos numeros da tabela, grandes e com o
     rotulo por extenso — e nada em volta. */
  .ficha-corretor-nome {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s3);
    margin: 0 0 var(--s3);
    font-size: var(--t-lg);
    font-weight: 600;
  }
  .ficha-corretor-nome a {
    display: inline-flex;
    align-items: center;
    min-height: var(--tap);
    color: var(--ink);
  }
  .ficha-corretor-nome a:hover {
    color: var(--blue);
  }
  .ficha-numeros {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--s3);
    margin: 0;
  }
  .ficha-numeros > div {
    padding: var(--s3);
    background: var(--surface-2);
    border-radius: var(--r);
    min-width: 0;
  }
  .ficha-numeros dt {
    font-size: var(--t-sm);
    color: var(--slate);
  }
  .ficha-numeros dd {
    margin: var(--s1) 0 0;
    font-family: var(--serif);
    font-size: var(--t-xl);
    font-weight: 600;
    line-height: 1.1;
  }
  .ficha-numeros dd.ficha-nota {
    font-family: var(--sans);
    font-size: var(--t-xs);
    font-weight: 400;
    color: var(--slate);
  }
  .ficha-numeros > div[data-tom="warn"] dd:not(.ficha-nota) {
    color: var(--warn);
  }

  /* A equipe. Abaixo de 45rem a tabela vira uma pilha de cartoes: cada linha e
     um bloco, e cada celula carrega o proprio rotulo por data-rot. */
  .equipe {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--t-sm);
  }
  .equipe thead {
    display: none;
  }
  .equipe tbody {
    display: block;
  }
  .equipe tr {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--s2) var(--s3);
    padding: var(--s3) 0;
    border-bottom: 1px solid var(--line);
  }
  .equipe tr:last-child {
    border-bottom: 0;
  }
  .equipe th[scope="row"] {
    grid-column: 1 / -1;
    text-align: left;
    font-weight: 600;
  }
  .equipe th[scope="row"] a {
    display: inline-flex;
    align-items: center;
    min-height: var(--tap);
    color: var(--ink);
  }
  .equipe th[scope="row"] a:hover {
    color: var(--blue);
  }
  .equipe td {
    display: block;
    min-width: 0;
  }
  .equipe td::before {
    content: attr(data-rot);
    display: block;
    font: 500 var(--t-micro) / 1.3 var(--mono);
    color: var(--slate-2);
  }
  .equipe td small {
    display: block;
    font-size: var(--t-micro);
    color: var(--slate);
  }
  .equipe td[data-tom="warn"] {
    color: var(--warn);
    font-weight: 600;
  }

  @media (min-width: 45rem) {
    .kpis {
      grid-template-columns: repeat(4, minmax(0, 1fr));
    }
    .hoje {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
    .ficha-numeros {
      grid-template-columns: repeat(4, minmax(0, 1fr));
    }
    .fatia {
      grid-template-columns: minmax(0, 12rem) minmax(0, 1fr) 2.5rem;
    }
    .equipe thead {
      display: table-header-group;
    }
    .equipe tbody {
      display: table-row-group;
    }
    .equipe tr {
      display: table-row;
      padding: 0;
    }
    .equipe th,
    .equipe td {
      display: table-cell;
      padding: var(--s2) var(--s2);
      border-bottom: 1px solid var(--line);
      vertical-align: middle;
    }
    .equipe thead th {
      padding-bottom: var(--s2);
      font: 500 var(--t-micro) / 1.3 var(--mono);
      letter-spacing: 0.06em;
      text-transform: uppercase;
      color: var(--slate-2);
      text-align: left;
      border-bottom: 1px solid var(--line-2);
    }
    .equipe th[scope="row"] {
      padding-left: 0;
    }
    .equipe td::before {
      display: none;
    }
    .equipe .u-num {
      text-align: right;
    }
    .equipe tr:last-child th,
    .equipe tr:last-child td {
      border-bottom: 0;
    }
  }

  .panorama-coluna {
    display: grid;
    gap: var(--s4);
    align-content: start;
  }

  @media (min-width: 68.75rem) {
    .panorama-grade {
      grid-template-columns: repeat(2, minmax(0, 1fr));
      align-items: start;
    }
    .cartao-largo {
      grid-column: 1 / -1;
    }
  }
  /* --------------------------------------- o que abre: alvos, gaveta, leituras */

  /* Tudo que é número vira <a>. O alvo herda a caixa do que ele embrulha — a
     barra, a coluna, o valor — e o sinal de "isto abre" é o sublinhado no hover
     mais o anel de foco global, não uma cor nova. */
  .kpi-valor,
  .fatia-alvo,
  .coluna-alvo,
  .leitura-valor {
    color: inherit;
  }
  a.kpi-valor:hover,
  .fatia-alvo:hover .fatia-nome,
  .leitura-valor:hover {
    color: var(--blue);
  }
  a.kpi-valor[aria-current="true"],
  .leitura-valor[aria-current="true"] {
    color: var(--blue);
  }
  /* Alvo de 44px em tudo que abre, inclusive no que é texto no meio de uma
     frase: a regra do projeto não abre exceção para link pequeno, e é no
     celular que esta tela é consultada de pé. */
  .kpi-valor,
  a.kpi-valor {
    display: inline-flex;
    align-items: center;
    min-height: var(--tap);
  }
  .kpi-nota a,
  .aviso a {
    display: inline-flex;
    align-items: center;
    min-height: var(--tap);
    color: var(--slate);
    text-decoration: underline;
    text-underline-offset: 2px;
  }
  .aviso a {
    color: inherit;
  }
  .kpi-nota a:hover {
    color: var(--blue);
  }
  .leitura-valor {
    display: inline-flex;
    align-items: center;
    min-height: var(--tap);
  }

  /* A barra inteira é o alvo: a linha toda, e não só o nome. */
  .fatia-alvo {
    display: grid;
    grid-template-columns: subgrid;
    grid-column: 1 / -1;
    align-items: center;
    gap: var(--s3);
    min-height: var(--tap);
  }
  .fatia-alvo[aria-current="true"] .fatia-barra {
    background: var(--blue-ink);
  }
  .fatia-alvo:hover .fatia-trilho {
    background: var(--blue-soft);
  }

  /* A coluna do gráfico: o alvo cobre barra e rótulo, com 44px de altura
     garantidos pela própria altura do gráfico. */
  .coluna-alvo {
    display: grid;
    grid-template-rows: minmax(0, 1fr) auto;
    justify-items: center;
    height: 100%;
    min-width: 0;
  }
  .coluna-alvo:hover .coluna-barra,
  .coluna[data-aberta] .coluna-barra {
    background: var(--blue-ink);
  }
  .coluna[data-aberta] .coluna-dia {
    color: var(--blue);
    font-weight: 600;
  }

  /* As leituras derivadas: valor grande, nota curta dizendo de onde ele sai. */
  .leituras {
    display: grid;
    gap: var(--s5);
  }
  .leitura-bloco {
    min-width: 0;
  }
  .leitura-bloco > .cartao-sub:first-child {
    margin-top: 0;
  }
  .leituras-lista {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--s2);
  }
  .leitura {
    display: grid;
    grid-template-columns: minmax(4.5rem, auto) minmax(0, 1fr);
    align-items: baseline;
    gap: var(--s3);
    min-height: var(--tap);
  }
  .leitura-valor {
    font-family: var(--serif);
    font-size: var(--t-xl);
    font-weight: 600;
    line-height: 1.1;
  }
  .leitura-valor [data-sentido="bom"] {
    color: var(--ok);
  }
  .leitura-valor [data-sentido="ruim"],
  .leitura-valor[data-sentido="ruim"] {
    color: var(--crit);
  }
  .leitura-nota {
    font-size: var(--t-xs);
    color: var(--slate);
  }
  /* Amostra pequena não vira conclusão: o número fica cinza e a nota diz por
     quê. Apagar o cartão esconderia que existe dado; deixá-lo colorido faria
     dois casos parecerem tendência. */
  .leitura[data-sem-base] .leitura-valor {
    color: var(--slate-2);
    font-family: var(--sans);
    font-size: var(--t);
  }

  /* A gaveta do detalhe. Abre ABAIXO, na própria tela, e uma por vez. */
  .gaveta {
    padding: var(--s4);
    background: var(--surface);
    border: 1px solid var(--line-2);
    border-left: 3px solid var(--blue);
    border-radius: var(--r-lg);
  }
  .gaveta-fechar {
    display: inline-flex;
    align-items: center;
    min-height: var(--tap);
    font-size: var(--t-sm);
  }
  .itens {
    list-style: none;
    margin: 0;
    padding: 0;
  }
  /* Linha de detalhe: nome, o que importa naquela pergunta, e o número à
     direita. Sempre <a> quando há ficha para abrir — clique do meio e voltar
     funcionam, como no cartão de lead. */
  .item {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 0 var(--s3);
    align-items: baseline;
    min-height: var(--tap);
    padding: var(--s2) var(--s1);
    border-bottom: 1px solid var(--line);
    color: var(--ink);
  }
  .itens > li:last-child > .item {
    border-bottom: 0;
  }
  a.item:hover {
    background: var(--surface-2);
  }
  .item-nome {
    font-size: var(--t-sm);
    font-weight: 600;
  }
  .item-meta {
    grid-column: 1 / -1;
    font-size: var(--t-xs);
    color: var(--slate);
  }
  .item-dir {
    font-family: var(--mono);
    font-size: var(--t-sm);
    font-weight: 600;
    color: var(--slate);
  }

  /* As janelas do gráfico: três alvos curtos no cabeçalho do cartão. */
  .janelas {
    display: flex;
    gap: var(--s1);
    margin: 0;
  }
  .janelas a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: var(--tap);
    min-height: var(--tap);
    font: 500 var(--t-xs) / 1 var(--mono);
    color: var(--slate);
    border-radius: var(--r);
  }
  .janelas a:hover {
    background: var(--surface-2);
    color: var(--blue);
  }
  .janelas a[aria-current="true"] {
    background: var(--blue-soft);
    color: var(--blue);
    font-weight: 600;
  }

  @media (min-width: 45rem) {
    .leituras {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
  }

  @media (min-width: 68.75rem) {
    .leituras {
      grid-template-columns: repeat(4, minmax(0, 1fr));
    }
  }

}

@layer utilitarios {
  .u-mono {
    font-family: var(--mono);
  }
  .u-tnum {
    font-variant-numeric: tabular-nums;
  }
  .u-oculto {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .pular {
    position: absolute;
    left: -9999px;
  }
  .pular:focus {
    left: var(--s3);
    top: var(--s3);
    z-index: 99;
    background: var(--surface);
    padding: var(--s2) var(--s3);
    border-radius: var(--r);
  }
}

@layer estado {
  /* O atributo `hidden` vence qualquer `display` declarado por classe.
   *
   * Isto é correção de um defeito real: `.tl-form { display: grid }` derrotava
   * o `hidden` do formulário de corrigir nota — o `display:none` do navegador
   * vem da folha do agente do usuário, que perde para qualquer regra de autor.
   * O campo de edição aparecia aberto assim que a interação era salva.
   *
   * Como regra geral vale mais que o conserto pontual: qualquer elemento que
   * este projeto esconda com `el.hidden` fica escondido, sem depender de quem
   * escreveu a classe lembrar disso. */
  [hidden] {
    display: none !important;
  }

  /* O atraso de 150ms é o truque: request rápido não pisca nada. */
  .htmx-request {
    opacity: 0.55;
    pointer-events: none;
  }
  .htmx-request {
    transition: opacity var(--dur) 150ms;
  }

  @media (prefers-reduced-motion: reduce) {
    .bar i,
    #progresso,
    .htmx-request,
    summary::after {
      transition: none;
    }
  }
}
