/* =========================================================
   NORMA — Enhancements
   New interaction/section styles added after the initial build:
   testimonials, sticky header, active nav link, legal pages,
   back-to-top, focus-visible upgrade. (Scroll-reveal was also
   here and has been retired -- see the block further down.)
   Kept in a separate file
   so styles.css doesn't grow past the 500-line project limit
   (it was already at 597 lines before this file existed).
   All values reuse tokens defined in css/styles.css :root —
   no new colors, fonts, radii, or spacing values are introduced.
   ========================================================= */

/* ---------------------------------------------------------
   Focus-visible — the Design System ring (bundle.css:14): 2px of
   `--focus`, prussian in light and dodger in dark. It replaces the
   old two-tone ring (onyx outline + 5px blue halo), which existed
   so a ring stayed visible on the prussian bands; the DS covers
   that case itself, because a dark band carries data-theme="dark"
   and `--focus` turns dodger inside it (FinalCta.tsx). This file is
   unlayered and the bundle is layered on these pages, so this rule
   is the one that draws: it has to say what the DS says.
   --------------------------------------------------------- */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

/* =========================================================
   Testimonials (placeholder section, styled like .results-note)
   ========================================================= */

.testimonials { padding-block: var(--space-5xl); background: var(--color-platinum); }

.testimonials-head { margin-bottom: var(--space-2xl); }

/* A faixa que rola vive agora em css/marquee.css, sob `.marquee-*`.

   O `.testimonial-grid` de três colunas tinha saído daqui: a grelha
   exigia saber quantos depoimentos existem para ficar equilibrada, e
   quem escreve não é quem faz deploy -- o CMS pode publicar um, dois ou
   nove, e uma grelha de três com um único cartão é uma fila torta numa
   página de marketing. Uma pista que rola serve qualquer número,
   incluindo um.

   As regras da pista mudaram de sítio a 8 set 2026, sem mudar de
   comportamento: passaram a servir também a faixa de marcas, e duas
   cópias da mesma marquise divergem à primeira correcção que só uma
   delas recebe. `.testimonial-card` e o resto do cartão ficam aqui, que
   é onde pertencem -- o que se generalizou foi a pista, não o conteúdo
   dela. */

/* A Ruling 9 dispensou o filete aqui, e a premissa que o dispensava
   morreu na troca de token seguinte. O argumento era: este cartão é
   branco sobre a faixa de .testimonials e o seu próprio preenchimento já
   é a fronteira, a 2.58:1 -- verdade enquanto a faixa foi slate. Sobre
   platinum o mesmo par lê 1.1858:1, ABAIXO dos 1.2258:1 que esta
   auditoria existe para eliminar, e o cartão que tinha mais separação da
   página de marketing passou a ser o que tem menos. O comentário ficou
   para trás a afirmar 2.58:1 como se ainda fosse verdade.
   A E2 volta a aplicar-se como aos irmãos: 1px num token que já existe,
   o mesmo de .card e .stat-card. Aresta entre pares, não o contorno de
   um controlo -- um <article> não é focável, logo --color-hairline e não
   --color-control-edge (Ruling 10). Nada de sombra: a Ruling 9 continua
   a valer e o site continua com zero elevações.
   Medido: 2.1528:1 contra a faixa platinum, 2.5528:1 contra o branco do
   próprio cartão. */
.testimonial-card {
  background: var(--color-white);
  border: 1px solid var(--color-hairline);
  border-radius: var(--radius-card);
  padding: var(--space-2xl);
  display: flex;
  flex-direction: column;
  gap: var(--space-base);
  /* Largura fixa porque a pista é horizontal: sem isto cada cartão mede
     o seu próprio texto e a faixa fica com colunas de larguras
     aleatórias, decididas pelo comprimento do depoimento que alguém
     escreveu. 22rem lê confortável e cabe em 390px com folga. */
  flex: 0 0 min(22rem, 80vw);
  margin: 0;
}

.testimonial-quote {
  font-size: 1.125rem;
  line-height: 1.6;
  font-style: italic;
  margin: 0;
}

.testimonial-person {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  margin-top: auto;
  padding-top: var(--space-base);
}

/* O retrato é opcional: um depoimento publicado sem foto continua a ser
   um depoimento. Sem `src`, o <img> não pede nada à rede e some, em vez
   de deixar o ícone de imagem partida ao lado do nome de um cliente. */
.testimonial-photo {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-pill);
  object-fit: cover;
  flex: 0 0 auto;
  background: var(--color-platinum);
}
.testimonial-photo:not([src]) { display: none; }

.testimonial-person-text { display: flex; flex-direction: column; }

.testimonial-name {
  font-weight: 700;
  font-size: 0.9375rem;
}

.testimonial-role {
  font-size: 0.875rem;
  color: var(--color-onyx-soft);
}

/* Mantido: entradas gravadas antes de o molde ganhar nome/cargo ainda
   escrevem `attribution`, e apagar a regra deixaria-as sem estilo. */
.testimonial-attribution {
  font-weight: 700;
  font-size: 0.875rem;
  color: var(--color-onyx-soft);
}

/* =========================================================
   Scroll-reveal — RETIRADO

   Eram sete secções da landing page a desvanecer de baixo para cima ao
   longo de 600ms, armadas por um IntersectionObserver em js/main.js.
   Saiu por três motivos que se somam:

   (a) 600ms é 2,3x o tecto de 260ms e era o movimento não-cíclico mais
       lento do código por um factor de 2,4 sobre o seguinte. Um fade-up
       de 600ms é LÂNGUIDO: é a assinatura de movimento de um template
       comprado, e trabalha directamente contra "técnico, preciso,
       profissional". Era também o movimento mais visto do site, porque
       todos os prospectos rolam a landing page.
   (b) Movimento é confirmação, nunca decoração. Um scroll-reveal não
       confirma nada -- a pessoa rolou, o conteúdo sempre lá ia estar,
       não aconteceu nada que precise de ser reconhecido.
   (c) Podia piscar o próprio conteúdo da página para fora de existência.
       O estado honesto era `opacity: 1`; era o JS que, ao correr, punha
       as secções a zero para as trazer de volta. index.html carrega
       js/main.js sem `defer` e sem `async`, portanto qualquer pintura
       entre a renderização das secções e a execução do script mostrava o
       conteúdo e só depois o apagava. E numa janela alta (~1250px) o
       observador disparava sobre conteúdo que já estava na tela.

   Remover não custou nada e isto é verificável: `.reveal` só era
   declarado aqui, o estado por omissão já era o estado visível (o
   fallback sem JS), e o próprio bloco de movimento reduzido já provava
   que a página renderiza correctamente sem reveal nenhum. A página fica
   exactamente como já ficava hoje com o JS desligado.
   ========================================================= */

/* =========================================================
   Cabeçalho sticky

   .is-scrolled já não desenha nada. Fazia duas coisas e as duas saíram:

   (a) uma sombra em rgba(5,5,5,.12) -- o único valor de cor base do
       repositório que não é um token nem é igual a um. O cabeçalho já
       tem fronteira: o filete de 1px em styles.css.
   (b) encolher o .header-inner em 5px. Não havia transição a cobrir
       `height` (e a regra de movimento proíbe acrescentar uma), portanto
       a barra saltava 5px num único frame e todo o conteúdo por baixo
       saltava com ela, uma vez por sentido de rolagem, a meio da
       primeira descida do visitante pela página.
       Os mesmos 5px produziam um segundo defeito: .primary-nav é
       `position: absolute; top: var(--header-height)` e lê o token NÃO
       encolhido, portanto assim que a classe entrava o menu descolava da
       barra. Medido a 375x812 com o menu aberto e a página em y=2200:
       fundo do cabeçalho a 64, topo do menu a 68, e elementFromPoint em
       y=64..67 devolvia um <p> da página -- conteúdo real, visível e a
       rolar, por uma fresta de 4px.
   ========================================================= */

/* =========================================================
   Active nav-link highlighting — decorative blue underline,
   same non-text-color pattern as .eyebrow::before, so text
   itself stays onyx (compliant) and only a decorative mark
   uses Dodger Blue.
   ========================================================= */

.primary-nav a.is-active {
  font-weight: 700;
  position: relative;
}

.primary-nav a.is-active::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  /* -5px, na escala. Eram -6px aqui e -2px abaixo de 1024px: a distância
     de um sublinhado ao seu próprio texto mudava 4px ao cruzar um
     breakpoint, em dois valores que não estão na escala nem partilham
     justificação. A regra de tablet existia só para compensar a fonte de
     13px daquela faixa, e era a única regra deste ficheiro a usar a
     aresta de 1024px -- a mesma aresta que abria o buraco de altura de
     cabeçalho descrito em styles.css. Sai daqui também. */
  bottom: calc(var(--space-xs) * -1);
  height: 2px;
  border-radius: var(--radius-badge);
  background: var(--color-dodger-blue);
}

/* =========================================================
   Back-to-top button
   Hidden by default (no function without JS, since the click
   handler that drives it lives in main.js); revealed via
   ".is-visible" once the user scrolls past the hero.
   ========================================================= */

/* O botão em si é do DS (BackToTop.tsx: n-btn n-btn-secondary n-btn-lg
   n-btn-icon n-btn-pill, 48px redondo, surface + line-strong, tinta).
   Aqui fica só o que o faz flutuar. Seletor de duas classes de propósito:
   `.n-btn` (bundle.css, carregado depois desta folha) declara
   `position: relative`, e com uma classe só ganhava -- o botão caía no
   fim da página, 20px fora da borda esquerda (medido 01/10/2026).
   Sombra `shadow-md`, a mesma das pílulas flutuantes da SiteNav. */
.back-to-top.n-btn {
  position: fixed;
  right: var(--space-lg);
  bottom: var(--space-lg);
  box-shadow: var(--shadow-md);
  opacity: 0;
  transform: translateY(10px);
  pointer-events: none;
  transition: opacity 0.25s ease, transform 0.25s ease;
  z-index: 40;
}

.back-to-top.n-btn.is-visible {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

@media (prefers-reduced-motion: reduce) {
  .back-to-top { transition: none; }
}

/* =========================================================
   Páginas legais (privacidade, termos, cookies)

   Layout de leitura corrida: medida curta, hierarquia clara,
   nada além dos tokens já definidos em styles.css.
   ========================================================= */

.legal { padding-block: var(--space-3xl) var(--space-5xl); }

/* Sem `margin-inline: auto`. A medida de leitura vive agora num filho do
   .container em vez de no próprio .container: capar a largura no mesmo nó
   fazia cada secção recentrar-se dentro da janela em vez de segurar a
   coluna, e o site inteiro tinha SEIS arestas esquerdas de conteúdo
   diferentes. Medido a 1440px: o logótipo a 164.5px, o h1 destas páginas
   a 402.9px, o h1 das páginas de pagamento a 472.5px -- 308px de
   desalinhamento entre a marca e a tela onde o dinheiro sai. Nenhum valor
   muda: as medidas são as que já estavam. */
.legal-inner {
  max-width: 68ch; /* medida de leitura, não a largura do container */
}

.legal-inner h1 { margin-bottom: var(--space-md); }

.legal-updated {
  font-size: 0.875rem;
  color: var(--color-onyx-soft);
  margin-bottom: var(--space-2xl);
}

.legal-inner h2 {
  font-size: 1.25rem;
  font-weight: 800;
  margin-top: var(--space-3xl);
  margin-bottom: var(--space-base);
}

.legal-inner h3 {
  font-size: 1rem;
  font-weight: 700;
  margin-top: var(--space-lg);
  margin-bottom: var(--space-sm);
}

.legal-inner p,
.legal-inner li { line-height: 1.7; }

.legal-inner p { margin-bottom: var(--space-base); }

/* A outra metade da regra do último bloco (ver .portal-section em
   css/styles.css, onde a regra está escrita por extenso): sem isto os
   15px do último parágrafo de termos, privacidade e cookies escapavam
   do .legal-inner e essas três páginas fechavam a 85px do rodapé
   enquanto o checkout, o contato e as páginas de autenticação fechavam
   a 70. O selector é `> :last-child` e não `p` porque a última coisa da
   página tanto pode ser um <p> como uma <ul> ou uma <ol>, e as três
   levam a mesma margem.
   A segunda linha é a mesma correcção de ordem-de-layout que a regra do
   .portal-section leva, escrita aqui pela mesma razão e na mesma forma:
   nenhuma página legal termina hoje num bloco `hidden`, mas a regra é
   uma e escrever as duas metades de maneira diferente é como esta
   família de defeitos se repõe na cópia seguinte. Separadas, e não numa
   lista com vírgula, para degradar em vez de desaparecer onde `:has()`
   não existir. */
.legal-inner > :last-child { margin-bottom: 0; }
.legal-inner > :not(:has(~ :not([hidden]))) { margin-bottom: 0; }

/* O reset global apaga marcadores de lista no site inteiro, e este bloco
   restaurava o recuo mas não o marcador -- por isso as sete listas das
   páginas legais saíam como parágrafos indentados, sem pontos e sem
   NÚMEROS. Numa política de privacidade e num termo de uso, uma obrigação
   enumerada que renderiza sem número não pode ser citada nem
   referenciada, nem pelo cliente, nem pelo advogado dele, nem pela Norma.
   Efeito secundário, no site inteiro: o Safari retira o papel de "lista"
   de qualquer lista com `list-style: none`, e com isso o VoiceOver deixa
   de anunciar "lista, 5 itens". As listas que mantêm o marcador
   escondido de propósito ganham `role="list"` na marcação. */
.legal-inner ul,
.legal-inner ol {
  margin-bottom: var(--space-base);
  padding-left: var(--space-2xl);
}

.legal-inner ul { list-style: disc; }
.legal-inner ol { list-style: decimal; }

.legal-inner li { margin-bottom: var(--space-sm); }

/* Tratamento de link em linha sobre fundo claro. `a` global é
   `color: inherit; text-decoration: none` (styles.css:186), portanto um link
   dentro de um parágrafo fica indistinguível do texto à volta -- o peso e o
   sublinhado são toda a afordância que existe.
   NÃO se usa aqui o tratamento da `.announcement-bar` (dodger blue
   sublinhado): aquele assenta sobre prussian blue; o mesmo azul sobre branco
   mede 2.72:1 e reprova o mínimo de 4.5:1 para texto. Onyx sublinhado mede
   19.80:1. */
.legal-inner a {
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Marca o que ainda depende de um dado que só a Norma tem. Visível de
   propósito: um placeholder discreto é um placeholder publicado. */
.legal-todo {
  background: var(--color-platinum);
  border-left: 3px solid var(--color-prussian-blue);
  padding: var(--space-md) var(--space-base);
  border-radius: 0 var(--radius-card) var(--radius-card) 0;
  font-weight: 700;
  font-size: 0.9375rem;
}

.legal-table-wrap { overflow-x: auto; margin-bottom: var(--space-lg); }

.legal-table { width: 100%; border-collapse: collapse; font-size: 0.9375rem; }

.legal-table th,
.legal-table td {
  text-align: left;
  padding: var(--space-md) var(--space-base);
  border-bottom: 1px solid var(--color-hairline);
  vertical-align: top;
}

.legal-table th {
  font-weight: 700;
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-bottom: 2px solid var(--color-onyx);
  /* O filete de baixo sai do preenchimento de baixo:
     `padding-bottom + border-bottom-width = padding-top`. Esta célula
     herdava `--space-md` nos dois lados da regra genérica acima e depois
     acrescentava 2px de filete por baixo, portanto a caixa media 10 em
     cima e 12 em baixo, e o texto 13/15 -- um desvio de 2px. Com
     `--space-sm` em baixo, 8 + 2 = 10 e a inserção volta a ser 10/10.
     Não é compensação óptica: é aritmética, e é exactamente o mesmo
     terno que .data-table thead th já carrega em portal.css. As duas
     tabelas do site declaram o mesmo papel -- micro-rótulo maiúsculo de
     12px sobre um filete onyx de 2px -- e uma delas descontava o filete
     e a outra não.
     As células de corpo ficam como estão, e de propósito: o filete
     delas é de 1px, portanto fechar a conta pedia `padding-bottom: 9px`
     aqui e 4px na .data-table, e nenhum dos dois existe na escala de
     oito degraus. A regra só se aplica onde o filete é de 2px. */
  padding: var(--space-md) var(--space-base) var(--space-sm);
}
