/* Tema "Editorial claro" — mesmo do ConsumidorForte (03_Consumidor-Forte):
   fundo osso, tinta quase-preta, acento único teal, Fraunces (display) + Manrope (corpo).
   Ao mudar o tema lá, espelhar os tokens aqui.
   Compartilhado por template.html (hub /ofertas/) e template-guia.html (/ofertas/guias/<slug>/)
   — publicado como estilo.css na raiz de /ofertas/; cada template linka pelo caminho
   relativo para o preview local continuar funcionando. */
:root{
  --bg:#f4f1ea; --card:#fcfbf7; --ink:#1f1b16; --muted:#6e685d; --soft:#8d8577;
  --line:#e5dfd3; --accent:#0f5c57; --accent-600:#0c4a46; --accent-50:#dfecea;
  --green:#3e6b4f; --orange:#b4532a;
  --shadow:0 1px 2px rgba(31,27,22,.05); --shadow-md:0 4px 16px rgba(31,27,22,.07);
  --radius:16px; --radius-sm:11px; --ease-out:cubic-bezier(.22,1,.36,1);
}
* { box-sizing:border-box; margin:0; }
/* NÃO pôr `html{scroll-behavior:smooth}` aqui. Medido em 26/08/2026: neste
   navegador o scroll suave PROGRAMÁTICO não acontece — nem por
   `scrollTo({behavior:"smooth"})`, nem pelo CSS, que ainda desliga o
   `scrollTo(0,y)` normal junto. O "voltar ao topo" ficava inerte, que é pior
   que não existir. Salto instantâneo funciona em todo lugar; a rolagem manual
   do dedo não é afetada por nada disto. */
body { font-family:"Manrope",system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
       background:var(--bg); color:var(--ink); font-size:14px; line-height:1.5;
       -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility; }
::selection { background:var(--accent-50); }
button { cursor:pointer; border:none; background:none; font-family:inherit;
         font-size:inherit; color:inherit; }
/* Folha editorial: papel claro com hairlines laterais sobre o fundo osso */
.folha { max-width:1100px; margin:0 auto; background:var(--card);
         border-left:1px solid var(--line); border-right:1px solid var(--line);
         min-height:100dvh; display:flex; flex-direction:column; }
header { padding:2.6rem 1.6rem 1.4rem; border-bottom:1px solid var(--line); }
.kicker { color:var(--accent); font-size:.72rem; font-weight:800;
          letter-spacing:.14em; text-transform:uppercase;
          display:flex; align-items:center; gap:.5rem; margin-bottom:.85rem; }
.kicker::before { content:""; width:7px; height:7px; border-radius:50%;
                  background:var(--accent); }
.marca-linha { display:flex; align-items:center; gap:.7rem; }
.marca { width:40px; height:40px; border-radius:12px; background:var(--accent);
         display:grid; place-items:center; box-shadow:var(--shadow); flex:none; }
header h1 { font-family:"Fraunces",Georgia,"Times New Roman",serif;
            letter-spacing:-.01em; font-size:2rem; font-weight:600; }
header h1 span { color:var(--accent); }
header p { color:var(--muted); margin-top:.55rem; font-size:.95rem; }
/* Barra de filtros (só o hub) */
.filtros { padding:1.1rem 1.6rem 1.2rem; border-bottom:1px solid var(--line);
           display:flex; flex-direction:column; gap:.65rem; }
.fgrupo { display:flex; align-items:baseline; gap:.8rem; flex-wrap:wrap; }
.flabel { color:var(--soft); font-size:.68rem; font-weight:800;
          letter-spacing:.1em; text-transform:uppercase; min-width:72px; }
.chips { display:flex; gap:.4rem; flex-wrap:wrap; }
.chip { border:1px solid var(--line); border-radius:999px; padding:.28rem .8rem;
        font-size:.8rem; font-weight:600; color:var(--muted); background:var(--card);
        transition:background .15s, color .15s, border-color .15s; }
/* Cor de marca da loja (mapa em atualizar.py: MARCA_SLUG). Serve o chip do
   filtro E o badge .loja do card — a cor mora só aqui, não duplicada.
   O matiz é o da marca ESCURECIDO até passar AA sobre o fundo (#fcfbf7): o
   laranja puro da Amazon (#FF9900) dá 2,07:1 e é ilegível. Medido: 6,17 / 5,73
   / 5,27:1 — faixa do --muted (5,34), então muda o matiz e não o peso visual.
   Declarado ANTES de :hover e .ativo DE PROPÓSITO: os três empatam em
   especificidade (0,2,0), e é a ordem que faz o chip sob o mouse e o
   selecionado voltarem ao teal, como todos os outros filtros. */
/* ==marcas:inicio== gerado do config.json das lojas — nao editar a mao */
.m-aliexpress { --marca:#c9280a; }
.m-amazon { --marca:#8a5200; }
.m-magalu { --marca:#0063bf; }
.m-shopee { --marca:#b52a0f; }
.m-temu { --marca:#b8430f; }
.chip.m-aliexpress, .chip.m-amazon, .chip.m-magalu, .chip.m-shopee, .chip.m-temu { color:var(--marca); font-weight:700; }
.loja.m-aliexpress, .loja.m-amazon, .loja.m-magalu, .loja.m-shopee, .loja.m-temu { color:var(--marca); }
/* ==marcas:fim== */
/* Ícone da loja no chip (data URI, gerado por logo_loja no atualizar.py). Loja
   sem arquivo em 4-SISTEMA/logos/ não tem <img> nenhum — o chip fica só com o
   nome colorido e nada aqui se aplica. width/height vêm no HTML para não haver
   salto de layout enquanto o data URI decodifica. */
.logo-loja { height:14px; width:auto; vertical-align:-2px; margin-right:.35rem;
             border-radius:3px; }
/* Wordmark (Magalu) entra sozinho no chip, sem texto ao lado — aí a margem
   direita sobraria e desalinharia o padding do botão.
   NÃO usar :only-child aqui: ela conta só ELEMENTOS e ignora nós de texto,
   então o <img> de "<img>Amazon" também casaria e a margem morria em todos. */
.logo-loja.logo-wordmark { margin-right:0; }
.chip:hover { border-color:var(--accent); color:var(--accent-600); }
.chip.ativo { background:var(--accent-50); border-color:var(--accent);
              color:var(--accent-600); }
/* Campo de busca: com ~400 cards, achar pelo nome é mais rápido que caçar chip.
   A lupa é SVG inline (não background data:) — fica imune a aperto de CSP. */
.fbusca { align-items:center; }
.busca-wrap { position:relative; display:flex; align-items:center;
              flex:1; min-width:200px; max-width:420px; }
.busca-wrap svg { position:absolute; left:.75rem; width:15px; height:15px;
                  color:var(--soft); pointer-events:none; }
#busca { width:100%; font-family:inherit; font-size:.85rem; color:var(--ink);
         background:var(--card); border:1px solid var(--line); border-radius:999px;
         padding:.4rem .9rem .4rem 2.1rem; transition:border-color .15s, box-shadow .15s; }
#busca::placeholder { color:var(--soft); }
#busca:focus { outline:none; border-color:var(--accent);
               box-shadow:0 0 0 3px var(--accent-50); }
.contagem { color:var(--soft); font-size:.8rem; }
.link-todos { color:var(--accent-600); font-size:inherit; font-weight:700;
              text-decoration:underline; text-underline-offset:2px; padding:0; }
.link-todos:hover { color:var(--accent); }
main { padding:0 1.6rem 3rem; flex:1; }
.grade { display:grid; grid-template-columns:repeat(auto-fill,minmax(210px,1fr));
         gap:1rem; margin-top:1.4rem; }
.card { background:var(--card); border:1px solid var(--line);
        border-radius:var(--radius-sm); padding:.95rem; text-decoration:none;
        color:inherit; display:flex; flex-direction:column; gap:.5rem;
        box-shadow:var(--shadow);
        transition:transform .18s var(--ease-out), box-shadow .18s var(--ease-out); }
.card:hover { transform:translateY(-2px); box-shadow:var(--shadow-md); }
.card img { width:100%; height:150px; object-fit:contain; background:#fff;
            border-radius:6px; }
.sem-img { height:150px; background:var(--bg); border:1px dashed var(--line);
           border-radius:6px; }
.tile-recompensa { height:150px; background:var(--accent-50); border-radius:6px;
                   display:grid; place-items:center; color:var(--accent); }
.tile-recompensa svg { width:54px; height:54px; }
.recompensa { font-family:"Fraunces",Georgia,serif; font-size:1.05rem;
              font-weight:600; color:var(--accent); display:flex;
              align-items:center; gap:.35rem; }
.recompensa::before { content:"🎁"; font-size:.95em; }
.meta { display:flex; justify-content:space-between; align-items:baseline;
        gap:.5rem; }
.loja { color:var(--soft); font-size:.65rem; font-weight:800;
        letter-spacing:.08em; text-transform:uppercase; }
/* Badge com a cor da marca: a regra .loja.m-* vive no bloco gerado lá em cima
   (especificidade 0,2,0 vence o .loja 0,1,0 em qualquer ordem). Além da
   identidade, corrige contraste: --soft em 10,4px dá 3,52:1, abaixo de AA.
   Loja sem .m-* continua em --soft. */
.rank { color:var(--accent); font-size:.65rem; font-weight:700;
        letter-spacing:.08em; text-transform:uppercase; }
.card h3 { font-size:.9rem; font-weight:600; flex:1; }
.cupom { align-self:flex-start; border:1px dashed var(--accent); color:var(--accent-600);
         border-radius:6px; padding:.05rem .5rem; font-size:.7rem; font-weight:700;
         letter-spacing:.05em; text-transform:uppercase; }
.preco { font-family:"Fraunces",Georgia,serif; font-variant-numeric:tabular-nums;
         font-size:1.15rem; font-weight:600; color:var(--accent); }
.preco s { color:var(--soft); font-size:.8em; font-weight:400; margin-right:.35rem; }
.off { color:var(--green); font-size:.75em; font-weight:800;
       font-family:"Manrope",sans-serif; margin-left:.3rem; }
.badge-aviso { font-size:.65rem; font-weight:700; color:var(--orange);
               border:1px solid currentColor; border-radius:999px;
               padding:.05rem .45rem; vertical-align:middle;
               letter-spacing:.04em; text-transform:uppercase; }
.vazio { color:var(--soft); font-style:italic; padding:1.5rem 0; }
footer { padding:1.6rem; color:var(--muted); font-size:.8rem;
         border-top:1px solid var(--line); }

/* ---- Guias de compra (/ofertas/guias/<slug>/) ---- */
/* Coluna de leitura estreita (~68 caracteres) dentro da mesma folha do hub.
   Cabeçalho e migalha usam a MESMA coluna: com o h1 na borda da folha e o texto
   centralizado, a página ganhava dois eixos de leitura. As bordas do header
   seguem de ponta a ponta (a folha editorial depende disso). */
.artigo { max-width:660px; margin:0 auto; padding-top:1.8rem; }
.cabeca-guia > * { max-width:660px; margin-left:auto; margin-right:auto; }
/* +3.2rem = o padding lateral da própria migalha, para o texto interno cair
   exatamente na coluna de 660px do artigo (box-sizing:border-box) */
.migalha { max-width:calc(660px + 3.2rem); margin:0 auto; }
.artigo h2 { font-family:"Fraunces",Georgia,serif; font-size:1.35rem; font-weight:600;
             margin:2.2rem 0 .7rem; letter-spacing:-.01em; }
.artigo h3 { font-size:1rem; font-weight:700; margin:1.5rem 0 .5rem; }
.artigo p { margin:.85rem 0; font-size:.98rem; line-height:1.7; color:#2b261f; }
.artigo ul, .artigo ol { margin:.85rem 0 .85rem 1.2rem; font-size:.98rem; line-height:1.7; }
.artigo li { margin:.35rem 0; }
/* sublinhado só nos links de TEXTO — card e CTA são blocos, não links de leitura */
.artigo a:not(.card):not(.cta-hub) { color:var(--accent-600); text-decoration:underline;
                                     text-underline-offset:2px; }
.artigo strong { font-weight:700; }
.artigo table { width:100%; border-collapse:collapse; margin:1.2rem 0; font-size:.9rem; }
.artigo th, .artigo td { border-bottom:1px solid var(--line); padding:.5rem .4rem;
                         text-align:left; vertical-align:top; }
.artigo th { color:var(--soft); font-size:.7rem; font-weight:800;
             letter-spacing:.08em; text-transform:uppercase; }
/* A "conta" dos guias: bloco ``` do markdown, que só virou <pre><code> em
   26/08/2026, quando `fenced_code` entrou. Não é código-fonte — é uma fórmula de
   compra —, então nada de tema de editor: caixa clara e monoespaçada só para os
   números alinharem. `overflow-x:auto` porque a linha da fórmula não quebra e no
   celular ela estouraria a folha. */
.artigo pre { background:#f0ece3; border:1px solid var(--line); border-radius:var(--radius-sm);
              padding:.85rem 1rem; margin:1.1rem 0; overflow-x:auto; }
.artigo pre code { font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
                   font-size:.82rem; line-height:1.65; color:#2b261f;
                   /* pre-wrap, não pre: a linha longa QUEBRA em vez de exigir
                      rolagem lateral. Medido no celular em 26/08/2026 — a conta
                      do guia de controle tem 466px de conteúdo numa caixa de
                      322px, e "preço do original ÷ preço do compatível" ficava
                      cortada. É fórmula para ler, não código para copiar: quebrar
                      preserva o sentido, rolar esconde metade. A indentação das
                      linhas continua valendo, e o overflow-x acima segue como
                      rede para o que não quebra (uma palavra longa demais). */
                   white-space:pre-wrap; overflow-wrap:anywhere; }
/* Citação/aviso do markdown (`>`). Sem esta regra o blockquote saía com
   margin:0 e sem nenhuma marca visual — indistinguível do parágrafo ao lado.
   Medido no celular em 26/08/2026 no guia de antipulgas, onde o `>` carrega o
   aviso de que antipulgas é MEDICAMENTO e quem indica a dose é o veterinário:
   um aviso de segurança lido como texto corrido, e sem nem o respiro de
   parágrafo. Barra lateral + fundo, não itálico: é aviso para ler, não citação
   literária, e itálico em bloco longo atrapalha a leitura. */
.artigo blockquote { margin:1.1rem 0; padding:.8rem 1rem; background:var(--accent-50);
                     border-left:3px solid var(--accent); border-radius:0 var(--radius-sm) var(--radius-sm) 0; }
.artigo blockquote p { margin:.4rem 0; }
.artigo blockquote p:first-child { margin-top:0; }
.artigo blockquote p:last-child { margin-bottom:0; }
/* code fora de bloco: termo técnico no meio da frase */
.artigo :not(pre) > code { font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
                           font-size:.86em; background:#f0ece3; border-radius:4px;
                           padding:.08em .32em; }
.dek { font-size:1.05rem; color:var(--muted); line-height:1.6; }
.datas { color:var(--soft); font-size:.75rem; margin-top:.9rem; }
.migalha { padding:1rem 1.6rem 0; font-size:.78rem; color:var(--soft); }
.migalha a { color:var(--muted); text-decoration:none; }
.migalha a:hover { color:var(--accent-600); text-decoration:underline; }
/* Bloco de produtos dentro do guia: separado do texto por hairline */
.bloco-produtos { border-top:1px solid var(--line); margin-top:2.4rem; padding-top:1.4rem; }
.bloco-produtos h2 { margin-top:0; }
.aviso-preco { color:var(--soft); font-size:.78rem; font-style:italic; margin-top:.6rem; }
.cta-hub { display:inline-block; margin-top:1.6rem; background:var(--accent);
           color:var(--card); border-radius:999px; padding:.55rem 1.1rem;
           font-weight:700; font-size:.85rem; text-decoration:none; }
.cta-hub:hover { background:var(--accent-600); }
/* Lista de guias no hub */
.guias { border-top:1px solid var(--line); margin-top:2.4rem; padding-top:1.3rem; }
.guias h2 { font-family:"Fraunces",Georgia,serif; font-size:1.2rem; font-weight:600;
            margin-bottom:.9rem; }
.lista-guias { display:grid; grid-template-columns:repeat(auto-fill,minmax(280px,1fr));
               gap:.8rem; }
.item-guia { border:1px solid var(--line); border-radius:var(--radius-sm);
             padding:.9rem 1rem; text-decoration:none; color:inherit;
             background:var(--card); box-shadow:var(--shadow);
             transition:transform .18s var(--ease-out), box-shadow .18s var(--ease-out); }
.item-guia:hover { transform:translateY(-2px); box-shadow:var(--shadow-md); }
.item-guia h3 { font-size:.95rem; font-weight:700; margin-bottom:.3rem; }
.item-guia p { color:var(--muted); font-size:.83rem; }
/* Mais vendidos por departamento (Amazon): mesma lista, itens mais baixos */
.guias .sub-secao { color:var(--muted); font-size:.88rem; margin:-.4rem 0 .9rem; }
.item-depto { padding:.7rem .9rem; }
.item-depto p { font-size:.78rem; }

/* Voltar ao topo — só no hub. Medido no celular em 26/08/2026: sem filtro são
   828 cards e 289.260 px de altura (356 telas de 812 px), e nada na página é
   sticky, então quem rolava não tinha caminho de volta aos filtros. Só aparece
   depois de 2 telas: em vista filtrada (11 cards, 10,6 telas) ele não atrapalha.
   48px de alvo — acima do mínimo de 44px para toque. */
   Mostrar/esconder é `display`, NÃO opacity+visibility com transição: a 1ª
   versão usava a dupla animada e, medido em 26/08/2026, o botão continuava
   `visibility:hidden` mesmo com a classe `.vis` aplicada e 400 ms de espera —
   com a regra correta no arquivo, na ordem certa e com especificidade maior.
   Não valia mais tempo de investigação: a animação é enfeite, o botão é
   função. `display` não depende de transição e funciona em qualquer motor. */
   O padrão é VISÍVEL e o JS só ESCONDE perto do topo — nunca o contrário.
   Medido em 26/08/2026: neste navegador o `scrollTo` programático rola a página
   sem emitir evento `scroll` (contador de eventos zerado com scrollY em 2000),
   e a rolagem real não pôde ser testada porque o painel trava com os 304.431 px
   do hub. Ou seja, não dá para provar aqui que o listener roda. Com o padrão
   invertido isso deixa de importar: JS mudo = botão sempre à mão, que é o
   comportamento aceitável numa página de 356 telas; JS vivo = ele some no topo,
   onde os filtros já estão na tela. A falha cai do lado seguro. */
.ao-topo { position:fixed; right:1rem; bottom:1rem; width:48px; height:48px;
           display:flex; align-items:center; justify-content:center;
           background:var(--accent); color:#fff; border:none; border-radius:50%;
           box-shadow:var(--shadow-md); cursor:pointer; z-index:20; }
.ao-topo.no-topo { display:none; }
.ao-topo:hover { background:var(--accent-600); }
.ao-topo:focus-visible { outline:2px solid var(--accent-600); outline-offset:3px; }
