/**
 * SPEC-11 §5.10, blob do fundo da primeira dobra, em CSS puro.
 *
 * Técnica: um quadrado com gradiente, recortado por uma MÁSCARA de círculos
 * sobrepostos. Um `filter: blur()` funde os círculos numa massa orgânica só.
 * O borrão não é enfeite: é ele que transforma "alguns círculos" em "uma
 * forma". Sem ele a máscara aparece como o que é.
 *
 * São três massas SOBREPOSTAS no centro da dobra, não três formas espalhadas:
 * juntas leem como um corpo só, de contorno contínuo, o deslocamento entre
 * elas serve para engrossar a silhueta de um lado, não para separá-las. Uma
 * quarta, pequena e esférica, fica solta no canto inferior direito: sem ela a
 * composição é uma mancha única no meio e a dobra não tem para onde respirar.
 *
 * ── Por que cada forma tem DUAS massas ───────────────────────────────────
 * Uma máscara é rígida. Girá-la, movê-la e escaloná-la move a forma pelo
 * quadro, mas o CONTORNO é sempre o mesmo contorno, a coisa gira, não muda de
 * forma. Não há como interpolar uma máscara em CSS sem animar `mask-position`
 * ou `mask-size`, e aí cada quadro repinta a máscara inteira.
 *
 * Então cada forma são duas massas mascaradas (`::before` e `::after`) que se
 * sobrepõem dentro do MESMO pai borrado. O borrão as funde numa só, e como
 * elas giram e passeiam em compassos diferentes, o contorno da união muda o
 * tempo todo: onde a satélite avança nasce uma saliência, quando ela recolhe a
 * saliência é reabsorvida. Isso é mudança de forma de verdade, e sai só de
 * transform, nada de repintar máscara por quadro.
 *
 * ── O que dessincroniza ──────────────────────────────────────────────────
 * A silhueta NÃO gira na duração declarada no `span`. As massas moram dentro
 * de um pai que também gira: o que se vê é a SOMA das taxas. Duração declarada
 * engana, 19s+21s e 23s+18s parecem bem diferentes e dão 10,0s e 10,1s de
 * período composto. Eram duas formas girando em uníssono.
 *
 * O que está calibrado é o período composto do corpo principal:
 *   solta   13s +  9s →  5,3s
 *   média   24s + 21s → 11,2s
 *   grande  26s + 31s → 14,1s
 *   pequena 44s + 38s → 20,4s
 * Razões 1 : 2,11 : 2,66 : 3,85, nenhuma harmônica da outra.
 *
 * A massa principal é a mais devagar das três do grupo, de propósito: ela ocupa
 * quase toda a largura da composição, e giro que passa despercebido numa forma
 * pequena vira agitação quando é essa área que se move.
 *
 * ── Quatro eixos, porque só girar é mecânico ─────────────────────────────
 *   girar     `blob-girar`       9–44s, linear
 *   passear   `blob-vagar-*`    21–55s, com aceleração
 *   respirar  `blob-respirar-*`  7–21s, escala não uniforme
 *   orbitar   `blob-orbitar-*`  13–31s, só a massa satélite
 * mais atraso negativo em cada um, nenhuma animação entra em quadro no
 * próprio zero, então nada começa na mesma pose.
 *
 * Os períodos de uma mesma forma são primos entre si de propósito: com 15s de
 * giro e 30s de respiração a pose composta se repetiria a cada 30s, e o olho
 * pega repetição muito antes de conseguir nomeá-la.
 *
 * `rotate`, `translate` e `scale` são propriedades independentes, três
 * animações convivem no mesmo elemento sem uma sobrescrever o `transform` da
 * outra, e sem precisar de um keyframe combinado por forma. Todas continuam
 * sendo transform: nada de layout, nada de CLS (§6.5).
 *
 * O borrão fica em CADA forma, não no pai comum: a razão borrão/tamanho é o
 * que decide entre "forma" e "véu de cor" (1/25), e um borrão único no topo
 * seria proporcionalmente o dobro nas formas pequenas, elas se dissolveriam.
 *
 * Zero JavaScript. Nenhum canvas, nenhum shader, nenhuma compilação, nada a
 * adiar e nada que dependa de GPU disponível.
 *
 * Uso na landing: um palco `.blob-stage` (relative + isolation) contendo
 * `<div class="blob" aria-hidden="true"><span></span>×4</div>` e, depois dele,
 * `<div class="blob-scrim" aria-hidden="true"></div>`; o conteúdo vem em seguida.
 */

.blob {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  opacity: var(--blob-opacity);
}

.blob > span {
  position: absolute;
  display: block;
  width: var(--s);
  height: var(--s);
  filter: blur(calc(var(--s) / var(--blob-blur-ratio)));
}

/* A massa principal, acima do centro da dobra. Quatro lóbulos suaves em volta
   de um núcleo que domina, a silhueta do pen de referência, arredondada.

   As três alturas do corpo (40%, 34%, 56%) sobem e descem JUNTAS: são pontos de
   uma mesma massa, e mexer numa só estica a silhueta até abrir pescoço. */
.blob > span:nth-child(1) {
  --s: var(--blob-size);
  --lobos:
    radial-gradient(circle, var(--mask-opaque) 50%, transparent 50%) 50% 50% / var(--s) var(--s) no-repeat,
    radial-gradient(circle, var(--mask-opaque) 50%, transparent 50%) 125% 20% / calc(var(--s) * 0.78) calc(var(--s) * 0.78) no-repeat,
    radial-gradient(circle, var(--mask-opaque) 50%, transparent 50%) -25% 70% / calc(var(--s) * 0.72) calc(var(--s) * 0.72) no-repeat,
    radial-gradient(circle, var(--mask-opaque) 50%, transparent 50%) 40% 130% / calc(var(--s) * 0.68) calc(var(--s) * 0.68) no-repeat;
  --lobos-sat:
    radial-gradient(circle, var(--mask-opaque) 50%, transparent 50%) 50% 50% / calc(var(--s) * 0.86) calc(var(--s) * 0.86) no-repeat;
  top: calc(40% - var(--s) / 2);
  left: calc(50% - var(--s) / 2 - 4vmax);
  animation:
    blob-girar 26s -3s infinite linear both,
    blob-vagar-a 55s -6s infinite ease-in-out both,
    blob-respirar-a 18s -4s infinite ease-in-out both;
}

/* As outras duas NÃO são formas vizinhas: são as bossas do mesmo corpo. Ficam
   deslocadas o suficiente para engrossar a silhueta de um lado, e sobrepostas o
   suficiente para o contorno da união seguir contínuo, a leitura é uma massa
   só, grande, com relevo, e não três bolhas próximas.

   O critério é geométrico: distância entre centros menor que o raio da massa
   principal (senão aparece o pescoço entre as duas) e maior que raio − raio da
   bossa (senão ela some dentro e não deforma nada).

   Os offsets são do CENTRO, em vmax, a mesma unidade de `--blob-size`. Em
   porcentagem da largura o grupo se abriria junto com a janela: no desktop as
   três ficavam a meia tela uma da outra, cada uma sozinha num canto. */

/* Corpo ELÍPTICO com dois lóbulos: alongado, tipo feijão. A elipse é o que
   mais afasta esta silhueta das outras, nenhuma combinação de círculos dá um
   corpo oblongo. */
.blob > span:nth-child(2) {
  --s: calc(var(--blob-size) * 0.62);
  --lobos:
    radial-gradient(ellipse, var(--mask-opaque) 50%, transparent 50%) 50% 50% / var(--s) calc(var(--s) * 0.8) no-repeat,
    radial-gradient(circle, var(--mask-opaque) 50%, transparent 50%) 120% 25% / calc(var(--s) * 0.66) calc(var(--s) * 0.66) no-repeat,
    radial-gradient(circle, var(--mask-opaque) 50%, transparent 50%) -20% 78% / calc(var(--s) * 0.6) calc(var(--s) * 0.6) no-repeat;
  --lobos-sat:
    radial-gradient(ellipse, var(--mask-opaque) 50%, transparent 50%) 56% 46% / calc(var(--s) * 0.84) calc(var(--s) * 0.66) no-repeat;
  top: calc(34% - var(--s) / 2);
  left: calc(50% - var(--s) / 2 + 7vmax);
  animation:
    blob-girar 24s -14s infinite linear reverse both,
    blob-vagar-b 53s -19s infinite ease-in-out both,
    blob-respirar-b 17s -9s infinite ease-in-out both;
}

/* Bossa de baixo: gota rechonchuda, contorno quase liso. Contagem de lóbulos é
   contagem de PONTAS, cada lóbulo abre duas concavidades onde encontra o
   corpo, e numa massa menor isso vira respingo espetado. Aqui o relevo vem da
   proporção e da satélite, não do recorte. */
.blob > span:nth-child(3) {
  --s: calc(var(--blob-size) * 0.48);
  --lobos:
    radial-gradient(circle, var(--mask-opaque) 50%, transparent 50%) 50% 50% / var(--s) var(--s) no-repeat,
    radial-gradient(circle, var(--mask-opaque) 50%, transparent 50%) 118% 62% / calc(var(--s) * 0.7) calc(var(--s) * 0.7) no-repeat;
  --lobos-sat:
    radial-gradient(circle, var(--mask-opaque) 50%, transparent 50%) 45% 55% / calc(var(--s) * 0.82) calc(var(--s) * 0.82) no-repeat;
  top: calc(56% - var(--s) / 2);
  left: calc(50% - var(--s) / 2 + 4vmax);
  animation:
    blob-girar 44s -21s infinite linear both,
    blob-vagar-b 47s -11s infinite ease-in-out reverse both,
    blob-respirar-a 21s -13s infinite ease-in-out reverse both;
}

/* A quarta não é bossa do corpo: é uma esfera miúda que se soltou dele, abaixo
   e à direita. Fica perto, o vão entre ela e a bossa de baixo é da ordem do
   próprio diâmetro dela, porque longe demais ela vira um segundo assunto no
   fundo, e encostada some dentro da massa.

   Offset do centro em vmax como as outras, e não porcentagem da largura: é
   distância em relação ao GRUPO que precisa se manter, não em relação à borda
   da tela.

   A altura é 62% e não mais embaixo porque a partir de ~66% ela cai atrás do
   campo de URL e do botão, um ponto de luz brotando debaixo do CTA lê como
   estado do controle, não como fundo.

   E o compasso dela é o oposto do da massa principal: períodos curtos onde a
   grande tem períodos longos, caminho próprio (`blob-vagar-c`) e respiração
   própria (`blob-respirar-c`), mais funda e mais rápida. Não é só variação de
   número, corpo pequeno que se move devagar parece pesado, e o que se quer
   aqui é o contrário: a massa grande arrasta, a bolinha é ligeira. 

   Um lóbulo só, do tamanho do quadro: essa é a diferença dela. Onde as outras
   têm relevo, esta é redonda; o movimento que sobra vem da satélite e da
   respiração, e é sutil de propósito. */
.blob > span:nth-child(4) {
  --s: calc(var(--blob-size) * 0.102);
  --lobos:
    radial-gradient(circle, var(--mask-opaque) 50%, transparent 50%) 50% 50% / var(--s) var(--s) no-repeat;
  --lobos-sat:
    radial-gradient(circle, var(--mask-opaque) 50%, transparent 50%) 50% 50% / calc(var(--s) * 0.62) calc(var(--s) * 0.62) no-repeat;
  top: calc(62% - var(--s) / 2);
  left: calc(50% - var(--s) / 2 + 18vmax);
  animation:
    blob-girar 13s -4s infinite linear reverse both,
    blob-vagar-c 21s -9s infinite ease-in-out both,
    blob-respirar-c 7s -3s infinite ease-in-out both;
}

/* As duas massas de cada forma. Mesmo box; o que difere é a máscara que cada
   uma lê e o compasso em que se move.

   O `no-repeat` vai DENTRO de cada camada de `--lobos`, não numa declaração
   `mask-repeat` à parte: a shorthand `mask` reseta `mask-repeat` para o valor
   inicial (`repeat`), então uma declaração separada só sobrevive se vier
   depois, e aqui a shorthand vem numa regra posterior. Ladrilhado, cada
   lóbulo se repetia pela tela inteira e o fundo virava um véu com bordas
   retas. Dentro da camada é imune a ordem de regra. */
.blob > span::before,
.blob > span::after {
  content: '';
  position: absolute;
  inset: 0;
}

/* Corpo: mesmo sentido de giro do pai, e é dessa soma que sai o período
   composto calibrado lá em cima. */
.blob > span::before {
  -webkit-mask: var(--lobos);
  mask: var(--lobos);
}

/* Satélite: gira ao contrário do corpo e orbita por dentro dele. Amplitude
   calibrada para ela chegar à borda e voltar, se saísse de vez viraria uma
   quarta forma, e se ficasse dentro não deformaria nada. */
.blob > span::after {
  -webkit-mask: var(--lobos-sat);
  mask: var(--lobos-sat);
}

.blob > span:nth-child(1)::before {
  background: linear-gradient(var(--blob-a), var(--blob-b), var(--blob-c) 40%);
  animation: blob-girar 31s -9s infinite linear both;
}
.blob > span:nth-child(1)::after {
  background: linear-gradient(var(--blob-c), var(--blob-b));
  animation:
    blob-girar 38s -7s infinite linear reverse both,
    blob-orbitar-a 26s -5s infinite ease-in-out both,
    blob-respirar-b 16s -2s infinite ease-in-out both;
}

.blob > span:nth-child(2)::before {
  background: linear-gradient(var(--blob-a), var(--blob-c));
  animation: blob-girar 21s -5s infinite linear reverse both;
}
.blob > span:nth-child(2)::after {
  background: linear-gradient(var(--blob-b), var(--blob-a));
  animation:
    blob-girar 33s -12s infinite linear both,
    blob-orbitar-b 27s -8s infinite ease-in-out both,
    blob-respirar-a 15s -6s infinite ease-in-out both;
}

.blob > span:nth-child(3)::before {
  background: linear-gradient(var(--blob-c), var(--blob-b));
  animation: blob-girar 38s -12s infinite linear both;
}
.blob > span:nth-child(3)::after {
  background: linear-gradient(var(--blob-b), var(--blob-c));
  animation:
    blob-girar 19s -3s infinite linear reverse both,
    blob-orbitar-a 23s -14s infinite ease-in-out reverse both,
    blob-respirar-b 12s -7s infinite ease-in-out both;
}

.blob > span:nth-child(4)::before {
  background: linear-gradient(var(--blob-b), var(--blob-c));
  animation: blob-girar 9s -2s infinite linear reverse both;
}
.blob > span:nth-child(4)::after {
  background: linear-gradient(var(--blob-c), var(--blob-a));
  animation:
    blob-girar 11s -5s infinite linear both,
    blob-orbitar-b 13s -6s infinite ease-in-out both,
    blob-respirar-a 8s -1s infinite ease-in-out both;
}

@keyframes blob-girar {
  from { rotate: 0deg; }
  to   { rotate: 360deg; }
}

/* Passeio da forma inteira. Percentuais são do próprio tamanho, então a
   amplitude acompanha `--s` e a pequena não vagueia tanto quanto a grande.
   Quatro paradas, nenhuma no eixo da anterior: com poucas paradas o caminho
   vira um vaivém reconhecível, e vaivém não parece vivo. */
@keyframes blob-vagar-a {
  0%   { translate: 0 0; }
  22%  { translate: 9% -5%; }
  44%  { translate: 4% 8%; }
  71%  { translate: -7% 3%; }
  100% { translate: 0 0; }
}
@keyframes blob-vagar-b {
  0%   { translate: 0 0; }
  27%  { translate: -8% -7%; }
  52%  { translate: 5% -2%; }
  78%  { translate: 6% 7%; }
  100% { translate: 0 0; }
}

/* Órbita da satélite: maior que a do passeio, porque aqui o deslocamento não é
   para a forma andar, é para o contorno da união mudar. Mas com teto: passando
   de ~12% do próprio tamanho a satélite sai o bastante para virar um braço com
   pescoço, e a forma deixa de ser redonda. Até aí ela é um bojo que migra. */
@keyframes blob-orbitar-a {
  0%   { translate: 0 0; }
  25%  { translate: 11% 4%; }
  50%  { translate: 5% 12%; }
  75%  { translate: -9% 6%; }
  100% { translate: 0 0; }
}
@keyframes blob-orbitar-b {
  0%   { translate: 0 0; }
  30%  { translate: -10% 7%; }
  55%  { translate: -4% -10%; }
  80%  { translate: 9% -3%; }
  100% { translate: 0 0; }
}

/* Respirar: escala NÃO uniforme, um eixo enchendo enquanto o outro esvazia,
   como massa de volume constante. Escala uniforme lê como zoom, não como corpo
   mole. O eixo do achatamento gira junto com a forma, `scale` entra antes de
   `rotate` na composição das propriedades individuais, então a deformação
   nunca é "achatou na vertical", é um bambolear que muda de direção. */
/* Caminho só da bolinha: amplitude maior e paradas mais espaçadas em ritmo.
   Ela é pequena, então o mesmo deslocamento em porcentagem do próprio tamanho
   dá um trajeto curto na tela, daí o dobro da amplitude das massas grandes. */
@keyframes blob-vagar-c {
  0%   { translate: 0 0; }
  18%  { translate: 16% 9%; }
  39%  { translate: -6% 18%; }
  58%  { translate: -19% 2%; }
  81%  { translate: 7% -14%; }
  100% { translate: 0 0; }
}

/* Respiração da bolinha: mais funda e mais rápida que a das massas grandes. */
@keyframes blob-respirar-c {
  0%   { scale: 1 1; }
  31%  { scale: 1.14 0.89; }
  62%  { scale: 0.88 1.13; }
  100% { scale: 1 1; }
}

@keyframes blob-respirar-a {
  0%   { scale: 1 1; }
  34%  { scale: 1.08 0.93; }
  67%  { scale: 0.94 1.06; }
  100% { scale: 1 1; }
}
@keyframes blob-respirar-b {
  0%   { scale: 1 1; }
  29%  { scale: 0.93 1.07; }
  63%  { scale: 1.09 0.95; }
  100% { scale: 1 1; }
}

/* §6.3, sem movimento a forma fica; giro, passeio, órbita e respiração somem. */
@media (prefers-reduced-motion: reduce) {
  .blob > span,
  .blob > span::before,
  .blob > span::after {
    animation: none;
  }
}

/* ── palco e véu (landing) ──────────────────────────────────────────────
   No original o blob usa `-z-10` do Tailwind dentro da tela do hero. Aqui o
   palco cria o contexto de empilhamento (isolation) e as duas camadas de
   fundo ficam atrás do conteúdo sem precisar de z-index nos filhos. */
.blob-stage {
  position: relative;
  isolation: isolate;
  overflow: hidden;
}
.blob,
.blob-scrim {
  z-index: -1;
}
/* Véu entre o fundo e a copy (§5.10): mantém o contraste do texto enquanto
   as manchas passam por baixo. */
.blob-scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: var(--liquid-scrim);
}
