/* =============================================================================
   Portal Gratuito FSS
   Tokens em :root, sem valor cru espalhado. Uma cor de destaque (vermelho FSS)
   sobre neutros de tom azulado — sem arco-iris de categorias.
   Suporte a claro e escuro; nenhuma fonte externa (a CSP bloqueia).
   ============================================================================= */

/* Componentes que o PAINEL ADMINISTRATIVO tambem usa. Moram em assets/comum/
   porque sao um so arquivo para os dois produtos — copiar as regras para o
   bundle do admin criaria um segundo toast (e um segundo indicador 3D) fora do
   contrato que os testes travam, e o primeiro conserto feito de um lado so ja
   separaria os dois.

   O @import obriga a ficar ANTES de qualquer regra deste arquivo; por isso os
   compartilhados dobram a classe nos seletores que precisam vencer regras de
   mesma especificidade escritas mais abaixo (ver a nota de especificidade no
   topo de comum/toast.css). Cada arquivo le so tokens `--toast-*`/`--c3d-*`,
   reapontados para a paleta do portal logo abaixo, em :root. */
@import url("../comum/toast.css");
@import url("../comum/carregando3d.css");

:root {
    /* Sem isto os controles nativos (radio, checkbox, barra de rolagem) saem
       com a pintura clara do sistema sobre o tema escuro — um radio vazio
       aparece como um circulo branco cheio, indistinguivel do marcado. */
    color-scheme: light dark;

    --fss: #E63946;
    --fss-forte: #C1121F;

    /* Vermelho de acao e vermelho de texto miudo sao tokens SEPARADOS do
       vermelho de marca por contraste (WCAG 2.2 AA): branco sobre --fss da
       4,17:1, abaixo dos 4,5:1 exigidos para texto normal. --fss segue valendo
       para tipo grande (marca, score) e para elementos graficos, onde 3:1
       basta. */
    --fss-acao: #D62839;        /* fundo de botao com texto branco — 4,97:1 */
    --fss-acao-hover: #C1121F;  /* 6,22:1 */
    /* CALIBRADO CONTRA A SUPERFICIE MAIS ESCURA EM QUE POUSA, nao contra a
       mais clara (corrigido em 18/08/2026). Era #C1121F, medido sobre branco;
       so que este token tambem pinta `.caps` e `.muro` DENTRO de `.tile_wash`,
       e a lavagem (--lavagem, fss 10% sobre --painel-solido) compoe #E2D3D9.
       Ali #C1121F dava 4,31:1 em 11-12px negrito: reprovado pelo axe nas tres
       telas que usam o tile (relatorio, painel e home) desde que a lavagem
       existe. Escolher o valor pela superficie mais clara e o erro que se
       repete — um token de texto vale pelo PIOR fundo que encontra.
       Medido no pixel renderizado em 18/08/2026: 5,30:1 sobre a lavagem,
       6,93:1 sobre --fundo, 7,65:1 sobre branco. Escurecer e monotonico no
       tema claro (todo fundo que ele toca e mais claro que ele), entao nenhum
       consumidor piora. No escuro o token e outro (#FF8A90) e nao se mexe. */
    --fss-texto: #A80F18;       /* texto pequeno em vermelho — 5,30:1 na lavagem */

    /* ELEVACAO APONTA PARA A LUZ (corrigido em 14/08/2026).
       Antes: --fundo #FFFFFF e --superficie #F7F8FA. O cartao era mais ESCURO
       que a pagina, e superficie elevada mais escura que o chao nao le como
       elevada — le como suja. No escuro a relacao ja estava certa (fundo
       #0D0D14, cartao #151520: o cartao sobe em direcao a luz).
       Agora o chao e levemente tingido e a superficie elevada e o branco puro,
       que e a mesma logica, espelhada. */
    --fundo: #F1F4F8;
    --superficie: #FFFFFF;
    --superficie-alta: #FFFFFF;
    /* Borda 0.10 sobre chao branco quase nao existia; 0.14 separa sem virar traco. */
    --borda: rgba(15, 18, 32, 0.14);
    --texto: #0F1220;
    --texto-suave: #5A6072;
    /* Verde escurecido em 12/08/2026 (era #12805C): o valor antigo dava 4,24:1
       sobre --painel-solido, e o "Potencial futuro" da home cai justamente ali,
       em 17,9px negrito a 320px — abaixo do piso de texto grande, entao exige
       4,5:1. Este da 6,40:1 sobre painel e 7,37:1 sobre branco; onde ja era
       usado (.valor_potencial, .gate_ok, .msg.success) so melhora. */
    --sucesso: #0C6046;
    --alerta: #B45309;
    --erro: #C1121F;

    --raio: 14px;
    --raio-p: 8px;

    /* Escala de espaco: 4/8/12/16/24/32/48/64. --gap e --secao seguem como
       aliases semanticos (o resto do arquivo referencia esses, nao os
       degraus da escala diretamente). */
    --esp-1: 4px;
    --esp-2: 8px;
    --esp-3: 12px;
    --esp-4: 16px;
    --esp-5: 24px;
    --esp-6: 32px;
    --esp-7: 48px;
    --esp-8: 64px;
    --gap: var(--esp-4);
    --secao: var(--esp-6);

    /* Elevacao: 2 niveis. --sombra segue como alias do nivel destacado
       (unico usado hoje, em .card) — par escuro em @media abaixo. */
    /* Sombra a .05/.06 sobre branco e invisivel — a profundidade do tema claro
       vem da sombra, ja que nao pode vir do valor da superficie. */
    --elev-1: 0 1px 2px rgba(15, 18, 32, .08);
    --elev-2: 0 2px 4px rgba(15, 18, 32, .07), 0 12px 32px rgba(15, 18, 32, .10);
    --sombra: var(--elev-2);

    /* Motion. --dur-entrada e --curva religam a animacao ja existente de
       .js-etapas .pergunta (180ms ease-out, sensacao inalterada). --dur-micro
       e primitivo para feedback instantaneo — nenhuma regra do arquivo hoje
       declara transition, entao ainda nao tem religacao (nao e redesenho
       inventar uma agora). */
    --dur-micro: 140ms;
    --dur-entrada: 180ms;
    --curva: ease-out;

    /* PONTE DE TEMA DO TOAST (o componente mora em comum/toast.css, importado
       no topo). O arquivo compartilhado nao conhece a paleta de nenhum dos dois
       produtos: ele le `--toast-*`, e e aqui que cada nome aponta para o token
       do portal. Trocar o tema muda o toast junto, sem editar o compartilhado.
       --toast-dur (o CRONOMETRO do auto-fecho), --toast-entra, --toast-sai e
       --toast-largura vivem la, com o porque de cada numero. */
    --toast-fundo: var(--superficie-alta);
    --toast-borda: var(--borda);
    --toast-texto: var(--texto);
    --toast-texto-suave: var(--texto-suave);
    --toast-fechar-hover: var(--preenchimento);
    --toast-sombra: var(--elev-cartao);
    --toast-sucesso: var(--sucesso);
    --toast-alerta: var(--alerta);
    --toast-erro: var(--erro);
    --toast-raio: var(--raio);
    --toast-raio-p: var(--raio-p);
    --toast-gap: var(--esp-2);
    --toast-gap-interno: var(--esp-3);
    --toast-tipo: var(--tipo-2);
    --toast-curva: var(--curva-suave);
    --toast-dur-micro: var(--dur-micro);
    /* Distancia do topo da JANELA. O header nao e sticky, entao isto so
       precisa livra-lo no inicio da rolagem: 82px medidos a 1280 (ver o
       comentario de .topo_inner) + 12 de folga. O par de <=640px esta no
       bloco responsivo do fim do arquivo, onde o header vira duas linhas. */
    --toast-topo: 94px;
    --toast-lado: clamp(16px, 3vw, 28px);

    /* Estados base — so tokeniza o que ja existe. */
    --opacidade-desabilitado: .55;
    /* Percentual de referencia p/ tints de hover via color-mix, na mesma
       familia dos color-mix ja usados no arquivo (7%–14%, ver .msg/
       .opcao:checked). Declarado como primitivo: nenhum hover do arquivo usa
       color-mix hoje (trocam flat para --superficie), entao nao ha regra
       existente para religar sem alterar a cor renderizada. */
    --mix-hover: 8%;

    /* Escala tipografica fluida (6 passos, clamp). Calibrada para bater
       exatamente com os tamanhos ja usados no arquivo a partir de ~1280px de
       viewport (a faixa mais comum de uso); abaixo disso reduz suavemente ate
       o minimo, sem nunca cruzar o passo vizinho — a hierarquia relativa
       nao muda em nenhuma largura. --tipo-6 preserva o clamp ja usado em h1,
       valor a valor. */
    --tipo-1: clamp(0.75rem, 0.7292rem + 0.104vw, 0.8125rem);  /* 12 -> 13px */
    --tipo-2: clamp(0.875rem, 0.8542rem + 0.104vw, 0.9375rem); /* 14 -> 15px */
    --tipo-3: clamp(1rem, 0.9792rem + 0.104vw, 1.0625rem);     /* 16 -> 17px */
    --tipo-4: clamp(1.1875rem, 1.125rem + 0.3125vw, 1.375rem); /* 19 -> 22px */
    --tipo-5: clamp(1.5rem, 1.4375rem + 0.3125vw, 1.6875rem);  /* 24 -> 27px */
    --tipo-6: clamp(1.75rem, 4vw, 2.5rem);                     /* 28 -> 40px, = h1 atual */
    /* DOIS DEGRAUS DE DISPLAY, criados pela home em 25/08/2026 (onda 42).

       A direcao B nao e "letra menor": e "toda letra pertence a um degrau". No
       /app isso deu escala PARA BAIXO, porque a tela e leitura e o assunto dela
       e o relatorio. Na home da para CIMA, porque a tela e venda e o assunto
       dela e a promessa — mas o principio e o mesmo, e sem estes dois degraus
       ele nao poderia valer aqui.

       O que eles substituem, e a prova de que eram um degrau disfarcado de tres:

         --tipo-7   clamp(1.875rem, 3.8vw, 2.875rem)  .secao_head h2 e .faq h2
                    clamp(1.875rem, 3.6vw, 2.75rem)   .fecho h2
                    Tres cabecalhos de secao com DOIS clamps quase iguais: 30->46
                    e 30->44. Ninguem escolheu que o fecho fosse 2px menor que as
                    outras secoes; ele so foi escrito noutro dia. O degrau fica
                    com 30->46, o valor da maioria.
         --tipo-8   clamp(2.5rem, 6.4vw, 4.75rem)     .hero h1
                    O h1 da home, unico na pagina e unico no portal. Vira degrau
                    para deixar de ser um numero solto, com o valor que ja tinha.

       Por que nao empurrar a home para --tipo-5, como o /app fez: 27px abre uma
       secao de painel e nao abre uma pagina de venda. A escala existe para que
       toda medida seja um degrau — nao para que toda tela use os mesmos degraus. */
    --tipo-7: clamp(1.875rem, 3.8vw, 2.875rem);                /* 30 -> 46px */
    --tipo-8: clamp(2.5rem, 6.4vw, 4.75rem);                   /* 40 -> 76px */

    /* Score/faixa neutros — decisao do dono (DEC-002), REVERSIVEL: colorir por
       classificacao (ex.: faixa vermelha p/ score baixo) e regra de negocio
       da FSS ainda nao definida; ate la o vermelho fica reservado a acao.
       Trocar = editar so estes tres tokens.
       Quem os consome (18/08/2026): --score-cor em `.anel_score`, e
       --faixa-fundo/--faixa-texto em `.rel_selo_faixa`, o chip de
       classificacao do relatorio e do painel. Se um dia um componente novo
       desenhar score ou faixa, ele LE daqui — o chip passou seis dias vermelho
       justamente por ter nascido fora deste caminho. */
    --score-cor: var(--texto);
    --faixa-fundo: var(--superficie);
    --faixa-texto: var(--texto);

    /* O ARCO do anel de pontuacao (.anel_total, relatorio e painel) segue a
       MESMA regra dos tres tokens acima, e pelo mesmo motivo.
       Ate 17/08/2026 ele era `var(--fss)`: TODA pontuacao desenhava o arco em
       vermelho de marca. 85 "Previsivel" saia com o mesmo alarme de 42
       "Instavel" — a cor nao informava nada e, no resultado bom, informava o
       contrario. Quem carrega a classificacao e a palavra (o chip ao lado), que
       nunca dependeu de cor.
       Neutro de alto contraste. Medido em 17/08/2026 no cartao real, com o tema
       forcado por cookie e o alfa composto de baixo para cima — o fundo do
       cartao e um gradiente, entao vale o pior extremo:
           claro  #5A6072 sobre o topo do gradiente  4,92:1 (base 5,68:1)
           escuro #A0A5B8 sobre o topo do gradiente  6,83:1 (base 7,90:1)
       Contra a TRILHA cinza, que e a cor vizinha: 3,69:1 no claro, 5,07:1 no
       escuro. O piso de elemento grafico e 3:1 (WCAG 1.4.11) — passa nos dois
       temas, contra os dois vizinhos.
       Colorir por faixa continua sendo regra de negocio da FSS (DEC-002): o dia
       em que ela existir, muda ESTE token (ou vira variante por classe emitida
       pelo servidor), e nenhuma regra de componente se mexe. */
    --anel-arco: var(--texto-suave);
    /* O TRILHO PRECISA SER VISIVEL, senao o anel nao informa proporcao.

       Ele herdava --borda. Medido em 18/08/2026: arco contra trilho dava
       2,45:1 no escuro e 2,97:1 no claro, abaixo dos 3:1 que a WCAG 1.4.11
       pede para objeto grafico que carrega informacao. O arco aparecia; onde
       ele TERMINA, nao — e um anel cuja borda de fim nao se ve vira um arco
       flutuante, nao uma fracao de 100.

       Token proprio, e nao --borda subido: aquele governa toda borda do
       portal, e clarea-lo por causa do anel mexeria em cada cartao. */
    --anel-trilha: rgba(15, 18, 32, 0.26);

    --fonte: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

    /* =========================================================================
       TOKENS DA DIRECAO VISUAL (variante D — home)
       -------------------------------------------------------------------------
       Camada ADITIVA: nada acima muda de valor, entao nenhuma outra tela do
       portal se mexe. Tudo o que a home desenha sai daqui — para trocar cor,
       raio, glow ou ritmo, edite ESTE bloco, nunca a secao `--- home ---`.

       Tres familias, de proposito:
       1) DERIVADAS  — escritas uma vez, feitas de color-mix() sobre --texto /
                       --fundo / --fss. Trocam de tema sozinhas, porque a base
                       ja troca. Nao duplicar no bloco escuro.
       2) SUPERFICIE FIXA — mesma cor nos DOIS temas, de proposito: o tile
                       "Gargalos" e sempre escuro e a ilha do FAQ e sempre
                       clara. Isso e variacao de superficie, nao tema.
       3) POR TEMA   — as poucas que precisam de valor proprio no escuro estao
                       repetidas nos dois blocos escuros abaixo.
       ========================================================================= */

    /* 1) derivadas ------------------------------------------------------- */
    --texto-fraco: #565C73;   /* terciario. No claro o teto de luminancia e o
                                 proprio branco, entao o terciario e um pouco
                                 MAIS escuro que --texto-suave e ganha hierarquia
                                 por tamanho/peso — assimetria real com o escuro,
                                 documentada para nao parecer defeito. 5,60:1 */
    --borda-marca: color-mix(in srgb, var(--fss) 32%, transparent);
    /* CONCLUIDO TEM COR PROPRIA, E ELA NAO E A DA MARCA.

       O vermelho neste produto significa PROBLEMA: e ele que pinta o gargalo
       na lista de pilares e a perda atual na estimativa. Usa-lo tambem para
       "Concluido em 13/08/2026" punha o fato bom e o fato ruim na mesma cor,
       na mesma tela.

       O verde ja dizia "concluido" a 400px dali, no glifo do marco
       (.pnl_conquista_glifo). Eram duas cores para um estado so. */
    --borda-feito: color-mix(in srgb, var(--sucesso) 34%, transparent);
    --painel: color-mix(in srgb, var(--texto) 4.5%, transparent);        /* vidro */
    --painel-solido: color-mix(in srgb, var(--texto) 7%, var(--fundo));  /* opaco */
    /* --lavagem foi REMOVIDA em 25/08/2026. Era a tinta rosa de `.tile_wash`, e
       o ultimo consumidor dela morreu quando a home entrou na direcao B — o
       /app ja a tinha trocado pela barra de acento na onda 32. Token sem
       consumidor nao e reserva, e armadilha: o proximo cartao que quisesse
       "olhe para mim" a encontraria pronta e reintroduziria os 4,34:1.
       O valor era: color-mix(in srgb, var(--fss) 10%, var(--painel-solido)). */
    --contorno: color-mix(in srgb, var(--texto) 26%, transparent);
    --contorno-forte: color-mix(in srgb, var(--texto) 46%, transparent);
    /* O CONTORNO DE UM CONTROLE NAO E O CONTORNO DE UM ENFEITE (onda 51).

       --contorno (26%) pinta traco DECORATIVO — o selo, o cartao pontilhado,
       o trilho vazio. Ninguem precisa enxerga-lo para operar a tela, e a
       WCAG nao cobra 3:1 dele.

       Borda de campo, caixa de aceite e divisor entre dois controles sao
       outra coisa: sao a UNICA informacao visual que diz onde o controle
       comeca e acaba (WCAG 1.4.11), e o axe nao mede nenhuma delas. Medido em
       26/08/2026 na tela de acesso, no pixel renderizado: a borda de campo
       (--borda) dava 1,35:1 no claro e 1,32:1 no escuro, e o preenchimento do
       campo contra o cartao dava 1,10:1 e 1,07:1 — nem a borda nem o fundo
       identificavam o campo. A caixa de aceite (--contorno) dava 1,79:1 e
       2,22:1.

       52% de --texto sobre a superficie do cartao mede 3,35:1 no claro e
       5,05:1 no escuro. E derivado, entao troca de tema sozinho e NAO se
       repete nos dois blocos escuros. */
    --borda-controle: color-mix(in srgb, var(--texto) 52%, transparent);
    --preenchimento: color-mix(in srgb, var(--texto) 6%, transparent);

    /* 2) superficie fixa (nao muda com o tema) ---------------------------- */
    --escuro-fundo: #10121E;
    --escuro-texto: #F2F3F7;
    --escuro-suave: #A8ADC0;
    --escuro-borda: rgba(255, 255, 255, .14);
    /* O ACENTO ESCURO, O MAIS PROXIMO DA MARCA QUE AINDA PASSA.

       #FF8A90 nao era engano: o vermelho de marca (#E63946) da 4,34:1 sobre
       --superficie no escuro e reprova AA para os 12px em que este token vive.
       Mas 7,4:1 era folga demais paga em saturacao — o acento saia rosado, e
       deixava de parecer a marca.

       #EC4C58 e o ponto medido entre os dois: 4,96:1 sobre --superficie e
       5,10:1 sobre --fundo. Passa com margem, e volta a ler como vermelho.
       Descer mais aproxima o limite sem ganho visivel — #E83F4C ja e 4,53. */
    --escuro-acento: #EC4C58;

    --claro-fundo: #FBFBFD;
    --claro-cartao: #FFFFFF;
    --claro-borda: rgba(15, 18, 32, .10);
    --claro-texto: #14151F;
    --claro-suave: #565C73;
    --claro-acento: #C1121F;

    /* 3) cena de fundo (as camadas decorativas fixas atras de tudo).
       Intensidade e o botao de volume do glow vermelho: 0 apaga a cena inteira
       sem mexer em mais nada. */
    /* .32 e .10 tornavam a cena quase imperceptivel: o tema claro ficava um
       vazio branco enquanto o escuro tinha textura. Subir demais, porem,
       suja o fundo de um formulario — .55 e .18 dao relevo sem ruido visual. */
    --cena-intensidade: .55;
    --cena-ruido: .18;
    --cena-frio: rgba(88, 108, 168, .06);
    --cena-forma: color-mix(in srgb, var(--texto) 7%, transparent);
    --cena-glow-1: rgba(230, 57, 70, .22);
    --cena-glow-2: rgba(230, 57, 70, .13);
    --cena-glow-3: rgba(230, 57, 70, .16);
    --ruido: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="180" height="180"><filter id="n"><feTurbulence type="fractalNoise" baseFrequency="0.85" numOctaves="2" stitchTiles="stitch"/><feColorMatrix type="matrix" values="0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 0.05 0"/></filter><rect width="100%25" height="100%25" filter="url(%23n)"/></svg>');

    /* OS CINCO RAIOS DA HOME VIRARAM UM, E SOBROU O QUE NAO E SUPERFICIE
       (onda 42, 25/08/2026).

       Ate aqui a home declarava --raio-g (22, tiles e depoimentos), --raio-m
       (18, itens do FAQ), --raio-peca (28, o cartao do hero) e --raio-limite
       (30, o painel de transparencia). Somados ao 16 cru de `.grandeza` e ao 40
       da ilha, davam SEIS raios renderizados na mesma pagina — enquanto o /app,
       depois da direcao B, renderiza dois. Nao era a home tendo personalidade:
       era a home nao tendo decidido.

       Os quatro foram embora; toda superficie da home passou a ler --raio-app,
       o MESMO token do /app. Nao um valor parecido: o mesmo. Se fossem 20 aqui
       e 16 la, a divergencia so teria mudado de escala.

       O QUE SOBROU, E POR QUE CADA UM E OUTRA COISA:

         --raio-ilha (40px)  NAO e um cartao. E a dobra da pagina: a faixa
                             sangrada do FAQ, larga de borda a borda, cujos
                             cantos DE CIMA curvam quando o fundo escuro vira a
                             ilha clara. Curvar 1440px com 16 nao le como
                             decisao, le como cartao que nao coube. Raio de
                             dobra e raio de superficie sao papeis diferentes,
                             e um numero so nao serve aos dois.
         --pilula (999px)    controle, nao superficie — a mesma excecao que a
                             direcao B ja escreve para campo, pilula e circulo.

       --raio-peca sai junto: `.peca_cartao` e `.rel_peca` liam 28px e o /app ja
       reapontava a segunda para --raio-app. Com a base lendo --raio-app, as
       duas passam a ser a mesma superficie por construcao. */
    --raio-ilha: 40px;
    --pilula: 999px;

    /* =========================================================================
       DIRECAO B — "ASSISTENTE CALMO" (escolhida pelo dono em 20/08/2026, entre
       tres direcoes renderizadas sobre as telas REAIS do /app; a folha de prova
       injetada esta em evidencias/w31/direcoes/b-assistente-calmo.css e a
       medida que a motivou, em evidencias/w31/medidas.json).
       -------------------------------------------------------------------------
       O diagnostico nao era de linguagem, era de VOLUME: o painel e o relatorio
       desenhavam SEIS niveis de superficie e DOZE tamanhos de tipo na mesma
       pagina, com tres raios diferentes competindo. A direcao afina o
       instrumento em vez de trocar de instrumento.

       Estes dois tokens sao o que ela acrescenta. Todo o resto dela e
       SUBTRACAO: valores soltos que passaram a ler --tipo-*, uma segunda
       pintura de cartao que virou a primeira, e tres relogios de hover que
       viraram um.

       A HOME ENTROU NA DIRECAO B EM 25/08/2026 (onda 42). Enquanto ela ficou
       de fora, o portal falava duas linguas e o lead atravessava de uma para a
       outra no meio do funil — a home e a primeira impressao, e era a que
       destoava do resto. O que a home NAO importou foi a densidade: ela e
       pagina de venda, e o degrau de titulo dela continua sendo display
       (--tipo-7/-8, criados por causa dela). A direcao e a lingua, nao o
       tamanho da letra.
       ========================================================================= */
    /* UM RAIO SO para toda superficie do /app — entre o raio de CAMPO (8px, que
       fica) e o grande de antes (22px). Ainda macio; deixa de ser o elemento
       que mais grita "aplicativo de consumo". Campo, pilula e circulo nao
       entram: eles nao sao superficie, sao controle. */
    --raio-app: 16px;
    /* A BARRA DE ACENTO — o "carimbo de papel" que substitui a lavagem rosa.
       Larga o bastante para ler como marcacao de bloco a 320px, estreita o
       bastante para nao virar moldura. Nao e espacamento: e a espessura de uma
       borda, e por isso nao sai de --esp-*. */
    --acento-largura: 4px;

    /* ritmo. --curva/--dur-entrada seguem intocados no diagnostico; a home usa
       --curva-suave e as duracoes abaixo. Mexer aqui muda o ritmo inteiro. */
    --curva-suave: cubic-bezier(.2, .8, .2, 1);
    --dur-hover: 260ms;
    --dur-revelar: 640ms;
    --dur-tema: 200ms;
    --dur-anel: 1.3s;
    /* Coreografia da peca da home (relatorio-exemplo). Sao DOIS tokens porque o
       contador do score e feito em rAF: o JS le --dur-peca-arco e
       --dur-peca-gargalo para nascer e morrer na mesma janela do ultimo arco.
       Duplicar esses numeros em JS reintroduziria a divergencia classica entre
       o que a tela desenha e o que o script conta. --dur-anel fica intocado
       porque e do anel do relatorio REAL (.anel_total, result.php). */
    --dur-peca-arco: 760ms;
    --dur-peca-gargalo: 320ms;
    --dur-pulso: 1.9s;
    /* Indicador 3D: o componente e --dur-3d/--curva-3d moram em
       comum/carregando3d.css (importado no topo), com o porque de cada numero.
       Aqui fica so a ponte de tema — o compartilhado le `--c3d-*`. */
    --c3d-halo: color-mix(in srgb, var(--fss) 30%, transparent);
    --c3d-anel: var(--borda-marca);
    --dur-flutua: 5.8s;
    /* A festa da calculadora. --dur-festa e o teto da queda de uma particula; o
       JS sorteia entre 1100ms e 1700ms dentro dela. As quatro cores NAO sao
       cores novas: sao apelidos das que ja existem, e por serem `var()`
       resolvidas em :root elas trocam junto com o tema, sem uma segunda lista
       no bloco escuro. */
    --dur-festa: 1.7s;
    --confete-1: var(--fss-acao);
    --confete-2: var(--sucesso);
    --confete-3: var(--alerta);
    --confete-4: var(--texto-suave);
    --dur-marquee: 34s;
    --dur-glow: 34s;

    /* sombras da direcao D: mais profundas que --elev-*, que continua valendo
       nas outras telas. */
    --elev-cartao: 0 1px 2px rgba(15, 18, 32, .05), 0 24px 56px rgba(15, 18, 32, .09);
    --glow-acao: 0 4px 10px rgba(0, 0, 0, .28), 0 16px 40px rgba(214, 40, 57, .38), inset 0 1px 0 rgba(255, 255, 255, .2);
/* Sombra da barra flutuante — NEUTRA desde 13/08/2026: as parcelas vermelha
   (0 18px 46px rgba(214,40,57,.36)) e o inset branco saíram junto com o
   fundo vermelho da barra. Brilho vermelho e do botao (--glow-acao). */
    --glow-flutuante: 0 10px 30px rgba(0, 0, 0, .38);
}

/* Tokens de acento (vermelho FSS) — usados em momentos específicos de ênfase.
   Apenas --glow-acao é usado globalmente; os demais são aplicados via className
   quando o servidor confirma o estado de ênfase (meta atingida, KPI em destaque).

   O `:root` ABAIXO ESTAVA FALTANDO, e a falta era invisivel ate alguem USAR os
   tokens (medido em 01/09/2026, evidencias/w70).

   Sem seletor, o parser nao le isto como bloco de declaracoes: ele tenta montar
   uma regra qualificada, engole `--accent-primary: ...` ate o `}` como se fosse
   PRELUDIO, continua engolindo ate achar a proxima `{` — a de `.kpi-meta-alerta`
   — e descarta a regra inteira por prelude invalido. Resultado: os seis tokens
   nunca existiram em lugar nenhum, e `.kpi-meta-alerta` foi junto (medido:
   animationName = "none").

   Enquanto ninguem consumia os tokens isso era codigo morto silencioso. Quando o
   header passou a usar `var(--accent-primary)`, virou tres defeitos de uma vez:
   `.nav_cta` sem fundo (texto branco sobre header branco, 1,00:1 — a pilula so
   aparecia no hover, que usa outro token), o fio de 3px da marca com
   `border-top-width` computado em 0px nos dois temas, e o "System" da marca
   preto em vez de vermelho. `var()` sem fallback e token inexistente = invalido
   no tempo de valor computado, e a propriedade cai para herdada/inicial em vez
   de falhar barulhento. */
:root {
    --accent-primary: #D82641;
    --accent-hover: #C01F38;
    --accent-pressed: #A8192F;
    --accent-subtle: rgba(216, 38, 65, 0.08);
    --glow-accent-strong: 0 0 32px 4px rgba(216, 38, 65, 0.4);
    --glow-accent-soft: 0 0 16px 0 rgba(216, 38, 65, 0.25);
}

/* Efeito de meta atingida em KPIs do modo TV.
   Aplicado via class .kpi-meta-alerta quando o servidor confirma
   que a meta daquele KPI foi atingida (≥100%). Usa o token
   glow-accent-strong que já existe (line 440): só deve ser
   adicionado ao elemento numérico em momento específico de ênfase. */
.kpi-meta-alerta {
    animation: kpi-pulse 2s ease-in-out infinite;
    box-shadow: var(--glow-accent-strong);
}

@keyframes kpi-pulse {
    0%, 100% { color: var(--accent-primary); }
    50% { color: var(--fss-texto); }
}

/* --- tema escuro ---
   O bloco existe DUAS vezes de proposito, mesma convencao do painel admin
   (public/assets/admin/admin.css):

   - `:root:not([data-tema])` = automatico. Sem cookie, quem decide e o sistema.
   - `[data-tema="escuro"]`   = forcado pelo seletor, mesmo contra a preferencia
                                do sistema. O atributo sai do SERVIDOR
                                (themes/portal/_theme.php le o cookie portal_tema),
                                entao o primeiro paint ja nasce certo — sem
                                piscada de tema errado.

   CSS puro nao tem como referenciar um bloco no outro; a duplicacao e o preco.
   Editar um sem editar o outro e defeito: os dois listam os MESMOS tokens. */
@media (prefers-color-scheme: dark) {
    :root:not([data-tema]) {
        --fundo: #0D0D14;
        --superficie: #151520;
        --superficie-alta: #1C1C2A;
        --borda: rgba(255, 255, 255, 0.10);
        --anel-trilha: rgba(255, 255, 255, 0.26);
        --texto: #F2F3F7;
        --texto-suave: #A0A5B8;
        --sucesso: #3DDC97;
        --alerta: #F0A02E;
        --erro: #FF6B6B;
        --elev-1: 0 1px 2px rgba(0, 0, 0, .4);
        --elev-2: 0 1px 2px rgba(0, 0, 0, .4), 0 8px 24px rgba(0, 0, 0, .35);

        /* No escuro o vermelho de marca perde contraste contra a superficie
           (4,03:1): texto miudo passa a usar um tom claro — 6,57:1. O fundo de
           acao nao muda, porque o texto branco sobre ele independe do tema. */
        --fss-texto: #EC4C58;

        /* direcao D: no escuro o terciario clareia (o teto de luminancia agora
           e o proprio fundo escuro) e a cena tecnologica sobe de volume. */
        --texto-fraco: #868CA0;
        --cena-intensidade: 1;
        --cena-ruido: .5;
        --cena-frio: rgba(88, 108, 168, .015);
        --elev-cartao: 0 2px 4px rgba(0, 0, 0, .4), 0 30px 70px rgba(0, 0, 0, .55);
    }
}

[data-tema="escuro"] {
    color-scheme: dark;

    --fundo: #0D0D14;
    --superficie: #151520;
    --superficie-alta: #1C1C2A;
    --borda: rgba(255, 255, 255, 0.10);
    --anel-trilha: rgba(255, 255, 255, 0.26);
    --texto: #F2F3F7;
    --texto-suave: #A0A5B8;
    --sucesso: #3DDC97;
    --alerta: #F0A02E;
    --erro: #FF6B6B;
    --elev-1: 0 1px 2px rgba(0, 0, 0, .4);
    --elev-2: 0 1px 2px rgba(0, 0, 0, .4), 0 8px 24px rgba(0, 0, 0, .35);
    --fss-texto: #EC4C58;

    --texto-fraco: #868CA0;
    --cena-intensidade: 1;
    --cena-ruido: .5;
    --cena-frio: rgba(88, 108, 168, .015);
    --elev-cartao: 0 2px 4px rgba(0, 0, 0, .4), 0 30px 70px rgba(0, 0, 0, .55);
}

/* Forcar o tema tem de forcar tambem a pintura nativa (radio, barra de
   rolagem): sem isto, `light dark` deixaria o sistema decidir os controles. */
[data-tema="claro"] { color-scheme: light; }

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

body {
    margin: 0;
    font-family: var(--fonte);
    font-size: 16px;
    line-height: 1.6;
    color: var(--texto);
    background: var(--fundo);
    -webkit-font-smoothing: antialiased;
}

.wrap { width: min(1080px, 92vw); margin-inline: auto; }

/* --fss-acao, nao --fss: branco sobre o vermelho de marca da 4,17:1 e o link
   de pular e texto normal (piso 4,5:1). Corrigido em 13/08/2026 — o token de
   acao existe exatamente para este caso e vale nos dois temas. */
.skip {
    position: absolute; left: -9999px;
    background: var(--fss-acao); color: #fff; padding: 10px 16px; border-radius: var(--raio-p);
}
.skip:focus { left: 16px; top: 16px; z-index: 100; }

/* Foco sempre visivel — requisito de acessibilidade (secao 12.6).
   O anel usa duas camadas (vermelho + halo do fundo) para permanecer visivel
   tanto sobre superficie clara quanto sobre o proprio vermelho dos botoes. */
:focus-visible {
    outline: 3px solid var(--fss-acao);
    outline-offset: 2px;
    border-radius: 4px;
    box-shadow: 0 0 0 2px var(--fundo);
}
.btn:focus-visible, .nav_cta:focus-visible { outline-color: var(--texto); }

/* WCAG 2.2 (2.4.11): a barra de progresso e sticky e poderia cobrir o
   elemento focado ao rolar. */
:target, legend, fieldset, .campo, .btn { scroll-margin-top: 96px; }

/* Rolagem suave SO na home (ancoras do menu #recebe/#funciona/#transparencia/
   #faq). Escopo deliberado, nao preguica: global no html, o smooth animaria o
   window.scrollTo(0,0) do stepper a CADA uma das 30 perguntas (lag, nao
   polish) e o "Pular para o conteudo" das outras telas. O :has e progressive
   enhancement puro — navegador sem ele so nao ganha o deslize. A guarda de
   prefers-reduced-motion la embaixo ja neutraliza isto (scroll-behavior: auto
   !important) — ela existia antes do proprio smooth. */
html:has(.pagina-home) { scroll-behavior: smooth; }

/* --- topo ---
   O HEADER TROCA COM O TEMA (14/08/2026), e desde 01/09/2026 a MARCA tambem e a
   mesma nos dois. Historico curto, porque duas notas antigas ja foram revogadas
   aqui: o header nasceu "sempre escuro" porque o unico lockup da FSS era
   `logo-fss-branco.webp` (simbolo vermelho + tipo BRANCO), que so contrasta
   sobre fundo escuro; depois o claro passou a usar `logo.png` (o simbolo) + o
   nome em texto, e o escuro seguiu com o lockup em imagem.

   O QUE ISSO CUSTAVA, medido na onda 70: o desenho era o mesmo nos dois
   arquivos (silhueta com 1% de diferenca), mas a COMPOSICAO nao — uma linha no
   claro contra tres linhas empilhadas no escuro —, e isso lia como duas marcas.
   Havia ainda 9% de diferenca de tamanho otico, porque o PNG traz margem
   transparente e o webp era sangrado.

   HOJE: um desenho, duas cores. `logo.png` no claro, `logo-branco.png` no
   escuro (o mesmo arquivo recolorido, alfa intacto: 0 pixel de diferenca de
   silhueta), e o nome em TEXTO nos dois — logo a composicao e identica e o
   tamanho otico bate sozinho, porque as duas imagens tem a mesma margem.

   As cores deste bloco saem de --topo-*, que trocam com o tema. Nao use
   --texto/--superficie direto aqui: o alternador de tema e a preferencia do
   sistema mexem nos dois lugares e o header precisa de um so ponto de verdade.

   A linha vermelha de 3px no topo absoluto e a assinatura da marca, herdada do
   site institucional: largura total, --fss, e nenhuma outra borda ou sombra. */
/* --topo-acento: o VERMELHO DA MARCA COMO TEXTO, medido sobre cada fundo do
   header (01/09/2026). Ele nasceu quando "System" passou a ser texto tambem no
   tema escuro: `--accent-primary` (#D82641) da 4,91:1 sobre o header claro e
   so 3,79:1 sobre o escuro (#10121E) — e o axe reprovou, com razao, a 375px,
   onde `.marca_nome` encolhe de 22px para 16px e sai da faixa de "texto
   grande" (>= 18,66px em negrito, onde o limiar cairia para 3:1).
   No escuro ele reusa --escuro-acento (#EC4C58, 5,09:1), o mesmo tom que o
   resto do portal ja usa para vermelho pequeno sobre superficie escura — nao e
   um vermelho novo, e continua sendo o acento da marca. */
:root {
    --topo-fundo: var(--claro-cartao);
    --topo-texto: var(--claro-texto);
    --topo-suave: var(--claro-suave);
    --topo-borda: var(--claro-borda);
    --topo-acento: var(--accent-primary);
}

@media (prefers-color-scheme: dark) {
    :root:not([data-tema]) {
        --topo-fundo: var(--escuro-fundo);
        --topo-texto: var(--escuro-texto);
        --topo-suave: var(--escuro-suave);
        --topo-borda: var(--escuro-borda);
        --topo-acento: var(--escuro-acento);
    }
}

:root[data-tema="escuro"] {
    --topo-fundo: var(--escuro-fundo);
    --topo-texto: var(--escuro-texto);
    --topo-suave: var(--escuro-suave);
    --topo-borda: var(--escuro-borda);
    --topo-acento: var(--escuro-acento);
}

/* A FAIXA DE PERSONIFICACAO (01/09/2026).

   ELA VEM ANTES DO CABECALHO, e isso e decisao e nao ordem de arquivo: o
   operador precisa ler "voce nao e voce" ANTES de reconhecer a marca e agir por
   habito. Depois do topo, ela competiria com a barra de navegacao no mesmo
   instante em que a pessoa ja decidiu onde clicar.

   NAO E `position: fixed`. Faixa fixa cobre conteudo em tela baixa e some do
   fluxo de leitura de quem usa leitor de tela na ordem do documento. Ela e a
   primeira coisa do corpo e rola com a pagina — quem rola de volta ao topo, que
   e o que se faz para navegar, a reencontra.

   `--alerta` e nao `--erro`: personificar nao e um erro, e um estado legitimo e
   perigoso. Vermelho aqui gastaria o unico tom que o portal reserva para coisa
   quebrada.

   Sem animacao de entrada de proposito: a faixa esta presente desde o primeiro
   quadro, entao nao ha nada a anunciar — e movimento aqui viraria ruido em toda
   navegacao sob disfarce. Por isso tambem nao ha regra sob prefers-reduced-motion:
   nao ha o que reduzir. */
.disfarce {
    background: color-mix(in srgb, var(--alerta) 14%, var(--superficie));
    border-bottom: 3px solid var(--alerta);
    color: var(--texto);
    font-size: var(--tipo-2);
}
.disfarce_inner {
    display: flex; flex-wrap: wrap; align-items: center;
    justify-content: space-between; gap: 12px 20px;
    padding-top: 12px; padding-bottom: 12px;
}
.disfarce_texto { display: flex; align-items: flex-start; gap: 10px; margin: 0; max-width: 78ch; }
.disfarce_texto svg { flex: none; margin-top: 2px; color: var(--alerta); }
.disfarce_prazo { color: var(--texto-suave); white-space: nowrap; }
.disfarce_saida { flex: none; margin: 0; }

/* VENCIDO MUDA A COR, NAO SO O TEXTO. Enquanto vale, o estado e legitimo; depois
   de vencer, nada mais grava — e aí a faixa passa a ser sobre algo que quebrou,
   que e exatamente quando `--erro` cabe. */
.disfarce_vencido { background: color-mix(in srgb, var(--erro) 12%, var(--superficie)); border-bottom-color: var(--erro); }
.disfarce_vencido .disfarce_texto svg { color: var(--erro); }

.topo {
    border-top: 3px solid var(--accent-primary);
    border-bottom: 1px solid var(--topo-borda);
    background: var(--topo-fundo);
}

/* Uma cor de logo por tema. Ambas vem no HTML e o CSS esconde a que nao serve —
   trocar `src` por JS piscaria a imagem errada no primeiro paint, o mesmo
   defeito que o cookie de tema existe para evitar, e sem JS (secao 12.4) nao
   trocaria nada: aqui a alternancia e 100% CSS. */
/* NOME EM TEXTO NOS DOIS TEMAS (dono, 01/09/2026). Ate aqui isto valia so no
   claro, e o escuro trazia o nome dentro da imagem, empilhado em tres linhas —
   duas composicoes para uma marca so. Agora a marcacao e a mesma e quem troca e
   a COR, que ja vem de token: --topo-texto acompanha o header e --topo-acento
   da o vermelho de "System" (vermelho que a onda 70 consertou; nao voltar a
   escrever a cor a mao). Fonte de sistema, como todo o resto do portal — nao ha
   webfont nem toolchain para uma. */
.marca_nome {
    display: inline-flex; align-items: baseline; gap: .32em;
    margin-left: 10px;
    font-size: var(--tipo-4); font-weight: 800; letter-spacing: -.02em;
    color: var(--topo-texto); white-space: nowrap;
}
/* --topo-acento e nao --accent-primary: a palavra continua no vermelho da marca
   (onda 70), so que no tom que passa em CADA fundo do header — ver a nota do
   token acima. Trocar por --accent-primary aqui reprova o axe a 375px no
   escuro, com numero: 3,79:1 contra os 4,5:1 exigidos. */
.marca_nome_sys { color: var(--topo-acento); }

@media (max-width: 420px) {
    .marca_nome { font-size: var(--tipo-3); margin-left: 8px; }
}

/* DUAS classes no seletor de proposito: `.marca_logo` (definida mais abaixo,
   com `display: block`) tem a mesma especificidade de `.marca_logo_escuro` e,
   por vir depois no arquivo, venceria — as duas logos apareciam lado a lado,
   com o lockup branco invisivel sobre o header claro deixando so o simbolo
   dele visivel. Dobrar a classe resolve sem depender da ordem. */
.marca_logo.marca_logo_claro { display: block; }
.marca_logo.marca_logo_escuro { display: none; }

@media (prefers-color-scheme: dark) {
    :root:not([data-tema]) .marca_logo.marca_logo_claro { display: none; }
    :root:not([data-tema]) .marca_logo.marca_logo_escuro { display: block; }
}

:root[data-tema="escuro"] .marca_logo.marca_logo_claro { display: none; }
:root[data-tema="escuro"] .marca_logo.marca_logo_escuro { display: block; }
/* Altura baixa, como a referencia: 3 (linha) + 16 + 46 (a pilula, o item mais
   alto da linha — maior que os 36px da logo e que o alvo de 44) + 16 + 1
   (borda) = 82px medidos a 1280. */
/* A BARRA NAO E COLUNA DE LEITURA, e por isso ela deixou de herdar a largura
   de .wrap (24/08/2026).
   O DEFEITO, medido: o orcamento do topo pedia 1.207px — marca 116 + os oito
   itens do menu 863 + a pilula "Agendar reuniao" 201 + os vaos — e .wrap
   oferece 1.080px. Faltavam 127px em QUALQUER tela, inclusive a 1600, porque o
   teto e do container e nao do monitor. Resultado: o header quebrava em duas
   linhas e passava de 82px para 213px.
   E ele quebrava so para QUEM QUALIFICOU: a pilula do agendamento e o nono item,
   e so aparece para quem passou nos cinco gates (RF07). Ou seja, o lead que
   converteu — o unico que a operacao quer no portal — era o unico a receber um
   cabecalho de 213px empurrando o conteudo para fora da tela.
   1.080px existe para o TEXTO nao passar da medida de leitura. Uma barra de
   navegacao nao tem medida de leitura: e uma regua de alvos de toque, e o que
   ela pede e caber. */
.topo_inner {
    /*
     * A LARGURA VOLTOU (31/08/2026) — a regra descrita no comentario acima
     * tinha sumido do arquivo, e o defeito com ela.
     *
     * Medido antes de restaurar: container 1.080px, marca 221px, menu 937px.
     * 221 + 937 + 28 de vao = 1.186px de orcamento contra 1.080 oferecidos —
     * faltavam 106px em QUALQUER tela, porque o teto e do container e nao do
     * monitor. A barra quebrava em duas linhas e o cabecalho ia de 82px para
     * 141px, sobrando 143px vazios a direita.
     *
     * `min(1240px, 94vw)` cobre o orcamento com folga para o nono item (a
     * pilula de agendamento, que so aparece para quem qualificou — e era
     * justamente quem levava o cabecalho maior).
     *
     * Vem DEPOIS de `.wrap` no arquivo, entao vence por ordem com a mesma
     * especificidade. O elemento carrega as duas classes de proposito: `.wrap`
     * da o `margin-inline: auto`.
     */
    /*
     * A MARGEM VIROU CONSTANTE (01/09/2026, onda 72). Era `94vw`: uma margem
     * PROPORCIONAL, que encolhe justamente quando falta espaco. A 1.440 ela
     * cobrava 86px do orcamento; a 1.080, 65px — e a 1.080 faltavam exatamente
     * 166px para a barra do lead qualificado caber. Margem de gutter nao e
     * conteudo: 24px de cada lado bastam em qualquer monitor, e o que sobra vai
     * para a barra. Medido: +17px a 1.080 e +29px a 1.280, que e o que decide o
     * 1.280 entre uma linha e duas.
     */
    width: min(1240px, 100vw - 48px);
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--esp-5); padding: 16px 0; flex-wrap: wrap;
}
.marca { display: inline-flex; align-items: center; text-decoration: none; }
/* height manda; width:auto mantem a proporcao real (500x499, o simbolo) mesmo
   se os atributos do HTML forem arredondados. Os dois arquivos tem a MESMA
   caixa e a mesma margem transparente, entao o tamanho otico bate nos dois
   temas sem regra extra. */
.marca_logo { display: block; height: 36px; width: auto; }
/* Espacamento generoso da referencia (28px) e peso REGULAR — o menu do portal
   e navegacao, nao chamada. Alvo de toque de 44px (WCAG 2.2, 2.5.8).
   .nav_secoes (ancoras da home) entra nas mesmas regras: fora de .nav, sem
   isto herdaria o azul de link do navegador — que sobre o header escuro fica
   em 2,3:1. */
.nav { --nav-gap: 16px; display: flex; align-items: center; gap: var(--nav-gap); flex-wrap: wrap; }

/*
 * O MENU OCUPA A LINHA, E A ACAO ANCORA A DIREITA (31/08/2026).
 *
 * Duas coisas de uma vez, e a segunda so aparece quando a barra empilha:
 *
 * 1. NAVEGACAO E ACAO DEIXAM DE SER VIZINHAS. "Agendar reuniao" e a unica
 *    pilula da barra e estava entre "Analise de call" e "Conta" — a acao
 *    primaria lida como o sexto link. Empurrada para a ponta, ela para de
 *    competir com o menu e ganha a posicao onde a mao ja procura acao.
 *
 * 2. A LINHA PARA DE SOBRAR. Medido a 1.200px, quando a barra empilha: o menu
 *    terminava com 193px vazios a direita, e a fila de itens parecia
 *    interrompida em vez de distribuida.
 *
 * `flex: 1` faz o menu tomar o que sobra da linha; `margin-left: auto` no CTA
 * empurra ele e o que vem depois (Conta, tema) para a ponta. Numa linha cheia
 * — 1.280px para cima — nao sobra folga, e o efeito e nenhum.
 */
.nav { flex: 1 1 auto; }
.nav_cta { margin-left: auto; }

/*
 * ...E QUANDO O CTA NAO EXISTE, QUEM ANCORA E O TEMA (01/09/2026).
 *
 * A ancora da ponta direita morava no `.nav_cta`, e ele e OPCIONAL: desde
 * 01/09 ele nao aparece em `/entrar`, porque ali apontaria para a propria
 * pagina. Sem o CTA, o alternador de tema ficava sozinho na nav — e a nav tem
 * `flex: 1`, entao ele encostava na LOGO, com 1.000px de vazio a direita.
 *
 * O defeito nao foi o CTA sair: foi a ponta direita depender de um elemento
 * que pode nao existir. Quem carrega a ancora tem de ser quem esta la.
 *
 * `:first-child` E DE PROPOSITO, e nao `.tema_alterna` solto: no /app a nav
 * tem menu, sair e tema, e todos comecam na esquerda — de proposito, e a tela
 * esta certa assim. A regra so morde quando o tema E o primeiro, que e
 * exatamente o caso em que a ancora sumiu.
 */
.nav > .tema_alterna:first-child { margin-left: auto; }

/* A CONTA TAMBEM ANCORA NA PONTA — mas so quando nao ha pilula (onda 72).
 *
 * QUEM NAO QUALIFICOU nao tem "Agendar reuniao", e era a pilula que segurava a
 * ponta direita: sem ela, "Conta" parava onde o ultimo link acabasse — a 1.280
 * sobravam 241px depois dela, e a 768 ela caia SOZINHA na terceira linha, colada
 * a esquerda, com 656px de vazio a direita. Um controle solto no meio do nada le
 * como sobra de quebra, nao como canto de conta.
 *
 * O IRMAO ADJACENTE E O QUE MANTEM O CASO QUALIFICADO INTACTO: com a pilula no
 * ar, ela ja empurra tudo para a direita e a conta vem GRUDADA nela. Duas
 * margens automaticas na mesma linha nao se somam — elas REPARTEM a folga —, e o
 * par "acao + conta" apareceria separado por metade do vao vazio. Por isso a
 * segunda regra cancela a primeira exatamente no arranjo em que ela atrapalha.
 * `+` ignora os comentarios PHP entre os dois no _theme.php: eles nao emitem no. */
.nav_conta { margin-left: auto; }
.nav_cta + .nav_conta { margin-left: 0; }

/* A PRIMEIRA LINHA DEIXA DE SER UM VAZIO COM UMA LOGO (01/09/2026, onda 72).
 *
 * O DEFEITO, MEDIDO: quando a barra nao cabia, o cabecalho virava duas faixas e
 * a de cima levava SO a marca — 1.019px vazios a 1.440 e 815 a 1.080
 * (evidencias/w72/geometria-antes.json). Enquanto isso a faixa de baixo ia
 * lotada, e a 1.080 ela transbordava para uma TERCEIRA linha com um unico item
 * orfao. Havia espaco sobrando exatamente uma linha acima do aperto.
 *
 * POR QUE ISSO ACONTECIA (e nao e bug de ninguem): num flex container que
 * quebra, a linha e escolhida pelo tamanho HIPOTETICO do item — o menu inteiro,
 * ~1.000px — e so DEPOIS se aplica o encolhimento. O menu, entao, nunca tentava
 * caber ao lado da marca: ele descia inteiro, e a linha de cima ficava com o que
 * sobrou.
 *
 * A CORRECAO E TIRAR A QUEBRA DE FORA E DEIXAR A DE DENTRO. `nowrap` aqui nao
 * torna a barra rigida: quem passa a quebrar e o proprio `.nav`, que ja e um
 * flex container com `wrap`. O resultado medido a 1.080 com a pilula de
 * agendamento no ar: linha 1 = marca + os seis destinos, linha 2 = a acao e a
 * conta ancoradas a direita. Mesma altura de antes (140px), sem faixa vazia, sem
 * item orfao, e com o grupo dos entregaveis inteiro numa linha so.
 *
 * O PISO DE 1.040px SAIU DA MEDICAO, nao do gosto — e as duas pontas custam:
 *
 *   - abaixo dele o menu do lead NAO QUALIFICADO (que nao tem a pilula, mas tem
 *     os seis destinos + a conta = 748px) nao cabe ao lado da marca, e sobraria
 *     "Conta" sozinha numa segunda linha. Trocar a faixa vazia por um orfao seria
 *     mudar de defeito. Em 1.037px ele ja cabe; 1.040 e o degrau redondo acima;
 *   - abaixo de 640px a barra vira COLUNA (regra propria, mais adiante), que e a
 *     forma certa no telefone. Entre 640 e 1.040 fica a forma empilhada de
 *     sempre: marca em cima, menu embaixo — ali a faixa da marca ocupa 44px de
 *     uma tela estreita, e nao 1.000px de um monitor.
 *
 * NOWRAP EXIGE PISO, E ESSE E O MOTIVO REAL DE HAVER UM: sem a quebra externa, o
 * menu nao pode encolher abaixo do seu item mais largo (a pilula, ~200px). A
 * 320px sobrariam 78px para ele e a barra estouraria a tela na horizontal — o
 * unico defeito desta lista que o usuario sentiria com o dedo. */
@media (min-width: 1040px) {
    .topo_inner { flex-wrap: nowrap; }
}

/* NUCLEO x ENTREGAVEIS: um fio, nenhuma caixa (01/09/2026, onda 71).
 *
 * Painel, Diagnostico e Calculadora existem desde o primeiro minuto da conta.
 * Curso, Analise de call e Mapa de objecoes CHEGAM — e ver que chegaram e parte
 * do que a pessoa ganhou. Uma regua plana apaga essa diferenca; o porque de
 * produto esta no `_theme.php`, onde o <span> nasce.
 *
 * `display: contents` E O QUE FAZ ISTO CUSTAR ZERO. O invólucro nao vira caixa
 * no layout: os tres <a> continuam sendo itens flex DIRETOS da barra, cada um
 * quebrando linha por conta propria como antes. Trocar por um flex container
 * aninhado mudaria o ponto de quebra e prenderia os tres numa unidade so — que
 * e exatamente o que a barra nao pode fazer, porque ela ja empilha em telas
 * estreitas.
 *
 * O FIO MORA NO PRIMEIRO FILHO, E DENTRO DA FOLGA QUE JA EXISTIA. O padding
 * empurra, a margem negativa devolve, e a soma e zero — o `-1px` compensa a
 * propria borda, entao a largura pedida pela barra nao muda em nenhum pixel
 * (orcamento medido em evidencias/w71). Sem isso, separar custaria largura numa
 * barra que ja e o gargalo do cabecalho.
 *
 * SEM ROTULO E SEM `role="group"`: para quem ouve, a lista continua plana e cada
 * rotulo ja diz o que e. O fio nao carrega informacao que so ele tenha — e
 * decoracao honesta, e por isso nao lhe cabe piso de contraste de 3:1.
 *
 * OS TRES NAO SAO REBAIXADOS: mesmo tipo, mesmo peso, mesma cor do nucleo. O fio
 * diz "outra especie", nunca "especie menor" — quem chegou ate eles chegou por
 * merito, e a regra de entregavel e de sequencia, jamais de nota (RF11, §3.2).
 *
 * O <span> vazio (nenhum entregavel liberado) nao pinta nada: sem filho nao ha
 * `:first-child`, e sem caixa no layout ele nao ocupa espaco. */
.nav_grupo { display: contents; }
.nav_grupo > a:first-child {
    border-left: 1px solid var(--borda);
    padding-left: calc(var(--nav-gap) / 2 - 1px);
    margin-left: calc(var(--nav-gap) / -2);
}
/* O VAO NAO DEPENDE MAIS DA JANELA, e a versao anterior desta regra estava de
   cabeca para baixo. Ela apertava o vao ABAIXO de 1.400px, de quando o topo ainda
   herdava um teto de 92vw. Com o cabecalho de volta a largura do conteudo — 1.080
   fixos, para alinhar com a pagina —, o container nao cresce com o monitor e o vao
   tambem nao pode: medido, 28px davam 1.115px de barra a 1.600 (estourava) e 20px
   davam 1.067 a 1.366 (cabia). Quebrava na tela GRANDE e cabia na pequena, que e o
   contrario do que se procura quando o defeito aparece.
   16px EM TODA LARGURA desde 01/09/2026 (onda 72), e nao 20. O vao e o unico
   ajuste da barra que nao custa nem desenho nem palavra: entre oito vaos, os 4px
   de cada um somam 32px — metade do que faltava a 1.440 para o lead qualificado.
   O piso continua sendo o alvo de toque, e ele nao mexeu: cada item mede 44px de
   altura e os 16px separam CAIXAS, nao textos.
   Continua apertado de proposito: sobram 30px de folga a 1.440 com a pilula de
   agendamento no ar. Item novo NAO cabe na regua, e tem de entrar no controle de
   conta, que existe para isso. */
.nav a, .nav_secoes a {
    color: var(--topo-suave); text-decoration: none;
    font-size: var(--tipo-2); font-weight: 500;
    display: inline-flex; align-items: center; min-height: 44px;
}
.nav a:hover, .nav_secoes a:hover { color: var(--topo-texto); }
/* Glifo do menu (14/08/2026). O item do autenticado e glifo + rotulo: o texto
   continua sendo quem carrega o significado (o glifo entra decorativo), entao
   aqui so ha o respiro entre os dois e o tamanho. `flex: none` impede que o
   desenho encolha quando a barra fica apertada — icone amassado le pior que
   icone nenhum. .nav_secoes (ancoras da home) nao tem glifo e nao paga nada. */
.nav a { gap: 8px; }
.nav a .icone { flex: none; font-size: 1.125rem; }
/* Pilula da referencia: raio total, vermelho de acao, branco bold, padding
   horizontal largo. Sem sombra — no header a unica peca com relevo e a linha. */
/* `.nav a.nav_cta` e nao `.nav_cta`: o seletor precisa de UM elemento a mais
   para vencer `.nav a` (0,1,1), que repintava `font-weight: 500` por cima do 700
   declarado aqui. A pilula do header rendia mais leve do que quem a escreveu
   quis desde que a barra nasceu — o defeito estava anotado em `.flutuante_ir`
   (bloco da barra flutuante) esperando o dono deste bloco. Agora e (0,2,1).
   `.pagina-acesso .nav .nav_cta` (0,3,0) continua vencendo por contar mais
   classes, entao o rebaixamento das portas segue de pe. */
.nav a.nav_cta {
    background: var(--accent-primary); color: #fff !important;
    padding: 10px 26px; border-radius: var(--pilula);
    font-weight: 700; letter-spacing: .01em;
}
/* Sobe junto com a regra base: `.nav a.nav_cta` (0,2,1) venceria
   `.nav_cta:hover` (0,2,0) e o hover teria parado de pintar. `.pagina-acesso
   .nav .nav_cta:hover` (0,4,0) continua acima destes (0,3,1). */
.nav a.nav_cta:hover { background: var(--fss-acao-hover); }

/* A PILULA SAI DAS DUAS PORTAS (27/08/2026), E O CONTROLE FICA.

   MEDIDO na captura de 1440 depois da separacao: com a raiz virando o cadastro,
   a barra do topo carregava um "Entrar" em pilula vermelha, peso 700, a 60px do
   "Criar conta" — que e a acao primaria da pagina, na MESMA cor e no MESMO
   peso. Duas acoes primarias na mesma tela, e a de menos importancia era a que
   estava mais alto. Em /entrar era pior: a pilula apontava para a propria
   pagina e ficava ao lado de um botao com o mesmo rotulo.

   A escada de botoes do portal e solido > vazado > sem caixa, com UM primario
   por regiao. Nas portas o primario e o botao do formulario, e o caminho ate a
   outra porta ja existe dentro do cartao (`.autenticar_pe`) — que e onde
   quem esta lendo o formulario procura.

   ELE NAO SOME: vira um item de barra como os outros. Nas demais telas
   publicas — /termos, /privacidade, /recuperar-senha, as de erro — a pilula
   continua, porque la ela e a unica acao da tela e nao compete com nada. */
.pagina-acesso .nav .nav_cta {
    background: none; color: var(--topo-suave) !important;
    padding: 0; border-radius: 0;
    font-weight: 500; letter-spacing: normal;
}
.pagina-acesso .nav .nav_cta:hover { background: none; color: var(--topo-texto) !important; }

/* --- o controle de conta ---------------------------------------------------
   Recolhe Perfil, Administracao e Sair num item so. O porque esta no
   _theme.php: a barra pedia 1.352px e a coluna do conteudo oferece 1.080.
   <details> e nao um menu de script: abre no clique, fecha no clique, recebe
   foco pelo teclado e anuncia o estado sozinho. Sem JavaScript a conta continua
   alcancavel — o que nao acontece com um menu que so existe depois do load. */
.nav_conta { position: relative; }
.nav_conta > summary {
    display: inline-flex; align-items: center; gap: 8px; min-height: 44px;
    padding: 0; list-style: none; cursor: pointer;
    color: var(--topo-suave); font-size: var(--tipo-2); font-weight: 500;
}
/* O triangulo de fabrica e desenho do navegador, nao da casa, e muda de forma
   entre Safari e o resto. O estado aberto se le pelo painel, que aparece. */
.nav_conta > summary::-webkit-details-marker { display: none; }
.nav_conta > summary::marker { content: ''; }
.nav_conta > summary:hover,
.nav_conta[open] > summary { color: var(--topo-texto); }
.nav_conta > summary:focus-visible { outline: 3px solid var(--accent-primary); outline-offset: 4px; border-radius: 4px; }

/* O painel usa os tokens da PAGINA, e nao os do topo: ele cai por cima do
   conteudo, e nao dentro da barra. Herdar a tinta do header o deixaria escuro
   sobre a pagina clara. */
.nav_conta_menu {
    position: absolute; top: calc(100% + 10px); right: 0; z-index: 60;
    display: grid; min-width: 13rem;
    padding: 6px;
    background: var(--superficie); color: var(--texto);
    border: 1px solid var(--borda); border-radius: var(--raio-app);
    box-shadow: 0 12px 32px rgba(0, 0, 0, .18);
}
.nav_conta_menu a {
    display: flex; align-items: center; gap: 10px; min-height: 44px;
    padding: 0 12px; border-radius: var(--raio-p, 8px);
    color: var(--texto); text-decoration: none;
    font-size: var(--tipo-2); font-weight: 500;
}
.nav_conta_menu a:hover { background: var(--painel); }
.nav_conta_menu a:focus-visible { outline-offset: -3px; }
/* Sair fecha a sessao: fica por ultimo e separado por um fio, para nao ser
   clicado no lugar de Perfil. */
.nav_conta_menu .nav_sair { margin-top: 6px; border-top: 1px solid var(--borda); border-radius: 0; }

/* Numa barra que ja empilhou, o painel absoluto brigaria com a linha de baixo:
   ali ele volta ao fluxo normal e a conta abre empurrando, sem cobrir nada. */
@media (max-width: 640px) {
    .nav_conta_menu { position: static; min-width: 0; box-shadow: none; margin-top: 8px; }
}


/* O ULTIMO LINK DA BARRA (onda 41) — o unico destino que vem depois do Sair.

   NEM TODA CONTA O RECEBE: quem decide e o servidor, no tema, e para quem nao
   recebe este seletor simplesmente nao casa com nada. Dai a forma dele.

   POR QUE ESTRUTURA, E NAO CLASSE NEM SELETOR DE ATRIBUTO. Esta folha e
   baixada por TODO visitante, inclusive por quem nao recebe o item. Casar pelo
   `href` escreveria aqui um endereco que o HTML daquela pessoa nao contem — e e
   justamente esse endereco que o resto do sistema evita confirmar. `.nav_sair +
   a` diz a mesma coisa pela posicao. Este comentario segue a mesma regra e nao
   nomeia o destino: nao e descuido de redacao.
   (LIMITE CONHECIDO, e ele e ANTERIOR a esta regra: uns dez comentarios mais
   antigos deste mesmo arquivo nomeiam o painel a vontade, e o diretorio que
   serve esta folha serve tambem arquivos com o nome dele. Ou seja: a folha
   nunca foi tratada como superficie de vazamento. A regra vale daqui para a
   frente; limpar o resto e decisao de escopo, nao de estilo.)

   RESSALVA DO SELETOR POSICIONAL: qualquer ancora que nasca depois do Sair
   herda este desenho, inclusive na barra de quem nao e staff. Hoje so ha uma,
   e ha teste no tema garantindo que continue havendo so uma.

   O DESENHO E UM DEGRAU DA MESMA ESCADA DOS BOTOES (ver `--- botoes ---`): cada
   degrau perde uma camada, e a perda tem de ser visivel sem depender de cor.
   Este perde tipo (--tipo-2 -> --tipo-1, e o glifo encolhe junto, senao o
   desenho ficaria maior que a palavra), perde peso (500 -> 400) e perde a
   companhia — o fio separa os DESTINOS do que vem depois deles, que sao
   controles do momento (trocar de aplicacao, trocar de tema) e nao etapas do
   produto. A COR NAO MUDA: mexer nela custaria contraste, e este item passa em
   AA nos dois temas como qualquer outro da barra.

   O FIO CABE NA FOLGA QUE JA EXISTIA: `padding-left` + `margin-left` somam
   zero, entao o item nao ficou mais largo por causa do separador — o fio ocupa
   o MEIO da folga que a barra ja dava. Os dois saem de `--nav-gap` e nao de um
   14 escrito a mao: a barra troca a folga por 20px abaixo de 1400, e com o
   numero fixo o fio ficava a 6px do Sair e a 14px do glifo, encostado no
   vizinho errado.

   ALTURA: continua 44px, o piso de alvo que toda a barra respeita (WCAG 2.2,
   2.5.8). Diminuir o TIPO nao pode diminuir o ALVO — sao duas coisas, e so uma
   delas e o assunto aqui. */
.nav .nav_sair + a {
    font-size: var(--tipo-1); font-weight: 400;
    padding-left: calc(var(--nav-gap) / 2); margin-left: calc(var(--nav-gap) / -2);
    /* O fio NAO e `border-left` porque a borda iria de ponta a ponta dos 44px
       de alvo e leria como divisao de celula. Este gradiente desenha 20px no
       meio da altura — separador de GRUPO, que e o que ele e. Uma coluna de
       1px, sem repetir, ancorada a esquerda. */
    background:
        linear-gradient(
            to bottom,
            transparent 0 12px,
            color-mix(in srgb, var(--topo-texto) 38%, transparent) 12px calc(100% - 12px),
            transparent calc(100% - 12px) 100%
        ) left center / 1px 100% no-repeat;
}
.nav .nav_sair + a .icone { font-size: 1rem; }
/* Com o foco visivel, o anel ja e a moldura: o fio dentro dele viraria um
   risco solto entre o anel e o glifo. Some enquanto o anel existe. */
.nav .nav_sair + a:focus-visible { background: none; }

/* EMPILHADO, O FIO SAI. Quando a barra quebra, o item pode cair no COMECO de
   uma linha, e um fio vertical solto na margem esquerda nao separa nada: so
   parece sujeira. No empilhado quem separa os grupos e a propria quebra.

   O NUMERO E MEDIDO, nao chutado: varrendo 1024..1440 nos dois temas, com a
   barra mais cheia que existe hoje (staff qualificado E o curso ligado, 9
   alvos), o item nunca comeca linha acima de 1150 — o que quebra primeiro e
   o header inteiro (a marca sobe para a propria linha e o menu desce
   completo). Abaixo de 1150 ele comeca linha com frequencia. Se um dia
   nascer mais um destino na barra, refaca a varredura antes de confiar
   neste 1150. */
@media (max-width: 1150px) {
    .nav .nav_sair + a { background: none; padding-left: 0; margin-left: 0; }
}

/* O anel de foco global e --fss-acao com halo de --fundo. Sobre a barra escura
   isso da um anel vermelho de 3,75:1 (passa raspando) com halo BRANCO no tema
   claro — vermelho sobre vermelho no CTA, e um halo que vira o elemento mais
   claro da barra. Aqui o par se inverte: anel claro (16,80:1) e halo escuro. */
.topo :focus-visible { outline-color: var(--topo-texto); box-shadow: 0 0 0 2px var(--topo-fundo); }
@media (prefers-reduced-motion: no-preference) {
    .nav a, .nav_secoes a, .nav_cta {
        transition: color var(--dur-micro) ease-out, background-color var(--dur-micro) ease-out;
    }
}

/* Seletor de tema (todas as telas do portal, nao so a home).
   Nasce com [hidden] no HTML e so aparece quando o app.js roda: um controle que
   nao funciona seria pior que controle nenhum. Sem JS o tema segue o sistema,
   por prefers-color-scheme. O primeiro paint NUNCA depende deste botao — o
   atributo data-tema sai do servidor, do cookie portal_tema.

   O botao mora no header, que e escuro nos DOIS temas: as cores tem de sair da
   familia --escuro-*, nunca de --texto/--borda. Com os tokens que trocam, no
   tema claro o icone ficaria quase preto sobre quase preto — o controle
   desapareceria justamente para quem quer sair do tema claro. */
.tema_alterna {
    display: inline-flex; align-items: center; justify-content: center;
    width: 44px; height: 44px; border-radius: 50%; flex: none;
    /* 38%, e nao --escuro-borda (14%): a borda E o contorno do controle, entao
       precisa de 3:1 contra o header (WCAG 2.2, 1.4.11). 14% dava 1,48:1;
       38% da 3,35:1. */
    /* --topo-texto e nao --escuro-texto: com o header seguindo o tema
       (14/08/2026), um contorno derivado do branco fixo virava branco-sobre-
       branco no claro — o controle sumia. Derivando do texto DO HEADER, a
       proporcao de 38% continua valendo nos dois temas. */
    border: 1px solid color-mix(in srgb, var(--topo-texto) 38%, transparent);
    background: color-mix(in srgb, var(--topo-texto) 7%, transparent);
    color: var(--topo-texto);
    cursor: pointer; padding: 0;
}
.tema_alterna[hidden] { display: none; }
.tema_alterna:hover { border-color: var(--topo-suave); background: color-mix(in srgb, var(--topo-texto) 14%, transparent); }
.tema_alterna svg { width: 20px; height: 20px; }

/* O MESMO BOTAO, DENTRO DO CONTROLE DE CONTA (01/09/2026, onda 72).
 *
 * POR QUE ELE SAIU DA BARRA: era o controle menos importante com o desenho mais
 * forte — o unico circulo com borda da ponta direita, ao lado de "Conta", que e
 * texto simples e guarda perfil, administracao e a saida da sessao. O porque de
 * produto (e a conta dos 64px que a mudanca devolveu a barra) esta no _theme.php.
 *
 * AQUI ELE DEIXA DE SER PILULA E VIRA LINHA, igual as ancoras vizinhas: dentro
 * do painel o que ordena e a lista, e um circulo no meio dela seria de novo o
 * item mais gritado — o defeito mudaria de lugar, nao sumiria.
 *
 * TROCA A FAMILIA DE COR JUNTO COM O LUGAR. `.tema_alterna` deriva de
 * `--topo-texto` porque o header e escuro nos dois temas; o painel da conta cai
 * sobre a PAGINA e usa `--texto`/`--superficie`. Herdar a tinta do topo aqui
 * daria texto quase branco sobre superficie clara.
 *
 * O `[hidden]` E REDECLARADO DE PROPOSITO: `.tema_alterna[hidden]` tem a mesma
 * especificidade (0,2,0) do seletor base deste bloco, e quem viesse depois no
 * arquivo venceria. Sem esta linha, um dia de reordenacao faria o botao aparecer
 * SEM JavaScript — visivel e inerte, que e pior que ausente (secao 12.4). */
.nav_conta_menu .tema_alterna_item {
    display: flex; align-items: center; justify-content: flex-start; gap: 10px;
    width: 100%; height: auto; min-height: 44px;
    padding: 0 12px; border: 0; border-radius: var(--raio-p, 8px);
    background: none; color: var(--texto);
    font-family: inherit; font-size: var(--tipo-2); font-weight: 500;
    text-align: left;
}
.nav_conta_menu .tema_alterna_item[hidden] { display: none; }
.nav_conta_menu .tema_alterna_item:hover { background: var(--painel); border-color: transparent; }
.nav_conta_menu .tema_alterna_item:focus-visible { outline-offset: -3px; }
.nav_conta_menu .tema_alterna_item svg { width: 20px; height: 20px; flex: none; }
/* Sem cookie o icone e o de "automatico"; com cookie, o do tema em vigor. */
.icone_sol, .icone_lua { display: none; }
[data-tema="escuro"] .icone_lua { display: block; }
[data-tema="escuro"] .icone_auto { display: none; }
[data-tema="claro"] .icone_sol { display: block; }
[data-tema="claro"] .icone_auto { display: none; }

/* --- conteudo --- */
main { padding-block: var(--secao) 56px; }
h1 { font-size: var(--tipo-6); line-height: 1.15; margin: 0 0 12px; letter-spacing: -.02em; }
h2 { font-size: var(--tipo-4); margin: 0 0 12px; letter-spacing: -.01em; }
h3 { font-size: var(--tipo-3); margin: 0 0 8px; }
p { margin: 0 0 12px; }
.sub { color: var(--texto-suave); font-size: var(--tipo-3); max-width: 62ch; }
.miudo { font-size: var(--tipo-1); color: var(--texto-suave); }

.card {
    background: var(--superficie-alta);
    border: 1px solid var(--borda);
    border-radius: var(--raio);
    padding: 24px;
    box-shadow: var(--sombra);
}
.grid { display: grid; gap: var(--gap); }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.pilha > * + * { margin-top: var(--gap); }
.secao { margin-top: var(--secao); }

/* --- botoes ---
   TRES DEGRAUS, E A ESCADA E DE SUBTRACAO (direcao B, 20/08/2026).

   O DEFEITO: existiam tres desenhos de botao e NENHUMA hierarquia declarada
   entre eles. `.btn` e `.btn_sec` tinham a mesma altura, o mesmo padding, o
   mesmo brilho de varredura no hover — a unica diferenca era o preenchimento,
   e `.ligacao` era outra especie inteira (texto sublinhado). Tres pesos iguais
   e uma especie solta: a tela nao dizia o que fazer.

   A ESCADA. Cada degrau perde EXATAMENTE UMA camada do anterior, e a perda e
   visivel sem depender de cor:

     1. PRIMARIO  (.btn)      caixa cheia + brilho + varredura no hover.
                              Peso 700. UM por regiao da tela.
     2. SECUNDARIO(.btn_sec)  perde o preenchimento, o brilho e a varredura;
                              fica a MESMA caixa, so que vazada. Peso 600.
                              Mesma altura do primario de proposito: ele e a
                              ALTERNATIVA a acao principal, e alternativa que
                              vem num alvo menor nao e alternativa.
     3. TERCIARIO (.ligacao)  perde tambem a borda. Em repouso nao ha caixa
                              nenhuma; ela aparece no hover e no foco. Peso 600,
                              altura 44px — o piso de alvo (WCAG 2.5.8), nao o
                              teto: e a terceira escolha.

   POR QUE O TERCIARIO NAO E SUBLINHADO. Ele era, e a folha de prova da direcao
   B propunha o contrario — transforma-lo numa copia do secundario, para acabar
   com a terceira variante. As duas saidas foram recusadas, pelo mesmo motivo:

     - sublinhado e o sinal de LINK DENTRO DE TEXTO CORRIDO neste portal (ver
       `.pagina-app main a:not(...)`), e `.ligacao` renderiza uma PERGUNTA
       INTEIRA por linha, numa lista de pendencias. Sublinhar trinta frases
       pinta a lista de riscos — o argumento ja escrito, e aceito, em
       `.link_bloco`;
     - vira-lo em `.btn_sec` apagaria o terceiro degrau em vez de hierarquiza-lo,
       e o pedido era dar hierarquia, nao reduzir a duas.

   O que carrega a afordancia em repouso: cada `.ligacao` ocupa a linha inteira
   de um <li> com separador, sob um paragrafo que diz "Toque para responder",
   e e um <button> de verdade (o leitor de tela anuncia "botao"). No hover e no
   foco a caixa aparece. */
.btn {
    display: inline-flex; align-items: center; justify-content: center;
    border: 0; cursor: pointer; font: inherit; font-weight: 700;
    min-height: 44px; padding: 12px 22px; border-radius: var(--pilula);
    text-decoration: none; text-align: center;
    background: var(--fss-acao); color: #fff;
}
.btn:hover { background: var(--fss-acao-hover); }
.btn[disabled] { opacity: var(--opacidade-desabilitado); cursor: not-allowed; }

/* ENVIO EM ANDAMENTO. Sem opacidade de proposito: botao ocupado nao e botao
   desabilitado e continua tendo de passar em contraste AA. O sinal e o disco
   girando mais o cursor — e o rotulo, que o app.js troca.
   Sob prefers-reduced-motion a regra global la de cima congela a rotacao e
   sobra um anel parado: sinal sem movimento, que continua sendo sinal. */
.btn[data-pendente] { cursor: progress; }
.btn[data-pendente]::before {
    content: ""; width: 1em; height: 1em; margin-right: .5em; flex: none;
    border-radius: 50%; border: 2px solid currentColor; border-top-color: transparent;
    animation: btn_gira 700ms linear infinite;
}
@keyframes btn_gira { to { transform: rotate(1turn); } }
/* Degrau 2: a mesma caixa, vazada. Um ponto de peso abaixo do primario. */
.btn_sec { background: transparent; color: var(--texto); border: 1px solid var(--borda); font-weight: 600; }
.btn_sec:hover { background: var(--superficie); }
.btn_sec[disabled]:hover { background: transparent; }

/* Degrau 3: sem caixa em repouso. A caixa e o feedback, nao o repouso.
   `width: 100%` porque ele e a linha inteira de um <li>: o alvo e a linha, e
   nao as primeiras palavras dela (WCAG 2.5.8). */
.ligacao {
    display: inline-flex; align-items: center; width: 100%; min-height: 44px;
    background: none; border: 0; padding: 10px 12px; font: inherit; font-weight: 600;
    border-radius: var(--raio-p);
    color: var(--texto); text-decoration: none; text-align: left; cursor: pointer;
}
.ligacao:hover { background: var(--preenchimento); color: var(--texto); }

/* --- formularios --- */
.campo { margin-bottom: var(--gap); }
.campo label { display: block; font-size: var(--tipo-2); font-weight: 600; margin-bottom: 6px; }
.campo .dica { font-size: var(--tipo-1); color: var(--texto-suave); margin: 4px 0 0; }
input[type=text], input[type=email], input[type=password], input[type=number], input[type=tel], select {
    width: 100%; padding: 11px 13px; font: inherit; color: var(--texto);
    background: var(--fundo); border: 1px solid var(--borda); border-radius: var(--raio-p);
}
input:focus, select:focus { border-color: var(--fss-acao); }
input, select, textarea { accent-color: var(--fss-acao); }
input[type=text], input[type=email], input[type=password], input[type=number], input[type=tel], select { min-height: 44px; }
/* Campo com erro nao se distingue so pela cor: ganha barra lateral e peso. */
[aria-invalid="true"] { border-color: var(--erro) !important; box-shadow: inset 3px 0 0 var(--erro); }
/* Mensagem adjacente ao campo, ligada a ele por aria-describedby. O prefixo
   textual existe pelo mesmo motivo do flash: cor nao pode ser o unico
   portador de significado (WCAG 1.4.1). */
.field-error { font-size: var(--tipo-1); font-weight: 600; color: var(--erro); margin: 6px 0 0; }
.field-error::before { content: "Erro: "; }

.check { display: flex; gap: 10px; align-items: flex-start; font-size: var(--tipo-2); min-height: 44px; padding: 6px 0; cursor: pointer; }
/* A CAIXA DE ACEITE ERA O UNICO CONTROLE SEM DESENHO.

   Nativa, ela sai do sistema operacional: um quadrado cinza claro que nao
   acompanha nem o raio, nem a borda, nem a cor de foco de nenhum outro campo do
   formulario — e ela fica exatamente entre o campo de senha e o botao
   principal, que sao os dois mais desenhados da tela.

   `appearance: none` desliga o desenho nativo e NAO desliga nada mais: o
   elemento continua sendo um <input type="checkbox">, com o estado, o rotulo
   ligado pelo <label>, o teclado e o leitor de tela intactos. O visto e um
   pseudo-elemento, entao nao ha SVG novo nem markup a manter.

   44px de alvo continuam vindo do .check ao redor (padding + min-height): a
   caixa desenhada tem 20px, mas o clique vale na linha inteira. */
.check input {
    appearance: none;
    flex: none;
    margin-top: 3px;
    width: 20px; height: 20px;
    /* 1.4.11 (onda 51): com --contorno (26% de --texto) a caixa media 1,79:1
       no claro e 2,22:1 no escuro contra o cartao — e ela e o unico sinal de
       que existe um controle ali, porque o estado VAZIO nao tem visto nem
       preenchimento. --borda-controle e o token de fronteira de controle. */
    border: 1.5px solid var(--borda-controle);
    border-radius: 6px;
    background: var(--fundo);
    display: grid;
    place-content: center;
    cursor: pointer;
}
.check input::before {
    content: "";
    width: 10px; height: 10px;
    transform: scale(0);
    transform-origin: center;
    /* O visto desenhado em clip-path: sem fonte, sem imagem, sem depender de um
       glifo que pode nao existir na maquina de quem le. */
    clip-path: polygon(14% 44%, 0 60%, 39% 100%, 100% 16%, 84% 0, 39% 68%);
    background: var(--fss-contraste, #fff);
}
.check input:checked {
    background: var(--fss);
    border-color: var(--fss);
}
.check input:checked::before { transform: scale(1); }
.check input:focus-visible {
    outline: 3px solid var(--fss);
    outline-offset: 3px;
}

/* --- icones ---
   Um glifo desenhado em themes/portal/_icones.php, nunca solto num template.
   Dimensao em `em` de proposito: o icone acompanha o tipo do bloco onde entra e
   NAO empurra a altura de botao nenhum (os alvos de 44px continuam vindo do
   min-height, nao do conteudo). `currentColor` no traco resolve tema claro,
   escuro e header escuro fixo sem uma regra por contexto.
   `vertical-align` alinha o glifo ao texto ao lado — a disciplina do sistema e
   que icone SEMPRE acompanha palavra. */
.icone { width: 1.1em; height: 1.1em; vertical-align: -.2em; flex: none; }
.icone_g { width: 1.35em; height: 1.35em; vertical-align: -.28em; }

/* RF06: o par perda x potencial carrega a distincao na FORMA (vazamento contra
   linha de tendencia). A cor entra so como reforco, e e a mesma do numero logo
   abaixo (.valor_perda / .valor_potencial, .grandeza_perda / .grandeza_pot) —
   nao como portador solitario de significado. */
.icone_perda { color: var(--erro); }
.icone_potencial { color: var(--sucesso); }

/* --- mensagens ---
   .message e a classe emitida por App\Support\Message (o flash); .msg e a
   usada pelos templates. As duas compartilham o mesmo tratamento — sem isto o
   flash sairia sem estilo nenhum.
   O par glifo + prefixo ("Erro:", "Atencao:") vem do MARKUP (estado_msg() em
   _icones.php), nao de `content:` de CSS: texto gerado por CSS some quando a
   folha nao carrega e nao pode ficar depois do glifo. Forma + texto + cor —
   nunca cor sozinha (WCAG 1.4.1). */
.msg, .message { padding: 12px 16px; border-radius: var(--raio-p); margin: 0 0 var(--gap); border: 1px solid transparent; border-left-width: 4px; }
.msg.success, .message.success { background: color-mix(in srgb, var(--sucesso) 12%, transparent); border-color: var(--sucesso); }
.msg.warning, .message.warning { background: color-mix(in srgb, var(--alerta) 12%, transparent); border-color: var(--alerta); }
.msg.error, .message.error     { background: color-mix(in srgb, var(--erro) 12%, transparent); border-color: var(--erro); }
.msg.info, .message.info       { background: var(--superficie); border-color: var(--borda); }
.msg > .icone, .message > .icone { margin-right: 7px; }
.msg_rotulo { font-weight: 700; }
.msg.success .icone, .message.success .icone { color: var(--sucesso); }
.msg.warning .icone, .message.warning .icone { color: var(--alerta); }
.msg.error .icone, .message.error .icone { color: var(--erro); }
.wrap > .msg { margin-top: var(--gap); }
.flash { margin-top: var(--gap); }

/* --- toast ---
   O componente inteiro (regras, keyframes e o token --toast-dur, que E o
   cronometro do auto-fecho) mora em public/assets/comum/toast.css, importado no
   topo deste arquivo e tambem pelo bundle do painel administrativo. A ponte de
   tema — os `--toast-*` apontando para a paleta do portal — esta no :root la em
   cima. Nao ha regra de toast neste arquivo de proposito: duas copias divergem
   no primeiro conserto feito de um lado so. */

/* --- score ---
   `.score` e `.faixa` moravam aqui e nenhuma tela os usava desde a direcao D:
   quem desenha o score e `.anel_score`, e quem desenha a faixa e
   `.rel_selo_faixa`. Duas casas para a mesma decisao foi exatamente o que
   deixou o chip vermelho para tras. As regras mortas sairam em 18/08/2026; a
   decisao continua inteira nos tres tokens do :root, agora consumidos pelos
   componentes vivos. */

.barra { height: 8px; border-radius: 999px; background: var(--superficie); overflow: hidden; }
.barra > i { display: block; height: 100%; background: var(--fss); border-radius: 999px; }

/* --- dinheiro ---
   As duas grandezas usam tratamento visual DIFERENTE de proposito: perda atual
   e potencial futuro nunca podem parecer parcelas de uma mesma soma (RF06). */
.valor { font-family: var(--mono); font-size: var(--tipo-5); font-weight: 700; letter-spacing: -.02em; }
.valor_perda { color: var(--erro); }
.valor_potencial { color: var(--sucesso); }
.rotulo { font-size: var(--tipo-1); font-weight: 700; text-transform: uppercase; letter-spacing: .07em; color: var(--texto-suave); }

/* --- gates --- */
.gate { display: flex; align-items: center; gap: 10px; padding: 11px 0; border-bottom: 1px solid var(--borda); }
.gate:last-child { border-bottom: 0; }
.gate_ok, .gate_nao { font-weight: 800; width: 22px; text-align: center; }
.gate_ok { color: var(--sucesso); }
.gate_nao { color: var(--erro); }

/* --- diagnostico --- */
.progresso { position: sticky; top: 0; z-index: 10; background: var(--fundo); padding: 14px 0; border-bottom: 1px solid var(--borda); }
.contador { font-size: var(--tipo-3); }
.contador_sec { font-weight: 400; font-size: var(--tipo-1); color: var(--texto-suave); }
/* O reset do <fieldset> (border/padding/margin do agente de usuario) mora aqui
   desde 13/08/2026. Antes era `style` inline no template — e por ser inline
   vencia esta propria regra, deixando `padding` e `border-bottom` mortos: sem
   JS, as 30 perguntas sairam ate hoje sem nenhum separador entre elas. Com o
   reset na folha, a regra abaixo passa a valer como sempre foi escrita, e
   `.js-etapas .pergunta` (mais especifica) continua zerando o separador no
   modo de uma pergunta por tela. */
.pergunta { border: 0; margin: 0; padding: 20px 0; border-bottom: 1px solid var(--borda); }
.pergunta:last-of-type { border-bottom: 0; }
.pergunta_titulo { font-weight: 600; margin-bottom: 12px; font-size: var(--tipo-4); line-height: 1.35; }

/* O TITULO DA PERGUNTA RECEBE FOCO, E NAO MOSTRA ANEL — e as duas metades sao
   necessarias.

   O foco existe para o leitor de tela: ao trocar de passo, `app.js` faz
   `legend.focus()`, e e isso que faz a pergunta nova ser ANUNCIADA. Sem ele,
   quem usa leitor ouviria silencio e continuaria no contexto antigo.

   O anel nao: `tabindex="-1"` significa "alvo de foco por script, nunca por
   Tab". Ninguem chega aqui de proposito, entao o anel nao esta confirmando o
   gesto de ninguem — e, desde que o clique passou a avancar sozinho, ele
   piscava uma moldura vermelha em volta do enunciado a CADA resposta. Os aneis
   que importam continuam nos controles de verdade (opcoes e botoes), que sao os
   alcancaveis por teclado. */
.pergunta_titulo:focus,
.pergunta_titulo:focus-visible { outline: none; box-shadow: none; }

.opcoes { display: grid; gap: 8px; }
/* O label envolve a linha inteira: o alvo de toque e a opcao toda, com no
   minimo 44px de altura (WCAG 2.2, 2.5.8). */
.opcao { display: flex; gap: 12px; align-items: center; min-height: 44px; padding: 12px 14px; border: 1px solid var(--borda); border-radius: var(--raio-p); cursor: pointer; }
.opcao input { width: 20px; height: 20px; flex: none; }
.opcao:hover { background: var(--superficie); }
.opcao input:checked ~ span { font-weight: 700; }
/* Selecionado nao depende so de cor: ganha anel de 2px (via box-shadow, que
   nao desloca o layout) e o peso do texto acima. */
.opcao:has(input:checked) { border-color: var(--fss-acao); background: color-mix(in srgb, var(--fss) 7%, transparent); box-shadow: inset 0 0 0 2px var(--fss-acao); }
/* O radio e pequeno demais para carregar o foco sozinho: a linha inteira o
   mostra. */
.opcao:has(input:focus-visible) { outline: 3px solid var(--fss-acao); outline-offset: 2px; }
.opcao input:focus-visible { outline: none; box-shadow: none; }

/* --- etapas (so existe com JS; .js-etapas e .js-etapas-pagina sao
   adicionadas por app.js — sem JS nada aqui se aplica) --- */
.js-etapas [hidden] { display: none !important; }
.js-etapas-pagina h1 { font-size: var(--tipo-4); margin: 4px 0 8px; letter-spacing: -.01em; }
.js-etapas-pagina .progresso { padding: 10px 0; }
/* Secao 12.6: em modo etapa a pergunta tem de caber na PRIMEIRA tela do
   celular. Tudo o que vem antes dela encolhe — cabecalho da pagina, titulo e a
   introducao que explica o autosave (que so aparece na etapa 1 de qualquer
   forma). Nada aqui esconde pergunta: a unica regra de ocultacao continua
   sendo `.js-etapas [hidden]`, acima. Medido em 13/08/2026 a 320x568.

   `.pagina-app` entra no seletor de algumas regras abaixo so para vencer, por
   especificidade, as regras de superficie da direcao D — que aparecem depois
   neste arquivo.

   CORRIGIDO EM 14/08/2026: este comentario estava FECHADO na linha acima e o
   paragrafo seguinte ficava solto no meio da folha. O parser entao engolia o
   texto solto como se fosse seletor ate a proxima chave — e levava junto a
   regra `.js-etapas-pagina .diag_titulo`, que nunca chegou a valer. */
.js-etapas-pagina .diag_titulo { margin-top: 12px; }
.pagina-app.js-etapas-pagina [data-intro] { font-size: var(--tipo-2); line-height: 1.5; margin: 8px 0 0; max-width: 60ch; }
.pagina-app.js-etapas-pagina .card { padding: 16px; }
.pagina-app.js-etapas-pagina main { padding-top: 12px; }
.js-etapas-pagina .progresso_linha { gap: 2px 10px; line-height: 1.35; }
.js-etapas .pergunta { border-bottom: 0; padding: 4px 0 0; }
/* --- a navegacao do passo a passo ------------------------------------------
   OS DOIS BOTOES ERAM DO MESMO TAMANHO E DO MESMO PESO, cada um ocupando metade
   da largura — "Anterior" com a mesma massa de "Proxima", e o vermelho da marca
   no pe da tela competindo com as cinco opcoes que sao, de fato, a acao da
   pergunta.

   Agora eles tem tamanho de BOTAO e nao de faixa, e a direcao aparece no glifo:
   seta para tras a esquerda, seta para frente a direita, com o vao no meio
   (margin-left: auto) separando voltar de seguir. Um do lado do outro, do mesmo
   tamanho, os dois eram alvos de 50% de largura para acoes opostas — e errar o
   lado custava uma pergunta. */
.etapas_nav {
    display: flex; align-items: center; gap: 12px;
    margin-top: var(--gap); padding-top: var(--esp-4);
    border-top: 1px solid var(--borda);
}
.etapas_nav .btn { flex: none; }
.etapas_seguir { margin-left: auto; }

/* O texto num <span> proprio (ver `botao()` no app.js): sem ele, trocar o
   rotulo para "Revisar" apagaria a seta junto. */
.btn_rotulo { display: inline-block; }
.etapas_nav .btn .icone { flex: none; width: 17px; height: 17px; }
.etapas_voltar .icone { margin-right: 8px; }
.etapas_seguir .icone { margin-left: 8px; }


/* NAVEGACAO NAO E A ACAO DA TELA. No /app o botao mede 56px e usa --tipo-3
   porque quase sempre ele E o que a pessoa veio fazer. Aqui nao: a acao da
   pergunta e escolher uma das cinco opcoes, e um par de botoes daquele tamanho
   no pe da tela pesava mais que a propria pergunta. Um degrau abaixo. */
.pagina-app .etapas_nav .btn {
    min-height: 48px; padding: 12px 22px; font-size: var(--tipo-2);
}

/* DESABILITADO NA PRIMEIRA PERGUNTA, e visivelmente — nao apagado. Um botao
   que some faz a barra inteira pular de lugar entre a pergunta 1 e a 2. */
.etapas_nav .btn:disabled { opacity: .38; cursor: not-allowed; }
.etapas_nav .btn:disabled:hover { background: transparent; color: var(--texto-suave); }
.pendentes { list-style: none; margin: 0 0 var(--gap); padding: 0; }
.pendentes li { border-bottom: 1px solid var(--borda); }

@keyframes etapa_entra { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* Motion opt-in: a entrada animada so roda quando o usuario nao pediu menos
   movimento. O bloco reduce abaixo continua como cinto de seguranca para
   transitions eventuais. */
@media (prefers-reduced-motion: no-preference) {
    .js-etapas .pergunta { animation: etapa_entra var(--dur-entrada) var(--curva) both; }
}

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

.estado { font-size: var(--tipo-1); color: var(--texto-suave); min-height: 20px; }
.estado[data-estado="salvo"] { color: var(--sucesso); }
.estado[data-estado="erro"] { color: var(--erro); }
/* Pendente NAO e erro: a resposta existe e vai subir sozinha. Cor de alerta,
   e nao a vermelha, porque nada se perdeu enquanto a aba estiver aberta. */
.estado[data-estado="pendente"] { color: var(--alerta); }

/* --- tabela --- */
table { width: 100%; border-collapse: collapse; font-size: var(--tipo-2); }
th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--borda); }
th { font-size: var(--tipo-1); text-transform: uppercase; letter-spacing: .06em; color: var(--texto-suave); }
td.num, th.num { text-align: right; font-family: var(--mono); }
/* REGIAO ROLAVEL ALCANCAVEL POR TECLADO (WCAG 2.1.1, corrigido em 18/08/2026).
   Uma caixa com overflow rola no mouse e na roda, mas quem navega por teclado
   so a move se ela mesma puder receber foco — sem isso, a metade direita da
   tabela de cenarios simplesmente nao existe para quem nao usa mouse. Por isso
   o template marca `tabindex="0"` + `role="region"` + `aria-labelledby`: os
   tres andam juntos. Foco sem nome trocaria uma falha por outra — a parada de
   tabulacao apareceria anonima no leitor de tela ("group", e nada mais).
   O anel e o global (:focus-visible, secao 12.6), so que INSETADO: a regiao
   ocupa toda a largura util do cartao e um anel com offset positivo sairia
   por baixo da borda do `.tile`. -3px o desenha por dentro, sobre a propria
   area que vai rolar, que e exatamente o que precisa ser apontado. */
.rolagem { overflow-x: auto; }
.rolagem:focus-visible { outline-offset: -3px; box-shadow: none; border-radius: var(--raio-p); }

/* =============================================================================
   --- home --- (direcao D, aprovada pelo dono em 12/08/2026)
   -----------------------------------------------------------------------------
   TUDO aqui esta escopado em `.pagina-home` (classe do <body>, posta pelo
   template). Nenhuma regra vaza para cadastro/diagnostico/resultado, mesmo
   reusando nomes compartilhados (.btn, .topo, .secao, .rodape). Para promover
   esta linguagem ao portal inteiro depois, e so remover o escopo — nao ha
   nada aqui que dependa de ser "so a home".

   Nenhum valor cru: cor, raio, sombra, glow e duracao saem dos tokens do
   bloco "TOKENS DA DIRECAO VISUAL" no topo do arquivo.

   Ordem: chrome -> cena -> marquee -> topo -> hero -> peca -> bento ->
          trilho -> transparencia -> depoimentos -> FAQ -> fecho -> rodape ->
          barra flutuante -> motion.
   ============================================================================= */

/* --- home: chrome compartilhado ------------------------------------------- */
.pagina-home {
    font-size: var(--tipo-3);
    line-height: 1.7;
    color: var(--texto-suave);
    overflow-x: clip;
    transition: background-color var(--dur-tema) ease-out, color var(--dur-tema) ease-out;
}
.pagina-home h1, .pagina-home h2, .pagina-home h3,
.pagina-app h1, .pagina-app h2, .pagina-app h3 { color: var(--texto); }
.pagina-home strong,
.pagina-app strong { color: var(--texto); }
.pagina-home main { padding-block: 0; }
.pagina-home .wrap { width: min(1180px, 92vw); }
.pagina-home .secao { margin-top: 0; padding-top: clamp(76px, 10vw, 140px); }
.pagina-home .secao_head h2,
.pagina-app .secao_head h2 { margin: 12px 0 0; font-weight: 900; letter-spacing: -.035em; line-height: 1.05; max-width: 22ch; }
/* A GEOMETRIA E A MESMA NOS DOIS; A ESCALA, NAO (direcao B, 20/08/2026).

   A home vende: o cabecalho de secao dela e display, e 30->46px e o tamanho
   que abre uma pagina de venda. O /app e leitura — o assunto da tela e o
   relatorio, e um titulo de 46px anunciando a secao pesava mais do que o dado
   que ela contem. --tipo-5 (24->27px) e o degrau de SECAO da escala do portal:
   maior que qualquer titulo de cartao (--tipo-4), menor que a capa (--tipo-6).

   E o que faz a escala existir: com estes dois clamps proprios, o /app tinha
   um tamanho que nao pertencia a nenhum degrau. */
.pagina-home .secao_head h2 { font-size: var(--tipo-7); }
.pagina-app .secao_head h2 { font-size: var(--tipo-5); }

/* Rotulo curto acima do titulo. Vermelho so onde ha racional de contraste
   (--fss-texto ja e o token medido para texto pequeno nos dois temas). */
.pagina-home .caps,
.pagina-app .caps { font-size: var(--tipo-1); font-weight: 800; text-transform: uppercase; letter-spacing: .16em; color: var(--fss-texto); }

/* Botoes: mesmos nomes de classe do resto do portal (app.js injeta .btn/.btn_sec
   no diagnostico) — aqui eles so ficam maiores e ganham o brilho da marca. */
.pagina-home .btn,
.pagina-app .btn {
    position: relative; overflow: hidden;
    gap: 10px; font-weight: 700; font-size: var(--tipo-3);
    min-height: 56px; padding: 15px 30px; border-radius: var(--pilula);
    box-shadow: var(--glow-acao);
}
.pagina-home .btn::after,
.pagina-app .btn::after {
    content: ""; position: absolute; inset: 0; pointer-events: none;
    background: linear-gradient(115deg, transparent 32%, rgba(255, 255, 255, .32) 50%, transparent 68%);
    transform: translateX(-130%);
}
/* O SECUNDARIO NAO VARRE (direcao B, 20/08/2026).
   Ele tinha o proprio brilho de varredura, em --preenchimento: o gesto do
   primario, repetido mais fraco. Dois botoes que fazem a MESMA coisa no hover,
   com intensidades diferentes, nao formam hierarquia — formam ruido. O gesto
   agora e exclusivo do degrau 1, e o degrau 2 responde com superficie e borda,
   que e o que ele tem.
   `content: none` e nao `display: none`: assim a caixa do pseudo nem chega a
   existir, e a transicao declarada la embaixo nao tem alvo para animar. */
.pagina-home .btn_sec,
.pagina-app .btn_sec { background: transparent; color: var(--texto); border: 1.5px solid var(--contorno); box-shadow: none; font-weight: 600; }
.pagina-home .btn_sec::after,
.pagina-app .btn_sec::after { content: none; }
.pagina-home .btn_sec:hover,
.pagina-app .btn_sec:hover { border-color: var(--contorno-forte); background: var(--preenchimento); }
/* O TERCEIRO DEGRAU. O sistema tinha dois — primario (tinta da marca, brilho,
   varredura) e secundario (transparente com borda) —, e o "Anterior" do passo a
   passo nao e nenhum dos dois: ele precisa estar SEMPRE disponivel, porque e ele
   que torna o avanco automatico reversivel — sem ele o recurso viraria
   armadilha —, mas nao e o que se quer que a pessoa faca. Com borda, voltava a
   parecer o par simetrico de "Proxima": dois retangulos do mesmo tamanho, lado a
   lado, para acoes opostas.

   MORA AQUI, JUNTO DOS OUTROS DOIS, e nao no bloco do passo a passo. Escrito la
   em cima ele empatava em especificidade com `.pagina-app .btn` (0,2,0) e perdia
   por ORDEM — o "fantasma" saia com o fundo da marca e o halo do primario em
   volta. Um degrau de botao se define onde os degraus se definem; foi a
   distancia entre os dois lugares que produziu o defeito. */
.pagina-home .btn_fantasma,
.pagina-app .btn_fantasma {
    background: transparent; color: var(--texto-suave);
    border: 1px solid transparent; box-shadow: none; font-weight: 600;
}
/* Sem varredura, pelo mesmo motivo do secundario: o gesto e exclusivo do 1. */
.pagina-home .btn_fantasma::after,
.pagina-app .btn_fantasma::after { content: none; }
.pagina-home .btn_fantasma:hover,
.pagina-app .btn_fantasma:hover { background: var(--preenchimento); color: var(--texto); }
.pagina-home .acoes,
.pagina-app .acoes { display: flex; flex-wrap: wrap; gap: 14px; margin: 34px 0 0; }

/* --- home: cena de fundo ---
   Camadas decorativas (aria-hidden), fixas atras de tudo. A mesma cena nos dois
   temas; o que muda e o VOLUME, por --cena-intensidade/--cena-ruido.
   contain: isola as camadas gigantes do calculo de viewport ideal do modo
   movel — sem isto, a emulacao de 320px alarga a viewport para ~343px. */
.cena { position: fixed; inset: 0; z-index: -3; overflow: hidden; background: var(--fundo); contain: layout paint; }
.cena_glow {
    position: absolute; inset: -20vmax; opacity: var(--cena-intensidade);
    background:
        radial-gradient(46vmax 40vmax at 16% 6%, var(--cena-glow-1), transparent 62%),
        radial-gradient(54vmax 46vmax at 92% 28%, var(--cena-glow-2), transparent 66%),
        radial-gradient(60vmax 50vmax at 40% 108%, var(--cena-glow-3), transparent 68%);
}
.cena_frio { position: absolute; inset: -20vmax; background: radial-gradient(58vmax 48vmax at 74% 62%, var(--cena-frio), transparent 70%); }
/* As formas da cena sao decoracao numa camada FIXA atras de tudo, mas 34px era
   um numero solto como qualquer outro. Lendo --raio-app elas entram no mesmo
   vocabulario; em quadrados de 20 a 46vmax a diferenca entre 34 e 16 nao chega
   ao olho (conferido nas capturas de depois), e some de vez o unico raio da
   home que nao tinha de onde vir. */
.cena_forma { position: absolute; border: 1.5px solid var(--cena-forma); border-radius: var(--raio-app); }
.cena_forma.a { width: 46vmax; height: 46vmax; top: -18vmax; right: -14vmax; transform: rotate(38deg); }
.cena_forma.b { width: 30vmax; height: 30vmax; bottom: -12vmax; left: -10vmax; transform: rotate(20deg); border-color: var(--borda-marca); }
.cena_forma.c { width: 20vmax; height: 20vmax; top: 46%; left: 62%; transform: rotate(45deg); }

/* ===========================================================================
   A MARCA NA CENA — colar logo depois de `.cena_forma.c` (linha ~1738)
   ===========================================================================

   O documento de identidade pede a marca d'agua do simbolo no fundo. Ela existe
   no painel desde a onda 76 e nunca existiu no portal — faltava justamente na
   tela que o LEAD ve.

   E UMA `.cena_forma`, E NAO UMA CAMADA NOVA. As formas a/b/c ja sao a peca
   "silhueta de fundo" desta cena: mesmo lugar no empilhamento, mesma cor
   (--cena-forma), mesmo parcial decidindo quais desenhar. Uma camada nova
   precisaria repetir o `overflow: hidden`, o `z-index: -3` e o `aria-hidden`
   que a `.cena` ja resolve, e brigaria com eles no primeiro ajuste.

   ---------------------------------------------------------------------------
   MASCARA, E NAO IMAGEM — a decisao que muda o resultado
   ---------------------------------------------------------------------------

   `logo.png` e VERMELHO. Desenhado como imagem a 7% sobre o cinza-azulado do
   fundo, ele nao vira cinza claro: vira um rosa sujo, uma cor que o brandbook
   nao tem e que ninguem escolheu.

   A mascara usa so o canal alfa do arquivo e deixa a COR aqui — `--cena-forma`,
   que ja e `color-mix(in srgb, var(--texto) 7%, transparent)`. Duas
   consequencias: a marca fica neutra como na referencia do dono, e acompanha o
   tema escuro SEM uma segunda regra, porque `--texto` ja acompanha. Medido:
   navy a 7% no claro, quase-branco a 7% no escuro.

   `border: 0` desfaz o contorno que `.cena_forma` aplica a todas — aqui o
   desenho E o preenchimento, e um contorno em volta de uma silhueta mascarada
   sai como um retangulo fantasma.

   ---------------------------------------------------------------------------
   POR QUE ELA SANGRA PELA BORDA
   ---------------------------------------------------------------------------

   Um simbolo inteiro e centralizado le como LOGO, e logo no fundo compete com o
   conteudo. Cortado pela borda, le como textura — que e o papel que o documento
   lhe da, e a mesma razao pela qual a marca do painel fica com metade fora da
   barra lateral.

   ---------------------------------------------------------------------------
   O QUE FOI MEDIDO ANTES DE ENTREGAR
   ---------------------------------------------------------------------------

   - contraste do texto do corpo sobre o fundo composto: 5,68:1 (piso AA 4,5);
   - a `.cena` esta em `z-index: -3`, ATRAS do cartao de cadastro: a marca nunca
     aparece atraves dele, entao nao convive com o foco/hover/entrada que a
     onda 81 acrescentou naquela tela;
   - fora da `.cena` — testado num `body::before` — ela passa POR CIMA do fundo
     branco do rodape. Dentro, nao. E por isso que ela e uma forma da cena.
   ========================================================================== */

.cena_forma.marca {
    border: 0;
    width: min(880px, 68vmax);
    aspect-ratio: 1;
    top: -14vmax;
    left: -12vmax;

    background: var(--cena-forma);
    -webkit-mask: url("../../logo.png") no-repeat center / contain;
    mask: url("../../logo.png") no-repeat center / contain;
}

/* NO TELEFONE ELA SAI, e nao encolhe: a 400px a silhueta ocuparia metade da
   area util competindo com o conteudo, e textura de fundo e um luxo de tela
   larga. */
@media (max-width: 720px) {
    .cena_forma.marca { display: none; }
}

/* A MARCA OBEDECE AO VOLUME DA CENA — e ela e a unica forma que precisa disso.
 *
 * `--cena-intensidade` e aplicada como `opacity` em `.cena_glow` e no ruido, e
 * NAO alcanca `.cena_forma`: os quadrados em contorno sao finos o bastante para
 * conviverem com qualquer tela. Medido ao ligar a marca em todas as telas a
 * pedido do dono (02/09/2026).
 *
 * A marca e outra coisa: uma silhueta preenchida de 880px. Na tela de aula, com
 * video rodando, ela na intensidade cheia disputa o unico elemento que importa
 * ali. Entao ela — e so ela — acompanha o volume, pelo mesmo mecanismo que o
 * resto da cena ja usa.
 *
 * NAO E UMA EXCECAO A DECISAO DO DONO: a marca esta em TODAS as telas, como ele
 * pediu. O que muda e o volume, que e exatamente a distincao que
 * `.cena_discreta` existe para expressar — "o usuario esta trabalhando, nao
 * sendo apresentado ao produto".
 */
.cena_discreta .cena_forma.marca { opacity: .45; }
.pagina-app .cena_forma.marca { opacity: .6; }
.cena_ruido { position: absolute; inset: 0; background-image: var(--ruido); mix-blend-mode: overlay; opacity: var(--cena-ruido); }

/* NO TEMA ESCURO A MARCA CLAREIA O CHAO, e a margem de contraste some.
 *
 * `--cena-forma` e `color-mix(var(--texto) 7%)`. No claro isso e um navy sobre
 * um chao claro — escurece pouco. No escuro e um quase-branco sobre um chao
 * quase preto, e 7% de branco levanta muito mais do que 7% de navy abaixa.
 *
 * MEDIDO na coluna esquerda de `acesso.php`, no PIOR pixel sob o texto (com o
 * texto escondido para nao medir antisserrilhado):
 *
 *   escuro  sem marca   fundo [13,13,20]   paragrafo 5,29:1
 *   escuro  com marca   fundo [30,30,37]   paragrafo 4,53:1   <- piso e 4,50
 *   claro   com marca   fundo [225,228,232] paragrafo 5,99:1
 *
 * TRES CENTESIMOS ACIMA DO PISO NAO E MARGEM. Passa nesta fonte, neste
 * navegador, com este texto — e reprova se qualquer um dos tres mudar. Um
 * ajuste de copy na frase, um degrau de tipo no celular, ou uma renderizacao
 * diferente derrubam abaixo de AA sem ninguem tocar no fundo.
 *
 * A .72 o paragrafo volta a 4,82:1 e a marca continua 72% presente — no escuro
 * ela e mais visivel que no claro de qualquer forma, porque silhueta clara
 * sobre chao escuro le mais que o inverso.
 *
 * NAO E DECISAO DE GOSTO: presenca da marca e decisao do dono e continua em
 * todas as telas. Piso de contraste e obrigacao, e este numero e o que o mantem.
 */
[data-tema="escuro"] .cena_forma.marca { opacity: .72; }

@media (prefers-color-scheme: dark) {
    :root:not([data-tema="claro"]) .cena_forma.marca { opacity: .72; }
}

/* As duas regras de volume ja existentes continuam valendo e se multiplicam com
   esta: no escuro, uma tela discreta fica em .72 x .45. E o desfecho certo — e
   onde a pessoa trabalha, com o chao mais claro, que a margem era menor. */
[data-tema="escuro"] .cena_discreta .cena_forma.marca { opacity: .32; }
[data-tema="escuro"] .pagina-app .cena_forma.marca { opacity: .43; }

/* O MESMO PAR SOB O TEMA DO SISTEMA (acrescentado ao colar).
   O tema tem TRES estados: `data-tema` escuro, `data-tema` claro, e NENHUM —
   que e o padrao e cai em `prefers-color-scheme`. Sem este bloco, quem usa o
   sistema no escuro SEM ter escolhido tema recebia o .72 (que vem do media
   query acima) e NAO recebia o .32/.43: as telas de trabalho ficariam com mais
   marca, e sao justamente as de chao mais claro, onde a margem era menor.
   E o desfecho invertido, no caso mais comum — ninguem troca tema no primeiro
   acesso. */
@media (prefers-color-scheme: dark) {
    :root:not([data-tema="claro"]) .cena_discreta .cena_forma.marca { opacity: .32; }
    :root:not([data-tema="claro"]) .pagina-app .cena_forma.marca { opacity: .43; }
}


/* --- home: marquee ---
   Superficie fixa (vermelho + branco nos dois temas), decorativa: o mesmo
   conteudo ja esta em texto estatico no hero, entao sai da arvore de
   acessibilidade em vez de duplicar informacao em movimento.
   width em % (nao max-content) pelo mesmo motivo do contain acima. */
.marquee { background: linear-gradient(90deg, var(--fss-acao-hover), var(--fss-acao)); overflow: hidden; contain: layout paint; }
.marquee_track { display: flex; width: 200%; }
.marquee_grupo { display: flex; width: 50%; flex-shrink: 0; white-space: nowrap; padding: 7px 0; }
.marquee_seg { display: inline-flex; align-items: center; gap: 14px; font-size: var(--tipo-1); font-weight: 800; letter-spacing: .14em; text-transform: uppercase; color: #fff; padding-right: 14px; }
.marquee_seg::after { content: "\2022"; margin-left: 14px; opacity: .6; }

/* --- home: topo ---
   O que era o header de vidro sobre a cena virou a barra escura fixa do bloco
   `--- topo ---`: la mora TUDO (cor, logo, pilula, foco), aqui sobra so o
   comportamento exclusivo da home — grudar no topo ao rolar. Sem
   backdrop-filter: o fundo agora e opaco, e blur atras de opaco e so custo de
   composicao. */
.pagina-home .topo { position: sticky; top: 0; z-index: 50; }
/* Ancoras internas: so existem nesta pagina, entao somem antes de espremer o
   resto da barra. */
.nav_secoes { display: flex; align-items: center; gap: 28px; list-style: none; margin: 0; padding: 0; }
@media (max-width: 980px) { .nav_secoes { display: none; } }

/* --- home: hero ---
   minmax(0, 1fr) e obrigatorio: sem coluna explicita, o grid implicito de 1
   coluna dimensiona pelo max-content dos filhos e vaza largura real a 320px. */
.hero { padding-block: clamp(56px, 9vw, 116px) clamp(48px, 7vw, 96px); display: grid; grid-template-columns: minmax(0, 1fr); gap: 52px; align-items: center; }
.hero_chip {
    display: inline-flex; align-items: center; gap: 9px; margin: 0;
    padding: 8px 16px; border-radius: var(--pilula);
    /* SEM PREENCHIMENTO desde 25/08/2026. O chip pintava uma quarta superficie
       da pagina (--fss 12%) para dizer o que o contorno vermelho, o ponto
       vermelho e a tinta vermelha do texto ja diziam tres vezes. E a mesma
       subtracao da escada dos botoes: perde a camada mais cara, mantem as que
       carregam o sentido. De quebra o texto passa a pousar em --fundo, e nao no
       tingido: medido no escuro, de 4,64:1 para 5,63:1. */
    background: transparent;
    border: 1px solid var(--borda-marca);
    color: var(--fss-texto); font-size: var(--tipo-1); font-weight: 700; letter-spacing: .03em;
}
.hero_chip .ponto { position: relative; width: 8px; height: 8px; border-radius: 50%; background: var(--fss); flex: none; }
.hero_chip .ponto::after { content: ""; position: absolute; inset: -6px; border-radius: 50%; border: 1.5px solid var(--fss); }
.pagina-home .hero h1 {
    margin: 22px 0 0;
    font-size: var(--tipo-8);
    font-weight: 900; line-height: .98; letter-spacing: -.045em;
    text-wrap: balance; max-width: 15ch;
}
/* Titulo gigante em peso 900: muito acima do piso de 3:1 nos dois temas. */
.destaque { color: var(--fss); }
.pagina-home .sub,
.pagina-app .sub { color: var(--texto-suave); line-height: 1.65; max-width: 50ch; margin: 24px 0 0; }
/* MESMO DEGRAU DO /app (--tipo-4, 19->22px). O clamp proprio ia de 17 a 21 e
   nao era degrau de nada; e, no meio da faixa, o subtitulo da home ficava MENOR
   que o do painel, que e a tela onde ninguem precisa ser convencido. */
.pagina-home .sub { font-size: var(--tipo-4); }
/* Mesma razao do h2 acima: --tipo-4 (19->22px) e o degrau de subtitulo. O
   clamp proprio ia a 21px e nao era degrau de coisa nenhuma. */
.pagina-app .sub { font-size: var(--tipo-4); }
.pagina-home .sub strong,
.pagina-app .sub strong { color: var(--texto); font-weight: 800; }
.confianca { display: flex; flex-wrap: wrap; gap: 20px 28px; margin: 34px 0 0; padding: 0; list-style: none; }
.confianca li { display: inline-flex; align-items: center; gap: 9px; font-size: var(--tipo-1); color: var(--texto-fraco); }
.confianca svg { flex: none; opacity: .85; }

/* --- home: a peca (relatorio-exemplo) ---
   position:relative e essencial: sem ele o halo desfocado (::before) ancora no
   viewport e vaza largura real a 320px. */
.peca { position: relative; width: min(440px, 100%); }
/* .rel_peca (relatorio real) compartilha a receita visual da peca da home —
   mesma superficie, mesmo raio, mesma elevacao — mas NAO a animacao de
   flutuacao: um cartao de dados que o usuario le nao pode ficar boiando. */
.peca_cartao, .rel_peca {
    position: relative;
    background: linear-gradient(180deg, var(--painel-solido), var(--fundo));
    border: 1px solid var(--borda);
    border-radius: var(--raio-app);
    padding: clamp(22px, 4vw, 34px);
    box-shadow: var(--elev-1), var(--elev-cartao), inset 0 1px 0 var(--preenchimento);
}
.peca::before {
    content: ""; position: absolute; inset: 6% 2%; z-index: -1; border-radius: 50%;
    background: radial-gradient(closest-side, color-mix(in srgb, var(--fss) 30%, transparent), transparent 72%);
    filter: blur(14px);
}
.peca_rotulo { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 8px 12px; margin: 0 0 8px; }
/* O aviso e o ULTIMO ato da coreografia — o espetaculo termina nele, entao ele
   precisa se ler sozinho. Trocado de --texto-fraco para --texto-suave em
   13/08/2026; medido sobre --painel-solido (o topo do gradiente do cartao, que
   e onde o chip fica), com o tema forcado por cookie:
       claro   #565C73 5,69:1  ->  #5A6072 5,42:1
       escuro  #868CA0 4,93:1  ->  #A0A5B8 6,83:1
   Os dois valores passam AA para texto normal (4,5:1) antes e depois; a troca
   compra folga justamente no escuro, onde a margem era de meio ponto.
   position:relative existe para o anel do pulso (::after, no bloco de motion).
   Classe exclusiva da home — nao existe em result.php. */
.peca_exemplo { position: relative; font-size: var(--tipo-1); font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--texto); border: 1px dashed var(--borda); border-radius: var(--pilula); padding: 4px 10px; white-space: nowrap; }
/* Grade de instrumento: papel milimetrado sob o anel. Estatica (nao e motion:
   vale tambem para quem pediu menos movimento) e mascarada para sumir no meio,
   onde o anel e os numeros moram — grade atras de dado e ruido. Vive no ::before
   da peca da HOME; .rel_peca nao tem nem herda isto. */
.peca_cartao::before {
    content: ""; position: absolute; inset: 1px; border-radius: inherit; pointer-events: none;
    background-image: linear-gradient(var(--borda) 1px, transparent 1px), linear-gradient(90deg, var(--borda) 1px, transparent 1px);
    background-size: 26px 26px;
    opacity: .55;
    -webkit-mask-image: radial-gradient(closest-side at 50% 42%, transparent 46%, #000 92%);
    mask-image: radial-gradient(closest-side at 50% 42%, transparent 46%, #000 92%);
}
.anel { display: block; width: 100%; height: auto; position: relative; }
.anel .trilha { fill: none; stroke: var(--borda); stroke-width: 12; }
.anel .arco { fill: none; stroke-width: 12; stroke-linecap: round; transform: rotate(-90deg); transform-origin: 110px 110px; }
.arco_pessoas { stroke: var(--texto-suave); stroke-dasharray: 552.92; stroke-dashoffset: 154.82; }
.arco_processos { stroke: var(--texto-fraco); stroke-dasharray: 427.26; stroke-dashoffset: 192.27; }
.arco_tec { stroke: var(--fss); stroke-dasharray: 301.59; stroke-dashoffset: 177.94; }
/* --score-cor (= --texto hoje): o token da DEC-002, nao a cor crua. */
.anel_score { font-family: var(--mono); font-size: 46px; font-weight: 800; fill: var(--score-cor); }
.anel_de { font-size: 12px; fill: var(--texto-fraco); font-family: var(--fonte); }
.legenda { list-style: none; margin: 20px 0 0; padding: 16px 0 0; border-top: 1px solid var(--borda); display: grid; gap: 9px; }
.legenda li { display: flex; align-items: center; gap: 10px; font-size: var(--tipo-2); color: var(--texto-suave); }
.legenda .amostra { width: 10px; height: 10px; border-radius: 3px; flex: none; }
.legenda .amostra.p1 { background: var(--texto-suave); }
.legenda .amostra.p2 { background: var(--texto-fraco); }
.legenda .amostra.p3 { background: var(--fss); }
.pagina-home .legenda .valor,
.pagina-app .legenda .valor { margin-left: auto; font-family: var(--mono); font-variant-numeric: tabular-nums; font-size: var(--tipo-2); color: var(--texto); font-weight: 700; }
.pagina-home .legenda .gargalo,
.pagina-app .legenda .gargalo { color: var(--fss-texto); font-weight: 800; }
.peca_nota { margin: 14px 0 0; font-size: var(--tipo-1); color: var(--texto-fraco); }

@media (min-width: 980px) {
    .hero { grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); gap: 56px; }
    .peca { justify-self: end; }
}

/* --- home: bento (o que voce recebe) --- */
.bento { display: grid; gap: 20px; margin-top: 46px; }
.tile { border-radius: var(--raio-app); padding: 30px; min-width: 0; position: relative; }
/* --tipo-5 (24->27px) na home, --tipo-4 (19->22px) no /app: o titulo de cartao
   tem de ficar abaixo do cabecalho da secao, e os dois cabecalhos sao
   diferentes (--tipo-7 aqui, --tipo-5 la). Mesma regra de subordinacao, degrau
   distinto — que e o que uma escala serve para permitir. */
.tile h3 { margin: 14px 0 8px; font-size: var(--tipo-5); font-weight: 800; letter-spacing: -.02em; line-height: 1.15; }
.tile p { margin: 0; font-size: var(--tipo-2); line-height: 1.65; color: var(--texto-suave); }
.tile_vidro { background: var(--painel); -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px); border: 1px solid var(--borda); }
/* Superficie fixa: acento sempre escuro, nos dois temas. Reaponta os tokens
   semanticos DENTRO do escopo — assim .tile p, .caps e .rank nao precisam
   saber que estao numa ilha escura. */
.tile_ink {
    background: var(--escuro-fundo);
    border: 1px solid var(--escuro-borda);
    color-scheme: dark;
    /* `color` explicito, e nao so a troca dos tokens: a cor herdada de fora
       chega ja COMPUTADA, entao redefinir --texto aqui nao repinta quem so
       herda (um h3 sem regra de cor sairia escuro sobre a ilha escura — razao
       1:1). Corrigido em 13/08/2026 ao portar o relatorio. */
    color: var(--escuro-texto);
    --texto: var(--escuro-texto);
    --texto-suave: var(--escuro-suave);
    --texto-fraco: var(--escuro-suave);
    --fss-texto: var(--escuro-acento);
    --borda: var(--escuro-borda);
}
/* A LAVAGEM ROSA FUNDIU NO VIDRO — AGORA NAS DUAS TELAS (onda 42, 25/08/2026).

   Esta regra era a da direcao D (`background: var(--lavagem)`), e o /app tinha
   uma copia sua em `.pagina-app .tile_wash` com a receita da direcao B. Duas
   regras, dois desenhos, um nome de classe: o mesmo cartao de estimativa
   aparecia rosa na home e de vidro no relatorio.

   Agora ha UMA regra, sem escopo de pagina, e ela e a da direcao B. Nada muda
   no /app — a copia de la declarava exatamente isto, e foi apagada por ser
   redundante, nao por ser diferente.

   POR QUE A BARRA, E NAO UM FUNDO TINGIDO (o argumento vem inteiro da onda 32,
   e a home so confirma cada palavra dele): um fundo tingido pinta tambem o que
   ele nao quer enfatizar — o texto corrido, a nota fina, o muro do RF06 — e
   arrasta todo mundo para baixo em contraste. A barra enfatiza o BLOCO sem
   tocar em um pixel de texto.

   E o que era previsao la, aqui foi MEDIDO na home em producao, em 25/08/2026,
   por dois instrumentos independentes que chegaram ao mesmo numero:
       --texto-suave  sobre a lavagem clara   4,34:1   (piso 4,5)
       .caps          sobre a lavagem escura  4,20:1   (piso 4,5)
   O axe acusava as duas em oito combinacoes de tema x largura x preferencia de
   movimento. A lavagem nao era so uma terceira tinta: era um defeito de
   contraste em producao, na secao que explica a regra RF06.

   `.tile_ink` continua de fora da fusao, de proposito: ela passa a ser a UNICA
   ilha escura do conteudo, e fica mais forte por ser a excecao. Excecao nao
   precisa de truque de cor — precisa ser rara. */
.tile_wash {
    background: var(--painel);
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
    border: 1px solid var(--borda);
    border-inline-start: var(--acento-largura) solid var(--fss-acao);
}
/* O hover compartilhado (bloco de motion) troca `border-color` no atalho, o
   que repintaria tambem a barra de acento — o carimbo mudaria de cor ao passar
   o mouse, que e exatamente o contrario de "carimbo". Reafirma so o lado. */
.tile_wash:hover { border-inline-start-color: var(--fss-acao); }
@media (min-width: 900px) {
    .bento { grid-template-columns: repeat(6, minmax(0, 1fr)); }
    .tile_pontuacao { grid-column: 1 / 5; }
    .tile_gargalos { grid-column: 5 / 7; }
    .tile_estimativa { grid-column: 1 / 7; }
}

.barras { list-style: none; margin: 22px 0 0; padding: 0; display: grid; gap: 14px; }
.barras li { display: grid; grid-template-columns: 92px minmax(0, 1fr) 34px; align-items: center; gap: 12px; font-size: var(--tipo-2); }
.barras .nome { color: var(--texto-fraco); }
/* display explicito: a pista e sempre um bloco, mesmo fora de um grid. */
.barras .trilho, .rel_pilar .trilho, .pnl_pilar .trilho { display: block; height: 8px; border-radius: var(--pilula); background: var(--borda); overflow: hidden; }
.barras .valorb { font-family: var(--mono); font-variant-numeric: tabular-nums; font-weight: 700; text-align: right; color: var(--texto); }
.preench { display: block; height: 100%; border-radius: var(--pilula); transform-origin: left; }
.preench.p1 { background: var(--texto-suave); width: 72%; }
.preench.p2 { background: var(--texto-fraco); width: 55%; }
.preench.p3 { background: var(--fss); width: 41%; }
.pagina-home .nota_fina,
.pagina-app .nota_fina { margin: 16px 0 0; font-size: var(--tipo-1); color: var(--texto-fraco); }

.rank { list-style: none; margin: 20px 0 0; padding: 0; display: grid; }
.rank li { display: flex; align-items: baseline; gap: 10px; padding: 12px 0; border-top: 1px solid var(--borda); font-size: var(--tipo-2); color: var(--texto-fraco); }
.rank .pos { font-family: var(--mono); font-variant-numeric: tabular-nums; font-size: var(--tipo-1); }
.rank .valorb { margin-left: auto; font-family: var(--mono); font-variant-numeric: tabular-nums; font-weight: 700; color: var(--texto); }
.rank li:first-child .nome, .rank li:first-child .pos, .rank li:first-child .valorb { color: var(--fss-texto); font-weight: 800; }

/* RF06: as duas grandezas com um muro no meio. Elas NUNCA se somam — perda
   atual e a distancia ate o benchmark no volume de hoje; potencial futuro e o
   ganho alem desse mesmo benchmark. Somar contaria o mesmo ganho duas vezes,
   por isso nao existe (nem pode existir) um total combinado aqui. */
.duplo { display: grid; gap: 14px; margin-top: 24px; align-items: stretch; }
/* O 16 estava CRU aqui — nem token era. Agora e o mesmo --raio-app de toda
   superficie do portal, e por acaso o mesmo pixel: a diferenca e que agora ele
   acompanha o token se o token mudar. */
.grandeza { background: var(--painel-solido); border: 1px solid var(--borda); border-radius: var(--raio-app); padding: 20px 22px; }
.grandeza .caps { display: block; }
.grandeza_valor { display: block; margin-top: 9px; font-family: var(--mono); font-variant-numeric: tabular-nums; font-weight: 800; font-size: clamp(1.0625rem, 5.6vw, 1.875rem); letter-spacing: -.02em; white-space: nowrap; }
/* O ROTULO SEGUE O ESTADO QUE O GLIFO E O NUMERO JA DIZEM.

   Medido em 19/08/2026, no bloco da estimativa: QUATRO coisas saiam no mesmo
   vermelho — o rotulo da secao, "PERDA ATUAL", "POTENCIAL FUTURO" e o muro
   "nunca se somam" — enquanto os glifos e os valores ao lado ja diziam outra
   coisa.

     perda zerada:      glifo cinza,  rotulo VERMELHO, valor cinza
     potencial futuro:  glifo verde,  rotulo VERMELHO, valor verde

   Nos dois lados a peca do meio contradizia as duas ao redor. No potencial e
   pior do que inconsistente: a boa noticia do relatorio — o ganho que a
   empresa pode alcancar — vinha rotulada na cor que, tres secoes acima, marca
   o gargalo.

   A lavagem vermelha do .tile_wash FICA: ela e enfase da direcao visual, usada
   em cinco lugares de tres telas, e nao quer dizer "problema". O que muda e o
   que diz respeito ao DADO. */
.grandeza_perda .grandeza_valor { color: var(--erro); }
.grandeza_pot .grandeza_valor { color: var(--sucesso); }
/* Cada grandeza usa UM token: o rotulo, o glifo e o valor saem da mesma cor.
   O rotulo da perda vinha de --fss-texto (o acento da marca) enquanto o glifo
   e o valor vinham de --erro — dois vermelhos diferentes na mesma linha, um
   deles significando "marca" e o outro "problema". */
.pagina-home .grandeza_perda .caps,
.pagina-app .grandeza_perda .caps { color: var(--erro); }
.pagina-home .grandeza_pot .caps,
.pagina-app .grandeza_pot .caps { color: var(--sucesso); }
.pagina-home .grandeza .miudo,
.pagina-app .grandeza .miudo { margin: 7px 0 0; font-size: var(--tipo-1); color: var(--texto-fraco); }
/* O muro enuncia uma REGRA de leitura (RF06), nao um problema. Em vermelho ele
   era a quarta coisa alarmante do mesmo cartao, e a unica que nao fala de
   dado nenhum. A enfase que ele precisa ja esta na caixa abaixo, em negrito.
   Os tracos continuam em --borda-marca: ali o vermelho e desenho da direcao,
   como a lavagem do tile. */
.muro { display: grid; place-items: center; text-align: center; font-size: var(--tipo-1); font-weight: 800; text-transform: uppercase; letter-spacing: .1em; color: var(--texto-suave); padding: 4px 8px; }
.muro::before, .muro::after { content: ""; width: 1px; height: 18px; background: var(--borda-marca); margin: 6px auto; }
@media (min-width: 760px) {
    .duplo { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); }
    .muro { padding: 0 10px; max-width: 130px; }
}

/* --- home: passos (como funciona) ---
   Chamava-se .trilho ate 13/08/2026 e COLIDIA com o .trilho de .barras (a
   pista da barra de pontuacao): o display:grid + margin + ::before desta
   regra vazavam para dentro de cada barra e o preenchimento passava a medir
   a coluna do grid, nao a pista. As barras da home renderizavam ~21/16/12%
   onde deviam mostrar 72/55/41%. Um nome, um componente.
   ------------------------------------------------------------------------- */
.passos { list-style: none; margin: 48px 0 0; padding: 0; display: grid; gap: 26px; position: relative; }
.passos::before { content: ""; position: absolute; left: 15px; top: 30px; bottom: 30px; width: 2px; background: linear-gradient(180deg, var(--fss), transparent); }
.passo { position: relative; padding-left: 54px; }
.passo_n {
    position: absolute; left: 0; top: 2px; width: 34px; height: 34px; border-radius: 50%;
    display: grid; place-items: center; font-family: var(--mono); font-variant-numeric: tabular-nums;
    font-size: var(--tipo-1); font-weight: 800; background: var(--fundo); color: var(--fss-texto);
    border: 1.5px solid var(--borda-marca); box-shadow: 0 0 0 6px color-mix(in srgb, var(--fss) 9%, transparent);
}
.passo h3 { margin: 0 0 7px; font-size: var(--tipo-4); font-weight: 800; letter-spacing: -.01em; }
.passo p { margin: 0; color: var(--texto-suave); font-size: var(--tipo-2); line-height: 1.6; max-width: 44ch; }
@media (min-width: 880px) {
    .passos { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 34px; }
    .passos::before { left: 8%; right: 8%; top: 16px; bottom: auto; width: auto; height: 2px; background: linear-gradient(90deg, var(--fss), transparent); }
    .passo { padding-left: 0; padding-top: 58px; }
    .passo_n { top: 0; }
}

/* --- home: transparencia --- */
.limite {
    margin-top: clamp(76px, 10vw, 140px);
    background: linear-gradient(165deg, var(--painel-solido), var(--fundo));
    border: 1px solid var(--borda);
    border-radius: var(--raio-app);
    padding: clamp(30px, 5vw, 64px);
    display: grid; gap: 30px;
    position: relative; overflow: hidden;
}
.limite::before {
    content: ""; position: absolute; inset: auto -20% -60% -20%; height: 90%;
    background: radial-gradient(closest-side at 50% 100%, color-mix(in srgb, var(--fss) 24%, transparent), transparent 74%);
    pointer-events: none;
}
/* A moldura do painel de limite entra no raio unico do /app (direcao B): ela
   era a ultima superficie de 30px numa tela onde tudo o mais e 16. A home
   segue com --raio-limite, que e da direcao D. */
.pagina-app .limite { border-radius: var(--raio-app); }
/* A peca (o cartao do anel de pontuacao) era a outra: 28px de --raio-peca, o
   raio do hero da home. Aqui ela e um cartao de dado como os outros. */
.pagina-app .rel_peca { border-radius: var(--raio-app); }
/* O SELETOR COMPARTILHADO TINHA DESFEITO, NA HOME, O QUE O COMENTARIO PROMETE.

   O texto abaixo e de 13/08/2026 e diz o certo: "Mesma escala de .secao_head h2
   e .faq h2 (30 -> 46px). Antes esta era a UNICA secao com titulo menor que as
   vizinhas, e ainda perdia para o .negado ao lado — o olho pousava primeiro na
   promessa que a secao NEGA."

   So que a onda 32 trocou o valor por --tipo-5 (24->27px) para o /app, com
   razao — la o cabecalho de secao E --tipo-5 — e o `.pagina-home` estava na
   MESMA lista de seletores, entao veio junto sem que ninguem decidisse. Efeito
   na home: "O que voce nao vai encontrar aqui" voltou a 27px enquanto "O que
   voce recebe", "Como funciona", "Perguntas frequentes" e o fecho ficaram em
   46 — exatamente o defeito que o comentario declara resolvido, de volta em
   producao por sete dias, e visivel na captura de antes desta onda.

   Os dois seletores se separam. Cada tela le o degrau de cabecalho de secao da
   PROPRIA lingua: --tipo-7 na home, --tipo-5 no /app. Regra compartilhada e
   boa enquanto as duas telas quiserem o mesmo numero; quando querem numeros
   diferentes pela mesma razao, compartilhar e o que produz o erro. */
.pagina-home .limite h2,
.pagina-app .limite h2 { margin: 12px 0 0; font-size: var(--tipo-5); font-weight: 900; letter-spacing: -.035em; line-height: 1.05; max-width: 18ch; }
/* DEPOIS da regra comum, e nao antes: as duas tem a mesma especificidade (0,2,1),
   entao quem vence e a ultima. Escrita acima, a linha da home seria sobrescrita
   pelo proprio valor que ela existe para corrigir — e o defeito continuaria, so
   que agora com um comentario de 20 linhas jurando o contrario. */
.pagina-home .limite h2 { font-size: var(--tipo-7); max-width: 22ch; }
/* A negacao aparece riscada, mas o texto continua legivel e na ordem: o titulo
   da secao ja carrega o sentido para quem nao ve o risco. */
/* Subordinado ao h2 (30 -> 46px) em toda a faixa, e nao o contrario. O que esta
   riscado e o exemplo do que NAO se promete: precisa ser legivel, nao dominante. */
.negado { margin: 0; font-size: var(--tipo-5); font-weight: 900; letter-spacing: -.03em; color: var(--texto-suave); }
/* Espessura em em, nao em px: o risco acompanha o corpo do texto em toda a faixa
   do clamp. Fixo em 5px ele foi calibrado para 48px e sufocava a palavra a 20px. */
.negado s { text-decoration-color: var(--fss); text-decoration-thickness: .1em; }
.limite_texto { margin: 16px 0 0; color: var(--texto-suave); font-size: var(--tipo-3); max-width: 54ch; position: relative; }
@media (min-width: 960px) { .limite { grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr); align-items: center; } }

/* --- home: depoimentos ---
   Nenhuma prova social inventada: os cartoes ficam com marcador explicito ate a
   FSS fornecer relatos reais e autorizados. Borda tracejada e selo "Pendente"
   existem para que ninguem confunda placeholder com depoimento. */
.depo_grid { display: grid; gap: 20px; margin-top: 44px; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.depo_card { background: var(--painel); border: 1px dashed var(--contorno); border-radius: var(--raio-app); padding: 26px; display: grid; gap: 16px; }
.depo_avatar { width: 46px; height: 46px; border-radius: 50%; background: var(--preenchimento); border: 1px solid var(--borda); display: grid; place-items: center; color: var(--texto-fraco); }
.depo_quote { margin: 0; font-size: var(--tipo-3); line-height: 1.55; font-style: italic; color: var(--texto-fraco); }
.depo_quem { display: flex; align-items: center; gap: 12px; }
.depo_nome { font-weight: 700; font-size: var(--tipo-2); color: var(--texto-fraco); margin: 0; }
.depo_cargo { font-size: var(--tipo-1); color: var(--texto-fraco); opacity: .82; margin: 0; }
.depo_pendente { display: inline-flex; align-self: start; font-size: var(--tipo-1); font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--fss-texto); border: 1px solid var(--borda-marca); border-radius: var(--pilula); padding: 3px 10px; }
.depo_nota { margin: 20px 0 0; font-size: var(--tipo-1); color: var(--texto-fraco); max-width: 62ch; }

/* --- home: FAQ ---
   Ilha de superficie FIXA CLARA nos dois temas. Os tokens semanticos sao
   reapontados aqui dentro, entao as regras de dentro nao sabem que estao numa
   ilha. Accordion e <details> nativo: funciona sem uma linha de JS. */
.faq {
    color-scheme: light;
    --texto: var(--claro-texto);
    --texto-suave: var(--claro-suave);
    --texto-fraco: var(--claro-suave);
    --fss-texto: var(--claro-acento);
    background: var(--claro-fundo);
    border-radius: var(--raio-ilha) var(--raio-ilha) 0 0;
    margin-top: clamp(76px, 10vw, 140px);
    padding-block: clamp(64px, 9vw, 120px);
}
.pagina-home .faq h2 { margin: 12px 0 0; font-size: var(--tipo-7); font-weight: 900; letter-spacing: -.035em; line-height: 1.05; }
.faq h2 em { font-style: normal; color: var(--fss-texto); }
/* O FILETE VERMELHO DO FAQ SAIU (25/08/2026), e o argumento e o da assinatura.

   A barra vermelha e assinatura, e assinatura vale UMA por tela. Depois que a
   direcao B trouxe a barra de acento de `.tile_wash` para a home, o filete
   passou a ser a segunda — e a menos justificada das duas: a de `.tile_wash`
   marca QUAL bloco importa, e esta so sublinhava um titulo que ja tinha dois
   outros sinais vermelhos em cima dele (o rotulo `.caps` e o <em> de
   "frequentes"). Tres marcas para um cabecalho, nenhuma delas informando nada
   que o texto nao dissesse.

   A regra fica, vazia de consumidor, apenas enquanto durar esta nota? Nao: ela
   foi apagada junto com o <div> em home.php. Ficar seria convidar o filete de
   volta sem o argumento. */
/* Titulo + lista formam UMA coluna de 860px centrada no wrap de 1080px.
   Antes a lista tinha max-width sem margin auto: encostava a esquerda e
   deixava ~220px de vao morto a direita (o "torto" que o usuario viu).
   Centralizar SO a lista desalinharia a borda esquerda dela com a do titulo;
   por isso o bloco INTEIRO desce junto. Abaixo de ~935px o wrap (92vw) ja e
   menor que 860px e nada disto morde — 320/768 ficam como estavam. */
.faq .secao_head { max-width: 860px; margin-inline: auto; }
.faq_lista { margin: 44px auto 0; display: grid; gap: 14px; list-style: none; padding: 0; max-width: 860px; }
.faq_item { background: var(--claro-cartao); border: 1px solid var(--claro-borda); border-radius: var(--raio-app); box-shadow: 0 1px 2px rgba(15, 18, 32, .04); overflow: hidden; }
/* O alvo e a LINHA inteira: <summary> e o bloco todo do cartao, nao so o texto.
   min-height 44px e o piso da 2.5.5; o padding leva a altura real a ~64px. */
.faq_item summary { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 20px 24px; cursor: pointer; font-weight: 700; font-size: var(--tipo-3); color: var(--texto); list-style: none; min-height: 44px; }
.faq_item summary::-webkit-details-marker { display: none; }
/* min-width: 0 e o que deixa a pergunta longa quebrar a 320px em vez de
   empurrar o glifo para fora do cartao (item de flex nao encolhe abaixo do
   min-content sem isto). */
.faq_q { min-width: 0; line-height: 1.35; }
.faq_item summary:hover { background: color-mix(in srgb, var(--claro-acento) 5%, transparent); }
/* Foco na ILHA CLARA. O anel global (:focus-visible, secao 12.6) erra duas
   vezes aqui: o outline-offset positivo cai no overflow:hidden do cartao e
   some, e o halo usa --fundo, que e a cor da PAGINA (escura no tema escuro) e
   mancharia a ilha. Anel por dentro, sem halo, na cor de acento da ilha. */
.faq_item summary:focus-visible { outline: 3px solid var(--claro-acento); outline-offset: -3px; box-shadow: none; border-radius: var(--raio-app); }
/* Aberto, o anel acompanha so os cantos de cima — os de baixo agora encostam
   no filete divisor e curvariam a linha. */
.faq_item[open] summary:focus-visible { border-radius: var(--raio-app) var(--raio-app) 0 0; }
/* O GLIFO SEGUE A ESCALA porque ele E dimensionado por `font-size`: icone()
   devolve um <svg width="1em" height="1em">. Os 18px de `1.125rem` eram um
   degrau que nao existia; --tipo-3 e o mesmo degrau do texto da pergunta ao
   lado — o `+` e a palavra passam a ter a mesma altura optica, que e o que se
   espera de um par. O circulo de 34px nao muda: ele e alvo, nao letra. */
.faq_plus { flex: none; width: 34px; height: 34px; border-radius: 50%; background: color-mix(in srgb, var(--fss-texto) 12%, transparent); color: var(--fss-texto); display: grid; place-items: center; font-size: var(--tipo-3); line-height: 1; }
.faq_item summary:hover .faq_plus { background: color-mix(in srgb, var(--fss-texto) 20%, transparent); }
/* O glifo unico de icone('mais') girado 45 graus vira "x". Isto e INFORMACAO
   de estado, nao enfeite: fica FORA do bloco de motion e vale tambem para quem
   pediu menos movimento. O que morre sob reduce e so a transicao entre os dois
   estados (la embaixo), nunca o estado final. */
.faq_item[open] .faq_plus { transform: rotate(45deg); }
.faq_item[open] summary { border-bottom: 1px solid var(--claro-borda); }
/* Abertura suave em CSS puro, tres caixas com um papel cada:
     .faq_revela  a GRADE, cuja unica linha vai de 0fr a 1fr;
     .faq_corte   o item da grade, que RECORTA (min-height: 0 + overflow);
     .faq_body    o respiro (padding) e a tipografia da resposta.
   O padding NAO pode morar no item da grade: overflow: hidden zera a
   contribuicao do CONTEUDO para a altura da linha, mas nunca a do padding do
   proprio item — a linha fechada media 28px (4 + 24) e metade da abertura
   estalava em vez de deslizar. Medido, nao suposto.
   O <details> segue nativo — nada de JS, nada de aria-expanded a mao. */
.faq_revela { display: grid; grid-template-rows: 0fr; }
.faq_item[open] .faq_revela { grid-template-rows: 1fr; }
.faq_corte { min-height: 0; overflow: hidden; }
.faq_body { padding: 4px 24px 24px; color: var(--texto-suave); font-size: var(--tipo-3); line-height: 1.7; }
.pagina-home .faq_body p { margin: 0; }
.pagina-home .faq_body p + p { margin-top: 10px; }
/* A 400px o padding de 24px come um quarto da largura util: a pergunta passa a
   quebrar em tres linhas e o cartao vira um bloco. */
@media (max-width: 400px) {
    .faq_lista { gap: 12px; }
    /* O tamanho ja e --tipo-3 e ele proprio encolhe a 320: repetir um `1rem`
       aqui era um degrau a mais so para esta faixa. Sobra o respiro, que e o
       que a largura de fato pedia. */
    .faq_item summary { padding: 16px 18px; gap: 12px; }
    .faq_body { padding: 2px 18px 20px; }
}

/* --- home: fecho --- */
.fecho { margin-top: clamp(60px, 8vw, 100px); text-align: center; padding-bottom: clamp(60px, 8vw, 100px); }
/* O MESMO degrau das outras secoes. O clamp daqui parava em 44px onde o das
   vizinhas ia a 46 — dois pixels que ninguem escolheu e que faziam o fecho, que
   e a ultima chamada da pagina, chegar menor que os cabecalhos que o antecedem. */
.pagina-home .fecho h2 { margin: 0 auto; font-size: var(--tipo-7); font-weight: 900; letter-spacing: -.035em; line-height: 1.06; max-width: 20ch; }
.fecho .acoes { justify-content: center; margin-top: 30px; }
.fecho .confianca { justify-content: center; }

/* --- home: rodape --- */
.pagina-home .rodape { padding-block: 48px 40px; background: var(--superficie); font-size: var(--tipo-3); }
.rodape_grid { display: grid; gap: 36px; grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr); }
/* <h4> VIROU <h3> em 25/08/2026, e a mudanca e de arvore, nao de desenho.
   O ultimo cabecalho antes do rodape e o <h2> do fecho; os titulos de coluna
   entravam como h4 e pulavam o nivel 3. O axe acusava `heading-order` em TODAS
   as oito combinacoes de tema x largura x preferencia de movimento — e para
   quem navega por cabecalhos um nivel pulado e um degrau que nao existe. O
   tamanho renderizado nao mudou um pixel: o seletor acompanhou a tag. */
.pagina-home .rodape h3 { margin: 0 0 16px; font-size: var(--tipo-1); font-weight: 800; text-transform: uppercase; letter-spacing: .1em; color: var(--texto-fraco); }
.rodape_marca { font-weight: 900; color: var(--texto); font-size: var(--tipo-3); margin: 0 0 8px; }
.pagina-home .rodape p { margin: 0; font-size: var(--tipo-2); color: var(--texto-fraco); line-height: 1.6; }
.rodape_links { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }

/* UM tratamento para TODO link do rodape. A coluna Legal ficava de fora e caia
   no padrao do navegador (azul, roxo quando visitado, sublinhado) — destoava de
   tudo e ainda entregava o historico de navegacao do visitante.

   Sublinhado some no repouso e VOLTA no hover/foco: em rodape a cor sozinha ja
   distingue o link do texto morto ao redor, mas na interacao o sublinhado
   confirma que aquilo e clicavel. `text-underline-offset` afasta o traco das
   descidas (g, ç, y) — sublinhado colado e o que faz link parecer amador. */
.rodape_links a,
.rodape_legal a {
    color: var(--texto-suave);
    text-decoration: none;
    font-size: var(--tipo-2);
    border-radius: var(--raio-p);
}

.rodape_links a:hover,
.rodape_legal a:hover {
    color: var(--texto);
    text-decoration: underline;
    text-underline-offset: .22em;
    text-decoration-thickness: 1px;
}

/* Foco visivel proprio: o anel global e desenhado para superficie clara e some
   sobre o rodape escuro. */
.rodape_links a:focus-visible,
.rodape_legal a:focus-visible {
    color: var(--texto);
    outline: 2px solid var(--fss-acao);
    outline-offset: 3px;
}
.selo { display: inline-flex; align-items: center; gap: 8px; font-size: var(--tipo-1); color: var(--texto-fraco); border: 1px dashed var(--contorno); border-radius: var(--pilula); padding: 6px 12px; margin: 0 8px 8px 0; }
.selo_nota { margin-top: 10px; font-size: var(--tipo-1); }
.rodape_legal { display: grid; gap: 8px; }
.rodape_legal span { font-size: var(--tipo-2); color: var(--texto-fraco); }
.rodape_legal .tag { font-size: var(--tipo-1); font-weight: 800; text-transform: uppercase; letter-spacing: .06em; color: var(--texto-fraco); border: 1px solid var(--borda); border-radius: var(--raio-p); padding: 1px 6px; margin-left: 8px; }
.pagina-home .rodape_aviso { max-width: 78ch; font-size: var(--tipo-1); margin-top: 28px; padding-top: 24px; border-top: 1px solid var(--borda); }
.pagina-home .rodape_aviso strong { color: var(--texto-suave); }
@media (max-width: 820px) { .rodape_grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } }
@media (max-width: 480px) { .rodape_grid { grid-template-columns: minmax(0, 1fr); } }

/* --- home: barra flutuante ---
   DECISAO (12/08/2026): a barra nasce escondida e so aparece DEPOIS que o hero
   sai da viewport. Em tela curta (320x568) ela cobria os CTAs do hero — dois
   caminhos para a mesma acao, e o de baixo tapando o de cima. Como o gatilho e
   um IntersectionObserver, sem JS ela nunca aparece: por isso o padrao aqui e
   display:none, e nao "visivel com JS opcional".
   .com-flutuante entra no <html> junto com a primeira exibicao e reserva o
   espaco no fim da pagina — sem JS nao ha barra nem espaco reservado.

   DECISAO (13/08/2026): a barra e SUPERFICIE ESCURA, nao vermelha. O fundo
   --fss-acao era o token certo com a leitura errada: uma area grande de
   vermelho, mais o brilho vermelho da --glow-flutuante, lia como um SEGUNDO
   vermelho ao lado dos acentos --fss da pagina, e invertia a hierarquia (o
   CTA virava branco, contrariando a linguagem de acao do produto). Agora ela
   e a mesma familia --escuro-* do header — identica nos dois temas, com a
   mesma linha --fss no topo: o header ancora o alto da tela, a barra o rodape.
   Dentro dela o CTA volta a ser a pilula vermelha padrao.
   Raio 18px (< --pilula do botao) de proposito: a pilula do botao precisa ser
   a forma dominante — contorno e conteudo com o mesmo raio competiam. */
.flutuante {
    display: none;
    position: fixed; left: 50%; bottom: 18px; transform: translateX(-50%);
    z-index: 70; max-width: min(620px, 92vw);
    align-items: center; gap: 16px; flex-wrap: wrap;
    background: var(--escuro-fundo); color: var(--escuro-texto);
    /* Borda de 1px = definicao do contorno; a linha --fss no topo e a assinatura
       da marca, o mesmo device do .topo (o header ancora o alto, a barra o pe).
       20% e nao --escuro-borda (14%): diferente do header, esta superficie
       FLUTUA sobre o conteudo, e no tema escuro a pagina (#0D0D14) e quase a
       mesma cor da barra — a 14% o contorno sumia. */
    border: 1px solid color-mix(in srgb, var(--escuro-texto) 20%, transparent);
    border-top: 2px solid var(--fss);
    border-radius: var(--raio-app);
    padding: 11px 12px 11px 20px;
    box-shadow: var(--glow-flutuante);
}
.flutuante.visivel { display: flex; }
.com-flutuante .pagina-home { padding-bottom: 92px; }
/* O texto e o elemento informativo; o rotulo so diz onde voce esta. Por isso o
   peso e a cor plena ficam no texto (16,80:1) e o rotulo recua para
   --escuro-suave (8,34:1), sem o 900 que o tornava o acento mais forte. */
.flutuante_copy { display: grid; gap: 1px; min-width: 0; }
.flutuante_rotulo { font-weight: 600; font-size: var(--tipo-1); letter-spacing: .1em; text-transform: uppercase; white-space: nowrap; color: var(--escuro-suave); }
.flutuante_texto { font-size: var(--tipo-2); font-weight: 600; color: var(--escuro-texto); min-width: 0; }
/* Pilula de acao do CHROME: --fss-acao, branco, alvo 44. Ela e o degrau abaixo
   dos botoes do corpo — 15px contra 17px, e sem o brilho nem a varredura do
   primario (medido em evidencias/w42/escada-depois.txt).

   O comentario anterior dizia "mesma do .nav_cta", o que era falso enquanto
   `.nav_cta` declarava `font-weight: 700` e renderizava 500 — `.nav a` (0,1,1)
   vencia `.nav_cta` (0,1,0) e repintava o peso. CONSERTADO em 01/09/2026 no
   proprio bloco `--- topo ---`: o seletor la virou `.nav a.nav_cta` (0,2,1) e a
   pilula do header renderiza os 700 declarados.
   As duas pilulas seguem DIFERENTES de proposito, e a diferenca e de escada e
   nao de descuido: esta aqui e 800/15px com o brilho da barra flutuante, a do
   header e 700/tipo-2 sem relevo. Nao unificar. */
.flutuante_ir { margin-left: auto; display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; background: var(--fss-acao); color: #fff; text-decoration: none; font-weight: 800; font-size: var(--tipo-2); padding: 11px 20px; border-radius: var(--pilula); min-height: 44px; }
.flutuante_ir:hover { background: var(--fss-acao-hover); }
/* Mesma inversao do header: sobre superficie escura o anel padrao (--fss-acao)
   seria vermelho sobre vermelho. Anel claro com halo escuro da 16,80:1. */
.flutuante_ir:focus-visible { outline-color: var(--escuro-texto); box-shadow: 0 0 0 2px var(--escuro-fundo); }
@media (max-width: 560px) {
    .flutuante { left: 12px; right: 12px; bottom: 12px; transform: none; max-width: none; justify-content: space-between; }
    /* Sem o texto, o rotulo e a unica palavra da barra: assume a cor plena. */
    .flutuante_texto { display: none; }
    .flutuante_rotulo { color: var(--escuro-texto); font-weight: 700; }
}

/* A 320px os CTAs ocupam a linha inteira em vez de espremer o rotulo — mesmo
   comportamento ja adotado em .etapas_nav. A barra flutuante entra na mesma
   regra: a 320 o rotulo e a pilula nao cabem lado a lado, e a pilula empurrada
   para a direita deixava um vazio a esquerda. Rotulo em cima, botao inteiro
   embaixo — dai a barra fica em ~85px e continua dentro dos 92 reservados. */
@media (max-width: 400px) {
    .pagina-home .acoes .btn { flex: 1 1 100%; }
    .flutuante { padding: 10px; gap: 8px; }
    .flutuante_ir { flex: 1 1 100%; justify-content: center; margin-left: 0; }
    /* Em duas linhas a barra passa de 92px: a reserva acompanha, senao o fim do
       rodape fica embaixo dela. */
    .com-flutuante .pagina-home { padding-bottom: 116px; }
}

/* --- home: motion ---
   Tudo opt-in: nada anima para quem pediu menos movimento. Duracoes e curva
   saem de tokens (--dur-*, --curva-suave) — mudar o ritmo da pagina inteira e
   editar o bloco de tokens, nao estas regras. */
@media (prefers-reduced-motion: no-preference) {
    @keyframes home_sobe { from { opacity: 0; transform: translateY(28px); filter: blur(6px); } }
    /* Entrada da peca. Encurtada e com menos desfoque em 13/08/2026: com
       blur(8px) por 840ms o cartao ainda estava borrado enquanto os aneis se
       desenhavam e o score corria — o espetaculo acontecia atras de um vidro
       fosco. Agora o cartao entra em foco em 740ms e a coreografia (que vai ate
       ~2,08s) se le inteira. So .peca usa este keyframe. */
    @keyframes home_chega { from { opacity: 0; transform: translateX(28px) scale(.985); filter: blur(4px); } }
    @keyframes home_deriva { from { transform: translate3d(-1.5%, -1%, 0) scale(1); } to { transform: translate3d(1.5%, 1.5%, 0) scale(1.05); } }
    @keyframes home_flutua { to { transform: translateY(-9px); } }
    @keyframes home_pulsa { 0% { opacity: .9; transform: scale(1); } 70%, 100% { opacity: 0; transform: scale(2.4); } }
    @keyframes home_respira { from { opacity: .5; } to { opacity: 1; } }
    @keyframes home_marquee { to { transform: translateX(-50%); } }
    @keyframes home_arco_pessoas { from { stroke-dashoffset: 552.92; } }
    @keyframes home_arco_processos { from { stroke-dashoffset: 427.26; } }
    @keyframes home_arco_tec { from { stroke-dashoffset: 301.59; } }
    @keyframes home_surge { from { opacity: 0; } }

    .cena_glow { animation: home_deriva var(--dur-glow) ease-in-out infinite alternate; }
    .marquee_track { animation: home_marquee var(--dur-marquee) linear infinite; }
    .hero_chip .ponto::after { animation: home_pulsa var(--dur-pulso) ease-out infinite; }

    .hero_chip           { animation: home_sobe var(--dur-revelar) var(--curva-suave) both; }
    .pagina-home .hero h1 { animation: home_sobe 700ms var(--curva-suave) 90ms both; }
    .pagina-home .sub    { animation: home_sobe var(--dur-revelar) var(--curva-suave) 210ms both; }
    .hero .acoes         { animation: home_sobe var(--dur-revelar) var(--curva-suave) 320ms both; }
    .hero .confianca     { animation: home_sobe var(--dur-revelar) var(--curva-suave) 420ms both; }
    .peca                { animation: home_chega 620ms var(--curva-suave) 120ms both; }
    .peca_cartao         { animation: home_flutua var(--dur-flutua) ease-in-out 1.7s infinite alternate; }
    .peca::before        { animation: home_respira 4.4s ease-in-out 1.7s infinite alternate; }

    /* --- home: coreografia da peca (relatorio-exemplo) ---------------------
       O cartao se apresenta como um instrumento medindo: entra em foco -> tres
       arcos em cascata -> o score contado ate 62 -> as duas primeiras linhas da
       legenda -> uma pausa -> o gargalo -> e, no fim, o AVISO. Terminar no
       "exemplo ilustrativo" e decisao de produto: quem seguiu a animacao ate o
       fim termina no disclaimer, nao no numero.

       A textura tecnica e a grade estatica de .peca_cartao::before (mais acima,
       fora do bloco de motion, porque textura nao e movimento). Uma varredura
       animada chegou a existir aqui e foi REMOVIDA: rodava exatamente sobre a
       entrada do cartao (0-740ms, que sai do desfoque), entao sumia no claro e
       virava uma emenda diagonal no escuro; joga-la para depois arrastaria uma
       faixa vermelha por cima do dado. Um dispositivo so, e o que se le.

       TODO seletor deste bloco comeca em `.peca_cartao`. `.rel_peca` (o
       relatorio REAL, result.php) compartilha .anel, .anel_score, .anel_de e
       .legenda com esta peca — e nao pode encenar nada disso: um cartao de
       dados que o usuario le nao conta o proprio numero na frente dele.
       Escopo verificavel por grep: nenhuma linha daqui cita .rel_peca.

       Dois gatilhos, ambos postos por app.js:
         .peca_pronta  — estado inicial (arcos vazios, score e legenda a zero).
                         So existe quando o JS roda, como .vt-js: sem script o
                         cartao nasce completo e nada fica escondido.
         .peca_anima   — a sequencia, na PRIMEIRA revelacao (IntersectionObserver
                         compartilhado com .vt). Roda uma vez; nao ha loop.

       Linha do tempo, a partir de .peca_anima (total 2,08 s medidos):
         80    arco pessoas ............ 760ms  (fim 840)
         200   arco processos .......... 760ms  (fim 960)
         320   arco tecnologia ......... 760ms  (fim 1080)  <- o gargalo
         280   score aparece ........... 280ms
         320   contador 0->62 (rAF) .... 760ms  (fim 1080, junto com o arco)
         560   legenda pessoas ......... 380ms
         660   legenda processos ....... 380ms
         1160  legenda tecnologia ...... 400ms  (fim 1560, depois da pausa)
         1580  pulso do aviso .......... 500ms  (fim 2080)                    */
    @keyframes peca_linha { from { opacity: 0; transform: translateY(9px); } }
    @keyframes peca_aviso_escala { 45% { transform: scale(1.04); } }
    @keyframes peca_aviso_anel { 0%, 100% { opacity: 0; } 45% { opacity: 1; } }

    /* A sequencia inteira e declarada em .peca_pronta ja PAUSADA, e .peca_anima
       so a solta. Ninguem escreve o estado inicial a mao: com `both`, uma
       animacao pausada na fase de atraso mostra exatamente o proprio primeiro
       keyframe.

       Isso nao e preciosismo — e correcao de um defeito real, encontrado no
       frame de prova em 13/08/2026: escrever o estado inicial como declaracao
       (`.peca_pronta .arco_pessoas { stroke-dashoffset: 552.92 }`) MATAVA a
       animacao. Estes keyframes so tem `from`; o `to` implicito e o valor
       corrente do elemento — que passava a ser o proprio valor inicial. O arco
       animava de 552,92 para 552,92 e o score de opacidade 0 para 0. */
    .peca_cartao.peca_pronta { overflow: hidden; }
    .peca_cartao.peca_pronta .arco_pessoas   { animation: home_arco_pessoas var(--dur-peca-arco) var(--curva-suave) 80ms both paused; }
    .peca_cartao.peca_pronta .arco_processos { animation: home_arco_processos var(--dur-peca-arco) var(--curva-suave) 200ms both paused; }
    .peca_cartao.peca_pronta .arco_tec       { animation: home_arco_tec var(--dur-peca-arco) var(--curva-suave) var(--dur-peca-gargalo) both paused; }
    /* O score so APARECE — quem o move de 0 a 62 e o rAF de app.js. Contador em
       <text> DENTRO de role="img": os filhos sao apresentacionais, entao o
       leitor de tela le o aria-label do <svg> e nunca a contagem. Por isso os
       numeros da legenda, que sao HTML de verdade, NAO contam. */
    .peca_cartao.peca_pronta .anel_score { animation: home_surge 280ms ease-out 280ms both paused; }
    .peca_cartao.peca_pronta .anel_de    { animation: home_surge 380ms ease-out 400ms both paused; }

    /* A cascata da legenda. O shorthand (que carrega o `paused`) fica na regra
       SEM :nth-child de proposito: com a pseudo-classe ela venceria por
       especificidade o gatilho la embaixo, e a legenda nunca apareceria — foi
       o que aconteceu no primeiro frame de prova. As variantes so ajustam
       atraso e duracao.
       A terceira linha e o gargalo: chega depois de uma pausa de 320ms, como
       conclusao, e ja tem o acento --fss-texto que a regra de .gargalo da. */
    .peca_cartao.peca_pronta .legenda li { animation: peca_linha 380ms var(--curva-suave) 560ms both paused; }
    .peca_cartao.peca_pronta .legenda li:nth-child(2) { animation-delay: 660ms; }
    .peca_cartao.peca_pronta .legenda li:nth-child(3) { animation-delay: 1160ms; animation-duration: 400ms; }

    /* O ultimo ato. Pulso UNICO, sem loop: o aviso cresce junto com o
       espetaculo e e onde o olho para. transform + opacity apenas. */
    .peca_cartao.peca_pronta .peca_exemplo { animation: peca_aviso_escala 500ms var(--curva-suave) 1580ms both paused; }
    .peca_cartao.peca_pronta .peca_exemplo::after {
        content: ""; position: absolute; inset: -2px; border-radius: var(--pilula);
        border: 1px solid var(--fss-texto); pointer-events: none;
        animation: peca_aviso_anel 500ms var(--curva-suave) 1580ms both paused;
    }

    /* O gatilho: uma linha solta a sequencia inteira. */
    .peca_cartao.peca_anima .arco,
    .peca_cartao.peca_anima .anel_score,
    .peca_cartao.peca_anima .anel_de,
    .peca_cartao.peca_anima .legenda li,
    .peca_cartao.peca_anima .peca_exemplo,
    .peca_cartao.peca_anima .peca_exemplo::after { animation-play-state: running; }

    .pagina-home .btn, .pagina-home .nav_cta, .pagina-app .btn, .pagina-app .nav_cta,
    .tile, .grandeza, .depo_card, .faq_item, .flutuante_ir, .tema_alterna {
        transition: transform var(--dur-hover) var(--curva-suave), box-shadow var(--dur-hover) var(--curva-suave), border-color var(--dur-hover) var(--curva-suave), background-color var(--dur-micro) ease-out;
    }
    .pagina-home .btn::after, .pagina-app .btn::after { transition: transform var(--dur-revelar) var(--curva-suave); }
    .pagina-home .btn:hover::after, .pagina-app .btn:hover::after { transform: translateX(130%); }
    .pagina-home .btn:hover, .pagina-app .btn:hover { transform: translateY(-2px); }
    .pagina-home .btn:active, .pagina-app .btn:active { transform: translateY(0) scale(.98); }
    .pagina-home .nav_cta:hover, .pagina-app .nav_cta:hover { transform: translateY(-1px); }
    .tile_vidro:hover, .tile_wash:hover, .tile_ink:hover { transform: translateY(-5px); border-color: var(--borda-marca); }
    .grandeza:hover { transform: translateY(-3px); }
    /* `:not(.tema_alterna_item)`: o MESMO botao agora tambem vive dentro do
       controle de conta (onda 72), e la ele e uma LINHA de lista. Sem esta
       excecao, passar o mouse sobre "Tema" levantava so aquela linha 1px
       enquanto Perfil, Administracao e Sair ficavam paradas — a unica linha que
       se mexe volta a ser a mais gritada da lista, que e exatamente o defeito
       que a mudanca de lugar existiu para corrigir. Na barra (o botao redondo)
       o levantar continua valendo. */
    .flutuante_ir:hover, .tema_alterna:not(.tema_alterna_item):hover { transform: translateY(-1px); }
    .faq_item:hover { border-color: color-mix(in srgb, var(--claro-acento) 28%, var(--claro-borda)); }
    /* Aqui mora SO a transicao entre os dois estados do glifo; a rotacao em
       [open] esta na regra de cima e sobrevive ao reduce, porque ela diz
       "aberto", nao "movimento". */
    .check input::before { transition: transform var(--dur-micro) var(--curva-suave); }
    .check input { transition: background-color var(--dur-micro) ease-out, border-color var(--dur-micro) ease-out; }

    .faq_plus,
    .reenvio_glifo,
    .pnl_dobra_glifo { transition: transform var(--dur-hover) var(--curva-suave), background-color var(--dur-micro) ease-out; }
    .faq_item summary { transition: background-color var(--dur-micro) ease-out; }
    /* O SEGUNDO RELOGIO DA HOME, RECOLHIDO (25/08/2026).

       Os links do rodape declaravam a propria transicao FORA deste bloco:
           transition: color var(--dur-micro, 150ms) var(--curva, ease-out);
       Duas coisas erradas numa linha so. A curva era --curva (ease-out), e o
       resto da home anda em --curva-suave — um relogio a mais numa pagina que
       agora tem um. E, por estar fora do gate, ela era a UNICA animacao da home
       que continuava rodando para quem pediu menos movimento: o bloco de reduce
       nao a alcancava, porque ela nunca esteve aqui dentro.

       (Os fallbacks `, 150ms` e `, ease-out` tambem eram letra morta: os dois
       tokens existem desde que a folha existe.) */
    .rodape_links a,
    .rodape_legal a { transition: color var(--dur-micro) var(--curva-suave); }
    /* A ABERTURA desliza; o FECHAMENTO estala, e continua nativo. Animar o
       fechamento pedia ::details-content (sem suporte largo ainda) ou um
       accordion de JS no lugar de um <details> que ja funciona — os dois
       custam mais do que os 260ms valem.
       O deslize depende de o motor guardar o estilo do conteudo fechado
       (content-visibility). Onde ele o esconder com display:none, a linha nasce
       ja em 1fr e a abertura estala — mesma tela, sem o deslize. Degradacao
       aceita de proposito: o conteudo nunca depende da transicao. */
    .faq_revela { transition: grid-template-rows var(--dur-hover) var(--curva-suave); }
    .flutuante.visivel { animation: home_sobe var(--dur-revelar) var(--curva-suave) both; }

    /* Revelacao por rolagem, sem JS onde o navegador ja sabe fazer.

       `forwards`, E NAO `both` — o conserto de 20/08/2026, e ele nao e cosmetico.

       O QUE ACONTECIA. Com `both`, a animacao pinta tambem a FASE ANTES do
       intervalo: enquanto o elemento nao comecou a entrar, ele fica no primeiro
       quadro — `opacity: 0` no .vt, `scaleX(0)` na barra de pilar. Como o
       intervalo so comeca quando a borda do elemento toca o fim da viewport,
       "antes" quer dizer, na pratica, TUDO O QUE ESTA ABAIXO DA DOBRA. O estado
       inicial e invisivel, e ele so sai de la se houver rolagem REAL.

       O QUE ISSO CUSTOU, DUAS VEZES. Capturas de pagina inteira sairam em
       branco (o CDP compoe alem da viewport sem disparar rolagem), e — pior —
       a varredura de acessibilidade PULOU METADE DA PAGINA: o axe trata
       `opacity: 0` como conteudo oculto e nao mede o que nao ve. Uma auditoria
       acusou 2 violacoes onde havia 10. Quem paga a conta nao e so o
       instrumento: e qualquer pessoa que abra a tela numa janela alta, com
       zoom, ou que simplesmente nao role — o dado da barra de pilar fica em
       zero para sempre, e zero e um numero, nao uma ausencia.

       O CONSERTO. `forwards` remove a fase ANTES do preenchimento e deixa so a
       fase DEPOIS. Medido em 20/08/2026, quadro a quadro, com e sem rolagem:
       DENTRO do intervalo os valores sao identicos aos de `both` (0,018 ->
       0,245 -> 0,427 -> ... -> 1), entao a revelacao que a pessoa ve ao rolar
       nao muda em nada. FORA dele, o elemento passa a nascer no proprio estilo
       base: visivel. E como o intervalo comeca exatamente onde 0px do elemento
       aparecem, nao existe quadro em que a diferenca esteja na tela.

       Em outras palavras: o enfeite continua igual para quem rola, e deixou de
       decidir se o conteudo existe para quem nao rola. Que e o que o comentario
       do fallback logo abaixo ja prometia — e o caminho do CSS nao cumpria.

       A SEGUNDA METADE DO CONSERTO: A REVELACAO NAO MEXE MAIS EM `opacity`.

       `forwards` resolve a fase ANTES (abaixo da dobra). Sobra a fase ATIVA — e
       ela tambem cegava, de um jeito mais dificil de ver. Medido em /app/empresa
       a 1440x900, sem rolar um pixel: o segundo bloco do formulario comeca em
       816px, entao 84px dele JA APARECEM na tela, e a revelacao o mantinha em
       `opacity: .31` — para sempre, para quem nao rolasse. O axe media 11
       violacoes de contraste em 107 nos por causa disso, e todas eram reais: e
       texto visivel, ilegivel, em regime permanente.

       Nao ha valor de opacidade que resolva: qualquer fracao abaixo de 1 derruba
       o contraste do texto que ela pinta, e o intervalo inteiro existe para
       varrer essa fracao. Entao a revelacao passa a mover, e so mover: 38px de
       subida, mesma curva, mesmo intervalo. O gesto continua; o que sai e a
       unica parte dele capaz de tornar uma palavra ilegivel.

       (E, de quebra, e o gesto mais coerente com "assistente calmo": conteudo
       que se acomoda, em vez de conteudo que pisca.) */
    @supports (animation-timeline: view()) {
        @keyframes home_entra_vista { from { transform: translateY(38px); } }
        @keyframes home_cresce { from { transform: scaleX(0); } }
        .vt { animation: home_entra_vista 1ms linear forwards; animation-timeline: view(); animation-range: entry 0% entry 55%; }
        .preench { animation: home_cresce 1ms var(--curva-suave) forwards; animation-timeline: view(); animation-range: entry 10% entry 70%; }
    }
    /* Fallback: app.js marca .vt-js so quando view() nao existe. Sem JS nada
       recebe a marca e todo o conteudo fica visivel — a revelacao e enfeite,
       nunca o que decide se o texto existe. */
    /* Mesma regra do caminho nativo, pelo mesmo motivo: move, nao apaga. */
    .vt-js { transform: translateY(38px); }
    .vt-js.in { transform: none; transition: transform 740ms var(--curva-suave); }
}

/* O bloco global de reduce (acima) encurta duracoes; estas tres precisam PARAR
   de fato — um ticker congelado no meio da volta e pior que um ticker parado. */
@media (prefers-reduced-motion: reduce) {
    .marquee_track { animation: none !important; transform: none !important; }
    .hero_chip .ponto::after { animation: none !important; opacity: 0; }
    .peca_cartao, .peca::before { animation: none !important; }
}

/* =============================================================================
   --- app --- (relatorio, processamento, diagnostico)
   -----------------------------------------------------------------------------
   Mesma direcao D da home, mesmos TOKENS e, sempre que possivel, os MESMOS
   componentes: .cena, .caps, .secao_head, .tile/.tile_vidro/.tile_ink/
   .tile_wash, .duplo/.muro/.grandeza, .trilho/.preench, .rank, .legenda, .vt.
   Nada aqui inventa cor, raio, sombra ou duracao — se um valor nao sai de
   token, e defeito.

   Escopado em `.pagina-app` (classe do <body>): as telas ainda no desenho
   anterior (auth, empresa, painel, agendamento) nao se mexem enquanto nao
   forem portadas.

   Diferencas deliberadas em relacao a `.pagina-home`:
   - o topo NAO e sticky (o diagnostico ja tem a barra de progresso sticky;
     duas camadas grudadas se cobririam);
   - o corpo usa --texto, nao --texto-suave: relatorio e documento de leitura,
     nao pagina de venda;
   - sem `overflow-x: clip`, para que a medicao de 320px continue honesta.

   Ordem: chrome -> capa -> pilares -> gargalos -> oportunidade -> tabela ->
          processamento -> diagnostico -> motion.
   ============================================================================= */

/* --- app: chrome ---------------------------------------------------------- */
.pagina-app {
    /* O CORPO TAMBEM LE A ESCALA (direcao B, 20/08/2026).

       Sem esta linha, todo texto sem regra propria herdava os 16px do <body> —
       e 16px nao e degrau nenhum acima de 1280px, onde --tipo-3 vale 17. Era o
       tamanho ORFAO que sobrava em cada medida: `.pnl_passo_nome`, o <option>
       de cada <select>, o prefixo do telefone. Nao ha regra nova para eles; ha
       um corpo que finalmente pertence a escala.
       (A home ja fazia isto, com o proprio 1.0625rem fixo.) */
    font-size: var(--tipo-3);
    line-height: 1.65;
    transition: background-color var(--dur-tema) ease-out, color var(--dur-tema) ease-out;
    /* Rodape colado no fim da janela nas telas curtas (espera, erro), sem
       flutuar no meio do nada. .cena e .skip sao fora de fluxo e nao viram
       itens flex. */
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}
.pagina-app main { flex: 1 0 auto; }
.pagina-app main { padding-block: clamp(26px, 4vw, 44px) clamp(56px, 8vw, 88px); }
/* Peso e aperto da direcao D. O TAMANHO nao entra aqui de proposito: quem
   manda no h1 do diagnostico em modo etapa e `.js-etapas-pagina h1`, e uma
   regra de tamanho neste ponto do arquivo o sobrescreveria. */
.pagina-app h1 { font-weight: 900; letter-spacing: -.03em; }
.pagina-app h2 { font-weight: 800; letter-spacing: -.02em; }
.pagina-app .secao { margin-top: clamp(34px, 5vw, 60px); }
/* O header nao tem variante por tela: e a mesma barra escura em todo o portal,
   definida uma vez no bloco `--- topo ---`. O vidro sobre a cena que existia
   aqui saiu junto com o da home. */
.pagina-app .rodape { background: color-mix(in srgb, var(--superficie) 88%, transparent); }
.pagina-app .btn[disabled] { box-shadow: none; }
.pagina-app .btn[disabled]:hover { transform: none; }
.pagina-app code {
    font-family: var(--mono); font-size: var(--tipo-1);
    background: var(--preenchimento); border-radius: var(--raio-p); padding: 2px 6px;
    overflow-wrap: anywhere;
}
.pagina-app .secao_head { max-width: 62ch; }
.pagina-app .secao_head .sub { margin-top: 14px; }
.rel_bloco { margin-top: 26px; }
/* ============================================================================
   DIRECAO B, PARTE 1: UM RAIO SO, E DUAS PINTURAS QUE VIRARAM UMA
   ----------------------------------------------------------------------------
   Estas cinco regras sao o corpo da direcao escolhida. Elas moram AQUI, no
   escopo `.pagina-app`, e nao la em cima nas regras compartilhadas, porque a
   home segue na direcao D — ela nao foi para a mesa de escolha do dono.

   O raio: `.tile`, `.grandeza`, `.card`, `.rel_regra`, `.pnl_passo`,
   `.pnl_ferr`, `.pnl_fecho` e os blocos da calculadora liam TRES raios
   diferentes (22, 18 e 8). Agora leem --raio-app, e so ele. O que continua
   fora e o que nao e superficie: campo (--raio-p), pilula e circulo.
   ============================================================================ */
.pagina-app .tile { border-radius: var(--raio-app); }

/* A LAVAGEM ROSA FUNDIU NO VIDRO.

   `.tile_wash` pintava o cartao inteiro de rosa (--lavagem: 10% da marca sobre
   a superficie) para dizer "olhe para este". Na mesma tela, `.tile_vidro`
   dizia "bloco" com vidro e `.tile_ink` dizia "prioridade" com tinta escura:
   TRES tintas para uma ideia so. A direcao B funde as duas primeiras e deixa a
   funcao numa barra de 4px na borda de inicio — o carimbo de papel.

   POR QUE A BARRA, E NAO UM FUNDO MAIS CLARO: um fundo tingido pinta tambem o
   que ele nao quer enfatizar (o texto corrido, a nota fina, o muro do RF06) e
   arrasta todo mundo para baixo em contraste. A barra enfatiza o BLOCO sem
   tocar em nenhum pixel de texto.

   E ela conserta um defeito de contraste que estava em producao: --texto-suave
   sobre a lavagem clara media 4,34:1 (piso 4,5) e `.caps` sobre a lavagem
   escura media 4,20:1. Ver a nota completa em `.pnl_fecho`, no fim do arquivo.

   `.tile_ink` FICA DE FORA da fusao, de proposito: ela passa a ser a UNICA
   ilha escura do /app e fica mais forte por ser a excecao. Excecao nao precisa
   de truque de cor — precisa ser rara. */
/* A receita subiu para `.tile_wash`, sem escopo de pagina, em 25/08/2026: a
   home passou a usa-la tambem, e manter uma copia identica aqui so criaria dois
   lugares para consertar da proxima vez. O argumento inteiro esta la. */

/* Dentro de um tile, h2 e h3 sao o MESMO degrau visual: o que define o nivel e
   a posicao na arvore do documento, nao o tamanho da letra.
   --tipo-4 (19->22px) no lugar dos 23px fixos: um degrau da escala, e o degrau
   MENOR dos dois candidatos. Titulo de cartao anuncia o que esta logo abaixo,
   nao abre secao — 27px (--tipo-5) o faria competir com o cabecalho da secao. */
.pagina-app .tile h2,
.pagina-app .tile h3 { margin: 14px 0 8px; font-size: var(--tipo-4); font-weight: 800; letter-spacing: -.02em; line-height: 1.15; }
.pagina-app .tile p,
.pagina-app .legenda li,
.pagina-app .rank li,
.pagina-app .barras li { font-size: var(--tipo-2); }
.pagina-app .rank .pos,
.pagina-app .muro { font-size: var(--tipo-1); }
.pagina-app .tile > .acoes { margin-top: 26px; }
.pagina-app .tile > p:first-of-type { margin-top: 0; }
.pagina-app .limite .acoes { margin-top: 26px; }
.pagina-app .limite_texto { font-size: var(--tipo-3); }

/* --- app: capa do relatorio ---
   O eco da home: la a peca aparece rotulada "Exemplo ilustrativo"; aqui e a
   mesma peca com os numeros reais do usuario. Fecha o ciclo da promessa. */
.rel_capa { display: grid; gap: clamp(28px, 4vw, 44px); align-items: center; }
.rel_capa_texto { min-width: 0; }
/* A CAPA E O MAIOR TIPO DO /app, E ELE E O ULTIMO DEGRAU DA ESCALA.
   Era clamp(34 -> 56px), acima de qualquer token. --tipo-6 (28 -> 40px)
   continua sendo, com folga, a maior coisa da pagina — e a 320px o titulo
   passa de 34 para 28px, onde ele disputava a largura com a propria caixa. */
.pagina-app .rel_capa h1 {
    margin: 20px 0 0;
    font-size: var(--tipo-6);
    font-weight: 900; line-height: 1; letter-spacing: -.04em;
    text-wrap: balance; max-width: 16ch;
}
.rel_selos { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 22px 0 0; padding: 0; list-style: none; }
.rel_selo {
    display: inline-flex; align-items: center; gap: 8px;
    font-size: var(--tipo-1); font-weight: 700; letter-spacing: .02em;
    color: var(--texto-suave);
    border: 1px solid var(--borda); border-radius: var(--pilula); padding: 6px 14px;
}
/* O CHIP DE CLASSIFICACAO — a "faixa" da DEC-002 (corrigido em 18/08/2026).
   Ate aqui ele saia em vermelho de marca em TODAS as faixas: "Previsivel" (88)
   vestia o mesmo alarme de "Critico" (18). Cor que nao varia com o dado nao
   informa nada e, no resultado bom, informa o contrario — o mesmo defeito que
   o arco do anel teve ate 17/08 (ver --anel-arco).
   Ele nunca foi migrado para os tokens da DEC-002; os tres tokens ficaram sem
   consumidor quando `.score`/`.faixa` sairam da marcacao na direcao D. Agora
   consome --faixa-fundo/--faixa-texto, e o dia em que a FSS definir cor por
   classificacao muda o TOKEN (ou ele vira variante por classe emitida pelo
   servidor), nunca esta regra.
   A hierarquia contra os selos vizinhos e por CONTRASTE e SUPERFICIE, nao por
   matiz: o vizinho e --texto-suave sem fundo, este e --texto sobre --superficie.

   O NOME. Chamou-se `.rel_selo_marca` ate 18/08/2026, e o nome mentia desde o
   conserto acima: ele nao pinta mais marca — pinta FAIXA, e a cor sai inteira
   de --faixa-fundo/--faixa-texto (:root do style.css, DEC-002). Um seletor
   que promete uma decisao e cumpre outra e o que faz o proximo conserto nascer
   no lugar errado, entao virou `.rel_selo_faixa`. Renomeado nos tres unicos
   consumidores: esta regra, result.php e dashboard.php (duas ocorrencias).
   Quando a FSS definir cor por classificacao, o que muda e o TOKEN — ou o
   servidor emite uma classe de variante por faixa. Nunca esta regra, nunca os
   templates. */
.rel_selo_faixa { color: var(--faixa-texto); background: var(--faixa-fundo); }
.rel_peca { width: min(420px, 100%); justify-self: start; }
/* Cor por token, nunca por faixa — ver --anel-arco no :root. Vale para as duas
   telas que desenham o anel real (relatorio e painel). */
.anel_total .arco_total { stroke: var(--anel-arco); stroke-dasharray: 552.92; }

/* A COR DA FAIXA — DEC-002 revertida em 19/08/2026, a pedido do dono.

   Ate aqui o anel era neutro por decisao registrada: pintar o arco de vermelho
   fazia 85 "Previsivel" desenhar o mesmo alarme que 42 "Instavel". O mapa
   pedido resolve isso pela raiz — a cor VARIA com a faixa, entao 85 e 42 nunca
   mais desenham igual:

     faixas de baixo  -> --erro     (vermelho)
     faixa do meio    -> neutro     (o arco continua como estava)
     faixa do topo    -> --sucesso  (verde)

   O MEIO CALA DE PROPOSITO. Ele e a maior parte da populacao, e uma cor ali nao
   informaria nada: nem alarme nem conquista. Silencio e a informacao correta.

   QUEM DECIDE O NIVEL E O SERVIDOR, nao este arquivo. `data-nivel` vem de
   NivelDaFaixa, que le a POSICAO da faixa nas regras publicadas — renomear
   "Previsivel" ou recortar os limites move a cor junto, sem tocar em CSS. Era
   exatamente a reversibilidade que a DEC-002 prometeu: "variantes por classe
   emitida pelo servidor".

   Os tokens sao os que ja existem (--erro, --sucesso), os mesmos da gramatica
   de cor do resto do painel. Nenhum valor de marca foi inventado (secao 30.7);
   quando o brandbook chegar, muda o token e nenhuma regra daqui se mexe. */
.anel_total[data-nivel="ruim"] .arco_total { stroke: var(--erro); }
.anel_total[data-nivel="bom"] .arco_total { stroke: var(--sucesso); }

/* A pilula da faixa concorda com o anel: sao a mesma afirmacao, e o chip fica a
   150px do arco. Cor de TEXTO, nao de fundo — o fundo colorido brigaria com o
   contraste em 13px negrito, e a palavra ja carrega o significado sozinha. */
.rel_selo_faixa[data-nivel="ruim"] { color: var(--erro); }
.rel_selo_faixa[data-nivel="bom"] { color: var(--sucesso); }
.anel_total .trilha { stroke: var(--anel-trilha); }
@media (min-width: 900px) {
    .rel_capa { grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr); gap: 56px; }
    .rel_peca { justify-self: end; }
}

/* --- app: pilares ---
   Lista dirigida por dado (o questionario define quantas dimensoes existem),
   por isso barra e nao rosca de N fatias. Reusa .trilho/.preench da home.
   Dimensao sem resposta tem score null e NAO vira zero: nao ganha barra. */
.rel_pilares { list-style: none; margin: 26px 0 0; padding: 0; display: grid; gap: 18px; }
.rel_pilar { display: grid; gap: 8px; }
.rel_pilar_topo { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.rel_pilar_nome { font-weight: 700; font-size: var(--tipo-3); color: var(--texto); }
.rel_pilar_valor { font-family: var(--mono); font-variant-numeric: tabular-nums; font-weight: 800; font-size: var(--tipo-3); color: var(--texto); }
.rel_pilar_nota { font-size: var(--tipo-1); color: var(--texto-fraco); margin: 0; }
.rel_pilar_gargalo .rel_pilar_nome, .rel_pilar_gargalo .rel_pilar_valor { color: var(--fss-texto); }
.preench.rel_barra { background: var(--texto-suave); }
.rel_pilar_gargalo .preench.rel_barra { background: var(--fss); }
/* Sem base de calculo: trilho vazio e tracejado, para nao parecer pontuacao 0. */
.rel_pilar_vazio .trilho { background: transparent; border: 1px dashed var(--contorno); }
/* Empate geral: o .rank destaca o primeiro item por padrao, e ali isso seria
   apontar um gargalo que o calculo nao produziu. */
.rank_empate li:first-child .nome,
.rank_empate li:first-child .pos,
.rank_empate li:first-child .valorb { color: inherit; font-weight: inherit; }
.rank_empate li:first-child .valorb { font-weight: 700; color: var(--texto); }

/* --- app: oportunidade (RF06) ---
   As duas grandezas usam a MESMA gramatica da home: dois cartoes com o muro
   "nunca se somam" entre eles. Perda atual e a distancia ate o benchmark no
   volume de hoje; potencial futuro e o ganho ALEM desse mesmo benchmark.
   Somar contaria o mesmo ganho duas vezes — por isso nao existe total. */
.pagina-app .duplo { margin-top: 30px; }
.pagina-app .grandeza { padding: 24px 26px; border-radius: var(--raio-app); }
.pagina-app .grandeza_valor { font-size: clamp(1.25rem, 5.4vw, 2.125rem); }
.rel_grandeza_ano { display: block; margin-top: 10px; font-family: var(--mono); font-variant-numeric: tabular-nums; font-size: var(--tipo-2); font-weight: 700; color: var(--texto-suave); }
/* SUPERFICIE SOLIDA, e a MESMA dos dois cartoes que a nota explica.
   Ate 18/08/2026 o fundo era --painel (vidro). No tema claro esse vidro e um
   escurecimento (4,5% de --texto sobre o que estiver atras) e a caixa mora
   dentro de `.tile_wash`: o resultado composto era #D9CAD1, mais escuro que a
   propria lavagem, e --texto-suave caia para 3,97:1 — reprovado. Vidro sobre
   superficie ja tingida empilha duas reducoes de contraste; a segunda ninguem
   ve ao escolher a cor do texto.
   Trocar o FUNDO, e nao o texto, foi deliberado: este e o texto do RF06 e ele
   nao pode mudar de peso na hierarquia por causa de um conserto de contraste.
   --painel-solido e o mesmo fundo de `.grandeza`, entao a nota passa a ler
   como parte do mesmo bloco que ela explica.
   Medido no pixel renderizado em 18/08/2026: claro 4,00:1 -> 4,92:1 (fundo
   #D9CBD1 -> #E1E4E9); escuro 5,59:1 -> 6,84:1 (#392930 -> #1D1D24). */
.rel_regra {
    margin: 22px 0 0; padding: 18px 22px;
    background: var(--painel-solido); border: 1px solid var(--borda-marca); border-radius: var(--raio-app);
    font-size: var(--tipo-2); color: var(--texto-suave);
}

/* A CAIXA acompanha a largura dos cartoes; o TEXTO e que tem medida.
   Antes, o max-width de 74ch estava na propria caixa: ela parava bem antes
   da borda dos cartoes acima e o bloco lia como desalinhado, nao como
   escolha de leitura. Limite de linha e propriedade do texto — moldura
   com borda pertence a grade. */
/* `margin-inline: auto` centraliza o BLOCO de texto dentro da caixa. Sem ele a
   medida de 74ch empilhava a prosa a esquerda e sobrava um vazio grande a
   direita — a caixa parecia meio preenchida. O texto em si segue alinhado a
   esquerda: sao tres linhas, e centralizar linha a linha faria o olho procurar
   o inicio de cada uma. Mesmo ajuste do aviso do painel e do rodape. */
.rel_regra_txt { display: block; max-width: 74ch; margin-inline: auto; }
.rel_regra strong { color: var(--texto); }

/* --- app: tabela de cenarios --- */
.pagina-app table { font-size: var(--tipo-2); }
.pagina-app th { color: var(--texto-fraco); }
.pagina-app td.num, .pagina-app th.num { font-variant-numeric: tabular-nums; }
.pagina-app tbody tr:last-child td { border-bottom: 0; }
.pagina-app .rolagem { margin-top: 22px; }

/* --- app: meta (procedencia do calculo) ------------------------------------
   AQUI MORAVAM `.rel_meta` E `.rel_meta span`, removidas com o markup que as
   usava (onda 69). Era o rodape do relatorio com o hash do calculo e as versoes
   das regras de pontuacao e de qualificacao — identificador interno na tela de
   quem acabou de responder o diagnostico, e com o sufixo `-provisorio` das
   fixtures a reboque. Motivo completo em themes/portal/result.php, no
   comentario que fechou o arquivo; o dado agora vive na ficha do lead em
   /admin. Nao ha outro uso das classes no projeto (grep = 0 fora daqui).
   ------------------------------------------------------------------------- */

/* --- app: processamento ---
   Indicador INDETERMINADO de proposito: nao ha percentual real do calculo,
   e barra que finge progresso e dark pattern (secao 12.6). O elemento nao
   declara aria-valuenow — quem carrega o estado e o texto em role="status". */
/* UM EIXO SO (onda 68).
   Medido em 1440: a secao tinha 640px comecando em x=180 dentro de um .wrap de
   1080 — centro do conteudo em 500 contra centro da janela em 720, 220px de
   deslocamento. E o cartao ainda misturava TRES alinhamentos: o rotulo a
   esquerda, o simbolo e a frase de estado centrados, os ossos ocupando a
   largura toda. Numa tela sem nada para ler alem do proprio aviso, assimetria
   nao tem funcao — ela so faz o cartao parecer deslocado, que foi exatamente o
   relato do dono.
   Isto vale para ESTA tela e so para ela: as demais do /app tem conteudo de
   leitura corrida, onde centralizar seria regressao. */
.rel_espera { display: grid; gap: clamp(22px, 4vw, 34px); max-width: 640px; margin-inline: auto; text-align: center; }
/* A copy nasce com medida de linha propria: centralizado, paragrafo largo
   perde o ponto de retorno da leitura. */
.rel_espera .sub { max-width: 46ch; margin-inline: auto; }
.rel_espera h1 { text-wrap: balance; }
.rel_indeterminada { margin-top: 18px; height: 8px; border-radius: var(--pilula); background: var(--preenchimento); overflow: hidden; position: relative; }
.rel_indeterminada::after {
    content: ""; position: absolute; inset-block: 0; left: 0; width: 40%;
    border-radius: var(--pilula);
    background: linear-gradient(90deg, transparent, var(--fss), transparent);
    transform: translateX(-100%);
}
.rel_status { margin: 14px 0 0; font-size: var(--tipo-2); color: var(--texto-suave); }
/* --- a trilha do calculo (onda 68) ------------------------------------------
   AQUI MORAVA O ESQUELETO (.rel_esqueleto / .rel_osso), removido com o markup
   que o usava: tres pares de ossos prometiam que o conteudo abriria naquele
   lugar e naquela forma, e o relatorio chega por recarga com outra estrutura e
   cinco pilares. Placeholder que nao casa com o que chega e mentira educada.

   O QUE ENTROU NO LUGAR nao e barra e nao mede: sao os tres estados da maquina
   de DiagnosticStatus, cada um um fato do banco. O trilho preenchido conta
   passos CUMPRIDOS — quantidade discreta e verdadeira —, nunca fracao de
   tempo, e ele nao anda sozinho: sem worker, fica em "Na fila" para sempre, e
   e isso que se quer que a pessoa veja.

   MESMA LINGUAGEM VISUAL DA TRILHA DA CALL (.calls_trilha, secao das calls):
   marca redonda, --sucesso para cumprido, --fss-acao pulsando no corrente. As
   duas nao compartilham regra porque tem topologias diferentes (aquela e uma
   linha que quebra, esta e uma grade de colunas iguais com trilho entre as
   marcas) e porque os dois arquivos estao em maos diferentes hoje; unificar
   sob um nome neutro e trabalho de quem tiver as duas telas de uma vez. */
.esp_trilha {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    width: min(400px, 100%);
    /* A margem de baixo existe porque o vizinho seguinte (`.nota_fina`) traz
       so 16px: sem ela o rotulo do passo encosta na frase e as duas viram um
       paragrafo so. */
    margin: 28px auto 14px;
    padding: 0;
    list-style: none;
}
.esp_passo {
    position: relative;
    display: grid;
    justify-items: center;
    gap: 10px;
    font-size: var(--tipo-1);
    color: var(--texto-fraco);
    /* A troca de estado nao pisca: ela atravessa, no relogio do /app. */
    transition: color var(--dur-hover) var(--curva-suave);
}
/* O TRECHO DE TRILHO QUE CHEGA NESTE PASSO. Com todas as colunas em 1fr,
   `left: -50%` sai do centro da coluna anterior; os 13px de cada lado abrem o
   vao ao redor das marcas, o que dispensa pintar fundo atras delas — e fundo
   solido sobre o cartao de vidro apareceria como remendo. */
.esp_passo::before {
    content: "";
    position: absolute;
    top: 6px;
    left: calc(-50% + 13px);
    width: calc(100% - 26px);
    height: 2px;
    border-radius: var(--pilula);
    background: var(--contorno);
    transition: background-color var(--dur-hover) var(--curva-suave);
}
.esp_passo:first-child::before { content: none; }
.esp_passo_marca {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    border: 2px solid var(--texto-fraco);
    transition: background-color var(--dur-hover) var(--curva-suave),
                border-color var(--dur-hover) var(--curva-suave),
                box-shadow var(--dur-hover) var(--curva-suave);
}
/* TRES PORTADORES em cada estado, e nenhum deles e animacao: forma da marca
   (vazada / cheia), cor e peso do rotulo. Quem desliga o movimento continua
   lendo a trilha inteira — e o axe tambem, que so ve o quadro parado. */
.esp_passo[data-estado="feito"] { color: var(--texto-suave); }
.esp_passo[data-estado="feito"] .esp_passo_marca { background: var(--sucesso); border-color: var(--sucesso); }
.esp_passo[data-estado="agora"] { color: var(--texto); font-weight: 600; }
.esp_passo[data-estado="agora"] .esp_passo_marca { background: var(--fss-acao); border-color: var(--fss-acao); }
/* O trilho enche ATE o passo corrente: o trecho antes dele corresponde a um
   passo que terminou de verdade. */
.esp_passo[data-estado="feito"]::before,
.esp_passo[data-estado="agora"]::before { background: var(--sucesso); }

/* --- app: diagnostico ---
   Mudanca deliberadamente minima: tokens, superficie e micro-motion. A
   estrutura do stepper (secao 12.6) nao se mexe — .js-etapas, [data-pergunta],
   [data-etapa], [data-final], .contador, .pendentes e .ligacao seguem sendo
   contrato com o app.js. */
.diag_wrap { max-width: 820px; }
.progresso_linha { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.progresso .barra { margin-top: 8px; }
.diag_titulo { margin-top: 24px; }
.diag_nota { margin-top: 12px; }
.pagina-app .progresso {
    background: color-mix(in srgb, var(--fundo) 86%, transparent);
    -webkit-backdrop-filter: blur(12px) saturate(1.15);
    backdrop-filter: blur(12px) saturate(1.15);
}
/* A CENA BAIXA DE VOLUME NO /app INTEIRO (direcao B, 20/08/2026).

   Nao some: e o mesmo lugar, com o volume mais baixo — que e o que "calmo"
   quer dizer aqui. O corte e de ~45% em cada tema, feito no TOKEN e nao numa
   opacidade posta por cima da cena: mexer no token mantem a proporcao entre o
   glow e o ruido, e a cena continua sendo uma coisa so.

   O par escuro precisa ser escrito a mao pelo mesmo motivo do `.cena_discreta`
   logo abaixo: --cena-intensidade e declarado no :root por tema, e o valor
   posto no <body> vence a heranca — sem o par, o /app escuro voltaria ao
   volume cheio. */
.pagina-app { --cena-intensidade: .3; --cena-ruido: .1; }
[data-tema="escuro"] .pagina-app { --cena-intensidade: .55; --cena-ruido: .28; }
@media (prefers-color-scheme: dark) {
    :root:not([data-tema]) .pagina-app { --cena-intensidade: .55; --cena-ruido: .28; }
}

/* A cena em volume ainda mais baixo: o diagnostico e tela de trabalho. Um
   token, nao um segundo desenho — no escuro ela ja nasce mais forte, entao o
   corte e maior. */
.cena_discreta { --cena-intensidade: .12; --cena-ruido: .06; }
[data-tema="escuro"] .cena_discreta { --cena-intensidade: .34; --cena-ruido: .3; }
@media (prefers-color-scheme: dark) {
    :root:not([data-tema]) .cena_discreta { --cena-intensidade: .34; --cena-ruido: .3; }
}
.pagina-app .card {
    background: var(--painel-solido);
    border-radius: var(--raio-app);
    box-shadow: var(--elev-1);
    padding: clamp(20px, 3vw, 30px);
}
.pagina-app .pergunta_titulo { font-weight: 800; letter-spacing: -.01em; }
.pagina-app .opcao { border-radius: var(--raio-p); background: var(--fundo); }
.pagina-app .opcao:hover { background: var(--preenchimento); }
.pagina-app .barra { background: var(--preenchimento); }
.pagina-app .estado { font-weight: 700; }

/* --- app: motion ---
   Opt-in, como na home: nada se move para quem pediu menos movimento. */
@media (prefers-reduced-motion: no-preference) {
    @keyframes app_arco { from { stroke-dashoffset: 552.92; } }
    @keyframes app_surge { from { opacity: 0; } }
    @keyframes app_varre { from { transform: translateX(-100%); } to { transform: translateX(320%); } }
    @keyframes app_sobe { from { opacity: 0; transform: translateY(22px); filter: blur(5px); } }

    .anel_total .arco_total { animation: app_arco var(--dur-anel) var(--curva-suave) 220ms both; }

    /* O NUMERO CHEGA COM O ARCO, nao depois dele.
       `app_surge` era so opacidade: o 81 piscava no lugar enquanto o arco ainda
       corria. Um respiro de escala amarra os dois — o numero nasce do centro do
       anel que acabou de se desenhar. 4% de escala, nao mais: acima disso o
       algarismo passa a "saltar" e vira enfeite pedindo atencao para si. */
    @keyframes app_score { from { opacity: 0; transform: scale(.96); } }
    .anel_total .anel_score {
        animation: app_score var(--dur-revelar) var(--curva-suave) 420ms both;
        transform-origin: 110px 118px;
    }
    .anel_total .anel_de { animation: app_surge var(--dur-revelar) ease-out 560ms both; }

    /* AS BARRAS DE PILAR SEGUIAM A ROLAGEM, E ESTE CARTAO NASCE ACIMA DA DOBRA.

       `.preench` tem revelacao por rolagem (animation-timeline: view(), na secao
       da home). Para o cartao de score isso nunca dispara: quando a pagina abre,
       ele ja esta em vista e o intervalo `entry 10% -> entry 70%` ja passou —
       a barra nasce no estado final. O resultado era um cartao que animava pela
       METADE: o anel preenchia e as tres barras ao lado ja estavam prontas.

       Aqui a linha do tempo e o RELOGIO. `animation-timeline: auto` vai
       explicito: o atalho `animation` reseta o longhand, mas depender disso e
       depender de uma sutileza de cascata que a proxima leitura nao tem por que
       conhecer.

       Elas entram DEPOIS do anel (560ms contra 220ms) porque a leitura e essa:
       primeiro a nota, depois de onde ela vem. */
    @keyframes app_cresce { from { transform: scaleX(0); } }
    .pnl_pilar .preench.pnl_barra {
        animation: app_cresce var(--dur-revelar) var(--curva-suave) 560ms both;
        animation-timeline: auto;
    }
    .pnl_pilares li:nth-child(2) .preench.pnl_barra { animation-delay: 650ms; }
    .pnl_pilares li:nth-child(3) .preench.pnl_barra { animation-delay: 740ms; }

    .pagina-app .rel_capa .caps { animation: app_sobe var(--dur-revelar) var(--curva-suave) both; }
    .pagina-app .rel_capa h1 { animation: app_sobe var(--dur-revelar) var(--curva-suave) 80ms both; }
    .pagina-app .rel_capa .sub { animation: app_sobe var(--dur-revelar) var(--curva-suave) 180ms both; }
    .rel_selos { animation: app_sobe var(--dur-revelar) var(--curva-suave) 260ms both; }
    .rel_peca { animation: app_sobe 760ms var(--curva-suave) 140ms both; }

    .rel_indeterminada::after { animation: app_varre 1.7s var(--curva-suave) infinite; }

    /* A UNICA COISA QUE SE MOVE NA TRILHA E O PASSO CORRENTE, e o halo cresce
       em `box-shadow` — animar o tamanho da marca reflui a coluna e faz o
       rotulo dancar a cada batida. O ritmo e mais lento que o do simbolo 3D de
       proposito: dois pulsos no mesmo compasso viram um so, e a leitura de
       "duas coisas acontecendo" e o que da a sensacao de avanco. */
    @keyframes esp_pulso {
        0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--fss-acao) 50%, transparent); }
        50%      { box-shadow: 0 0 0 8px color-mix(in srgb, var(--fss-acao) 0%, transparent); }
    }
    .esp_passo[data-estado="agora"] .esp_passo_marca { animation: esp_pulso 2s ease-in-out infinite; }

    /* UM RELOGIO SO (direcao B, 20/08/2026).

       Antes conviviam TRES ritmos de hover na mesma tela: 260ms/--curva-suave
       para transform, sombra e borda (regra compartilhada com a home);
       140ms/ease-out para o FUNDO, dentro dessa mesma regra; e 140ms/ease-out
       sozinho na opcao do diagnostico e no botao terciario. Cada peca era
       coerente por dentro e discordava das vizinhas — o sintoma que a direcao
       chamou de "volume alto".

       Nao ha efeito novo aqui: e o que ja existia, acertado no mesmo compasso.
       Uma regra so declara o relogio de TODO alvo interativo do /app, entao a
       proxima peca nasce no ritmo certo por herdar a lista, e nao por alguem
       lembrar de copiar duas duracoes.

       As duas regras que este bloco substituiu (`.pagina-app .opcao` e
       `.pagina-app .ligacao`, ambas em --dur-micro) foram REMOVIDAS, e nao
       sobrescritas: sobrescrever deixaria os dois ritmos no arquivo, e o
       proximo leitor teria de descobrir qual vence. */
    .pagina-app .btn,
    .pagina-app .btn_sec,
    .pagina-app .ligacao,
    .pagina-app .nav_cta,
    .pagina-app .tile,
    .pagina-app .grandeza,
    .pagina-app .opcao,
    .pagina-app .pnl_ferr,
    .pagina-app .pnl_ferr_alvo,
    .pagina-app .pnl_dobra > summary,
    .pagina-app .pnl_dobra_glifo {
        transition: background-color var(--dur-hover) var(--curva-suave),
                    border-color var(--dur-hover) var(--curva-suave),
                    box-shadow var(--dur-hover) var(--curva-suave),
                    color var(--dur-hover) var(--curva-suave),
                    transform var(--dur-hover) var(--curva-suave);
    }
}

/* Sob reduce o indicador nao pode congelar no meio da varredura (leria como
   percentual falso): vira faixa listada estatica, sem posicao nenhuma. */
@media (prefers-reduced-motion: reduce) {
    .rel_indeterminada::after {
        animation: none !important; transform: none !important;
        width: 100%;
        background: repeating-linear-gradient(115deg, var(--contorno) 0 10px, transparent 10px 22px);
    }

    /* A TRILHA NAO PRECISA DE REGRA AQUI, e isso e o resultado, nao o
       esquecimento: `esp_pulso` nasceu dentro do bloco `no-preference`, e cor,
       forma e peso — os tres portadores do estado — nao dependem de animacao
       nenhuma. Quem pediu menos movimento ve a MESMA trilha, so que quieta:
       continua sabendo em que passo o calculo esta e quantos ja passaram.
       O que muda para essa pessoa e a chegada — o app.js recarrega direto, sem
       a saida em fade, porque fazer alguem esperar um efeito que nao vai
       acontecer e so lentidao. */
}

/* --- rodape --- */
.rodape { border-top: 1px solid var(--borda); padding: 28px 0; color: var(--texto-suave); font-size: var(--tipo-2); background: var(--superficie); }
.rodape_aviso { max-width: 70ch; font-size: var(--tipo-1); }

/* Aviso legal e copyright CENTRALIZADOS: sao o fecho da pagina, nao conteudo de
   leitura corrida. O `>` limita aos filhos diretos do .wrap — os paragrafos das
   colunas da home vivem dentro de .rodape_grid e continuam alinhados a esquerda.
   `margin-inline: auto` centraliza o BLOCO (o aviso tem max-width); `text-align`
   sozinho so centralizaria as linhas dentro de uma caixa ainda encostada. */
.rodape .wrap > .rodape_aviso,
.rodape .wrap > p { text-align: center; margin-inline: auto; }

/* OS DOIS LINKS LEGAIS DO RODAPE DO PORTAL (onda 51).

   Eles nasceram em 26/08/2026, quando a linha de Termos/Privacidade deixou de
   ser condicional, e nasceram SEM ESTILO: caiam no padrao do navegador — azul,
   roxo quando visitado, sublinhado colado. E o mesmo defeito que o bloco
   `.rodape_links` mais acima ja documenta ter corrigido uma vez ("entregava o
   historico de navegacao do visitante"), de volta por uma porta nova.

   Aqui o sublinhado FICA no repouso, ao contrario daquele bloco. La o texto ao
   redor tinha cor diferente do link; aqui o rodape inteiro e --texto-suave, e
   sem o traco o link nao se distinguiria do aviso ao lado por nada alem de
   peso (WCAG 1.4.1). */
.rodape .wrap > p a {
    color: var(--texto);
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: .22em;
    text-decoration-thickness: 1px;
    text-decoration-color: var(--contorno-forte);
    border-radius: 4px;
}
.rodape .wrap > p a:hover { color: var(--fss-texto); text-decoration-color: currentColor; }
.rodape .wrap > p a:focus-visible { outline: 2px solid var(--fss-acao); outline-offset: 3px; }

/* Abaixo de 640px a barra vira duas linhas (logo em cima, menu embaixo) em vez
   de espremer as duas metades: a 320px o menu anonimo — Entrar + pilula + botao
   de tema — mede ~259px numa linha de 294px (a .wrap de 92vw), entao cabe
   inteiro sem quebrar palavra nem estourar a largura. */
@media (max-width: 640px) {
    .topo_inner { flex-direction: column; align-items: flex-start; gap: var(--esp-3); padding: 14px 0; }
    .marca_logo { height: 30px; }
    /* row-gap menor que column-gap: no pior caso (qualificado, quatro itens) o
       menu ocupa duas linhas, e 16px entre elas empurrariam a barra para perto
       de 200px de altura numa tela de 320. */
    .nav { column-gap: var(--esp-4); row-gap: var(--esp-2); }
    /* Aqui a barra e uma COLUNA alinhada a esquerda: ancorar a conta na ponta
       direita a mandaria para longe dos vizinhos, sozinha na margem oposta a de
       todo o resto. O `auto` do bloco base existe para a barra DEITADA. */
    .nav_conta { margin-left: 0; }
    /* A MARGEM VOLTA A SER A DA PAGINA quando a barra empilha (onda 72).
       O gutter constante de 24px do bloco base foi medido para MONITOR, onde ele
       devolve largura a barra. No telefone ele faz o contrario: a 375px daria
       327px de cabecalho contra os 345 da `.wrap` do conteudo — a logo entraria
       9px para dentro da margem do texto que vem logo abaixo. Aqui a barra nao
       disputa espaco com ninguem (ela e uma coluna), entao o que importa e
       alinhar: 92vw e exatamente a medida da `.wrap`. */
    .topo_inner { width: min(1240px, 92vw); }
    /* O FIO DO GRUPO SAI QUANDO A BARRA EMPILHA (onda 72).

       MEDIDO a 375px: com a barra em coluna, o menu quebra onde couber, e ali
       "Curso" calhava de ABRIR uma linha. O fio mora na margem negativa do
       primeiro item do grupo — feita para cair no MEIO do vao entre dois itens —,
       entao, sem vizinho a esquerda, ele ia parar em x=16 contra uma caixa que
       comeca em 24: um risco solto para fora da margem da tela.

       Nao ha como perguntar em CSS "voce abriu a linha?", e a resposta certa nao
       e apertar o desenho ate o defeito ficar pequeno: no telefone o grupo ja se
       le pela ORDEM (os tres entregaveis vem juntos, sempre), e um fio que
       aparece em lugar sorteado a cada largura diz menos que fio nenhum. */
    .nav_grupo > a:first-child { border-left: 0; padding-left: 0; margin-left: 0; }
    .card { padding: 18px; }

    /* O header vira duas linhas aqui: 3 (linha da marca) + 14 + 30 (logo) + 12
       (gap) + 44 (a linha do menu) + 14 + 1 = 118px, + 12 de folga. O cartao
       passa a ocupar a largura util, porque a 320px `min(384px, ...)` ja daria
       a largura inteira de qualquer forma — explicitar evita depender do
       clamp. LIMITE CONHECIDO: com sessao aberta e menu em DUAS linhas (o pior
       caso, quatro itens a 320px) o cartao cobre a segunda linha do menu por
       alguns segundos. E sobreposicao de aviso, nao perda: o menu volta
       inteiro assim que o toast fecha, e o erro so fecha por acao do usuario. */
    :root { --toast-topo: 130px; --toast-lado: 12px; }
    /* Classe DOBRADA porque a regra que ela ajusta mora em comum/toast.css e ja
       vem dobrada (0,2,0) para nao depender de ordem. Com 0,1,0 aqui, a largura
       do cartao continuaria a do desktop e este ajuste seria silenciosamente
       ignorado — geometria e a unica coisa que cada produto sobrescreve. */
    .toast_ativo.toast_ativo { left: var(--toast-lado); width: auto; }
}

/* A partir de 320px: os botoes de etapa ocupam a largura inteira em vez de
   espremer o rotulo, e nada estoura a linha. */
@media (max-width: 400px) {
    /* Em 320px o par nao cabe lado a lado sem espremer o rotulo. "Proxima"
       assume a linha inteira e "Anterior" fica abaixo, discreto: a ordem
       vertical passa a ser a ordem de importancia, que e a mesma que a
       horizontal dizia com o vao. */
    .etapas_nav { flex-wrap: wrap; }
    /* DUAS COISAS PRECISAM SER VERDADE PARA A QUEBRA ACONTECER, e cada uma ja
       falhou sozinha aqui:

       `flex-shrink: 0` — com o padrao 1, a base de 100% CEDE e os dois voltam a
       caber lado a lado; a quebra so ocorre se o item for proibido de encolher.

       `.etapas_nav .btn` na frente — a regra larga acima e (0,2,0) e `.etapas_seguir`
       sozinho e (0,1,0). Media query nao acrescenta especificidade nenhuma, entao o
       `flex: none` de cima vencia dentro do @media e o ajuste parecia ignorado. */
    .etapas_nav .btn.etapas_seguir { flex: 1 0 100%; margin-left: 0; order: -1; }
    .etapas_nav .btn.etapas_voltar { flex: none; }
    .opcao { padding: 12px; }
}

/* =====================================================================
   AUTENTICACAO — entrar, criar conta, recuperar/redefinir senha
   =====================================================================
   Escopado em .pagina-auth: nada daqui vaza para as outras telas, mesmo
   reusando nomes (.campo, .btn, .card).

   O que estava errado antes e por que cada correcao existe:

   1. LINKS SEM ESTILO. "Esqueci minha senha" e "Criar conta" caiam no
      padrao do navegador — azul, roxo quando visitado, sublinhado colado.
      Num formulario de credencial isso destoa de tudo e ainda entrega o
      historico de navegacao de quem olha a tela por cima do ombro.
   2. PREENCHIMENTO AUTOMATICO. O Chrome pinta o campo autopreenchido com
      um azul proprio que ignora o tema: o campo de senha ficava com fundo
      diferente do de e-mail na mesma tela. `-webkit-autofill` so aceita
      ser sobrescrito por `box-shadow inset` — `background-color` nao pega.
   3. SEM IDENTIDADE. Era um cartao cinza no vazio. Agora divide a tela com
      um painel de marca que carrega a mesma cena da home; abaixo de 900px
      o painel sai e o formulario ocupa tudo, porque em celular quem chegou
      aqui quer digitar, nao ler.
   ===================================================================== */

.pagina-auth main { display: flex; align-items: center; min-height: calc(100vh - 220px); padding-block: var(--esp-6) var(--esp-7); }

/* SEM `width` aqui: este elemento tambem carrega .wrap, que ja define
   `width: min(1080px, 92vw)` + `margin-inline: auto`. Declarar `width: 100%`
   nesta regra sobrescrevia aquela (mesma especificidade, esta vem depois no
   arquivo) e o painel de marca ia colar na borda da janela. */
/* `start`, e nao `center` (onda 51): centrado, o painel de marca flutuava no
   meio de uma coluna vazia — com o cadastro aberto, o cartao mede 1106px e a
   promessa comecava em y=299, ABAIXO do titulo do formulario. As duas colunas
   sao dois comecos de leitura, e comeco de leitura se alinha pelo topo. */
.autenticar { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 440px); gap: var(--esp-7); align-items: center; }
/* `start` SO NA PORTA DE ENTRADA. Nas outras telas de auth o cartao e curto e
   o centramento continua sendo a composicao certa; aqui o cartao chega a
   1117px com o cadastro aberto e o centramento empurrava a promessa para
   y=299 — abaixo do titulo do formulario, flutuando numa coluna vazia. Dois
   comecos de leitura se alinham pelo topo. */
.pagina-acesso .autenticar { align-items: start; }

/* O PAINEL QUE EXPLICA O PRODUTO — E QUE NAO PODE MAIS SUMIR NO CELULAR.

   Ate 26/08/2026 este bloco era `display: none` abaixo de 900px, com a razao
   escrita quando havia uma home antes dele: "em celular quem chegou aqui quer
   digitar, nao ler". A home saiu do produto e a regra ficou. Medido a
   320x568, a primeira dobra inteira era o cabecalho + "Entrar" + "Use o
   e-mail com que voce criou a conta": nenhuma das sete mencoes ao
   diagnostico sobrevivia, e quem vem de anuncio encontrava a caixa de login
   de um produto que nunca ouviu falar.

   Ele volta em TODAS as larguras. O que muda no celular e a forma, nao a
   presenca — ver a media query no fim do bloco. */
.autenticar_marca { max-width: 46ch; }
/* `.caps` so tinha regra sob .pagina-home / .pagina-app: aqui o rotulo saia
   SEM ESTILO NENHUM — 16px, peso normal, cor de corpo. As quatro telas de auth
   usam a classe; a regra vale para as quatro. */
.autenticar_marca .caps { display: block; font-size: var(--tipo-1); font-weight: 800; text-transform: uppercase; letter-spacing: .14em; color: var(--fss-texto); margin: 0; }
/* h1 E h2 NA MESMA REGRA, e isso nao e indecisao.
   Na porta de entrada o titulo deste painel e o <h1> da pagina (o assunto e o
   diagnostico, nao o formulario). Nas outras tres telas de auth — recuperar,
   redefinir, confirmar e-mail — o assunto DA pagina e o proprio formulario:
   ali o <h1> fica no cartao e este painel continua com <h2>. Sao dois papeis
   com a mesma aparencia, e escrever so um dos seletores apaga a tipografia de
   tres telas em silencio (achado da auto-revisao desta onda). */
.autenticar_marca h1,
.autenticar_marca h2 { font-size: var(--tipo-5); font-weight: 800; line-height: 1.05; letter-spacing: -.02em; margin: var(--esp-3) 0 var(--esp-4); }
.autenticar_marca .destaque { color: var(--fss-acao); }
.autenticar_marca .sub { color: var(--texto-suave); font-size: var(--tipo-2); line-height: 1.6; margin: 0 0 var(--esp-5); }

/* O cartao. `--elev-2` e a mesma elevacao dos tiles do relatorio: uma
   linguagem de superficie no produto inteiro, nao uma por tela. */
.autenticar_painel { background: var(--superficie); border: 1px solid var(--borda); border-radius: var(--raio); box-shadow: var(--elev-2); padding: var(--esp-6); }
/* O TITULO DO CARTAO E <h2> DESDE A ONDA 51: o <h1> desta pagina passou a ser
   a promessa do produto, e nao o verbo da porta. A regra segue valendo para
   as outras telas de auth (recuperar, redefinir, confirmar), que continuam
   com <h1> proprio porque ali o assunto da pagina E o formulario. */
.autenticar_painel h1,
.autenticar_painel .autenticar_titulo { font-size: var(--tipo-4); font-weight: 800; letter-spacing: -.02em; margin: 0 0 var(--esp-2); }
.autenticar_painel > .sub { color: var(--texto-suave); font-size: var(--tipo-1); line-height: 1.6; margin: 0 0 var(--esp-5); }

/* Nota de sessao ativa na recuperacao de senha. Informativa, nao alarme: usa a
   borda da marca e nao a cor de erro, porque nada deu errado — o portal so esta
   avisando o que vai acontecer com a sessao atual. */
.aviso_sessao {
    margin: 0 0 var(--esp-5); padding: var(--esp-3) var(--esp-4);
    border: 1px solid var(--borda-marca); border-radius: var(--raio-p);
    background: color-mix(in srgb, var(--fss) 6%, transparent);
    color: var(--texto-suave); font-size: var(--tipo-1); line-height: 1.55;
}
.aviso_sessao strong { color: var(--texto); font-weight: 700; overflow-wrap: anywhere; }

.autenticar_form .campo { margin-bottom: var(--esp-4); }

/* CONTEXTO ACIMA DO QUE RECEBE O FOCO (onda 51).

   Quem aterrissa no 422 e o resumo de erros; quem aterrissa depois, ao clicar
   num item do resumo, e o campo. Nos dois casos o navegador encosta o alvo no
   TOPO da janela, sem nada acima — e um campo isolado no topo da tela nao diz
   a que formulario pertence. `scroll-margin-top` nao muda o layout: ele so diz
   ao navegador onde parar. */
.autenticar_form input,
.autenticar_form .telefone,
.autenticar_form .check,
.acesso_falhas { scroll-margin-top: var(--esp-6); }
.autenticar_form label { display: block; font-size: var(--tipo-1); font-weight: 600; color: var(--texto); margin-bottom: 6px; }

/* 48px de altura: alvo confortavel no toque e alinhado ao botao. */
.autenticar_form input[type="text"],
.autenticar_form input[type="email"],
.autenticar_form input[type="tel"],
.autenticar_form input[type="password"] {
    width: 100%;
    min-height: 48px;
    padding: 12px 14px;
    background: var(--campo-fundo, var(--fundo));
    /* 1.4.11: ver a nota de --borda-controle. Com --borda o campo media
       1,35:1 (claro) e 1,32:1 (escuro) contra o cartao, e o preenchimento
       dele nao chegava a 1,1:1 — nada dizia onde o campo comecava. */
    border: 1px solid var(--borda-controle);
    border-radius: var(--raio-p);
    color: var(--texto);
    font: inherit;
    transition: border-color var(--dur-micro) var(--curva), box-shadow var(--dur-micro) var(--curva);
}

.autenticar_form input::placeholder { color: var(--texto-fraco); }

/* FOCO EM NEUTRO, NAO NO VERMELHO DA MARCA.
   A borda de erro tambem e vermelha: com o anel de foco na mesma cor, campo
   focado e campo reprovado ficavam identicos — no /redefinir-senha o campo
   "Nova senha" recem-focado parecia ter falhado na validacao. `--texto` e a
   cor de maior contraste de cada tema, entao o anel aparece sempre e nunca
   compete com o significado do vermelho. */
.autenticar_form input:focus-visible {
    outline: 2px solid var(--texto);
    outline-offset: 2px;
    border-color: var(--texto-suave);
}

/* Campo reprovado na validacao: a borda acompanha o texto do erro que o
   servidor ja imprime — cor nunca e o unico sinal (WCAG 1.4.1). */
.autenticar_form input[aria-invalid="true"] { border-color: var(--erro); }
.autenticar_form input[aria-invalid="true"]:focus-visible { outline-color: var(--erro); border-color: var(--erro); }

/* Preenchimento automatico: ver nota 2 no topo do bloco. */
.autenticar_form input:-webkit-autofill,
.autenticar_form input:-webkit-autofill:hover,
.autenticar_form input:-webkit-autofill:focus {
    -webkit-text-fill-color: var(--texto);
    caret-color: var(--texto);
    box-shadow: 0 0 0 1000px var(--campo-fundo, var(--fundo)) inset;
    transition: background-color 9999s ease-out;
}

/* Campo de senha com o botao de revelar dentro. */
.campo_senha { position: relative; }
.campo_senha input { padding-right: 52px; }
.campo_senha .revelar {
    position: absolute; right: 4px; bottom: 4px;
    width: 44px; height: 40px;
    display: inline-flex; align-items: center; justify-content: center;
    background: none; border: 0; border-radius: var(--raio-p);
    color: var(--texto-suave); cursor: pointer;
}
.campo_senha .revelar:hover { color: var(--texto); }
.campo_senha .revelar:focus-visible { outline: 2px solid var(--fss-acao); outline-offset: 2px; }
.campo_senha .revelar[hidden] { display: none; }

.autenticar_form .btn { width: 100%; justify-content: center; margin-top: var(--esp-2); }

/* `--tipo-0` NAO EXISTE. Esta regra pedia um token inexistente e caia no
   fallback `.8125rem` — 13px literais, o unico tamanho da tela de acesso que
   nao vinha da escala, e por isso o unico que nao acompanharia uma mudanca
   dela. Medido na onda 52 ao contar os degraus de tipo da tela. */
.autenticar_form .dica { font-size: var(--tipo-1); color: var(--texto-fraco); margin: 6px 0 0; }

/* TELEFONE — CONTROLE UNICO (conforme referencia do dono, 14/08/2026)
   Uma borda so envolve pais e numero; o divisor vertical separa os dois.
   A borda vive no CONTAINER e o `:focus-within` a acende — assim o foco de
   qualquer um dos dois controles acende a caixa inteira, que e o que a pessoa
   percebe como "o campo". Os filhos ficam sem borda propria. */
.telefone {
    display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: stretch;
    background: var(--campo-fundo, var(--fundo));
    border: 1px solid var(--borda-controle); border-radius: var(--raio-p);
    min-height: 48px;
    transition: border-color var(--dur-micro) var(--curva);
}
.telefone:focus-within { outline: 2px solid var(--texto); outline-offset: 2px; border-color: var(--texto-suave); }
.telefone:has(input[aria-invalid="true"]) { border-color: var(--erro); }
.telefone:has(input[aria-invalid="true"]):focus-within { outline-color: var(--erro); }

/* O divisor e borda do lado do pais: um elemento a menos no DOM. */
.telefone_pais { position: relative; display: inline-flex; align-items: center; border-right: 1px solid var(--borda-controle); }

.telefone_visual { display: inline-flex; align-items: center; gap: 8px; padding: 0 12px; pointer-events: none; }
.telefone_visual[hidden] { display: none; }
.telefone_ddi { font-variant-numeric: tabular-nums; color: var(--texto); font-weight: 600; }
.telefone_seta { color: var(--texto-fraco); flex: none; }

/* COM JS: o select vira uma camada transparente por cima do visual — o clique
   e o teclado continuam indo para o controle nativo (que abre a lista do
   sistema, com o nome dos paises), mas quem se ve e a dupla bandeira + DDI.
   SEM JS: nada disso se aplica, o select aparece com o nome do pais escrito e
   o campo continua utilizavel. */
.telefone .ddi_select {
    min-height: 46px; border: 0; background: none; color: var(--texto);
    font: inherit; padding: 0 10px; max-width: none;
}
.telefone .ddi_select:focus-visible { outline: none; }

.js-ddi .telefone_pais .ddi_select {
    position: absolute; inset: 0; width: 100%; height: 100%;
    opacity: 0; cursor: pointer; padding: 0;
}

/* 12px de recuo lateral, e nao 14 (onda 51). Medido a 320px: a caixa inteira
   fica com 260px, o bloco do pais come 106 e sobram 153 para o numero — 125
   de conteudo com 14px de cada lado. O placeholder "(11) 90000-0000" mede
   exatamente 125px na fonte do portal, e aparecia cortado no ultimo digito.
   Dois pixels de cada lado resolvem sem mexer em tipo nem em altura. */
.telefone input[type="tel"] {
    border: 0; background: none; min-height: 46px;
    padding: 12px; color: var(--texto); font: inherit; width: 100%;
    font-variant-numeric: tabular-nums;
}
.telefone input[type="tel"]:focus-visible { outline: none; }

.bandeira { display: block; border-radius: 2px; box-shadow: 0 0 0 1px rgba(15, 18, 32, .18); flex: none; }
.bandeira[hidden] { display: none; }

/* CADASTRO — o cartao denso.
   Sao 7 campos. Com a largura padrao (440px) a coluna interna fica em 374px,
   e o `.grid-2` global (`repeat(auto-fit, minmax(280px, 1fr))`) precisa de
   560px para formar duas colunas: colapsava tudo numa coluna so, o cartao ia
   a 956px e o botao "Criar conta" nascia FORA de um viewport de 900px. Quem
   nao rola, nao se cadastra. */
.autenticar_largo { grid-template-columns: minmax(0, 1fr) minmax(0, 580px); }

/* Duas colunas de verdade, em fracao — nao dependem de um minimo em pixel que
   o cartao nao tem como oferecer. O empilhamento vira responsabilidade da
   media query abaixo, no ponto certo para ESTE cartao. */
.autenticar_form .grid-2 { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--esp-4); }

/* O par telefone + cargo nao e simetrico: o telefone carrega o seletor de pais
   E o numero dentro da mesma caixa, entao dividir a linha ao meio deixava o
   numero com pouco mais de 140px — apertado para "(88) 99905-8653". O cargo e
   texto livre e aceita bem o espaco menor. */
.autenticar_form .grid-2_tel { grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr); }
.autenticar_largo .autenticar_form .campo { margin-bottom: var(--esp-3); }

@media (max-width: 620px) {
    .autenticar_form .grid-2 { grid-template-columns: minmax(0, 1fr); }
}

/* `safe center` protege o topo: quando o cartao e mais alto que a janela, o
   centramento comum empurra o inicio para fora da area rolavel e o titulo
   fica inalcancavel. Com `safe`, o alinhamento cai para o inicio nesse caso. */
.pagina-auth main { align-items: safe center; }

/* Rodape do cartao: alternar entre entrar e criar conta. */
.autenticar_pe { margin: var(--esp-5) 0 0; padding-top: var(--esp-4); border-top: 1px solid var(--borda); font-size: var(--tipo-1); color: var(--texto-suave); text-align: center; }
.autenticar_esqueci { margin: 10px 0 0; font-size: var(--tipo-1); }

/* Ver nota 1: os links DO CARTAO — nao os da pagina inteira.
   Escopo em .autenticar de proposito: a primeira versao usava
   `.pagina-auth a:not(.btn):not(.btn_sec)`, que tem especificidade 0-3-1
   (o :not() conta a classe que carrega dentro) e atropelava `.nav a`
   (0-1-1). A barra do topo e escura nos DOIS temas e usa token claro fixo;
   ao herdar `--texto`, o link "Entrar" virava preto sobre preto no tema
   claro — contraste medido: 1,0. Invisivel. */
/* O SUBLINHADO VOLTOU AO REPOUSO (onda 51).

   Ele tinha sido removido junto com o azul do navegador, e o efeito colateral
   apareceu na tela real: "Esqueci minha senha" ficava com a MESMA cor
   (--texto), o MESMO peso (600) e o MESMO tamanho (--tipo-1) do rotulo
   "Senha" 40px acima — dois textos identicos, um clicavel e o outro nao. O
   mesmo vale para "Termos de Uso" e "Politica de Privacidade" dentro da frase
   do aceite. Cor nao pode ser o unico portador (WCAG 1.4.1), e aqui nem cor
   havia.

   O traco fica em --contorno-forte no repouso — presente, discreto — e assume
   a cor do link no hover/foco. */
.autenticar a:not(.btn):not(.btn_sec) {
    color: var(--texto);
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: .22em;
    text-decoration-thickness: 1px;
    text-decoration-color: var(--contorno-forte);
    border-radius: 4px;
    transition: color var(--dur-micro) var(--curva), text-decoration-color var(--dur-micro) var(--curva);
}
.autenticar a:not(.btn):not(.btn_sec):hover {
    color: var(--fss-texto);
    text-decoration-color: currentColor;
}
.autenticar a:not(.btn):not(.btn_sec):focus-visible { outline: 2px solid var(--fss-acao); outline-offset: 3px; }

.autenticar_form .check { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 10px; align-items: start; font-size: var(--tipo-1); color: var(--texto-suave); line-height: 1.5; }
.autenticar_form .check input { width: 20px; height: 20px; margin-top: 1px; accent-color: var(--fss-acao); }

/* --- CONFIRMACAO DE E-MAIL: A INSTRUCAO E A HEROINA ------------------------

   O cartao do /app/verificar-email abria, ate 20/08/2026, com um <input>
   VAZIO no centro e um botao de largura inteira embaixo — a gramatica de acao
   principal, gasta no caminho da MINORIA (quem nao recebeu). A instrucao real
   era `.sub`: 13px em --texto-suave. O olho encontrava primeiro o pedido de
   digitar outro endereco.

   A inversao aqui e de PESO, nao de conteudo: nada saiu da tela.
     - o lead sobe de --tipo-1 (13px, suave) para --tipo-3 (17px, --texto);
     - os tres passos ganham numeracao e a unica superficie do cartao que
       carrega CONTEUDO (a da dobra so aparece depois do clique);
     - o reenvio vira <details> fechado, com botao de largura natural.

   Sem cor nova: tudo sai de --texto, --superficie e --fss-acao, que ja tem os
   tres blocos de tema (:root, prefers-color-scheme e [data-tema]). */

/* Lead: a primeira frase do cartao passa a ter peso de instrucao.
   Seletor com `.autenticar_painel >` de proposito — `.autenticar_lead` sozinho
   (0-1-0) perderia para `.autenticar_painel > .sub` (0-2-0), que vem antes. */
.autenticar_painel > .autenticar_lead {
    font-size: var(--tipo-3);
    line-height: 1.55;
    color: var(--texto);
    margin-bottom: var(--esp-4);
}

/* O bloco dos passos: superficie levemente recuada dentro do cartao. Recuada,
   e nao elevada, porque ele nao flutua sobre o cartao — ele e um trecho DELE.
   color-mix contra --superficie (e nao contra transparent) mantem a cor
   OPACA: e o que permite medir contraste sem adivinhar o que ha embaixo. */
.passo_bloco {
    margin: 0 0 var(--esp-5);
    padding: var(--esp-4);
    border: 1px solid var(--borda);
    border-radius: var(--raio-p);
    background: color-mix(in srgb, var(--texto) 4%, var(--superficie));
}

/* Rotulo do bloco. NAO usa `.caps`: aquela classe so existe dentro de
   .pagina-home/.pagina-app e nesta pagina nao pinta nada — ela ja aparece
   sem estilo no painel da esquerda. Aqui o rotulo se descreve inteiro. */
.passo_rotulo {
    margin: 0 0 var(--esp-3);
    font-size: .75rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: .14em;
    color: var(--texto-suave);
}

/* `role="list"` no <ol> do template compensa o que `list-style: none` tira do
   VoiceOver: sem ele o Safari deixa de anunciar "lista de 3 itens", e a
   contagem e metade do recado de um passo a passo. */
.passo_lista { margin: 0; padding: 0; list-style: none; counter-reset: passo; display: grid; gap: var(--esp-3); }
.passo_lista li {
    position: relative;
    counter-increment: passo;
    padding-left: 40px;
    min-height: 28px;
    font-size: var(--tipo-3);
    line-height: 1.5;
    color: var(--texto);
}
.passo_lista li::before {
    content: counter(passo);
    position: absolute; left: 0; top: 1px;
    width: 26px; height: 26px; border-radius: 50%;
    display: grid; place-items: center;
    background: var(--fss-acao); color: #fff;
    font-size: .8125rem; font-weight: 700; line-height: 1;
}
.passo_lista strong { font-weight: 700; color: var(--texto); }

/* --- A DOBRA DO REENVIO ---------------------------------------------------

   <details> nativo, como no FAQ da home e na dobra do /admin: estado, teclado
   e semantica de expandido/recolhido saem de graca, e a tela continua inteira
   sem uma linha de JS (secao 12.4). O `open` vem do SERVIDOR quando o proprio
   reenvio devolve erro — dobra que esconde o erro que ela produziu e pior do
   que dobra nenhuma.

   O triangulo nativo sai nas DUAS declaracoes: Safari so obedece a
   ::-webkit-details-marker, e sem ela o marcador sobrevive so naquele
   navegador — defeito que nenhuma captura feita no Chrome mostra. */
.reenvio { margin: 0; border: 1px solid var(--borda); border-radius: var(--raio-p); }
.reenvio > summary {
    display: flex; align-items: center; justify-content: space-between; gap: var(--esp-3);
    min-height: 44px; padding: 8px var(--esp-4);
    cursor: pointer; list-style: none;
    font-size: var(--tipo-2); font-weight: 600; color: var(--texto-suave);
    border-radius: var(--raio-p);
}
.reenvio > summary::-webkit-details-marker { display: none; }
.reenvio > summary:hover { color: var(--texto); }
.reenvio > summary:focus-visible { outline: 2px solid var(--texto); outline-offset: 2px; }
.reenvio[open] > summary { color: var(--texto); border-radius: var(--raio-p) var(--raio-p) 0 0; border-bottom: 1px solid var(--borda); }

.reenvio_glifo {
    flex: none; width: 26px; height: 26px; border-radius: 50%;
    display: grid; place-items: center;
    background: color-mix(in srgb, var(--texto) 10%, transparent);
    color: var(--texto-suave);
}
.reenvio > summary:hover .reenvio_glifo { background: color-mix(in srgb, var(--texto) 18%, transparent); }
.reenvio[open] .reenvio_glifo { transform: rotate(45deg); }

.reenvio_corpo { padding: var(--esp-4); background: color-mix(in srgb, var(--texto) 3%, var(--superficie)); border-radius: 0 0 var(--raio-p) var(--raio-p); }
.reenvio_dica { margin: 0 0 var(--esp-4); font-size: var(--tipo-2); line-height: 1.55; color: var(--texto-suave); }
/* A RESPOSTA NEUTRA, ancorada onde a acao aconteceu.
   Serve as duas telas gemeas — o reenvio de confirmacao e a recuperacao de
   senha —, que dao a mesma classe de resposta pela mesma razao: nenhuma das
   duas pode dizer se a conta existe. Nasceu com nome de reenvio e virou
   `.resposta_neutra` em 20/08/2026, quando a segunda tela precisou dela.
   Verde de concluido pelo criterio do resto do portal — o PEDIDO foi aceito, e
   e disso que ela fala; a frase e condicional justamente porque a entrega nao e
   afirmada. Caixa discreta, e nao a do flash: ela nao repete o toast, ancora. */
.resposta_neutra {
    display: flex; align-items: start; gap: var(--esp-2);
    margin: 0 0 var(--esp-4); padding: var(--esp-3) var(--esp-4);
    border: 1px solid color-mix(in srgb, var(--sucesso) 34%, transparent);
    border-radius: var(--raio-p);
    background: color-mix(in srgb, var(--sucesso) 9%, transparent);
    font-size: var(--tipo-2); line-height: 1.55; color: var(--texto);
}
.resposta_neutra .icone { flex: none; margin-top: .15em; color: var(--sucesso); }

/* O BOTAO DA DOBRA NAO E O BOTAO DA TELA.
   `.autenticar_form .btn` estica para 100% — que e o certo no cadastro e no
   login, onde enviar E a acao da pagina. Aqui nao e: o reenvio e saida de
   quem procurou por ela. Largura natural, e nada de --fss-acao. */
.reenvio_form .btn { width: auto; margin-top: 0; }
.reenvio_form .campo { margin-bottom: var(--esp-3); }

@media (prefers-reduced-motion: no-preference) {
    .autenticar_painel { animation: auth_entra 420ms var(--curva) both; }
    @keyframes auth_entra { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
}

/* Abaixo de 900px o painel de marca sai: quem abre isto no celular veio
   para digitar. O formulario passa a ocupar a largura toda. */
/* NO CELULAR O PAINEL ENCOLHE — ELE NAO SOME (onda 51).

   O custo de espaco e real e foi medido: em forma compacta ele acrescenta
   ~150px acima do cartao a 320px. O custo de nao te-lo tambem foi medido, e e
   maior: a primeira dobra ficava sem uma palavra sobre o que a pessoa vai
   fazer com o e-mail que esta digitando.

   O que encolhe: a promessa cai de --tipo-5 para --tipo-4, a folga vertical
   passa a ser a menor da escala, e os tres selos de confianca viram UMA linha
   que quebra, com o mesmo tipo e a mesma cor. Nada e escondido. */
@media (max-width: 900px) {
    .autenticar { grid-template-columns: minmax(0, 1fr); gap: var(--esp-4); }
    .pagina-auth main { align-items: flex-start; padding-block: var(--esp-5); }

    /* O `display: none` CONTINUA VALENDO NAS OUTRAS TRES TELAS DE AUTH.
       Recuperar, redefinir e confirmar e-mail tambem tem `.autenticar_marca`,
       e ali a decisao de esconder no estreito segue certa: quem chegou aquelas
       telas ja e da casa, o painel repete o que o cartao diz e o <h1> real
       esta dentro do cartao. Quem nao pode perde-lo e a PORTA DE ENTRADA, onde
       ele e a unica apresentacao do produto — e por isso a excecao e nomeada
       por `.pagina-acesso`, e nao o contrario. */
    .pagina-auth:not(.pagina-acesso) .autenticar_marca { display: none; }

    .pagina-acesso .autenticar_marca { max-width: 60ch; }
    /* So `h1`: nas DUAS portas o titulo deste painel e o <h1> da pagina (a
       promessa), e o rotulo do formulario e <h2> dentro do cartao. Nas outras
       tres telas de auth o painel tem <h2> — e la ele nem chega a esta largura,
       porque a regra acima o esconde. */
    .pagina-acesso .autenticar_marca h1 { font-size: var(--tipo-4); margin: var(--esp-2) 0 var(--esp-3); }
    .pagina-acesso .autenticar_marca .sub { font-size: var(--tipo-1); margin-bottom: var(--esp-3); }
    .pagina-acesso .confianca { gap: 6px 14px; margin: 0; }
}

@media (max-width: 420px) {
    .autenticar_painel { padding: var(--esp-4); border-radius: var(--raio-p); }
}

/* --- modal de intencao de saida -------------------------------------------

   Mesma familia visual do header e da barra flutuante: superficie escura,
   linha --fss de assinatura no topo, pilula vermelha como acao. Um terceiro
   dialeto so para o modal quebraria o sistema que as ondas anteriores
   fecharam.

   O <dialog> nativo ja centraliza sozinho quando aberto por showModal(); o
   que resta aqui e superficie, ritmo e a entrada. */
.saida {
    width: min(560px, 92vw);
    padding: clamp(28px, 4vw, 44px);
    border: 1px solid color-mix(in srgb, var(--escuro-texto) 20%, transparent);
    border-top: 3px solid var(--fss);
    border-radius: var(--raio-l, 24px);
    background: var(--escuro-fundo);
    color: var(--escuro-texto);
    box-shadow: 0 24px 70px rgba(0, 0, 0, .55);
    text-align: center;
    overflow: visible;
}

.saida::backdrop {
    /* color-mix nao vale em ::backdrop (fora da arvore); valor literal. */
    background: rgba(6, 7, 12, .72);
    backdrop-filter: blur(3px);
}

/* O form existe so para o formmethod=dialog; nao pode ocupar espaco. */
.saida_fechar_form { display: contents; }

.saida_fechar {
    position: absolute; top: 10px; right: 10px;
    display: inline-flex; align-items: center; justify-content: center;
    /* 44px de alvo (WCAG 2.5.8) mesmo com o icone de 20px. */
    width: 44px; height: 44px;
    border: 0; border-radius: 50%; cursor: pointer;
    background: transparent; color: var(--escuro-suave, #A0A5B8);
    transition: background var(--dur-micro) linear, color var(--dur-micro) linear;
}
.saida_fechar:hover { background: color-mix(in srgb, var(--escuro-texto) 10%, transparent); color: var(--escuro-texto); }

.saida_marca { display: block; margin: 4px auto 22px; height: auto; }

.saida_titulo {
    margin: 0; font-size: var(--tipo-4);
    font-weight: 800; line-height: 1.25; letter-spacing: -.02em;
}
/* A pergunta e o que o visitante precisa levar embora — ela recebe o acento,
   nao a chamada que a introduz. */
.saida_titulo strong { display: block; margin-top: 8px; color: var(--fss-texto, var(--fss)); }

.saida_texto { margin: 16px 0 0; color: var(--escuro-suave, #A0A5B8); font-size: var(--tipo-2); line-height: 1.6; }
.saida_ir { margin-top: 26px; }
.saida_nota { margin: 14px 0 0; font-size: var(--tipo-1); color: var(--escuro-suave, #A0A5B8); }
/* O @media (max-width: 400px) que morava aqui SUMIU em 20/08/2026, e nao foi
   sobrescrito: ele existia so para encolher o titulo e o texto do modal em
   tela estreita (18px e 15px), que e exatamente o que --tipo-4 e --tipo-2
   entregam sozinhos naquela largura. Ponto de quebra que repete o que o clamp
   ja faz e uma segunda fonte de verdade para o mesmo numero. */

/* Entrada discreta: sobe 8px e aparece. Quem pediu menos movimento recebe o
   modal ja posicionado — a informacao e a mesma, sem o deslocamento. */
@media (prefers-reduced-motion: no-preference) {
    .saida[open] { animation: saida_entra var(--dur-entrada) var(--curva-suave, ease-out) both; }
    .saida[open]::backdrop { animation: saida_fundo var(--dur-entrada) linear both; }
}
@keyframes saida_entra { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes saida_fundo { from { opacity: 0; } to { opacity: 1; } }

/* =============================================================================
   ONDA 6 — painel, empresa, agendamento e o indicador 3D da marca
   -----------------------------------------------------------------------------
   O que entra aqui e o que faltava para o /app inteiro falar a MESMA lingua do
   relatorio e da home (direcao D): as tres telas que ainda estavam no desenho
   antigo (painel, empresa, agendamento) e um componente novo de espera.

   Este bloco fica no FIM do arquivo de proposito. Tudo aqui e escopado em
   `.pagina-app` ou em classe propria (`.carregando3d`, `.pnl_*`, `.emp_*`,
   `.agenda_*`), e as telas reusam os componentes definidos ACIMA — .tile,
   .caps, .bento, .duplo/.muro/.grandeza, .rank, .anel, .rel_selo, .vt. Escrever
   depois evita depender de ordem para vencer regra antiga; nao ha um
   `!important` novo em todo o bloco.

   Nenhum valor cru: cor, raio, sombra, duracao e espaco saem dos tokens do topo.

   Ordem: carregando3d -> painel -> empresa -> agendamento -> motion.
   ============================================================================= */

/* --- carregando3d: o simbolo da marca girando em 3D -------------------------
   O componente mora em public/assets/comum/carregando3d.css (importado no topo
   deste arquivo e tambem pelo bundle do admin), com o porque de cada decisao:
   espera de duracao DESCONHECIDA, CSS puro, e o simbolo que NAO some sob
   prefers-reduced-motion. A ponte de tema (--c3d-halo/--c3d-anel) esta no :root.
   Aqui ficam so as composicoes proprias do portal. */

/* O par simbolo + frase. A frase e obrigatoria: o glifo nunca fica sozinho. */
.espera3d { display: grid; justify-items: center; gap: 18px; text-align: center; }
.espera3d p { margin: 0; color: var(--texto-suave); font-size: var(--tipo-2); }
.espera3d strong { display: block; color: var(--texto); font-size: var(--tipo-3); }

/* --- links de texto dentro do /app -----------------------------------------
   Ate agora um <a> solto no corpo de uma tela do app caia no padrao do
   navegador: azul, roxo depois de visitado, sublinhado colado. O bloco de
   autenticacao ja resolveu isso para o cartao de login e documentou a armadilha
   — `.pagina-auth a:not(.btn)` tem especificidade 0-3-1 e atropelava `.nav a`,
   deixando o menu invisivel no tema claro.

   Aqui o escopo e `main`: o header e o rodape ficam FORA por construcao, e nao
   por sorte. Os botoes saem pelos :not(), como la. */
/* `.link_bloco` e a terceira saida, ao lado dos dois botoes: LINK QUE E UM
   CARTAO — a area inteira e o alvo, e o que ha dentro e titulo, rotulo e
   paragrafo, nao uma frase. Sublinhar tudo isso pinta o cartao de riscos (foi o
   que aconteceu com os dois atalhos da calculadora em 20/08/2026, quando ela
   finalmente passou a receber `pagina-app` no corpo). O sublinhado existe para
   o link DENTRO de texto corrido, que precisa se distinguir do texto ao redor;
   um cartao ja se distingue por borda, fundo e cursor. */
.pagina-app main a:not(.btn):not(.btn_sec):not(.link_bloco) {
    color: var(--texto); font-weight: 600;
    text-decoration: underline; text-underline-offset: .18em; text-decoration-thickness: 1px;
    border-radius: 4px;
}
.pagina-app main a:not(.btn):not(.btn_sec):not(.link_bloco):hover { color: var(--fss-texto); }

/* --- painel (dashboard, RF17) ---------------------------------------------- */

/* A peca do painel e a MESMA do relatorio (.rel_peca), so que menor.
   17/08/2026: deixou de ser "so o anel". O cartao mostrava um numero enorme e
   ~25% da propria altura em vazio; num painel, area ociosa nao e respiro — e
   informacao que nao esta ali. Agora carrega tambem a pontuacao POR PILAR, que
   ja chegava no template (dimensions_json) e so aparecia no relatorio.
   O anel encolhe de 232px para 196: o vazio que ele criava embaixo vira a
   lista, e o cartao cresce muito menos do que a informacao que ganhou. */
.pnl_peca { width: min(320px, 100%); }
.pnl_peca .anel_total { width: min(180px, 100%); margin-inline: auto; }
/* Capa sem peca ao lado (quem ainda nao tem resultado): uma coluna so. A grade
   de duas colunas de .rel_capa deixaria metade da linha vazia a partir de 900px. */
@media (min-width: 900px) { .rel_capa.pnl_capa_solo { grid-template-columns: minmax(0, 1fr); } }

/* A saida da capa. Mesmo respiro do .rel_selos logo acima, para que chip e
   botao formem uma pilha e nao dois blocos soltos. */
.pnl_capa_acao { margin: 22px 0 0; }
.pnl_peca_pe {
    margin: 10px 0 0; padding-top: 12px; border-top: 1px solid var(--borda);
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; flex-wrap: wrap; font-size: var(--tipo-1); color: var(--texto-suave);
}

/* PONTUACAO POR PILAR, dentro da peca.
   A gramatica e a do relatorio (.rel_pilar), so que compacta: nome + numero na
   mesma linha, trilho embaixo, e o gargalo marcado com PALAVRA alem da cor
   (WCAG 1.4.1). Reusa .trilho/.preench, entao a barra nasce com o mesmo raio e
   a mesma altura das outras do portal.
   O titulo NAO usa .caps de proposito: dentro do /app o .caps e vermelho de
   marca (linha 818), e este cartao acabou de tirar o vermelho do anel — dois
   acentos de marca num cartao de 320px devolveriam o alarme pela porta dos
   fundos. */
.pnl_pilares_bloco { margin-top: 16px; }
.pnl_pilares_titulo {
    margin: 0 0 10px; font-size: var(--tipo-1); font-weight: 800;
    letter-spacing: .12em; text-transform: uppercase; color: var(--texto-fraco);
}
.pnl_pilares { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
/* Duas colunas: o nome ocupa o que sobra, o numero tem largura propria e fica
   alinhado a direita (tabular-nums para as unidades empilharem). O trilho e a
   tag atravessam as duas. */
.pnl_pilar { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: baseline; gap: 4px 10px; }
.pnl_pilar_nome { font-size: var(--tipo-2); font-weight: 600; color: var(--texto); min-width: 0; }
.pnl_pilar_valor {
    font-family: var(--mono); font-variant-numeric: tabular-nums;
    font-size: var(--tipo-2); font-weight: 800; color: var(--texto); text-align: right;
}
/* A receita do trilho (fundo, raio, overflow) vem da regra compartilhada la em
   cima, onde `.pnl_pilar .trilho` foi acrescentado ao seletor: aqui so a
   posicao na grade e a altura menor, que e o que muda dentro da peca.
   A barra CRESCE por rolagem sem uma linha nova: `.preench` ja tem
   `home_cresce` com animation-timeline: view(), dentro do bloco de
   prefers-reduced-motion: no-preference. Declarar outra animacao aqui
   disputaria a mesma propriedade com ela. */
.pnl_pilar .trilho { grid-column: 1 / -1; height: 6px; margin-top: 4px; }
.pnl_pilar .preench.pnl_barra { background: var(--texto-suave); }
/* O UNICO acento de marca do cartao, e ele aponta ACAO: por onde comecar. Nao e
   cor por faixa de pontuacao (DEC-002) — e a mesma marcacao de gargalo que o
   relatorio ja faz, e vem acompanhada da mesma palavra. */
.pnl_pilar_gargalo .preench.pnl_barra { background: var(--fss); }
.pnl_pilar_tag {
    grid-column: 1 / -1; font-size: var(--tipo-1); font-weight: 700;
    letter-spacing: .02em; color: var(--texto-fraco);
}
.pnl_pilar_tag_gargalo { color: var(--fss-texto); }
/* Sem base de calculo: trilho vazio e tracejado, para nao parecer pontuacao 0
   (a mesma regra de .rel_pilar_vazio no relatorio). */
.pnl_pilar_vazio .trilho { background: transparent; border: 1px dashed var(--contorno); }
.pnl_pilar_vazio .pnl_pilar_valor { color: var(--texto-fraco); }

/* PROGRESSO REAL (secao 12.6): tres etapas, contadas do estado do SERVIDOR —
   empresa cadastrada, diagnostico enviado, relatorio pronto. Nao ha percentual
   inventado em lugar nenhum; o aria-valuenow sai da mesma conta que o texto. */
.pnl_progresso { display: grid; gap: 10px; margin-top: 30px; max-width: 640px; }
.pnl_progresso_linha { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap; font-size: var(--tipo-2); color: var(--texto-suave); }
.pnl_progresso_linha strong { color: var(--texto); }

.pnl_trilha { list-style: none; margin: 22px 0 0; padding: 0; display: grid; gap: 14px; }
@media (min-width: 760px) { .pnl_trilha { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; } }
.pnl_passo {
    display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 14px; align-items: start;
    padding: 18px; border: 1px solid var(--borda); border-radius: var(--raio-app);
    background: var(--painel);
}
.pnl_passo_n {
    width: 34px; height: 34px; border-radius: 50%; display: grid; place-items: center;
    border: 1.5px solid var(--borda); color: var(--texto-fraco);
    font-family: var(--mono); font-variant-numeric: tabular-nums; font-size: var(--tipo-1); font-weight: 800;
}
.pnl_passo_nome { display: block; font-weight: 700; color: var(--texto); }
.pnl_passo_nota { margin: 4px 0 0; font-size: var(--tipo-1); color: var(--texto-fraco); }
/* O estado tambem vem escrito ("Concluído", "Agora", "Depois"): cor e traco
   nunca sao os unicos portadores do sentido (WCAG 1.4.1). */
.pnl_passo_estado { display: inline-block; margin-top: 8px; font-size: var(--tipo-1); font-weight: 800; letter-spacing: .09em; text-transform: uppercase; color: var(--texto-fraco); }
.pnl_passo_feito .pnl_passo_n { border-color: color-mix(in srgb, var(--sucesso) 45%, transparent); color: var(--sucesso); }
.pnl_passo_feito .pnl_passo_estado { color: var(--sucesso); }
/* O PASSO "AGORA" ERA A TERCEIRA LAVAGEM DA MESMA TELA (direcao B, 20/08/2026).
   Ele pintava o cartao inteiro de rosa para dizer "e aqui que voce esta", com
   `.tile_wash` e `.pnl_fecho` dizendo "olhe para mim" da mesma forma, na mesma
   rolagem. Agora usa o mesmo carimbo dos outros dois: superficie normal, barra
   de acento no inicio. O `.pnl_passo_n` ao lado continua vermelho, e ele e que
   carrega o numero do passo. */
.pnl_passo_agora {
    border-color: var(--borda);
    border-inline-start: var(--acento-largura) solid var(--fss-acao);
}
.pnl_passo_agora .pnl_passo_n { border-color: var(--borda-marca); color: var(--fss-texto); }
.pnl_passo_agora .pnl_passo_estado { color: var(--fss-texto); }
.pnl_passo_espera { border-style: dashed; }

/* Spans do bento (a grade de 6 colunas ja existe em .bento a partir de 900px).
   Nomes por largura, e nao por conteudo: o painel muda de composicao conforme o
   estado do usuario, entao um `.tile_pontuacao` fixo nao serviria. */
@media (min-width: 900px) {
    .pnl_col2 { grid-column: span 2; }
    .pnl_col3 { grid-column: span 3; }
    .pnl_col4 { grid-column: span 4; }
    .pnl_col6 { grid-column: 1 / -1; }
}

/* Ferramentas: estado VAZIO honesto. O selo diz "em breve" e o cartao nao e
   link nenhum — prometer clique que nao existe seria dark pattern (12.6). */
/* DOBRA DE SECAO DO PAINEL — <details> nativo, sem JS.

   O marcador padrao (o triangulo) sai: ele fica preso a esquerda do primeiro
   filho e briga com a hierarquia do cabecalho. O sinal de estado vira o glifo
   proprio a direita, que gira ao abrir — e ele e aria-hidden porque o <summary>
   ja anuncia expandido/recolhido sozinho.

   list-style em DUAS declaracoes de proposito: Safari so obedece a
   ::-webkit-details-marker, e sem ela o triangulo sobrevive so naquele
   navegador — defeito que nao aparece em nenhuma captura feita no Chrome. */
.pnl_dobra { border-top: 1px solid var(--borda); padding-top: 28px; }
.pnl_dobra > summary {
    display: flex; align-items: center; justify-content: space-between;
    flex-wrap: wrap; gap: 10px 24px;
    cursor: pointer; list-style: none; padding: 4px 0; min-height: 44px;
    border-radius: var(--raio-app);
}

/* O TAMANHO SAIU DAQUI EM 20/08/2026, PORQUE DEIXOU DE SER NECESSARIO.

   Esta regra existia para desfazer os 46px de `.secao_head h2`: numa secao
   FECHADA, um titulo de display anunciava com estardalhaco o que nem estava na
   tela. A direcao B baixou o cabecalho de secao do /app inteiro para --tipo-5
   (24 -> 27px), que ja e a escala que esta dobra pedia — manter um clamp
   proprio aqui so reintroduziria um setimo tamanho de tipo na pagina.

   O que sobra e o que NAO e tamanho: o limite de largura precisa cair (o
   titulo divide a linha com o resumo e o glifo) e o aperto acompanha o corpo.

   `align-items: baseline` saiu junto, na mesma revisao de antes: o titulo tem
   uma linha e o resumo tem duas, entao alinhar por baseline pendurava os tres
   pedacos em alturas diferentes e eles paravam de ler como uma linha so. */
.pnl_dobra > summary .secao_head h2 {
    letter-spacing: -.02em; max-width: none;
}
.pnl_dobra > summary::-webkit-details-marker { display: none; }
.pnl_dobra > summary:focus-visible { outline: 3px solid var(--fss); outline-offset: 4px; }
.pnl_dobra > summary .secao_head { margin: 0; }
.pnl_dobra > summary h2 { margin: 0; }

/* O resumo carrega a regra que nao pode dobrar (RF11/RF17). Ele fica na MESMA
   linha do titulo em tela larga e desce embaixo no estreito — nunca some. */
.pnl_dobra_resumo { color: var(--texto-suave); font-size: var(--tipo-2); max-width: 46ch; }
.pnl_dobra_resumo strong { color: var(--texto); }

.pnl_dobra_glifo {
    flex: none; width: 32px; height: 32px; border-radius: 50%;
    display: grid; place-items: center;
    background: color-mix(in srgb, var(--texto) 10%, transparent);
    color: var(--texto-suave);
}
.pnl_dobra > summary:hover .pnl_dobra_glifo { background: color-mix(in srgb, var(--texto) 18%, transparent); }
.pnl_dobra[open] .pnl_dobra_glifo { transform: rotate(45deg); }

.pnl_dobra_sub { margin-top: 18px; }
.pnl_dobra[open] > summary { margin-bottom: 6px; }

/* ABERTO, O RESUMO SAI.

   Ele existe para carregar a regra do RF11/RF17 enquanto a secao esta
   FECHADA — e so para isso. Com a secao aberta, o paragrafo logo abaixo diz a
   mesma coisa com mais precisao, e manter os dois punha "nenhuma depende do
   seu resultado" duas vezes em 90px. */
.pnl_dobra[open] .pnl_dobra_resumo { display: none; }

/* Sem animacao de abrir: `height` de conteudo desconhecido nao anima sem JS, e
   um salto honesto e melhor do que meio salto. */
/* A MESMA GRADE DAS CONQUISTAS (.conq): auto-fill em 240px, gap 14.

   auto-FILL e nao auto-FIT, de proposito e pelo mesmo motivo de la: com
   auto-fit, uma lista curta estica os cartoes ate a largura toda, e um cartao
   de 700px com 38px de selo e tres palavras vira uma faixa vazia. auto-fill
   deixa a coluna vaga vaga.

   228 -> 240 porque o cartao virou horizontal: o selo come 38px + 13 de gap, e
   sobrava pouco para o titulo de duas palavras nao quebrar em tres linhas. */
.pnl_ferramentas { list-style: none; margin: 26px 0 0; padding: 0; display: grid; gap: 14px; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
/* O CARTAO DE FERRAMENTA USA A ANATOMIA DO CARTAO DE CONQUISTA.

   As duas secoes contam a mesma historia em dois tempos — o que ja aconteceu e
   o que vem depois — e desenhavam isso de formas diferentes: a conquista em
   linha (selo redondo a esquerda, texto a direita, estado embaixo), a
   ferramenta empilhada (glifo em cima, quadrado, e uma pilula tracejada no pe).
   Duas gramaticas para a mesma ideia.

   Agora e uma so: mesmo selo redondo de 38px, mesmo gap, mesma linha de estado.
   O que continua diferente e o que DEVE diferir — a conquista concluida ganha
   verde e borda propria; a ferramenta que nao existe fica discreta.

   O QUE NAO MUDA: nao ha cadeado, nao ha "desbloqueie" e o cartao nao e link.
   Aproximar o desenho das conquistas nao pode fazer a ferramenta parecer premio
   de diagnostico — RF11/RF17 (prd.md:113) proibe, e e o oposto do que a nota
   ao pe da secao afirma. */
.pnl_ferr {
    display: flex; align-items: start; gap: 13px;
    padding: 16px;
    border: 1px solid var(--borda); border-radius: var(--raio-app);
    background: var(--superficie);
}
.pnl_ferr_corpo { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
/* NEUTRO, PORQUE ESTAS FERRAMENTAS NAO EXISTEM AINDA.

   A pagina passou a ter tres estados com tres cores, e a regra vale para as
   duas secoes de cartao:

     concluido        -> verde   (.conq_feito .conq_selo, .conq_data)
     pendente/futuro  -> neutro  (.conq_item:not(.conq_feito), este selo)
     problema         -> vermelho (gargalo do pilar, perda atual)

   O selo saia em --fss-texto, o mesmo vermelho que marca o gargalo tres
   secoes acima. Quatro circulos vermelhos anunciando o que ainda nao foi
   construido liam como quatro alarmes — e a nota ao pe da secao existe
   justamente para dizer que nao ha nada errado aqui.

   Mesmo tom do selo de conquista PENDENTE, pelo mesmo motivo escrito la:
   pendente nao e erro. */
.pnl_ferr_glifo {
    width: 38px; height: 38px; border-radius: 50%; flex: none; display: grid; place-items: center;
    background: var(--superficie-alta); border: 1px solid var(--borda); color: var(--texto-suave);
}
.pagina-app .pnl_ferr h3 { margin: 0; font-size: var(--tipo-3); font-weight: 800; letter-spacing: -.01em; }
.pnl_ferr p { margin: 0; font-size: var(--tipo-1); line-height: 1.55; color: var(--texto-fraco); }
/* Mesma linha de estado da conquista pendente (.conq_pendente): pequena,
   discreta, sem moldura. A pilula tracejada dizia a mesma coisa com o triplo
   do peso visual, e quatro delas competiam com o relatorio — que e o que a
   pagina tem para entregar hoje.

   Discreto NAO e escondido: pendente nao e erro, e quem ainda nao tem a
   ferramenta nao falhou em nada. Mesma razao da nota em .conq_item. */
.pnl_breve { margin-top: 4px; font-size: var(--tipo-1); color: var(--texto-suave); }

/* --- empresa (o formulario longo) ------------------------------------------
   Tres grupos em tiles, na mesma superficie do relatorio. O que muda de fato
   nao e a moldura: e o campo de dinheiro ganhar a unidade DENTRO da caixa
   (R$ / %), e o 422 abrir com um resumo dos erros que leva ao campo. */
.emp_form { display: grid; gap: clamp(18px, 3vw, 26px); margin-top: 30px; }
.emp_par { display: grid; gap: var(--esp-4); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 620px) { .emp_par { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } }
.pagina-app .emp_form .campo { margin-bottom: 0; }
.pagina-app .emp_form label { font-size: var(--tipo-2); font-weight: 600; }
.pagina-app .emp_form .dica { font-size: var(--tipo-1); color: var(--texto-fraco); }
.emp_campos { display: grid; gap: var(--esp-4); margin-top: 22px; }

/* Resumo de erros do 422. WCAG 2.2, 3.3.1: em vez de deixar a pessoa cacar
   quais dos onze campos falharam, a lista nomeia cada um e leva ate ele. O
   `.field-error` por campo continua exatamente onde estava — este resumo se
   SOMA a ele, nao o substitui. */
.emp_erros { border: 1px solid var(--erro); border-left-width: 4px; border-radius: var(--raio-p); background: color-mix(in srgb, var(--erro) 10%, transparent); padding: 16px 18px; margin: 26px 0 0; }
.emp_erros p { margin: 0; font-weight: 700; color: var(--texto); }
/* O bloco nao e `.msg.error` (nao tem a caixa dela), entao a tinta do glifo
   precisa ser dita aqui — senao ele herda --texto e o estado se perde. */
.emp_erros .icone { color: var(--erro); }
.emp_erros ul { margin: 10px 0 0; padding-left: 20px; font-size: var(--tipo-2); color: var(--texto-suave); }
.emp_erros li + li { margin-top: 4px; }
.emp_erros a { color: var(--texto); font-weight: 600; }

/* Campo com unidade. A borda mora no CONTAINER (como em .telefone) e o
   :focus-within a acende: quem digita percebe a caixa inteira como "o campo". */
.unidade {
    display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: stretch;
    background: var(--fundo); border: 1px solid var(--borda); border-radius: var(--raio-p);
    min-height: 48px;
}
.unidade_fim { grid-template-columns: minmax(0, 1fr) auto; }
.unidade_marca { display: inline-flex; align-items: center; padding: 0 13px; font-weight: 700; font-size: var(--tipo-2); color: var(--texto-suave); border-right: 1px solid var(--borda); }
.unidade_fim .unidade_marca { border-right: 0; border-left: 1px solid var(--borda); }
/* Mesma especificidade do seletor global de input (0,1,1) — quem vence e a
   ordem, e este bloco e o ultimo do arquivo. Sem !important. */
.unidade input { border: 0; background: none; min-height: 46px; border-radius: var(--raio-p); font-variant-numeric: tabular-nums; }
.unidade:focus-within { outline: 2px solid var(--texto); outline-offset: 2px; border-color: var(--texto-suave); }
.unidade input:focus-visible { outline: none; box-shadow: none; }
/* Campo reprovado: a caixa inteira fica vermelha. A barra interna de 3px que
   `[aria-invalid]` ja pinta continua aparecendo dentro do controle, e o texto
   do erro segue logo abaixo — forma + texto + cor. */
.unidade:has(input[aria-invalid="true"]) { border-color: var(--erro); }
.unidade:has(input[aria-invalid="true"]):focus-within { outline-color: var(--erro); }

/* Os dois consentimentos viram alvos grandes, na mesma gramatica de .opcao (o
   radio do diagnostico): anel de 2px quando marcado, nunca so a cor. */
.emp_check {
    display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 12px; align-items: start;
    padding: 16px 18px; border: 1px solid var(--borda); border-radius: var(--raio-app);
    background: var(--fundo); cursor: pointer; font-size: var(--tipo-2);
}
.emp_check input { width: 20px; height: 20px; margin: 1px 0 0; flex: none; }
.emp_check:hover { background: var(--preenchimento); }
.emp_check:has(input:checked) { border-color: var(--fss-acao); background: color-mix(in srgb, var(--fss) 7%, transparent); box-shadow: inset 0 0 0 2px var(--fss-acao); }
.emp_check:has(input:focus-visible) { outline: 3px solid var(--fss-acao); outline-offset: 2px; }
.emp_check input:focus-visible { outline: none; box-shadow: none; }
.emp_check_nota { display: block; margin-top: 4px; font-size: var(--tipo-1); color: var(--texto-fraco); }

.emp_pe { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; }
.emp_pe .nota_fina { margin: 0; max-width: 46ch; }

/* --- agendamento ------------------------------------------------------------
   O calendario e um iframe de terceiro: chega quando chega. Enquanto nao chega,
   o quadro mostra o simbolo girando e uma frase em role="status" — e a espera
   de duracao desconhecida para a qual o componente 3D existe.
   A camada de espera nasce com [hidden] e so aparece se o app.js estiver vivo
   (mesma disciplina de .tema_alterna): sem JS ninguem fica olhando um simbolo
   que nada removeria. */
.agenda_quadro { position: relative; border: 1px solid var(--borda); border-radius: var(--raio-app); background: var(--fundo); overflow: hidden; }
.agenda_frame { display: block; width: 100%; min-height: 640px; border: 0; }
.agenda_espera { position: absolute; inset: 0; display: grid; place-content: center; padding: 24px; background: var(--painel-solido); }
.agenda_espera[hidden] { display: none; }
.agenda_saidas { display: grid; gap: 6px; margin: 22px 0 0; font-size: var(--tipo-2); color: var(--texto-suave); }

/* --- motion da onda 6 -------------------------------------------------------
   Opt-in, como todo o resto: nada se move para quem pediu menos movimento. */
@media (prefers-reduced-motion: no-preference) {
    /* O giro e o halo do indicador 3D moram em comum/carregando3d.css, junto do
       resto do componente. */
    .pnl_passo, .pnl_ferr, .emp_check {
        transition: transform var(--dur-hover) var(--curva-suave), border-color var(--dur-hover) var(--curva-suave), background-color var(--dur-micro) ease-out, box-shadow var(--dur-hover) var(--curva-suave);
    }
    .pnl_ferr:hover { transform: translateY(-4px); border-color: var(--borda-marca); }
    .pnl_passo_agora { animation: app_sobe var(--dur-revelar) var(--curva-suave) both; }
    .pagina-app .unidade { transition: border-color var(--dur-micro) ease-out; }
}

/* =============================================================================
   ONDA 7 — progresso por pilar, retomada e campos numericos
   -----------------------------------------------------------------------------
   O bloco fica no FIM do arquivo pela mesma razao do da onda 6: vencer por
   ORDEM, sem `!important` e sem inflar seletor. Nada aqui redefine cor, raio,
   duracao ou espaco fora dos tokens do topo.

   NENHUMA regra deste bloco esconde pergunta. A unica ocultacao de pergunta
   continua sendo `.js-etapas [hidden]`, la em cima, posta por app.js.
   ============================================================================= */

/* Texto que existe so para leitor de tela. Nao usa `display:none` nem
   `visibility:hidden` — os dois tiram o no da arvore de acessibilidade, que e
   exatamente o contrario do que se quer aqui. */
.so-leitor {
    position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap; margin: -1px; padding: 0; border: 0;
}

/* --- progresso por pilar ----------------------------------------------------
   Tres chips dentro da barra fixa: nome, contagem em texto e um trilho fino.
   O NUMERO e o portador do sentido; o trilho e reforco (WCAG 1.4.1), e por isso
   ele e aria-hidden no markup — a leitura vive em .so-leitor, atualizada junto.

   `flex-wrap` na linha interna: a 320px a coluna tem ~94px e "Tecnologia 0/10"
   nao cabe deitado. Deixar quebrar custa 16px de altura e evita o overflow que
   `white-space: nowrap` produziria (a armadilha ja documentada no brain). */
/* `auto-fit`, e nao `repeat(3, ...)`: os pilares sao os STEPS publicados, e o
   template faz questao de nao conhecer "Pessoas/Processos/Tecnologia" (RF03).
   Com tres fixos, um questionario de quatro pilares jogaria o quarto chip para
   uma segunda linha com um terco da largura, e um de dois deixaria uma coluna
   fantasma. O minimo de 84px e o que cabe em "Tecnologia 0/10" a 320px. */
.pilares {
    list-style: none; margin: 10px 0 0; padding: 0;
    display: grid; grid-template-columns: repeat(auto-fit, minmax(84px, 1fr)); gap: var(--esp-2);
}
.pilar { display: grid; gap: 5px; align-content: start; min-width: 0; }
/* `flex-start`, e nao `space-between`: a 1440px a coluna tem ~380px e o
   espacamento jogava o nome numa ponta e a contagem na outra — as tres duplas
   liam como uma frase corrida ("Pessoas 2/10 Processos 0/10"). Juntos, cada
   par e uma unidade.
   `nowrap` + `overflow: hidden` no nome: quebrar so em ALGUNS chips (o nome
   mais longo quebra, os curtos nao) desalinhava os trilhos entre si a 320px.
   Determinismo > pixel: o corte e rede de seguranca e nao chega a acontecer
   nas larguras medidas. */
.pilar_linha { display: flex; flex-wrap: nowrap; align-items: baseline; gap: 6px; min-width: 0; }
.pilar_nome {
    display: inline-flex; align-items: center; gap: 4px; min-width: 0; overflow: hidden;
    font-size: var(--tipo-1); font-weight: 700; color: var(--texto-suave);
}
.pilar_conta {
    font-family: var(--mono); font-variant-numeric: tabular-nums;
    font-size: var(--tipo-1); font-weight: 700; color: var(--texto);
}
.pilar_trilho { display: block; height: 4px; border-radius: var(--pilula); background: var(--preenchimento); overflow: hidden; }
.pilar_trilho > i { display: block; height: 100%; border-radius: var(--pilula); background: var(--fss); }
/* O glifo so entra quando o pilar fecha: e o sinal do marco, e ocupar a linha
   antes disso roubaria largura de "Tecnologia" a 320px. */
.pilar_glifo { display: none; }
.pilar_feito .pilar_glifo { display: inline-flex; color: var(--sucesso); }
.pilar_feito .pilar_nome, .pilar_feito .pilar_conta { color: var(--sucesso); }
.pilar_feito .pilar_trilho > i { background: var(--sucesso); }

/* --- a linha do que falta (e o marco, quando fecha) -------------------------
   Marco e contagem moram no MESMO paragrafo de proposito: o texto troca, a
   caixa nao, e nada empurra a pergunta para baixo no momento da celebracao.
   Celebrar nao pode custar layout. */
/* `block` pelo mesmo motivo de .emp_completude: glifo e frase sao dois itens, e
   em flex a 320px o glifo ganhava uma linha so para ele. */
.diag_restante {
    display: block;
    margin: 14px 0 0; font-size: var(--tipo-2); color: var(--texto-suave);
}
.diag_restante_glifo { color: var(--sucesso); margin-right: 5px; }
.diag_restante_glifo[hidden] { display: none; }
.diag_restante_pronto { color: var(--sucesso); font-weight: 700; }

/* --- onde a pessoa parou (sem JS, e a unica pista) -------------------------- */
.diag_retomada {
    display: grid; gap: 4px; margin: 14px 0 0;
    padding: 12px 14px; border-inline-start: var(--acento-largura) solid var(--fss-acao);
    border-radius: 0 var(--raio-p) var(--raio-p) 0;
    background: var(--painel); font-size: var(--tipo-2);
}
.diag_retomada[hidden] { display: none; }
.diag_retomada_rotulo {
    font-size: var(--tipo-1); font-weight: 800; letter-spacing: .08em;
    text-transform: uppercase; color: var(--fss-texto);
}

/* Numero de ordem da pergunta. Sai por `content` porque o app.js monta a lista
   de pendencias com `legend.textContent` — ver o comentario do template. */
.pergunta_titulo[data-n]::before {
    content: attr(data-n);
    display: inline-block; margin-right: 9px;
    font-family: var(--mono); font-size: var(--tipo-1); font-weight: 800;
    color: var(--texto-fraco);
}

.diag_falta_envio {
    margin: 0 0 var(--gap); font-size: var(--tipo-2); color: var(--texto-suave);
    max-width: 62ch;
}
.diag_falta_envio[hidden] { display: none; }
.diag_falta_envio .icone { color: var(--texto-suave); }

/* Em modo etapa cada pixel acima da pergunta e disputado (secao 12.6: a
   pergunta cabe na primeira tela do celular). Os chips ficam — sao o placar —
   mas apertados. */
.js-etapas-pagina .pilares { margin-top: 8px; gap: 6px; }
.js-etapas-pagina .diag_restante { margin-top: 10px; }

/* A 320px cada chip tem ~93px. Medido: "Tecnologia" + "0/10" a 13px pede 94px
   e estoura; a 11px pede 86px e sobra folga. E o unico lugar do bloco com
   tamanho fora da escala, e existe por medida, nao por gosto. */
@media (max-width: 400px) {
    .pilares { gap: var(--esp-1); }
    .pilar_nome, .pilar_conta { font-size: .6875rem; }
}

/* --- campos numericos do cadastro da empresa -------------------------------- */

/* O eco: como o SERVIDOR vai ler o que foi digitado. Nasce [hidden] e quem o
   revela e o app.js — sem JS ninguem fica olhando um espelho que nao reflete. */
.campo_eco {
    margin: 6px 0 0; font-size: var(--tipo-1);
    color: var(--texto-fraco); font-variant-numeric: tabular-nums;
}
.campo_eco[hidden] { display: none; }
.campo_eco_duvida { color: var(--alerta); }

/* Passo -/+ : ajuste, nunca a entrada principal. Nasce [hidden] pela mesma
   disciplina de .tema_alterna e do botao de revelar senha. */
.ajuste { display: inline-flex; align-items: stretch; }
.ajuste[hidden] { display: none; }
.ajuste_btn {
    display: grid; place-items: center; width: 44px; min-height: 46px;
    font: inherit; font-size: var(--tipo-4); font-weight: 700; line-height: 1;
    color: var(--texto-suave); background: none; border: 0;
    border-left: 1px solid var(--borda); cursor: pointer;
}
.ajuste_btn:hover { background: var(--preenchimento); color: var(--texto); }
.ajuste_btn:focus-visible { outline: 2px solid var(--fss-acao); outline-offset: -2px; }
.unidade_ajuste { grid-template-columns: minmax(0, 1fr) auto auto; }

/* Completude dos numeros: contagem, nao cobranca.
   O seletor e longo por NECESSIDADE, nao por gosto: `.tile p` (0,1,1) vence
   `.emp_completude` (0,1,0) por especificidade, independentemente da ordem, e
   comia margem, tamanho e cor deste bloco. O par `.pagina-app .emp_form` e o
   mesmo escopo que a regra irma de `.dica` ja usa. */
/* `block`, e nao `flex`: em flex o glifo, o <strong> e o resto da frase sao
   TRES itens, e a 320px cada um caia numa linha propria — o glifo sozinho no
   alto de uma caixa de tres linhas. Em fluxo normal a frase quebra como texto,
   que e o que ela e. O glifo continua alinhado pela regra `.icone`. */
.pagina-app .emp_form .emp_completude {
    display: block;
    margin: 18px 0 0; padding: 12px 14px;
    border: 1px dashed var(--contorno); border-radius: var(--raio-p);
    font-size: var(--tipo-2); line-height: 1.6; color: var(--texto-suave);
}
.pagina-app .emp_form .emp_completude strong { color: var(--texto); }
/* Mesma especificidade da regra acima, senao o tracejado dela vence o solido
   daqui e o estado "completo" nunca muda de forma. */
.pagina-app .emp_form .emp_completude_ok {
    border-style: solid; border-color: color-mix(in srgb, var(--sucesso) 45%, transparent);
}
.pagina-app .emp_form .emp_completude_ok strong { color: var(--sucesso); }
.emp_completude_glifo { color: var(--sucesso); margin-right: 5px; }

/* --- motion da onda 7 -------------------------------------------------------
   Tres efeitos, todos curtos e todos opt-in. Nenhum deles atrasa a resposta ao
   clique: a classe entra no mesmo tick do evento e o autosave segue no proprio
   listener, com o debounce de 500ms intocado. */
@media (prefers-reduced-motion: no-preference) {
    /* A opcao escolhida "assenta": um empurrao de 2% que volta. */
    @keyframes op_pulso { 40% { transform: scale(1.015); } }
    /* O chip do pilar que fechou pisca uma vez na cor de sucesso. */
    @keyframes pil_marco { 30% { transform: translateY(-3px); } }

    .opcao.pulso { animation: op_pulso 260ms var(--curva-suave); }
    .pilar.pulso { animation: pil_marco 420ms var(--curva-suave); }

    .pilar_trilho > i, .pagina-app .barra > i { transition: width var(--dur-hover) var(--curva-suave); }
    .pilar_nome, .pilar_conta { transition: color var(--dur-hover) var(--curva-suave); }
    .ajuste_btn { transition: background-color var(--dur-micro) ease-out, color var(--dur-micro) ease-out; }
    .diag_restante { transition: color var(--dur-hover) var(--curva-suave); }
}

/* =============================================================================
   ONDA 8 — conquista honesta no painel
   -----------------------------------------------------------------------------
   Quatro pecas, todas escopadas em classe propria e escritas no FIM do arquivo
   pela mesma razao das ondas 6 e 7: vencer por ORDEM, sem `!important` e sem
   inflar seletor. Nenhum valor cru — cor, raio, espaco e duracao saem dos
   tokens do topo.

     .pnl_medida     -> quantas de N respondidas, DENTRO do passo do diagnostico
     .pnl_premio     -> o relatorio como recompensa (ele existe; e o unico premio)
     .pnl_conquista  -> o marco de quem fechou as tres etapas
     .pnl_ferr_nota  -> o desmentido do cadeado na secao "o que vem depois"

   O QUE NAO EXISTE AQUI, DE PROPOSITO: cadeado, cinza-desabilitado sobre
   ferramenta, barra que anima sozinha, brilho pulsante permanente. A secao 12.6
   pede progresso real e proibe dark pattern; uma folha de estilo tambem mente
   quando desenha tranca em cima do que nunca foi trancado.
   ============================================================================= */

/* --- a medida fina do diagnostico -------------------------------------------
   Mora na segunda coluna do .pnl_passo, abaixo da nota. So e renderizada quando
   o servidor tem contagem REAL (respondidas != null): nao existe estado "0 de
   30" de consolo, nem trilho vazio decorativo.

   O NUMERO e o portador do sentido e o trilho e reforco — por isso ele vai
   `aria-hidden` no markup e nao ha um segundo role="progressbar" no cartao (a
   barra de etapas da secao ja e a regiao de progresso). Mesma decisao dos chips
   de pilar do diagnostico (WCAG 1.4.1). */
.pnl_medida { display: grid; gap: 7px; margin: 12px 0 0; }
.pnl_medida_conta {
    font-family: var(--mono); font-variant-numeric: tabular-nums;
    font-size: var(--tipo-2); font-weight: 700; color: var(--texto);
}
.pnl_medida_trilho {
    display: block; height: 6px; border-radius: var(--pilula);
    background: var(--preenchimento); overflow: hidden;
}
.pnl_medida_trilho > i { display: block; height: 100%; border-radius: var(--pilula); background: var(--fss); }
/* A COR SAIU DE MEDICAO, nao de gosto. Esta linha vive dentro do cartao
   `.pnl_passo_agora`, cujo fundo e `--lavagem` (a marca a 10% sobre o painel) —
   e sobre ELE, no tema claro, `--texto-suave` cai para 4,34:1 e `--texto-fraco`
   raspa em 4,58:1. A 13px isso reprova ou passa sem folga. A mistura abaixo da
   5,83:1 no claro e 7,50:1 no escuro, mantendo o tom secundario: e o token
   `--texto` diluido, nunca uma cor nova. */
.pnl_medida_falta {
    font-size: var(--tipo-1); line-height: 1.5;
    color: color-mix(in srgb, var(--texto) 70%, transparent);
}

/* Corpo do passo em coluna, com o rotulo de estado ancorado no PE. O passo do
   diagnostico e o unico que ganha a medida fina, e sem a ancora ele esticava a
   fileira inteira: os outros dois ficavam com ~130px de vao morto embaixo do
   texto e o "Concluído"/"Depois" flutuando no meio do nada. `padding-top`, e
   nao `margin-top`, porque o `auto` que empurra o rotulo consome a margem. */
.pnl_passo { align-items: stretch; }
.pnl_passo > .pnl_passo_n { align-self: start; }
/* `align-items` fica no default (stretch) DE PROPOSITO: com `flex-start` o
   .pnl_medida encolhe para max-content e o trilho, que e um bloco sem largura
   propria, colapsa para zero. */
.pnl_passo_corpo { display: flex; flex-direction: column; min-width: 0; }
.pnl_passo_corpo .pnl_passo_estado { margin-top: auto; padding-top: 12px; }

/* --- o passo que e o premio -------------------------------------------------
   O cartao do relatorio ganha a borda da marca mesmo enquanto espera: ele e o
   destino da trilha, e o tracejado de .pnl_passo_espera continua dizendo "ainda
   nao". Marcar o destino nao e prometer desbloqueio — o relatorio e calculado e
   entregue, e a secao abaixo diz exatamente o que ele traz. */
.pnl_passo_premio { border-color: var(--borda-marca); }

/* --- a faixa do premio ------------------------------------------------------
   Superficie de TEMA (--painel-solido), nunca cor fixa: painel que nao troca
   com o tema herdando --texto da o preto-sobre-preto do claro. O filete
   esquerdo repete a assinatura de .diag_retomada. */
.pnl_premio {
    display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 18px; align-items: start;
    margin: 22px 0 0; padding: 22px 24px;
    /* SEM A BARRA DE ACENTO (direcao B, 20/08/2026). Ela tinha um filete
       vermelho de 3px no inicio, que virou o carimbo desta direcao — e o
       carimbo tem um significado so: PROXIMO PASSO. Este bloco descreve o
       premio da trilha, nao pede acao nenhuma, e ficava a 200px do passo
       "Agora", que e o proximo passo de verdade. Dois carimbos na mesma
       rolagem, um deles mentindo. Fica so a borda da marca, que ja o distingue
       dos cartoes vizinhos. */
    border: 1px solid var(--borda-marca);
    border-radius: var(--raio-app); background: var(--painel-solido);
}
.pnl_premio_glifo {
    width: 44px; height: 44px; border-radius: var(--raio-p); display: grid; place-items: center;
    background: color-mix(in srgb, var(--fss) 12%, transparent); border: 1px solid var(--borda-marca); color: var(--fss-texto);
}
/* (0,1,0) vence o `h3` global (0,0,1) — e por ordem, nao por peso inflado. */
.pnl_premio_titulo { margin: 8px 0 8px; font-size: var(--tipo-4); font-weight: 800; letter-spacing: -.02em; line-height: 1.2; color: var(--texto); }
.pnl_premio_txt { margin: 0; font-size: var(--tipo-2); line-height: 1.65; color: var(--texto-suave); max-width: 66ch; }
.pnl_premio_txt strong { color: var(--texto); }
/* A 380px o quadro do glifo come um terco da linha do titulo. Some ele: a
   informacao inteira esta no texto. */
@media (max-width: 420px) {
    .pnl_premio { grid-template-columns: minmax(0, 1fr); gap: 0; padding: 18px 20px; }
    .pnl_premio_glifo { display: none; }
}

/* Efeito "Level Up" — usado em modais de curso e análise de call.
   Apenas transforms/transitions, NENHUM box-shadow vermelho proibido.
   Apenas --accent-primary, que e a cor oficial FSS.
   Ativado via classe .level-up-ativo no elemento container. */
.level-up {
    --_level-start: 0;
    --_level-fim: 100%;
    --_level-dur: 400ms;
    --_level-curva: cubic-bezier(0.65, 0, 0.35, 1);
    position: relative;
    overflow: hidden;
}
.level-up::before {
    content: ""; position: absolute; inset: 0; pointer-events: none;
    border-bottom: var(--acento-largura) solid var(--accent-primary);
    transform: translateY(100%);
    transition: transform var(--_level-dur) var(--_level-curva);
}
.level-up .level-numero {
    font-family: var(--mono); font-size: var(--tipo-2); color: var(--accent-primary);
    position: relative; z-index: 1;
    transition: transform var(--_level-dur) var(--_level-curva),
                opacity var(--_level-dur) ease-out;
}
.level-up .level-numero::after {
    content: " ✓"; position: absolute; inset: 0; pointer-events: none;
    transform: scale(0); transition: transform var(--_level-dur) var(--_level-curva);
}
.level-up-ativo::before { transform: translateY(var(--_level-fim)); }
.level-up-ativo .level-numero { transform: scale(1); opacity: 1; }
.level-up-ativo .level-numero::after { transform: scale(1); }

/* Variante provisional — opacidade reduzida para indicar versao em dev */
.level-up-provisorio::before {
    border-color: color-mix(in srgb, var(--accent-primary) 70%, transparent);
}
.level-up-provisorio .level-numero {
    color: color-mix(in srgb, var(--accent-primary) 70%, transparent);
}

/* --- o marco de conclusao ---------------------------------------------------
   Uma linha, um fato: as tres etapas fecharam. Sem confete e sem "voce ganhou".
   Forma (glifo) + texto + cor, nunca cor sozinha. */
.pnl_conquista {
    display: flex; align-items: flex-start; gap: 11px;
    margin: 0 0 26px; padding: 14px 18px;
    border: 1px solid color-mix(in srgb, var(--sucesso) 42%, transparent);
    border-bottom: 1px solid color-mix(in srgb, var(--accent-subtle) 100%, transparent);
    border-radius: var(--raio-app);
    background: color-mix(in srgb, var(--sucesso) 9%, transparent);
    font-size: var(--tipo-2); line-height: 1.55; color: var(--texto-suave);
}
.pnl_conquista strong { color: var(--texto); }
/* inline-flex para que o pulso (transform) tenha efeito: transform nao se
   aplica a caixa inline nao-substituida. */
.pnl_conquista_glifo { display: inline-flex; flex: none; margin-top: 2px; color: var(--sucesso); }

/* Selo "em breve" ancorado no PE do cartao. Os quatro nomes tem alturas
   diferentes (dois quebram em duas linhas), e com `align-content: start` os
   selos flutuavam em quatro alturas distintas — a fileira lia como quatro
   cartoes desalinhados em vez de um conjunto. A linha de `1fr` e a do texto:
   ela absorve a sobra e empurra o selo para baixo. */
.pnl_ferr { align-content: stretch; grid-template-rows: auto auto 1fr auto; }

/* --- o desmentido do cadeado ------------------------------------------------
   `block`, e nao `flex`: em flex o glifo vira um item so e a 320px ele ganha
   uma linha inteira no alto da caixa (a armadilha ja documentada em
   .emp_completude e .diag_restante). Em fluxo normal a frase quebra como texto,
   que e o que ela e. */
/* `margin-inline: auto` e o que CENTRALIZA a caixa. Com `max-width` e margem
   lateral zero ela ficava encostada a esquerda, desalinhada da grade de
   ferramentas logo acima — mesmo defeito que o aviso do rodape teve em 13/08.
   O TEXTO segue alinhado a esquerda de proposito: sao tres linhas de prosa, e
   centralizar paragrafo faz o olho procurar o inicio de cada linha. */
.pnl_ferr_nota {
    display: block; margin: 20px auto 0; padding: 14px 16px;
    border: 1px dashed var(--contorno); border-radius: var(--raio-p);
    font-size: var(--tipo-2); line-height: 1.6; color: var(--texto-suave);
    max-width: 76ch;
}
.pnl_ferr_nota strong { color: var(--texto); }
.pnl_ferr_nota_glifo { color: var(--texto-suave); margin-right: 6px; }

/* --- motion da onda 8 -------------------------------------------------------
   UM efeito, uma vez, e so ele: o glifo do marco cresce 18% e volta. Celebrar
   nao pode custar layout (o transform nao reflui) nem repetir para sempre. Quem
   pediu menos movimento ve o marco parado — a informacao e a mesma. */
@media (prefers-reduced-motion: no-preference) {
    @keyframes pnl_marco { 35% { transform: scale(1.18); } }

    .pnl_conquista_glifo { animation: pnl_marco 520ms var(--curva-suave) 200ms; }
    .pnl_medida_trilho > i { transition: width var(--dur-hover) var(--curva-suave); }
}

/* --- /app/configuracoes: o bloco em LEITURA ---------------------------------
   Minimo funcional da onda de backend (14/08/2026). O acabamento da referencia
   do dono — cartoes empilhados, selo de secao, valores em monoespacada — e da
   onda de frontend; o que existe aqui e o suficiente para a tela nao nascer
   quebrada.

   <dl>, e nao uma grade de <div>: rotulo e valor sao um par de definicao, e o
   leitor de tela anuncia "E-mail, fulano@..." sem que o markup precise repetir
   o rotulo em aria-label. */
.conta_leitura { display: grid; gap: 14px; margin: 0 0 20px; }
.conta_leitura dt {
    font-size: var(--tipo-1); text-transform: uppercase; letter-spacing: .08em;
    color: var(--texto-suave);
}
.conta_leitura dd {
    margin: 4px 0 0; display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
    font-family: var(--mono); color: var(--texto);
}
/* O selo diz o ESTADO do campo (nao editavel), entao ele e texto de verdade:
   cor sozinha nao pode carregar a informacao (WCAG 1.4.1). */
.conta_selo {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 3px 10px; border: 1px solid var(--contorno); border-radius: var(--pilula);
    font-family: var(--fonte); font-size: var(--tipo-1); color: var(--texto-suave);
}

/* =============================================================================
   ONDA 9 — a espera honesta (a tela "Calculando")
   -----------------------------------------------------------------------------
   O bloco fica no FIM pela mesma razao das ondas 6, 7 e 8: vencer por ORDEM,
   sem `!important` e sem inflar seletor. Nenhum valor cru — as duas duracoes
   novas sao DERIVADAS de tokens que ja existiam.

   A tela agora tem seis fases (normal, demora, limite, falhou, sessao, pronto)
   e todas moram no MESMO HTML: quem esconde as outras e `hidden`, posto pelo
   servidor no render e trocado pelo app.js depois. Isto e o que faz a tela
   funcionar sem JavaScript.

   O QUE CONTINUA NAO EXISTINDO, de proposito: barra de progresso, percentual,
   contagem regressiva, "faltam X segundos". A secao 12.6 proibe progresso
   simulado e o worker termina quando termina — nenhum numero seria verdade.
   ============================================================================= */

:root {
    /* Marcha lenta do simbolo 3D, usada quando a espera passa do limite. E o
       MESMO token em outra marcha (o dobro), nao uma duracao nova solta. */
    --dur-3d-lento: calc(var(--dur-3d) * 2);
    /* Saida da tela de espera. A duracao mora aqui e em lugar nenhum mais: o
       app.js escuta o `animationend` em vez de repetir o numero. Dois passos de
       --dur-hover — tempo de ler "Pronto!" antes de a pagina trocar. */
    --dur-saida: calc(var(--dur-hover) * 2);
    /* A COMEMORACAO (onda 68): o atraso ANTES de a saida comecar. A chegada e o
       instante de recompensa da tela — a pessoa acabou de responder um
       diagnostico inteiro — e ate aqui ela durava os 45 por cento parados de
       `esp_sai`, tempo curto demais para a trilha fechar e o simbolo assentar.
       E atraso, e nao duracao maior: a saida em si continua no mesmo compasso,
       e o `animationend` continua sendo quem avisa o app.js (delay + duracao
       cabem folgados na rede de seguranca de 1400 ms). */
    --dur-celebra: calc(var(--dur-hover) * 1.5);
}

/* --- a tela ocupa a altura, porque nao ha nada abaixo dela (onda 68) --------
   Mesmo recurso de `.pagina-auth main`, e pelo mesmo motivo: uma tela sem
   conteudo de leitura fica ancorada no topo com o resto da janela vazio, e o
   olho le isso como "a pagina nao terminou de carregar". `safe center` e o
   detalhe que importa — com `center` puro, numa janela baixa o topo do cartao
   sai para fora e fica INALCANCAVEL pela rolagem.
   A altura descontada e a soma de cabecalho e rodape medidos aqui; abaixo dela
   o `min-height` some e a tela volta a fluir. */
.pagina-espera main { display: grid; align-items: safe center; min-height: calc(100vh - 260px); }
@media (max-height: 640px) {
    .pagina-espera main { min-height: 0; align-items: start; }
}

/* A ARMADILHA QUE ESTA REGRA FECHA. `hidden` e do agente de usuario e vale
   `display: none` com especificidade ZERO: qualquer regra deste arquivo que
   declare `display` no mesmo no vence dele. Aqui havia duas prontas para
   morder — `.espera3d strong { display: block }` e a lista de fases, que na
   onda 9 era o esqueleto do relatorio e desde a 68 e `.esp_trilha { display:
   grid }` — e o resultado seria a fase escondida continuar na tela, as sete de
   uma vez. (0,2,0) resolve sem `!important`.
   O exemplo trocou de nome e a armadilha nao: quem declarar `display` dentro
   de `.rel_espera` na proxima onda cai nela do mesmo jeito. */
.rel_espera [hidden] { display: none; }

/* Cada fase do estado e um bloco: `strong` (o titulo) ja quebra linha sozinho
   por `.espera3d strong`, e o `span` que envolve os dois precisa ser o bloco
   para nao virar uma linha corrida com a frase colada.

   O `:not([hidden])` NAO e decoracao — sem ele esta regra (0,3,0) atropela o
   guarda logo acima (0,2,0) e as SEIS fases aparecem empilhadas de uma vez.
   Foi medido acontecendo: primeira rodada de capturas da onda 9. Regra geral
   para este arquivo: quem declara `display` dentro de `.rel_espera` precisa
   excluir o estado escondido explicitamente. */
.rel_espera .rel_status > span:not([hidden]) { display: block; }

/* --- as saidas (limite, falha, sessao) --------------------------------------
   A caixa de mensagem ja traz a moldura; o que falta e o respiro entre ela, o
   indicador acima e os botoes abaixo. A margem inferior do .msg vai a zero
   porque quem separa dali para baixo e o .acoes. */
.esp_saida { margin-top: 24px; }
/* A COR SAIU DE MEDICAO, nao de gosto. `.msg` nao declara cor propria: ela
   herda o tom secundario do cartao e cai sobre o veu de 12% da cor de estado.
   Medido nesta tela, tema claro, 15px normal: 4,24:1 no erro e 4,45:1 no
   alerta — os dois REPROVAM o piso de 4,5:1 (WCAG 2.2 AA) por pouco, que e o
   jeito mais facil de reprovar sem ninguem notar. Com --texto: 12,6:1 no claro
   e 13,6:1 no escuro. E a frase que carrega o estado inteiro da tela; ela nao
   pode ser a mais fraca do cartao.
   (O mesmo veu afeta `.msg` em outras telas do /app — fica anotado, e correcao
   de outra onda: mexer no componente global daqui atingiria painel e
   relatorio, que nao estao sob revisao.) */
.esp_saida .msg { margin-bottom: 0; color: var(--texto); }
/* Empata em especificidade com `.pagina-app .acoes` (34px) e vence por ordem:
   dentro do cartao, 34px afasta demais o botao da frase que o justifica. */
.esp_saida .acoes { margin-top: 20px; }
/* `text-align` nao alcanca item de flex: sem esta linha os botoes ficavam
   ancorados a esquerda dentro de um cartao centralizado — o mesmo desencontro
   de eixos que a onda 68 veio resolver, so que em miniatura. Vale para o
   <form> da retomada tambem, que carrega a classe `.acoes`. */
.rel_espera .acoes { justify-content: center; }

/* A nota de atualizacao automatica. Fluxo normal, nao flex: em flex o glifo
   vira item proprio e a 320px ganha uma linha inteira (armadilha ja documentada
   em .pnl_ferr_nota e .emp_completude). */
.esp_auto > .icone { margin-right: 7px; color: var(--texto-suave); }

/* --- o simbolo muda de marcha quando a espera passa do limite ---------------
   Ele NAO some e NAO para: o polling continua vivo, e apagar o sinal de
   "trabalhando" enquanto o trabalho pode estar acontecendo seria outra mentira.
   Ele recua — mais lento e mais discreto — porque a partir dali o assunto da
   tela e a saida, nao a espera. Sao dois tokens; nenhuma keyframe nova. */
.rel_espera[data-fase="limite"] .carregando3d,
.rel_espera[data-fase="falhou"] .carregando3d,
.rel_espera[data-fase="sessao"] .carregando3d { --dur-3d: var(--dur-3d-lento); opacity: .55; }

/* A TRILHA NAO RECUA NO LIMITE, e isso foi MEDIDO e nao escolhido.
   A primeira versao desta onda dava a ela o mesmo `opacity: .55` do simbolo. O
   simbolo e uma imagem; a trilha tem TEXTO, e a opacidade derrubou o rotulo do
   passo corrente de 15,4:1 para 3,97:1 no tema claro — abaixo do piso de
   4,5:1, com o axe da mesma pagina reportando ZERO violacoes (ele nao computa
   opacidade herdada de ancestral; ja e a segunda vez que este projeto e
   avisado disso).
   E a decisao continuaria errada mesmo se passasse: `limite` e justamente onde
   a trilha vale mais — parada em "Na fila" depois de muito tempo, ela e o
   retrato do worker fora do ar. Apagar informacao para "dar destaque a saida"
   e apagar a unica pista de por que nao ha resultado. */

/* Na sessao expirada o polling REALMENTE parou — aqui o simbolo parado e a
   verdade, e nao um enfeite congelado. */
.rel_espera[data-fase="sessao"] .carregando3d_simbolo { animation: none; }

/* --- a chegada (onda 68) ----------------------------------------------------
   O anel do indicador vira verde no instante em que a trilha fecha: o simbolo
   deixa de ser "trabalhando" e vira "terminado" sem trocar de desenho. Nao e
   animacao — e uma transicao de cor, entao vale tambem sob `reduce`, onde o
   navegador so a encurta. */
   ESCOPADO EM `.rel_espera` de proposito: `.carregando3d` e componente
   compartilhado (portal, painel, espera da call) e uma transicao declarada no
   seletor nu chegaria em telas que nao estao nesta onda. */
.rel_espera .carregando3d::after { transition: border-color var(--dur-hover) var(--curva-suave); }
.rel_espera[data-fase="pronto"] .carregando3d::after { border-color: var(--sucesso); }

/* --- motion da onda 9 -------------------------------------------------------
   Opt-in, como todo o resto do arquivo. Sob `reduce` a tela troca de fase por
   corte — o texto e o mesmo, a informacao e a mesma. */
@media (prefers-reduced-motion: no-preference) {
    /* A troca de fase nao pode ser um corte seco: a frase nova surge. Nao ha
       classe de estado nem timer para isso — quando o no sai de `display:none`
       o navegador reinicia a animacao dele sozinho, que e exatamente o gatilho
       que se quer. Vale tambem para a carga inicial. */
    .rel_espera [data-espera-fase] { animation: app_surge var(--dur-entrada) var(--curva) both; }

    /* A SAIDA, o unico efeito novo desta onda. O relatorio e o momento de maior
       expectativa do produto e ate agora ele chegava por reload seco. Os
       primeiros 45% do tempo sao parados de proposito: e a janela em que se le
       "Pronto! Abrindo seu relatorio…" antes de a pagina ceder lugar. */
    @keyframes esp_sai {
        0%, 45% { opacity: 1; transform: none; filter: blur(0); }
        100%    { opacity: 0; transform: translateY(-10px); filter: blur(6px); }
    }
    /* O ATRASO E A COMEMORACAO (onda 68). Durante ele o quadro esta parado no
       0 por cento (`both` faz o preenchimento para tras), entao o que a pessoa
       ve e a trilha fechando, o simbolo assentando e o anel virando verde —
       e so depois a pagina cede lugar. Sem o atraso, tudo isso comecava junto
       com o desaparecimento e nao dava tempo de acontecer. */
    .rel_espera.esp_saindo { animation: esp_sai var(--dur-saida) var(--curva-suave) var(--dur-celebra) both; }

    /* O SIMBOLO ASSENTA em vez de parar no meio do giro. Trocar `c3d_gira` por
       `animation: none` daria um salto para a face de frente vindo de um
       angulo qualquer; a escala mascara a troca e le como "peca pousando".
       Vence `c3d_gira` por especificidade (0,3,0 contra 0,1,0) e por ordem —
       comum/carregando3d.css e importado no topo deste arquivo. */
    @keyframes esp_assenta {
        from { transform: scale(.82); }
        60%  { transform: scale(1.06); }
        to   { transform: none; }
    }
    .rel_espera[data-fase="pronto"] .carregando3d_simbolo {
        animation: esp_assenta 420ms var(--curva-suave) both;
    }

    /* A trilha fecha por ULTIMO, e nao junto: o passo "Pronto" chega com um
       impulso proprio, que e o unico ponto da tela em que algo "acontece" em
       vez de mudar de estado. Nao ha keyframe nova — e `esp_assenta` no
       tamanho da marca, onde ela nao reflui nada porque a marca ja e um
       quadrado fixo. */
    .rel_espera[data-fase="pronto"] .esp_passo:last-child .esp_passo_marca {
        animation: esp_assenta 380ms var(--curva-suave) 120ms both;
    }
}

/* =============================================================================
   CONQUISTAS — marcos da jornada, e o botao de carregar mais.

   Nao ha ponto, nivel nem ofensiva: cada cartao e um fato com data. O visual
   distingue CONCLUIDO de PENDENTE por tres portadores ao mesmo tempo — cor,
   preenchimento do selo e a palavra escrita —, porque cor sozinha nao serve
   (WCAG 1.4.1) e "pendente" nao pode parecer punicao.
   ========================================================================== */

.conq {
    list-style: none;
    margin: 24px 0 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 14px;
}

/* [hidden] PRECISA vir com a mesma especificidade e DEPOIS do display.
   A folha do navegador define [hidden]{display:none} com especificidade de
   elemento; `display:flex` numa classe vence, e o item marcado como oculto
   continuava desenhado. O sintoma so aparece na tela — no DOM o atributo
   estava la, e a contagem de escondidos batia. */
.conq_item[hidden] { display: none; }

.conq_item {
    display: flex;
    align-items: start;
    gap: 13px;
    padding: 16px;
    border: 1px solid var(--borda);
    border-radius: var(--raio-p);
    background: var(--superficie);
}

/* Pendente NAO e erro: fica apenas mais discreto. Nada de vermelho nem de "x" —
   o usuario que ainda nao qualificou nao falhou em nada.

   A DISCRICAO MUDOU DE LUGAR EM 20/08/2026, e o motivo e medido.

   Era `opacity: .62` no CARTAO INTEIRO. Opacidade de container nao "apaga um
   pouco": ela compoe TODO texto de dentro contra o fundo, e o contraste cai
   junto. Medido no pixel renderizado, com o runner da onda 19 (o que enxerga
   `opacity` acumulada na cadeia): `.conq_nota` e `.conq_data` caiam a 2,78:1 no
   claro e 3,52:1 no escuro, contra um piso de 4,5. Reprovacao de verdade, em
   producao — e nao havia valor de alfa que salvasse: para o texto voltar aos
   4,5:1 seria preciso alfa ~0,9, que ninguem ve como "mais discreto".

   Este e o terceiro defeito de contraste da onda, e ele nao foi encontrado por
   leitura: ele estava ESCONDIDO do axe pela revelacao por rolagem, e apareceu
   assim que o conserto de `.vt` (mais acima) parou de deixar meia pagina
   invisivel. E a prova de que aquele conserto valia por si.

   O que ficou no lugar: a MESMA gramatica que o portal ja usa para "ainda nao"
   — contorno tracejado e sem preenchimento (`.pnl_passo_espera`,
   `.rel_pilar_vazio`, `.emp_completude`). A discricao passa a viver na
   SUPERFICIE, que nao tem texto por cima, e o conteudo do cartao volta a ser
   legivel. A palavra continua sendo o portador principal ("Ainda não"), como
   manda a WCAG 1.4.1. */
.conq_item:not(.conq_feito) {
    background: transparent;
    border-style: dashed;
}
.conq_feito { border-color: var(--borda-feito); }

.conq_selo {
    display: grid;
    place-items: center;
    width: 38px;
    height: 38px;
    flex: none;
    border-radius: 50%;
    background: var(--superficie-alta);
    color: var(--texto-suave);
    font-size: var(--tipo-4);
}

.conq_feito .conq_selo {
    background: color-mix(in srgb, var(--sucesso) 14%, transparent);
    color: var(--sucesso);
}

.conq_corpo { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.conq_titulo { font-weight: 700; font-size: var(--tipo-2); letter-spacing: -.01em; }
.conq_nota { color: var(--texto-suave); font-size: var(--tipo-1); line-height: 1.45; }
/* Medido em 18/08/2026: os CINCO piores consumidores de --fss-texto na pagina
   eram estes — "Concluido em ..." em vermelho de marca. Agora e o verde de
   sucesso: 10,24:1 no cartao escuro, 7,56:1 no claro. */
.conq_data { margin-top: 4px; font-size: var(--tipo-1); font-weight: 600; color: var(--sucesso); }
.conq_pendente { color: var(--texto-suave); font-weight: 400; }

/* --- o botao de carregar mais --------------------------------------------- */

.conq_mais {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    margin: 18px auto 0;
    padding: 11px 20px;
    border: 1px solid var(--borda-marca);
    border-radius: var(--pilula);
    background: transparent;
    color: var(--fss-texto);
    font: inherit;
    font-weight: 700;
    font-size: var(--tipo-2);
    cursor: pointer;
}

.conq_mais[hidden] { display: none; }
.conq_mais:hover { background: color-mix(in srgb, var(--fss) 8%, transparent); }

/* O GLIFO EM 3D.
   perspective no pai + preserve-3d no filho e o que da profundidade REAL: o
   giro em rotateY encurta a largura como um objeto que vira, e nao como um
   desenho que estica. Sem perspective o mesmo rotateY vira um achatamento
   chapado — e a diferenca entre parecer 3D e ser. */
.conq_mais_glifo {
    display: grid;
    place-items: center;
    width: 22px;
    height: 22px;
    perspective: 90px;
}

.conq_mais_glifo .icone {
    transform-style: preserve-3d;
    transition: transform 520ms cubic-bezier(.34, 1.3, .5, 1);
}

.conq_mais:hover .conq_mais_glifo .icone { transform: rotateY(180deg); }

/* NAO HA ESTADO "CARREGANDO" AQUI — E ISSO E DELIBERADO (17/08/2026).

   A primeira versao girava o glifo por 1,1s enquanto um aria-busy ficava
   ligado. So que este botao NAO CARREGA NADA: os sete marcos ja estao no
   HTML, e o giro so existia porque eu havia inserido 420ms de espera
   artificial para ele ser visto. Era progresso simulado.

   comum/carregando3d.css — o indicador 3D compartilhado pelos dois
   produtos — diz a regra na propria documentacao: ele e para espera de
   duracao DESCONHECIDA (calculo do relatorio, proxima pagina da listagem,
   iframe da agenda). Onde nao ha espera, nao ha indicador. O portal ja o
   importa e o usa nesses tres lugares; duplicar a ideia aqui, para uma
   revelacao instantanea, seria inventar trabalho para mostrar animacao.

   O que ficou e o giro no HOVER: resposta a uma acao real do ponteiro,
   nao simulacao de processamento. */

/* Entrada dos itens revelados: escalonada, para o olho acompanhar o que chegou
   em vez de tudo aparecer de uma vez. */
@media (prefers-reduced-motion: no-preference) {
    .conq_revelado { animation: conq_entra 420ms var(--curva-suave) both; }
    .conq_revelado:nth-child(2) { animation-delay: 70ms; }
    .conq_revelado:nth-child(3) { animation-delay: 140ms; }
}

@keyframes conq_entra {
    from { opacity: 0; transform: translateY(14px); }
    to { opacity: 1; transform: none; }
}

/* Quem pediu menos movimento nao recebe giro nenhum — nem no hover, nem no
   carregando. O componente continua funcionando; so para de girar. */
@media (prefers-reduced-motion: reduce) {
    .conq_mais_glifo .icone,
    .conq_mais[aria-busy="true"] .conq_mais_glifo .icone {
        animation: none;
        transition: none;
        transform: none;
    }
}

/* PERDA ZERO — benchmark alcancado.
   O cartao perde o vermelho de alerta e ganha o tom de confirmacao. Manter o
   vermelho num zero diria "atencao" onde nao ha nada a corrigir; pintar de
   verde o cartao inteiro, por outro lado, quebraria o par visual com o de
   potencial. So o VALOR e a nota mudam de cor — a moldura continua a mesma. */
/* Perda ZERO nao e perda. O estado ja neutralizava o valor e o glifo e
   deixava o rotulo em vermelho — meio alarme, na mesma linha do glifo
   apagado. Aqui a especificidade precisa vencer `.pagina-app .caps`
   (0,2,0), por isso o seletor carrega a pagina. */
.grandeza_zerada .grandeza_valor { color: var(--texto-suave); }
.grandeza_zerada .icone_perda { color: var(--texto-suave); }
.pagina-home .grandeza_zerada .caps,
.pagina-app .grandeza_zerada .caps { color: var(--texto-suave); }

.grandeza_nota_boa {
    display: flex;
    align-items: start;
    gap: 7px;
    color: var(--sucesso);
    font-weight: 600;
}

.grandeza_nota_boa .icone { flex: none; margin-top: .15em; }

/* =============================================================================
   ONDA 14 — /app/configuracoes vira "Perfil"
   -----------------------------------------------------------------------------
   O bloco fica no FIM pelo motivo de sempre neste arquivo: vencer por ORDEM, sem
   `!important` e sem inflar seletor a esmo. Onde ele PRECISA inflar, precisa
   mesmo, e esta anotado — `.pagina-app .tile h2` e (0,2,1) e `.tile h3` e (0,1,1):
   um seletor de classe unica perde dos dois em silencio, e o sintoma seria um
   subtitulo de 23px onde deveria haver um rotulo de 17px.

   Nenhum valor cru: espacos, raios, tipos e cores saem dos tokens do topo.
   ============================================================================= */

/* --- cabeca do cartao: rotulo + titulo a esquerda, selo de estado a direita ---
   Grade de duas colunas, e nao flex com wrapper: `.caps` e `<h2>` sao irmaos
   diretos (o resto do /app usa esse par assim) e um wrapper so para alinhar o
   selo mudaria a marcacao de todos os cartoes. O selo ocupa a coluna 2 nas duas
   linhas — fica centrado vertically contra o par inteiro, nao contra o rotulo. */
.conta_cabeca {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    column-gap: var(--esp-4);
}
.conta_cabeca > .caps,
.conta_cabeca > h1,
.conta_cabeca > h2 { grid-column: 1; }
.pagina-app .conta_cabeca h2 { margin: 6px 0 0; }
/* O h1 SO acontece aqui na aula do curso (`course-modulo.php`), onde o cartao E
   o documento da pagina. --tipo-6 (o h1 de capa, 40px/peso 900) esmagaria um
   cartao de leitura; --tipo-4 era o h2 de antes e nao produzia degrau nenhum
   contra o corpo (22 contra 17px, razao 1,29). --tipo-5 e o degrau que ja
   existe na escala — nao entra tamanho novo na pagina, o de 22px e que sai. */
.pagina-app .conta_cabeca h1 { margin: 6px 0 0; font-size: var(--tipo-5); line-height: 1.2; }
.conta_cabeca > .conta_selo { grid-column: 2; grid-row: 1 / span 2; justify-self: end; }

/* --- os blocos dentro do cartao de perfil ------------------------------------
   O cartao 1 guarda DOIS estados no mesmo assunto: o que o portal ja sabe (nao
   se edita aqui) e o que voce muda. A separacao e um fio, nao uma caixa dentro
   da caixa: o `.tile_vidro` ja e uma superficie, e aninhar molduras deixa o
   vidro turvo. */
/* O primeiro bloco precisa RESPIRAR do titulo do cartao: sem isto o rotulo
   "O que o portal ja sabe" encosta no h2 e os dois viram um bloco de texto so.
   (0,2,0) para vencer a margem que `.pagina-app .tile h2` deixa. */
.conta_cartao .conta_cabeca + .conta_bloco,
.conta_cartao .emp_erros + .conta_bloco { margin-top: var(--esp-5); }

.conta_bloco + .conta_bloco {
    margin-top: var(--esp-6);
    padding-top: var(--esp-5);
    border-top: 1px solid var(--borda);
}

/* Linha longa demais e o defeito classico da nota fina: ela e pequena, entao
   cabe muito texto por linha e o olho perde o retorno. 76ch e o mesmo teto da
   nota do painel. Sem `margin-inline: auto` de proposito — este bloco e
   alinhado a esquerda dentro do cartao, nao centralizado. */
.conta_cartao .nota_fina { max-width: 76ch; }
.conta_bloco_cabeca {
    display: flex; align-items: center; justify-content: space-between;
    flex-wrap: wrap; gap: var(--esp-3);
    margin: 0 0 var(--esp-4);
}
/* (0,2,0) de proposito: `.tile h3` e (0,1,1) e imporia 1.4375rem/800 aqui. */
.conta_cartao .conta_bloco_titulo {
    margin: 0; font-size: var(--tipo-3); font-weight: 700;
    letter-spacing: -.01em; line-height: 1.3; color: var(--texto);
}

/* Valores do bloco de leitura em monoespacada e um grau maior: sao DADOS
   (endereco de login, razao social), nao prosa — a monoespacada e o que faz
   `rn`, `m`, `l` e `1` se distinguirem quando alguem confere o proprio e-mail. */
.conta_leitura dd { font-size: var(--tipo-3); line-height: 1.5; word-break: break-word; }

/* O selo do bloco EDITAVEL e o negativo do de leitura: preenchido em vez de
   contornado. Os dois carregam a informacao no TEXTO (WCAG 1.4.1) — a diferenca
   de superficie e reforco, e nenhum dos dois usa matiz semantico, porque
   "editavel" nao e sucesso nem alerta. */
.conta_selo_livre {
    background: color-mix(in srgb, var(--texto) 8%, transparent);
    border-color: transparent;
    color: var(--texto);
}

.conta_cartao .conta_intro { max-width: 68ch; margin-top: var(--esp-4); }

/* O resumo do 422 recebe `autofocus` (ver settings.php). O header do portal e
   fixo: sem margem de rolagem o navegador para com a caixa DEBAIXO dele. Mesmo
   valor ja usado por `.campo` e `.btn`. */
.conta_cartao .emp_erros { scroll-margin-top: 96px; }

/* --- o aviso que precede a acao ---------------------------------------------
   Nao e alerta de erro (nada falhou), entao nao tem `role` nem cor de estado:
   e prosa emoldurada, posta no caminho do olho entre o ultimo campo e o botao.
   Alinhamento a esquerda e deliberado — o texto e uma frase, e centralizar
   paragrafo faz o olho procurar o inicio de cada linha. */
.conta_cartao .conta_aviso {
    display: flex; align-items: start; gap: var(--esp-2);
    margin: var(--esp-5) 0 0; padding: 12px 14px;
    border: 1px dashed var(--contorno); border-radius: var(--raio-p);
    font-size: var(--tipo-2); line-height: 1.6; color: var(--texto-suave);
    max-width: 72ch;
}
.conta_cartao .conta_aviso .icone { flex: none; margin-top: .2em; color: var(--texto-suave); }
.conta_cartao .conta_aviso strong { color: var(--texto); }

/* --- botao largo -------------------------------------------------------------
   "Largo", nao "da largura do cartao": a 816px o mesmo pill viraria uma faixa
   vermelha de ponta a ponta, e o alvo de clique util continuaria sendo o texto
   no meio. Piso de 280px no desktop; abaixo de 560px, onde a coluna e estreita
   e o polegar chega de qualquer lado, ele ocupa a linha inteira. */
/* MEDIDO: `min-width` sozinho vaza. Abaixo de 560px a coluna do cartao tem
   ~232px (320 - margem do wrap - 2x30 de padding do tile), e um piso de 280px
   no botao empurra o CONTEUDO INTEIRO do formulario para 280 — nao so o botao:
   ele e o item mais largo do flex, e o resto estica junto. O sintoma foi
   scrollX=4 real a 320px (rolagem lateral ALCANCAVEL, nao o artefato de
   emulacao documentado no CLAUDE.md, que da scrollX=0). Por isso o piso vive
   dentro do `min-width: 560px` e nao existe abaixo dele. */
@media (min-width: 560px) {
    .btn_largo { min-width: 280px; }
}
@media (max-width: 559px) {
    .btn_largo { width: 100%; }
    /* O selo desce para a propria linha antes de espremer o titulo. */
    .conta_cabeca { grid-template-columns: minmax(0, 1fr); }
    .conta_cabeca > .conta_selo { grid-column: 1; grid-row: auto; justify-self: start; margin-top: var(--esp-3); }
}

/* --- revelar senha: o glifo tambem muda -------------------------------------
   O app.js ja mantinha `aria-pressed` (o estado para quem usa leitor de tela) e
   trocava so a cor/classe para quem enxerga. Os DOIS glifos saem no HTML e o CSS
   escolhe qual aparece pelo mesmo atributo — nenhuma funcao de JS mudou, e o
   estado passa a ter FORMA: olho aberto = escondida, olho cortado = a mostra.
   Sem JS o botao continua `hidden` e nada disto existe. */
.revelar .revelar_ocultar { display: none; }
.revelar[aria-pressed="true"] .revelar_ver { display: none; }
.revelar[aria-pressed="true"] .revelar_ocultar { display: block; }

/* --- Confirmação de exclusão -----------------------------------------------
   <dialog> nativo: foco preso, Esc, resto da página inerte e ::backdrop vêm de
   graça do showModal(). O que fica aqui é só a aparência. */
.confirmar {
    border: 1px solid var(--borda); border-radius: var(--raio-app);
    background: var(--superficie); color: var(--texto);
    padding: clamp(22px, 4vw, 30px); max-width: min(440px, calc(100vw - 32px));
    box-shadow: var(--elev-2, 0 24px 60px rgba(0,0,0,.35));
}
.confirmar::backdrop { background: rgba(6, 5, 8, .62); }
.confirmar h2 { margin: 0 0 10px; font-size: var(--tipo-4); font-weight: 800; letter-spacing: -.02em; }
.confirmar p { margin: 0 0 22px; color: var(--texto-suave); font-size: var(--tipo-2); line-height: 1.6; }

/* O botão perigoso à DIREITA e separado: cancelar é o gesto comum, apagar é o
   raro, e vizinhos demais eles se clicam por engano. */
.confirmar_acoes { display: flex; justify-content: flex-end; gap: 10px; flex-wrap: wrap; }
.btn_perigo { background: var(--erro); border-color: var(--erro); color: #fff; }
.btn_perigo:hover { filter: brightness(1.08); }

/* Sem JavaScript a caixa aparece; com script o modal assume e ela some de vista
   — continua no formulário, que é o que o servidor lê. */
.confirmar_campo { display: inline-flex; align-items: center; gap: 7px; font-size: var(--tipo-1); color: var(--texto-suave); }
.confirmar-oculto { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* A linha que nomeia o ponto de partida na calculadora.
   Tom de FATO, não de troféu: verde de concluído (a mesma cor que marca
   conquista no painel), tipo pequeno, sem caixa nem confete. O que se celebra
   aqui é ter números apurados — não um acesso, que nunca esteve trancado. */
.calc_base {
    display: flex; align-items: start; gap: 9px;
    margin: 18px 0 0; max-width: 62ch;
    font-size: var(--tipo-2); line-height: 1.55; color: var(--texto-suave);
}
.calc_base .icone { flex: none; margin-top: 3px; color: var(--sucesso); }
.calc_base strong { color: var(--texto); font-weight: 600; }

/* --- calculadora (RF10) — /app/calculadora ----------------------------------
   O QUE ESTAVA AQUI ATE 20/08/2026: nada. Onze classes `.calc_*`, mais
   `.campo_erro` e `.campo_msg`, escritas no template e sem uma linha de regra.
   O efeito na tela media com CDP: dez caixas de texto de 1.012px de largura,
   uma embaixo da outra, para digitar numeros de dois a seis algarismos; a
   mensagem de recusa saindo preta no tamanho do corpo; e as duas perguntas do
   topo em roxo sublinhado, porque `<a>` dentro de `<ul>` nao era alcancado por
   regra nenhuma do tema e caia no padrao do navegador.

   A tela e um FORMULARIO, e a disciplina daqui e a de formulario: o campo tem
   largura de leitura, a unidade mora dentro da caixa, o erro se distingue por
   forma alem de cor, e o par pergunta-resposta fica visivelmente junto.

   Reuso, e nao vocabulario novo: `.unidade`/`.unidade_marca` vem do formulario
   da empresa (mesmos numeros, mesma duvida de formato), `.field-error` vem do
   resto do portal, `.tile_vidro` + `.conta_cabeca` vem de /app/configuracoes.
   As classes abaixo so arranjam o que ja existe. */

/* A bifurcacao do topo: duas contas, dois cartoes de mesmo peso. Eram dois
   itens de lista; lista e enumeracao, e o que ha aqui e uma escolha. */
.calc_escolha { display: grid; gap: var(--esp-4); margin-top: var(--esp-6); }
@media (min-width: 820px) { .calc_escolha { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.calc_atalho {
    display: grid; align-content: start; gap: var(--esp-2);
    padding: clamp(18px, 3vw, 24px);
    border: 1px solid var(--borda); border-radius: var(--raio-app);
    background: var(--painel-solido); color: var(--texto); text-decoration: none;
}
.calc_atalho_selo { display: inline-flex; align-items: center; gap: var(--esp-2); min-width: 0; }
.calc_atalho_selo .icone { flex: none; color: var(--fss-texto); }
.calc_atalho_selo .caps { line-height: 1.3; }
.calc_atalho strong {
    font-size: var(--tipo-3); font-weight: 700; line-height: 1.3; letter-spacing: -.01em;
    text-wrap: balance;
}
/* A seta diz para onde o clique leva: e ancora na propria pagina, entao aponta
   para BAIXO. Decorativa — o destino ja esta no href e no texto. */
.calc_atalho strong::after { content: " \2193"; color: var(--fss-texto); }
.calc_atalho_txt { font-size: var(--tipo-2); line-height: 1.55; color: var(--texto-suave); }
.calc_atalho:hover { border-color: var(--borda-marca); background: var(--preenchimento); }
.calc_atalho:focus-visible { outline: 3px solid var(--fss-acao); outline-offset: 3px; }

/* Cada modelo num cartao, com a mesma gramatica de /app/configuracoes. Sem o
   cartao os dois formularios eram uma coluna continua de 2.100px em que nada
   dizia onde um acabava e o outro comecava. */
.calc_cartao { margin-top: var(--secao); padding: clamp(22px, 4vw, 34px); }
/* O cartao NAO flutua no hover: `.tile_vidro:hover` levanta 5px, o que faz
   sentido num tile que se clica e nao num container de formulario — o campo
   sob o cursor sairia do lugar enquanto a pessoa mira. */
.calc_cartao:hover { transform: none; border-color: var(--borda); }
/* ARMADILHA DE ESPECIFICIDADE, e ela morde tres regras deste bloco: `.tile p`
   e (0,1,1) e vale para TODO paragrafo dentro de um tile — impoe margin 0,
   .9375rem e --texto-suave. Como os dois modelos agora vivem dentro de um
   cartao, `.calc_intro`, `.calc_premissas` e `.field-error`, todas (0,1,0),
   perdiam. O estrago visivel: a frase das premissas colada no bloco de cima
   (margin zerada) e, pior, a mensagem de recusa saindo CINZA no tamanho do
   corpo, com a mesma cara da legenda de referencia logo acima dela. O prefixo
   `.pagina-app` leva as tres a (0,2,0) e devolve o que estava escrito. */
.pagina-app .calc_intro { margin: var(--esp-5) 0 0; max-width: 68ch; font-size: var(--tipo-2); line-height: 1.65; color: var(--texto-suave); }
.pagina-app .calc_intro strong { color: var(--texto); font-weight: 700; }
/* Cor + peso + prefixo "Erro:" — os tres, porque cor sozinha nao carrega
   significado (WCAG 1.4.1) e porque aqui ela nem sequer estava chegando. */
.pagina-app .field-error { font-size: var(--tipo-1); font-weight: 600; color: var(--erro); }

/* Grade, e nao bloco: os tres filhos do formulario (campos, acoes, salvar) tem
   margem propria, e em fluxo normal a margem de baixo de um colapsaria com a de
   cima do seguinte — o espaco entre eles passaria a ser o MAIOR dos dois em vez
   da soma, que nao e o que as regras abaixo dizem. */
/* O AVISO DE QUE OS NUMEROS SAO DO LEAD.

   Fica ANTES dos campos, e nao junto do botao, porque a duvida que ele desfaz
   nasce ao olhar o formulario — nao ao apertar. Chegando depois, ele so
   explicaria os cinco erros que a pessoa ja levou.

   Sobrio de proposito: e orientacao, nao alarme. Nada esta errado quando a tela
   abre; ha trabalho a fazer, e isso se diz baixo. */
.calc_secao_aviso {
    display: flex; align-items: flex-start; gap: 9px;
    margin: 0 0 var(--esp-4); padding: var(--esp-3) var(--esp-4);
    border-radius: var(--raio-p);
    border: 1px solid var(--borda);
    background: var(--superficie);
    font-size: var(--tipo-2); line-height: 1.55; color: var(--texto);
}
.calc_secao_aviso .icone { width: 16px; height: 16px; flex: none; margin-top: 2px; color: var(--texto-fraco); }

.calc_form { display: grid; }

/* Quatro campos em duas colunas; os seis do funil em tres quando a pagina
   permite. Coluna unica so quando ela e mesmo a unica opcao. */
.calc_campos { display: grid; gap: clamp(16px, 2.4vw, 22px); margin-top: var(--esp-5); }
@media (min-width: 640px) { .calc_campos { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1040px) { .calc_campos_seis { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* (0,2,0) para zerar o `margin-bottom` que `.campo` traz: quem espaca aqui e o
   `gap` da grade, e os dois somados abriam um buraco por linha. */
.pagina-app .calc_campo { margin-bottom: 0; align-content: start; }
.pagina-app .calc_campo label { font-size: var(--tipo-2); font-weight: 600; }
.pagina-app .calc_campo .dica { margin: var(--esp-2) 0 0; font-size: var(--tipo-1); line-height: 1.5; color: var(--texto-fraco); }
/* Caixa nua e caixa com unidade precisam ter a MESMA altura, senao a linha de
   campos fica serrilhada. 48px e a altura de `.unidade`. */
.calc_campo > input { min-height: 48px; }
.calc_campo .unidade input { font-variant-numeric: tabular-nums; }
/* Ancora do 422: quem volta com erro cai no campo, e nao no topo da pagina. */
.campo_erro { scroll-margin-top: 96px; }

/* Simular e o gesto principal; a frase ao lado responde a duvida que nasce
   junto com ele ("isso grava alguma coisa?"). O fio acima separa o que se
   preenche do que se aciona. */
.calc_acoes {
    display: flex; flex-wrap: wrap; align-items: center; gap: var(--esp-4);
    margin-top: var(--esp-6); padding-top: var(--esp-5);
    border-top: 1px solid var(--borda);
}
.calc_acoes .miudo { max-width: 36ch; }

/* Nomear e salvar so existem depois de haver resultado. O bloco se destaca do
   fundo do cartao para nao parecer mais um campo do formulario. */
.calc_salvar {
    display: grid; gap: var(--esp-4); align-items: end;
    margin-top: var(--esp-5); padding: var(--esp-5);
    border: 1px solid var(--borda); border-radius: var(--raio-app);
    background: var(--preenchimento);
}
@media (min-width: 700px) { .calc_salvar { grid-template-columns: minmax(0, 1fr) auto; } }
.pagina-app .calc_salvar .campo { margin-bottom: 0; }

/* A resposta e do modelo logo acima: o rotulo diz isso e o espaco encurta, para
   que pergunta e resposta nao pareçam duas secoes independentes. */
.calc_resposta { margin-top: var(--esp-6); }
/* "O que esses numeros produzem" nao e titulo de pagina. `.pagina-app
   .secao_head h2` vai a 46px, a mesma escala do h1 da capa — dois titulos desse
   porte na mesma tela disputam quem manda. (0,3,1) para vencer aquele (0,2,1). */
.pagina-app .calc_resposta .secao_head h2 { font-size: var(--tipo-5); max-width: 30ch; }

/* CARTAO DE CENARIO EM SUPERFICIE NEUTRA, e nao na lavagem vermelha.
   Dentro dele mora o par da RF06: perda atual em --erro, potencial futuro em
   --sucesso. Um fundo tingido de vermelho por baixo dos dois pinta o bloco
   inteiro com o significado de UM dos lados — e a gramatica de cor do portal
   reserva o vermelho para problema. Aqui o problema e a coluna da esquerda, e
   nao os tres cenarios. */
/* Os sete quadros do funil (faturamento, CAC, ROAS, time) seguem a mesma
   regra e pelo mesmo motivo: sao FATOS DE OPERACAO. "Faturamento R$ 106.773,33"
   sobre lavagem vermelha e a tela dizendo, com a cor, que aquele numero e um
   problema. */
.calc_cenario, .calc_bloco { background: var(--painel-solido); border: 1px solid var(--borda); }
.calc_cenario + .calc_cenario { margin-top: var(--esp-4); }
/* Mesma razao e mesmo teto da nota do cartao de conta: a nota e pequena, entao
   cabe texto demais por linha e o olho perde o retorno. */
.calc_resposta .nota_fina { max-width: 76ch; }
.pagina-app .calc_premissas {
    margin: var(--esp-5) 0 0; max-width: 76ch;
    font-size: var(--tipo-2); line-height: 1.65; color: var(--texto-suave);
}
.pagina-app .calc_premissas strong { color: var(--texto); font-weight: 700; }
.calc_premissas code { font-family: var(--mono); font-size: var(--tipo-1); }
.calc_cenario_nome { white-space: nowrap; }

/* Cenarios salvos: um cartao por simulacao, com o tipo de conta em cima (a
   mesma lista guarda os dois modelos) e a acao de apagar longe do texto. */
.calc_salvos { list-style: none; display: grid; gap: var(--esp-3); margin: var(--esp-5) 0 0; padding: 0; }
.calc_salvo {
    display: grid; gap: var(--esp-4); align-items: start;
    padding: clamp(16px, 2.6vw, 22px);
    border: 1px solid var(--borda); border-radius: var(--raio-app);
    background: var(--painel-solido);
}
@media (min-width: 760px) { .calc_salvo { grid-template-columns: minmax(0, 1fr) auto; } }
.calc_salvo_txt { display: grid; gap: 6px; min-width: 0; }
.calc_salvo_tipo { display: inline-flex; align-items: center; gap: 7px; }
.calc_salvo_tipo .icone { flex: none; color: var(--fss-texto); }
.calc_salvo_nome { font-size: var(--tipo-3); font-weight: 700; letter-spacing: -.01em; }
.calc_salvo_linha, .calc_salvo_saida { font-size: var(--tipo-1); line-height: 1.6; color: var(--texto-suave); font-variant-numeric: tabular-nums; }
.calc_salvo_saida strong { color: var(--texto); font-weight: 700; }
.calc_salvo_acao { display: flex; flex-wrap: wrap; align-items: center; gap: var(--esp-3); }

/* Botao de acao secundaria dentro de item de lista: menor que o botao de
   formulario, e ainda com 40px de alvo (o piso de 44px vale para o alvo
   isolado; aqui o item inteiro tem 22px de folga em volta). */
.btn_mini { padding: 9px 14px; font-size: var(--tipo-1); min-height: 40px; }

/* --- a regua da calculadora -------------------------------------------------
   Barra deslizante + pontas nomeadas + degraus da leitura qualitativa. A
   referencia visual e a calculadora publica da FSS; a lição que ela ensina e
   que UM NUMERO SOZINHO NAO ENSINA NADA — a barra da a ordem de grandeza, as
   pontas dao o intervalo, os degraus dao o julgamento.

   TRES SISTEMAS DE COR, e cada um diz uma coisa so:

     o trecho percorrido   -> --fss-acao   (onde o valor esta: e a marca agindo)
     a zona de referencia  -> neutro       (o que e comum: fato, nao veredito)
     os degraus            -> --erro / --alerta / --sucesso (o veredito da FSS)

   A zona e NEUTRA de proposito. Pintar de verde "5% a 20% de agendamento"
   diria que a faixa inteira e boa, quando a propria FSS diz que 5% e ruim — os
   degraus e que graduam, e sao eles que carregam cor de estado. E o ponto
   colorido nunca vem sozinho: cada degrau traz o texto da FSS ao lado, porque
   cor nao pode ser o unico portador de significado (WCAG 1.4.1). */
.calc_regua { margin-top: var(--esp-3); }
.calc_regua[hidden] { display: none; }

.calc_regua_barra {
    --trilho: var(--preenchimento);
    --zona: color-mix(in srgb, var(--texto-suave) 34%, transparent);
    -webkit-appearance: none; appearance: none;
    display: block; width: 100%; height: 20px;
    background: none; border: 0; cursor: pointer;
}

/* Os pseudo-elementos de trilho e de polegar NAO PODEM SER AGRUPADOS: seletor
   com um vendor prefix desconhecido invalida a regra INTEIRA, e o Firefox
   perderia o desenho do WebKit junto. Por isso os quatro blocos repetidos. */
.calc_regua_barra::-webkit-slider-runnable-track {
    height: 5px; border-radius: 999px;
    background:
        linear-gradient(90deg, var(--fss-acao) var(--valor, 0%), transparent 0),
        linear-gradient(90deg,
            transparent var(--zona-de, 0%), var(--zona) 0,
            var(--zona) var(--zona-ate, 0%), transparent 0),
        var(--trilho);
}
.calc_regua_barra::-moz-range-track {
    height: 5px; border-radius: 999px;
    background:
        linear-gradient(90deg, var(--fss-acao) var(--valor, 0%), transparent 0),
        linear-gradient(90deg,
            transparent var(--zona-de, 0%), var(--zona) 0,
            var(--zona) var(--zona-ate, 0%), transparent 0),
        var(--trilho);
}
.calc_regua_barra::-webkit-slider-thumb {
    -webkit-appearance: none; appearance: none;
    width: 18px; height: 18px; margin-top: -7px;
    border-radius: 50%; background: var(--superficie);
    border: 2px solid var(--fss-acao); box-shadow: var(--elev-1);
}
.calc_regua_barra::-moz-range-thumb {
    width: 18px; height: 18px; box-sizing: border-box;
    border-radius: 50%; background: var(--superficie);
    border: 2px solid var(--fss-acao); box-shadow: var(--elev-1);
}
.calc_regua_barra:focus-visible { outline: 3px solid var(--fss-acao); outline-offset: 4px; border-radius: 999px; }

/* (0,2,0): `.tile p` e (0,1,1) e os dois paragrafos abaixo vivem dentro do
   cartao do modelo — sem o prefixo herdariam 15px e margem zero. */
.pagina-app .calc_regua_pontas {
    display: flex; justify-content: space-between; gap: var(--esp-3);
    margin: 2px 0 0; font-size: var(--tipo-1); color: var(--texto-fraco);
    font-variant-numeric: tabular-nums;
}
.pagina-app .calc_regua_fora {
    margin: var(--esp-2) 0 0; font-size: var(--tipo-1); font-weight: 600; color: var(--alerta);
}
.calc_regua_fora[hidden] { display: none; }

.calc_degraus {
    list-style: none; display: flex; flex-wrap: wrap; gap: 4px var(--esp-3);
    margin: var(--esp-2) 0 0; padding: 0;
    font-size: var(--tipo-1); line-height: 1.5; color: var(--texto-fraco);
}
.calc_degrau { display: inline-flex; align-items: center; gap: 6px; }
.calc_degrau_ponto { width: 8px; height: 8px; flex: none; border-radius: 50%; background: var(--texto-fraco); }
.calc_degrau_ruim .calc_degrau_ponto { background: var(--erro); }
.calc_degrau_regular .calc_degrau_ponto { background: var(--alerta); }
.calc_degrau_bom .calc_degrau_ponto { background: var(--sucesso); }
/* O degrau em que o numero caiu ganha PESO alem do anel — de novo, nunca so a
   cor. Acima do ultimo degrau nenhum acende: a FSS graduou ate ali. */
.calc_degrau_ativo { color: var(--texto); font-weight: 700; }
.calc_degrau_ativo .calc_degrau_ponto { box-shadow: 0 0 0 3px color-mix(in srgb, var(--texto-suave) 26%, transparent); }

/* Caixa com prefixo (R$) E passo -/+ : tres colunas com o campo no MEIO. A
   regra generica de .unidade_ajuste assume o campo na primeira coluna, que e o
   caso do sufixo (% e dias). */
.unidade_ajuste:not(.unidade_fim) { grid-template-columns: auto minmax(0, 1fr) auto; }
/* O -/+ dentro da grade de tres colunas da calculadora divide espaco com o
   rotulo da unidade; 44px cada deixaria a caixa de digitar menor que o proprio
   controle de ajuste. 40 mantem o alvo confortavel (o minimo de 24px da WCAG
   2.5.8 com folga) e devolve 8px por campo para o numero. */
.calc_campo .ajuste_btn { width: 40px; }

/* Visualmente escondida, audivel do mesmo jeito. Mesma tecnica de
   .confirmar-oculto: `display: none` e `hidden` tirariam o texto da arvore de
   acessibilidade junto, e este paragrafo e o `aria-describedby` do campo. */
.calc_dica_coberta {
    position: absolute; width: 1px; height: 1px;
    margin: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* --- o portal, hoje e depois (grade de dois estados) ------------------------
   A secao virou UMA grade com DOIS estados, na gramatica da cartela de selos
   que serviu de referencia: o que ja e seu em cor e clicavel, o que vem depois
   em cinza e inerte. Antes eram so os cinza — a secao inteira era a ausencia, e
   era a ultima coisa do painel.

   O ESTADO VAI EM TRES PORTADORES AO MESMO TEMPO, e nao so na cor (WCAG 1.4.1):
   a tinta do selo, a frase do estado ("Você simulou pela primeira vez em ..." /
   "Em breve") e o fato de o cartao ser ou nao um link.

   VERDE AQUI E EXTENSAO DA GRAMATICA, e nao excecao a ela. O portal usa verde
   para concluido, neutro para pendente/futuro e vermelho para problema. "Esta de
   pe e e seu" cai do lado do concluido — e a frase que acompanha o selo e, na
   maioria das vezes, literalmente um fato com data, no mesmo tom de .conq_data.
   O que continua proibido e o contrario: nada aqui diz "desbloqueado", porque
   nada aqui esteve trancado (RF11/RF17, e a nota ao pe da secao). */

/* O alvo e o cartao INTEIRO quando ha para onde ir (WCAG 2.5.8), entao o padding
   e o flex mudaram do <li> para dentro dele. Sem destino o mesmo no e um <span>
   e nao vira link morto. `link_bloco` tira o sublinhado de link-em-texto: ver a
   nota em `.pagina-app main a:not(...)`. */
/* Tres colunas, e nao quatro: os cinco cartoes vivem em dois grupos de dois e
   de tres, e uma grade de quatro deixaria o segundo grupo com um orfao na
   segunda fileira. 300px de piso e o que produz tres no `.wrap` de 1080. */
.pnl_ferramentas { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }
/* O rotulo do grupo e um marcador de secao, e nao um titulo de conteudo: vem
   em versal miuda, com a contagem ao lado, para separar sem competir com os
   nomes das ferramentas logo abaixo. */
.pagina-app .pnl_ferr_grupo {
    display: flex; align-items: center; gap: var(--esp-2);
    margin: var(--esp-6) 0 0;
    font-size: var(--tipo-1); font-weight: 800; letter-spacing: .16em; text-transform: uppercase;
    color: var(--texto-suave);
}
.pagina-app .pnl_ferr_grupo span {
    display: inline-grid; place-items: center; min-width: 20px; height: 20px; padding: 0 6px;
    border-radius: var(--pilula); background: var(--preenchimento);
    font-size: var(--tipo-1); letter-spacing: 0; color: var(--texto-suave);
}
.pnl_ferramentas { margin-top: var(--esp-3); }
.pnl_ferr { padding: 0; overflow: hidden; }
.pnl_ferr_alvo {
    display: flex; align-items: start; gap: 13px;
    height: 100%; padding: 16px;
    color: inherit; text-decoration: none;
}
.pnl_ferr_viva { border-color: var(--borda-feito); }
.pnl_ferr_viva .pnl_ferr_glifo {
    background: color-mix(in srgb, var(--sucesso) 14%, transparent);
    border-color: color-mix(in srgb, var(--sucesso) 30%, transparent);
    color: var(--sucesso);
}
/* Mesma linha de estado de .conq_data — e a mesma coisa que ela diz. */
.pnl_ferr_estado {
    display: flex; align-items: start; gap: 6px;
    margin-top: 6px; font-size: var(--tipo-1); font-weight: 600; color: var(--sucesso);
}
.pnl_ferr_estado .icone { flex: none; margin-top: .1em; }
.pnl_ferr_viva:hover { border-color: var(--sucesso); }
.pnl_ferr_alvo:focus-visible { outline: 3px solid var(--fss-acao); outline-offset: -3px; border-radius: var(--raio-app); }

/* --- o fecho do painel ------------------------------------------------------
   O painel terminava na nota do desmentido do cadeado: quem rolava ate o fim
   saia sem nenhuma acao a um clique, e para quem qualificou o botao de agendar
   ficava mil pixels acima, no meio da grade.

   O conteudo do bloco e uma ESCADA no template (agendar / simular / terminar o
   diagnostico), porque `/app/agendar` responde 404 para quem nao qualificou e
   um botao unico ou levaria a um 404 ou vazaria o perimetro. O desenho e o
   mesmo nos tres degraus: o que muda e o passo, nao o peso. */
/* A LAVAGEM ROSA FUNDIU NO VIDRO (direcao B, 20/08/2026).

   Ate aqui este bloco era `background: var(--lavagem)` + `border-marca`: a
   SEGUNDA pintura de cartao da mesma tela, para dizer a mesma coisa que
   `.tile_wash` ja dizia tres secoes acima — "este bloco importa". Duas tintas
   para uma ideia so e o que a direcao chamou de volume alto.

   Agora e a MESMA superficie de vidro de todo cartao do /app, com uma barra de
   acento na borda de inicio carregando a funcao. A enfase deixou de estar no
   fundo inteiro e passou a estar em 4px — que e onde o olho a encontra sem ter
   de atravessar o texto.

   ELE TAMBEM ERA O DEFEITO DE CONTRASTE. Medido em 20/08/2026, no pixel
   renderizado: `--texto-suave` sobre a lavagem clara (#E2D3D9) dava 4,34:1,
   reprovando os 4,5:1 de texto normal — e no escuro `.caps` sobre a lavagem
   escura (#312027) dava 4,20:1. Os dois estavam em producao. O vidro sobe os
   dois fundos para perto da superficie do cartao e a reprovacao sai pela raiz,
   sem mexer em nenhum token de texto: 4,34 -> 5,20:1 no claro; 4,20 -> 5,18:1
   no escuro. Escolher OUTRO cinza teria consertado o numero e mantido a segunda
   pintura — o conserto que a direcao pedia era o mesmo. */
.pnl_fecho {
    display: grid; gap: var(--esp-5); align-items: center;
    margin-top: var(--esp-6); padding: clamp(22px, 4vw, 32px);
    border-radius: var(--raio-app);
    background: var(--painel);
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
    border: 1px solid var(--borda);
    border-inline-start: var(--acento-largura) solid var(--fss-acao);
}
@media (min-width: 860px) { .pnl_fecho { grid-template-columns: minmax(0, 1fr) auto; } }
.pnl_fecho_txt { min-width: 0; }
.pagina-app .pnl_fecho_txt h3 {
    margin: 8px 0 0; font-size: var(--tipo-4); font-weight: 800; letter-spacing: -.02em;
    line-height: 1.2; text-wrap: balance;
}
.pagina-app .pnl_fecho_txt p {
    margin: var(--esp-3) 0 0; max-width: 60ch;
    font-size: var(--tipo-2); line-height: 1.65; color: var(--texto-suave);
}
/* (0,2,0) para vencer o `margin: 34px 0 0` de `.pagina-app .acoes`: aqui o
   espaco entre o texto e os botoes e o `gap` da grade. */
.pagina-app .pnl_fecho .acoes { margin: 0; }

/* --- o curso (RF11) — /app/curso --------------------------------------------
   Uma lista de aulas, e nao um bento: a ordem importa, e a leitura e vertical.
   O numero a esquerda e a sequencia SUGERIDA — nao ha trava, nao ha cadeado e
   nao ha "desbloqueie" (RF11/RF17: o curso nao depende de resultado).

   O estado vai em tres portadores, como no resto do portal: a tinta do selo, a
   frase ("Concluída em ...", "Começada") e a borda do item. Cor sozinha nao
   carrega significado (WCAG 1.4.1).

   O QUE A ONDA 34 MEDIU AQUI, e o que cada numero virou:

     raio 18px          esta era a UNICA tela do /app fora do raio unico da
                        direcao B. Ela lia --raio-m, que e token da HOME (a
                        direcao D). A onda 32 baixou os raios por tela de 5
                        para 2; o curso, escrito depois, devolveu um terceiro.
                        Agora le --raio-app, como todo o resto do /app.
     0 botoes na 1a tela quem voltava dias depois via cinco cartoes iguais e
                        tinha de varrer a lista para descobrir onde parou. A
                        RETOMADA passou a ser um degrau primario, e ela usa a
                        MESMA receita que a direcao B ja deu a `.pnl_fecho`:
                        vidro + barra de acento. Nao ha linguagem nova aqui.
     altura identica    0/5, 1/5 e 5/5 renderizavam a MESMA pagina de 1416px.
                        O progresso era uma frase de 13px. Virou trilho, com o
                        numero seguindo como portador (o trilho e aria-hidden,
                        igual ao de `.pilar_trilho`).
     duracao some       a lista mostrava "Texto · 16 min" so em aula intocada:
                        4/5 no primeiro acesso, 2/5 em curso, 0/5 no fim. O
                        formato virou linha PROPRIA, que nao e substituida pelo
                        estado — e justamente quem ja voltou que precisa saber
                        se tem 16 minutos agora.
     .curso_n 4,35:1    --texto-suave sobre --preenchimento compunha #D4D7DD no
                        tema claro e reprovava AA em 14px negrito. O numero e
                        FATO, e fato neste portal se pinta com --texto — a mesma
                        escolha ja feita em `.pilar_conta`. 12,91:1. */

/* A RETOMADA — o unico degrau primario da tela.
   Receita identica a de `.pnl_fecho` (vidro + barra de acento na borda de
   inicio). Repetir a receita e o ponto: a direcao B decidiu que enfase no /app
   mora em 4px de acento sobre a mesma superficie, e nao numa segunda pintura de
   cartao. Uma terceira variante aqui reabriria o que a onda 32 fechou. */
.curso_retoma {
    display: grid; gap: var(--esp-5); align-items: center;
    margin-top: var(--esp-6); padding: clamp(20px, 3.4vw, 28px);
    border-radius: var(--raio-app);
    background: var(--painel);
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
    border: 1px solid var(--borda);
    border-inline-start: var(--acento-largura) solid var(--fss-acao);
}
@media (min-width: 780px) { .curso_retoma { grid-template-columns: minmax(0, 1fr) auto; } }
/* COM O CURSO FECHADO O ACENTO E VERDE, e nao vermelho. Mesma regra ja escrita
   em `--borda-feito`: neste produto o vermelho significa PROBLEMA (e ele que
   pinta o gargalo e a perda atual), e "concluido" tem cor propria. Com o
   trilho cheio em --sucesso ao lado, uma barra vermelha aqui poria o fato bom
   em duas cores na mesma dobra. */
.curso_retoma_feito { border-inline-start-color: var(--sucesso); }
.curso_retoma_txt { min-width: 0; }
.pagina-app .curso_retoma_txt h2 {
    margin: 8px 0 0; font-size: var(--tipo-4); font-weight: 800; letter-spacing: -.02em;
    line-height: 1.25; text-wrap: balance;
}
.pagina-app .curso_retoma_txt p {
    margin: var(--esp-3) 0 0; max-width: 58ch;
    font-size: var(--tipo-2); line-height: 1.6; color: var(--texto-suave);
}
.curso_retoma .acoes { margin: 0; }

/* O TRILHO DE 4px SAIU DAS DUAS TELAS DO CURSO NA ONDA 45, e a mesma frase vale
   para a lista e para a barra lateral da aula: quem desenha o progresso agora e
   o FIO DA TRILHA — cinza no que falta, verde no que ja foi, vermelho na aula da
   vez. Ele diz a mesma fracao ao lado das aulas de que ela fala, em vez de um
   retangulo abstrato no topo da tela. A contagem em texto continua sendo o
   PORTADOR (WCAG 1.4.1); o fio e pseudo-elemento e leitor de tela nunca o
   alcanca. */
.curso_medida { display: grid; gap: var(--esp-2); margin: var(--esp-5) 0 0; max-width: 46ch; }
.curso_medida_linha {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px;
    font-size: var(--tipo-2); color: var(--texto-suave);
}
.curso_medida_conta {
    font-family: var(--mono); font-variant-numeric: tabular-nums;
    font-size: var(--tipo-2); font-weight: 700; color: var(--texto);
}

/* --- a barra lateral da aula ------------------------------------------------
   Anel, barra, trilha e a conclusao. Ela ocupa a coluna que apareceu quando a
   aula voltou a largura das outras telas do /app — antes disso eram 500px de
   superficie pintada sem dono. */
.curso_lateral {
    display: grid; gap: var(--esp-4);
    padding: var(--esp-5);
    border: 1px solid var(--borda); border-radius: var(--raio-app);
    background: var(--superficie);
}
/* (0,3,1) PORQUE A AULA MORA DENTRO DE UM `.tile`, e `.pagina-app .tile h2`
   (0,2,1) vencia em silencio o `.curso_lateral > .caps` (0,2,0): o rotulo da
   coluna saia em 22px/800 caixa alta — a maior peca de texto de uma barra cujo
   assunto e a lista abaixo dela. Medido em 25/08/2026 e visivel na captura de
   antes. Ele e RÓTULO DE SECAO, e rotulo de secao neste portal e 12/13px. */
.pagina-app .curso_lateral > h2.caps {
    margin: 0; font-size: var(--tipo-1); font-weight: 800; line-height: 1.3;
    color: var(--texto-fraco); letter-spacing: .16em;
}
/* Mesma disputa, mesma correcao: `.pagina-app .tile p` impunha --tipo-2 ao
   agregado e a contagem. */
.pagina-app .curso_lateral .curso_lateral_soma { font-size: var(--tipo-1); }
.pagina-app .curso_lateral .curso_conta { font-size: var(--tipo-2); }

/* A CONTAGEM, DEPOIS QUE O ANEL SAIU (onda 45). O anel de 68px e a barra de 4px
   desenhavam a MESMA fracao um em cima do outro, e o anel era a maior peca
   grafica de uma coluna cujo assunto e a lista de aulas embaixo dele — no
   primeiro acesso ele abria a barra lateral com um "0%" em corpo de titulo. A
   barra de 4px saiu junto, pela mesma razao. O fato ficou; as duas repeticoes
   dele sairam — sobrou a linha de texto, que e o PORTADOR (WCAG 1.4.1), e o FIO
   da trilha logo abaixo, que desenha a mesma fracao ao lado das aulas de que ela
   fala. */
.curso_conta {
    margin: 0; font-size: var(--tipo-2); color: var(--texto-suave); line-height: 1.5;
}
.curso_conta strong {
    font-family: var(--mono); font-variant-numeric: tabular-nums;
    font-weight: 700; color: var(--texto);
}
.curso_conta_fim { display: block; color: var(--sucesso); font-weight: 700; }

/* O TITULO DA AULA NA TRILHA NAO E LINK EM TEXTO CORRIDO.
   `.pagina-app main a:not(.btn):not(.btn_sec)` (0,3,2) sublinha todo link do
   corpo — regra certa para link dentro de frase, errada para o nome de um item
   de lista, que E a linha. Um seletor de classe simples perde para ela em
   silencio, e foi o que aconteceu na primeira tentativa: a trilha saiu com os
   cinco titulos sublinhados, um debaixo do outro. */
.pagina-app main a.curso_passo_nome:not(.btn):not(.btn_sec) { text-decoration: none; }
.pagina-app main a.curso_passo_nome:not(.btn):not(.btn_sec):hover { text-decoration: underline; }

/* A nota da conclusao fala do BOTAO, e por isso mora embaixo dele. */
/* O agregado do cabecalho: quantas aulas e quanto tempo. */
.curso_lateral_soma {
    display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
    margin: -6px 0 0; font-size: var(--tipo-1); color: var(--texto-fraco);
}
.curso_lateral_soma .icone { width: 14px; height: 14px; margin-right: 3px; }

/* A LINHA DO TEMPO — a lista lida como SEQUENCIA, e nao como cinco itens
   soltos. O fio nasce no centro do primeiro marcador e morre no do ultimo:
   `top`/`bottom` de meia altura de marcador (11px) mais o respiro do item.
   Puramente decorativo, entao `aria-hidden` nao se aplica: e um pseudo-elemento
   e leitor de tela nunca o encontra. */
.curso_lateral_lista { position: relative; }
.curso_lateral_lista::before {
    content: ""; position: absolute; left: 19px; top: 19px; bottom: 19px;
    width: 2px; border-radius: 2px; background: var(--borda);
}
/* O trecho ja andado e o ponto em que a pessoa esta, como em /app/curso: o fio
   colorido e o progresso desenhado ONDE ele acontece — foi ele que deixou o anel
   de 68px sem trabalho.

   AS DUAS PONTAS SAO APARADAS NO MESMO LUGAR QUE A TRILHA CINZA. O fio de fundo
   (`.curso_lateral_lista::before`) nasce e morre a 19px, que e o centro do
   primeiro e do ultimo marcador. Sem esta correcao o segmento colorido do
   PRIMEIRO item subia 19px acima do primeiro marcador e o do ULTIMO descia 19px
   abaixo do ultimo — dois cotocos pendurados fora da linha do tempo, e os dois
   aparecem nos casos mais comuns: abrir a primeira aula do curso, e concluir a
   ultima. */
.curso_passo { position: relative; }
.curso_passo_feito::before {
    content: ""; position: absolute; left: 19px; top: 0; bottom: 0;
    width: 2px; border-radius: 2px;
    background: color-mix(in srgb, var(--sucesso) 80%, transparent);
}
.curso_passo:first-child::before { top: 19px; }
.curso_passo:last-child::before { bottom: calc(100% - 19px); }
/* O marcador tapa o fio atras dele — sem isto a linha atravessa o numero. A
   aula ATUAL tem o halo dela mais abaixo, junto do anel da marca. */
.curso_passo_marca { position: relative; z-index: 1; box-shadow: 0 0 0 4px var(--superficie); }


/* Hairline entre as aulas, como na referencia: separa sem pesar. Nao vai na
   ultima nem depois da atual, que ja tem fundo proprio fechando o bloco. */
.curso_passo + .curso_passo { border-top: 1px solid var(--borda); }
.curso_passo_atual, .curso_passo_atual + .curso_passo { border-top-color: transparent; }

.curso_passo_meta .icone { width: 13px; height: 13px; }


/* A TRILHA. Cada linha e numero (ou visto), nome e duracao — a mesma leitura da
   lista de /app/curso, repetida aqui de proposito: quem esta na aula 3 nao
   deveria voltar duas telas para saber o que vem na 4. */
.curso_lateral_lista { list-style: none; display: grid; gap: 2px; margin: 0; padding: 0; }
.curso_passo {
    display: grid; grid-template-columns: 22px minmax(0, 1fr); gap: 2px 10px;
    align-items: center;
    padding: 8px; border-radius: var(--raio-p, 8px);
}
/* O NUMERO E `--texto`, e nao `--texto-fraco`. Medido no pixel renderizado em
   25/08/2026: na aula ATUAL o marcador empilhava `--preenchimento` sobre
   `--preenchimento` (o fundo do realce) e o terciario compunha 3,96:1 no tema
   escuro — reprovando AA em 11px negrito (piso 4,5). Estava em producao. O
   numero e FATO, e fato neste portal se pinta com `--texto`: a mesma escolha ja
   registrada em `.pilar_conta` e na trilha de /app/curso. */
.curso_passo_marca {
    grid-row: 1 / span 2; align-self: start;
    display: grid; place-items: center;
    width: 22px; height: 22px; border-radius: 50%;
    background: var(--preenchimento); color: var(--texto);
    font-size: 11px; font-weight: 800; font-variant-numeric: tabular-nums;
}
/* O fundo e OPACO, e nao transparente: com o fio verde do trecho ja andado
   passando por tras, um marcador transparente deixava a linha atravessar o
   visto. */
.curso_passo_feito .curso_passo_marca {
    background: color-mix(in srgb, var(--sucesso) 14%, var(--superficie));
    color: var(--sucesso);
}
.curso_passo_feito .curso_passo_marca .icone { width: 18px; height: 18px; }
.curso_passo_nome { font-size: var(--tipo-2); font-weight: 600; color: var(--texto); }
a.curso_passo_nome { text-decoration: none; }
a.curso_passo_nome:hover { color: var(--fss-texto, var(--fss)); text-decoration: underline; }
.curso_passo_meta {
    display: flex; align-items: center; gap: 6px;
    font-size: var(--tipo-1); color: var(--texto-fraco);
}
/* O selo repete em PALAVRA o que o visto ja diz em forma: a cor sozinha nao
   pode carregar o estado (WCAG 1.4.1), e o visto sozinho e forma sem nome. */
.curso_passo_selo { color: var(--sucesso); font-weight: 700; }
.curso_passo_feito .curso_passo_nome { color: var(--texto-suave); }
/* A ATUAL NAO E UM LINK e nao precisa parecer clicavel: ela precisa parecer
   ONDE VOCE ESTA.

   O FIO VERMELHO DE 2px NA BORDA SAIU NA ONDA 45. Ele era um fio ENCOSTADO na
   linha, na mesma tinta que o portal usa em gargalo e em perda atual, e o dono
   leu alerta — leu certo. A tinta continua sendo a da marca, mas agora ela mora
   no TRILHO e no anel do marcador, que e onde "voce esta aqui" acontece: a
   linha do tempo passa a ser vermelha exatamente no ponto em que a pessoa
   parou. Mesma decisao, e mesmos tokens, da trilha de /app/curso. */
.curso_lateral_lista {
    --curso-agora: #FF083D;
    /* OPACO de proposito: o halo do marcador precisa casar EXATAMENTE com o
       fundo da linha, e halo semitransparente sobre fundo semitransparente
       compoe um terceiro tom. */
    --curso-toque: color-mix(in srgb, var(--curso-agora) 4%,
        color-mix(in srgb, var(--texto) 6%, var(--superficie)));
}
.curso_passo_atual { background: var(--curso-toque); }
.curso_passo_atual .curso_passo_nome { color: var(--texto); }
/* O fio fica da cor da marca no ponto em que a pessoa parou — o mesmo desenho
   da trilha de /app/curso, e o que substituiu o fio encostado na borda. */
.curso_passo_atual::before {
    content: ""; position: absolute; left: 19px; top: 0; bottom: 0;
    width: 2px; border-radius: 2px; background: var(--curso-agora);
    box-shadow: 0 0 0 2px var(--superficie);
}
/* O anel da marca em volta do numero. #FF083D como MARCA GRAFICA da 3,92:1 e
   passa (piso 3,0); como fundo de texto branco reprovaria, e por isso o numero
   continua em `--texto`. Disco e halo leem `--superficie` — a cor do CARTAO, e
   nao a do realce — pela mesma razao medida em `.curso_item_agora .curso_marco`:
   entre duas lavagens rosadas o anel caia para 2,90:1 no tema claro. */
.curso_passo_atual .curso_passo_marca {
    background: var(--superficie);
    box-shadow: 0 0 0 2px var(--curso-agora), 0 0 0 5px var(--superficie);
}

/* A LEGENDA DA CONTAGEM (onda 48). O interruptor saiu desta coluna e subiu para
   a faixa sob o video; o que ficou aqui e a frase que explica COMO o numero
   acima e medido — ao lado do botao ela era ressalva, ao lado do numero e
   legenda. Mesmo fio de separacao que o botao tinha, pela mesma razao: ela
   comenta a trilha, nao faz parte dela. */
.curso_lateral_nota {
    margin: 0; padding: var(--esp-4) 0 0;
    border-top: 1px solid var(--borda);
    font-size: var(--tipo-1); line-height: 1.5; color: var(--texto-fraco);
}

/* --- a trilha do curso (onda 45) — /app/curso -------------------------------
   A LISTA VIROU CAMINHO. Ate aqui as aulas eram cinco cartoes de superficie
   pintada, com borda e raio proprios, empilhados com 12px de respiro: cinco
   blocos identicos, e nada no desenho dizia que eles formam uma SEQUENCIA. A
   referencia que o dono trouxe resolve isso com um fio vertical, um marcador
   por aula e o conteudo a direita — a mesma gramatica que `.curso_lateral_lista`
   ja usa na barra da aula, aqui em escala de tela inteira. Repetir a gramatica
   e o ponto: nao ha desenho novo no portal, ha o mesmo desenho no tamanho certo.

   O QUE A ONDA 45 MEDIU, e o que cada numero virou:

     2 desenhos de progresso   a capa tinha contagem + barra de 4px, e a lista
                               nao dizia nada sobre onde a pessoa estava no
                               conjunto. Agora ha UM desenho: o FIO. Ele nasce
                               cinza, fica verde no trecho ja andado e da cor da
                               marca na aula da vez. A barra da capa saiu — duas
                               medidas do mesmo fato obrigavam a casar dois
                               graficos do mesmo numero.
     4px vermelhos no item     `.curso_item_agora` levava a barra de acento, a
                               MESMA marcacao que o portal usa em gargalo e em
                               perda atual. O dono leu alerta, e leu certo. O
                               "voce esta aqui" passou a ser o trilho, o anel do
                               marcador e um toque de fundo na linha — e a unica
                               seta vermelha que sobrou na tela e a da retomada,
                               que e botao.
     2 linhas de 12px negrito  formato/duracao e estado ocupavam duas linhas em
                               peso 600/700 logo abaixo do titulo. Viraram UMA
                               linha de apoio, com o relogio primeiro.

   A COR DA MARCA AQUI E `--curso-agora`, e ela nao e `--fss-acao`.
   O dono pediu #FF083D, a cor do logo. Medido antes de aplicar: branco sobre
   ela da 3,92:1 e ela como texto no tema claro da 3,92:1 — reprova nos dois
   casos para texto normal (piso 4,5). Como MARCA GRAFICA passa (piso 3,0). Por
   isso ela so pinta o fio, o anel do marcador e o toque de fundo, e NUNCA um
   texto nem um fundo com texto branco em cima. O rotulo do estado da aula da vez
   continua em `--fss-texto` (#A80F18 no claro, #EC4C58 no escuro), que e o
   vermelho que este portal ja tem para texto pequeno.

   O TOKEN E LOCAL, e de proposito: trocar `--fss-acao` (#D62839) pelo #FF083D
   pintaria todo botao, todo anel de foco e a barra da home do portal inteiro,
   com AA a remedir em cada tela — outra onda. Aqui ele vive no escopo da lista. */
.curso_lista {
    /* Marca #FF083D do logo, so como marca grafica — ver a nota acima. */
    --curso-agora: #FF083D;
    /* O trecho ja andado. `--sucesso` cheio a 2px vira um traco duro. Comecou em
       62% e subiu para 80% quando a medicao no pixel acusou 2,97:1 contra a
       pagina no tema claro — abaixo do piso de 3,0 de componente de UI. Com 80%:
       4,38:1 no claro e 7,24:1 no escuro. */
    --curso-feito: color-mix(in srgb, var(--sucesso) 80%, transparent);
    /* O toque de fundo da linha da vez. E OPACO de proposito: o halo do marcador
       precisa casar exatamente com ele, e halo semitransparente sobre fundo
       semitransparente compoe um terceiro tom. */
    --curso-toque: color-mix(in srgb, var(--curso-agora) 4%, var(--painel-solido));

    --marco: 30px;
    --recuo: 3px;
    --fio: 2px;
    /* O RESPIRO ENTRE AULAS. A 320px cada 8px aqui custa 80px de rolagem nas
       cinco aulas, entao o ar cresce so quando ha tela para ele. */
    --pad-y: var(--esp-4);
    /* O UNICO numero que amarra fio, marcador e titulo. Muda um, muda os tres. */
    --marco-centro: calc(var(--pad-y) + var(--marco) / 2);

    list-style: none; display: block; margin: var(--esp-5) 0 0; padding: 0;
}
/* Espelha `.pnl_ferramentas`: sob o rotulo de secao o respiro e menor, senao os
   dois --esp-5/6 (o do rotulo e o da lista) somam vazio demais. */
.pnl_ferr_grupo + .curso_lista,
.curso_bussola + .curso_lista { margin-top: var(--esp-3); }

/* O CABECALHO DE MODULO. So renderiza quando o modulo traz mais de uma aula —
   ver a nota do template. Ele nao tem marcador e nao tem fio: e o rotulo de um
   trecho, e nao um degrau dele. */
.curso_grupo { padding: var(--esp-5) 0 var(--esp-3); }
.curso_grupo:first-child { padding-top: var(--esp-2); }
.pagina-app .curso_grupo_nome {
    margin: 0; font-size: var(--tipo-4); font-weight: 800;
    letter-spacing: -.02em; line-height: 1.25; color: var(--texto);
}
.curso_grupo_soma {
    display: flex; align-items: center; flex-wrap: wrap; gap: 5px;
    margin: 4px 0 0; font-size: var(--tipo-1); color: var(--texto-fraco);
}
.curso_grupo_soma .icone { width: 14px; height: 14px; }

.curso_item { position: relative; border-radius: var(--raio-app); }
/* Hairline entre as aulas, como na referencia: separa sem pesar. Ela comeca na
   COLUNA DO TITULO, e nao na borda do item — atravessar o fio faria a estrutura
   e o divisor brigarem no mesmo pixel. E ela nao vai antes nem depois da linha
   da vez, que ja tem fundo proprio fechando o bloco, nem no primeiro item de um
   trecho de modulo. */
.curso_item + .curso_item::after {
    content: ""; position: absolute; z-index: 0;
    left: calc(var(--recuo) + var(--marco) + var(--esp-4)); right: 0; top: 0;
    height: 1px; background: var(--borda);
}
.curso_item_agora::after,
.curso_item_agora + .curso_item::after,
.curso_item_topo::after { display: none; }

/* O FIO. Um segmento POR AULA, e nao um fio unico no <ol>: e assim que cada
   trecho pode ter a sua cor (andado / aqui / ainda nao) sem nenhum calculo de
   porcentagem, e e assim que o cabecalho de modulo consegue cortar a linha.
   Puramente decorativo — e pseudo-elemento, entao leitor de tela nunca o
   encontra e `aria-hidden` nao se aplica.

   ELE NAO E A ASSINATURA DA MARCA. A assinatura e um PONTEIRO de 4px
   (`--acento-largura`) que aponta uma coisa numa tela; isto e um fio de 2px que
   desenha a estrutura da lista inteira. Ver AssinaturaDoCursoTest, que separa os
   dois pela espessura. */
.curso_item::before {
    content: ""; position: absolute; z-index: 0;
    left: calc(var(--recuo) + (var(--marco) - var(--fio)) / 2);
    top: 0; bottom: 0; width: var(--fio); border-radius: var(--fio);
    background: var(--borda);
}
.curso_item_topo::before { top: var(--marco-centro); }
.curso_item_fim::before { bottom: calc(100% - var(--marco-centro)); }
.curso_item_feito::before { background: var(--curso-feito); }
/* A LUVA DE 2px E O QUE FAZ O FIO PASSAR NO CONTRASTE, e nao um enfeite.
   Medido no pixel em 25/08/2026: #FF083D direto sobre o toque da linha da vez
   compunha 2,90:1 no tema claro — abaixo do piso de 3,0 de componente de UI,
   porque o toque escurece o fundo justo onde o vermelho precisa dele claro. Com
   a luva de `--fundo` o fio passa a ser lido contra a cor da pagina: 3,56:1 no
   claro e 4,94:1 no escuro. E o mesmo truque do halo do marcador, um degrau
   menor. */
.curso_item_agora::before {
    background: var(--curso-agora);
    box-shadow: 0 0 0 2px var(--fundo);
}

/* A LINHA DA VEZ. Fundo proprio na linha INTEIRA, como na referencia — e nao
   uma barra na borda. O raio e o do /app; nao ha borda, porque a borda voltaria
   a desenhar um cartao. */
.curso_item_agora { background: var(--curso-toque); }

/* O item INTEIRO e o alvo (WCAG 2.5.8), entao o padding vive no <a>.
   `link_bloco` tira o sublinhado de link-em-texto. O z-index poe o conteudo
   acima do fio; quem tapa o fio de fato e o halo do marcador. */
.curso_alvo {
    position: relative; z-index: 1;
    display: grid; grid-template-columns: var(--marco) minmax(0, 1fr) auto;
    gap: 6px var(--esp-4); align-items: start;
    padding: var(--pad-y) var(--esp-3) var(--pad-y) var(--recuo);
    border-radius: var(--raio-app);
    color: inherit; text-decoration: none;
}
@media (min-width: 780px) {
    .curso_lista { --pad-y: 22px; }
    .curso_alvo { padding-inline: var(--recuo) var(--esp-5); }
}

/* O MARCADOR. Numero para a aula da vez e para as futuras (a sequencia SUGERIDA
   continua legivel), visto para a concluida. O halo de 4px e o que abre o buraco
   no fio — sem ele a linha atravessa o glifo. */
.curso_marco {
    grid-column: 1; grid-row: 1;
    position: relative; z-index: 1;
    display: grid; place-items: center;
    width: var(--marco); height: var(--marco); border-radius: 50%;
    background: var(--preenchimento); color: var(--texto);
    font-family: var(--mono); font-variant-numeric: tabular-nums;
    font-size: var(--tipo-1); font-weight: 700; line-height: 1;
    box-shadow: 0 0 0 4px var(--fundo);
}
/* Concluida: visto em tinta de sucesso sobre lavagem da mesma tinta. O glifo e
   MARCA GRAFICA (piso 3,0) e o estado vai em palavra na linha de apoio. */
.curso_item_feito .curso_marco {
    background: color-mix(in srgb, var(--sucesso) 14%, var(--fundo));
    color: var(--sucesso);
}
.curso_item_feito .curso_marco .icone { width: 19px; height: 19px; }
/* A da vez: anel da marca em volta do numero. O numero segue em `--texto` —
   branco sobre #FF083D daria 3,92:1 e reprovaria.

   O DISCO E O HALO SAO A COR DA PAGINA, E ISSO E O QUE FAZ O ANEL PASSAR.
   A primeira versao pintava os dois com o toque da linha, para que o marcador
   "fundisse" nela. Medido no pixel em 25/08/2026: #FF083D entre duas lavagens
   rosadas dava 2,90:1 no tema claro — abaixo do piso de 3,0 de componente de UI,
   e justamente no grafico que responde "voce esta aqui". Com `--fundo` dos dois
   lados o anel passa a ser lido contra a cor da pagina: 3,56:1 no claro, 4,94:1
   no escuro. O marcador deixa de fundir e passa a PERFURAR a linha — que e o
   mesmo desenho que `.curso_passo_marca` ja usava na barra lateral. */
.curso_item_agora .curso_marco {
    background: var(--fundo);
    box-shadow: 0 0 0 2px var(--curso-agora), 0 0 0 6px var(--fundo);
}

.curso_corpo { grid-column: 2; display: grid; gap: 6px; min-width: 0; }
/* O TITULO E O PROTAGONISTA: e o unico texto do item em corpo de titulo, e o
   resto do item desceu para 12/13px. `text-wrap: pretty` evita a palavra orfa a
   320px, onde os titulos quebram em tres linhas. */
.curso_titulo {
    font-size: var(--tipo-3); font-weight: 700;
    letter-spacing: -.01em; line-height: 1.35; color: var(--texto);
    text-wrap: pretty;
}
.curso_item_feito .curso_titulo { color: var(--texto-suave); }
.curso_nota { font-size: var(--tipo-2); line-height: 1.55; color: var(--texto-suave); }

/* A LINHA DE APOIO. Uma so, e nao duas: o relogio primeiro (e ele que responde
   "da para fazer agora?"), o formato depois e o estado por ultimo, com tinta
   propria. Os pontos separadores sao `::before` de irmao, e nao caracteres no
   HTML — assim o leitor de tela nao le "ponto" entre cada pedaco. */
.curso_meta {
    display: flex; align-items: center; flex-wrap: wrap; gap: 2px 6px;
    font-size: var(--tipo-1); color: var(--texto-fraco);
}
.curso_meta > * { display: inline-flex; align-items: center; gap: 5px; }
/* O PONTO SEPARADOR PENDURA NO PEDACO SEGUINTE, e some junto com ele quando a
   linha quebra. As duas amarracoes ja foram tentadas, e cada uma erra de um
   jeito:

   `::after` no anterior deixava o ponto PENDURADO no fim da linha de cima
   ("8 min · Video ·") quando o estado descia, e quem apagava esse ponto era
   `:has(+ .curso_estado)` — correto, e sem rede: onde `:has()` nao existe, o
   ponto volta. Nao e hipotese distante: o Firefox que a suite visual usa e o
   119, anterior ao suporte (121), e la o defeito aparece de verdade a 390px.

   `::before` no seguinte, SOZINHO, punha o ponto abrindo a linha quebrada
   ("· Concluida em 25/08") — o defeito que motivou a troca original.

   O que fecha os dois e `::before` MAIS a supressao explicita no unico pedaco
   que quebra por decisao (`.curso_estado`, com `flex-basis: 100%` logo abaixo).
   Nada de `:has()`: o suporte e o que faltava. */
.curso_meta > * + *::before {
    content: "·"; margin-inline-end: 6px; color: inherit; opacity: .55;
}
.curso_meta .icone { flex: none; width: 14px; height: 14px; }
.curso_meta_tempo { font-variant-numeric: tabular-nums; }
/* EM TELA ESTREITA A LINHA DE APOIO NAO CABE, e o estado descia sozinho de
   qualquer jeito. Aqui a quebra passa a ser DECIDIDA (flex-basis) em vez de
   sofrida — e, decidida, da para apagar o ponto que sobraria abrindo a linha. */
@media (max-width: 479px) {
    .curso_estado { flex-basis: 100%; }
    .curso_estado::before { content: none; }
}

/* O estado tem peso e tinta — e a unica coisa da linha de apoio que muda de
   aula para aula. */
.curso_estado { font-weight: 700; color: var(--texto-suave); }
.curso_item_feito .curso_estado { color: var(--sucesso); }
/* A DA VEZ NAO PINTA O ROTULO DE VERMELHO, e a razao e medida duas vezes.
   No escuro `--fss-texto` (#EC4C58) sobre o toque da linha da vez deu 4,41:1 —
   reprova AA em 13px (piso 4,5), e o toque e justamente o que subiu o fundo. E
   no claro seria o QUARTO vermelho da mesma linha (fio, anel, toque, texto)
   dizendo a mesma coisa. Em `--texto` cheio o rotulo passa a ser o texto de
   maior contraste da linha de apoio — que e o que "voce esta aqui" merece — e a
   cor volta a ter um dono so. */
.curso_item_agora .curso_estado { color: var(--texto); }
/* Estados das aulas: concluido, em andamento e pendente */
.curso_item_concluido .curso_estado { color: var(--sucesso); background: color-mix(in srgb, var(--sucesso) 15%, var(--superficie)); }
.curso_item_andamento .curso_estado { color: var(--fss); background: color-mix(in srgb, var(--fss) 15%, var(--superficie)); }
.curso_item_pendente .curso_estado { color: var(--texto-suave); background: var(--superficie); }

.curso_alvo:focus-visible { outline: 3px solid var(--fss-acao); outline-offset: -3px; }

/* --- o que acontece se eu clicar -------------------------------------------
   ANTES ERA UM SUBLINHADO NO TITULO, e ele falhava em tres frentes de uma vez:
   so existia sob o mouse (quem varre a lista antes de apontar nao via affordance
   nenhuma), nao dizia O QUE viria — assistir, ler e baixar sao tres coisas — e
   no toque nao existe hover, entao metade dos leads nunca o viu.

   A PILULA E VISIVEL EM REPOUSO, e essa e a diferenca que importa: a linha passa
   a anunciar o que ela faz sem esperar gesto nenhum. O hover so intensifica.

   E ELA PREENCHE O VAZIO DA DIREITA. A lista e larga, o conteudo se amontoava a
   esquerda e sobravam ~800px de nada em cada linha — o olho tinha de voltar todo
   o caminho para o proximo titulo. Com uma ancora na direita, cada linha ganha
   duas bordas e vira um bloco em vez de um texto solto num campo aberto. */
.curso_acao {
    grid-column: 3; grid-row: 1; align-self: center;
    display: inline-flex; align-items: center; justify-content: center; gap: 7px;
    /* Largura minima igual para todos: "Ler" tem tres letras e "Assistir" oito,
       e pilulas de tamanhos diferentes empilhadas viram uma borda direita
       serrilhada. Alinhadas, as cinco linhas ganham uma segunda margem. */
    min-width: 116px; padding: 8px 15px; border-radius: var(--pilula);
    border: 1px solid var(--borda);
    color: var(--texto-suave); font-size: var(--tipo-1); font-weight: 700;
    white-space: nowrap;
    transition: background var(--dur-1, 120ms) var(--curva-suave, ease),
                border-color var(--dur-1, 120ms) var(--curva-suave, ease),
                color var(--dur-1, 120ms) var(--curva-suave, ease);
}
.curso_acao .icone { flex: none; width: 15px; height: 15px; }

/* Sob o dedo ou sob o foco do teclado a pilula vira o botao que ela ja parecia.
   `:focus-visible` no <a> acende a pilula tambem: quem navega por Tab merece a
   mesma resposta que quem aponta — e o outline sozinho diz "selecionado", nao
   diz "isto e uma acao". */
.curso_item:hover .curso_acao,
.curso_alvo:focus-visible .curso_acao {
    background: var(--fss-acao); border-color: var(--fss-acao); color: #fff;
}

/* A AULA DA VEZ JA CHEGA ACESA. Ela e a acao principal da tela — a pessoa veio
   aqui para continuar de onde parou —, e uma pilula de contorno igual as outras
   a deixaria disputando atencao com cinco linhas identicas. */
.curso_item_agora .curso_acao {
    background: var(--fss-acao); border-color: var(--fss-acao); color: #fff;
}

/* A concluida recua um degrau: "Rever" e oferta, nao chamado. */
.curso_item_feito .curso_acao { border-style: dashed; }

@media (prefers-reduced-motion: reduce) { .curso_acao { transition: none; } }

/* Em tela estreita nao ha coluna sobrando: a pilula desce para a linha de
   baixo, alinhada ao texto (e nao ao marcador), e mantem verbo e glifo — em
   375px o que falta e largura, nao clareza. */
@media (max-width: 560px) {
    .curso_alvo { grid-template-columns: var(--marco) minmax(0, 1fr); }
    .curso_acao { grid-column: 2; grid-row: 2; justify-self: start; margin-top: 4px; }
}

/* --- a bussola (onda 39) ---------------------------------------------------
   A SUGESTAO NAO PODE PARECER UMA TRAVA, e o desenho e onde isso se decide.

   NAO E UMA BARRA DE ACENTO. `.curso_retoma` e `.curso_item_agora` ja usam a
   barra vermelha, e as duas apontam para a MESMA coisa — onde a pessoa parou.
   Uma terceira barra, num item diferente, poria duas setas vermelhas na mesma
   lista brigando pelo mesmo verbo (ver AssinaturaDoCursoTest). Por isso a marca
   e uma pilula de contorno: presente, legivel, e um degrau ABAIXO do estado.

   O VERMELHO SO TOCA O ICONE, e em `--fss-texto`, que e o token que muda com o
   tema. O rotulo sai em `--texto` cheio sobre `--preenchimento` — a nota de
   `.curso_n` acima ja registra que `--texto-suave` sobre esse fundo compunha
   #D4D7DD e reprovava AA.

   E A COR NAO CARREGA NADA: o texto diz tudo (WCAG 1.4.1). */
.curso_pilar {
    display: inline-flex; align-items: center; gap: 6px; justify-self: start;
    margin-top: 3px; padding: 3px 9px; border-radius: var(--pilula);
    border: 1px solid var(--borda-marca); background: var(--preenchimento);
    font-size: var(--tipo-1); font-weight: 700; color: var(--texto);
}
.curso_pilar .icone { flex: none; color: var(--fss-texto); }
/* A 320px o rotulo quebra em duas linhas e o glifo centralizado flutuava no
   meio da pilula. Ele pertence a PRIMEIRA linha. */
.curso_pilar { align-items: flex-start; }
.curso_pilar .icone { margin-top: 2px; }

/* A FRASE, na lista e na aula. Ela EXPLICA a marca, entao anda no mesmo tom do
   resto do texto de apoio (`--texto-suave`, como `.curso_nota`) e nunca no de
   alerta: nada aqui e um problema a resolver. */
.curso_bussola {
    display: flex; align-items: flex-start; gap: 8px;
    margin: var(--esp-3) 0 0; max-width: 62ch;
    font-size: var(--tipo-2); line-height: 1.55; color: var(--texto-suave);
}
.curso_bussola .icone { flex: none; margin-top: 3px; color: var(--fss-texto); }
.curso_bussola strong { color: var(--texto); font-weight: 700; }
/* Na AULA ela mora entre o titulo e o resumo, dentro do cartao de leitura —
   entao segue a medida de linha do lead, e nao a da lista. */
.pagina-app .curso_aula > p.curso_bussola { margin: var(--esp-4) 0 0; max-width: 54ch; }

/* --- a aula ---------------------------------------------------------------- */
/* A AULA E UM DOCUMENTO, e nao um cartao de painel.
   Com a medida de linha corrigida para 54ch, o corpo passou a ocupar ~60% da
   largura do cartao a 1440px e os 40% restantes viravam um vazio a direita
   dentro de uma superficie pintada — o cartao continuava do tamanho do painel
   enquanto o conteudo tinha virado coluna de leitura. Aqui a SUPERFICIE segue a
   coluna: cabecalho, corpo e acoes na mesma medida, centrados.

   O NUMERO SAI DA MEDIDA, e nao do gosto: 54ch de corpo dao 578px, mais os
   34px de `padding` de cada lado do cartao — 46rem e o cartao que ABRACA a
   coluna de leitura em vez de deixar 45% de superficie pintada vazia a direita.
   Abaixo desse limite o `min()` devolve a largura toda, e nada muda a 320px. */
.pagina-app .curso_volta,
.pagina-app .curso_aula,
.pagina-app .curso_depois { max-width: 100%; }

/* A AULA VOLTOU A LARGURA DE TODA TELA DO /app (25/08/2026), e a terceira
   tentativa e que fecha as duas anteriores.
   O ESTADO ANTERIOR e o porque dele: com a medida de linha em 54ch, o corpo
   ocupava ~60% de um cartao de 1.080px e os outros 40% viravam vazio pintado. A
   resposta na epoca foi encolher a SUPERFICIE ate abracar a coluna — 46rem.
   Resolveu o vazio e criou outro problema, que so aparece olhando o /app inteiro:
   medido a 1440px, o maior bloco de /app, /app/calculadora e /app/curso mede
   1.080px; o de /app/diagnostico, /app/empresa e /app/configuracoes mede 820. Duas
   larguras, cada uma com uma razao. A aula media 736 — a UNICA tela do portal cujo
   conteudo nao preenche o proprio container. Nao lia como decisao: lia como outra
   biblioteca.
   O QUE MUDA E O QUE NAO MUDA. A superficie passa a acompanhar as irmas; a coluna
   de LEITURA continua exatamente onde estava (54ch, media 66 e pior caso 75
   caracteres — ver a nota de .curso_texto). Os 40% deixam de ser vazio porque
   ganham dono: a acao de concluir sobe para um trilho a direita, onde ela fica
   visivel durante a leitura inteira em vez de esperar no fim de dezesseis minutos
   de texto.
   So a partir de 1.100px. Abaixo disso a grade some, tudo volta a empilhar na
   ordem do documento, e o trilho vira o que sempre foi: o fim da aula. */
@media (min-width: 1100px) {
    .pagina-app .curso_aula {
        display: grid;
        /* 22rem, e o numero saiu de uma medicao: "Marcar como concluida" com o
           glifo e o respiro pede 285px numa linha so, e um trilho de 17rem
           oferecia 222 — o rotulo quebrava em duas linhas dentro de um cartao
           estreito, que foi a primeira coisa que o dono apontou. Encurtar o texto
           era a outra saida e custava mais: "Marcar como concluida" diz que quem
           marca e a pessoa, e e isso que a tela precisa dizer.
           A coluna de escrita nao paga por isso: ela e capada em 54ch (578px) e o
           que sobra depois do trilho continua sendo 632px. */
        grid-template-columns: minmax(0, 1fr) 22rem;
        column-gap: var(--esp-7, 40px);
        align-items: start;
        /* AS LINHAS VAZIAS NAO PODEM ENGORDAR — e este e um defeito da onda 46
           que so ficou visivel na 47, quando a coluna principal ganhou um vídeo
           de 343px onde havia um botão de 40.

           O MECANISMO. O trilho da direita ocupa `grid-row: 1 / span 20` (ver a
           nota abaixo: `span` é o único jeito que funciona sem
           `grid-template-rows`). Vinte linhas, e a aula de vídeo tem TRÊS filhos
           na coluna 1 — as outras dezessete existem e estão vazias. Quando o
           navegador precisa acomodar os 816px do trilho, ele distribui a
           diferença entre TODAS as linhas que o item atravessa, inclusive as
           vazias: medido, `36,5px` em cada uma das dezessete. O cartão inteiro
           passa a medir 1.193px para um conteúdo de 501 e um trilho de 816 —
           342px de superfície pintada e vazia abaixo de tudo.

           POR QUE NINGUEM VIU NA ONDA 46: a única aula de vídeo do catálogo é a
           do YouTube, e ela era um botão de 40px. Com a coluna curta, a
           distribuição tinha para onde ir e o cartão parava nos 886 do trilho.
           A aula de TEXTO nunca sofreu: ela tem filhos suficientes para preencher
           as vinte linhas. Medido nas três, antes e depois — evidencias/w47/
           medidas-grade.txt.

           `max-content` E NAO `auto`: com `auto` a linha vazia aceita o espaço
           distribuído; com `max-content` o teto dela é o conteúdo, que em linha
           vazia é zero. As linhas COM conteúdo não mudam — altura de bloco em
           largura fixa é a mesma nos dois modos, e a medição confirma (a aula de
           texto fica em 1.667px, o mesmo número de antes).

           `min-content` dava exatamente o mesmo resultado nas três telas.
           `max-content` é o mais conservador dos dois para quem vier depois: uma
           linha futura com filho que se estica não é achatada. */
        grid-auto-rows: max-content;
    }
    .pagina-app .curso_aula > * { grid-column: 1; }
    /* O TRILHO ATRAVESSA TODAS AS LINHAS, e o `span` nao e estilo: e o unico
       jeito que funciona aqui.
       Ocupando UMA linha, ele obrigava a primeira linha da grade a ter a altura
       DELE — medido: `grid-template-rows: 177px 1305px`, com o cabecalho de 60px
       dentro de uma faixa de 177 — e abria um vao de ~140px entre o titulo da aula
       e o primeiro paragrafo.
       `1 / -1` parecia a correcao e nao e: `-1` aponta para a ultima linha do grid
       EXPLICITO, e aqui nao ha `grid-template-rows` nenhum. Todas as linhas sao
       implicitas, `-1` volta a valer 1, e a regra vira `grid-row: 1` de novo — o
       vao continuou igual e so a medicao mostrou por que.
       Com `span` a contagem e relativa e independe de grid explicito. Vinte cobre
       qualquer aula: o cartao tem tres filhos hoje. */
    .pagina-app .curso_aula > .curso_lateral {
        grid-column: 2; grid-row: 1 / span 20; align-self: start;
        position: sticky; top: 96px;
    }
    /* O texto do bloco seguinte tem a mesma medida do corpo: a largura do
       cartao cresceu, a linha de leitura nao. */
    .pagina-app .curso_depois_txt { max-width: 54ch; }
}
.curso_volta { margin: var(--esp-5) 0 0; font-size: var(--tipo-2); }

/* A VOLTA E UM ALVO DE 18px, e isso e uma reprovacao de AA, nao um detalhe de
   acabamento. Medido em 21/08/2026: o <a> media 121x18px e a WCAG 2.2 pede
   24x24 (2.5.8, nivel AA). A excecao "inline" nao vale aqui — ela cobre link
   DENTRO de uma frase, e este ocupa uma linha sozinho, sem texto ao redor que
   restrinja a altura.

   No mesmo lugar, o icone estava COLADO no rotulo: folga de 0px entre o svg e
   o "T" de "Todas as aulas", enquanto todo par icone+rotulo do portal anda com
   8 ou 10px (`.nav a`, `.btn`). O sublinhado atravessava os dois. Com
   `inline-flex` o Chromium desenha o sublinhado so sob o TEXTO — o icone e
   item de flex, nao conteudo de linha —, entao a afordancia de link continua
   inteira e o icone para de parecer uma letra.

   (0,4,2) para empatar com `.pagina-app main a:not(.btn):not(.btn_sec):not(
   .link_bloco)`, que e quem pinta e sublinha link de texto no /app; empatando,
   ganha quem vem depois no arquivo, e este vem. */
.pagina-app main .curso_volta a:not(.btn):not(.btn_sec) {
    display: inline-flex; align-items: center; gap: var(--esp-2);
    min-height: 24px; padding-block: 3px;
}
.curso_volta .icone { flex: none; }

/* A ASSINATURA DA MARCA, NO TITULO DA AULA.
   O QUE FALTAVA, CONTADO ANTES DE MEXER (evidencias/w35/identidade-antes.txt,
   1440px, nos dois temas): o painel toca o vermelho da FSS 15 vezes e desenha
   2 barras; o relatorio, 9 e 1; a LISTA do curso, 6 e 2. A AULA: 2 marcas e
   ZERO barras — e as duas marcas sao o mesmo rotulo ("TEXTO · 8 MIN"). A tela
   onde a pessoa passa de 8 a 16 minutos era a unica do curso sem nenhuma
   assinatura de marca.

   A BARRA VERTICAL VERMELHA e o recurso que o brandbook FSS repete em toda
   pagina interna do manual, e que a onda 33 trouxe para o titulo de toda tela
   do /admin. Ela PENDURA na margem interna do cartao, e nao empurra o titulo:
   rotulo, titulo, resumo, corpo e botoes compartilham um unico eixo vertical, e
   recuar so o titulo quebraria o unico alinhamento que a pagina tem.

   A ESPESSURA E --acento-largura (4px), e nao os 3px do /admin. A forma vem do
   brandbook; a medida ja estava decidida em casa — a direcao B fixou quanto
   vale uma barra de acento no /app, e ela e a mesma em `.pnl_fecho`,
   `.curso_retoma` e `.curso_item_agora`. Importar a espessura do painel abriria
   uma SEGUNDA largura de barra dentro do mesmo produto, que e o tipo de
   divergencia que a direcao veio fechar.

   MEDIDA no pixel renderizado (evidencias/w35/marcas-depois.txt), contra a
   superficie do cartao, que e a cor vizinha: 4,13:1 no claro (#D62839 contra
   #E8EAEE) e 3,62:1 no escuro (contra #16161E), nas DUAS preferencias de
   movimento. O piso de objeto grafico e 3:1 (WCAG 1.4.11).

   VALE --fss-acao, E NAO --fss-texto, e os dois valores continuam existindo de
   proposito. Aqui o vermelho e SUPERFICIE, nao tinta de letra — e --fss-acao e
   o unico dos dois que NAO muda com o tema (--fss-texto vira #EC4C58 no
   escuro, o tom calibrado para 12px de texto). Pintar a barra com o token de
   texto trocaria a cor da marca entre os temas para pagar um contraste que
   este uso nao exige. E a mesma separacao que a onda 17 escreveu no portal e a
   onda 33 repetiu no painel.

   NA LISTA ELA NAO ENTRA, e isso e recusa medida, nao esquecimento: la a barra
   ja fala duas vezes, e nas duas ela APONTA (a retomada e a aula da vez). Uma
   terceira, no titulo, seria a unica que nao aponta para nada, e as tres
   ficariam no MESMO eixo vertical a menos de 300px uma da outra — deixam de
   marcar e viram trilho. E a licao que a onda 33 ja tinha pago no /admin
   ("cinco barras por tela viram textura"). A prova esta em
   evidencias/w35/recusadas/lista-com-barra-1440.png.

   `--curso-recuo` repete o padding que `.calc_cartao` ja dava ao cartao, para
   que a barra saiba de quanto e a margem em que ela pendura. Um numero so,
   lido pelos dois — e nao um -17px cravado que erra a 320px, onde o clamp
   entrega 22. */
.pagina-app .curso_aula {
    --curso-recuo: clamp(22px, 4vw, 34px);
    padding: var(--curso-recuo);
}
.curso_aula .conta_cabeca { position: relative; }
.curso_aula .conta_cabeca::before {
    content: ""; position: absolute; top: 2px; bottom: 2px;
    left: calc(-1 * (var(--curso-recuo) / 2) - var(--acento-largura) / 2);
    width: var(--acento-largura); border-radius: var(--pilula);
    background: var(--fss-acao);
}

/* O RESUMO DA AULA ESTAVA COLADO NO TITULO, e a margem que faltava tinha dono.
   `.pagina-app .calc_intro` pede `margin: var(--esp-5) 0 0`, e o que chegava
   era ZERO: o cartao da aula tambem e um `.tile`, e `.pagina-app .tile >
   p:first-of-type { margin-top: 0 }` — escrita para o bento da HOME, onde o
   paragrafo segue um <h3> — tem (0,2,1) contra os (0,2,0) da outra. Medido em
   21/08/2026: 0px entre o h1 de 27px e o resumo. E o mesmo tropeco de
   especificidade ja documentado quatro regras acima, com outro vencedor.

   E A COLUNA DE LEITURA TINHA DUAS MEDIDAS. A onda 34 levou o CORPO para 54ch
   (66 caracteres de media, 75 no pior caso) e nao tocou no resumo, que seguia
   com o `68ch` da calculadora: 642px, 85 caracteres na primeira linha — mais
   longo que qualquer linha do texto que ele resume, e e a PRIMEIRA linha que a
   pessoa le. Agora as duas medidas sao a mesma, por construcao: mesmo corpo,
   mesmo 54ch, 72 caracteres contra os 72-73 do texto (medido por Range, nao
   por `ch` — ver a nota da medida de linha).

   O RESUMO SOBE PARA --tipo-3 e para a tinta cheia. Ele e o lead da aula, e
   estava um degrau ABAIXO do corpo que apresenta (15 contra 17px): hierarquia
   invertida, com o resumo menor que o texto. A separacao passa a ser tinta —
   lead em --texto, corpo em --texto-suave —, que e o degrau que o portal ja usa
   entre primario e secundario.

   O CONTADOR DE TAMANHOS DA PAGINA NAO MUDA, e vale dizer por que: continuam
   quatro (13, 15, 17, 27). O 15 nao era so do resumo — e o corpo de
   `.curso_volta` e do cartao de vizinho, que ficam FORA do cartao de leitura.
   O que se fechou foi a COLUNA: dentro dela agora ha dois tamanhos (27 do
   titulo, 17 do lead e do texto), e nao tres. Medido em
   evidencias/w35/medidas-depois.txt. */
/* `p.calc_intro`, e nao `.calc_intro`: (0,3,0) PERDE de (0,3,1) e a margem
   continuaria em zero — medido, depois de a primeira versao desta regra sair
   com o resumo ainda colado. Com o `p` no seletor empatam, e empate se decide
   por ordem no arquivo: `.pagina-app .tile > p:first-of-type` esta na secao da
   home, muito acima. E a terceira vez que este arquivo registra o mesmo
   tropeco; a licao e sempre a mesma, e sempre por medida. */
.pagina-app .curso_aula > p.calc_intro {
    margin-top: var(--esp-4); max-width: 54ch;
    font-size: var(--tipo-3); line-height: 1.7; color: var(--texto);
}
/* O estado vazio da LISTA carrega o mesmo defeito de especificidade (o texto
   colado no titulo do cartao) e leva so o conserto da margem: ali o paragrafo
   nao e lead de nada, e continua sendo texto de apoio. */
.pagina-app .curso_vazio > p.calc_intro { margin-top: var(--esp-4); }

/* O QUE VEM DEPOIS DE CONCLUIR, no lugar onde o redirect ATERRISSA.
   `POST /app/curso/{slug}/progresso` devolve para a mesma aula, no topo — entao
   quem acaba de marcar reencontra o texto que ja leu, e a proxima aula fica
   ~1.900px abaixo a 1440px. Esta faixa nasce no topo do cartao, ja concluida, e
   oferece o passo seguinte no primeiro pixel visivel. Enquanto o destino do
   redirect for o servidor quem decide, ela e o conserto que a tela alcanca. */
.curso_fecho {
    display: flex; flex-wrap: wrap; align-items: center; gap: var(--esp-4);
    margin-bottom: var(--esp-5); padding: var(--esp-4) var(--esp-5);
    border-radius: var(--raio-app);
    /* SEM LAVAGEM VERDE. A onda 32 fundiu a lavagem rosa de `.pnl_fecho` no
       vidro porque uma SEGUNDA pintura de cartao na mesma tela era o volume
       alto que a direcao B veio baixar. Pintar esta faixa de verde repetiria o
       erro com outra cor: a enfase mora nos 4px de acento, e o resto e a mesma
       superficie de sempre. Medido: com a lavagem, a aula concluida desenhava
       4 superficies; sem ela, 3 — as mesmas da aula nao concluida. */
    background: var(--painel);
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
    border: 1px solid var(--borda-feito);
    border-inline-start: var(--acento-largura) solid var(--sucesso);
}
/* (0,2,0) para vencer `.pagina-app .tile p`, que pinta todo paragrafo de cartao
   com --texto-suave. Aqui a frase e a CONFIRMACAO do que a pessoa acabou de
   fazer, e confirmacao em tinta secundaria sobre o vidro dava 4,39:1 no tema
   claro — reprovado, e medido nesta onda depois de a faixa nascer. */
.pagina-app .curso_fecho_txt { flex: 1 1 22ch; min-width: 0; font-size: var(--tipo-2); color: var(--texto); }
.curso_fecho_txt .icone { color: var(--sucesso); margin-right: 6px; }
.curso_fecho strong { font-weight: 700; }

/* A MEDIDA DA LINHA, medida e nao estimada.
   `68ch` parecia dentro da norma e nao estava: `ch` e a largura do "0", e nesta
   familia ele vale ~1,14 caractere real — as linhas saiam com 77 caracteres de
   media e 94 no pior caso, contra os 45-75 de leitura longa.
   58ch ainda deixava 81 no pior caso. 54ch poe a MEDIA em 66 (o otimo da norma)
   e o PIOR CASO em 75 — e o pior caso e o que importa, porque e nele que o olho
   perde a linha ao voltar. Corpo e entrelinha seguem intocados. */
.pagina-app .curso_texto { margin: var(--esp-5) 0 0; max-width: 54ch; }
.pagina-app .curso_texto p {
    margin: 0 0 var(--esp-4);
    font-size: var(--tipo-3); line-height: 1.75; color: var(--texto-suave);
}
.pagina-app .curso_texto > :last-child { margin-bottom: 0; }
/* O TITULO DE SECAO DENTRO DA AULA.
   Quem escreveu as aulas marcou as secoes em CAIXA ALTA numa linha propria
   ("POR QUE UM DE CADA VEZ"). O renderizador antigo jogava tudo em <p>: 2.500
   caracteres sem um unico degrau de hierarquia, com o titulo de secao no mesmo
   corpo, no mesmo peso e na mesma tinta do texto corrido. Agora e <h2> de
   verdade — o leitor de tela ganha o indice da aula junto. */
.pagina-app .curso_texto h2 {
    margin: var(--esp-6) 0 var(--esp-3);
    font-size: var(--tipo-2); font-weight: 800; letter-spacing: .08em;
    line-height: 1.35; text-transform: uppercase; color: var(--texto);
}
.pagina-app .curso_texto > h2:first-child { margin-top: 0; }
/* LISTA E LISTA. "1. Abra o relatorio" saia como paragrafo com <br>: a segunda
   linha voltava para debaixo do numero e o item deixava de ler como item.
   Recuo pendente resolve, e de quebra o leitor de tela passa a anunciar
   "lista de 4 itens". */
.pagina-app .curso_texto ol,
.pagina-app .curso_texto ul {
    margin: 0 0 var(--esp-4); padding-inline-start: 1.6em;
    font-size: var(--tipo-3); line-height: 1.75; color: var(--texto-suave);
}
.pagina-app .curso_texto li { margin-bottom: var(--esp-2); padding-inline-start: .2em; }
.pagina-app .curso_texto li:last-child { margin-bottom: 0; }
.pagina-app .curso_texto li::marker { color: var(--texto-fraco); font-weight: 700; }

/* AS NOTAS DA AULA DE VIDEO (onda 60).
   As duas aulas de video tem corpo escrito e ele nao aparecia — a tela
   ramificava por formato e cada ramo era exclusivo. O texto entra ABAIXO do
   player, e a hierarquia e dita por ORDEM, TITULO e MEDIDA, nunca por cor:

   ORDEM    o player vem antes, sempre. O video e a aula.
   TITULO   "Notas da aula" e h2 (filho do h1 do titulo da aula) e os titulos
            de secao do corpo descem para h3 — ver `$corpoEmBlocos` na tela.
   MEDIDA   o texto para em 54ch, a mesma medida de leitura da aula de texto
            (a nota logo acima explica o numero). MEDIDO a 1440: o palco do
            video tem 610px e o texto 578px — a diferenca e de 32px, entao a
            largura NAO e o que cria a hierarquia aqui, e seria desonesto
            dizer que e. Ela faz outra coisa, que e a que importa: mantem a
            linha em 66 caracteres de media e 73 no pior caso, dentro dos
            45-75 da norma, exatamente como na aula de texto.

   E NENHUMA COR, NENHUMA CAIXA E NENHUMA SEGUNDA SUPERFICIE: pintar as notas
   seria a quarta superficie do cartao, que e o volume que a direcao B veio
   baixar.

   O FIO DE CIMA e o unico ornamento, e ele nao e decoracao: sem ele o texto
   encosta no video como se fosse legenda do player. Um fio de 1px na mesma
   `--borda` de todo separador do app, e nada mais. */
.curso_notas { margin: var(--esp-6) 0 0; padding-top: var(--esp-5); border-top: 1px solid var(--borda); }
/* (0,3,1), E A CONTA IMPORTA — a primeira versao desta regra era (0,2,0) e
   NAO PEGAVA. Quem vence e `.pagina-app .tile h2` (0,2,1): duas classes MAIS um
   seletor de tipo, e a aula inteira vive dentro de `.tile`. Medido no
   navegador antes do conserto: o rotulo saia com 22px e `margin: 14px 0 8px`
   em vez dos 17px e `margin: 0` escritos aqui — a cascata decidia, e o
   comentario mentia. E a terceira vez que esta armadilha aparece nesta folha
   (ver as notas em .rel_* e .pnl_*); por isso o seletor agora carrega o tipo.

   Sem versalete: o caixa alta e a voz dos titulos de secao DENTRO do corpo
   (h3, abaixo), e usar a mesma voz aqui apagaria o degrau que este rotulo
   existe para criar. */
.pagina-app .curso_notas h2.curso_notas_rotulo {
    margin: 0; max-width: 54ch;
    font-size: var(--tipo-3); font-weight: 800; letter-spacing: -.02em; line-height: 1.3;
    color: var(--texto);
}
.pagina-app .curso_notas .curso_texto { margin-top: var(--esp-4); }
/* O h3 herda a forma do h2 do corpo (o titulo de secao em caixa alta que quem
   escreve as aulas ja usa). O degrau entre eles e SEMANTICO e de largura, nao
   de tamanho de fonte: sao o mesmo tipo de coisa em dois niveis de arvore, e
   encolher o h3 so o afastaria do corpo que ele titula. */
.pagina-app .curso_texto h3 {
    margin: var(--esp-6) 0 var(--esp-3);
    font-size: var(--tipo-2); font-weight: 800; letter-spacing: .08em;
    line-height: 1.35; text-transform: uppercase; color: var(--texto);
}
.pagina-app .curso_texto > h3:first-child { margin-top: 0; }

/* A acao principal da aula: assistir. Sem fio proprio — quem separa e o
   `.curso_marcar` logo abaixo, e dois fios seguidos partiriam o cartao em tres
   pedacos para duas acoes. */
.pagina-app .curso_abrir {
    display: flex; flex-wrap: wrap; align-items: center; gap: var(--esp-4);
    margin: var(--esp-6) 0 0;
}
.pagina-app .curso_abrir .miudo { flex: 1 1 18ch; }

/* --- a faixa da aula (onda 48) ----------------------------------------------
   "‹ Anterior" | o interruptor | "Proxima ›", numa linha so, LOGO ABAIXO DO
   VIDEO. Ela substitui DUAS pecas que viviam separadas: o interruptor no pe da
   barra lateral e os dois cartoes de vizinho no fim da pagina. As duas sairam
   de la — dois pares de setas na mesma pagina e pior que nenhum.

   O FIO EM CIMA E EMBAIXO, e nao so em cima: a faixa fica ENTRE duas coisas (o
   video e o corpo da aula, ou o corpo e a barra lateral). Um fio so a colaria
   na de baixo, e ela leria como cabecalho do texto seguinte em vez de peca
   propria. E o mesmo par de fios que `.diag_barra` usa.

   A GRADE A 320px E DE UMA COLUNA SO, e a razao e ORDEM DE FOCO — nao gosto.
   A faixa tem tres focaveis: Anterior, o interruptor, Proxima. Em duas colunas
   com o interruptor em cima (a primeira versao desta regra), a tabulacao ia do
   canto INFERIOR esquerdo para o topo e voltava para o canto inferior direito:
   o foco pulava para tras dentro de um bloco de 190px. Empilhados na ordem do
   documento, a sequencia visual e a de foco sao a mesma coisa, de cima para
   baixo — que e o que a WCAG 2.4.3 pede e o que a tecnica C27 recomenda.

     linha 1   "‹ Anterior", largura cheia (o alvo de toque vira a linha toda);
     linha 2   o interruptor. "Marcar como concluida" mede 164px de rotulo mais
               o trilho e o respiro: 242px dos 248 disponiveis, numa linha so;
     linha 3   a legenda — o estado em texto + "Aula N de M" — colada no
               interruptor que ela descreve;
     linha 4   "Proxima ›", largura cheia, alinhada a direita.

   O QUE CUSTOU: 44px de altura. A faixa a 320px media 190px com os dois lados
   dividindo uma linha e mede 234 com cada um na sua (medido, evidencias/w48/
   medidas-320.txt). Numa pagina de ~4.900px de rolagem a essa largura, e o
   preco de o foco nao andar para tras — e a conta nao e proxima.

   A partir de 640px vira uma linha de tres colunas, que e a referencia do dono.
   O NUMERO SAIU DE MEDICAO, e a medicao esta em evidencias/w48/medidas-320.txt:
   forcando as tres colunas em nove larguras, o interruptor fica estavel em
   ~245px e quem quebra primeiro e o LADO. A 540px a celula da esquerda mede
   87px e "Primeira aula" passa a ocupar DUAS linhas (altura 49 contra 44); a
   560px ela mede 96 e volta para uma. Ou seja: o limite real esta por volta de
   550.
   640 E CONSERVADOR DE PROPOSITO, com 33px de folga na celula, e a folga tem
   dono: a medicao e do Chromium com a fonte do portal CARREGADA. Numa fonte de
   fallback — a primeira pintura, uma rede ruim, um sistema sem a familia — o
   mesmo rotulo sai mais largo, e a 550 ele quebraria em duas linhas. Quebrar o
   rotulo do interruptor foi exatamente o defeito que o dono apontou na onda 46;
   custar 55px de altura numa faixa de larguras estreita (560..639) e o preco
   barato de nao repeti-lo.

   `align-items: center` e `1fr auto 1fr`: os dois lados dividem o que sobra e o
   interruptor fica com o que precisa — e assim ele fica no CENTRO OPTICO
   mesmo quando um lado diz "Primeira aula" e o outro diz "Proxima". */
.curso_barra {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--esp-2) var(--esp-4);
    align-items: center;
    margin: var(--esp-5) 0 0;
    padding: var(--esp-5) 0;
    border-top: 1px solid var(--borda);
    border-bottom: 1px solid var(--borda);
}

/* O <form> E SO O INVOLUCRO DO POST: ele nao desenha nada. Sem isto ele herda
   `.curso_marcar` e traz de volta o fio e a margem que a faixa ja tem. */
.curso_marcar {
    grid-column: 1; grid-row: 2;
    display: block; margin: 0; padding: 0; border: 0;
}

/* OS DOIS LADOS SAO A MESMA PECA, com ou sem destino: o <a> e o <span> inerte
   compartilham tudo menos a afordancia. Assim a faixa nao muda de desenho na
   primeira e na ultima aula.
   `min-height: 44px` porque este e um alvo de toque isolado (WCAG 2.5.8 pede
   24x24; 44 e o piso confortavel que o resto do /app usa).
   `.link_bloco` no HTML tira o sublinhado de link-em-texto corrido: aqui o
   rotulo E a peca inteira, e sublinhar "‹ Anterior" pinta um risco sob a seta. */
.curso_barra_lado {
    display: flex; align-items: center; gap: 6px;
    min-height: 44px; padding: 6px 2px;
    font-size: var(--tipo-2); font-weight: 700; line-height: 1.3;
    color: var(--texto); text-decoration: none;
}
.curso_barra_lado { grid-row: 1; grid-column: 1; }
.curso_barra_frente { grid-row: 4; grid-column: 1; justify-content: flex-end; text-align: right; }
a.curso_barra_lado:hover { color: var(--fss-texto); }
a.curso_barra_lado:focus-visible { outline: 3px solid var(--fss-acao); outline-offset: 3px; border-radius: 6px; }

/* A SETA E TEXTO, e por isso o piso dela e 4,5:1 (contraste de TEXTO) e nao os
   3:1 de elemento grafico — o mais rigoroso dos dois, herdado de graca da cor
   do rotulo. Ela e `aria-hidden` no HTML: "‹" pode ser lido como "menor que".
   1.4em porque o glifo de aspa angular e pequeno no corpo do texto; sem isso
   ele lê como sujeira, e nao como direcao. */
.curso_barra_seta { font-size: 1.4em; line-height: 1; }

/* O LADO SEM DESTINO. Nao e botao desabilitado, nao entra na ordem de foco e
   nao promete clique — e um rotulo de posicao ("Primeira aula" / "Ultima
   aula"). Peso normal para nao competir com o lado que e link, mas a cor
   continua sendo texto de verdade: `--texto-suave` passa AA nos dois temas,
   porque a frase INFORMA (por que nao ha destino) e informacao nao pode ficar
   abaixo do piso so por estar inativa. */
.curso_barra_inerte { font-weight: 500; color: var(--texto-suave); }

/* A LEGENDA DO INTERRUPTOR: o estado em texto (WCAG 1.4.1) mais o contador.
   Ela vem logo depois do </form> no documento, e nao no fim do <nav>: assim um
   leitor de tela anuncia o controle e, em seguida, quanto ele vale — em vez de
   atravessar o link "Proxima" no meio. Como <p> nao recebe foco, isso nao muda
   a ordem de tabulacao. */
.curso_barra_pe {
    grid-column: 1; grid-row: 3;
    margin: 0; text-align: center;
    font-size: var(--tipo-2); line-height: 1.5; color: var(--texto-suave);
}
.curso_barra_pe strong { font-family: var(--mono); font-variant-numeric: tabular-nums; color: var(--texto); }
/* `.curso_marcar_estado` e `display: block` na regra dele — dentro da linha ele
   voltaria a ocupar uma linha propria e separaria o contador do estado. */
.curso_barra_pe .curso_marcar_estado { display: inline; font-family: inherit; }

/* O INTERRUPTOR DENTRO DA FAIXA. `.curso_switch` nasceu com `width: 100%`
   porque era a unica acao de um trilho estreito; aqui ele e a coluna do meio e
   precisa medir o proprio conteudo, ou empurra os dois lados para fora. */
.curso_barra .curso_switch { width: auto; }

/* A REFERENCIA DO DONO, a partir de 640px: uma linha, tres colunas.
   A ORDEM DE FOCO CONTINUA CASANDO com a visual — Anterior (coluna 1),
   interruptor (coluna 2), Proxima (coluna 3) e exatamente a ordem do documento,
   da esquerda para a direita. A legenda desce para a segunda linha e nao entra
   na conta porque <p> nao e focavel. */
@media (min-width: 640px) {
    .curso_barra { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); column-gap: var(--esp-4); }
    .curso_barra_lado { grid-row: 1; grid-column: 1; }
    .curso_marcar { grid-row: 1; grid-column: 2; }
    .curso_barra_frente { grid-row: 1; grid-column: 3; }
    .curso_barra_pe { grid-row: 2; grid-column: 1 / -1; }
}

/* O PASSO SEGUINTE DA AULA — o bloco que muda com a qualificacao, e SO ele.

   FORA DO CARTAO, de proposito. Dentro dele o bloco seria a quarta superficie
   da mesma tela e disputaria com a conclusao, que e a acao que a aula pede.
   Aqui ele le como o que e: o que vem DEPOIS de a aula acabar. A superficie e a
   mesma de `.curso_retoma`, que e o bloco de passo seguinte que a lista ja tem.

   A LARGURA VEM DA COLUNA DA AULA, e nao de si mesmo: `.curso_depois` esta no
   grupo de `max-width: min(100%, 46rem)` logo acima, junto com o cartao da aula
   e a navegacao. Sem isso ele media 1080px a 1440px entre um cartao de 736px e
   uma navegacao de 736px, saltando dos dois lados (medido em 21/08/2026).

   EMPILHADO, E NAO EM DUAS COLUNAS COMO A RETOMADA — a diferenca e o numero de
   acoes. A retomada tem duas; esta tem tres, e tres botoes numa coluna `auto` a
   1440px comeram 560px dos 1080 e espremeram o texto em cinco linhas de 43
   caracteres, com o titulo partido ao meio (medido em 21/08/2026, antes desta
   regra). Empilhar devolve a linha de leitura ao paragrafo e poe as tres acoes
   na mesma altura, que e onde se compara uma com a outra.

   SEM BARRA DE ACENTO, e isso e decisao, nao esquecimento. A barra deste
   produto e um PONTEIRO, uma por tela, e nesta tela ela ja aponta: esta no
   titulo da aula (`.curso_aula .conta_cabeca::before`, onda 35). Uma segunda,
   a menos de uma dobra da primeira, deixaria de marcar e viraria textura — a
   licao que o /admin ja pagou com cinco barras por tela. `AssinaturaDoCursoTest`
   conta as barras do curso e falha se esta aqui nascer com uma.

   A TINTA VEM DE `.curso_retoma`, e nao de `.curso_fecho`: os dois blocos usam
   `--painel`, mas o fecho vive DENTRO do cartao de vidro (vidro sobre vidro, e
   ali `--texto-suave` mediu 4,39:1 no tema claro — reprovado). Este vive sobre
   o fundo da pagina, exatamente como a retomada, que e onde a mesma tinta foi
   medida e aprovada. Nao mova este bloco para dentro do cartao sem remedir. */
.curso_depois {
    display: grid; gap: var(--esp-5);
    margin-top: var(--esp-5); padding: clamp(20px, 3.4vw, 28px);
    border-radius: var(--raio-app);
    background: var(--painel);
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
    border: 1px solid var(--borda);
}
.curso_depois_txt { min-width: 0; }
.pagina-app .curso_depois_txt h2 {
    margin: 8px 0 0; font-size: var(--tipo-4); font-weight: 800; letter-spacing: -.02em;
    line-height: 1.25; text-wrap: balance;
}
.pagina-app .curso_depois_txt p {
    margin: var(--esp-3) 0 0; max-width: 58ch;
    font-size: var(--tipo-2); line-height: 1.6; color: var(--texto-suave);
}
/* A 320px cada botao ocupa a largura que precisa e a linha quebra; nas larguras
   maiores os tres cabem lado a lado. `.acoes` ja e flex com wrap no /app. */
.curso_depois .acoes { margin: 0; }

/* O RODAPE DE NAVEGACAO (`.curso_navegar`, `.curso_vizinho`) SAIU NA ONDA 48.
   As duas setas subiram para a faixa sob o video; manter os cartoes no pe
   daria DOIS pares de setas na mesma pagina, que e pior que nenhum. O que se
   perdeu com eles — o TITULO do vizinho — continua na trilha da barra lateral e
   no `.curso_fecho` do topo. Ver `.curso_barra`. */

/* --- a aula virou sala de aula (onda 46) -------------------------------------
   O PALCO DO VIDEO, O INTERRUPTOR DA CONCLUSAO E O CONTADOR DA NAVEGACAO.

   O QUE ESTA ONDA ENCONTROU: uma aula de VIDEO era um titulo, um rotulo
   "VIDEO - 8 MIN" e um botao vermelho que levava o lead para fora do portal. A
   coluna principal ficava VAZIA — 632px de largura por ~900px de altura de
   superficie pintada, medidos a 1440px, com um botao de 40px no topo. A tela
   dizia "aula" e entregava um link.

   O QUE ENTROU: quando o arquivo e NOSSO, ele toca aqui. O player e o Plyr
   3.8.4 vendorizado em public/assets/vendor/plyr/ (MIT; versao, hashes e as
   duas fugas para o cdn.plyr.io estao em VENDOR.txt).

   E DESDE 25/08/2026 A AULA DO YOUTUBE TAMBEM TOCA AQUI, no mesmo palco, por
   um <iframe> do youtube-nocookie.com — `frame-src`, autorizado pelo dono.
   `script-src` continua `self`: o modo YouTube do Plyr, que carregaria o
   `iframe_api` do Google no NOSSO contexto, segue recusado. Por isso o quadro
   do YouTube NAO tem Plyr em volta — ele e o player deles, dentro do nosso
   retangulo.
   ---------------------------------------------------------------------------- */

/* O PALCO. Fundo preto e nao `--superficie`: enquanto o primeiro quadro nao
   chega (e enquanto o `preload="metadata"` so trouxe a duracao), o que se ve e
   este retangulo — e um retangulo CLARO onde vai entrar video pisca branco no
   tema escuro e no claro.

   `aspect-ratio` RESERVA O ESPACO ANTES DO PRIMEIRO BYTE. Sem ele um <video>
   sem metadados mede 300x150 (o padrao do CSS), e a pagina inteira pula quando
   a duracao chega — a mesma razao pela qual a logo do topo leva width/height. */
.curso_palco {
    margin: var(--esp-5) 0 0;
    border-radius: var(--raio-app);
    overflow: hidden;
    background: #000;
    /* O raio precisa de um contexto proprio: o `overflow: hidden` sozinho nao
       corta o <video>, que e conteudo substituido, em todos os navegadores. */
    isolation: isolate;
}
.curso_video {
    display: block; width: 100%; height: auto;
    aspect-ratio: 16 / 9;
    /* `contain` e nao `cover`: um video 4:3 dentro de um palco 16:9 ganha faixas
       pretas nas laterais. `cover` CORTARIA a imagem — e o que se corta num
       video de aula costuma ser exatamente o slide. */
    object-fit: contain;
    background: #000;
}
.curso_video_sem {
    margin: 0; padding: var(--esp-5);
    color: #F2F3F7; font-size: var(--tipo-2); line-height: 1.5;
}
.curso_video_sem a { color: #fff; }
/* O aviso de uso exclusivo (onda 64) e legenda do palco: `miudo` da a voz
   baixa; aqui mora so a distancia — perto o bastante para pertencer ao video,
   longe o bastante para nao parecer controle do player. */
.curso_uso { margin: var(--esp-2) 0 0; }

/* O QUADRO DO YOUTUBE (25/08/2026) — mesmo palco, mesma proporção, sem moldura.

   REUSA `.curso_video` DE PROPÓSITO: `width: 100%`, `height: auto` e
   `aspect-ratio: 16 / 9` são exatamente o que o iframe precisa, e são a razão
   pela qual ele NÃO estoura 320px — a largura vem do contêiner, e a altura sai
   da proporção. Um `<iframe>` sem isso mede 300x150 (o padrão do CSS) e ganha
   `width`/`height` em atributo, que é o clássico do vídeo embutido rolando a
   página para o lado no celular.

   `border: 0` porque o padrão do navegador para `<iframe>` é uma borda de 2px
   `inset` — cinza, ao redor de um retângulo preto, dentro de um cartão com raio.
   Só isso: `object-fit` herdado de `.curso_video` não se aplica a iframe, e não
   atrapalha. */
.curso_moldura { border: 0; }

/* O PLYR NA MARCA — re-tokenizado, nunca copiado com a tinta da vitrine.
   O Plyr expoe a propria paleta em custom properties, entao a marca entra sem
   um seletor sequer sobrescrevendo regra dele. Escopo em `.curso_palco` de
   proposito: nenhum token `--plyr-*` vaza para o resto do portal. */
.curso_palco {
    /* A tinta da marca dentro do player: o botao grande de play, o anel de foco
       e o realce dos controles. `--fss` (e nao `--fss-acao`) porque aqui ele e
       ELEMENTO GRAFICO sobre fundo preto — 3:1 basta, e sobra: #E63946 sobre
       #000 da 4,4:1. */
    --plyr-color-main: var(--fss);

    /* A BARRA DE PROGRESSO NAO PODE SER O VERMELHO DA MARCA, e o numero e que
       decide: medido no pixel renderizado, `--fss` (#E63946) contra o trilho
       vazio do Plyr (rgba(255,255,255,.25) sobre a faixa escura, que compoe
       #404040) da 2,49:1 — abaixo dos 3:1 da WCAG 1.4.11. E nao e defeito que
       nasceu aqui: o padrao do proprio Plyr (#00b3ff no mesmo trilho) mede 2,7.
       O vermelho da marca tem luminancia de MEIO, e meio contra cinza-medio nao
       fecha 3:1 de nenhum lado.
       DUAS SAIDAS, e a segunda e a que se paga. Escurecer o TRILHO ate o
       vermelho se destacar deixa o trilho invisivel contra a faixa preta — a
       pessoa perde a nocao de quanto o video tem. Clarear o PREENCHIMENTO
       resolve os dois de uma vez: 4,1:1 contra o trilho e 8:1 contra o preto.
       E ele continua sendo a marca, e nao uma cor nova: sai de `--fss` por
       `color-mix`, do mesmo jeito que o portal ja clareia o vermelho de texto
       no tema escuro. O player e sempre escuro — video e preto —, entao aqui
       nao ha versao clara para conciliar. */
    --plyr-range-fill-background: color-mix(in srgb, var(--fss) 62%, #fff);
    --plyr-video-background: #000;
    --plyr-font-family: inherit;
    --plyr-font-size-base: 15px;
    --plyr-font-size-small: 13px;
    --plyr-font-size-time: 14px;
    --plyr-font-size-menu: 14px;
    --plyr-control-radius: 10px;
    --plyr-menu-radius: 12px;
    /* Alvo de 24x24 (WCAG 2.5.8) sem contar com o `padding` padrao: 7px de
       respiro em volta de um icone de 18 da 32x32 em cada controle. */
    --plyr-control-icon-size: 18px;
    --plyr-control-spacing: 12px;
    --plyr-range-thumb-height: 14px;
    --plyr-range-track-height: 6px;
    --plyr-tooltip-radius: 8px;
    /* O gradiente padrao do Plyr e mais claro no topo da barra, e o tempo
       corrente cai justamente ali. Escurecer o pe da faixa e o que sustenta o
       branco do relogio em cima de video claro — medido no tema claro e no
       escuro, que aqui dao o mesmo pixel: a faixa nao le token de tema. */
    --plyr-video-controls-background: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, .85));
}
/* O foco do teclado dentro do player usa o MESMO anel do resto do /app, e nao o
   do Plyr: dois desenhos de foco na mesma pagina fazem a pessoa procurar duas
   coisas. (0,2,0) vence o `.plyr__control` (0,1,0) da folha vendorizada. */
.curso_palco .plyr__control:focus-visible,
.curso_palco .plyr__controls button:focus-visible {
    outline: 3px solid var(--fss-acao); outline-offset: 2px;
}

/* MOVIMENTO REDUZIDO: a folha do Plyr NAO tem uma linha de
   `prefers-reduced-motion` (contadas na 3.8.4: 35 `transition` e 3
   `animation`). Nao ha regra nova aqui porque a rede geral la de cima —
   `*, *::before, *::after { animation-duration: .001ms !important; ... }` —
   pega a folha vendorizada tambem, por ser universal e `!important`.

   O QUE ELA NAO PEGA, e por isso vive no JS: COMPORTAMENTO. A barra de
   controles que se esconde sozinha durante a reproducao (`hideControls`) e o
   balao que sobe a cada passagem do ponteiro (`tooltips`) sao opcoes do player,
   nao propriedades de estilo — nenhum seletor os alcanca. `curso-aula.js` le
   `matchMedia('(prefers-reduced-motion: reduce)')` e desliga os dois: quem
   pediu menos movimento fica com a barra SEMPRE visivel, que tambem e o alvo
   que nao foge do ponteiro. */

/* --- o interruptor da conclusao --------------------------------------------
   Ele nomeia a COISA ("Marcar como concluida") e o estado sai do `aria-checked`,
   do trilho e da nota em texto logo abaixo. O rotulo NAO muda com o estado: e a
   gramatica que separa interruptor de botao, e trocar os dois juntos faria o
   leitor de tela anunciar a mesma mudanca duas vezes.

   SEM JAVASCRIPT ELE E O MESMO: `<button type="submit" role="switch">` dentro
   do <form> POST com CSRF. Teclado ativa, o servidor grava, a pagina volta com
   o pino do outro lado. */
.curso_switch {
    display: flex; align-items: center; gap: var(--esp-3);
    width: 100%; min-height: 48px;
    margin: 0; padding: 10px 12px;
    border: 1px solid var(--borda); border-radius: var(--raio-app);
    background: var(--painel-solido); color: var(--texto);
    font: inherit; text-align: left; cursor: pointer;
}
.curso_switch:hover { border-color: var(--borda-marca); }
.curso_switch:focus-visible { outline: 3px solid var(--fss-acao); outline-offset: 3px; }

/* O TRILHO CARREGA O ESTADO EM COR **E** EM POSICAO. So a posicao do pino
   deixaria a mudanca invisivel para quem enxerga pouco; so a cor reprovaria em
   1.4.1. As duas juntas, mais a frase abaixo, dizem a mesma coisa tres vezes em
   tres canais diferentes — que e o piso, nao o exagero. */
/* O TOM DO CONTORNO E DO PINO NO DESLIGADO — um token so, e ele existe porque a
   MEDICAO obrigou. Ver a nota do pino. */
.curso_switch { --switch-traco: color-mix(in srgb, var(--texto) 62%, var(--superficie)); }

.curso_switch_calha {
    flex: 0 0 auto;
    position: relative; display: block;
    width: 44px; height: 26px; border-radius: 999px;
    /* DESLIGADO É CONTORNO, E NÃO PREENCHIMENTO — e a correção veio de medir.
       A primeira versão pintava o trilho apagado de `--texto` a 30% sobre a
       superfície. Lido no pixel renderizado, isso dava 1,98:1 contra o cartão no
       tema claro: abaixo dos 3:1 que a WCAG 1.4.11 pede para o que identifica
       um componente. E não dava para simplesmente escurecer o trilho, porque a
       corrente tem TRÊS elos — cartão / trilho / pino — e apertar um afrouxa o
       outro: qualquer cinza escuro o bastante para se ver sobre o cartão branco
       fica claro demais para o pino escuro aparecer dentro dele.
       A saída é a mesma que o switch do Material usa: o desligado NÃO tem
       preenchimento próprio (fica da cor da superfície) e se identifica pelo
       CONTORNO. Aí só há dois elos, e os dois são o mesmo traço:
       contorno x cartão e pino x interior do trilho medem a mesma distância. */
    background: var(--superficie);
    box-shadow: inset 0 0 0 2px var(--switch-traco);
    transition: background-color var(--dur-micro) var(--curva),
                box-shadow var(--dur-micro) var(--curva);
}
/* O PINO TROCA DE TINTA COM O ESTADO, e nao e enfeite: e o que sustenta os 3:1
   de cada estado contra o que ele encosta (WCAG 1.4.11). Os numeros estao em
   evidencias/w46/medidas-graficas.txt, lidos no PIXEL RENDERIZADO — e as duas
   primeiras versoes desta regra reprovaram ali, o que e a razao de a nota ser
   longa.

     desligado   trilho e o proprio fundo com um traco de contorno; o pino usa
                 o MESMO traco, cheio. Contorno x cartao e pino x interior do
                 trilho sao a mesma distancia, entao ou os dois passam ou os
                 dois falham — nao ha como apertar um e afrouxar o outro;
     ligado      trilho e `--sucesso`, que ja e o OPOSTO de `--superficie` em
                 cada tema por construcao (#0C6046 escuro no claro, #3DDC97
                 claro no escuro) -> o pino volta a `--superficie` e contrasta
                 pelos dois lados de graca, sem mais nenhum ajuste.

   O QUE ISSO CUSTA em leitura: no desligado o pino nao e branco, e sim o tom do
   contorno. Parece menos com um interruptor de iOS e mais com um do Material —
   e e o unico dos dois desenhos que fecha os 3:1 nos quatro casos (dois temas x
   dois estados) sem pintar o cartao de outra cor. */
.curso_switch_pino {
    position: absolute; top: 3px; left: 3px;
    width: 20px; height: 20px; border-radius: 50%;
    background: var(--switch-traco);
    transition: transform var(--dur-micro) var(--curva),
                background-color var(--dur-micro) var(--curva);
}
.curso_switch_on .curso_switch_calha { background: var(--sucesso); box-shadow: none; }
.curso_switch_on .curso_switch_pino { background: var(--superficie); }
.curso_switch_on .curso_switch_pino { transform: translateX(18px); }
.curso_switch_txt { font-size: var(--tipo-2); font-weight: 700; line-height: 1.3; }

/* INDO, E NUNCA "FEITO". Enquanto o POST viaja, o pino para no MEIO do trilho e
   o controle fica `aria-busy`. Ele nao anuncia o resultado — quem anuncia e a
   pagina que volta. Sem JavaScript esta classe nunca aparece, e nada se perde:
   sem ela o clique simplesmente recarrega. */
.curso_switch_indo { pointer-events: none; opacity: .75; }
.curso_switch_indo .curso_switch_pino { transform: translateX(9px); }

.curso_marcar_estado { display: block; color: var(--texto); }

/* --- o nome do modulo na trilha da barra lateral ---------------------------
   So aparece quando o modulo traz MAIS DE UMA aula (a mesma regra de
   /app/curso). Com o catalogo de hoje — 5 modulos de 1 aula — nao desenha nada,
   e e assim que deve ser: o rotulo repetiria o titulo logo abaixo dele. */
.curso_lateral_grupo {
    margin: var(--esp-4) 0 var(--esp-2);
    padding: 0 0 0 var(--esp-6);
    font-size: var(--tipo-1); font-weight: 800; letter-spacing: .16em;
    text-transform: uppercase; color: var(--texto-fraco);
}
.curso_lateral_grupo:first-child { margin-top: 0; }


/* O PLAYER ESTREITO — o que a medicao a 320px mostrou, e o que ela obrigou.
   O Plyr 3.8.4 poe onze controles numa unica linha flex e deixa o `flex-shrink`
   resolver quando nao cabe. Medido a 320px (palco da onda 46): a barra de
   PROGRESSO ficava com 3px de largura e o volume com 107 — o controle mais
   importante do player virava um risco, e o menos importante ficava com um
   terco da barra. Nao e defeito nosso, e nao adianta esperar: a folha do Plyr
   so tem media queries de 480/768/1024 e nenhuma delas mexe nisso.

   O QUE A REGRA FAZ, em ordem de importancia:
     1. o progresso sobe para uma LINHA PROPRIA, de ponta a ponta. E o layout
        que todo player de celular usa, e ele devolve ao arrastar-para-buscar a
        largura inteira;
     2. voltar/avancar 10s e recomecar SAEM. Os tres duplicam o que a barra de
        progresso faz melhor com o dedo, e cada um custava 35px;
     3. o CONTROLE DESLIZANTE de volume sai; o botao de mudo FICA. Volume fino
        em toque e gesto de sistema, nao de pagina — e o mudo, que e o que se
        usa de fato, continua a um toque.

   Nada some para quem tem espaco: acima de 640px a barra e a de sempre. */
@media (max-width: 640px) {
    .curso_palco { --plyr-control-spacing: 8px; }
    .curso_palco .plyr__controls { flex-wrap: wrap; row-gap: 6px; }
    .curso_palco .plyr__progress__container {
        flex: 1 0 100%; min-width: 100%; order: -1; margin-inline: 0;
    }
    .curso_palco .plyr__control[data-plyr="restart"],
    .curso_palco .plyr__control[data-plyr="rewind"],
    .curso_palco .plyr__control[data-plyr="fast-forward"],
    .curso_palco .plyr__volume input[type="range"] { display: none; }
}

/* O bloco de resposta enquanto o servidor recalcula. Só opacidade e cursor —
   nada que mude o TAMANHO, senão a página pula a cada tecla e o campo que está
   sendo digitado sai de baixo do dedo. Os números velhos continuam à vista de
   propósito: apagá-los faria a tela piscar em branco 300ms a cada pausa. */
[data-vivo-alvo].calc_vivo_calculando {
    opacity: .55;
    cursor: progress;
    transition: opacity var(--dur-2, 200ms) var(--curva-suave, ease);
}

@media (prefers-reduced-motion: reduce) {
    [data-vivo-alvo].calc_vivo_calculando { transition: none; }
}

/* --- o funil em uma linha, colado nos campos --------------------------------
   Ele existe porque o bloco completo de resposta fica DEPOIS do formulário, e
   quem está arrastando uma régua não vê nada acontecer: a tela inteira, naquele
   momento, é campo. Uma conta ao vivo fora da vista é indistinguível de conta
   nenhuma. */
.calc_resumo {
    display: flex; flex-wrap: wrap; align-items: center; gap: var(--esp-4) var(--esp-5);
    margin: var(--esp-5) 0 0; padding: var(--esp-4) var(--esp-5);
    border: 1px solid var(--borda); border-radius: var(--raio-app);
    background: var(--painel);
}
.calc_resumo_vazio { justify-content: center; }
.calc_resumo_falta { margin: 0; font-size: var(--tipo-2); color: var(--texto-suave); text-align: center; }
.calc_resumo_falta strong { color: var(--texto); }

/* Os quatro passos na ordem em que o dinheiro anda. `tabular-nums` porque os
   números trocam a cada tecla: sem ele a linha inteira treme enquanto se
   digita, e o olho persegue o movimento em vez de ler o valor. */
.calc_resumo_passos {
    list-style: none; display: flex; flex-wrap: wrap; align-items: baseline;
    gap: var(--esp-3) var(--esp-5); margin: 0; padding: 0;
}
.calc_resumo_passos li { display: flex; align-items: baseline; gap: 6px; }

/* A seta entre os passos é do CSS, e não do HTML: ela é pontuação visual, não
   conteúdo — um leitor de tela lendo "seta" quatro vezes não ganharia nada. */
.calc_resumo_passos li + li::before {
    content: "→"; margin-right: var(--esp-3);
    color: var(--texto-fraco); font-size: var(--tipo-2);
}
.calc_resumo_num {
    font-size: var(--tipo-3); font-weight: 800; color: var(--texto);
    font-variant-numeric: tabular-nums; letter-spacing: -.01em;
}
.calc_resumo_rot { font-size: var(--tipo-1); color: var(--texto-suave); }

/* O faturamento fecha a linha, empurrado para a direita e com a tinta de
   marca: é o número que a pergunta do modelo 2 vem buscar. */
.calc_resumo_dinheiro {
    display: flex; align-items: baseline; gap: 6px; margin: 0 0 0 auto;
    padding-left: var(--esp-5); border-left: 1px solid var(--borda);
}
/* A TINTA DE MARCA, PUXADA 15% NA DIREÇÃO DO TEXTO — medido em 26/08/2026.

   `--fss-texto` puro dava 4,37:1 no tema escuro sobre o vidro do resumo
   (#EC4C58 em #212128), com 17px negrito: abaixo do piso de 4,5:1 e acima do
   corte de "texto grande", que só começa em 18,66px negrito. Passava
   despercebido porque no tema claro o mesmo token dá 7,65:1 — a régua do escuro
   é outra e o defeito só existia lá.

   A correção não inventa cor: mistura os DOIS tokens que já governam a tela, e
   por isso ela anda com o tema sozinha. No escuro o vermelho clareia em direção
   a --texto (5,10:1); no claro ele escurece pelo mesmo caminho (7,84:1). Trocar
   o token de marca continua trocando isto junto, que é o ponto. */
.calc_resumo_dinheiro .calc_resumo_num {
    color: color-mix(in srgb, var(--fss-texto, var(--fss)) 85%, var(--texto));
}

@media (max-width: 720px) {
    /* Em tela estreita o faturamento desce para a própria linha: espremido ao
       lado dos quatro passos, ele quebraria no meio do "R$". */
    .calc_resumo_dinheiro { margin: 0; padding: 0; border-left: 0; }
}

/* --- o modelo 1 em uma linha ------------------------------------------------
   Mesmo componente do resumo do funil, outro conteúdo: lá são quatro passos de
   um caminho, aqui são DUAS MEDIDAS INDEPENDENTES da mesma situação. Por isso
   não há seta entre elas — e, mais importante, não há nem pode haver um total:
   perda atual e potencial futuro não se somam (RF06). O espaço entre os pares é
   o que diz isso ao olho, do mesmo jeito que a seta do funil diz "e então". */
.calc_resumo_cenario { flex-basis: 100%; margin: 0; }
.calc_resumo_par { display: flex; align-items: baseline; gap: 6px; }
.calc_resumo_par + .calc_resumo_par { margin-left: auto; padding-left: var(--esp-5); border-left: 1px solid var(--borda); }
.calc_resumo_par .icone { vertical-align: -.12em; }

/* As duas tintas são as mesmas dos cartões da resposta completa, para o olho
   reencontrar lá embaixo o número que viu aqui em cima. */
.calc_resumo_perda { color: var(--erro); }
.calc_resumo_pot { color: var(--sucesso); }

@media (max-width: 720px) {
    /* Espremidos, os dois pares quebrariam no meio do "R$". Cada um na sua
       linha, e a borda vira separador horizontal. */
    .calc_resumo_par { flex-basis: 100%; }
    .calc_resumo_par + .calc_resumo_par {
        margin-left: 0; padding-left: 0; border-left: 0;
        padding-top: var(--esp-4); border-top: 1px solid var(--borda);
    }
}

/* =====================================================================
   AS DUAS PORTAS — a raiz cadastra, /entrar entra (27/08/2026)
   =====================================================================
   A onda 50 fundiu login e cadastro num cartao so, com o cadastro dobrado num
   <details>; o dono desfez a fusao. As duas telas passam a ter endereco
   proprio e dividem a MOLDURA (cena, painel de marca, grade, cartao), nao o
   formulario — ver `themes/portal/acesso.php`.

   O QUE MORREU AQUI, E POR QUE NAO VOLTA POR ENGANO

   `.acesso_criar` (o <details>, o <summary>-controle, o sinal de "+", o corpo
   da dobra) e `.autenticar_atalho` (a ancora "Criar conta gratis ↓" que so
   aparecia abaixo de 900px). As duas eram RESPOSTAS A FUSAO, e nao decisoes de
   estilo:

     - a dobra existia porque eram 2 campos de um lado e 7 do outro no mesmo
       cartao, e abertos juntos o primeiro terco da tela virava uma parede de
       nove campos;
     - a ancora existia porque, a 320px, o <summary> caia em y=807 — quase uma
       dobra e meia abaixo — e quem vinha criar conta atravessava um formulario
       de login inteiro que nao podia usar.

   Sem a fusao, as duas causas deixaram de existir no mesmo minuto. Quem
   reintroduzir qualquer uma delas esta reintroduzindo a tela dupla junto.

   O QUE SOBREVIVEU, E ISSO NAO E NOSTALGIA: o resumo de erros (WCAG 3.3.1), o
   "(opcional)" dentro do rotulo, `--borda-controle` nos campos, o painel de
   marca no celular e o <h1> como promessa na raiz. Cada um foi conserto
   medido; separar as telas nao os revoga.

   O FUNDO PERDEU AS FORMAS, E O ARGUMENTO E DE FORMULARIO. `_cena` desenha,
   por padrao, dois quadrados girados de 46vmax e 30vmax com borda de 1,5px.
   Numa tela de leitura eles dao profundidade; numa tela de FORMULARIO eles
   cruzam o campo de trabalho, e uma reta continua de 1,5px atras de um cartao
   e lida pelo olho como fronteira de alguma coisa — afordancia falsa, do lado
   de fora de todos os controles reais. A decisao esta no TEMPLATE
   (`insert('_cena', ['formas' => []])`) e nao aqui, porque quais formas
   desenhar sempre foi parametro do parcial; os dois campos radiais e o ruido
   ficam, e a profundidade vem deles. Nao ha `display: none` nenhum: o que nao
   e desenhado nao chega ao documento.
   ===================================================================== */

/* O RESUMO DE ERROS (WCAG 3.3.1) — indice, nao substituto.

   A mensagem por campo continua sendo a fonte da verdade; este bloco existe
   por causa da ALTURA: no 422 do cadastro a pagina passa de 2.500px a 320px e
   ate seis campos podem falhar juntos. Sem indice, "o que deu errado" so se
   descobre rolando.

   Nao usa `role="alert"`: ele nasce junto com o documento, e regiao viva so
   anuncia o que MUDA depois da carga. Quem anuncia e o `autofocus` — que vem
   NELE, e nao no primeiro campo errado: medido a 320x568, com o foco no campo
   a pagina parava em y=974 e o resumo, em y=944, ficava 30px acima da area
   visivel. */
.acesso_falhas {
    margin: 0 0 var(--esp-4); padding: var(--esp-3) var(--esp-4);
    border: 1px solid var(--erro); border-left-width: 3px;
    border-radius: var(--raio-p);
    background: color-mix(in srgb, var(--erro) 8%, var(--superficie));
    font-size: var(--tipo-1);
}
.acesso_falhas h3 { margin: 0 0 var(--esp-2); color: var(--texto); font-size: var(--tipo-2); font-weight: 800; letter-spacing: -.01em; }
/* Destino de foco, e nao parada de Tab (tabindex="-1"): o anel precisa ser
   visivel quando o 422 aterrissa aqui, ou o salto acontece sem sinal nenhum. */
.acesso_falhas:focus-visible { outline: 2px solid var(--texto); outline-offset: 2px; }
.acesso_falhas ul { margin: 0; padding-left: 1.15em; display: grid; gap: 4px; }
.acesso_falhas li { color: var(--texto-suave); }

/* Sublinhado aqui e informacao, nao enfeite: cada item e um atalho que MOVE O
   FOCO para o campo (ancora para <input> faz isso sozinha, sem JavaScript).
   Sem o sublinhado, uma lista de erros clicaveis pareceria texto morto. */
.autenticar .acesso_falhas a:not(.btn):not(.btn_sec) {
    color: var(--texto); font-weight: 600;
    text-decoration: underline; text-underline-offset: .2em;
    text-decoration-thickness: 1px; text-decoration-color: var(--erro);
}
.autenticar .acesso_falhas a:not(.btn):not(.btn_sec):hover { color: var(--fss-texto); }

/* "(opcional)" tem de ser lido junto com o rotulo — e por isso vive DENTRO do
   <label>, e nao numa dica ao lado. Ele nao pode ter o peso do rotulo: o que
   nomeia o campo e "Telefone", nao a ressalva. */
.campo_opcional { font-weight: 400; color: var(--texto-suave); }

/* ---------------------------------------------------------------------------
   O CAMINHO PARA A OUTRA PORTA — discreto, e um so.

   `.autenticar_pe` ja era o rodape de cartao que as outras tres telas de auth
   usam para mandar a pessoa ao lugar certo quando ela caiu no lugar errado.
   Reusar e o que impede um quarto dialeto de "saida secundaria" no produto.

   O QUE ELE NAO PODE VIRAR: um `.btn_sec` de largura inteira. A escada de
   botoes deste portal e solido > vazado > sem caixa, com UM primario por
   regiao da tela — um secundario aqui embaixo teria o mesmo alvo e quase o
   mesmo peso do envio, e devolveria em outra forma a tela de duas portas que
   o dono acabou de desfazer.

   O que ele ganha nas portas: alvo de 44px (WCAG 2.5.8) e o peso de link de
   acao, porque aqui ele nao e uma nota de rodape — e o unico caminho ate a
   outra metade do produto. */
.pagina-acesso .autenticar_pe {
    display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
    column-gap: 6px;
}
.pagina-acesso .autenticar_pe a:not(.btn):not(.btn_sec) {
    display: inline-flex; align-items: center; min-height: 44px;
    font-weight: 700; color: var(--fss-texto);
}

/* ---------------------------------------------------------------------------
   MINIMALISMO MEDIDO: UM DEGRAU DE APOIO, E NAO DOIS.

   Medido em `evidencias/w52` antes desta onda: a tela de acesso usava 6
   tamanhos de tipo a 1440 (13, 15, 16, 17, 22, 27) e 5 a 320 — com 13 e 15
   fazendo o MESMO trabalho (texto de apoio) em lugares diferentes do mesmo
   cartao, e um 13px literal que nem vinha da escala (`--tipo-0`, que nao
   existe, com fallback `.8125rem` — ver a regra de `.autenticar_form .dica`).

   A regra abaixo colapsa o apoio DO CARTAO num degrau so, `--tipo-1`. O painel
   de marca fica em `--tipo-2` de proposito: ele e o outro lado da grade, com
   outra funcao (apresentar, nao instruir), e igualar os dois apagaria a unica
   hierarquia que a tela tem entre "o que e isto" e "o que digitar".

   O que NAO muda: 16px do campo e do botao (nunca abaixo disso num controle
   de toque) e o titulo do cartao. */
.pagina-acesso .autenticar_painel > .sub,
.pagina-acesso .autenticar_form label,
.pagina-acesso .autenticar_form .check,
.pagina-acesso .autenticar_form .dica,
.pagina-acesso .autenticar_esqueci,
.pagina-acesso .autenticar_pe,
.pagina-acesso .acesso_falhas { font-size: var(--tipo-1); }

/* ---------------------------------------------------------------------------
   MOTION — quatro movimentos, e os quatro CONFIRMAM alguma coisa.

   Numa tela de formulario o movimento util e o que responde a uma acao (foco,
   erro, envio, saida); animacao de entrada e decoracao, e decoracao numa porta
   de conversao custa atencao que a pessoa ia gastar lendo o rotulo do campo.
   Por isso esta onda ACRESCENTOU pouco e nao mexeu no relogio: as duracoes
   saem de `--dur-micro` e `--dur-hover`, as curvas de `--curva`/`--curva-suave`.

   TODA ANIMACAO TEM CONTRAPARTE, e nenhuma informacao existe so no movimento:

     1. CHEGADA DO CARTAO (`.autenticar_painel`, 420ms, herdada da onda
        anterior) — ja nasce dentro de `prefers-reduced-motion: no-preference`.
        Contraparte: o cartao aparece pronto, no estado final.
     2. FOCO DE CAMPO (`transition` de `border-color`/`box-shadow`, --dur-micro,
        herdada) — contraparte: o anel de foco e a borda mudam de cor na hora.
        O sinal e a COR e a espessura, nunca a transicao.
     3. O 422 CHEGANDO (`.acesso_falhas`, abaixo) — contraparte: a caixa
        vermelha, o titulo "Faltam corrigir N campos" e o foco que salta para
        ela continuam identicos sem uma unica animacao.
     4. O ENVIO SENDO APERTADO (`:active`, abaixo) — contraparte: o proprio
        `:hover`/`:active` troca a cor de fundo do botao, que e o sinal que
        sobra quando o deslocamento e congelado.

   A regra global de `prefers-reduced-motion: reduce` (linha ~1252) zera
   duracao de animacao e de transicao no documento inteiro; o bloco abaixo esta
   em `no-preference` para que o DESLOCAMENTO sequer seja declarado — congelar
   um `translateY` a 0,001ms funciona, mas declarar movimento que nunca deve
   acontecer e pedir para alguem "otimizar" o !important um dia. */
@media (prefers-reduced-motion: no-preference) {
    /* 3. O resumo de erros e a unica coisa da tela que nao estava la antes do
       envio. Ele APARECE, e nao entra deslizando: `translateY` num elemento
       que recebe `autofocus` briga com a rolagem que o proprio foco provoca —
       o navegador calcula o destino durante a animacao e pode parar no lugar
       errado. Opacidade nao mexe no layout. */
    .pagina-acesso .acesso_falhas { animation: acesso_falha 260ms var(--curva-suave) both; }
    @keyframes acesso_falha { from { opacity: 0; } to { opacity: 1; } }

    /* 4. O botao afunda 1px enquanto o dedo (ou o Enter) esta nele. E o unico
       retorno tatil possivel num envio sincrono de <form>: nao ha JavaScript
       no caminho, e a proxima coisa que acontece e o navegador trocar de
       pagina. Sem ele, o intervalo entre apertar e a tela mudar nao tem sinal
       nenhum — e e nesse intervalo que a pessoa aperta de novo. */
    .pagina-acesso .autenticar_form .btn:active { transform: translateY(1px); }
    .pagina-acesso .autenticar_form .btn { transition: background-color var(--dur-micro) var(--curva), transform var(--dur-micro) var(--curva); }
}

/* ============================================================================
   O SELO E A FESTA — a leitura qualitativa do resultado (RF10)
   ============================================================================

   O SELO É A PALAVRA, e a cor só a acompanha (WCAG 1.4.1). Tirada a cor, ele
   continua dizendo "Bom" ou "Excelente" — que é o teste que a gramática de
   estado do resto do arquivo já passa (`.calc_degrau`, `.gate_ok`, `.msg`).
   Mesmos tokens, de propósito: --erro / --alerta / --sucesso, na mesma ordem de
   leitura. Verde escuro no claro, verde claro no escuro, os dois medidos.

   "Bom" e "Excelente" dividem o verde porque dividem o julgamento — o que os
   separa é a palavra e o peso do anel, não um quinto matiz inventado para a
   ocasião. */
.calc_selo {
    display: inline-flex; align-items: center;
    margin-top: var(--esp-2);
    padding: 3px 10px;
    border: 1px solid currentColor;
    border-radius: 999px;
    font-size: var(--tipo-1);
    font-weight: 700;
    letter-spacing: .01em;
    line-height: 1.4;
    color: var(--texto-suave);
    background: color-mix(in srgb, currentColor 10%, transparent);
}
.calc_selo_ruim { color: var(--erro); }
.calc_selo_regular { color: var(--alerta); }
.calc_selo_bom { color: var(--sucesso); }
.calc_selo_excelente {
    color: var(--sucesso);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--sucesso) 20%, transparent);
}

/* O AVISO DA FESTA É A FESTA, sob movimento reduzido.

   A comemoração carrega uma informação — "seu cenário chegou ao topo" — e
   informação não pode depender de movimento. Este parágrafo aparece nos DOIS
   casos, com o mesmo texto e no mesmo lugar; o que o `prefers-reduced-motion`
   tira são as partículas e a transição de entrada. O portador permanente
   continua sendo o selo, que fica no cartão do ROAS depois que tudo passa.

   `role="status"` (posto pelo script) faz o leitor de tela anunciar sem roubar
   o foco de quem está arrastando a régua. */
.calc_festa_aviso {
    position: fixed;
    left: 50%; bottom: var(--esp-5);
    z-index: 90;
    margin: 0;
    max-width: min(420px, calc(100vw - 2 * var(--esp-4)));
    padding: var(--esp-3) var(--esp-5);
    border: 1px solid var(--sucesso);
    border-radius: 999px;
    background: var(--superficie-alta, var(--superficie));
    box-shadow: var(--elev-2);
    color: var(--texto);
    font-size: var(--tipo-2);
    font-weight: 700;
    text-align: center;
    /* Nasce fora da vista SEM `display:none` e sem `visibility`: os dois
       tirariam o texto da árvore de acessibilidade junto, e é ele quem carrega
       o recado. `opacity: 0` com `pointer-events: none` some para o olho e
       continua existindo para o leitor. */
    opacity: 0;
    pointer-events: none;
    transform: translateX(-50%) translateY(var(--esp-3));
    transition: opacity var(--dur-hover) var(--curva-suave),
                transform var(--dur-hover) var(--curva-suave);
}
.calc_festa_aviso_visivel { opacity: 1; transform: translateX(-50%) translateY(0); }

/* Confete: 18 retângulos caindo. `position: fixed` cobrindo a tela inteira,
   `pointer-events: none` para não engolir o clique de ninguém, e
   `overflow: hidden` para que a queda não crie rolagem lateral a 320px — que é
   como este efeito estragaria a página em vez de enfeitá-la. */
.calc_festa {
    position: fixed; inset: 0;
    z-index: 89;
    overflow: hidden;
    pointer-events: none;
}
.calc_festa_p {
    position: absolute;
    top: -14px;
    left: var(--x, 50%);
    width: 7px; height: 12px;
    border-radius: 2px;
    background: var(--cor, var(--fss-acao));
    /* Só `transform` e `opacity`: as duas propriedades que o compositor anima
       sem relayout, e a diferença entre 60fps e a página engasgando enquanto a
       pessoa arrasta a régua. */
    animation: calc_cai var(--dur, 1.4s) var(--atraso, 0ms) cubic-bezier(.35, .1, .5, 1) both;
    will-change: transform, opacity;
}

@keyframes calc_cai {
    0%   { transform: translate3d(0, 0, 0) rotate(0deg); opacity: 1; }
    85%  { opacity: 1; }
    100% { transform: translate3d(var(--dx, 0), 104vh, 0) rotate(var(--giro, 180deg)); opacity: 0; }
}

/* SOB MOVIMENTO REDUZIDO O SCRIPT NEM CRIA AS PARTÍCULAS — esta regra é a
   segunda tranca, para o caso de o palco existir por outro caminho (uma festa
   já em voo quando a preferência muda). O aviso continua aparecendo, agora sem
   deslizar: ele é a informação, e informação não se desliga. */
@media (prefers-reduced-motion: reduce) {
    .calc_festa { display: none; }
    .calc_festa_p { animation: none; }
    .calc_festa_aviso { transition: none; transform: translateX(-50%); }
    .calc_festa_aviso_visivel { transform: translateX(-50%); }
}

/* =====================================================================
   ANALISE DE CALL (RF12)
   =====================================================================
   A tela existe para uma pessoa ler a propria nota — e nota de desempenho
   e o tipo de numero que machuca. O desenho todo trabalha para ela ser
   lida com contexto, e nao como veredito solto. */

/* A REGRA DE OURO EM DESTAQUE, e nao em nota de rodape. Quem tira 4 numa
   call que FECHOU precisa saber que a nota mede processo ANTES de abrir o
   relatorio — senao a primeira leitura e "isso esta quebrado" e a segunda
   nao acontece. */
.calls_regra {
    display: flex; align-items: flex-start; gap: 10px;
    margin: var(--esp-5) 0 0; padding: var(--esp-4) var(--esp-5);
    border-left: 3px solid var(--fss-acao); border-radius: var(--raio-p);
    background: var(--preenchimento);
    font-size: var(--tipo-2); line-height: 1.55; color: var(--texto-suave);
    max-width: 68ch;
}
.calls_regra strong { color: var(--texto); }
.calls_regra .icone { flex: none; margin-top: 3px; color: var(--fss-texto); }

/* A caixa de transcricao e o objeto principal do formulario: ela precisa
   caber uma call inteira sem virar um poco de rolagem de tres linhas. */
.calls_caixa {
    width: 100%; min-height: 260px; resize: vertical;
    padding: 14px; border: 1px solid var(--borda-controle);
    border-radius: 10px; background: var(--campo-fundo, var(--fundo));
    color: var(--texto); font: inherit; line-height: 1.5;
    /* Monoespacada: transcricao com MM:SS no comeco da linha so fica
       legivel se os timestamps alinharem em coluna. */
    font-family: var(--mono); font-size: var(--tipo-1);
}
.calls_caixa:focus-visible { outline: 2px solid var(--texto); outline-offset: 2px; }

/* --- o historico --- */
.calls_lista { list-style: none; margin: 0; padding: 0; }
.calls_item + .calls_item { border-top: 1px solid var(--borda); }
.calls_alvo {
    display: flex; align-items: center; justify-content: space-between; gap: var(--esp-5);
    padding: var(--esp-4) var(--esp-3); border-radius: var(--raio-app);
    color: inherit; text-decoration: none;
}
.calls_item:hover .calls_alvo { background: var(--preenchimento); }
.calls_alvo:focus-visible { outline: 3px solid var(--fss-acao); outline-offset: -3px; }
.calls_corpo { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.calls_quando { font-size: var(--tipo-2); }
.calls_estado {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: var(--tipo-1); color: var(--texto-suave);
}
.calls_estado .icone { width: 14px; height: 14px; }

/* A nota no historico e grande porque e o unico dado que a pessoa procura
   quando volta a esta lista. */
.calls_nota {
    flex: none; font-size: var(--tipo-4); font-weight: 800;
    font-variant-numeric: tabular-nums; letter-spacing: -.02em;
}

/* --- o relatorio --- */

/* O DESFECHO FICA LONGE DA NOTA, e a distancia e o argumento: a rubrica
   proibe que um influencie o outro, e junta-los num bloco so convidaria a
   leitura de que a nota "explica" a venda. */
.calls_desfecho {
    display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
    margin: var(--esp-5) 0 0; padding-top: var(--esp-4);
    border-top: 1px solid var(--borda);
    font-size: var(--tipo-2);
}
.calls_desfecho .caps { color: var(--texto-fraco); }

.calls_etapa { padding: var(--esp-5); margin-bottom: var(--esp-4); }
.calls_etapa_topo {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: var(--esp-4); margin-bottom: var(--esp-3);
}
.calls_etapa_nota {
    font-size: var(--tipo-4); font-weight: 800;
    font-variant-numeric: tabular-nums; letter-spacing: -.02em;
}

/* O tempo ao lado do teto ideal: sem a referencia, "18:45" nao diz nada
   sobre a penalidade que a nota levou. Vermelho SO quando estourou — e a
   cor nao carrega sozinha, o numero do teto esta ali do lado (WCAG 1.4.1). */
.calls_tempo {
    display: inline-flex; align-items: center; gap: 7px;
    margin: 0 0 var(--esp-3); font-size: var(--tipo-1); color: var(--texto-suave);
    font-variant-numeric: tabular-nums;
}
.calls_tempo .icone { width: 14px; height: 14px; }
.calls_tempo_estourou { color: var(--erro); }

/* OS TRES BLOCOS ABAIXO SAO ANINHADOS POR CAUSA DE `.tile p` (0,1,1) — e aqui
   o defeito e ANTERIOR a lista de pilares: a entrelinha declarada em
   `.calls_justificativa` e `.calls_faltou` nunca valeu, desde que a tela
   nasceu. Ninguem viu porque `.tile p` tambem e --tipo-2 e tambem e cinza: a
   regra derrotada tinha toda a aparencia de estar aplicada. */

/* O paragrafo cru — o caso em que o texto do modelo NAO foi reconhecido como
   lista. Ele E o conteudo da etapa, entao le-se em --texto, como a evidencia. */
.calls_etapa .calls_justificativa {
    margin: 0;
    font-size: var(--tipo-2);
    line-height: 1.6;
    color: var(--texto);
}

/* O preambulo e CONTEXTO — carimbo de tempo, nota estrutural —, e nao o
   julgamento. Dividia classe com o paragrafo cru, o que obrigava os dois ao
   mesmo peso; separar deixa cada um dizer o seu tamanho. */
.calls_etapa .calls_preambulo {
    margin: 0 0 var(--esp-3);
    font-size: var(--tipo-1);
    line-height: 1.55;
    color: var(--texto-suave);
}
/* --- os pilares dentro da justificativa ----------------------------------
   A justificativa nao e um paragrafo: e a lista de pilares que a rubrica manda
   o modelo escrever (`qa-auditor-v1.txt`, "REGRA CRITICA DE FORMATO"). Ate aqui
   ela chegava emendada em prosa corrida — ate quinze julgamentos em mil
   caracteres, sem uma borda onde o olho pudesse parar. Era esse o defeito de
   leitura, e nao o corpo da fonte.

   A COLUNA DA ESQUERDA E QUEM CARREGA A VARREDURA. Todo pilar comeca no mesmo
   x, entao "quantas falhas houve nesta etapa" se responde descendo a coluna,
   sem ler uma palavra. */
.calls_pilares {
    margin: var(--esp-4) 0 0;
    padding: 0;
    list-style: none;
    display: grid;
    gap: 6px;
}

/* SUPERFICIE PROPRIA, e nao uma tinta sobre o cartao.

   A primeira versao usava `var(--texto) 3%` — pilar acinzentado dentro de
   cartao acinzentado dentro de pagina acinzentada. Medido, o contraste passava
   em AA (5,33:1 no claro, 7,42:1 no escuro): a norma nunca foi o problema. O
   problema era nao haver DEGRAU entre as camadas, e degrau e o que diz ao olho
   onde um item acaba e o proximo comeca.

   `--superficie` e branco no claro e #151520 no escuro — o mesmo token que
   todo cartao do portal usa. Com ele o texto passa a ser lido sobre fundo
   limpo, que era o pedido, e a lista deixa de depender so do espaco vazio para
   se separar. */
.calls_pilar {
    position: relative;
    padding: var(--esp-3) var(--esp-4) var(--esp-3) calc(var(--esp-4) + 8px);
    border-radius: var(--raio-p);
    background: var(--superficie);
    border: 1px solid var(--borda);
    box-shadow: var(--elev-1);
}

/* A FAIXA E O SELO DIZEM A MESMA COISA, DE PROPOSITO. Cor sozinha nao informa
   (WCAG 1.4.1) e a faixa some na impressao em preto e branco; o selo escrito
   sobrevive aos dois casos. */
.calls_pilar::before {
    content: "";
    position: absolute;
    inset: -1px auto -1px -1px;
    width: 3px;
    border-radius: var(--raio-p) 0 0 var(--raio-p);
    background: var(--borda);
}

.calls_pilar_falha::before   { background: var(--erro); }
.calls_pilar_parcial::before { background: var(--alerta); }
.calls_pilar_ok::before      { background: var(--sucesso); }

/* Os tres paragrafos abaixo sao aninhados no pai DE PROPOSITO, e nao por
   estilo: `.tile p` vale (0,1,1) e derrubava os tres a (0,1,0) — cor, margem,
   corpo e entrelinha, tudo. Nada acusava, porque `.tile p` tambem e cinza e
   tambem e --tipo-2: a regra perdida parecia aplicada. Aninhar sobe para
   (0,2,0) sem `!important` e sem inventar classe nova. */
.calls_pilar .calls_pilar_topo {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0 0 4px;
}

.calls_pilar_nome {
    font-size: var(--tipo-2);
    font-weight: 650;
    letter-spacing: -.01em;
    color: var(--texto);
}

.calls_pilar_selo {
    font-size: var(--tipo-1);
    font-weight: 600;
    letter-spacing: .02em;
    text-transform: lowercase;
    padding: 1px 7px;
    border-radius: 999px;
    border: 1px solid currentColor;
    color: var(--texto-fraco);
}

.calls_pilar_falha   .calls_pilar_selo { color: var(--erro); }
.calls_pilar_parcial .calls_pilar_selo { color: var(--alerta); }
.calls_pilar_ok      .calls_pilar_selo { color: var(--sucesso); }

/* O placar fica a direita, tabular, para as fracoes alinharem entre si —
   `0/3` sobre `0/6` sobre `2/5` se comparam de relance quando a barra cai
   sempre na mesma coluna. */
.calls_pilar_placar {
    margin-left: auto;
    font-size: var(--tipo-1);
    font-variant-numeric: tabular-nums;
    color: var(--texto-fraco);
}

/* `situacional` explica por que um "nao se aplica" ali e resultado esperado, e
   nao lacuna da auditoria. Sem essa palavra, tres N/A seguidos parecem analise
   que desistiu. */
.calls_pilar_situacional {
    font-size: var(--tipo-1);
    color: var(--texto-fraco);
    font-style: italic;
}

/* A EVIDENCIA E O CONTEUDO, e nao legenda dele. Ela estava em
   `--texto-suave`, o tom reservado a texto de apoio — e o que o cinza dizia,
   sem querer, era "isto aqui e detalhe". E o julgamento inteiro da etapa: o
   nome do pilar so nomeia, o selo so classifica, e quem sustenta as duas
   coisas e este paragrafo. Ele sobe para `--texto`. */
.calls_pilar .calls_pilar_ev {
    margin: 0;
    font-size: var(--tipo-2);
    line-height: 1.6;
    color: var(--texto);
    text-wrap: pretty;
}

/* A FALA DO VENDEDOR E A CADEIA DE CUSTODIA: e o unico trecho da linha que
   pode ser conferido contra a gravacao. Corrida no meio da prosa, lia-se igual
   ao julgamento que ela sustenta — o que e exatamente a confusao a evitar num
   documento de auditoria. */
/* Sobre fundo branco a faixa tinta virou ruido: com a evidencia ja em
   `--texto`, o italico e as aspas curvas sozinhos separam a fala do
   julgamento. A cor fica para o que precisa dela — o selo e a faixa de
   estado. */
.calls_fala {
    color: var(--texto);
    font-style: italic;
    font-weight: 500;
    quotes: "\201C" "\201D";
    background: color-mix(in srgb, var(--fss) 7%, transparent);
    border-radius: 3px;
    padding: 0 2px;
    box-decoration-break: clone;
    -webkit-box-decoration-break: clone;
}

/* A cauda de tempo fala da ETAPA inteira, e nao do ultimo pilar da lista —
   por isso sai da lista e ganha regua acima. */
.calls_etapa .calls_timeboxing {
    display: flex;
    align-items: baseline;
    gap: 8px;
    flex-wrap: wrap;
    margin: var(--esp-4) 0 0;
    padding-top: var(--esp-3);
    border-top: 1px solid var(--borda);
    font-size: var(--tipo-1);
    line-height: 1.55;
    color: var(--texto-suave);
}
.calls_timeboxing .icone { width: 14px; height: 14px; flex: none; }
.calls_timeboxing .caps { color: var(--texto-fraco); flex: none; }

/* O CONSELHO E O QUE A PESSOA VAI FAZER AMANHA. Com os pilares agora em preto
   sobre branco, este bloco tinha virado a coisa mais apagada do cartao — a
   hierarquia passou a dizer que a unica parte acionavel valia menos que o
   diagnostico que a motiva. */
.calls_etapa .calls_faltou {
    margin: var(--esp-4) 0 0; padding: var(--esp-4);
    border-radius: var(--raio-p); background: var(--preenchimento);
    font-size: var(--tipo-2); line-height: 1.55; color: var(--texto);
}
.calls_faltou .caps { display: block; margin-bottom: 4px; color: var(--fss-texto); }

.calls_resumos { display: grid; gap: var(--esp-4); grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.calls_resumo { padding: var(--esp-5); }
.calls_resumo .caps { display: flex; align-items: center; gap: 7px; margin-bottom: var(--esp-3); }
.calls_resumo ul { margin: 0; padding-left: 1.1em; font-size: var(--tipo-2); line-height: 1.6; }
.calls_resumo li + li { margin-top: 6px; }

@media (max-width: 560px) {
    .calls_alvo { flex-direction: column; align-items: flex-start; gap: 8px; }
    .calls_etapa_topo { flex-direction: column; gap: 4px; }
}

/* --- envio de audio de call (RF12) ---------------------------------------
   O bloco nasce `hidden` no HTML e so aparece quando o script liga: o PUT
   direto no bucket nao existe sem JavaScript. A caixa de transcricao ao
   lado continua fazendo o mesmo trabalho sem uma linha de script. */
.calls_envio[hidden] { display: none; }

/* A BARRA E O UNICO SINAL DE VIDA de um envio de cem megabytes, que acontece
   FORA da pagina. Sem ela a tela fica parada por minutos — indistinguivel de
   travada, e a pessoa recarrega no meio do upload. */
.calls_progresso { margin: var(--esp-4) 0 0; }
.calls_barra {
    height: 8px; border-radius: 999px; overflow: hidden;
    background: var(--preenchimento);
}
.calls_barra i {
    display: block; height: 100%; width: 0;
    background: var(--fss-acao); border-radius: inherit;
    transition: width var(--dur-hover, 260ms) var(--curva-suave, ease);
}
@media (prefers-reduced-motion: reduce) { .calls_barra i { transition: none; } }
.calls_progresso .miudo { margin: 8px 0 0; font-variant-numeric: tabular-nums; }

/* O campo de arquivo do navegador e feio e nao se estiliza por dentro; o que
   da para fazer e a moldura em volta ficar com a mesma linguagem dos outros
   campos, para ele nao parecer de outra pagina. */
.calls_envio input[type="file"] {
    width: 100%; padding: 12px 14px;
    border: 1px dashed var(--borda-controle); border-radius: 10px;
    background: var(--campo-fundo, var(--fundo)); color: var(--texto);
    font: inherit; font-size: var(--tipo-1);
}
.calls_envio input[type="file"]:focus-visible { outline: 2px solid var(--texto); outline-offset: 2px; }

/* -----------------------------------------------------------------------------
   Apagar uma analise de call (secao 18.3 — exclusao antecipada)

   FICA RECOLHIDO NUM <details> de proposito. Ninguem abre o relatorio para
   apagar; quem chega aqui vem ler. Um botao destrutivo sempre visivel, perto de
   conteudo que se rola, e um botao que se clica sem querer.
   -------------------------------------------------------------------------- */
.calls_apagar { margin-top: var(--esp-5); border-top: 1px solid var(--borda); padding-top: var(--esp-4); }

.calls_apagar > summary {
    cursor: pointer;
    width: fit-content;
    font-size: var(--tipo-1);
    color: var(--texto-suave);
}

.calls_apagar > summary:hover { color: var(--texto); }

/* O foco precisa aparecer: `summary` e o unico controle desta area no teclado. */
.calls_apagar > summary:focus-visible { outline: 2px solid var(--fss-acao); outline-offset: 3px; border-radius: 6px; }

.calls_apagar > .miudo { margin: var(--esp-3) 0; max-width: 62ch; }

.calls_apagar_form { display: flex; align-items: center; gap: var(--esp-3); flex-wrap: wrap; }

/* A cota, acima do formulario de envio. */
.calls_cota_nota { display: block; margin-top: 4px; font-size: var(--tipo-1); opacity: .85; }

/* =============================================================================
   A ESPERA DA ANALISE DE CALL (28/08/2026)

   O QUE ISTO CONSERTA. A tela ficava parada dizendo "Auditando a sua call" por
   dois ou tres minutos, sem um pixel se mexendo — e nao havia como distinguir
   "processando" de "travado". Com o worker fora do ar, a mesma frase ficava
   horas na tela.

   A ANIMACAO AQUI NAO E ENFEITE, E SINAL DE VIDA. Ela responde a uma pergunta
   que a pessoa esta realmente fazendo ("ainda esta rodando?"), e por isso o que
   se move e a fase CORRENTE — nao uma barra que avanca sozinha e chegaria a 90%
   com o processamento morto.

   TUDO SOB `prefers-reduced-motion`. Sem movimento, o passo corrente continua
   distinguivel por COR e por PESO, e nao so por animacao: quem desliga o
   movimento nao pode perder a informacao junto.
   ========================================================================== */

.calls_espera { display: grid; gap: var(--esp-4); }

.calls_espera_topo { display: flex; align-items: center; gap: var(--esp-4); flex-wrap: wrap; }

/* O simbolo menor que na espera do diagnostico: ali ele e o assunto da tela,
   aqui divide espaco com a trilha. */
.calls_espera .carregando3d { --c3d: 72px; flex: none; }

/* --- a trilha das fases -------------------------------------------------- */

.calls_trilha {
    display: flex;
    flex-wrap: wrap;
    gap: var(--esp-3) var(--esp-5);
    margin: 0;
    padding: 0;
    list-style: none;
}

.calls_passo {
    display: flex;
    align-items: center;
    gap: 9px;
    font-size: var(--tipo-1);
    color: var(--texto-suave);
    /* A troca de fase nao pisca: o passo muda de estado suavemente. */
    transition: color .35s ease;
}

.calls_passo_marca {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--borda);
    flex: none;
    transition: background .35s ease, box-shadow .35s ease;
}

/* Cumprido: marca cheia, texto normal. */
.calls_passo[data-estado="feito"] { color: var(--texto); }
.calls_passo[data-estado="feito"] .calls_passo_marca { background: var(--sucesso); }

/* CORRENTE: e o unico que se move. Cor e peso carregam a informacao sozinhos
   quando o movimento esta desligado. */
.calls_passo[data-estado="agora"] { color: var(--texto); font-weight: 600; }
.calls_passo[data-estado="agora"] .calls_passo_marca { background: var(--fss-acao); }

@media (prefers-reduced-motion: no-preference) {
    .calls_passo[data-estado="agora"] .calls_passo_marca {
        animation: calls_pulso 1.8s ease-in-out infinite;
    }
}

/*
 * O halo cresce e some, em vez de a marca mudar de tamanho: animar `box-shadow`
 * nao reflui o layout, e a linha do texto nao dança junto a cada batida.
 */
@keyframes calls_pulso {
    0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--fss-acao) 55%, transparent); }
    50%      { box-shadow: 0 0 0 7px color-mix(in srgb, var(--fss-acao) 0%, transparent); }
}

/* --- os avisos de demora -------------------------------------------------- */

.calls_espera_demora { color: var(--texto-suave); }

/*
 * NO LIMITE, O SIMBOLO PARA DE SER O ASSUNTO. Ele continua girando — o polling
 * continua vivo e a analise realmente pode sair —, mas desacelera e esmaece,
 * porque a essa altura quem manda na tela e o aviso, e nao o indicador.
 * Mesmo tratamento da espera do diagnostico.
 */
.calls_espera[data-fase="limite"] .carregando3d { opacity: .45; }

@media (prefers-reduced-motion: no-preference) {
    .calls_espera[data-fase="limite"] .carregando3d_simbolo { animation-duration: 4.5s; }
}

/* =============================================================================
   O RELATORIO DE CALL NO PAPEL (28/08/2026)

   "Baixar em PDF" nao gera PDF no servidor: prepara a FOLHA e deixa o navegador
   gerar. A escolha e deliberada e vale registrar o porque.

   Uma biblioteca de PDF em PHP (dompdf, mpdf) seria uma dependencia nova, com
   motor de CSS proprio e incompleto — o layout teria de ser reescrito num
   dialeto reduzido, e divergiria da tela na primeira mudanca. O navegador ja
   tem o melhor renderizador disponivel, ja conhece as fontes desta pagina e ja
   sabe paginar. O que faltava era alguem dizer a ele o que e conteudo e o que e
   navegacao.

   O CUSTO, dito em voz alta: sai um dialogo de impressao, e nao um arquivo
   baixado direto. Em troca, zero dependencia e uma folha que nao envelhece
   separada da tela.
   ========================================================================== */

/* Blocos que existem SO no papel — invisiveis na tela, em ambos os temas. */
.so_papel { display: none; }

@media print {
    /* ---------------------------------------------------------------------
       A folha e branca. O portal tem tema escuro, e imprimir fundo escuro
       gasta tinta, borra o texto e sai ilegivel em impressora comum.
       `color-adjust` impede o navegador de "ajudar" reimpondo cores.
       --------------------------------------------------------------------- */
    :root, :root[data-tema="escuro"] {
        --fundo: #fff;
        --superficie: #fff;
        --superficie-alta: #fff;
        --texto: #000;
        --texto-suave: #333;
        --borda: rgba(0, 0, 0, .25);
    }

    html, body {
        background: #fff !important;
        color: #000 !important;
        print-color-adjust: exact;
        -webkit-print-color-adjust: exact;
    }

    @page {
        size: A4;
        margin: 16mm 14mm;
    }

    /* ---------------------------------------------------------------------
       O QUE NAO E O RELATORIO SAI DA FOLHA: navegacao, rodape do site, o
       proprio botao de baixar, e a area de apagar a analise — imprimir um
       controle destrutivo e, na melhor hipotese, ruido.
       --------------------------------------------------------------------- */
    header.topo, .nav, .nav_cta, .rodape, .voltar,
    .calls_baixar, .calls_apagar, .calls_espera,
    [data-tema-alternar], noscript {
        display: none !important;
    }

    .so_papel { display: block; }

    .so_papel_marca { margin: 0; font-size: 11pt; }
    .so_papel_meta { margin: 2mm 0 6mm; font-size: 9pt; color: #333; }

    .so_papel_rodape {
        margin-top: 8mm;
        padding-top: 3mm;
        border-top: 1px solid rgba(0, 0, 0, .25);
        font-size: 8.5pt;
        color: #333;
    }

    /* Sem sombra, sem vidro, sem gradiente: no papel isso vira mancha cinza. */
    .tile, .tile_vidro, .rel_capa, .pnl_capa_solo, .calls_etapa, .calls_resumo {
        box-shadow: none !important;
        background: #fff !important;
        border: 1px solid rgba(0, 0, 0, .2) !important;
        backdrop-filter: none !important;
    }

    .wrap { max-width: none; padding: 0; }

    /* A nota e o assunto da primeira folha. */
    #titulo_rel { font-size: 26pt; margin: 0 0 3mm; }

    /* ---------------------------------------------------------------------
       PAGINACAO: uma etapa nao se parte ao meio.

       Cortar um cartao entre a nota e a justificativa produz meia pagina de
       numero sem explicacao — que e exatamente o pedaco que alguem levaria
       fora de contexto.
       --------------------------------------------------------------------- */
    /*
     * MEDIDO ANTES DE DECIDIR: os cartoes de etapa tem de 172 a 381 mm, e a
     * area util de um A4 e ~265 mm. O maior deles NAO CABE em pagina nenhuma.
     *
     * Com `break-inside: avoid` neles, o navegador tentava nao parti-los,
     * desistia, e deixava a folha anterior pela metade — oito paginas com
     * buracos. Deixa-los FLUIR gasta o mesmo papel sem os vazios.
     *
     * O que nao pode partir e o CABECALHO da etapa: nota e duracao separadas da
     * justificativa viram meia pagina de numero sem explicacao, que e
     * exatamente o pedaco que alguem levaria fora de contexto.
     */
    .calls_etapa_topo { break-after: avoid; page-break-after: avoid; }

    /* Aninhados como na base: `@media` NAO soma especificidade, entao a regra
       (0,2,0) la de cima venceria uma (0,1,0) daqui — e o ajuste de impressao
       seria descartado sem aviso. */
    .calls_etapa .calls_justificativa,
    .calls_etapa .calls_preambulo,
    .calls_etapa .calls_faltou,
    .calls_pilar .calls_pilar_ev { orphans: 3; widows: 3; }

    /* UM PILAR NAO SE PARTE ENTRE PAGINAS: o nome numa folha e o veredito na
       seguinte e pior no papel que na tela, porque no papel nao da para rolar
       de volta. A faixa colorida some na impressao em preto e branco — quem
       carrega o estado ali e o selo escrito, que continua legivel. */
    .calls_pilar { break-inside: avoid; page-break-inside: avoid; }
    .calls_pilar::before { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
    .calls_timeboxing { break-inside: avoid; page-break-inside: avoid; }

    /* Estes cabem: 95 a 246 mm. Aqui `avoid` funciona. */
    .calls_resumo, .calls_desfecho, .rel_capa {
        break-inside: avoid;
        page-break-inside: avoid;
    }

    .secao_head { break-after: avoid; page-break-after: avoid; }

    /* Nenhuma animacao no papel — e nada que dependa de estado de foco. */
    *, *::before, *::after {
        animation: none !important;
        transition: none !important;
    }

    /* O link nao clica no papel; sublinhado sem destino so polui. */
    a { text-decoration: none; color: inherit; }

    /* ---------------------------------------------------------------------
       DENSIDADE DE PAPEL.

       O espaçamento da tela e generoso de proposito — ali a rolagem e de graca.
       No papel cada milimetro custa folha: a primeira versao saiu com OITO
       paginas e metade da primeira em branco, porque um cartao de etapa nao
       cabia no que sobrava e pulava inteiro.

       Compactar nao e so estetica. Um relatorio de oito paginas para cinco
       etapas nao e lido; e arquivado.
       --------------------------------------------------------------------- */
    body { font-size: 10pt; line-height: 1.42; }

    .wrap > * + * { margin-top: 5mm; }

    .secao, .calls_resumos { display: block; margin-top: 5mm; }

    .tile, .rel_capa, .calls_etapa, .calls_resumo {
        padding: 4mm 5mm !important;
        margin: 0 0 3mm !important;
        border-radius: 3px !important;
    }

    .secao_head { margin: 0 0 3mm; }
    .secao_head h2, .conta_cabeca h2 { font-size: 13pt; margin: 0; }

    .calls_etapa_topo { margin-bottom: 2mm; }
    .calls_etapa .calls_justificativa,
    .calls_etapa .calls_faltou { margin: 2mm 0 0; }
    .calls_etapa .calls_preambulo { margin: 0 0 1.5mm; }
    .calls_pilares { margin: 2mm 0 0; gap: 0; }
    .calls_pilar {
        padding: 1.5mm 2mm 1.5mm 3mm;
        background: none;
        box-shadow: none;
        border: none;
        border-radius: 0;
    }
    /* A FAIXA FICA, e a borda sai. No papel a moldura completa gasta tinta e
       nao informa; a faixa colorida e o unico canal visual do estado que
       sobrevive a impressao — e por isso ela mantem `print-color-adjust`. */
    .calls_pilar::before { inset: 0 auto 0 0; border-radius: 0; }
    .calls_timeboxing { margin: 2mm 0 0; padding-top: 1mm; }

    .calls_resumo ul { margin: 2mm 0 0; padding-left: 5mm; }
    .calls_resumo li { margin: 0 0 1mm; }

    .caps { font-size: 8pt; letter-spacing: .04em; }
    .miudo, .nota_fina { font-size: 8.5pt; }

    /* As tres listas de resumo lado a lado economizam uma folha inteira. */
    .calls_resumos { columns: 2; column-gap: 6mm; }
    .calls_resumo { break-inside: avoid; }
}

/* O botao de baixar, na tela. */
.calls_baixar { display: flex; align-items: center; gap: var(--esp-3); flex-wrap: wrap; margin-top: var(--esp-4); }

/* -----------------------------------------------------------------------------
   O historico de analises de call (31/08/2026)

   MEDIDO ANTES DE MEXER: duas linhas liam "31/08/2026 15:21 · Pronta · 3.5/10",
   identicas fora o numero — e o numero era o mesmo nas duas. Havia 807px de
   vazio entre o texto e a nota, e ZERO px entre a lista e o paragrafo abaixo,
   o que fazia o realce de hover encostar no texto seguinte.

   O conserto nao e decorativo: a linha passa a carregar o que DISTINGUE uma
   call da outra — de quem era, e por onde entrou.
   -------------------------------------------------------------------------- */

.calls_cabeca { display: flex; align-items: baseline; gap: var(--esp-3); flex-wrap: wrap; }

/* A origem e contexto, nao titulo: mesma linha da data, peso menor. */
.calls_origem { font-size: var(--tipo-1); color: var(--texto-suave); }

/*
 * O RESUMO OCUPA O VAO QUE EXISTIA.
 *
 * `max-width` em medida de leitura porque isto e PROSA — sem ela, numa tela
 * larga a frase atravessaria 900px e viraria uma linha unica dificil de varrer.
 * Duas linhas no maximo: a terceira ja e o relatorio, e para isso existe o
 * clique.
 */
.calls_resumo_linha {
    max-width: 68ch;
    font-size: var(--tipo-1);
    color: var(--texto-suave);
    /*
     * O corte de verdade e no servidor (160 caracteres, ver calls.php); isto e
     * so a rede para o caso de uma frase sem espacos esticar a linha.
     */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/*
 * A NOTA ALINHA COM A DATA, e nao com o centro do bloco.
 *
 * Centralizada contra um corpo de tres linhas, ela flutuava no meio do vao e
 * nao parecia pertencer a nenhuma linha. No topo, ela compartilha a linha de
 * base com a data — e as duas juntas sao o par que a pessoa compara ao varrer
 * o historico.
 */
.calls_alvo { align-items: flex-start; }
.calls_nota { margin-top: -2px; }

/* A lista para de encostar no aviso que vem depois. */
.calls_lista { margin-bottom: var(--esp-4); }

/* -----------------------------------------------------------------------------
   SEM SCRIPT, COLAR VOLTA A SER A ACAO PRIMARIA (31/08/2026).

   Com JavaScript, o envio da gravacao e a porta principal e a caixa de
   transcricao e a alternativa — dai o botao secundario. Sem script a secao de
   envio nem aparece, e a transcricao passa a ser a UNICA acao da tela.

   Um botao secundario sozinho numa pagina nao e hierarquia: e um formulario que
   parece desativado. `js-audio` so entra no corpo quando o envio foi revelado,
   entao a ausencia dela e exatamente a condicao "colar e tudo que ha".
   -------------------------------------------------------------------------- */
body:not(.js-audio) .calls_colar_acao {
    background: var(--fss-acao);
    border-color: var(--fss-acao);
    color: #fff;
}

body:not(.js-audio) .calls_colar_acao:hover { background: var(--fss-acao-hover); }

/* =============================================================================
   A ZONA DE ENVIO DA GRAVACAO (31/08/2026)

   O campo era o `<input type="file">` cru: "Escolher arquivo | Nenhum arquivo
   escolhido", com a fonte e o botao do sistema operacional. Num cartao que tem
   tipografia, raio e espacamento proprios, ele lia como um pedaco de outra
   pagina — e, pior, nao dizia o que aceita nem que da para arrastar.

   O INPUT NAO FOI SUBSTITUIDO, so escondido de vista. Ele continua sendo quem
   guarda o arquivo, quem valida `accept` e quem responde ao teclado.
   ========================================================================== */

/*
 * `.campo .campo_arquivo` E NAO `.campo_arquivo` — colisao de cascata medida.
 *
 * `.campo label { display: block }` (0,1,1) vence uma classe sozinha (0,1,0), e
 * a zona saia empilhada: glifo em cima, texto embaixo. O seletor descendente
 * (0,2,0) resolve, e os `font-weight`/`margin` herdados do rotulo tambem
 * precisam ser desfeitos — senao a zona inteira sai em negrito.
 */
.campo .campo_arquivo {
    display: flex;
    font-weight: 400;
    margin-bottom: 0;
    align-items: center;
    gap: var(--esp-4);
    padding: var(--esp-5);
    border: 1.5px dashed var(--borda);
    border-radius: var(--raio);
    background: var(--superficie);
    cursor: pointer;
    position: relative;
    transition: border-color .18s ease, background .18s ease;
}

.campo .campo_arquivo:hover { border-color: var(--fss-acao); }

/*
 * ESCONDIDO DA VISTA, NUNCA DO TECLADO.
 *
 * `display: none` e o atributo `hidden` tirariam o input da ordem de tabulacao:
 * quem navega por teclado perderia a unica forma de escolher um arquivo. Com
 * `opacity: 0` ele continua focavel, e o `:focus-visible` abaixo desenha o anel
 * na ZONA, que e o que a pessoa enxerga.
 */
.campo_arquivo_real {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
}

.campo .campo_arquivo:has(.campo_arquivo_real:focus-visible) {
    outline: 3px solid var(--fss-acao);
    outline-offset: 2px;
}

.campo_arquivo_glifo {
    display: grid;
    place-items: center;
    flex: none;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: var(--preenchimento);
    color: var(--texto-suave);
}

.campo_arquivo_glifo .icone { width: 20px; height: 20px; }

.campo_arquivo_texto { display: flex; flex-direction: column; gap: 2px; min-width: 0; }

.campo_arquivo_titulo { font-size: var(--tipo-2); }

/* O nome do arquivo pode ser longo; a zona nao pode crescer por causa disso. */
.campo_arquivo_titulo { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.campo_arquivo_sub { font-size: var(--tipo-1); color: var(--texto-suave); }

/* Arrastando por cima: a zona confirma que vai aceitar a soltura. */
.campo .campo_arquivo[data-arrastando] {
    border-color: var(--fss-acao);
    border-style: solid;
    background: var(--preenchimento);
}

/* Com arquivo escolhido, a zona vira confirmacao — e o glifo, um sinal de ok. */
.campo .campo_arquivo[data-escolhido] { border-style: solid; border-color: var(--sucesso); }
.campo_arquivo[data-escolhido] .campo_arquivo_glifo { color: var(--sucesso); }

/* --- mapa de objecoes (RF13) — /app/objecoes ---------------------------------
   REUSO, E NAO VOCABULARIO NOVO. `.tile_vidro` + `.conta_cabeca` vem de
   /app/configuracoes, `.calls_lista`/`.calls_item` vem do historico de calls
   (mesma forma: linha clicavel com estado), `.campo`/`.dica`/`.field-error` vem
   do formulario do portal. As classes abaixo so ARRANJAM o que ja existe.

   O que e proprio daqui e a hierarquia da leitura. Esta tela entrega quatro
   coisas de peso muito diferente, e trata-las como quatro cartoes iguais faria
   a mais importante desaparecer no meio. A ordem visual contraria a ordem do
   JSON de proposito: as PERGUNTAS vem antes das hipoteses, porque sao elas que
   mudam o resultado — quem abre a tela quer a frase pronta, e o desenho tem de
   levar o olho para o que serve. */

.obj_opcionais { display: grid; gap: var(--esp-4); }
@media (min-width: 640px) { .obj_opcionais { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.obj_opcionais select { min-height: 48px; }

/* O contexto recolhido: conferivel, nunca no caminho. */
.obj_contexto { margin-top: var(--esp-5); }
.obj_contexto > summary {
    cursor: pointer; width: fit-content;
    font-size: var(--tipo-1); font-weight: 600; color: var(--texto-suave);
}
.obj_contexto > summary:focus-visible { outline: 2px solid var(--fss-acao); outline-offset: 3px; border-radius: var(--raio-p); }
.obj_dados { display: grid; gap: var(--esp-3); margin: var(--esp-4) 0 0; }
@media (min-width: 720px) { .obj_dados { grid-template-columns: max-content minmax(0, 1fr); align-items: baseline; } }
.obj_dados dt { font-size: var(--tipo-1); font-weight: 600; color: var(--texto-fraco); }
.obj_dados dd { margin: 0; font-size: var(--tipo-2); line-height: 1.55; color: var(--texto-suave); }

.obj_bloco { margin-top: var(--esp-5); }
.obj_texto { margin: var(--esp-4) 0 0; max-width: 68ch; font-size: var(--tipo-3); line-height: 1.6; color: var(--texto); }

/* Tipo e confianca sao METADADOS: informam sem competir com o texto. */
.obj_selos { display: flex; flex-wrap: wrap; gap: var(--esp-2); margin: var(--esp-4) 0 0; }
.obj_selo {
    display: inline-flex; align-items: center; padding: 4px 10px;
    border: 1px solid var(--borda); border-radius: 999px;
    font-size: var(--tipo-1); font-weight: 600; letter-spacing: .02em; color: var(--texto-suave);
}
.obj_selo_ok { border-color: var(--sucesso); color: var(--sucesso); }
.obj_selo_alerta { border-color: var(--alerta); color: var(--alerta); }

/* AS PERGUNTAS SAO O PRODUTO. Numeradas porque sao uma sequencia de verdade —
   investigar fora de ordem custa a resposta —, e com a razao de cada uma logo
   abaixo: perguntar sem saber o que se procura devolve conversa, nao sinal. */
.obj_perguntas { display: grid; gap: var(--esp-4); margin: var(--esp-5) 0 0; padding-left: 1.4em; }
.obj_perguntas > li { max-width: 68ch; }
.obj_perguntas > li::marker { font-variant-numeric: tabular-nums; color: var(--fss-acao); font-weight: 700; }
.obj_perguntas strong { display: block; font-size: var(--tipo-3); line-height: 1.45; color: var(--texto); }
.obj_porque { display: block; margin-top: 4px; font-size: var(--tipo-1); line-height: 1.5; color: var(--texto-fraco); }

/* Hipotese e sinal andam em par: uma hipotese sem como reconhece-la e palpite. */
.obj_hipoteses { display: grid; gap: var(--esp-4); margin: var(--esp-5) 0 0; padding: 0; list-style: none; }
.obj_hipoteses > li {
    max-width: 68ch; padding-left: var(--esp-4);
    border-left: 3px solid var(--borda);
}
.obj_hipoteses strong { display: block; font-size: var(--tipo-2); line-height: 1.5; color: var(--texto); }
.obj_sinal { display: block; margin-top: 6px; font-size: var(--tipo-1); line-height: 1.5; color: var(--texto-suave); }
.obj_sinal .caps { margin-right: 6px; color: var(--texto-fraco); }

.obj_passos { display: grid; gap: var(--esp-3); margin: var(--esp-4) 0 0; padding-left: 1.4em; max-width: 68ch; }
.obj_passos > li { font-size: var(--tipo-2); line-height: 1.55; color: var(--texto-suave); }

/* A FALA DE EXEMPLO PARECE CITACAO, e nao campo de copiar — a forma tambem diz
   que aquilo e exemplo. O aviso vai na legenda, colado: longe dele, nao e lido
   por quem esta copiando. */
.obj_fala { margin: var(--esp-5) 0 0; }
.obj_fala blockquote {
    margin: 0; padding: var(--esp-4) var(--esp-5);
    border-left: 3px solid var(--fss-acao); border-radius: 0 var(--raio-p) var(--raio-p) 0;
    background: var(--painel-solido);
    font-size: var(--tipo-3); line-height: 1.6; color: var(--texto);
}
.obj_fala figcaption {
    display: flex; align-items: flex-start; gap: var(--esp-2);
    margin-top: var(--esp-3); max-width: 62ch;
    font-size: var(--tipo-1); line-height: 1.5; color: var(--texto-fraco);
}
.obj_fala figcaption .icone { flex: none; margin-top: 2px; }

/* Cuidados sao o unico bloco em tom de aviso: eles dizem o que PIORA. */
.obj_lista_cuidado { display: grid; gap: var(--esp-3); margin: var(--esp-4) 0 0; padding: 0; list-style: none; }
.obj_lista_cuidado > li {
    display: flex; align-items: flex-start; gap: var(--esp-2);
    max-width: 68ch; font-size: var(--tipo-2); line-height: 1.55; color: var(--texto-suave);
}
.obj_lista_cuidado .icone { flex: none; margin-top: 3px; color: var(--alerta); }

.obj_lacuna { margin-top: var(--esp-5); }

.obj_fontes { margin-top: var(--esp-6); }
.obj_lista_fonte { display: grid; gap: var(--esp-2); margin: var(--esp-4) 0 0; padding: 0; list-style: none; }
.obj_lista_fonte > li { font-size: var(--tipo-1); line-height: 1.5; color: var(--texto-fraco); }
.obj_lista_fonte > li::before { content: "— "; color: var(--borda); }

/* `objection_type` NAO E ENUM (decisao O2: a base FSS ainda nao definiu a
   lista), entao o valor pode chegar como rotulo curto — "Custo de troca" — ou
   como frase inteira, e a primeira chamada real devolveu cada um numa vez. Um
   selo de largura livre com frase dentro empurraria a linha para fora; aqui ele
   quebra em duas linhas e para de crescer. Feio e legivel ganha de bonito e
   quebrado. */
.obj_selo { max-width: min(46ch, 100%); text-align: left; }

/* A caixa de texto do mapa de objecoes.
   -----------------------------------------------------------------------------
   CLASSE PROPRIA, E NAO `.campo textarea` — ESPECIFICIDADE (01/09/2026).

   Ate aqui nao havia regra NENHUMA para textarea dentro de `.campo`: os quatro
   campos caiam no padrao do navegador (`cols=20`), e a caixa para 2.000
   caracteres de contexto comercial saia com 185px de largura. Medido em
   Chromium — o controle mais importante da tela era o menor dela.

   O reflexo seria escrever `.campo textarea`. Isso tem especificidade (0,1,1) e
   venceria `.calls_caixa` (0,1,0), que tambem vive dentro de um `.campo`: a
   transcricao de call perderia a fonte monoespacada, e com ela o alinhamento em
   coluna dos timestamps MM:SS, que e a unica razao daquela regra existir.

   Mesma armadilha que ja custou o empilhamento da zona de arrastar arquivo, em
   que `.campo label` (0,1,1) venceu `.campo_arquivo` (0,1,0). */
.obj_caixa {
    width: 100%; resize: vertical;
    padding: 12px 14px; border: 1px solid var(--borda-controle);
    border-radius: 10px; background: var(--campo-fundo, var(--fundo));
    color: var(--texto); font: inherit; font-size: var(--tipo-2); line-height: 1.55;
    /* Nunca monoespacada: e texto corrido escrito a mao, nao transcricao com
       timestamp em coluna (que e o caso de `.calls_caixa`).

       O TETO DE LARGURA SAIU DAQUI e vive em `--obj-medida`, no bloco do
       formulario. Deixar um `max-width` tambem nesta regra criaria duas
       declaracoes concorrendo, com a de fora vencendo por especificidade
       (0,2,0 contra 0,1,0) — a armadilha que ja custou a este projeto o
       empilhamento da zona de arrastar arquivo e o peso da pilula do header.
       Quem for mexer na medida mexe num lugar. */
}
.obj_caixa:focus-visible { outline: 2px solid var(--texto); outline-offset: 2px; }
.obj_caixa[aria-invalid="true"] { border-color: var(--erro); }

/* --- espera do mapa de objecoes ---------------------------------------------
   REUSO: `.calls_espera`, `.calls_trilha` e `.calls_passo` vem da espera da
   call, e o simbolo 3D e o mesmo de la e do diagnostico. O que muda aqui e so
   o que e proprio desta tela. */

/* A saida em fade quando o mapa chega. O app.js poe `.esp_saindo` no elemento
   que carrega `data-aguardando`, e a regra existente esta presa a `.rel_espera`
   — sem esta linha, a chegada seria um reload seco no meio da animacao. */
@media (prefers-reduced-motion: no-preference) {
    .obj_espera.esp_saindo { animation: esp_sai var(--dur-saida) var(--curva-suave) var(--dur-celebra) both; }
}

/* "O que vem" e informacao de apoio: precisa ser legivel e nao competir com a
   frase de estado, que e quem responde "esta andando?". */
.obj_espera_promessa { max-width: 62ch; line-height: 1.55; }

/* O TITULO DA PAGINA DO MAPA E UMA CITACAO, e citacao longa em tipo display
   vira parede. O campo aceita mil caracteres; o corte no servidor ja limita a
   150, e aqui o tamanho cede mais um degrau em relacao ao titulo de relatorio —
   o que identifica a pagina e a objecao, nao o tamanho da letra. */
.obj_titulo { font-size: clamp(1.5rem, 1.1rem + 1.6vw, 2.1rem); line-height: 1.25; max-width: 24ch; }
@media (min-width: 720px) { .obj_titulo { max-width: 34ch; } }

/* `hidden` PRECISA VENCER O `display` DECLARADO — dentro desta secao (01/09/2026).
   -----------------------------------------------------------------------------
   O atributo `hidden` do HTML e implementado pelo navegador como
   `[hidden] { display: none }`, especificidade (0,1,0). `.calc_acoes` declara
   `display: flex` com a MESMA especificidade — e a folha do autor vem depois da
   do navegador, entao ela vence e o elemento aparece.

   Medido: os botoes "Recarregar" e "Todas as consultas", que so deveriam existir
   na fase `limite`, apareciam ja no primeiro segundo da espera — oferecendo uma
   saida de emergencia para quem nao tinha problema nenhum.

   Escopado a `.calls_espera` de proposito. Um `[hidden] { display: none
   !important }` global consertaria isto e mais uma dezena de casos que ninguem
   auditou; a especificidade (0,2,0) daqui basta para o motor de fases, que e
   quem liga e desliga `hidden` nesta tela. O projeto ja resolve assim em
   `.tema_alterna[hidden]` e `.campo_senha .revelar[hidden]`. */
.calls_espera [hidden] { display: none; }

/* A MEDIDA DOS CAMPOS E UMA SO, E MORA NUM LUGAR (01/09/2026).
   -----------------------------------------------------------------------------
   As caixas de texto tinham teto de leitura e a grade dos dois seletores nao
   tinha nenhum: media a 1280, as caixas terminavam em x=777 e os seletores em
   x=1145 — 368px de diferenca, com as bordas direitas dos campos do MESMO
   formulario desalinhadas. O dono viu antes de mim.

   O ALINHAMENTO SE FAZ PELA LARGURA DO CARTAO, POR DECISAO DO DONO.

   Eu tinha resolvido para o outro lado — encolhi os seletores ate a medida de
   leitura das caixas — com o argumento de que uma linha longa demais perde a
   volta (a regra dos ~65-75 caracteres). O dono pediu o oposto e reafirmou:
   alargar as caixas.

   O argumento dele vence o meu no caso concreto, e vale registrar por que. Estes
   campos nao sao para LER: sao para COLAR. "A objecao, com as palavras dela"
   pede o trecho literal de uma conversa, e o contexto da venda vem quase sempre
   de outro lugar. A regra da medida de leitura protege quem le paragrafos
   corridos da esquerda para a direita, muitas linhas seguidas — nao quem cola
   quatro linhas e confere. Uma caixa estreita, aqui, so obriga a rolar dentro
   dela para conferir o que colou.

   O token continua porque o defeito original foi as duas coisas terem medidas
   separadas. Com um lugar so, o proximo campo daqui nasce alinhado. */
.obj_form { --obj-medida: 100%; }
.obj_form .obj_caixa,
.obj_form .obj_opcionais { max-width: var(--obj-medida); }

/* O RODAPE DO CARTAO CONTINUA NA LARGURA DO CARTAO, de proposito: o fio de
   `.calc_acoes` separa o que se preenche do que se aciona, e um separador que
   para no meio da caixa nao separa nada. */

/* =============================================================================
   BOAS-VINDAS DO /app (onda 85) — o modal da primeira chegada
   -----------------------------------------------------------------------------
   QUEM O ABRE, E QUANDO. O servidor decide a elegibilidade (`$boasVindas` em
   dashboard.php: nunca abriu o diagnostico) e o `app.js` decide a dispensa
   (localStorage). Aqui so moram a superficie e a entrada.

   MESMA FAMILIA DO MODAL DE SAIDA (`.saida`, mais acima): tinta escura, fio
   --fss no topo, pilula vermelha como acao. Um terceiro dialeto de modal
   quebraria o sistema que as ondas anteriores fecharam — e a mesma razao pela
   qual `.saida` nao inventou o seu.

   O QUE MUDA EM RELACAO A `.saida`, e por que:

   1. A SUPERFICIE NAO E O `<dialog>`, e sim `.bv_caixa` dentro dele. O
      `<dialog>` fica transparente e sem padding, carregando so a PERSPECTIVA.
      Isto nao e preferencia: `perspective` nao se aplica ao proprio elemento
      transformado, e o dialogo aberto por `showModal()` esta na top layer, sem
      ancestral do documento onde declarar a perspectiva. Sem essa separacao o
      `rotateX` da entrada achata num giro 2D — a mesma armadilha documentada em
      `comum/carregando3d.css`.

   2. A ENTRADA E EM PROFUNDIDADE, e nao um deslocamento de 8px. Foi o pedido do
      dono ("modal animado, com efeitos 3D"), e o teto tecnico e a CSP:
      `script-src 'self'` (PortalController.php) so admitiria three.js
      VENDORIZADO, e uma engine WebGL no primeiro contato e peso exatamente onde
      ele custa mais caro. CSS 3D entrega relevo real, custa zero requisicao e
      degrada sozinho.

   CONTRASTE. A caixa e opaca (`--escuro-fundo`, #10121E solido), entao a marca
   d'agua da cena e o desfoque do backdrop ficam ATRAS dela e nao entram na
   composicao do texto — medido no pixel renderizado, o fundo sob o texto e
   exatamente rgb(16,18,30). Os tokens da ilha escura sao reapontados como em
   `.tile_ink`: a cor herdada de fora chega ja COMPUTADA, entao trocar so as
   variaveis deixaria um <h2> sem regra propria escuro sobre fundo escuro.
   ============================================================================= */
.bv {
    /* Container: sem superficie propria. A perspectiva PRECISA morar aqui,
       porque quem gira e o filho. 1100px e uma camera "longa": profundidade
       visivel sem a distorcao de grande-angular que torce as bordas do cartao. */
    perspective: 1100px;
    width: min(520px, 92vw);
    max-height: 92dvh;
    padding: 0;
    border: 0;
    background: transparent;
    overflow: visible;
}
.bv::backdrop {
    /* color-mix nao vale em ::backdrop (fora da arvore); valor literal, o mesmo
       que `.saida` usa. */
    background: rgba(6, 7, 12, .74);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
}

/* A CAIXA NAO ROLA, E ISSO E DECISAO (02/09/2026).

   A primeira versao declarava rolagem vertical aqui, como rede de seguranca.
   `RegiaoRolavelTest` reprovou, e tem razao: uma caixa que rola vira PARADA DE
   TABULACAO no Chrome e no Firefox, e uma parada sem nome acessivel e sem anel
   de foco no meio de um modal de dois botoes e pior do que o problema que ela
   resolvia — ainda mais porque, medido, a caixa nunca rola (scrollHeight ==
   clientHeight a 320, 375, 740x360 e 1440).

   O caso que a rede cobria era janela BAIXA (celular deitado). Ele se resolve
   tirando o adorno, e nao acrescentando rolagem: ver o @media (max-height) que
   acompanha o palco, mais abaixo.

   E esta nota mora FORA da chave de proposito: o detector daquele teste le o
   CORPO da regra e nao distingue codigo de comentario. Escrita la dentro, a
   propria explicacao do conserto reprovava o conserto — a mesma armadilha que
   `CapaDoPainelTest` ja documenta. */
.bv_caixa {
    position: relative;
    padding: clamp(24px, 4vw, 40px);
    border: 1px solid color-mix(in srgb, var(--escuro-texto) 20%, transparent);
    border-top: 3px solid var(--fss);
    /* `--raio-l` nao existe em :root: o valor efetivo e o fallback, 24px. Esta
       linha e copia literal de `.saida` de proposito — os dois modais do portal
       tem de ter o mesmo raio, e no dia em que o token nascer os dois mudam
       juntos. Trocar por --raio-app (16px) aqui separaria os dois em silencio. */
    border-radius: var(--raio-l, 24px);
    background: var(--escuro-fundo);
    box-shadow: 0 30px 80px rgba(0, 0, 0, .6);
    text-align: center;
    /* Ilha escura: os mesmos reapontamentos de `.tile_ink`. */
    color-scheme: dark;
    color: var(--escuro-texto);
    --texto: var(--escuro-texto);
    --texto-suave: var(--escuro-suave);
    --texto-fraco: var(--escuro-suave);
    --fss-texto: var(--escuro-acento);
    --borda: var(--escuro-borda);
}

/* O form existe so para o formmethod=dialog; nao pode ocupar espaco. */
.bv_fechar_form { display: contents; }
.bv_fechar {
    /* z-index: A SAIDA PINTA ACIMA DE TUDO, E RECEBE O PONTEIRO.
       Medido em 02/09/2026: sem esta linha (e sem o `pointer-events: none` do
       palco), o Chromium entregava o clique do X para `.bv_pilha` — decoracao
       posicionada, mais abaixo no DOM, com z-index auto. Quem usasse mouse nao
       conseguia fechar o modal; quem usasse teclado, sim. Ver
       evidencias/w85/04-defeito-palco-comia-o-x.txt. */
    z-index: 2;
    position: absolute; top: 8px; right: 8px;
    display: inline-flex; align-items: center; justify-content: center;
    /* 44px de alvo (WCAG 2.5.8) mesmo com o icone de 20px. */
    width: 44px; height: 44px;
    border: 0; border-radius: 50%; cursor: pointer;
    background: transparent; color: var(--escuro-suave);
    transition: background var(--dur-micro) linear, color var(--dur-micro) linear;
}
.bv_fechar:hover { background: color-mix(in srgb, var(--escuro-texto) 10%, transparent); color: var(--escuro-texto); }

/* --- o palco 3D -------------------------------------------------------------
   Tres placas em profundidade, a da frente acesa: a trilha de tres etapas da
   pagina, vista de lado. Decorativa (aria-hidden no HTML) e sem rotulo — rotulo
   aqui seria informacao que so existe dentro do modal.

   AS PLACAS NAO SAO VERMELHAS, de proposito. No portal o vermelho tem uma funcao
   so — problema/gargalo e a acao que o ataca (`GramaticaDeCorTest`) — e uma
   placa vermelha na frente diria "aqui esta o seu problema" para quem acabou de
   chegar. O unico vermelho do palco e o simbolo da marca, que ja e vermelho por
   ser a marca. Mesma escolha do `carregando3d`.

   CONTRASTE DO QUE E GRAFICO: quem define a FORMA e a borda da placa da frente,
   e ela da 3,83:1 contra o cartao (piso 3:1). O sombreado de profundidade — as
   placas de tras a 1,48:1 e a face lateral a 1,27:1 — fica abaixo de proposito:
   e sombreado, nao contorno de objeto, e nada aqui precisa ser percebido para a
   tela ser entendida. */
.bv_palco {
    /* DECORACAO NAO RECEBE PONTEIRO. `aria-hidden` esconde de leitor de tela e
       NAO do mouse, e a geometria PROJETADA de um `preserve-3d` sai da caixa de
       layout: as placas alcancavam o botao de fechar 90px acima. Sem esta linha
       o modal ficava sem saida para quem usa mouse. */
    pointer-events: none;
    /* Camera curta: aqui a distorcao e o efeito. Origem acima do centro para as
       placas de tras "subirem", que e como uma pilha se le em perspectiva. */
    perspective: 620px;
    perspective-origin: 50% 38%;
    /* ALTURA MEDIDA, NAO CHUTADA. A 124px a pilha inteira cabia em ~92px de
       largura projetada e lia como um CRACHA com sombra — o relevo existia e nao
       se via. Compare evidencias/w85/modal-no-preference-1440.png (antes) com
       modal-3d-no-preference-1440.png (depois). */
    height: clamp(124px, 26vw, 158px);
    margin-bottom: clamp(16px, 3vw, 26px);
}
/* JANELA BAIXA (celular deitado, ~360px de altura): o palco sai inteiro. Ele
   custa ate 184px com a margem, e sem ele o cartao passa de ~476px para 282 e
   volta a caber (medido a 740x360). A ordem de sacrificio nao tem duvida: o
   adorno sai, o passo fica. Sem esta regra o botao ficaria fora da janela. */
@media (max-height: 560px) {
    .bv_palco { display: none; }
}

.bv_pilha {
    position: relative;
    width: 100%; height: 100%;
    transform-style: preserve-3d;
    /* O REPOUSO E UM ANGULO, NAO O ZERO. Sob prefers-reduced-motion nada anima,
       e e este transform que sobra: a profundidade continua na tela, parada.
       Relevo nao e movimento — quem pediu menos movimento nao pediu menos
       desenho. Medido: a matriz de repouso e IDENTICA nas duas preferencias. */
    transform: rotateX(10deg) rotateY(-31deg);
}

.bv_placa {
    position: absolute;
    top: 50%; left: 50%;
    width: 132px; height: 86px;
    margin: -43px 0 0 -66px;
    border-radius: 16px;
    border: 1px solid var(--escuro-borda);
    background: color-mix(in srgb, var(--escuro-texto) 6%, var(--escuro-fundo));
    display: grid; place-items: center;
}

/* A PLACA DA FRENTE, em tres partes.

   1. A SUPERFICIE. Mais clara que as de tras, com borda mais forte e sombra
      propria — e ela que a projecao coloca perto do observador.
   2. O VEU DE LUZ (background-image). A luz cai de cima e da esquerda e some
      antes da metade; e o que faz a placa parecer uma SUPERFICIE e nao um
      retangulo. Sem ele as tres sao chapadas e a profundidade fica so no tamanho.
   3. A ESPESSURA (::after). E o unico truque que separa "CSS 3D" de "sombra bem
      posta": uma face LATERAL de verdade, num pseudo-elemento girado 90 graus em
      Y. Ela se comporta como face real — cresce quando a pilha vira e some de
      frente —, e e ela que impede as placas de lerem como folhas de papel no
      inicio da entrada, com o grupo a -70 graus.

   `transform-style: preserve-3d` na PROPRIA placa e obrigatorio para o item 3:
   sem ele o pseudo-elemento e achatado no plano da placa e vira uma barra clara
   de 14px colada na borda. */
.bv_placa_a {
    transform: translateZ(0);
    transform-style: preserve-3d;
    border-color: color-mix(in srgb, var(--escuro-texto) 42%, transparent);
    background: color-mix(in srgb, var(--escuro-texto) 13%, var(--escuro-fundo));
    background-image: linear-gradient(148deg, color-mix(in srgb, var(--escuro-texto) 10%, transparent), transparent 58%);
    box-shadow: 0 16px 34px rgba(0, 0, 0, .55);
}
.bv_placa_a::after {
    content: "";
    position: absolute;
    /* O RECUO DE 9px E O RAIO ESCONDEM O CANTO QUADRADO: a face lateral e um
       retangulo e a frente tem 16px de raio, entao sem recuo aparecem duas
       farpas nos cantos (visiveis em evidencias/w85/palco-repouso-4x.png). */
    top: 9px; bottom: 9px; right: 0; width: 14px; border-radius: 3px;
    /* A ARESTA E A DIREITA, E ISSO SE CALCULA, NAO SE CHUTA. Com o grupo em
       rotateY(-31deg) a aresta direita e a que vem PARA o observador (a normal
       (1,0,0) girada ganha componente +Z), entao e a face direita que aparece.
       Ancorada na esquerda o pseudo-elemento fica de costas e nao pinta nada —
       foi o primeiro desenho, e a captura de 120ms provou que ele sumia. */
    transform-origin: right center;
    transform: rotateY(90deg);
    /* A FACE E MAIS CLARA QUE A FRENTE, e nao mais escura: ela e o unico plano
       do palco virado para a luz. A 3% de mistura ela existia e era invisivel —
       5,7px projetados na mesma cor da frente. */
    background: color-mix(in srgb, var(--escuro-texto) 20%, var(--escuro-fundo));
}

/* Profundidade: a da frente em z=0, as outras atras. O deslocamento horizontal
   vem da PROJECAO (o rotateY do grupo), nao de translateX — assim uma variavel
   so governa a abertura do leque. */
.bv_placa_b { transform: translateZ(-60px) translateY(-11px); opacity: .70; }
.bv_placa_c { transform: translateZ(-120px) translateY(-22px); opacity: .42; }
.bv_simbolo { display: block; width: 54px; height: 54px; object-fit: contain; }

.bv_titulo {
    margin: 0; font-size: var(--tipo-5);
    font-weight: 800; line-height: 1.2; letter-spacing: -.02em;
    color: var(--escuro-texto);
}
.bv_texto {
    margin: 14px 0 0;
    color: var(--escuro-suave);
    font-size: var(--tipo-2); line-height: 1.65;
    /* MEDIDA DE LEITURA. Sem teto, a 520px o paragrafo saia com ~58 caracteres
       por linha CENTRALIZADOS — e linha centralizada e mais dificil de retomar
       que alinhada a esquerda, porque o inicio de cada linha muda de lugar.
       Ela pede, por isso, uma medida mais curta que as ~65-75 usuais. */
    max-width: 40ch;
    margin-inline: auto;
}
/* O convite (o proximo passo) e o que a pessoa precisa levar embora — ele recebe
   o realce, e o realce e a cor de TEXTO da ilha escura, nao o vermelho: o
   vermelho ja esta no botao logo abaixo, que e a acao. */
.bv_texto strong { color: var(--escuro-texto); font-weight: 700; }
.bv_acoes { margin: clamp(20px, 3vw, 28px) 0 0; }

/* --- entrada ----------------------------------------------------------------
   DUAS animacoes, e nenhuma em laco. A caixa entra girando em X (o cartao
   inclinando-se ate ficar de frente) e a pilha abre o leque. Laco infinito no
   primeiro contato e ruido: o movimento aqui tem inicio, fim e um motivo.

   Sob `prefers-reduced-motion: reduce` este bloco inteiro nao existe — o modal
   nasce posicionado, opaco e com a mesma inclinacao de repouso da pilha. Nada
   fica quebrado, nada fica invisivel: so nao ha deslocamento. Medido nas duas
   preferencias, a 1440 e a 320, com zero violacao de axe em todas. */
@media (prefers-reduced-motion: no-preference) {
    @keyframes bv_entra {
        from { opacity: 0; transform: translateY(26px) translateZ(-190px) rotateX(-13deg); }
        to   { opacity: 1; transform: none; }
    }
    /* `from` explicito pelo mesmo motivo de `c3d_gira`: um keyframe so com `to`
       interpolaria a partir do valor corrente, que aqui e o transform de repouso
       da pilha — e o navegador teria de decompor a matriz para chegar la.
       Escrever os dois lados na mesma forma evita isso. */
    @keyframes bv_leque {
        from { transform: rotateX(22deg) rotateY(-70deg); }
        to   { transform: rotateX(10deg) rotateY(-31deg); }
    }
    @keyframes bv_fundo { from { opacity: 0; } to { opacity: 1; } }

    .bv[open] .bv_caixa { animation: bv_entra 460ms var(--curva-suave, ease-out) both; }
    .bv[open] .bv_pilha { animation: bv_leque 760ms 120ms var(--curva-suave, ease-out) both; }
    .bv[open]::backdrop { animation: bv_fundo var(--dur-entrada) linear both; }
}

/* =============================================================================
   A TELA DE ERRO (onda 90) — /themes/portal/error.php
   =============================================================================

   ELA E SERVIDA A QUEM NAO TEM SESSAO, e e a MESMA resposta que o perimetro do
   painel devolve para uma rota escondida. Duas consequencias de desenho:

     1. NADA AQUI PODE PARECER PAINEL. Sem barra lateral, sem grupos de menu,
        sem cromo de area interna — a propria pagina confirmaria a existencia do
        que o 404 acabou de negar. Por isso estes seletores vivem na folha do
        PORTAL e nao em painel.css, e nao ha nenhuma variante `.pagina-admin`.

     2. NADA AQUI PODE DEPENDER DE ESTADO. A tela nao tem usuario garantido, e o
        unico que varia e a LISTA DE SAIDAS — que o servidor monta a partir da
        sessao, nunca do caminho pedido.

   O centro vertical e `min-height` com `dvh`, e nao `height`: em telefone a
   barra do navegador entra e sai, e `100vh` fixo deixaria a coluna maior que a
   janela — rolagem em uma tela de tres paragrafos. O `dvh` acompanha; o `svh`
   do fallback serve quem nao o tem. Nada de `overflow: hidden` para "resolver":
   com zoom de 200% o conteudo PRECISA poder rolar (WCAG 1.4.10).

   CONTRASTE. `--texto-suave` (#5A6072 no claro, #A7ADBE no escuro) e o mesmo
   par que o resto do portal ja usa em `.sub`, medido acima de 4,5:1 nos dois
   temas. O selo usa `--texto` cheio de proposito: e o unico lugar onde o
   codigo do erro aparece, e ele nao pode ser o elemento mais fraco da tela. */
/* `margin-inline: auto` porque a coluna e ESTREITA dentro de um `.wrap`
   LARGO (1080). Sem ela o bloco fica ancorado a esquerda de um espaco vazio de
   500px — a leitura e a mesma, mas a tela parece cortada pela metade. O texto
   continua alinhado a esquerda: centralizar tres paragrafos de comprimentos
   diferentes e o que produz aquele losango de linhas que ninguem le. */
.erro {
    max-width: 560px;
    margin-inline: auto;
    min-height: 62svh;
    min-height: 62dvh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding-block: var(--esp-6, 40px);
}

/* O selo: lupa + "Erro 404". `inline-flex` e nao `flex` para a caixa terminar
   onde o texto termina — uma etiqueta que atravessa a coluna inteira vira
   faixa, e faixa e hierarquia que este elemento nao tem. */
.erro_selo {
    display: inline-flex;
    align-items: center;
    gap: var(--esp-2, 8px);
    align-self: flex-start;
    margin: 0 0 14px;
    padding: 6px 12px 6px 10px;
    border: 1px solid var(--borda);
    border-radius: var(--pilula);
    background: var(--preenchimento);
    color: var(--texto);
    font-size: var(--tipo-1);
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
}
.erro_selo .icone { width: 15px; height: 15px; flex: none; }

.erro h1 { margin: 0; }
.erro .sub { margin: 12px 0 0; }

/* A dica pratica, um degrau abaixo da mensagem: mesma cor, corpo menor. Ela
   nao e um aviso — nao ganha caixa, borda nem cor de estado. */
.erro_dica {
    margin: 10px 0 0;
    color: var(--texto-suave);
    font-size: var(--tipo-2);
    max-width: 52ch;
}

/* AS SAIDAS. `flex-wrap` e nao grid: a lista tem 1, 2 (ou, no dia em que
   crescer, 3) itens de largura desigual, e quebrar por conteudo e o
   comportamento certo em 320px sem media query nenhuma. */
.erro_saidas {
    display: flex;
    flex-wrap: wrap;
    gap: var(--esp-3, 12px);
    margin-top: 28px;
}
.erro_saidas .btn,
.erro_saidas .btn_sec { gap: 8px; }
.erro_saidas .icone { width: 17px; height: 17px; flex: none; }

/* 320px: os alvos ocupam a linha inteira em vez de espremer o rotulo em duas
   linhas dentro de uma pilula. `min-width: 0` porque um flex item nao encolhe
   abaixo do conteudo sem isso, e e assim que a pilula estoura a coluna. */
@media (max-width: 380px) {
    .erro_saidas { flex-direction: column; align-items: stretch; }
    .erro_saidas .btn,
    .erro_saidas .btn_sec { min-width: 0; width: 100%; }
}
