/* =========================================================================
   O3LAB — base e componentes

   Forma: a ficha de ensaio de laboratório. Grid de dados, linhas de 1px,
   par rótulo/valor, numeral tabular, notação técnica. É a linguagem gráfica
   que essa audiência já lê todo dia em relatório de ensaio, certificado de
   calibração e datasheet de fabricante — e não a grade de cards iguais que
   todo site de equipamento entrega.
   ========================================================================= */

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

/* O atributo `hidden` precisa vencer.
   A folha do navegador traz `[hidden] { display: none }`, mas qualquer regra
   de autor que declare `display` no mesmo elemento a supera — e o site declara
   em vários: `.form__row` é grid, `.field-group` é flex. O resultado é
   `el.hidden = true` no script sem efeito nenhum na tela, sem erro que denuncie.
   Foi assim que o recibo do orçamento apareceu com o formulário inteiro ainda
   visível atrás dele. */
[hidden] { display: none !important; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* A barra de rolagem é uma superfície do produto, não do navegador. */
  scrollbar-color: var(--line-strong) transparent;
  scrollbar-width: thin;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  background: var(--surface);
  color: var(--text);
  font-family: var(--font);
  font-size: var(--text-base);
  font-weight: var(--weight-regular);
  line-height: var(--leading-normal);
  letter-spacing: var(--tracking-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* --- Superfícies que o navegador pinta por padrão -------------------------
   Seleção, cursor de texto, barra de rolagem, anel de foco e sublinhado
   chegam com estilo de ninguém. Aqui eles pertencem à marca. */

::selection {
  background: var(--o3-deep);
  color: var(--o3-white);
}

:root[data-theme="dark"] ::selection {
  background: var(--o3-bright);
  color: var(--action-text);
}

input, textarea, select { caret-color: var(--brand-ink); }

::-webkit-scrollbar { width: 12px; height: 12px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--line-strong);
  border-radius: var(--radius-pill);
  border: 3px solid var(--surface);
}
::-webkit-scrollbar-thumb:hover { background: var(--brand-ink); }

:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}
:focus:not(:focus-visible) { outline: none; }

/* --- Tipografia ---------------------------------------------------------- */

h1, h2, h3, h4 {
  margin: 0;
  color: var(--text);
  font-weight: var(--weight-bold);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-title);
  text-wrap: balance;
}

h1 { font-size: var(--text-2xl); font-weight: var(--weight-extra); letter-spacing: var(--tracking-display); }
h2 { font-size: var(--text-xl); }
h3 { font-size: var(--text-lg); }
h4 { font-size: var(--text-md); font-weight: var(--weight-semibold); }

p { margin: 0; max-width: var(--measure); text-wrap: pretty; }

a {
  color: var(--brand-ink);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
  text-decoration-color: color-mix(in srgb, var(--brand-ink) 35%, transparent);
  transition: text-decoration-color var(--duration-fast) var(--ease-out);
}
a:hover { text-decoration-color: currentColor; }

strong, b { font-weight: var(--weight-semibold); }

/* Números em contexto técnico são dados, e dado se lê em coluna. */
.tabular, table, .spec-sheet, .stat-value { font-variant-numeric: tabular-nums; }

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

/* --- Estrutura ----------------------------------------------------------- */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.container--narrow { max-width: var(--container-narrow); }

.section { padding-block: var(--section-y); }
.section--sunken { background: var(--surface-sunken); }

/* Campo de cor: o azul ocupa a região inteira, não pinta detalhes soltos.
   É assim que a proporção 25% do brandbook acontece de verdade. */
.field-deep {
  background: var(--o3-deep);
  color: var(--text-on-inverse);
}
.field-navy {
  background: var(--o3-navy);
  color: var(--text-on-inverse);
}
.field-deep h1, .field-deep h2, .field-deep h3, .field-deep h4,
.field-navy h1, .field-navy h2, .field-navy h3, .field-navy h4 { color: var(--text-on-inverse); }
.field-deep p, .field-navy p { color: var(--text-muted-on-inverse); }
.field-deep a, .field-navy a { color: var(--brand-ink-on-inverse); }
/* Campo azul devolve o Bright Blue ao anel de foco: sobre ele o Deep Blue
   ficaria invisível, e o vibrante rende 4,75:1. Mesma inversão que o texto,
   o link e o botão já fazem duas linhas acima. */
.field-deep, .field-navy { --focus-ring: var(--o3-bright); }

.stack > * + * { margin-block-start: var(--flow, var(--space-4)); }
.stack--tight { --flow: var(--space-2); }
.stack--loose { --flow: var(--space-6); }

/* Mais espaço acima de um título do que abaixo dele. */
.stack > h2 + *, .stack > h3 + * { margin-block-start: var(--space-3); }
.stack > * + h2, .stack > * + h3 { margin-block-start: var(--space-7); }

/* Duas colunas que viram uma antes de apertar. O ponto de quebra é o
   conteúdo, não um breakpoint herdado de framework. */
.split {
  display: grid;
  gap: var(--space-7);
  align-items: start;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 0.85fr);
}
.split--even { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 900px) {
  .split, .split--even { grid-template-columns: minmax(0, 1fr); gap: var(--space-6); }
  .split > aside { position: static !important; }
}

/* --- Rótulo técnico ------------------------------------------------------
   O único uso de caixa alta no sistema, e curto por regra: é o cabeçalho de
   coluna de uma ficha de ensaio, não um kicker decorativo acima de título. */

.label {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-muted);
}
.field-deep .label, .field-navy .label { color: var(--text-muted-on-inverse); }

/* --- Linha estrutural ----------------------------------------------------- */

.rule {
  border: 0;
  border-top: 1px solid var(--line);
  margin: 0;
}
.field-deep .rule, .field-navy .rule { border-top-color: var(--line-on-inverse); }

/* --- Ação ----------------------------------------------------------------- */

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 48px;
  padding: var(--space-3) var(--space-5);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: var(--action-bg);
  color: var(--action-text);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  letter-spacing: 0;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-out),
              transform var(--duration-fast) var(--ease-out);
}
.button:hover { background: var(--action-bg-hover); text-decoration: none; }
.button:active { transform: translateY(1px); }
.button[disabled], .button[aria-disabled="true"] {
  background: var(--line-strong);
  color: var(--surface);
  cursor: not-allowed;
  transform: none;
}

.button--ghost {
  background: transparent;
  color: var(--action-ghost-text);
  border-color: var(--action-ghost-line);
}
.button--ghost:hover { background: var(--o3-deep-050); }
:root[data-theme="dark"] .button--ghost:hover { background: rgba(44, 173, 255, 0.12); }

/* Sobre campo azul, a ação primária inverte: branco sólido com texto Deep
   Blue rende 11,27:1, enquanto azul-vibrante-sobre-azul não passaria. */
.field-deep .button, .field-navy .button {
  background: var(--o3-white);
  color: var(--o3-deep);
}
.field-deep .button:hover, .field-navy .button:hover { background: var(--o3-deep-050); }
.field-deep .button--ghost, .field-navy .button--ghost {
  background: transparent;
  color: var(--o3-white);
  border-color: rgba(255, 255, 255, 0.45);
}
.field-deep .button--ghost:hover, .field-navy .button--ghost:hover {
  background: rgba(255, 255, 255, 0.1);
}

/* --- Cabeçalho ------------------------------------------------------------ */

.masthead {
  position: sticky;
  top: 0;
  z-index: 40;
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
}

.masthead__bar {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  min-height: 88px;
}

.masthead__logo { display: flex; align-items: center; gap: var(--space-3); flex: none; }
/* A assinatura da marca é o primeiro elemento que identifica a empresa; a 34px
   ela competia de igual para igual com um link de menu. */
.masthead__logo img, .masthead__logo svg { height: 52px; width: auto; }

@media (max-width: 620px) {
  .masthead__bar { min-height: 76px; }
  .masthead__logo img, .masthead__logo svg { height: 42px; }
}

/* Busca do cabeçalho.
   `margin-inline-start: auto` sai do nav e vem para cá: a busca é o primeiro
   item do lado direito, e o nav passa a se encostar nela. */
.masthead__busca {
  display: flex;
  align-items: center;
  margin-inline-start: auto;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-raised);
}
/* O campo suprime o próprio outline (logo abaixo) para que o anel apareça em
   volta da moldura inteira, e não só do <input> dentro dela. Sem esta regra a
   supressão ficava sem substituto e o único sinal de foco era a borda mudando
   para o azul vibrante — 2,29:1 contra o fundo do cabeçalho e 2,06:1 contra a
   borda que ela substitui, quando a WCAG 2.4.11 pede 3:1 de um indicador.
   É o mesmo defeito que o anel de foco global já tinha e que foi corrigido
   trocando o vibrante pelo Deep Blue; sobreviveu aqui porque este componente
   chamava a cor da marca direto, sem passar pelo token. */
.masthead__busca:focus-within {
  border-color: var(--accent);
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

.masthead__busca-campo {
  width: 7.5rem;
  min-height: 40px;
  padding-inline: var(--space-3);
  border: 0;
  background: none;
  color: var(--text);
  font: inherit;
  font-size: var(--text-sm);
}
.masthead__busca-campo:focus-visible { outline: none; }
.masthead__busca-campo::placeholder { color: var(--text-muted); }

.masthead__busca-acao {
  display: grid;
  place-items: center;
  width: 40px;
  min-height: 40px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--text-muted);
  cursor: pointer;
}
.masthead__busca-acao:hover { color: var(--brand-ink); }

.masthead__nav {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

/* O cabeçalho é uma linha só, por regra.
   Com a busca ocupando 186px, "Solicitar orçamento" e o telefone passaram a
   quebrar em duas linhas dentro dos próprios elementos — a barra tinha largura
   sobrando (1088 de 1216), mas o texto não tinha. Duas linhas de menu no
   desktop é layout quebrado, então o texto não quebra. */
.masthead__nav .button,
.masthead__contact,
.masthead__link { white-space: nowrap; }

.masthead__link {
  color: var(--text);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  text-decoration: none;
  padding-block: var(--space-2);
}
.masthead__link:hover { color: var(--brand-ink); text-decoration: none; }
.masthead__link[aria-current="page"] {
  box-shadow: inset 0 -2px 0 var(--accent);
}

/* Contato sempre visível, inclusive no telefone. No site atual esta barra
   carrega `hidden-mobile` e some exatamente onde tocar num número é a ação
   de maior intenção. */
.masthead__contact {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  font-size: var(--text-sm);
}
.masthead__contact a {
  display: inline-block;
  padding-block: var(--space-3);
  color: var(--text-muted);
  text-decoration: none;
}
.masthead__contact a:hover { color: var(--brand-ink); }

@media (max-width: 900px) {
  /* No celular a busca vira só o ícone: o campo de 9rem competiria com o
     logotipo e o botão de menu na mesma linha. Tocar leva à página de busca,
     que tem o campo inteiro e o teclado já aberto. */
  .masthead__busca { border: 0; background: none; }
  .masthead__busca-campo { display: none; }

  .masthead__nav { display: none; }
  .masthead__nav[data-open="true"] {
    display: flex;
    position: absolute;
    inset: 88px 0 auto;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: var(--space-4) var(--gutter) var(--space-6);
    background: var(--surface-raised);
    border-bottom: 1px solid var(--line);
  }
  .masthead__nav[data-open="true"] .masthead__link {
    padding-block: var(--space-4);
    border-bottom: 1px solid var(--line);
  }
}

.menu-toggle {
  display: none;
  margin-inline-start: auto;
  min-width: 48px;
  min-height: 48px;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  color: var(--text);
  cursor: pointer;
}
@media (max-width: 900px) { .menu-toggle { display: inline-flex; } }

/* --- Busca ---------------------------------------------------------------
   O site atual tem 109 produtos com nomenclatura de modelo e nenhuma caixa
   de busca. Este é o componente que resolve a maior lacuna de navegação. */

.search {
  position: relative;
  display: flex;
  align-items: center;
  width: min(100%, 30rem);
}

.search__input {
  width: 100%;
  min-height: 52px;
  padding: var(--space-3) var(--space-5) var(--space-3) 3rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-raised);
  color: var(--text);
  font: inherit;
  font-size: var(--text-base);
}
.search__input::placeholder { color: var(--text-muted); }
.search__input:focus-visible { border-color: var(--accent); }

.search__icon {
  position: absolute;
  inset-inline-start: var(--space-4);
  color: var(--text-muted);
  pointer-events: none;
}

.field-deep .search__input {
  background: rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.32);
  color: var(--o3-white);
}
.field-deep .search__input::placeholder { color: var(--text-muted-on-inverse); }
.field-deep .search__icon { color: var(--text-muted-on-inverse); }

.search__results {
  position: absolute;
  top: calc(100% + var(--space-2));
  inset-inline: 0;
  z-index: 30;
  max-height: 24rem;
  overflow-y: auto;
  background: var(--surface-raised);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lifted);
  padding: var(--space-2);
}
.search__results:empty { display: none; }

.search__result {
  display: block;
  padding: var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--text);
  text-decoration: none;
}
.search__result:hover, .search__result:focus-visible { background: var(--surface-raised); }
.search__result strong { display: block; font-weight: var(--weight-semibold); }
.search__result span { font-size: var(--text-sm); color: var(--text-muted); }

/* --- Hero ----------------------------------------------------------------- */

.hero {
  position: relative;
  overflow: hidden;
  padding-block: clamp(var(--space-8), 9vw, var(--space-10));
}

.hero__inner { position: relative; z-index: 2; max-width: 46rem; }

.hero h1 {
  font-size: var(--text-3xl);
  margin-block-end: var(--space-5);
}

.hero__lede {
  font-size: var(--text-md);
  line-height: var(--leading-loose);
  max-width: var(--measure-narrow);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-block-start: var(--space-6);
}

/* Os três círculos como marca d'água estrutural: identidade presente sem
   competir com o conteúdo, como a regra dos 3 níveis determina. */
.hero__mark {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-end: -6%;
  translate: 0 -50%;
  width: min(46rem, 60%);
  opacity: 0.18;
  z-index: 1;
  pointer-events: none;
}
@media (max-width: 900px) {
  .hero__mark { inset-inline-end: -30%; opacity: 0.12; }
}

/* --- Entrada por problema -------------------------------------------------
   Não é uma grade de cards de ícone + título + texto. É uma lista de
   perguntas de laboratório, cada uma abrindo para a tecnologia que responde. */

.problem-list { display: grid; gap: 0; border-block-start: 1px solid var(--line); }

.problem {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr) auto;
  gap: var(--space-5);
  align-items: baseline;
  padding-block: var(--space-6);
  border-block-end: 1px solid var(--line);
  color: inherit;
  text-decoration: none;
  transition: background var(--duration-fast) var(--ease-out);
}
.problem:hover { background: var(--surface-raised); text-decoration: none; }
.problem:hover .problem__go { translate: 4px 0; }

.problem__question {
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-title);
  color: var(--text);
}
.problem__answer { color: var(--text-muted); font-size: var(--text-sm); }
.problem__go {
  color: var(--brand-ink);
  transition: translate var(--duration) var(--ease-out);
}

@media (max-width: 760px) {
  .problem { grid-template-columns: 1fr auto; gap: var(--space-3); }
  .problem__answer { grid-column: 1 / -1; }
}

/* --- Ficha de ensaio ------------------------------------------------------
   O componente que dá nome à direção. Especificação como par rótulo/valor,
   linha fina entre registros, numeral tabular, unidade separada do número. */

.spec-sheet {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
}
.spec-sheet caption {
  text-align: start;
  padding-block-end: var(--space-3);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-muted);
}
.spec-sheet th, .spec-sheet td {
  padding-block: var(--space-3);
  border-block-end: 1px solid var(--line);
  vertical-align: baseline;
  text-align: start;
}
.spec-sheet th {
  width: 42%;
  font-weight: var(--weight-medium);
  color: var(--text-muted);
}
.spec-sheet td { font-weight: var(--weight-medium); color: var(--text); }
.spec-sheet .unit { color: var(--text-muted); font-weight: var(--weight-regular); }

/* Estado vazio honesto: o brandbook proíbe inventar especificação, então uma
   ficha sem dado verificado diz isso em vez de exibir "Pequeno, Médio e
   grande" no lugar de um número. */
.spec-sheet__empty {
  padding: var(--space-5);
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  font-size: var(--text-sm);
}

/* --- Equipamento ---------------------------------------------------------- */

.equipment-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
  gap: var(--space-5);
}

.equipment {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-5);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-raised);
  color: inherit;
  text-decoration: none;
  transition: border-color var(--duration-fast) var(--ease-out),
              box-shadow var(--duration) var(--ease-out);
}
.equipment:hover {
  border-color: var(--line-strong);
  box-shadow: var(--shadow-raised);
  text-decoration: none;
}

.equipment__figure {
  aspect-ratio: 4 / 3;
  background: var(--surface);
  border-radius: var(--radius-sm);
  overflow: hidden;
  display: grid;
  place-items: center;
}
.equipment__figure img { width: 100%; height: 100%; object-fit: contain; mix-blend-mode: multiply; }
:root[data-theme="dark"] .equipment__figure img { mix-blend-mode: normal; }

.equipment__model {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-label);
  color: var(--brand-ink);
}

.equipment__name {
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-title);
}
.equipment__summary { font-size: var(--text-sm); color: var(--text-muted); }

/* Espaço reservado, marcado com honestidade, para quando não existe foto
   própria do equipamento. Melhor um vazio declarado do que um thumbnail de
   busca do Google — que é o que o site atual publica hoje. */
.equipment__figure--pending {
  border: 1px dashed var(--line-strong);
  color: var(--text-muted);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  text-align: center;
  padding: var(--space-4);
}

/* --- Prova ---------------------------------------------------------------- */

.proof {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: var(--space-6);
}
.proof__item { display: flex; flex-direction: column; gap: var(--space-1); }
.stat-value {
  font-size: var(--text-xl);
  font-weight: var(--weight-extra);
  letter-spacing: var(--tracking-display);
  line-height: 1;
}
.stat-label { font-size: var(--text-sm); color: var(--text-muted); }
.field-deep .stat-label, .field-navy .stat-label { color: var(--text-muted-on-inverse); }

/* --- Formulário ----------------------------------------------------------- */

.form { display: grid; gap: var(--space-5); }
.form__row { display: grid; gap: var(--space-5); grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }

.field-group { display: flex; flex-direction: column; gap: var(--space-2); }

/* Rótulo visível acima do campo, sempre. O formulário atual usa apenas
   placeholder, então o rótulo desaparece no instante em que a pessoa começa
   a digitar — e some justamente durante a revisão antes do envio. */
.field-group > label {
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--text);
}
.field-group__hint { font-size: var(--text-xs); color: var(--text-muted); }

.input, .textarea, .select {
  min-height: 48px;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-raised);
  color: var(--text);
  font: inherit;
  font-size: var(--text-base);
  width: 100%;
}
.textarea { min-height: 8rem; resize: vertical; line-height: var(--leading-normal); }
.input::placeholder, .textarea::placeholder { color: var(--text-muted); }
.input:focus-visible, .textarea:focus-visible, .select:focus-visible { border-color: var(--accent); }

.input[aria-invalid="true"], .textarea[aria-invalid="true"] { border-color: var(--danger-line); }

.field-error {
  font-size: var(--text-sm);
  color: var(--danger-text);
  display: flex;
  gap: var(--space-2);
  align-items: baseline;
}


.form__status {
  padding: var(--space-4) var(--space-5);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
}
/* Recebe foco por script depois do envio; sem isto o navegador desenha o anel
   e o visitante não entende por que aquela caixa está selecionada. */
.form__status:focus { outline: none; }

/* Equipamento de referência: a ficha de ensaio aplicada ao próprio formulário.
   Par rótulo/valor com linha de 1px, que é a gramática do resto do site. */
.form__referencia {
  padding: var(--space-4) var(--space-5);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-raised);
}
.form__referencia-nome {
  margin-block-start: var(--space-2);
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
  color: var(--brand-ink);
  max-width: none;
}
.form__referencia-trocar {
  margin-block-start: var(--space-3);
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: var(--text-sm);
  color: var(--text-muted);
  text-decoration: underline;
  text-underline-offset: 0.2em;
  cursor: pointer;
}
.form__referencia-trocar:hover { color: var(--brand-ink); }

/* O que acontece depois, dito antes de enviar. */
.form__antes-de-enviar {
  font-size: var(--text-sm);
  color: var(--text-muted);
  max-width: var(--measure-narrow);
}

/* Recibo: repete o que foi enviado, para o envio ter fim visível. */
.form__recibo-dados {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: var(--space-2) var(--space-5);
  margin: 0;
  padding-block-start: var(--space-4);
  border-block-start: 1px solid var(--line);
}
.form__recibo-dados dt {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-muted);
}
.form__recibo-dados dd { margin: 0; }
.form__status[data-tone="success"] {
  background: var(--ok-surface);
  color: var(--ok-on-surface);
}
.form__status[data-tone="error"] {
  background: var(--danger-surface);
  color: var(--danger-on-surface);
}


/* --- Rodapé --------------------------------------------------------------- */

.footer { padding-block: var(--space-8) var(--space-6); }
.footer__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--space-7);
}
.footer__list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-1); }
.footer__list a {
  display: inline-block;
  padding-block: var(--space-2);
  color: var(--text-muted-on-inverse);
  text-decoration: none;
  font-size: var(--text-sm);
}
.footer__list a:hover { color: var(--o3-white); }
.footer__legal {
  margin-block-start: var(--space-7);
  padding-block-start: var(--space-5);
  border-block-start: 1px solid var(--line-on-inverse);
  font-size: var(--text-xs);
  color: var(--text-muted-on-inverse);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  justify-content: space-between;
}

/* Lista de links em superfície clara. Existe como classe própria porque
   reutilizar a lista do rodapé fora do campo azul obriga a corrigir a cor
   com estilo inline — e foi exatamente assim que um Deep Blue fixo acabou
   sobre fundo escuro a 1,6:1. */
.link-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-1);
}
.link-list a {
  display: inline-block;
  padding-block: var(--space-2);
  color: var(--brand-ink);
  text-decoration: none;
  font-size: var(--text-sm);
}
.link-list a:hover { text-decoration: underline; }
.link-list .count { color: var(--text-muted); }

/* --- Trilha de navegação --------------------------------------------------- */

.breadcrumb { font-size: var(--text-sm); color: var(--text-muted); }
.breadcrumb ol { list-style: none; display: flex; flex-wrap: wrap; gap: var(--space-2); margin: 0; padding: 0; }
.breadcrumb li:not(:last-child)::after { content: "/"; margin-inline-start: var(--space-2); color: var(--line-strong); }
.breadcrumb a { color: var(--text-muted); text-decoration: none; }
.breadcrumb a:hover { color: var(--brand-ink); }

/* --- Pular para o conteúdo -------------------------------------------------- */

.skip-link {
  position: absolute;
  inset-inline-start: var(--space-4);
  inset-block-start: -100%;
  z-index: 100;
  padding: var(--space-3) var(--space-4);
  background: var(--o3-deep);
  color: var(--o3-white);
  border-radius: var(--radius-sm);
  text-decoration: none;
}
.skip-link:focus { inset-block-start: var(--space-4); }

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- Movimento -------------------------------------------------------------
   Um momento autoral: o conteúdo já chega visível e apenas assenta. Nada de
   entrada idêntica em toda seção. E quem pede movimento reduzido recebe o
   estado final, não uma página inerte. */

@media (prefers-reduced-motion: no-preference) {
  .settle {
    animation: settle var(--duration-slow) var(--ease-out) both;
  }
  @keyframes settle {
    from { opacity: 0; transform: translateY(12px); }
    to   { opacity: 1; transform: none; }
  }
}

/* Movimento reduzido: menos movimento, não ausência de resposta.
 *
 * A regra anterior zerava a duração de TODA transição do site com um
 * `transition-duration: 1ms !important` em `*`. Isso apagava junto o que a
 * preferência não pede para apagar: o realce do link ao passar o mouse, o
 * fundo do botão mudando ao clicar, a borda do campo acendendo ao receber
 * foco, o ponto do carrossel alongando para dizer qual slide está ativo.
 * Quem liga "reduzir movimento" quer parar de ser deslocado pela tela, não
 * perder a confirmação de que a ação aconteceu.
 *
 * O critério aqui é a distância percorrida, não a existência de transição.
 * Cor, opacidade, borda e sombra continuam com a duração normal, porque nada
 * disso desloca nada. O que percorre distância é desligado, e são quatro
 * lugares no site inteiro: o empurrão de 1px do botão ao ser pressionado, as
 * duas setas que avançam no hover, e a trilha do carrossel.
 *
 * A rede para animação continua, porque ela protege do que ainda não existe:
 * qualquer keyframe futuro salta para o estado final em vez de repetir. O
 * único keyframe atual, `settle`, já está atrás de `no-preference` e sequer
 * chega aqui. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
  }

  .button, .problem__go, .document__arrow, .hero__slides {
    transition-property: opacity, color, background, background-color,
                         border-color, box-shadow;
  }
}

/* --- Impressão -------------------------------------------------------------
   A ficha do equipamento é anexada ao processo de compra. Ela precisa
   imprimir como documento, não como captura de site. */

/* Única exceção declarada à regra do tokens.css de não ter cor literal fora
   dele: papel é outro meio. O off-white do sistema vira cinza gasto na
   impressora, o grafite consome tinta sem ganhar legibilidade, e o campo azul
   de página inteira esvazia um cartucho para nada. Preto puro sobre branco
   puro é o certo aqui, e justamente por não ser cor de tela não pertence à
   paleta da marca. */
@media print {
  .masthead, .footer, .search, .hero__mark, .button { display: none !important; }
  body { background: #fff; color: #000; font-size: 11pt; }
  .field-deep, .field-navy { background: #fff !important; color: #000 !important; }
  .spec-sheet { page-break-inside: avoid; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; color: #444; }
}

/* --- Corpo de artigo -------------------------------------------------------
   O texto herdado do WordPress chega sem classe nenhuma depois da limpeza, e é
   aqui que ele ganha ritmo. Uma coluna, medida de leitura respeitada, e mais
   espaço acima de um subtítulo do que abaixo. */

.prose { max-width: var(--measure); }

.prose > * + * { margin-block-start: var(--space-5); }
.prose > * + h2 { margin-block-start: var(--space-8); }
.prose > * + h3 { margin-block-start: var(--space-7); }
.prose > h2 + *, .prose > h3 + * { margin-block-start: var(--space-3); }

.prose p, .prose li { line-height: var(--leading-loose); }

/* Texto corrido justificado, em produto e em artigo.

   Justificar sem hifenização abre rios de espaço em branco no meio do
   parágrafo, e em português — que tem palavras longas — o efeito é pior que
   em inglês. Por isso `hyphens: auto` anda junto: o navegador só sabe
   hifenizar porque o documento declara lang="pt-BR".

   Célula de tabela fica fora: a coluna é estreita demais, e ali justificar
   produz exatamente os rios que a hifenização evita no texto corrido. */
.prose p,
.prose li {
  text-align: justify;
  hyphens: auto;
}

.prose td p,
.prose th p,
.prose td,
.prose th {
  text-align: start;
  hyphens: manual;
}
.prose h2 { font-size: var(--text-lg); }
.prose h3 { font-size: var(--text-md); }

.prose ul, .prose ol { padding-inline-start: var(--space-5); display: grid; gap: var(--space-2); }
.prose li::marker { color: var(--text-muted); }

.prose img {
  width: 100%;
  border-radius: var(--radius-sm);
  background: var(--surface-raised);
}

.prose figure { margin: 0; display: grid; gap: var(--space-3); }
.prose figcaption { font-size: var(--text-sm); color: var(--text-muted); }

.prose blockquote {
  margin: 0;
  padding-inline-start: var(--space-5);
  border-inline-start: 1px solid var(--line-strong);
  color: var(--text-muted);
}

/* Tabela dentro de artigo herda a ficha de ensaio: mesmo grid de dados, mesma
   linha de 1px, mesmo numeral tabular. */
.prose table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
}
.prose th, .prose td {
  padding-block: var(--space-3);
  padding-inline-end: var(--space-4);
  border-block-end: 1px solid var(--line);
  text-align: start;
  vertical-align: baseline;
}
.prose th { font-weight: var(--weight-semibold); color: var(--text-muted); }

/* Tabela larga rola dentro do próprio bloco; a página nunca rola na horizontal. */
.prose > table { display: block; overflow-x: auto; }

/* --- Hero claro ------------------------------------------------------------
   O hero deixou de ser um campo azul sólido. A presença de marca passa a vir
   do título em Deep Blue e dos três círculos como marca d'água, e não de um
   bloco escuro ocupando o primeiro viewport — que era o que fazia a página
   inteira parecer escura. */

.hero {
  background:
    radial-gradient(120% 90% at 82% 20%, rgba(44, 173, 255, 0.10), transparent 62%),
    linear-gradient(180deg, var(--surface-raised), var(--surface));
  border-block-end: 1px solid var(--line);
}

.hero h1 { color: var(--brand-ink); }

/* A marca d'água clara precisa de mais opacidade que a versão sobre azul para
   registrar na mesma intensidade. */
.hero:not(.field-deep):not(.field-navy) .hero__mark { opacity: 0.55; }

/* Ficha técnica e prova numérica ganham o azul institucional, que é onde a
   cor da marca rende mais: no dado, não no fundo. */
.stat-value { color: var(--brand-ink); }
.section--sunken .stat-value { color: var(--brand-ink); }
.field-deep .stat-value, .field-navy .stat-value { color: var(--o3-white); }

/* --- Página de equipamento -------------------------------------------------
   O corpo preserva a estrutura escrita pela equipe: Descrição, Descrição
   Detalhada, Características Principais, Aplicações e a tabela de
   Especificações Técnicas. A tabela é o coração da página para quem compara
   fornecedores, então ela ocupa a largura toda em vez de espremer numa coluna
   lateral. */

.product-body { max-width: 60rem; }

/* Corpo mais largo que o de artigo: a tabela de especificações precisa de
   espaço.

   Aqui o texto acompanha a tabela em vez de manter a medida de leitura de
   68ch. O parágrafo parava 231px antes da borda da tabela, e a diferença
   aparecia como um degrau na página — o olho lê duas colunas onde existe
   uma. A ficha técnica é o assunto da página; alinhar o texto a ela é o que
   faz a página parecer um documento só.

   A linha fica em torno de 90 caracteres, acima da medida clássica de
   leitura. Sustenta-se aqui porque .product-body trava a coluna em 60rem —
   a linha não cresce em monitor grande —, os parágrafos são curtos e a
   entrelinha é folgada. Em artigo, que é leitura corrida, .prose mantém a
   medida de 68ch.

   O `none` precisa ser explícito: a regra base `p { max-width: var(--measure) }`
   alcança estes parágrafos, e sem anulá-la aqui eles continuam em 68ch. */
.prose--wide { max-width: none; }
.prose--wide p, .prose--wide li { max-width: none; }

.prose--wide .spec-sheet { margin-block: var(--space-5); }
.prose--wide .spec-sheet thead th {
  background: var(--surface);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-muted);
  padding-inline: var(--space-4);
}
.prose--wide .spec-sheet td,
.prose--wide .spec-sheet tbody th {
  padding-inline: var(--space-4);
  width: auto;
}
.prose--wide .spec-sheet tbody tr:nth-child(odd) { background: var(--surface); }

/* Tabela larga rola dentro do próprio bloco, em qualquer largura de tela.

   A regra anterior dizia isto no comentário e fazia o contrário: `display:
   table` no desktop anulava o `.prose > table { display: block; overflow-x:
   auto }` de cima, e a rolagem só existia abaixo de 720px. Duas fichas de
   sete colunas ficavam 50px mais largas que a coluna de texto e vazavam para
   fora dela — justamente o desalinhamento que o resto deste bloco corrige.

   `width: 100%` mantém a tabela na medida da coluna; quem decide se rola é o
   conteúdo. As tabelas que já cabiam não mudam de tamanho, e a matriz de
   especificações não é alcançada por esta regra: ela é montada pelo template
   fora do .prose--wide. */
.prose--wide > table,
.prose--wide .spec-sheet { display: block; overflow-x: auto; width: 100%; }
@media (max-width: 720px) {
  .prose--wide .spec-sheet { white-space: nowrap; }
  .prose--wide .spec-sheet td { white-space: normal; min-width: 12rem; }
}

/* --- Documentação ----------------------------------------------------------
   Catálogo e ebook: o material que o comprador leva para a reunião de
   aprovação. Sai do meio do parágrafo, onde estava, e vira ação visível. */

.documents { margin-block-start: var(--space-7); }

/* Cartão de download em campo azul claro. É a única superfície colorida do
   corpo da página, e por isso destaca sem competir: o brandbook reserva o
   azul vibrante para elementos pontuais, não para blocos de texto. */
.documents {
  --doc-bg: var(--o3-deep-050);
}
:root[data-theme=dark] .documents {
  --doc-bg: rgba(44, 173, 255, .10);
  --doc-bg-hover: rgba(44, 173, 255, .16);
  --doc-line: rgba(44, 173, 255, .38);
}

.document-list {
  list-style: none;
  margin: var(--space-4) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: var(--space-4);
}

.document {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  padding-inline-end: var(--space-8);
  border: 1px solid var(--doc-line);
  border-radius: var(--radius);
  background: var(--doc-bg);
  color: var(--text);
  text-decoration: none;
  transition: background var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out),
              box-shadow var(--duration) var(--ease-out);
}
.document:hover {
  background: var(--doc-bg-hover);
  border-color: var(--brand-ink);
  box-shadow: var(--shadow-raised);
  text-decoration: none;
}
.document:hover .document__arrow { translate: 0 2px; opacity: 1; }

/* O ícone ganha um disco branco: sobre o azul claro do cartão, um traço solto
   sumiria. */
.document__icon {
  flex: none;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-sm);
  background: var(--surface-raised);
  color: var(--brand-ink);
}

.document strong {
  display: block;
  color: var(--brand-ink);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-snug);
}

/* Seta de download à direita: diz que o clique baixa um arquivo, e não que
   navega para outra página. */
.document__arrow {
  position: absolute;
  inset-inline-end: var(--space-5);
  color: var(--brand-ink);
  opacity: .55;
  transition: translate var(--duration) var(--ease-out), opacity var(--duration-fast) var(--ease-out);
}

.document__meta {
  display: block;
  margin-block-start: var(--space-1);
  font-size: var(--text-sm);
  color: var(--text-muted);
}

/* O ebook é material institucional e o catálogo é do equipamento; o acento
   ciano separa os dois sem trocar a cor da marca. */
.document[data-kind=ebook] .document__icon { color: var(--o3-deep-600); }

/* --- Hero com fotografia ---------------------------------------------------
   O equipamento aparece em uso, dentro de um laboratório, com uma pessoa
   operando — que é como o brandbook manda apresentar equipamento: solução em
   contexto de aplicação, nunca objeto isolado sobre fundo neutro. */

.hero--figure { padding-block: clamp(var(--space-7), 6vw, var(--space-9)); }

.hero__grid {
  position: relative;
  z-index: 2;
  display: grid;
  /* 1.15/0.85 e não 1.05/0.95. A chamada mede 1434px em linha única a 56px;
     na coluna de 563px do split anterior ela precisava de 2,55 linhas e caía
     em 4, porque "O equipamento" sozinho consumia a primeira. Com 616px cai
     em 3, e a foto ainda fica com 456px — larga o bastante para reconhecer o
     equipamento. Alargar mais não tira a terceira linha, só encolhe a foto. */
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
  gap: clamp(var(--space-6), 5vw, var(--space-8));
  align-items: center;
}

.hero--figure .hero__inner { max-width: none; }

.hero__figure {
  position: relative;
  margin: 0;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--surface-raised);
  box-shadow: var(--shadow-lifted);
  /* O deslocamento do parallax é escrito nesta variável pelo script; o CSS
     decide o que fazer com ela. Sem JS, fica em zero e a composição segue
     correta. */
  translate: 0 var(--parallax, 0px);
  will-change: translate;

  /* Devolve o eixo vertical ao navegador e reserva o horizontal para o gesto
     de trocar slide. Sem isso, o arrasto no celular disputa com a rolagem da
     página, e a rolagem é o que o visitante quer fazer primeiro. */
  touch-action: pan-y;
}

/* Trilha horizontal, não pilha.
 *
 * Antes os slides ocupavam a mesma célula do grid e trocavam por esmaecimento.
 * Para o slide acompanhar o dedo, ele precisa existir ao lado do atual: dá
 * para esmaecer sem mover, mas não dá para mover sem estar lá.
 *
 * A trilha mantém a largura do contêiner e os itens transbordam dela, contidos
 * pelo overflow: hidden da moldura. É isso que faz `translate: -100%` valer
 * exatamente um slide, e não a largura somada dos quatro: a porcentagem se
 * resolve contra a largura do próprio elemento, que aqui continua sendo a da
 * moldura.
 *
 * --indice é o slide atual; --arrasto é o deslocamento em curso, em pixels,
 * escrito pelo script durante o gesto. Sem JavaScript ambos ficam em zero e o
 * primeiro slide aparece normalmente. */
.hero__slides {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  translate: calc(var(--indice, 0) * -100% + var(--arrasto, 0px)) 0;
  transition: translate var(--duration-slow) var(--ease-out);
  will-change: translate;
  /* Quadrada, e não 5:4.

     Com object-fit contain, a fração da moldura que a foto ocupa é
     min(r,R)/max(r,R), com r a proporção da foto e R a da moldura. As quatro
     fotos do carrossel são 0,75 (spray dryer), 1,0, 1,0 e 1,50 (skid de
     filtração), e nesse conjunto:

       5:4  média 76%, pior caso 60%
       1:1  média 85%, pior caso 67%

     O 5:4 tinha sido escolhido como meio-termo, mas cai justamente no vão
     entre o retrato e a paisagem e não favorece nenhuma das duas. O quadrado
     também melhora onde mais importa: o spray dryer é o primeiro slide, o que
     a maioria das visitas vê, e vai de 60% para 75%.

     Não custa altura: a coluna de texto do hero é mais alta que a figura e a
     grade centraliza, então a moldura cresce dentro de espaço que já existia. */
  aspect-ratio: 1 / 1;
}

/* Cada slide ocupa a moldura inteira e o seguinte espera fora dela, à direita.
   Sem JavaScript a trilha fica em zero e o primeiro slide aparece; os demais
   ficam além da borda, cortados pelo overflow da moldura. */
.hero__slide {
  position: relative;
  flex: 0 0 100%;
  /* min-height: 0 impede que o item cresça até a altura intrínseca da imagem;
     sem isso uma foto em retrato estica a moldura inteira. */
  min-height: 0;
  overflow: hidden;
  /* Só o slide da vez recebe clique. Os vizinhos aparecem durante o arrasto,
     mas tocar num deles não deve navegar para a categoria dele. */
  pointer-events: none;
}
.hero__slide[data-active="true"] { pointer-events: auto; }

/* Durante o gesto a trilha segue o dedo sem suavização: qualquer transição
   aqui vira atraso entre o dedo e a imagem, que é exatamente a sensação que o
   arrasto existe para eliminar. */
.hero__slides[data-arrastando="true"] { transition: none; }

/* Quem pediu menos movimento troca de slide sem o deslizamento. */
@media (prefers-reduced-motion: reduce) {
  .hero__slides { transition: none; }
}

.hero__slide-link {
  position: absolute;
  inset: 0;
  display: block;
  text-decoration: none;
}

/* O arrasto nativo de imagem do navegador competia com o gesto de trocar
   slide: no desktop, puxar a foto começava a arrastar o arquivo. */
.hero__slide img {
  width: 100%;
  height: 100%;
  user-select: none;
  -webkit-user-drag: none;
}

/* Cena de laboratório preenche a moldura; recorte em fundo branco respira
   dentro dela, sobre um campo azul muito claro que evita o branco chapado. */
.hero__slide img[data-fit="cover"] { object-fit: cover; scale: 1.06; }
/* O respiro em volta do recorte foi de 32/32/64 para 20/20/56. Numa moldura de
   456px, 32px de cada lado consumiam 14% da largura antes de a foto começar —
   e a foto já perdia área para a diferença de proporção. O padding de baixo
   segue maior que os outros porque é ali que a legenda entra. */
.hero__slide img[data-fit="contain"] {
  object-fit: contain;
  padding: var(--space-5) var(--space-5) var(--space-7);
  background: linear-gradient(160deg, var(--o3-deep-050), var(--surface-raised) 70%);
}

.hero__slide-caption {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  /* Acima da foto, sempre. Fica explícito porque já custou uma vez: quando a
     imagem ganhou z-index para se posicionar numa camada, passou a cobrir o
     nome do equipamento. O nome não é decoração da foto, é o dado. */
  z-index: 2;
  padding: var(--space-7) var(--space-5) var(--space-5);
  /* O véu precisa estar escuro ONDE O TEXTO ESTÁ, não só no rodapé.
   *
   * O gradiente anterior ia de transparente a 0,88 ao longo de toda a altura,
   * e o texto fica a 49% e 70% dela — onde a opacidade ainda era baixa. Com as
   * quatro fotos atuais, que são recortes claros, o composto ficava claro e o
   * contraste caía a 2,89:1 no nome e 3,64:1 na linha de apoio, contra os
   * 4,5:1 da WCAG AA. Funcionava quando a foto era escura; parou de funcionar
   * quando padronizamos os recortes.
   *
   * Agora chega a 0,88 aos 45% e segue subindo, o que põe os dois textos em
   * faixa escura e mantém o topo suave para não virar barra sólida sobre a
   * foto. Calculado para o pior caso: fundo claro (#F2F5F8) atrás. */
  background: linear-gradient(180deg,
    transparent 0%,
    rgba(1, 30, 72, 0.55) 22%,
    rgba(1, 30, 72, 0.88) 45%,
    rgba(1, 30, 72, 0.94) 100%);
  color: var(--o3-white);
}
.hero__slide-caption strong {
  display: block;
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-title);
}
.hero__slide-caption > span {
  font-size: var(--text-sm);
  color: var(--text-muted-on-inverse);
}

/* Os controles ganham chão próprio.
 *
 * Ponto branco sobre o fundo claro do recorte rende 1,14:1 — existe, mas o
 * olho não acha. O desenho original supunha foto escura preenchendo a moldura;
 * as quatro fotos atuais são recorte sobre gradiente quase branco.
 *
 * Colorir o ponto de azul resolveria hoje e quebraria na primeira foto escura
 * que entrasse no carrossel. A pastilha translúcida resolve para os dois casos:
 * o controle passa a ter fundo próprio, independente do que está atrás. */
.hero__dots {
  position: absolute;
  inset-block-start: var(--space-4);
  inset-inline-end: var(--space-4);
  display: flex;
  align-items: center;
  gap: var(--space-1);
  padding-inline: var(--space-2);
  border-radius: var(--radius-pill);
  background: rgba(1, 30, 72, 0.62);
}

@supports (backdrop-filter: blur(6px)) {
  .hero__dots {
    background: rgba(1, 30, 72, 0.42);
    backdrop-filter: blur(6px) saturate(140%);
  }
}

.hero__dot {
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  cursor: pointer;
}
/* O alvo tem 32px para o dedo, mas o ponto desenhado tem 8px.
   `content` vazio é obrigatório: sem ele o ::before não é gerado, e a regra
   estava escrita como `content: ;`, declaração inválida. O resultado eram
   quatro alvos de 32px invisíveis no canto da imagem — ninguém tinha como
   saber que o carrossel tem quatro slides, nem como chegar aos outros três. */
.hero__dot::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--o3-white);
  opacity: .5;
  box-shadow: 0 1px 3px rgba(1, 30, 72, .5);
  transition: opacity var(--duration-fast) var(--ease-out),
              width var(--duration) var(--ease-out);
}
.hero__dot[aria-current=true]::before { opacity: 1; width: 22px; }
.hero__dot:hover::before { opacity: .85; }

/* Botão de pausa: mesmo alvo de 32px dos pontos, na mesma linha, para não
   abrir um segundo lugar de controle na imagem. Ícone branco sobre a foto,
   com a mesma sombra dos pontos porque cai sobre fundo imprevisível. */
.hero__pause {
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--o3-white);
  opacity: .55;
  cursor: pointer;
  filter: drop-shadow(0 1px 3px rgba(1, 30, 72, .5));
  transition: opacity var(--duration-fast) var(--ease-out);
}
.hero__pause:hover, .hero__pause:focus-visible { opacity: 1; }

/* Anel de duas cores nos controles do carrossel.
 *
 * Aqui nenhuma cor única resolve. O alvo tem 32px e o anel sai a 2px dele, de
 * modo que ele cruza a borda da pastilha escura e cai também sobre a foto, que
 * é clara e muda a cada slide. Deep Blue sumiria na pastilha; Bright Blue
 * sumiria na foto.
 *
 * Branco em 2–4px e Deep Blue em 4–6px: sobre a pastilha o branco aparece,
 * sobre a foto clara o azul aparece, e em qualquer fundo intermediário pelo
 * menos um dos dois contrasta. É o mesmo raciocínio da pastilha translúcida
 * dos controles — não depender do que estiver atrás. */
.hero__dot:focus-visible, .hero__pause:focus-visible {
  outline: 2px solid var(--o3-white);
  outline-offset: 2px;
  box-shadow: 0 0 0 6px var(--o3-deep);
}

/* Duas barras enquanto roda, seta enquanto pausado. Um ícone só, dois estados,
   sem trocar o SVG por script. */
.hero__pause[data-estado="rodando"] .hero__pause-seta { display: none; }
.hero__pause[data-estado="pausado"] .hero__pause-barra { display: none; }

@media (max-width: 900px) {
  .hero__grid { grid-template-columns: minmax(0, 1fr); }

  /* A foto vinha primeiro no celular, com a justificativa de que ela explicaria
     o que a empresa vende antes de qualquer linha de texto. A execução não
     sustentava o argumento: o carrossel mostra UM item rotativo de um catálogo
     de 133, então o visitante via um Mini Spray Dryer sem contexto e a proposta
     da empresa só aparecia a 425px de rolagem. Medido em 375x812, a foto na
     frente empurrava os dois botões para 1024px, muito abaixo da dobra; com o
     título na frente eles terminam em 724px, dentro da tela.

     Efeito colateral bom: o LCP deixa de ser a imagem do carrossel e passa a
     ser o texto do título. */
  .hero__mark { display: none; }
}

/* --- Ficha em matriz -------------------------------------------------------
   Uma coluna por modelo, com células mescladas onde o valor se repete. É como
   o comprador compara: lendo a linha inteira de uma vez, não célula a célula. */

.table-scroll {
  overflow-x: auto;
  margin-block-start: var(--space-4);
  /* Sombra que aparece só quando há conteúdo cortado à direita, avisando que
     a tabela continua. */
  background:
    linear-gradient(90deg, var(--surface-raised) 30%, transparent),
    linear-gradient(90deg, transparent, var(--surface-raised) 70%) 100% 0,
    radial-gradient(farthest-side at 0 50%, rgba(1, 53, 123, .14), transparent),
    radial-gradient(farthest-side at 100% 50%, rgba(1, 53, 123, .14), transparent) 100% 0;
  background-repeat: no-repeat;
  background-size: 40px 100%, 40px 100%, 14px 100%, 14px 100%;
  background-attachment: local, local, scroll, scroll;
}

.spec-sheet--matrix {
  /* table-layout fixed é o que resolve a distribuição: no modo automático, uma
     célula mesclada puxa largura para si e as colunas finais ficam espremidas
     — o SF9012 saía com metade do espaço do SF7009. No modo fixo, a grade é
     definida pelo cabeçalho e o colspan apenas ocupa colunas já dimensionadas. */
  table-layout: fixed;
  width: 100%;
  /* Largura mínima proporcional ao número de modelos, informada pelo template:
     a coluna de rótulo mais uma faixa confortável por coluna de valor. */
  min-width: calc(16rem + var(--cols, 3) * 7.5rem);
  background: var(--surface-raised);
}

/* A coluna de rótulos tem largura própria; as de valor dividem o resto em
   partes iguais, que é o que faz a tabela ficar regular. */
.spec-sheet--matrix thead th:first-child,
.spec-sheet--matrix tbody th { width: 16rem; }

.spec-sheet--matrix thead th {
  background: var(--surface);
  vertical-align: middle;
  color: var(--text);
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-title);
  text-transform: none;
  border-block-end: 1px solid var(--line-strong);
  white-space: nowrap;
}

.spec-sheet--matrix th,
.spec-sheet--matrix td {
  padding: var(--space-4);
  border-block-end: 1px solid var(--line);
  /* Valor curto centrado na altura da linha; o rótulo acompanha. Alinhar ao
     topo deixava linhas de duas alturas com o número solto no alto. */
  vertical-align: middle;
  text-align: start;
  /* Texto longo quebra dentro da célula em vez de alargar a coluna. */
  overflow-wrap: break-word;
  hyphens: auto;
}

/* A coluna de rótulos é a âncora da leitura: fica fixa na rolagem horizontal
   para o nome do parâmetro não sumir quando o comprador compara o quarto
   modelo. */
.spec-sheet--matrix tbody th {
  position: sticky;
  inset-inline-start: 0;
  width: 15rem;
  background: var(--surface-raised);
  font-weight: var(--weight-medium);
  color: var(--text);
  border-inline-end: 1px solid var(--line);
}

.spec-sheet--matrix tbody td {
  color: var(--text-muted);
  /* Célula mesclada ganha uma tinta muito leve, para o olho perceber que
     aquele valor cobre mais de um modelo. */
  border-inline-end: 1px solid var(--line);
}
.spec-sheet--matrix tbody td[colspan] { background: var(--surface); color: var(--text); }
.spec-sheet--matrix tbody td:last-child { border-inline-end: 0; }
.spec-sheet--matrix tbody tr:last-child th,
.spec-sheet--matrix tbody tr:last-child td { border-block-end: 0; }

/* Campo-armadilha do formulário de orçamento. Sai do fluxo sem usar
   display:none — alguns robôs ignoram campos ocultos por display, mas
   preenchem os que continuam no DOM com posição fora da tela. */
.trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* --- Publicações científicas -----------------------------------------------
   Tabela longa: 106 linhas de literatura indexada. O que a torna utilizável
   não é o estilo, é o filtro — e o cabeçalho que permanece visível enquanto
   se rola, sem o qual a coluna deixa de ter significado na metade da lista. */
.pub__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  align-items: center;
  justify-content: space-between;
  margin-block-start: var(--space-6);
}

.pub__meta .input { max-width: 26rem; }

.pub__tabela {
  margin-block-start: var(--space-5);
  overflow-x: auto;
}

.pub-table { width: 100%; font-size: var(--text-sm); }

.pub-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--surface-raised);
  box-shadow: 0 1px 0 var(--border);
}

/* A coluna do título carrega o peso da linha; as de classificação são
   estreitas e não devem quebrar palavra. */
.pub-table td:nth-child(1),
.pub-table td:nth-child(2) { white-space: nowrap; color: var(--text-muted); }
.pub-table td:nth-child(3) { min-width: 22rem; }

.pub__ano {
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.pub__link { text-align: center; }

.pub__link a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: var(--radius-sm);
  color: var(--o3-deep);
  transition: background-color .15s ease, color .15s ease;
}

/* O realce é o fundo, não a tinta. Antes o texto virava azul vibrante sobre
   superfície clara — 2,46:1, abaixo dos 4,5:1 da WCAG 1.4.3 — de modo que
   apontar o mouse ou chegar pelo teclado deixava o link menos legível, e não
   mais. A tinta da marca fica onde já estava, a 10,89:1. */
.pub__link a:hover,
.pub__link a:focus-visible { background: var(--surface-sunken); color: var(--brand-ink); }

.pub__nota {
  margin-block-start: var(--space-5);
  font-size: var(--text-sm);
  color: var(--text-muted);
}

@media (max-width: 760px) {
  .pub-table td:nth-child(2) { display: none; }
  .pub-table thead th:nth-child(2) { display: none; }
}

/* Explicação de expansão por sinônimo, na página de busca.
   Aparece quando o resultado veio de um termo que o visitante não digitou —
   buscar "liofilização" e receber "Liofilizador" parece acaso sem esta linha. */
.search__expansao {
  margin-block-start: var(--space-2);
  font-size: var(--text-sm);
  color: var(--text-muted);
}

/* --- Problema de laboratório ---------------------------------------------
   A tese do site é "catálogo por problema", e até aqui o problema era
   renderizado no mesmo componente do índice de artigos: mesmo tamanho, mesmo
   peso, mesma seta. "Preciso secar um extrato sem degradar o princípio ativo"
   e "Misturador centrífugo assimétrico" tinham exatamente a mesma aparência,
   e a ideia que diferencia o site não chegava à retina de ninguém.

   A forma vem da ficha de ensaio, que é o único componente autoral do
   projeto: rótulo técnico em caixa alta, a pergunta em corpo grande, e abaixo
   dela pares rótulo/valor separados por linha de 1px. É o .spec-sheet
   aplicado a um problema em vez de a um equipamento. */

.lab-problem {
  display: block;
  padding: var(--space-6);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-raised);
  color: inherit;
  text-decoration: none;
  transition: border-color var(--duration-fast) var(--ease-out),
              box-shadow var(--duration) var(--ease-out);
}
.lab-problem:hover {
  border-color: var(--line-strong);
  box-shadow: var(--shadow-raised);
  text-decoration: none;
}

.lab-problem__setor {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-muted);
}

.lab-problem__pergunta {
  display: block;
  margin-block-start: var(--space-3);
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-title);
  color: var(--text);
  text-wrap: pretty;
}

/* Os pares rótulo/valor. Grid de duas colunas com a linha entre eles, igual
   ao corpo de uma ficha técnica. */
.lab-problem__ficha {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: var(--space-2) var(--space-5);
  margin: 0;
  margin-block-start: var(--space-5);
  padding-block-start: var(--space-4);
  border-block-start: 1px solid var(--line);
}
.lab-problem__ficha dt {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-muted);
}
.lab-problem__ficha dd {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--text);
}

.lab-problem-list {
  display: grid;
  gap: var(--space-5);
  grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
}

@media (max-width: 600px) {
  .lab-problem__ficha { grid-template-columns: minmax(0, 1fr); gap: var(--space-1); }
  .lab-problem__ficha dd { margin-block-end: var(--space-2); }
}
