/* ==========================================================================
   NEXUS theme-final / assets/css/sections/footer.css
   Território exclusivo da seção #footer. Reusa .section, .section--band,
   .section-divider, .link, .link--muted, .btn e .sr-only de 02-base.css,
   03-ui.css e 04-sections.css. Só o que é genuinamente específico do
   rodapé (faixa de fecho, redes, assinatura em escala, linha final) mora
   aqui.

   Só consome tokens de 01-tokens.css: nenhum hex, nenhuma família de fonte
   solta, nenhum raio em px, nenhuma matiz derivada por calc(). A tinta do
   rodapé é --foreground, --muted-foreground e --input; --border só pinta
   filete, nunca glifo (§2.5, proibição 2). Motion: só transform e opacity.

   ESTRUTURA (três faixas, ver o cabeçalho de partials/footer.js):
     .footer__lead        fecho editorial
       .footer__statement   ESQUERDA: tagline + barra de redes
       .footer__directory   DIREITA:  navegação, contato e endereço
     .footer__mark        wordmark em escala grande, com realce ao ponteiro
     .footer__base        copyright e voltar ao topo, atrás de um filete

   O QUE ESTA REVISÃO CORRIGE (quatro pedidos do dono sobre index2.html).

   1. ENDEREÇO À DIREITA. Ele estava na coluna esquerda, 27px abaixo de uma
      tagline de 158px de altura, e era a última coisa daquela coluna: um
      bloco de texto miúdo espremido contra um título enorme, com ~130px de
      vazio embaixo. Endereço é DIRETÓRIO, do mesmo gênero de "Navegação" e
      "Contato". Listado com eles, como terceira coluna rotulada em mono, a
      linha fecha nas duas pontas e a esquerda recupera o respiro.
   2. REDES SOCIAIS ocupam o lugar que o endereço deixou. Não é preenchimento:
      é o bloco com o peso visual certo para equilibrar a altura da coluna
      direita sem alongar a coluna esquerda com mais texto.
   3. RITMO VERTICAL. O par tagline/endereço tinha o espaço errado entre duas
      escalas muito diferentes de tipo. Agora o ritmo da esquerda é um só
      degrau (--space-8) entre o título e a barra de redes, e as três emendas
      da faixa (lead -> assinatura -> linha final -> fim da página) crescem em
      ordem, em vez de a última ser a maior de todas por acidente do
      padding de seção.
   4. EFEITO NO WORDMARK. Duas camadas do mesmo desenho: repouso embaixo,
      tinta acesa em cima, recortada por máscara radial cuja posição vem de
      --px/--py. Ver a seção 4 desta folha.

   Decisão anterior que permanece (redesenho de agosto de 2026): o wordmark
   é faixa própria de largura total, e as colunas do diretório têm largura de
   CONTEÚDO (flex-basis auto), não fração igual de linha. A coluna "Contato"
   fica do tamanho do e-mail em vez de virar um terço vazio de linha.
   ========================================================================== */

.footer {
  /* o wordmark é dimensionado pela largura do container, mas overflow: clip
     é a rede de segurança contra qualquer família de display exótica que o
     estúdio venha a carregar: o body nunca rola na horizontal (§7.5). Vale
     também para o halo do realce (.footer__mark-glow, seção 4 abaixo): ele
     agora cobre o RODAPÉ inteiro de propósito, e overflow: clip é quem
     desenha o único corte aceitável, bem na borda da faixa. */
  overflow: clip;
  /* .section já dá position: relative (02-base.css), mas fica explícito
     aqui porque, desde a correção de 5 de agosto de 2026 (parte 2, ver
     seção 4), .footer virou a caixa de contenção do halo: é nela que
     .footer__mark-glow ancora inset: 0, não mais na caixa pequena do <h2>.
     isolation: isolate contém o z-index: -1 do halo AQUI dentro, senão ele
     escaparia para trás do preenchimento de .section--band (mesmo motivo
     que valia para o <h2> antes da mudança). */
  position: relative;
  isolation: isolate;
  /* CORREÇÃO DE 5 DE AGOSTO DE 2026 (RODAPÉ LENTO NO SAFARI, PARTE 5) --
     contain: paint isola o que o halo (.footer__mark-glow, seção 4 abaixo)
     pinta: o compositor pode parar de considerar o resto da página ao
     decidir o que invalidar quando o halo se move. Não é redundante com
     overflow: clip (linha 55, acima) -- overflow recorta o QUE aparece,
     contain diz ao motor de renderização que PODE ignorar o que está fora
     da caixa ao invalidar pintura, que é exatamente o complemento que falta
     para a camada de luz (agora movida só por transform, ver seção 4) valer
     a pena. */
  contain: paint;
  /* a base já é fechada visualmente pela assinatura e pelo filete final;
     o respiro cheio de seção embaixo deles só afastaria o rodapé do fim da
     página, que é exatamente onde ele deve encostar. 0.34 e não 0.45: com
     0.45 a distância entre a linha final e o fim da página (90px em 1440)
     era maior que a distância entre a assinatura e a linha final (37px), e
     o rodapé terminava com o maior vazio da seção inteira. */
  padding-block-end: calc(var(--section-y) * 0.34);

  /* Os seis parâmetros do realce do wordmark, declarados em .footer (não em
     .footer__mark) desde a correção de 5 de agosto de 2026 (parte 2): o halo
     (.footer__mark-glow) mora agora fora do <h2>, direto em .footer, para
     poder cobrir o rodapé inteiro sem herdar o tamanho minúsculo da caixa do
     título. Como custom property é herança normal de CSS, declarar aqui
     alimenta os DOIS consumidores — o <h2> (.footer__mark, descendente) e o
     halo (também descendente, agora irmão do <h2>) — com o mesmo valor, sem
     duplicar. Pele que muda o CARÁTER da luz sobrescreve estas mesmas seis
     variáveis em .footer (06/08/09/10-skin-*.css), não em .footer__mark.

     --mark-lit-r    raio da MÁSCARA que recorta o glifo aceso (camada
                     .footer__mark-lit, mais abaixo). Cerca de metade da
                     largura do wordmark em desktop, com piso para não sumir
                     no mobile e teto para não virar um lençol no 4K.
     --mark-lit-ink  tinta do glifo aceso.
     --mark-lit-o    quanto dessa tinta entra (fill-opacity, não opacity: ver
                     a regra do texto aceso, mais abaixo).
     --mark-halo-ink tinta do halo atrás dos glifos.
     --mark-halo-k   multiplicador da força do halo. 1 é o padrão medido; a
                     pele sobe quando o ambiente dela aguenta mais luz.
     --mark-glow-r   raio do HALO LIVRE (.footer__mark-glow, mais abaixo),
                     que é uma camada DIFERENTE de --mark-lit-r: aquele
                     recorta texto, este ilumina a área EM VOLTA do texto.
                     Precisa ser maior que --mark-lit-r, senão o halo mora
                     inteiro atrás dos glifos e nunca escapa deles. Fica em
                     calc() sobre --mark-lit-r, e não como valor fixo, para
                     que uma pele que já mexe no raio do realce (a smooth
                     mexe) arraste o halo junto sem precisar declarar os
                     dois. */
  --mark-lit-r: clamp(10.5rem, 24vw, 32rem);
  --mark-lit-ink: var(--foreground);
  --mark-lit-o: 0.78;
  --mark-halo-ink: var(--foreground);
  --mark-halo-k: 1;
  --mark-glow-r: calc(var(--mark-lit-r) * 1.75);
}

/* Filete superior: a linha que separa a última seção do rodapé é a BORDA da
   faixa, não um enfeite solto a 144px de distância dela. Como .section é
   position: relative, tirar o <hr> do fluxo o encosta exatamente na quina
   onde a faixa (.section--band) começa. Continua sangrando de ponta a ponta,
   com o mesmo fade nas extremidades de .section-divider (04-sections.css). */
.footer > .section-divider {
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
}

/* --------------------------------------------------------------------------
   1. Faixa de fecho: declaração de um lado, diretório do outro.
   flex-wrap, não grade de colunas fixas: em telas estreitas os dois blocos
   empilham sozinhos, sem media query dedicada (§7.5).
   -------------------------------------------------------------------------- */

.footer__lead {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-10) var(--space-16);
}

.footer__statement {
  display: grid;
  gap: var(--space-8);
  /* start, e a alternativa foi medida antes de ser descartada. Esticar as
     duas colunas e distribuir a declaração na altura resultante
     (align-content: space-between) alinha a barra de redes com o fim do
     diretório, o que parece a decisão elegante, e em 1920 fica mesmo boa.
     Em 1440, onde a coluna de conteúdo desta pele tem 976px e o diretório
     ocupa duas linhas, a mesma regra abre 185px de buraco ENTRE a tagline e
     as redes: a declaração deixa de ser um bloco e vira dois elementos
     soltos. Um vazio no fim de uma coluna mais curta é ritmo; um vazio no
     meio de um bloco é defeito. A tagline e as redes são uma coisa só, com
     um degrau de --space-8 entre elas, em qualquer largura. */
  align-content: start;
  justify-items: start;
  /* cresce até caber a tagline em duas linhas e para: medida de leitura
     continua sendo assunto de --measure, não da largura da faixa.

     A base é 30rem porque é o que a tagline pede em --fs-h2 para fechar
     "Bonito por fora." em uma linha; o teto de 34rem é o que impede que, em
     tela muito larga, ela vire uma faixa de texto com duas frases curtas
     boiando dentro. Quando o teto trava, a sobra vai inteira para o
     diretório, que é quem sabe usá-la (ver .footer__directory). */
  flex: 1 1 min(100%, 30rem);
  max-inline-size: 34rem;
}

/* A tagline institucional é o texto de fecho do site, não uma legenda: entra
   em escala de título, na fonte de display, com o mesmo ritmo dos títulos de
   seção. O limite em ch é declarado AQUI (e não no bloco pai) porque ch é
   relativo ao próprio corpo do elemento. */
.footer__tagline {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 600;
  line-height: var(--lh-tight);
  letter-spacing: var(--tracking-display);
  color: hsl(var(--foreground));
  max-inline-size: 18ch;
  text-wrap: balance;
}

/* --------------------------------------------------------------------------
   2. Redes sociais.

   Cápsula quadrada de 44px (--tap-min), ou seja, o alvo de toque do §7.5 é
   atendido pela CAIXA, em todo viewport, sem depender do pseudo-elemento de
   .link. Não precisa de regra de mobile.

   A tinta é --muted-foreground e o limite é --input, que é o token de limite
   de componente interativo do §8 (3:1) e não --border, que é divisor e não
   tem esse piso. Hover: translateY de 2px e troca de borda e de tinta, que é
   literalmente o efeito nomeado na lista de permitidos do §6.
   -------------------------------------------------------------------------- */

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

.footer__social-item {
  display: flex;
}

.footer__social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: var(--tap-min);
  block-size: var(--tap-min);
  border: var(--hairline) solid hsl(var(--input));
  border-radius: var(--radius-md);
  background-color: hsl(var(--surface-2));
  color: hsl(var(--muted-foreground));
  font-size: var(--fs-base);
  text-decoration: none;
  transition:
    background-color calc(var(--dur-fast) * var(--motion)) var(--ease-out),
    border-color calc(var(--dur-fast) * var(--motion)) var(--ease-out),
    color calc(var(--dur-fast) * var(--motion)) var(--ease-out),
    transform calc(var(--dur-fast) * var(--motion)) var(--ease-out);
}

.footer__social-link:hover,
.footer__social-link:focus-visible {
  border-color: hsl(var(--foreground));
  background-color: hsl(var(--surface-3));
  color: hsl(var(--foreground));
  transform: translateY(-2px);
}

.footer__social-link:focus-visible {
  outline: 2px solid hsl(var(--ring));
  outline-offset: 2px;
}

/* ÍCONE SEM DESTINO (06/08/2026, decisão do dono: só o LinkedIn leva a
   algum lugar; os outros ficam desenhados e não redirecionam). Ele é um
   <span>, então não tem foco nem hover de link por natureza; o que esta
   regra faz é tirar a AFORDÂNCIA: cursor de texto no lugar do de clique e
   tinta um passo mais discreta, para o olho não ler como botão que não
   responde. O contorno e o tamanho continuam iguais, porque a fileira é
   uma unidade visual e quebrar o alinhamento por causa do estado seria
   pior que a promessa que se está evitando. */
.footer__social-link--inerte {
  cursor: default;
  color: hsl(var(--faint-foreground, var(--muted-foreground)));
}

/* --------------------------------------------------------------------------
   3. Diretório: navegação, contato e endereço, colunas com largura de
   conteúdo.

   flex-basis: auto em vez de 1fr é o ponto da correção antiga. Cada coluna
   ocupa o que o texto pede; a linha inteira fecha à direita.

   O <nav> envolve só as colunas de LINK: o endereço não é navegação e não
   pode entrar no landmark. Por isso existe .footer__directory por fora, com
   o mesmo gap do <nav>, de modo que as três colunas leiam como uma régua só.
   -------------------------------------------------------------------------- */

.footer__directory,
.footer__nav {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: flex-start;
  gap: var(--space-8) var(--space-12);
}

/* A LARGURA DO DIRETÓRIO É O QUE DECIDE SE ELE TEM UMA OU DUAS LINHAS, e é
   de propósito que isso não seja media query.

   Com flex-basis auto (max-content), a soma "tagline + três colunas" passa
   de 1030px, e em 1440 a coluna de conteúdo desta pele tem 976px: quem
   quebrava era a FAIXA inteira, jogando o diretório para baixo da tagline e
   devolvendo o rodapé empilhado que esta revisão veio desfazer.

   Com base de 20rem quem quebra é o diretório POR DENTRO: em 1440 ele fica
   com cerca de 370px, cabem "Navegação" e "Contato" lado a lado e o endereço
   desce para a linha de baixo, ainda à direita e ainda no mesmo bloco. Acima
   de 1560px, quando a tagline trava em 34rem, toda a sobra do container vem
   para cá e as três colunas voltam para uma linha só, sozinhas. Um layout,
   dois arranjos, nenhuma consulta de largura.

   min-inline-size: 0 é o que autoriza o encolhimento: item de flex tem
   min-width auto por padrão, o que o trava no min-content e reintroduz a
   quebra da faixa. */
.footer__directory {
  flex: 1 1 min(100%, 20rem);
  min-inline-size: 0;
}

.footer__col {
  flex: 0 1 auto;
  min-inline-size: 8rem;
}

.footer__col-title {
  margin-block-end: var(--space-5);
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  font-weight: 500;
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;
  color: hsl(var(--muted-foreground));
}

.footer__col-list {
  display: grid;
  gap: var(--space-4);
  list-style: none;
  margin: 0;
  padding: 0;
  justify-items: start;
}

/* .link já estende a área clicável para 44x44 por ::before (03-ui.css), sem
   crescer a caixa visual. Por isso o ritmo aqui é tipográfico, e a caixa só
   cresce onde o ponteiro é o dedo. */
.footer__link {
  display: inline-flex;
  align-items: center;
  font-size: var(--fs-sm);
  font-weight: 500;
  line-height: 1.4;
}

/* CORRIGIDO NA 14ª RODADA (06/08/2026, júri), e o defeito era o SELETOR, não
   a medida. Esta regra existia só sob `(max-width: 767px)`, e o §7.5 diz com
   todas as letras que o teste de alvo de toque é o DEDO — `pointer: coarse`
   — e não a largura da viewport. Um tablet em retrato tem 768px e ponteiro
   grosso: ficava exatamente um pixel fora da consulta e caía no pior dos dois
   mundos, caixa de 20px de altura com área de toque de 44px por
   pseudo-elemento.

   Medido em 768x1024 com `isMobile: true, hasTouch: true`, nas cinco páginas:
   `.footer__col-list` é grade com 15,84px de calha e linha de 20px, ou seja,
   passo de 35,84px entre links vizinhos, contra os 44px que cada `::before`
   ocupa. As áreas de toque se SOBREPUNHAM em ~8px, e o ponto 22px abaixo do
   centro de um link resolvia para o link de baixo: no dedo, tocar embaixo de
   "Portfólio" abria "Capacidades". Quatro links por página, nas cinco peles.

   A condição de largura FICA junto, em vez de ser trocada: ela é quem atende
   a janela estreita de ponteiro fino, que também aperta os alvos. É a mesma
   forma de duas condições que `.chip` já usa (sections/portfolio.css). Com a
   caixa em `--tap-min`, o passo vira 44 + calha e a sobreposição some. */
@media (pointer: coarse), (max-width: 767px) {
  .footer__link {
    min-block-size: var(--tap-min);
  }

  .footer__col-list {
    gap: var(--space-1);
  }
}

/* Endereço: CAIXA PRÓPRIA dentro da coluna Contato (rodada de 5 de agosto de
   2026), com título no mesmo desenho de .footer__col-title — não mais um
   ícone de pin fazendo às vezes de rótulo. .footer__col--address só ajusta
   a largura mínima da coluna (ela agora carrega duas caixas rotuladas
   empilhadas, precisa de mais fôlego que as 8rem de .footer__col genérica).
   .footer__col-title--endereco soma o respiro pedido ("pular linha") acima
   do segundo título, separando visualmente Contato de Endereço; o
   margin-block-end normal de .footer__col-title já fecha embaixo dele. */
.footer__col--address {
  min-inline-size: 11rem;
}

.footer__col-title--endereco {
  margin-block-start: var(--space-6);
}

.footer__address {
  color: hsl(var(--muted-foreground));
  font-size: var(--fs-xs);
  font-style: normal;
  line-height: 1.55;
  max-inline-size: 34ch;
}

/* gap entre as três linhas (era zero, dependia só do line-height do bloco
   inteiro): o dono pediu respiro melhor agora que o endereço tem título
   próprio acima — sem o gap, a proximidade entre o título novo e uma
   primeira linha colada nas demais ficaria ainda mais evidente. */
.footer__address-lines {
  display: grid;
  gap: var(--space-1);
}

/* --------------------------------------------------------------------------
   4. Assinatura: o wordmark em escala grande, ancorando a base da página,
   com realce que segue o ponteiro.

   O <h2> é o alvo de aria-labelledby do landmark e carrega o nome acessível
   em .sr-only; os dois SVGs ao lado são decoração (aria-hidden no markup).

   Geometria (x, y, font-size, textLength) mora no atributo do SVG, em
   unidades do viewBox, não aqui: não é dimensão de tela, é coordenada de
   desenho, e escrever "300px" em CSS de seção seria confundir as duas
   coisas. Aqui ficam só as decisões visuais, todas em token.

   COMO O REALCE FUNCIONA, e por que ele não viola o §6.

   São duas camadas do MESMO desenho, sobrepostas em registro exato (mesmo
   viewBox, mesma largura, mesma proporção, então a de cima cai pixel a pixel
   em cima da de baixo):

     .footer__mark-rest  o gradiente de dissolução que já existia. É o
                         repouso, e é a única coisa que existe sem ponteiro.
     .footer__mark-lit   a mesma palavra em tinta chapada, RECORTADA por uma
                         máscara radial. A máscara é o efeito: onde ela é
                         opaca, a tinta acesa aparece; onde é transparente,
                         some e sobra o repouso.

   A posição da máscara é `at var(--px) var(--py)`, e quem publica esses dois
   valores é NX.motion.pointer (core/motion.js), acionado pelo atributo
   data-pointer no <h2>. O handler é passivo, guarda só as coordenadas e lê
   layout dentro do rAF; no pointerleave ele devolve 50%/50%, ou seja, o
   realce volta ao centro sozinho. 05-motion.css já declara 50%/50% como
   valor de fábrica de [data-pointer], então antes do primeiro movimento a
   máscara nasce centrada.

   O que ANIMA é a opacidade da camada acesa (0 -> 1 no hover), que é
   propriedade permitida. A máscara não é transição: ela é redesenhada porque
   uma custom property mudou, exatamente como o brilho de cursor dos cartões
   que o §6 lista entre os efeitos permitidos.

   O gradiente da máscara usa hsl(var(--foreground)) com alfa. Isso NÃO é a
   proibição do §2.5: ali o proibido é alfa em TINTA DE TEXTO, porque vira
   aposta sobre o que está pintado atrás. Aqui nada é pintado: uma máscara lê
   só o canal alfa do gradiente e descarta a cor. O token entra porque o
   contrato proíbe cor literal, não porque a cor importe.

   O HALO (.footer__mark-glow) NÃO mora mais dentro deste <h2> — ver a
   camada em si, mais abaixo, e o comentário datado de 5 de agosto de 2026
   (parte 2) sobre por que ele foi para .footer. Os seis parâmetros do
   realce (--mark-lit-r, --mark-lit-ink, --mark-lit-o, --mark-halo-ink,
   --mark-halo-k, --mark-glow-r) também moraram aqui antes e agora estão
   declarados em .footer (topo desta folha): o <h2> continua os lendo
   normalmente por herança, porque .footer é ancestral dele.
   -------------------------------------------------------------------------- */

.footer__mark {
  position: relative;
  display: block;
  margin: 0;
  margin-block-start: var(--space-14);
  line-height: 0;
  /* CORREÇÃO DE 5 DE AGOSTO DE 2026 (PARTE 4) — pointer-events: none aqui,
     cascateando por herança para os dois SVGs (.footer__mark-rest,
     .footer__mark-lit) e para o <text> de cada um: nenhum descendente
     redeclara pointer-events com valor diferente (.footer__mark-lit já
     tinha "none" próprio, redundante agora; .footer__mark-rest nunca teve
     nenhum, herda daqui).

     Causa raiz do defeito "Voltar ao topo não funciona": hit-test real
     confirmou clique no centro do botão (.footer__to-top, .footer__base)
     acertando um <text class="footer__mark-text"> em vez do botão.
     .footer__mark-svg é `overflow: visible` de propósito (comentário no
     topo de .footer, sobre a "família de display exótica" que pode
     estourar a caixa calculada pelo viewBox) — o texto do wordmark pinta
     além da altura que o <h2> reserva no fluxo, e pointer-events padrão de
     <text> em SVG é "visiblePainted": onde há tinta, há alvo de clique,
     mesmo fora da caixa do ancestral. Antes desta rodada o <h2> PRECISAVA
     ficar clicável para o gatilho antigo (`.footer__mark:hover`) funcionar;
     agora que o gatilho é `.footer:hover` (PARTE 3, acima), o wordmark não
     precisa mais receber ponteiro nenhum — é só arte decorativa,
     `aria-hidden` nos dois SVGs, sr-only já cobre acessibilidade. Tirar o
     wordmark do caminho do ponteiro resolve o vazamento de clique na raiz,
     em vez de tentar conter a pintura numa caixa menor (que reintroduziria
     o corte que a correção de 5 de agosto já eliminou do halo). O gatilho
     de :hover do efeito de luz não depende de pointer-events no wordmark:
     `.footer:hover` é decidido pelo hit-test de QUALQUER descendente
     clicável do rodapé (ou do próprio `.footer`, via o "buraco" que o
     wordmark agora deixa passar), nunca do <h2> em si. */
  pointer-events: none;
}

.footer__mark-svg {
  display: block;
  inline-size: 100%;
  block-size: auto;
  overflow: visible;
}

.footer__mark-text {
  font-family: var(--font-display);
  font-weight: 800;
  fill: url(#nx-footer-fade);
}

/* Luz branca de baixa opacidade no escuro, tinta preta de baixa opacidade no
   claro: a mesma regra nos dois modos, porque é --foreground em alfa. O
   gradiente desce até quase zero, de modo que a marca dissolve na borda de
   baixo da página em vez de terminar em um bloco chapado. */
.footer__mark-stop-a {
  stop-color: hsl(var(--foreground));
  stop-opacity: 0.26;
}

.footer__mark-stop-b {
  stop-color: hsl(var(--foreground));
  stop-opacity: 0.06;
}

/* A camada acesa cobre a de repouso em registro exato. inset: 0 basta porque
   as duas têm o mesmo viewBox e a mesma largura, logo a mesma altura. */
.footer__mark-lit {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  opacity: 0;
  pointer-events: none;
  transition: opacity calc(var(--dur-base) * var(--motion)) var(--ease-out);
  -webkit-mask-image: radial-gradient(
    circle var(--mark-lit-r) at var(--px) var(--py),
    hsl(var(--foreground)) 0%,
    hsl(var(--foreground) / 0.42) 44%,
    hsl(var(--foreground) / 0) 76%
  );
  mask-image: radial-gradient(
    circle var(--mark-lit-r) at var(--px) var(--py),
    hsl(var(--foreground)) 0%,
    hsl(var(--foreground) / 0.42) 44%,
    hsl(var(--foreground) / 0) 76%
  );
}

/* Tinta chapada, sem o gradiente de dissolução: quem modula a intensidade é
   a máscara, e a queda vertical do repouso continua visível por baixo dela.
   fill-opacity e não opacity: opacity no elemento derrubaria a camada
   inteira e a sonda de contraste passaria a enxergar um nó "invisível" com
   opacity intermediária. */
.footer__mark-lit .footer__mark-text {
  fill: hsl(var(--mark-lit-ink));
  fill-opacity: var(--mark-lit-o);
}

/* Halo atrás dos glifos: a luz que passa por trás da palavra, agora livre
   para se espalhar pelo RODAPÉ INTEIRO. Só existe junto com a camada acesa
   e some com ela.

   CORREÇÃO DE 5 DE AGOSTO DE 2026, dois defeitos medidos juntos porque a
   causa é a mesma conta:

   1. RAIO. O halo usava `circle var(--mark-lit-r)`, o MESMO raio da máscara
      que recorta o texto aceso (.footer__mark-lit, acima). Como as duas
      camadas nascem no mesmo lugar e no mesmo tamanho, o halo inteiro cabia
      DENTRO da área que os próprios glifos já cobriam, então nunca havia
      "círculo de luz" sobrando ao redor da palavra — só a palavra, iluminada
      por dentro dela mesma. `--mark-glow-r` (1.75x `--mark-lit-r`, definida
      em .footer) resolve isso: um raio maior que a máscara do texto
      necessariamente estoura os limites dela e aparece na área livre em
      volta.
   2. FORÇA. `0.14 * --mark-halo-k` combinado com `z-index: -1` media perto
      do piso de percepção fotográfica. A tinta central sobe para a casa de
      0.30-0.45, com `min()` como TETO em vez de multiplicar `--mark-halo-k`
      direto: glass declara `--mark-halo-k: 2.6` (06-skin-glass.css) porque
      foi calibrado contra o 0.14 antigo (0.14 x 2.6 = 0.364, um halo
      comedido); se o valor-base subisse sem teto, o mesmo cálculo em glass
      chegaria a quase opacidade total (0.36 x 2.6 = 0.94), um disco sólido
      em vez de halo. `min(0.42, 0.36 * --mark-halo-k)` deixa toda pele
      abaixo do teto escalar normalmente pelo próprio `--mark-halo-k` (é o
      caso do padrão, da surface e da cult, todas em k=1: chegam a 0.36) e
      trava toda pele ACIMA do teto na mesma luz máxima de 0.42 (glass nos
      dois modos, e smooth em k=1.5, que chegaria a 0.54 sem o freio). O
      segundo stop segue a mesma lógica numa escala menor, para o decaimento
      continuar suave em vez de saltar de "aceso" para "nada" no raio de
      corte.

   CORREÇÃO DE 5 DE AGOSTO DE 2026 (PARTE 2) — o raio maior do item 1 expôs
   um SEGUNDO defeito, batido pelo dono com captura na hora: um retângulo de
   corte nítido em volta do wordmark quando o halo cresce. Causa raiz: até
   aqui, esta camada era filha do <h2> (.footer__mark) e sua caixa própria
   era dimensionada por INSET EM PORCENTAGEM da caixa do título
   (`inset: -40% -12%`) — uma caixa deliberadamente pequena, porque o <h2> só
   tem a altura do wordmark, não a do rodapé. Com `--mark-glow-r` a 1.75x
   `--mark-lit-r`, o raio de decaimento total do gradiente (72% do raio)
   passou a ser MAIOR que a metade da altura dessa caixa — medido em 1440px:
   meia-caixa de ~240px contra ~436px de decaimento necessário. O gradiente
   era cortado em reta na borda da própria caixa do halo, bem ANTES de
   chegar a `transparent`, e essa reta lia como o retângulo relatado.

   A correção não é aumentar a porcentagem (qualquer fração fixa da caixa do
   <h2>, que é pequena e não escala na mesma proporção do raio, volta a
   estourar em algum breakpoint ou em alguma pele — a smooth usa raio bem
   maior ainda). É trocar de CAIXA: esta camada saiu de dentro do <h2> no
   marcador (partials/footer.js) e é agora filha direta de <footer>, com
   `inset: 0` — cobre o RODAPÉ inteiro, não mais a vizinhança do título. A
   única borda que ainda corta é `overflow: clip` de `.footer` (acima nesta
   folha), no limite da faixa — o corte que o dono pediu para manter.

   Como a caixa mudou de dono, a POSIÇÃO do gradiente também: as duas
   conversões antigas (`(var(--px) + 12%) / 1.24` etc.) desfaziam o
   alargamento de uma caixa MAIOR-QUE-O-<H2>-EM-PROPORÇÃO-FIXA — não fazem
   mais sentido para uma caixa do tamanho do rodapé, cuja altura não guarda
   proporção fixa com a do <h2> (depende do conteúdo do diretório, do
   endereço, da pele). Em vez de tentar recalcular essa proporção, o <footer>
   ganhou seu PRÓPRIO rastreador de ponteiro (`data-pointer` direto nele,
   mesmo mecanismo genérico de `[data-pointer]` que já preenche `--px`/`--py`
   no <h2>, `core/motion.js`): o ponteiro é lido relativo ao rodapé inteiro,
   e esta camada, agora filha direta de `<footer>` (não mais do <h2>), herda
   esse `--px`/`--py` do PAI CORRETO. `at var(--px) var(--py)` sem conversão
   nenhuma — a percentagem já nasce relativa à caixa certa. O <h2> mantém seu
   PRÓPRIO `data-pointer`/`--px`/`--py`, inalterado, para a máscara do texto
   aceso (que continua precisando de coordenadas relativas ao título, não ao
   rodapé): os dois rastreadores coexistem porque cada elemento com
   `data-pointer` guarda seu par --px/--py como estilo inline NELE MESMO —
   o <h2> não herda do <footer> porque a declaração mais próxima (a dele
   mesmo) sempre vence a cascata. */
/* CORREÇÃO DE 5 DE AGOSTO DE 2026 (RODAPÉ LENTO NO SAFARI, PARTE 5) — o
   gradiente deixou de nascer em `at var(--px) var(--py)`.

   O QUE ESTAVA ERRADO. A técnica das PARTES 1-4 (comentário grande acima)
   posicionava a luz redesenhando o PRÓPRIO GRADIENTE a cada pointermove: a
   caixa cobre o rodapé inteiro (PARTE 2), então cada mudança de --px/--py
   forçava o WebKit a recalcular estilo e REPINTAR um radial-gradient do
   tamanho do rodapé inteiro, a cada frame de movimento do ponteiro — o pior
   caso de custo de pintura que existe em CSS (pintura de área grande, na
   frequência de um evento de entrada de alta cadência). É essa repintura,
   não o rAF em si (core/motion.js já throttla a 1x por frame desde sempre),
   que fica pesada no Safari: o motor de composição dele é mais caro para
   invalidar áreas grandes do que o do Chromium.

   A CORREÇÃO É COMPOSIÇÃO PURA. O gradiente agora nasce ESTÁTICO, sempre
   `at 50% 50%` — sempre o MESMO pixel, então o navegador pinta essa camada
   UMA VEZ (quando o hover liga, via a transição de opacity) e guarda o
   resultado numa textura de compositor. O que segue o ponteiro depois disso
   é só a POSIÇÃO da caixa: `transform: translate3d(...)`, propriedade que o
   compositor move sem tocar em pintura nenhuma (`will-change: transform`
   promove a camada a seu próprio layer). O deslocamento vem de
   `--pointer-dx`/`--pointer-dy` — pixels a partir do centro do `.footer`,
   publicados por NX.motion.pointer (core/motion.js) no MESMO rAF que já
   escreve --px/--py, sem listener novo, sem rect novo.

   A CAIXA MUDOU DE GEOMETRIA para a conta fechar sem depender do tamanho do
   `.footer` (que varia com pele/conteúdo/viewport, ao contrário de
   `--mark-glow-r`, que é só função da largura do wordmark): em vez de
   `inset: 0` (caixa = rodapé inteiro, repintada a cada movimento), a caixa
   agora tem o TAMANHO FIXO do próprio halo (diâmetro `--mark-glow-r * 2`,
   raio suficiente para o decaimento do gradiente — 72%, ver o antigo
   comentário de PARTE 1 — nunca estourar a própria caixa) e nasce centrada
   no `.footer` via `top/left: 50%` + margem negativa de meio-diâmetro — o
   MESMO repouso visual de antes, porque `--pointer-dx/dy` também nascem em
   `0px` (`0px` é o centro: o ponteiro ainda não pousou/já saiu). Mover essa
   caixa por `translate3d` desloca só ELA, nunca redesenha o degradê pintado
   dentro dela — é exatamente o que faz o halo seguir o ponteiro sem
   repintura, com o mesmo raio, a mesma força e o mesmo corte por
   `overflow: clip` do `.footer` de antes (nada disso mudou).

   O QUE NÃO MUDOU, de propósito, porque já estava provado: `.footer:hover`
   continua o gatilho (PARTE 3, comentário abaixo), `--mark-glow-r`/
   `--mark-halo-ink`/`--mark-halo-k` continuam os mesmos seis parâmetros
   herdados de `.footer` (topo desta folha), reduced-motion e
   `--motion: 0` continuam escondendo a camada (regra logo abaixo, também
   inalterada) e o `.footer__mark-lit` (máscara do texto aceso, dentro do
   `<h2>`) continua na técnica antiga: a caixa dele é a do `<h2>`, não a do
   `.footer` — uma fração do tamanho do rodapé, então o custo de repintura
   por movimento já era ordens de grandeza menor; reescrevê-la também
   trocaria a caixa de dono (romperia o registro pixel-a-pixel com
   `.footer__mark-rest` que o comentário da seção 4 documenta) por um ganho
   que o próprio pedido classificou como opcional. */
.footer__mark-glow {
  position: absolute;
  inset-inline-start: 50%;
  inset-block-start: 50%;
  z-index: -1;
  display: block;
  inline-size: calc(var(--mark-glow-r) * 2);
  block-size: calc(var(--mark-glow-r) * 2);
  margin-inline-start: calc(var(--mark-glow-r) * -1);
  margin-block-start: calc(var(--mark-glow-r) * -1);
  opacity: 0;
  pointer-events: none;
  will-change: transform;
  transform: translate3d(var(--pointer-dx, 0px), var(--pointer-dy, 0px), 0);
  transition: opacity calc(var(--dur-base) * var(--motion)) var(--ease-out);
  background: radial-gradient(
    circle var(--mark-glow-r) at 50% 50%,
    hsl(var(--mark-halo-ink) / min(0.42, calc(0.36 * var(--mark-halo-k)))),
    hsl(var(--mark-halo-ink) / min(0.18, calc(0.15 * var(--mark-halo-k)))) 40%,
    hsl(var(--mark-halo-ink) / 0) 72%
  );
}

/* :hover puro, sem gate de (hover: hover) / (pointer: fine), e a razão está
   medida: o Chrome do container de captura responde `false` às DUAS
   consultas (não há mouse físico atrás dele), então qualquer regra escondida
   ali dentro é uma regra que a auditoria desta casa NUNCA consegue
   fotografar. Efeito que só existe fora da evidência não existe.

   O que a gate protegia era o :hover grudado depois do toque em tela sem
   ponteiro. O custo real disso aqui é uma palavra decorativa acesa no centro
   até o próximo toque em outro lugar, em um <h2> que não é clicável: nada
   fica ilegível, nada fica inalcançável, nada muda de posição.

   CORREÇÃO DE 5 DE AGOSTO DE 2026 (PARTE 3) — gatilho movido de
   `.footer__mark:hover` para `.footer:hover`.

   O gatilho antigo (`.footer__mark:hover`, com `.footer:has(.footer__mark:
   hover)` replicando para o halo) parou de disparar depois da PARTE 2 desta
   mesma correção: hit-test real confirmou, com o ponteiro fisicamente sobre
   o wordmark, `elementFromPoint` devolvendo `.footer` — não o `<h2>` — e
   `.footer__mark.matches(':hover')` como `false`, nas peles padrão e smooth.
   Nenhuma regra desta folha nem das peles põe `pointer-events: none` no
   `<h2>` ou em algum ancestral dele (checado por grep); o wordmark é um SVG
   de glifos finos dentro de uma caixa cujo miolo (entrelinhas, respiro do
   `viewBox`) não é preenchido por tinta — em telas grandes, com o raio do
   realce (`--mark-lit-r`) hoje bem maior que a altura do próprio `<h2>`, a
   maior parte da área "sobre o wordmark" que um visitante mira com o mouse
   cai fora da caixa estreita do `<h2>` e dentro da caixa do `.footer` que a
   envolve — daí o `elementFromPoint` devolver o ancestral, não o título.

   Pedido do dono, motivado pelo mesmo raciocínio: já que o halo (PARTE 2)
   cobre o RODAPÉ INTEIRO, a ÁREA DE ATIVAÇÃO acompanha — o gatilho passa a
   ser o ponteiro em qualquer ponto do `.footer`, não mais restrito à caixa
   estreita do `<h2>`. `.footer:hover` cobre exatamente a caixa que
   `elementFromPoint` já mostrava estar recebendo o ponteiro, então a luz
   acende de verdade tanto sobre o wordmark quanto sobre as colunas do
   diretório. Não depende de `:has()` (ainda usado em outros pontos da base,
   mas dispensável aqui agora que as duas camadas escutam o mesmo ancestral
   host); a posição continua vindo só de `data-pointer` (PARTE 2, inalterado
   no CONCEITO -- `.footer__mark-lit` ainda lê `--px`/`--py`; `.footer__mark-
   glow` passou a ler `--pointer-dx`/`--pointer-dy`, ver PARTE 5 acima):
   `.footer:hover` decide SE acende, os dois `data-pointer` decidem ONDE. */
.footer:hover .footer__mark-lit {
  opacity: 1;
}

.footer:hover .footer__mark-glow {
  opacity: 1;
}

/* Congelamento (§6). As duas travas são independentes e as duas obrigatórias.
   NX.motion.pointer nem se registra nesses dois casos, então --px/--py
   ficariam parados no centro e o realce viraria uma mancha fixa acesa no
   meio da palavra. Aqui ele simplesmente não é desenhado: o wordmark fica no
   repouso e nada acende. */
@media (prefers-reduced-motion: reduce) {
  .footer__mark-lit,
  .footer__mark-glow {
    display: none;
  }
}

@container style(--motion: 0) {
  .footer__mark-lit,
  .footer__mark-glow {
    display: none;
  }
}

/* Sem suporte a máscara CSS o recorte não acontece e a camada acesa cobriria
   a palavra inteira de tinta chapada no hover. Nesse caso ela não existe: o
   rodapé degrada para o wordmark de repouso, que é o comportamento anterior.

   A palavra-chave `black` aqui não é decisão visual e não pode ser token:
   @supports precisa de um valor RESOLVÍVEL na hora do parse, e uma
   declaração que contenha var() é considerada válida por definição, o que
   faria o teste passar sempre e a rede de segurança nunca existir. Mesma
   razão e mesma palavra usadas na máscara do rail em 04-sections.css. */
@supports not ((mask-image: radial-gradient(circle, black, transparent)) or (-webkit-mask-image: radial-gradient(circle, black, transparent))) {
  .footer__mark-lit {
    display: none;
  }
}

/* --------------------------------------------------------------------------
   5. Linha final: copyright e voltar ao topo, discretos, atrás de um filete.
   -------------------------------------------------------------------------- */

.footer__base {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4) var(--space-6);
  margin-block-start: var(--space-10);
  padding-block-start: var(--space-6);
  border-block-start: var(--hairline) solid hsl(var(--border));
}

.footer__copyright {
  margin: 0;
  color: hsl(var(--muted-foreground));
  font-size: var(--fs-xs);
}

.footer__to-top {
  flex: none;
  margin-inline-start: auto;
  color: hsl(var(--muted-foreground));
}

.footer__to-top:hover {
  color: hsl(var(--accent-foreground));
}

.footer__to-top-icon {
  display: inline-flex;
  transform: rotate(-90deg);
  transition: transform calc(var(--dur-fast) * var(--motion)) var(--ease-out);
}

.footer__to-top:hover .footer__to-top-icon,
.footer__to-top:focus-visible .footer__to-top-icon {
  transform: translateY(-3px) rotate(-90deg);
}

/* --------------------------------------------------------------------------
   6. Telas estreitas.
   Ordem de empilhamento: tagline, redes, colunas do diretório, wordmark,
   linha final. O wordmark encolhe junto com o container (é 100% da largura
   do container, com proporção fixa do viewBox), então não precisa de regra.
   -------------------------------------------------------------------------- */

@media (max-width: 640px) {
  .footer__lead {
    gap: var(--space-10);
  }

  .footer__directory,
  .footer__nav {
    gap: var(--space-8) var(--space-10);
    inline-size: 100%;
  }

  .footer__mark {
    margin-block-start: var(--space-12);
  }

  .footer__base {
    justify-content: center;
    text-align: center;
  }

  .footer__to-top {
    margin-inline-start: 0;
  }
}

/* --------------------------------------------------------------------------
   7. Telas largas.
   O container já sobe para --container-wide acima de 1900px (02-base.css),
   então o wordmark acompanha sozinho. O que muda aqui é só a escala do
   fecho editorial, para a tagline não virar uma nota de rodapé ao lado de
   uma assinatura de 1500px de largura.
   -------------------------------------------------------------------------- */

@media (min-width: 1280px) {
  .footer__tagline {
    font-size: var(--fs-h2);
    max-inline-size: 16ch;
  }

  .footer__directory,
  .footer__nav {
    gap: var(--space-8) var(--space-12);
  }
}

/* Acima de 1560px o container salta para 1420px e depois para 1600px
   (rampa de 02-base.css). A tagline não cresce junto: são duas frases de
   dezessete caracteres, e alargar a caixa não alarga o texto, então ela
   trava no teto de 34rem e a sobra inteira do container vai para o
   diretório, que aí tem largura para as três colunas em uma linha só. O que
   esta regra acrescenta é apenas a DISTRIBUIÇÃO dentro dessa largura: sem
   ela as três colunas ficariam empilhadas à esquerda do próprio bloco e o
   vão apareceria entre "Endereço" e a quina direita. O <nav> NÃO recebe a
   mesma regra: ele é filho do diretório, e distribuir duas vezes abriria um
   buraco entre "Contato" e "Endereço". */
@media (min-width: 1560px) {
  .footer__directory {
    justify-content: space-between;
  }
}

/* 12a rodada, pedido do dono: faixa de cima em tres zonas. Declaracao a
   esquerda, Navegacao ao CENTRO, Contato (com endereco) a DIREITA. O <nav>
   vira display: contents para as duas colunas participarem da grade da
   faixa diretamente. */
@media (min-width: 62rem) {
  .footer__lead {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    align-items: start;
    column-gap: var(--space-10);
  }
  .footer__statement { grid-column: 1; }
  .footer__directory { display: contents; }
  .footer__nav { display: contents; }
  .footer__nav .footer__col:first-child { grid-column: 2; justify-self: center; }
  .footer__nav .footer__col:last-child { grid-column: 3; justify-self: end; }
}
