/* css/home.css — só o que é da home e não do sistema.

   O sistema desenha .cromo, .heroi, .ficha, .medidor, .video, .tema, .papel.
   Aqui moram as grades que arranjam essas peças na página, o reflow das
   quatro faixas, e o punhado de coisas que a home tem e o pacote não: o
   pular-para-o-conteúdo, o painel compacto do menu e o pictograma em <use>. */

.ico { width: 1em; height: 1em; flex: none; }

/* .cromo__marca virou <a href="/"> (achado 3, rodada 1) — no kit nada linka
   de verdade (os elos são href="#" com preventDefault), então o <span>
   original era artefato de protótipo, não decisão de design. .sitio a
   (elementos-sitio.css) tem a mesma especificidade e vem antes na cascata,
   então sem isto o link herdava cor de sinal e perdia a cor de tinta cheia
   que .cromo__marca declara — a aparência mudaria. Trava aqui, depois da
   folha do sistema, pra manter idêntico ao que era quando span. */
a.cromo__marca,
a.cromo__marca:hover {
  color: var(--sitio-tinta-cheia);
  text-decoration: none;
}

.sitio__pular {
  position: absolute;
  left: -9999px;
}
.sitio__pular:focus {
  position: fixed;
  left: 16px;
  top: 16px;
  z-index: 100;
  padding: 12px 16px;
  border-radius: var(--sitio-raio-fino);
  background: var(--sitio-sinal);
  color: var(--sobre-sinal);
}

/* ── O menu compacto ────────────────────────────────────── */

/* Acima do breakpoint o botão não existe e o painel é transparente ao layout:
   nav e fim voltam a ser filhos diretos do cromo. */
.cromo__compacto { display: none; }
.cromo__menu { display: contents; }

/* O ícone de hambúrguer não existe em assets/icones.svg (22 símbolos, nenhum
   "menu"), e acrescentar um símbolo novo ao sprite é escopo maior (passa por
   scripts/baixar_icones.py). Três traços em CSS puro: o miolo é o
   background do próprio span, os outros dois são pseudo-elementos
   posicionados em cima e embaixo. Sem isto o botão existe, é clicável, tem
   aria-label — e não mostra nada (achado 1, rodada 1). */
.cromo__compacto {
  width: 44px;
  height: 44px;
  border: 1px solid var(--sitio-traco-forte);
  border-radius: var(--sitio-raio-fino);
  background-color: var(--sitio-superficie);
  cursor: pointer;
  transition: border-color var(--t-toque) var(--e-entrada);
}
.cromo__compacto:hover { border-color: var(--sitio-tinta-fraca); }

.cromo__compacto-icone,
.cromo__compacto-icone::before,
.cromo__compacto-icone::after {
  content: "";
  display: block;
  width: 18px;
  height: 2px;
  border-radius: 1px;
  background-color: var(--sitio-tinta-cheia);
  transition: transform var(--t-toque) var(--e-entrada), opacity var(--t-toque) var(--e-entrada), top var(--t-toque) var(--e-entrada);
}
.cromo__compacto-icone { position: relative; }
.cromo__compacto-icone::before,
.cromo__compacto-icone::after { position: absolute; left: 0; }
.cromo__compacto-icone::before { top: -6px; }
.cromo__compacto-icone::after { top: 6px; }

/* Painel aberto: os dois traços de fora viram um X, o do meio some. */
.cromo__compacto[aria-expanded="true"] .cromo__compacto-icone {
  background-color: transparent;
}
.cromo__compacto[aria-expanded="true"] .cromo__compacto-icone::before {
  top: 0;
  transform: rotate(45deg);
}
.cromo__compacto[aria-expanded="true"] .cromo__compacto-icone::after {
  top: 0;
  transform: rotate(-45deg);
}

@media (max-width: 1180px) {
  .cromo__compacto { display: grid; place-items: center; margin-inline-start: auto; flex: none; }
  .cromo__menu {
    display: none;
    position: absolute;
    inset-inline: 0;
    top: var(--sitio-cromo-altura);
    /* --sitio-sangria vive em sitio-web.css (:root, 32px acima de 680px,
       20px abaixo) — sem fallback aqui de propósito, pra não voltar a
       mascarar o token não existir num escopo por acidente. */
    padding: 16px var(--sitio-sangria) 24px;
    background: var(--sitio-cromo);
    border-block: 1px solid var(--sitio-traco);
    box-shadow: var(--sitio-relevo);
    max-height: calc(100dvh - var(--sitio-cromo-altura));
    overflow-y: auto;
    overscroll-behavior-y: contain;
  }
  .cromo__menu.is-open { display: grid; gap: 16px; }
  .cromo__nav { display: grid; gap: 4px; margin-left: 0; }
  .cromo__elo { display: flex; align-items: center; min-height: 44px; }
}

/* ── As faixas ──────────────────────────────────────────── */

/* .heroi__texto::before e .retrato::before (elementos-sitio.css) são glows
   decorativos com inset negativo — sangram de propósito além da borda dos
   dois blocos. .sitio tem overflow:hidden, mas overflow em <body> só
   propaga pro viewport (spec de overflow propagation): o scroll não
   aparece, mas document.documentElement.scrollWidth cresce do mesmo jeito,
   e é isso que test_nao_rola_na_horizontal mede. Corta na .faixa — só no
   eixo horizontal, o sangramento vertical do glow continua de propósito.

   ESTE CORTE É SÓ PRA BRILHO, NUNCA PRA CONTEÚDO (achado 1, rodada 1: ele
   escondeu 61px de .heroi__deck cortado no meio da palavra, e a suíte
   ficava verde do mesmo jeito — "sem rolagem" não é "cabe"). A causa do
   estouro de conteúdo era outra, corrigida abaixo (minmax(0, 1fr)); com o
   conteúdo já cabendo, confirmado sem este overflow-x que o único motivo
   pra ele continuar aqui é o sangramento dos ::before — TestSemClip prova
   que nenhum seletor de conteúdo chega perto da borda que ele corta. */
.faixa { overflow-x: hidden; }

/* Task 28, mudança 3: a foto do retrato trocou de fechada/vertical (720×900,
   4:5) pra um plano largo de estúdio (16:9) — o dono entregou o arquivo
   certo; a prancha original (~/design-system/uploads/website-1.png) sempre
   quis isto: foto larga preenchendo o resto da linha do herói, não um
   cartão de retrato ao lado. O remendo fechado era falta de material, não
   decisão de design.

   .heroi (elementos-sitio.css) tinha a trilha do retrato FIXA em 420px
   (minmax(0,420px)) e a do texto FLEXÍVEL (1fr) — o oposto do que a foto
   nova pede. Invertido aqui: o texto (que já tem max-width:560px próprio,
   elementos-sitio.css) vira a trilha travada — 560px é teto suficiente,
   não precisa de mais — e o retrato vira 1fr, ocupando o resto da linha.
   Medido nas larguras do contrato: a foto vai de ~444px (1180px, a borda
   de baixo antes do grid empilhar) a ~704px (1440px+, onde .heroi trava —
   mudança 1 acima nesta mesma Task). Não sangra até a borda do viewport
   como a prancha sugere numa tela ultralarga: mudança 1 já decidiu que o
   CONTEÚDO do herói (texto + retrato, o par inteiro) trava e centra em
   1440 enquanto só o campo sangra — estender esse mesmo raciocínio ao
   retrato (ele também é "conteúdo do herói") evita reabrir uma decisão já
   tomada, e evita o grid precisar de um segundo breakout dentro do
   primeiro. As duas colunas ficam lado a lado com o gap de 48px de sempre
   — SEM sobrepor o texto (grid normal, sem posicionamento absoluto), então
   o glow de legibilidade que .heroi__texto::before já desenha (achado
   pré-existente, pensado pra exatamente este caso) segue sendo suficiente:
   medido, a manchete e o deck nunca ficam sobre pixel nenhum da foto —
   TestSemClip mede as bordas dos dois blocos, e eles não se tocam. */
.heroi { grid-template-columns: minmax(0, 560px) minmax(0, 1fr); }

/* Task 29 (2026-08-14): o dono entregou um recorte de verdade — PNG com
   alfa, sem fundo, 2120×2096 (do peito pra cima, quase quadrado). O
   comentário que já morava em .retrato__quadro (elementos-sitio.css,
   intocável) previa exatamente este dia: "SEM RECORTE FALSO... quando
   chegar um recorte de verdade, basta trocar a máscara por nada." A foto
   de estúdio 16:9 era montada com mask-image (dissolvia as quatro bordas
   pra imitar um recorte) porque o material disponível até ontem era uma
   foto de ambiente, com fundo — o Task 28 documentou isso como "remendo
   fechado por falta de material", não decisão de design.

   As três correções são as três que o mask-image fazia por conta própria
   e agora atrapalham: aspect-ratio (16:9 forçava widescreen; o recorte tem
   a proporção DELE, quase quadrada — forçar 16:9 nele cortaria ombro),
   mask-image (dissolvia bordas de uma foto opaca; o alfa do PNG já FAZ
   esse trabalho, um segundo dissolve por cima cortaria pedaço da silhueta
   perto da borda) e object-fit (cover cortava a foto pra caber na caixa;
   com aspect-ratio batendo a proporção real do arquivo, contain não corta
   nada — a caixa e a imagem têm a mesma forma).

   .retrato__quadro deixa de ser MOLDURA (caixa que recorta/dissolve uma
   foto retangular) e vira só o SLOT que dá à imagem a largura da coluna e
   a altura que a proporção real dela pede — sem borda ou raio próprios
   (nunca teve; conferido no elementos-sitio.css), então não sobra nenhuma
   borda RETA em volta da silhueta. */
.retrato__quadro {
  aspect-ratio: 2120 / 2096;
  -webkit-mask-image: none;
  mask-image: none;
}
.retrato__quadro img { object-fit: contain; object-position: 50% 100%; }

/* MEDIDO (screenshot real a 1440px, pixel a pixel, fórmula WCAG de
   luminância — a mesma de tests/test_home_contrato.py — comparando o
   pixel da silhueta contra o pixel de --sitio-fundo puro):
     ombro esquerdo   rgb(39,31,27)  contra --sitio-fundo  → 1.24:1
     ombro direito    rgb(35,30,32)  contra --sitio-fundo  → 1.22:1
     topo da cabeça   rgb(57,46,44)  contra --sitio-fundo  → 1.53:1
   Por essa régua (que é a régua de TEXTO, feita pra tipografia — não existe
   uma equivalente oficial pra silhueta fotográfica) os três números são
   baixos; a camiseta preta é só um pouco menos escura que o #04080c do
   fundo, e nenhum gradiente razoável muda MUITO esse número: o alfa do
   recorte é um CONE (estreito na cabeça, quase encostando nas duas bordas
   do quadro na altura do ombro) — testei um raio pequeno (62%) primeiro e
   um grande (88%/92%, o que ficou) depois, e a leitura
   nos dois pontos que importam nem chegou a se mover: na altura do
   ombro/braço a margem transparente ao lado da silhueta é fina demais pra
   qualquer aura CSS caber nela sem também acender os quatro cantos vazios
   da caixa.

   O que realmente separa a silhueta — CONFERIDO EM RECORTE AMPLIADO
   (crop_left_shoulder.png/crop_right_shoulder.png/crop_head.png, gerados
   durante esta task) — não é luminância média, é BORDA: a grade do campo
   reativo (.sitio__grade, quadriculado visível atrás) muda de padrão bem
   onde a manga do recorte termina, e o próprio recorte já vem com luz de
   borda (rim light) da sessão de foto original — visível como um contorno
   mais claro na manga e no cabelo. O olho lê a DESCONTINUIDADE de textura
   e o contorno iluminado, não a média de cinza — por isso a composição
   "funciona" como o dono descreveu, apesar do número WCAG baixo.

   --sitio-emissao (o halo âmbar do kit) foi cogitado e descartado: é
   box-shadow reto, desenharia RETÂNGULO atrás de uma silhueta — o defeito
   que este Task inteiro existe pra evitar. Em vez dele, um gradiente
   radial PRÓPRIO, pequeno mas real: não resolve o pior caso (ombro rente
   à borda), mas suaviza a faixa um pouco mais afastada da silhueta —
   --sitio-superficie-alta (#0d141b) é o tom "superfície elevada" do
   próprio kit, não decoração nova. Contido bem dentro do slot (90% de
   alcance, nunca chega nos 100% da borda, e o alfa do PNG já é zero nos
   quatro cantos) — sem isso o retângulo do gradiente ficaria visível
   encostando na moldura que acabou de sumir. Ancorado em 50% 58%, não
   50% 50%: a faixa que mais precisa de reforço (ombro) fica abaixo do
   centro geométrico da caixa, que cai na altura do peito/cabeça.

   Conclusão medida: a separação depende principalmente da GRADE atrás
   (já existe, sem mudança) e da luz de borda do recorte (já existe, vem
   do arquivo) — não deste gradiente, que é reforço marginal, não a
   correção. Se um redesign algum dia trocar a grade por um fundo liso, a
   silhueta perde a borda que hoje a separa e este comentário — não o
   número WCAG sozinho — é o aviso de por quê. */
.retrato__quadro {
  background: radial-gradient(88% 92% at 50% 58%,
    color-mix(in srgb, var(--sitio-superficie-alta) 55%, transparent) 0%,
    color-mix(in srgb, var(--sitio-superficie-alta) 24%, transparent) 55%,
    transparent 90%);
}

/* O recorte é mais alto que a foto 16:9 que ele substitui (quase quadrado
   contra widescreen) — .retrato tinha align-items:center (elementos-
   sitio.css), pensado pra centrar uma faixa curta dentro da coluna. Com a
   figura ocupando quase toda a altura da coluna, centrar sobra em cima e
   embaixo em proporções desiguais (a cabeça tem mais “ar” que os pés no
   recorte original); alinhar embaixo planta a figura no piso da coluna —
   a leitura de "emergindo do escuro" que o dono descreveu, e a mesma borda
   inferior que a prancha original mostra a foto tocando. */
.retrato { align-items: end; }

/* Abaixo de 1180px o grid de .heroi empilha numa trilha só (regra logo
   acima, "minmax(0, 1fr)") e .retrato passa a valer a LARGURA INTEIRA da
   coluna — 1052px a 1180px, por exemplo. Com o recorte quase quadrado
   (2120/2096), largura assim dá uma imagem de ~1039px de altura: a figura
   sozinha dominaria a dobra inteira, texto incluso, o oposto de "presença
   clara sem exagero". A foto 16:9 antiga nunca bateu nesse teto (largura
   1052px só dava ~592px de altura), por isso a coluna nunca precisou de
   limite antes deste recorte.

   min(320px, 100%): mesma largura do breakpoint stacked até 1180px pra
   375px — 320px de figura mede uns 308px de alto, presença de retrato
   fotográfico, não pôster. O 100% do min() é rede de segurança pra uma
   faixa mais estreita que 320px (não existe na malha hoje, mas não custa).
   Encolhe o PRÓPRIO .retrato, não só .retrato__quadro. O motivo original
   era a legenda: `.retrato__cota` ("ViktorKav") era irmã de
   `.retrato__quadro`, não filha, e o right:8%/bottom:14% dela
   (elementos-sitio.css) resolvia contra a caixa de quem tem position:
   relative mais próximo — `.retrato`, não o quadro. Encolher só o quadro
   deixava `.retrato` do tamanho antigo e a legenda flutuava ao lado da
   foto em vez de sobre o canto dela (achado, medido a 1180px).

   A legenda foi removida a pedido do dono, então esse motivo caducou — mas
   a regra fica, porque continua sendo ela que dá à figura a largura de
   retrato fotográfico abaixo de 1180px. `justify-self:center` centra o ITEM
   de grid dentro da trilha, e `.retrato__quadro` segue width:100%
   (elementos-sitio.css) sem override próprio, porque 100% do pai já é a
   largura pequena certa. */
@media (max-width: 1180px) {
  .retrato { width: min(320px, 100%); justify-self: center; }

  /* `min-height: 420px` vem do pacote (elementos-sitio.css), calibrado pra
     coluna de desktop, onde o retrato divide a linha com o texto e precisa de
     corpo. Empilhado, ele vira vão: medido a 390px, `.retrato` media 420px de
     altura com a imagem ocupando só 259 — **161px de nada** entre o texto e a
     figura.
     O preço disso era a primeira tela inteira: o rosto começava em y=831 numa
     janela de 844 (13px dele apareciam), e a busca — a peça mais original da
     página — só em y=1122, uma tela e meia abaixo. */
  .retrato { min-height: 0; }
}

/* No celular o herói também respirava demais pra cima e pra baixo: 48px de
   padding no topo da faixa, 48px de vão da grade e mais 48px de padding no pé
   do texto, somando quase uma tela de folga antes de a figura começar. Com a
   coluna empilhada, esse respiro não separa nada — ele só empurra o conteúdo
   pra fora da dobra. */
@media (max-width: 680px) {
  /* A prancha deixava 64px de cada lado do herói e somava 24px internos
     às margens das seções. Uma única margem de 20px devolve área de leitura
     e alinha marca, apresentação e conteúdo no celular. */
  .cromo__miolo { padding-inline: var(--sitio-sangria); }
  .sitio__miolo { padding-inline: 0; }
  .heroi { padding: 32px var(--sitio-sangria) 0; gap: 20px; min-height: 0; }
  .heroi__texto { padding-bottom: 0; }
  .heroi__manchete { font-size: clamp(36px, 9.7vw, 52px); line-height: 1.08; }
  .heroi__deck { margin-top: 20px; }
  .heroi__acoes { margin-top: 24px; }
  .heroi__acoes .acao { flex: 1 1 150px; justify-content: center; padding-inline: 12px; font-size: 14px; }
  .heroi__linha { margin-top: 24px; }
  .retrato { width: min(260px, 100%); }
  /* A cota é decorativa e, nesta largura, encostava no rótulo Apresentação. */
  .campo__cota { display: none; }
}

/* minmax(0, 1fr), não "1fr" puro: um item de grid tem min-width:auto por
   padrão, então mesmo com uma trilha só e "1fr" o item não encolhe abaixo do
   seu conteúdo (texto sem quebra, imagem) — ele estoura a trilha e a própria
   .heroi por baixo, embora a caixa de .heroi em si meça certo (achado 1,
   rodada 1: 61px de conteúdo cortado a 390px, escondido pelo overflow-x da
   .faixa). minmax(0, ...) é o mesmo padrão que a trilha do retrato no
   desktop já usa (560px/1fr, mudança 3 acima) — zera o mínimo automático da
   trilha e força o item a caber. */
@media (max-width: 1180px) {
  .heroi { grid-template-columns: minmax(0, 1fr); }
}

/* ── Task 30 — a busca vira um container só ──────────────── */

/* elementos-sitio.css desenha .busca como grade de duas trilhas
   (minmax(0,1fr) 320px) — a caixa do prompt e o <aside class="prompt painel">
   ao lado. O painel saiu inteiro (o pedido do dono: era coluna quase vazia,
   com três números, e o botão "Ver todo o acervo" se sobrepunha ao "Reindexado
   há N h" no canto apertado). Sobrou uma coluna só, em qualquer largura — e
   por isso o override é incondicional, não mais dentro do @media 1180.
   O gap agora separa a caixa do prompt do trilho de cards abaixo dela. */
.busca { grid-template-columns: minmax(0, 1fr); gap: 20px; }

/* O envio é uma ação nativa do form, compartilhada com Enter. A grade
   reserva o botão sem comprimir o campo; nenhuma mudança no motor da busca. */
.busca__caixa .prompt__campo {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
}
.busca__caixa .prompt__entrada { width: 100%; min-width: 0; font-size: 16px; min-height: 44px; }
.busca__caixa .prompt__entrada::placeholder { color: var(--sitio-tinta-secundaria); }
.busca__enviar { font-size: 14px; padding-inline: 16px; }
.busca__escopo {
  margin: 10px 0 0;
  font-size: 13px;
  line-height: 20px;
  color: var(--sitio-tinta-secundaria);
}
.busca__caixa:focus-within { border-color: var(--sitio-sinal); }

.heroi__manchete, .secao__titulo { text-wrap: balance; }
.secao__deck { max-width: 68ch; text-wrap: pretty; }

/* O teclado realça o mesmo cartão que o ponteiro já encontra por inteiro. */
#projetos .ficha:has(a:focus-visible),
.video:has(a:focus-visible),
.peca--todas:focus-visible { outline: 2px solid var(--sitio-sinal); outline-offset: -2px; }
.cromo :is(a, button):focus-visible,
.busca :is(a, button):focus-visible {
  outline: 2px solid var(--sitio-sinal);
  outline-offset: 3px;
}

/* A barra de estado, no rodapé da caixa da busca. A sobreposição de hoje
   nasce de a idade do índice e o link do acervo disputarem um canto de 320px
   de largura; uma linha flex com wrap e gap de verdade é a correção — os dois
   grupos afastam-se com space-between enquanto couberem lado a lado, e caem
   em linhas próprias quando não couberem, sem nunca se encostar. */
.busca__estado {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 24px;
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--sitio-traco);
}
.busca__contagens { display: flex; flex-wrap: wrap; gap: 6px 18px; }
.busca__fim { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; }

/* Mesma voz das antigas .painel__linha (elementos-sitio.css): monoespaçada,
   número em tinta cheia e tabular pra não dançar quando a contagem muda. */
.busca__conta {
  font-family: var(--voz-sistema);
  font-size: 12px;
  line-height: 22px;
  color: var(--sitio-tinta-secundaria);
}
.busca__conta b {
  font-weight: 400;
  color: var(--sitio-tinta-cheia);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 680px) {
  /* elementos-sitio.css declara .prompt__sugestoes flex-wrap:wrap — sem
     nowrap aqui os cinco chips quebram linha em vez de rolar, e
     overflow-x:auto nunca dispara porque depois de quebrar tudo já cabe
     (medido: a 390px os cinco chips empilhavam em cinco linhas cheias, sem
     rolagem nenhuma — Task 6, achado por medição, não por raciocínio). */
  .prompt__sugestoes {
    display: flex;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .prompt__sugestoes::-webkit-scrollbar { display: none; }

  /* .heroi__acoes é flex sem wrap (elementos-sitio.css) e cada .acao é
     white-space:nowrap — os dois botões cabem lado a lado até 768px, mas a
     390px "Conhecer o canal" + "Explorar projetos" juntos passam da largura
     da coluna, e sem quebra o segundo botão vaza 61px pra fora da .faixa
     (achado 1, rodada 1: mesmo defeito do grid, um nível abaixo — container
     certo, filho sem-quebra estourando por conta própria). */
  .heroi__acoes { flex-wrap: wrap; }

  .busca__caixa { padding: 16px; }
  .busca__caixa .prompt__campo { gap: 8px; }
  .busca__enviar { width: 44px; padding: 0; justify-content: center; gap: 0; }
  .busca__enviar-texto { display: none; }
  .busca__escopo { font-size: 12px; }
  .prompt__sugestoes .chip { min-height: 44px; }
}

/* Task 7 — as quatro fichas. elementos-sitio.css desenha .ficha em si (a
   caixa, a cena, o corpo, a tarja); o que falta ali é só o arranjo em grade
   das quatro — igual ao padrão do .heroi/.busca acima, 4 → 2 → 1 nos mesmos
   dois breakpoints do resto da home (1180, 680), não os três do kit. */
.fichas {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
  margin-top: 28px;
}
@media (max-width: 1180px) {
  .fichas { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 680px) {
  .fichas { grid-template-columns: 1fr; }
}

/* Régua: a seção 03 apresenta a ferramenta de membros sem depender do
   catálogo da antiga bancada. Cores e fontes vêm do pacote do sítio. */
.regua {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  gap: clamp(32px, 5vw, 80px);
  align-items: center;
  margin-top: 24px;
}
.regua__corpo, .regua__guia { min-width: 0; }
.regua__exclusivo {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 20px;
  color: var(--casa);
  font-size: 14px;
  line-height: 1.5;
}
.regua__corpo .secao__titulo { max-width: 20ch; }
.regua__corpo .secao__deck { max-width: 48ch; }
.regua__acoes { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }
.regua__acoes .acao { min-height: 44px; }
.regua__acoes a:focus-visible { outline: 2px solid var(--sitio-sinal); outline-offset: 4px; }
.regua__acesso { margin: 14px 0 0; font-size: 13px; line-height: 1.6; color: var(--sitio-tinta-secundaria); }
.regua__guia {
  padding: 32px;
  border: 1px solid var(--sitio-traco-forte);
  border-top: 3px solid var(--casa);
  border-radius: var(--sitio-raio-fino);
  background: var(--sitio-superficie);
}
.regua__marca { font: 500 40px/1.1 var(--voz-editorial); color: var(--sitio-tinta-cheia); }
.regua__marca span { display: block; margin-top: 10px; font: 14px/1.5 var(--voz-funcional); color: var(--sitio-tinta-secundaria); }
.regua__recursos { margin: 28px 0 0; }
.regua__recursos > div { padding: 18px 0; border-top: 1px solid var(--sitio-traco); }
.regua__recursos > div:last-child { padding-bottom: 0; }
.regua__recursos dt { font-size: 16px; font-weight: 500; color: var(--sitio-tinta-cheia); }
.regua__recursos dd { margin: 6px 0 0; font-size: 14px; line-height: 1.6; color: var(--sitio-tinta-secundaria); }
@media (max-width: 1180px) {
  .regua { grid-template-columns: minmax(0, 1fr); }
  .regua__corpo .secao__deck { max-width: 64ch; }
}
@media (max-width: 680px) {
  .regua__guia { padding: 24px; }
  .regua__acoes .acao { justify-content: center; flex: 1 1 160px; }
}

/* A cena da ficha não declarava `object-fit`, então caía no `fill` do padrão
   e ESTICAVA a arte. Medido antes desta linha, com a peça de 640×352 no
   quadro: 0,89× a 1440px (espremida) e 1,65× a 1180px (esticada 65% na
   horizontal). Nunca foi notado porque pixel art de cena larga tolera
   deformação — mas a arte final do VKPromos é um render fotográfico, e um
   render esticado 65% se denuncia sozinho.
   `cover` corta o excedente em vez de deformar: perde-se borda, não
   proporção. Aqui e não no pacote (`ds/sitio/`, saída compilada). */
.ficha__cena img { object-fit: cover; }

/* Arte final, fotográfica — não pixel art. `.ficha__cena img` do pacote impõe
   `image-rendering: pixelated`, que existe pra manter a grade de pixels
   nítida ao ampliar; aplicado a uma foto reduzida, ele serrilha as bordas em
   vez de suavizar. Esta classe marca as peças que já saíram do provisório.
   Enquanto as outras três fichas forem pixel art de placeholder, elas
   continuam SEM a classe, e de propósito. */
.ficha__cena img.ficha__foto { image-rendering: auto; }

/* O ladrilho de reserva da cena — mesmo papel do `.video__reserva` da busca,
   e pelo mesmo motivo: relatório sem `video` preenchido (o caso de todos
   hoje) não pode virar `<img>` quebrada nem cartão sem altura. O
   posicionamento vem de `.ficha__cena > *` (absolute, inset 0, 100%/100%,
   elementos-sitio.css); aqui falta só centrar o pictograma. */
.ficha__reserva { display: grid; place-items: center; }
.ficha__reserva svg { width: 28px; height: 28px; color: var(--sitio-tinta-fraca); }

/* ── O rodapé ────────────────────────────────────────────── */

/* `.rodape__legal` nunca teve regra de layout. O pacote desenha `.rodape`
   (flex, gap 40px) mas não conhece este filho — ele nasceu aqui, no HTML da
   home, como `<nav>` com dois links e o copyright dentro. Sem `display`, caiu
   no `block` do padrão, e os três viraram inline separados só pelo espaço em
   branco do HTML.

   Medido antes desta regra, a 1440px: `display: block`, `gap: normal`, filhos
   a **3px** um do outro — "Privacidade Termos © 2026 ViktorKav…" lê como uma
   coisa só, e os dois links parecem um.

   A prova de que o `display` nunca foi declarado estava no próprio arquivo:
   o bloco de 1180px abaixo já dava `justify-content: center` a este seletor —
   propriedade que **só** vale em contêiner flex ou grid, escrita por alguém
   supondo um layout que não existia. Ela era no-op desde sempre.

   Isto não é cosmético: é a home que o revisor da verificação do app OAuth do
   Google abre, e é o link de privacidade dali que a verificação exige. O
   login de membro depende dessa aprovação. */
.rodape__legal {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
}

/* elementos-sitio.css desenha .rodape numa linha só (space-between,
   white-space: nowrap) — calibrado para a prancha de 1440px, sem media
   query própria. Com marca + frase + legal (dois links + copyright) isso
   estoura a largura visível bem antes do fim da faixa desktop. A home é
   quem solta a largura (sitio-web.css), então é aqui que o rodapé precisa
   quebrar — no mesmo 1180 que já colapsa .cromo__menu, .heroi e .busca
   (achado 2, rodada 1: 768 era um quarto breakpoint sem paralelo no
   sistema; 1180 cobre 768 e 390 do mesmo jeito). */
@media (max-width: 1180px) {
  .rodape {
    flex-wrap: wrap;
    justify-content: center;
    white-space: normal;
    text-align: center;
    row-gap: 8px;
  }
  .rodape__legal {
    justify-content: center;
    white-space: normal;
  }
}

@media (max-width: 680px) {
  /* Em três colunas, o lema quebrava em três linhas e disputava largura
     com os links legais. O empilhamento mantém cada grupo fácil de ler. */
  .rodape .sitio__miolo {
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
    text-align: left;
  }
  .rodape__legal { justify-content: flex-start; gap: 12px 20px; }
  .rodape__legal a { display: inline-flex; align-items: center; min-height: 44px; }
}

/* ── Task 9 — o canal ────────────────────────────────────── */

/* Task 30: o trilho de cards da busca é a MESMA peça do canal — o pedido do
   dono foi literalmente "não muito diferente do que fizemos em últimos
   vídeos". Por isso os seletores entram agrupados aqui, na regra que já
   existe, em vez de ganharem uma segunda cópia das mesmas medidas noutro
   bloco: duas cópias divergem calada­mente na primeira vez que alguém
   ajustar uma só. A única diferença é o margin-top, que a .canal tem por
   vir depois do .medidor e a .busca__cartoes não precisa (o gap de .busca
   já separa). */
/* O trilho do canal também ocupa a largura inteira, com as setas por cima —
   mesma correção que a busca e o setup já tinham recebido. A trilha de 88px
   que existia aqui reservava espaço pras setas e era ela que cortava o quarto
   cartão ao meio: a régua de 4 batia numa caixa 108px mais estreita que a
   faixa. */
.canal { position: relative; margin-top: 28px; }

/* A meta ("há 2 dias · 9 mil visualizações") ancorada na ÚLTIMA linha do
   cartão, pedido do dono: sem isto ela sobe junto com o título, e um vídeo
   de nome curto deixa a linha desalinhada em relação ao vizinho de nome
   longo — o olho lê isso como cartão torto, não como texto de tamanho
   diferente.
   São duas distribuições: o CARTÃO dá ao corpo toda a altura que sobra
   depois do quadro (`auto 1fr`), e o CORPO empurra a meta pro fim dessa
   altura. `.video__corpo` já é grid no pacote (`1fr auto`, com a meta em
   `grid-column: 1/-1`); aqui só se acrescenta a régua de linhas. */
.canal__trilho > .video,
.busca__trilho > .video { display: grid; grid-template-rows: auto 1fr; }
.canal__trilho > .video > .video__corpo,
.busca__trilho > .video > .video__corpo { grid-template-rows: auto 1fr; }
.canal__trilho > .video .video__meta,
.busca__trilho > .video .video__meta { align-self: end; }
/* O trilho da busca ocupa a largura inteira e as setas flutuam POR CIMA dele
   (pedido do dono). Antes isto era `grid-template-columns: minmax(0,1fr) 88px`,
   como o .canal ao lado: a trilha de 88px reservava espaço pras setas, e era
   ela que cortava o quarto cartão ao meio — a régua de 4 cartões batia numa
   caixa 108px mais estreita que a faixa. */
.busca__cartoes { position: relative; }
/* `display:grid` de uma classe vence o `display:none` que o atributo [hidden]
   ganha da folha do agente (seletor de tipo, especificidade menor) — sem esta
   linha o trilho VAZIO aparece na primeira pintura, com as duas setas e sem
   cartão nenhum, e nunca some depois de uma busca sem resultado. Não dá erro:
   só nasce uma faixa vazia com cara de coisa que falhou ao carregar. */
.busca__cartoes[hidden] { display: none; }
/* Task 32: o trilho do Setup (seção 05) é a MESMA peça, pelo mesmo motivo
   que o da busca — "cards horizontais na estética da home". Ele entra nas
   regras que já existem, agrupado, em vez de ganhar uma cópia das mesmas
   medidas: duas cópias divergem caladamente na primeira vez que alguém
   ajustar uma só. Como a busca, ele ocupa a largura inteira e as setas
   flutuam por cima. */
/* O padding de baixo NÃO é respiro decorativo: a seção 06 (.papel,
   elementos-sitio.css, intocável) sobe 48px por cima da seção anterior
   (`margin-top: -48px`) e pinta uma rampa opaca de 144px que começa na cor
   do fundo da página. Como as duas têm o mesmo z-index, quem vem depois no
   DOM pinta em cima: os últimos 48px desta seção ficam DEBAIXO da rampa.
   `.secao` só reserva 8px embaixo (padding: 64px 0 8px), e o trilho é o
   último elemento — sem estes 56px, a segunda linha da nota de cada cartão
   some sob o degradê, sem cortar nada no DOM (medido: o cartão continua
   inteiro, com a nota dentro; só não dá pra ler). */
.setup { position: relative; margin-top: 28px; padding-bottom: 56px; }
.canal__trilho,
.busca__trilho,
.setup__trilho {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(280px, 1fr);
  gap: 20px; overflow-x: auto; scroll-snap-type: x mandatory;
  scrollbar-width: none; padding-bottom: 8px;
}

/* O trilho da busca tem largura de cartão FIXA, calibrada pra caber quatro
   inteiros — o `minmax(280px, 1fr)` compartilhado com o .canal continua
   valendo lá, mas aqui o `1fr` era o que fazia dois resultados virarem dois
   cartões gigantes de meia tela.
   Quatro cartões e três vãos somam exatamente 100%, então o quinto começa
   depois da borda: nunca sobra a tira de um cartão cortado no canto. E como
   cada cartão mede o mesmo, o passo da seta (largura + vão, em busca.js)
   cai sempre num ponto de encaixe — a rolagem entra um cartão inteiro de um
   lado e sai um cartão inteiro do outro. */
/* O trilho do Setup usa a MESMA régua de quatro: são quatro peças sorteadas
   por carregamento, e o quinto cartão (o elo pro catálogo inteiro) começa
   depois da borda de propósito — é ele que anuncia, com a fatia que aparece
   no canto, que o trilho anda. */
.busca__trilho,
.canal__trilho,
.setup__trilho { grid-auto-columns: calc((100% - 3 * 20px) / 4); }

/* Abaixo de 1180px a régua de quatro não serve MAIS pro Setup, e só pra ele:
   o cartão de peça tem uma trilha a mais que o de vídeo — o preço, que é
   `white-space: nowrap` e não cede. A 681px a coluna cai pra 143px, o preço
   leva ~90 deles, e sobram 6px pro nome: o texto sangra pra fora da própria
   caixa (medido — scrollWidth 20 contra clientWidth 6, pego por
   TestSemClip::test_conteudo_nao_transborda_a_propria_caixa). O trilho passa
   à mesma régua do carrossel do canal, que tem piso de 280px por cartão e
   deixa o resto rolar. `1fr` num scroller não estica: o piso é o que vale. */
@media (max-width: 1180px) {
  .setup__trilho { grid-auto-columns: minmax(280px, 1fr); }
  /* Quatro colunas a 681px deixavam menos de 140px por vídeo. Dois cartões
     inteiros mantêm o título legível; os demais continuam no trilho. */
  .canal__trilho,
  .busca__trilho { grid-auto-columns: calc((100% - 20px) / 2); }
}
.canal__trilho::-webkit-scrollbar,
.busca__trilho::-webkit-scrollbar,
.setup__trilho::-webkit-scrollbar { display: none; }
.canal__trilho > .video,
.busca__trilho > .video,
/* No Setup o encaixe é `> *`, não `> .video`: o último cartão do trilho é o
   elo pro catálogo (um <a>, não um <article class="video">), e sem isto ele
   seria o único que não para no ponto de encaixe. */
.setup__trilho > * { scroll-snap-align: start; }

/* O ladrilho de reserva do quadro: item sem `capa` no índice, ou capa que
   falha ao carregar (thumb do YouTube fora do ar, PNG de tutorial ainda não
   publicado). .video__quadro já é position:relative com aspect-ratio 16/9 e
   fundo --sitio-rebaixo (elementos-sitio.css), então o card nunca fica sem
   altura — o que falta é só o pictograma no meio. Nunca um <img> quebrado:
   busca.js remove o <img> antes de pôr o ladrilho no lugar. */
.video__reserva { position: absolute; inset: 0; display: grid; place-items: center; }
.video__reserva svg { width: 28px; height: 28px; color: var(--sitio-tinta-fraca); }

/* .video__nome (elementos-sitio.css, intocável) só tem text-wrap:pretty —
   isso quebra em espaços, mas um token sem espaço (URL, #hashtag) maior que
   a coluna (grid-auto-columns: minmax(280px,1fr), então o card raramente
   passa de ~280px) simplesmente sangra pra fora do .video (que tem
   overflow:hidden) e corta a palavra no meio, sem reticências e sem erro.
   overflow-wrap:anywhere força a quebra dentro da própria caixa quando não
   há espaço nenhum pra quebrar — só entra em jogo nesse caso extremo; texto
   normal, com espaços, continua quebrando exatamente como antes. */
.video__nome { overflow-wrap: anywhere; }
/* As setas dos três trilhos flutuam sobre os cartões, encostadas na direita e
   centradas na vertical — nenhuma delas reserva coluna. `pointer-events`
   volta a `auto` só nos botões: a caixa é maior que eles e, sem isso, um
   retângulo invisível engoliria o clique no cartão que está por baixo. */
.busca__setas, .canal__setas, .setup__setas {
  display: grid; gap: 12px; justify-items: center;
  position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
  z-index: 2; pointer-events: none;
}
.busca__setas > .disco,
.canal__setas > .disco,
.setup__setas > .disco { pointer-events: auto; }
/* As setas do Setup sobem pro meio da FOTO, não pro meio do cartão. No
   trilho da busca o centro vertical cai dentro da capa do vídeo; aqui,
   como o cartão tem foto + nome + preço + nota, o mesmo 50% cai em cima do
   preço da última peça e esconde um número. 32% é o meio do quadro
   (211px de 327). */
.setup__setas { top: 32%; }
/* A dica saiu de dentro de .canal__setas (ver o comentário no index.html) e
   virou irmã do trilho. Alinhada à direita, embaixo: é onde o olho já está
   depois de percorrer os cartões, e é o lado de onde vêm os próximos. */
.canal__dica {
  display: block; margin-top: 12px; text-align: right;
  font-family: var(--voz-sistema); font-size: 11px; line-height: 1.4;
  color: var(--sitio-tinta-fraca);
}
.canal__reserva {
  margin: 0; padding: 24px;
  font-size: var(--sitio-corpo-corpo); color: var(--sitio-tinta-secundaria);
}
.canal__reserva a { color: var(--sitio-sinal); }

/* Sem ponteiro, arrastar é o gesto — as setas não têm o que fazer (o mesmo
   corte que já existe pro campo, Task 5). */
@media (hover: none) {
  .canal__setas,
  .busca__setas,
  .setup__setas { display: none; }
  /* A dica vivia DENTRO de .canal__setas e sumia junto com elas no toque.
     Agora que é irmã do trilho, precisa ser escondida por nome — senão o
     comportamento mudaria de lado sem ninguém ter pedido. (Que uma dica de
     "arraste" seja escondida justamente onde arrastar é o gesto é estranho,
     mas é o comportamento de hoje e não é esta a mudança que foi pedida.) */
  .canal__dica { display: none; }
  /* As três faixas deixaram de ser grid de duas colunas — o
     `grid-template-columns` que existia aqui virou no-op quando as setas
     passaram a flutuar. Removido em vez de mantido: regra que não faz nada
     é a que sobrevive a refactor nenhum e confunde a próxima leitura. */
}

@media (max-width: 680px) {
  .canal__trilho,
  .busca__trilho,
  .setup__trilho { grid-auto-columns: 82%; }
}

/* ── Task 32 — as peças do setup (seção 05) ──────────────── */

/* O cartão é o .video do sistema (pacote compilado, intocável) — o pedido do
   dono foi "cards horizontais na estética da home", e a estética da home
   pros cards é essa. O que muda vem do dado, não de gosto:

   .video__quadro é 16/9 com object-fit:cover, calibrado pra thumb de vídeo.
   Foto de produto não é cena: ela vem quadrada-ish, com fundo branco ou
   transparente, e `cover` cortaria justamente a peça. `contain` mostra o
   objeto inteiro; o vão que sobra é o próprio fundo do quadro
   (--sitio-rebaixo), e o padding evita a peça encostar na borda. A proporção
   4/3 é a que gasta menos altura sem apertar produto alto (microfone, torre)
   — as fotos do Mercado Livre chegam quase todas quadradas. */
.peca .video__quadro { aspect-ratio: 4 / 3; }
.peca .video__quadro img { object-fit: contain; padding: 14px; }

/* O QUADRO DA PEÇA É BRANCO, e não é descuido de paleta: as fotos do
   Mercado Livre vêm com fundo branco chapado dentro do arquivo. Sobre o
   --sitio-rebaixo (quase preto) do quadro padrão, cada foto vira uma ilha
   branca flutuando num retângulo escuro — a moldura briga com a foto em vez
   de segurá-la. É a mesma decisão que o VKPromos já tomou na página de onde
   este dado vem (`data-modo="claro"` no .vk-setup-fig, que resolve
   --superficie-alta pra #ffffff): a foto ENCOSTA no quadro. Branco literal
   pelo mesmo motivo — o valor vem do fundo das fotos, não da paleta do
   sítio, e mudar o tema não muda o fundo de um JPEG.

   O branco vai no <img>, não no .video__quadro, e a diferença importa: o
   <img> ocupa o quadro inteiro (100%/100%, elementos-sitio.css), então
   pintar o fundo DELE cobre a mesma área — mas só existe quando existe
   foto. Quando a foto falha, setup.js tira o <img> do DOM e põe o ladrilho
   de reserva no lugar; o quadro volta a ser escuro sozinho, e o pictograma
   (--sitio-tinta-fraca) continua legível. Com o branco no quadro, o
   ladrilho cinza-claro sobre branco sumiria — sem erro nenhum. */
.peca .video__quadro img { background-color: #fff; }

/* NOME E NOTA TÊM TETO DE DUAS LINHAS, com altura fixa — e o que isso
   compra é ALTURA DE CARTÃO ESTÁVEL, não estética.

   A seção sorteia quatro das 27 peças a cada carregamento, e o cartão é o
   .video do pacote: a altura dele vem da linha do grid do trilho, que por
   sua vez vem do cartão mais alto. Sem teto, a altura da faixa inteira
   passa a depender de QUAIS peças caíram: medido em doze carregamentos com
   o catálogo real, a mesma seção mediu 317px, 341px e 386px de altura,
   trocando a cada F5 — o conteúdo de baixo dança sozinho, sem nada ter
   mudado na página.

   Com duas linhas fixas em cada bloco de texto (mais as reticências do
   line-clamp), a altura passou a ser 327px nos doze carregamentos. É a
   MESMA decisão que a página de onde este dado vem já tinha tomado
   (vk-clamp-1 no nome e vk-clamp-2 na nota, em
   VKPromos/apps/site/src/features/setup) — e o texto que não coube está a um
   clique de distância, no elo do fim do trilho.

   -webkit-line-clamp precisa do trio (display box + orient + overflow); é
   prefixado no nome mas é o que todos os navegadores implementam. O clamp
   sozinho não fixa altura nenhuma (ele é um TETO: o bloco de uma linha só
   continua medindo uma linha), por isso a altura explícita vem junto. */
.peca .video__nome,
.peca .video__meta {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}
.peca .video__nome { line-height: 21px; height: 42px; }
.peca .video__meta { line-height: 17px; height: 34px; }

/* O preço cai na trilha `auto` de .video__corpo (grid 1fr auto), ao lado do
   nome. Voz de sistema e tabular-nums porque é número que o olho compara
   entre cartões; nowrap porque "R$ 30.942,00" quebrado em duas linhas vira
   dois números. A string vem formatada do VKPromos e é exibida como veio —
   ver o comentário de criarCartao() em js/sitio/setup.js. */
.peca__preco {
  font-family: var(--voz-sistema); font-size: 12px;
  color: var(--sitio-tinta-cheia); text-align: right;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}

/* O último cartão do trilho: o elo pro catálogo inteiro. É <a>, não
   <article>, então precisa desfazer duas heranças — a cor de sinal de
   `.sitio a` (aqui o cartão inteiro é o alvo, não uma palavra dentro de um
   texto) e o layout de .video, que espera quadro + corpo. */
.setup__trilho > .peca--todas {
  display: grid; align-content: center; justify-items: start;
  gap: 6px; padding: 20px 22px;
  color: var(--sitio-tinta-cheia); text-decoration: none;
}
.peca__chamada { font-size: 14px; line-height: 21px; font-weight: 500; }
.peca__conta {
  font-family: var(--voz-sistema); font-size: 11px;
  color: var(--sitio-tinta-fraca);
}
.setup__trilho > .peca--todas .ico { color: var(--sitio-sinal); }

/* .secao__cabeca é flex row calibrado pra caber título + secao__elo, um elo
   estreito (Task 7/8 nunca precisaram de outra coisa ali). O .medidor de
   cinco itens ao lado do título não sobra espaço nenhum a 1180px — precisa
   da própria linha, empilhado abaixo do título. */
@media (max-width: 1180px) {
  .secao__cabeca { flex-direction: column; align-items: flex-start; gap: 24px; }
  .medidor { width: 100%; }
}

/* Mesmo remédio do Task 6 pro .prompt__sugestoes: cinco itens com
   border-left e padding não têm pra onde quebrar sem partir o ritmo visual
   (o traço ficaria solto no primeiro item de cada linha nova). Em vez de
   empilhar, o .medidor vira scroller — o CONTÊINER não estoura (é isso que
   TestSemClip mede), os itens além da borda estão a um scroll de distância,
   não escondidos. */
@media (max-width: 1180px) {
  .medidor { overflow-x: auto; scrollbar-width: none; padding-bottom: 4px; }
  .medidor::-webkit-scrollbar { display: none; }
  .medidor__item { flex: none; }
}

/* ── Task 10 — o extra (06) ──────────────────────────────── */

/* Três colunas, duas linhas, todas as colunas terminando na mesma altura —
   pedido do dono, e o motivo de as regras de posição serem explícitas em vez
   de deixar o auto-placement decidir: "Sobre" e "Links de afiliados"
   empilham na primeira coluna, enquanto "Vamos conversar" e "Onde estou"
   atravessam as duas linhas.

   `align-items` volta pro padrão (stretch): com `start`, que era o valor
   anterior, os cartões que atravessam duas linhas ficariam com a altura do
   próprio conteúdo e a simetria não fecharia. A segunda linha é `1fr` pelo
   mesmo motivo — é ela que absorve a diferença. */
.extra-grade {
  display: grid;
  grid-template-columns: 340px 1fr 1fr;
  grid-template-rows: auto 1fr;
  gap: 32px;
  margin-top: 8px;
}
.extra-sobre   { grid-column: 1; grid-row: 1; }
/* `.secao__deck` (elementos-sitio.css, intocável) tem `margin: 8px 0 0` —
   topo só, base zero. Serve onde o deck é o último elemento do cabeçalho,
   que é o caso das outras cinco seções. Aqui embaixo dele vem o CTA, e sem
   esta linha o botão encosta no texto. */
.extra-sobre .acao { margin-top: 20px; }
.afiliados     { grid-column: 1; grid-row: 2; }
.extra-contato { grid-column: 2; grid-row: 1 / span 2; }
.extra-onde    { grid-column: 3; grid-row: 1 / span 2; }

/* "Onde estou" distribui: rótulo, lugar e lema pedem o que precisam, e a
   última trilha (a cena, com o mapa) fica com o resto. Sem isto o mapa
   mantém o piso de 132px e sobra vão branco no pé do cartão mais alto. */
.extra-onde { grid-template-rows: auto auto auto 1fr; }

@media (max-width: 1180px) {
  /* Duas colunas não comportam o arranjo de três: as posições explícitas
     voltam ao automático e a grade reflui sozinha. Sem este reset, os
     `grid-column: 3` acima criariam uma terceira coluna implícita fora da
     largura declarada — a página ganharia rolagem horizontal em silêncio. */
  .extra-grade { grid-template-columns: 1fr 1fr; grid-template-rows: auto; }
  .extra-sobre, .afiliados, .extra-contato, .extra-onde {
    grid-column: auto; grid-row: auto;
  }
}
@media (max-width: 680px) {
  .extra-grade { grid-template-columns: 1fr; gap: 24px; }
}

/* O cartão de papel some com display:grid — os dois cartões da seção 06
   (Vamos conversar / Onde estou) tinham style={{display:'grid', gap:14}}
   no componente fonte; sem isto o rótulo cola no conteúdo de baixo. */
.cartao-papel { display: grid; gap: 14px; }

/* "Onde estou": local, fuso, lema e a cena em pixel art. No kit era tudo
   style inline (14px/22px pro local, 13px pro fuso, 14px cinza pro lema) —
   viram classe pra existir no HTML servido. Cor explícita nos três: a
   seção é clara (.papel já resolve a tinta geral), mas texto que confia só
   na herança é o tipo de coisa que passa a sangrar tinta escura no primeiro
   redesign que mover a ordem dos blocos — CONTRASTE-011 do brief. */
.extra-lugar { margin: 0; font-size: 14px; line-height: 22px; color: var(--sitio-papel-tinta); }
.extra-fuso { font-family: var(--voz-sistema); font-size: 13px; color: var(--sitio-papel-tinta-secundaria); }
.extra-lema { margin: 0; font-size: 14px; color: var(--sitio-papel-tinta-secundaria); }
/* A cena deixou de ter altura fixa (eram 132px, medida da arte em pixel art
   que estava aqui). Agora ela é o elemento elástico do cartão: como "Onde
   estou" atravessa as duas linhas da grade, sobra altura, e é o mapa que a
   ocupa — não um vão em branco embaixo dele. O piso continua existindo pra
   ele nunca colapsar quando a coluna for curta. */
.extra-cena {
  position: relative;
  min-height: 132px;
  border-radius: 8px;
  overflow: hidden;
  border: 1px solid var(--sitio-papel-traco);
}
.extra-cena img { display: block; width: 100%; height: 100%; object-fit: cover; image-rendering: pixelated; }

/* O iframe do Google Maps entra no lugar da arte. `border:0` porque o
   navegador desenha borda própria em iframe e ela apareceria por dentro do
   raio do .extra-cena; a moldura é do cartão, não do frame. */
.extra-mapa { display: block; width: 100%; height: 100%; min-height: 132px; border: 0; }

/* Os links de afiliados não estão no kit — voltam por decisão explícita do
   dono (nada que gera receita ou tráfego sai sem ele decidir), então nascem
   inteiros aqui: rótulo, os dois elos lado a lado e a divulgação de
   comissão (test_afiliados_declaram_a_comissao cobra o rel="sponsored"). */
/* O `margin-top: 24px` que existia aqui saiu: o bloco deixou de flutuar solto
   abaixo da grade e virou célula dela (coluna 1, linha 2), onde o `gap` já
   dá o afastamento. Mantê-lo somaria ao gap e furaria a simetria de altura
   que a grade acabou de estabelecer. */
.afiliados__linha { display: flex; flex-wrap: wrap; align-items: center; gap: 20px; }

/* Achado I1 (revisão de acessibilidade 2026-08-13): "Amazon"/"Hostinger"
   mediam 2,15:1, a mesma falha do âmbar sobre papel — mas a causa aqui não
   é falta de token, é empate de especificidade perdido. `.sitio a` (uma
   classe + um tipo) e `.afiliados__elo` (uma classe só) empatam em peso de
   classe, e o tipo extra de `.sitio a` desempata a favor dela mesmo esta
   folha carregando por último — a cor escura abaixo nunca chegava a valer.
   `.papel .afiliados__elo` (duas classes) vence por contagem de classe,
   antes de chegar a comparar tipo, então a cor pretendida passa a valer de
   verdade. Os elos são cartão/chip (como .chip, texto neutro), não link de
   texto corrido — por isso o texto fica escuro, não vira a variante clara
   do âmbar que os outros achados do I1 usam. */
/* Os elos deixaram de ser chip de texto e passaram a ser a marca de cada
   parceiro (pedido do dono). Desenhadas por `mask` + `background-color`, e
   não por `<img>`, por um motivo concreto: o hostinger.svg vem da marca com
   fill #E8ECF0 — quase branco, feito pra fundo escuro —, e sobre o papel
   creme ele seria invisível. Por <img> não há como recolorir; por máscara,
   o SVG vira recorte e a cor é a tinta do papel, igual pros dois. Nenhum
   arquivo de marca precisou ser editado.

   Cada elo declara largura E altura porque a máscara não tem tamanho
   intrínseco: sem elas o <a> vazio mede 0×0 e o logo simplesmente não
   aparece — sem erro nenhum. (test_sub_elementos_do_extra_tem_dimensao
   cobre exatamente isso pra .afiliados__elo.)

   As proporções vêm do viewBox de cada arquivo: amazon 24×24 (1:1),
   hostinger 150×30 (5:1). A Amazon vai um pouco mais baixa que a altura da
   faixa porque um glifo quadrado pesa mais no olho que um wordmark fino da
   mesma altura.

   O texto visível saiu, então o nome acessível passou a ser o aria-label no
   próprio <a> — um link sem conteúdo e sem rótulo seria anunciado só pelo
   href. */
.papel .afiliados__elo {
  display: inline-block;
  background-color: var(--sitio-papel-tinta);
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center;  mask-position: center;
  -webkit-mask-size: contain;     mask-size: contain;
  transition: opacity var(--t-toque) var(--e-entrada);
}
.papel .afiliados__elo--amazon {
  width: 22px; height: 22px;
  -webkit-mask-image: url("../assets/afiliados/amazon.svg");
  mask-image: url("../assets/afiliados/amazon.svg");
}
.papel .afiliados__elo--hostinger {
  width: 125px; height: 25px;
  -webkit-mask-image: url("../assets/afiliados/hostinger.svg");
  mask-image: url("../assets/afiliados/hostinger.svg");
}
/* Sem `color` no hover: não há texto pra recolorir, e a regra antiga existia
   só pra impedir que `.sitio a:hover` pintasse o rótulo de âmbar. O realce
   agora é opacidade, que a máscara respeita. */
.papel .afiliados__elo:hover { opacity: .62; }
.afiliados__aviso { margin: 0; font-size: 12.5px; color: var(--sitio-papel-tinta-secundaria); }

/* ── O cartão inteiro vira alvo de clique ────────────────── */

/* Medido antes desta regra, a 390px: a ficha de Projetos tinha **0,7%** da
   própria área clicável (302×389, com um `+` de 28×28 no canto); o cartão de
   vídeo, 10,3% (só o título — a miniatura era morta); a peça do setup, **0%**
   (o link é o título, e a foto do produto, o preço e a nota não respondiam).
   O visitante mira no cartão porque o cartão parece um botão; acertar o alvo
   virava perícia.

   Link ESTICADO, não cartão embrulhado em `<a>`: envolver o cartão inteiro
   levaria a foto, o preço e a nota pra dentro do nome acessível do link, e o
   leitor de tela anunciaria tudo de uma vez. Assim continua UM link na árvore
   de acessibilidade, com o mesmo texto de antes, e o retângulo de clique é
   que cresce.

   A Bancada fica de fora de propósito (`#projetos`, e não `.ficha` solto):
   por decisão do dono os cartões dela não levam a lugar nenhum, e um alvo de
   clique do tamanho do cartão seria promessa que ela não cumpre. */
#projetos .ficha,
.canal__trilho > .video,
.busca__trilho > .video,
.setup__trilho > .video { position: relative; }

#projetos .ficha__mais::after,
.canal__trilho > .video .video__nome a::after,
.busca__trilho > .video .video__nome a::after,
.setup__trilho > .video .video__nome a::after,
.setup__trilho > .peca--todas a::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
}

/* NÃO se eleva o corpo do cartão pra preservar a seleção de texto. Tentei, e
   é contraditório: elevar `.video__corpo`/`.ficha__corpo` acima da camada
   esticada cobre justamente a área que se queria tornar clicável — medido,
   caiu pra 15% dos pontos. Querer clique no cartão inteiro E seleção livre do
   texto é querer que a mesma camada esteja em cima e embaixo.
   O padrão de link esticado troca uma coisa pela outra de propósito, e aqui a
   troca é fácil: ninguém seleciona o título de um cartão de vídeo, e todo
   mundo tenta clicar nele. */
