/* =====================================================================================
   FariaOS — Intro cinematográfica do site institucional (Rodada 3.3 — boot recovery +
   deterministic startup + motion final).

   "O site nasce da marca": ESCURO → PRESENÇA → FORMA → PROFUNDIDADE → MATERIALIZAÇÃO →
   MARCA → AMBIENTE → PRODUTO. Uma wordmark SVG "FARIAOS" se materializa da esquerda para a
   direita (frente de luz sobre uma estrutura fantasma já presente no escuro), assina a marca
   por um instante, e o preto se abre revelando o Hero por trás da própria palavra antes dela
   desaparecer — nunca um corte seco entre intro e site.

   ARQUITETURA:
   - Nenhuma dependência nova. Sem GSAP/Three.js/Canvas/WebGL/Lottie/vídeo/partículas.
   - Motion 100% CSS @keyframes (ver "POR QUE NÃO WAAPI" abaixo) sobre um único SVG inline
     (1 <text> base reaproveitada via <use> — nunca paths duplicados, nunca dezenas de spans).
   - Linha do tempo inteira como custom properties abaixo (ms, sem unidade — consumidas via
     calc(var(--x) * 1ms) nas regras, e lidas em JS via getComputedStyle para o agendamento de
     site.js) — mudar os valores aqui é o único lugar a editar para retimar a intro. A única
     exceção inevitável: os PERCENTUAIS internos de cada @keyframes são estáticos (limitação
     da linguagem CSS — não é possível usar calc(var()) como offset de keyframe), então cada
     bloco documenta a aritmética exata que os gerou a partir destas variáveis.
   - --intro-word-width É a única variável de layout calculada em runtime (site.js mede a
     largura real do texto via getBBox() depois da fonte carregar e escreve o valor aqui) —
     nunca um número de largura "chutado", sempre a geometria real renderizada.

   POR QUE NÃO WAAPI (ver pedido, seção 3):
   Consideramos seriamente. WAAPI ganha quando a coreografia precisa ser CONSTRUÍDA em JS a
   partir de dados que só existem em runtime (nº de itens variável, curvas por dispositivo...).
   Aqui a única incógnita real é a largura da palavra — e resolvemos isso escrevendo-a como
   custom property que o @keyframes consome, o que elimina a única razão prática para
   construir keyframes via element.animate(). Para o resto (scrub/pause/play do painel de
   debug), CSS Animations expõem exatamente a mesma API via el.getAnimations() — Animation
   objects com .currentTime/.pause()/.play() idênticos aos de WAAPI. Resultado: paridade total
   de controle para o debug, com a vantagem de @keyframes declarativos serem mais simples de
   ler/ajustar do que arrays de keyframes en JS para uma coreografia que é, no fim, estática.

   FAIL-SAFE (camadas, da mais externa para a mais interna — reforçado na Rodada 3.3):
   1. Bootstrap síncrono inline em site-head.php decide ANTES do primeiro paint se
      html.fariaos-intro-pending deve existir (sessionStorage em try/catch, fail-open para
      "mostrar o site"). Essa é a ÚNICA leitura de elegibilidade da página inteira — a decisão
      fica em window.__FARIAOS_INTRO_BOOT__ e nunca é reavaliada por site.js.
   2. #site-intro tem `display:none` como padrão de CSS (não mais um atributo `hidden`
      removido por JS — ver bloco ESTRUTURA/FAIL-SAFE abaixo). Sem a classe do passo 1, o
      elemento nunca existe visualmente, ponto — nenhuma corrida entre JS e atributo HTML.
   3. <noscript> em site-head.php força os itens do Hero visíveis sem JS.
   4. Fail-safe puro-CSS adicional aqui (intro-hard-failsafe) e em site.css (reveal-item) —
      caso o JS aplique a classe de exibição e trave no meio da sequência, o overlay e o Hero
      se resolvem sozinhos por um relógio CSS, sem depender de nenhum timeout de JS.
   ===================================================================================== */

:root {
  --z-intro: 2000;       /* acima de .skip-link (1000) — o maior z-index já existente no site */
  --z-intro-debug: 2001; /* painel de debug fica acima do próprio overlay */

  /* ---- Linha do tempo mestra (ms, sem unidade) — fonte única de verdade ---- */
  --intro-total: 3250;

  --intro-ghost-fade-start: 220;      /* FIRST SIGNAL começa */
  --intro-ghost-fade-duration: 980;   /* GHOST estável em 220+980=1200ms */
  --intro-echo1-extra-delay: 90;      /* eco 1 acende ~90ms depois do ghost base */
  --intro-echo2-extra-delay: 170;     /* eco 2 acende ~170ms depois — "iluminação irregular" */
  --intro-settle-start: 2140;
  --intro-settle-duration: 340;       /* SETTLE termina em 2140+340=2480ms */

  --intro-materialization-start: 1120;
  --intro-materialization-duration: 1120; /* termina em 1120+1120=2240ms */

  --intro-backdrop-fade-delay: 2720;
  --intro-backdrop-fade-duration: 520; /* fundo totalmente transparente em 2720+520=3240ms */
  --intro-wordmark-fade-delay: 2980;
  --intro-wordmark-fade-duration: 260; /* wordmark totalmente sumida em 2980+260=3240ms */

  --intro-hero-reveal-start: 2790; /* só documentado aqui — site.js lê via getComputedStyle */
  --intro-end: 3240;               /* idem — instante em que finishIntro() roda */

  --intro-reduced-fade-duration: 220; /* variante reduced-motion: marca já formada, fade curto */

  --intro-word-width: 380; /* placeholder — site.js sobrescreve com a largura real (getBBox) */
  --intro-word-x: 190;     /* placeholder — borda esquerda real do <text> (text-anchor:middle
                               não fica em x=0; site.js sobrescreve com box.x medido) */
}

/* ============================== ESTRUTURA / FAIL-SAFE ============================== */

/* Rodada 3.3 (seção 9 do pedido): DEIXAMOS de usar o atributo `hidden` como estado principal.
   O padrão de fábrica do elemento é display:none — SEM DEPENDER DE JS PARA ISSO — e só passa a
   existir visualmente quando html.fariaos-intro-pending está presente (aplicada pelo bootstrap
   síncrono em site-head.php, ANTES do primeiro paint). A regra abaixo tem especificidade
   estritamente maior que a de cima só por conter os mesmos seletores mais qualificadores
   extras (html + .fariaos-intro-pending) — não há ambiguidade possível de cascata aqui, ao
   contrário de um `[hidden]` competindo por especificidade igual com uma classe (a causa raiz
   de bugs análogos já vistos neste projeto, ex. o menu mobile na Rodada 1). Resultado:
   SEM JS → nunca existe visualmente, site aparece normal.
   COM boot elegível → aparece.
   COM usuário recorrente (boot decidiu não rodar) → nunca aparece, nem por 1 frame. */
#site-intro {
  display: none;
  position: fixed;
  inset: 0;
  z-index: var(--z-intro);
  align-items: center;
  justify-content: center;
  contain: paint;      /* isola a pintura do overlay do resto da página (seção 37) */
  isolation: isolate;  /* evita composição/blend inesperado com o que está atrás */
  background: transparent; /* o preto é o .intro-backdrop, não o próprio overlay (seção 20) */
}

html.fariaos-intro-pending #site-intro { display: flex; }

#site-intro.is-inert { pointer-events: none; }

/* Fail-safe adicional: se hidden for removido e o JS travar antes de terminar por qualquer
   motivo, este relógio puramente CSS torna o overlay transparente e para de bloquear cliques
   sozinho aos ~6s — bem depois do fim normal (3.25s), nunca concorre com o fluxo normal. */
#site-intro {
  animation: intro-hard-failsafe 0s linear 6s forwards;
}
@keyframes intro-hard-failsafe { to { opacity: 0; pointer-events: none; } }

/* ============================== BACKDROP + GLOW ============================== */
/* Camadas SEPARADAS de propósito (seção 20/18): o preto (.intro-backdrop) e a marca
   (.intro-wordmark) desaparecem em janelas DIFERENTES — o preto começa a abrir primeiro
   (2720ms), a marca continua visível por cima, o Hero aparece por trás, e só depois (2980ms)
   a marca também começa a sumir. Se fosse um único opacity no #site-intro inteiro, tudo
   sumiria junto e pareceria "dois vídeos colados" em vez de um nascimento contínuo. */
.intro-backdrop {
  position: absolute; inset: 0;
  background: #08080A; /* == --bg de .site-body: nunca um salto de cor na dissolução */
}
#site-intro.is-playing .intro-backdrop {
  animation: intro-backdrop-fade calc(var(--intro-backdrop-fade-duration) * 1ms) ease-in-out
             calc(var(--intro-backdrop-fade-delay) * 1ms) forwards;
  /* ease-in-out, não a curva de entrada usada alhures: uma curva "rápida no início" colapsaria
     a opacidade quase de imediato em vez de dissolver — bug real já visto e corrigido na
     Rodada 3 (ver histórico do commit anterior); ease-in-out dissolve perceptivelmente ao
     longo de toda a janela. */
}
@keyframes intro-backdrop-fade { from { opacity: 1; } to { opacity: 0; } }

/* Glow dourado radial atrás da marca — nasce discreto, cresce sutilmente até a assinatura
   (BRAND HOLD) e se dissolve em conjunto com o backdrop, cedendo lugar ao glow real do Hero
   (.site-hero-bg::after em site.css, mesma família de cor --site-glow). A continuidade é
   perceptiva (mesma temperatura de cor), não uma animação literal de raio (seção 21). */
.intro-glow {
  position: absolute; inset: 0;
  background: radial-gradient(46vmin 46vmin at 50% 52%, rgba(217, 169, 77, .22), rgba(217, 169, 77, .07) 55%, transparent 76%);
  opacity: 0;
}
/* Percentuais calculados sobre --intro-glow-total implícito de 3240ms (backdrop-fade-delay +
   backdrop-fade-duration): 1200/3240=37%, 2460/3240=76% (início do BRAND HOLD), 2720/3240=84%
   (começa a sumir junto do backdrop), 100%=3240ms. */
#site-intro.is-playing .intro-glow {
  animation: intro-glow-arc 3240ms ease-in-out forwards;
}
@keyframes intro-glow-arc {
  0%   { opacity: 0; }
  37%  { opacity: .38; }
  76%  { opacity: .55; }
  84%  { opacity: .4; }
  100% { opacity: 0; }
}

/* ============================== WORDMARK (grupo) ============================== */

.intro-wordmark {
  position: relative;
  width: clamp(300px, 46vw, 620px);
  height: auto;
  overflow: visible;
}
#site-intro.is-playing .intro-wordmark {
  animation: intro-wordmark-fade calc(var(--intro-wordmark-fade-duration) * 1ms) ease-in-out
             calc(var(--intro-wordmark-fade-delay) * 1ms) forwards;
}
@keyframes intro-wordmark-fade { from { opacity: 1; } to { opacity: 0; } }

/* ---- Camadas dentro do SVG (5 no total: ghost, eco 1, eco 2, sólida, sweep) ---- */

#introWordBase {
  font-family: var(--site-font-display, "Plus Jakarta Sans", sans-serif);
  font-weight: 800;
  letter-spacing: .01em;
}

.intro-echo, .intro-ghost { opacity: 0; }
.intro-echo-1 { transform: translateX(-3px); }
.intro-echo-2 { transform: translateX(-6px); }

/* As TRÊS camadas escuras (ghost + 2 ecos) reaproveitam o MESMO @keyframes — só o
   animation-delay muda (0 / +90ms / +170ms), o que já produz a sensação de "iluminação
   irregular controlada" pedida (cada uma acende e perde energia num instante ligeiramente
   diferente) sem precisar de ruído aleatório nem de lógica por-letra.
   Percentuais sobre a janela ghost-fade-start → settle-start+settle-duration (220→2480,
   totalizando 2260ms): rampa até (--intro-ghost-fade-duration / 2260) = 980/2260 ≈ 43%,
   mantém até (--intro-settle-start - --intro-ghost-fade-start) / 2260 = 1920/2260 ≈ 85%,
   cai a 0 em 100% (2480ms, fim do SETTLE). */
#site-intro.is-playing .intro-ghost,
#site-intro.is-playing .intro-echo-1,
#site-intro.is-playing .intro-echo-2 {
  animation-name: intro-ghost-fade;
  animation-duration: 2260ms;
  animation-timing-function: ease-in-out;
  animation-fill-mode: forwards;
}
#site-intro.is-playing .intro-ghost   { animation-delay: calc(var(--intro-ghost-fade-start) * 1ms); }
#site-intro.is-playing .intro-echo-1  { animation-delay: calc((var(--intro-ghost-fade-start) + var(--intro-echo1-extra-delay)) * 1ms); }
#site-intro.is-playing .intro-echo-2  { animation-delay: calc((var(--intro-ghost-fade-start) + var(--intro-echo2-extra-delay)) * 1ms); }
@keyframes intro-ghost-fade {
  0%   { opacity: 0; }
  43%  { opacity: .16; }
  85%  { opacity: .16; }
  100% { opacity: 0; }
}

/* Camada sólida (off-white — a MESMA cor do wordmark real do cabeçalho, var(--ink); nunca
   dourado o tempo todo: auditado em site.css, .site-brand-name usa var(--ink), só o quadrado
   da marca é dourado. O dourado nesta intro vive só no sweep/glow/assinatura, não na palavra
   inteira formada — ver seção 15 do pedido). Revelada progressivamente por um clip-path cujo
   <rect> cresce de 0 até a largura real da palavra (--intro-word-width, medida em runtime). */
.intro-solid { opacity: 1; }
/* x/width NÃO são declarados aqui em CSS: medimos duas vezes que este Chromium não repinta um
   <rect> SVG a partir de CSS width/x (a Animation corre com progress correto, mas o valor
   nunca aparece na tela — bug real, 1ª/2ª passagem visual desta rodada) — a geometria real
   (posição/largura da palavra, via getBBox) é escrita como ATRIBUTO SVG diretamente por
   measureWordBox() em site.js. Aqui só cuidamos do transform-origin/transform, que É
   confiável via CSS para SVG, e é o que de fato revela a palavra progressivamente (scaleX,
   ancorado na borda esquerda via transform-box:fill-box). */
#introRevealRect {
  transform-box: fill-box; transform-origin: 0% 50%;
  transform: scaleX(0);
}
#site-intro.is-playing #introRevealRect {
  animation: intro-reveal-scale calc(var(--intro-materialization-duration) * 1ms)
             cubic-bezier(.4, .05, .2, 1) calc(var(--intro-materialization-start) * 1ms) forwards;
}
@keyframes intro-reveal-scale { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* Pequeno assentamento ao final da materialização (SETTLE) — a marca "ganha precisão"; nunca
   elástico, um deslocamento de 2px que se resolve. */
#site-intro.is-playing .intro-solid {
  animation: intro-settle-transform calc(var(--intro-settle-duration) * 1ms) ease-out
             calc(var(--intro-settle-start) * 1ms) forwards;
}
@keyframes intro-settle-transform { from { transform: translateX(2px); } to { transform: translateX(0); } }

/* Sweep: um segundo <rect> de clip, ESTREITO, que percorre a mesma janela/curva da
   materialização — confina o preenchimento em gradiente (transparente→quente→transparente)
   à FORMA das letras (é um <use> do mesmo texto-base, nunca um retângulo sobre o fundo preto),
   por isso nunca parece "uma barra passando pela logo": só acende onde já existe glifo.
   Mesmo raciocínio do reveal acima: x/width vêm do atributo SVG (site.js), o movimento é
   100% via transform (translateX), e transform-box:fill-box é obrigatório — sem ele, o
   transform neste <rect> dentro de <clipPath> simplesmente não repinta nesta engine (mesmo
   bug do reveal). O retângulo nasce achatado à esquerda da palavra e percorre a MESMA
   distância que ela ocupa (largura real + a própria largura do retângulo). */
#introSweepRect { transform-box: fill-box; transform: translateX(0); }
#site-intro.is-playing #introSweepRect {
  animation: intro-sweep-translate calc(var(--intro-materialization-duration) * 1ms)
             cubic-bezier(.4, .05, .2, 1) calc(var(--intro-materialization-start) * 1ms) forwards;
}
/* px aqui não é "pixel de tela" — é a unidade exigida pela sintaxe de <length> do CSS;
   translateX(calc(var(--intro-word-width) + 70)) SEM unidade é CSS INVÁLIDO e o navegador
   descarta a declaração inteira silenciosamente (bug real, 2ª passagem visual: a Animation
   corria com progress correto e mesmo assim o transform computado ficava em matrix identidade
   — só apareceu ao inspecionar `el.style.transform` de um valor equivalente isolado, que
   resolvia para ""). Como o <rect> vive no espaço de usuário do próprio SVG, "px" aqui é
   equivalente a 1 unidade de viewBox, não a um pixel de tela real. */
@keyframes intro-sweep-translate {
  from { transform: translateX(0); }
  to   { transform: translateX(calc((var(--intro-word-width) + 70) * 1px)); }
}
.intro-sweep { mix-blend-mode: screen; opacity: 0; }
#site-intro.is-playing .intro-sweep {
  animation: intro-sweep-visibility calc(var(--intro-materialization-duration) * 1ms) linear
             calc(var(--intro-materialization-start) * 1ms) forwards;
}
@keyframes intro-sweep-visibility { 0% { opacity: 0; } 4% { opacity: .9; } 96% { opacity: .9; } 100% { opacity: 0; } }

/* ============================== VARIANTE REDUCED-MOTION ============================== */
/* Caminho curto escolhido por site.js quando prefers-reduced-motion: reduce está ativo: a
   marca nasce JÁ FORMADA (ver bloco @media (prefers-reduced-motion: reduce) mais abaixo, que
   força os estados finais) e some num fade curto — nunca a coreografia de 3.25s inteira.
   .is-reduced e .is-playing são mutuamente exclusivas (site.js nunca aplica as duas). */
#site-intro.is-reduced .intro-backdrop,
#site-intro.is-reduced .intro-wordmark {
  animation: intro-backdrop-fade calc(var(--intro-reduced-fade-duration) * 1ms) ease-in-out forwards;
}
/* Estado final já formado, sem coreografia — mecanismo PRINCIPAL (não uma segunda camada:
   .is-reduced só é aplicada por site.js quando reduced-motion já está ativo, então não faz
   sentido condicionar isto de novo a @media). */
#site-intro.is-reduced .intro-ghost,
#site-intro.is-reduced .intro-echo-1,
#site-intro.is-reduced .intro-echo-2,
#site-intro.is-reduced .intro-sweep { display: none; }
#site-intro.is-reduced .intro-solid { opacity: 1; transform: none; }
#site-intro.is-reduced #introRevealRect { transform: scaleX(1); }
#site-intro.is-reduced .intro-glow { opacity: .4; }

/* ============================== DEBUG (?intro=debug) ============================== */
/* Nunca visível/ativo sem o query param — ver site.js. Puramente visual/funcional para QA,
   não precisa do mesmo rigor de acessibilidade do resto do site. */
#intro-debug {
  position: fixed; left: 50%; bottom: 18px; transform: translateX(-50%);
  z-index: var(--z-intro-debug);
  display: flex; flex-direction: column; gap: 6px; align-items: stretch;
  width: min(560px, calc(100vw - 32px));
  background: rgba(10, 10, 12, .92); border: 1px solid rgba(255, 255, 255, .14);
  border-radius: 10px; padding: 10px 14px;
  font: 500 12px/1.4 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  color: #F3F1EC;
  box-shadow: 0 12px 32px -12px rgba(0, 0, 0, .7);
}
#intro-debug[hidden] { display: none; }
.intro-debug-row { display: flex; align-items: center; gap: 10px; }
.intro-debug-row button {
  font: inherit; color: inherit; background: rgba(255, 255, 255, .08);
  border: 1px solid rgba(255, 255, 255, .18); border-radius: 6px; padding: 4px 10px; cursor: pointer;
}
.intro-debug-row button:hover { background: rgba(255, 255, 255, .16); }
.intro-debug-phase { color: #D9A94D; font-weight: 700; }
.intro-debug-time { margin-left: auto; color: #9C9BA3; }
#intro-debug-scrub { width: 100%; accent-color: #D9A94D; }
.intro-debug-status { display: flex; flex-direction: column; gap: 2px; padding-top: 4px; border-top: 1px solid rgba(255, 255, 255, .12); }
.intro-debug-status strong { color: #9C9BA3; font-weight: 700; margin-right: 6px; }

/* ============================== RESPONSIVO ============================== */
@media (max-width: 480px) {
  /* Mesma coreografia, mesma assinatura — só menos densidade (seção 39): ecos mais curtos,
     glow mais contido. Nunca uma animação separada para mobile. */
  .intro-wordmark { width: clamp(260px, 78vw, 420px); }
  .intro-echo-1 { transform: translateX(-2px); }
  .intro-echo-2 { transform: translateX(-3.5px); }
  .intro-glow { background: radial-gradient(60vmin 60vmin at 50% 52%, rgba(217, 169, 77, .18), rgba(217, 169, 77, .05) 55%, transparent 76%); }
}

/* ============================== REDUCED MOTION (reforço) ============================== */
/* site.js já escolhe o caminho curto (.is-reduced, acima) sempre que prefers-reduced-motion:
   reduce está ativo — este bloco é só uma SEGUNDA camada de segurança caso #site-intro chegue
   a ficar visível com a coreografia completa (.is-playing) por qualquer outro motivo sob
   reduced-motion: força tudo ao estado final estático, sem espera. */
@media (prefers-reduced-motion: reduce) {
  #site-intro.is-playing .intro-ghost,
  #site-intro.is-playing .intro-echo-1,
  #site-intro.is-playing .intro-echo-2,
  #site-intro.is-playing .intro-sweep { display: none; }
  #site-intro.is-playing .intro-solid { opacity: 1; transform: none; }
  #site-intro.is-playing #introRevealRect { transform: scaleX(1); }
}
