/* ============================================================
   NicoChat — camada de polimento global
   Carregada DEPOIS de css/styles.css por site/src/layouts/SiteLayout.astro
   e BaseLayout.astro. Vale para as páginas institucionais e para o /blog.

   O que vive aqui (e por quê aqui e não em css/styles.css):
     1. Fallback de fonte com métricas calibradas  — evita o salto de layout
     2. Transições de página (View Transitions)    — cromo estático, conteúdo cruza
     3. Revelação no scroll                        — um observer, zero marcação por página
     4. Sistema de hover/foco                      — mesma linguagem em todo card e botão
     5. Ritmo vertical e respiro interno           — "margens mais bonitas"

   css/styles.css é a base compartilhada com o espelho Framer e é editada por
   outras frentes; manter o polimento num arquivo próprio evita conflito e
   deixa reversível (basta remover o <link>).
   ============================================================ */

/* ============================================================
   1. FALLBACK DE FONTE COM MÉTRICAS CALIBRADAS
   ------------------------------------------------------------
   Sintoma relatado: no carregamento o H1 da home quebrava em TRÊS linhas e,
   milissegundos depois, em DUAS — todo o conteúdo abaixo pulava junto. Isso é
   Cumulative Layout Shift, não só troca de desenho da letra.

   Causa: sem a webfont, "Cabinet Grotesk" caía em Arial/Helvetica, que é ~7%
   MAIS LARGA que a Cabinet no peso 800 — largura extra suficiente para forçar
   uma quebra a mais.

   Correção: uma família de fallback que usa a fonte local do sistema mas
   declara `size-adjust` para bater a largura da fonte real, e
   `ascent/descent-override` para bater a caixa de linha. O texto ainda troca
   de desenho, mas ocupa a MESMA área — a quebra de linha não muda.

   Os números NÃO são estimados. Foram medidos no Chrome com canvas
   measureText() sobre uma amostra de texto real do site (PT-BR, com acentos),
   comparando cada peso da fonte real contra Arial 400:

     amostra: "Automação é a chave para aumentar seus Ganhos Lucros Clientes
               ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789"
     a 100px:  Arial 400 = 6653.08px   asc 91  desc 21
               Cabinet Grotesk 500 = 6318.40  |  700 = 6414.70  |  800 = 6523.30
                                     asc 87  desc 28  (todos os pesos)
               Instrument Sans 400 = 6756.80  |  500 = 6826.70
                                     600 = 6894.40  |  700 = 6964.30
                                     asc 97  desc 25  (todos os pesos)

     size-adjust      = largura(real) / largura(Arial 400)
     ascent-override  = (asc(real)/100) / size-adjust
     descent-override = (desc(real)/100) / size-adjust

   `src: local(...)` só resolve fonte já instalada — nada é baixado, o custo é
   zero. A cadeia cobre Windows/macOS (Arial, Helvetica) e Linux
   (Liberation Sans, metricamente compatível com Arial). Onde nenhuma existir,
   a face simplesmente não casa e o navegador segue para o próximo item da
   pilha, como antes.

   Cada peso precisa da sua própria face: a largura relativa da Cabinet contra
   a Arial muda de 94.97% (500) para 98.05% (800), e uma única correção média
   deixaria os títulos errados nas duas pontas.
   ============================================================ */

/* ---------- Cabinet Grotesk (títulos) ---------- */
@font-face {
  font-family: "Cabinet Grotesk Fallback";
  src: local("Arial"), local("Helvetica"), local("Liberation Sans");
  font-weight: 500;
  font-style: normal;
  size-adjust: 94.97%;
  ascent-override: 91.61%;
  descent-override: 29.48%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Cabinet Grotesk Fallback";
  src: local("Arial"), local("Helvetica"), local("Liberation Sans");
  font-weight: 700;
  font-style: normal;
  size-adjust: 96.42%;
  ascent-override: 90.23%;
  descent-override: 29.04%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Cabinet Grotesk Fallback";
  src: local("Arial"), local("Helvetica"), local("Liberation Sans");
  font-weight: 800;
  font-style: normal;
  size-adjust: 98.05%;
  ascent-override: 88.73%;
  descent-override: 28.56%;
  line-gap-override: 0%;
}

/* ---------- Instrument Sans (corpo) ---------- */
@font-face {
  font-family: "Instrument Sans Fallback";
  src: local("Arial"), local("Helvetica"), local("Liberation Sans");
  font-weight: 400;
  font-style: normal;
  size-adjust: 101.56%;
  ascent-override: 95.51%;
  descent-override: 24.62%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Instrument Sans Fallback";
  src: local("Arial"), local("Helvetica"), local("Liberation Sans");
  font-weight: 500;
  font-style: normal;
  size-adjust: 102.61%;
  ascent-override: 94.53%;
  descent-override: 24.36%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Instrument Sans Fallback";
  src: local("Arial"), local("Helvetica"), local("Liberation Sans");
  font-weight: 600;
  font-style: normal;
  size-adjust: 103.63%;
  ascent-override: 93.6%;
  descent-override: 24.12%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Instrument Sans Fallback";
  src: local("Arial"), local("Helvetica"), local("Liberation Sans");
  font-weight: 700;
  font-style: normal;
  size-adjust: 104.68%;
  ascent-override: 92.66%;
  descent-override: 23.88%;
  line-gap-override: 0%;
}

/* As pilhas de css/styles.css com o fallback calibrado inserido logo após a
   fonte real. Redefinir a variável aqui evita mexer em css/styles.css, que é
   compartilhado com o espelho Framer e editado por outras frentes.

   Em --font-display o fallback precisa vir ANTES de "Instrument Sans": sem
   isso, quando só a Instrument tivesse carregado, os títulos usariam ela — e
   ela também é mais larga que a Cabinet, reintroduzindo o salto. */
:root {
  --font-display: "Cabinet Grotesk", "Cabinet Grotesk Fallback", "Instrument Sans", sans-serif;
  --font-body: "Instrument Sans", "Instrument Sans Fallback", "Inter", sans-serif;
}

/* ============================================================
   2. TRANSIÇÕES DE PÁGINA (astro:transitions)
   ------------------------------------------------------------
   Reclamação do dono: "toda vez que clica em um menu, tem que meio que
   carregar tudo de novo. Antes era suave — ao clicar, o menu mantinha e
   mudava a página."

   O <ClientRouter /> devolve a navegação sem recarregar. Aqui só se define a
   coreografia: o cromo (navbar/rodapé) fica PARADO e o conteúdo cruza.

   Navbar e rodapé recebem `transition:persist` — o nó do DOM é reaproveitado,
   não recriado — e um `view-transition-name` próprio, para saírem do snapshot
   raiz. Sem o nome próprio eles entrariam no cross-fade do documento inteiro
   e voltariam a piscar, mesmo persistidos.
   ============================================================ */

::view-transition-old(root) {
  animation: nc-fade-out 0.16s ease-out both;
}
::view-transition-new(root) {
  animation: nc-fade-in 0.24s ease-out both;
}

@keyframes nc-fade-out {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}
@keyframes nc-fade-in {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* Cromo fora do cross-fade do documento.

   Dar um `view-transition-name` próprio tira o elemento do snapshot `root`:
   em vez de participar do fade da página inteira, ele vira uma camada
   independente. Entre duas páginas institucionais a navbar é o MESMO nó
   (persistido) com os mesmos pixels, então essa camada não muda — o cromo
   fica visivelmente imóvel enquanto o conteúdo cruza.

   Os nomes do blog são distintos dos institucionais de propósito. Nomes
   iguais fariam o navegador PAREAR a navbar do site com o cabeçalho do blog
   ao atravessar as duas áreas e interpolar entre duas caixas de alturas
   diferentes — um esticão no topo da tela. Com nomes distintos, cada um
   simplesmente entra ou sai.

   Por que o grupo do cromo não anima: navbar e rodapé não são pixel-a-pixel
   iguais entre duas páginas — o item ativo do menu muda de cor. Com a
   animação padrão do grupo, as imagens ANTIGA e NOVA ficam sobrepostas
   durante o cross-fade e o texto do menu aparece duplicado por ~150ms
   (verificado em captura no meio da transição: "Sobre Nós" saía escrito duas
   vezes). Escondendo a imagem antiga e cortando a animação da nova, a troca
   do item ativo é instantânea e o cromo fica de fato imóvel. */
::view-transition-group(nc-navbar),
::view-transition-group(nc-footer),
::view-transition-group(nc-blog-header),
::view-transition-group(nc-blog-footer) {
  animation: none;
}
::view-transition-old(nc-navbar),
::view-transition-old(nc-footer),
::view-transition-old(nc-blog-header),
::view-transition-old(nc-blog-footer) {
  display: none;
}
::view-transition-new(nc-navbar),
::view-transition-new(nc-footer),
::view-transition-new(nc-blog-header),
::view-transition-new(nc-blog-footer) {
  animation: none;
  mix-blend-mode: normal;
}

.navbar {
  view-transition-name: nc-navbar;
}
.footer {
  view-transition-name: nc-footer;
}
.blog-header {
  view-transition-name: nc-blog-header;
}
.blog-footer {
  view-transition-name: nc-blog-footer;
}

/* ============================================================
   3. REVELAÇÃO NO SCROLL
   ------------------------------------------------------------
   Um IntersectionObserver só (src/components/SitePolish.astro) para o site
   inteiro. As seções não precisam optar por atributo: o alvo é a estrutura
   que TODA página já usa — filhos diretos de <main>.

   Degradação sem JS: o estado escondido só existe sob `html.nc-anim`, e essa
   classe é posta por um script inline no <head>. Sem JS (ou com
   prefers-reduced-motion) a classe nunca entra e tudo renderiza estático,
   visível, sem depender de nada.

   A classe entra no <head>, ANTES do primeiro paint — daí não haver o flash
   de "aparece, some, reaparece" que acontece quando o estado inicial é
   aplicado só depois do DOMContentLoaded.

   `transform: none` no estado final (e não `translateY(0)`) é deliberado: um
   transform computado diferente de `none` cria bloco de contenção e quebraria
   `position: sticky`/`fixed` de qualquer descendente. Com `none`, depois de
   revelado o elemento volta a ser um contexto normal.
   ============================================================ */

html.nc-anim main > section,
html.nc-anim main > article,
html.nc-anim main > aside {
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity 0.5s cubic-bezier(0.22, 0.61, 0.36, 1),
    transform 0.5s cubic-bezier(0.22, 0.61, 0.36, 1);
}

html.nc-anim main > .is-in {
  opacity: 1;
  transform: none;
}

/* Posto pelo runtime em `astro:after-swap` nas seções que já estão acima da
   dobra da página de destino: elas entram visíveis e SEM transição, para o
   snapshot da View Transition não capturar uma página vazia (e para não
   animar por cima do cross-fade). Removido no frame seguinte. */
html.nc-anim main > .nc-instant {
  transition: none;
}

/* Escape hatch: qualquer bloco que não deva animar. */
html.nc-anim main > .nc-no-reveal {
  opacity: 1;
  transform: none;
  transition: none;
}

/* ============================================================
   4. SISTEMA DE HOVER E FOCO
   ------------------------------------------------------------
   Antes da migração os cards reagiam ao ponteiro; o Astro herdou markup sem
   estado. Aqui todos passam a falar a mesma língua: subir 3px, escurecer a
   borda um degrau (--border -> --border-2) e trocar a sombra de contato pela
   de elevação. Nada de escala ou bounce — o dono pediu sutil.

   Paridade de foco é obrigatória: um card que só responde ao mouse é
   inacessível por teclado. Onde o card é clicável por um link interno, o
   gatilho é :focus-within — assim tabular até o link acende o card inteiro.
   ============================================================ */

:root {
  --nc-ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --nc-hover-t: 180ms;
  --nc-lift: -3px;
}

/* ---------- Cards ----------
   Um seletor só para toda a família. Os que já tinham hover próprio em
   css/styles.css (.channel-card) ou em blog.css (.post-card) continuam
   funcionando: este bloco vem depois e apenas uniformiza os valores.

   Duas ausências deliberadas:

   .integ-card  — a página de integrações tem interação PRÓPRIA (o card
     expande e revela o link da documentação ao passar o mouse). Levantar o
     card por cima disso brigaria com a expansão, então ele fica fora daqui e
     o comportamento continua sendo o de integracoes.astro, que o cancela
     explicitamente com maior especificidade.

   .testimonial-card — vive dentro de um letreiro em animação contínua. Um
     card que se move sozinho não tem estado de repouso para o ponteiro
     encontrar; o hover só produziria tremor. */
.plan-card,
.addon-card,
.channel-card,
.post-card,
.agn-card,
.about-step,
.faq-item {
  transition:
    transform var(--nc-hover-t) var(--nc-ease),
    box-shadow var(--nc-hover-t) var(--nc-ease),
    border-color var(--nc-hover-t) var(--nc-ease);
}

.plan-card:hover,
.addon-card:hover,
.channel-card:hover,
.post-card:hover,
.agn-card:hover,
.about-step:hover,
.plan-card:focus-within,
.addon-card:focus-within,
.channel-card:focus-within,
.post-card:focus-within,
.agn-card:focus-within {
  transform: translateY(var(--nc-lift));
  border-color: var(--border-2);
  box-shadow: var(--shadow-lg);
}

/* O card em destaque já tem borda azul e sombra azulada próprias: subir sem
   trocar a cor da borda preserva a hierarquia visual do plano recomendado. */
.plan-featured:hover,
.plan-featured:focus-within {
  border-color: var(--blue);
  box-shadow: 0 20px 44px rgba(0, 153, 255, 0.22);
}

/* .faq-item é <details>: não levanta (o conteúdo abre embaixo e o movimento
   ficaria estranho), só ganha borda e uma sombra rente. */
.faq-item:hover,
.faq-item:focus-within {
  border-color: var(--border-2);
  box-shadow: var(--shadow-card);
}
.faq-item summary:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
  border-radius: var(--radius);
}

/* Título do card acompanha o estado, como já fazia .post-card */
.agn-card:hover .agn-nome,
.channel-card:hover .channel-body h3,
.post-card:focus-within .post-card-title {
  color: var(--blue);
}

/* ---------- Chips e logos ---------- */
.logo-chip {
  transition:
    transform var(--nc-hover-t) var(--nc-ease),
    box-shadow var(--nc-hover-t) var(--nc-ease);
}
.logo-chip:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-card);
}

.blog-chip,
.agn-chip {
  transition:
    background-color var(--nc-hover-t) var(--nc-ease),
    border-color var(--nc-hover-t) var(--nc-ease),
    color var(--nc-hover-t) var(--nc-ease);
}
.blog-chip:hover,
.agn-chip:hover:not(.is-active) {
  border-color: var(--border-2);
  background: var(--bg-soft);
  color: var(--blue);
}

/* ---------- Anel de foco base ----------
   Percorrendo o site inteiro com Tab, boa parte das paradas caía no anel
   padrão do navegador (1px auto), que muda de aparência entre sistemas e
   quase some sobre fundo claro — e o campo de busca do blog não tinha anel
   nenhum. Esta regra dá um piso único a TODA parada de tabulação.

   Especificidade de propósito baixíssima (0,1,0): qualquer componente que
   queira um foco próprio continua vencendo sem precisar de !important. É um
   piso, não um teto. */
:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
}

/* Campos de formulário levam o anel colado: o offset descolaria o anel da
   borda do campo e daria a impressão de dois retângulos. */
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
  outline-offset: 1px;
}

/* ---------- Botões ----------
   css/styles.css já dá hover a .btn-primary/.btn-white/.btn-ghost/.btn-outline.
   Falta o foco de teclado, que ali não existe em nenhum deles. */
.btn:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
}
.btn-primary:focus-visible {
  outline-color: var(--navy);
}
.btn-white:focus-visible,
.cta-secondary:focus-visible {
  outline-color: var(--white);
}
.btn-primary:hover,
.btn-white:hover {
  box-shadow: var(--shadow-card);
}
/* Feedback de clique: afunda de volta. Sem isso o botão parece travado no
   estado de hover enquanto o ponteiro está pressionado. */
.btn:active {
  transform: translateY(0);
}

/* ---------- Links de rodapé ----------
   Eram estáticos nas duas variantes de rodapé. Sublinhado em vez de só cor:
   funciona também para quem não distingue azul de cinza. */
.footer-col a,
.blog-footer-col a,
.footer-credit a,
.footer-verse a {
  transition: color var(--nc-hover-t) var(--nc-ease);
  text-underline-offset: 3px;
}
.footer-col a:hover,
.blog-footer-col a:hover,
.footer-credit a:hover,
.footer-verse a:hover {
  color: var(--blue);
  text-decoration: underline;
}
.footer-col a:focus-visible,
.blog-footer-col a:focus-visible,
.footer-credit a:focus-visible,
.footer-verse a:focus-visible,
.nav-links a:focus-visible,
.nav-dd-menu a:focus-visible,
.nav-dd-trigger:focus-visible,
.blog-cats a:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
  border-radius: 4px;
}

/* Itens de menu: o hover já muda cor via css/styles.css, falta a suavização */
.nav-links > a,
.blog-cats a {
  transition: color var(--nc-hover-t) var(--nc-ease);
}

/* ============================================================
   5. RITMO VERTICAL E RESPIRO INTERNO
   ------------------------------------------------------------
   "Margens mais bonitas". Duas frentes:

   a) Entre seções — o espelho usava 96px fixos em desktop e mantinha os
      mesmos 96px a 560px de largura, onde a faixa fica desproporcional.
      Aqui o ritmo passa a escalar com a viewport.

   b) Dentro dos cards — o respiro interno estava apertado nos cards de post
      e de plano em relação ao tamanho da tipografia.

   Só as seções cujo padding vem de css/styles.css são alcançadas por este
   bloco (mesma especificidade, arquivo posterior). Seções com padding em
   <style> de página ficam de fora: o estilo escopado do Astro tem
   especificidade maior e sobrescrever exigiria !important.
   ============================================================ */

:root {
  /* 64px a 560px -> 96px a 1200px, sem media query. */
  --nc-section-y: clamp(64px, 3.4rem + 3.5vw, 96px);
}

.integrations,
.features,
.channels,
.testimonials,
.pricing,
.faq {
  padding: var(--nc-section-y) 0;
}

/* Respiro lateral do container: 24px é justo num celular de 360px, onde o
   conteúdo encosta na borda da tela. */
@media (max-width: 560px) {
  .container {
    padding-left: 20px;
    padding-right: 20px;
  }
}

/* Acima de 1200px o container trava em 1200 e as margens laterais viram o
   espaço morto da janela — folga um pouco mais o topo/base para a página não
   parecer comprimida entre duas faixas largas. */
@media (min-width: 1400px) {
  :root {
    --nc-section-y: 104px;
  }
}

/* ---------- Respiro interno dos cards ---------- */
.post-card-body {
  padding: 22px 24px 26px;
}
.channel-body {
  padding: 22px 20px 24px;
}
.faq-item summary {
  padding: 22px 26px;
}

/* Distância entre o cabeçalho da seção e o conteúdo. 48px de css/styles.css
   é generoso em desktop e exagerado no celular, onde come uma tela inteira. */
@media (max-width: 640px) {
  .section-sub {
    margin-bottom: 32px;
  }
}

/* ============================================================
   6. prefers-reduced-motion
   ------------------------------------------------------------
   A revelação já é desligada na origem (a classe .nc-anim não é aplicada).
   Aqui se neutraliza o resto: transições de página, elevação nos cards e
   qualquer animação herdada de css/styles.css.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }

  html.nc-anim main > section,
  html.nc-anim main > article,
  html.nc-anim main > aside {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .plan-card,
  .addon-card,
  .channel-card,
  .post-card,
  .agn-card,
  .about-step,
  .faq-item,
  .logo-chip,
  .btn {
    transition: none;
  }
  .plan-card:hover,
  .addon-card:hover,
  .channel-card:hover,
  .post-card:hover,
  .agn-card:hover,
  .about-step:hover,
  .logo-chip:hover {
    transform: none;
  }
}
