/*
  Os tokens do sistema visual, em um lugar só.

  Extraídos de `app.css` em 2026-08-07, sem alterar nenhum valor, para que o
  site institucional (`site/styles/site.css`) e o app leiam a mesma paleta. Uma
  segunda paleta é como os dois deixam de parecer o mesmo produto.

  Quem consome:
  - `src/styles/app.css`, por `@import` — o Vite o inlina no build.
  - `tools/site/build.ts`, que concatena este arquivo com o CSS do site dentro
    de `public/site.css`. O site não passa pelo Vite (mora em `public/`), então
    um `@import` em tempo de execução apontaria para um arquivo que o build não
    publica.
*/

:root {
  /* Superficies claras — o app fora do palco. */
  --ground: #eef1f5;
  --plate: #ffffff;
  --plate-sunken: #f6f8fa;
  --line: #dde3ea;
  --line-strong: #c3cedb;

  --ink: #0f1720;
  --ink-2: #46556a;
  /* O cinza mais claro que ainda passa 4.5:1 **sobre o fundo da pagina**, e nao
     so sobre a placa branca: texto de apoio mora nos dois. */
  --ink-3: #59677b;

  /* Acao. Um azul so, em acao primaria e selecao — nunca decoracao. */
  --accent: #1a53d8;
  --accent-strong: #143fab;
  --accent-soft: #eaf0ff;
  --accent-ink: #ffffff;

  /* Semantica: as mesmas tintas que `overlay.ts` pinta na folha. */
  --incorrect: rgb(211, 47, 47);
  --incorrect-ink: #a52121;
  --incorrect-soft: #fdecea;
  --ambiguous: rgb(245, 166, 35);
  --ambiguous-ink: #4a3200;
  --ambiguous-soft: #fff8e1;

  /* Palco da correcao: escuro, porque o video e o papel sao a informacao. */
  --stage-bg: #0d1117;
  --stage-plate: #171d26;
  --stage-line: #2a323e;
  --stage-ink: #e7eef6;
  --stage-ink-2: #9fb0c4;

  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-pill: 999px;

  /* Sombra com deslocamento e desfoque: halo sem offset e decoracao. */
  --shadow-1: 0 1px 2px rgba(15, 23, 32, 0.05), 0 1px 3px rgba(15, 23, 32, 0.04);

  --s-1: 0.25rem;
  --s-2: 0.5rem;
  --s-3: 0.75rem;
  --s-4: 1rem;
  --s-5: 1.5rem;
  --s-7: 3rem;

  /* Alvo de toque. A professora repete o gesto dezenas de vezes seguidas. */
  --touch: 2.75rem;

  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  color-scheme: light;
  accent-color: var(--accent);
  scrollbar-color: var(--line-strong) var(--ground);
}

/*
  Tema escuro das telas claras (`src/ui/theme.ts`). **Diverge de `features/07`
  §10 de propósito**, por decisão de 2026-08-07 registrada no roteiro.

  Só os tokens mudam: nenhuma regra abaixo pergunta pelo tema, e o palco da
  correção não participa — ele usa os `--stage-*`, que são os mesmos nos dois.
*/
:root[data-theme="dark"] {
  --ground: #090d13;
  /* Duas paradas acima do fundo: com placa e pagina quase da mesma cor, quem
     separava as duas era a borda de 1px — e onde a aurora passa por baixo, ela
     some. */
  --plate: #1e2734;
  --plate-sunken: #27313f;
  --line: #303a49;
  --line-strong: #445162;

  --ink: #e8eff7;
  --ink-2: #c3cfdd;
  --ink-3: #9dabbe;

  --accent: #6f9bff;
  --accent-strong: #8fb2ff;
  --accent-soft: #17233b;
  --accent-ink: #07101f;

  --incorrect: rgb(239, 83, 80);
  --incorrect-ink: #ffa39c;
  --incorrect-soft: #2b1614;
  --ambiguous: rgb(245, 166, 35);
  --ambiguous-ink: #ffd899;
  --ambiguous-soft: #2a2211;

  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.4), 0 1px 3px rgba(0, 0, 0, 0.3);

  color-scheme: dark;
  scrollbar-color: var(--line-strong) var(--ground);
}

/*
  Os componentes que o site institucional e o corretor dividem.

  Entre `tokens.css` (valores) e os dois consumidores (`src/styles/app.css` e
  `site/styles/site.css`). Existe porque os dois implementavam este mesmo
  sistema em paralelo, com nomes diferentes, e divergiram no primeiro retoque —
  a aurora do app ainda pinta a dosagem clara no tema escuro, que é a versão que
  o site mediu e rejeitou.

  Quem consome:
  - `src/styles/app.css`, por `@import` — o Vite o inlina no build.
  - `tools/site/build.ts`, que concatena `tokens + shared + site` dentro de
    `public/site.css`. O site não passa pelo Vite, então um `@import` em tempo
    de execução apontaria para um arquivo que o build não publica.

  Regra de convivência, vigiada por `shared.test.ts`: o consumidor **posiciona**
  o que está aqui (`.top-bar .theme-toggle { margin-left: auto }`), mas nunca
  **redefine**. O que precisar mudar para os dois muda aqui.

  D23: DOM puro, zero dependência, zero CDN.
*/

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100dvh;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font);
  font-size: 1rem;
  line-height: 1.5;
  /* O iPhone tem entalhe e indicador. `env()` com zero de fallback em quem não
     conhece a função. */
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom)
    env(safe-area-inset-left);
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

::selection {
  background: var(--accent-soft);
  color: var(--ink);
}

/*
  Uma escala só para os dois. Os tamanhos são fluidos porque a mesma página é
  lida num iPhone de 390px e num monitor de 1280 — e `clamp` faz isso sem media
  query. `text-wrap: balance` evita a linha órfã de uma palavra, que é o defeito
  mais visível de um título curto em coluna estreita.
*/
h1,
h2,
h3 {
  text-wrap: balance;
  letter-spacing: -0.02em;
  font-weight: 700;
  line-height: 1.15;
  margin: 0;
}

h1 {
  font-size: clamp(2rem, 4vw + 1rem, 3.25rem);
}

h2 {
  font-size: clamp(1.5rem, 2vw + 1rem, 2rem);
}

h3 {
  font-size: 1.25rem;
}

/* A medida que se lê sem perder a linha (~65 caracteres). */
p {
  margin: 0;
  max-width: 65ch;
}

/* A superfície de todo conteúdo que não é o fundo: uma borda de 1px, canto de
   12px e uma sombra com deslocamento — halo sem offset é decoração. */
.plate {
  background: var(--plate);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-1);
  padding: var(--s-5);
}

/*
  O botão vale para o elemento e para a classe: o app usa `<button>` puro e o
  site usa `<a class="button">` para link que age como botão. Dois seletores
  numa regra só, em vez de dois sistemas de botão.
*/
.button,
button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  font: inherit;
  font-weight: 550;
  color: var(--ink);
  background: var(--plate);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  padding: 0.5rem 0.875rem;
  min-height: 2.25rem;
  text-decoration: none;
  cursor: pointer;
  transition:
    background-color 150ms ease-out,
    border-color 150ms ease-out;
}

/* `.button` é alvo de página, e não controle denso: o site o usa em `<a>` que
   age como botão, e onde o dedo mira uma vez o piso é `--touch`. O `<button>`
   puro do app é o outro papel — controle secundário que ela toca dezenas de
   vezes seguidas, numa barra onde 44px empurrariam o palco para baixo. */
.button {
  min-height: var(--touch);
  padding: 0.75rem 1.25rem;
  font-weight: 600;
}

@media (hover: hover) {
  button:hover:not(:disabled),
  .button:hover {
    background: var(--plate-sunken);
    border-color: var(--ink-3);
  }
}

button:active:not(:disabled) {
  background: var(--line);
}

button:disabled {
  color: var(--ink-3);
  background: var(--plate-sunken);
  border-color: var(--line);
  cursor: not-allowed;
}

/*
  Barra fixa com fundo translúcido: o desfoque atrás dela é o que deixa o fundo
  em movimento passar sem competir com o texto. `backdrop-filter` aqui é efeito
  específico, e não decoração — sem ele, ou a barra fica opaca e corta o fundo,
  ou fica transparente e o texto anda por cima do gradiente.

  A **largura da coluna** não mora aqui: o app usa 60rem e o site 75rem, e cada
  um declara o seu `padding` horizontal.
*/
.top-bar {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: var(--s-4);
  background: color-mix(in srgb, var(--ground) 78%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid color-mix(in srgb, var(--line) 70%, transparent);
}

/* O mesmo desenho nos dois lados (`site/templates/brand.ts`, importado e não
   copiado pelo app), então o mesmo invólucro. O que cada consumidor precisa
   por cima — o app é um `<button>` e reseta a caixa, o site é um `<a>` e perde
   o sublinhado — mora no CSS de cada um, atrás de um seletor de contexto. */
.brand {
  display: inline-flex;
  align-items: center;
  color: var(--ink);
}

.brand svg {
  height: 1.5rem;
  width: auto;
}

/* Um botão de ícone é quadrado: o rótulo vive no `aria-label`. O alvo é
   `--touch` (44px), o piso da mesma régua que `.button` usa acima — o site já
   media isso antes da fusão, e reduzir o alvo por fundir com o app seria uma
   regressão de acessibilidade escondida numa refatoração de nome. */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--touch);
  height: var(--touch);
  padding: 0;
  flex: none;
  border: none;
  border-radius: var(--r-sm);
  color: var(--ink-2);
  background: color-mix(in srgb, var(--plate) 70%, transparent);
}

@media (hover: hover) {
  .theme-toggle:hover {
    background: var(--plate-sunken);
    color: var(--ink);
  }
}

.theme-toggle svg {
  width: 1.25rem;
  height: 1.25rem;
}

/* Um ícone por tema: o botão mostra para onde o toque leva, não onde se está. */
.icon-sun {
  display: none;
}

.icon-moon {
  display: block;
}

:root[data-theme="dark"] .icon-sun {
  display: block;
}

:root[data-theme="dark"] .icon-moon {
  display: none;
}

/* ------------------------------------------------ o menu recolhido da barra */

/*
  Um `<details>` só, para os três estados da barra. Até 939 px ele é o menu
  recolhido do celular, e `open` é o próprio estado — sem JavaScript. A partir
  de 940 px o `<summary>` some e o menu **se dissolve**: `display: contents` no
  `<details>` e no painel faz a navegação e o grupo de ações virarem itens da
  própria barra, na ordem em que estão no DOM.

  O `content-visibility` do `::details-content` é o que precisa ser desfeito, e
  não o `display` do conteúdo. Chromium ≥ 131 (e Safari ≥ 18.4) escondem o
  conteúdo de um `<details>` fechado por esse pseudo-elemento, e nenhum
  `display: ... !important` no filho o alcança — a navegação em linha ficava
  com caixa, com largura e sem um pixel pintado. O `display: contents
  !important` nos filhos continua ali para os motores mais antigos, que
  escondem o conteúdo pela regra de agente do usuário.

  Os dois consumidores montam esta mesma estrutura: o site em HTML estático
  (`site/templates/layout.ts`), o app em DOM (`src/ui/app-bar.ts`).
*/
/* Sem `position: relative`: o painel se ancora no cabeçalho, e não no botão.
   Preso ao botão, um painel de 14rem pendurado num alvo de 66 px sai 21 px
   pela esquerda da tela num iPhone de 390 px — medido. */
.nav-menu {
  margin-left: auto;
}

.nav-menu > summary {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--touch);
  min-height: var(--touch);
  padding: 0 var(--s-3);
  border-radius: var(--r-sm);
  font-weight: 600;
  color: var(--ink);
}

.nav-menu > summary::-webkit-details-marker,
.nav-menu > summary::marker {
  display: none;
  content: "";
}

@media (hover: hover) {
  .nav-menu > summary:hover {
    background: var(--plate-sunken);
  }
}

.nav-panel {
  /* Ancorado no `.top-bar`, que é `sticky` e portanto posicionado: a borda
     direita do painel acompanha a do conteúdo da barra, e não a do botão. */
  position: absolute;
  right: var(--s-4);
  top: calc(100% - var(--s-2));
  z-index: 20;
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  min-width: 14rem;
  max-width: calc(100% - 2 * var(--s-4));
  padding: var(--s-4);
  background: var(--plate);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-1);
  /* Medido num iPhone 14 deitado (844×390): sete destinos mais o grupo de
     ações somam 443px de painel, e a tela só tem 390px de altura — sem isto o
     último destino e o botão de tema ficam fora dela, e rolar a página não os
     alcança porque o painel é `position: absolute` sobre um `.top-bar`
     `sticky`, que viaja junto com a rolagem em vez de ficar para trás. */
  max-height: calc(100dvh - 5rem);
  overflow-y: auto;
}

.nav-main ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
}

.nav-menu a,
.nav-main button {
  display: flex;
  align-items: center;
  min-height: var(--touch);
  padding: 0 var(--s-2);
  border-radius: var(--r-sm);
  color: var(--ink-2);
  text-decoration: none;
}

/*
  Dois itens do app ("opções" e "imprimir folha") trocam de tela por JS e não
  navegam: são `<button>`, e a regra genérica de botão os pintaria com caixa e
  borda no meio de uma lista de links. Aqui só o que precisa ser desfeito.

  O seletor é `.nav-main button`, e **não** `.nav-menu` combinado direto com
  `button`: o botão de tema também é um `<button>` dentro do `<details>`, em
  `.nav-actions`, e essa combinação (0,1,1) venceria `.theme-toggle` (0,1,0) na
  especificidade — o alvo quadrado de 44 px viraria um item de lista de
  largura inteira.
*/
.nav-main button {
  width: 100%;
  justify-content: flex-start;
  background: none;
  border: none;
  font-weight: inherit;
}

@media (hover: hover) {
  .nav-menu a:hover,
  .nav-main button:hover {
    background: var(--plate-sunken);
    color: var(--ink);
  }
}

.nav-actions {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  border-top: 1px solid var(--line);
  padding-top: var(--s-4);
}

/*
  940 px, e não os 835 px do resto do site: medido no cabeçalho em pt-BR, que é
  o mais largo dos três idiomas. Marca, quatro destinos, o grupo de ações e o
  botão do corretor somam ~900 px com o respiro do `gap` — abaixo disso a linha
  estoura, e o menu recolhido volta a ser o certo.
*/
@media (min-width: 940px) {
  .nav-menu > summary {
    display: none;
  }

  .nav-menu::details-content {
    content-visibility: visible;
    display: contents;
  }

  .nav-menu,
  .nav-panel {
    display: contents !important;
  }

  .nav-main,
  .nav-actions {
    display: flex !important;
    align-items: center;
  }

  /* Margem automática dos dois lados: a navegação fica no centro do que sobra
     entre a marca e o grupo da direita, sem largura fixa e sem `order:`. */
  .nav-main {
    margin-inline: auto;
  }

  .nav-main ul {
    flex-direction: row;
    gap: var(--s-5);
  }

  .nav-actions {
    border-top: none;
    padding-top: 0;
  }

  .nav-menu a,
  .nav-main button {
    min-height: auto;
    padding: 0;
    width: auto;
  }
}

/* A ação primária. Uma por tela — é o azul único do `tokens.css`. */
.button--primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
  font-size: 1.0625rem;
  font-weight: 600;
  min-height: var(--touch);
  padding: 0.75rem 1.25rem;
  box-shadow: var(--shadow-1);
}

@media (hover: hover) {
  .button--primary:hover:not(:disabled) {
    background: var(--accent-strong);
    border-color: var(--accent-strong);
  }
}

.button--primary:active:not(:disabled) {
  background: var(--accent-strong);
}

.button--primary:disabled {
  background: var(--line);
  border-color: var(--line);
  color: var(--ink-3);
  box-shadow: none;
}

/*
  O fundo em movimento.

  Duas manchas de gradiente radial que **só transladam**: nada de `filter:
  blur`, que num celular custa uma passada de GPU por quadro — a borda suave
  vem do próprio gradiente, que o navegador rasteriza uma vez. `translate3d`
  mantém a animação na camada de composição, sem repintura.

  A segunda camada do `background` de `::before` é um realce quase branco por
  cima da mancha de cor: só clareia, nunca escurece — por isso o pior quadro
  do contraste (medido abaixo) ignora essa camada com segurança e mede só a
  tinta.

  Aparece também na correção ao vivo do app, por pedido explícito de
  2026-08-07, ciente de que ali o pipeline de visão disputa a mesma GPU (D11
  registra aquecimento como problema medido). O que aparece atrás do vídeo é a
  tarja que sobra ao lado dele; a folha continua sobre preto.

  O posicionamento padrão aqui é o de tela inteira — o caso do app, e o mais
  comum. O site recorta a aurora dentro do `.hero`; ele só reposiciona
  (`.hero .aurora`), nunca redefine o resto.
*/
.aurora {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
  contain: strict;
}

.aurora::before,
.aurora::after {
  content: "";
  position: absolute;
  width: 40rem;
  height: 40rem;
  border-radius: 50%;
  will-change: transform;
}

.aurora::before {
  top: -12rem;
  left: -8rem;
  background:
    radial-gradient(circle at 30% 30%, color-mix(in srgb, #fff 35%, transparent), transparent 60%),
    radial-gradient(closest-side, color-mix(in srgb, var(--accent) 26%, transparent), transparent);
  animation: aurora-a 46s ease-in-out infinite alternate;
}

.aurora::after {
  bottom: -14rem;
  right: -10rem;
  background: radial-gradient(
    closest-side,
    color-mix(in srgb, var(--ambiguous) 18%, transparent),
    transparent
  );
  animation: aurora-b 58s ease-in-out infinite alternate;
}

/*
  As mesmas duas manchas no escuro, com outra dosagem. Um realce de branco a 35%
  desenhado para clarear um cinza-frio claro vira uma nuvem cinza-lilás sobre um
  fundo quase preto — visível demais, e da cor errada.

  Medido no pixel pintado, no pior quadro de 24 amostras da animação, sobre a
  caixa do parágrafo do hero (`--ink-2`, texto normal, AA pede 4,5:1):

    | quadro pior de              | 1280 px | 390 px |
    | --------------------------- | ------- | ------ |
    | escuro com a dosagem clara  |  6,5:1  | 5,4:1  |
    | escuro com a dosagem daqui  |  9,5:1  | 8,9:1  |
    | claro (referência, T5)      |  5,3:1  | 5,1:1  |

  Os dois passavam no AA; o que a dosagem daqui compra é a mancha voltar a
  parecer uma mancha de luz, e não uma névoa cinza. Não é uma segunda paleta:
  as cores continuam sendo `--accent` e `--ambiguous` do `tokens.css`, e o que
  muda é quanto de cada uma entra.
*/
:root[data-theme="dark"] .aurora::before {
  background:
    radial-gradient(circle at 30% 30%, color-mix(in srgb, #fff 8%, transparent), transparent 60%),
    radial-gradient(closest-side, color-mix(in srgb, var(--accent) 20%, transparent), transparent);
}

:root[data-theme="dark"] .aurora::after {
  background: radial-gradient(
    closest-side,
    color-mix(in srgb, var(--ambiguous) 12%, transparent),
    transparent
  );
}

@keyframes aurora-a {
  from {
    transform: translate3d(0, 0, 0) scale(1);
  }
  to {
    transform: translate3d(14vw, 8vh, 0) scale(1.12);
  }
}

@keyframes aurora-b {
  from {
    transform: translate3d(0, 0, 0) scale(1.08);
  }
  to {
    transform: translate3d(-12vw, -8vh, 0) scale(1);
  }
}

/* O fundo para no lugar em vez de continuar a animação de dezenas de segundos
   em 0,01 ms. */
@media (prefers-reduced-motion: reduce) {
  .aurora::before,
  .aurora::after {
    animation: none !important;
  }
}

/*
  CSS do site institucional. Nenhum token aqui — só regras que consomem os de
  `tokens.css`, que `renderStylesheet()` (`tools/site/build.ts`) concatena na
  frente deste arquivo dentro de `public/site.css`.

  O tema vem do `data-theme` do `<html>`, escrito antes da primeira pintura
  pelo script do `<head>` (`site/templates/layout.ts`) e trocado pelo botão da
  barra. Os tokens escuros são os do app, no `tokens.css` concatenado à frente:
  **não existe uma segunda paleta escura aqui**, e um tom que faltar entra lá.
  Sem preferência guardada, o site segue o `prefers-color-scheme` do sistema.

  D23: DOM puro, zero dependência, zero CDN.
*/

img,
svg {
  max-width: 100%;
  display: block;
}

/* Escala tipografica (h1-h3, p) em `shared.css` agora — vale para os dois. */

a {
  color: var(--accent);
}

/* --------------------------------------------------------------- controles */

/* Some visualmente até ganhar foco de teclado: quem usa mouse nunca vê, quem
   tabula vê primeiro que tudo. */
.skip-link {
  position: absolute;
  z-index: 100;
  left: var(--s-3);
  top: -3.5rem;
  background: var(--plate);
  color: var(--ink);
  padding: var(--s-2) var(--s-4);
  border-radius: var(--r-sm);
  box-shadow: var(--shadow-1);
  text-decoration: none;
  font-weight: 600;
  transition: top 150ms ease-out;
}

.skip-link:focus {
  top: var(--s-3);
}

/* ------------------------------------------------------------ cabeçalho fixo */

/*
  A barra em si e `.top-bar`, definida em `shared.css` — mesma tecnica do
  `.top-bar` do app, pelo mesmo motivo: o fundo em movimento do hero passa por
  baixo sem competir com o texto. Aqui so a coluna, ancorada no `<main
  id="conteudo">` que existe nas 39 paginas do site e nao existe no app
  (`shared.test.ts` proibe redefinir `.top-bar` em si).
*/
body:has(#conteudo) .top-bar {
  padding: var(--s-3) max(var(--s-4), calc((100% - 75rem) / 2));
}

/* O logotipo é SVG desenhado (`site/templates/brand.ts`), não texto: as letras
   são `<path>` com `stroke="currentColor"`, então `color` continua sendo o que
   pinta a marca — inclusive no foco do teclado. O nome acessível vem do
   `aria-label` do próprio `<svg>`, e por isso o link não precisa de texto
   dentro. `.brand` em si é `shared.css` (`shared.test.ts` proíbe redefini-la
   aqui) — aqui só o que sobra por ser `<a>`, que por padrão sublinha. */
body:has(#conteudo) .brand {
  text-decoration: none;
}

/* A página em que se está, dita pelo `aria-current` do template: o estilo sai
   do atributo, e não de uma classe em paralelo que pode discordar dele. */
.nav-main a[aria-current] {
  color: var(--ink);
  font-weight: 700;
}

.nav-login {
  white-space: nowrap;
}

/* O seletor de idioma: sigla à mostra, os três nomes por extenso na lista. O
   alvo tem os 44 px de sempre, mesmo com duas letras dentro. */
.lang-picker {
  position: relative;
}

.lang-picker summary {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--touch);
  min-height: var(--touch);
  border-radius: var(--r-sm);
  color: var(--ink-2);
  font-size: 0.875rem;
  font-weight: 700;
  letter-spacing: 0.04em;
}

.lang-picker summary::-webkit-details-marker,
.lang-picker summary::marker {
  display: none;
  content: "";
}

/* Dentro do menu recolhido o seletor fica no canto esquerdo do painel, então a
   lista abre para a direita; na barra em linha ele é o penúltimo alvo da
   direita, e abrir para a direita empurraria a lista para fora da janela — a
   regra do estado em linha inverte as duas âncoras. */
.lang-picker ul {
  position: absolute;
  left: 0;
  top: calc(100% + var(--s-2));
  z-index: 30;
  list-style: none;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
  min-width: 9rem;
  padding: var(--s-2);
  background: var(--plate);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-1);
}

.lang-picker a[aria-current] {
  color: var(--accent);
  font-weight: 700;
}

/* O que o ponto de quebra faz com as duas peças que são só do site: o botão de
   entrar e a lista de idiomas. O resto do bloco de 940 px mora no
   `shared.css`, com os componentes que ele reposiciona. */
@media (min-width: 940px) {
  .nav-actions .nav-login {
    padding: 0 var(--s-2);
    min-height: var(--touch);
  }

  /* Dentro do menu recolhido o seletor fica no canto esquerdo do painel, e a
     lista abre para a direita; na barra em linha ele é o penúltimo alvo da
     direita, e abrir para a direita empurraria a lista para fora da janela. */
  .lang-picker ul {
    left: auto;
    right: 0;
  }
}

/* --------------------------------------------------------------------- rodapé */

.site-footer {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s-5);
  max-width: 75rem;
  margin: 0 auto;
  padding: var(--s-7) var(--s-4);
  color: var(--ink-2);
  border-top: 1px solid var(--line);
}

.footer-col h2 {
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: var(--s-3);
}

.footer-col ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}

.footer-col a {
  color: var(--ink-2);
  text-decoration: none;
}

@media (hover: hover) {
  .footer-col a:hover {
    color: var(--accent);
  }
}

.footer-tagline {
  font-weight: 600;
  color: var(--ink);
}

.footer-rights {
  font-size: 0.875rem;
  color: var(--ink-3);
}

@media (min-width: 431px) {
  .site-footer {
    grid-template-columns: repeat(3, 1fr);
  }

  .footer-tagline,
  .footer-rights {
    grid-column: 1 / -1;
  }
}

/* --------------------------------------------------------------------- main */

main {
  max-width: 75rem;
  margin: 0 auto;
  padding: var(--s-5) var(--s-4) var(--s-7);
  display: flex;
  flex-direction: column;
  gap: var(--s-7);
}

@media (min-width: 835px) {
  main {
    padding: var(--s-7) var(--s-5);
  }
}

/*
  As quatro larguras do site (`T3 §Step 4`): uma coluna até 430 px, duas de
  431 a 834, grade a partir de 835 — a mesma progressão em toda seção que
  precisar de colunas (planos, artigos, blocos de recurso).
*/
.grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s-5);
}

@media (min-width: 431px) {
  .grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 835px) {
  .grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* ------------------------------------------------------------------- o hero */

/*
  Elemento de assinatura. Três camadas por cima do texto, nesta ordem no DOM
  (T5 segue este contrato exatamente — ver `.hero-content` embaixo):

    <section class="hero">
      <div class="aurora" aria-hidden="true"></div>
      <svg class="hero-bubbles" aria-hidden="true">...</svg>
      <div class="hero-veil" aria-hidden="true"></div>
      <svg class="hero-corner hero-corner--tl" aria-hidden="true">...</svg>
      <svg class="hero-corner hero-corner--tr" aria-hidden="true">...</svg>
      <svg class="hero-corner hero-corner--bl" aria-hidden="true">...</svg>
      <svg class="hero-corner hero-corner--br" aria-hidden="true">...</svg>
      <div class="hero-content">
        <h1>…</h1>
        <p>…</p>
      </div>
    </section>
*/
.hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  border-radius: var(--r-lg);
  padding: var(--s-7) var(--s-5);
}

/* No site a aurora vive dentro do hero, e não atrás da página: ela é o fundo
   de um bloco, e o que rola por cima dela é o resto da página. */
.hero .aurora {
  position: absolute;
  z-index: 0;
}

.hero-content {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: var(--s-5);
  max-width: 40rem;
}

.hero-text {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
}

/* O mockup do celular ao lado do texto só quando há largura para os dois. Até
   lá ele vem embaixo, e limitado: numa tela de 390 px, um celular desenhado em
   tamanho cheio empurraria a ação primária para fora do alcance do polegar. */
.hero-content .mockup {
  width: 100%;
  max-width: 13rem;
}

@media (min-width: 835px) {
  .hero-content {
    max-width: none;
    flex-direction: row;
    align-items: center;
    gap: var(--s-7);
  }

  .hero-text {
    max-width: 38rem;
  }

  .hero-content .mockup {
    max-width: 15rem;
    flex: none;
  }
}

.hero-content p {
  font-size: 1.125rem;
  color: var(--ink-2);
}

/*
  Camada 2 — a grade de bolinhas: círculos quase invisíveis na geometria da
  folha, esmaecendo nas bordas por `mask-image` (sem precisar de `<mask>`
  nativo do SVG). Decoração pura — `aria-hidden` no elemento (T5).

  T5 desenha um `<circle>` por bolinha e numera cada um com
  `style="--i: N"` (N = 0, 1, 2…): é essa variável que escalona o atraso do
  preenchimento abaixo. Uma vez, ~2 s, nunca em loop — a barra de progresso da
  professora não é decoração que repete.
*/
.hero-bubbles {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  mask-image: radial-gradient(circle at center, black 55%, transparent 100%);
  -webkit-mask-image: radial-gradient(circle at center, black 55%, transparent 100%);
}

/*
  O traço (1%) e o preenchimento final (1%) foram calibrados no Step 7 para o
  pior caso real, não dois cenários isolados: `stroke` em SVG é centralizado no
  caminho por padrão (não sobrescrito aqui), então na bolinha preenchida e
  parada para sempre (`animation-fill-mode: both`) o traço cai **por cima** do
  próprio preenchimento — as duas tintas coexistem no mesmo pixel, na ordem de
  pintura padrão (preenchimento, depois traço). 12%/14% isolados já falhavam;
  mesmo 3%/2% isolados passavam mas a faixa de sobreposição das duas ainda
  ficava abaixo de AA (4,45:1). 1%/1% é o piso que fecha a conta com a
  sobreposição real incluída — ver T3 §Step 7, Fix round 2.
*/
.hero-bubbles circle {
  fill: transparent;
  stroke: color-mix(in srgb, var(--ink) 1%, transparent);
  stroke-width: 1;
  animation: hero-bubble-fill 900ms ease-out both;
  animation-delay: calc(var(--i, 0) * 15ms);
}

@keyframes hero-bubble-fill {
  from {
    fill: transparent;
  }
  to {
    fill: color-mix(in srgb, var(--accent) 1%, transparent);
  }
}

/*
  Camada 3 — o véu. Sem ele o contraste do texto dependeria de onde o
  gradiente parou quando a aba foi escondida; com ele, o pior quadro medido em
  T3 §Step 7 (contraste analítico) já é o pior quadro real. 20% de
  `--ground` sobre o fundo, nunca sobre o gradiente em si — reduzir a
  intensidade das manchas é reduzir o elemento de assinatura, e a instrução
  explícita foi não fazer isso.
*/
.hero-veil {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: color-mix(in srgb, var(--ground) 20%, transparent);
  pointer-events: none;
}

/* Os quatro cantos: os marcadores fiduciais da folha (`visao-omr.md`),
   redesenhados como ornamento. `currentColor` porque o traço é a única tinta
   — T5 desenha um quadrado de canto arredondado (`<rect rx="…">`) dentro. */
.hero-corner {
  position: absolute;
  z-index: 0;
  width: 2.5rem;
  height: 2.5rem;
  color: var(--accent);
  opacity: 0.55;
  pointer-events: none;
}

.hero-corner--tl {
  top: var(--s-4);
  left: var(--s-4);
}

.hero-corner--tr {
  top: var(--s-4);
  right: var(--s-4);
}

.hero-corner--bl {
  bottom: var(--s-4);
  left: var(--s-4);
}

.hero-corner--br {
  bottom: var(--s-4);
  right: var(--s-4);
}

/* ------------------------------------------------- as seções da página inicial */

/* Par de botões. Embrulha no celular em vez de encolher: um botão apertado
   erra mais que um botão na linha de baixo. */
.actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
}

/* O aviso de que o corretor está só em português. Fica junto do botão de
   propósito: dizer depois, na página de dentro, é deixar a pessoa descobrir. */
.app-note {
  margin: 0;
  color: var(--ink-2);
  font-size: 0.9375rem;
}

/* A faixa de fatos. Sem marcador de lista e sem título: são quatro afirmações
   verificáveis, e cada uma se sustenta sozinha. */
.facts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3) var(--s-5);
  margin: 0;
  padding: var(--s-4) var(--s-5);
  list-style: none;
  border-block: 1px solid var(--line);
  color: var(--ink-2);
  font-weight: 600;
}

.band {
  display: flex;
  flex-direction: column;
  gap: var(--s-5);
}

.band > h2 {
  margin: 0;
}

.band > p {
  max-width: 42rem;
}

/* Texto de um lado, mockup do outro. `1fr` nas duas colunas, e não `auto` na
   do desenho: com `auto` o SVG dita a largura e o parágrafo fica espremido.

   As colunas alinham pelo topo, e só o desenho se centraliza: numa seção de
   texto ao lado de texto — o contato, o login — centralizar as duas deixava a
   coluna curta flutuando no meio da alta, sem nada que explicasse o buraco. */
.split {
  display: grid;
  gap: var(--s-5);
  align-items: start;
}

.split > div {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
}

/* Teto de largura do desenho dentro de uma seção de duas colunas. Sem ele, o
   mockup da folha — que é alto e estreito — estica até a metade da tela e fica
   com quase 900 px de altura, três vezes o bloco de texto ao lado. */
.split > .mockup {
  max-width: 30rem;
  max-height: 20rem;
  margin-inline: auto;
  align-self: center;
}

@media (min-width: 835px) {
  .split {
    grid-template-columns: 1fr 1fr;
    gap: var(--s-7);
  }

  /* Alterna o lado do desenho de uma seção para a outra — duas seções seguidas
     com o mesmo lado leem como uma seção só, longa. */
  .split--flip > div {
    order: 2;
  }
}

.card {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  margin: 0;
}

.card h2,
.card h3,
.card p {
  margin: 0;
}

/* Dentro de um cartão, `<h2>` é o nível certo (a página tem um `<h1>` só), mas
   o tamanho de um `<h2>` de seção não é: ele passaria o título do cartão à
   frente do título da seção que o contém. Nível semântico e tamanho não são a
   mesma decisão. */
.card h2 {
  font-size: 1.25rem;
}

.grid {
  list-style: none;
  padding: 0;
  margin: 0;
}

/* Quatro itens numa grade de três colunas deixam um órfão sozinho na segunda
   linha. Onde a contagem é par, duas colunas. */
@media (min-width: 835px) {
  .grid--pairs {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* O número do passo. `aria-hidden` no HTML: a ordem já é a da `<ol>`, e o
   leitor de tela anunciando "1" antes do título seria a mesma coisa duas vezes. */
.card-step {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: var(--r-pill);
  background: var(--accent-soft);
  color: var(--accent-strong);
  font-weight: 700;
}

/* Lista de capacidades. O marcador é desenhado com `::before` para poder usar
   a cor de ação sem `list-style-image`, que não aceita `currentColor`. */
.ticks {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.ticks li {
  position: relative;
  padding-left: 1.75rem;
  color: var(--ink-2);
}

.ticks li::before {
  content: "";
  position: absolute;
  left: 0.25rem;
  top: 0.55em;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: var(--r-pill);
  background: var(--accent);
}

/* O antes e o depois. O "antes" fica esmaecido e o "agora" na tinta cheia —
   a hierarquia diz qual dos dois é o ponto sem precisar de seta nem de ícone. */
.swap {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  margin: 0;
}

.swap p {
  margin: 0;
}

.swap span {
  display: block;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.swap-before {
  color: var(--ink-3);
}

.swap-before span {
  color: var(--ink-3);
}

.swap-after span {
  color: var(--accent-strong);
}

/* O que acontece quando o sistema não entende uma questão — a parte que a
   professora precisa ler antes de confiar na importação, porque falhar
   visivelmente é requisito e não detalhe (D4).

   Mesmo tratamento de `.banner-warning` em `src/styles/app.css` (fundo suave,
   tinta âmbar, borda de 1px nos quatro lados): quem vir o aviso no site e
   depois o aviso dentro do corretor reconhece a mesma coisa. Repetido aqui, e
   não herdado, porque o site não importa o CSS do app. */
.note {
  margin: 0;
  padding: var(--s-3) var(--s-4);
  border: 1px solid color-mix(in srgb, var(--ambiguous) 45%, transparent);
  border-radius: var(--r-sm);
  background: var(--ambiguous-soft);
  color: var(--ambiguous-ink);
  font-size: 0.9375rem;
  font-weight: 550;
}

.why {
  max-width: 46rem;
}

.final-call {
  align-items: flex-start;
  padding: var(--s-7) var(--s-5);
}

/* Os mockups nunca são a informação — são a ilustração dela. Largura cheia da
   coluna, altura livre: `svg { max-width: 100% }` lá em cima já impede corte. */
.mockup {
  width: 100%;
  height: auto;
}

/* Um mockup solto no fluxo da página, sem coluna que o contenha, esticaria até
   os 75 rem do `main` — meia página de altura, competindo com o conteúdo que
   ele deveria ilustrar. Medido em `/testar/`, onde ele fica sozinho no fim. */
main > .mockup {
  max-width: 16rem;
  margin-inline: auto;
}

/* ------------------------------------------------------------- as subpáginas */

.page-head {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  max-width: 46rem;
}

.page-head h1 {
  margin: 0;
}

/* A linha de abertura. Um degrau acima do corpo do texto, e um abaixo do
   título: é ela que decide se a pessoa lê o resto. */
.lede {
  margin: 0;
  font-size: 1.125rem;
  color: var(--ink-2);
}

/* Texto corrido de verdade — documentação e artigo. A largura é limitada em
   `ch` e não em `rem`: o que cansa a leitura é o número de caracteres por
   linha, não a quantidade de pixels. */
.prose {
  max-width: 68ch;
}

.prose h2 {
  margin: var(--s-7) 0 var(--s-3);
}

.prose h3 {
  margin: var(--s-5) 0 var(--s-2);
}

.prose p {
  margin: 0 0 var(--s-4);
}

.prose-list,
.prose-steps {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  margin: 0 0 var(--s-4);
  padding-left: var(--s-5);
  color: var(--ink-2);
}

.prose .note {
  margin-bottom: var(--s-4);
}

/* Índice lateral. Vira coluna só quando há largura; no celular ele fica em
   cima, que é onde um índice serve para pular seção. */
.with-aside {
  display: grid;
  gap: var(--s-5);
  align-items: start;
}

/*
  `min-width: 0` nos filhos de grade, e não é detalhe: um item de grade nasce
  com `min-width: auto`, o que o proíbe de encolher abaixo do próprio conteúdo.
  A tabela dos sons tem `min-width: 32rem` (512 px) para não espremer as três
  colunas — dentro de `.table-scroll` ela deveria rolar sozinha, mas sem esta
  regra era a **coluna da grade** que crescia para 512 px, e a página inteira
  passava a rolar na horizontal a 430 px. Medido: 530 px numa tela de 430.
*/
.with-aside > *,
.split > * {
  min-width: 0;
}

@media (min-width: 835px) {
  .with-aside {
    grid-template-columns: 16rem 1fr;
    gap: var(--s-7);
  }

  .aside {
    position: sticky;
    top: var(--s-4);
  }
}

.aside h2 {
  margin: 0 0 var(--s-3);
  font-size: 0.9375rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.aside ul {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.doc-section {
  scroll-margin-top: var(--s-5);
}

.doc-section:first-child h2 {
  margin-top: 0;
}

/* Tabela larga rola dentro da própria caixa. Nunca a página: barra de rolagem
   horizontal no `body` some com o texto do lado esquerdo no celular. */
.table-scroll {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--plate);
}

table {
  border-collapse: collapse;
  width: 100%;
  min-width: 32rem;
}

th,
td {
  padding: var(--s-3) var(--s-4);
  text-align: left;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}

tbody tr:last-child th,
tbody tr:last-child td {
  border-bottom: 0;
}

thead th {
  font-size: 0.875rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--ink-3);
}

tbody th {
  font-weight: 600;
}

/* É um produto sobre números que se comparam em coluna: "20" e "150" na mesma
   coluna da tabela de planos, e o preço de um cartão ao lado do outro. Sem
   `tabular-nums` a largura do dígito varia e as colunas dançam.

   Era classe utilitária desde a T3, e em nove tarefas nenhum template a
   aplicou — o lugar dela sempre foi aqui, onde o número de fato se compara. */
td,
.tier-price {
  font-variant-numeric: tabular-nums;
}

td {
  color: var(--ink-2);
}

/* ------------------------------------------------------------------ planos */

.tier {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  margin: 0;
}

.tier h2 {
  margin: 0;
  font-size: 1.25rem;
}

/* A faixa em destaque ganha a borda na cor de ação, e não um selo de "mais
   popular": não há popularidade a relatar — nenhum plano pago está à venda. */
.tier--highlight {
  border-color: var(--accent);
}

.tier-price {
  margin: 0;
  font-size: 1.75rem;
  font-weight: 700;
}

.tier-price span {
  font-size: 1rem;
  font-weight: 400;
  color: var(--ink-3);
}

.tier-quota {
  margin: 0;
  color: var(--ink-2);
}

/* ------------------------------------------------------------- formulários */

.form {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
}

.field {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  margin: 0;
}

.field label {
  font-weight: 600;
}

.field input,
.field textarea {
  min-height: var(--touch);
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--plate-sunken);
  color: var(--ink);
  font: inherit;
}

.field textarea {
  resize: vertical;
}

.form p {
  margin: 0;
}

/* --------------------------------------------------- a demonstração na tela */

/* A folha o maior possível, e o que a pessoa precisa ler ao lado dela. Quem faz
   a demonstração está olhando esta página num aparelho e o corretor no outro,
   então a coluna estreita do celular é o caso raro, não o comum. */
.demo {
  display: grid;
  gap: var(--s-5);
  align-items: start;
}

@media (min-width: 835px) {
  .demo {
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    gap: var(--s-7);
  }
}

/* A moldura é o sistema de coordenadas das marcações: elas são posicionadas em
   porcentagem, e porcentagem só significa alguma coisa dentro de um elemento
   posicionado. `line-height: 0` porque a imagem é inline por padrão e o espaço
   reservado para descida de letra deixaria uma faixa embaixo — faixa essa que
   deslocaria toda marcação em relação ao desenho. */
.demo-frame {
  position: relative;
  line-height: 0;
}

/* Fundo branco explícito: a folha é preto sobre branco e o PNG tem canal alfa.
   Sobre o `--ground` acinzentado do site, o contraste que a câmera mede seria
   outro — e é justamente ele que decide a leitura. */
.demo-sheet {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: #ffffff;
}

/* A marcação sorteada, pintada sobre a bolinha em branco do PNG.

   `left`/`top` são o **centro** da bolinha, e o `translate(-50%, -50%)` é o que
   converte "onde a bolinha está" em "onde a caixa começa". Sem ele cada
   marcação sairia deslocada de meio diâmetro para baixo e para a direita — o
   suficiente para o corretor ler a alternativa vizinha e a nota prometida
   deixar de bater, com a tela parecendo certa.

   Largura e `padding-top` vêm do script, os dois em porcentagem da **largura**
   da moldura: é assim que o círculo continua redondo em qualquer tamanho de
   tela. Altura em porcentagem se resolveria contra a altura e daria uma elipse. */
.demo-mark {
  position: absolute;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: #000000;
}

.demo-aside {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
}

.demo-aside p {
  margin: 0;
}

/* O gabarito é para ser copiado a olho, letra por letra, para o celular. Daí o
   espaçamento largo e a caixa própria: dez letras coladas viram um borrão. */
.demo-key code {
  display: block;
  margin-top: var(--s-2);
  padding: var(--s-3);
  border-radius: var(--r-sm);
  background: var(--plate-sunken);
  font-size: 1.125rem;
  letter-spacing: 0.12em;
}

.demo-score span {
  display: block;
  margin-top: var(--s-1);
  font-size: 2rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* A nota e a legenda são um bloco só: as duas trocam juntas a cada cinco
   segundos, e separá-las deixaria a nota de uma prova ao lado do nome de
   outra durante o repaint. */
.demo-now {
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
}

/* `min-height` porque a legenda troca de texto durante o intervalo: sem altura
   reservada, "Trocando de prova..." e "Prova 2 de 6" com larguras diferentes
   empurrariam o resto da coluna a cada volta. */
.demo-label {
  min-height: 1.5em;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------- artigos */

/* Um cartão só, e por isso fora da `.grid`: numa grade de três colunas ele
   sairia com um terço da largura e o texto quebraria em três palavras. */
.related-list {
  margin: 0;
  padding: 0;
  list-style: none;
  max-width: 32rem;
}

.article-meta {
  margin: 0;
  color: var(--ink-3);
  font-size: 0.9375rem;
}

.article .page-head {
  margin-bottom: var(--s-5);
}

/* -------------------------------------------------------- movimento e aba oculta */

/*
  A pausa por aba oculta é o único JavaScript do site (`site/templates/layout.ts`).
  Ele alterna esta classe no `<html>`; a regra é a mesma para as duas famílias
  de animação, sem tocar em cada elemento uma por uma.
*/
.is-hidden *,
.is-hidden *::before,
.is-hidden *::after {
  animation-play-state: paused !important;
}

/* "Nada se move sozinho na página além do fundo do hero e do preenchimento das
   bolinhas" (restrição global do plano) — a aurora já para em `shared.css`, e
   nem as bolinhas se movem aqui. */
@media (prefers-reduced-motion: reduce) {
  .hero-bubbles circle {
    animation: none !important;
  }
}
