@charset "UTF-8";

/* =============================================================================
   ReduzziHub — folha de estilo única

   01  Tipografia local            08  Cartões e painéis
   02  Tokens                      09  Botões
   03  Reinício e base             10  Campos de formulário
   04  Estrutura da aplicação      11  Janela modal
   05  Barra superior              12  Telas de acesso
   06  Navegação lateral           13  Estados e vazios
   07  Trilha e cabeçalho          14  Rodapé
                                   15  Utilitários
                                   16  Responsividade
                                   17  Movimento, impressão, acessibilidade

   Zero CDN: fontes, ícones e scripts vivem dentro do projeto. O servidor de
   produção pode não ter acesso à internet (CLAUDE.md §16).
   ============================================================================= */


/* =============================================================================
   01 · TIPOGRAFIA LOCAL
   ============================================================================= */

@font-face {
    font-family: 'IBM Plex Sans';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/ibm-plex-sans-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                   U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                   U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'IBM Plex Sans';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/ibm-plex-sans-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                   U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,
                   U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: 'IBM Plex Sans';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('../fonts/ibm-plex-sans-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                   U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                   U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'IBM Plex Sans';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('../fonts/ibm-plex-sans-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                   U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,
                   U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: 'IBM Plex Sans';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('../fonts/ibm-plex-sans-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                   U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                   U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'IBM Plex Sans';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('../fonts/ibm-plex-sans-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                   U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,
                   U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'IBM Plex Sans Condensed';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('../fonts/ibm-plex-condensed-600-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                   U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                   U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'IBM Plex Sans Condensed';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('../fonts/ibm-plex-condensed-600-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                   U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,
                   U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'IBM Plex Mono';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/ibm-plex-mono-400-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                   U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                   U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'IBM Plex Mono';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/ibm-plex-mono-400-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                   U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,
                   U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}


/* =============================================================================
   02 · TOKENS

   O tema claro é a definição base. O tema escuro apenas REDEFINE. Nenhuma cor
   tem sua única definição dentro de um bloco de tema — se tivesse, a tela
   renderizaria o texto de um tema sobre o fundo do outro.

   A cor da ÁREA é um segundo eixo, independente do tema: [data-area] troca
   --marca / --marca-clara / --marca-profunda, e nada mais. É o que faz a
   franquia ser verde, a franqueadora azul e o Light System violeta sem
   duplicar uma linha de componente.
   ============================================================================= */

:root {
    /* ---- Tipografia ---- */
    --fonte-ui:      'IBM Plex Sans', 'Segoe UI', system-ui, -apple-system, sans-serif;
    --fonte-marca:   'IBM Plex Sans Condensed', 'IBM Plex Sans', 'Segoe UI', sans-serif;
    --fonte-mono:    'IBM Plex Mono', 'Cascadia Mono', Consolas, monospace;

    --t-micro:  0.6875rem;  /* 11px — rótulo técnico, cabeçalho de tabela */
    --t-xs:     0.75rem;    /* 12px — texto secundário, legendas */
    --t-sm:     0.8125rem;  /* 13px — corpo padrão do ERP */
    --t-base:   0.875rem;   /* 14px — campos e botões */
    --t-md:     1rem;       /* 16px — título de janela */
    --t-lg:     1.25rem;    /* 20px — título de seção */
    --t-xl:     1.625rem;   /* 26px — título de tela */
    --t-xxl:    2.125rem;   /* 34px — destaque */

    /* ---- Métrica ---- */
    --topo-h:        52px;
    --rodape-h:      44px;
    --trilho-w:      274px;
    --trilho-w-mini: 64px;

    /* Altura de um campo de formulario. Vale para a caixa de texto, para o
       select e para o cartao de marcacao: tudo que ocupa uma celula da grade
       termina na mesma linha de base. Sem um numero unico, cada componente
       chega perto por conta propria e a linha fica com degraus de 1px. */
    --altura-campo: 43px;

    /* Altura de um botao. Menor que a de um campo de proposito: o botao e um
       alvo de clique, e nao uma caixa de digitacao. */
    --altura-botao: 34px;

    --r-sm: 4px;
    --r:    7px;
    --r-lg: 12px;

    --e1:  4px;
    --e2:  8px;
    --e3: 12px;
    --e4: 16px;
    --e5: 24px;
    --e6: 32px;
    --e7: 48px;

    /* A paleta da FRANQUIA (marca e trilho) saiu daqui para o seletor
       `:root, [data-area="franquia"]`, logo antes das outras duas áreas. Ela
       continua sendo o padrão do sistema — o que mudou é que agora também tem
       um seletor próprio, porque o painel de acompanhamento precisa vestir as
       cores da franquia dentro de uma página da franqueadora. */

    /* ---- O chat ----
       Cores do proprio WhatsApp, e nao aproximacoes da nossa paleta. E
       deliberado: esta e a UNICA tela do sistema que imita um aplicativo que o
       usuario ja usa o dia inteiro. Aqui a familiaridade vale mais que a
       identidade -- ninguem precisa aprender a ler uma conversa.
       O resto da tela (cabecalho, lista, campo de envio) continua ReduzziHub. */
    --chat-papel:     #efeae2;   /* o bege atras dos baloes */
    --chat-dele:      #ffffff;   /* recebido */
    --chat-nosso:     #d9fdd3;   /* enviado -- o verde que todo mundo reconhece */
    --chat-hora:      #667781;

    /* ---- Estado ----
       O tom base inverte entre temas; o vestígio, não — ele é alfa e compõe
       corretamente sobre qualquer fundo. */
    --ok:      #15a46f;
    --aviso:   #c4832f;
    --erro:    #b23a2e;
    --info:    #2f7dc9;

    /* ---- Verde de AÇÃO da calculadora ----
       #099250, o verde do InssObra (`--bs-primary` do theme.css dele), dito
       pelo dono com o valor na mão.

       NÃO é `--marca` e não pode ser: desde a troca de paletas a franquia ficou
       AZUL, e a calculadora mora nela. `botao--principal` ali sai azul, que foi
       exatamente o que apareceu na tela. Também não é `--ok` (#15a46f): aquele
       é o verde de ESTADO do sistema, e um dia alguém o ajusta pensando em
       selo de situação, sem imaginar que está repintando os botões da
       calculadora.

       Não inverte no tema escuro: é cor de marca de referência, e não tom
       semântico — mudá-la no escuro faria a tela discordar do sistema que ela
       está copiando. O contraste com branco passa em AA nos dois temas. */
    --acao:        #099250;
    --acao-profunda: #087443;
    /* O vestigio da acao, para fundo de selo. Mesma familia de --marca-vestigio. */
    --acao-vestigio: rgba(9, 146, 80, .13);

    --ok-vestigio:    rgba(21, 164, 111, .12);
    --aviso-vestigio: rgba(196, 131, 47, .12);
    --erro-vestigio:  rgba(178, 58, 46, .12);
    --info-vestigio:  rgba(47, 125, 201, .12);

    /* Tom para uso SOBRE fundo escuro — hoje, o cabeçalho da janela modal.
       Não sai daqui por tema: o cabeçalho é escuro no claro e no escuro, então
       `--erro` do tema claro afundaria nele e o do tema escuro não valeria
       quando a página estivesse clara. Um par próprio resolve os dois casos. */
    --ok-no-escuro:    #35c07a;
    --aviso-no-escuro: #e0a458;
    --erro-no-escuro:  #ec6a63;
    --info-no-escuro:  #58a6e8;

    /* ---- Superfícies ---- */
    --fundo:    #eef1f0;
    --sup:      #ffffff;
    --sup-2:    #f7f9f8;
    --sup-3:    #eef2f0;
    --linha:    #dce3e0;
    --linha-forte: #c4cfca;

    --texto:    #0f1613;
    --texto-2:  #3f4b46;
    --texto-3:  #6c7b74;
    --texto-inv: #ffffff;

    --sombra-1: 0 1px 2px rgba(15, 22, 19, .06), 0 1px 3px rgba(15, 22, 19, .04);
    --sombra-2: 0 2px 4px rgba(15, 22, 19, .06), 0 8px 20px rgba(15, 22, 19, .08);
    --sombra-3: 0 12px 40px rgba(15, 22, 19, .18);

    --transicao: 140ms cubic-bezier(.4, 0, .2, 1);

    color-scheme: light;
}

/* ---- Área: franquia ----

   Ela é o PADRÃO do sistema, e por isso morava solta no `:root`, sem seletor.
   Ganhou um quando o painel de acompanhamento chegou: ali a página é da
   FRANQUEADORA e um pedaço dela — o menu da unidade — tem de vestir as cores
   da franquia. Sem um seletor para pedir, não havia como.

   O `:root` continua no grupo: quem abre o lado da franquia recebe estas cores
   como sempre recebeu, e elas ficam declaradas em UM lugar só.

   TRILHO ESCURO: IDENTIDADE, NÃO SUPERFÍCIE
   Idêntico nos dois temas, de propósito. O menu lateral é a moldura da marca;
   se ele clareasse junto com o resto, o sistema perderia o eixo visual que
   orienta o olho. Os realces são branco translúcido, e não uma cor fixa, para
   funcionarem sobre o topo e sobre a base do gradiente.

   AZUL desde a troca pedida pelo dono: a franquia ficou com o azul que era da
   franqueadora, e a franqueadora com o verde que era daqui. As duas paletas
   trocaram INTEIRAS -- marca, vestígio, trilho e gradiente --, e não só o tom
   principal: metade trocada produziria uma tela azul com o menu ainda
   esverdeado, que é pior que não ter trocado. A Light System não entra na
   troca: continua roxa.

   A ORDEM IMPORTA: este bloco vem ANTES dos das outras duas áreas. As três têm
   a mesma especificidade, e em empate vence quem está por último — invertê-los
   pintaria a franqueadora de azul. */
:root,
[data-area="franquia"] {
    --trilho-grad:     linear-gradient(160deg, #060a0f 0%, #0e1620 52%, #14202e 100%);
    --trilho-bg:       #0e1620;
    --trilho-bg-fundo: #060a0f;
    --trilho-linha:    rgba(255, 255, 255, .075);
    --trilho-hover:    rgba(255, 255, 255, .055);
    --trilho-ativo:    rgba(255, 255, 255, .10);
    --trilho-guia:     rgba(255, 255, 255, .10);
    --trilho-texto:    #a6b4c2;
    --trilho-forte:    #eef2f8;
    --trilho-fraco:    #74818f;

    --marca:           #17568f;
    --marca-clara:     #2e82c9;
    --marca-profunda:  #0e3a63;
    --marca-contraste: #f2f6fa;
    --marca-vestigio:  rgba(46, 130, 201, .12);
    --marca-vestigio-forte: rgba(46, 130, 201, .22);
}

/* ---- Área: franqueadora ---- */
[data-area="franqueadora"] {
    --marca:           #116b5b;
    --marca-clara:     #17b981;
    --marca-profunda:  #0b4a3e;
    --marca-contraste: #f2f5f3;
    --marca-vestigio:  rgba(23, 185, 129, .12);
    --marca-vestigio-forte: rgba(23, 185, 129, .22);
    --trilho-grad:     linear-gradient(160deg, #070c0a 0%, #101a16 52%, #17241f 100%);
    --trilho-bg:       #101a16;
    --trilho-bg-fundo: #070c0a;
    --trilho-texto:    #a8b8b1;
    --trilho-forte:    #eef4f1;
    --trilho-fraco:    #74857d;
}

/* ---- Área: Light System ---- */
[data-area="lightsystem"] {
    --marca:           #5a45a8;
    --marca-clara:     #7e68d6;
    --marca-profunda:  #3b2b75;
    --marca-contraste: #f4f2fb;
    --marca-vestigio:  rgba(126, 104, 214, .13);
    --marca-vestigio-forte: rgba(126, 104, 214, .24);
    --trilho-grad:     linear-gradient(160deg, #08060f 0%, #131020 52%, #1c1830 100%);
    --trilho-bg:       #131020;
    --trilho-bg-fundo: #08060f;
    --trilho-texto:    #aca6c0;
    --trilho-forte:    #f0edf8;
    --trilho-fraco:    #7d768f;
}

/* ---- Tema escuro ---- */
[data-tema="escuro"] {
    --fundo:    #0a0f0d;
    --sup:      #121a17;
    --sup-2:    #16201c;
    --sup-3:    #1c2723;
    --linha:    #223029;
    --linha-forte: #33453c;

    --texto:    #e7efeb;
    --texto-2:  #b2c0ba;
    --texto-3:  #7e8d86;
    --texto-inv: #0a0f0d;

    --ok:    #35c07a;
    --aviso: #e0a458;
    --erro:  #ec6a63;
    --info:  #58a6e8;

    --sombra-1: 0 1px 2px rgba(0, 0, 0, .5);
    --sombra-2: 0 2px 6px rgba(0, 0, 0, .45), 0 12px 28px rgba(0, 0, 0, .4);
    --sombra-3: 0 16px 48px rgba(0, 0, 0, .6);

    /* As do modo escuro do proprio aplicativo. */
    --chat-papel:     #0b141a;
    --chat-dele:      #202c33;
    --chat-nosso:     #005c4b;
    --chat-hora:      #8696a0;

    color-scheme: dark;
}

/* No escuro, a cor da área precisa clarear para manter contraste sobre a
   superfície escura. Só o tom muda; o papel de cada token continua igual. */
[data-tema="escuro"]                        { --marca: #4d97d8; }
[data-tema="escuro"][data-area="franqueadora"] { --marca: #2a9c83; }
[data-tema="escuro"][data-area="lightsystem"]  { --marca: #8e7ae0; }


/* =============================================================================
   03 · REINÍCIO E BASE
   ============================================================================= */

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

html {
    -webkit-text-size-adjust: 100%;
    scrollbar-color: var(--linha-forte) transparent;
}

body {
    margin: 0;
    min-height: 100vh;
    background: var(--fundo);
    color: var(--texto);
    font-family: var(--fonte-ui);
    font-size: var(--t-sm);
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;

    /* Conjuntos alternativos da IBM Plex: cv05 troca o "l" pelo desenho com
       cauda, que deixa de se confundir com "I" e com "1" em codigo e em nome
       proprio; ss03 acerta o desenho das letras acentuadas. E a diferenca
       entre o texto so estar na fonte certa e estar bem definido nela. */
    font-feature-settings: "cv05" 1, "ss03" 1;
    text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, p, figure, ul, ol, dl, dd { margin: 0; }
ul, ol { padding: 0; list-style: none; }

h1, h2, h3, h4 {
    font-weight: 600;
    line-height: 1.2;
    text-wrap: balance;
}

a {
    color: var(--marca);
    text-decoration: none;
    transition: color var(--transicao);
}
a:hover { text-decoration: underline; }

img, svg { display: block; max-width: 100%; }

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

code, kbd, samp, .mono {
    font-family: var(--fonte-mono);
    font-size: .92em;
    font-variant-numeric: tabular-nums;
}

:focus-visible {
    outline: 2px solid var(--marca-clara);
    outline-offset: 2px;
    border-radius: var(--r-sm);
}

::selection {
    background: var(--marca-vestigio-forte);
    color: var(--texto);
}

/* Barras de rolagem discretas, para não competirem com o conteúdo. */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
    background: var(--linha-forte);
    border: 3px solid transparent;
    border-radius: 99px;
    background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover { background-color: var(--texto-3); background-clip: content-box; }


/* =============================================================================
   04 · ESTRUTURA DA APLICAÇÃO

   Grade de duas colunas e três linhas. O trilho ocupa a coluna da esquerda em
   toda a altura; a barra superior e o rodapé ocupam só a coluna do conteúdo.
   Assim o menu não "pula" quando o conteúdo rola.
   ============================================================================= */

.app {
    display: grid;
    grid-template-columns: var(--trilho-w) minmax(0, 1fr);
    grid-template-rows: var(--topo-h) minmax(0, 1fr) var(--rodape-h);
    grid-template-areas:
        "trilho topo"
        "trilho conteudo"
        "trilho rodape";
    min-height: 100vh;
    transition: grid-template-columns var(--transicao);
}

.app[data-trilho="recolhido"] { grid-template-columns: var(--trilho-w-mini) minmax(0, 1fr); }

.app__trilho   { grid-area: trilho; }
.app__topo     { grid-area: topo; }
/* `clip`, e não `hidden`.

   As duas cortam o que passa da largura, mas `hidden` num eixo obriga o OUTRO
   a virar `auto`: com isso este <main> deixava de ser uma caixa comum e virava
   uma CAIXA DE ROLAGEM. E uma caixa de rolagem é justamente o que um
   `position: sticky` lá dentro passa a acompanhar — não mais a janela. Como
   esta caixa tem a altura do próprio conteúdo, ela nunca rola; o sticky nunca
   encontrava o topo dela e ficava parado, com toda a aparência de uma regra
   que ninguém escreveu. Era o Resumo da Proposta, na calculadora.

   `clip` corta sem criar rolagem, e por isso o eixo vertical continua
   `visible`. A declaração antiga fica logo acima como reserva para navegador
   sem `clip`: lá o corte continua valendo, e só o sticky deixa de funcionar. */
.app__conteudo {
    grid-area: conteudo;
    min-width: 0;
    overflow-x: hidden;
    overflow-x: clip;

    /* "Pular para o conteúdo" leva a âncora até o topo da janela — e o topo da
       janela agora tem a barra fixa por cima. Sem esta folga o primeiro título
       da tela chega escondido atrás dela, justo para quem usa teclado ou leitor
       de tela, que é quem usa esse atalho. */
    scroll-margin-top: var(--topo-h);
}
.app__rodape   { grid-area: rodape; }

/* Ocupa a largura inteira, como no Argus.
   Havia aqui um `max-width: 1360px`, e ele estava errado por dois motivos. O
   primeiro é visível: a faixa branca do título não tem limite, então em monitor
   largo o cabeçalho ia até a borda e o conteúdo parava antes, deixando uma
   coluna vazia à direita que parecia defeito. O segundo é que quem decide a
   largura útil é cada tela — o formulário reparte a grade de 12 colunas e a
   tabela rola dentro do próprio painel. Um teto aqui limita as duas de fora,
   sem saber do que se trata. */
.conteudo {
    padding: var(--e5) var(--e5) var(--e6);
}


/* =============================================================================
   05 · BARRA SUPERIOR
   ============================================================================= */

.topo {
    display: flex;
    align-items: center;
    gap: var(--e3);
    height: var(--topo-h);
    padding: 0 var(--e4);
    background: var(--sup);
    border-bottom: 1px solid var(--linha);

    /* FIXA, e não `sticky` — o `sticky` que estava aqui não tinha como
       funcionar um dia sequer.

       Um `position: sticky` só percorre o próprio bloco recipiente, e o desta
       barra é o `.app__topo`: um item de grade da faixa `var(--topo-h)`, da
       exata altura dela. Curso disponível: zero. Rolando 900px, a barra ia para
       -900 junto com a página. A regra existia, parecia certa, e nunca teve
       chance.

       Fixa, ela sai do fluxo — mas nenhum buraco aparece, porque a faixa da
       grade é declarada em `grid-template-rows` e continua reservando os 52px
       mesmo vazia.

       O `left` acompanha o trilho, que muda de largura em três situações, e por
       isso são três valores; a transição é a mesma da grade, senão a barra
       chega ao lugar antes do menu. */
    position: fixed;
    top: 0;
    left: var(--trilho-w);
    right: 0;
    z-index: 40;
    transition: left var(--transicao);
}

.app[data-trilho="recolhido"] .topo { left: var(--trilho-w-mini); }

.topo__botao {
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    flex: 0 0 auto;
    background: none;
    border: 1px solid transparent;
    border-radius: var(--r);
    color: var(--texto-2);
    cursor: pointer;
    transition: background var(--transicao), color var(--transicao), border-color var(--transicao);
}
.topo__botao:hover { background: var(--sup-3); color: var(--texto); }
.topo__botao svg { width: 19px; height: 19px; }

/* O sino só existe quando há algo para ler — ver o comentário no topbar.html.
   Por isso ele não tem estado "vazio": a contagem sempre aparece. */
.topo__sino {
    position: relative;
    text-decoration: none;
}

.topo__sino-conta {
    position: absolute;
    top: -2px;
    right: -2px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    display: grid;
    place-items: center;
    border-radius: 8px;
    background: var(--marca);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    line-height: 1;
}
.topo__botao[hidden] { display: none; }

/* O botão de tema carrega os dois ícones; o CSS decide qual aparece, para que
   a troca não dependa de JavaScript ter rodado. */
.tema-claro  { display: block; }
.tema-escuro { display: none; }
[data-tema="escuro"] .tema-claro  { display: none; }
[data-tema="escuro"] .tema-escuro { display: block; }

.topo__divisor {
    width: 1px;
    height: 22px;
    background: var(--linha);
    flex: 0 0 auto;
}

.topo__etiqueta {
    font-family: var(--fonte-mono);
    font-size: var(--t-micro);
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--marca);
    white-space: nowrap;
}

.topo__espaco { flex: 1 1 auto; }

/* Identificação de quem está usando o sistema */
/* ---- Menu do usuário ----
   O canto direito superior é onde se procura por "minha conta". */
.usuario-menu { position: relative; }

.usuario {
    display: flex;
    align-items: center;
    gap: var(--e2);
    padding: var(--e1) var(--e2) var(--e1) var(--e1);
    background: none;
    border: 1px solid var(--linha);
    border-radius: 99px;
    cursor: pointer;
    max-width: 260px;
    transition: background var(--transicao), border-color var(--transicao);
}
.usuario:hover { background: var(--sup-3); }
.usuario[aria-expanded="true"] { background: var(--sup-3); border-color: var(--linha-forte); }

.usuario__avatar {
    display: grid;
    place-items: center;
    width: 26px;
    height: 26px;
    flex: 0 0 auto;
    border-radius: 50%;
    background: var(--marca);
    color: var(--marca-contraste);
    font-size: var(--t-micro);
    font-weight: 600;
    letter-spacing: .02em;
}
/* Com foto o círculo não é mais um fundo colorido, é a imagem. object-fit
   cobre o círculo inteiro; a imagem já vem quadrada do servidor, então isto é
   só cinto de segurança. */
.usuario__avatar--foto {
    object-fit: cover;
    background: var(--sup-3);
}
.usuario__seta {
    width: 14px;
    height: 14px;
    flex: 0 0 auto;
    color: var(--texto-3);
    transition: transform var(--transicao);
}
.usuario[aria-expanded="true"] .usuario__seta { transform: rotate(180deg); }

/* ---- Painel que abre ---- */
.usuario-painel {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 60;
    min-width: 248px;
    padding: var(--e2);
    background: var(--sup);
    border: 1px solid var(--linha);
    border-radius: var(--r-lg);
    box-shadow: var(--sombra-3);
    animation: usuario-painel 140ms cubic-bezier(.2, .9, .3, 1);
}
.usuario-painel[hidden] { display: none; }

@keyframes usuario-painel {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: none; }
}

/* Repete nome e e-mail: aberto o menu, é bom saber de qual conta se trata —
   ainda mais com as três áreas abertas em abas diferentes. */
.usuario-painel__topo {
    display: flex;
    align-items: center;
    gap: var(--e3);
    padding: var(--e2) var(--e2) var(--e3);
    margin-bottom: var(--e2);
    border-bottom: 1px solid var(--linha);
}
.usuario-painel__foto,
.usuario-painel__iniciais {
    width: 40px;
    height: 40px;
    flex: 0 0 auto;
    border-radius: 50%;
    object-fit: cover;
}
.usuario-painel__iniciais {
    display: grid;
    place-items: center;
    background: var(--marca);
    color: var(--marca-contraste);
    font-size: var(--t-sm);
    font-weight: 600;
}
.usuario-painel__dados {
    display: grid;
    gap: 1px;
    min-width: 0;
}
.usuario-painel__dados strong {
    font-size: var(--t-sm);
    font-weight: 600;
    color: var(--texto);
}
.usuario-painel__dados span {
    font-size: var(--t-micro);
    color: var(--texto-3);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.usuario-painel__item {
    display: flex;
    align-items: center;
    gap: var(--e3);
    width: 100%;
    padding: 8px 10px;
    border: 0;
    border-radius: var(--r);
    background: none;
    color: var(--texto-2);
    font-size: var(--t-sm);
    text-align: left;
    text-decoration: none;
    cursor: pointer;
    transition: background var(--transicao), color var(--transicao);
}
.usuario-painel__item:hover {
    background: var(--sup-3);
    color: var(--texto);
    text-decoration: none;
}
.usuario-painel__item svg { width: 17px; height: 17px; flex: 0 0 auto; color: var(--texto-3); }
.usuario-painel__item:hover svg { color: var(--marca); }

/* A saída fica separada e em cor de erro: é a única do menu que encerra algo. */
.usuario-painel__item--sair { color: var(--erro); }
.usuario-painel__item--sair:hover { background: var(--erro-vestigio); color: var(--erro); }
.usuario-painel__item--sair svg { color: var(--erro); }
.usuario-painel__item--sair:hover svg { color: var(--erro); }
.usuario-painel form {
    margin-top: var(--e2);
    padding-top: var(--e2);
    border-top: 1px solid var(--linha);
}

@media (max-width: 620px) {
    .usuario__nome { display: none; }
    .usuario-painel { min-width: 216px; }
}
.usuario__nome {
    font-size: var(--t-xs);
    font-weight: 500;
    color: var(--texto-2);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Contexto: a rede e a unidade em que a pessoa está */
.contexto {
    display: flex;
    flex-direction: column;
    gap: 1px;
    padding: 0 var(--e3);
    border-left: 1px solid var(--linha);
    max-width: 280px;
}
.contexto__titulo {
    font-size: var(--t-xs);
    font-weight: 600;
    color: var(--texto);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.contexto__rotulo {
    font-family: var(--fonte-mono);
    font-size: 10px;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--texto-3);
}


/* =============================================================================
   06 · NAVEGAÇÃO LATERAL
   ============================================================================= */

.trilho {
    display: flex;
    flex-direction: column;
    height: 100vh;
    position: sticky;
    top: 0;
    background: var(--trilho-bg);
    background-image: var(--trilho-grad);
    color: var(--trilho-texto);
    overflow: hidden;
    z-index: 50;
}

/* ---- Marca ---- */
.marca {
    display: flex;
    align-items: center;
    gap: var(--e2);
    height: var(--topo-h);
    padding: 0 var(--e4);
    flex: 0 0 auto;
    border-bottom: 1px solid var(--trilho-linha);
    background: var(--trilho-bg-fundo);
    color: var(--trilho-forte);
    text-decoration: none;
}
.marca:hover { text-decoration: none; }
.marca__simbolo { width: 26px; height: 26px; flex: 0 0 auto; }
.marca__texto {
    font-family: var(--fonte-marca);
    font-weight: 600;
    font-size: 1.18rem;
    letter-spacing: -.022em;
    white-space: nowrap;
    color: var(--trilho-forte);
}
.marca__texto em { font-style: normal; color: var(--marca-clara); }

/* Light System assina em caixa alta espaçada — outra voz tipográfica, para que
   ninguém confunda as duas marcas nem de relance. */
.marca__texto--sistema {
    text-transform: uppercase;
    font-size: .84rem;
    letter-spacing: .17em;
    font-weight: 600;
}
.marca__texto--sistema em { font-weight: 400; }

/* ---- Itens ---- */
.trilho__corpo {
    flex: 1 1 auto;
    overflow-y: auto;
    overflow-x: hidden;
    padding: var(--e3) var(--e2);
}

.nav__linha {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 8px 10px;
    border: 0;
    border-radius: var(--r);
    background: none;
    color: var(--trilho-texto);
    font-size: var(--t-sm);
    text-align: left;
    text-decoration: none;
    cursor: pointer;
    transition: background var(--transicao), color var(--transicao);
}
.nav__linha:hover { background: var(--trilho-hover); color: var(--trilho-forte); text-decoration: none; }

.nav__linha[aria-current="page"] {
    background: var(--trilho-ativo);
    color: var(--trilho-forte);
    font-weight: 500;
}
/* A barra de cor à esquerda é o único ponto do trilho onde a cor da área
   aparece. É o suficiente para identificar onde se está. */
.nav__linha[aria-current="page"]::before {
    content: "";
    position: absolute;
    left: 0;
    width: 3px;
    height: 20px;
    border-radius: 0 3px 3px 0;
    background: var(--marca-clara);
}
.nav__item { position: relative; }

.nav__icone {
    width: 18px;
    height: 18px;
    flex: 0 0 auto;
    color: var(--trilho-fraco);
    transition: color var(--transicao);
}
.nav__linha:hover .nav__icone,
.nav__linha[aria-current="page"] .nav__icone { color: var(--marca-clara); }

/* ---- Primeiro nível ----
   O item de raiz é um ASSUNTO, e vem em destaque: símbolo na cor da área,
   rótulo um pouco maior e mais pesado. O que está dentro dele é uma tela
   daquele assunto, e vem apagado, com um ponto no lugar do símbolo.

   Sem essa separação o menu inteiro tem o mesmo peso, e a árvore vira uma lista
   comprida onde nada se destaca. O seletor é estrutural — filho direto da lista
   raiz do trilho — porque a marcação não carrega classe de nível. */
.trilho__corpo > ul > .nav__item > .nav__linha {
    font-size: var(--t-base);
    font-weight: 600;
    color: var(--trilho-forte);
}
.trilho__corpo > ul > .nav__item > .nav__linha .nav__icone { color: var(--marca-clara); }

/* ---- Ponto dos itens de dentro ----
   Ocupa a mesma faixa que o símbolo ocuparia, para que os rótulos do submenu
   fiquem alinhados entre si. Apagado em repouso; acende no ponteiro e assume a
   cor da área na tela aberta. */
.nav__ponto {
    width: 5px;
    height: 5px;
    flex: 0 0 auto;
    margin: 0 1px 0 6px;
    border-radius: 50%;
    background: currentColor;
    color: var(--trilho-fraco);
    opacity: .55;
    transition: opacity var(--transicao), color var(--transicao);
}
.nav__linha:hover .nav__ponto { opacity: 1; }
.nav__linha[aria-current="page"] .nav__ponto {
    opacity: 1;
    color: var(--marca-clara);
}

.nav__rotulo {
    flex: 1 1 auto;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.nav__seta {
    width: 14px;
    height: 14px;
    flex: 0 0 auto;
    color: var(--trilho-fraco);
    transition: transform var(--transicao);
}
.nav__linha[aria-expanded="true"] .nav__seta { transform: rotate(90deg); }

/* ---- Filhos ---- */
.nav__filhos {
    display: none;
    margin: 2px 0 var(--e2) 20px;
    padding-left: 12px;
    border-left: 1px solid var(--trilho-guia);
}
.nav__filhos[data-aberto="sim"] { display: block; }
.nav__filhos .nav__linha { font-size: var(--t-xs); padding: 6px 10px; }

/* ---- Formulário de ação (saída) ---- */
.nav__acao { display: contents; }

/* ---- Rodapé do trilho ---- */
.trilho__pe {
    flex: 0 0 auto;
    padding: var(--e3) var(--e4);
    border-top: 1px solid var(--trilho-linha);
    font-family: var(--fonte-mono);
    font-size: 10px;
    letter-spacing: .06em;
    color: var(--trilho-fraco);
    white-space: nowrap;
    overflow: hidden;
}

/* ---- Estado recolhido ---- */
.app[data-trilho="recolhido"] .marca__texto,
.app[data-trilho="recolhido"] .nav__rotulo,
.app[data-trilho="recolhido"] .nav__seta,
.app[data-trilho="recolhido"] .trilho__pe,
.app[data-trilho="recolhido"] .nav__filhos { display: none; }

.app[data-trilho="recolhido"] .marca { padding: 0; justify-content: center; }
.app[data-trilho="recolhido"] .nav__linha { justify-content: center; padding: 10px 0; }


/* =============================================================================
   07 · CABEÇALHO DA TELA
   ============================================================================= */

/* ---- Faixa de cabeçalho ----
   Fundo branco, separada do corpo cinza por uma linha, ocupando a largura
   inteira da área de conteúdo. É o recorte do Argus, e ele resolve um problema
   real: o título fica sempre no mesmo lugar, e não some no meio de uma tabela
   longa. */
.pagina-topo {
    padding: var(--e4) var(--e5) var(--e5);
    background: var(--sup);
    border-bottom: 1px solid var(--linha);
}

.pagina-topo__linha {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--e4);
    flex-wrap: wrap;
}

.pagina-topo__acoes { display: flex; gap: var(--e2); align-items: center; }

/* As regras de `.trilha` saíram junto com a trilha de navegação — ver o
   comentário em fragments/pagehead.html. Nada mais no sistema desenha essas
   classes. */

.pagina__titulo {
    font-size: var(--t-xl);
    letter-spacing: -.015em;
    line-height: 1.15;
}

/* Selo de método, dentro do título. Alinhado ao meio da linha do texto, e não à
   base: um selo colado embaixo de um título grande parece ter escorregado. */
.pagina__metodo {
    vertical-align: middle;
    margin-left: var(--e2);
    position: relative;
    top: -2px;
}

.pagina__resumo {
    margin-top: 4px;
    font-size: var(--t-sm);
    color: var(--texto-3);
    max-width: 64ch;
}


/* =============================================================================
   08 · CARTÕES E PAINÉIS
   ============================================================================= */

.grade {
    display: grid;
    gap: var(--e4);
    grid-template-columns: repeat(auto-fit, minmax(232px, 1fr));
}
.grade--larga { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }

.painel {
    background: var(--sup);
    border: 1px solid var(--linha);
    border-radius: var(--r-lg);
    box-shadow: var(--sombra-1);
    /* Corta o canto quadrado da tabela que encosta na borda do cartao. */
    overflow: hidden;
}

/* Cartao de formulario: nao corta. Um seletor que abre painel -- a escolha de
   icone -- precisa transbordar o cartao, e sem isto a grade aparece cortada na
   borda de baixo. Aqui nao ha tabela encostando na borda, entao nada se perde. */
.painel--formulario { overflow: visible; }

/* ---- Cartões empilhados nunca se encostam ----

   Medido em 02/09/2026, em navegador: cinco telas tinham cartão colado no
   seguinte, com vão de ZERO pixel — a do lead (4 emendas), a Tabela SELIC, a
   Tabela VAU, as etapas do CRM e a importação. Duas bordas de 1px encostadas
   lêem como um cartão só, partido ao meio.

   Todas pelo mesmo motivo: os cartões são filhos DIRETOS da raiz do fragmento
   de conteúdo, que é um <div> sem classe e sem espaçamento. Onde havia um
   contêiner próprio — `.calc__form`, com a sua própria coruja — o vão já era o
   certo, e por isso a calculadora nunca teve o problema.

   O SELETOR É ESTREITO DE PROPÓSITO. `.painel + .painel` sozinho pegaria também
   os cartões dentro de `.form-grade`, que é `display: grid`: ali quem espaça é o
   `gap` do contêiner, e uma margem por cima somaria aos 16px quando a grade
   quebra de linha. Ancorar em `.conteudo > *` alcança só o que está na raiz da
   tela — exatamente onde falta — e nada do que está aninhado.

   O valor é o mesmo `--e5` que a calculadora usa: um cartão termina, o próximo
   começa, e o respiro entre cartões é maior que o respiro entre campos. */
.conteudo > * > .painel + .painel { margin-top: var(--e5); }

/* Cartao DENTRO de outro cartao.

   As areas complementares, as destinacoes adicionais e a reforma nascem cada
   uma logo abaixo do interruptor que a abre, dentro de "Parametros da
   Afericao" -- e nao como cartoes irmaos depois dele. Sem esta regra o bloco
   de dentro fica branco sobre branco, distinguido so por um filete cinza igual
   ao de qualquer borda, e some justamente no momento em que aparece.

   A borda na cor da area e a mesma marca que o sistema de referencia usa: ela
   diz "isto pertence ao que voce acabou de ligar". Sem sombra, porque sombra
   dentro de sombra faz o cartao de fora parecer rachado, e o cabecalho fica
   transparente para nao repetir a faixa cinza do painel que o contem. */
.painel--aninhado {
    border-color: var(--marca);
    border-radius: var(--r);
    box-shadow: none;
}
.painel--aninhado > .painel__cabecalho { background: transparent; }

.painel__cabecalho {
    display: flex;
    align-items: center;
    gap: var(--e2);
    padding: var(--e3) var(--e4);
    border-bottom: 1px solid var(--linha);
    background: var(--sup-2);
}
.painel__titulo { font-size: var(--t-base); font-weight: 600; }
/* Icone escrito DENTRO do titulo (onze telas fazem assim). Sem tamanho, o SVG
   ocupava o padrao do navegador -- ~150px -- e engolia o painel; achado nas
   Notificacoes da franqueadora em 28/09/2026. */
.painel__titulo > svg {
    width: 17px; height: 17px; flex: 0 0 auto;
    color: var(--marca); vertical-align: -3px; margin-right: 4px;
}
.painel__icone { width: 17px; height: 17px; color: var(--marca); flex: 0 0 auto; }
.painel__corpo { padding: var(--e4); }
.painel__corpo > * + * { margin-top: var(--e3); }

/* ---- Cartão de número ---- */
.numero {
    display: flex;
    flex-direction: column;
    gap: var(--e2);
    padding: var(--e4);
    background: var(--sup);
    border: 1px solid var(--linha);
    border-radius: var(--r-lg);
    box-shadow: var(--sombra-1);
    transition: border-color var(--transicao), box-shadow var(--transicao);
}
.numero:hover { border-color: var(--linha-forte); box-shadow: var(--sombra-2); }

.numero__topo {
    display: flex;
    align-items: center;
    gap: var(--e2);
    font-family: var(--fonte-mono);
    font-size: var(--t-micro);
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--texto-3);
}
.numero__topo svg { width: 15px; height: 15px; color: var(--marca); flex: 0 0 auto; }

.numero__valor {
    font-family: var(--fonte-marca);
    font-size: var(--t-xxl);
    font-weight: 600;
    line-height: 1;
    letter-spacing: -.02em;
    font-variant-numeric: tabular-nums;
    color: var(--texto);
}
.numero__unidade {
    font-family: var(--fonte-ui);
    font-size: var(--t-sm);
    font-weight: 400;
    color: var(--texto-3);
    margin-left: 6px;
    letter-spacing: 0;
}
.numero__detalhe { font-size: var(--t-xs); color: var(--texto-3); }

/* ---- Selo ---- */
.selo {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 9px;
    border-radius: 99px;
    font-size: var(--t-micro);
    font-weight: 500;
    letter-spacing: .02em;
    white-space: nowrap;
}
.selo svg { width: 12px; height: 12px; }
.selo--ok    { background: var(--ok-vestigio);    color: var(--ok); }
.selo--aviso { background: var(--aviso-vestigio); color: var(--aviso); }
.selo--erro  { background: var(--erro-vestigio);  color: var(--erro); }

/* Quem assina cada contrato, na tabela da ficha (V087). Uma linha por pessoa,
   compacta: a coluna divide espaço com data, redação e hash. */
.assinatura-lista {
    margin: 0;
    font-size: var(--t-xs);
    line-height: 1.5;
}

.assinatura-quando { color: var(--texto-3); }
.selo--info  { background: var(--info-vestigio);  color: var(--info); }
.selo--marca { background: var(--marca-vestigio); color: var(--marca); }
/* Situação apagada — "Inativo", "Encerrado". Cinza é a cor certa: o registro
   existe, mas não está em jogo. */
.selo--neutro { background: var(--sup-3); color: var(--texto-3); }

/* ---- Lista de definição ---- */
.dados { display: grid; gap: var(--e3); }
.dados__linha {
    display: grid;
    grid-template-columns: minmax(120px, 34%) 1fr;
    gap: var(--e3);
    align-items: baseline;
}
.dados__rotulo {
    font-family: var(--fonte-mono);
    font-size: var(--t-micro);
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--texto-3);
}
.dados__valor { font-size: var(--t-sm); color: var(--texto); }

/* ---- Texto livre em exibição ----
   A observação foi digitada num textarea, com quebras de linha. Sem pre-line o
   HTML as colapsa e o que era uma lista vira um parágrafo só. */
.texto-livre {
    font-size: var(--t-sm);
    color: var(--texto);
    white-space: pre-line;
    line-height: 1.6;
}


/* =============================================================================
   09 · BOTÕES
   ============================================================================= */

/* Altura fixa, e nao derivada do padding: e ela que da ao raio de 7px a
   proporcao certa. Um botao mais alto com o mesmo raio parece quadrado. */
.botao {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--e2);
    height: var(--altura-botao);
    padding: 0 var(--e4);
    border: 1px solid var(--linha-forte);
    border-radius: var(--r);
    background: none;
    color: var(--texto-2);
    font-size: var(--t-sm);
    font-weight: 500;
    line-height: 1.2;
    cursor: pointer;
    white-space: nowrap;
    transition: background var(--transicao), border-color var(--transicao),
                color var(--transicao), box-shadow var(--transicao);
}
.botao:hover {
    background: var(--sup-3);
    border-color: var(--texto-3);
    color: var(--texto);
    text-decoration: none;
}
.botao:active { transform: translateY(1px); }
.botao svg { width: 15px; height: 15px; flex: 0 0 auto; }

.botao[disabled], .botao[aria-disabled="true"] {
    opacity: .55;
    cursor: not-allowed;
    pointer-events: none;
}

.botao--principal {
    background: var(--marca);
    border-color: var(--marca);
    color: var(--marca-contraste);
}
.botao--principal:hover {
    background: var(--marca-profunda);
    border-color: var(--marca-profunda);
    color: var(--marca-contraste);
}

/* Sem moldura: para acao secundaria dentro de um cartao, onde mais uma borda
   competiria com a do proprio cartao. */
.botao--discreto { border-color: transparent; }
.botao--discreto:hover { border-color: transparent; }

/* ---- Ver PDF ----
   Verde #099250, o do InssObra. Hoje só o "Ver PDF" da calculadora usa isto:
   Calcular e Salvar ficam com `botao--principal`, na cor da área.

   Por que existe uma classe em vez de `botao--principal`: aquele pinta com
   `--marca`, e desde a troca de paletas a franquia é AZUL — não há como pedir
   verde por ali sem repintar a área inteira.

   O nome é `--acao` e não `--pdf` porque a cor é do gesto, e não do formato do
   arquivo: se amanhã outro botão de saída precisar do mesmo destaque, ele
   reusa isto em vez de nascer um `botao--docx`. */
.botao--acao {
    background: var(--acao);
    border-color: var(--acao);
    color: #fff;
}
.botao--acao:hover {
    background: var(--acao-profunda);
    border-color: var(--acao-profunda);
    color: #fff;
}

.botao--bloco { width: 100%; }
.botao--grande { height: 46px; padding: 0 18px; font-size: var(--t-md); }

/* Acao destrutiva. Moldura e texto na cor de erro, fundo transparente ate o
   ponteiro chegar: um botao vermelho solido atrai o clique justamente onde ele
   nao deve ser dado por engano. */
.botao--perigo {
    border-color: var(--erro);
    color: var(--erro);
    background: transparent;
}
.botao--perigo:hover { background: var(--erro-vestigio); border-color: var(--erro); }


/* =============================================================================
   10 · CAMPOS DE FORMULÁRIO
   ============================================================================= */

.formulario { display: grid; gap: var(--e4); }

/* `min-width: 0` não é detalhe: sem ele o campo é um item de grade que PODE
   encolher, mas cujo conteúdo NÃO encolhe junto — um <select> ou um <input>
   carrega largura mínima própria. O resultado é o campo passando por cima da
   borda do cartão conforme a janela estreita, que é exatamente o defeito que
   isto corrige. Vale para os três níveis: o campo, o controle e a entrada. */
.campo { display: grid; gap: 6px; min-width: 0; }

/* Mesmo motivo de `.campo__erro[hidden]`, mais adiante: `display: grid` acima é
   regra de AUTOR e vence o `[hidden] { display: none }` do navegador, que é
   regra de agente. Sem esta linha, TODO campo que a tela esconde pelo atributo
   continuava visível — RMT Declarada, o valor do honorário fixo, "Área a
   Aferir", a coluna "A Aferir" da destinação adicional e o bloco de
   paralisação apareciam mesmo quando o cálculo não os usa, e quem preenchesse
   um deles veria o número ignorado sem entender por quê.

   `!important` porque quem esconde é o script, no meio de uma tela em que
   `.form-grade > *` e as colunas `.col-*` também opinam sobre o item. */
.campo[hidden] { display: none !important; }

/* A grade de doze colunas aninhada DENTRO de um campo — a origem dos créditos
   é o caso — é item de grade de um `.campo`, que é `display: grid`. O
   `.form-grade > * { min-width: 0 }` cuida dos filhos dela, não dela própria:
   sem isto a grade de dentro carrega a largura mínima do próprio conteúdo e
   transborda o cartão em tela estreita. */
.campo > .form-grade { min-width: 0; }

/* O rótulo à esquerda e o selo "opcional" à direita, na mesma linha — QUANDO
   couberem. Em coluna estreita (`col-2` em 1280x768, por exemplo) a palavra do
   rótulo mais o selo passam da largura, e sem `wrap` os dois vazavam para fora
   do campo: o selo aparecia por cima do vizinho.

   Com a quebra, o selo desce para a linha de baixo e o campo cresce alguns
   pixels de altura — que é o preço certo. `min-width: 0` no rótulo é o
   complemento: sem ele, um item de flex não encolhe abaixo do próprio
   min-content, e um rótulo de palavra longa voltaria a estourar mesmo com a
   quebra ligada. */
.campo__legenda {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--e3);
    flex-wrap: wrap;
}
.campo__legenda .campo__rotulo { min-width: 0; }

.campo__rotulo {
    font-size: var(--t-xs);
    font-weight: 500;
    color: var(--texto-2);
}

/* Marca de campo exigido.
   O asterisco sai do `required` do PRÓPRIO campo, via `:has` — o mesmo atributo
   que a guarda de envio lê. Escrever a marca à mão em cada template abriria a
   chance de um campo obrigatório sem asterisco, ou de um asterisco em campo que
   o servidor aceita vazio; assim marca e regra não têm como divergir.

   Fica no `::after` e é decorativo: quem usa leitor de tela já recebe a
   obrigatoriedade pelo próprio `required`, e um "asterisco" lido em voz alta
   não acrescenta nada. */
.campo:has(.campo__controle [required]) .campo__rotulo::after {
    content: "*";
    margin-left: 3px;
    color: var(--erro);
    font-weight: 600;
}

/* Marca de campo dispensável, à direita do rótulo. As duas convivem: o
   asterisco no que é exigido, "opcional" no que é dispensável, e nada no que é
   apenas informativo — como o "Código interno", que é só leitura. */
.campo__opcional {
    font-size: var(--t-micro);
    color: var(--texto-3);
    text-transform: uppercase;
    letter-spacing: .08em;
}

.campo__controle {
    display: flex;
    align-items: center;
    min-width: 0;
    min-height: var(--altura-campo);
    background: var(--sup);
    border: 1px solid var(--linha-forte);
    border-radius: var(--r);
    transition: border-color var(--transicao), box-shadow var(--transicao);
}
.campo__controle:focus-within {
    border-color: var(--marca);
    box-shadow: 0 0 0 3px var(--marca-vestigio);
}

.campo__icone {
    width: 17px;
    height: 17px;
    margin-left: 11px;
    flex: 0 0 auto;
    color: var(--texto-3);
}

.campo__entrada {
    flex: 1 1 auto;
    min-width: 0;
    padding: 10px 12px;
    border: 0;
    background: none;
    font-size: var(--t-base);
    color: var(--texto);
}
.campo__entrada:focus { outline: none; }
.campo__entrada::placeholder { color: var(--texto-3); opacity: .8; }

.campo__acao {
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    margin-right: 3px;
    flex: 0 0 auto;
    border: 0;
    border-radius: var(--r-sm);
    background: none;
    color: var(--texto-3);
    cursor: pointer;
    transition: color var(--transicao), background var(--transicao);
}
.campo__acao:hover { color: var(--texto); background: var(--sup-3); }
.campo__acao svg { width: 17px; height: 17px; }

.campo__ajuda { font-size: var(--t-xs); color: var(--texto-3); }

/* ---- Campo com botão ao lado ----
   Usado pela consulta de banco. O botão fica FORA do controle, e o controle
   encolhe para o tamanho do conteúdo — ícone mais os dígitos, e nada além.

   Dentro do controle, o botão obrigava o campo a ocupar a coluna inteira só
   para acomodá-lo, e era o que empurrava o vizinho. */
.campo-com-botao {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}
/* O padrão é NÃO esticar: quem tem lupa ao lado costuma guardar um código curto
   — 341, 1.02, RH —, e uma caixa de trinta caracteres para três dígitos sugere
   que cabe mais coisa. */
.campo-com-botao .campo__controle {
    flex: 0 0 auto;
    width: max-content;
}
.campo-com-botao .botao { flex: 0 0 auto; }

/* A exceção: quando o valor é longo por natureza, e não um código.

   O e-mail da conta de acesso é o caso. Com `width: max-content` a caixa ficava
   do tamanho do padrão do navegador — perto de vinte caracteres — e cortava o
   endereço, por mais colunas que o campo tivesse. Aqui ela ocupa a coluna
   inteira que sobrar depois do botão.

   `min-width: 0` junto: sem ele um item flex não encolhe abaixo do conteúdo, e
   um endereço muito longo empurraria a lupa para fora. */
.campo-com-botao--largo .campo__controle {
    flex: 1 1 auto;
    width: auto;
    min-width: 0;
}

/* Botão que é só o símbolo: quadrado, da mesma altura dos demais. */
/* Duas ações lado a lado, ocupando a mesma faixa de um campo. */
.campo__acoes {
    display: flex;
    align-items: center;
    gap: var(--e2);
    min-height: var(--altura-campo);
    flex-wrap: wrap;
}

.botao--icone {
    width: var(--altura-botao);
    padding: 0;
    justify-content: center;
}
.botao--icone svg { margin: 0; }


/* =============================================================================
   11 · JANELA MODAL

   Toda mensagem ao usuário passa por aqui — sucesso, aviso e recusa. Um lugar
   só significa um comportamento só: mesma aparência, mesmo foco, mesmo caminho
   de teclado, e nenhuma tela que esquece de exibir o erro.
   ============================================================================= */

.modal {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: grid;
    place-items: center;
    padding: var(--e4);
    background: rgba(7, 12, 10, .55);
    backdrop-filter: blur(2px);
    animation: modal-fundo 160ms ease-out;
}
.modal[hidden] { display: none; }

.modal__caixa {
    width: min(430px, 100%);
    background: var(--sup);
    border: 1px solid var(--linha);
    border-radius: var(--r-lg);
    box-shadow: var(--sombra-3);
    overflow: hidden;
    animation: modal-caixa 180ms cubic-bezier(.2, .9, .3, 1);
}

/* ---- Cabeçalho ----
   Faixa escura, com o mesmo gradiente do trilho lateral: a janela passa a ter
   a cabeça no idioma escuro do sistema, e o título se destaca do corpo sem
   precisar de mais uma linha divisória.

   `background-size: 100% 240px` fatia o gradiente: sem isso ele se ajustaria à
   altura do cabeçalho e cada janela sairia com um tom diferente, conforme o
   título ocupasse uma ou duas linhas. */
.modal__cabecalho {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--e3);
    padding: var(--e4) var(--e5);
    background: var(--trilho-grad);
    background-size: 100% 240px;
    color: var(--trilho-forte);
}

/* Fio de 3px no topo, dizendo a natureza da mensagem. É o que diferencia um
   "gravado" de um "não deu" antes mesmo de ler o título — e diferencia por
   cor E por posição, não só por cor. */
.modal__cabecalho::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 3px;
    background: var(--marca-clara);
}
.modal--sucesso    .modal__cabecalho::before { background: var(--ok-no-escuro); }
.modal--informacao .modal__cabecalho::before { background: var(--info-no-escuro); }
.modal--atencao    .modal__cabecalho::before { background: var(--aviso-no-escuro); }
.modal--erro       .modal__cabecalho::before { background: var(--erro-no-escuro); }

.modal__icone {
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    flex: 0 0 auto;
    border-radius: 50%;
    background: rgba(255, 255, 255, .08);
    color: var(--marca-clara);
}
.modal__icone svg { width: 18px; height: 18px; }
.modal--sucesso    .modal__icone { color: var(--ok-no-escuro); }
.modal--informacao .modal__icone { color: var(--info-no-escuro); }
.modal--atencao    .modal__icone { color: var(--aviso-no-escuro); }
.modal--erro       .modal__icone { color: var(--erro-no-escuro); }

.modal__titulo {
    font-size: var(--t-md);
    font-weight: 600;
    letter-spacing: -.01em;
    line-height: 1.25;
}

.modal__corpo {
    padding: var(--e5);
    font-size: var(--t-base);
    line-height: 1.6;
    color: var(--texto-2);
    overflow-y: auto;
}
/* A lista de impedimentos do login chega como um texto com quebras de linha.
   Sem isto ela vira um parágrafo corrido, e quem está sem entrar tem de garimpar
   os motivos no meio da frase. Mensagem de uma linha só não é afetada: não tem
   quebra nenhuma para preservar. */
#modal-texto p { white-space: pre-line; }

.modal__detalhe {
    margin-top: var(--e3);
    padding-top: var(--e3);
    border-top: 1px dashed var(--linha);
    font-size: var(--t-xs);
    color: var(--texto-3);
}

/* Uma enumeração curta dentro de uma janela: o que falta para o rascunho virar
   proposta, por exemplo. Marcador de verdade, e não traço nem ícone — são itens
   que a pessoa vai conferir um por um, e o marcador é o que diz "conte estes". */
.lista-simples {
    margin: var(--e2) 0 0;
    padding-left: var(--e5);
    list-style: disc;
}

.lista-simples li {
    margin-bottom: var(--e1);
}

.modal__pe {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: var(--e2);
    flex-wrap: wrap;
    padding: var(--e3) var(--e5) var(--e4);
    background: var(--sup-2);
    border-top: 1px solid var(--linha);
}
/* A confirmação de exclusão põe um <form> no rodapé — ele não pode ficar dentro
   do formulário de cadastro, e aqui precisa se comportar como mais um botão. */
.modal__pe form { display: contents; }

/* -----------------------------------------------------------------------------
   O balanço de uma conta que vai ser encerrada

   A janela pergunta o destino dos dados de alguém, e para isso mostra o que a
   conta carrega: rótulo à esquerda, número à direita, uma linha por natureza.
   Duas listas separadas por um título, porque as duas naturezas não se somam —
   contato passa de dono, proposta não passa.

   As linhas com zero não são desenhadas (o script as esconde), então esta grade
   nunca tem mais do que três ou quatro linhas.
   -------------------------------------------------------------------------- */
.encerrar__grupo {
    margin: var(--e4) 0 var(--e2);
    font-size: var(--t-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--texto-3);
}

.encerrar__contas { margin: 0; }

.encerrar__conta {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--e3);
    padding: var(--e1) 0;
    border-bottom: 1px solid var(--linha);
}
.encerrar__conta:last-child { border-bottom: 0; }

.encerrar__conta dt { color: var(--texto-2); }

.encerrar__conta dd {
    margin: 0;
    font-weight: 600;
    color: var(--texto);
    /* O número é o que se lê primeiro nesta janela: ele não pode ficar do
       tamanho do rótulo. */
    font-size: var(--t-base);
}

.encerrar__vazio {
    margin: 0;
    font-size: var(--t-xs);
    color: var(--texto-3);
}

@keyframes modal-fundo { from { opacity: 0; } to { opacity: 1; } }
@keyframes modal-caixa {
    from { opacity: 0; transform: translateY(10px) scale(.985); }
    to   { opacity: 1; transform: none; }
}


/* =============================================================================
   12 · TELAS DE ACESSO

   Duas colunas: a esquerda carrega a marca sobre o gradiente do trilho, e a
   direita é só o formulário. A cor do gradiente vem de [data-area], então a
   pessoa sabe em qual porta está antes de digitar o e-mail.
   ============================================================================= */

.acesso {
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
    min-height: 100vh;
}

/* ---- Lado da marca ---- */
.acesso__marca {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: var(--e6);
    padding: var(--e7) clamp(var(--e5), 6vw, 72px);
    background: var(--trilho-bg);
    background-image:
        radial-gradient(120% 80% at 18% 0%, var(--marca-vestigio-forte) 0%, transparent 58%),
        var(--trilho-grad);
    color: var(--trilho-forte);
}

.acesso__assinatura { display: flex; align-items: center; gap: var(--e3); }
.acesso__assinatura .marca__simbolo { width: 40px; height: 40px; }
.acesso__assinatura .marca__texto { font-size: 1.7rem; }
.acesso__assinatura .marca__texto--sistema { font-size: 1.05rem; }

.acesso__discurso { max-width: 42ch; }
.acesso__chamada {
    font-family: var(--fonte-marca);
    font-size: clamp(1.9rem, 3.6vw, 2.7rem);
    font-weight: 600;
    line-height: 1.1;
    letter-spacing: -.02em;
    color: var(--trilho-forte);
}
.acesso__texto {
    margin-top: var(--e3);
    font-size: var(--t-base);
    line-height: 1.65;
    color: var(--trilho-texto);
}

.acesso__lista { display: grid; gap: var(--e3); margin-top: var(--e5); }
.acesso__ponto {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    font-size: var(--t-sm);
    color: var(--trilho-texto);
}
.acesso__ponto svg {
    width: 16px;
    height: 16px;
    margin-top: 2px;
    flex: 0 0 auto;
    color: var(--marca-clara);
}

.acesso__rodape {
    font-family: var(--fonte-mono);
    font-size: 10px;
    letter-spacing: .08em;
    color: var(--trilho-fraco);
}

/* ---- Lado do formulário ---- */
.acesso__painel {
    display: grid;
    place-items: center;
    /* O painel passou a ter DOIS filhos: o recado e o cartão. Sem
       `align-content`, cada um ganharia metade da altura e ficaria centralizado
       na sua metade — o recado boiando lá em cima, o cartão lá embaixo. Com
       ele, os dois viram um bloco só, centralizado junto e separado pelo gap.
       Com um filho só (o normal, sem mensagem) o resultado é idêntico ao de
       antes. */
    align-content: center;
    gap: var(--e4);
    padding: var(--e7) var(--e5);
    background: var(--fundo);
}

.acesso__cartao { width: min(384px, 100%); }

/* ---- O recado da tela de acesso ----

   Existe porque a janela de mensagem não pode ser a única voz aqui: ela é
   `position: fixed` com `backdrop-filter`, e num navegador antigo ou com CSS
   velho em cache ela some — deixando quem errou a senha sem nenhum aviso, na
   única tela em que a pessoa ainda não entrou e não tem a quem recorrer.

   Fluxo normal do documento, largura do cartão, sem sobreposição e sem
   JavaScript. Se o HTML chegou, isto aparece. */
.acesso__recado {
    display: flex;
    align-items: flex-start;
    gap: var(--e3);
    width: min(384px, 100%);
    padding: var(--e4);
    border: 1px solid var(--linha);
    border-left: 3px solid var(--texto-3);
    border-radius: var(--r-sm);
    background: var(--sup);
}

.acesso__recado-icone {
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    margin-top: 2px;
    color: var(--texto-3);
}

.acesso__recado-titulo {
    margin: 0;
    font-size: var(--t-sm);
    font-weight: 600;
    color: var(--texto);
}

.acesso__recado-texto {
    margin: 3px 0 0;
    font-size: var(--t-xs);
    line-height: 1.5;
    color: var(--texto-2);
}

.acesso__recado--erro    { border-left-color: var(--erro);  background: var(--erro-vestigio); }
.acesso__recado--atencao { border-left-color: var(--aviso); background: var(--aviso-vestigio); }
.acesso__recado--sucesso { border-left-color: var(--ok);    background: var(--ok-vestigio); }

.acesso__recado--erro    .acesso__recado-icone { color: var(--erro); }
.acesso__recado--atencao .acesso__recado-icone { color: var(--aviso); }
.acesso__recado--sucesso .acesso__recado-icone { color: var(--ok); }

.acesso__cabecalho { margin-bottom: var(--e5); }
.acesso__etiqueta {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-bottom: var(--e3);
    padding: 4px 10px;
    border-radius: 99px;
    background: var(--marca-vestigio);
    color: var(--marca);
    font-family: var(--fonte-mono);
    font-size: var(--t-micro);
    letter-spacing: .12em;
    text-transform: uppercase;
}
.acesso__etiqueta svg { width: 13px; height: 13px; }

.acesso__titulo { font-size: var(--t-lg); }
.acesso__subtitulo { margin-top: 4px; font-size: var(--t-sm); color: var(--texto-3); }

.acesso__aviso {
    margin-top: var(--e5);
    padding-top: var(--e4);
    border-top: 1px solid var(--linha);
    font-size: var(--t-xs);
    line-height: 1.55;
    color: var(--texto-3);
}


/* =============================================================================
   12b · FORMULÁRIOS DE CONFIGURAÇÃO

   Campos em grade de duas colunas, que viram uma só em tela estreita. É o
   suficiente para uma tela de configuração e evita o formulário de coluna única
   que obriga a rolar para conferir o que já foi preenchido.
   ============================================================================= */

.campos {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(248px, 1fr));
    gap: var(--e4);
    /* Sem isto, um campo sem texto de ajuda estica para acompanhar a altura do
       vizinho que tem, e a caixa de entrada fica desproporcional. */
    align-items: start;
}

/* Ocupa a linha inteira, para endereço e nome longos. */
.campo--largo { grid-column: 1 / -1; }

/* Link discreto ao lado do rótulo — "Esqueci minha senha". */
.campo__link {
    font-size: var(--t-xs);
    color: var(--marca);
    white-space: nowrap;
}

/* O select herda a mesma caixa dos demais campos. A seta é desenhada em CSS
   para não depender de imagem nem de fonte de ícones. */
select.campo__entrada {
    appearance: none;
    -webkit-appearance: none;
    cursor: pointer;
    padding-right: 34px;
    background-image:
        linear-gradient(45deg, transparent 50%, currentColor 50%),
        linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position: right 16px center, right 11px center;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
}

/* ---- A LISTA ABERTA DO <select> ----

   O popup e desenhado pelo NAVEGADOR, e ele o pinta com o fundo do proprio
   <select> -- nao com o do wrapper. Como .campo__entrada tem background: none
   (o visual mora no .campo__controle, de proposito), o popup caia no branco
   padrao do navegador enquanto o texto herdava --texto. No tema escuro isso
   da quase-branco sobre branco: a lista abria ilegivel, parecendo desabilitada.

   A regra vale para TODO select do sistema, e nao so o que apareceu com o
   defeito: o wrapper transparente e o padrao daqui, entao qualquer select novo
   nasceria com o mesmo problema.

   Nao basta color-scheme: dark -- ele ja esta declarado em [data-tema="escuro"].
   Quem escolhe o tema pelo botao, com o sistema operacional no claro, continua
   recebendo o popup claro do sistema. Cor explicita fecha os dois casos. */
select option,
select optgroup {
    background-color: var(--sup);
    color: var(--texto);
}

/* O "Selecione" desabilitado fica mais fraco, mas LEGIVEL: --texto-3 e o tom
   de apoio, e nao o cinza de sistema que sumia. */
select option:disabled {
    color: var(--texto-3);
}

textarea.campo__entrada { min-height: 88px; resize: vertical; line-height: 1.6; }

/* ---- Caixa de marcação ----
   O <input> real fica invisível mas continua no fluxo de foco e de teclado:
   trocá-lo por um <div> quebraria leitor de tela e navegação por Tab. */
.marcador {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--e3);
    align-items: start;
    padding: var(--e3) 0;
    cursor: pointer;
}

.marcador input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.marcador__caixa {
    display: grid;
    place-items: center;
    width: 20px;
    height: 20px;
    margin-top: 1px;
    border: 1px solid var(--linha-forte);
    border-radius: var(--r-sm);
    background: var(--sup);
    color: transparent;
    transition: background var(--transicao), border-color var(--transicao), color var(--transicao);
}
.marcador__caixa svg { width: 14px; height: 14px; }

.marcador input:checked + .marcador__caixa {
    background: var(--marca);
    border-color: var(--marca);
    color: var(--marca-contraste);
}
.marcador input:focus-visible + .marcador__caixa {
    outline: 2px solid var(--marca-clara);
    outline-offset: 2px;
}

.marcador__texto { display: grid; gap: 2px; font-size: var(--t-sm); }
.marcador__texto span { font-size: var(--t-xs); color: var(--texto-3); }

/* ---- Separador dentro de painel ---- */
.divisor {
    height: 1px;
    margin: var(--e5) 0;
    border: 0;
    background: var(--linha);
}

/* ---- Bloco recolhido ---- */
.avancado { margin-top: var(--e5); }

.avancado > summary {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 0;
    font-size: var(--t-xs);
    font-weight: 500;
    color: var(--texto-2);
    cursor: pointer;
    list-style: none;
}
.avancado > summary::-webkit-details-marker { display: none; }
.avancado > summary::before {
    content: "";
    width: 0;
    height: 0;
    border-left: 5px solid currentColor;
    border-top: 4px solid transparent;
    border-bottom: 4px solid transparent;
    transition: transform var(--transicao);
}
.avancado[open] > summary::before { transform: rotate(90deg); }
.avancado > summary:hover { color: var(--texto); }
.avancado > *:not(summary) { margin-top: var(--e3); }

/* ---- Rodapé de painel com ações ---- */
.painel__pe {
    display: flex;
    justify-content: flex-end;
    gap: var(--e2);
    flex-wrap: wrap;
    padding: var(--e3) var(--e4);
    border-top: 1px solid var(--linha);
    background: var(--sup-2);
}

.rodape-nota {
    margin-top: var(--e3);
    font-size: var(--t-xs);
    color: var(--texto-3);
    max-width: 72ch;
}

/* ---- Ações empilhadas nas telas de acesso ---- */
.acesso__acoes { display: grid; gap: var(--e2); margin-top: var(--e5); }

/* A lista de pontos também aparece no lado claro, na confirmação de envio. */
.acesso__lista--claro .acesso__ponto { color: var(--texto-2); }
.acesso__lista--claro .acesso__ponto svg { color: var(--marca); }


/* =============================================================================
   12d · CADASTROS: ABAS, GRADE E RODAPÉ

   O padrão de todo formulário de cadastro do sistema: um painel só, abas no
   topo, grade de 12 colunas no meio, ações no rodapé. Cadastro novo reaproveita
   estas classes — não deve nascer CSS por tela.
   ============================================================================= */

/* ---- Abas ---- */
/* A faixa das abas usa `--sup-2`, a MESMA do rodapé de botões. Não é enfeite:
   os dois são moldura, e a área de campos, no branco `--sup`, é o miolo. O
   cartão fica lido de cima a baixo como cabeça / conteúdo / ações, sem precisar
   de mais nenhuma borda. É a divisão do Argus. */
.abas {
    display: flex;
    gap: var(--e1);
    padding: 0 var(--e4);
    border-bottom: 1px solid var(--linha);
    background: var(--sup-2);
    overflow-x: auto;
    scrollbar-width: none;
    scroll-behavior: smooth;
}
.abas::-webkit-scrollbar { display: none; }

/* ---- Régua de abas que não cabe na tela ----
   Rolar sozinho não basta. No celular, as abas que sobram simplesmente somem
   pela borda, e quem não sabe que existem não as procura — foi o que acontecia
   aqui. A área abaixo põe uma seta em cada ponta, visível SÓ quando há o que
   rolar daquele lado, e esmaece a borda para dizer que o conteúdo continua.

   O invólucro é montado pelo próprio script, e não escrito em cada template:
   assim vale nos quatro cadastros de hoje e em todo o que vier depois, sem
   ninguém precisar lembrar de repetir a marcação. */
.abas-area {
    position: relative;
    display: flex;
    align-items: stretch;
    border-bottom: 1px solid var(--linha);
    background: var(--sup-2);
}
.abas-area .abas {
    flex: 1 1 auto;
    min-width: 0;
    border-bottom: 0;
}

.abas__seta {
    position: relative;
    z-index: 2;
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    width: 34px;
    border: 0;
    background: var(--sup-2);
    color: var(--texto-3);
    cursor: pointer;
    transition: color var(--transicao);
}
.abas__seta:hover { color: var(--texto); }
.abas__seta[hidden] { display: none; }
.abas__seta svg { width: 18px; height: 18px; }

/* Não existe i-chevron-left no catálogo, e não vale inchá-lo por causa de um
   espelho: a seta da esquerda é a da direita refletida. */
.abas__seta--esq svg { transform: scaleX(-1); }

/* O esmaecimento nasce da seta, para o lado em que há rolagem. */
.abas__seta::after {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    width: 22px;
    pointer-events: none;
}
.abas__seta--esq::after {
    left: 100%;
    background: linear-gradient(to right, var(--sup-2), transparent);
}
.abas__seta--dir::after {
    right: 100%;
    background: linear-gradient(to left, var(--sup-2), transparent);
}

/* `hidden` precisa vencer o `display` de baixo.

   O atributo vale `display: none`, mas vem da folha do NAVEGADOR — qualquer
   regra de autor que defina `display` o derrota, e `.aba` define. O sintoma foi
   concreto: a aba "Áreas de atuação", escondida por script quando a unidade não
   vende fora da área, continuava à vista e clicável.

   Vale para toda aba condicional que venha depois desta. */
.aba[hidden] { display: none; }

.aba {
    display: inline-flex;
    align-items: center;
    gap: var(--e2);
    padding: var(--e4) var(--e3);
    border: 0;
    /* A linha de baixo existe sempre, transparente: sem isso o texto pularia
       dois pixels ao trocar de aba. */
    border-bottom: 2px solid transparent;
    background: none;
    color: var(--texto-3);
    font-size: var(--t-base);
    font-weight: 500;
    white-space: nowrap;
    cursor: pointer;
    transition: color var(--transicao), border-color var(--transicao);
}
.aba svg { width: 17px; height: 17px; flex: 0 0 auto; }
.aba:hover { color: var(--texto); }

.aba[aria-selected="true"] {
    color: var(--marca);
    border-bottom-color: var(--marca);
}

/* Aba fechada com erro dentro: sem esta marca, o formulário pareceria recusar
   sem motivo, porque a mensagem estaria escondida. */
.aba[data-com-erro="true"] { color: var(--erro); }
.aba[data-com-erro="true"]::after {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--erro);
}

/* Ponto discreto quando a aba tem conteúdo preenchido. */
.aba__marca {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--marca-clara);
}

.aba-painel { padding: var(--e5) var(--e4); }
.aba-painel[hidden] { display: none; }

/* ---- Grade de 12 colunas ---- */
.form-grade {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: var(--e4);
    align-items: start;
}

/* Todo item da grade pode encolher. Sem isto, o tamanho mínimo automático de um
   item de grade é o do CONTEÚDO dele — e um <select> ou um <input> tem largura
   mínima própria, que não cede. Ao estreitar a janela, o item deixa de caber na
   faixa e transborda por cima do vizinho, em vez de encolher: era o CEP subindo
   no endereço, e as datas de vigência subindo no Ativo.

   `minmax(0, 1fr)` acima resolve a FAIXA; isto resolve o ITEM. Os dois são
   necessários, e é comum corrigir só um e achar que resolveu. */
.form-grade > * { min-width: 0; }

/* Grade apertada: para um conjunto de opcoes que se le como UMA resposta.

   As tres origens do credito -- eSocial, GFIP, GPS -- sao tres cartoes de uma
   escolha unica, e nao tres campos. Com o respiro de 16px entre eles a fileira
   parecia tres perguntas separadas; com 8px ela se le como um grupo, que e o
   arranjo do sistema de referencia. Vale so onde a modificadora e escrita. */
.form-grade--apertada { gap: var(--e2); }

/* O controle nativo não herda o encolhimento do pai: sem o teto explícito, um
   <select> com opção longa força a largura da coluna inteira. */
.campo__entrada,
.campo__controle select { max-width: 100%; }

.col-1  { grid-column: span 1; }
.col-2  { grid-column: span 2; }
.col-3  { grid-column: span 3; }
.col-4  { grid-column: span 4; }
.col-5  { grid-column: span 5; }
.col-6  { grid-column: span 6; }
.col-7  { grid-column: span 7; }
.col-8  { grid-column: span 8; }
.col-9  { grid-column: span 9; }
.col-10 { grid-column: span 10; }
.col-11 { grid-column: span 11; }
.col-12 { grid-column: span 12; }

/* ---- Quando a grade de 12 deixa de caber ----

   O ponto de quebra estava em 900px, e era tarde demais. Entre 900 e 1200 o
   trilho lateral come 274px, e o que sobra dividido em doze produz coluna de
   quatro centímetros: o telefone mascarado não cabe inteiro, e o campo com
   ícone mais botão passa por cima do vizinho.

   Três degraus, e o de cima é o que faltava:

     acima de 1200px   doze colunas
     700 a 1200px      seis  — cada campo ganha o dobro de largura
     abaixo de 700px   uma   — no celular, um campo por linha e ponto final
*/
@media (max-width: 1200px) {
    .form-grade { grid-template-columns: repeat(6, minmax(0, 1fr)); }
    .col-7, .col-8, .col-9, .col-10, .col-11, .col-12 { grid-column: span 6; }
    .col-4, .col-5, .col-6 { grid-column: span 6; }
    /* `.col-1` entrava aqui sem regra e continuava valendo 1 de 6 — uma coluna
       de dois centímetros, com o conteúdo saindo por fora. Vira metade da
       linha, como as outras estreitas. */
    .col-1, .col-2, .col-3 { grid-column: span 3; }
}
@media (max-width: 700px) {
    .form-grade { grid-template-columns: minmax(0, 1fr); }
    .form-grade > * { grid-column: span 1 !important; }
}

/* ---- Linha de inclusão: cinco controles que precisam ficar juntos ----

   A grade de doze é a ferramenta errada para esta linha. Entre 700 e 1200px ela
   cai para seis colunas e a cidade (`col-4`) passa a ocupar a linha inteira
   sozinha — o que espalha "Estado, Cidade, % de Split, Ativo e Incluir" em
   quatro fileiras, e a ação de incluir uma área deixa de ser uma coisa só.

   Mexer no ponto de quebra consertaria aqui e estragaria os formulários todos:
   ali a quebra existe justamente para o campo de texto não ficar com quatro
   centímetros. O que muda é o INSTRUMENTO, e só nesta linha.

   Cada controle pede uma largura própria, e nenhuma delas é uma fração de doze:
   uma sigla de UF cabe em nove caracteres, uma porcentagem em seis, uma caixa
   de marcação é do tamanho do desenho. Quem tem nome de verdade dentro é a
   cidade, e é ela que fica com o que sobra.

   Abaixo de 560px a linha quebra — e aí é certo que quebre: no celular, cinco
   controles lado a lado não cabem em largura nenhuma. */
.form-linha {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--e4);
}

/* Por padrão, cada controle ocupa exatamente o que pede. */
.form-linha > .campo { flex: 0 0 auto; min-width: 0; }

/* A cidade absorve a sobra, e pode encolher até 180px antes de a linha quebrar. */
.form-linha__cidade { flex: 1 1 180px; min-width: 0; }

.form-linha__uf    { width: 10ch; }
.form-linha__split { width: 11ch; }

/* CUIDADO COM `ch` AQUI: ele mede o dígito da fonte DESTE elemento, e este
   elemento é o `.campo` de fora, em IBM Plex Sans. O texto que precisa caber
   está no input, em IBM Plex Mono e num corpo maior — dígito mais largo. Foi
   assim que `13ch` deu ~101px para um conteúdo que pede 110, e a data aparecia
   cortada.

   A conta, em vez do palpite:
     10 dígitos × 8,4px (Plex Mono a 14px)  = 84px
     recuo interno do campo (12px de cada)  = 24px
     borda                                  =  2px
                                              110px

   8rem = 128px deixa a folga do cursor e do zoom do navegador. */
.form-linha__data  { width: 8rem; }

/* Ativo aqui é a caixa e mais nada: um cartão com título e explicação, do
   tamanho que tem, empurraria a cidade para fora da linha. A explicação some
   sem perda — a coluna Ativo da tabela logo abaixo usa a mesma caixa.

   A caixa ocupa a MESMA faixa vertical dos campos ao lado, e fica centrada
   nela. Sem isto ela pousaria acima da linha dos controles: o `.marcador` é
   mais baixo que um `.campo__controle`, e alinhar pelo rodapé encostaria os
   dois em alturas diferentes. */
.form-linha__ativo .marcador {
    min-height: var(--altura-campo);
    align-items: center;
    padding: 0;
}

/* O botão fica encostado na direita, separado dos campos: ele não é um campo, e
   alinhá-lo junto sugeriria que sim. */
.form-linha__acao { margin-left: auto; }

@media (max-width: 560px) {
    /* Sem larguras fixas: cada um passa a ocupar a linha, como no resto do
       formulário abaixo de 700px. */
    .form-linha > .campo,
    .form-linha__uf,
    .form-linha__split,
    .form-linha__data,
    .form-linha__cidade { flex: 1 1 100%; width: auto; }
    .form-linha__acao { margin-left: 0; }
}

/* ---- Campo dentro de uma linha de tabela ----

   Uma célula editável não é um campo de formulário: ela divide a linha com o
   texto ao lado e não pode empurrá-la. Altura menor e largura justa para o que
   guarda — no caso, uma porcentagem de até seis caracteres ("100,00"). */
.campo__controle--enxuto {
    min-height: auto;
    width: 8ch;
}
.campo__controle--enxuto .campo__entrada {
    padding: 4px 8px;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* Data dentro de uma linha de tabela.

   Oito caracteres bastam para uma porcentagem e não para "dd/mm/aaaa", que tem
   dez. E data não se alinha à direita como número: ela é lida da esquerda, e o
   dia é o que se procura primeiro.

   Em rem, e não em `ch`, pela mesma razão de `.form-linha__data`: aqui o recuo
   interno é menor (8px de cada lado, do `--enxuto`), então 84 + 16 + 2 = 102px.
   7rem = 112px cobre com folga. */
.campo__controle--data { width: 7rem; }
.campo__controle--data .campo__entrada { text-align: left; }

/* ---- Tipo do anexo, com o símbolo ao lado ----

   O símbolo escolhido no cadastro de tipos aparece aqui e no campo de seleção.
   Sem isso, escolher um ícone lá não teria efeito visível em lugar nenhum — e
   um campo que não muda nada é um campo que não deveria existir. */
.anexo-tipo {
    display: inline-flex;
    align-items: center;
    gap: var(--e2);
}
.anexo-tipo__icone {
    width: 18px;
    height: 18px;
    flex: 0 0 auto;
    color: var(--marca);
}
.tabela tbody tr.inativa .anexo-tipo__icone { color: var(--texto-3); }

/* Variante larga do campo enxuto: descrição e observação precisam de espaço
   para o texto, ao contrário de uma porcentagem. */
.campo__controle--largo { width: 100%; min-width: 14rem; }
.campo__controle--largo .campo__entrada { text-align: left; }

/* ---- Tabela dentro de um formulário ----

   Mais apertada que a da listagem: aqui ela é um campo composto, e não a tela
   inteira. Sem isso, uma lista de dez áreas empurra o rodapé do formulário
   para fora da vista.

   ATENÇÃO, ARMADILHA MEDIDA: estas duas declarações NÃO estão pegando hoje.
   `.tabela--compacta td` pesa (0,1,1) e `.tabela tbody td` — lá embaixo, na
   seção 12c — pesa (0,1,2) com a `padding` abreviada; ela ganha por
   especificidade E por vir depois. Todas as doze telas que usam esta classe
   estão com o respiro normal, e ninguém notou porque a diferença é de 4px por
   ponta. Consertar é subir a especificidade daqui, e isso muda as doze de uma
   vez — por isso não foi feito de passagem. Quem for mexer, meça antes.
   A carteira de leads NÃO usa esta classe por causa disto: ela declara o
   próprio respiro em `.tabela--leads`, no fim do arquivo. */
.tabela--compacta th,
.tabela--compacta td {
    padding-top: var(--e2);
    padding-bottom: var(--e2);
}
.tabela--compacta .marcador { margin: 0; }

/* ---- Campo somente leitura ---- */
.campo__controle--leitura {
    background: var(--sup-3);
    border-style: dashed;
}
.campo__controle--leitura .campo__entrada {
    color: var(--texto-3);
    cursor: default;
}

/* ---- Subtítulo dentro de uma aba ----
   Uma aba com trinta campos precisa de marcos, senão vira uma parede. Não é
   outra aba: endereço e presença na internet pertencem à identificação, e
   separá-los em abas faria procurar em duas telas o que é um assunto só. */
.form-secao {
    margin-top: var(--e2);
    padding-bottom: 6px;
    border-bottom: 1px solid var(--linha);
    font-size: var(--t-xs);
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--texto-3);
}
.form-grade > .campo:first-child .form-secao { margin-top: 0; }

/* Prefixo fixo dentro do campo — o "@" das redes sociais. Faz parte do
   controle, e não do valor: o que se grava é o perfil, sem o arroba. */
.campo__prefixo {
    padding-left: 11px;
    flex: 0 0 auto;
    color: var(--texto-3);
    font-size: var(--t-base);
    user-select: none;
}

/* Ajuda que virou aviso. Mesma linha, outra cor — sem empurrar o layout. */
.campo__ajuda--erro { color: var(--erro); }

/* ---- Arquivo anexado ---- */
.arquivo {
    display: flex;
    align-items: center;
    gap: var(--e4);
    padding: var(--e3) var(--e4);
    border: 1px solid var(--linha);
    border-radius: var(--r);
    background: var(--sup-2);
}
.arquivo__marca {
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    flex: 0 0 auto;
    border-radius: var(--r);
    background: var(--marca-vestigio);
    color: var(--marca);
}
.arquivo__marca svg { width: 20px; height: 20px; }

.arquivo__dados { display: grid; gap: 2px; flex: 1 1 auto; min-width: 0; }
.arquivo__nome {
    font-size: var(--t-sm);
    font-weight: 500;
    color: var(--texto);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
a.arquivo__nome:hover { color: var(--marca); }
.arquivo__apoio { font-size: var(--t-micro); color: var(--texto-3); }

/* De qual obra e o documento (V085). Discreta: so aparece quando o cliente
   tem mais de uma obra, e o que ela responde e "este alvara e de qual". */
.arquivo__obra {
    display: inline-block;
    margin-top: 2px;
    padding: 1px 6px;
    border: 1px solid var(--linha);
    border-radius: 999px;
    font-size: var(--t-micro);
    color: var(--texto-3);
}

.arquivo__acoes { display: flex; gap: var(--e2); flex: 0 0 auto; flex-wrap: wrap; }

/* Uma pilha deles: os documentos do lead. Gap pequeno de proposito -- a
   lista e para varrer com o olho ate achar "ja mandou a matricula?". */
.arquivos { display: grid; gap: var(--e2); }

@media (max-width: 620px) {
    .arquivo { flex-wrap: wrap; }
    .arquivo__acoes { width: 100%; }
}

/* ---- Lista de escolha dentro de uma janela ----
   Usada pela consulta de bancos. Rola dentro da janela, e não faz a janela
   crescer: com trezentos bancos o rodapé sairia da tela. */
.modal__caixa--larga { width: min(560px, 100%); }

.lista-escolha {
    display: grid;
    gap: 2px;
    max-height: 320px;
    margin-top: var(--e3);
    overflow-y: auto;
}
.lista-escolha__item {
    display: flex;
    align-items: center;
    gap: var(--e3);
    width: 100%;
    padding: 9px 10px;
    border: 0;
    border-radius: var(--r);
    background: none;
    text-align: left;
    cursor: pointer;
    transition: background var(--transicao);
}
.lista-escolha__item:hover { background: var(--sup-3); }
.lista-escolha__item svg {
    width: 18px;
    height: 18px;
    flex: 0 0 auto;
    color: var(--marca);
}
.lista-escolha__codigo {
    flex: 0 0 auto;
    font-size: var(--t-sm);
    color: var(--texto-2);
}
/* Mesmo recuo da listagem: sem ele a janela de escolha vira uma lista plana de
   códigos parecidos, e quem procura não enxerga onde cada um entra. */
.lista-escolha__arvore {
    padding-left: calc(var(--recuo, 0) * 0.9rem);
    font-variant-numeric: tabular-nums;
}
.lista-escolha__nome {
    flex: 1 1 auto;
    min-width: 0;
    font-size: var(--t-sm);
    color: var(--texto);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* ---- O item de DUAS linhas ----

   Para escolhas cujo nome é longo e cujos detalhes importam: nome em cima,
   telefone · cidade · área · etapa embaixo. Em uma linha só, um nome de quarenta
   caracteres empurra os detalhes para fora da janela — que ganha rolagem lateral
   e esconde justamente o que distingue duas opções parecidas. */
.lista-escolha__item--duas {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: center;
    row-gap: 1px;
}
.lista-escolha__item--duas svg { grid-row: 1 / span 2; }

.lista-escolha__detalhe {
    grid-column: 2;
    font-size: var(--t-xs);
    color: var(--texto-3);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* O nome volta a quebrar a própria largura, e não a esticar a grade: sem isto o
   nome longo alarga a coluna e a rolagem lateral volta pela porta dos fundos. */
.lista-escolha__item--duas .lista-escolha__nome {
    grid-column: 2;
    min-width: 0;
    font-weight: 600;
}

.lista-escolha__vazio {
    margin-top: var(--e3);
    padding: var(--e4);
    text-align: center;
    font-size: var(--t-sm);
    color: var(--texto-3);
}

/* A saída, embaixo do "nada encontrado". Menor e mais clara que a frase de
   cima: é explicação, e não o recado principal. */
.lista-escolha__dica {
    display: block;
    max-width: 46ch;
    margin: var(--e2) auto 0;
    font-size: var(--t-xs);
    line-height: 1.5;
    color: var(--texto-3);
}

/* ---- Cadastrar sem sair da janela de escolha ----

   O formulário curto no pé da janela de consulta: o mínimo para o registro
   nascer válido, para quem procurou e não achou. Separado da lista por uma linha
   e por um fundo mais fundo, porque é outra coisa — ali não se escolhe, se cria.

   Não é um <form>. A gravação vai por fetch e a página não navega: é o que
   preserva o formulário grande que está atrás desta janela. */
.escolha-criar {
    margin-top: var(--e4);
    padding-top: var(--e4);
    border-top: 1px dashed var(--linha);
}

.escolha-criar__titulo {
    font-size: var(--t-sm);
    font-weight: 600;
    color: var(--texto);
}

.escolha-criar__nota {
    margin-top: var(--e1);
    font-size: var(--t-xs);
    line-height: 1.5;
    color: var(--texto-3);
}

/* Código estreito, nome elástico, botão do tamanho do texto: é a ordem em que se
   preenche, e a mesma do cadastro completo. */
.escolha-criar__campos {
    display: grid;
    grid-template-columns: 8.5rem 1fr auto;
    align-items: end;
    gap: var(--e3);
    margin-top: var(--e3);
}
.escolha-criar__campos .campo { min-width: 0; }

/* A ajuda vira recusa no mesmo parágrafo, e a recusa por código repetido traz um
   botão junto — "Escolher RH". Dois elementos na mesma linha, alinhados pela
   base, para a frase e a saída serem lidas como uma coisa só. */
.escolha-criar .campo__ajuda {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--e2);
    margin-top: var(--e2);
}
/* A regra acima é de AUTOR e venceria o `[hidden] { display: none }` do
   navegador, que é de agente — a mesma armadilha de `.campo[hidden]`. */
.escolha-criar .campo__ajuda[hidden] { display: none; }

/* ---- "Usar os dados da conta" ----
   Fica dentro de um `.campo`, que é uma grade: sem isto o botão se estica pela
   coluna inteira e passa a parecer a ação principal do formulário, quando é uma
   saída de exceção. */
[data-conta-aproveitar] { justify-self: start; }

/* Abaixo disso os três em coluna: com o código e o nome lado a lado numa janela
   estreita, o nome fica com quatro caracteres visíveis. */
@media (max-width: 520px) {
    .escolha-criar__campos {
        grid-template-columns: 1fr;
        align-items: stretch;
    }
}

/* ---- Foto de perfil ----
   O círculo grande, mais o botão de escolher arquivo e o nome do que foi
   escolhido. O <input type="file"> fica escondido e quem aparece é o <label>:
   o controle nativo não aceita estilo, e o label continua alcançável pelo
   teclado porque está ligado ao campo. */
.foto-perfil {
    display: flex;
    align-items: center;
    gap: var(--e4);
}
.foto-perfil__imagem,
.foto-perfil__iniciais {
    width: 96px;
    height: 96px;
    flex: 0 0 auto;
    border-radius: 50%;
    object-fit: cover;
    border: 1px solid var(--linha);
}
.foto-perfil__iniciais {
    display: grid;
    place-items: center;
    border-color: transparent;
    background: var(--marca);
    color: var(--marca-contraste);
    font-size: var(--t-lg);
    font-weight: 600;
    letter-spacing: .02em;
}
.foto-perfil__acoes { display: grid; gap: 6px; min-width: 0; }

/* O nome do arquivo escolhido, escrito pelo script. Vazio até haver escolha. */
.foto-perfil__arquivo {
    font-size: var(--t-micro);
    color: var(--texto-3);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* O <label> vira botão: sem isto ele herdaria o cursor de texto. */
label.botao { cursor: pointer; }

/* ---- Área de texto ---- */
.campo__controle--area { align-items: stretch; }
.campo__controle--area .campo__entrada {
    padding: var(--e3) 12px;
    line-height: 1.6;
    resize: vertical;
    min-height: 220px;
    font-family: inherit;
}

/* Contador de caracteres, alinhado à direita sob a área de texto. Em fonte
   monoespaçada porque o número muda a cada tecla: com fonte proporcional a
   linha inteira dança de largura enquanto se digita. */
.campo__contador {
    justify-self: end;
    font-family: var(--fonte-mono);
    font-size: var(--t-micro);
    color: var(--texto-3);
}
.campo__contador.no-limite { color: var(--erro); }

/* ---- Pré-visualização do ícone escolhido ---- */

/* ---- Marcador em cartão ----
   Tem de fechar a MESMA altura da caixa de um campo comum (≈42px), senão a
   linha da grade fica irregular e o formulário parece torto. Por isso o padding
   e as entrelinhas são apertados: são duas linhas de texto dentro da altura de
   uma caixa de entrada. */
.marcador--cartao {
    align-items: center;
    gap: 10px;
    /* Padding menor que a altura de proposito: quem manda aqui e o
       min-height, e as duas linhas de texto cabem dentro dele com folga. */
    padding: 4px 11px;
    min-height: var(--altura-campo);
    border: 1px solid var(--linha-forte);
    border-radius: var(--r);
    background: var(--sup);
    transition: border-color var(--transicao), background var(--transicao);
}
.marcador--cartao:hover { border-color: var(--texto-3); }
.marcador--cartao:has(input:checked) {
    border-color: var(--marca);
    background: var(--marca-vestigio);
}

.marcador--cartao .marcador__caixa { margin-top: 0; width: 18px; height: 18px; }
.marcador--cartao .marcador__caixa svg { width: 13px; height: 13px; }

.marcador--cartao .marcador__texto { gap: 0; line-height: 1.25; }
.marcador--cartao .marcador__texto strong { font-size: var(--t-sm); }
.marcador--cartao .marcador__texto span { font-size: var(--t-micro); line-height: 1.25; }

/* ---- Cartão-opção: sem caixa de marcação, pinta inteiro quando escolhido ----

   O gesto da referência (InssObra): três botões lado a lado, o escolhido em
   verde sólido. Lá são `<button>` com um campo oculto e JavaScript trocando
   `btn-outline-primary` por `btn-primary`; aqui continua sendo um `input:radio`
   de verdade, e quem pinta é o `:has(input:checked)`.

   A diferença importa: sem script a tela continua correta e enviando o valor, o
   Tab entra no grupo uma vez só e as setas percorrem as opções — comportamento
   que um grupo de botões teria de reimplementar à mão, e que a origem não tem.

   A caixa de marcação sai da tela mas o input NÃO: ele continua no fluxo, só
   visualmente oculto, para o leitor de tela continuar anunciando "opção 1 de 3,
   marcada". Esconder o input com `display:none` o tiraria da navegação. */
.marcador--opcao .marcador__caixa { display: none; }

.marcador--opcao {
    /* Sem a caixa, o texto encosta na borda esquerda. */
    padding-left: var(--e4);
    text-align: left;
}

/* VERDE `--acao`, e não `--marca`: a franquia é azul desde a troca de paletas,
   e era o azul que aparecia aqui. O verde é o do InssObra, que é o desenho que
   esta tela copia. */
.marcador--opcao:has(input:checked) {
    background: var(--acao);
    border-color: var(--acao);
}
.marcador--opcao:has(input:checked) .marcador__texto strong,
.marcador--opcao:has(input:checked) .marcador__texto span {
    color: #fff;
}

/* O foco do teclado tem de aparecer, e com o cartão pintado o anel padrão
   sumiria dentro do próprio verde: por isso ele fica FORA da borda. */
.marcador--opcao:has(input:focus-visible) {
    outline: 2px solid var(--acao);
    outline-offset: 2px;
}

/* ---- Rodapé de formulário ---- */
.form-pe {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--e2);
    flex-wrap: wrap;
    padding: var(--e3) var(--e4);
    border-top: 1px solid var(--linha);
    background: var(--sup-2);
}

/* Dois lados: à esquerda a ação destrutiva, à direita a ação da tela. Longe uma
   da outra de propósito — "Excluir" encostado em "Salvar" é erro esperando
   acontecer. Com o lado esquerdo vazio, o `space-between` já joga o par
   Cancelar/Salvar para a direita, e o rodapé continua igual ao de antes. */
.form-pe__esquerda,
.form-pe__direita {
    display: flex;
    align-items: center;
    gap: var(--e2);
    flex-wrap: wrap;
}

@media (max-width: 480px) {
    .form-pe { flex-direction: column-reverse; align-items: stretch; }
    .form-pe__esquerda,
    .form-pe__direita { width: 100%; }
    .form-pe .botao { flex: 1; justify-content: center; }
}

/* ---- Linha de auditoria ----
   Quem cadastrou e quem mexeu por último, no rodapé da aba de identificação.
   Separada por linha tracejada: é informação sobre o registro, e não mais um
   campo dele. */
.auditoria {
    display: flex;
    flex-wrap: wrap;
    gap: var(--e4);
    margin-top: var(--e4);
    padding-top: var(--e4);
    border-top: 1px dashed var(--linha);
    font-size: var(--t-micro);
    color: var(--texto-3);
}
.auditoria span strong { font-weight: 500; color: var(--texto-2); }

/* ---- Escolha de ícone ----
   Sobre um <select> de verdade. Quem escolhe um ícone precisa VER o desenho:
   "i-landmark" não diz nada a ninguém, e mesmo o rótulo em português —
   "Instituição" — só faz sentido ao lado da figura. O <select> continua sendo o
   campo; este seletor apenas o comanda. */
.icone-escolha {
    position: relative;
    width: 100%;
}
.icone-escolha__botao {
    display: flex;
    align-items: center;
    gap: var(--e2);
    width: 100%;
    min-height: var(--altura-campo);
    padding: 0 11px;
    border: 1px solid var(--linha-forte);
    border-radius: var(--r);
    background: var(--sup);
    color: var(--texto);
    font: inherit;
    font-size: var(--t-base);
    text-align: left;
    cursor: pointer;
    transition: border-color var(--transicao), box-shadow var(--transicao);
}
.icone-escolha__botao:hover { border-color: var(--texto-3); }
.icone-escolha__botao:focus-visible {
    outline: none;
    border-color: var(--marca);
    box-shadow: 0 0 0 3px var(--marca-vestigio);
}
.icone-escolha__marca {
    width: 20px;
    height: 20px;
    flex: 0 0 auto;
    color: var(--marca);
}
.icone-escolha__texto {
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.icone-escolha__seta {
    width: 16px;
    height: 16px;
    flex: 0 0 auto;
    color: var(--texto-3);
}

.icone-painel {
    position: absolute;
    z-index: 60;
    top: calc(100% + 6px);
    left: 0;

    /* Mais largo que o campo, de propósito: preso à largura dele, a grade
       viraria uma coluna só e a escolha voltaria a ser uma lista de nomes —
       exatamente o que este seletor existe para evitar. */
    width: max-content;
    min-width: 100%;
    max-width: min(460px, calc(100vw - 2 * var(--e4)));

    padding: var(--e3);
    border: 1px solid var(--linha);
    border-radius: var(--r-lg);
    background: var(--sup);
    box-shadow: var(--sombra-3);
}
.icone-painel__busca { margin-bottom: var(--e3); }
.icone-painel__grade {
    display: grid;
    /* Colunas que se acomodam sozinhas: em tela estreita viram três, em tela
       larga viram cinco, sem media query. */
    grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
    gap: var(--e2);
    max-height: min(42dvh, 320px);
    overflow-y: auto;
}
.icone-painel__grupo {
    grid-column: 1 / -1;
    margin-top: var(--e2);
    padding: 0 2px;
    font-size: var(--t-micro);
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--texto-3);
}
.icone-painel__grupo:first-child { margin-top: 0; }

.icone-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: var(--e2) 6px;
    border: 1px solid transparent;
    border-radius: var(--r);
    background: none;
    color: var(--texto-2);
    font: inherit;
    font-size: var(--t-micro);
    cursor: pointer;
}
.icone-tile svg { width: 22px; height: 22px; }
.icone-tile__rotulo {
    width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    text-align: center;
}
.icone-tile:hover { background: var(--sup-3); color: var(--texto); }
.icone-tile:focus-visible {
    outline: none;
    border-color: var(--marca);
    box-shadow: 0 0 0 3px var(--marca-vestigio);
}
.icone-tile[aria-selected="true"] {
    border-color: var(--marca);
    background: var(--marca-vestigio);
    color: var(--texto);
}
.icone-tile[hidden] { display: none; }

/* Sem isto, uma busca sem resultado deixa um retângulo vazio, que parece
   defeito e não resposta. */
.icone-painel__vazio {
    margin: 0;
    padding: var(--e5) var(--e4);
    text-align: center;
    font-size: var(--t-sm);
    color: var(--texto-3);
}


/* =============================================================================
   12c · LISTAGENS

   A tabela vira lista de cartões abaixo de 720px. Rolagem horizontal em tela de
   celular funciona mal com o polegar; empilhar é a única forma de manter tudo
   legível sem esconder coluna.
   ============================================================================= */

/* ---- Barra de ferramentas ---- */
.barra {
    display: flex;
    align-items: center;
    gap: var(--e3);
    flex-wrap: wrap;
    margin-bottom: var(--e4);
}
/* Largura fixa, e não elástica: um campo de busca que ocupa a tela inteira
   sugere que cabe muito texto ali, quando o que se digita é "341" ou "itau". */
.barra__busca { flex: 0 1 420px; min-width: 0; }
.barra__acoes { display: flex; gap: var(--e2); flex-wrap: wrap; margin-left: auto; }
@media (max-width: 560px) { .barra__busca { flex: 1 1 100%; } }

/* ---- Tabela ---- */
.tabela {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--t-sm);
}

.tabela thead th {
    padding: var(--e3) var(--e4);
    background: var(--sup-2);
    border-bottom: 1px solid var(--linha);
    font-family: var(--fonte-mono);
    font-size: var(--t-micro);
    font-weight: 500;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--texto-3);
    text-align: left;
    white-space: nowrap;
}

.tabela tbody td {
    padding: var(--e3) var(--e4);
    border-bottom: 1px solid var(--linha);
    vertical-align: middle;
}

.tabela tbody tr:last-child td { border-bottom: 0; }
.tabela tbody tr { transition: background var(--transicao); }
.tabela tbody tr:hover { background: var(--sup-2); }

/* Linha inativa continua legível: apagá-la esconderia justamente o que a
   pessoa veio conferir. O sinal fica no selo e num tom mais discreto. */
.tabela tbody tr.inativa td { color: var(--texto-3); }
.tabela tbody tr.inativa .tabela__link { color: var(--texto-3); }

/* Números alinhados: código de banco é comparado de cima a baixo. */
.tabela__num {
    text-align: right;
    width: 1%;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.tabela thead th.tabela__num { text-align: right; }

/* Coluna do ícone: largura mínima, na cor da área. É identificação visual, e
   não decoração — quem varre a lista reconhece a linha antes de ler. */
.tabela__icone { width: 1%; padding-right: 0 !important; }
.tabela__icone svg {
    width: 22px;
    height: 22px;
    color: var(--marca);
}
.tabela tbody tr.inativa .tabela__icone svg { color: var(--texto-3); }
@media (max-width: 720px) {
    .tabela__icone { padding: var(--e2) var(--e4) 0 !important; }
    .tabela__icone::before { content: none; }
}

.tabela__link { font-weight: 500; color: var(--texto); }
.tabela__link:hover { color: var(--marca); }

.tabela__apoio { font-size: var(--t-xs); color: var(--texto-3); }

/* ---- Coluna de código em árvore ----

   A lista já vem ordenada por código, que é a ordem da árvore. O recuo por
   nível é o que transforma essa ordem em desenho de estrutura, sem componente
   de árvore nenhum e sem uma única linha de JavaScript.

   O recuo é padding, e não espaço no texto: assim o código continua
   selecionável e copiável inteiro, e a busca do navegador o encontra.

   O traço à esquerda é a guia visual do nível. Só aparece a partir do segundo:
   um traço na raiz sugeriria que ela pende de alguma coisa. */
.tabela__arvore {
    position: relative;
    display: inline-block;
    padding-left: calc(var(--recuo, 0) * 1.15rem);
    font-variant-numeric: tabular-nums;
}
.tabela__arvore::before {
    content: "";
    position: absolute;
    left: calc(var(--recuo, 0) * 1.15rem - 0.7rem);
    top: 50%;
    /* Largura zero na raiz, e 0.45rem em qualquer nível abaixo. O min() faz o
       papel de um "se maior que zero" que o CSS não tem — e evita depender de
       um seletor de atributo sobre o style, que o navegador pode normalizar. */
    width: calc(min(var(--recuo, 0), 1) * 0.45rem);
    height: 1px;
    background: var(--borda);
}

/* No celular a tabela vira cartões e a coluna some da linha: o recuo perderia
   o sentido, porque não há mais coluna de códigos para alinhar. */
@media (max-width: 720px) {
    .tabela__arvore { padding-left: 0; }
    .tabela__arvore::before { content: none; }
}

.tabela__acoes {
    width: 1%;
    white-space: nowrap;
    text-align: right;
}

/* O botão de conversar virou <form> — ele cria conversa, e isso é POST com
   token anti-CSRF. Um <form> é bloco e quebraria a fileira de ícones da célula,
   então ele volta a ser inline e some do fluxo como se fosse o próprio botão. */
.tabela__acao-forma {
    display: inline;
    margin: 0;
}

.tabela__rodape {
    display: flex;
    justify-content: space-between;
    gap: var(--e4);
    flex-wrap: wrap;
    padding: var(--e3) var(--e4);
    border-top: 1px solid var(--linha);
    background: var(--sup-2);
    font-size: var(--t-xs);
    color: var(--texto-3);
}

/* ---- Tabela empilhada, em tela estreita ---- */
@media (max-width: 720px) {
    .tabela thead { display: none; }
    .tabela, .tabela tbody, .tabela tr, .tabela td { display: block; width: auto; }

    .tabela tbody tr {
        padding: var(--e3) 0;
        border-bottom: 1px solid var(--linha);
    }
    .tabela tbody tr:hover { background: none; }

    .tabela tbody td {
        display: grid;
        grid-template-columns: 40% 1fr;
        gap: var(--e3);
        padding: 5px var(--e4);
        border: 0;
        text-align: left;
    }

    /* O rótulo da coluna volta ao lado do valor, vindo do atributo. */
    .tabela tbody td[data-rotulo]::before {
        content: attr(data-rotulo);
        font-family: var(--fonte-mono);
        font-size: var(--t-micro);
        letter-spacing: .08em;
        text-transform: uppercase;
        color: var(--texto-3);
    }

    .tabela__acoes {
        display: flex;
        gap: var(--e2);
        justify-content: flex-start;
        padding-top: var(--e2);
    }
    .tabela__acoes::before { content: none; }
}

/* ---- Campo com erro ---- */
.campo__controle--erro {
    border-color: var(--erro);
    background: var(--erro-vestigio);
}
.campo__controle--erro:focus-within {
    border-color: var(--erro);
    box-shadow: 0 0 0 3px var(--erro-vestigio);
}

.campo__erro {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    font-size: var(--t-xs);
    color: var(--erro);
}
.campo__erro svg { width: 14px; height: 14px; margin-top: 1px; flex: 0 0 auto; }

/* O parágrafo de erro nasce `hidden` e só o script o mostra. Sem esta linha ele
   aparecia vazio, com o triângulo solto sob o campo: `display: flex` acima é
   regra de autor e vence o `[hidden] { display: none }` do navegador, que é
   regra de agente. É o mesmo motivo pelo qual .modal, .aba e .aba-painel já
   trazem a sua — esta faltava. */
.campo__erro[hidden] { display: none; }

/* Código curto: caixa estreita, monoespaçada e centralizada. Um campo de três
   dígitos ocupando a largura inteira sugere que cabe mais coisa. */
.campo__entrada--codigo {
    max-width: 7ch;
    font-family: var(--fonte-mono);
    font-variant-numeric: tabular-nums;
    letter-spacing: .06em;
}

/* ---- Campo que outro preencheu -------------------------------------------

   A regra: campo preenchido por alguém que não foi a pessoa NÃO PODE PARECER
   campo digitado. Hoje a origem é confiável — proposta e lead, cópia de dado
   já gravado. Amanhã será a leitura automática de documento, e aí um m²
   lido errado do alvará não é defeito de tela: é contrato assinado errado,
   com o cliente tendo assinado embaixo.

   Tracejado e não colorido-sólido de propósito: o campo continua editável e
   comum, e a borda só conta de onde o valor veio. Sólido pareceria travado.

   O `focus` limpa a marca — a partir do instante em que a pessoa mexe no
   campo, o valor é dela. */
.campo__entrada--sugerido {
    background: var(--info-vestigio);
    border-color: var(--info);
    border-style: dashed;
}

.campo__entrada--sugerido:focus {
    border-style: solid;
    background: var(--sup);
}

/* ---- Aviso dentro do conteúdo --------------------------------------------

   Diferente do DialogMessage, que é uma janela e interrompe. Este fica na
   página, explicando algo sobre o que está na tela — "estes campos vieram
   preenchidos", "estes documentos não batem". Quem lê continua trabalhando.

   Nasceu para o aviso de campos sugeridos, e a conferência entre documentos
   usa o mesmo desenho: as duas dizem "olhe isto antes de seguir". */
.aviso {
    display: flex;
    align-items: flex-start;
    gap: var(--e3);
    padding: var(--e3) var(--e4);
    margin-bottom: var(--e4);
    border: 1px solid var(--linha);
    border-left-width: 3px;
    border-radius: var(--r-lg);
    background: var(--sup);
    font-size: .88rem;
}

.aviso > svg {
    width: 20px;
    height: 20px;
    flex: none;
    margin-top: 1px;
}

.aviso strong {
    display: block;
    margin-bottom: 2px;
}

.aviso p {
    margin: 0;
    color: var(--texto-2);
}

.aviso--info    { border-left-color: var(--info); }
.aviso--info    > svg { color: var(--info); }
.aviso--atencao { border-left-color: var(--aviso); background: var(--aviso-vestigio); }
.aviso--atencao > svg { color: var(--aviso); }
.aviso--erro    { border-left-color: var(--erro); background: var(--erro-vestigio); }
.aviso--erro    > svg { color: var(--erro); }

/* ---- Divergência entre documentos -----------------------------------------

   O mesmo dado lido de dois documentos, com valores diferentes. A tarja
   lateral diz o peso: metragem e nome do proprietário mudam o contrato;
   bairro, não.

   Cartão e não linha de tabela: cada divergência carrega DUAS OU MAIS
   afirmações, e uma tabela de tabelas seria ilegível. */
.divergencia {
    border: 1px solid var(--linha);
    border-left-width: 4px;
    border-radius: var(--r-lg);
    padding: var(--e3) var(--e4);
    margin-bottom: var(--e3);
    background: var(--sup-2);
}

.divergencia--alta  { border-left-color: var(--erro); }
.divergencia--media { border-left-color: var(--aviso); }
.divergencia--baixa { border-left-color: var(--texto-3); }

.divergencia__topo {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--e3);
    margin-bottom: var(--e2);
}

.divergencia__tabela {
    width: 100%;
    border-collapse: collapse;
}

.divergencia__tabela td {
    padding: 5px 0;
    border-top: 1px solid var(--linha);
    font-size: .85rem;
}

.divergencia__tabela td:last-child {
    text-align: right;
    width: 1%;
    white-space: nowrap;
}

/* Código hierárquico: `1.02.001.0001` são 13 caracteres, e não os 3 do código
   COMPE — o teto de 7ch acima cortava o que a máscara acabara de escrever.

   AQUI NÃO ENTRA LARGURA.

   A tentativa anterior foi `max-width: 15ch`, e ela errava por dois motivos que
   se somam: `box-sizing` é border-box, então os 24px de padding do próprio
   campo saem de dentro dos 15ch; e `ch` mede o glifo, ignorando o
   `letter-spacing` de .06em que cada caractere ainda acrescenta. Sobravam 102px
   para um código que pede 120px, e o texto rolava escondendo o começo.

   Quem dimensiona é o atributo `size`, no template, com o número vindo de
   CodigoHierarquico.TAMANHO_MASCARADO: o navegador o resolve com a fonte de
   verdade, letter-spacing incluído, e soma o padding por fora. Mudar as
   larguras dos trechos ajusta o campo junto, sem ninguém tocar em CSS. */
.campo__entrada--conta {
    font-family: var(--fonte-mono);
    font-variant-numeric: tabular-nums;
    letter-spacing: .06em;
}


/* =============================================================================
   13 · ESTADOS E VAZIOS
   ============================================================================= */

.estado {
    display: grid;
    justify-items: center;
    gap: var(--e3);
    padding: var(--e7) var(--e5);
    text-align: center;
}
.estado__arte { width: 116px; height: 116px; color: var(--linha-forte); }

/* O vazio que espera uma ESCOLHA, e não um cadastro.

   No painel da conversa não há nada a convidar: a lista está do lado, e o que
   falta é um clique. A arte cheia de 116px em cor de marca vira um símbolo
   enorme no meio da tela, competindo com a própria lista que deveria ser
   olhada. */
.estado--discreto .estado__arte {
    width: 56px;
    height: 56px;
    color: var(--linha-forte);
    opacity: .7;
}
.estado--discreto .estado__titulo { font-size: var(--t-md); }
.estado--discreto .estado__texto { max-width: 42ch; }

/* Cadastro ainda vazio: o símbolo do próprio cadastro, na cor da área. Convida,
   em vez de só ocupar espaço — ao contrário da arte de "nada encontrado", que é
   cinza porque não há nada a convidar. */
.estado__arte--marca { color: var(--marca); opacity: .85; }
.estado__codigo {
    font-family: var(--fonte-marca);
    font-size: 3.4rem;
    font-weight: 600;
    line-height: 1;
    letter-spacing: -.03em;
    color: var(--linha-forte);
    font-variant-numeric: tabular-nums;
}
.estado__titulo { font-size: var(--t-lg); }
.estado__texto { max-width: 52ch; font-size: var(--t-sm); color: var(--texto-3); }
.estado__acoes { display: flex; gap: var(--e2); flex-wrap: wrap; justify-content: center; margin-top: var(--e2); }

/* Aviso de ausência de rede, fixado no rodapé da janela */
.offline {
    position: fixed;
    left: 50%;
    bottom: var(--e4);
    transform: translateX(-50%);
    display: none;
    align-items: center;
    gap: var(--e2);
    padding: 8px 16px;
    border-radius: 99px;
    background: var(--trilho-bg-fundo);
    color: var(--trilho-forte);
    font-size: var(--t-xs);
    box-shadow: var(--sombra-3);
    z-index: 150;
}
.offline[data-visivel="sim"] { display: flex; }
.offline svg { width: 15px; height: 15px; color: var(--aviso); }


/* =============================================================================
   14 · RODAPÉ
   ============================================================================= */

.rodape {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--e4);
    flex-wrap: wrap;
    height: var(--rodape-h);
    padding: 0 var(--e5);
    border-top: 1px solid var(--linha);
    background: var(--sup-2);
    font-size: var(--t-xs);
    color: var(--texto-3);
}
.rodape__tecnico {
    font-family: var(--fonte-mono);
    font-size: 10px;
    letter-spacing: .05em;
}

/* O build como botão: abre "O que mudou". Continua com a cara da linha técnica
   — quem não procura não tropeça nele —, e só se revela no passar do cursor. */
.rodape__novidades {
    padding: 2px 4px;
    border: 0;
    border-radius: var(--r);
    background: none;
    color: inherit;
    cursor: pointer;
}
.rodape__novidades:hover,
.rodape__novidades:focus-visible {
    color: var(--acao);
    text-decoration: underline;
}

/* ---- A janela "O ReduzziHub foi atualizado" ----
   Mais larga que a mensagem comum: são itens de uma ou duas frases, e numa
   caixa de 430px cada um viraria um parágrafo de cinco linhas. O corpo rola por
   dentro, para o botão Entendi ficar sempre à vista com o histórico aberto. */
.novidades {
    width: min(640px, 100%);
    max-height: calc(100vh - 2 * var(--e4));
    display: flex;
    flex-direction: column;
}

.novidades__corpo {
    flex: 1 1 auto;
    min-height: 0;
}

.novidades__bloco + .novidades__bloco {
    margin-top: var(--e4);
    padding-top: var(--e4);
    border-top: 1px dashed var(--linha);
}

.novidades__quando {
    margin: 0;
    font-family: var(--fonte-mono);
    font-size: var(--t-xs);
    color: var(--texto-3);
}

.novidades__titulo {
    margin: 2px 0 0;
    font-size: var(--t-base);
    font-weight: 600;
    color: var(--texto);
    line-height: 1.35;
}

.novidades__itens li { margin-bottom: var(--e2); }

.novidades__historico {
    margin-top: var(--e4);
    padding-top: var(--e3);
    border-top: 1px solid var(--linha);
}
.novidades__historico summary {
    cursor: pointer;
    font-size: var(--t-xs);
    font-weight: 600;
    color: var(--acao);
}
.novidades__historico[open] summary { margin-bottom: var(--e3); }

.novidades__filtro {
    display: flex;
    align-items: center;
    gap: var(--e2);
    margin-bottom: var(--e3);
}
.novidades__filtro select { flex: 1; }

.novidades__vazio {
    color: var(--texto-3);
    font-size: var(--t-sm);
    margin: 0 0 var(--e3);
}


/* =============================================================================
   15 · UTILITÁRIOS
   ============================================================================= */

/* Sprite de ícones: presente no documento, invisível e fora do fluxo.
   Precisa ser classe, e não atributo style, porque a política de conteúdo
   recusa estilo embutido (ver EncodingFilter). */
.sprite {
    position: absolute;
    width: 0;
    height: 0;
    overflow: hidden;
}

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

/* Salto para o conteúdo: primeiro elemento focável da página */
.pular {
    position: absolute;
    left: var(--e3);
    top: -60px;
    z-index: 300;
    padding: 10px 16px;
    border-radius: var(--r);
    background: var(--marca);
    color: var(--marca-contraste);
    font-size: var(--t-sm);
    font-weight: 500;
    transition: top var(--transicao);
}
.pular:focus { top: var(--e3); text-decoration: none; }

.rolagem-h { overflow-x: auto; }

.espaco-topo { margin-top: var(--e5); }


/* =============================================================================
   16 · RESPONSIVIDADE
   ============================================================================= */

/* Tela de acesso vira coluna única: o lado da marca some, porque em um celular
   ele empurraria o formulário para fora da primeira dobra. */
@media (max-width: 900px) {
    .acesso { grid-template-columns: 1fr; }
    .acesso__marca { display: none; }
    .acesso__painel { padding: var(--e6) var(--e4); align-content: start; }
    .acesso__cartao { padding-top: var(--e5); }
}

/* Trilho vira gaveta sobreposta. Em tela estreita não há largura para dividir
   com um menu permanente. */
@media (max-width: 860px) {
    .app,
    .app[data-trilho="recolhido"] {
        grid-template-columns: minmax(0, 1fr);
        grid-template-areas:
            "topo"
            "conteudo"
            "rodape";
    }

    /* Sem coluna de menu, a barra começa na borda. As duas regras juntas —
       inclusive a do `recolhido`, que aqui não quer dizer nada — porque a do
       trilho recolhido continua valendo em largura estreita se a pessoa tiver
       recolhido o menu antes no computador: o estado é lembrado. */
    .topo,
    .app[data-trilho="recolhido"] .topo { left: 0; }

    /* O z-index precisa estar AQUI, e não só no `.trilho` de dentro.

       `position: fixed` cria contexto de empilhamento. Sem um z-index próprio,
       esse contexto nasce no nível 0 e PRENDE lá dentro o `z-index: 50` do
       `.trilho` — o número existia, mas não valia para fora. A gaveta ficava
       embaixo da barra superior (40) e embaixo da cortina (45), e os três
       sintomas relatados eram um defeito só:

         topo cinza          a barra superior pintada por cima da gaveta
         tudo apagado        a cortina de 50% de preto por cima do resto
         menu não responde   o clique caía na CORTINA, não no botão; e como
                             `evento.target` deixava de estar dentro de
                             `.app__trilho`, o fechamento por "clique fora"
                             entendia cada toque no menu como toque fora

       O valor é o mesmo 50 do `.trilho`: a camada pretendida não mudou, o que
       faltava era declará-la em quem forma o contexto. */
    .app__trilho {
        position: fixed;
        top: 0;
        left: 0;
        z-index: 50;
        width: min(var(--trilho-w), 86vw);
        height: 100vh;
        transform: translateX(-100%);
        transition: transform var(--transicao);
        box-shadow: var(--sombra-3);
    }
    .app[data-gaveta="aberta"] .app__trilho { transform: none; }

    /* Cortina: fecha a gaveta ao toque fora dela. */
    .app[data-gaveta="aberta"]::after {
        content: "";
        position: fixed;
        inset: 0;
        z-index: 45;
        background: rgba(7, 12, 10, .5);
    }

    /* No modo gaveta o trilho está sempre completo, nunca em ícones. */
    .app[data-trilho="recolhido"] .marca__texto,
    .app[data-trilho="recolhido"] .nav__rotulo,
    .app[data-trilho="recolhido"] .nav__seta,
    .app[data-trilho="recolhido"] .trilho__pe { display: revert; }

    /* `.nav__filhos` fica FORA da lista de `revert` acima de propósito: ali o
       `revert` abriria todos os submenus de uma vez, porque venceria em
       especificidade o `[data-aberto="nao"]` que os mantém fechados. Quem manda
       continua sendo o estado do grupo — só o `sim` volta a aparecer.

       Sem esta linha o submenu simplesmente não abria na gaveta: quem tinha
       deixado o trilho recolhido no computador levava o `display: none` do modo
       ícone junto para o celular, e o clique no grupo trocava o `data-aberto`
       para `sim` sem nada aparecer na tela. */
    .app[data-trilho="recolhido"] .nav__filhos[data-aberto="sim"] { display: block; }

    .app[data-trilho="recolhido"] .marca { padding: 0 var(--e4); justify-content: flex-start; }
    .app[data-trilho="recolhido"] .nav__linha { justify-content: flex-start; padding: 8px 10px; }

    .conteudo { padding: var(--e4) var(--e4) var(--e6); }
    .contexto { display: none; }
}

@media (max-width: 560px) {
    .usuario__nome { display: none; }
    .rodape { height: auto; padding: var(--e3) var(--e4); }
    .pagina__cabecalho { align-items: flex-start; }
}


/* =============================================================================
   16.9 · OCUPADO — nada no sistema pode parecer travado
   =============================================================================

   Três sinais, para três esperas diferentes. Um só não serve: barra para tudo
   é ruído, e véu para tudo trava a tela em operações de meio segundo.

     barra no topo   navegação e requisição de fundo — informa sem atrapalhar
     botão ocupado   a ação que a pessoa disparou; ALÉM de informar, impede o
                     segundo clique, que em gravação vira registro duplicado
     véu             só o que bloqueia de verdade e demora, como o teste de
                     SMTP: a ida ao servidor de e-mail leva segundos

   A barra só aparece depois de um atraso (ver ATRASO no script). Navegação de
   80 ms com barra piscando é pior que navegação sem barra nenhuma.
   ============================================================================= */

/* ---- Barra de progresso no topo ---- */
.progresso {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    z-index: 9999;
    pointer-events: none;   /* nunca rouba clique */
    opacity: 0;
    transition: opacity .2s ease;
}
.progresso[data-ativo] { opacity: 1; }

/* A barra nasce LIGADA no HTML da página, e o script a apaga quando a tela
   fica pronta.

   Sem isso ela não aparecia nunca: as telas carregam em 33–163 ms aqui, e o
   atraso do script era maior que a navegação inteira. A barra existia, estava
   correta, e era invisível — que é o mesmo que não existir.

   Assim o sinal é contínuo: some na página que sai, já está desenhado na que
   entra, e só apaga quando ela termina de montar.

   A animação é desistência para o caso de o script não carregar: sem ela a
   barra ficaria no ar para sempre. Não dá para acender por script em linha —
   a CSP é 'self' puro e recusaria. */
.progresso[data-inicial] { opacity: 1; }

/* A desistência é animação, e por isso só existe onde há movimento.

   A regra global de `prefers-reduced-motion` desta folha força
   `animation-duration: .01ms !important` em tudo. Com a desistência fora deste
   bloco, ela pulava direto para o quadro final — opacidade zero — e o
   `forwards` congelava ali: a barra ficava invisível para quem pede menos
   movimento. O sinal de "estou ocupado" não pode depender de animação, e muito
   menos ser APAGADO por ela. */
@media (prefers-reduced-motion: no-preference) {
    .progresso[data-inicial] { animation: progresso-desiste 8s linear forwards; }
}
@keyframes progresso-desiste {
    0%, 92% { opacity: 1; }
    100%    { opacity: 0; }
}

.progresso__trilho {
    height: 100%;
    width: 100%;
    overflow: hidden;
    background: var(--marca-vestigio);
}

/* Duas barras deslizando em tempos diferentes: é o padrão "indeterminado", e
   é o honesto aqui — não sabemos quanto falta, então uma barra que enche até
   90%% e para mentiria sobre o progresso. */
.progresso__barra {
    display: block;
    height: 100%;
    width: 100%;
    background: linear-gradient(90deg,
                var(--marca) 0%, var(--marca-clara) 50%, var(--marca) 100%);
    transform-origin: 0% 50%;
    animation: progresso-desliza 1.4s cubic-bezier(.4, 0, .2, 1) infinite;
}
.progresso__barra:nth-child(2) {
    animation: progresso-desliza-2 1.4s cubic-bezier(.165, .84, .44, 1) 1.15s infinite;
    position: relative;
    top: -3px;
}

@keyframes progresso-desliza {
    0%   { transform: translateX(-100%) scaleX(.4); }
    60%  { transform: translateX(20%)   scaleX(.7); }
    100% { transform: translateX(100%)  scaleX(.3); }
}
@keyframes progresso-desliza-2 {
    0%   { transform: translateX(-100%) scaleX(.15); }
    100% { transform: translateX(100%)  scaleX(.6); }
}

/* O botão traz `display` próprio, e regra de autor vence o `[hidden]` do
   navegador — sem esta linha, um botão marcado como escondido continua na tela.
   Foi o que aconteceu com o submit do teste de e-mail, que o script esconde
   quando há JavaScript: ele reaparecia embaixo do painel, com spinner e tudo.

   Mesmo motivo de `.campo__erro[hidden]`, alguns blocos acima. */
.botao[hidden] { display: none !important; }

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

   O rótulo continua legível: trocar o texto por "Aguarde" faria a largura do
   botão saltar e mexeria no layout inteiro no instante do clique. */
.botao[data-ocupado] {
    position: relative;
    pointer-events: none;
    color: transparent !important;
}
.botao[data-ocupado] > * { visibility: hidden; }

.botao[data-ocupado]::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 16px;
    height: 16px;
    margin: -8px 0 0 -8px;
    border-radius: 50%;
    border: 2px solid currentColor;
    /* A cor do botão, com uma volta transparente: é o que dá a sensação de giro
       sem precisar de imagem nem de SVG animado. */
    border-color: rgba(255, 255, 255, .35);
    border-top-color: #fff;
    animation: gira .7s linear infinite;
}
/* Botão claro: o anel branco sumiria no fundo. */
.botao:not(.botao--principal):not(.botao--perigo)[data-ocupado]::after {
    border-color: var(--linha);
    border-top-color: var(--marca);
}

/* De 0 a 360 EXPLÍCITO. Escrito só com `to`, o quadro inicial vinha do
   transform computado -- que é `none` -- e a primeira volta interpolava de um
   valor de tipo diferente. Com os dois quadros declarados a volta é sempre a
   mesma, e a primeira não destoa das seguintes.

   `translateZ(0)` viaja junto nos dois quadros para a camada de compositor
   não ser descartada no meio da animação. */
@keyframes gira {
    from { transform: translateZ(0) rotate(0deg); }
    to   { transform: translateZ(0) rotate(360deg); }
}

/* ---- Véu, para o que bloqueia mesmo ---- */
.veu {
    position: fixed;
    inset: 0;
    z-index: 9998;
    display: grid;
    place-items: center;
    /* Desenho adotado do sistema Sena. O desfoque subiu de 2px para 4px --
       com 4px o que fica atrás deixa de competir com a mensagem, e o véu passa
       a parecer uma camada, não um filtro.

       O fundo continua saindo do tema, e não fixo como lá: o Sena tem uma cor
       clara escrita à mão, que sobre o tema escuro do ReduzziHub clarearia a tela
       inteira no meio de uma operação. */
    /* .82 e nao .55, pelo mesmo motivo que o Sena usa .85: o veu precisa ser
       uma SUPERFICIE, e nao um filtro. Com 55% o fundo atravessava, e numa tela
       meio escura e meio clara -- como a de entrada -- o anel branco sumia na
       metade clara. A cor continua sendo a nossa, verde-escura; o que se adota
       do Sena e a opacidade que faz o conteudo do veu ter um chao so. */
    background: rgba(12, 24, 20, .82);
    opacity: 0;
    transition: opacity .18s ease;
}
/* APAGADO NÃO ROUBA CLIQUE.

   O véu cobre a tela inteira e nasce com opacity: 0. Sem esta linha, um véu
   que ficasse sem [data-ativo] e sem [hidden] — por um caminho de código que
   esqueceu de escondê-lo — seria uma folha invisível engolindo todo clique da
   página, sem nada na tela explicando por quê. A barra de progresso já se
   protege assim desde sempre (ver .progresso). */
.veu { pointer-events: none; }
.veu[data-ativo] { opacity: 1; pointer-events: auto; }
.veu[hidden] { display: none; }

/* Nasce aceso no HTML, como a barra, e o script o apaga quando a tela fica
   pronta. A desistência vale só onde há movimento, pelo mesmo motivo da barra:
   sob `prefers-reduced-motion` a animação salta para o quadro final e o véu
   ficaria preso na tela. */
.veu[data-inicial] { opacity: 1; }

@media (prefers-reduced-motion: no-preference) {
    .veu[data-inicial] { animation: veu-desiste 8s linear forwards; }
}
@keyframes veu-desiste {
    0%, 92% { opacity: 1; }
    100%    { opacity: 0; visibility: hidden; }
}

/* SEM CARTÃO, como no Sena: o anel, o texto e a barra ficam direto sobre o
   véu desfocado. O cartão branco competia com o desfoque -- desfocar o fundo
   serve para ele sumir, e um retângulo opaco por cima devolvia o peso que o
   desfoque tinha tirado. */
.veu__caixa {
    display: grid;
    justify-items: center;
    gap: var(--e4);
    max-width: 320px;
    text-align: center;
    background: none;
    box-shadow: none;
    padding: 0;
}

/* SEM `backdrop-filter`, e a razão é o engasgo.

   Um fundo desfocado obriga o navegador a REFAZER o desfoque a cada quadro
   enquanto qualquer coisa se mexe por cima -- e o que se mexe aqui é
   justamente o anel. O resultado é a rotação travando de tempos em tempos,
   sempre nas máquinas mais fracas, que são as que mais esperam.

   E o desfoque já não estava pagando o próprio custo: a 82% de opacidade o
   fundo praticamente não aparece. Trocamos um efeito quase invisível por uma
   rotação lisa.

   ---- O anel duplo, do Sena ----

   Dois anéis concêntricos girando em sentidos OPOSTOS: o de fora em 0,8s, o de
   dentro em 1,2s ao contrário. O contraste entre as duas velocidades é o que
   faz o conjunto parecer que está trabalhando, e não apenas rodando.

   Os dois saem de --marca, que muda com a área (verde na Franquia, azul na
   Franqueadora, roxo na Light System) e com o tema. O de dentro usa opacidade,
   e não um segundo token de cor: assim ele acompanha as três áreas e os dois
   temas sem nenhuma tabela de exceções. */
.veu__anel {
    position: relative;
    width: 56px;
    height: 56px;
}

.veu__anel::before,
.veu__anel::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 50%;
    border: 3px solid transparent;
}

/* Branco no anel de fora: sobre o véu escuro, o verde da marca perdia
   contraste justamente na parte que gira. A marca fica na letra do meio, que
   é onde a cor identifica sem precisar competir. */
/* `will-change` e `translateZ(0)` põem cada anel na PRÓPRIA camada do
   compositor. Sem isso o navegador redesenha a região inteira a cada quadro;
   com isso ele só reaproveita a textura e gira, que é trabalho de GPU e não
   sai do orçamento de 16ms. */
.veu__anel::before {
    border-top-color: #fff;
    border-right-color: #fff;
    will-change: transform;
    animation: gira .8s linear infinite;
}

.veu__anel::after {
    inset: 6px;
    border-bottom-color: var(--marca);
    border-left-color: var(--marca);
    opacity: .9;
    will-change: transform;
    animation: gira 1.2s linear infinite reverse;
}

/* A marca no meio do anel, pulsando. No Sena é o nome do sistema; aqui são as
   duas letras, que cabem nos 56px sem encolher a fonte a ponto de sumir. */
/* FLEX, e não grid, e a diferença é visível.

   O selo era um texto só ("RT") e um único item de grid. Ao virar R + <em>H</em>
   passou a ter DOIS itens — e `grid-auto-flow: column` deu uma coluna a cada
   um, com `place-items: center` centralizando os dois dentro das suas: as
   letras nasceram separadas por um vão que não existia antes.

   Em flex sem `gap` elas voltam a se encostar como texto corrido, e o conjunto
   continua centrado no anel. */
.veu__marca {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0;
    font-family: var(--fonte-marca);
    font-size: 13px;
    font-weight: 800;
    letter-spacing: .5px;
    color: #fff;
    animation: veu-pulsa 1.5s ease-in-out infinite;
}

/* O "H" na cor da área, como no logotipo do trilho — lá é
   `Reduzzi<em>Hub</em>`, e a mesma regra pinta o `em`. Duas cores fazem o selo
   ser lido como a marca do sistema, e não como duas letras quaisquer.

   `--marca-clara`, e não `--marca`: o fundo do véu é escuro, e o tom fechado
   sumiria nele. */
.veu__marca em {
    font-style: normal;
    color: var(--marca-clara);
}

/* A marca pulsa só na OPACIDADE. A escala saiu: ela redesenhava o texto a
   cada quadro -- letra é traçado, e traçado reescalado não se reaproveita --
   e era o segundo motivo do engasgo, junto com o desfoque. Opacidade é
   composição pura. */
@keyframes veu-pulsa {
    0%, 100% { opacity: .55; }
    50%      { opacity: 1; }
}

/* A barra que desliza sob o texto. Não mede progresso -- e não finge medir:
   ela atravessa e recomeça, dizendo "ainda estou aqui" a quem esperou o
   bastante para desconfiar. */
.veu__barra {
    width: 160px;
    height: 3px;
    border-radius: 3px;
    background: rgba(255, 255, 255, .25);
    overflow: hidden;
}

.veu__barra::after {
    content: '';
    display: block;
    width: 40%;
    height: 100%;
    border-radius: 3px;
    background: #fff;
    animation: veu-desliza 1.2s ease-in-out infinite;
}

@keyframes veu-desliza {
    0%   { transform: translateX(-100%); }
    100% { transform: translateX(400%); }
}

/* Branco, e não --texto-2: sem o cartão, o texto passou a ficar sobre o véu
   escuro, onde o cinza de corpo de texto quase desaparecia. */
.veu__texto {
    font-size: var(--t-sm);
    color: #fff;
    line-height: 1.45;
    text-shadow: 0 1px 2px rgba(0, 0, 0, .4);
}

/* Sem movimento: o anel para de girar, mas o véu e a barra continuam
   aparecendo — a informação "estou ocupado" não pode depender de animação. */
@media (prefers-reduced-motion: reduce) {
    /* `!important` porque é preciso: a regra global desta folha força
       `animation-duration: .01ms !important` em tudo, e uma animação assim
       salta direto para o último quadro. No caso da barra esse quadro é
       `translateX(100%)` — fora da tela. E declaração de animação vence
       declaração normal, então `transform: none` sozinho não bastava: a barra
       sumia para quem pede menos movimento.

       É a terceira vez que a mesma armadilha aparece hoje. A regra que fica:
       um sinal de "estou ocupado" nunca pode depender de animação para ser
       visto — a animação enfeita, a cor informa. */
    .progresso__barra,
    .botao[data-ocupado]::after,
    /* O VÉU É A EXCEÇÃO: aqui o anel continua girando, só que devagar.
       "Reduzir movimento" é reduzir, e não abolir -- e uma rotação lenta e
       constante não tem paralaxe, deslocamento nem repique, que são as três
       coisas que incomodam quem pede menos movimento.

       Foi um erro meu tirar o giro daqui: no Windows com animações
       desligadas -- o padrão de muita máquina em RDP -- o véu ficava
       inteiramente parado, e um indicador de "estou trabalhando" parado
       parece um sistema travado. O remédio era pior que a doença.

       O que continua abolido é o que SALTA: a marca para de pulsar e a barra
       para de correr, virando uma barra cheia. */
    /* Os longhands vao repetidos de proposito. A regra global da secao 17
       forca animation-duration .01ms E animation-iteration-count 1, as
       duas com !important, em '*, *::before, *::after'. A minha ganha por
       especificidade -- mas escrever so o atalho deixaria o giro dependendo de
       um empate de cascata que ninguem lembra ao editar. Explicito, quem mexer
       ve o que esta sendo revertido. */
    .veu__anel::before {
        animation: gira 2.4s linear infinite !important;
        animation-duration: 2.4s !important;
        animation-iteration-count: infinite !important;
    }
    .veu__anel::after {
        animation: gira 3.2s linear infinite reverse !important;
        animation-duration: 3.2s !important;
        animation-iteration-count: infinite !important;
    }

    .veu__marca { animation: none !important; opacity: 1; transform: none; }
    .veu__barra::after {
        animation: none !important;
        width: 100%;
        transform: none;
    }

    /* Uma barra cheia, parada. Diz a mesma coisa sem se mexer. */
    .progresso__barra {
        transform: none !important;
        opacity: 1;
    }
    /* A segunda existe só para o efeito de deslize. Sem movimento, sobra. */
    .progresso__barra:nth-child(2) { display: none; }

    /* O botão continua virando um círculo cheio: ele é pequeno demais para
       uma rotação lenta ser percebida. */
    .botao[data-ocupado]::after { border-color: currentColor; }
}


/* =============================================================================
   16.9 · TABELA VAU
   ============================================================================= */

/* ---- Texto de contexto na barra de ferramentas ----

   Nas listas a barra começa com o campo de busca. Aqui não há o que buscar: são
   27 linhas fixas, e o que a pessoa precisa saber ao chegar é QUAL competência
   está valendo. O lugar do campo passa a ser desse texto. */
.barra__texto { flex: 1 1 auto; min-width: 0; }
.barra__titulo { font-size: var(--t-base); }
.barra__apoio { font-size: var(--t-xs); color: var(--texto-3); }

/* ---- Painel que pede uma decisão ----

   A faixa lateral, e não a borda inteira: um cartão contornado de laranja lê
   como erro, e isto não é erro — é uma carga esperando conferência. A faixa diz
   "olhe aqui" sem dizer "deu ruim". */
.painel--aviso {
    border-color: var(--aviso);
    border-left-width: 3px;
}
.painel--aviso .painel__cabecalho { background: var(--aviso-vestigio); }
.painel--aviso .painel__icone { color: var(--aviso); }

.painel__apoio {
    font-size: var(--t-xs);
    color: var(--texto-3);
    margin-top: 2px;
}

/* ---- Célula de valor ----

   `tabular-nums` é o que faz as 189 células ficarem com as casas decimais uma
   embaixo da outra. Sem isso o "1" ocupa menos que o "8" na fonte de texto, e a
   coluna sai serrilhada — justo numa tabela cuja única serventia é ser
   comparada de cima a baixo. */
.vau__valor {
    text-align: right;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.tabela thead th.vau__valor { text-align: right; }

/* Respiro menor nas sete colunas de valor: com o padrão, a oitava coluna sai da
   tela num monitor de 1366. O aperto é só na horizontal — a altura da linha, que
   é o que se percorre com o olho, fica igual. */
.tabela th.vau__valor,
.tabela td.vau__valor { padding-left: var(--e2); padding-right: var(--e2); }

.vau__uf {
    width: 1%;
    white-space: nowrap;
    font-weight: 600;
}

/* Subiu, caiu, ficou. Cor, e não seta: são 189 células, e uma seta em cada uma
   viraria ruído. */
.vau__variacao--alta   { color: var(--erro); }
.vau__variacao--baixa  { color: var(--ok); }
.vau__variacao--neutro { color: var(--texto-3); }

/* Em tela estreita a tabela vira cartões e o alinhamento à direita brigaria com
   o rótulo que aparece à esquerda de cada linha. */
@media (max-width: 720px) {
    .vau__valor { text-align: right; }
    .vau__uf { width: auto; }
}


/* =============================================================================
   16.10 · CALCULADORA, AFERIÇÃO E MINHAS PROPOSTAS
   ============================================================================= */

/* ---- Selo de origem, na lista de propostas ----

   Linha própria, e não fluindo atrás da destinação: o texto de apoio quebra em
   duas linhas quando é longo, e o selo acabava ora embaixo, ora colado no fim
   da frase. Duas linhas com o mesmo selo em lugares diferentes obrigam a
   procurá-lo em cada linha, que é o oposto do que um selo serve para fazer. */
.proposta__origem {
    display: block;
    margin-top: 4px;
}

/* ---- Nove colunas numa tela só ----

   Minhas Propostas tem número, responsável, data, UF, área, economia, honorário,
   situação e quatro botões. Com o respiro padrão de 16px de cada lado, só as
   margens somavam quase 300px, e a tabela passava a rolar de lado num monitor
   de 1366 — que é onde a maior parte das pessoas usa o sistema.

   Rolagem lateral numa tabela larga não é detalhe estético: as colunas de valor
   ficam fora da tela justamente quando se quer comparar duas linhas, e o
   ponteiro precisa sair da linha para trazê-las de volta.

   O aperto é SÓ horizontal. A altura da linha — o que o olho percorre de cima a
   baixo — continua a mesma das demais listas do sistema. */
.tabela--propostas th,
.tabela--propostas td { padding-left: var(--e3); padding-right: var(--e3); }

/* Em tela estreita a tabela vira cartões: cada célula ganha o rótulo à esquerda
   e o aperto lateral atrapalharia em vez de ajudar. */
@media (max-width: 720px) {
    .tabela--propostas th,
    .tabela--propostas td { padding-left: var(--e4); padding-right: var(--e4); }
}

/* ---- Ações da linha: só o símbolo ----

   Três ou quatro botões por linha, sem rótulo. O espaço entre eles é o que
   impede o clique errado numa lista onde um dos botões apaga. */
.tabela__acoes .botao--icone + .botao--icone,
.tabela__acoes .botao--icone + .tabela__acao-futura,
.tabela__acoes .tabela__acao-futura + .botao--icone,
/* O de conversar mora dentro de um <form>: sem estas duas linhas o irmão
   deixa de ser o botão e o espaçamento some justamente onde um dos vizinhos
   abre a ficha. */
.tabela__acoes .tabela__acao-forma + .botao--icone,
.tabela__acoes .botao--icone + .tabela__acao-forma { margin-left: var(--e2); }

/* Invólucro de ação ainda não disponível.

   O botão desabilitado não recebe ponteiro — é o que o torna inerte —, e com
   ele o `title` também sumiria. O invólucro existe só para segurar a
   explicação, e por isso precisa ocupar exatamente a caixa do botão. */
.tabela__acao-futura {
    display: inline-flex;
    vertical-align: middle;
}

/* ---- Duas colunas: o formulário e o resumo ----

   O formulário de uma obra com várias destinações passa da altura da janela.
   Com o resumo empilhado embaixo, cada mudança de metragem exigiria rolar até o
   fim para ver o efeito e voltar para continuar — e é justamente o efeito no
   número que a pessoa está perseguindo. Lado a lado, ele fica sempre à vista.

   Abaixo de 1100px a coluna vira uma só: espremer 30ch de resumo ao lado de um
   formulário de doze colunas não sobra largura para nenhum dos dois. */
.calc {
    /* Dois terços para o formulário, um terço para o resumo — a proporção do
       original. Fluida, e não os 340px fixos de antes: num monitor largo a
       coluna travada deixava uma faixa vazia entre ela e o formulário, e a
       linha do honorário com o preço cheio ao lado quebrava em três.

       O piso de 300px é nosso, e não do original: aqui o trilho come 274px que
       lá não existem, e sem ele "INSS por Aferição · R$ 128.450,00" chegaria
       espremido antes de a coluna se desfazer. */
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(300px, 1fr);
    gap: var(--e5);
    align-items: start;

    /* Onde o resumo para, ao acompanhar a rolagem. Um número só, usado no
       `top` e no teto de altura: se os dois divergissem, ou sobraria uma faixa
       morta acima do cartão, ou o teto o faria terminar fora da janela.

       A altura da barra ENTRA na conta. Durante muito tempo não entrava, e com
       razão: `.topo` era `sticky` dentro de `.app__topo`, um item de grade da
       faixa de 52px, e um `sticky` não passa do próprio quadrante — não tinha
       um milímetro para percorrer. Medido na época: rolando 900px, a barra
       ficava em -900. Ela saía de vista com a página, e descontar a altura dela
       deixava o resumo flutuando 52px abaixo do topo, sem nada naquela faixa.

       A barra agora é `position: fixed` e fica de verdade (ver `.topo`), então
       o resumo tem de parar ABAIXO dela — senão desliza para debaixo da barra e
       o topo do cartão fica coberto. */
    --calc-parada: calc(var(--topo-h) + var(--e4));
}

.calc__forma { min-width: 0; }

/* Os cartões do formulário se empilham com o respiro do original entre cartões
   — maior que o respiro ENTRE CAMPOS, que é o da `.form-grade`. É essa
   diferença que faz um cartão terminar e o próximo começar. */
.calc__form > * + * { margin-top: var(--e5); }

/* ---- A linha do cliente do CRM ----

   Fica ACIMA dos campos, e não entre eles: ela não é um campo — é a resposta a
   "de quem é esta proposta?", e essa pergunta vem antes de qualquer dado da
   obra. Uma faixa, e não um cartão: cartão dentro de cartão empurraria o
   formulário inteiro para baixo por uma linha de texto. */
.calc__lead {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--e3);
    margin-bottom: var(--e4);
    padding: var(--e3);
    background: var(--sup-2);
    border: 1px solid var(--linha);
    border-radius: var(--r);
}

.calc__lead-marca {
    display: grid;
    place-items: center;
    width: 28px;
    height: 28px;
    flex: none;
    border-radius: 50%;
    background: var(--acao-vestigio);
    color: var(--acao);
}
.calc__lead-marca svg { width: 15px; height: 15px; }

.calc__lead-texto {
    margin: 0;
    font-size: var(--t-sm);
    color: var(--texto-2);
}

/* A escolha ocupa o resto da faixa para o botão encostar na direita: o gesto
   fica no mesmo lugar quer o texto seja curto ou longo. */
.calc__lead-escolha {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--e3);
    flex: 1;
}
.calc__lead-escolha .calc__lead-texto { margin-right: auto; }

.calc__lead-escolhido {
    flex-basis: 100%;
    margin: 0;
    color: var(--acao);
    font-size: var(--t-sm);
    font-weight: 600;
}
.calc__lead-escolhido[hidden] { display: none; }

/* ---- O rodapé do formulário, solto ----

   No original ele NÃO é uma barra: é uma fileira de botões debaixo do último
   cartão, sem borda, sem fundo e sem cartão próprio. `.form-pe` — a barra com
   filete e fundo `--sup-2` que as telas de cadastro usam — existe para fechar
   um painel, e aqui não há painel para fechar: os botões pertencem ao
   formulário inteiro, e não ao último bloco dele.

   As cinco formas de terminar a mesma digitação — Calcular, Salvar, Ver PDF,
   Nova proposta, Limpar — ficam num grupo só à esquerda, na ordem do original.
   Partir a fileira faria procurar o botão em dois lugares. */
/* ---- E a fileira ACOMPANHA A ROLAGEM ----

   Pedido do dono em 08/09/2026: os cinco botoes flutuando. O motivo e o
   tamanho da tela — o formulario da calculadora tem varios cartoes, e depois de
   preencher a ultima destinacao o "Calcular" estava a tres rolagens de
   distancia. Calcular e conferir sao um ciclo, nao um fim: quem ajusta um mes
   paralisado quer recalcular ali mesmo, e nao voltar ao pe da pagina toda vez.

   `sticky`, e nao `fixed`: fixo, a barra ficaria pendurada tambem nas telas em
   que ela nao existe mais (a coluna do resumo, o rodape do sistema) e teria de
   ser desligada a mao. Sticky ocupa o lugar dela no fim do formulario e SOBE
   ate o pe da janela enquanto ha formulario abaixo — some sozinha quando o
   assunto acaba.

   Quem rola aqui e a JANELA (o `.app__conteudo` nao pode virar caixa de
   rolagem, ver o comentario da secao do estudio), entao `bottom: 0` e o pe da
   janela mesmo.

   O fundo e a borda deixam de ser enfeite e viram necessidade: sem eles os
   campos passariam POR BAIXO dos botoes, legiveis atraves deles. Pela mesma
   razao ela recua para fora da coluna com margem negativa — uma barra que
   comeca depois da margem do cartao mostra uma tira de conteudo rolando ao
   lado dela.

   z-index 20: acima do formulario e abaixo de tudo o que precisa cobri-la — o
   trilho lateral e 50, o modal e 300, o veu e 9998.

   SO NA CALCULADORA, por enquanto. A classe `.calc__acoes` e compartilhada por
   SEIS telas (calculadora, afericao avulsa, analise tributaria, decadencia,
   fator de ajuste e obras nao prediais), e o pedido foi de uma. O gancho e o
   `#proposta-form`, que so a calculadora tem — as outras cinco continuam com a
   fileira solta no fim do formulario. Para estender, e trocar o seletor de
   cima pela classe pura. */
.calc__acoes {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--e2);
    margin-top: var(--e5);
}

/* TUDO o que vira barra fica AQUI DENTRO, e nao na classe acima: o fundo e a
   borda so fazem sentido acompanhando a rolagem.

   AS SEIS TELAS DE CALCULO, desde 08/09/2026. Comecou so na calculadora, a
   pedido do dono, e ele mandou estender: afericao indireta, analise tributaria,
   decadencia, fator de ajuste e obras nao prediais tem o mesmo formulario
   comprido e o mesmo problema — depois da ultima destinacao, o "Calcular"
   estava a tres rolagens de distancia.

   A ancora e `.calc__form >`, e nao a classe pura: `.calc__acoes` tambem
   aparece em lugar nenhum fora dessas seis, mas amarrar ao formulario mantem a
   regra presa ao caso que ela descreve — barra do formulario de calculo — em
   vez de virar "qualquer fileira com esse nome, onde quer que ela apareca". */
.calc__form > .calc__acoes {
    position: sticky;
    bottom: 0;
    z-index: 20;
    margin: var(--e5) calc(var(--e3) * -1) var(--e2);
    padding: var(--e3);
    background: var(--sup);
    border-top: 1px solid var(--linha);
    border-radius: var(--r) var(--r) 0 0;
    box-shadow: 0 -2px 8px rgba(15, 22, 19, .07);
}

/* Navegador sem `position: sticky` (ou com ela desligada por alguma extensao)
   cai na fileira solta de sempre, no fim do formulario — que era o desenho
   anterior e continua correto. Nada aqui depende de JavaScript. */
@supports not (position: sticky) {
    .calc__form > .calc__acoes {
        margin: var(--e5) 0 0;
        padding: 0;
        background: none;
        border-top: 0;
        box-shadow: none;
    }
}


/* ---- O rodape dos formularios de cadastro, pelo mesmo motivo ----

   `.form-pe` e o par de botoes que fecha 19 formularios de cadastro, e alguns
   deles sao longos: o de consultor passa de mil linhas. Salvar ficava no fim de
   uma rolagem inteira.

   Funciona aqui, e nao funcionaria em qualquer cartao, por causa de UMA linha
   que ja existia: `.painel--formulario` troca o `overflow: hidden` do painel
   comum por `visible`. Com `hidden`, o cartao vira caixa de recorte e o sticky
   la dentro passa a acompanhar a caixa — que tem a altura do proprio conteudo,
   entao curso zero e a regra nao faz nada. E o mesmo tropeço que este arquivo ja
   documenta duas vezes.

   O rodape ja nascia com fundo e filete superiores, entao nao ha nada de
   aparencia a acrescentar: so a parada e a sombra que separa a barra do que
   passa por baixo dela. */
.painel--formulario > .form-pe,
.painel--formulario > form > .form-pe {
    position: sticky;
    bottom: 0;
    z-index: 20;
    box-shadow: 0 -2px 8px rgba(15, 22, 19, .07);
}

@supports not (position: sticky) {
    .painel--formulario > .form-pe,
    .painel--formulario > form > .form-pe { box-shadow: none; }
}

/* "Excluir" é a exceção, e vai empurrada para a outra ponta.

   Não é `space-between` na fileira inteira: com ela, tirar o botão de apagar —
   ele só existe editando uma proposta gravada — reabriria o espaço e mudaria o
   lugar dos outros cinco. A margem automática mora no próprio botão, então a
   fileira é a mesma com ou sem ele.

   Encostado em "Salvar proposta", apagar vira erro de meio centímetro. */
.calc__acoes--separado { margin-left: auto; }


/* O resumo acompanha a rolagem.

   `sticky` vai na COLUNA, e não no cartão dentro dela. É o item da grade que
   tem a altura da linha inteira para percorrer; o cartão tem a altura do
   próprio conteúdo, e um sticky ali não teria para onde ir — ficaria parado,
   e pareceria que a regra não funciona.

   ISTO SÓ FUNCIONA PORQUE `.app__conteudo` CORTA COM `clip`. Enquanto ele
   cortava com `overflow-x: hidden`, o eixo vertical virava `auto` por baixo
   dos panos, o <main> passava a ser a caixa de rolagem que este sticky
   acompanha, e como ele nunca rola o resumo nunca grudava. A explicação
   inteira está na seção 04.

   O teto de altura e a rolagem própria são o que o original não tem: lá, com a
   memória de cálculo aberta, o fim do cartão ficava inalcançável enquanto ele
   estava grudado. Aqui a coluna rola por dentro, e quando chega ao fim a
   rolagem volta a ser da página — que é o encadeamento padrão do navegador, e
   por isso não se mexe nele. */
.calc__lado {
    min-width: 0;
    position: sticky;
    top: var(--calc-parada);
    max-height: calc(100vh - var(--calc-parada) - var(--e4));
    overflow-y: auto;
}

@media (max-width: 1100px) {
    .calc { grid-template-columns: minmax(0, 1fr); }
    /* Empilhado, `sticky` colaria o resumo no topo enquanto o formulário rola
       por baixo — e ele cobriria os campos. O teto de altura sai junto: numa
       coluna só, um resumo com rolagem própria dentro da rolagem da página é
       duas rolagens disputando o mesmo gesto. */
    .calc__lado {
        position: static;
        max-height: none;
        overflow-y: visible;
    }
}


/* ---- As linhas do resumo ----

   Rótulo à esquerda, número à direita, e os números alinhados pela vírgula:
   é uma coluna que se lê de cima a baixo comparando ordens de grandeza, e sem
   `tabular-nums` o "1" ocupa menos que o "8" e a coluna sai serrilhada. */
.calc__linhas { display: grid; gap: 2px; }

.calc__linha {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--e3);
    padding: 7px 0;
    border-bottom: 1px solid var(--linha);
}
.calc__linha:last-child { border-bottom: 0; }

.calc__linha dt {
    font-size: var(--t-xs);
    color: var(--texto-3);
}
.calc__linha dd {
    font-size: var(--t-sm);
    font-variant-numeric: tabular-nums;
    text-align: right;
    white-space: nowrap;
}

/* O honorário com brinde sai acompanhado do preço cheio —
   "R$ 1.800,00 (padrão R$ 2.200,00 − desc. R$ 400,00)" — e a frase inteira não
   cabe em 340px numa linha só. Esta é a única linha da coluna que pode quebrar.

   Quebrar não estraga o número: o "R$" e o valor são unidos por espaço fixo
   (NumeroBr.ESPACO_FIXO, U+00A0), então a quebra só acontece ENTRE as parcelas,
   nunca no meio de uma delas. O `nowrap` das demais linhas continua valendo.

   Quem monta a frase é o servidor, em RespostaDoCalculo.honorarioEscrito(); a
   tela só a recebe pronta. */
.calc__linha dd[data-calc-valor="honorarioEscrito"] {
    white-space: normal;
}

/* A economia é o número que a proposta existe para mostrar. */
.calc__linha--destaque dt,
.calc__linha--total dt { color: var(--texto); font-weight: 600; }

.calc__linha--total {
    margin-top: var(--e2);
    padding-top: var(--e3);
    border-top: 2px solid var(--linha-forte);
    border-bottom: 0;
}
.calc__linha--total dd { font-size: var(--t-base); }

.calc__economia { color: var(--ok); font-weight: 600; }

/* Economia líquida negativa acontece: um honorário fixo digitado pode passar da
   economia apurada. Verde ali diria que está tudo certo. */
.calc__economia--negativa { color: var(--erro); }

/* ---- Distribuição: Franqueadora, Franquia e Parceiro (V074) ----
   Separada do resumo por um filete, como o total: é outra pergunta ("para
   onde vai o dinheiro"), e não mais uma linha da mesma conta. */
.calc__split {
    margin-top: var(--e3);
    padding-top: var(--e3);
    border-top: 2px solid var(--linha-forte);
}
.calc__split-titulo {
    font-size: var(--t-xs);
    color: var(--texto-3);
    text-transform: uppercase;
    letter-spacing: .02em;
    margin: 0 0 var(--e2);
}
.calc__split-icone {
    width: 14px;
    height: 14px;
    vertical-align: -2px;
    color: var(--marca);
}


/* ---- A recusa ----

   Faixa lateral, e não borda inteira: formulário pela metade e unidade sem
   Tabela VAU são estados normais de quem está montando um cálculo, não falhas.
   Um cartão contornado de vermelho leria como erro do sistema. */
.calc__recusa {
    padding: var(--e3);
    margin-bottom: var(--e3);
    border-left: 3px solid var(--aviso);
    border-radius: var(--r-sm);
    background: var(--aviso-vestigio);
}
.calc__recusa-texto { font-size: var(--t-sm); color: var(--texto-2); }
.calc__recusa .botao { margin-top: var(--e3); }


/* ---- O botão que abre a memória ----

   No original é um botão contornado ocupando a largura inteira do resumo, e
   não o texto discreto com que os blocos recolhidos do resto do sistema se
   abrem. A diferença tem razão: aqui embaixo do último número é o único lugar
   da tela onde se confere a conta linha a linha, e um link tímido no fim de
   uma coluna de dez valores não é encontrado por quem nunca o abriu.

   Continua sendo <summary>: o gesto funciona sem JavaScript e o leitor de tela
   já o anuncia como "expandir". Só a aparência mudou.

   A setinha de `.avancado > summary::before` FICA, e vem centralizada junto do
   texto pelo `justify-content`: é ela que diz se a memória está aberta ou
   fechada, e um botão de largura total sem esse sinal parece um botão que
   dispara alguma coisa, não um que revela.

   O seletor traz o `.avancado >` na frente de propósito: `.avancado > summary`
   já declara `display`, `padding` e `color`, e um seletor de uma classe só
   perderia a disputa para ele — o botão nasceria com a aparência do bloco
   recolhido comum e nada disto apareceria. */
.avancado > .calc__memoria-botao {
    display: flex;
    justify-content: center;
    width: 100%;
    padding: 6px var(--e3);
    border: 1px solid var(--linha-forte);
    border-radius: var(--r-sm);
    color: var(--marca);
    font-weight: 600;
}
.avancado > .calc__memoria-botao:hover {
    border-color: var(--marca);
    background: var(--marca-vestigio);
    color: var(--marca);
}


/* ---- Memória de cálculo ----

   Numerada: a memória é conferida linha a linha contra a planilha de quem
   fiscaliza, e "a linha 7" precisa ser uma coisa que se possa dizer em voz
   alta. */
.calc__memoria {
    margin: 0;
    padding-left: var(--e5);
    font-size: var(--t-xs);
    color: var(--texto-3);
    line-height: 1.7;
}
.calc__memoria li { padding-left: 2px; }


/* ---- Os meses paralisados ----

   Caixas de marcação em forma de pastilha, uma por competência da obra. A
   pastilha inteira é clicável — o alvo de um quadradinho de 14px é pequeno
   demais para uma tela que às vezes se opera em pé, num canteiro. */
.calc__meses {
    display: flex;
    flex-wrap: wrap;
    gap: var(--e2);
    margin-top: var(--e2);
}

.calc__mes {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 6px 11px;
    border: 1px solid var(--linha);
    border-radius: var(--r-sm);
    background: var(--sup);
    font-size: var(--t-xs);
    cursor: pointer;
    transition: border-color var(--transicao), background var(--transicao);
}
.calc__mes:hover { border-color: var(--marca); }
.calc__mes:has(input:checked) {
    border-color: var(--marca);
    background: var(--marca-vestigio);
    color: var(--marca);
    font-weight: 600;
}
.calc__mes input { accent-color: var(--marca); }


/* ---- A faixa da decadência ----

   Fica embaixo do período, dentro do cartão "Parâmetros da Obra", porque é do
   período que ela fala. O tom vem em `data-tom` — três estados, escolhidos no
   servidor por `AvisoDeDecadencia.getTom()`:

     erro   já há competência prescrita
     aviso  nada prescreveu, mas prescreve em 01/01
     ok     o período inteiro está salvo

   ATRIBUTO, E NÃO CLASSE, de propósito. Com classes o script teria de remover
   as outras duas a cada pintura, e esquecer uma delas deixaria a faixa
   vermelha com o texto de "nada decaiu" — o pior erro possível numa faixa que
   existe para ser lida de relance. `setAttribute` substitui o valor anterior
   sozinho.

   A cor mora só na borda, no fundo em vestígio e no ícone. O texto fica na cor
   normal: a frase tem duas linhas e um período em `mono` ao lado, e escrita em
   vermelho ela competiria com os campos em erro do próprio formulário. */
.calc__decadencia {
    display: flex;
    align-items: flex-start;
    gap: var(--e3);
    margin-top: var(--e2);
    padding: var(--e3);
    /* Mesma gramática de `.calc__recusa`: filete de 3px à esquerda e fundo em
       vestígio, sem contorno fechado. É o formato que esta tela já usa para
       "leia isto antes de seguir", e um segundo formato para o mesmo papel
       faria a pessoa aprender duas vezes a mesma coisa. */
    border-left: 3px solid var(--linha);
    border-radius: var(--r-sm);
    background: var(--sup);
}

.calc__decadencia-icone {
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    margin-top: 1px;
    color: var(--texto-3);
}

/* Cresce e encolhe; o período ao lado tem largura própria. `min-width: 0`
   porque um filho de flex não encolhe abaixo do conteúdo sem isso, e a frase
   empurraria o período para fora do cartão. */
.calc__decadencia-texto {
    flex: 1 1 auto;
    min-width: 0;
}

.calc__decadencia-frase {
    margin: 0;
    font-size: var(--t-sm);
    line-height: 1.45;
}

.calc__decadencia-virada {
    margin: 4px 0 0;
    font-size: var(--t-xs);
    color: var(--texto-3);
}

.calc__decadencia-periodo {
    flex: 0 0 auto;
    align-self: center;
    font-size: var(--t-xs);
    color: var(--texto-3);
    white-space: nowrap;
}

.calc__decadencia[data-tom="erro"] {
    border-left-color: var(--erro);
    background: var(--erro-vestigio);
}
.calc__decadencia[data-tom="erro"] .calc__decadencia-icone { color: var(--erro); }

.calc__decadencia[data-tom="aviso"] {
    border-left-color: var(--aviso);
    background: var(--aviso-vestigio);
}
.calc__decadencia[data-tom="aviso"] .calc__decadencia-icone { color: var(--aviso); }

/* Sem regra para `data-tom="ok"`: o servidor manda `avisar: false` nesse caso e
   a faixa nem chega a aparecer. O tom continua existindo no modelo — quem
   quiser mostrar o período salvo um dia já tem o valor pronto. */


/* ---- A linha de entrada dos blocos que se somam ----

   `.form-linha` é flex e não dá largura a ninguém: cada controle declara a
   dele. Sem isto, o <select> de destinação ocupa a linha toda e o botão
   "Incluir" cai sozinho na fileira de baixo — o que faz a inclusão de uma área
   deixar de parecer uma coisa só. */
.form-linha .calc__ent--largo  { flex: 1 1 190px; }
.form-linha .calc__ent--medio  { flex: 0 1 160px; }
.form-linha .calc__ent--numero { flex: 0 0 8.5rem; }
.form-linha .calc__ent--sim    { flex: 0 0 7rem; }


/* ---- Indique e ganhe ----

   MORA DENTRO DO CARTÃO DE HONORÁRIOS, e não em painel próprio: o desconto é
   do honorário, e separá-lo num painel com cabeçalho igual ao dos outros faz
   perder de vista de onde os R$ 200,00 saem.

   O MARKUP QUE ESTAS REGRAS ESPERAM

     <div class="calc__brindes">
       <p class="calc__brindes-titulo">
         <svg aria-hidden="true"><use href="#i-chevron-right"></use></svg>
         Indique e ganhe!
       </p>
       <p class="campo__ajuda">Indique nosso trabalho e ganhe um
          <strong>super desconto</strong> no valor total.
          <span class="calc__brindes-preco">(R$ 200,00 cada)</span></p>
       <div class="calc__brindes-lista">
         <label class="calc__brinde">
           <input type="checkbox" name="…" value="SIM" data-calc-recalcular>
           <span class="calc__brinde-ponto" aria-hidden="true"></span>
           <span>Divulgar (2x) em grupo de condomínio</span>
         </label>
         …
       </div>
     </div>

   O PREÇO APARECE UMA VEZ SÓ, no parágrafo de apoio. Repeti-lo dentro de cada
   pílula faz "R$ 200,00" surgir três vezes em quinze centímetros de tela, e aí
   ninguém lê nenhuma das três. */
/* Só filete e respiro POR DENTRO: o afastamento do que vem acima é dado pelo
   container — `.painel__corpo > * + *` ou a `.form-grade`, conforme onde o
   bloco for parar. Uma margem própria aqui perderia a disputa de
   especificidade com aquela regra e não faria nada, ou faria em um lugar e não
   no outro.

   `:not(:first-child)` porque o bloco tem DOIS lares. Na calculadora ele é a
   última linha da grade do cartão de Honorários, e o filete o separa do
   percentual logo acima. Na aferição avulsa não existe cartão de honorários —
   a tela não pergunta percentual nem valor fixo — e ele ocupa um cartão só
   seu: ali o filete apareceria colado no alto do cartão, riscando um espaço
   onde não há nada de que separar. */
.calc__brindes:not(:first-child) {
    padding-top: var(--e4);
    border-top: 1px solid var(--linha);
}

/* A faixa-título.

   Não é `.painel__cabecalho`: se fosse, este bloco viraria mais um painel
   igual aos outros e deixaria de ser o convite que ele é. A cor é `--aviso`
   porque é o único tom do sistema que chama atenção sem afirmar nada: o
   original usa vermelho, e vermelho aqui é `--erro` — anunciar um desconto na
   cor de falha faria a oferta parecer um problema.

   A caixa alta é da PELE, e não do texto: o template escreve "Indique e
   ganhe!" em caixa mista, e o leitor de tela continua lendo uma frase em vez
   de soletrar letra a letra. */
.calc__brindes-titulo {
    display: flex;
    align-items: center;
    gap: var(--e2);
    margin-bottom: var(--e1);
    /* Vermelho, como no InssObra (`fw-bold text-danger`). Era `--aviso`, e o
       âmbar dizia "cuidado" numa linha que oferece desconto. O vermelho aqui
       não é erro: é o preço chamando atenção, e é assim que o vendedor usa. */
    color: var(--erro);
    font-size: var(--t-xs);
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
}
.calc__brindes-titulo svg { width: 13px; height: 13px; flex: 0 0 auto; }

/* O valor de cada indicação, dentro do parágrafo de apoio: é informação de
   apoio da informação de apoio. */
.calc__brindes-preco { color: var(--texto-3); }

/* As duas indicações lado a lado, metade da largura cada, como no original.
   Abaixo de 720px empilham: uma pílula com a frase inteira não cabe em meia
   coluna de telefone sem quebrar em duas linhas. */
.calc__brindes-lista {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--e3);
    margin-top: var(--e3);
}
@media (max-width: 720px) {
    .calc__brindes-lista { grid-template-columns: minmax(0, 1fr); }
}

/* A pílula.

   Alvo de clique inteiro, e não um quadradinho de 20px ao lado de um texto: é
   uma escolha de venda, feita muitas vezes ao lado do cliente, e o gesto tem
   de acertar de primeira. Raio de pílula, e não `--r`, para que ela não se
   confunda com um campo do formulário logo acima — ela não é um dado da obra,
   é uma oferta.

   O <input> continua no documento, invisível: trocá-lo por um <div> tiraria a
   marcação do Tab e do leitor de tela. */
.calc__brinde {
    display: flex;
    align-items: center;
    gap: var(--e2);
    width: 100%;
    min-height: var(--altura-botao);
    padding: var(--e2) var(--e4);
    border: 1px solid var(--linha-forte);
    border-radius: 999px;
    background: var(--sup-3);
    color: var(--texto-3);
    font-size: var(--t-xs);
    font-weight: 600;
    letter-spacing: .04em;
    line-height: 1.35;
    text-transform: uppercase;
    cursor: pointer;
    transition: border-color var(--transicao), background var(--transicao),
                color var(--transicao);
}

.calc__brinde input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.calc__brinde:hover { border-color: var(--ok); }

/* Marcada em verde, e não na cor da área: verde é "ganho", e é o mesmo verde
   com que a economia aparece no resumo, três dedos à direita. Na cor da área a
   pílula ficaria idêntica a todo controle escolhido do sistema, e esta se lê
   como um brinde conquistado, não como um campo preenchido.

   Duas montagens atendidas de propósito: o <input> DENTRO do <label>, que é
   como o resto do sistema escreve, e o <input> ANTES dele, que é como o
   original escreve. Uma regra só cobriria uma delas, e a pílula ficaria morta
   no dia em que o template mudasse de mão. */
.calc__brinde:has(input:checked),
input:checked + .calc__brinde {
    border-color: var(--ok);
    background: var(--ok-vestigio);
    color: var(--ok);
}

.calc__brinde:has(input:focus-visible),
input:focus-visible + .calc__brinde {
    outline: 2px solid var(--ok);
    outline-offset: 2px;
}

/* O ponto: anel vazio quando não, cheio quando sim. É o indicador do original;
   quem carrega o sinal de verdade é a pílula inteira mudando de cor, e por
   isso ele pode ser discreto. */
.calc__brinde-ponto {
    flex: 0 0 auto;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--sup);
    box-shadow: inset 0 0 0 2px var(--linha-forte);
    transition: background var(--transicao), box-shadow var(--transicao);
}
.calc__brinde:has(input:checked) .calc__brinde-ponto,
input:checked + .calc__brinde .calc__brinde-ponto {
    background: var(--ok);
    box-shadow: inset 0 0 0 2px var(--ok);
}

/* Rede de segurança: se a pílula for montada com o `.marcador` do sistema, a
   caixa quadrada dele faz as vezes do ponto em vez de aparecer um quadrado
   dentro de uma pílula. */
.calc__brinde .marcador__caixa {
    width: 16px;
    height: 16px;
    margin: 0;
    border-radius: 50%;
}
.calc__brinde input:checked + .marcador__caixa {
    background: var(--ok);
    border-color: var(--ok);
}
.calc__brinde .marcador__texto {
    display: block;
    font-size: inherit;
    font-weight: inherit;
}


/* ---- Barra de filtro de Minhas Propostas ----

   Duas entradas e um botão numa faixa só: busca e situação são um recorte
   único, e separá-los em dois formulários faria um apagar o outro ao ser
   enviado. A modificadora existe para não mexer no `.barra__busca` das outras
   listagens, que têm um campo só. */
.barra__busca--filtro {
    display: flex;
    align-items: center;
    gap: var(--e2);
    flex: 1 1 620px;
}
.barra__busca--filtro > .campo__controle:first-of-type { flex: 1 1 240px; min-width: 0; }
.barra__busca-situacao { flex: 0 0 11rem; }

@media (max-width: 560px) {
    .barra__busca--filtro { flex-wrap: wrap; }
    .barra__busca-situacao { flex: 1 1 100%; }
}


/* ---- Cartão de contagem que também filtra ----

   O número em destaque convida ao clique; sem o link, ele seria decoração.
   `color: inherit` porque o cartão inteiro é o alvo — sublinhar o número o
   faria parecer um link dentro do cartão, e não o cartão sendo o link. */
.calc__cartao {
    color: inherit;
    text-decoration: none;
}
.calc__cartao:hover { border-color: var(--marca); }
.calc__cartao:focus-visible {
    outline: 2px solid var(--marca);
    outline-offset: 2px;
}


/* ---- Coluna de data na listagem ---- */
.tabela__data { white-space: nowrap; }


/* ---- Navegação entre páginas ----

   Vive no rodapé da tabela, ao lado do intervalo: "1 a 20 de 137" e os botões
   respondem à mesma pergunta, e separá-los faria procurar em dois lugares. */
.calc__paginacao {
    display: inline-flex;
    align-items: center;
    gap: var(--e2);
}


/* A linha de entrada incompleta reclama no MESMO parágrafo de ajuda — a regra
   é a `.campo__ajuda--erro` da seção 9, que a lista de áreas de atuação já usa.
   Um segundo elemento escondido ao lado empurraria o layout ao aparecer, e o
   texto de ajuda ficaria dizendo o contrário do aviso. */


/* ---- As calculadoras avulsas ----

   Obras Não Prediais, Decadência, Fator de Ajuste e Análise Tributária reusam
   `.calc`, `.calc__forma`, `.calc__lado` e `.calc__linha` inteiros: são a mesma
   forma da Calculadora — formulário à esquerda, resumo grudado à direita. O que
   segue é só o que essas quatro têm e a Calculadora não tem. */


/* ---- A nota permanente da tela ----

   Não é aviso de erro nem recusa de cálculo: é uma declaração que fica ali o
   tempo todo — "os coeficientes desta tela são de exemplo, calibrar com as
   tabelas oficiais antes de produção". Removê-la muda o que a tela significa
   juridicamente, então ela não pode parecer descartável.

   NEUTRA, e de propósito. `--aviso` já é a cor da `.calc__recusa`, que aparece
   e some conforme o formulário fica pronto; duas faixas laranja na mesma tela
   fariam a que muda desaparecer no meio da que nunca muda — que é exatamente a
   que precisa ser notada. O filete forte e o fundo levantado bastam para ela
   não se confundir com o texto do formulário. */
.calc__nota {
    display: flex;
    gap: var(--e2);
    align-items: flex-start;
    padding: var(--e3);
    margin-bottom: var(--e4);
    border-left: 3px solid var(--linha-forte);
    border-radius: var(--r-sm);
    background: var(--sup-2);
    font-size: var(--t-sm);
    color: var(--texto-2);
    line-height: 1.55;
}
.calc__nota svg {
    width: 15px;
    height: 15px;
    flex: 0 0 auto;
    margin-top: 2px;
    color: var(--texto-3);
}


/* ---- A proporção, em barra ----

   A Decadência responde "quanto do débito prescreveu": um par de números que só
   significa alguma coisa como fração de um todo. A barra é a resposta; os dois
   percentuais escritos ao lado são a conferência.

   AS DUAS LARGURAS VÊM PRONTAS DO SERVIDOR, e nenhuma é derivada da outra.
   `width: calc(100% - var(--outra))` seria o caminho natural e é justamente o
   errado: `3,13%` e `96,87%` só somam 100 porque o servidor os arredondou como
   um par, e refazer a subtração aqui devolveria o meio-par do JavaScript.

   `overflow: hidden` no trilho para os cantos arredondados valerem para o
   segmento também — sem ele, a ponta quadrada do preenchimento aparece por
   cima do canto do trilho. */
.calc__proporcao {
    display: flex;
    height: 10px;
    margin: var(--e2) 0 var(--e3);
    border-radius: 999px;
    overflow: hidden;
    background: var(--sup-3);
}
.calc__proporcao-parte {
    height: 100%;
    /* A largura é escrita pelo JavaScript com o número que veio na resposta.
       Zero é o estado antes do primeiro cálculo, e não um valor apurado. */
    width: 0;
    transition: width var(--transicao);
}

/* Decadente é o que se ganha, e vigente é o que continua devido. A cor segue o
   mesmo par do resto do sistema — verde é economia, e o cinza-linha não é
   "ruim", é "permanece". Vermelho ali leria como erro do cálculo. */
.calc__proporcao-parte--ganho    { background: var(--ok); }
.calc__proporcao-parte--restante { background: var(--linha-forte); }

/* A legenda da barra: o quadradinho de cor, o rótulo e o percentual. Sem ela a
   barra é decoração — duas faixas coloridas sem nada dizendo qual é qual. */
.calc__legenda {
    display: flex;
    flex-wrap: wrap;
    gap: var(--e1) var(--e4);
    font-size: var(--t-xs);
    color: var(--texto-3);
}
.calc__legenda-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.calc__legenda-cor {
    width: 9px;
    height: 9px;
    flex: 0 0 auto;
    border-radius: 2px;
    background: var(--linha-forte);
}
.calc__legenda-item--ganho .calc__legenda-cor { background: var(--ok); }


/* ---- Tabela dentro da coluna do resumo ----

   O Fator de Ajuste devolve uma linha por competência, e a coluna do resumo tem
   300px na pior das larguras. Reduzir o corpo é o que faz caber a competência,
   a base e o juro sem cortar coluna; quando ainda assim não couber, quem
   envolve a tabela é `.rolagem-h`, e a rolagem fica dentro do cartão em vez de
   virar rolagem lateral da página. */
.calc__lado .tabela {
    font-size: var(--t-xs);
}
.calc__lado .tabela th,
.calc__lado .tabela td {
    padding-left: var(--e2);
    padding-right: var(--e2);
}


/* ---- Lista de detalhe vazia ----

   Uma linha, e não o `.estado` de tela cheia: aqui não há cadastro nenhum a
   convidar — a lista está vazia porque o cálculo ainda não foi pedido, e daqui
   a meio segundo ela terá conteúdo. A arte grande de "nada encontrado"
   empurraria o resumo inteiro para baixo a cada recálculo. */
.calc__vazio {
    padding: var(--e3) 0;
    font-size: var(--t-xs);
    color: var(--texto-3);
    text-align: center;
}


/* ---- A confirmação de que gravou ----

   Aparece DENTRO do resumo, encostada no número que ela confirma. Uma faixa no
   topo da página obrigaria a subir a tela para ler que a simulação daqui de
   baixo foi salva — e em tela de 1366 o resumo já está no fim da rolagem.

   Some no próximo cálculo, junto com o resto do resumo: uma confirmação que
   sobrevive à mudança dos campos estaria confirmando outro número. */
.calc__salvo {
    display: flex;
    gap: var(--e2);
    align-items: flex-start;
    padding: var(--e2) var(--e3);
    margin-top: var(--e3);
    border-radius: var(--r-sm);
    background: var(--ok-vestigio);
    font-size: var(--t-xs);
    color: var(--ok);
    line-height: 1.5;
}
.calc__salvo svg { width: 14px; height: 14px; flex: 0 0 auto; margin-top: 1px; }



/* =============================================================================
   17 · MOVIMENTO, IMPRESSÃO, ACESSIBILIDADE
   ============================================================================= */

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
        scroll-behavior: auto !important;
    }
}

@media print {
    .app { display: block; }
    .app__trilho,
    .app__topo,
    .app__rodape,
    .modal,
    .offline,
    .pular { display: none !important; }

    .conteudo { padding: 0; }
    .painel, .numero { border-color: #999; box-shadow: none; break-inside: avoid; }

    body { background: #fff; color: #000; font-size: 11pt; }
}

/* =========================================================================
   FUNIL (Kanban do CRM)

   Colunas que rolam na horizontal, cartões que rolam na vertical dentro de
   cada uma. Doze colunas não cabem numa tela; a rolagem lateral é a forma
   honesta de dizer isso — encolher a coluna até caber tornaria o cartão
   ilegível, que é o oposto do que um quadro serve para fazer.

   A cor vem do BANCO (crm.etapa.cor), por atributo `style` na borda de cima.
   Não há classe por etapa: a unidade renomeia e recolore as etapas dela, e
   uma classe por cor obrigaria uma migração de CSS a cada ajuste.
   ========================================================================= */
.funil {
    display: flex;
    gap: var(--e3);
    overflow-x: auto;
    padding-bottom: var(--e3);
    align-items: flex-start;
}

.funil__coluna {
    flex: 0 0 268px;
    display: flex;
    flex-direction: column;
    background: var(--sup-2);
    border: 1px solid var(--linha);
    border-radius: var(--r-lg);
    max-height: calc(100vh - 260px);
}

.funil__cabecalho {
    padding: var(--e3);
    border-top: 3px solid var(--linha-forte);
    border-radius: var(--r-lg) var(--r-lg) 0 0;
    background: var(--sup);
}
.funil__titulo  { font-size: var(--t-sm); font-weight: 600; }
.funil__contagem {
    display: block;
    margin-top: 2px;
    font-family: var(--fonte-mono);
    font-size: var(--t-micro);
    color: var(--texto-3);
}
.funil__descricao {
    margin-top: var(--e2);
    font-size: var(--t-xs);
    color: var(--texto-3);
}

.funil__cartoes {
    padding: var(--e2);
    display: flex;
    flex-direction: column;
    gap: var(--e2);
    overflow-y: auto;
    min-height: 80px;
}

/* Enquanto um cartão paira sobre a coluna. O JS põe e tira a classe. */
.funil__cartoes--alvo {
    background: var(--marca-vestigio, rgba(17, 107, 91, .08));
    outline: 2px dashed var(--marca);
    outline-offset: -4px;
    border-radius: var(--r);
}

/* O cartao passa a ter GRADE: o selo na primeira coluna, o conteudo na
   segunda. Antes era fluxo normal, e por isso nao havia onde por a ancora. */
.funil__cartao {
    display: grid;
    grid-template-columns: 26px 1fr;
    column-gap: var(--e2);
    align-items: center;
    background: var(--sup);
    border: 1px solid var(--linha);
    /* `--r-md` NAO EXISTE neste projeto -- os tokens sao --r-sm, --r e --r-lg.
       A declaracao ficava invalida e era descartada, e o cartao do funil vinha
       de canto vivo desde sempre, sem ninguem notar. `--r` e o raio padrao. */
    border-radius: var(--r);
    padding: var(--e3);
    cursor: grab;
    transition: border-color var(--transicao), box-shadow var(--transicao);
}
.funil__cartao:hover { border-color: var(--linha-forte); box-shadow: var(--sombra-1); }
.funil__cartao--arrastando { opacity: .45; cursor: grabbing; }

/* Contato atrasado: a faixa lateral, e não a borda inteira. Um cartão
   contornado de vermelho lê como erro, e isto é uma cobrança de agenda. */
.funil__cartao--atrasado { border-left: 3px solid var(--erro); }

/* ---- O selo do cartao ----
   Quadrado de canto arredondado, e nao circulo: o circulo e do AVATAR, que
   carrega rosto de gente. Aqui nao ha rosto -- e um marcador, e a forma
   diferente impede que os dois sejam lidos como a mesma coisa. */
.funil__marca {
    /* SO a primeira linha, ao lado do nome.

       A primeira versao atravessava o cartao inteiro (`grid-row: 1 / -1`) e foi
       um erro medido: a coluna do funil tem 268px, o selo comia 38, e o que
       sobrava espremia o telefone em duas linhas e fazia o aviso de atraso
       colidir com o valor. O selo ancora o NOME; o resto usa a largura toda. */
    grid-row: 1;
    display: grid;
    place-items: center;
    width: 26px;
    height: 26px;
    border-radius: var(--r-sm);
    background: var(--acao-vestigio, rgba(9, 146, 80, .13));
    color: var(--acao);
}
.funil__marca svg { width: 15px; height: 15px; }

/* Tudo o que nao e o selo nem o nome ocupa as duas colunas: numa coluna de
   268px, abrir mao de 38 em cada linha e o que espreme o cartao. */
.funil__cartao > *:not(.funil__marca):not(.funil__nome) { grid-column: 1 / -1; }

/* Sem telefone o selo apaga. Continua ocupando o lugar -- some-lo faria a
   coluna de cartoes perder o alinhamento a cada lead sem contato. */
.funil__marca--mudo {
    background: var(--sup-2);
    color: var(--texto-3);
}

.funil__nome {
    display: block;
    font-weight: 600;
    font-size: var(--t-sm);
    color: var(--texto);
    text-decoration: none;
}
.funil__nome:hover { color: var(--marca); text-decoration: underline; }

.funil__linha {
    margin-top: 2px;
    font-size: var(--t-xs);
    color: var(--texto-3);
}
.funil__linha--alerta { color: var(--erro); }

/* O rodape carrega o honorario e o dono. O valor ganha peso porque e o unico
   numero do cartao -- e e por ele que se compara uma coluna inteira de relance.
   O dono continua apagado: ele responde "de quem e", e nao "quanto vale". */
.funil__rodape {
    margin-top: var(--e3);
    padding-top: var(--e2);
    border-top: 1px solid var(--linha);
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--e2);
    font-size: var(--t-sm);
    font-family: var(--fonte-mono);
    font-weight: 600;
    color: var(--texto);
}
.funil__dono {
    font-family: var(--fonte-ui);
    font-size: var(--t-xs);
    font-weight: 400;
    color: var(--texto-3);
}

.funil__vazia {
    padding: var(--e3);
    font-size: var(--t-xs);
    color: var(--texto-3);
    text-align: center;
}

/* =========================================================================
   LINHA DO TEMPO (histórico do lead)

   O que o sistema fez e o que as pessoas fizeram, na mesma lista. As duas
   famílias se distinguem pelo PESO, e não pela posição: a linha automática
   tem a marca oca e o texto mais discreto; a registrada por alguém vem com a
   marca preenchida na cor da marca.

   Separá-las em duas listas responderia pior a pergunta que a tela faz — "o
   que já foi feito com este cliente?" quer a sequência inteira.
   ========================================================================= */
/* ============================================================
   OS RECADOS ENTRE A REDE E A UNIDADE

   Não lidas primeiro, e com um sinal que se lê de longe: a faixa à esquerda.
   Quem abre esta tela quer saber o que falta ler, e não percorrer a lista
   inteira procurando o que mudou.
   ============================================================ */
.recados {
    list-style: none;
    margin: 0;
    padding: 0;
}

.recados__item {
    display: grid;
    grid-template-columns: auto 1fr auto;
    gap: var(--e3);
    align-items: start;
    padding: var(--e3) var(--e4);
    border-bottom: 1px solid var(--linha);
    border-left: 3px solid transparent;
}

.recados__item:last-child { border-bottom: 0; }

/* A não lida tem cor; a lida sai do caminho sem sumir. */
.recados__item.recado-novo { border-left-color: var(--marca); }
.recados__item.recado-lido { opacity: 0.72; }

.recados__marca {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--sup-3);
    color: var(--texto-2);
}

.recados__marca svg {
    width: 16px;
    height: 16px;
    fill: currentColor;
}

.recados__topo {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--e2);
    margin: 0;
    font-size: var(--t-sm);
}

.recados__texto {
    margin: var(--e1) 0 0;
    font-size: var(--t-sm);
    color: var(--texto-2);
    white-space: pre-line;
    overflow-wrap: anywhere;
}

.recados__pe {
    margin: var(--e1) 0 0;
    font-size: var(--t-xs);
    color: var(--texto-3);
}

.recados__acao { align-self: center; }

.recados__lida {
    font-size: var(--t-xs);
    color: var(--texto-3);
}

/* No celular a coluna do botão desce: três colunas em 400px espremem o texto
   até a linha de uma palavra. */
@media (max-width: 640px) {
    .recados__item {
        grid-template-columns: auto 1fr;
    }
    .recados__acao {
        grid-column: 2;
        justify-self: start;
    }
}

/* ============================================================
   A CONVERSA DO WHATSAPP DENTRO DA FICHA

   Bolhas, e não uma tabela: quem lê precisa distinguir num relance quem falou
   o quê, e alinhamento é o sinal que o olho lê antes de qualquer rótulo — é
   assim em todo aplicativo de mensagem, e imitar isso aqui não é enfeite, é
   não obrigar ninguém a aprender uma convenção nova.

   Só leitura. Responder continua na tela do WhatsApp, onde estão o anexo, o
   áudio e o encaminhar.
   ============================================================ */
.ficha-conversa {
    list-style: none;
    margin: 0;
    padding: var(--e4);
    display: flex;
    flex-direction: column;
    gap: var(--e2);
    max-height: 420px;
    overflow-y: auto;
}

.ficha-conversa__item {
    max-width: 72%;
    padding: var(--e2) var(--e3);
    border: 1px solid var(--linha);
    border-radius: var(--r);
    background: var(--fundo);
}

/* O que veio do cliente encosta à esquerda; o que saiu daqui, à direita. */
.ficha-conversa__item.conversa-dele  { align-self: flex-start; }
.ficha-conversa__item.conversa-nossa {
    align-self: flex-end;
    background: var(--sup-3);
}

.ficha-conversa__texto {
    margin: 0;
    font-size: var(--t-sm);
    color: var(--texto);
    white-space: pre-line;
    overflow-wrap: anywhere;
}

.ficha-conversa__pe {
    margin: var(--e1) 0 0;
    font-size: var(--t-xs);
    color: var(--texto-3);
}

.ficha-conversa__nota {
    margin: 0;
    padding: 0 var(--e4) var(--e4);
    font-size: var(--t-xs);
    color: var(--texto-3);
}

@media (max-width: 640px) {
    .ficha-conversa__item { max-width: 88%; }
}

.linha-tempo {
    list-style: none;
    margin: 0;
    padding: var(--e4);
    display: flex;
    flex-direction: column;
    gap: 0;
}

.linha-tempo__item {
    display: grid;
    grid-template-columns: 28px 1fr;
    gap: var(--e3);
    padding-bottom: var(--e4);
    position: relative;
}
.linha-tempo__item:last-child { padding-bottom: 0; }

/* O fio que liga uma marca à seguinte. Não desenhado no último item: um fio
   que continua depois do fim sugere que falta carregar alguma coisa. */
.linha-tempo__item:not(:last-child)::before {
    content: "";
    position: absolute;
    left: 13px;
    top: 28px;
    bottom: 0;
    width: 1px;
    background: var(--linha);
}

.linha-tempo__marca {
    width: 27px;
    height: 27px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--marca);
    color: #fff;
    flex: 0 0 auto;
    z-index: 1;
}
.linha-tempo__marca svg { width: 14px; height: 14px; }

/* A linha do sistema é mais quieta: ela informa, não pede leitura. */
.linha-tempo__item--sistema .linha-tempo__marca {
    background: var(--sup-2);
    color: var(--texto-3);
    border: 1px solid var(--linha);
}
.linha-tempo__item--sistema .linha-tempo__frase { color: var(--texto-2); }

.linha-tempo__corpo { display: flex; flex-direction: column; gap: 2px; padding-top: 3px; }

.linha-tempo__topo {
    display: flex;
    align-items: baseline;
    gap: var(--e2);
    flex-wrap: wrap;
    font-size: var(--t-sm);
}
.linha-tempo__quando {
    font-family: var(--fonte-mono);
    font-size: var(--t-micro);
    color: var(--texto-3);
}

.linha-tempo__frase { font-size: var(--t-sm); color: var(--texto); }

.linha-tempo__pe {
    font-size: var(--t-xs);
    color: var(--texto-3);
}


/* =========================================================================
   CALENDÁRIO DO CRM (crm/agenda)

   Substituiu o bloco da agenda semanal. A rota continua /app/crm/agenda —
   no menu deste sistema o caminho É o endereço, e renomeá-lo quebraria todo
   link salvo.

   NOMES SÓ COM HÍFEN, SEM `__`
   ----------------------------
   Não é desleixo de BEM: o Thymeleaf trata `__…__` como pré-processamento, e
   duas classes como `calendario__celula--hoje` e `calendario__celula--fora` na
   MESMA expressão formam esse par de sublinhados e têm a expressão cortada ao
   meio. A agenda antiga registrou o defeito em comentário e o contornou
   marcando o fim de semana pela posição. Aqui o problema simplesmente não
   existe, e o que resta de condicional vem pronto de Celula.getClasses().

   SETE COLUNAS DE TAMANHO IGUAL
   -----------------------------
   Numa grade de mês a largura da coluna não pode significar nada: quarta com
   uma tarefa e quinta com nove precisam ocupar o mesmo espaço, senão o olho lê
   "quinta é mais importante" antes de ler o conteúdo.

   EM TELA ESTREITA A GRADE VIRA LISTA
   -----------------------------------
   Sete colunas de 40 pixels não são um calendário, são um enigma. Abaixo de
   900px o mês empilha os dias que TÊM algo, e a visão diária — que já é uma
   lista — passa a ser o caminho natural.
   ========================================================================= */

/* ---------------------------------------------------------- navegação ---- */

.calendario-nav {
    display: flex;
    align-items: center;
    gap: var(--e2);
}

.calendario-nav-voltar svg { transform: rotate(180deg); }

.calendario-nav-periodo {
    display: flex;
    align-items: center;
    gap: var(--e2);
    margin: 0;
    font-size: var(--t-base);
    font-weight: 600;
    color: var(--texto);
    white-space: nowrap;
}

.calendario-nav-icone {
    width: 16px;
    height: 16px;
    color: var(--marca);
}

/* O par de visões, colado como um controle só. O botão da visão corrente
   continua clicável de propósito: um botão que some ao ser escolhido tira a
   referência de onde se está. */
.calendario-visoes {
    display: inline-flex;
    gap: 0;
}

.calendario-visoes .calendario-visao:first-child {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
}

.calendario-visoes .calendario-visao:last-child {
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
    margin-left: -1px;
}

.calendario-visao-ativa {
    background: var(--marca);
    border-color: var(--marca);
    color: var(--marca-contraste);
    position: relative;
    z-index: 1;
}

.calendario-visao-ativa:hover,
.calendario-visao-ativa:focus-visible {
    background: var(--marca-profunda);
    border-color: var(--marca-profunda);
    color: var(--marca-contraste);
}

/* ---------------------------------------------------------- atrasadas ---- */

.calendario-atraso-lista {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--e2);
}

.calendario-atraso-item {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--e2);
    padding-bottom: var(--e2);
    border-bottom: 1px solid var(--linha);
}

.calendario-atraso-item:last-child { border-bottom: 0; padding-bottom: 0; }

.calendario-atraso-data {
    font-size: var(--t-xs);
    color: var(--erro);
    font-weight: 600;
}

.calendario-atraso-nome {
    font-size: var(--t-sm);
    font-weight: 600;
    color: var(--texto);
    text-decoration: none;
}

.calendario-atraso-nome:hover { color: var(--marca); text-decoration: underline; }

.calendario-atraso-apoio { font-size: var(--t-xs); color: var(--texto-3); }

/* Empurra o botão de concluir para a direita da linha, sem depender da ordem
   dos elementos que vieram antes — alguns são opcionais. */
.calendario-atraso-acao { margin-left: auto; }

.calendario-atraso-resto {
    margin: var(--e3) 0 0;
    font-size: var(--t-xs);
    color: var(--texto-2);
}

/* ------------------------------------------------------- grade do mês ---- */

.calendario {
    display: flex;
    flex-direction: column;
    gap: var(--e2);
}

.calendario-semana,
.calendario-grade {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: 1px;
}

.calendario-cabecalho {
    padding: var(--e2);
    font-size: var(--t-micro);
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--texto-3);
    text-align: center;
}

/* O fundo da grade faz as linhas: as células têm 1px de vão entre si e a cor
   de baixo aparece. Sai mais barato que uma borda por célula, e não dobra a
   linha entre duas vizinhas. */
.calendario-grade {
    background: var(--linha);
    border: 1px solid var(--linha);
    border-radius: var(--r-lg);
    overflow: hidden;
}

.calendario-celula {
    background: var(--sup);
    min-height: 108px;
    padding: var(--e2);
    display: flex;
    flex-direction: column;
    gap: var(--e1);
}

/* O dia do mês vizinho aparece, e não some: esconder o que cai no dia 1 porque
   ele ficou na primeira linha seria mentir sobre o mês seguinte. Fica só mais
   discreto. */
.calendario-celula--fora { background: var(--sup-2); }
.calendario-celula--fora .calendario-numero { color: var(--texto-3); }

.calendario-celula--fim { background: var(--sup-2); }
.calendario-celula--fora.calendario-celula--fim { background: var(--sup-3); }

.calendario-celula--hoje {
    background: var(--marca-vestigio);
    box-shadow: inset 0 0 0 2px var(--marca);
}

.calendario-celula-topo {
    display: flex;
    align-items: center;
    gap: var(--e1);
}

.calendario-numero {
    font-size: var(--t-sm);
    font-weight: 700;
    color: var(--texto);
    text-decoration: none;
    line-height: 1.2;
    padding: 2px 4px;
    border-radius: var(--r-sm);
}

.calendario-numero:hover,
.calendario-numero:focus-visible {
    background: var(--marca);
    color: var(--marca-contraste);
}

.calendario-marca-hoje {
    font-size: var(--t-micro);
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--marca);
}

/* Sempre visível, e não só no :hover. No telefone não existe "passar o mouse",
   e um atalho invisível ali seria inalcançável justamente onde a tela é mais
   usada. Fica discreto até receber o foco. */
.calendario-mais {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    border-radius: var(--r-sm);
    color: var(--texto-3);
    text-decoration: none;
}

.calendario-mais svg { width: 12px; height: 12px; }

.calendario-mais:hover,
.calendario-mais:focus-visible {
    background: var(--marca);
    color: var(--marca-contraste);
}

.calendario-itens {
    display: flex;
    flex-direction: column;
    gap: 2px;
    overflow: hidden;
}

.calendario-chip {
    display: flex;
    align-items: baseline;
    gap: 4px;
    padding: 2px 5px;
    border-radius: var(--r-sm);
    background: var(--marca-vestigio-forte);
    border-left: 3px solid var(--marca);
    font-size: var(--t-micro);
    color: var(--texto);
    text-decoration: none;
    line-height: 1.35;
}

.calendario-chip:hover,
.calendario-chip:focus-visible { background: var(--marca-vestigio); }

/* O contato do lead tem marca própria porque é OUTRA coisa: não tem hora, não
   se conclui e não se remarca aqui. Cor diferente evita que as duas sejam
   contadas como uma só. */
.calendario-chip-contato {
    background: var(--info-vestigio);
    border-left-color: var(--info);
}

.calendario-chip-feita {
    background: var(--sup-2);
    border-left-color: var(--texto-3);
    color: var(--texto-3);
    text-decoration: line-through;
}

.calendario-chip-hora {
    font-size: var(--t-micro);
    font-weight: 700;
    color: var(--texto-2);
    flex: 0 0 auto;
}

.calendario-chip-icone {
    width: 10px;
    height: 10px;
    flex: 0 0 auto;
    align-self: center;
}

/* Uma linha só por chip: o título inteiro está no title=, e a célula precisa
   caber sete vezes na largura da tela. */
.calendario-chip-titulo {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.calendario-legenda {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--e3);
    margin: 0;
    font-size: var(--t-xs);
    color: var(--texto-3);
}

.calendario-legenda-item {
    display: inline-flex;
    align-items: center;
    gap: var(--e1);
}

.calendario-amostra {
    width: 12px;
    height: 12px;
    border-radius: 3px;
    background: var(--marca-vestigio-forte);
    border-left: 3px solid var(--marca);
}

.calendario-amostra-contato {
    background: var(--info-vestigio);
    border-left-color: var(--info);
}

.calendario-legenda-nota { margin-left: auto; }

/* ------------------------------------------------------- lista do dia ---- */

.calendario-dia-lista {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--e2);
}

.calendario-tarefa {
    display: flex;
    align-items: flex-start;
    gap: var(--e3);
    padding: var(--e3);
    border: 1px solid var(--linha);
    border-left: 3px solid var(--marca);
    border-radius: var(--r);
    background: var(--sup);
}

.calendario-tarefa-feita {
    border-left-color: var(--ok);
    background: var(--sup-2);
}

.calendario-tarefa-feita .calendario-tarefa-titulo {
    text-decoration: line-through;
    color: var(--texto-3);
}

/* Largura fixa para as horas alinharem em coluna. "Dia todo" cabe, e é o texto
   mais largo que este espaço recebe. */
.calendario-tarefa-hora {
    flex: 0 0 62px;
    font-size: var(--t-xs);
    font-weight: 700;
    color: var(--texto-2);
    padding-top: 2px;
}

.calendario-tarefa-corpo {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: var(--e1);
}

.calendario-tarefa-titulo {
    font-size: var(--t-sm);
    font-weight: 600;
    color: var(--texto);
    text-decoration: none;
}

.calendario-tarefa-titulo:hover { color: var(--marca); text-decoration: underline; }

.calendario-tarefa-apoio {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--e2);
    margin: 0;
    font-size: var(--t-xs);
    color: var(--texto-3);
}

.calendario-tarefa-descricao {
    margin: 0;
    font-size: var(--t-xs);
    color: var(--texto-2);
    white-space: pre-line;
}

.calendario-tarefa-acoes {
    display: flex;
    align-items: center;
    gap: var(--e2);
    flex: 0 0 auto;
}

.calendario-contatos {
    margin-top: var(--e4);
    padding-top: var(--e3);
    border-top: 1px solid var(--linha);
}

.calendario-contatos-titulo {
    display: flex;
    align-items: center;
    gap: var(--e2);
    margin: 0 0 var(--e2);
    font-size: var(--t-xs);
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--texto-3);
}

/* ------------------------------------------------------------ estreito --- */

@media (max-width: 900px) {

    /* Sete colunas de 40px não são um calendário. O mês vira lista, e mostra
       só os dias que TÊM algo — trinta linhas dizendo "nada aqui" fariam
       rolar a tela inteira para descobrir isso. O dia livre continua
       alcançável pelo botão "Nova tarefa" do topo e pela visão diária. */
    .calendario-semana { display: none; }

    .calendario-grade {
        display: flex;
        flex-direction: column;
        gap: 1px;
    }

    .calendario-celula { min-height: 0; }

    /* Sem suporte a :has(), todas as células continuam aparecendo — que era o
       comportamento anterior, e não uma tela quebrada. */
    .calendario-celula:not(:has(.calendario-chip)):not(.calendario-celula--hoje) {
        display: none;
    }

    .calendario-tarefa { flex-wrap: wrap; }
    .calendario-tarefa-acoes { width: 100%; justify-content: flex-end; }
}

/* =============================================================================
   ETAPAS DO FUNIL — tela de manutenção das colunas do Kanban
   =============================================================================

   Bloco do módulo crm/etapas. Fica no fim do arquivo e não altera nada acima.

   Três coisas, e só elas:
     .funil-previa   o quadro desenhado em miniatura, na listagem e no formulário
     .etapas-cor     a amostra de cor de uma linha da tabela
     .etapas-mover   os dois botões que sobem e descem a coluna

   A COR VEM DO BANCO, EM style INLINE
   -----------------------------------
   Não há uma classe por cor porque a cor é dado da unidade, e não do CSS: a
   V036 guarda #rrggbb em crm.etapa.cor justamente para que renomear e recolorir
   não exijam migração. O ck_etapa_cor só aceita seis hexadecimais, e o
   Thymeleaf escapa o atributo — não há injeção possível por esse caminho. */

/* A miniatura do quadro. As colunas em fila, roláveis na horizontal quando não
   couberem: um funil de quinze etapas não pode espremer a tela. */
.funil-previa {
    display: flex;
    gap: var(--e2);
    align-items: stretch;
    list-style: none;
    padding: 0;
    margin: 0;
}

/* A cabeça de coluna do Kanban, reduzida. A borda superior colorida é o mesmo
   sinal do .funil__cabecalho -- e é ela que faz a prévia ser reconhecível como
   "aquilo ali é o quadro". */
.funil-previa__coluna {
    flex: 0 0 148px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: var(--e2) var(--e3);
    background: var(--sup-2);
    border: 1px solid var(--linha);
    border-top: 3px solid var(--linha-forte);
    border-radius: var(--r) var(--r) 0 0;
}

.funil-previa__codigo {
    font-size: var(--t-micro);
    color: var(--texto-3);
}

.funil-previa__nome {
    font-size: var(--t-sm);
    font-weight: 600;
    color: var(--texto);
}

.funil-previa__contagem {
    font-family: var(--fonte-mono);
    font-size: var(--t-micro);
    color: var(--texto-3);
}

.funil-previa__desfecho { align-self: flex-start; margin-top: var(--e1); }

/* A amostra de cor da linha da tabela. Círculo, e não quadrado: o quadrado
   pequeno lê como caixa de marcação, e esta amostra não é clicável. */
.etapas-cor {
    display: inline-block;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    border: 1px solid var(--linha-forte);
    vertical-align: middle;
}

/* Os dois botões de reordenar, colados. Largura fixa para que a coluna não
   mude de tamanho quando o primeiro ou o último ficam desabilitados. */
.etapas-mover { width: 1%; white-space: nowrap; }
.etapas-mover form { display: flex; gap: var(--e1); }

/* Não há ícone de seta para cima na biblioteca: é o mesmo chevron, virado.
   Acrescentar um símbolo ao sprite por causa de meia volta seria pagar bytes em
   toda página do sistema para economizar uma linha aqui. */
.etapas-seta--cima { transform: rotate(180deg); }

/* O seletor nativo de cor e o hexadecimal ao lado. O código não é decoração: é
   o que se copia para repetir a mesma cor em outra unidade. */
.etapas-cor-linha { display: flex; align-items: center; gap: var(--e2); }

/* O input[type=color] tem moldura própria do navegador; a do campo sobraria em
   volta. Ele ocupa a altura do campo para não quebrar a linha de base da grade
   (ver --altura-campo). */
.etapas-cor-entrada {
    width: 56px;
    height: calc(var(--altura-campo) - 10px);
    padding: 2px;
    cursor: pointer;
}

.etapas-cor-eco { font-size: var(--t-sm); color: var(--texto-2); }


/* =========================================================================
   GESTÃO DE NEGÓCIO (crm/gestao)

   O painel da manhã de segunda-feira: em aberto, fechados e cancelados por
   responsável, no período escolhido. Reaproveita o que já existe — .grade e
   .numero nos cartões, .tabela na lista — e acrescenta só o que essas peças
   não têm: o filtro de duas datas e a linha de total.
   ========================================================================= */

/* ---- O filtro de período ----

   Classe própria em vez de barra__busca--filtro. Aquele modificador dá
   flex-basis de 240px ao primeiro campo, o que é o certo para uma caixa de
   busca e o errado para uma data: a base do flex vence a largura de 7rem de
   campo__controle--data, e o campo sairia com o triplo do texto que cabe nele.
   Aqui os dois campos ficam do tamanho de "31/12/2026", que é tudo o que se
   digita neles. */
.gestao-filtro {
    display: flex;
    align-items: center;
    gap: var(--e2);
    flex-wrap: wrap;
}

/* O "até" entre os dois campos. Não usa barra__texto: aquele cresce para
   ocupar a sobra (flex: 1 1 auto) e empurraria o segundo campo para longe do
   primeiro — e as duas datas precisam ser lidas como um intervalo só. */
.gestao-filtro__ate {
    font-size: var(--t-xs);
    color: var(--texto-3);
    flex: 0 0 auto;
}

/* ---- Dinheiro no cartão de número ----

   34px é a medida de "12" e de "0,0%". "R$ 1.284.930,55" nessa altura estoura
   o cartão de 232px da grade e quebra em duas linhas, e o cartão passa a ter
   altura diferente dos vizinhos. Vinte pixels mantêm o destaque e cabem. */
.numero__valor.gestao__moeda {
    font-size: var(--t-lg);
    letter-spacing: 0;
}

/* ---- A linha de total ----

   Fundo e peso, e não uma borda: a tabela já tem filete em toda linha, e mais
   um faria o rodapé parecer o começo de outra tabela. O tom é o mesmo do
   cabeçalho — as duas pontas da tabela dizem a mesma coisa, "isto não é um
   registro, é a moldura". */
.gestao__total td {
    padding: var(--e3) var(--e4);
    background: var(--sup-2);
    border-top: 1px solid var(--linha);
    font-weight: 600;
    vertical-align: middle;
}
.gestao__total .tabela__apoio { font-weight: 400; }

/* Em tela estreita a tabela vira cartões, e as regras que fazem isso miram
   `tbody`. O tfoot ficaria com as células empilhadas SEM o rótulo da coluna ao
   lado — sete números soltos, sem dizer de quê. Estas quatro regras repetem
   para o rodapé o que o tbody já ganha. */
@media (max-width: 720px) {
    .gestao__total td {
        display: grid;
        grid-template-columns: 40% 1fr;
        gap: var(--e3);
        padding: 5px var(--e4);
        border-top: 0;
        text-align: left;
    }
    .gestao__total td:first-child { padding-top: var(--e3); }
    .gestao__total td:last-child { padding-bottom: var(--e3); }

    .gestao__total td[data-rotulo]::before {
        content: attr(data-rotulo);
        font-family: var(--fonte-mono);
        font-size: var(--t-micro);
        letter-spacing: .08em;
        text-transform: uppercase;
        color: var(--texto-3);
        font-weight: 400;
    }
}

/* =========================================================================
   PAINEL COMERCIAL — as barras de conversão                    [crm/painel]
   -------------------------------------------------------------------------
   Gráfico de barras sem biblioteca nenhuma: não há CDN e não se acrescenta
   dependência (CLAUDE.md §15 e §16). Cada barra é uma caixa cuja largura em
   porcentagem foi calculada NO SERVIDOR — a folha só a desenha.

   POR QUE EXISTEM 101 CLASSES DE LARGURA
   --------------------------------------
   A política de conteúdo da aplicação é `style-src 'self'`, sem
   'unsafe-inline' (ver EncodingFilter). Um navegador que a aplique à risca
   IGNORA `style="width:42%"` — e uma barra sem largura declarada é um bloco,
   ou seja, ocupa a linha inteira: todas as barras afirmariam 100%, que é pior
   do que não desenhar gráfico nenhum.

   A largura por classe não depende da política. O servidor escreve o mesmo
   inteiro nos dois lugares — classe e style —, então os dois caminhos não têm
   como discordar, e o gráfico continua correto qualquer que seja a política em
   vigor. A cor da etapa, essa sim, só cabe no atributo style: é um hexadecimal
   arbitrário escolhido pela unidade, e não há classe para cor arbitrária.
   Bloqueada, a barra cai na cor da área — o comprimento, que é o que o gráfico
   mede, permanece exato.
   ========================================================================= */

.grafico {
    display: flex;
    flex-direction: column;
    gap: var(--e3);
    list-style: none;
}

.grafico__item {
    display: flex;
    flex-direction: column;
    gap: 5px;
}

/* O rótulo empurra os números para a direita; o rótulo longo é que encolhe. */
.grafico__linha {
    display: flex;
    align-items: baseline;
    gap: var(--e2);
    font-size: var(--t-sm);
}

/* A pastilha de cor. É a mesma cor da coluna do Kanban, e serve de âncora para
   quem chega ao painel vindo de lá. `align-self` porque o pai alinha pela linha
   de base do texto, e um quadrado não tem linha de base. */
.grafico__marca {
    width: 10px;
    height: 10px;
    flex: 0 0 auto;
    align-self: center;
    border-radius: 3px;
    background: var(--marca);
}

.grafico__rotulo {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--texto);
}

/* Tabular para que a coluna de números fique alinhada de uma linha para a
   outra — é assim que se compara doze etapas de relance. */
.grafico__numero {
    flex: 0 0 auto;
    font-family: var(--fonte-marca);
    font-size: var(--t-md);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--texto);
}

.grafico__parte {
    flex: 0 0 auto;
    min-width: 3.6rem;
    text-align: right;
    font-family: var(--fonte-mono);
    font-size: var(--t-micro);
    font-variant-numeric: tabular-nums;
    color: var(--texto-3);
}

.grafico__trilho {
    height: 8px;
    border-radius: 999px;
    background: var(--sup-3);
    overflow: hidden;
}

/* `display:block` porque o elemento é um <span>: sem isto a largura não pega.
   A largura padrão é ZERO, e não automática — uma barra que perdesse o valor
   calculado deve sumir, e nunca afirmar cem por cento. */
.grafico__barra {
    display: block;
    width: 0;
    height: 100%;
    border-radius: 999px;
    background: var(--marca);
    transition: width var(--transicao);
}

.grafico__nota {
    display: flex;
    flex-wrap: wrap;
    gap: var(--e1) var(--e3);
    font-size: var(--t-xs);
    color: var(--texto-3);
}

.grafico__vazio {
    font-size: var(--t-sm);
    color: var(--texto-3);
}

/* Dinheiro não cabe no tamanho de um número de contagem: "R$ 1.284.900,00" em
   34px estoura o cartão e quebra em duas linhas. */
.numero__valor--dinheiro {
    font-size: var(--t-lg);
    letter-spacing: -.01em;
}

/* ---- As larguras. Uma classe por ponto percentual; ver o cabeçalho. ---- */
.grafico__barra--l0 { width: 0%; }
.grafico__barra--l1 { width: 1%; }
.grafico__barra--l2 { width: 2%; }
.grafico__barra--l3 { width: 3%; }
.grafico__barra--l4 { width: 4%; }
.grafico__barra--l5 { width: 5%; }
.grafico__barra--l6 { width: 6%; }
.grafico__barra--l7 { width: 7%; }
.grafico__barra--l8 { width: 8%; }
.grafico__barra--l9 { width: 9%; }
.grafico__barra--l10 { width: 10%; }
.grafico__barra--l11 { width: 11%; }
.grafico__barra--l12 { width: 12%; }
.grafico__barra--l13 { width: 13%; }
.grafico__barra--l14 { width: 14%; }
.grafico__barra--l15 { width: 15%; }
.grafico__barra--l16 { width: 16%; }
.grafico__barra--l17 { width: 17%; }
.grafico__barra--l18 { width: 18%; }
.grafico__barra--l19 { width: 19%; }
.grafico__barra--l20 { width: 20%; }
.grafico__barra--l21 { width: 21%; }
.grafico__barra--l22 { width: 22%; }
.grafico__barra--l23 { width: 23%; }
.grafico__barra--l24 { width: 24%; }
.grafico__barra--l25 { width: 25%; }
.grafico__barra--l26 { width: 26%; }
.grafico__barra--l27 { width: 27%; }
.grafico__barra--l28 { width: 28%; }
.grafico__barra--l29 { width: 29%; }
.grafico__barra--l30 { width: 30%; }
.grafico__barra--l31 { width: 31%; }
.grafico__barra--l32 { width: 32%; }
.grafico__barra--l33 { width: 33%; }
.grafico__barra--l34 { width: 34%; }
.grafico__barra--l35 { width: 35%; }
.grafico__barra--l36 { width: 36%; }
.grafico__barra--l37 { width: 37%; }
.grafico__barra--l38 { width: 38%; }
.grafico__barra--l39 { width: 39%; }
.grafico__barra--l40 { width: 40%; }
.grafico__barra--l41 { width: 41%; }
.grafico__barra--l42 { width: 42%; }
.grafico__barra--l43 { width: 43%; }
.grafico__barra--l44 { width: 44%; }
.grafico__barra--l45 { width: 45%; }
.grafico__barra--l46 { width: 46%; }
.grafico__barra--l47 { width: 47%; }
.grafico__barra--l48 { width: 48%; }
.grafico__barra--l49 { width: 49%; }
.grafico__barra--l50 { width: 50%; }
.grafico__barra--l51 { width: 51%; }
.grafico__barra--l52 { width: 52%; }
.grafico__barra--l53 { width: 53%; }
.grafico__barra--l54 { width: 54%; }
.grafico__barra--l55 { width: 55%; }
.grafico__barra--l56 { width: 56%; }
.grafico__barra--l57 { width: 57%; }
.grafico__barra--l58 { width: 58%; }
.grafico__barra--l59 { width: 59%; }
.grafico__barra--l60 { width: 60%; }
.grafico__barra--l61 { width: 61%; }
.grafico__barra--l62 { width: 62%; }
.grafico__barra--l63 { width: 63%; }
.grafico__barra--l64 { width: 64%; }
.grafico__barra--l65 { width: 65%; }
.grafico__barra--l66 { width: 66%; }
.grafico__barra--l67 { width: 67%; }
.grafico__barra--l68 { width: 68%; }
.grafico__barra--l69 { width: 69%; }
.grafico__barra--l70 { width: 70%; }
.grafico__barra--l71 { width: 71%; }
.grafico__barra--l72 { width: 72%; }
.grafico__barra--l73 { width: 73%; }
.grafico__barra--l74 { width: 74%; }
.grafico__barra--l75 { width: 75%; }
.grafico__barra--l76 { width: 76%; }
.grafico__barra--l77 { width: 77%; }
.grafico__barra--l78 { width: 78%; }
.grafico__barra--l79 { width: 79%; }
.grafico__barra--l80 { width: 80%; }
.grafico__barra--l81 { width: 81%; }
.grafico__barra--l82 { width: 82%; }
.grafico__barra--l83 { width: 83%; }
.grafico__barra--l84 { width: 84%; }
.grafico__barra--l85 { width: 85%; }
.grafico__barra--l86 { width: 86%; }
.grafico__barra--l87 { width: 87%; }
.grafico__barra--l88 { width: 88%; }
.grafico__barra--l89 { width: 89%; }
.grafico__barra--l90 { width: 90%; }
.grafico__barra--l91 { width: 91%; }
.grafico__barra--l92 { width: 92%; }
.grafico__barra--l93 { width: 93%; }
.grafico__barra--l94 { width: 94%; }
.grafico__barra--l95 { width: 95%; }
.grafico__barra--l96 { width: 96%; }
.grafico__barra--l97 { width: 97%; }
.grafico__barra--l98 { width: 98%; }
.grafico__barra--l99 { width: 99%; }
.grafico__barra--l100 { width: 100%; }


/* =============================================================================
   WhatsApp — a caixa de entrada e a conversa gravada

   Bloco acrescentado no FIM da folha, sem tocar em nada acima: outras telas
   entraram no mesmo arquivo em paralelo.

   POR QUE OS NOMES NÃO USAM “__”
   ------------------------------
   O resto da folha é BEM com `bloco__elemento`. Aqui não, e é deliberado: o
   pré-processador do Thymeleaf resolve `__…__` ANTES da expressão principal, e
   quase toda bolha desta tela escolhe a classe por condição
   (`${x} ? 'a' : 'b'`). Dois nomes com `__` na mesma condição formam esse par e
   a expressão é cortada ao meio — a armadilha já documentada em crm-agenda. Com
   `wpp-elemento--modificador` ela não pode acontecer.

   A ALTURA É A DA JANELA, E O QUE ROLA É POR DENTRO
   -------------------------------------------------
   Numa conversa de duzentas mensagens a caixa de escrever ficaria abaixo da
   dobra, e responder passaria a exigir rolar a página inteira até o fim. As
   duas colunas têm altura fixa e rolagem própria — a lista de conversas de um
   lado, o histórico do outro —, e a caixa de escrever fica sempre à vista.
   ============================================================================= */

.wpp {
    display: grid;
    /* Tres colunas a partir de 1400px: caixa, conversa e o cliente. Abaixo
       disso a terceira sai -- a conversa e o que nao pode encolher, e os
       documentos continuam a um clique, na ficha. */
    grid-template-columns: minmax(260px, 330px) minmax(0, 1fr);
    gap: var(--e4);

    /* A janela menos a barra de cima, o rodapé, a faixa do título e o respiro
       do conteúdo. Aproximado de propósito: se sobrar, sobra fundo; se faltar,
       a página rola um pouco. O que não pode é a caixa de escrever sair da
       vista.

       Eram 172px, e sobrava uma faixa morta de fundo entre o painel e o rodapé
       — numa tela cujo problema é caber conversa. 132px é o que a faixa do
       título e o respiro realmente ocupam. */
    height: calc(100vh - var(--topo-h) - var(--rodape-h) - 132px);
    min-height: 460px;
}

/* ---------------------------------------------------------------- Caixa ---- */

.wpp-caixa {
    display: flex;
    flex-direction: column;
    min-height: 0;
    background: var(--sup);
    border: 1px solid var(--linha);
    border-radius: var(--r);
    box-shadow: var(--sombra-1);
    overflow: hidden;
}

/* ---- Conversas | Grupos (V072) ----

   Duas abas do tamanho da coluna, meio a meio. O grupo não se mistura à fila
   de clientes: fica ao lado, a um clique. A contagem de não lidas vai DENTRO
   da aba, com as cores do selo `.wpp-nao-lidas` — é o mesmo fato, dito no
   lugar onde se decide para qual lado olhar. */
.wpp-abas {
    display: flex;
    border-bottom: 1px solid var(--linha);
}

.wpp-aba {
    flex: 1 1 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--e2);
    padding: var(--e2) var(--e3);
    font-size: var(--t-xs);
    font-weight: 600;
    color: var(--texto-3);
    text-decoration: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
}
.wpp-aba svg { width: 15px; height: 15px; flex: 0 0 auto; }
.wpp-aba:hover { background: var(--sup-2); color: var(--texto); }

.wpp-aba--ativa {
    color: var(--acao);
    border-bottom-color: var(--acao);
}

.wpp-aba-contagem {
    min-width: 18px;
    padding: 0 6px;
    border-radius: 999px;
    background: var(--erro-vestigio);
    color: var(--erro);
    font-size: var(--t-xs);
    line-height: 18px;
    text-align: center;
}

.wpp-procura {
    padding: var(--e3) var(--e3) var(--e2);
    border-bottom: 1px solid var(--linha);
}

/* ---- A peneira por responsável ----

   Só existe para quem alcança a equipe. Fica ABAIXO do campo de procura e não
   ao lado: a caixa de entrada é uma coluna estreita, e dois controles lado a
   lado deixariam os dois pequenos demais para ler o nome de uma pessoa.

   O botão é largura fixa porque o rótulo é uma palavra e não cresce; o select
   fica com o resto e é ele que precisa de espaço para "Operação Reduzzi
   Limeira". */
.wpp-peneira {
    display: flex;
    align-items: center;
    gap: var(--e2);
    margin-top: var(--e2);
}

.wpp-peneira .campo__controle { flex: 1 1 auto; min-width: 0; }

.wpp-peneira__ir {
    flex: 0 0 auto;
    padding-inline: var(--e3);
}

/* ---- Começar uma conversa ----
   Fechado, é uma linha só: a caixa de entrada existe para ler a fila, e um
   formulário sempre aberto empurraria a fila para baixo da dobra. Aberto, ocupa
   o lugar que a lista cede — ver fragments do template. */
.wpp-nova {
    border-bottom: 1px solid var(--linha);
}

.wpp-nova__abrir {
    display: flex;
    align-items: center;
    gap: var(--e2);
    padding: var(--e2) var(--e3);
    font-size: var(--t-xs);
    font-weight: 600;
    color: var(--acao);
    cursor: pointer;
    user-select: none;
    list-style: none;          /* Firefox */
}
.wpp-nova__abrir::-webkit-details-marker { display: none; }
.wpp-nova__abrir:hover { background: var(--sup-2); }
.wpp-nova__abrir svg { width: 15px; height: 15px; }

.wpp-nova__forma {
    display: flex;
    flex-direction: column;
    gap: var(--e2);
    padding: 0 var(--e3) var(--e3);
}
.wpp-nova__forma textarea { resize: vertical; min-height: 60px; }
.wpp-nova__forma .campo__ajuda { margin: 0; }

.wpp-resumo {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--e2);
    margin: 0;
    padding: var(--e2) var(--e3);
    font-size: var(--t-xs);
    color: var(--texto-3);
    border-bottom: 1px solid var(--linha);
}

.wpp-nao-lidas {
    padding: 1px 7px;
    border-radius: 999px;
    background: var(--erro-vestigio);
    color: var(--erro);
    font-weight: 600;
}
/* Sem nada escrito, o selo não existe. Ele fica no HTML de qualquer jeito
   porque é onde a conferência de fundo escreve quando o zero vira um. */
.wpp-nao-lidas:empty { display: none; }

.wpp-limpar { margin-left: auto; font-size: var(--t-xs); }

/* Cartões separados, como no Funil de vendas — e não linhas rentes divididas
   por filete, que era o desenho anterior.

   O dono pediu que as duas telas concordassem, e a razão é de leitura: a fila
   do WhatsApp é uma lista de PESSOAS com dados soltos — nome, telefone, cidade,
   espera —, e um filete entre elas não separa o suficiente para o olho agrupar
   o que é de quem. No funil o mesmo conteúdo já vinha em cartão, e ali funciona.

   Os valores são os mesmos de `.funil__cartao`: mudar um sem o outro faz as duas
   telas divergirem de novo. */
.wpp-lista {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    margin: 0;
    padding: var(--e2);
    list-style: none;

    /* O respiro entre cartões vem do contêiner, e não de margem em cada um:
       margem no último deixaria um vão morto no fim da rolagem. */
    display: flex;
    flex-direction: column;
    gap: var(--e2);
}

.wpp-item {
    display: flex;
    gap: var(--e3);
    /* Menos respiro em cima e embaixo do que nas laterais: o que faz o cartão
       parecer um cartão é a borda, e não o vão interno. Com `var(--e3)` nos
       quatro lados sobravam 118px por conversa e só quatro cabiam na tela. */
    padding: 10px var(--e3);
    color: inherit;
    text-decoration: none;

    /* Os três valores do `.funil__cartao`. Ver o comentário da `.wpp-lista`. */
    background: var(--sup);
    border: 1px solid var(--linha);
    border-radius: var(--r);

    transition: background var(--transicao), border-color var(--transicao);
}
.wpp-item:hover { background: var(--sup-2); }

.wpp-item--aberta {
    background: var(--marca-vestigio);
    /* A borda inteira na cor da marca, e não só a barra da esquerda: agora que
       cada conversa é um cartão com borda própria, tingir a borda diz "esta" com
       mais clareza do que um filete numa aresta só. A barra fica junto — no tema
       escuro o vestígio é sutil demais para responder sozinho. */
    border-color: var(--marca);
    box-shadow: inset 3px 0 0 var(--marca);
}
.wpp-item--aberta:hover { background: var(--marca-vestigio-forte); }

.wpp-avatar {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    background: var(--marca);
    color: var(--marca-contraste);
    font-family: var(--fonte-marca);
    font-size: var(--t-md);
    font-weight: 600;
    text-transform: uppercase;
}

/* O ponto de não lida, no avatar.

   Substitui o chip "novo" da fileira de marcas. Um chip a mais era a diferença
   entre a fileira caber numa linha e quebrar em duas — e quem varre a caixa de
   entrada procurando o que falta ler não precisa LER a palavra "novo": um ponto
   verde no canto do rosto responde antes.

   Fica FORA do `overflow: hidden` do avatar com foto, por isso é do item e não
   do avatar. */
.wpp-item--nova .wpp-avatar::after {
    content: "";
    position: absolute;
    right: -1px;
    bottom: -1px;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: var(--acao);
    border: 2px solid var(--sup);
}
.wpp-item--nova .wpp-item-nome { font-weight: 700; }
.wpp-item--nova .wpp-item-previa { color: var(--texto); font-weight: 500; }

.wpp-item-dados { display: block; min-width: 0; flex: 1 1 auto; }

.wpp-item-topo {
    display: flex;
    align-items: baseline;
    gap: var(--e2);
}

.wpp-item-nome {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 600;
    font-size: var(--t-sm);
    color: var(--texto);
}

.wpp-item-hora {
    flex: 0 0 auto;
    font-size: var(--t-micro);
    color: var(--texto-3);
}

.wpp-item-previa {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    margin-top: 2px;
    font-size: var(--t-xs);
    color: var(--texto-2);
}

/* UMA linha de marcas, sempre.

   Com `wrap`, três chips viravam duas fileiras e cada conversa passava de 118px
   — quatro cabiam na tela de 900px. Sem `wrap`, a fileira tem altura fixa e o
   que não couber é cortado pelo `overflow`: a caixa de entrada é para ESCOLHER
   uma conversa, e o detalhe que ficou de fora está inteiro do lado, na conversa
   aberta. */
.wpp-item-marcas {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    gap: var(--e1);
    margin-top: 5px;
    overflow: hidden;
}

.wpp-chip {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    padding: 1px 7px;
    border: 1px solid var(--linha);
    border-radius: 999px;
    font-size: var(--t-micro);
    line-height: 1.5;
    color: var(--texto-3);
}

/* O que falta amarrar. Único chip com cor de aviso na lista — se dois
   competissem, nenhum chamaria atenção. */
.wpp-chip--alerta {
    flex: 0 0 auto;
    border-color: var(--aviso);
    background: var(--aviso-vestigio);
    color: var(--aviso);
}

/* A espera é tempo, e tempo se lê melhor sem moldura: aqui ela é texto com um
   relógio implícito, e não mais um selo colorido disputando com o "sem lead". */
.wpp-chip--espera {
    flex: 0 0 auto;
    padding-left: 0;
    padding-right: 0;
    border: 0;
    background: none;
    color: var(--texto-3);
    font-variant-numeric: tabular-nums;
}
.wpp-chip--espera::before {
    content: "·";
    margin-right: 5px;
    color: var(--linha-forte);
}

.wpp-lista-vazia {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--e2);
    padding: var(--e5) var(--e4);
    text-align: center;
}

/* ----------------------------------------------------------------- Chat ---- */

.wpp-chat {
    display: flex;
    flex-direction: column;
    min-height: 0;
    min-width: 0;
    background: var(--sup);
    border: 1px solid var(--linha);
    border-radius: var(--r);
    box-shadow: var(--sombra-1);
    overflow: hidden;
}

.wpp-topo {
    display: flex;
    align-items: center;
    gap: var(--e3);
    flex: 0 0 auto;
    padding: var(--e3) var(--e4);
    border-bottom: 1px solid var(--linha);
    background: var(--sup-2);
}

/* Só existe na largura em que a lista some da tela. */
.wpp-voltar { display: none; }
.wpp-voltar svg { transform: rotate(180deg); }

.wpp-topo-dados { min-width: 0; flex: 1 1 auto; }

.wpp-topo-nome {
    margin: 0;
    font-weight: 600;
    font-size: var(--t-base);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.wpp-topo-apoio {
    margin: 0;
    font-size: var(--t-xs);
    color: var(--texto-3);
}

.wpp-espera { color: var(--info); }

.wpp-topo-acoes {
    display: flex;
    flex: 0 0 auto;
    flex-wrap: wrap;
    gap: var(--e2);
}

/* ------------------------------------------------------- Conversa sem lead - */

/* "Este número é do parceiro X."

   Mora acima do aviso de "sem lead", e é informação, não alerta: o número tem
   dono no sistema, ele só não é um cliente. Por isso o fundo neutro do painel,
   e não o amarelo do aviso logo abaixo. */
.wpp-quem-e {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: var(--e2);
    margin: 0;
    padding: var(--e2) var(--e4);
    border-bottom: 1px solid var(--linha);
    font-size: var(--t-xs);
    color: var(--texto-2);
}

.wpp-quem-e svg {
    flex: 0 0 auto;
    width: 16px;
    height: 16px;
    fill: currentColor;
}

.wpp-sem-lead {
    flex: 0 0 auto;
    padding: var(--e2) var(--e4);
    border-bottom: 1px solid var(--linha);
    background: var(--aviso-vestigio);
}
.wpp-sem-lead[open] { padding-bottom: var(--e3); }

/* Uma linha, e o campo de busca embaixo só quando se decide amarrar.

   O aviso tinha três linhas e o campo vivia aberto: quase cem pixels tirados das
   mensagens, em toda conversa sem lead — que hoje são todas. */
.wpp-sem-lead-texto {
    display: flex;
    align-items: center;
    gap: var(--e2);
    margin: 0;
    list-style: none;
    cursor: pointer;
    font-size: var(--t-xs);
    color: var(--texto-2);
}
.wpp-sem-lead > summary::marker { content: ''; }
.wpp-sem-lead > summary::-webkit-details-marker { display: none; }

/* A palavra que diz o que o clique faz. Sem ela, um aviso clicável não parece
   clicável — e o gesto que ele existe para provocar ficaria escondido. */
.wpp-sem-lead-acao {
    flex: 0 0 auto;
    margin-left: auto;
    padding: 2px 10px;
    border: 1px solid var(--aviso);
    border-radius: 999px;
    color: var(--aviso);
    font-weight: 600;
}
.wpp-sem-lead[open] .wpp-sem-lead-acao { opacity: .55; }
.wpp-sem-lead-texto:hover .wpp-sem-lead-acao { background: var(--sup); }

.wpp-sem-lead .wpp-procura-lead { margin-top: var(--e3); }
.wpp-sem-lead-texto svg {
    width: 16px;
    height: 16px;
    flex: 0 0 auto;
    margin-top: 1px;
    color: var(--aviso);
}

.wpp-procura-lead {
    display: flex;
    align-items: center;
    gap: var(--e2);
}
.wpp-procura-lead .campo__controle { flex: 1 1 auto; }

.wpp-candidatos {
    margin: var(--e2) 0 0;
    padding: 0;
    list-style: none;
    max-height: 190px;
    overflow-y: auto;
    border: 1px solid var(--linha);
    border-radius: var(--r-sm);
    background: var(--sup);
}
.wpp-candidatos form {
    display: flex;
    align-items: center;
    gap: var(--e2);
    padding: var(--e2) var(--e3);
    border-bottom: 1px solid var(--linha);
}
.wpp-candidatos li:last-child form { border-bottom: 0; }

.wpp-candidato-nome {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--t-sm);
}
.wpp-candidato-apoio { font-size: var(--t-xs); color: var(--texto-3); }

.wpp-sem-lead-nada {
    margin: var(--e2) 0 0;
    font-size: var(--t-xs);
    color: var(--texto-2);
}

/* ---- Criar, embaixo de escolher ----

   A regra em cima faz o papel do "ou": sem ela o formulário parece continuação
   da lista de candidatos, e o botão Cadastrar parece mais um Amarrar. */
.wpp-novo-lead {
    margin-top: var(--e3);
    padding-top: var(--e3);
    border-top: 1px solid var(--linha);
}

/* `flex-start`, e não `center`: quando o aviso de obrigatório aparece embaixo do
   campo, `.campo` cresce — centralizado, o botão desceria junto e a linha inteira
   pularia. Alinhados pelo topo, só o aviso ocupa espaço novo. */
.wpp-novo-lead-linha {
    display: flex;
    align-items: flex-start;
    gap: var(--e2);
}
.wpp-novo-lead-linha .campo { flex: 1 1 auto; min-width: 0; }

.wpp-novo-lead-titulo {
    margin: 0 0 var(--e2);
    font-size: var(--t-xs);
    font-weight: 600;
    color: var(--texto-2);
}
.wpp-novo-lead-nota {
    margin: var(--e2) 0 0;
    font-size: var(--t-xs);
    color: var(--texto-3);
}

/* ------------------------------------------------------------- Mensagens --- */

/* O PAPEL DE PAREDE, que e a primeira coisa que se reconhece numa tela de
   WhatsApp. Nao e uma imagem: e um losango desenhado em gradiente, que pesa
   zero byte, funciona sem Internet (CLAUDE.md secao 16) e some no modo escuro
   como no aplicativo. */
.wpp-corpo {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: var(--e4);
    background-color: var(--chat-papel);
    background-image:
        repeating-linear-gradient(45deg,
            rgba(0, 0, 0, .018) 0 2px, transparent 2px 14px),
        repeating-linear-gradient(-45deg,
            rgba(0, 0, 0, .018) 0 2px, transparent 2px 14px);
}
[data-tema="escuro"] .wpp-corpo {
    background-image:
        repeating-linear-gradient(45deg,
            rgba(255, 255, 255, .012) 0 2px, transparent 2px 14px),
        repeating-linear-gradient(-45deg,
            rgba(255, 255, 255, .012) 0 2px, transparent 2px 14px);
}

.wpp-vazio-msg {
    margin: var(--e6) 0;
    text-align: center;
    font-size: var(--t-xs);
    color: var(--texto-3);
}

.wpp-dia {
    display: table;
    margin: var(--e4) auto var(--e3);
    padding: 2px 10px;
    border-radius: 999px;
    background: var(--sup);
    border: 1px solid var(--linha);
    font-size: var(--t-micro);
    color: var(--texto-3);
}
.wpp-dia:first-child { margin-top: 0; }

/* O BALAO. Tres mudancas em relacao ao cartao generico que ele era:

   1. SEM BORDA. Balao de conversa nao tem contorno -- tem sombra rasa. A borda
      transformava a conversa numa lista de cartoes empilhados.
   2. O BICO. O canto de cima do lado de quem falou fica quase reto (4px)
      enquanto os outros tres ficam redondos. E o unico detalhe geometrico que
      diz, sem cor nenhuma, de que lado a mensagem entrou -- e funciona para
      quem nao distingue as duas cores.
   3. Largura maxima de 68%, a do aplicativo: acima disso o olho perde a
      coluna e as duas pontas da conversa deixam de se distinguir de relance. */
.wpp-msg {
    position: relative;
    max-width: min(68%, 620px);
    /* ABRACA o texto. Sem isto o balao e um bloco e ocupa a largura inteira ate
       o teto, entao "ok" virava uma faixa de 68% da tela -- que e o que mais
       destoa de uma conversa de verdade. Com fit-content a bolha tem o tamanho
       da frase, e a coluna do lado oposto respira. */
    width: fit-content;
    margin-bottom: var(--e3);
    padding: 7px 11px 5px;
    border-radius: 10px;
    background: var(--chat-dele);
    border: 0;
    box-shadow: 0 1px 1px rgba(0, 0, 0, .09);
    font-size: var(--t-sm);
}

/* A convenção que todo mundo já tem no dedo: o que saiu daqui fica à direita. */
.wpp-msg--nossa {
    margin-left: auto;
    background: var(--chat-nosso);
    /* O bico do nosso lado: canto de cima a DIREITA. */
    border-top-right-radius: 4px;
}
.wpp-msg--dele {
    margin-right: auto;
    /* E o dele, a esquerda. */
    border-top-left-radius: 4px;
}

/* No escuro o balao do cliente e escuro, e o texto precisa acompanhar -- sem
   isto ele herdaria --texto do tema, que ali ate funciona, mas o balao NOSSO
   e verde-escuro e o texto padrao do tema claro sumiria nele. */
[data-tema="escuro"] .wpp-msg .wpp-msg-texto,
[data-tema="escuro"] .wpp-msg-autor { color: #e9edef; }

/* A anotação NÃO foi para o cliente. Uma bolha igual às outras faria alguém
   jurar que mandou — daí o meio da coluna, o tracejado e o tom de aviso. */
.wpp-msg--nota {
    max-width: min(88%, 720px);
    margin-left: auto;
    margin-right: auto;
    background: var(--aviso-vestigio);
    border: 1px dashed var(--aviso);
    box-shadow: none;
}

.wpp-msg-autor {
    margin: 0 0 2px;
    font-size: var(--t-micro);
    font-weight: 600;
    color: var(--marca);
}

.wpp-msg-nota-marca {
    display: flex;
    align-items: center;
    gap: var(--e1);
    margin: 0 0 var(--e1);
    font-size: var(--t-micro);
    font-weight: 600;
    color: var(--aviso);
}
.wpp-msg-nota-marca svg { width: 13px; height: 13px; }

.wpp-msg-citada {
    margin: 0 0 var(--e1);
    padding-left: var(--e2);
    border-left: 3px solid var(--linha-forte);
    font-size: var(--t-micro);
    font-style: italic;
    color: var(--texto-3);
}

.wpp-msg-texto {
    margin: 0;
    /* O que o cliente digitou vem com as quebras de linha dele. */
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    color: var(--texto);
}

/* Texto que não é conteúdo: o mesmo idioma visual de `.wpp-msg-citada`. A frase
   da exclusão não é o que o cliente escreveu, e não deve se parecer com isso. */
.wpp-msg-texto--apagada {
    font-style: italic;
    color: var(--texto-3);
}

.wpp-msg-erro {
    margin: var(--e1) 0 0;
    font-size: var(--t-micro);
    color: var(--erro);
}

.wpp-msg-pe {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--e1);
    margin: 2px 0 0;
    font-size: 10.5px;
    color: var(--chat-hora);
}

.wpp-editada { font-style: italic; }

.wpp-tique {
    display: inline-flex;
    align-items: center;
    color: var(--texto-3);
}
.wpp-tique svg { width: 13px; height: 13px; }

/* O tique duplo é feito com dois tiques sobrepostos: o sprite local não tem um
   símbolo próprio para ele, e §16 não admite ícone vindo de fora. */
.wpp-tique--duplo svg + svg { margin-left: -7px; }
.wpp-tique--lida { color: var(--info); }
.wpp-tique--erro { color: var(--erro); }

.wpp-reacao {
    position: absolute;
    right: 10px;
    bottom: -10px;
    padding: 0 5px;
    border-radius: 999px;
    background: var(--sup);
    border: 1px solid var(--linha);
    font-size: var(--t-xs);
    line-height: 1.5;
}

/* ----------------------------------------------------------------- Mídia --- */

.wpp-imagem {
    display: block;
    max-width: 100%;
    max-height: 320px;
    width: auto;
    border-radius: var(--r-sm);
    margin-bottom: var(--e1);
}

.wpp-audio, .wpp-video {
    display: block;
    max-width: 100%;
    margin-bottom: var(--e1);
}
.wpp-audio { width: 280px; }
.wpp-video { max-height: 320px; border-radius: var(--r-sm); }

.wpp-arquivo {
    display: flex;
    align-items: center;
    gap: var(--e2);
    margin-bottom: var(--e1);
    padding: var(--e2);
    border: 1px solid var(--linha);
    border-radius: var(--r-sm);
    background: var(--sup-2);
    color: var(--texto);
    text-decoration: none;
    font-size: var(--t-xs);
}
.wpp-arquivo:hover { border-color: var(--marca); }
.wpp-arquivo svg { width: 16px; height: 16px; flex: 0 0 auto; color: var(--texto-3); }

.wpp-arquivo-nome {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.wpp-arquivo-peso { flex: 0 0 auto; color: var(--texto-3); }

.wpp-arquivo-ausente {
    display: flex;
    align-items: center;
    gap: var(--e1);
    margin: 0 0 var(--e1);
    font-size: var(--t-micro);
    color: var(--texto-3);
}
.wpp-arquivo-ausente svg { width: 13px; height: 13px; color: var(--aviso); }

/* ------------------------------------------------------------ Novidade ----- */

.wpp-novidade {
    display: flex;
    align-items: center;
    gap: var(--e2);
    flex: 0 0 auto;
    margin: 0;
    padding: var(--e2) var(--e4);
    background: var(--info-vestigio);
    border-top: 1px solid var(--linha);
    font-size: var(--t-xs);
    color: var(--texto-2);
}
.wpp-novidade[hidden] { display: none; }
.wpp-novidade svg { width: 14px; height: 14px; color: var(--info); }

/* -------------------------------------------------------------- Escrever --- */

.wpp-pe {
    flex: 0 0 auto;
    padding: var(--e3) var(--e4);
    border-top: 1px solid var(--linha);
    background: var(--sup-2);
}

/* UMA fileira, e não quatro.

   O compositor ocupava quase metade do painel da conversa: a caixa de escrever
   numa fileira, "Gravar áudio" noutra, o cronômetro da gravação numa terceira
   (visível sem se estar gravando — ver `.wpp-gravando[hidden]`), e "Anexar
   arquivo … até 32 MB" numa quarta. Sobravam duzentos pixels para as mensagens,
   que são o assunto da tela.

   Agora tudo cabe ao lado do campo, em botões de ícone. Nada saiu: o que era
   rótulo virou `title` e `aria-label`, que é como o resto do sistema trata
   ação repetida em barra estreita. */
.wpp-envio {
    display: flex;
    align-items: flex-end;
    gap: var(--e2);
}

/* `textarea.wpp-texto`, e não `.wpp-texto`: o seletor de elemento é o que
   permite vencer o `textarea.campo__entrada { min-height: 88px }` lá de cima.
   Sem ele, esta caixa nascia com 88px de altura — duas linhas e meia de nada,
   com o script logo em seguida gravando esse mesmo 88 como altura inline. Era o
   maior pedaço do compositor, e ele começava vazio. */
textarea.wpp-texto {
    /* Cresce com o texto, até um teto: quem cola um parágrafo precisa ver o
       parágrafo, e quem escreve uma linha não quer uma caixa de dez. */
    flex: 1 1 auto;
    min-width: 0;
    min-height: var(--altura-campo);
    max-height: 160px;
    padding: 9px 12px;
    resize: vertical;
    line-height: 1.45;
}

.wpp-enviar { flex: 0 0 auto; height: var(--altura-campo); }

/* Os botões de ícone do compositor, com a mesma altura do campo para a fileira
   assentar numa linha de base só. */
.wpp-envio .botao--icone {
    flex: 0 0 auto;
    width: var(--altura-campo);
    height: var(--altura-campo);
}

/* ---- Gravar audio ----
   A barra SUBSTITUI o botao enquanto grava, e nao aparece ao lado: dois
   controles visiveis ao mesmo tempo fariam alguem clicar em Gravar de novo no
   meio da gravacao. */
/* Os controles da gravação de áudio. Só existem ENQUANTO se grava.

   Faltava a linha do `[hidden]` embaixo, e uma regra de autor com `display`
   vence o `[hidden]` do navegador: o cronômetro em 0:00 com "Concluir" e
   "Descartar" ficava permanentemente na tela, ao lado de um botão "Gravar
   áudio" que ainda não tinha sido apertado. Três controles mortos ocupando uma
   fileira inteira do compositor. É o mesmo defeito que `.campo[hidden]` já
   documenta mais acima. */
.wpp-gravando {
    display: flex;
    align-items: center;
    gap: var(--e2);
    padding: 6px 10px;
    border-radius: 999px;
    background: var(--sup-2);
    border: 1px solid var(--linha);
}
.wpp-gravando[hidden] { display: none !important; }

/* O ponto pulsando e o unico sinal de que o microfone esta LIGADO. Sob
   movimento reduzido ele para de piscar mas continua vermelho e visivel --
   a cor informa, a animacao so enfeita. */
.wpp-gravando-ponto {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--erro);
    animation: veu-pulsa 1.2s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
    .wpp-gravando-ponto { animation: none; }
}

.wpp-gravando-tempo {
    font-family: var(--fonte-mono);
    font-size: var(--t-sm);
    font-variant-numeric: tabular-nums;
    color: var(--texto);
    min-width: 4ch;
}

.wpp-gravando-cancelar { color: var(--erro); }

/* O nome do arquivo anexado, ao lado do clipe. Some quando não há nada. */
.wpp-anexo-nome {
    align-self: center;
    max-width: 22ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--t-xs);
    color: var(--texto-2);
}
.wpp-anexo-nome:empty { display: none; }


/* =============================================================================
   18 · EXPORTAR A PROPOSTA — PDF ou imagem
   ============================================================================= */

/* A linha de apoio do cabeçalho da janela: qual proposta se está exportando.
   Sem ela, a janela abre igual para as vinte linhas da lista e quem clicou
   errado não tem como perceber. */
.modal__apoio {
    margin: 2px 0 0;
    font-size: var(--t-xs);
    color: var(--texto-3);
}

/* Duas opções lado a lado, do mesmo tamanho: nenhuma é a "certa".

   O PDF é o documento e a imagem é o que se manda — dois momentos do mesmo
   atendimento. Destacar uma delas escolheria pelo vendedor. */
.exportar {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: var(--e3);
}

.exportar__opcao {
    display: grid;
    justify-items: start;
    gap: 4px;
    padding: var(--e4);
    background: var(--sup);
    border: 1px solid var(--linha);
    border-radius: var(--r);
    color: inherit;
    text-decoration: none;
    transition: background var(--transicao), border-color var(--transicao);
}
.exportar__opcao:hover {
    background: var(--marca-vestigio);
    border-color: var(--marca);
}
.exportar__opcao:focus-visible {
    outline: 2px solid var(--marca);
    outline-offset: 2px;
}

.exportar__icone {
    width: 26px;
    height: 26px;
    margin-bottom: 4px;
    color: var(--marca);
}

.exportar__nome { font-size: var(--t-md); font-weight: 600; }

.exportar__apoio {
    font-size: var(--t-xs);
    color: var(--texto-3);
    line-height: 1.45;
}


/* =============================================================================
   19 · A PRIMEIRA PÁGINA DO ORÇAMENTO COMO IMAGEM
   ============================================================================= */

/* Fundo escuro atrás do canvas, como no palco do estúdio: enquanto o desenho
   não chega, um retângulo da cor do cartão não parece um lugar onde imagem vai
   aparecer.

   A folha é A4 em pé, e não mais 16:9: o teto é a altura da janela, e não a
   largura do cartão — uma folha alta esticada na largura toda empurraria os
   botões para fora da tela. */
.imagem-palco {
    max-width: min(100%, calc(78vh * 210 / 297));
    margin: 0 auto var(--e4);
    background: #0B1015;
    border-radius: var(--r);
    overflow: hidden;
}

.imagem-tela {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
}

/* A folha do orçamento: A4 em pé. O `aspect-ratio` é só para a caixa não pular
   de tamanho enquanto o PDF é baixado — depois disso o próprio canvas tem as
   medidas certas. */
.imagem-tela--folha { aspect-ratio: 210 / 297; }

.wpp-envio-nota {
    margin: var(--e2) 0 0;
    font-size: var(--t-xs);
    color: var(--aviso);
}

/* O mesmo chip dos extras: fechados, todos formam uma faixa só de gestos
   secundários embaixo do compositor. Fica fora do `.wpp-extras` no HTML porque
   aquele bloco tem condição própria — anotar existe sempre, localização e
   enquete dependem de rota configurada. */
.wpp-mais { margin-top: var(--e2); }

.wpp-mais-titulo {
    display: inline-flex;
    align-items: center;
    padding: 3px 10px;
    border: 1px solid var(--linha);
    border-radius: 999px;
    list-style: none;
    cursor: pointer;
    font-size: var(--t-xs);
    color: var(--texto-3);
    transition: background var(--transicao), color var(--transicao),
                border-color var(--transicao);
}
.wpp-mais > summary::marker { content: ''; }
.wpp-mais > summary::-webkit-details-marker { display: none; }
.wpp-mais-titulo:hover { background: var(--sup-2); }
.wpp-mais[open] > .wpp-mais-titulo {
    border-color: var(--marca);
    color: var(--marca);
}

.wpp-mais-corpo {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: var(--e3);
    margin-top: var(--e3);
}

.wpp-form-linha {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--e2);
    padding: var(--e3);
    border: 1px solid var(--linha);
    border-radius: var(--r-sm);
    background: var(--sup);
}
.wpp-form-linha .campo__entrada { width: 100%; }
.wpp-form-linha .campo__ajuda { margin: 0; }

/* ------------------------------------------------------------ Estreito ----- */

/* No telefone as duas colunas não cabem lado a lado. A tela passa a mostrar UMA
   por vez — a lista quando não há conversa aberta, a conversa quando há —, que
   é a mesma navegação do aplicativo. */
@media (max-width: 900px) {
    .wpp {
        grid-template-columns: minmax(0, 1fr);
        height: auto;
        min-height: 0;
    }
    .wpp-caixa { max-height: 60vh; }
    /* Com conversa aberta, a lista sai da vista; sem ela, a lista é a tela. */
    .wpp-caixa:not(.wpp-caixa--sozinha) { display: none; }
    .wpp-chat { min-height: 70vh; }
    .wpp-voltar { display: inline-flex; }
    .wpp-msg { max-width: 92%; }
}


/* ===========================================================================
   FILTRO DA BARRA E COLUNA DE AÇÕES

   DOIS DEFEITOS MEDIDOS NO NAVEGADOR, e não deduzidos.

   1. O SELECT DO FILTRO USAVA `campo__controle--enxuto`.
      Aquele modificador é `width: 8ch` com `text-align: right` — feito para a
      célula de porcentagem DENTRO de uma tabela. Num filtro escrito
      "Todos os responsáveis" ele dá oito caracteres de largura e a seta nativa
      do select passa por cima do texto. O comentário de propostas-lista.html já
      avisava disso; a classe foi copiada para a barra assim mesmo.

   2. A COLUNA DE AÇÕES SUMIA À DIREITA.
      A tabela de leads tem largura mínima de 1046px (a coluna Lead sozinha come
      413). Medido:

          1440   cabe
          1366   estoura  4px
          1280   estoura 90px   — Ações termina em 1345, fora da tela
          1024   estoura 346px

      O `.rolagem-h` já rolava na horizontal, então nada estava quebrado de
      verdade — mas quem abre a tela vê a linha cortada e conclui que o botão
      não existe. Rolar para achar botão não é descoberta que se espere de
      ninguém.

      A coluna de ações passa a ficar GRUDADA na direita. O fundo é opaco de
      propósito: sem ele, o texto da coluna vizinha passa por baixo enquanto se
      rola, e o par de cores acompanha o `:hover` da linha, senão a célula fica
      de uma cor e o resto da linha de outra.
   =========================================================================== */

/* O filtro é um campo de barra, e não uma célula: largura de campo. */
.barra__filtro {
    flex: 0 0 13rem;
    min-width: 0;
}
@media (max-width: 560px) {
    .barra__filtro { flex: 1 1 100%; }
}

/* A última coluna gruda na direita enquanto a tabela rola por baixo. */
.tabela--acoes-fixas thead th:last-child,
.tabela--acoes-fixas tbody td:last-child {
    position: sticky;
    right: 0;
    background: var(--sup);
    /* O filete separa o que gruda do que passa por baixo; sem ele as duas
       colunas se encostam e parecem uma só. */
    box-shadow: inset 1px 0 0 var(--linha);
}
.tabela--acoes-fixas thead th:last-child {
    background: var(--sup-2);
    z-index: 2;
}
.tabela--acoes-fixas tbody tr:hover td:last-child {
    background: var(--sup-2);
}


/* ===========================================================================
   SESSÃO DE WHATSAPP — a aba "WhatsApp" de Meu Perfil

   O NÚMERO É DO VENDEDOR, e não da instalação. Cada consultor conecta o próprio
   celular lendo um código, e por isso este assunto mora ao lado do nome e da
   senha, e não numa tela de configuração do sistema.

   A COR SAI DE `data-situacao`, E NÃO DE UMA CLASSE POR ESTADO.
   O código da situação (DESCONECTADA, AGUARDANDO_QRCODE, CONECTADA, ...) é o
   mesmo texto no banco, no Java, no JSON e aqui. Com uma classe por estado, o
   script teria de saber traduzir cada código em cada nome de classe — cinco
   traduções que divergem no dia em que um estado for acrescentado. Trocando um
   atributo de dado, o CSS reagia sozinho.

   NENHUM ESTILO ESCRITO NO HTML. A política de conteúdo desta aplicação recusa
   `style=""` (ver EncodingFilter), e o QR code é a única imagem da tela que
   precisa de medida — ela vem daqui, e não do atributo.
   =========================================================================== */

.wa {
    display: grid;
    gap: var(--e4);
}

/* O miolo é um segundo grid porque ele é UM item do primeiro: o bloco de
   "instalação sem servidor" e o conteúdo normal são alternativas, e sem esta
   grade os filhos do conteúdo se empilhariam colados. */
.wa__conteudo {
    display: grid;
    gap: var(--e4);
}

/* `hidden` precisa vencer o display do próprio componente.
   As linhas de `.dados` são `display: grid` e os pés de formulário são `flex`;
   os dois derrotam o `[hidden] { display: none }` da folha do navegador, que é
   apenas um seletor de atributo. Sem esta regra, esconder o bloco do QR o
   deixaria na tela — e o defeito só apareceria depois que o celular pareasse. */
.wa [hidden] { display: none !important; }

/* ---- Instalação sem servidor configurado ---- */
.wa__desligado {
    display: flex;
    gap: var(--e3);
    align-items: flex-start;
    padding: var(--e4);
    border: 1px solid var(--linha);
    border-radius: var(--r);
    background: var(--sup-2);
}
.wa__desligado-icone {
    width: 22px;
    height: 22px;
    flex: 0 0 auto;
    color: var(--texto-3);
}
.wa__titulo { font-size: var(--t-base); font-weight: 600; }

/* Ocupa o lugar do botão de desconectar para quem não administra a unidade.
   Um canto vazio faria a pessoa procurar o botão; a frase diz onde ele está. */
.wa__recado {
    margin: 0;
    align-self: center;
    font-size: var(--t-sm);
    color: var(--texto-3);
    max-width: 48ch;
}

.wa__ajuda {
    margin-top: var(--e1);
    font-size: var(--t-sm);
    color: var(--texto-3);
    max-width: 62ch;
}

/* ---- A situação atual ----
   A faixa colorida à esquerda é o sinal que se lê de longe; o selo repete a
   informação em palavras, porque cor sozinha não informa quem não a distingue. */
.wa__estado {
    display: grid;
    gap: var(--e2);
    justify-items: start;
    padding: var(--e4);
    border: 1px solid var(--linha);
    border-left: 3px solid var(--linha-forte);
    border-radius: var(--r);
    background: var(--sup-2);
}
.wa__selo { background: var(--sup-3); color: var(--texto-3); }
.wa__explicacao { font-size: var(--t-sm); color: var(--texto-2); max-width: 62ch; }

/* O servidor não respondeu: a tela mostra a ÚLTIMA situação conhecida e diz
   isso, em vez de fingir certeza sobre um celular que talvez esteja atendendo. */
.wa__aviso {
    display: flex;
    gap: var(--e2);
    align-items: baseline;
    font-size: var(--t-sm);
    color: var(--aviso);
    max-width: 62ch;
}

.wa__estado[data-situacao="CONECTADA"] { border-left-color: var(--ok); }
.wa__estado[data-situacao="CONECTADA"] .wa__selo {
    background: var(--ok-vestigio);
    color: var(--ok);
}
.wa__estado[data-situacao="AGUARDANDO_QRCODE"],
.wa__estado[data-situacao="INICIANDO"] { border-left-color: var(--info); }
.wa__estado[data-situacao="AGUARDANDO_QRCODE"] .wa__selo,
.wa__estado[data-situacao="INICIANDO"] .wa__selo {
    background: var(--info-vestigio);
    color: var(--info);
}
.wa__estado[data-situacao="ERRO"] { border-left-color: var(--erro); }
.wa__estado[data-situacao="ERRO"] .wa__selo {
    background: var(--erro-vestigio);
    color: var(--erro);
}
/* Pareamento desfeito por fora: âmbar, e não vermelho. Nada quebrou — alguém
   desconectou o aparelho pelo próprio WhatsApp, e o conserto é ler o código
   de novo. Vermelho aqui mandaria procurar um defeito que não existe. */
.wa__estado[data-situacao="EXPIRADA"] { border-left-color: var(--aviso); }
.wa__estado[data-situacao="EXPIRADA"] .wa__selo {
    background: var(--aviso-vestigio);
    color: var(--aviso);
}

/* ---- O número pareado ---- */
.wa__dados {
    padding: 0 var(--e1);
    max-width: 46rem;
}

/* ---- O código a ser lido ----
   O FUNDO É BRANCO NOS DOIS TEMAS, de propósito, e a moldura branca em volta
   também. O código é lido pela câmera de um celular, que espera módulos escuros
   sobre claro; no tema escuro, um QR encostado no fundo da página perde a
   "zona de silêncio" que a norma exige em volta e a leitura falha — de um jeito
   difícil de diagnosticar, porque na tela o código parece perfeito. */
.wa__qr {
    display: grid;
    gap: var(--e4);
    grid-template-columns: auto 1fr;
    align-items: center;
    padding: var(--e4);
    border: 1px solid var(--linha);
    border-radius: var(--r);
    background: var(--sup);
}
.wa__qr-imagem {
    display: block;
    width: 264px;
    height: 264px;
    max-width: 100%;
    padding: var(--e3);
    border-radius: var(--r-sm);
    background: #ffffff;
    /* A imagem chega em 264px e é ampliada por telas densas. `pixelated` evita
       que a suavização borre a borda dos módulos, que é o que a câmera lê. */
    image-rendering: pixelated;
}
.wa__passos {
    display: grid;
    gap: var(--e2);
    margin: 0;
    padding-left: 1.2rem;
    font-size: var(--t-sm);
    color: var(--texto-2);
}

@media (max-width: 640px) {
    .wa__qr {
        grid-template-columns: 1fr;
        justify-items: center;
    }
    .wa__passos { justify-self: stretch; }
}

/* ---- Rodapé ----
   O pé de ações fecha o painel, como nas outras duas abas — ele traz filete e
   faixa próprios, e no meio da coluna pareceria um corte sem motivo. Não precisa
   de regra: `.form-pe` já sabe se desenhar. */
.wa__rodape { max-width: 62ch; }


/* ===========================================================================
   FICHA TÉCNICA — PORTEIRO: o pouco de estilo que os blocos condicionais pedem

   O módulo `data-porteiro` (fim do reduzzihub.js) esconde e mostra com o atributo
   `hidden`, e nada mais. Quase tudo já funciona sem uma linha daqui:
   `.campo[hidden] { display: none !important }` existe desde a calculadora, e
   é ele que vence o `display: grid` de `.campo` — regra de autor ganha do
   `[hidden]` do navegador, que é regra de agente, e sem ela TODO campo
   escondido pelo atributo continuaria visível.

   Sobram duas coisas.
   =========================================================================== */

/* 1. O bloco que NÃO é um `.campo`.

   `data-bloco` pode pousar em qualquer elemento — um `<p>`, um `<fieldset>`,
   uma faixa de aviso. Nenhum deles tem `display: grid` para vencer, mas um
   `.form-secao` ou um contêiner com `display: flex` teria, e o mesmo defeito
   voltaria em silêncio: o bloco "fecha" e continua na tela. Uma linha resolve
   para todos, agora e para quem vier. */
[data-bloco][hidden],
[data-bloco-fechado][hidden] { display: none !important; }

/* 2. O recado que explica a ausência.

   Com a redução especial (57), a aba 4 encolhe de dezenove campos para um. Sem
   uma frase no lugar dos campos que sumiram, a tela parece quebrada — e a
   pessoa procura o que não está mais lá. `data-bloco-fechado` é o avesso do
   `data-bloco`: aparece exatamente quando o bloco some.

   Ícone e texto na mesma linha, com o ícone alinhado pela primeira linha do
   texto e não pelo meio do parágrafo: com duas ou três linhas, `center` deixa
   o ícone flutuando no meio do bloco, longe da palavra a que ele se refere.
   `.campo__ajuda` sozinha não faz isso — ela é só tamanho e cor. */
.porteiro-recado .campo__ajuda {
    display: flex;
    gap: var(--e2);
    align-items: flex-start;
    max-width: 62ch;
}
.porteiro-recado .campo__ajuda svg {
    flex: none;
    width: 16px;
    height: 16px;
    /* Meio ponto abaixo do topo do texto: o glifo tem altura menor que a linha,
       e alinhado ao topo cru ele fica visivelmente alto. */
    margin-top: 2px;
    color: var(--info);
}


/* ===========================================================================
   WHATSAPP — A CARA DE GENTE, A LIGAÇÃO E OS GESTOS DO APLICATIVO

   Segundo bloco de WhatsApp, acrescentado no FIM da folha sem tocar no
   primeiro: outras telas entraram neste arquivo em paralelo, e reabrir o bloco
   de cima seria pedir para perder o trabalho de alguém.

   Vale aqui a mesma regra de nome do bloco original: `wpp-elemento--modificador`
   e NUNCA `__`, porque quase toda escolha desta tela é condicional em Thymeleaf
   e `__…__` é lido pelo pré-processador como expressão a resolver antes.

   O QUE ESTE BLOCO ACRESCENTA, E POR QUÊ
   --------------------------------------
   1. A FOTO. Uma lista de números vira uma lista de gente. A inicial continua
      existindo e não é um remendo: contato sem foto é a maioria no primeiro
      dia, e um buraco cinza no lugar dela seria pior que a letra.
   2. A LIGAÇÃO. Chamada NÃO é mensagem, e por isso não é balão: é uma faixa
      no meio da coluna, com geometria própria. Um balão igual faria alguém
      jurar que o cliente escreveu.
   3. PERDIDA GRITA. É o sinal comercial mais quente que existe — alguém quis
      falar com a unidade AGORA e não conseguiu. Fundo, borda e peso de fonte
      trabalham juntos; a cor sozinha não serve para quem não a distingue, e
      por isso o ícone e a palavra "perdida" dizem a mesma coisa.
   4. OS MENUS SÃO `details`. Sem JavaScript eles abrem igual — estrelar,
      fixar, arquivar e marcar não lida continuam funcionando com o script
      desligado. Só encaminhar depende de script, e por isso o botão dele nasce
      escondido em vez de prometer o que não faz.
   =========================================================================== */

/* ------------------------------------------------------------------ Foto --- */

/* O avatar já era um círculo com a inicial. Agora ele é o RECORTE: a foto
   preenche por dentro e o `overflow` faz o círculo. Sem `object-fit: cover` uma
   foto retangular entraria achatada, que é o defeito mais comum de avatar. */
.wpp-avatar { overflow: hidden; }

/* O icone que substitui a inicial quando ela nao e letra. Menor que o
   circulo, para respirar dentro dele. */
.wpp-avatar-vazio { width: 18px; height: 18px; opacity: .85; }

.wpp-avatar-foto {
    /* `flex: none` porque o avatar é um contêiner flex: sem isto a foto
       fica sujeita a encolher e o círculo aparece com uma fatia branca. */
    flex: none;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* No alto da conversa o contato é o assunto da tela inteira, e não um item de
   lista: quatro pixels a mais bastam para ele parar de parecer uma linha. */
.wpp-avatar--grande { width: 42px; height: 42px; font-size: var(--t-base); }

/* -------------------------------------------------------------- Presença --- */

/* Nasce escondido: quem o acende é a conferência de fundo. `display` explícito
   obriga a repetir o `[hidden]` — sem esta linha o elemento apareceria vazio,
   porque `inline-flex` vence o `display: none` que o navegador dá ao atributo. */
.wpp-presenca {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin-right: var(--e2);
    font-weight: 600;
    color: var(--ok);
}
.wpp-presenca[hidden] { display: none; }

.wpp-presenca-ponto {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: currentColor;
    flex: 0 0 auto;
}

/* "digitando…" é outro estado, e não o mesmo em outra cor: online é um fato
   estável, digitar é uma coisa que está acontecendo agora. */
.wpp-presenca[data-estado="digitando"] { color: var(--info); }
.wpp-presenca[data-estado="digitando"] .wpp-presenca-ponto {
    animation: veu-pulsa 1s ease-in-out infinite;
}
.wpp-presenca[data-estado="offline"] { color: var(--texto-3); font-weight: 400; }
@media (prefers-reduced-motion: reduce) {
    .wpp-presenca[data-estado="digitando"] .wpp-presenca-ponto { animation: none; }
}

/* ------------------------------------------------------------- A ligação --- */

/* NÃO É UM BALÃO, e essa é a decisão inteira deste trecho. Ocupa o meio da
   coluna, tem largura própria e um contorno que nenhuma mensagem tem. */
.wpp-chamada {
    display: flex;
    align-items: center;
    gap: var(--e3);
    max-width: min(78%, 560px);
    margin: 0 auto var(--e3);
    padding: var(--e2) var(--e3);
    border: 1px solid var(--linha);
    border-left: 3px solid var(--texto-3);
    border-radius: var(--r-sm);
    background: var(--sup);
    box-shadow: 0 1px 1px rgba(0, 0, 0, .07);
    font-size: var(--t-xs);
}

.wpp-chamada-icone {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: var(--sup-2);
    color: var(--texto-3);
}
.wpp-chamada-icone svg { width: 15px; height: 15px; }

.wpp-chamada-dados { display: grid; gap: 1px; min-width: 0; flex: 1 1 auto; }

.wpp-chamada-titulo {
    font-weight: 600;
    font-size: var(--t-sm);
    color: var(--texto);
}

.wpp-chamada-apoio { font-size: var(--t-micro); color: var(--texto-3); }

.wpp-chamada-meio {
    display: flex;
    flex: 0 0 auto;
    color: var(--texto-3);
}
.wpp-chamada-meio svg { width: 15px; height: 15px; }

/* A COR SAI DO DESFECHO, POR ATRIBUTO — e não por uma classe montada em
   condição no template. O valor é o próprio `name()` do enum do banco, então
   ninguém precisa manter duas listas de nomes em dois arquivos. */
.wpp-chamada[data-desfecho="ATENDIDA"] { border-left-color: var(--ok); }
.wpp-chamada[data-desfecho="ATENDIDA"] .wpp-chamada-icone {
    background: var(--ok-vestigio);
    color: var(--ok);
}

.wpp-chamada[data-desfecho="TOCANDO"] { border-left-color: var(--info); }
.wpp-chamada[data-desfecho="TOCANDO"] .wpp-chamada-icone {
    background: var(--info-vestigio);
    color: var(--info);
}

.wpp-chamada[data-desfecho="RECUSADA"] { border-left-color: var(--aviso); }
.wpp-chamada[data-desfecho="RECUSADA"] .wpp-chamada-icone {
    background: var(--aviso-vestigio);
    color: var(--aviso);
}

/* PERDIDA GRITA. Fundo inteiro, borda vermelha nos quatro lados e o título em
   vermelho: é o único item desta tela que muda a cor do próprio fundo, porque
   é o único que significa dinheiro saindo pela porta. */
.wpp-chamada[data-desfecho="PERDIDA"] {
    border-color: var(--erro);
    border-left-color: var(--erro);
    background: var(--erro-vestigio);
}
.wpp-chamada[data-desfecho="PERDIDA"] .wpp-chamada-icone {
    background: var(--erro);
    color: #fff;
}
.wpp-chamada[data-desfecho="PERDIDA"] .wpp-chamada-titulo { color: var(--erro); }

/* -------------------------------------------------------- Fixada e estrela - */

/* A tira do alto NÃO tem estilo próprio: se nenhuma mensagem fixada estiver no
   trecho carregado ela fica vazia, e uma caixa vazia com borda parece defeito.
   Quem desenha é a LINHA. */
/* A tira em si NÃO tem aparência — só a posição na coluna. Declarada
   assim mesmo para que quem procurar por ela ache a decisão escrita, e não
   o nada que faz alguém supor que faltou CSS. */
.wpp-fixadas { flex: 0 0 auto; }

.wpp-fixada-linha {
    display: flex;
    align-items: center;
    gap: var(--e2);
    margin: 0;
    padding: var(--e2) var(--e4);
    border-bottom: 1px solid var(--linha);
    background: var(--sup-2);
    font-size: var(--t-xs);
    color: var(--texto-2);
}
.wpp-fixada-linha svg { width: 14px; height: 14px; flex: 0 0 auto; color: var(--marca); }

.wpp-fixada-texto {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.wpp-fixada-prazo { flex: 0 0 auto; font-size: var(--t-micro); color: var(--texto-3); }

/* As duas marcas no pé da bolha, ao lado da hora. */
.wpp-fixada { display: inline-flex; align-items: center; color: var(--marca); }
.wpp-fixada svg { width: 12px; height: 12px; }

.wpp-estrela { display: inline-flex; align-items: center; color: var(--aviso); }

/* A ESTRELA É DESENHADA, e não um ícone nem um caractere.

   O sprite local não tem estrela (§18 proíbe ícone de fora), e o glifo ★ não
   existe nas IBM Plex que o projeto carrega — sairia como quadrado vazio na
   máquina que não tiver outra fonte com ele. `clip-path` recorta a forma de um
   bloco de cor: nenhuma fonte, nenhum arquivo, nenhuma Internet. */
.wpp-estrela-marca {
    display: inline-block;
    width: 12px;
    height: 12px;
    background: currentColor;
    border-radius: 2px;
    clip-path: polygon(50% 1%, 61% 35%, 98% 35%, 68% 57%, 79% 91%,
                       50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
}

/* ------------------------------------------------------------------ Menus -- */

/* `details` estilizado como menu. O triângulo nativo sai pelos dois caminhos
   porque nenhum deles é universal: `::marker` é o padrão e
   `::-webkit-details-marker` é o que os motores antigos ainda usam. */
.wpp-menu { position: relative; display: inline-flex; }

.wpp-menu > summary {
    list-style: none;
    cursor: pointer;
}
.wpp-menu > summary::marker { content: ''; }
.wpp-menu > summary::-webkit-details-marker { display: none; }

.wpp-menu-abrir {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--altura-botao);
    height: var(--altura-botao);
    border: 1px solid var(--linha-forte);
    border-radius: var(--r);
    color: var(--texto-2);
    transition: background var(--transicao), border-color var(--transicao);
}
.wpp-menu-abrir:hover { background: var(--sup); border-color: var(--marca); color: var(--marca); }
.wpp-menu-abrir svg { width: 16px; height: 16px; }
.wpp-menu[open] > .wpp-menu-abrir { background: var(--sup); border-color: var(--marca); }

/* O painel abre POR CIMA do que já está desenhado, e não empurrando: um menu
   que empurra a conversa move a mensagem que a pessoa estava lendo. */
.wpp-menu-painel {
    position: absolute;
    z-index: 30;
    top: calc(100% + 4px);
    right: 0;
    min-width: 216px;
    display: flex;
    flex-direction: column;
    padding: var(--e1);
    border: 1px solid var(--linha);
    border-radius: var(--r);
    background: var(--sup);
    box-shadow: 0 8px 24px rgba(0, 0, 0, .18);
}

.wpp-menu-item {
    display: flex;
    align-items: center;
    gap: var(--e2);
    width: 100%;
    padding: 7px 10px;
    border: 0;
    border-radius: var(--r-sm);
    background: none;
    color: var(--texto-2);
    font-family: inherit;
    font-size: var(--t-xs);
    text-align: left;
    cursor: pointer;
}
.wpp-menu-item:hover { background: var(--sup-2); color: var(--texto); }
.wpp-menu-item svg { width: 15px; height: 15px; flex: 0 0 auto; color: var(--texto-3); }
.wpp-menu-item:hover svg { color: var(--marca); }
/* `display: flex` venceria o `display: none` do atributo; o botão de
   encaminhar nasce escondido e sem esta linha apareceria assim mesmo. */
.wpp-menu-item[hidden] { display: none; }

/* O único item destrutivo do menu. Vermelho no texto e no ícone, e não fundo
   sólido: um botão vermelho cheio atrai o clique justamente onde ele não deve
   ser dado por engano — o mesmo raciocínio de `.botao--perigo`. */
.wpp-menu-item--perigo { color: var(--erro); }
.wpp-menu-item--perigo svg,
.wpp-menu-item--perigo:hover svg { color: var(--erro); }
.wpp-menu-item--perigo:hover { background: var(--erro-vestigio); color: var(--erro); }

.wpp-menu-nota {
    margin: var(--e1) 0 0;
    padding: 0 10px 6px;
    font-size: var(--t-micro);
    color: var(--texto-3);
}

/* ---- O menu de uma bolha ----
   Botão pequeno, dentro do pé, à esquerda da hora. Ele fica APAGADO até o
   ponteiro chegar na bolha: cinquenta botões acesos ao mesmo tempo competiriam
   com o texto da conversa, que é o que se veio ler. Em tela de toque não há
   ponteiro, e por isso a opacidade de repouso não é zero — some, não é
   invisível. */
.wpp-msg-menu { margin-right: auto; }

.wpp-msg-menu-abrir {
    width: 20px;
    height: 20px;
    border: 0;
    border-radius: var(--r-sm);
    color: var(--chat-hora);
    opacity: .45;
    transition: opacity var(--transicao), background var(--transicao);
}
.wpp-msg-menu-abrir svg { width: 14px; height: 14px; }
.wpp-msg:hover .wpp-msg-menu-abrir,
.wpp-msg-menu[open] > .wpp-msg-menu-abrir { opacity: 1; }
.wpp-msg-menu-abrir:hover { background: rgba(0, 0, 0, .08); color: var(--texto); }
.wpp-msg-menu[open] > .wpp-msg-menu-abrir { background: rgba(0, 0, 0, .08); }

/* Abre PARA CIMA. A conversa abre rolada no fim, e é nas mensagens de baixo que
   se mexe: para baixo o painel sairia pela borda da área que rola. */
.wpp-msg-menu .wpp-menu-painel {
    top: auto;
    bottom: calc(100% + 4px);
    left: 0;
    right: auto;
}
/* Do nosso lado a bolha encosta na direita da tela; o painel acompanha, senão
   ele é quem sai pela borda. */
.wpp-msg--nossa .wpp-msg-menu .wpp-menu-painel { left: auto; right: 0; }

/* SOLTO DA CAIXA QUE ROLA.

   As duas regras acima posicionam o painel dentro de `.wpp-corpo` — e
   `.wpp-corpo` declara `overflow-y`, o que faz o navegador tratar o outro eixo
   como `auto` também: a caixa RECORTA. O corpo do chat costuma ser mais baixo
   que o painel, e então NENHUM lado cabe: para cima o painel some pela borda de
   cima, para baixo pela de baixo. Escolher o lado não resolve o que não cabe.

   Com `fixed` o painel sai do recorte e passa a ser medido contra a janela, que
   sempre tem espaço. As coordenadas vêm de ReduzziHubGestosWpp.apontarMenu, por
   CSSOM — atributo `style` no HTML a CSP desta aplicação descarta em silêncio.

   Sem script a classe nunca é posta, e valem as regras de cima: o menu abre
   preso, como abria antes. Pior nas bolhas do topo, e igual ao que já existia —
   nada regride por causa desta melhoria. */
.wpp-msg-menu--solto .wpp-menu-painel {
    position: fixed;
    top: auto;
    bottom: auto;
    left: auto;
    right: auto;
}

/* ------------------------------------------------- Localização e enquete --- */

/* Uma fileira de botõezinhos, e não três blocos de 260px empilhados.

   Cada extra ocupava uma faixa própria com `flex: 1 1 260px`, e em painel
   estreito as três desciam uma sob a outra — noventa pixels de rótulos
   fechados, tirados das mensagens. Fechados, agora são chips lado a lado;
   aberto, o formulário abre em largura cheia embaixo, porque `details` aberto
   passa a ocupar a fileira inteira. */
.wpp-extras {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: var(--e2);
    margin-top: var(--e2);
}

.wpp-extra { flex: 0 0 auto; min-width: 0; }
.wpp-extra[open] { flex: 1 1 100%; }

.wpp-extra-titulo {
    display: inline-flex;
    align-items: center;
    gap: var(--e1);
    padding: 3px 10px;
    border: 1px solid var(--linha);
    border-radius: 999px;
    list-style: none;
    cursor: pointer;
    font-size: var(--t-xs);
    color: var(--texto-3);
    transition: background var(--transicao), color var(--transicao),
                border-color var(--transicao);
}
.wpp-extra-titulo:hover { background: var(--sup-2); }
.wpp-extra[open] > .wpp-extra-titulo {
    border-color: var(--marca);
    color: var(--marca);
}
.wpp-extra > summary::marker { content: ''; }
.wpp-extra > summary::-webkit-details-marker { display: none; }
.wpp-extra-titulo:hover { color: var(--marca); }
.wpp-extra-titulo svg { width: 14px; height: 14px; }

.wpp-extra-corpo {
    display: grid;
    gap: var(--e2);
    margin-top: var(--e2);
    padding: var(--e3);
    border: 1px solid var(--linha);
    border-radius: var(--r-sm);
    background: var(--sup);
}
.wpp-extra-corpo .campo__ajuda { margin: 0; }

/* Latitude e longitude andam juntas: separá-las em duas linhas faria parecer
   que uma pode ser preenchida sem a outra. */
.wpp-extra-par {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: var(--e2);
}

.wpp-extra-acoes {
    display: flex;
    flex-wrap: wrap;
    gap: var(--e2);
}

.wpp-enquete-opcoes { display: grid; gap: var(--e1); }

/* ----------------------------------------------------------- Encaminhar --- */

.wpp-encaminhar {
    margin-top: var(--e3);
    padding: var(--e3);
    border: 1px solid var(--marca);
    border-radius: var(--r-sm);
    background: var(--marca-vestigio);
}
.wpp-encaminhar[hidden] { display: none; }
.wpp-encaminhar form { display: grid; gap: var(--e2); }
.wpp-encaminhar .campo__ajuda { margin: 0; }

/* ------------------------------------------------------------ Estreito ----- */

@media (max-width: 900px) {
    /* Na largura do telefone o menu de bolha some por hover nenhum: sem
       ponteiro, `:hover` nunca acontece e o botão ficaria em .45 para sempre. */
    .wpp-msg-menu-abrir { opacity: .8; }
    .wpp-chamada { max-width: 94%; }
}

/* ------------------------------------------------------------- O recado --- */

/* O que o NAVEGADOR recusou — microfone e localização negados. Não é erro do
   sistema, e por isso não é vermelho de falha: é o tom de aviso, e sai sozinho
   depois de alguns segundos (ver ReduzziHubGestosWpp.recado). */
.wpp-recado {
    display: flex;
    align-items: center;
    gap: var(--e2);
    margin: var(--e2) 0 0;
    padding: var(--e2) var(--e3);
    border: 1px solid var(--aviso);
    border-radius: var(--r-sm);
    background: var(--aviso-vestigio);
    font-size: var(--t-xs);
    color: var(--texto-2);
}
.wpp-recado[hidden] { display: none; }


/* =============================================================================
   17 · O ESTÚDIO DE VÍDEO DA PROPOSTA
   =============================================================================

   Só a tela interna. A página que o CLIENTE vê tem folha própria
   (assets/css/video.css) — ela não tem área, não tem menu e não pode depender
   de `data-area` no <html> para escolher cor.
   ============================================================================= */

.estudio__aviso {
    margin: 0 0 var(--e3);
    padding: var(--e3);
    background: var(--erro-vestigio);
    border: 1px solid var(--erro);
    border-radius: var(--r);
    color: var(--texto);
    font-size: var(--t-sm);
}

/* Fundo preto no palco, e não no <video>: enquanto não há gravação o elemento
   é transparente, e um retângulo da cor do cartão não parece um lugar onde
   vídeo vai aparecer. */
/* O palco não passa de meia tela de altura. O painel é 16:9 e em largura cheia
   ele empurraria os botões de gravar para baixo da dobra — e o botão de PARAR
   fora da vista é o pior defeito possível numa tela de gravação. */
.estudio__palco {
    position: relative;
    max-width: min(100%, calc(54vh * 16 / 9));
    margin: 0 auto var(--e3);
    background: #000;
    border-radius: var(--r);
    overflow: hidden;
}

/* O canvas E o video: e ele que o MediaRecorder captura. Largura cheia, 16:9
   fixo -- o mesmo formato do arquivo gravado, para o que se ve ser o que sai. */
.estudio__tela {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
    background: #0B1015;
}
.estudio__tela[hidden] { display: none; }

/* O cursor conta qual modo está valendo, antes de o dedo encostar no painel
   que está indo para o vídeo. */
.estudio__tela { cursor: default; }
.estudio__tela--mover   { cursor: grab; }
.estudio__tela--lousa   { cursor: crosshair; }
.estudio__tela--zoom    { cursor: zoom-in; }
.estudio__tela--recorte { cursor: move; }
.estudio__tela--pegando { cursor: grabbing; }

/* ---- A barra de ferramentas do palco ---- */

.estudio__ferramentas {
    display: flex;
    flex-wrap: wrap;
    gap: var(--e2);
    margin-bottom: var(--e3);
    padding-bottom: var(--e3);
    border-bottom: 1px solid var(--linha);
}

.estudio__ferramenta svg { width: 14px; height: 14px; }

/* O modo escolhido, na cor da ação. Um só de cada grupo — quem lê a barra
   precisa saber o que está valendo sem testar. */
.estudio__ferramenta--ativa {
    background: var(--acao-vestigio);
    border-color: var(--acao);
    color: var(--acao);
}

/* A mesma coisa, ancorada em `.botao`, e o motivo é especificidade: sozinha, a
   regra acima tem peso 0,1,0 e PERDE para `.botao:hover` (0,2,0) — passar o
   mouse por cima da ferramenta LIGADA apagava o verde dela. Com a coluna de
   modos sempre à vista, esse verde vira a principal referência de "o que o
   ponteiro faz", e o defeito ficaria em cena o tempo todo.

   As bolinhas de cor não são `.botao`, então não são alcançadas aqui e
   continuam pintadas por `.estudio__cor[data-video-lousa-cor]`, mais abaixo. */
.botao.estudio__ferramenta--ativa,
.botao.estudio__ferramenta--ativa:hover {
    background: var(--acao-vestigio);
    border-color: var(--acao);
    color: var(--acao);
}

/* A sub-barra do modo em curso. Só uma fica visível por vez. */
.estudio__sub {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--e3);
    margin-bottom: var(--e3);
    padding: var(--e2) var(--e3);
    background: var(--sup-2);
    border: 1px solid var(--linha);
    border-radius: var(--r);
}
.estudio__sub[hidden] { display: none; }
.estudio__sub .campo__ajuda { flex-basis: 100%; margin: 0; }

.estudio__grupo { display: flex; flex-wrap: wrap; gap: var(--e1); }

/* As cinco cores da lousa.

   A cor sai de SELETOR, e não de `style` inline: a política de conteúdo tem
   `style-src 'self'`, e um atributo `style` é descartado em silêncio — é o
   mesmo defeito que deixou os cartões do Kanban cinza. Cinco cores fixas
   significam cinco regras, e nenhuma delas some. */
.estudio__cor {
    width: 26px;
    height: 26px;
    padding: 0;
    border: 2px solid var(--linha-forte);
    border-radius: 50%;
    cursor: pointer;
    transition: transform var(--transicao), border-color var(--transicao);
}
.estudio__cor:hover { transform: scale(1.12); }
.estudio__cor.estudio__ferramenta--ativa {
    border-color: var(--texto);
    transform: scale(1.12);
}

.estudio__cor[data-video-lousa-cor="#EF4444"] { background: #EF4444; }
.estudio__cor[data-video-lousa-cor="#FACC15"] { background: #FACC15; }
.estudio__cor[data-video-lousa-cor="#16B364"] { background: #16B364; }
.estudio__cor[data-video-lousa-cor="#3B82F6"] { background: #3B82F6; }
.estudio__cor[data-video-lousa-cor="#FFFFFF"] { background: #FFFFFF; }

/* O chip do modo, sobre o palco. Verde porque é estado da FERRAMENTA, e não da
   gravação — o de gravação é o que fica ao lado, em preto. */
.estudio__chip--modo { background: var(--acao); }

/* ---- As quatro etapas ---- */

/* A etapa fora de cena sai da TELA, e não do documento: `display: none` faz
   alguns navegadores pararem de entregar quadros de um <video>, e o <video> da
   câmera vive dentro da etapa de preparo. Escondida assim, ela levaria a câmera
   junto — e o canvas desenharia um círculo preto na hora de gravar. */
.estudio__etapa-corpo--fora {
    position: absolute;
    left: -99999px;
    top: 0;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

.estudio__etapas {
    display: flex;
    flex-wrap: wrap;
    gap: var(--e2);
    list-style: none;
    margin: 0 0 var(--e4);
    padding: 0;
    counter-reset: etapa;
}

.estudio__etapa {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 5px 12px 5px 8px;
    border: 1px solid var(--linha);
    border-radius: 999px;
    color: var(--texto-3);
    font-size: var(--t-xs);
    font-weight: 600;
    counter-increment: etapa;
}

/* O número vem do CSS e não do HTML: a ordem das etapas é uma propriedade da
   lista, e escrevê-la à mão em quatro <li> é convidar a que ela desencontre. */
.estudio__etapa::before {
    content: counter(etapa);
    display: grid;
    place-items: center;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--sup-3);
    font-size: 10px;
}

.estudio__etapa--atual {
    border-color: var(--acao);
    background: var(--acao-vestigio);
    color: var(--acao);
}
.estudio__etapa--atual::before { background: var(--acao); color: #fff; }

.estudio__etapa--feita { color: var(--texto-2); }
.estudio__etapa--feita::before {
    content: "✓";
    background: var(--acao-vestigio);
    color: var(--acao);
}

/* ---- Preparo ---- */

.estudio__preparo {
    display: grid;
    grid-template-columns: minmax(260px, 1fr) minmax(280px, 1fr);
    gap: var(--e4);
    margin-bottom: var(--e4);
}

@media (max-width: 860px) {
    .estudio__preparo { grid-template-columns: 1fr; }
}

/* Fundo preto no espelho, e não no <video>: enquanto a câmera não abriu o
   elemento é transparente, e um retângulo da cor do cartão não parece um lugar
   onde vídeo vai aparecer. */
.estudio__espelho {
    position: relative;
    display: grid;
    place-items: center;
    aspect-ratio: 16 / 9;
    background: #000;
    border-radius: var(--r);
    overflow: hidden;
}

/* Espelhada de propósito: é assim que a pessoa se vê no espelho, e é a única
   imagem de si que ela sabe julgar. */
.estudio__camera-previa {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transform: scaleX(-1);
}

.estudio__espelho-vazio {
    position: absolute;
    margin: 0;
    padding: 0 var(--e4);
    color: #9AA4B2;
    font-size: var(--t-sm);
    text-align: center;
}
.estudio__espelho-vazio[hidden] { display: none; }

.estudio__opcoes {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--e3) var(--e4);
    align-content: start;
}

/* Cada campo encosta no topo da própria linha. Sem isto, o campo do microfone
   — que tem medidor e legenda embaixo — estica a linha inteira, e o rótulo
   "Câmera" fica pendurado longe do seu próprio select. */
.estudio__opcoes .campo { align-content: start; }

.estudio__marcas { grid-column: 1 / -1; }
.estudio__marcas .marcador { padding: 4px 0; }

/* O medidor de voz. Sem transição na largura: o atraso faria a barra parecer
   responder a outra frase, e a pergunta que ela responde é "o microfone é
   este mesmo?". */
.estudio__medidor {
    height: 6px;
    margin-top: 6px;
    background: var(--sup-3);
    border-radius: 999px;
    overflow: hidden;
}

.estudio__medidor-nivel {
    display: block;
    width: 0;
    height: 100%;
    background: var(--acao);
}

.estudio__previa {
    display: block;
    width: 100%;
    max-height: 46vh;
    background: #000;
}
.estudio__previa[hidden] { display: none; }

/* Os avisos por cima do vídeo, e não ao lado: durante a gravação a pessoa olha
   para o painel que está sendo gravado, e um número fora do palco fica fora do
   campo de visão. */
.estudio__chips {
    position: absolute;
    top: var(--e2);
    right: var(--e2);
    display: flex;
    gap: var(--e2);
}

.estudio__chip {
    padding: 3px 10px;
    border-radius: 999px;
    background: rgba(0, 0, 0, .65);
    color: #fff;
    font-size: var(--t-xs);
    font-weight: 600;
}
.estudio__chip[hidden] { display: none; }
/* Chip sem texto nao existe: e o caso do zoom em 1x, que nao tem o que dizer. */
.estudio__chip:empty { display: none; }

.estudio__chip--tempo {
    font-family: var(--fonte-mono);
    font-variant-numeric: tabular-nums;
}

/* 3 · 2 · 1 no meio do palco. Grande porque ela é vista de longe: quem grava
   apoia o celular ou se afasta do teclado para falar. */
.estudio__contagem {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    background: rgba(0, 0, 0, .45);
    color: #fff;
    font-size: clamp(3rem, 12vw, 7rem);
    font-weight: 800;
    letter-spacing: -.02em;
}
.estudio__contagem[hidden] { display: none; }

.estudio__acoes { display: flex; flex-wrap: wrap; gap: var(--e2); }
.estudio__envio { margin-top: var(--e4); }

/* ---- "Como devo gravar minha proposta?" ----
   A janela de mensagem tem 430px porque carrega texto; esta carrega um vídeo
   de tela, e em 430px ninguém lê o que está sendo clicado no exemplo. Cresce
   até 960px e cede a altura para o vídeo — o corpo não rola. */
.estudio__ajuda-caixa { width: min(960px, 100%); }
.estudio__ajuda-corpo { overflow: visible; }
.estudio__ajuda-corpo p { margin-bottom: var(--e3); }

.estudio__ajuda-video {
    display: block;
    width: 100%;
    max-height: min(70vh, 560px);
    background: #000;
    border-radius: var(--r);
}
.estudio__envio[hidden] { display: none; }

/* Os ajustes ao vivo ficam numa faixa separada das ações: são de outra
   natureza — não avançam nada, só mudam o que está sendo desenhado. */
.estudio__ajustes {
    display: flex;
    flex-wrap: wrap;
    gap: var(--e2);
    margin-top: var(--e3);
    padding-top: var(--e3);
    border-top: 1px solid var(--linha);
}

/* ---- Revisão: o corte ---- */

.estudio__corte { margin-top: var(--e4); }

/* A faixa mostra o TRECHO, e não a posição: os dois deslizantes já dizem onde
   começa e onde termina, e o que falta é enxergar quanto sobrou. */
.estudio__faixa {
    position: relative;
    height: 10px;
    margin-bottom: var(--e3);
    background: var(--sup-3);
    border: 1px solid var(--linha);
    border-radius: 999px;
    overflow: hidden;
}

.estudio__faixa-trecho {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 100%;
    background: var(--acao);
}

.estudio__deslizante { width: 100%; accent-color: var(--acao); }

.estudio__corte-pe {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--e4);
    margin-top: var(--e2);
}

.estudio__duracao { font-size: var(--t-sm); color: var(--texto-2); }
.estudio__duracao strong { font-variant-numeric: tabular-nums; }

/* O aviso do reprocessamento não é erro: ele explica uma espera. Vermelho ali
   faria a pessoa desfazer o corte achando que errou. */
.estudio__aviso--calmo {
    background: var(--sup-3);
    border-color: var(--linha);
    color: var(--texto-2);
}

/* ---- A barra de progresso ---- */

.estudio__progresso { margin: var(--e3) 0; }
.estudio__progresso[hidden] { display: none; }

.estudio__progresso-trilho {
    height: 8px;
    background: var(--sup-3);
    border-radius: 999px;
    overflow: hidden;
}

.estudio__progresso-barra {
    display: block;
    width: 0;
    height: 100%;
    background: var(--acao);
    transition: width var(--transicao);
}

.estudio__progresso-texto {
    margin: 6px 0 0;
    font-size: var(--t-xs);
    color: var(--texto-3);
    font-variant-numeric: tabular-nums;
}

/* ---- Compartilhar ---- */

.estudio__pronto {
    display: flex;
    align-items: center;
    gap: var(--e2);
    margin: 0 0 var(--e4);
    padding: var(--e3);
    background: var(--acao-vestigio);
    border: 1px solid var(--acao);
    border-radius: var(--r);
    color: var(--acao);
    font-weight: 600;
}
.estudio__pronto svg { width: 16px; height: 16px; flex: none; }

/* ---- A lista do que já foi gravado ---- */

.estudio__lista { list-style: none; margin: 0; padding: 0; }

.estudio__item {
    padding: var(--e3) 0;
    border-bottom: 1px solid var(--linha);
}
.estudio__item:last-child { border-bottom: none; }

.estudio__cabeca {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--e2);
}

.estudio__nome { margin: 0; font-size: var(--t-md); font-weight: 600; }

.estudio__meta,
.estudio__numeros {
    margin: var(--e1) 0 0;
    font-size: var(--t-xs);
    color: var(--texto-3);
}
.estudio__forte { color: var(--acao); font-weight: 600; }

/* O link inteiro visível: um endereço cortado com reticências não dá para
   conferir antes de mandar ao cliente. */
.estudio__link {
    display: flex;
    gap: var(--e2);
    margin: var(--e2) 0;
}
.estudio__link .campo__entrada {
    font-family: var(--fonte-mono);
    font-size: var(--t-xs);
}

/* Botão de ajuste: mesma peça, corpo menor. Os ajustes ao vivo são muitos e
   com o corpo cheio empurrariam o palco para fora da tela do notebook. */
.botao--pequeno {
    padding: 4px 10px;
    font-size: var(--t-xs);
}

.estudio__botoes {
    display: flex;
    flex-wrap: wrap;
    gap: var(--e2);
    margin-top: var(--e2);
    align-items: center;
}
.estudio__botoes form { margin: 0; }

/* ---- A trilha do cliente ---- */

.estudio__trilha {
    list-style: none;
    margin: var(--e3) 0 0;
    padding: var(--e3);
    background: var(--sup-2);
    border-radius: var(--r);
    font-size: var(--t-sm);
}
.estudio__trilha > li {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--e2);
    padding: 5px 0;
}
.estudio__trilha-icone { width: 14px; height: 14px; color: var(--texto-3); }
.estudio__trilha-quando {
    margin-left: auto;
    font-family: var(--fonte-mono);
    font-size: var(--t-xs);
    color: var(--texto-3);
}
.estudio__trilha-recado {
    flex: 1 1 100%;
    margin: 2px 0 0;
    padding-left: 22px;
    color: var(--texto-2);
}

/* Os pedidos de alteracao, escritos no cartao do video. Faixa de aviso: e o
   que o consultor precisa responder. */
.estudio__pedidos {
    margin: 10px 0 0;
    padding: 10px 12px;
    border-left: 3px solid var(--aviso);
    border-radius: 6px;
    background: var(--aviso-vestigio);
}

.estudio__pedidos-titulo {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0 0 6px;
    font-weight: 600;
    color: var(--texto);
}

.estudio__pedidos-titulo svg {
    width: 16px;
    height: 16px;
    color: var(--aviso);
}

.estudio__pedidos ul {
    margin: 0;
    padding: 0;
    list-style: none;
}

.estudio__pedidos li + li {
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px dashed rgba(127, 127, 127, .3);
}

.estudio__pedidos li p {
    margin: 2px 0 0;
    color: var(--texto);
    white-space: pre-line;
    overflow-wrap: anywhere;
}

.estudio__pedidos-quando {
    font-size: 12px;
    color: var(--texto-3);
}

.estudio__pedidos .estudio__pedidos-vazio {
    color: var(--texto-3);
    font-style: italic;
}


/* =============================================================================
   20 · O ESTÚDIO EM MODO GRAVAÇÃO

   A etapa 2 é a única tela travada do sistema, e o motivo é o pedido de quem
   usa: na tela de referência (InssObra) os botões estavam todos visíveis de uma
   vez, e aqui eles se empilhavam abaixo de um painel 16:9 — com o botão de
   PARAR frequentemente abaixo da dobra.

   COMO O MODO É LIGADO, SEM UMA LINHA DE JAVASCRIPT

   `irPara('estudio')` já faz a única coisa de que o CSS precisa: tira
   `.estudio__etapa-corpo--fora` desta seção. Então o interruptor é
   `:has([data-etapa="estudio"]:not(.estudio__etapa-corpo--fora))` no `.app`. A
   tela de referência fazia o mesmo com uma classe no <body> posta pelo script;
   aqui não é preciso tocar em `video-estudio.js`, e o estado não pode ficar
   dessincronizado da etapa — ele É a etapa.

   QUEM ROLA CONTINUA SENDO A JANELA

   Nada aqui põe `overflow: hidden` no <body>, no `.app` ou no `.app__conteudo`
   (este último não pode virar caixa de rolagem: quebraria os `position: sticky`
   de dentro). A conta de altura tem folga, mas se um dos três avisos de
   impedimento aparecer — endereço inseguro, navegador sem MP4, permissão
   negada — a tela simplesmente passa a rolar um pouco. Rolar um pouco é o modo
   de falhar aceitável; cortar o botão de PARAR não é.

   POR QUE TUDO DENTRO DE UMA MEDIA QUERY DE LARGURA **E** ALTURA

   A tela travada só faz sentido quando há janela para travar. Abaixo de 1024px
   o trilho já virou gaveta `fixed` com cortina e a coluna de ferramentas não
   caberia ao lado do palco; abaixo de 680px de altura o palco ficaria menor que
   a prévia do preparo. Nos dois casos o estúdio empilhado continua valendo —
   inclusive em navegador sem `:has()`, onde nenhuma regra deste bloco casa e a
   tela fica exatamente como era antes desta entrega.
   ============================================================================= */

/* ---- 0 · O sinal de gravação em curso ----

   `data-video-parar` só perde o `hidden` enquanto existe gravação em curso —
   gravando ou pausado. Isso dá, sem nenhuma classe de estado e sem tocar no
   script, o chip vermelho com o ponto pulsando que era a marca da tela de
   referência.

   O ponto é `::before`, e NÃO um elemento filho: o script reescreve o
   `textContent` do chip de situação a cada troca de estado e apagaria qualquer
   coisa que estivesse aqui dentro. Vale em qualquer largura, inclusive na tela
   empilhada. */
[data-etapa="estudio"]:has([data-video-parar]:not([hidden])) [data-video-situacao] {
    background: var(--erro);
}
[data-etapa="estudio"]:has([data-video-parar]:not([hidden])) [data-video-situacao]::before {
    content: "";
    display: inline-block;
    width: 8px;
    height: 8px;
    margin-right: 6px;
    border-radius: 50%;
    background: #fff;
    vertical-align: middle;
    animation: estudioPulsa 1.1s ease-in-out infinite;
}
@keyframes estudioPulsa {
    0%, 100% { opacity: 1; }
    50%      { opacity: .25; }
}
/* O bloco global de `prefers-reduced-motion` derruba a duração para .01ms e a
   iteração para 1: o ponto fica aceso e parado, que é o comportamento certo —
   o sinal de "estou gravando" não pode depender de animação. */

/* ---- 0.1 · O anel de foco das bolinhas de cor ----

   O `:focus-visible` global força `border-radius: var(--r-sm)` no próprio
   elemento. Numa bolinha de 26px isso a transforma em quadradinho arredondado
   na hora em que ela recebe o foco pelo teclado — justamente para quem depende
   do anel. */
.estudio__cor:focus-visible { border-radius: 50%; }

/* ---- 0.2 · O rótulo da coluna de ferramentas ----

   A tela de referência escrevia "Lousa" em cima da coluna pelo mesmo motivo:
   uma pilha de botões sem nome é um enigma. Fora do modo travado ele também
   serve, como título da barra horizontal. */
.estudio__rotulo {
    margin: 0 0 var(--e1);
    color: var(--texto-3);
    font-size: var(--t-micro);
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
}


@media (min-width: 1024px) and (min-height: 680px) {

/* ---- 1 · A casca da página sai de cena ----

   O mesmo recorte da tela de referência: o menu lateral e a barra superior
   FICAM (são a orientação de onde se está) e some tudo que só descreve a tela —
   a faixa do título, o cabeçalho do cartão, o rodapé e os cartões de
   acompanhamento, que durante a gravação não têm nenhuma pergunta a responder.

   Os cartões de baixo são ESCONDIDOS, e não removidos: continuam no DOM, então
   o `raiz.querySelector('[data-video-lista-vazia]')` do `compartilhar()` segue
   encontrando o que precisa.

   A linha do rodapé precisa ir a ZERO junto com o `display: none`: a grade do
   `.app` reserva `var(--rodape-h)` por trilha FIXA, e esconder só o conteúdo
   deixaria 44px de faixa morta embaixo dos comandos. */
.app:has([data-etapa="estudio"]:not(.estudio__etapa-corpo--fora)) {
    grid-template-rows: var(--topo-h) minmax(0, 1fr) 0;
}

.app:has([data-etapa="estudio"]:not(.estudio__etapa-corpo--fora)) .pagina-topo,
.app:has([data-etapa="estudio"]:not(.estudio__etapa-corpo--fora)) .app__rodape,
.app:has([data-etapa="estudio"]:not(.estudio__etapa-corpo--fora))
    .painel--formulario > .painel__cabecalho,
.app:has([data-etapa="estudio"]:not(.estudio__etapa-corpo--fora))
    [data-video-proposta] > .painel:not(.painel--formulario) {
    display: none;
}

/* O respiro da tela encolhe para o de janela estreita: 16px em vez de 24/32.
   São 24px a mais de palco, e é altura que o olho usa. */
.app:has([data-etapa="estudio"]:not(.estudio__etapa-corpo--fora)) .conteudo {
    padding: var(--e4);
}

/* As quatro etapas FICAM. Custam 30px e são a única coisa que ainda diz "você
   está na 2 de 4" depois que a faixa do título saiu.

   A margem inferior vai a zero de propósito: ela e a `margin-top` que
   `.painel__corpo > * + *` dá à seção são margens adjacentes e COLAPSAM para a
   maior. Zerando esta, a conta de altura tem um número só para conferir. */
.app:has([data-etapa="estudio"]:not(.estudio__etapa-corpo--fora)) .estudio__etapas {
    margin-bottom: 0;
}


/* ---- 2 · A seção vira a grade do estúdio ----

   Seis linhas e duas colunas. O palco ocupa o alto da coluna da direita; a
   coluna da esquerda é o trilho de ferramentas inteiro, do jeito que a tela de
   referência fazia com a coluna da lousa.

   AS DUAS CONSTANTES, decompostas para poderem ser recalculadas

   O que sobra ACIMA e ABAIXO da seção, já sem o `--topo-h`:
       16 respiro do `.conteudo`      +  1 borda do painel
     + 16 do `.painel__corpo`         + 30 a lista de etapas
     + 12 a margem colapsada          + 16 do `.painel__corpo`
     +  1 borda do painel             + 16 respiro do `.conteudo`   = 108
   Arredondado para 120: os 12px de sobra viram fundo no pé da tela. Sobrar é
   inofensivo; faltar tira o botão de PARAR da vista.

   `--estudio-palco-h` é a altura livre da área do palco. Como o palco cobre a
   linha 1 (`auto`) MAIS a linha 2 (`minmax(0,1fr)`), e a linha 2 absorve toda a
   sobra, essa altura NÃO depende de quão alta fica a coluna de modos — só do
   que vem depois dela:
       18 a linha da dica              + 64 a faixa de comandos (46+16+2)
     + 52 a faixa de ajustes (34+16+2) + 24 os três vãos de 8px      = 158
   Somado ao 120 acima, e com 14px de folga, dá os 292 do `calc`. */
.app:has([data-etapa="estudio"]:not(.estudio__etapa-corpo--fora)) [data-etapa="estudio"] {
    --estudio-trilho: 232px;
    --estudio-fora: 120px;
    --estudio-palco-h: calc(100vh - var(--topo-h) - 292px);

    display: grid;
    grid-template-columns: var(--estudio-trilho) minmax(0, 1fr);
    grid-template-rows: auto auto minmax(0, 1fr) auto auto auto;
    grid-template-areas:
        "rotulo palco"
        "modos  palco"
        "sub    palco"
        "sub    ajuda"
        "sub    acoes"
        "sub    ajustes";
    gap: var(--e2) var(--e3);
    height: calc(100vh - var(--topo-h) - var(--estudio-fora));
    min-height: 460px;
}

.app:has([data-etapa="estudio"]:not(.estudio__etapa-corpo--fora))
    [data-etapa="estudio"] > .estudio__rotulo {
    grid-area: rotulo;
    align-self: end;
}


/* ---- 3 · O palco ----

   A largura sai da ALTURA disponível, e não mais de `54vh` fixo: é o mesmo
   `min()` da regra base, com a conta certa. Em janela larga o palco tem
   exatamente `--estudio-palco-h` de altura; em janela estreita ele para na
   largura da coluna e encolhe na proporção.

   `height: auto` é essencial: a altura vem do canvas, que continua sendo
   `width: 100%` + `aspect-ratio: 16/9`. Assim o quadro NUNCA deixa de ser 16:9
   — o que se enquadra é o que o cliente recebe — e o mapeamento do ponteiro
   (`getBoundingClientRect` → 1920×1080) continua linear e sem letterbox.

   `max-height: 100%` é a trava de segurança e o modo de falhar escolhido: se
   alguma faixa quebrar em duas linhas e a linha do palco encolher, o palco
   corta a tira de baixo (ele já é `overflow: hidden`) em vez de deformar o
   quadro ou passar por cima dos comandos. Corte não desalinha a caneta — o
   retângulo do canvas continua o mesmo. */
.app:has([data-etapa="estudio"]:not(.estudio__etapa-corpo--fora))
    [data-etapa="estudio"] > .estudio__palco {
    grid-area: palco;
    align-self: center;
    width: min(100%, calc(var(--estudio-palco-h) * 16 / 9));
    max-width: none;
    height: auto;
    max-height: 100%;
    margin: 0 auto;
}


/* ---- 4 · O trilho da esquerda ----

   Os quatro modos viram botões de largura inteira, um por linha: é o alvo de
   clique grande da tela de referência, e o rótulo alinhado à esquerda deixa a
   coluna legível de cima a baixo, em vez de quatro palavras centralizadas. */
.app:has([data-etapa="estudio"]:not(.estudio__etapa-corpo--fora))
    [data-etapa="estudio"] > .estudio__ferramentas {
    grid-area: modos;
    align-self: start;
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: stretch;
    gap: var(--e1);
    margin: 0;
    padding: var(--e2);
    background: var(--sup-2);
    border: 1px solid var(--linha);
    border-radius: var(--r);
}

.app:has([data-etapa="estudio"]:not(.estudio__etapa-corpo--fora))
    [data-etapa="estudio"] > .estudio__ferramentas .estudio__ferramenta {
    justify-content: flex-start;
}

/* As três sub-barras dividem a MESMA célula. O script garante que no máximo uma
   está sem `hidden`, e `.estudio__sub[hidden]` a tira da grade — então não há
   sobreposição nem altura reservada à toa.

   `align-items: stretch` no lugar do `center` da regra base: numa coluna,
   `center` deixaria cada grupo com a largura do conteúdo e o trilho viraria uma
   escada. Os grupos continuam `flex-wrap: wrap` e se acomodam sozinhos nos
   ~214px úteis — a lousa inteira ocupa ~208px de altura, contra ~434px se cada
   botão ganhasse a sua linha. É isso que a mantém visível de uma vez só.

   `max-height` + `overflow-y` são seguro de sobra, não plano: se um dia um
   grupo crescer, o trilho rola por dentro e nada vaza sobre os comandos. */
.app:has([data-etapa="estudio"]:not(.estudio__etapa-corpo--fora))
    [data-etapa="estudio"] > .estudio__sub {
    grid-area: sub;
    align-self: start;
    flex-direction: column;
    align-items: stretch;
    gap: var(--e2);
    margin: 0;
    max-height: 100%;
    overflow-y: auto;
}

/* `flex-basis: 100%` quebra a linha numa barra HORIZONTAL; numa coluna, a mesma
   declaração vira ALTURA de 100% e estoura o trilho. */
.app:has([data-etapa="estudio"]:not(.estudio__etapa-corpo--fora))
    [data-etapa="estudio"] > .estudio__sub .campo__ajuda {
    flex-basis: auto;
}

/* "Aproximar o rosto" tem ~120px e `.botao` é `white-space: nowrap`: em
   qualquer arranjo de duas colunas ele vazaria. Este grupo é o único que fica
   em coluna. */
.app:has([data-etapa="estudio"]:not(.estudio__etapa-corpo--fora))
    [data-etapa="estudio"] > [data-video-barra-recorte] .estudio__grupo {
    flex-direction: column;
    align-items: stretch;
}


/* ---- 5 · A dica, encostada no palco ---- */
.app:has([data-etapa="estudio"]:not(.estudio__etapa-corpo--fora))
    [data-etapa="estudio"] > .campo__ajuda {
    grid-area: ajuda;
    margin: 0;
    text-align: center;
}


/* ---- 6 · As duas faixas do pé do estúdio ----

   Dois cartões brancos colados, e não um só: é o mesmo par que já existia
   (comandos e ajustes ao vivo), e a linha que os separava vira a emenda entre
   eles. O separador vertical da tela de referência é este vão de 8px.

   Ficam EMPILHADOS, e não lado a lado, por conta: em 1366px de largura os cinco
   ajustes já ocupam ~650px e os comandos ~570px — lado a lado a faixa quebraria
   justamente na janela mais comum. Empilhadas, cada uma tem a largura toda e
   nenhuma das duas quebra em nenhuma janela onde este modo está ligado. */
.app:has([data-etapa="estudio"]:not(.estudio__etapa-corpo--fora))
    [data-etapa="estudio"] > .estudio__acoes {
    grid-area: acoes;
    align-items: center;
    gap: var(--e2);
    padding: var(--e2) var(--e3);
    background: var(--sup);
    border: 1px solid var(--linha);
    border-radius: var(--r);
    box-shadow: var(--sombra-1);
}

/* O empurrão para a direita. É o `span.ms-auto` da tela de referência: a saída
   fica na ponta oposta dos comandos, longe do dedo que está gravando. */
.app:has([data-etapa="estudio"]:not(.estudio__etapa-corpo--fora))
    [data-etapa="estudio"] > .estudio__acoes > [data-video-voltar-preparo] {
    margin-left: auto;
}

/* A regra base dos ajustes tem `border-top` + `margin-top` + `padding-top`: os
   três precisam ser zerados aqui, senão a faixa nasce com uma linha solta por
   cima do cartão. */
.app:has([data-etapa="estudio"]:not(.estudio__etapa-corpo--fora))
    [data-etapa="estudio"] > .estudio__ajustes {
    grid-area: ajustes;
    align-items: center;
    gap: var(--e2);
    margin: 0;
    padding: var(--e2) var(--e3);
    background: var(--sup);
    border: 1px solid var(--linha);
    border-radius: var(--r);
    border-top: 1px solid var(--linha);
    box-shadow: var(--sombra-1);
}

} /* fim da media query do modo gravação */


/* ===========================================================================
   A CARTEIRA DE LEADS FICA PARADA ENQUANTO SE PROCURA

   Dois pedidos do dono, e é um problema só. "Na lista preciso da barra de
   filtros com Ver o funil e Novo lead — FIXO FLUTUANTE" e "tem que permitir
   mais campos e uma barra horizontal". Na reunião de 03/09 ele já havia
   detalhado o resto: coluna do cliente FIXA, cabeçalho rolando junto, altura
   de linha menor.

   Procurar numa carteira de centenas é rolar nos DOIS eixos, e em cada eixo
   alguma coisa tem de ficar parada, senão a linha perde a referência:

       rolando para BAIXO   fica o cabeçalho — senão não se sabe QUE COLUNA é
       rolando para o LADO  fica o nome      — senão não se sabe DE QUEM é a linha
       nos dois             ficam os filtros — para trocar de recorte sem voltar ao topo

   POR QUE A LISTA PRECISOU DE ROLAGEM PRÓPRIA
   -------------------------------------------
   Não bastava um `sticky` no `thead`, e a razão é a MESMA armadilha que a
   seção 04 conta do `.app__conteudo` e a 16.10 conta do resumo da proposta.

   `.rolagem-h` é `overflow-x: auto` e nada mais — e `overflow` diferente de
   `visible` num eixo obriga o OUTRO a computar `auto`. Ela JÁ é caixa de
   rolagem nos dois eixos; o que lhe falta é ALTURA menor que o conteúdo. Um
   `position: sticky; top: 0` lá dentro acompanha ESSA caixa, e não a janela:
   curso disponível zero. A regra fica escrita, parece certa, e não sai do
   lugar nunca — foi assim duas vezes neste arquivo.

   O teto de altura é o que torna a rolagem vertical real. E ele traz o resto
   de brinde: com a lista rolando por dentro, a página quase não rola, e a
   barra de filtros fica no lugar por consequência. O `sticky` dela continua
   valendo como rede — janela baixa, zoom em 150%, aviso do sistema empurrando
   o conteúdo — e é o único comportamento que sobra no celular, onde a tabela
   vira cartões e o teto sai.

   O QUE NÃO ENTROU
   ----------------
   Nenhum JavaScript: não há um único ouvinte de rolagem aqui. E nenhuma
   alteração em `.barra`, `.rolagem-h`, `.tabela` ou `.tabela--acoes-fixas` na
   classe pura — as três primeiras servem quarenta telas, e a quarta serve
   também documentos e fichas, onde a primeira coluna é o ícone de 1% de
   largura: congelar um ícone não é pedido de ninguém.
   =========================================================================== */

/* ---- A barra de filtros acompanha a rolagem ----

   MODIFICADOR, e nunca a classe pura: `.barra` aparece 21 vezes em 20 telas —
   e DUAS vezes nesta, porque a paginação do rodapé também é uma `.barra`.
   Grudar a classe grudaria a paginação no meio da tela.

   Para em `var(--topo-h)` CRAVADO, e não um pouco abaixo: `.topo` é fixa e
   ocupa exatamente esses 52px; qualquer folga vira uma fresta por onde as
   linhas da lista aparecem entre as duas barras.

   Fundo OPACO por necessidade, e não por gosto — sem ele os selects e os
   botões deixam a lista passar por baixo, legível através deles. É
   `var(--fundo)` e não `var(--sup)`: isto é uma faixa da página, e não um
   cartão; com o branco do cartão ela anunciaria um conteúdo que não tem.

   A margem negativa mais o respiro próprio cobrem as goteiras de 24px do
   `.conteudo`; sem elas fica uma tira de lista rolando à vista dos dois lados
   da barra. Mesma conta de `#proposta-form > .calc__acoes`.

   z-index 20: acima da lista e das células grudadas — que vão até 3 — e
   abaixo de tudo o que precisa cobri-la: a barra do sistema é 40, o trilho 50,
   o modal 200, o véu 9998. */
.barra--fixa {
    position: sticky;
    top: var(--topo-h);
    z-index: 20;
    margin: 0 calc(var(--e5) * -1) var(--e4);
    padding: var(--e3) var(--e5);
    background: var(--fundo);
    border-bottom: 1px solid var(--linha);
}

/* Navegador sem `sticky` cai na barra solta de sempre, que era o desenho
   anterior e continua correto. */
@supports not (position: sticky) {
    .barra--fixa {
        position: static;
        margin: 0 0 var(--e4);
        padding: 0;
        background: none;
        border-bottom: 0;
    }
}

/* ---- A lista rola por dentro do painel ----

   O que se subtrai é o que fica FORA da caixa quando a página está rolada até
   o fim — e cada parcela vem de uma constante deste arquivo:

       barra de filtros    178   três fileiras: 3 × 43 (`--altura-campo`)
                                 + 2 × 12 de intervalo + 24 de respiro + 1
       rodapé do painel     45   12 + 12 de respiro, 18 de texto, 1 de borda
       respiro de baixo     32   `--e6`, o fim do `.conteudo`
       rodapé da aplicação  44   `--rodape-h`
       ---------------------------
                           299   arredondado para 300

   POR QUE A ALTURA DA BARRA ENTRA NA CONTA, e pelo PIOR caso.

   Com a página rolada até o fim, o topo do painel para SEMPRE à mesma distância
   do alto da janela: `100vh − altura do painel − o que vem depois dele`. Quem
   está acima do painel — a faixa branca do título, o respiro de cima — rolou
   embora e não conta; por isso os dois NÃO entram na soma. Se a barra grudada
   for mais alta que essa distância, ela cobre o cabeçalho da lista, que é
   justamente o que este trabalho existe para manter à vista.

   E a barra muda de altura com a largura da janela: uma fileira em monitor
   largo, duas em 1366, três abaixo de ~1300, porque a busca, os selects e os
   quatro botões vão quebrando. Medir isso em tempo de execução é JavaScript, e
   aqui não há; então o teto é calculado pela mais alta das três. Em tela larga
   sobra fundo entre a barra e o painel — o preço é uma linha da lista, e o
   troco é o cabeçalho nunca desaparecer atrás da barra.

   SEM `min-height`: uma carteira de três leads deve dar uma caixa de três
   leads. Um piso de altura encheria o painel de branco justamente na tela mais
   vazia.

   MODIFICADOR: `.rolagem-h` sozinha serve ~40 pontos em 39 telas, quase todos
   tabelas curtas dentro de formulário. Um teto de altura ali criaria uma
   segunda barra de rolagem em telas que não pediram nada. */
.rolagem-h--teto {
    max-height: calc(100vh - var(--topo-h) - 300px);
    overflow-y: auto;
}

/* ---- Primeira coluna grudada na esquerda ----

   Espelho exato da coluna de ações, do outro lado da tabela: mesma técnica,
   mesmo filete, mesmo par de cores no `:hover`. O que muda é o lado e o
   motivo — à direita ficam os botões, à esquerda fica QUEM É a linha.

   O filete é `box-shadow: inset`, e não `border`, pela razão já escrita na
   coluna de ações: com `border-collapse: collapse` a borda pertence à TABELA,
   e a célula grudada sobe sem ela. A sombra interna pertence à célula e viaja
   junto — e aqui são duas, porque a linha de baixo (o separador entre as
   linhas da lista) sofre do mesmo mal.

   E POR ISSO A BORDA DE BAIXO SAI. Trocar `border` por sombra só resolve se a
   borda for embora: uma sombra `inset` é desenhada RENTE à borda, e as duas
   juntas dão um separador de dois pixels na primeira coluna e de um em todas
   as outras — a lista ficaria com um risco mais grosso à esquerda. É a mesma
   troca que o cabeçalho grudado faz logo abaixo, pelo mesmo motivo. Com a
   borda zerada, a aresta some do modelo colapsado (a célula de baixo não
   declara `border-top`) e quem desenha o separador é a sombra, sozinha. */
.tabela--coluna-fixa thead th:first-child,
.tabela--coluna-fixa tbody td:first-child {
    position: sticky;
    left: 0;
    background: var(--sup);
    border-bottom: 0;
    box-shadow: inset -1px 0 0 var(--linha), inset 0 -1px 0 var(--linha);
}
.tabela--coluna-fixa tbody td:first-child  { z-index: 1; }
.tabela--coluna-fixa thead th:first-child  { background: var(--sup-2); z-index: 2; }
.tabela--coluna-fixa tbody tr:hover td:first-child { background: var(--sup-2); }

/* A última linha não leva separador: o painel fecha ali, e a linha sobrando
   apareceria como um risco solto encostado na borda do cartão. */
.tabela--coluna-fixa tbody tr:last-child td:first-child {
    box-shadow: inset -1px 0 0 var(--linha);
}

/* ---- Cabeçalho grudado no alto da caixa ----

   O `sticky` vai no `th`, e NUNCA no `thead` ou no `tr`: com
   `border-collapse: collapse` o navegador ignora `position: sticky` nesses
   dois. A coluna de ações já fazia certo; aqui é a mesma escolha, pelo mesmo
   motivo.

   A borda de baixo vira sombra interna pela razão do parágrafo anterior — e é
   justamente essa linha que separa o cabeçalho parado da lista que passa por
   baixo dele. Sem ela o cabeçalho e a primeira linha se encostam e parecem uma
   só enquanto se rola. */
.tabela--cabecalho-fixo thead th {
    position: sticky;
    top: 0;
    z-index: 2;
    border-bottom: 0;
    box-shadow: inset 0 -1px 0 var(--linha);
}

/* OS DOIS CANTOS são grudados nos DOIS eixos ao mesmo tempo, e por isso vão um
   degrau acima de todo o resto. A escada inteira, de baixo para cima:

       1  células do corpo na coluna congelada
       2  células do cabeçalho
       3  os dois cantos

   Sem o degrau 3 o canto da esquerda passaria POR BAIXO das outras células do
   cabeçalho ao rolar de lado: ele é o PRIMEIRO do DOM, e empate de z-index é
   resolvido pela ordem do documento.

   Os dois filetes de cada canto vêm num `box-shadow` só porque a propriedade
   não se acumula entre regras — a mais específica substitui a outra inteira,
   e não soma as sombras. */
.tabela--cabecalho-fixo.tabela--coluna-fixa thead th:first-child {
    z-index: 3;
    box-shadow: inset -1px 0 0 var(--linha), inset 0 -1px 0 var(--linha);
}
.tabela--cabecalho-fixo.tabela--acoes-fixas thead th:last-child {
    z-index: 3;
    box-shadow: inset 1px 0 0 var(--linha), inset 0 -1px 0 var(--linha);
}

/* ---- Texto longo que não pode alargar a coluna ----

   `overflow: hidden` num bloco zera a contribuição dele para a largura mínima
   da coluna: é isso, e não o `max-width` sozinho, que impede uma fase de obra
   de 60 caracteres de empurrar todas as outras colunas para fora da tela. O
   texto inteiro continua no `title` e na ficha. */
.tabela__corte {
    display: block;
    max-width: 14rem;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ---- Doze colunas numa tela de 1366 ----

   Doze para quem vê a unidade inteira, onze para o consultor — a coluna do
   responsável só existe para o primeiro.

   O aperto lateral é o mesmo já feito em Minhas Propostas: com o respiro
   padrão de 16px de cada lado, só as margens somariam quase 400px numa tabela
   que precisa caber nome, telefone, etapa, duas datas, cidade, bairro, área,
   fase da obra, origem, responsável e os botões.

   NOWRAP é o que faz a rolagem horizontal EXISTIR de verdade. Sem ele o
   navegador resolve a falta de largura quebrando o texto: as colunas se
   espremem, cada linha vira duas e a lista fica MAIS ALTA — o oposto exato do
   que o dono pediu na reunião. Com ele a tabela cresce e a barra horizontal
   aparece, que é o remédio que ele nomeou.

   O piso de 1200px não é o que causa a rolagem (o `nowrap` já causa): é o que
   a torna PREVISÍVEL, para que a tabela tenha a mesma cara em 1280 e em 1920
   em vez de encolher coluna a coluna conforme a janela.

   O RESPIRO VERTICAL CAI DE 12px PARA 8px, que é a "altura de linha menor" da
   reunião. Não é `.tabela--compacta`: aquela classe pesa (0,1,1) e perde para
   `.tabela tbody td`, que pesa (0,1,2) e vem depois — está sem efeito desde
   que foi escrita (ver o aviso na seção dela). Aqui a conta bate: o seletor
   abaixo também pesa (0,1,2) e mora no fim do arquivo, então ganha por ordem.
   Vinte e cinco linhas × 8px é meia tela a mais de carteira, sem tirar uma
   informação da vista. */
.tabela--leads { min-width: 1200px; }
.tabela--leads thead th,
.tabela--leads tbody td { padding: var(--e2) var(--e3); }
.tabela--leads tbody td { white-space: nowrap; }

/* A coluna do lead é a única que NÃO pode crescer sem teto: ela fica grudada,
   então cada pixel dela some da área rolável em toda posição da rolagem. O
   comentário da coluna de ações mediu a antiga em 413px de uma tabela de
   1046 — quase 40% da tela ocupados por um nome. Aqui ela vale 15rem, e o nome
   que passar disso termina em reticências, com o nome inteiro no `title`. */
.tabela--leads thead th:first-child { width: 15rem; }
.tabela--leads tbody td:first-child .tabela__link {
    display: block;
    max-width: 15rem;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ---- No celular nada disso vale ----

   Abaixo de 720px a tabela vira cartões (`display: block`): não há coluna para
   congelar, não há cabeçalho para parar e não há rolagem lateral. O que
   sobrasse das regras acima seria dano puro — o filete da primeira célula
   viraria um risco solto no meio do cartão, e o teto de altura poria uma
   segunda rolagem dentro da rolagem da página.

   A barra de filtros sai junto: abaixo de 560px a busca e os dois selects
   viram uma fileira cada, a barra passa a ter quatro ou cinco linhas, e
   grudada ela esconderia justamente a lista que serve para filtrar. É a mesma
   decisão tomada com o resumo da calculadora em 1100px.

   Os seletores dos cantos são repetidos INTEIROS aqui porque têm duas classes:
   um seletor de uma classe só não os alcançaria. */
@media (max-width: 720px) {
    .barra--fixa {
        position: static;
        margin: 0 0 var(--e4);
        padding: 0;
        background: none;
        border-bottom: 0;
    }

    /* Só o teto sai. `overflow-y` não se declara aqui de propósito: com
       `overflow-x: auto` na classe base, o eixo Y computa `auto` de qualquer
       jeito — e sem teto de altura não há o que rolar. */
    .rolagem-h--teto { max-height: none; }

    .tabela--cabecalho-fixo thead th,
    .tabela--cabecalho-fixo.tabela--coluna-fixa thead th:first-child,
    .tabela--cabecalho-fixo.tabela--acoes-fixas thead th:last-child,
    .tabela--coluna-fixa thead th:first-child,
    .tabela--coluna-fixa tbody td:first-child,
    .tabela--coluna-fixa tbody tr:last-child td:first-child {
        position: static;
        background: none;
        box-shadow: none;
    }

    /* O respiro volta ao do modo cartão — e precisa ser repetido aqui porque a
       regra de cima mora no FIM do arquivo, depois desta media query. */
    .tabela--leads { min-width: 0; }
    .tabela--leads tbody td { white-space: normal; padding: 5px var(--e4); }
    .tabela--leads thead th:first-child { width: auto; }
    .tabela--leads tbody td:first-child .tabela__link {
        max-width: none;
        overflow: visible;
    }
    .tabela__corte { max-width: none; overflow: visible; }
}


/* ---- No papel nada fica parado ----

   O teto de altura recorta a lista na tela DE PROPÓSITO, e na impressora ele
   recortaria do mesmo jeito: sairia uma tela de leads e o resto sumiria sem
   aviso nenhum. O mesmo vale de lado — a largura mínima e o `nowrap` mandam a
   tabela para além da folha, e o que passa da caixa não é impresso.

   No papel quem "rola" é a paginação da impressora, então tudo volta ao fluxo:
   sem caixa de rolagem, sem célula grudada e sem `nowrap`. De brinde, o
   `thead` solto volta a se repetir no alto de cada folha, que é o que se
   espera de uma lista impressa.

   O reparo é só desta tela: `overflow` é declarado no `--teto`, e não na
   `.rolagem-h` que serve as outras trinta e nove. A coluna de ações também
   fica de fora — `.tabela--acoes-fixas` sozinha serve documentos e fichas, e
   sem caixa de rolagem no papel um `sticky` não sai do lugar de qualquer
   modo. */
@media print {
    .barra--fixa {
        position: static;
        margin: 0 0 var(--e4);
        padding: 0;
        background: none;
        border-bottom: 0;
    }

    .rolagem-h--teto { max-height: none; overflow: visible; }

    .tabela--cabecalho-fixo thead th,
    .tabela--cabecalho-fixo.tabela--coluna-fixa thead th:first-child,
    .tabela--cabecalho-fixo.tabela--acoes-fixas thead th:last-child,
    .tabela--coluna-fixa thead th:first-child,
    .tabela--coluna-fixa tbody td:first-child,
    .tabela--coluna-fixa tbody tr:last-child td:first-child {
        position: static;
        box-shadow: none;
    }

    /* As bordas voltam onde a sombra as substituía. A última linha continua
       sem separador: `.tabela tbody tr:last-child td` é mais específica. */
    .tabela--cabecalho-fixo thead th,
    .tabela--coluna-fixa tbody td:first-child { border-bottom: 1px solid var(--linha); }

    .tabela--leads { min-width: 0; }
    .tabela--leads tbody td { white-space: normal; }
    .tabela--leads thead th:first-child { width: auto; }
    .tabela--leads tbody td:first-child .tabela__link {
        max-width: none;
        overflow: visible;
    }
    .tabela__corte { max-width: none; overflow: visible; }
}


/* =============================================================================
   18 · ACOMPANHAMENTO — a unidade aberta dentro da tela da rede

   Duas peças: a barra âmbar de contexto e o painel. O painel é um trilho
   escuro à esquerda (o mesmo desenho do trilho da aplicação, para que o menu
   da unidade seja reconhecível como menu) e um quadro à direita, onde as telas
   da franquia carregam inteiras.

   ÂMBAR, E SÓ AQUI
   ----------------
   É a única superfície do sistema nessa cor. Enquanto ela estiver na tela, o
   que se vê abaixo NÃO é a rede — e esse é um aviso que não pode depender de o
   usuário lembrar em que aba está.
   ============================================================================= */

.acompanha__barra {
    display: flex;
    align-items: center;
    gap: var(--e4);
    flex-wrap: wrap;
    padding: var(--e3) var(--e4);
    margin-bottom: var(--e4);
    background: var(--aviso-vestigio);
    border: 1px solid var(--aviso);
    border-left-width: 4px;
    border-radius: var(--r-lg);
}

.acompanha__simbolo {
    width: 22px;
    height: 22px;
    flex: 0 0 auto;
    color: var(--aviso);
}

.acompanha__quem {
    display: flex;
    align-items: baseline;
    gap: var(--e2);
    flex-wrap: wrap;
    min-width: 0;
}
.acompanha__etiqueta {
    font-size: .6875rem;
    text-transform: uppercase;
    letter-spacing: .09em;
    color: var(--texto-3);
}
.acompanha__nome { font-size: var(--t-md, 0.875rem); color: var(--texto); }
.acompanha__codigo { color: var(--texto-2); font-size: var(--t-sm); }

/* Os números empurram as ações para a direita: é o acumulado da unidade que
   está sendo olhada, e ele responde "faz sentido eu estar aqui agora?". */
.acompanha__numeros {
    display: flex;
    gap: var(--e4);
    flex-wrap: wrap;
    margin-left: auto;
    font-size: var(--t-sm);
    color: var(--texto-2);
}
.acompanha__numero strong {
    font-variant-numeric: tabular-nums;
    color: var(--texto);
}

.acompanha__acoes {
    display: flex;
    align-items: center;
    gap: var(--e3);
}
.acompanha__acoes form { margin: 0; }

/* ---- O painel ---- */

/* A altura sai da janela, e não do conteúdo: o quadro tem página inteira
   dentro, e uma caixa que crescesse com ele produziria DUAS rolagens verticais
   encaixadas — a da unidade e a da rede. Aqui a de fora não existe. */
.acompanha {
    display: grid;
    grid-template-columns: 248px 1fr;
    /* Sobrou altura quando a faixa branca de título saiu da casca: acima do
       quadro ficam só a barra superior, o respiro do conteúdo e a tarja âmbar. */
    height: calc(100vh - var(--topo-h) - 150px);
    min-height: 520px;
    border: 1px solid var(--linha);
    border-radius: var(--r-lg);
    overflow: hidden;
    background: var(--sup);
    box-shadow: var(--sombra-1);
}

/* Escuro como o trilho da aplicação de propósito: as regras de .nav__linha
   pintam com --trilho-texto, e um menu claro com aquelas cores sairia
   ilegível. Reaproveitar o desenho também é o que faz o menu de dentro ser
   lido como menu, e não como uma lista de links. */
/* Fundo E gradiente, como o trilho de verdade: com `data-area="franquia"` no
   próprio elemento, as duas variáveis já resolvem para a paleta da unidade — o
   azul escuro que ela tem do lado dela. Só o fundo chapado deixaria este menu
   parecido, mas não igual. */
.acompanha__trilho {
    background: var(--trilho-bg);
    background-image: var(--trilho-grad);
    border-right: 1px solid var(--trilho-linha);
    overflow-y: auto;
    overflow-x: hidden;
    padding: var(--e3) var(--e2);
}

/* O RECOLHIMENTO DA REDE NÃO ALCANÇA ESTE MENU.

   Enquanto a unidade está aberta, o menu da rede fica na faixa de ícones — e
   `data-trilho="recolhido"` mora no `.app`, que é ancestral também do painel.
   As regras que escondem rótulo, seta e filhos e centralizam a linha pegavam
   este menu junto: ele ficava com a largura toda e só os ícones no meio.

   Aqui elas são desfeitas. Não bastava trocar a ordem: as de cima são
   `.app[data-trilho="recolhido"] .nav__rotulo`, e desfazê-las exige um
   seletor mais específico, não um posterior. */
.app[data-trilho="recolhido"] .acompanha__trilho .nav__rotulo,
.app[data-trilho="recolhido"] .acompanha__trilho .nav__seta {
    display: revert;
}
.app[data-trilho="recolhido"] .acompanha__trilho .nav__filhos { display: none; }
.app[data-trilho="recolhido"] .acompanha__trilho .nav__filhos[data-aberto="sim"] {
    display: block;
}
.app[data-trilho="recolhido"] .acompanha__trilho .nav__linha {
    justify-content: flex-start;
    padding: 8px 10px;
}
.app[data-trilho="recolhido"] .acompanha__trilho .nav__filhos .nav__linha {
    padding: 6px 10px;
}

.acompanha__quadro {
    width: 100%;
    height: 100%;
    border: 0;
    display: block;
    background: var(--fundo);
}

/* Em tela estreita o menu vira uma faixa em cima e o quadro fica embaixo:
   248px de trilho ao lado de um sistema inteiro não cabem em telefone. */
@media (max-width: 900px) {
    .acompanha {
        grid-template-columns: 1fr;
        height: auto;
    }
    .acompanha__trilho {
        border-right: 0;
        border-bottom: 1px solid var(--trilho-linha);
        max-height: 210px;
    }
    .acompanha__quadro { height: 70vh; }
    .acompanha__numeros { margin-left: 0; }
}


/* =============================================================================
   19 · EMBUTIDO — a tela da franquia servida dentro do quadro

   Sem menu, sem barra superior e sem rodapé: eles já estão desenhados na casca,
   do lado de fora. O que sobra é o conteúdo, e ele ocupa o quadro inteiro.
   ============================================================================= */

.embutido, .embutido__corpo {
    height: 100%;
    background: var(--fundo);
}

.embutido__conteudo {
    display: block;
    min-height: 100%;
    scroll-margin-top: 0;
}


/* =============================================================================
   20 · ESCOLHA DA UNIDADE — a faixa da rede e os cartões

   Tela própria, separada do cadastro de franquias. A decisão que ela apoia é
   uma só — "qual unidade eu abro agora?" —, e ela se toma por quatro números
   e um nome. Por isso cartão, e não tabela: a tabela serve para comparar
   quinze colunas, e aqui há quatro.
   ============================================================================= */

.rede-numeros {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--e3);
    margin-bottom: var(--e5);
}

.rede-numeros__item {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: var(--e4);
    background: var(--sup);
    border: 1px solid var(--linha);
    border-radius: var(--r-lg);
}

/* O único com cor: "hoje" é o número que decide, e os outros três são
   contexto. Pintar os quatro faria nenhum se destacar. */
.rede-numeros__item--destaque {
    border-color: var(--marca-clara);
    background: var(--marca-vestigio);
}

.rede-numeros__valor {
    font-size: 1.75rem;
    font-weight: 600;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
    color: var(--texto);
}
.rede-numeros__rotulo {
    font-size: var(--t-sm);
    color: var(--texto-2);
}
.rede-numeros__apoio {
    font-size: .6875rem;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: var(--texto-3);
}

/* As unidades saíram do cartão e viraram lista (09/09/2026, decisão do dono):
   com trinta franquias, trinta blocos empilhados não se comparam. O que ficou
   de cor é a coluna "Hoje" — o número que diz quem está trabalhando agora, e
   por onde se escolhe qual unidade abrir. Zero não é pintado: fica traço. */
.acompanha__hoje { color: var(--ok, var(--marca)); }


/* -----------------------------------------------------------------------------
   Dentro do quadro, os gestos de gravar somem.

   ISTO É CORTESIA, E NÃO SEGURANÇA. Quem recusa a gravação é o
   SomenteLeituraFilter (403 em tudo que não é GET) e a conexão do banco, que
   sai somente leitura. O que estas regras evitam é a tela MENTIR: oferecer um
   botão que só pode terminar em recusa.

   O critério é o método do formulário, e não uma classe nova em noventa e nove
   botões: envio de POST é, por definição, o que altera estado neste sistema.
   Busca e filtro são GET e continuam ali, que é o que a rede veio usar.
   ----------------------------------------------------------------------------- */

.embutido form[method="post"] button[type="submit"],
.embutido form[method="POST"] button[type="submit"],
.embutido form[method="post"] input[type="submit"],
.embutido form[method="POST"] input[type="submit"] {
    display: none !important;
}

/* Os atalhos de CRIAR, que são links e não envios. O sufixo "/novo" é a
   convenção de rota deste sistema inteiro — ver Rotas.SUFIXO_NOVO.

   As duas formas: "/novo" no fim, e "/novo?" quando o formulário já abre com
   um campo preenchido — é o caso do "Nova ficha para 000.000.000-00", que leva
   o documento na consulta e por isso não termina em "/novo". */
.embutido a[href$="/novo"],
.embutido a[href*="/novo?"] { display: none !important; }

/* -----------------------------------------------------------------------------
   O item "Acompanhamento" some do menu em tela de telefone.

   ISTO É CORTESIA. Quem recusa é o servidor: o AcompanhamentoServlet responde
   a tela "não abre no celular" e não monta o painel, então digitar o endereço
   não adianta. O que estas regras evitam é oferecer no menu um caminho que só
   pode terminar em recusa.

   Os dois critérios são diferentes de propósito e não dá para unificá-los: o
   servidor decide pelo User-Agent, que é o que ele conhece; o menu decide pela
   largura, que é o que o navegador conhece. Na dúvida sobra o caso benigno —
   janela estreita no computador esconde o item, mas a tela abre se pedida.

   860px é a mesma quebra do modo gaveta (Trilho.LARGURA_GAVETA no JS): abaixo
   dela o menu já é uma gaveta sobreposta, e o painel não teria onde existir.
   ----------------------------------------------------------------------------- */
@media (max-width: 860px) {
    .nav__linha[data-caminho="franquias/acompanhamento"] { display: none; }
}

/* -----------------------------------------------------------------------------
   Os gestos que a REDE não faz, dentro do quadro.

   As regras acima pegam o que tem forma reconhecível — envio de POST e link
   para "/novo". Faltam dois tipos que não têm forma nenhuma: o link "Editar",
   que é uma âncora igual a qualquer outra, e o botão destrutivo, que é
   `type="button"` porque abre uma janela de confirmação antes.

   `.botao--perigo` cobre TODO destrutivo do sistema, inclusive os de telas que
   ainda não foram visitadas — encerrar conta, excluir proposta, excluir ficha.

   `[data-escrita]` é o marcador explícito, posto um a um nos gestos que só a
   forma não denuncia. É marcação manual de propósito: a alternativa era
   esconder toda âncora da coluna de ações, e isso levaria junto o que a rede
   VEIO ver — abrir a proposta, abrir o lead, baixar o documento, ver a
   conversa. O detalhe continua; o que sai é alterar, criar e apagar.
   ----------------------------------------------------------------------------- */
.embutido .botao--perigo,
.embutido [data-escrita] {
    display: none !important;
}

/* O cartão do funil não se arrasta dentro do painel, então não anuncia que se
   arrasta: `cursor: grab` prometeria um gesto que o servidor recusa. Quem
   desliga o arraste de verdade é o JS (módulo Funil), que nem registra os
   ouvintes aqui dentro — isto é só a mão do cursor. */
.embutido .funil__cartao { cursor: default; }

/* -----------------------------------------------------------------------------
   O rodapé de ações dos formulários some dentro do painel.

   `.form-pe` é onde este sistema põe, sem exceção, os gestos de um formulário:
   Salvar, Excluir, Cancelar, e os atalhos que nascem dali — "Fazer proposta",
   "Conversar". Nenhum deles é leitura. Escondê-lo de uma vez resolve a classe
   inteira, em vez de perseguir botão por botão em trinta telas.

   O que a rede veio ver — os campos com os dados da unidade — continua na tela,
   agora inerte: o módulo Acompanhamento põe `readonly` no que é texto e
   `disabled` no resto.
   ----------------------------------------------------------------------------- */
.embutido .form-pe { display: none !important; }

/* Anexar arquivo é gravação pura, e o controle nativo ainda desenha o botão
   "Escolher ficheiro" mesmo desabilitado. O campo inteiro sai — rótulo, ajuda e
   controle —, para não sobrar um rótulo órfão anunciando algo que não existe. */
.embutido .campo:has(input[type="file"]) { display: none !important; }
.embutido input[type="file"] { display: none !important; }

/* Conversar pelo WhatsApp é falar COM O CLIENTE DA UNIDADE em nome dela. É o
   oposto de acompanhar, e não passa pelo nosso servidor — nenhuma trava de
   banco o alcançaria. */
.embutido a[href^="https://wa.me/"],
.embutido a[href^="http://wa.me/"],
.embutido a[href^="https://api.whatsapp.com/"] { display: none !important; }

/* Campo travado: fica legível e copiável, e diz pela cor que não se digita
   nele. Sem isto a tela pareceria editável e só recusaria no clique.

   O gancho é `[data-travado]`, posto pelo módulo Acompanhamento em cada campo
   que ele trava — e não o formulário em volta. Campo que vive FORA de
   formulário também é travado, e uma regra ancorada no formulário deixaria
   justamente esses parecendo editáveis. */
.embutido [data-travado] {
    background: var(--sup-2);
    cursor: default;
}

/* -----------------------------------------------------------------------------
   As outras portas de CRIAR, que não terminam em "/novo".

   Uma varredura das trinta telas da franquia achou oito atalhos vivos dentro do
   painel — "Nova proposta" (quatro lugares), "Fazer um cálculo rápido" e
   "Importar a planilha" (três lugares). Todos escapavam pelo mesmo buraco: são
   âncoras (o JS trabalha em campos de formulário, não alcança <a>) e a rota de
   criação delas não segue a convenção Rotas.SUFIXO_NOVO.

   Três destinos, e não oito marcadores nos templates: o que identifica o gesto
   é PARA ONDE ele leva, e a mesma âncora se repete em estado vazio, estado
   filtrado e barra de ferramentas. Uma regra por destino não fica para trás
   quando a nona cópia nascer.

   Só a rota NUA casa. A proposta aberta para leitura é
   ".../calculadora/calculadora/11" e continua clicável — é justamente o detalhe
   que a rede foi ver.
   ----------------------------------------------------------------------------- */
.embutido a[href$="/calculadora"],
.embutido a[href$="/afericao-indireta"],
.embutido a[href$="/importar"],
.embutido a[href*="/importar?"] { display: none !important; }

/* A barra de ações da calculadora é o `.form-pe` dela, com outro nome: Calcular,
   Salvar proposta, Ver PDF, Nova proposta, Excluir. Nenhum é leitura — nem
   "Calcular", que é um POST por fetch e voltaria 403 do SomenteLeituraFilter,
   com os campos travados devolvendo o mesmo número de qualquer forma.

   O acesso ao documento não se perde: o "Exportar" do cabeçalho da proposta e o
   da lista continuam, e são GET. */
.embutido .calc__acoes { display: none !important; }

/* -----------------------------------------------------------------------------
   O rodapé da conversa some inteiro no acompanhamento.

   `.wpp-pe` guarda TUDO o que fala com o cliente da unidade: a caixa de
   escrever, o anexo, o microfone, e os três recolhidos — mandar uma
   localização, fazer uma enquete, enviar um cartão de contato — mais o
   "Anotar ou renomear o contato".

   É o mesmo raciocínio do `.form-pe`: uma peça só reúne os gestos, então uma
   regra só os cobre — inclusive os que ainda não existem, que vão nascer ali
   dentro como os outros nasceram.

   Os `<summary>` desses recolhidos não são controle de formulário: o módulo
   Acompanhamento nunca os alcançaria, porque ele trabalha em `form.elements`.
   Ficariam clicáveis, abrindo um formulário travado — pior do que não aparecer.

   A conversa continua inteira acima: mensagens, áudios, imagens e documentos
   recebidos e enviados. Ler é o que a rede veio fazer; falar, não.
   ----------------------------------------------------------------------------- */
.embutido .wpp-pe { display: none !important; }

/* Os dois menus da conversa somem inteiros no acompanhamento.

   `.wpp-menu` é o menu do alto da conversa (arquivar, reabrir, marcar como não
   lida, bloquear o contato) e, com `.wpp-msg-menu`, o de cada bolha (estrela,
   fixar, desafixar, encaminhar, apagar para todos). TODOS os itens dos dois
   escrevem — não há um único de leitura para preservar.

   Metade deles é `type="button"` que abre uma confirmação ou um painel, e por
   isso escapava das camadas anteriores: o módulo Acompanhamento desabilita
   apenas o que ENVIA, e o CSS de envio não os alcança. Escondê-los pelo
   contêiner pega os que existem e os que vierem — foi assim que "Bloquear este
   contato" e um "Encaminhar…" por mensagem apareceram na medição.

   ----------------------------------------------------------------------------- */
.embutido .wpp-menu { display: none !important; }

/* -----------------------------------------------------------------------------
   "Esta conversa não está amarrada a nenhum lead": o AVISO fica, a ação não.

   O aviso é informação de monitoramento — diz que o que foi conversado ali não
   aparece em ficha nenhuma —, e por isso continua na tela. O que sai é tudo o
   que vem depois dele quando o recolhido abre: a busca por lead (GET, e por
   isso fora da trava de campos), a lista de candidatos com o "Amarrar", e o
   formulário de cadastrar o cliente.

   Esconder o CORPO, e não só o clique: `pointer-events` impede o mouse, mas o
   `summary` continua focável e o teclado ainda o abriria. Com o corpo em
   `display:none`, abrir não revela nada — a defesa não depende de o clique ser
   interceptado.

   Some junto a palavra "amarrar" da direita do aviso: ela é o convite, e um
   convite para o que não acontece é pior que a ausência dele.
   ----------------------------------------------------------------------------- */
.embutido .wpp-sem-lead > :not(summary),
.embutido .wpp-sem-lead-acao { display: none !important; }

.embutido .wpp-sem-lead-texto {
    cursor: default;
    pointer-events: none;
    list-style: none;
}
.embutido .wpp-sem-lead-texto::-webkit-details-marker { display: none; }


/* =============================================================================
   ANALISE EVENTO (V073) — a captacao no stand, feita para TV touch de 32"
   =============================================================================
   Deitada (1920x1080): formulario | resultado. Em pe (1080x1920): formulario em
   cima, resultado embaixo. Campos e botoes maiores que no resto do sistema: e o
   dedo de quem nunca usou o ReduzziHub, e nao o mouse do consultor.
   ============================================================================= */

.evento-tv { display: grid; gap: var(--e4); }

.evento-tv__escolha {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: var(--e4);
}

.evento-tv__opcao {
    display: grid;
    gap: var(--e1);
    padding: var(--e5);
    border: 1px solid var(--linha);
    border-radius: var(--r-lg);
    background: var(--sup);
    color: var(--texto);
    text-decoration: none;
    font-size: 1.1rem;
    box-shadow: var(--sombra-1);
}
.evento-tv__opcao:hover { border-color: var(--marca-clara); }
.evento-tv__opcao span { color: var(--texto-3); font-size: .95rem; }

.evento-tv__faixa {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--e3);
}

.evento-tv__evento {
    display: flex;
    align-items: center;
    gap: var(--e2);
    font-size: 1.05rem;
}
.evento-tv__evento svg { width: 20px; height: 20px; color: var(--marca); }
.evento-tv__evento span { color: var(--texto-3); }

.evento-tv__aviso {
    display: flex;
    align-items: center;
    gap: var(--e2);
    padding: var(--e3) var(--e4);
    border-left: 4px solid var(--aviso);
    border-radius: var(--r);
    background: var(--aviso-vestigio);
    color: var(--texto);
}
.evento-tv__aviso svg { width: 20px; height: 20px; color: var(--aviso); flex: none; }

.evento-tv__grade {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--e5);
    align-items: start;
}

/* Em pe, ou estreita: um embaixo do outro. */
@media (orientation: portrait), (max-width: 1100px) {
    .evento-tv__grade { grid-template-columns: minmax(0, 1fr); }
}

/* ---- A grade de doze VOLTA nesta tela ----

   A TV Android de 32" nao entrega 1920 px de CSS: entrega ~960 (1920 fisicos
   divididos pela densidade 2). Com isso ela caia no degrau de 1200px la de
   cima, e `col-6` -- WhatsApp ao lado de M², UF ao lado de Cidade -- virava
   linha inteira. Sete linhas de campo numa tela de 540 px de altura: o stand
   rolava a pagina para achar "Destinacao da Obra", de dedo, com o cliente
   esperando. Foto do stand de Limeira, 16/09/2026.

   Aqui a excecao se justifica porque a RAZAO do degrau nao existe nesta tela: o
   trilho lateral recolhe sozinho ao entrar (analise-evento.js, acima de 860px)
   e ocupa 64px, e nao 274. Em 960px sobram ~850 para a grade -- coluna de 70px,
   `col-3` com 200 e `col-6` com 425. Cabe com folga.

   O piso de 880px e o proprio ponto em que o trilho recolhe (860) com margem:
   abaixo dele o menu volta a ser gaveta e a grade de doze deixaria de caber. */
@media (min-width: 880px) {
    .evento-tv__form .form-grade {
        grid-template-columns: repeat(12, minmax(0, 1fr));
    }
    .evento-tv__form .col-1  { grid-column: span 1; }
    .evento-tv__form .col-2  { grid-column: span 2; }
    .evento-tv__form .col-3  { grid-column: span 3; }
    .evento-tv__form .col-4  { grid-column: span 4; }
    .evento-tv__form .col-5  { grid-column: span 5; }
    .evento-tv__form .col-6  { grid-column: span 6; }
    .evento-tv__form .col-7  { grid-column: span 7; }
    .evento-tv__form .col-8  { grid-column: span 8; }
    .evento-tv__form .col-9  { grid-column: span 9; }
    .evento-tv__form .col-10 { grid-column: span 10; }
    .evento-tv__form .col-11 { grid-column: span 11; }
    .evento-tv__form .col-12 { grid-column: span 12; }
}

/* Toque: campos e rotulos maiores so nesta tela. */
.evento-tv__form .campo__rotulo { font-size: 1rem; }
.evento-tv__form .campo__entrada {
    min-height: 56px;
    font-size: 1.2rem;
}

.evento-tv__acoes {
    display: grid;
    grid-template-columns: 2fr 1fr;
    gap: var(--e3);
    padding: 0 var(--e5) var(--e5);
}
.evento-tv__acoes .botao {
    min-height: 64px;
    justify-content: center;
    font-size: 1.15rem;
}

.evento-tv__resultado { padding: var(--e5); display: grid; gap: var(--e4); }

.evento-tv__cliente {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--e2);
    font-size: 1.15rem;
}

/* A confirmacao do envio: discreta, pedido do dono. */
.evento-tv__envio {
    display: inline-flex;
    align-items: center;
    gap: var(--e1);
    font-size: .85rem;
    color: var(--texto-3);
}
.evento-tv__envio svg { width: 14px; height: 14px; }
.evento-tv__envio--ok svg { color: var(--ok); }
.evento-tv__envio--falha svg { color: var(--erro); }

.evento-tv__comparacao {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--e3);
}

.evento-tv__valor {
    display: grid;
    gap: var(--e1);
    padding: var(--e4);
    border: 1px solid var(--linha);
    border-radius: var(--r-lg);
    background: var(--sup-2);
}
.evento-tv__valor span { color: var(--texto-3); }
.evento-tv__valor strong {
    font-size: clamp(1.4rem, 2vw, 2rem);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.evento-tv__valor--bom { background: var(--ok-vestigio); }
.evento-tv__valor--bom strong { color: var(--ok); }

.evento-tv__economia {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--e4);
    padding: var(--e4) var(--e5);
    border-radius: var(--r-lg);
    background: #006b45;
    color: #fff;
}
.evento-tv__economia div { display: grid; }
.evento-tv__economia span { font-size: .85rem; letter-spacing: .06em; opacity: .9; }
.evento-tv__economia strong {
    font-size: clamp(1.8rem, 2.6vw, 2.6rem);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.evento-tv__percentual { text-align: right; }

.evento-tv__secao {
    margin: var(--e2) 0 0;
    font-weight: 600;
    color: var(--texto-2);
}

.evento-tv__dados {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    gap: var(--e2);
    margin: 0;
}
.evento-tv__dados div {
    padding: var(--e2) var(--e3);
    border: 1px solid var(--linha);
    border-radius: var(--r);
    background: var(--sup-2);
}
.evento-tv__dados dt { font-size: .75rem; color: var(--texto-3); }
.evento-tv__dados dd { margin: 0; font-weight: 600; font-variant-numeric: tabular-nums; }
.evento-tv__dados--pagamento dd { font-size: 1.1rem; }

.evento-tv__honorarios {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--e3);
}
.evento-tv__honorarios > div {
    display: grid;
    gap: var(--e1);
    padding: var(--e3) var(--e4);
    border: 1px solid var(--linha);
    border-radius: var(--r-lg);
}
.evento-tv__honorarios span { font-size: .85rem; color: var(--texto-3); }
.evento-tv__honorarios em {
    margin-left: var(--e1);
    padding: 1px 8px;
    border-radius: 999px;
    background: var(--ok);
    color: #fff;
    font-style: normal;
    font-size: .75rem;
}
.evento-tv__honorarios strong { font-size: 1.4rem; font-variant-numeric: tabular-nums; }
.evento-tv__honorario--avista { background: var(--ok-vestigio); }

.evento-tv__nota { margin: 0; font-size: .85rem; color: var(--texto-3); }

@media (max-width: 560px) {
    .evento-tv__comparacao,
    .evento-tv__honorarios,
    .evento-tv__acoes { grid-template-columns: 1fr; }
}

/* ---- Leads do Evento ---- */

.evento-leads__filtros { flex-wrap: wrap; align-items: center; gap: var(--e2); }
.evento-leads__filtros .campo { margin: 0; min-width: 160px; }

.evento-leads__resumo {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
    gap: var(--e3);
    margin-bottom: var(--e4);
}
.evento-leads__resumo > div {
    display: grid;
    padding: var(--e3) var(--e4);
    border: 1px solid var(--linha);
    border-radius: var(--r-lg);
    background: var(--sup);
}
.evento-leads__resumo strong { font-size: 1.5rem; font-variant-numeric: tabular-nums; }
.evento-leads__resumo span { font-size: .8rem; color: var(--texto-3); }
.evento-leads__resumo--alerta strong { color: var(--erro); }
.evento-leads__resumo--largo { grid-column: span 2; }

.evento-leads__paginas { display: inline-flex; align-items: center; gap: var(--e2); }

.evento-lead {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr));
    gap: var(--e4);
    align-items: start;
}
.evento-lead__largo { grid-column: 1 / -1; }
.evento-lead__candidatos { display: grid; gap: var(--e2); margin-bottom: var(--e4); }

.evento-form__destaque {
    display: flex;
    align-items: center;
    gap: var(--e1);
    color: var(--aviso);
    font-weight: 600;
}
.evento-form__destaque svg { width: 14px; height: 14px; }
/* =============================================================================
   Verificação em duas etapas (Meu perfil, aba Acesso — V084)

   Um bloco abaixo da troca de senha. A chave é o único dado que a pessoa vai
   DIGITAR no celular, por isso é mono, espaçada e selecionável de uma vez
   (user-select: all): um toque seleciona tudo, sem pegar meio caractere.
   ============================================================================= */
.duas-etapas {
    margin-top: var(--e5);
    padding-top: var(--e4);
    border-top: 1px solid var(--linha);
}
.duas-etapas__titulo {
    display: flex;
    align-items: center;
    gap: var(--e2);
    margin: 0 0 var(--e3);
    font-size: var(--t-sm);
    font-weight: 600;
    color: var(--texto);
}
.duas-etapas__titulo svg { width: 16px; height: 16px; flex: 0 0 auto; }
.duas-etapas__texto {
    margin: 0 0 var(--e3);
    font-size: var(--t-sm);
    line-height: 1.6;
    color: var(--texto-2);
}
.duas-etapas__texto--aviso {
    display: flex;
    align-items: flex-start;
    gap: var(--e2);
    color: var(--aviso);
}
.duas-etapas__texto--aviso svg { width: 16px; height: 16px; flex: 0 0 auto; margin-top: 2px; }
.duas-etapas__passos {
    display: grid;
    gap: var(--e3);
    margin: 0 0 var(--e4);
    padding-left: 1.4em;
    font-size: var(--t-sm);
    line-height: 1.6;
    color: var(--texto-2);
}
.duas-etapas__passos .dados { margin: var(--e2) 0; }
.duas-etapas__chave {
    font-family: var(--fonte-mono);
    font-size: var(--t-base);
    letter-spacing: .08em;
    user-select: all;
}
.duas-etapas__detalhe summary {
    cursor: pointer;
    font-size: var(--t-xs);
    color: var(--texto-3);
}
.duas-etapas__codigo {
    display: block;
    margin-top: var(--e2);
    font-family: var(--fonte-mono);
    font-size: var(--t-xs);
    word-break: break-all;
    user-select: all;
}

/* =============================================================================
   Um "O que é" por arquivo (22/09/2026)

   A lista só aparece a partir de dois arquivos: com um, o seletor de cima já
   respondeu. Nome à esquerda com reticência — nome de arquivo de cliente é
   longo e não pode empurrar o seletor para fora da tela.
   ============================================================================= */
.arquivos-tipos__linhas {
    display: grid;
    gap: var(--e2);
    margin-top: var(--e2);
}
.arquivos-tipos__linha {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(180px, 34%);
    gap: var(--e3);
    align-items: center;
}
.arquivos-tipos__nome {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--t-sm);
    color: var(--texto-2);
}
@media (max-width: 640px) {
    .arquivos-tipos__linha { grid-template-columns: 1fr; gap: var(--e1); }
}

/* =============================================================================
   Coluna do cliente na tela do WhatsApp (22/09/2026)

   Terceira coluna, à direita da conversa: obras e documentos do cliente, ao
   lado da papelada que está chegando. Some abaixo de 1400px — a conversa é o
   que não pode encolher, e os documentos continuam a um clique na ficha.
   ============================================================================= */
.wpp-cliente { display: none; }

@media (min-width: 1400px) {
    .wpp { grid-template-columns: minmax(260px, 330px) minmax(0, 1fr) 300px; }

    .wpp-cliente {
        display: flex;
        flex-direction: column;
        gap: var(--e3);
        min-height: 0;
        padding: var(--e4);
        overflow-y: auto;
        background: var(--sup);
        border: 1px solid var(--linha);
        border-radius: var(--r);
        box-shadow: var(--sombra-1);
    }
}

.wpp-cliente__titulo {
    display: flex;
    align-items: center;
    gap: var(--e2);
    margin: 0;
    font-size: var(--t-sm);
    font-weight: 600;
    color: var(--texto);
}
.wpp-cliente__titulo svg { width: 16px; height: 16px; }

.wpp-cliente__acoes { display: flex; flex-wrap: wrap; gap: var(--e2); }

.wpp-cliente__apoio {
    margin: 0;
    font-size: var(--t-xs);
    line-height: 1.5;
    color: var(--texto-3);
}

.wpp-cliente__vazio { display: grid; gap: var(--e2); font-size: var(--t-sm); color: var(--texto-2); }

.wpp-cliente__bloco { border-top: 1px solid var(--linha); padding-top: var(--e3); }

.wpp-cliente__abrir {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--e2);
    cursor: pointer;
    font-size: var(--t-xs);
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--texto-3);
}

.wpp-cliente__conta {
    padding: 0 6px;
    border-radius: 999px;
    background: var(--sup-2, var(--fundo));
    font-size: var(--t-micro);
    color: var(--texto-3);
}

.wpp-cliente__lista {
    display: grid;
    gap: var(--e2);
    margin: var(--e2) 0 0;
    padding: 0;
    list-style: none;
    font-size: var(--t-sm);
    color: var(--texto-2);
}

/* Nome de documento de cliente é longo; ele encolhe, e não a coluna. */
.wpp-cliente__doc { display: grid; gap: 2px; min-width: 0; }
.wpp-cliente__doc a { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wpp-cliente__doc-apoio { font-size: var(--t-micro); color: var(--texto-3); }

/* Guardar nos documentos: discreto, abaixo do arquivo, na cor do balão. */
.wpp-arquivo-guardar {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 4px;
    padding: 2px 8px;
    border: 1px solid var(--linha);
    border-radius: 999px;
    background: transparent;
    cursor: pointer;
    font-size: var(--t-micro);
    color: var(--texto-3);
}
.wpp-arquivo-guardar:hover { color: var(--texto); border-color: var(--texto-3); }
.wpp-arquivo-guardar svg { width: 13px; height: 13px; }

/* =============================================================================
   Aprovação do cálculo pela área técnica (V088, 23/09/2026)

   A faixa da calculadora (galpão industrial: número preliminar, saída
   travada) e a fila da rede, dentro de Notificações. Reaproveita .aviso e
   .recados; aqui só o que eles não têm: o formulário do pedido e o da decisão.
   ============================================================================= */
.aprovacao-calculo__corpo { display: grid; gap: var(--e2); min-width: 0; }
.aprovacao-calculo__corpo > p { margin: 0; }

.aprovacao-calculo__parecer q {
    display: block;
    margin-top: 2px;
    white-space: pre-line;
    overflow-wrap: anywhere;
    color: var(--texto);
}

.aprovacao-calculo__pe {
    font-size: var(--t-xs);
    color: var(--texto-3);
}

.aprovacao-calculo__pedido,
.aprovacao-fila__decisao {
    display: grid;
    gap: var(--e2);
    max-width: 640px;
    margin-top: var(--e2);
}

.aprovacao-calculo__pedido textarea,
.aprovacao-fila__decisao textarea {
    width: 100%;
    min-height: 3.2em;
    resize: vertical;
}

.aprovacao-calculo__pedido .botao { justify-self: start; }

.aprovacao-calculo__rotulo {
    font-size: var(--t-xs);
    font-weight: 600;
    color: var(--texto-2);
}
.aprovacao-calculo__rotulo span { font-weight: 400; color: var(--texto-3); }

.aprovacao-fila__aviso {
    margin: 0;
    padding: var(--e2) var(--e4);
    font-size: var(--t-sm);
    color: var(--texto-2);
    border-bottom: 1px solid var(--linha);
}

/* A decisão ocupa a linha inteira: sem coluna de botão à direita. */
.aprovacao-fila__item { grid-template-columns: auto 1fr; }

.aprovacao-fila__botoes {
    display: flex;
    flex-wrap: wrap;
    gap: var(--e2);
}

/* =============================================================================
   Conferência antes da assinatura (V109)

   Um item por linha, o selo à frente: o que não confere salta aos olhos sem
   precisar ler a frase inteira. A mesma lista serve à ficha e à fila da rede.
   ============================================================================= */
.conferencia-lista {
    list-style: none;
    margin: 0;
    padding: var(--e2) var(--e4);
    display: grid;
    gap: var(--e2);
    font-size: var(--t-sm);
}
.conferencia-lista li { min-width: 0; overflow-wrap: anywhere; }
.conferencia-lista .selo { margin-right: var(--e1); }
.recados__corpo .conferencia-lista { padding: 0; }
.conferencia-contrato .painel__titulo { display: flex; flex-wrap: wrap; align-items: center; gap: var(--e2); }
.conferencia-contrato > .campo__ajuda { padding: 0 var(--e4) var(--e3); margin: 0; }

/* =============================================================================
   Lista de leads: mover em lote e colunas de valor (24/09/2026)

   A barra fica entre os filtros e a tabela; as caixas moram DENTRO da coluna do
   nome (a que gruda ao rolar de lado), e nao numa coluna propria.
   ============================================================================= */
.lote-leads {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--e2);
    margin: 0 0 var(--e3);
    padding: var(--e2) var(--e3);
    border: 1px dashed var(--linha);
    border-radius: var(--r);
    font-size: var(--t-sm);
}
.lote-leads__conta { color: var(--texto-2); margin-right: auto; }
.lote-leads__etapa { width: auto; min-width: 220px; max-width: 100%; }
.lote-leads__marca,
.lote-leads__todos input {
    width: 16px;
    height: 16px;
    margin: 0 var(--e2) 0 0;
    vertical-align: middle;
    accent-color: var(--marca);
    cursor: pointer;
}
.lote-leads__todos { display: inline-flex; align-items: center; }

/* =============================================================================
   Mensagem enviada pelo sistema (V089, 24/09/2026)

   O verde do balão é de gente. O que o sistema mandou sozinho (lembrete,
   pedido de e-CAC, de trabalhadores) sai em azul, com a frase escrita em cima:
   Márcia, na reunião, quer saber o que foi dito ao cliente sem ela. A cor sozinha
   não bastaria — a frase é o que não depende de distinguir cores.
   ============================================================================= */
.wpp-msg--robo {
    background: var(--info-vestigio);
    border: 1px solid color-mix(in srgb, var(--info) 35%, transparent);
}
.wpp-msg-robo-marca {
    display: flex;
    align-items: center;
    gap: var(--e1);
    margin: 0 0 var(--e1);
    font-size: var(--t-micro);
    font-weight: 600;
    color: var(--info);
}
.wpp-msg-robo-marca svg { width: 13px; height: 13px; }

/* A etapa na lista de leads, com a bolinha na cor dela (25/09/2026). A cor
   chega por data-cor-fundo e quem pinta e o modulo Pintura (a CSP descarta
   style no HTML). */
.selo--etapa { display: inline-flex; align-items: center; gap: 6px; }
.selo__ponto {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    flex: 0 0 auto;
    background: var(--texto-3);
}

/* Sessao expirada (25/09/2026): uma faixa no topo, na primeira requisicao de
   fundo que voltar 401. Presa ao topo da JANELA, e nao do conteudo: aparece
   onde quer que a pessoa esteja rolando. */
.sessao-expirada {
    position: fixed;
    top: env(safe-area-inset-top, 0px);
    left: 0;
    right: 0;
    z-index: 1000;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--e3);
    padding: var(--e2) var(--e4);
    background: linear-gradient(var(--aviso-vestigio), var(--aviso-vestigio)), var(--sup);
    border-bottom: 2px solid var(--aviso);
    box-shadow: 0 2px 8px rgba(0, 0, 0, .12);
    backdrop-filter: blur(6px);
}
.sessao-expirada__texto {
    margin: 0;
    font-size: var(--t-sm);
    font-weight: 600;
    color: var(--texto);
}

/* Relacionamento (25/09/2026): pos-venda, divulgacao a cobrar e ranking. */
.relacionamento__explicacao {
    margin: 0;
    padding: 0 var(--e4) var(--e3);
    font-size: var(--t-sm);
    color: var(--texto-2);
    max-width: 80ch;
}
.relacionamento__vazio {
    margin: 0;
    padding: var(--e3) var(--e4) var(--e4);
    font-size: var(--t-sm);
    color: var(--texto-3);
}

/* Mover o documento para outra obra (25/09/2026): o seletor e o botao na
   mesma linha das acoes do arquivo. */
.arquivo__mover { display: inline-flex; align-items: center; gap: var(--e1); }
.arquivo__mover .campo__entrada { width: auto; max-width: 200px; min-height: 0; padding-block: 4px; }

/* Obras do cliente (V091): uma proposta por linha dentro da celula. */
.obra__proposta { display: flex; margin-block: 2px; }

/* Area tecnica da rede (V093): o processo, do contrato assinado a garantia.
   O quadro reaproveita o funil do CRM; aqui so o que ele nao tem. */
.processo-resumo {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--e2) var(--e4);
    margin: 0;
    padding: 0 var(--e4) var(--e3);
}
.processo-resumo dt { font-size: var(--t-sm); color: var(--texto-3); }
.processo-resumo dd { margin: 0; font-weight: 600; color: var(--texto); }
.processo-regra {
    margin: 0;
    padding: 0 var(--e4) var(--e4);
    font-size: var(--t-sm);
    color: var(--texto-2);
}
.processo-acao { padding: 0 var(--e4) var(--e3); }
.processo-mover {
    display: grid;
    gap: var(--e2);
    padding: 0 var(--e4) var(--e4);
    max-width: 640px;
}
.processo-mover .botao { justify-self: start; }

/* Registrar assinatura na ficha: o formulario abre dentro da linha. */
.contrato-assinar { display: inline-block; }
.contrato-assinar > summary { list-style: none; cursor: pointer; }
.contrato-assinar > summary::-webkit-details-marker { display: none; }
.contrato-assinar__form {
    display: grid;
    gap: var(--e2);
    margin-top: var(--e2);
    max-width: 320px;
}

/* Edicao direto na lista de leads (28/09/2026): a celula vira campo. */
.tabela--leads [data-editar] { cursor: pointer; }
.tabela--leads [data-editar]:hover { outline: 1px dashed var(--marca); outline-offset: -3px; }
.tabela__edicao { min-width: 120px; min-height: 0; padding-block: 4px; }

/* Documento substituido (V094): continua na lista, apagado. */
.arquivo--substituido { opacity: .6; }

/* Temperatura do lead (V096): selo clicavel e a sugestao da IA embaixo. */
.temperatura-lead { display: grid; gap: var(--e1); padding: 0 0 var(--e3); }
.temperatura-lead__valor { cursor: pointer; justify-self: start; }
.temperatura-lead__valor:hover { outline: 1px dashed var(--marca); outline-offset: 2px; }

/* Pagamento do honorario (V097): o painel da ficha e do processo, e o
   formulario de registro. Cancelado continua na lista, apagado e riscado. */
.pagamento--cancelado { opacity: .6; }
.pagamento--cancelado .pagamento__valor { text-decoration: line-through; }
.pagamento-honorario__vazio { padding: 0 var(--e4) var(--e4); }
.pagamento-form {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: var(--e3);
    padding: 0 var(--e4) var(--e4);
}
.pagamento-form__largo { grid-column: 1 / -1; }

/* =============================================================================
   Area Tecnica -- o processo redesenhado (28/09/2026)

   A mesa do tecnico: a esquerda o que conferir (cliente e obra, documentos
   abertos na pagina, triagem, pagamento), a direita o que decidir. Hierarquia
   pelo peso do texto, nao por caixas: os blocos da lateral sao planos, e a
   cor da marca aparece so no estado atual e nas acoes.
   ============================================================================= */
.proc { display: grid; gap: var(--e4); }

.proc-topo {
    display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between;
    gap: var(--e3) var(--e5);
}
.proc-topo__cliente {
    margin: 0; font-size: var(--t-xl); font-weight: 700; line-height: 1.2;
    letter-spacing: -0.01em; color: var(--texto); text-wrap: balance;
}
.proc-topo__meta {
    display: flex; flex-wrap: wrap; gap: var(--e1) var(--e3); margin: var(--e2) 0 0;
    font-size: var(--t-sm); color: var(--texto-2);
}
.proc-topo__meta > span + span::before {
    content: ""; display: inline-block; width: 3px; height: 3px; margin-right: var(--e3);
    border-radius: 50%; background: var(--linha-forte); vertical-align: middle;
}
.proc-topo__acoes { display: flex; flex-wrap: wrap; gap: var(--e2); }

/* A faixa de andamento: as oito etapas numa linha, a atual em destaque. */
.proc-andamento {
    display: grid; gap: var(--e3);
    padding: var(--e4) var(--e5);
    background: var(--sup); border: 1px solid var(--linha); border-radius: var(--r-lg);
    box-shadow: var(--sombra-1);
}
.proc-etapas {
    display: grid; grid-template-columns: repeat(8, minmax(88px, 1fr));
    margin: 0; padding: 0; list-style: none; overflow-x: auto;
}
.proc-etapas__item {
    position: relative; display: grid; justify-items: center; gap: var(--e2);
    padding-top: 2px; text-align: center;
}
/* O trilho entre as marcas: da metade da anterior ate a metade desta. */
.proc-etapas__item + .proc-etapas__item::before {
    content: ""; position: absolute; top: 8px; right: 50%; width: 100%; height: 2px;
    background: var(--linha);
}
.proc-etapa--feita::before,
.proc-etapa--atual::before { background: var(--marca) !important; }
.proc-etapas__marca {
    position: relative; z-index: 1; width: 14px; height: 14px; border-radius: 50%;
    background: var(--sup); border: 2px solid var(--linha-forte);
}
.proc-etapa--feita .proc-etapas__marca { background: var(--marca); border-color: var(--marca); }
.proc-etapa--atual .proc-etapas__marca {
    background: var(--sup); border: 4px solid var(--marca);
    box-shadow: 0 0 0 4px var(--marca-vestigio);
}
.proc-etapas__nome { font-size: var(--t-xs); color: var(--texto-3); line-height: 1.25; }
.proc-etapa--feita .proc-etapas__nome { color: var(--texto-2); }
.proc-etapa--atual .proc-etapas__nome { color: var(--texto); font-weight: 700; }
.proc-etapas--fora { opacity: .55; }
.proc-andamento__situacao {
    display: flex; flex-wrap: wrap; align-items: center; gap: var(--e2);
    font-size: var(--t-sm); color: var(--texto-2);
}
.proc-andamento__regra { margin: 0; font-size: var(--t-sm); color: var(--texto-2); }
.proc-andamento .aviso { margin: 0; }

/* A grade: conferir a esquerda, decidir a direita. */
.proc-grade {
    display: grid; grid-template-columns: minmax(0, 1fr) 360px;
    gap: var(--e4); align-items: start;
}
.proc-principal, .proc-lateral { display: grid; gap: var(--e4); min-width: 0; }
.proc-principal > .painel, .proc-lateral > .painel, .proc-principal > div > .painel { margin: 0; }

/* Cliente e obra: dois grupos de rotulo e valor, densos. */
.proc-dados__grupos {
    display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: var(--e5); padding: 0 var(--e4) var(--e4);
}
.proc-dados__lista {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--e3) var(--e4); margin: 0; align-content: start;
}
.proc-dados__lista:first-child { grid-template-columns: minmax(0, 1fr); }
.proc-dados__largo { grid-column: 1 / -1; }
.proc-dados__lista dt { font-size: var(--t-xs); color: var(--texto-3); }
.proc-dados__lista dd {
    margin: 2px 0 0; font-size: var(--t-sm); font-weight: 500; color: var(--texto);
    overflow-wrap: anywhere;
}
.proc-dados__vazio { margin: 0; padding: 0 var(--e4) var(--e4); color: var(--texto-2); }

/* Documentos: a lista e o documento aberto, lado a lado. */
.proc-docs__contagem {
    display: inline-block; min-width: 20px; margin-left: var(--e1); padding: 0 6px;
    border-radius: 999px; background: var(--sup-3); color: var(--texto-2);
    font-size: var(--t-xs); font-weight: 600; text-align: center;
}
.proc-docs__mesa {
    display: grid; grid-template-columns: 260px minmax(0, 1fr);
    border-top: 1px solid var(--linha); min-height: 520px;
}
.proc-docs__lista {
    display: grid; align-content: start; gap: 2px; padding: var(--e2);
    border-right: 1px solid var(--linha); background: var(--sup-2);
    max-height: min(74vh, 820px); overflow-y: auto;
}
.proc-docs__grupo {
    margin: var(--e3) var(--e2) var(--e1); font-size: var(--t-micro); font-weight: 600;
    letter-spacing: .04em; text-transform: uppercase; color: var(--texto-3);
}
.proc-docs__grupo:first-child { margin-top: var(--e1); }
.proc-doc {
    display: flex; gap: var(--e2); align-items: flex-start; padding: var(--e2);
    border-radius: var(--r); color: var(--texto); text-decoration: none;
    transition: background var(--transicao);
}
.proc-doc:hover { background: var(--sup-3); }
.proc-doc:focus-visible { outline: 2px solid var(--marca-clara); outline-offset: -2px; }
.proc-doc--ativo, .proc-doc--ativo:hover { background: var(--marca-vestigio); }
.proc-doc--ativo .proc-doc__nome { color: var(--marca); }
.proc-doc--substituido { opacity: .6; }
.proc-doc__icone { flex: 0 0 auto; width: 16px; height: 16px; margin-top: 2px; color: var(--texto-3); }
.proc-doc--ativo .proc-doc__icone { color: var(--marca); }
.proc-doc__texto { display: grid; gap: 1px; min-width: 0; }
.proc-doc__nome { font-size: var(--t-sm); font-weight: 600; }
.proc-doc__arquivo {
    font-size: var(--t-xs); color: var(--texto-2);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.proc-doc__pe { display: flex; flex-wrap: wrap; gap: var(--e1) var(--e2); font-size: var(--t-micro); color: var(--texto-3); }
.proc-doc__marca { color: var(--aviso); font-weight: 600; }
.proc-doc__marca--ok { color: var(--ok); }
.proc-doc__marca--apagado { color: var(--texto-3); }
.proc-docs__visor { display: grid; grid-template-rows: auto 1fr; min-width: 0; }
.proc-docs__barra {
    display: flex; align-items: center; justify-content: space-between; gap: var(--e3);
    padding: var(--e2) var(--e3); border-bottom: 1px solid var(--linha);
}
.proc-docs__titulo {
    font-size: var(--t-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.proc-docs__quadro {
    width: 100%; height: min(74vh, 820px); min-height: 480px; border: 0;
    background: var(--sup-3);
}
.proc-docs__vazio { padding: var(--e5) var(--e4); }

/* A lateral: blocos planos, sem caixa dentro de caixa. */
.proc-bloco { display: grid; gap: var(--e2); padding: var(--e4); }
.proc-bloco__titulo { margin: 0 0 var(--e1); font-size: var(--t-md); font-weight: 600; }
.proc-bloco__texto { margin: 0; font-size: var(--t-sm); color: var(--texto-2); }
.proc-bloco__linha { margin: 0; }
.proc-bloco__cheio { width: 100%; justify-content: center; }
.proc-bloco__citacao {
    margin: var(--e1) 0 0; padding: var(--e2) var(--e3);
    background: var(--sup-2); border-radius: var(--r);
    font-size: var(--t-sm); color: var(--texto); white-space: pre-line;
}
.proc-decisao__form, .proc-mover { display: grid; gap: var(--e2); }
.proc-decisao__botoes { display: grid; grid-template-columns: 1fr 1fr; gap: var(--e2); }
.proc-decisao__botoes .botao { justify-content: center; }
.proc-decisao__reprovar { color: var(--erro); border-color: var(--erro-vestigio); }
.proc-decisao__reprovar:hover { background: var(--erro-vestigio); color: var(--erro); }
.proc-mover .botao { justify-self: start; }

/* A linha do tempo: do mais novo para o mais antigo, num trilho fino. */
.proc-tempo { margin: 0; padding: 0; list-style: none; display: grid; }
.proc-tempo__item {
    position: relative; padding: 0 0 var(--e3) var(--e4);
    border-left: 1px solid var(--linha); margin-left: 4px;
}
.proc-tempo__item:last-child { padding-bottom: 0; border-left-color: transparent; }
.proc-tempo__item::before {
    content: ""; position: absolute; left: -5px; top: 4px; width: 9px; height: 9px;
    border-radius: 50%; background: var(--sup); border: 2px solid var(--linha-forte);
}
.proc-tempo__item:first-child::before { border-color: var(--marca); background: var(--marca); }
.proc-tempo__o-que { margin: 0; font-size: var(--t-sm); font-weight: 600; }
.proc-tempo__motivo { margin: 2px 0 0; font-size: var(--t-sm); color: var(--texto-2); white-space: pre-line; }
.proc-tempo__quem { margin: 2px 0 0; font-size: var(--t-xs); color: var(--texto-3); }

@media (max-width: 1180px) {
    .proc-grade { grid-template-columns: minmax(0, 1fr); }
    .proc-dados__grupos { grid-template-columns: minmax(0, 1fr); gap: var(--e4); }
}
@media (max-width: 760px) {
    .proc-andamento { padding: var(--e3); }
    .proc-docs__mesa { grid-template-columns: minmax(0, 1fr); }
    .proc-docs__lista { max-height: 260px; border-right: 0; border-bottom: 1px solid var(--linha); }
    .proc-docs__quadro { height: 70vh; min-height: 360px; }
    .proc-dados__lista { grid-template-columns: minmax(0, 1fr); }
}

/* Filtros do quadro da area tecnica. */
.area-filtro__periodo { display: flex; align-items: center; gap: var(--e2); }
.area-filtro__periodo .campo__entrada { width: auto; min-width: 140px; }
.area-filtro__rotulo { font-size: var(--t-xs); color: var(--texto-2); white-space: nowrap; }
.area-filtro__resumo { margin: var(--e2) 0 0; font-size: var(--t-sm); color: var(--texto-2); }

/* Ajustes da inspecao de 28/09/2026: respiro sob o cabecalho do painel, a seta
   de voltar apontando para tras, e a barra de filtros do quadro que quebra linha. */
.proc-dados__grupos { padding-top: var(--e3); }
.proc-principal .processo-resumo { padding-top: var(--e3); }
.proc-topo__voltar svg { transform: scaleX(-1); }
.area-filtro .barra__acoes { flex-wrap: wrap; row-gap: var(--e2); }
.area-filtro__periodo .campo__entrada { min-width: 136px; min-height: var(--altura-botao); padding-block: 4px; }
.painel__titulo:has(> svg) { display: flex; align-items: center; gap: var(--e1); }
.painel__titulo:has(> svg) > svg { margin-right: 0; vertical-align: 0; }

/* Notificacao com link (V099): o assunto e um botao com cara de link. */
.recados__abrir { display: inline; margin: 0; }
.recados__link {
    padding: 0; border: 0; background: none; cursor: pointer;
    font: inherit; font-weight: 700; color: var(--marca); text-align: left;
    text-decoration: underline; text-decoration-color: var(--marca-vestigio-forte);
    text-underline-offset: 3px;
}
.recados__link:hover { text-decoration-color: currentColor; }
.recados__link:focus-visible { outline: 2px solid var(--marca-clara); outline-offset: 2px; border-radius: 2px; }

/* Cobranca pelo Asaas (V100): a secao da ficha e a tela Conta Asaas. */
.cobranca-asaas__bloqueio { margin: 0 var(--e4) var(--e4); }
.campo-copiar {
    display: flex;
    gap: var(--e2);
    align-items: stretch;
}
.campo-copiar .campo__entrada { flex: 1; min-width: 0; }
.carteira--inativa { opacity: .6; }
.tabela .campo__entrada[name="walletId"] { min-width: 22rem; }
@media (max-width: 640px) {
    .tabela .campo__entrada[name="walletId"] { min-width: 0; width: 100%; }
}

/* O checklist da saida da Liberacao (28/09/2026): o que falta em ambar, o que
   esta ok em verde. E o mesmo que o servidor usa para recusar. */
.proc-liberacao__lista { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--e2); }
.proc-liberacao__lista li { display: flex; gap: var(--e2); align-items: flex-start; font-size: var(--t-sm); }
.proc-liberacao__lista li > svg { width: 18px; height: 18px; flex: none; margin-top: 2px; }
.proc-liberacao__lista li > span { display: grid; }
.proc-liberacao__lista li > span > span { color: var(--texto-2); }
.proc-liberacao-item--ok > svg { color: var(--ok, var(--marca)); }
.proc-liberacao-item--falta > svg { color: var(--aviso); }

/* Mesma obra em outra ficha da rede (V102). */
.proc-duplicada { margin: 0; }
.proc-duplicada__lista { margin: var(--e1) 0 0; padding-left: 1.1rem; display: grid; gap: 2px; }

/* Link do cliente para os trabalhadores (V103). */
.link-trabalhadores__corpo { display: grid; gap: var(--e3); padding: 0 var(--e4) var(--e4); }
.link-trabalhadores__acoes { display: flex; flex-wrap: wrap; gap: var(--e2); }

/* A lista de fichas: as vendas na area tecnica da rede (28/09/2026). */
.acompanhamento { margin-bottom: var(--e4); }
.acompanhamento__resumo {
    display: flex; flex-wrap: wrap; align-items: center; gap: var(--e2);
    padding: var(--e3) var(--e4); cursor: pointer; list-style: none;
}
.acompanhamento__resumo::-webkit-details-marker { display: none; }
.acompanhamento__resumo > svg { width: 18px; height: 18px; color: var(--marca); }
.acompanhamento[open] .acompanhamento__resumo { border-bottom: 1px solid var(--linha); }

/* Execucao do processo: recibos e realizado x previsto (V104). */
.proc-execucao__faixa { margin: 0 var(--e4) var(--e3); font-size: var(--t-sm); padding: var(--e2) var(--e3); border-radius: var(--r); background: var(--sup-2, var(--sup)); }
.proc-faixa-dentro { color: var(--ok); }
.proc-faixa-acima  { color: var(--aviso); }
.proc-faixa-abaixo { color: var(--info); }
.proc-faixa-sem-darf { color: var(--texto-2); }

/* Avisar a franquia, no processo (29/09/2026). */
.avisar__destino { border: 0; margin: 0 0 var(--e3); padding: 0; display: grid; gap: var(--e2); }
#avisar-franquia .modal__caixa { width: min(520px, 100%); }

/* Correcao pedida pela area tecnica, no topo da ficha (V107). */
.correcoes-da-rede__lista { margin: var(--e2) 0 0; padding-left: 1.1rem; display: grid; gap: 4px; }
