/* =============================================================================
   Alexandre Gutierrez Andrade (@alexandre.gutierrez.andrade) — link-in-bio  (Bootstrap 5.3 como base)

   ARQUITETURA DE TEMA
   -------------------
   Nenhuma cor pode ficar cravada nas regras: os esfumaçados (hero, banners,
   fotos) precisam dissolver na cor do tema, então usam --bg-rgb / --page-rgb.
   Um tema = um bloco de tokens (theme-*.css). A geometria mora aqui.

   A PREMISSA MUDOU EM RELAÇÃO AO PROJETO DE ORIGEM (Léo Nicolazzi). Lá o fundo
   era SEMPRE preto e um tema era só a cor do botão; por isso cada theme-*.css
   cabia em vinte linhas. Aqui o kit do Alexandre traz DOIS canvas — o claro e
   o `.canvas.escuro` — e o que muda entre eles é a SUPERFÍCIE inteira. Logo:

     · o :root abaixo é o tema MÁRMORE (claro), o que vale sem data-theme;
     · o theme-tinta.css sobrescreve superfície, rampa de texto, vidro, aresta
       e sombra — e não só o botão;
     · qualquer regra que assuma "o fundo é escuro" é bug, não estilo. Quem
       precisa de claro/escuro lê token, nunca uma cor.

   A PALETA é a do kit (docs/MARCA.md §2), cinco tons e nada mais:
     MÁRMORE #E9E6DF · MÁRMORE-2 #D8D4CA · TINTA #151511
     BRONZE  #3E6E5E · PEDRA     #8A8578 · FUMO  #4A483F

   TRÊS COISAS QUE SÃO MEDIDAS, E NÃO ESCOLHIDAS:

   1. O texto do botão. Branco sobre o bronze dá 5,8:1 — passa. É medido pelo
      gera-temas.mjs contra o preenchimento, não escolhido no olho.
   2. A SEPARAÇÃO da barra em relação ao fundo do tema. O bronze separa 4,68:1
      do mármore e 3,14:1 da tinta: nos dois ele se desenha sozinho e
      --gold-border fica `transparent`. Abaixo de 3:1 a barra perderia a FORMA
      (a cor certa e nenhum contorno), e aí o gerador avisa.
   3. A cor de TEXTO. O --gold não serve: contra o vidro do tema claro ele dá
      4,3:1. O --accent de cada tema é o bronze deslocado — ESCURECIDO no
      mármore, CLAREADO na tinta — até cruzar 4,5:1 no pior fundo.

   O PIOR FUNDO É O VIDRO, não o cartão. É onde moram os inputs, o bloco de
   endereço e a caixa "Sobre este produto"; medir só contra o cartão aprova cor
   que some dentro do formulário. No mármore o vidro compõe #DEDBD4; na tinta,
   #24241F. Os dois números estão no contrast-check.mjs.

   O token que PREENCHE o CTA se chama --gold em todos os temas — aqui ele não é
   dourado em nenhum, é o bronze da marca. O nome vem do projeto irmão e é
   mantido de propósito: assim os repositórios continuam comparáveis e uma
   correção lá porta para cá sem tradução.
   ============================================================================= */

/* ------------------------------------------------------------- TIPOGRAFIA ---
   LITERATA, variável, servida do próprio repositório (docs/MARCA.md §3).

   Por que local e não Google Fonts, como era a Inter: a Literata ESTÁ no CDN,
   mas as treze peças de Instagram do Alexandre foram feitas com o arquivo do
   kit. Hospedar esse arquivo é o que garante que site e Instagram tenham a
   MESMA letra, sem depender de a versão do CDN bater com a do kit — e mata a
   viagem de rede extra que o `@import` de fonte custa no primeiro paint.

   `font-weight:200 900` declara a FAIXA da fonte variável, e é o que faz o
   navegador interpolar em vez de arredondar. O eixo `opsz` (7..72) fica por
   conta do `font-optical-sizing:auto` mais abaixo: é ele que engrossa a haste
   do texto pequeno e afina a do nome, que é o que dá o ar de livro.

   `format("truetype")` e não `format("truetype-variations")`: a segunda é a
   sintaxe legada, e há navegador que a ignora e cai no fallback sem avisar. Com
   a faixa de peso declarada, "truetype" já é lido como variável em todos os
   navegadores que este site suporta.

   Georgia como rede, e não a fonte de sistema sem serifa: a Literata é SERIFA e
   mais estreita que a Inter que estava aqui. Cair numa grotesca faria o nome e
   os rótulos de botão MUDAREM DE LARGURA na troca — e é justamente a largura
   que aperta em 320px. Georgia erra menos. */
@font-face{
  font-family:"Literata";
  src:url("/assets/fonts/Literata.ttf") format("truetype");
  font-weight:200 900;
  font-style:normal;
  font-display:swap;
}
@font-face{
  font-family:"Literata";
  src:url("/assets/fonts/Literata-Italic.ttf") format("truetype");
  font-weight:200 900;
  font-style:italic;
  font-display:swap;
}

:root{
  /* ---- Superfícies: MÁRMORE (o tema claro do kit) -------------------------
     O cartão é o #E9E6DF do kit e a PÁGINA é o #D8D4CA (o "mármore-2", a
     superfície de apoio). No projeto de origem os dois eram o mesmo preto,
     porque lá quem separava o cartão do fundo era a foto desfocada e mais nada.
     Aqui os dois diferem por 1,19:1 — pouco de propósito: é o bastante para o
     cartão continuar existindo quando o .bg-blur não é pintado (celular,
     prefers-reduced-data, imagem que não carregou) e pouco demais para virar
     uma segunda cor competindo com o creme. */
  --page-rgb:216,212,202;               /* mármore-2 #D8D4CA */
  --bg-rgb:233,230,223;                 /* mármore   #E9E6DF */
  --page:rgb(var(--page-rgb));
  --bg:rgb(var(--bg-rgb));
  --page-bg:var(--page);
  --card-bg:var(--bg);
  --sheen:none;

  /* A TINTA DE TODA SOMBRA. Era preto puro cravado em cada box-shadow, o que
     funcionava enquanto o fundo também era preto: sombra preta sobre preto não
     desenha nada, então o exagero passava. Sobre o creme ela desenha, e desenha
     cinza sujo. Aqui a sombra sai da tinta do kit (#151511) e vira token para
     o tema escuro poder devolvê-la ao preto puro numa linha. */
  --sombra-rgb:21,21,17;

  /* A TEXTURA. Antes era grão de metal escovado em `overlay`, calibrado para
     preto — ver a nota inteira no body::after, que explica por que overlay e
     não véu. Sobre o mármore aquele ruído SUJA: ele clareia e escurece pixel a
     pixel um fundo que já é claro, e o resultado lê como chuvisco.
     A superfície aqui é PEDRA, não metal, e a textura é a placa do kit
     (/assets/brand/marmore.jpg) em `soft-light`. O número é a opacidade da
     camada; o porquê do valor está medido no body::after. */
  --grain:.55;

  /* O RELEVO DA BORDA. Uma linha de 1px por dentro do cartão, no topo.

     NO TEMA ESCURO ELA ERA LUZ. O raciocínio original: cartão preto sobre fundo
     preto, sombra preta não existe, então o que levanta a peça é o CONTRASTE DE
     ARESTA — o olho lê "borda clara em cima" como luz vinda de cima. Sobre o
     mármore isso se inverte: uma linha branca dentro de um cartão creme não
     aparece, e se aparecesse leria como risco. No claro o relevo é SOMBRA — um
     fio de tinta no topo, que é o que uma peça apoiada projeta de si mesma.
     O nome do token fica: ele é lido pelo box-shadow do .card-on-desktop e
     trocar o nome espalharia a mudança por arquivos que não são deste tema. */
  --aresta-luz:rgba(var(--sombra-rgb),.09);

  /* No desktop quem faz a moldura é a FOTO DESFOCADA (.bg-blur), e no claro ela
     precisa ficar MAIS ESCURA que o cartão — ver --blur-filter lá embaixo. */

  /* ---- Vidro: FUMO a baixa opacidade sobre o mármore ----------------------
     O tom é o --fumo do kit (#4A483F). Os 7% não são gosto: compostos sobre o
     cartão eles dão EXATAMENTE o #DEDBD4 que o docs/MARCA.md §2 chama de "o
     vidro", que é o fundo contra o qual toda cor de texto tem de cruzar 4,5:1.
     Medido: 233-159×.07 = 222 · 230-158×.07 = 219 · 223-160×.07 = 212. */
  --glass-bg:rgba(74,72,63,.07);        /* compõe #DEDBD4 sobre o cartão */
  --glass-bg-2:rgba(74,72,63,.12);      /* compõe #D6D3CC */
  --glass-border:rgba(74,72,63,.20);    /* compõe #C9C6BF */
  --glass-blur:blur(14px) saturate(1.1);
  --glass-shadow:0 10px 24px -16px rgba(var(--sombra-rgb),.45);

  --surface:rgba(74,72,63,.07);
  --surface-2:rgba(74,72,63,.12);
  --hairline:rgba(74,72,63,.20);
  /* Sobre o creme a sombra do cartão APARECE, e preto puro a 100% vira uma
     mancha cinza. .30 é o mesmo desenho com a tinta certa: ela ainda dá altura
     (o -30px de spread joga o borrão para longe) sem pintar um halo. */
  --shadow-card:0 30px 70px -30px rgba(var(--sombra-rgb),.30);

  /* ---- Texto (sobre o MÁRMORE) --------------------------------------------
     A rampa é a do kit, e cada linha é MEDIDA contra o cartão E contra o vidro
     (docs/MARCA.md §2). A pedra (#8A8578) não entra: ela dá 2,95:1 e é cor de
     filete, nunca de letra — onde o projeto precisa de um cinza legível, é a
     pedra escurecida em luz linear até cruzar o piso, matiz intacto. */
  --text:#151511;                       /* tinta — 14,7:1 cartão · 12,5:1 vidro */
  --text-2:#4A483F;                     /* fumo  —  7,4:1 cartão ·  6,3:1 vidro */
  --muted:#5A564D;                      /*          5,9:1 cartão ·  5,3:1 vidro */
  /* #656158 é o valor da tabela do MARCA.md e ele REPROVA por um fio: 4,46:1
     no vidro, contra o piso de 4,5 que o próprio MARCA.md fixa duas linhas
     acima da tabela. Um passo de luminância mais escuro resolve sem mudar o
     matiz. A regra vence a tabela — está anotado nas pendências para o
     Alexandre corrigir a tabela do kit. */
  --muted-2:#646056;                    /*          5,0:1 cartão ·  4,5:1 vidro */

  /* DOIS papéis diferentes, que antes eram um só:
       --on-photo  texto sobre a FOTO com véu escuro por baixo (título do banner).
                   Branco SEMPRE, nos dois temas — atrás dele há um gradiente
                   preto que o .v-vertical .overlay pinta, e esse véu não é do
                   tema: é do banner.
       --on-hero   nome e @ no pé do hero, onde a foto JÁ dissolveu no cartão.
                   Segue o tema; no mármore, é a tinta. */
  --on-photo:#fff;
  --on-hero:#151511;
  --on-hero-2:rgba(21,21,17,.72);       /* o @ — a proporção do link.me, na tinta */
  /* O text-shadow do nome é REDE DE SEGURANÇA, não decoração: ele existe para o
     caso de o esfumaçado falhar ou a foto ser trocada por uma que não dissolva.
     Com letra escura, a rede é um halo CLARO — preto sobre preto não salva
     ninguém. Por isso ele sai de --bg-rgb e acompanha o tema. */
  --on-hero-shadow:0 2px 20px rgba(var(--bg-rgb),.85), 0 1px 3px rgba(var(--bg-rgb),.7);

  /* O aro dos chips de rede de marca PRETA (TikTok, X) — ver .social-chip.
     Transparente no claro de propósito: lá o disco preto já tem forma. */
  --aro-preto:transparent;

  /* A barra de rolagem, o popup do <select> NATIVO e o autofill não leem CSS:
     eles leem isto. Sem `color-scheme`, o Windows pinta a lista do <select> com
     a cor do sistema — e num sistema em modo escuro a lista sai preta com o
     texto tinta por cima, ilegível dentro de um site claro. É o mesmo bug que o
     admin.css já registrava ao contrário. */
  color-scheme:light;

  /* ---- Botão: MÁRMORE (o padrão) — GERADO por gera-temas.mjs
       nome-exibido: Mármore -- */
  --gold:#3E6E5E;                 /* Bronze — texto branco: 5,8:1 */
  --gold-light:#56947F;
  --gold-dark:#2E5548;
  --gold-grad:linear-gradient(135deg,#2E5548 0%,#3E6E5E 45%,#56947F 100%);
  --gold-ring:rgba(62,110,94,.55);
  --gold-glow:rgba(62,110,94,.5);
  --on-gold:#FFFFFF;

  /* A barra separa do fundo #E9E6DF por 4,7:1 — desenha-se sozinha.
     Sem contorno, como a barra chapada do kit. */
  --gold-border:transparent;

  --shine:#8AB0A4;

  /* Cor de TEXTO. NÃO é o --gold: contra o vidro #DEDBD4 ele dá 4,3:1.
     Esta é a cor ESCURECIDA até cruzar 4,5:1 no pior fundo (o vidro #DEDBD4).
     No tema escuro o mesmo token é a cor CLAREADA — a direção depende da
     superfície, e é por isso que o gerador precisa saber qual ela é. */
  --accent:#3B695A;               /* 4,5:1 no vidro */
  --accent-hover:#2E5448;

  /* Os --seal-* NÃO entram aqui. O selo de verificado é o do
     link.me/hillerfit e tem cor fixa (#C29AFF -> #4062FF, check branco),
     definida uma vez no :root do site.css. Selo é sinal reconhecível,
     não enfeite: recolorido a cada tema, deixaria de dizer o que diz. */

  /* VERDE E VERMELHO DE ESTADO. Os anteriores (#5FD08A / #F08A82) eram tons
     pastel escolhidos para brilhar sobre preto: sobre o mármore eles dão 1,6:1
     e 1,9:1 — a mensagem de erro do formulário ficava invisível justamente na
     hora em que ela é a única coisa que importa. Estes dois foram escurecidos
     até cruzar 4,5:1 no VIDRO, que é onde as mensagens moram (dentro do modal).
     No tema escuro o theme-tinta.css devolve os pastéis. */
  --ok:#256845;                   /* 5,4:1 cartão · 4,8:1 vidro */
  --err:#A93B2E;                  /* 5,0:1 cartão · 4,5:1 vidro */
  /* O verde do WhatsApp é DELES e não muda com o tema — o botão é reconhecido
     por essa cor. O rótulo dentro dele continua quase preto (8,0:1). */
  --wa:#25d366;

  /* ------------------------------------------------------------------ SELO --
     Azul CHAPADO do Instagram, #0095F6. Não é o do link.me/hillerfit.
     DECIDIDO pelo Alexandre em 01/08/2026, depois de a cor ter ido e voltado:
     entre a rampa roxo→azul do HillerFit e o azul do Instagram, ele escolheu o
     do Instagram. Não trocar sem pedido explícito dele.

     Histórico, porque a diferença importa: primeiro o selo copiava a rampa do
     HillerFit (#C29AFF roxo -> #4062FF azul), medida no arquivo deles. Batia
     pixel a pixel — e a 21px o #4062FF domina os dois terços de cima, então ele
     lia como "azul escuro". O Alexandre pediu o do Instagram, que é mais claro
     e chapado. As duas pontas ficam iguais de propósito: o selo do Instagram
     não tem gradiente.

     Fica AQUI, abaixo do --wa, e não acima: o gera-temas.mjs reescreve tudo
     entre `/* ---- Botão:` e `--ok:`, e um token colocado ali some na próxima
     vez que alguém rodar o gerador. E fica fora dos theme-*.css porque o selo é
     um sinal que a pessoa reconhece de outros lugares — mudando de cor a cada
     tema, deixaria de ser selo. É o único elemento colorido que não segue o
     tema. */
  --seal-a:#0095F6;
  --seal-b:#0095F6;
  --seal-c:#0095F6;
  --seal-stroke:transparent;      /* o do Instagram não tem contorno */
  --seal-check:#FFFFFF;

  --brand:var(--gold);
  --brand-hover:var(--gold-light);
  --link:var(--gold);
  --verified:var(--gold);

  --hero-filter:brightness(.9) contrast(1.03);
  /* 27rem cortava o corpo: a foto tem 1920px de altura e a janela mostrava só
     74% dela no celular e 50% no desktop — sobrava a cabeça e o ombro.
     35rem sobe para 96% e 65%. Não passa disso: acima de 100% a foto deixa de
     caber pela altura e o `cover` começa a cortar as LATERAIS, que é trocar um
     corte por outro. Medido nas duas larguras, não estimado. */
  /* CELULAR. Aqui 35rem ja mostra 96% da foto; acima disso ela deixa de caber
     pela altura e o `cover` passa a cortar as LATERAIS — trocaria corte de
     corpo por corte de ombro. Medido: 42rem daria 115%. O override do desktop
     esta logo abaixo do :root. */
  --hero-h:29rem;
  /* object-position da foto do hero — hoje o Hércules (docs/MARCA.md §7).

     O X QUASE NÃO FAZ NADA, E ISSO É DE PROPÓSITO — mas o Y FAZ, e muito, numa
     largura só. Ver a tabela e a explicação logo abaixo. O recorte servido
     pelo prepara-hero.mjs (1033x1193, proporção 0,866) foi escolhido para bater
     com a janela nas três larguras que existem, e sobra pouquíssimo para
     deslocar. Medido:

       largura     janela      proporção   sobra
       320px       320x384       0,833     12px na HORIZONTAL
       360px       360x384       0,938     32px na VERTICAL (7,6%)
       375px       375x384       0,977     49px na VERTICAL (11,3%)  <- o pior
       390px       390x464       0,840     12px na HORIZONTAL
       430px       430x464       0,927     33px na VERTICAL
       desktop     580x688       0,843     16px na HORIZONTAL

     Enquadramento resolvido na IMAGEM é melhor que enquadramento resolvido
     aqui: o recorte está versionado num arquivo com a medição ao lado, e este
     número some no meio de mil linhas de CSS.

     O Y=0% NÃO É INDIFERENTE — ele é o que segura a cabeça em pé. Nas larguras
     com sobra vertical (360, 375 e 430px) a cabeça do Hércules começa a 21,2px
     do topo da imagem exibida, e a sobra a 375px é de 49,1px. Com o padrão
     `50%` o deslocamento seria de 24,5px e o topo da cabeça cairia em −3,3px:
     CORTADO. Não é margem apertada, é corte. Topo-alinhado, o rosto está
     garantido nas seis larguras medidas e a perda cai na base, que o esfumaçado
     já dissolve no cartão.

     (A primeira versão deste comentário dizia que o --hero-focus "deixa de
     decidir qualquer coisa". Era verdade para o X e falso para o Y — e a
     medição a 375px foi o que mostrou. Fica registrado porque a frase errada é
     convidativa: ela sugere que se pode mexer no valor sem consequência.)

     O X=50% centra os 12-16px de folga. Com o assunto já centrado no recorte
     (centro de massa em 51,1% da nova largura), não há o que puxar. */
  --hero-focus:50% 0%;
  --maxw:580px;



  /* Fundo desfocado (a foto do perfil borrada atrás do cartão, como no
     HillerFit). Só é PINTADO a partir de 768px — ver .bg-blur lá embaixo.

     brightness 1.3, e não 0.42. Medido no desktop, comparando a luz do fundo
     com a da borda do cartão:

       0.42   fundo 0,0103   cartão 0,0358   o FUNDO é mais escuro que o cartão
       1.00   fundo 0,0485                   praticamente empatam — 1,15:1
       1.30   fundo 0,0760                   fundo mais claro — 1,47:1
       1.70   fundo 0,1110                   1,88:1, mas o laranja da foto passa
                                             a competir com o conteúdo

     Em 0,42 o fundo era mais escuro que o próprio cartão preto, então não havia
     moldura nenhuma: o cartão sumia dentro do fundo em vez de flutuar sobre
     ele. É a foto desfocada que faz a moldura aqui — ela precisa ser mais clara
     que o que emoldura. */
  /* DESBOTADO, e não saturado. Estava saturate(1.25): o filtro puxava o
     vermelho da foto para néon, e a moldura virava uma faixa de cor pura
     brigando com o cartão. Na referência a moldura é um degradê quente e
     lavado — ela é AMBIENTE, o resto da foto vazando para fora do cartão, e
     ambiente não disputa atenção.

     Medido na moldura: saturação média caiu de 0,20 para 0,12. O brilho fica
     em 1,28 (praticamente o 1,3 de antes) porque o pedido de "fundo desfocado
     mais claro para dar contraste" continua valendo — o que mudou é a
     PUREZA da cor, não a luminosidade.

     O blur sobe de 44px para 60px junto: com menos saturação, um borrão curto
     deixava adivinhar a forma da foto atrás, e a moldura precisa ser massa de
     cor, não uma segunda imagem. */
  /* ---- INVERTEU DE SINAL NO TEMA CLARO -------------------------------------
     A regra continua a mesma — a moldura tem de DIFERIR do cartão, senão o
     cartão não flutua, ele afunda. O que muda é a direção: sobre preto a
     moldura precisava CLAREAR (brightness 1,28 levava o fundo de 0,048 para
     0,076, e o cartão preto ficava recortado contra ela); sobre o mármore ela
     precisa ESCURECER, porque o cartão já é a coisa mais clara da tela.

     A EXPOSIÇÃO NÃO MORA MAIS AQUI. Ela é resolvida no prepara-hero.mjs, que
     grava o hero-blur.jpg já na luz certa (média sRGB ~136 = luz linear 0,2466,
     que contra o mármore 0,7925 dá 2,84:1). Por isso o brightness abaixo é 1.

     Vale registrar por que mudou de lugar, porque a primeira versão fez o
     contrário e ficou VISIVELMENTE errada. O valor era brightness(2), calibrado
     contra a foto crua da época.

     As fotos do hero são estátuas em P&B de altíssimo contraste: mármore branco
     contra fundo quase preto. Medido nas duas que já passaram por aqui —
     estátua da adoração 77/75 e Hércules 43/44 (média/desvio) — a distribuição
     é quase bimodal, sem meio-tom. E `brightness()` MULTIPLICA: ele não aproxima
     as duas pontas, afasta. Os pretos continuavam pretos e os brancos batiam no
     teto de 255. Na tela: um borrão preto de um lado da página e uma mancha
     branca do outro. Lia como sujeira, não como moldura.

     `blur()` também não salva: ele faz média LOCAL, e a média local de uma
     região toda preta continua preta. Nenhum ajuste de filtro conserta uma
     imagem sem meio-tom — o conserto tem de vir antes, na imagem.

     Agora o prepara-hero.mjs comprime a faixa tonal antes de gravar, com
     `.linear(0,34, alvo − 0,34·média_da_origem)` — o deslocamento é DERIVADO da
     foto, para que qualquer original futuro caia na mesma luz. No Hércules o
     desvio cai de 44 para 14 e a média fecha em 136, o alvo. O filtro daqui só
     borra. Um lugar só decide a luz, e é o que mede.

     saturate fica em .7 mesmo a foto sendo P&B (onde ele não faz nada): é
     seguro se um dia a foto do topo for trocada por uma colorida, e nesse dia
     a moldura continua sendo AMBIENTE em vez de uma faixa de cor pura.

     REMEDIR SE A FOTO MUDAR: `node prepara-hero.mjs "Imagens/<nova>"` já
     confere e avisa se o fundo ficou claro demais ou desuniforme. */
  --blur-filter:blur(60px) saturate(.7) brightness(1);
  --blur-scale:1.18;                    /* >1 para o blur não vazar borda clara */
}

*{ -webkit-tap-highlight-color:transparent; }
html,body{ overflow-x:hidden; }
body{
  /* Literata primeiro, Georgia como rede — as duas são SERIFA, então a troca
     não muda a largura do texto. Era "Inter" + grotescas do sistema; trocar a
     família sem trocar o fallback deixaria a página oscilando entre serifa e
     sem-serifa a cada carregamento lento, e a largura da linha junto. */
  font-family:"Literata",Georgia,"Times New Roman",serif;
  /* O eixo `opsz` (7..72) da Literata, no automático: o navegador o move junto
     com o font-size, engrossando a haste do texto pequeno e afinando a do nome.
     É o que o kit chama de "opsz 10 na legenda, 18 no corpo, 72 no display" —
     aqui isso sai de graça em vez de virar uma variation-settings por regra. */
  font-optical-sizing:auto;
  /* Os algarismos ANTIGOS (com ascendente e descendente) são o que o kit usa e
     o que dá o ar de livro. Onde número é coluna — preço, contador, campo de
     formulário — a exceção está declarada regra a regra em `lining-nums
     tabular-nums`, senão a coluna de R$ desalinha. */
  font-variant-numeric:oldstyle-nums;
  /* 1,48 é a entrelinha do corpo no kit. A Literata tem altura-de-x menor que a
     Inter, então a mesma entrelinha em número dá MAIS ar aqui — e é isso que se
     quer num texto com serifa. */
  line-height:1.48;
  color:var(--text);
  background:var(--page-bg);
  background-attachment:fixed;
  min-height:100dvh;
}
/* NÚMERO QUE É COLUNA volta a ser alinhado e de altura fixa. `lining-nums` tem
   de vir junto: `tabular-nums` sozinho não desliga o oldstyle do body, e o
   resultado é uma coluna alinhada de algarismos que sobem e descem. */
.form-control, .form-select, textarea.form-control, .input-group-text,
input, select, textarea{ font-variant-numeric:lining-nums tabular-nums; }
/* --- As duas camadas que dão MATERIAL ao fundo (e não cor chapada) -----------
   sheen  (::before, z=0): reflexo especular. Fica ATRÁS do cartão — só aparece
                           nas margens do desktop.
   pedra  (::after,  z=2): a placa de mármore do kit. Fica POR CIMA do cartão.

   A camada de cima PRECISA ficar por cima: se ela morar dentro do --card-bg, o
   cartão ganha textura e o esfumaçado da foto continua liso — e aparece uma
   emenda dura exatamente na base do hero. Por cima de tudo, os dois lados
   recebem a MESMA textura e a emenda deixa de existir.

   z-index deles é 0 e 2; o modal (1055) e o backdrop (1050) do Bootstrap ficam
   acima dos dois. NÃO crie contexto de empilhamento no #site-chrome: o backdrop
   é filho do <body> e passaria a cobrir o próprio modal. */
body::before{
  content:""; position:fixed; inset:0; z-index:0; pointer-events:none;
  background:var(--sheen);
}
/* --------------------------------------------------------- A PEDRA ----------
   AQUI ERA GRÃO DE METAL ESCOVADO, EM `overlay`. A nota antiga fica registrada
   porque a conta dela continua valendo e é o que impede de "resolver isso com
   opacidade": um véu chapado a 5% sobre luminância 98 só varia entre 98 e 99,5,
   e a opacidade da camada é o TETO da textura, qualquer que seja o desenho do
   ruído. Foi por isso que o ruído virou alfa (feColorMatrix jogando o canal
   vermelho no alfa) em vez de cinza translúcido, e foi assim que o grão passou
   a existir sobre o preto.

   O que mudou não foi a mecânica, foi a SUPERFÍCIE. A do Alexandre é pedra, não
   metal (docs/MARCA.md §4), e o mesmo grão sobre o mármore SUJA: ruído de alta
   frequência que clareia e escurece pixel a pixel um fundo claro lê como
   chuvisco, não como material. Entra a placa do kit, em `soft-light`.

   `soft-light` e não `overlay`: os dois são neutros no cinza-médio, mas o
   overlay usa a claridade do FUNDO como pivô e satura rápido num fundo claro
   (o mármore está em 0,91 de 1) — a textura vira mancha. O soft-light usa a
   claridade da TEXTURA como pivô e comprime nas pontas; sobre um fundo claro
   ele empurra pouco e nunca estoura.

   A PLACA É QUASE LISA, e isso teve de ser medido antes de acreditar: o
   marmore.jpg tem 1080×1920 e desvio-padrão de 0,68 nível em 255 (mín 226, máx
   234). O veio existe — amplificado 30× ele aparece inteiro — mas em amplitude
   de ±4 níveis. Jogado cru em soft-light a 18%, ele mexe 0,03 nível no pixel
   final: a camada pinta e ninguém vê, exatamente o defeito que o grão anterior
   tinha.

   Daí o `filter`, que é o que faz a placa virar textura:
     grayscale(1)     tira o creme da própria placa, senão ela tinge a página
                      de bege por cima do bege — cor sobre cor, não relevo.
     brightness(.56)  leva a média de 228/255 para 128/255. É o passo que
                      importa: soft-light é neutro no CINZA-MÉDIO, e uma placa
                      centrada em 228 CLAREIA tudo. Com a média em 128 a
                      luminância média da página fica onde estava e só o veio
                      trabalha.
     contrast(16)     abre os ±4 níveis da placa para ±0,14 em torno do meio.
                      Sem isso não há o que mesclar. Acima de ~20 o bloco 8×8 do
                      JPEG começa a aparecer junto com o veio, e a textura passa
                      a ter grade — 16 é o ponto antes disso.

   `cover` e não `repeat`: o veio é uma FORMA grande, e repetir uma placa de
   1080px desenharia costura visível a cada tela. Esticado, o veio vira mancha
   larga de pedra, que é o que ele é.

   O número que fica no tema é a opacidade (--grain): .55 no mármore, .30 na
   tinta. A assimetria é física, não gosto — sobre fundo escuro o soft-light é
   ~2× mais sensível (a distância até a raiz da claridade é maior), então metade
   da opacidade dá a mesma textura. */
body::after{
  content:""; position:fixed; inset:0; z-index:2; pointer-events:none;
  opacity:var(--grain);
  mix-blend-mode:soft-light;
  background-image:url("/assets/brand/marmore.jpg");
  background-size:cover; background-position:center;
  filter:grayscale(1) brightness(.56) contrast(16);
}
/* Quem economiza dados não baixa uma placa de 44 KB para ver veio de pedra. A
   página continua correta sem ela: a textura é acabamento, não informação. */
@media (prefers-reduced-data:reduce){ body::after{ display:none; } }

/* DESKTOP: a janela do hero e proporcionalmente MUITO mais estreita que no
   celular — a mesma altura em rem cobre 64% da foto aqui contra 96% la. Por
   isso o valor nao pode ser um so. 48rem sobe o desktop para 88% e entrega o
   torso, o braco e a bola, que e o enquadramento do perfil do Instagram.

     altura   desktop   celular
     35rem      64%       96%
     42rem      77%      115%   <- ja corta as laterais no celular
     48rem      88%      131%
     54rem      99%      148%

   O celular fica de fora deste bloco de proposito: la 35rem ja esta no limite,
   e e a tela que converte. */
@media (min-width:768px){ :root{ --hero-h:43rem; } }

/* CELULAR ESTREITO. A conta que decide e sempre a mesma: a foto tem proporcao
   0,667, entao a altura em que ela cabe INTEIRA e largura/0,667. A 390px isso
   da 585px e os 35rem (560px) cabem; a 320px da 480px, e os mesmos 35rem viram
   117% — a foto deixa de caber e o `cover` corta 17% da LARGURA, levando o
   ombro junto. 30rem (480px) fecha exatamente a 320px.
   Medido em 320/360/375, nao estimado. */
@media (max-width:375px){ :root{ --hero-h:24rem; } }

a{ text-decoration:none; }
::selection{ background:var(--gold-ring); color:var(--text); }

/* ------------------------------------------------------- Fundo desfocado ---
   A foto do perfil, borrada, atrás de tudo — a camada de ambiente do
   link.me/hillerfit. Fica em z-index:0, ao lado do sheen e ABAIXO do .wrap
   (z-index:1), então nunca disputa com conteúdo nem com modal.

   SÓ EXISTE A PARTIR DE 768px, e isso é decisão de desempenho, não de gosto:
   no celular o cartão ocupa a largura toda e cobre este fundo por inteiro.
   Renderizá-lo lá seria pagar um blur de 44px sobre uma imagem de tela cheia —
   caro num Android médio, e logo no primeiro paint — por pixel que ninguém vê.
   A página que converte é a do celular; ela não paga por enfeite de desktop.

   O transform:scale existe porque `filter:blur()` amostra para fora do
   elemento e devolve borda transparente: sem escalar, aparece um halo claro
   nas quatro bordas da viewport. */
.bg-blur{ display:none; }
@media (min-width:768px){
  .bg-blur{
    display:block; position:fixed; inset:0; z-index:0; pointer-events:none;
    /* SEM fallback de URL. Ele existia como `var(--blur-img, url(...))` e era a
       TERCEIRA grafia do mesmo arquivo no site — o site.js escreve ?v=2, a home
       escreve ?v=2, e este fallback não tinha ?v= nenhum. Medido no /links a
       1440px: o .bg-blur pintava o fallback ANTES de o site.js definir a
       variável e depois trocava, baixando hero-blur.jpg duas vezes na mesma
       carga. E, por não ter ?v=, essa cópia nunca invalidava no cache de 24h.
       É o mesmo defeito que o comentário do chrome.js registra para o hero.
       O site.js define --blur-img sempre que houver heroBlur OU hero no config,
       então o fallback nunca era a única fonte — só uma segunda. */
    background-image:var(--blur-img);
    background-size:cover; background-position:center 18%;
    filter:var(--blur-filter);
    transform:scale(var(--blur-scale)); transform-origin:center;
  }
}
/* Quem pediu menos movimento não pediu menos contraste — o blur fica, só não
   custa animação nenhuma (ele já é estático). Mas em telas que economizam
   dados, não faz sentido baixar imagem só para borrar. */
@media (prefers-reduced-data:reduce){ .bg-blur{ display:none !important; } }

/* z-index:1 só aqui — levanta o cartão acima do sheen, sem tocar nos modais. */
.wrap{ max-width:var(--maxw); margin:0 auto; position:relative; z-index:1; }

/* Loader bar (topo) — varredura dourada */
.loader-bar{ display:none; height:.2rem; position:fixed; top:0; left:0; width:100%;
  z-index:9999; background:linear-gradient(90deg,var(--gold-dark),var(--gold),var(--gold-light)); }

/* MOBILE-FIRST: no celular a superfície é UMA SÓ, contínua do hero até o rodapé.
   Quem pinta é o .wrap — as seções ficam transparentes.

   Por que não deixar cada seção pintar o próprio --card-bg: nos metais esse token
   é um GRADIENTE com paradas próprias, e ele reinicia em cada elemento que o
   pinta. O cartão terminava num tom e os Resultados recomeçavam noutro → um
   degrau visível entre as duas seções. Com o .wrap pintando, o gradiente corre
   uma vez só, do topo ao rodapé.

   A faixa chapada é o que garante a emenda da foto: o hero dissolve em
   rgb(--bg-rgb) e a superfície embaixo dele precisa ser EXATAMENTE essa cor —
   não "quase". Como cada tema desenha o metal com stops próprios, essa garantia
   não pode depender do tema. */
.wrap{ background:
  linear-gradient(180deg,
    rgb(var(--bg-rgb)) 0,
    rgb(var(--bg-rgb)) calc(var(--hero-h) + 2.4rem),
    rgba(var(--bg-rgb),0) calc(var(--hero-h) + 13rem)),
  var(--card-bg); }
.card-on-desktop, .results, .footer-clear{ background:transparent; }

@media (min-width:768px){
  /* DESKTOP: voltam a ser cartões flutuantes, cada um com a sua superfície. */
  .wrap{ background:none; }
  .card-on-desktop{
    background:
      linear-gradient(180deg,
        rgb(var(--bg-rgb)) 0,
        rgb(var(--bg-rgb)) calc(var(--hero-h) + 2.4rem),
        rgba(var(--bg-rgb),0) calc(var(--hero-h) + 13rem)),
      var(--card-bg);
    margin-top:4.5rem !important;
    border-radius:2rem !important;
    /* SEM BORDA. Havia um fio de 1px aqui, e era ele que desenhava o traço
       escuro em volta do cartão — o mesmo que aparecia nos prints ampliados.

       Duas tentativas antes desta não resolveram, e vale registrar por quê:
       primeiro achei que era a sombra de contato que eu tinha somado (era um
       problema real, mas outro); depois que era o `background-clip:border-box`
       deixando o preto do cartão vazar por baixo da borda. Este segundo era
       verdade na ARESTA RETA — medido, o fio passou de rgb(31,32,34) para
       rgb(199,112,121). Só que no CANTO ARREDONDADO o traço continuou.

       Isolado trocando uma camada por vez, medindo a diagonal do canto:
         como estava .............. 110   traço escuro
         sem a borda .............. 215   limpo
         sem a sombra externa ...... 66   ainda escuro
         sem as duas .............. 216   limpo
       Ou seja: a sombra não tinha parte nisso, e no arredondamento o anel de
       1px é composto de um jeito que devolve escuro por mais que o fundo pare
       antes dele.

       A referência não tem borda: o que define a aresta é a foto encontrando o
       desfoque. Quem separa o cartão do fundo aqui é o mesmo — a moldura
       desfocada, mais o lábio de luz no topo e a sombra longe. */
    /* A ORDEM IMPORTA: as duas insets primeiro (elas desenham a aresta, e a
       primeira da lista fica por cima), as externas por último.

       EU TINHA POSTO UMA SOMBRA DE CONTATO AQUI — curta e escura, colada na
       borda — achando que era ela que "levantava" o cartão. Ela desenhou um
       ANEL PRETO em volta, e na referência esse anel não existe: lá a foto
       encosta direto no desfoque. Removida, junto com a inset escura da base,
       que somava ao mesmo efeito.

       Fica só o lábio de luz no topo, que é sutil e some quando não deve
       aparecer, mais o --shadow-card, que tem -30px de spread e por isso é a
       sombra LONGE — dá altura sem desenhar contorno. Era o suficiente.

       O --shadow-card não foi alterado: ele é compartilhado com o painel e com
       as páginas jurídicas, de fundo claro. */
    box-shadow:
      inset 0 1px 0 var(--aresta-luz),
      var(--shadow-card);
    overflow:clip;
  }
}

/* ---------------------------------------------------------------- Hero ----- */
.profile-hero-container{ position:relative; width:100vw; margin-left:calc(-50vw + 50%); }
@media (min-width:768px){
  .profile-hero-container{ width:100%; max-width:768px; margin:0 auto; }
}
.hero-background{ position:relative; width:100%; height:var(--hero-h); overflow:hidden; }
.hero-background img{ width:100%; height:100%; object-fit:cover;
  object-position:var(--hero-focus); filter:var(--hero-filter,brightness(.86) contrast(1.03)); display:block; }
.hero-background.no-img{ background:var(--card-bg); }

/* ------------------------------------------- Foto escurece ao rolar --------
   Como no link.me/hillerfit: conforme a pessoa desce, a foto vai apagando na cor
   do tema. Não é enfeite — é o que passa a atenção da foto para os links sem um
   corte seco, e é o que faz o topo "sair de cena" em vez de sumir de repente.

   É um véu com opacidade, e não `filter:brightness()` na imagem: filtro força o
   navegador a repintar a foto inteira a cada frame de rolagem; opacidade de uma
   camada já composta ele resolve na GPU. Num Android médio a diferença é entre
   rolar liso e rolar picotado.

   --hero-fade é escrito pelo site.js (0 no topo, 1 quando o hero saiu). Sem JS
   ele fica em 0 e a foto simplesmente não escurece — degradação limpa. */
.hero-veu{
  position:absolute; inset:0; z-index:1; pointer-events:none;
  background:rgb(var(--bg-rgb));
  opacity:calc(var(--hero-fade, 0) * .82);
  will-change:opacity;
}
/* Quem pediu menos movimento não pediu menos contraste: o véu fica, só não
   acompanha a rolagem — assume o valor cheio e para de mudar. */
@media (prefers-reduced-motion:reduce){ .hero-veu{ opacity:0; } }
@media (min-width:768px){
  .hero-image{ border-top-left-radius:2rem; border-top-right-radius:2rem; }
}
/* A foto DISSOLVE na cor do tema (mesma geometria em qualquer paleta). */
.hero-background::after{
  content:""; position:absolute; bottom:0; left:0; right:0; height:70%; pointer-events:none;
  background:
    linear-gradient(to top right, rgba(var(--bg-rgb),1) 0%, rgba(var(--bg-rgb),0) 30%),
    linear-gradient(to top left,  rgba(var(--bg-rgb),1) 0%, rgba(var(--bg-rgb),0) 30%),
    linear-gradient(to top,       rgba(var(--bg-rgb),.85) 0%, rgba(var(--bg-rgb),0) 25%),
    linear-gradient(to top,       rgba(var(--bg-rgb),1) 0%, rgba(var(--bg-rgb),1) 10%, rgba(var(--bg-rgb),0) 100%);
}
.hero-icon{ position:absolute; top:1rem; z-index:2; }
.hero-icon-left{ left:1rem; } .hero-icon-right{ right:1rem; }
.hero-icon button, .hero-icon a{ outline:none!important; box-shadow:none!important; }
/* O CÍRCULO continua com 32px (é o desenho); quem cresce para 44 é a ÁREA
   CLICÁVEL em volta dele. Aumentar o círculo deixaria o topo da foto pesado;
   aumentar só o alvo resolve o dedo sem mexer no visual. O padding negativo na
   margem mantém o ícone exatamente onde estava. */
.hero-icon a, .hero-icon button{
  display:inline-flex; align-items:center; justify-content:center;
  width:44px; height:44px; margin:-6px; }
/* O CHIP CARREGA O PRÓPRIO CONTRASTE. Era aro branco a 22% sobre preto a 30% com
   ícone branco: uma peça que só existia porque a foto atrás era escura. Sobre o
   mármore ela sumiria duas vezes — o preto a 30% clareia até quase nada e o
   ícone branco fica sobre um fundo claro.

   Agora o disco é a cor do CARTÃO a 55% e o ícone é a cor de TEXTO do tema: os
   dois se resolvem entre si (14,7:1 no mármore) e o chip para de depender do
   que a foto tem embaixo — inclusive quando a foto do topo for trocada. O
   desfoque continua, porque é ele que impede o disco translúcido de virar uma
   mancha leitosa sobre detalhe de foto. */
.icon-circle{ display:inline-flex; align-items:center; justify-content:center;
  width:2rem; height:2rem; border-radius:50%;
  border:1px solid rgba(var(--sombra-rgb),.16); background:rgba(var(--bg-rgb),.55);
  -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
  transition:border-color .18s ease, color .18s ease; }
.icon-circle i{ font-size:.9rem; color:var(--text); }
.hero-icon a:hover .icon-circle, .hero-icon button:hover .icon-circle{ border-color:var(--gold-ring); }
.hero-icon a:hover .icon-circle i, .hero-icon button:hover .icon-circle i{ color:var(--accent); }

/* ---------------------------------------- Identidade SOBRE a foto (hero) ---
   z-index:3 — acima do ::after (o esfumaçado) e dos .hero-icon (z-index:2).

   `pointer-events:none` no bloco, `auto` nos filhos clicáveis: sem isso, esta
   caixa cobriria a metade de baixo da foto e engoliria qualquer clique que
   passasse por ali. Os chips de rede continuam clicáveis porque são reativados
   um a um. */
.hero-overlay{
  position:absolute; left:0; right:0; bottom:0; z-index:3; pointer-events:none;
  /* gap:0 e cada vão declarado no próprio elemento. Com um gap uniforme aqui,
     as margens do @ e da fila de redes SOMAVAM a ele, e as medidas tiradas do
     link.me/hillerfit saíam 7px maiores do que o pedido — o erro era invisível
     em cada regra e visível na pilha inteira. */
  display:flex; flex-direction:column; align-items:center; gap:0;
  padding:0 1rem 1.1rem;
}
.hero-overlay > *{ pointer-events:auto; }

/* -------------------------------------------------------- CÍRCULO DO PERFIL -
   NÃO EXISTE NO SITE DE ORIGEM. Lá o nome cai direto na foto; aqui o Alexandre
   mandou o print do perfil do Instagram com a bolinha sobre o fundo fosco
   justamente para pedir isto (docs/MARCA.md §7). É a diferença visual mais
   visível entre os dois sites, e é intencional.

   O chrome.js emite exatamente esta marcação, como PRIMEIRO filho do
   .hero-overlay:
     <div class="hero-avatar"><img src="..." alt="Alexandre Gutierrez Andrade"></div>

   6,25rem (100px) no celular e 7rem (112px) a partir de 768px: a mesma
   proporção do avatar sobre a capa no perfil do Instagram, onde o círculo vale
   ~26% da largura útil. Maior que isso ele empurra o nome para dentro da foto e
   come o esfumaçado; menor, vira ícone e deixa de ser retrato.

   A borda de 3px é a cor do CARTÃO, não branca: ela é o "recorte" que separa o
   retrato da foto atrás, e por isso tem de ser a cor em que a foto dissolve —
   branca sobre creme desenharia um segundo anel que ninguém pediu.

   margin-bottom de .7rem (11,2px): é a ÚNICA medida de respiro registrada nesta
   pilha (a fila de redes fica a 11px do @, medida no link.me/hillerfit). Repetir
   o mesmo número mantém o ritmo vertical do hero em vez de inventar um terceiro.

   line-height:0 no bloco porque o <img> é inline por padrão e o navegador
   reserva o espaço do descendente embaixo dele — 4px de vão fantasma que
   estragariam justamente a medida acima. */
.hero-avatar{
  flex:0 0 auto; line-height:0; margin-bottom:.7rem;
  width:6.25rem; height:6.25rem; border-radius:50%;
  border:3px solid rgb(var(--bg-rgb));
  box-shadow:0 10px 26px -14px rgba(var(--sombra-rgb),.55);
  overflow:hidden; background:var(--surface);
}
.hero-avatar img{
  width:100%; height:100%; display:block; object-fit:cover; object-position:center;
  border-radius:50%;
}
@media (min-width:768px){ .hero-avatar{ width:7rem; height:7rem; } }
/* A linha do nome carrega o CORPO do nome. Só o selo se importa: ele é
   dimensionado em `em` (0,656× o nome, a proporção do HillerFit) e assim
   encolhe junto quando o nome encolhe, em vez de descolar. */
/* BLOCO DE TEXTO, e não linha de flex. Era `display:flex` e funcionava
   enquanto o nome cabia numa linha: o <h1> e o selo eram irmãos lado a lado.

   Com "Alexandre Gutierrez Andrade" (27 caracteres contra os 17 de antes) o
   nome passa a ocupar DUAS linhas em tudo abaixo de 1280px, e o flex fez o que
   flex faz: manteve os dois irmãos lado a lado. O selo saiu do fim do nome e
   foi parar centralizado na vertical à direita do bloco inteiro — solto no ar,
   ao lado de "Gutierrez", sem relação visível com o nome. E o <h1>, ocupando a
   largura toda, ficou com o texto encostado à esquerda enquanto o @ e as redes
   logo abaixo continuavam centrados.

   Como bloco com `text-align:center` e o <h1> em `display:inline`, o nome volta
   a ser TEXTO: quebra centralizado e o selo, sendo inline, corre atrás da
   última palavra em vez de flutuar. O comportamento passa a ser o mesmo com uma
   ou com duas linhas, que é o que o torna seguro para o próximo nome. */
.hero-overlay .name-line{ display:block; text-align:center;
  max-width:100%; font-size:2rem; line-height:1.14; }
.hero-overlay .name-line .profile-name{ display:inline; }
.hero-overlay .name-line #profileBadge{ display:inline; white-space:nowrap; }
@media (max-width:360px){ .hero-overlay .name-line{ font-size:1.7rem; } }

/* ------------------------------------------------------------- Perfil ------ */
/* Sobre a FOTO o nome é pesado e branco (não var(--text)): ele precisa
   funcionar mesmo que o esfumaçado falhe ou a foto seja trocada por uma clara.
   O text-shadow é rede de segurança, não decoração — por isso é largo e suave,
   e não um contorno duro. */
/* ---------------------------------------------------------------------------
   Os valores abaixo NÃO foram escolhidos a olho: foram lidos do CSS e do HTML do
   próprio link.me/hillerfit. Vale registrar porque o instinto erra para o mesmo
   lado — "parecer HillerFit" sugere mais peso e mais aperto, e a medição mostrou
   o contrário:

     nome       32px · peso 750 · letter-spacing +0,25px   (POSITIVO)
     @handle    12px · peso 400
     contador   14px · peso 500
     título     16px · peso 600 · line-height 1,3

   Antes daqui estava 900/-0,035em, e era essa a diferença que se via.

   O QUE MUDOU COM A LITERATA. O peso 750 e o letter-spacing POSITIVO de +0,25px
   eram da Inter: numa grotesca variável, 750 é o corpo do nome no HillerFit e o
   espaço extra compensa o aperto natural dela. A Literata é serifa, mais
   estreita e já espaçada pelas próprias serifas — repetir aqueles dois números
   deixava o nome ralo e largo. O kit do Alexandre fixa o display em **800 com
   letter-spacing -.028em** (docs/MARCA.md §3), e é isso que está abaixo.

   `opsz 72` é o topo do eixo óptico da Literata: hastes mais finas e serifas
   mais delicadas, que é o desenho que a fonte tem nos tamanhos grandes. Fica em
   `font-variation-settings` e NÃO em `font-optical-sizing`, porque o automático
   entregaria opsz 32 (o tamanho da letra) e o kit pede 72. `wght` continua fora
   da variation-settings de propósito: declarado ali, ele CONGELARIA o peso e o
   `font-weight` acima deixaria de valer.

   A entrelinha continua 1.14, e não o .96 que o kit usa em título de peça: 1.14
   é geometria do hero — é ela que posiciona o nome em relação ao @ e às redes,
   tudo medido no link.me/hillerfit. Trocar a entrelinha aqui move a pilha
   inteira para ganhar 5px numa linha só.
   --------------------------------------------------------------------------- */
.profile-name{ font-weight:800; font-size:2rem; letter-spacing:-.028em;
  font-variation-settings:"opsz" 72;
  color:var(--on-hero); margin:0; line-height:1.14;
  text-shadow:var(--on-hero-shadow);
  overflow-wrap:anywhere; }
/* O link.me encolhe o nome por JS quando ele não cabe. Aqui a mesma coisa em
   CSS: abaixo de 360px, 32px estoura em nome comprido — e "Alexandre Gutierrez Andrade"
   tem 17 caracteres, quatro a mais que "Léo Nicolazzi". Medido em 320px: a 2rem
   ele ocupa 285px dos 288px úteis e encosta nas duas margens; a 1.7rem sobram
   47px. */
@media (max-width:360px){ .profile-name{ font-size:1.7rem; } }
/* Selo, @ e chips: as medidas abaixo foram TIRADAS DA PÁGINA do link.me/hillerfit
   com o mesmo viewport (390px), e não estimadas por print. O que estava aqui
   antes era plausível e uniformemente mais frouxo — o efeito somado é o que se
   via como "espaçado demais".

     selo      21px, a 3px do nome        (aqui: 18,4px a 7,7px)
     @         14px, a 1,6px do nome      (aqui: 12,8px a 7,2px)
     chips     39,5px, vão de 1,9px       (aqui: 44px, vão de 8,8px)
     chips     a 11px do @                (aqui: 7,2px)

   O selo é 0,656× o corpo do nome; em `em` ele acompanha o nome quando a tela
   encolhe, em vez de descolar. */
/* SEM drop-shadow. O selo do link.me/hillerfit não tem nenhuma, e numa peça de
   21px uma sombra preta a 50% não lê como profundidade: ela escurece o desenho
   inteiro, porque o borrão cai em cima da própria figura tanto quanto ao redor.
   Medido: com a sombra, o roxo do canto inferior saía visivelmente mais escuro
   que o deles; sem ela, os dois batem. */
/* A ALTURA DELE NA LINHA. `vertical-align:middle` alinha o meio do selo com o
   meio do X-HEIGHT — a altura do "o", não a das maiúsculas. Em texto todo
   minúsculo (o @alexandre.gutierrez.andrade do Instagram) os dois coincidem e ninguém nota.
   Em "Léo Nicolazzi", com L e N, o meio das maiúsculas fica 4,5px mais alto, e
   o selo passa a parecer pendurado na linha de base.

   Medido nesta página, e não estimado por print: maiúsculas de 24px acima da
   base, selo de 21,7px, centro do selo 4,5px abaixo do centro das maiúsculas.
   4,5 / 32 = 0,14em — em `em` para acompanhar quando o nome encolhe abaixo de
   360px, senão o ajuste ficaria certo só numa largura.

   translateY e não margem: margem empurraria a linha inteira. */
.verified-badge{ width:.678em; height:.678em; flex:0 0 auto; margin-left:3px;
  transform:translateY(-.14em); }
.profile-handle{ font-size:14px; font-weight:400; color:var(--on-hero-2);
  text-shadow:var(--on-hero-shadow); line-height:1.15; margin-top:1.6px; }

/* ---------------------------------------------------- Redes (chips) --------
   Círculos com a cor da MARCA, como no HillerFit — 44px, que é o alvo de toque
   recomendado. O ícone é branco em todos; os fundos vêm de --net-* logo abaixo,
   um por rede, e não de token de tema: a cor do Instagram é do Instagram, não
   nossa, e não pode mudar quando o tema muda. */
.social-row{ display:flex; flex-wrap:wrap; justify-content:center; gap:1.9px; margin-top:11px; }
/* 39,5px é a medida deles, e é MENOR que os 44px de alvo de toque recomendado.
   O círculo fica no tamanho pedido e o alvo é devolvido por um pseudo-elemento
   invisível de 44px: quem olha vê o desenho do HillerFit, quem toca com o
   polegar acerta assim mesmo. Encolher o alvo junto com o desenho seria trocar
   acerto de toque por semelhança visual, e dá para ter os dois. */
.social-chip{ position:relative; }
.social-chip::after{ content:""; position:absolute; left:50%; top:50%;
  width:44px; height:44px; transform:translate(-50%,-50%); border-radius:50%; }
.social-chip{
  width:39.5px; height:39.5px; border-radius:50%;
  display:inline-flex; align-items:center; justify-content:center;
  color:#fff; font-size:1.15rem; text-decoration:none;
  /* A sombra sai da tinta do tema, não de preto puro: sobre o creme, preto a
     85% desenhava um borrão cinza embaixo de cada chip. */
  box-shadow:0 6px 18px -8px rgba(var(--sombra-rgb),.35);
  transition:transform .18s ease, box-shadow .18s ease;
}
.social-chip:hover, .social-chip:focus-visible{ color:#fff; transform:translateY(-3px);
  box-shadow:0 10px 22px -8px rgba(var(--sombra-rgb),.45); }
.social-chip i{ pointer-events:none; }
/* Redes de marca PRETA (TikTok, X). No tema ESCURO elas somem contra o hero e
   viram um buraco no meio da fileira — daí o aro claro. No MÁRMORE o problema
   não existe: um disco preto sobre creme já tem forma de sobra, e um aro claro
   ali só comeria a silhueta do chip. Por isso o aro é TOKEN e não cor: no claro
   ele é transparente (o 1px continua ocupando o mesmo lugar, então nada se
   move) e no escuro o theme-tinta.css devolve o aro branco a 28%. */
.social-chip[data-net="tiktok"], .social-chip[data-net="x"]{
  background:#000; border:1px solid var(--aro-preto); }
.social-chip[data-net="instagram"]{
  background:radial-gradient(circle at 30% 107%,
    #FDF497 0%, #FDF497 5%, #FD5949 45%, #D6249F 60%, #285AEB 90%); }
.social-chip[data-net="youtube"]{ background:#FF0000; }
.social-chip[data-net="facebook"]{ background:#1877F2; }
.social-chip[data-net="linkedin"]{ background:#0A66C2; }
.social-chip[data-net="whatsapp"]{ background:#25D366; }
/* O site oficial não tem cor de marca — usa a do tema, e é o único chip que
   acompanha a troca de azul. */
.social-chip[data-net="website"]{ background:var(--gold); background-image:var(--cta-bg,none); background-size:var(--cta-bg-size,auto); color:var(--on-gold); }
.social-chip[data-net="website"]:hover{ color:var(--on-gold); }

/* "Brasileiro" — a MESMA cor das credenciais logo abaixo (--text-2).
   Era --accent, a cor de destaque do tema. Funcionava enquanto o destaque era
   um azul discreto; com o Brasa virou vermelho, e três linhas vermelhas
   empilhadas competiam com o CTA vermelho a poucos pixels dali. Duas coisas
   gritando ao mesmo tempo é o mesmo que nenhuma gritar.
   O destaque agora é do CTA, sozinho. Este bloco é informação, e informação
   se lê melhor na cor de leitura. */
.profile-category{ color:var(--text-2); font-size:.9rem; text-decoration:none;
  display:inline-flex; align-items:center; gap:.4rem; line-height:1.28; }
/* Continua sendo um link, então continua reagindo — só que clareando, em vez
   de mudar de matiz. Sem nenhuma reação, deixa de parecer clicável. */
.profile-category:hover{ color:var(--text); }
/* A bandeira acompanha o tamanho do texto (em, não px) e fica levemente acima da
   linha de base ótica, senão "afunda" ao lado da maiúscula. */
.flag-br{ width:1.15em; height:auto; flex:0 0 auto; display:block; margin-top:-.05em;
  border-radius:.14em; box-shadow:0 1px 2px rgba(var(--sombra-rgb),.18); }
.profile-bio{ font-size:.9rem; line-height:1.45; color:var(--text-2); margin-top:0; }
/* IDENTIDADE: gruda no "Brasileiro" e agora na MESMA cor dele e das
   credenciais. O que mantém os dois blocos separados não é mais a cor — é o
   respiro do .bio-rest logo abaixo e a entrelinha apertada aqui (1.28), que
   faz as três linhas lerem como UM bloco em vez de uma lista. Espaço separa
   tão bem quanto cor, e não gasta o vermelho. */
.profile-bio .bio-lead{ color:var(--text-2); line-height:1.28; }
/* Respiro evidente antes das CREDENCIAIS: é o que separa "quem ele é" de
   "o que ele tem". */
.profile-bio .bio-rest{ margin-top:.95rem; }

/* Botões do cabeçalho — CTA liso; o metálico só no HOVER.

   min-height:44px NÃO é folga estética. Estes dois botões são a conversão
   inteira da página, e no projeto irmão eles ficaram com 35px de altura — abaixo
   do alvo de toque recomendado para o polegar, num site em que quase todo
   visitante chega pelo Instagram, no celular. Lá isso virou dívida registrada e
   nunca foi cobrado; aqui já nasce pago. */
.btn-header{
  border-radius:.65rem; font-weight:600; font-size:.95rem; padding:.55rem .5rem;
  min-height:44px;
  /* O contorno é --gold-border, e não `transparent`: nesta paleta há tons que
     separam do fundo preto por 1,1:1 — a cor está certa e a FORMA do botão some.
     Nos temas em que a barra já se destaca, o token é `transparent` e nada muda. */
  border:1px solid var(--gold-border,transparent);
  /* --cta-bg: a RAMPA, nos temas que têm uma. Nos temas de cor chapada o token
     nem existe e o fallback `none` mantém o botão exatamente como sempre foi —
     por isso os sete tons originais não mudaram um pixel quando os gradientes
     entraram. */
  background-color:var(--gold); background-image:var(--cta-bg,none); background-size:var(--cta-bg-size,auto);
  color:var(--on-gold); width:100%;
  transition:background-image .25s ease, box-shadow .2s ease, transform .15s ease;
}
.btn-header:hover, .btn-header:focus{
  background-image:var(--gold-grad); color:var(--on-gold);
  box-shadow:0 8px 22px -10px var(--gold-glow); transform:translateY(-1px);
}

/* ---------------------------------------------------------------------------
   MOTION: o brilho do CTA SEGUE O CURSOR (não fica parado).
   shine.js escreve --mx/--my (a posição do ponteiro dentro do botão, em %) e o
   radial se ancora ali. Sem JS, --mx/--my caem no fallback 50%/50% e vira um
   metálico centrado — degradação limpa.

   Gateado por (hover:hover) and (pointer:fine): no CELULAR não existe hover, e
   sem o gate o Android/iOS "grudam" o estado de hover no último botão tocado.
   No toque, o metálico entra no :active (um sweep curto ao pressionar).
   --------------------------------------------------------------------------- */
.btn-shine{
  --mx:50%; --my:50%;
  transition:background-image .25s ease, background-position .12s linear,
             box-shadow .2s ease, transform .15s ease;
}
@media (hover:hover) and (pointer:fine){
  .btn-shine:hover{
    background-image:radial-gradient(circle at var(--mx) var(--my),
      var(--shine) 0%, var(--gold) 42%, var(--gold-dark) 100%);
    /* o radial persegue o cursor: a transição do background-image ficaria
       "arrastando" a cada frame, então aqui ela é desligada */
    transition:box-shadow .2s ease, transform .15s ease;
  }
}
.btn-shine:active{ background-image:var(--gold-grad); }
@media (prefers-reduced-motion:reduce){
  .btn-shine, .btn-shine:hover{ transition:none; background-image:var(--gold-grad); }
}
/* o secundário (Parcerias) é de vidro: não brilha */
.btn-header-secondary.btn-shine:hover, .btn-header-secondary.btn-shine:active{ background-image:none; }
/* Secundário = VIDRO (painel translúcido, à la HWPO) */
.btn-header-secondary{
  background-color:var(--glass-bg-2); background-image:none; color:var(--text);
  border:1px solid var(--glass-border);
  -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur);
}
.btn-header-secondary:hover, .btn-header-secondary:focus{
  background-color:var(--glass-bg-2); background-image:none; color:var(--accent);
  border-color:var(--gold-ring); box-shadow:none; transform:none;
}

/* (As redes ficam no .hero-overlay, como .social-chip — ver a seção "Perfil".
   A antiga fileira de ícones chapados abaixo dos botões não existe mais.) */

/* ============================================================================
   VITRINE DE PRODUTOS — a faixa que passa sozinha
   ==========================================================================
   A faixa SANGRA até a borda do cartão (sem margem lateral) para os produtos
   saírem de cena pelos lados. O respiro que as margens dariam é devolvido por
   dentro, no padding da fila: assim o primeiro cartão nasce alinhado com o
   resto da página, mas a faixa continua correndo de ponta a ponta.
   ========================================================================== */
.produtos{ margin:1.15rem 0 .25rem; }
.produtos:empty{ display:none; }

.pv-janela{
  overflow:hidden; cursor:grab; touch-action:pan-y;
  user-select:none; -webkit-user-select:none;
  /* As máscaras esfumaçam as duas pontas na cor do cartão: sem elas, o produto
     aparece e some com um corte reto, e a faixa lê como conteúdo cortado em vez
     de conteúdo em movimento. */
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 5%,#000 95%,transparent 100%);
          mask-image:linear-gradient(90deg,transparent 0,#000 5%,#000 95%,transparent 100%);
}
.pv-janela.pv-pegando{ cursor:grabbing; }
/* Um produto só: nada a rolar. Fica parado e centrado, sem máscara. */
.pv-janela.pv-parada{ cursor:default; -webkit-mask-image:none; mask-image:none; }
.pv-janela.pv-parada .pv-fila{ justify-content:center; }

.pv-fila{ display:flex; gap:.9rem; width:max-content; padding:.35rem 1rem .5rem;
  will-change:transform; }
@media (min-width:768px){ .pv-fila{ padding-left:3rem; padding-right:3rem; } }

.pv-card{
  /* Legenda e preço CENTRADOS sob a capa. Alinhados à esquerda, um nome curto
     como "Pull-up" ficava encostado na borda enquanto a arte do cartão era
     simétrica — o desencontro entre um e outro é o que se lê como torto. */
  flex:0 0 auto; width:10rem; display:flex; flex-direction:column; gap:.45rem;
  padding:0; border:0; background:none; text-align:center; align-items:center;
  cursor:pointer; color:inherit;
}
.pv-card:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; border-radius:.9rem; }
/* ---------------------------------------------------- CAPA DO PRODUTO -------
   A capa usa OS MESMOS tokens do botão: --gold de fundo, --cta-bg quando o tema
   é rampa ou trama, --on-gold para tudo que é traço e letra. Antes ela era um
   JPEG com a cor cozida dentro, e a vitrine ficava azul-escura nos 24 temas
   enquanto as barras logo acima trocavam de cor. Onze imagens não acompanham
   vinte e quatro paletas; tokens acompanham. */
.pv-capa{
  position:relative; display:block; width:100%; aspect-ratio:3/4; border-radius:.85rem; overflow:hidden;
  background-color:var(--gold); background-image:var(--cta-bg,none);
  background-size:var(--cta-bg-size,auto);
  border:1px solid var(--glass-border);
  transition:transform .28s ease, border-color .28s ease,
             filter .45s ease, box-shadow .35s ease;
  /* Cor do foco do hover: derivada de --gold-light, que TODO tema tem e que é,
     por construção, mais clara que o preenchimento.

     A primeira tentativa usou --on-gold (a cor do rótulo). Funcionava nos temas
     escuros e falhava nos claros pelo motivo óbvio depois de ver: nos claros o
     rótulo é ESCURO, então o foco virava uma mancha suja seguindo o cursor, e
     não uma luz. Luz tem de clarear em qualquer tema — daí --gold-light. */
  --pv-brilho:rgba(255,255,255,.30);
}
@supports (color:color-mix(in srgb, red, blue)){
  .pv-capa{ --pv-brilho:color-mix(in srgb, var(--gold-light) 82%, white); }
}
@media (hover:hover) and (pointer:fine){
  .pv-card:hover .pv-capa{ transform:translateY(-3px); border-color:var(--gold-ring);
    filter:saturate(1.14) brightness(1.07); box-shadow:0 14px 30px -16px var(--gold-glow); }
  .pv-card:hover .pv-capa::before{ opacity:1; }
  .pv-card:hover .pv-arte{ opacity:.46; }
}

/* O pictograma entra como MÁSCARA: o PNG dá só a forma, a cor vem do tema. Um
   <img> ficaria branco e sumiria nos temas claros.

   E ele se APAGA sozinho para baixo, por uma segunda máscara sobreposta à
   primeira. Antes havia um VÉU pintado por cima do cartão, de transparente até
   `--gold`, para o texto assentar. Isso partia o cartão ao meio — e nos temas
   de rampa `--gold` é a MÉDIA das paradas, uma cor que não existe em ponto
   nenhum do gradiente: a metade de baixo ficava de um tom que não combinava com
   a de cima. Apagando o DESENHO em vez de pintar por cima, o fundo continua uma
   cor contínua só, em qualquer um dos 24 temas. */
.pv-arte{
  position:absolute; inset:0; display:block; opacity:.34;
  background-color:var(--on-gold);
  -webkit-mask:var(--m) center/contain no-repeat,
               linear-gradient(to bottom,#000 42%,transparent 68%);
  -webkit-mask-composite:source-in;
  mask:var(--m) center/contain no-repeat,
       linear-gradient(to bottom,#000 42%,transparent 68%);
  mask-composite:intersect;
  transition:opacity .4s ease;
}
/* Foco de luz que SEGUE o ponteiro dentro do cartão. As coordenadas chegam em
   --mx/--my (por cento), escritas pelo site.js a cada quadro.

   É um radial, e não uma faixa diagonal, porque a faixa passava UMA vez e
   acabava: o cartão voltava a ficar estático com o mouse ainda em cima dele. Um
   foco que acompanha responde enquanto a mão estiver ali — a luz existe por
   causa de onde a pessoa está olhando, que é o que dá sensação de material.

   A cor sai de --on-gold: branco fixo sumiria no Neon Aqua e no Sal, preto
   fixo mancharia o Dark Night e o Abissal. */
.pv-capa::before{
  content:""; position:absolute; inset:0; z-index:1; pointer-events:none;
  /* GRADIENTE de luz, não um ponto de luz. O ângulo (--ang) aponta para o lado
     onde o cursor está, e a claridade decai atravessando o cartão inteiro — a
     leitura é de uma superfície iluminada de um lado, como metal ou vidro sob
     uma janela. O radial que estava aqui antes era um foco de lanterna: uma
     bolha viajando por cima da arte, que chamava atenção para si em vez de dar
     material ao cartão.
     A parada em -20% joga o pico do gradiente para FORA da borda: assim a
     claridade máxima fica na aresta do lado do cursor, e não numa faixa
     brilhante no meio do caminho. */
  background:linear-gradient(var(--ang,135deg),
    var(--pv-brilho) -20%, transparent 58%);
  opacity:0; transition:opacity .3s ease;
}
/* Camadas, para o foco nunca lavar o texto: desenho embaixo, luz no meio,
   letras e moldura por cima. */
.pv-arte{ z-index:0; }
.pv-capa-txt{ z-index:2; }
.pv-capa::after{ z-index:3; }
/* Moldura fina, como a das capas antigas — agora na cor do tema. */
.pv-capa::after{
  content:""; position:absolute; inset:5.5%; border:1px solid var(--on-gold);
  opacity:.3; border-radius:.2rem; pointer-events:none;
}
.pv-capa-txt{
  /* Ancorado pelo TOPO, não pelo pé. Preso embaixo, a régua subia nos títulos
     de duas linhas e a fileira de cartões ficava desalinhada — o mesmo defeito
     que já tinha aparecido quando as capas eram imagem. Com o topo fixo, régua
     e primeira linha caem na mesma altura nos onze e só o título comprido desce
     mais. */
  /* O bloco tem TOPO E PÉ definidos, e o layout distribui o que está dentro:
     rótulo e título encostam no topo, a assinatura é empurrada para o pé por
     `margin-top:auto`. Posicionar os dois por conta própria — um pelo topo, a
     outra pelo pé — funcionava no título de uma linha e fazia o de duas linhas
     escrever por cima da assinatura. Aqui não há como colidir: é o mesmo
     espaço, repartido. */
  /* O TOPO SUBIU DE 56% PARA 42%, e isso é conta, não gosto.

     O chapéu mudou de "DESBLOQUEIE O" (13 caracteres) para "TUDO QUE VOCÊ
     PRECISA SABER SOBRE" (33). Na largura útil da capa (10rem menos os 8% de
     cada lado = 134px) ele ocupa DUAS linhas — e as duas linhas não cabiam no
     que sobrava abaixo de 56%.

     A conta, no cartão de 10rem (capa 3/4 = 213px de altura):
       assinatura + folga do pé (bottom 6.5%) .....  14px
       assinatura ....................................  9px
       nome, o pior caso — "Mindfulness e Regulação Emocional", que o site.js
         quebra palavra por palavra em 4 linhas de .98rem/1.1 ............ 69px
       chapéu, 2 linhas de .5rem/1.05 + filete e padding ................. 24px
       ------------------------------------------------------------------
       necessário .................................................. ~116px
     213 - 14 - 116 = 83px de topo, que é 39% da capa. 42% dá 89px e deixa 6px
     de folga para o arredondamento das fontes. Abaixo de 42% o chapéu invade a
     parte opaca do pictograma (a máscara só começa a apagar em 42%) e o cartão
     vira texto sobre desenho.

     RENDERIZAR OS SETE antes de mexer neste número. O que quebra não é a média,
     é o cartão mais comprido — e ele é sempre outro quando os nomes mudam. */
  position:absolute; left:8%; right:8%; top:42%; bottom:6.5%; z-index:1;
  display:flex; flex-direction:column; align-items:center; text-align:center;
  color:var(--on-gold);
}
/* O chapéu de DUAS linhas. `line-height:1.05` é o aperto que faz as duas linhas
   lerem como um bloco só, e não como duas frases empilhadas — em caixa alta e
   com .14em de tracking, entrelinha normal abre um vão do tamanho da própria
   letra. `text-wrap:balance` reparte as 33 letras entre as duas linhas em vez
   de deixar uma cheia e a outra com duas palavras, que é o que o navegador faz
   sozinho e o que faz o bloco parecer torto ao lado dos outros seis. */
.pv-olho{ font-size:.5rem; letter-spacing:.14em; text-transform:uppercase;
  line-height:1.05; text-wrap:balance;
  opacity:.72; padding-top:.42rem; border-top:1px solid currentColor;
  width:100%; margin-bottom:.28rem; }
/* O NOME PRECISA PODER QUEBRAR DENTRO DA PALAVRA, e isso não é preciosismo:
   sem esta regra, quatro dos sete cartões saíam CORTADOS a 320px e dois a
   390px. Medido na página, comparando a largura do texto com a da caixa
   (.pv-capa-txt, que é 116px a 320 e 133px a 390):

     AUTOGERENCIAMENTO ............ 199px   transborda 66px a 390, 83px a 320
     MEMÓRIA, APRENDIZADO E … ..... 142px   transborda  9px a 390, 26px a 320
     EFETIVIDADE INTERPESSOAL ..... 129px   transborda 13px a 320
     MINDFULNESS E REGULAÇÃO … .... 124px   transborda  8px a 320

   A causa é a soma de três coisas que sozinhas não fariam mal: o site.js troca
   os espaços do nome por <br> (para cada palavra cair numa linha), o
   `text-transform:uppercase` engorda o texto, e o .pv-capa tem
   `overflow:hidden`. Nome de UMA palavra só não tem espaço para virar <br>,
   então ele não quebra em lugar nenhum, cresce além da caixa e o overflow o
   decepa nas duas pontas — foi assim que "AUTOGERENCIAMENTO" apareceu na tela
   como "TOGERENCIAMENT", sem erro nenhum no console.

   `hyphens:auto` resolve direito: o navegador hifeniza pelo dicionário do
   idioma (o <html> declara lang="pt-BR"), então sai "AUTOGEREN-CIAMENTO" e não
   um corte no meio de sílaba. O `overflow-wrap:break-word` fica como rede: se o
   dicionário não estiver disponível, o texto quebra sem hífen — feio, mas
   inteiro. Vale mais palavra quebrada do que palavra decepada. */
.pv-nome{ font-size:.98rem; font-weight:700; line-height:1.1; text-transform:uppercase;
  letter-spacing:.01em;
  hyphens:auto; -webkit-hyphens:auto;
  overflow-wrap:break-word;
  /* SEM `text-wrap:balance`, e a tentativa fica registrada porque a intuição
     diz o contrário. Ele equaliza o comprimento das linhas, o que soa como
     "ocupa melhor o espaço" — na prática ele ACRESCENTA linha para equalizar, e
     medido no cartão isso piorou o transbordo em três dos sete. Aqui o que
     falta é altura, não simetria. */
}
/* Só os rótulos com mais de 20 caracteres. Ver a conta no site.js, onde a
   classe é decidida — resumo: com corpo único, os sete só cabem a 0,80rem, e aí
   "HIGIENE DO SONO" encolhe por causa de "MEMÓRIA, APRENDIZADO E
   CONCENTRAÇÃO". Encolhendo só os compridos, os curtos ficam em 0,98rem. */
.pv-nome-longo{ font-size:.76rem; }
/* A assinatura passou a ocupar DUAS linhas quando o nome virou "Alexandre
   Gutierrez Andrade" (27 caracteres contra 17). Sem entrelinha declarada ela
   herdava ~1,49, e as duas linhas somavam 21px num bloco que tinha 0px de
   folga: dois dos sete cartões estouravam 2px a 320 e 360px.
   1,2 é o aperto que uma linha de caixa alta com letter-spacing largo aceita
   sem as letras se tocarem na vertical — e devolve os 4px que faltavam. */
.pv-assin{ margin-top:auto; font-size:.44rem; letter-spacing:.16em;
  line-height:1.2;
  text-transform:uppercase; opacity:.55; }
/* Quando houver FOTO do Léo executando o movimento, ela entra por cima e a
   máscara não é usada — mas o texto continua no tema, sobre um véu. */
.pv-foto{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
  display:block; -webkit-user-drag:none; pointer-events:none; }

/* VÉU SOB O TEXTO, só nas capas com FOTO.
   Com o pictograma, o fundo do cartão é o bronze do tema: uma cor conhecida,
   contra a qual o branco do rótulo foi medido. Com foto o fundo passa a ser
   imprevisível — e o mesmo branco, sobre uma foto clara, simplesmente some.

   O gradiente começa transparente e só fecha a partir de 34%, que é onde o
   bloco de texto começa (medido: .pv-capa-txt abre em 42,1% da altura, e os 8
   pontos de folga evitam uma aresta visível bem na primeira linha). A parte de
   CIMA da foto fica limpa — é lá que o assunto deve estar.

   z-index 1: acima da foto (0) e abaixo do texto (2) e da moldura (3). */
.pv-capa-foto::before{
  content:""; position:absolute; inset:0; z-index:1; pointer-events:none;
  /* AS PARADAS SÃO CALCULADAS, não escolhidas. O texto começa em 42,1%, e a
     primeira versão punha só 24% de preto ali (o gradiente ia de 0 em 34% a
     0,55 em 52%, o que dá 0,244 interpolado em 42%). Parecia suficiente até
     alguém medir sobre uma foto com REFLEXO DE ESPELHO: o fundo tinha pixel
     branco PURO, e 24% de véu sobre branco puro ainda é quase branco. O chapéu
     saía em 1,23:1.

     A conta para o pior caso — branco puro, luz 1,0 — é direta: com véu de
     opacidade α o pixel resultante é (1−α)·255 em sRGB. Para o branco do texto
     manter 7:1 é preciso α ≥ 0,72; para 10:1, α ≥ 0,78.

     A primeira versão corrigida foi para 0,78 e ficou ESCURA DEMAIS — o cartão
     inteiro pesava. 0,78 dá 11,7:1, ou seja duas vezes e meia o piso: contraste
     comprado com escuridão que ninguém pediu.

     O piso real é 0,60, e quem o define não é o título (branco cheio, que
     aguentaria 0,55) e sim a ASSINATURA, que é branco a 92% de opacidade:

       alfa   título   assinatura
       0,78   11,7:1     9,5:1
       0,65    7,0:1     5,9:1
       0,60    5,7:1     4,9:1   <- escolhido, o mais claro que ainda passa
       0,55    4,7:1     4,1:1   REPROVA na assinatura

     Vale lembrar que esses números são do PIOR pixel — um ponto de branco puro
     no reflexo do espelho. A média da faixa é bem mais escura, então na tela a
     diferença entre 0,78 e 0,60 é grande e a legibilidade não muda. */
  background:linear-gradient(to bottom,
    rgba(0,0,0,0) 26%, rgba(0,0,0,.60) 42%, rgba(0,0,0,.76) 100%);
  /* Sobrescreve o foco de luz que o ::before carrega nas capas de DESENHO.
     Nelas ele é o brilho que segue o cursor; aqui o mesmo pseudo-elemento é o
     véu, e os dois não podem coexistir no mesmo nó. */
  opacity:1; transition:none;
}
/* Sem foco de luz sobre foto: ele foi feito para uma superfície de cor chapada
   e sobre fotografia vira um borrão claro viajando por cima do assunto. */
@media (hover:hover) and (pointer:fine){
  .pv-card:hover .pv-capa-foto::before{ opacity:1; }
  .pv-card:hover .pv-capa-foto{ filter:brightness(1.04); }
}

/* OPACIDADE CHEIA SOBRE FOTO. O chapéu (0,72) e a assinatura (0,55) foram
   calibrados contra o bronze CHAPADO, onde o fundo é uma cor conhecida e a
   transparência é o que dá hierarquia entre as três linhas. Sobre fotografia a
   mesma transparência é subtraída do contraste: medido, a assinatura saía em
   2,49:1 e o chapéu em 1,23:1.

   Aqui a hierarquia passa a vir do CORPO e do espaçamento — que já são
   diferentes nas três — e não da transparência. O texto fica opaco, e quem
   segura a leitura é o véu logo acima. */
.pv-capa-foto .pv-olho{ opacity:.96; }
/* 0,92 e não 0,88: é a assinatura que define o piso do véu lá em cima, e cada
   ponto de opacidade que ela ganha é véu que o cartão pode perder. */
.pv-capa-foto .pv-assin{ opacity:.92; }
/* Sombra curta e fechada. Não é decoração: é a rede para o caso de a próxima
   foto ter um ponto claro exatamente sob uma letra, que é o defeito que o véu
   sozinho não pega. Curta o bastante para não borrar o desenho da Literata. */
.pv-capa-foto .pv-capa-txt{ text-shadow:0 1px 3px rgba(0,0,0,.55); }

/* A capa dentro do pop-up: quando a imagem é MÁSCARA (o desenho branco sobre
   transparente), ela não pode entrar como <img> — sairia branca e sumiria nos
   temas claros. A figure vira o cartão colorido e o <img> é escondido; quem
   desenha é o mesmo par máscara + --on-gold usado na vitrine. */
.pm-capa.pm-capa-mascara{ position:relative;
  background-color:var(--gold); background-image:var(--cta-bg,none);
  background-size:var(--cta-bg-size,auto); border-radius:.6rem; overflow:hidden; }
.pm-capa.pm-capa-mascara img{ visibility:hidden; }
.pm-capa.pm-capa-mascara::after{ content:""; position:absolute; inset:0;
  background-color:var(--on-gold); opacity:.55;
  -webkit-mask:var(--m) center/contain no-repeat; mask:var(--m) center/contain no-repeat; }
.pv-titulo{ font-size:.86rem; font-weight:600; color:var(--text); line-height:1.25;
  width:100%;
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
.pv-preco{ font-size:.82rem; color:var(--muted); font-variant-numeric:tabular-nums; }
.pv-dica{ font-size:.72rem; color:var(--muted-2); text-align:center; margin:.15rem 0 0; }
@media (max-width:360px){ .pv-card{ width:8.75rem; } }

/* ------------------------------------------------- Pop-up do produto ------ */
.pm-quem{ display:flex; align-items:center; gap:.6rem; }
.pm-avatar{ width:2.2rem; height:2.2rem; border-radius:50%; object-fit:cover;
  object-position:center; flex:0 0 auto; }
.pm-quem span{ display:flex; flex-direction:column; line-height:1.25; }
.pm-quem small{ font-size:.72rem; color:var(--muted); }
.pm-quem b{ font-size:.85rem; color:var(--text); font-weight:600; }
.pm-titulo{ font-size:1.35rem; font-weight:800; letter-spacing:-.02em;
  color:var(--text); margin:.35rem 0 1rem; }
.pm-sobre{ background:var(--glass-bg); border:1px solid var(--glass-border);
  border-radius:.8rem; padding:.9rem 1rem; font-size:.86rem; color:var(--text-2); }
.pm-sobre p:last-child{ margin-bottom:0 !important; }

/* Uma coluna no celular, capa + compra lado a lado a partir de 576px. */
.pm-grade{ display:grid; gap:1rem; margin-top:1rem; }
@media (min-width:576px){ .pm-grade{ grid-template-columns:1fr 1fr; align-items:start; } }
.pm-capa{ margin:0; border-radius:.8rem; overflow:hidden;
  border:1px solid var(--glass-border); background:var(--glass-bg); }
.pm-capa img{ width:100%; height:auto; display:block; }
.pm-preco-cx{ background:var(--glass-bg); border:1px solid var(--glass-border);
  border-radius:.8rem; padding:.85rem 1rem; }
.pm-preco{ font-size:1.75rem; font-weight:800; color:var(--text); line-height:1.1;
  font-variant-numeric:tabular-nums; }
.pm-preco-sub{ font-size:.75rem; color:var(--muted); }
.pm-inclui{ list-style:none; padding:0; margin:0; font-size:.84rem; color:var(--text-2); }
.pm-inclui li{ display:flex; align-items:flex-start; gap:.5rem; padding:.2rem 0; }
.pm-inclui i{ color:var(--ok); margin-top:.2rem; flex:0 0 auto; }
/* Sem link de checkout o botão fica visivelmente inerte — e não um link morto. */
.btn-header.disabled{ opacity:.5; pointer-events:none; font-size:.78rem; }
.pm-share{ display:flex; align-items:center; justify-content:center; gap:.4rem;
  width:100%; min-height:44px; margin-top:.5rem; background:none; border:0;
  color:var(--muted); font-size:.82rem; cursor:pointer; }
.pm-share:hover{ color:var(--accent); }
.pm-arquivo{ display:flex; align-items:center; gap:.55rem; margin-top:1rem;
  padding:.7rem .9rem; border-radius:.7rem;
  background:var(--glass-bg); border:1px solid var(--glass-border);
  font-size:.82rem; color:var(--text-2); }
.pm-arquivo .pm-arq-tam{ margin-left:auto; color:var(--muted); }



/* ---------------------------------------------------------- Tabs galeria ---
   min-height:44px pelo mesmo motivo dos CTAs: são cinco alvos lado a lado num
   celular de 320px, o caso em que o dedo mais erra. */
.gallery-tabs{ border-bottom:none; gap:.25rem; }
.gallery-tabs .nav-link{
  color:var(--muted-2); border:none; border-bottom:2px solid transparent; padding:.5rem .75rem;
  min-height:44px; display:flex; align-items:center; justify-content:center;
  background:none; opacity:1; transition:color .15s ease, border-color .15s ease;
}
.gallery-tabs .nav-link:hover{ color:var(--text-2); }
.gallery-tabs .nav-link.active{ color:var(--text); border-bottom-color:var(--accent); background:none; }
.gallery-tabs .nav-link i, .gallery-tabs .nav-link svg{ font-size:1.05rem; }
.tab-ico{ width:20px; height:20px; vertical-align:middle; }

/* Cards de link (compartilhado) */
.shadow-link{ box-shadow:var(--glass-shadow); }
.thumb{ background-size:cover; background-position:center; background-color:var(--surface); }
.thumb.placeholder-thumb{ background:var(--card-bg); }
/* O aviãozinho de compartilhar. 44x44 de ÁREA, ícone do mesmo tamanho de antes.
   Ele vive DENTRO do banner, que também é clicável — e é justamente por isso que
   precisa de área generosa: com 18px, metade dos toques cai no banner e a pessoa
   é levada para outro lugar em vez de compartilhar. O site.js já dá prioridade a
   ele no clique (stopImmediatePropagation), então a área maior não rouba banner:
   ela decide certo o toque que hoje decide errado. */
/* A COR É --on-photo, não branco cravado: este ícone mora SEMPRE sobre uma foto
   (no banner ele cai sobre o véu preto do .v-vertical, no quadrado sobre a
   miniatura), e sobre foto o branco continua certo nos dois temas. O que o
   branco cravado escondia era o outro caso: quando a miniatura é
   `.placeholder-thumb` não há foto nenhuma — o fundo é o CARTÃO, e no mármore
   um aviãozinho branco sobre creme desaparece. Daí a regra logo abaixo.
   O drop-shadow é rede de segurança para foto clara: contorno duro escureceria
   o desenho, um borrão curto só o descola do fundo. */
.link-ico{ color:var(--on-photo); opacity:.9; background:transparent; border:none; padding:0;
  cursor:pointer; line-height:0; font-size:1.1rem;
  filter:drop-shadow(0 1px 2px rgba(0,0,0,.5));
  width:44px; height:44px; display:inline-flex; align-items:center; justify-content:center; }
.placeholder-thumb .link-ico{ color:var(--text); filter:none; }
.link-ico:hover{ opacity:1; color:var(--accent); }
.link-ico i{ pointer-events:none; }
.hand-ico{ width:1.4rem; height:1.4rem; display:block; }

/* ============================================================================
   View: BARRAS — a leitura do HillerFit, e a visualização PADRÃO.
   ----------------------------------------------------------------------------
   Barra inteira na cor da marca, miniatura quadrada à esquerda, título branco e
   pesado. É o oposto do banner 16:9 com foto: ali quem manda é a fotografia,
   aqui quem manda é a COR — a página vira uma pilha de blocos sólidos, que é o
   que faz o HillerFit parecer o HillerFit.

   O painel de vidro que existia aqui (herdado do projeto irmão) foi trocado por
   preenchimento sólido `--gold`: os cinco temas mudam a cor das barras junto,
   sem nenhuma regra nova.

   `.dots` (a mãozinha) sai desta visão: sobre o preenchimento sólido ela virava
   um borrão de baixo contraste no canto, e a barra inteira já é obviamente
   clicável — o ícone não estava dizendo nada que a cor não dissesse.
   ========================================================================== */
/* Vão de 8px entre as barras — MEDIDO no link.me/hillerfit, não estimado: um
   print da página deles, e a contagem dos pixels vermelhos numa coluna à
   direita do ícone. Deu barra de 76px com 8px de vão. Aqui estava .85rem
   (13,6px), e era o que fazia a pilha parecer mais solta que a de lá.
   O DOM deles não serve para isso: é gerado, aninhado e as classes trocam a
   cada deploy. A imagem não muda de nome. */
.v-bars .link-item{ display:block; margin-bottom:.5rem; }
.v-bars .card{
  /* --cta-bg: a RAMPA, nos temas que têm uma. Nos temas de cor chapada o token
     nem existe e o fallback `none` mantém o botão exatamente como sempre foi —
     por isso os sete tons originais não mudaram um pixel quando os gradientes
     entraram. */
  background:var(--gold); background-image:var(--cta-bg,none); background-size:var(--cta-bg-size,auto);
  border:1px solid var(--gold-border,transparent); box-shadow:none !important;
  height:4.75rem; border-radius:1rem; overflow:hidden;   /* 76px, como a deles */
  padding:.55rem; gap:.85rem;
  transition:transform .16s ease, box-shadow .2s ease, background-image .25s ease;
}
@media (hover:hover) and (pointer:fine){
  .v-bars .link-item:hover .card{
    transform:translateY(-2px); background-image:var(--gold-grad);
    box-shadow:0 10px 26px -12px var(--gold-glow);
  }
}
.v-bars .link-item:active .card{ transform:translateY(0) scale(.995); }
/* A miniatura é um QUADRADO com respiro, não uma faixa colada na borda: é o
   detalhe que separa "bloco de cor com uma foto dentro" de "cartão com capa". */
.v-bars .thumb{ width:3.5rem; height:3.5rem; flex:0 0 3.5rem;
  border-radius:.7rem; background-color:rgba(var(--sombra-rgb),.25); }
/* 16px/600/1.3 — os valores do .middle-link-title do link.me. O 800 que estava
   aqui deixava a barra "gritando" ao lado da referência. */
.v-bars .title{ font-weight:600; font-size:1rem; letter-spacing:normal;
  color:var(--on-gold); line-height:1.3; white-space:normal; }
.v-bars .sub{ font-size:.76rem; color:var(--on-gold); opacity:.72; }
.v-bars .dots{ display:none; }
@media (max-width:360px){
  /* o próprio link.me cai para 14px nas telas estreitas */
  .v-bars .title{ font-size:.875rem; }
  .v-bars .thumb{ width:3rem; height:3rem; flex:0 0 3rem; }
}

/* View: cards */
.v-cards .card{ background:var(--glass-bg); border:1px solid var(--glass-border);
  -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur);
  border-radius:.85rem; overflow:hidden; height:14rem; }
.v-cards .thumb{ height:8rem; position:relative; }
.v-cards .thumb .link-ico{ position:absolute; top:-.1rem; left:0; }
.v-cards .title{ font-size:.8rem; font-weight:600; color:var(--text); }
.v-cards .sub{ font-size:.72rem; color:var(--muted); }

/* View: quadrado */
.v-square .thumb{ position:relative; aspect-ratio:1; border-radius:.85rem; border:1px solid var(--hairline); }
.v-square .link-ico{ position:absolute; top:0; left:.05rem; font-size:1.15rem; }
/* Sobre a MINIATURA (uma foto), então --on-photo e não --text: o que está atrás
   é a imagem do banner, não a superfície do tema. O borrão é o mesmo do
   .link-ico e pelo mesmo motivo — foto clara existe. */
.v-square .dots{ position:absolute; top:.5rem; right:.6rem; color:var(--on-photo);
  filter:drop-shadow(0 1px 2px rgba(0,0,0,.5)); }
.v-square .placeholder-thumb .dots{ color:var(--text); filter:none; }

/* View: vertical 16:9 (padrão) */
.v-vertical .link-item{ margin-bottom:1.25rem; }
.v-vertical .card{ position:relative; aspect-ratio:16/9; border:none; background:transparent;
  border-radius:1rem; overflow:hidden; box-shadow:none !important; }
/* esfumaçado: a foto dissolve na cor do tema, sem borda dura */
.v-vertical .thumb{ position:absolute; inset:0; box-shadow:inset 0 0 14px 4px rgb(var(--bg-rgb)); }
/* O VÉU PRETO FICA, NOS DOIS TEMAS, e é a única peça deste arquivo em que preto
   cravado é a resposta certa. Ele não pertence ao tema: pertence ao BANNER. O
   que ele faz é garantir que o título branco leia sobre uma foto qualquer —
   inclusive uma foto clara, que é o caso em que ele é indispensável. Tingi-lo
   de creme no tema claro devolveria exatamente o problema que ele resolve
   (título branco sobre fundo claro). Medido: o título dá 15,4:1 contra a parada
   de 88% do gradiente, e é essa parada que o contrast-check mede. */
/* A PARADA É 40%, e não os 55% de origem. Ela foi encurtada para o banner da
   BeHealth poder trazer a assinatura "O seu hub de saúde" mais para baixo sem
   ela sair cinza: em 55% o véu já tinha 38% de preto na altura da assinatura;
   em 40%, tem 19%.

   Encurtar o véu tira proteção de onde o TÍTULO mora, então não foi escolha —
   foi medição. O `node mede-veu.mjs` compõe o véu sobre os quatro banners e lê
   o contraste do branco contra o pior pixel na faixa do título (y 84%..94%):

     parada   behealth   growth   setor3   terapia
       55%     13,58      7,37     16,06    8,70
       45%     12,25      6,04     15,06    7,27
       40%     11,38      5,28     14,37    6,44   <- escolhido
       35%     10,34      4,47     13,49    5,53   REPROVA (piso 4,5 para texto)

   Quem manda é o consultoria-growth: a parede clara atrás do Hércules é o
   fundo mais claro que um título branco encontra neste site. 40% deixa 0,78 de
   folga sobre o piso; 35% já não passa.

   RODAR O mede-veu.mjs DE NOVO ao trocar qualquer banner — este número descreve
   as quatro imagens que estão lá hoje, não uma regra. */
.v-vertical .overlay{ position:absolute; inset:0;
  background:linear-gradient(to top, rgba(0,0,0,.88) 0%, rgba(0,0,0,0) 40%); }
.v-vertical .title{ position:absolute; left:1rem; right:2.5rem; bottom:.9rem;
  color:var(--on-photo); font-weight:700; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.v-vertical .link-ico{ position:absolute; bottom:.3rem; right:.35rem; }
/* No topo do banner o véu ainda não começou (ele só ganha corpo nos 45% de
   baixo), então aqui a mãozinha está sobre a FOTO crua — mesmo tratamento do
   .v-square .dots. */
.v-vertical .dots{ position:absolute; top:.6rem; right:.8rem; color:var(--on-photo);
  filter:drop-shadow(0 1px 2px rgba(0,0,0,.5)); }

/* View: grid do Instagram */
.ig-grid{ display:grid; grid-template-columns:repeat(3,1fr); gap:3px; }
.ig-item{ position:relative; aspect-ratio:1; overflow:hidden; }
.ig-item > a, .ig-item > .link-cta{ display:block; width:100%; height:100%; }
.ig-item .thumb{ width:100%; height:100%; }
.ig-item .cap{ position:absolute; left:0; right:0; bottom:0; padding:6px 8px;
  background:linear-gradient(transparent, rgba(0,0,0,.7)); opacity:0; transition:opacity .2s ease; }
.ig-item:hover .cap{ opacity:1; }
.ig-item .cap span{ color:#fff; font-size:.7rem; font-weight:500; }

/* ============================================================================
   SOBRESSALTO — o realce ao apontar, igual nas CINCO visões
   ==========================================================================
   Antes disto só duas das cinco reagiam: a de barras tinha um translateY(-2px)
   próprio e a vitrine de produtos, outro de -3px. As de cartão, grade, vertical
   e Instagram não faziam nada — o mesmo banner respondia ou não conforme a aba
   em que a pessoa estivesse, o que lê como defeito e não como escolha.

   UM SELETOR PARA AS CINCO, e não cinco regras parecidas: o elemento clicável é
   sempre um <a> (link externo) ou um .link-cta (banner que abre pop-up), e
   dentro dele vem sempre um .card ou um .thumb. O `>` é o que segura a conta —
   na visão de barras existe um .thumb DENTRO do .card, e sem o filho direto os
   dois receberiam o transform, um sobre o outro.

   O gesto é LEVANTAR, não crescer: escalar um cartão que tem foto recortada
   deixa a borda tremida durante a transição, e num cartão com texto o corpo da
   letra muda de tamanho no meio do caminho. Subir 3px com uma sombra que abre
   junto diz "isto é clicável" sem mexer em nada do conteúdo.

   `will-change` NÃO entra aqui de propósito: são até 20 cartões por página, e
   promover todos a camada própria custa memória de GPU o tempo todo para uma
   animação que acontece em um de cada vez. */
.tab-pane :is(a, .link-cta) > :is(.card, .thumb){
  transition:transform .18s cubic-bezier(.2,.7,.3,1), box-shadow .18s ease;
}
@media (hover:hover) and (pointer:fine){
  .tab-pane :is(a, .link-cta):hover > :is(.card, .thumb){
    transform:translateY(-3px);
    box-shadow:0 12px 26px -14px rgba(var(--sombra-rgb,0,0,0),.55);
  }
}
/* TOQUE: no celular não existe apontar, e sem isto a fileira inteira fica
   inerte no dedo. O :active afunda em vez de levantar — é o gesto de pressionar,
   e ele acontece enquanto o dedo está lá, que é quando a pessoa precisa do
   retorno. */
.tab-pane :is(a, .link-cta):active > :is(.card, .thumb){
  transform:translateY(0) scale(.985);
  transition-duration:.08s;
}

/* A GRADE DO INSTAGRAM é a exceção, e por geometria: os cartões ficam a 3px um
   do outro, então levantar um mostra a fresta do vizinho em vez de destacá-lo.
   Ali o realce é uma aproximação da foto dentro do quadro, que é o idioma da
   própria grade do Instagram. */
.ig-item .thumb{ transition:transform .28s cubic-bezier(.2,.7,.3,1); }
@media (hover:hover) and (pointer:fine){
  .tab-pane .ig-item :is(a, .link-cta):hover > .thumb{
    transform:scale(1.06); box-shadow:none;
  }
}
.tab-pane .ig-item :is(a, .link-cta):active > .thumb{ transform:scale(1.02); }

/* Quem pediu menos movimento continua tendo o RETORNO, só não a viagem: a
   sombra aparece na hora, sem deslocamento nenhum. Um realce que some por
   completo deixa a pessoa sem saber o que está sob o cursor. */
@media (prefers-reduced-motion:reduce){
  .tab-pane :is(a, .link-cta) > :is(.card, .thumb),
  .ig-item .thumb{ transition:none; }
  .tab-pane :is(a, .link-cta):hover > :is(.card, .thumb),
  .tab-pane :is(a, .link-cta):active > :is(.card, .thumb),
  .tab-pane .ig-item :is(a, .link-cta):hover > .thumb{ transform:none; }
  .tab-pane :is(a, .link-cta):hover > :is(.card, .thumb){
    box-shadow:0 0 0 2px var(--gold-ring);
  }
}

/* --------------------------------------------------------- Rodapé fixo -----
   Os botões daqui usam AS MESMAS classes do cabeçalho (.btn-header e
   .btn-header-secondary). Antes tinham estilo próprio (.btn-follow/.btn-signup)
   e o par derivou: um ganhou borda e o outro não, e ficaram com 34,3px e 36,3px
   de altura — visivelmente desalinhados. Reusar a mesma classe torna isso
   impossível por construção. .btn-follow/.btn-signup ficam só como gancho.

   O fundo tinge com --bg-rgb (a cor do CARTÃO), não --page-rgb: no celular o
   cartão ocupa a largura toda, então é ELE que está atrás desta barra. Com
   --page-rgb a barra virava uma faixa de cor destoando do conteúdo.

   A borda de cima é cinza NEUTRO a baixa opacidade, e não --hairline: este
   risco atravessa a tela inteira, então precisa ser o mais discreto que ainda
   se vê. O --hairline é calibrado para desenhar a silhueta do cartão contra a
   página — usado aqui, vira uma linha clara cortando o conteúdo ao meio. */
#fixedFooter{ background:rgba(var(--bg-rgb),.88);
  -webkit-backdrop-filter:blur(14px); backdrop-filter:blur(14px);
  border-top:1px solid rgba(128,128,128,.28); box-shadow:none !important; }

/* -------------------------------------------------------------- Modal ------ */
.modal-content-rounded{ position:relative; border-radius:1.1rem 1.1rem 0 0;
  background:var(--card-bg); border:1px solid var(--hairline); }
@media (min-width:576px){ .modal-content-rounded{ border-radius:1.1rem; } }
/* O BACKDROP. O do Bootstrap é preto puro, e .75 era o valor que fazia sentido
   quando a página inteira já era preta: o escurecimento apenas apagava o
   contorno do conteúdo. Sobre o mármore ele vira uma placa quase opaca — a
   página some, e some junto o "onde eu estava" que o backdrop existe para
   preservar. .55 na tinta do kit ainda separa o modal com folga (o modal é
   creme, o fundo escurecido fica em 0,13 de luz: 4,9:1) e deixa a página
   reconhecível atrás. Nos dois casos a cor sai de token. */
.modal-backdrop{ --bs-backdrop-bg:rgb(var(--sombra-rgb)); }
.modal-backdrop.show{ opacity:.55; }
.close-x{ position:absolute; top:.85rem; right:1rem; z-index:5;
  background:transparent; border:none; color:var(--muted-2); padding:0; line-height:0;
  transition:color .15s ease; }
.close-x:hover{ color:var(--accent); }
.close-x i{ font-size:1.5rem; }
.modal-header .modal-title{ padding-right:1.75rem; color:var(--text); }
.avatar-initial{ width:30px; height:30px; border-radius:50%;
  background-image:var(--gold-grad); color:var(--on-gold);
  display:inline-flex; align-items:center; justify-content:center; font-size:.75rem; font-weight:700;
  /* Para quando o JS troca o gradiente pela foto do Léo. Ficam aqui e não
     inline porque descrevem COMO a foto se encaixa no círculo, não QUAL foto —
     e isso não muda por perfil. */
  background-size:cover; background-position:center 22%; flex:0 0 auto; }
/* Com foto, o fio escuro dá ao círculo a mesma aresta dos chips de rede: sem
   ele, um avatar de fundo claro encosta direto no cabeçalho e some. Continua
   ESCURO no tema claro — é justamente contra fundo claro que ele trabalha —,
   só que na tinta do kit em vez de preto puro. O theme-tinta.css devolve o
   preto puro por --sombra-rgb, sem tocar nesta regra. */
.avatar-initial.tem-foto{ box-shadow:inset 0 0 0 1px rgba(var(--sombra-rgb),.35); }
.form-hint{ font-size:.75rem; color:var(--muted); }
.form-hint a{ color:var(--accent); }

/* Aviso flutuante (link copiado) */
.toast-mini{ position:fixed; left:50%; bottom:5rem; transform:translateX(-50%);
  background:var(--glass-bg-2); color:var(--text); border:1px solid var(--glass-border);
  -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur);
  padding:.5rem .9rem; border-radius:.6rem; font-size:.85rem; z-index:2000;
  box-shadow:0 10px 30px -12px rgba(var(--sombra-rgb),.35); }

/* Painel de sucesso (após enviar o formulário) */
.form-success{ padding:1.4rem .5rem .5rem; }
/* O CHECK grande do sucesso lê --ok, e não --wa. O verde do WhatsApp é a cor de
   um BOTÃO — ele foi feito para ser fundo, com letra escura por cima. Como
   traço de 3,4rem sobre o mármore ele dá 1,6:1 e vira um fantasma verde-claro;
   o --ok é o mesmo verde escurecido até 5,4:1. O botão logo abaixo continua no
   verde deles, que é como a pessoa reconhece que aquilo é o WhatsApp. */
.success-check{ font-size:3.4rem; color:var(--ok); line-height:1; margin-bottom:.5rem; }
.success-title{ font-weight:700; font-size:1.05rem; margin-bottom:.45rem; color:var(--text); }
.success-text{ font-size:.85rem; color:var(--muted); line-height:1.5; margin-bottom:1.2rem; }
/* O botão do WhatsApp é um <a> DENTRO do .modal-body — e a regra `.modal-body a
   { color:var(--gold) }` tem especificidade (0,1,1), que VENCE `.btn-wa` (0,1,0).
   O texto saía DOURADO sobre verde: 1,2:1 (invisível) em 4 dos 5 temas. Passou
   despercebido no branco só porque lá o "dourado" é quase preto.
   Daí o seletor abaixo carregar o `.modal-body a` junto: ele precisa ganhar. */
.btn-wa{ background:var(--wa); font-weight:700; border-radius:.65rem; padding:.62rem; border:1px solid transparent; }
.modal-body a.btn-wa, .btn-wa{ color:#0B0B0B; }                       /* 8.0:1 sobre o verde */
.modal-body a.btn-wa:hover, .modal-body a.btn-wa:focus,
.btn-wa:hover, .btn-wa:focus{ background:#2ee07a; color:#0B0B0B; }
.btn-continue{ background:var(--glass-bg-2); color:var(--text); font-weight:600; border-radius:.65rem;
  padding:.55rem; border:1px solid var(--glass-border); }
.btn-continue:hover{ background:var(--glass-bg-2); color:var(--accent); border-color:var(--gold-ring); }

/* ===========================================================================
   REGRA: --gold PREENCHE, --accent ESCREVE.
   ---------------------------------------------------------------------------
   O --gold é a cor do BOTÃO e não tem compromisso de contraste com o fundo da
   página — no tema Midnight ele é #07101B, que sobre o preto dá 1,10:1. Usá-lo
   como cor de texto produz letra invisível, e o pior é que ela some só em
   ALGUNS temas: passa despercebido em revisão feita num tema claro.

   O --accent existe justamente para isso: cada tema o define como a sua cor
   clareada até cruzar 4,5:1 sobre o cartão. Todo texto, ícone, marcador de
   lista e filete indicador lê --accent. Quem lê --gold é só quem PREENCHE:
   fundo de botão, fundo de checkbox, anel de foco.

   Foi assim que o rótulo "Sobre este produto" ficou ilegível no Midnight.
   =========================================================================== */
.section-label{ font-weight:700; font-size:.72rem; text-transform:uppercase;
  letter-spacing:.08em; color:var(--accent); }

/* -------------------------------------------------- CTAs (labels longos) --- */
.btn-cta{ font-size:.82rem; line-height:1.15; padding-left:.35rem; padding-right:.35rem;
  white-space:normal; }
@media (max-width:360px){ .btn-cta{ font-size:.74rem; } }

/* ------------------------------------------- Campos no celular: 16px ------
   O iOS DÁ ZOOM AUTOMÁTICO ao focar um campo com fonte menor que 16px — e não
   desfaz sozinho. A pessoa toca no "Site (opcional)", a página salta ampliada, e
   ela termina de preencher o formulário enxergando um pedaço da tela. Isso
   acontece no meio da única página que converte.

   16px CRAVADO, e não `1rem`: se alguém mexer no font-size da raiz um dia, o rem
   acompanha e o problema volta calado. O tamanho aqui não é escolha estética; é
   o limiar que o navegador usa. */
@media (max-width:575.98px){
  .form-control, .form-select, textarea.form-control, .input-group-text{ font-size:16px; }
}

/* --------------------------------------------------------- Campo WhatsApp -- */
.wa-group .form-select{ flex:0 0 auto; width:auto; min-width:92px; max-width:112px; }
.wa-group input[name="waDdd"]{ flex:0 0 auto; width:72px; text-align:center; }

/* Espaço para o rodapé fixo não cobrir o último banner. */
/* Fundo transparente nos DOIS: no celular quem pinta é o .wrap (superfície
   contínua); no desktop aqui é o respiro fora dos cartões. */
.footer-clear{ height:5.5rem; }

/* ------------------------------------------------ Banner CTA (consultoria) - */
.link-cta{ cursor:pointer; }
.link-cta:focus-visible{ outline:2px solid var(--gold-light); outline-offset:2px; border-radius:1rem; }
.info-address{ background:var(--glass-bg); border:1px solid var(--glass-border); border-radius:.7rem;
  padding:.75rem .9rem; line-height:1.45; color:var(--text-2); }
.info-address .info-map{ display:inline-block; margin-top:.55rem; color:var(--accent); font-weight:600; }
.info-address .info-map:hover{ color:var(--accent-hover); }
.info-list{ padding-left:1.15rem; margin-bottom:.7rem; color:var(--text-2); }
.info-list li{ margin-bottom:.35rem; line-height:1.4; }
.info-list li::marker{ color:var(--accent); }
/* ------------------------------------------------- Dobra dentro do pop-up ---
   O <details> nativo do {dobra:…} (ver itemHtml no site.js). O <summary> tem de
   PARECER botão, porque é o que ele é — sem isso a pessoa não descobre que há
   27 linhas ali dentro. */
.info-dobra{ border:1px solid var(--glass-border); border-radius:.7rem;
  background:var(--glass-bg); margin:0 0 .9rem; overflow:hidden; }
.info-dobra > summary{
  list-style:none; cursor:pointer; user-select:none;
  display:flex; align-items:center; gap:.5rem;
  /* 44px de alvo de toque, a mesma régua dos outros controles da página. */
  min-height:44px; padding:.6rem .85rem;
  font-size:.85rem; font-weight:600; color:var(--accent);
}
/* O triângulo padrão do navegador é feio e muda de desenho em cada sistema.
   Desligado nos dois dialetos (::-webkit-details-marker é o do Safari/Chrome
   antigo, `list-style:none` cobre o resto) e trocado por um chevron nosso. */
.info-dobra > summary::-webkit-details-marker{ display:none; }
.info-dobra > summary::after{
  content:""; margin-left:auto; width:.5rem; height:.5rem; flex:0 0 auto;
  border-right:2px solid currentColor; border-bottom:2px solid currentColor;
  transform:rotate(45deg) translate(-2px,-2px);
  transition:transform .18s ease;
}
.info-dobra[open] > summary::after{ transform:rotate(-135deg) translate(-2px,-2px); }
.info-dobra > summary:hover{ color:var(--accent-hover); }
.info-dobra > summary:focus-visible{ outline:2px solid var(--accent); outline-offset:-2px; }
/* O contador é informação, não enfeite: ele diz o TAMANHO do que está escondido
   antes de a pessoa decidir abrir. */
.info-dobra-n{ font-size:.7rem; font-weight:700; line-height:1;
  padding:.2rem .4rem; border-radius:.35rem;
  background:var(--gold); color:var(--on-gold); }
.info-dobra-corpo{ padding:0 .85rem .3rem; border-top:1px solid var(--glass-border); }
.info-dobra-corpo > :first-child{ margin-top:.7rem; }

/* Lista NUMERADA ({ ordenada: [...] }). O <b> é o nome da dimensão; o resto é
   corrido, para o bloco não virar uma pilha de títulos. */
.info-list-num{ list-style:decimal; }
.info-list-num li{ margin-bottom:.6rem; }
.info-list-num b{ color:var(--text); }

/* ------------------------------------------------ Bifurcação de serviço ----
   As duas portas do #escolhaModal. São botões grandes de propósito: a escolha é
   obrigatória e é a primeira coisa que a pessoa faz depois de decidir falar —
   não é hora de alvo pequeno. */
.escolha-grade{ display:flex; flex-direction:column; gap:.6rem; }
.escolha-op{
  display:flex; align-items:center; gap:.8rem; width:100%; text-align:left;
  padding:.85rem .9rem; border-radius:.85rem; cursor:pointer;
  background:var(--glass-bg); border:1px solid var(--glass-border); color:var(--text);
  transition:border-color .16s ease, background-color .16s ease, transform .12s ease;
}
.escolha-op:hover, .escolha-op:focus-visible{
  background:var(--glass-bg-2); border-color:var(--gold-ring); transform:translateY(-1px);
}
.escolha-op:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
.escolha-ic{ display:inline-flex; align-items:center; justify-content:center;
  width:2.6rem; height:2.6rem; flex:0 0 2.6rem; border-radius:50%;
  background:var(--gold); color:var(--on-gold); font-size:1rem; }
.escolha-txt{ display:flex; flex-direction:column; gap:.15rem; min-width:0; }
.escolha-txt b{ font-size:.95rem; font-weight:700; color:var(--text); line-height:1.25; }
.escolha-txt small{ font-size:.78rem; color:var(--muted); line-height:1.35; }
.escolha-seta{ margin-left:auto; color:var(--muted-2); font-size:.8rem; flex:0 0 auto; }

/* linha final discreta do pop-up (item { note: "..." } no config) */
.info-note{ font-size:.78rem; line-height:1.45; color:var(--muted-2); margin-top:1rem; }

/* Bloco da consultoria DENTRO do pop-up do formulário (é um pop-up só).
   Vazio quando o modal é aberto pelo header/rodapé/sino. */
#athleteInfo:empty{ display:none; }
#athleteInfo.has-info{
  padding-bottom:1.1rem; margin-bottom:1.1rem;
  border-bottom:1px solid var(--hairline);
}

/* --------------------------------------------- Resultados (carrossel) ------ */
/* No celular NÃO pinta fundo (a regra acima deixa transparente): quem pinta é o
   .wrap, e o metal corre contínuo. No desktop volta a ser um cartão flutuante.

   No celular a margem some: como a superfície é contínua, ela virava só um vão
   VAZIO. Somada ao padding daqui, ao margin-bottom do último banner e ao padding
   da galeria, empilhava ~89px de nada entre o banner e o título. Aqui o respiro
   é dado uma vez só, pelo padding-top. */
.results{ margin-top:0; color:var(--text); padding:1.5rem 1.15rem 1.9rem; }
@media (min-width:768px){
  /* No desktop são dois cartões flutuantes: aí a margem é a separação entre eles. */
  .results{ background:var(--card-bg);
    max-width:768px; margin:2.6rem auto 0; border-radius:2rem;
    border:1px solid var(--hairline); box-shadow:var(--shadow-card);
    padding:2.2rem 2rem 2.4rem; }
}
/* Tipografia editorial/A+: título curto, peso leve, respiro */
.results-eyebrow{ font-size:.66rem; font-weight:500; letter-spacing:.22em; text-transform:uppercase; color:var(--accent); }
.results-title{ font-size:1.3rem; font-weight:500; letter-spacing:-.01em; line-height:1.22; margin:.55rem 0 .4rem;
  color:var(--text); text-wrap:balance; }
.results-sub{ font-size:.875rem; color:var(--accent); line-height:1.5; margin-bottom:1.35rem; max-width:34ch; text-wrap:pretty; }
@media (min-width:768px){ .results-title{ font-size:1.45rem; } }
/* Marquee: a "janela" (.results-track) fica PARADA e recorta; só a faixa
   interna (.results-lane) recebe o transform. */
.results-track{ overflow:hidden; cursor:grab; touch-action:pan-y; user-select:none; -webkit-user-select:none;
  padding:4px 6px 6px; }
.results-track.grabbing{ cursor:grabbing; }
.results-lane{ display:flex; gap:.5rem; width:max-content; will-change:transform; }
/* Card na proporção média das fotos (~0.95) + cover: todas ficam UNIFORMES. */
.results-card{ position:relative; flex:0 0 auto; width:16rem; height:16.8rem; background:var(--card-bg);
  border-radius:1.35rem; overflow:hidden; }
.results-card::after{ content:""; position:absolute; inset:0; border-radius:inherit; pointer-events:none;
  box-shadow:inset 0 0 9px 1px rgba(var(--bg-rgb),.55); }
.results-card img{ width:100%; height:100%; object-fit:cover; display:block;
  pointer-events:none; -webkit-user-drag:none; }
@media (min-width:768px){ .results-card{ width:20rem; height:21rem; } }
.results-hint{ font-size:.75rem; color:var(--muted-2); margin-top:.55rem; }

/* ============================================================================
   Overrides do Bootstrap (complementam data-bs-theme)
   ========================================================================== */
.modal-content{ background:var(--card-bg); border:1px solid var(--hairline); color:var(--text); }
.modal-body{ color:var(--text-2); }
.modal-body a{ color:var(--accent); }
.modal-body a:hover{ color:var(--accent-hover); }

.form-label{ color:var(--text-2); }
.form-control, .form-select, textarea.form-control{
  background-color:var(--glass-bg); border:1px solid var(--glass-border); color:var(--text);
  border-radius:.6rem;
}
.form-control:focus, .form-select:focus, textarea.form-control:focus{
  background-color:var(--glass-bg); color:var(--text);
  /* O ANEL DE FOCO era `rgba(201,159,75,.18)` — um dourado literal, resto do
     projeto de onde este arquivo veio, que ficou para tras quando os temas
     passaram a ser gerados. Ele nao respondia a tema nenhum: no mármore o
     campo focado ganhava um halo mostarda. Agora sai do --gold via color-mix,
     entao acompanha o bronze e qualquer cor que venha depois dele. */
  border-color:var(--gold-ring);
  box-shadow:0 0 0 .2rem color-mix(in srgb, var(--gold) 22%, transparent);
}
.form-control::placeholder{ color:var(--muted-2); opacity:1; }

/* O POPUP NATIVO do <select>: sem isto, o `option` fica com fundo TRANSPARENTE
   (medido: nos dois temas) e o navegador pinta a lista com a cor do SISTEMA. No
   Windows isso dá uma lista BRANCA — e no tema escuro o texto, que usa
   var(--text), é quase branco. Resultado: opções invisíveis.
   O fundo tem que ser OPACO: --glass-bg é vidro (7% de opacidade) e não serve.

   AGORA VALE PARA OS DOIS LADOS. Com o mármore o risco inverteu: num Windows em
   modo escuro a lista nativa sai PRETA e o texto, que aqui é a tinta, some. É o
   mesmo bug com o sinal trocado, e por isso o :root declara `color-scheme` além
   destas duas linhas — a cor resolve o popup, o color-scheme resolve a barra de
   rolagem e o autofill, que não leem CSS. */
.form-select option, .form-select optgroup{
  background-color:rgb(var(--bg-rgb));
  color:var(--text);
}
.input-group-text{
  background-color:var(--glass-bg-2); border:1px solid var(--glass-border); color:var(--muted);
}
.form-check-input{ background-color:var(--glass-bg); border-color:var(--glass-border); }
.form-check-input:checked{ background-color:var(--gold); border-color:var(--gold); }
.form-check-input:focus{ border-color:var(--gold-ring);
  box-shadow:0 0 0 .2rem color-mix(in srgb, var(--gold) 22%, transparent); }
.form-check label a, .form-check span a{ color:var(--accent); }

.form-msg.text-success{ color:var(--ok) !important; }
.form-msg.text-danger{ color:var(--err) !important; }

/* Cards do Bootstrap usados nas views bars/cards */
.card-body{ color:var(--text); }
