/* ==========================================================================
   DESFOQUE PROGRESSIVO — prefixo dsf-
   Uma faixa colada à borda de baixo da janela em que a página vai perdendo
   o foco à medida que chega na borda: nítida a uma altura de dedo, desfeita
   no rodapé da tela. CSS puro — nenhuma linha de JavaScript.

   Tokens usados:
     --dark     fallback da tinta opcional da borda (--dsf-cor)

   POR QUE CINCO CAMADAS, E NÃO UMA COM MÁSCARA. Um `backdrop-filter` só tem
   UM raio. Uma camada de 14px com máscara em gradiente não desfoca "aos
   poucos": desfoca tudo a 14px e esmaece o resultado, e no meio da faixa o
   que se vê são duas imagens sobrepostas — a nítida e a borrada — em vez de
   uma imagem meio desfocada. Lê como fantasma. A saída é empilhar camadas
   de raio crescente (1/16, 1/8, 1/4, 1/2 e o raio cheio), cada uma com uma
   JANELA de máscara que só a deixa valer numa fatia da faixa. As janelas se
   sobrepõem pela metade, e por isso a passagem de um raio para o seguinte
   não tem degrau. É o desenho do "progressive blur" do Framer, que a
   referência usa com oito camadas; aqui são cinco, e o porquê está na
   ficha.

   É A REGRA DO VÉU DO §6 LEVADA AO LIMITE: nenhuma das cinco camadas é
   caixa reta de `backdrop-filter`. Todas carregam máscara em gradiente.

   POR QUE STICKY, E NÃO FIXED. Uma faixa `fixed` cobriria o fim da página
   para sempre: o texto legal do rodapé ficaria desfocado justamente quando
   a pessoa rola até ele para ler. Uma faixa `sticky` com `bottom:0` gruda
   na borda da janela enquanto o trecho que a contém estiver passando, e
   quando o trecho acaba ela PARA no lugar natural dela — e o rodapé, que
   vem depois, entra nítido. Sem uma linha de script medindo o fim da
   página. A condição é estrutural: o .dsf é o ÚLTIMO filho do trecho.

   ALTURA ZERO, CAMADAS PARA FORA. O elemento grudado não ocupa espaço no
   fluxo (block-size:0) e as camadas saem dele para cima, em posição
   absoluta. É o que dispensa a margem negativa que uma faixa de 160px de
   altura real precisaria para não empurrar o conteúdo.

   PARAFUSOS (custom properties do próprio componente, §3):
     --dsf-h       altura da faixa
     --dsf-max     raio da camada mais forte, a da borda
     --dsf-tinta   quanto da cor --dsf-cor pinta a borda (0% = nenhum)
     --dsf-cor     a cor dessa tinta (padrão: --dark)
     --dsf-topo    distância do topo na variação .dsf--topo (a altura de um
                   menu fixo, quando houver)
   ========================================================================== */

.dsf{
  /* A ALTURA É O RESPIRO ENTRE DOBRAS, e não um número próprio. No fim do
     trecho a faixa para no lugar natural dela e fica PARADA sobre os últimos
     --dsf-h pixels da última dobra — para sempre, porque dali a página não
     rola mais. Com a altura igual ao --sec-gap, esses pixels são exatamente
     o padding de baixo da dobra (.sec-pad), onde não há texto. Uma faixa
     mais alta que o respiro deixaria as últimas linhas da última dobra
     desfocadas sem remédio. O token já tem piso e teto (110 a 160px), que é
     também a faixa em que cinco raios cabem sem virar degrau. */
  --dsf-h:var(--sec-gap);
  /* Na borda, o texto de corpo some por completo a partir de ~10px; 14 dá a
     margem para display grande, que resiste mais ao desfoque. */
  --dsf-max:14px;
  --dsf-tinta:0%;
  /* Sentido do gradiente das máscaras: do lado de DENTRO da faixa para a
     borda. Na faixa de baixo o lado de dentro é o de cima. */
  --dsf-dir:to bottom;

  position:sticky;
  inset-block-end:0;
  /* Abaixo do botão flutuante (90) e do menu fixo (100), que precisam ser
     lidos por cima da faixa. A escala da casa está comentada em
     core/tokens.css, junto do --z-overlay. */
  z-index:80;
  display:block;
  block-size:0;
  /* A faixa é decoração sobre conteúdo vivo: sem isto ela engoliria o
     clique em todo link que passasse por baixo dela. */
  pointer-events:none;
}

.dsf::before,
.dsf-camada{
  content:"";
  position:absolute;
  inset-inline:0;
  inset-block-end:0;
  block-size:var(--dsf-h);
}

/* A tinta opcional. Desligada no padrão (--dsf-tinta:0%), e é de propósito:
   a faixa passa sobre seções de tons diferentes, e uma tinta escura sobre
   uma .sec-paper vira mancha. Ligue só quando o trecho inteiro for de um
   tom só. */
.dsf::before{
  z-index:1;
  background:linear-gradient(var(--dsf-dir),
    transparent,
    color-mix(in srgb,var(--dsf-cor,var(--dark)) var(--dsf-tinta),transparent));
}

/* As cinco janelas. Com s = 1/6 da faixa, a camada k vale de (k-1)s a
   (k+2)s: sobe de zero a cheio em uma fatia, fica cheia em outra e volta a
   zero na terceira. A quinta não tem onde voltar a zero e fica cheia até a
   borda — é ela que manda no rodapé da tela. */
.dsf-camada{
  --dsf-s:calc(100% / 6);
  -webkit-backdrop-filter:blur(var(--dsf-b));
  backdrop-filter:blur(var(--dsf-b));
  /* Uma linha por máscara, e não quatro: o #000 aqui é OPACIDADE, não cor,
     e o bin/conformidade.py só reconhece isso na linha que diz mask-image. */
  -webkit-mask-image:linear-gradient(var(--dsf-dir),transparent calc((var(--dsf-k) - 1) * var(--dsf-s)),#000 calc(var(--dsf-k) * var(--dsf-s)),#000 calc((var(--dsf-k) + 1) * var(--dsf-s)),transparent calc((var(--dsf-k) + 2) * var(--dsf-s)));
  mask-image:linear-gradient(var(--dsf-dir),transparent calc((var(--dsf-k) - 1) * var(--dsf-s)),#000 calc(var(--dsf-k) * var(--dsf-s)),#000 calc((var(--dsf-k) + 1) * var(--dsf-s)),transparent calc((var(--dsf-k) + 2) * var(--dsf-s)));
}
/* Cada raio é a metade do seguinte. Progressão geométrica e não linear:
   o olho lê desfoque em escala logarítmica, e 3-6-9-12-14 pareceria
   "nítido, nítido, borrado" — o salto aconteceria todo no começo. */
.dsf-camada:nth-child(1){--dsf-k:1;--dsf-b:calc(var(--dsf-max) * .0625)}
.dsf-camada:nth-child(2){--dsf-k:2;--dsf-b:calc(var(--dsf-max) * .125)}
.dsf-camada:nth-child(3){--dsf-k:3;--dsf-b:calc(var(--dsf-max) * .25)}
.dsf-camada:nth-child(4){--dsf-k:4;--dsf-b:calc(var(--dsf-max) * .5)}
.dsf-camada:nth-child(5){--dsf-k:5;--dsf-b:var(--dsf-max)}

/* ------------------------------------------------- variação: topo */
/* A mesma faixa na borda de CIMA: o .dsf vira o PRIMEIRO filho do trecho e
   gruda no topo. Com menu fixo, --dsf-topo recebe a altura dele, e a faixa
   começa onde o menu termina em vez de passar por baixo dele. */
.dsf--topo{
  --dsf-dir:to top;
  inset-block-end:auto;
  inset-block-start:var(--dsf-topo,0px);
}
.dsf--topo::before,
.dsf--topo .dsf-camada{
  inset-block-end:auto;
  inset-block-start:0;
}

/* ------------------------------------------------- quem não quer */
/* Transparência reduzida é a pessoa pedindo ao sistema menos vidro e menos
   desfoque — exatamente o que esta peça é. Não há versão "menor" dela que
   faça sentido: some. (Chrome 118+; nos outros a consulta não casa e a
   faixa fica, que é o comportamento de antes da consulta existir.) */
@media (prefers-reduced-transparency:reduce){
  .dsf{display:none}
}
/* No papel não há o que rolar, e cinco camadas de backdrop-filter na
   impressão ou viram retângulo cinza ou somem, dependendo do navegador. */
@media print{
  .dsf{display:none}
}

/* ---------------------------------------------------------------- mobile */
/* Na tela do celular 16vh de faixa são ~130px de 844 — mas a coluna de
   texto é estreita e cada linha é curta, então a faixa cobre mais LINHAS do
   que no desktop. Mais baixa e mais branda. */
@media (max-width:640px){
  .dsf{--dsf-h:clamp(64px,11vh,104px);--dsf-max:10px}
}
/* (Acima:) continua menor que o --sec-gap, que tem piso de 110px — a regra
   do fim do trecho segue de pé no celular. */
