/*
  O desenho do catálogo em PDF: a folha que o Chrome imprime.

  Este é o desenho que o Natan aprovou em 19/09/2026 ("desde que seja feito
  exatamente como me mostrou"), passado do protótipo sem mudar medida, cor
  ou texto. O que entrou depois da aprovação:
  - o selo "Feito na Ktalogu" na contracapa (pedido dele);
  - as escolhas da tela (sem preço, sem tabela de quantidade, sem botão);
  - a loja sem WhatsApp, que o protótipo não tinha: o catálogo leva para a
    loja em vez de mostrar um número vazio.

  Dois formatos:
  - celular (450 × 800, 9:16): o catálogo que vai no WhatsApp. Cada página
    cabe numa tela de celular sem precisar dar zoom.
  - a4 (210 × 297 mm): para imprimir ou mandar por e-mail.

  As cores e a logo vêm da loja (`marca.ts` decide); aqui só se usam os
  tokens. Sem degradê: campos de cor chapada, foto grande e preço grande.
*/

import { emDestaque, type OpcoesDoCatalogo } from "./opcoes.ts";
import type { CategoriaDoCatalogo, LojaDoCatalogo, ProdutoDoCatalogo } from "./produtos.ts";

/* Para onde o selo da contracapa leva. */
export const ENDERECO_DO_SELO = "https://ktalogu.com.br/?utm_source=catalogo-pdf";

const esc = (valor: unknown) =>
  String(valor ?? "")
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;");

const ICONE = {
  seta: '<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path d="M5 12h13M12.5 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"/></svg>',
  whats:
    '<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M17.47 14.38c-.3-.15-1.76-.87-2.03-.97-.27-.1-.47-.15-.67.15-.2.3-.77.97-.94 1.16-.17.2-.35.22-.64.08-.3-.15-1.26-.47-2.39-1.48-.88-.79-1.48-1.76-1.65-2.06-.17-.3-.02-.46.13-.61.13-.13.3-.35.45-.52.15-.17.2-.3.3-.5.1-.2.05-.37-.03-.52-.07-.15-.67-1.61-.92-2.2-.24-.58-.49-.5-.67-.51h-.57c-.2 0-.52.07-.8.37-.27.3-1.04 1.02-1.04 2.48s1.07 2.88 1.21 3.07c.15.2 2.1 3.2 5.08 4.49.71.31 1.26.49 1.7.63.71.23 1.36.2 1.87.12.57-.09 1.76-.72 2-1.41.25-.7.25-1.29.17-1.41-.07-.13-.27-.2-.57-.35M12.05 21.79h-.01a9.87 9.87 0 0 1-5.03-1.38l-.36-.21-3.74.98 1-3.65-.24-.37a9.86 9.86 0 0 1-1.51-5.26c0-5.45 4.44-9.88 9.89-9.88 2.64 0 5.12 1.03 6.99 2.9a9.83 9.83 0 0 1 2.89 6.99c0 5.45-4.44 9.88-9.88 9.88m8.41-18.3A11.82 11.82 0 0 0 12.05 0C5.5 0 .16 5.34.16 11.89c0 2.1.55 4.14 1.59 5.95L.06 24l6.3-1.65a11.88 11.88 0 0 0 5.68 1.45h.01c6.55 0 11.89-5.34 11.89-11.89 0-3.18-1.24-6.16-3.48-8.41"/></svg>',
  insta:
    '<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="5.2" fill="none" stroke="currentColor" stroke-width="2"/><circle cx="12" cy="12" r="4.1" fill="none" stroke="currentColor" stroke-width="2"/><circle cx="17.4" cy="6.6" r="1.25" fill="currentColor"/></svg>',
  pino: '<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 21.2s-6.8-6-6.8-11.1a6.8 6.8 0 0 1 13.6 0c0 5.1-6.8 11.1-6.8 11.1Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/><circle cx="12" cy="10" r="2.3" fill="currentColor"/></svg>',
  sacola:
    '<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path d="M5.5 8h13l-1 12.2a1 1 0 0 1-1 .8H7.5a1 1 0 0 1-1-.8L5.5 8Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/><path d="M9 10V6.8a3 3 0 0 1 6 0V10" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>',
  /* O símbolo da Ktalogu (public/brand-symbol.svg), na cor do texto em volta. */
  ktalogu:
    '<svg class="ic" viewBox="0 0 30.3829 22.3696" aria-hidden="true"><path fill="currentColor" fill-rule="evenodd" d="M20.4013 6.2455c0,1.8645 1.4649,3.3761 3.2718,3.3761 1.807,0 3.2719,-1.5116 3.2719,-3.3761 0,-1.3228 -0.7374,-2.4677 -1.811,-3.0216 -0.3809,-0.2196 -0.8399,-0.3491 -1.3812,-0.3537 -0.0265,-0.0007 -0.0531,-0.001 -0.0797,-0.001 -1.9026,0 -3.2718,1.4804 -3.2718,3.3762zm9.9816 -6.0149l-3.5651 0.011 -0.2411 1.004c-9.417,-5.4408 -13.0042,8.5704 -5.2432,10.795 2.8855,0.8272 3.9518,-0.2815 5.1274,-0.901 -0.1985,3.7645 -3.225,6.2775 -6.685,7.1752 -2.7836,0.7219 -6.5949,0.4224 -9.0819,-1.0501 -2.0888,-1.2367 -3.7669,-2.8517 -4.658,-5.0073 -0.4391,-1.0623 -0.3781,-1.4465 -0.6328,-2.5599 -0.402,-1.7573 -3.0778,-2.0472 -3.7612,-0.3761 -0.9162,2.2399 1.8613,7.0969 3.8342,8.7977 1.214,1.0467 2.1538,1.785 3.8695,2.6047 3.4174,1.6329 7.2874,2.0804 10.9866,1.2091 3.1526,-0.7427 6.2451,-2.5775 8.0142,-5.3544 1.1843,-1.8588 2.0211,-3.9501 2.0561,-6.165l-0.0196 -10.1828z"/><circle cx="3.2687" cy="3.2687" r="3.2688" fill="currentColor"/></svg>',
};

/* ------------------------------------------------------------------ */
/* Pedaços                                                             */

function partesDoPreco(valor: number) {
  const [inteiro, centavos] = Number(valor || 0).toFixed(2).split(".");
  return { inteiro: Number(inteiro).toLocaleString("pt-BR"), centavos };
}

function numero(valor: number) {
  return Number(valor).toLocaleString("pt-BR", { maximumFractionDigits: 2 });
}

function reais(valor: number) {
  const { inteiro, centavos } = partesDoPreco(valor);
  return `${inteiro},${centavos}`;
}

/* "em pedidos de 500 un" / "acima de 20 m²" */
function referencia(p: ProdutoDoCatalogo) {
  if (p.preco.tipo !== "normal" || !p.preco.quantidadeRef) return "";
  return p.preco.unidade === "m²" ? `acima de ${numero(p.preco.quantidadeRef)} m²` : `em pedidos de ${numero(p.preco.quantidadeRef)} un`;
}

/* O preço do cartão pequeno: sem a referência, que vai ao lado do botão. */
function precoDoCartao(p: ProdutoDoCatalogo) {
  if (p.preco.tipo === "consulta") return `<div class="preco consulta"><span class="valor">Sob consulta</span></div>`;
  const { inteiro, centavos } = partesDoPreco(p.preco.valor);
  const longo = inteiro.length >= 4;
  /* A quantidade mora no rótulo: "a partir de 500 un". Numa linha à parte,
     espremida ao lado do botão, ela era cortada e "500" virava "50…". */
  const quantidade = p.preco.quantidadeRef ? ` ${numero(p.preco.quantidadeRef)} ${p.preco.unidade}` : "";
  const rotulo = p.preco.aPartirDe ? `a partir de${quantidade}` : "";
  return `<div class="preco ${longo ? "longo" : ""}">
    ${rotulo ? `<span class="apartir">${esc(rotulo)}</span>` : ""}
    <span class="valor"><span class="rs">R$</span><span class="int">${inteiro}</span><span class="cent">,${centavos}</span><span class="un">/${esc(p.preco.unidade)}</span></span>
  </div>`;
}

function blocoDePreco(p: ProdutoDoCatalogo, { classe = "" } = {}) {
  if (p.preco.tipo === "consulta") {
    return `<div class="preco consulta ${classe}"><span class="valor">Sob consulta</span><span class="ref">o valor sai no orçamento</span></div>`;
  }
  const { inteiro, centavos } = partesDoPreco(p.preco.valor);
  return `<div class="preco ${classe}">
    ${p.preco.aPartirDe ? '<span class="apartir">a partir de</span>' : ""}
    <span class="valor"><span class="rs">R$</span><span class="int">${inteiro}</span><span class="cent">,${centavos}</span><span class="un">/${esc(p.preco.unidade)}</span></span>
    ${referencia(p) ? `<span class="ref">${esc(referencia(p))}</span>` : ""}
  </div>`;
}

function bolinhas(cores: ProdutoDoCatalogo["cores"], limite = 6) {
  if (!cores.length) return "";
  const vistas = cores.slice(0, limite);
  const resto = cores.length - vistas.length;
  return `<span class="bolinhas">${vistas
    .map((cor) => `<i style="background:${esc(cor.hex)}" class="${cor.anel ? "anel" : ""}" title="${esc(cor.label)}"></i>`)
    .join("")}${resto > 0 ? `<em>+${resto}</em>` : ""}</span>`;
}

/* Uma linha só, para o cartão pequeno: as cores, ou as opções escritas. */
function linhaDeOpcoes(p: ProdutoDoCatalogo) {
  if (p.cores.length) return `<div class="opcoes-linha">${bolinhas(p.cores)}<span>${p.cores.length} ${p.cores.length === 1 ? "cor" : "cores"}</span></div>`;
  const primeira = p.opcoes[0];
  if (!primeira) return "";
  return `<div class="opcoes-linha"><span class="texto-opcoes">${esc(primeira.itens.map((item) => item.label).join(" · "))}</span></div>`;
}

function escada(p: ProdutoDoCatalogo, { compacta = false } = {}) {
  if (p.preco.tipo === "consulta" || p.faixas.length < 2) return "";
  const un = p.preco.unidade;
  if (compacta) {
    return `<div class="escada-mini">${p.faixas
      .slice(0, 3)
      .map((faixa, i, lista) => `<span class="${i === lista.length - 1 ? "melhor" : ""}"><small>${numero(faixa.min)}${faixa.max ? "" : "+"} ${un}</small><b>${reais(faixa.valor)}</b></span>`)
      .join("")}</div>`;
  }
  return `<div class="escada">
    <div class="escada-titulo"><span>Quanto mais, menos paga</span>${p.economia ? `<b class="economia">até -${p.economia}%</b>` : ""}</div>
    ${p.faixas
      .map((faixa, i, lista) => {
        const ate = faixa.max ? `a ${numero(faixa.max)}` : "ou mais";
        return `<div class="degrau ${i === lista.length - 1 ? "melhor" : ""}"><span>${numero(faixa.min)} ${ate} ${esc(un)}</span><b>R$ ${reais(faixa.valor)}</b></div>`;
      })
      .join("")}
  </div>`;
}

type TamanhoDaFoto = "fotoCartao" | "fotoGrande" | "fotoCapa" | "fotoMini";

function foto(p: ProdutoDoCatalogo, tamanho: TamanhoDaFoto, loja: LojaDoCatalogo) {
  /* Produto recortado em fundo branco entra inteiro e "some" no quadro da
     cor da loja; foto de ambiente preenche o quadro. */
  const endereco = p[tamanho];
  if (endereco) return `<img class="${p.recorte ? "recorte" : "cena"}" src="${esc(endereco)}" alt="${esc(p.nome)}" loading="eager" />`;
  /* Sem foto: a silhueta da logo na cor da marca, num quadro claro. O nome
     do produto já está logo abaixo; repetir aqui só pesa. */
  const logo = loja.logo.placeholder;
  if (logo.modo === "silhueta") return `<div class="sem-foto"><i class="silhueta"></i></div>`;
  if (logo.modo === "imagem") return `<div class="sem-foto"><img class="marca-dagua" src="${esc(logo.url)}" alt="" /></div>`;
  return `<div class="sem-foto"><b>${esc(p.nome.slice(0, 1))}</b></div>`;
}

function logoSobre(loja: LojaDoCatalogo, fundo: "naMarca" | "noClaro", classe = "") {
  const variante = loja.logo[fundo];
  if (!variante?.url) return `<span class="logo-texto ${classe}">${esc(loja.nome)}</span>`;
  return `<span class="logo ${classe} ${variante.placa ? `placa placa-${variante.placa}` : ""}"><img src="${esc(variante.url)}" alt="${esc(loja.nome)}" /></span>`;
}

function destinoDoProduto(p: ProdutoDoCatalogo, opcoes: OpcoesDoCatalogo) {
  if (opcoes.botao === "whatsapp") return p.linkWhatsapp;
  if (opcoes.botao === "nenhum") return null;
  return p.url;
}

function botao(opcoes: OpcoesDoCatalogo, { classe = "" } = {}) {
  if (opcoes.botao === "nenhum") return "";
  if (opcoes.botao === "whatsapp") return `<span class="botao botao-whats ${classe}">${ICONE.whats}<span>Pedir no WhatsApp</span></span>`;
  return `<span class="botao ${classe}"><span>Comprar</span>${ICONE.seta}</span>`;
}

function cabecalho(loja: LojaDoCatalogo, titulo: string, numeroDaPagina: number) {
  return `<header class="cabecalho">
    <div class="cab-esq">${logoSobre(loja, "noClaro", "logo-pequena")}</div>
    <div class="cab-dir"><span class="cab-categoria">${esc(titulo)}</span><span class="cab-pagina">${String(numeroDaPagina).padStart(2, "0")}</span></div>
  </header>`;
}

function rodape(loja: LojaDoCatalogo) {
  /* Sem WhatsApp, o pedido é feito na loja: o rodapé leva para ela. */
  if (!loja.whatsapp) {
    return `<footer class="rodape">
    <a class="rod-whats" href="${esc(loja.urlDaLoja)}">${ICONE.sacola}<span>Peça pela loja <b>${esc(loja.urlCurta)}</b></span></a>
  </footer>`;
  }
  return `<footer class="rodape">
    <a class="rod-whats" href="${esc(loja.whatsapp.link)}">${ICONE.whats}<span>Peça pelo WhatsApp <b>${esc(loja.whatsapp.rotulo)}</b></span></a>
    <span class="rod-loja">${esc(loja.urlCurta)}</span>
  </footer>`;
}

/* "a partir de R$ 6,40", só quando a pessoa escolheu mostrar preço. */
function aPartirDaCategoria(cat: CategoriaDoCatalogo, opcoes: OpcoesDoCatalogo, negrito: boolean) {
  if (!opcoes.mostrarPreco || !cat.menorPreco) return "";
  const valor = `R$ ${reais(cat.menorPreco)}`;
  return ` · a partir de ${negrito ? `<b>${valor}</b>` : valor}`;
}

/* ------------------------------------------------------------------ */
/* Páginas                                                             */

function capa(loja: LojaDoCatalogo, opcoes: OpcoesDoCatalogo) {
  const comFoto = loja.destaquesDaCapa.filter((p) => p.fotoCapa);
  const quantas = opcoes.formato === "a4" ? (comFoto.length >= 8 ? 8 : comFoto.length >= 4 ? 4 : 0) : comFoto.length >= 6 ? 6 : comFoto.length >= 3 ? 3 : 0;
  const vitrine = comFoto.slice(0, quantas);
  const contatos = [
    loja.whatsapp ? `<a href="${esc(loja.whatsapp.link)}">${ICONE.whats}${esc(loja.whatsapp.rotulo)}</a>` : `<a href="${esc(loja.urlDaLoja)}">${ICONE.sacola}${esc(loja.urlCurta)}</a>`,
    loja.instagram ? `<a href="${esc(loja.instagram.link)}">${ICONE.insta}${esc(loja.instagram.rotulo)}</a>` : "",
  ];
  return `<section class="pagina capa ${quantas ? "" : "capa-so-texto"}">
    <div class="capa-topo">${logoSobre(loja, "naMarca", "logo-capa")}</div>
    <div class="capa-titulo">
      <span class="rotulo">${esc(opcoes.titulo)}</span>
      <h1>${esc(opcoes.subtitulo || loja.slogan || loja.nome)}</h1>
    </div>
    ${quantas ? `<div class="capa-vitrine">${vitrine.map((p) => `<a class="capa-foto" href="${esc(p.url)}">${foto(p, "fotoCapa", loja)}</a>`).join("")}</div>` : ""}
    <div class="capa-rodape">
      <div class="capa-numeros">
        <span><b>${loja.totais.produtos}</b> ${loja.totais.produtos === 1 ? "produto" : "produtos"}</span>
        <span><b>${loja.totais.categorias}</b> ${loja.totais.categorias === 1 ? "categoria" : "categorias"}</span>
      </div>
      <div class="capa-contatos">
        ${contatos[0]}
        ${contatos[1]}
      </div>
    </div>
  </section>`;
}

function indice(loja: LojaDoCatalogo, mapa: Record<string, number>, opcoes: OpcoesDoCatalogo) {
  return `<section class="pagina indice">
    <div class="indice-topo">
      <span class="rotulo">Neste catálogo</span>
      <h2>Toque numa categoria e vá direto</h2>
    </div>
    <ol class="indice-lista">
      ${loja.categorias
        .map(
          (cat) => `<li><a href="#cat-${esc(cat.id)}">
            <span class="indice-fotos">${cat.produtos
              .filter((p) => p.fotoMini)
              .slice(0, 3)
              .map((p) => `<img src="${esc(p.fotoMini)}" alt="" />`)
              .join("")}</span>
            <span class="indice-nome"><b>${esc(cat.nome)}</b><small>${cat.produtos.length} ${cat.produtos.length === 1 ? "produto" : "produtos"}${aPartirDaCategoria(cat, opcoes, false)}</small></span>
            <span class="indice-pagina">p. ${mapa[cat.id]}</span>
          </a></li>`
        )
        .join("")}
    </ol>
    <a class="indice-loja" href="${esc(loja.urlDaLoja)}">
      <span class="qr">${loja.qrSvg}</span>
      <span><b>Prefere ver na loja?</b><small>Aponte a câmera para o código ou toque aqui: ${esc(loja.urlCurta)}</small></span>
    </a>
  </section>`;
}

function divisor(loja: LojaDoCatalogo, cat: CategoriaDoCatalogo, opcoes: OpcoesDoCatalogo) {
  const fotos = cat.produtos.filter((p) => p.fotoGrande).slice(0, 3);
  return `<section class="pagina divisor" id="cat-${esc(cat.id)}">
    <div class="divisor-texto">
      <span class="rotulo">Categoria</span>
      <h2>${esc(cat.nome)}</h2>
      <p>${cat.produtos.length} ${cat.produtos.length === 1 ? "produto" : "produtos"}${aPartirDaCategoria(cat, opcoes, true)}</p>
    </div>
    ${
      fotos.length
        ? `<div class="divisor-fotos n${fotos.length}">${fotos.map((p) => `<a href="${esc(p.url)}">${foto(p, "fotoGrande", loja)}</a>`).join("")}</div>`
        : `<ul class="divisor-lista">${cat.produtos.slice(0, 8).map((p) => `<li><a href="${esc(p.url)}">${esc(p.nome)}</a></li>`).join("")}</ul>`
    }
  </section>`;
}

function cartao(loja: LojaDoCatalogo, p: ProdutoDoCatalogo, opcoes: OpcoesDoCatalogo, extras: { categoria?: string | null; ancora?: string | null } = {}) {
  const destino = destinoDoProduto(p, opcoes);
  const ancora = extras.ancora ? ` id="cat-${esc(extras.ancora)}"` : "";
  const abre = destino ? `<a class="cartao" href="${esc(destino)}"${ancora}>` : `<div class="cartao"${ancora}>`;
  const fecha = destino ? "</a>" : "</div>";
  const comEscada = opcoes.mostrarPreco && opcoes.mostrarEscada;
  return `${abre}
    <div class="cartao-foto">${foto(p, "fotoCartao", loja)}${p.minimo ? `<span class="selo">Mín. ${numero(p.minimo)} ${esc(p.preco.unidade)}</span>` : ""}${extras.categoria ? `<span class="selo-categoria">${esc(extras.categoria)}</span>` : ""}</div>
    <div class="cartao-corpo">
      <h3>${esc(p.nome)}</h3>
      ${opcoes.formato === "a4" && p.descricao ? `<p class="cartao-desc">${esc(p.descricao)}</p>` : ""}
      ${linhaDeOpcoes(p)}
      ${opcoes.formato === "a4" && comEscada ? escada(p, { compacta: true }) : ""}
      <div class="cartao-base">
        ${opcoes.mostrarPreco ? precoDoCartao(p) : ""}
        <div class="cartao-acao">
          ${comEscada && (p.economia ?? 0) >= 5 ? `<span class="economia">até -${p.economia}%</span>` : "<span></span>"}
          ${botao(opcoes)}
        </div>
      </div>
    </div>
  ${fecha}`;
}

function paginaDeVitrine(loja: LojaDoCatalogo, cat: CategoriaDoCatalogo, produtos: ProdutoDoCatalogo[], opcoes: OpcoesDoCatalogo, n: number, ancorar: boolean) {
  return `<section class="pagina vitrine" ${ancorar ? `id="cat-${esc(cat.id)}"` : ""}>
    ${cabecalho(loja, cat.nome, n)}
    <div class="grade">${produtos.map((p) => cartao(loja, p, opcoes)).join("")}</div>
    ${rodape(loja)}
  </section>`;
}

type ItemDaFila = { p: ProdutoDoCatalogo; cat: CategoriaDoCatalogo };

/* Várias categorias pequenas numa página só. O cabeçalho diz quais são, e
   cada foto leva o nome da sua. A âncora do índice vai no primeiro produto
   de cada categoria no catálogo inteiro (`ancoradas` atravessa as páginas):
   categoria que continua na página seguinte não repete a âncora. */
function paginaMisturada(loja: LojaDoCatalogo, itens: ItemDaFila[], opcoes: OpcoesDoCatalogo, n: number, ancoradas: Set<string>) {
  const nomes = [...new Set(itens.map((item) => item.cat.nome))];
  return `<section class="pagina vitrine">
    ${cabecalho(loja, nomes.join(" · "), n)}
    <div class="grade">${itens
      .map((item) => {
        const primeira = !ancoradas.has(item.cat.id);
        ancoradas.add(item.cat.id);
        return cartao(loja, item.p, opcoes, { categoria: nomes.length > 1 ? item.cat.nome : null, ancora: primeira ? item.cat.id : null });
      })
      .join("")}</div>
    ${rodape(loja)}
  </section>`;
}

function paginaDeDestaque(loja: LojaDoCatalogo, cat: CategoriaDoCatalogo, p: ProdutoDoCatalogo, opcoes: OpcoesDoCatalogo, n: number, ancorar: boolean) {
  const destino = destinoDoProduto(p, opcoes);
  const extras = (p.fotosExtras || []).slice(0, 2);
  const comBotoes = opcoes.botao !== "nenhum";
  const comprar = comBotoes && destino && opcoes.botao !== "whatsapp" ? `<a class="botao" href="${esc(p.url)}">${ICONE.sacola}<span>Comprar na loja</span></a>` : "";
  const pedir = comBotoes && loja.whatsapp ? `<a class="botao botao-contorno" href="${esc(p.linkWhatsapp)}">${ICONE.whats}<span>Pedir no WhatsApp</span></a>` : "";
  return `<section class="pagina destaque" ${ancorar ? `id="cat-${esc(cat.id)}"` : ""}>
    <div class="destaque-foto">
      ${foto(p, "fotoGrande", loja)}
      ${p.minimo ? `<span class="selo">Pedido mínimo ${numero(p.minimo)} ${esc(p.preco.unidade)}</span>` : ""}
      ${extras.length ? `<span class="destaque-extras">${extras.map((url) => `<img src="${esc(url)}" alt="" />`).join("")}</span>` : ""}
    </div>
    <div class="destaque-corpo">
      <span class="rotulo">${esc(cat.nome)}</span>
      <h2>${esc(p.nome)}</h2>
      ${p.descricao ? `<p class="destaque-desc">${esc(p.descricao)}</p>` : ""}
      ${[
        p.cores.length
          ? `<div class="atributo"><span class="atributo-nome">${esc(p.nomeDasCores || "Cores")}</span><span class="fichas">${p.cores.map((cor) => `<span class="ficha"><i style="background:${esc(cor.hex)}" class="${cor.anel ? "anel" : ""}"></i>${esc(cor.label)}</span>`).join("")}</span></div>`
          : "",
        ...p.opcoes.map(
          (attr) =>
            `<div class="atributo"><span class="atributo-nome">${esc(attr.nome)}</span><span class="fichas">${attr.itens
              .map((item) => `<span class="ficha">${esc(item.label)}${item.delta ? ` <em>${item.delta > 0 ? "+" : "−"}R$ ${reais(Math.abs(item.delta))}</em>` : ""}</span>`)
              .join("")}</span></div>`
        ),
      ].join("")}
      ${
        opcoes.mostrarPreco
          ? `<div class="destaque-preco">
        ${blocoDePreco(p, { classe: "grande" })}
        ${opcoes.mostrarEscada ? escada(p) : ""}
      </div>`
          : ""
      }
      <div class="destaque-botoes">
        ${comprar}
        ${pedir}
      </div>
    </div>
    ${rodape(loja)}
  </section>`;
}

function contracapa(loja: LojaDoCatalogo, opcoes: OpcoesDoCatalogo) {
  const chamada = loja.whatsapp
    ? `<span class="rotulo">Gostou de algo?</span>
      <h2>Chama no WhatsApp que a gente monta seu pedido.</h2>
      <p>Manda o nome do produto e a quantidade. A resposta vem com o valor certinho e o prazo.</p>
      <a class="contra-whats" href="${esc(loja.whatsapp.link)}">${ICONE.whats}<span>${esc(loja.whatsapp.rotulo)}</span></a>`
    : `<span class="rotulo">Gostou de algo?</span>
      <h2>Faça seu pedido direto na nossa loja.</h2>
      <p>Lá tem foto, cor e preço de tudo. É só escolher a quantidade e finalizar.</p>
      <a class="contra-whats" href="${esc(loja.urlDaLoja)}">${ICONE.sacola}<span>Abrir a loja</span></a>`;
  const letras = opcoes.mostrarPreco
    ? `Preços de ${esc(loja.data)}, sujeitos a alteração sem aviso. Catálogo de ${esc(loja.nome)}.`
    : `Catálogo de ${esc(loja.nome)}, atualizado em ${esc(loja.data)}.`;
  return `<section class="pagina contracapa">
    <div class="contra-texto">
      ${chamada}
    </div>
    <a class="contra-qr" href="${esc(loja.urlDaLoja)}">
      <span class="qr">${loja.qrSvg}</span>
      <span class="contra-qr-texto"><b>Loja completa</b><small>Aponte a câmera e veja tudo com foto, cor e preço.</small><em>${esc(loja.urlCurta)}</em></span>
    </a>
    <div class="contra-contatos">
      ${loja.instagram ? `<a href="${esc(loja.instagram.link)}">${ICONE.insta}<span>${esc(loja.instagram.rotulo)}</span></a>` : ""}
      ${loja.endereco ? `<span>${ICONE.pino}<span>${esc(loja.endereco)}</span></span>` : ""}
    </div>
    <p class="contra-letras">${letras}</p>
    <a class="feito-na" href="${ENDERECO_DO_SELO}">${ICONE.ktalogu}<span>Feito na <b>Ktalogu</b></span></a>
  </section>`;
}

/* ------------------------------------------------------------------ */
/* O documento                                                          */

export type CatalogoMontado = { html: string; paginas: number };

export function montarCatalogo(loja: LojaDoCatalogo, opcoes: OpcoesDoCatalogo): CatalogoMontado {
  const destaque = emDestaque(opcoes);
  const porPagina = opcoes.formato === "a4" ? 6 : destaque ? 1 : 4;
  const paginas: (null | (() => string))[] = [];
  const mapa: Record<string, number> = {};
  paginas.push(() => capa(loja, opcoes));
  /* Índice só vale a pena com três categorias ou mais. Ele entra depois,
     quando as páginas estiverem contadas. */
  const temIndice = opcoes.indice && loja.categorias.length >= 3;
  if (temIndice) paginas.push(null);
  const posicaoDoIndice = temIndice ? 1 : -1;

  /* Categorias pequenas não ganham página própria: entram numa fila e
     dividem a página com as vizinhas. Sem isso, a loja com 1 ou 2 produtos
     por categoria virava um PDF de meias páginas em branco. */
  let fila: ItemDaFila[] = [];
  const ancoradas = new Set<string>();
  const despejarFila = () => {
    for (let i = 0; i < fila.length; i += porPagina) {
      const pedaco = fila.slice(i, i + porPagina);
      const n = paginas.length + 1;
      for (const item of pedaco) if (!mapa[item.cat.id]) mapa[item.cat.id] = n;
      paginas.push(() => paginaMisturada(loja, pedaco, opcoes, n, ancoradas));
    }
    fila = [];
  };

  for (const cat of loja.categorias) {
    const grande = destaque || cat.produtos.length >= porPagina;
    if (!grande) {
      fila.push(...cat.produtos.map((p) => ({ p, cat })));
      continue;
    }
    despejarFila();
    /* Página de abertura só para categoria que ocupa mais de uma página:
       numa loja pequena (a mediana é 9 produtos) ela viraria metade do PDF. */
    const temAbertura = opcoes.divisores && opcoes.formato === "celular" && cat.produtos.length > (destaque ? 2 : porPagina);
    if (temAbertura) {
      mapa[cat.id] = paginas.length + 1;
      paginas.push(() => divisor(loja, cat, opcoes));
    }
    for (let i = 0; i < cat.produtos.length; i += porPagina) {
      const pedaco = cat.produtos.slice(i, i + porPagina);
      const n = paginas.length + 1;
      if (i === 0 && !mapa[cat.id]) mapa[cat.id] = n;
      const ancorar = i === 0 && !temAbertura;
      if (destaque) {
        paginas.push(() => paginaDeDestaque(loja, cat, pedaco[0], opcoes, n, ancorar));
      } else {
        paginas.push(() => paginaDeVitrine(loja, cat, pedaco, opcoes, n, ancorar));
      }
    }
  }
  despejarFila();
  paginas.push(() => contracapa(loja, opcoes));
  if (posicaoDoIndice >= 0) paginas[posicaoDoIndice] = () => indice(loja, mapa, opcoes);

  const corpo = paginas.map((fazer) => (fazer ? fazer() : "")).join("\n");
  return { html: documento(loja, opcoes, corpo), paginas: paginas.length };
}

function documento(loja: LojaDoCatalogo, opcoes: OpcoesDoCatalogo, corpo: string) {
  const tamanho = opcoes.formato === "a4" ? { l: 794, a: 1123 } : { l: 450, a: 800 };
  const c = loja.cores;
  return `<!doctype html>
<html lang="pt-BR"><head><meta charset="utf-8" />
<title>${esc(opcoes.titulo)} · ${esc(loja.nome)}</title>
<link rel="preconnect" href="https://fonts.googleapis.com" /><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
${loja.fontes.folhas.map((folha) => `<link rel="stylesheet" href="${esc(folha)}" />`).join("\n")}
<style>
:root {
  --marca: ${c.marca}; --sobre-marca: ${c.sobreMarca}; --tinta-na-marca: ${c.tintaNaMarca};
  --tinta: ${c.tinta}; --sobre-tinta: ${c.sobreTinta};
  --papel: #FFFFFF; --papel-2: ${c.papel2}; --linha: ${c.linha}; --suave: ${c.suave}; --preco: ${c.preco};
  --marca-na-tinta: ${c.marcaNaTinta};
  --titulo: ${loja.fontes.titulo}; --texto: ${loja.fontes.texto};
  ${loja.logo.placeholder.modo === "silhueta" && loja.logo.placeholder.url ? `--logo: url("${loja.logo.placeholder.url}");` : ""}
  --L: ${tamanho.l}px; --A: ${tamanho.a}px;
}
@page { size: ${tamanho.l}px ${tamanho.a}px; margin: 0; }
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { background: #D8DAE0; }
body { font-family: var(--texto); color: var(--tinta); -webkit-print-color-adjust: exact; print-color-adjust: exact; font-feature-settings: "tnum" 1; }
a { color: inherit; text-decoration: none; }
img { display: block; }
.ic { width: 1em; height: 1em; flex: none; }
.pagina { width: var(--L); height: var(--A); position: relative; overflow: hidden; background: var(--papel); break-after: page; display: flex; flex-direction: column; }
.pagina:last-child { break-after: auto; }
@media screen { .pagina { margin: 0 auto 28px; box-shadow: 0 10px 40px rgba(0,0,0,.18); } }
.rotulo { font-family: var(--texto); font-weight: 700; font-size: 11px; letter-spacing: .16em; text-transform: uppercase; }

/* logo */
.logo { display: inline-flex; align-items: center; }
.logo img { height: 100%; width: auto; max-width: 100%; object-fit: contain; }
.logo.placa { border-radius: 14px; padding: 8px 12px; }
.placa-branca { background: #FFFFFF; }
.placa-tinta { background: var(--tinta); }
.logo-texto { font-family: var(--titulo); font-weight: 800; }

/* ============ CAPA ============ */
.capa { background: var(--marca); color: var(--tinta-na-marca); padding: 34px 32px 0; }
.capa-topo { height: 60px; display: flex; align-items: center; }
.logo-capa { height: 56px; }
.capa-titulo { margin-top: 30px; }
.capa-titulo .rotulo { display: inline-block; padding: 7px 12px; border-radius: 999px; background: var(--tinta); color: var(--sobre-tinta); }
.capa h1 { font-family: var(--titulo); font-weight: 800; font-size: 40px; line-height: 1.04; letter-spacing: -.02em; margin-top: 16px; text-wrap: balance; }
.capa-vitrine { margin-top: 26px; display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.capa-foto { aspect-ratio: 1; border-radius: 18px; overflow: hidden; background: #FFFFFF; }
.capa-foto img, .capa-foto .sem-foto { width: 100%; height: 100%; object-fit: cover; }
.capa-foto img.recorte { object-fit: contain; padding: 10%; }
.capa-so-texto h1 { font-size: 54px; }
.f-a4 .capa-so-texto h1 { font-size: 92px; }
.capa-rodape { margin: auto -32px 0; background: var(--tinta); color: var(--sobre-tinta); padding: 20px 32px 22px; display: flex; flex-direction: column; gap: 12px; }
.capa-numeros { display: flex; gap: 22px; font-size: 13px; }
.capa-numeros b { font-family: var(--titulo); font-size: 26px; font-weight: 800; color: var(--marca-na-tinta); margin-right: 6px; letter-spacing: -.02em; }
.capa-contatos { display: flex; flex-wrap: wrap; gap: 8px 18px; font-size: 13px; font-weight: 600; }
.capa-contatos a { display: inline-flex; align-items: center; gap: 7px; }
.capa-contatos .ic { width: 17px; height: 17px; color: var(--marca-na-tinta); }

/* ============ ÍNDICE ============ */
.indice { padding: 40px 28px 26px; border-top: 8px solid var(--marca); }
.indice-topo .rotulo { color: var(--preco); }
.indice h2 { font-family: var(--titulo); font-weight: 800; font-size: 28px; line-height: 1.08; letter-spacing: -.02em; margin-top: 10px; text-wrap: balance; }
.indice-lista { list-style: none; margin-top: 22px; }
.indice-lista li a { display: flex; align-items: center; gap: 14px; padding: 13px 0; border-bottom: 1px solid var(--linha); }
.indice-fotos { display: flex; flex: none; width: 88px; }
.indice-fotos img { width: 44px; height: 44px; border-radius: 50%; object-fit: cover; border: 3px solid #FFFFFF; margin-left: -16px; background: var(--papel-2); }
.indice-fotos img:first-child { margin-left: 0; }
.indice-nome { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.indice-nome b { font-family: var(--titulo); font-size: 15.5px; font-weight: 700; line-height: 1.15; }
.indice-nome small { font-size: 12px; color: var(--suave); }
.indice-pagina { flex: none; font-family: var(--titulo); font-weight: 800; font-size: 13px; color: var(--preco); }
.indice-loja { margin-top: auto; display: flex; align-items: center; gap: 16px; background: var(--papel-2); border-radius: 20px; padding: 16px; }
.indice-loja .qr { width: 84px; height: 84px; flex: none; background: #FFFFFF; border-radius: 12px; padding: 8px; }
.indice-loja b { display: block; font-family: var(--titulo); font-size: 16px; }
.indice-loja small { display: block; margin-top: 4px; font-size: 12px; line-height: 1.4; color: var(--suave); }
.qr svg { width: 100%; height: 100%; display: block; }

/* ============ DIVISOR ============ */
.divisor { background: var(--tinta); color: var(--sobre-tinta); padding: 44px 32px 32px; }
.divisor .rotulo { color: var(--marca-na-tinta); }
.divisor h2 { font-family: var(--titulo); font-weight: 800; font-size: 46px; line-height: 1.02; letter-spacing: -.025em; margin-top: 14px; text-wrap: balance; }
.divisor p { margin-top: 14px; font-size: 15px; opacity: .92; }
.divisor p b { color: var(--marca-na-tinta); }
.divisor-fotos { margin-top: auto; display: grid; gap: 10px; grid-template-columns: 1fr 1fr; }
.divisor-fotos a { border-radius: 22px; overflow: hidden; background: #FFFFFF; aspect-ratio: 1; }
.divisor-fotos.n3 a:first-child { grid-column: 1 / -1; aspect-ratio: 16 / 10; }
.divisor-fotos.n1 a { grid-column: 1 / -1; }
.divisor-fotos img, .divisor-fotos .sem-foto { width: 100%; height: 100%; object-fit: cover; }
.divisor-fotos img.recorte { object-fit: contain; padding: 9%; }
.divisor-lista { list-style: none; margin-top: 30px; display: flex; flex-direction: column; }
.divisor-lista li { border-top: 1px solid rgba(255,255,255,.16); }
.divisor-lista a { display: block; padding: 13px 0; font-family: var(--titulo); font-weight: 700; font-size: 17px; line-height: 1.2; }

/* ============ CABEÇALHO / RODAPÉ ============ */
.cabecalho { flex: none; height: 58px; display: flex; align-items: center; justify-content: space-between; padding: 0 18px; border-top: 6px solid var(--marca); }
.logo-pequena { height: 26px; }
.logo-pequena.placa { height: 34px; padding: 6px 10px; border-radius: 10px; }
.cab-dir { display: flex; align-items: center; gap: 10px; min-width: 0; }
.cab-categoria { font-family: var(--titulo); font-weight: 700; font-size: 13px; letter-spacing: -.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 250px; }
.cab-pagina { flex: none; font-family: var(--titulo); font-weight: 800; font-size: 11px; background: var(--tinta); color: var(--sobre-tinta); border-radius: 999px; padding: 4px 9px; }
.rodape { flex: none; height: 46px; margin-top: auto; display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 0 18px; background: var(--tinta); color: var(--sobre-tinta); font-size: 11.5px; }
.rod-whats { display: inline-flex; align-items: center; gap: 8px; }
.rod-whats .ic { width: 17px; height: 17px; color: var(--marca-na-tinta); }
.rod-loja { opacity: .75; white-space: nowrap; }

/* ============ VITRINE (cartões) ============ */
.grade { flex: 1; display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; gap: 12px 12px; padding: 2px 16px 10px; }
.cartao { display: flex; flex-direction: column; min-width: 0; }
.cartao-foto { position: relative; aspect-ratio: 1; border-radius: 18px; overflow: hidden; background: var(--papel-2); flex: none; }
.cartao-foto > img, .cartao-foto > .sem-foto { width: 100%; height: 100%; object-fit: cover; }
.cartao-foto > img.recorte, .destaque-foto > img.recorte { object-fit: contain; padding: 9%; mix-blend-mode: multiply; }
.selo { position: absolute; left: 8px; top: 8px; background: var(--tinta); color: var(--sobre-tinta); font-size: 10px; font-weight: 700; padding: 4px 8px; border-radius: 999px; letter-spacing: .01em; }
.cartao-corpo { flex: 1; display: flex; flex-direction: column; padding: 9px 2px 0; min-height: 0; }
.cartao h3 { font-family: var(--titulo); font-weight: 700; font-size: 13px; line-height: 1.2; letter-spacing: -.01em; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.opcoes-linha { display: flex; align-items: center; gap: 7px; margin-top: 6px; font-size: 11px; color: var(--suave); min-width: 0; }
.texto-opcoes { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bolinhas { display: inline-flex; align-items: center; }
.bolinhas i { width: 13px; height: 13px; border-radius: 50%; margin-right: -3px; border: 2px solid #FFFFFF; box-sizing: content-box; }
.bolinhas i.anel { box-shadow: inset 0 0 0 1px rgba(0,0,0,.18); }
.bolinhas em { font-style: normal; font-size: 10.5px; margin-left: 8px; }
.cartao-base { margin-top: auto; display: flex; flex-direction: column; gap: 3px; padding-top: 5px; }
.cartao-acao { display: flex; align-items: center; justify-content: space-between; gap: 6px; min-height: 26px; }
.economia { font-family: var(--texto); font-weight: 800; font-size: 10px; letter-spacing: .02em; color: var(--tinta); background: var(--papel-2); border-radius: 999px; padding: 4px 8px; white-space: nowrap; }
.selo-categoria { position: absolute; left: 8px; bottom: 8px; max-width: calc(100% - 16px); background: rgba(255,255,255,.94); color: var(--tinta); font-size: 9.5px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase; padding: 4px 8px; border-radius: 999px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cartao .valor .int { font-size: 23px; }
.cartao .preco.longo .int { font-size: 19px; }
.cartao .botao { height: 26px; font-size: 11px; padding: 0 10px; }
.cartao .botao .ic { width: 13px; height: 13px; }
.preco { display: flex; flex-direction: column; min-width: 0; }
.apartir { font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; color: var(--suave); }
.valor { display: flex; align-items: flex-start; color: var(--preco); font-family: var(--titulo); font-weight: 800; line-height: 1; letter-spacing: -.03em; white-space: nowrap; }
.valor .rs { font-size: 11px; margin: 3px 3px 0 0; letter-spacing: 0; }
.valor .int { font-size: 25px; }
.valor .cent { font-size: 13px; margin-top: 2px; }
.valor .un { font-family: var(--texto); font-weight: 600; font-size: 10.5px; color: var(--suave); align-self: flex-end; margin: 0 0 2px 3px; letter-spacing: 0; }
.ref { font-size: 10px; color: var(--suave); margin-top: 3px; white-space: nowrap; }
.consulta .valor { font-size: 16px; color: var(--tinta); }
.botao { display: inline-flex; align-items: center; justify-content: center; gap: 6px; flex: none; background: var(--marca); color: var(--sobre-marca); font-weight: 700; font-size: 12px; padding: 0 12px; height: 32px; border-radius: 999px; white-space: nowrap; }
.botao .ic { width: 15px; height: 15px; }
.botao-whats { padding: 0 10px; }
.botao-whats span { display: none; }

/* ============ DESTAQUE (1 por página) ============ */
.destaque-foto { position: relative; height: 392px; flex: none; background: var(--papel-2); }
.destaque-foto > img, .destaque-foto > .sem-foto { width: 100%; height: 100%; object-fit: cover; }
.destaque-foto > img.recorte { padding: 7%; }
.destaque-foto .selo { left: 18px; top: 18px; font-size: 11px; padding: 6px 11px; }
.destaque-extras { position: absolute; right: 16px; bottom: -26px; display: flex; gap: 8px; }
.destaque-extras img { width: 64px; height: 64px; border-radius: 14px; object-fit: cover; border: 3px solid #FFFFFF; box-shadow: 0 6px 16px rgba(0,0,0,.14); background: #FFFFFF; }
.destaque-corpo { padding: 18px 22px 12px; display: flex; flex-direction: column; gap: 9px; min-height: 0; flex: 1; }
.destaque-corpo .rotulo { color: var(--preco); font-size: 10px; }
.destaque h2 { font-family: var(--titulo); font-weight: 800; font-size: 23px; line-height: 1.1; letter-spacing: -.02em; max-width: 300px; text-wrap: balance; }
.destaque-desc { font-size: 12.5px; line-height: 1.45; color: var(--suave); display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.atributo { display: flex; align-items: baseline; gap: 10px; }
.atributo-nome { flex: none; width: 66px; font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; color: var(--suave); }
.fichas { display: flex; flex-wrap: wrap; gap: 5px; }
.ficha { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 600; border: 1px solid var(--linha); border-radius: 999px; padding: 4px 9px; }
.ficha i { width: 11px; height: 11px; border-radius: 50%; }
.ficha i.anel { box-shadow: inset 0 0 0 1px rgba(0,0,0,.2); }
.ficha em { font-style: normal; color: var(--preco); font-weight: 700; }
.destaque-preco { display: flex; align-items: stretch; gap: 12px; background: var(--papel-2); border-radius: 18px; padding: 12px 14px; margin-top: 2px; }
.preco.grande .int { font-size: 34px; }
.preco.grande .cent { font-size: 16px; }
.preco.grande .rs { font-size: 13px; }
.preco.grande { justify-content: center; }
.escada { flex: 1; display: flex; flex-direction: column; justify-content: center; gap: 3px; border-left: 1px solid var(--linha); padding-left: 12px; min-width: 0; }
.escada-titulo { display: flex; align-items: center; justify-content: space-between; gap: 6px; font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--suave); margin-bottom: 3px; }
.escada-titulo .economia { background: var(--tinta); color: var(--sobre-tinta); text-transform: none; font-size: 10px; }
.degrau { display: flex; justify-content: space-between; gap: 8px; font-size: 11.5px; }
.degrau b { font-family: var(--titulo); font-weight: 700; font-size: 11.5px; }
.degrau.melhor b { color: var(--preco); }
.destaque-botoes { display: flex; gap: 8px; margin-top: auto; }
.destaque-botoes .botao { flex: 1; height: 42px; font-size: 13px; }
.destaque-botoes .botao .ic { width: 17px; height: 17px; }
.botao-contorno { background: transparent; color: var(--tinta); box-shadow: inset 0 0 0 2px var(--tinta); }

/* ============ CONTRACAPA ============ */
.contracapa { background: var(--marca); color: var(--tinta-na-marca); padding: 46px 32px 26px; }
.contra-texto .rotulo { display: inline-block; padding: 7px 12px; border-radius: 999px; background: var(--tinta); color: var(--sobre-tinta); }
.contracapa h2 { font-family: var(--titulo); font-weight: 800; font-size: 36px; line-height: 1.05; letter-spacing: -.02em; margin-top: 16px; text-wrap: balance; }
.contracapa .contra-texto > p { margin-top: 14px; font-size: 15px; line-height: 1.45; max-width: 340px; }
.contra-whats { margin-top: 22px; display: inline-flex; align-items: center; gap: 12px; background: var(--tinta); color: var(--sobre-tinta); border-radius: 999px; padding: 0 24px 0 18px; height: 60px; font-family: var(--titulo); font-weight: 800; font-size: 19px; letter-spacing: -.01em; }
.contra-whats .ic { width: 28px; height: 28px; color: var(--marca-na-tinta); }
.contra-qr { margin-top: 26px; display: flex; align-items: center; gap: 16px; background: #FFFFFF; color: var(--tinta); border-radius: 22px; padding: 16px; }
.contra-qr .qr { width: 104px; height: 104px; flex: none; }
.contra-qr-texto b { display: block; font-family: var(--titulo); font-size: 17px; font-weight: 800; }
.contra-qr-texto small { display: block; margin-top: 5px; font-size: 12.5px; line-height: 1.4; color: var(--suave); }
.contra-qr-texto em { display: block; margin-top: 6px; font-style: normal; font-weight: 700; font-size: 12.5px; color: var(--preco); }
.contra-contatos { margin-top: auto; display: flex; flex-direction: column; gap: 10px; font-size: 13px; font-weight: 600; }
.contra-contatos > * { display: flex; align-items: center; gap: 9px; }
.contra-contatos .ic { width: 18px; height: 18px; }
.contra-letras { margin-top: 18px; font-size: 10.5px; opacity: .8; }
/* O selo da Ktalogu: pequeno, na cor do texto da contracapa, embaixo de tudo. */
.feito-na { margin-top: 12px; align-self: flex-start; display: inline-flex; align-items: center; gap: 6px; padding: 5px 11px 5px 9px; border-radius: 999px; font-size: 10.5px; font-weight: 600; letter-spacing: .01em; background: color-mix(in srgb, currentColor 12%, transparent); }
.feito-na .ic { width: 16px; height: 12px; }
.feito-na b { font-weight: 800; }

/* ============ SEM FOTO ============ */
.sem-foto { position: relative; display: flex; align-items: center; justify-content: center; background: var(--papel-2); color: var(--preco); }
.sem-foto .silhueta { display: block; width: 62%; height: 30%; background: var(--marca); opacity: .38; -webkit-mask: var(--logo) center / contain no-repeat; mask: var(--logo) center / contain no-repeat; }
.sem-foto .marca-dagua { width: 58%; max-height: 40%; object-fit: contain; opacity: .5; mix-blend-mode: multiply; }
.sem-foto > b { font-family: var(--titulo); font-size: 64px; line-height: 1; opacity: .35; }

/* ================================================================== */
/* A4                                                                  */
/* ================================================================== */
.f-a4 .capa { padding: 56px 56px 0; }
.f-a4 .capa-topo { height: 84px; }
.f-a4 .logo-capa { height: 76px; }
.f-a4 .capa-titulo { margin-top: 56px; }
.f-a4 .capa-titulo .rotulo { font-size: 13px; padding: 9px 16px; }
.f-a4 .capa h1 { font-size: 68px; margin-top: 22px; max-width: 640px; }
.f-a4 .capa-vitrine { margin-top: 48px; grid-template-columns: repeat(4, 1fr); gap: 14px; }
.f-a4 .capa-foto { border-radius: 22px; }
.f-a4 .capa-rodape { margin: auto -56px 0; padding: 30px 56px 32px; flex-direction: row; align-items: center; justify-content: space-between; }
.f-a4 .capa-numeros { font-size: 15px; gap: 30px; }
.f-a4 .capa-numeros b { font-size: 36px; }
.f-a4 .capa-contatos { font-size: 15px; flex-direction: column; align-items: flex-end; }
.f-a4 .cabecalho { height: 76px; padding: 0 40px; border-top-width: 8px; }
.f-a4 .logo-pequena { height: 34px; }
.f-a4 .cab-categoria { font-size: 17px; max-width: 420px; }
.f-a4 .cab-pagina { font-size: 12px; padding: 5px 11px; }
.f-a4 .grade { grid-template-columns: repeat(3, 1fr); gap: 22px 18px; padding: 8px 40px 26px; }
.f-a4 .cartao h3 { font-size: 14.5px; }
.f-a4 .economia { font-size: 10.5px; }
.f-a4 .indice { padding: 72px 64px 48px; border-top-width: 12px; }
.f-a4 .indice-topo .rotulo { font-size: 13px; }
.f-a4 .indice h2 { font-size: 46px; margin-top: 14px; }
.f-a4 .indice-lista { margin-top: 40px; }
.f-a4 .indice-lista li a { padding: 22px 0; gap: 22px; }
.f-a4 .indice-fotos { width: 150px; }
.f-a4 .indice-fotos img { width: 74px; height: 74px; margin-left: -26px; border-width: 4px; }
.f-a4 .indice-fotos img:first-child { margin-left: 0; }
.f-a4 .indice-nome b { font-size: 24px; }
.f-a4 .indice-nome small { font-size: 15px; }
.f-a4 .indice-pagina { font-size: 18px; }
.f-a4 .indice-loja { padding: 24px; gap: 24px; border-radius: 26px; }
.f-a4 .indice-loja .qr { width: 120px; height: 120px; }
.f-a4 .indice-loja b { font-size: 22px; }
.f-a4 .indice-loja small { font-size: 15px; }
.f-a4 .cartao .valor .int { font-size: 24px; }
.f-a4 .cartao .botao { height: 28px; font-size: 11.5px; }
.f-a4 .cartao-desc { margin-top: 5px; font-size: 11px; line-height: 1.4; color: var(--suave); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.f-a4 .escada-mini { display: flex; gap: 4px; margin-top: 8px; }
.escada-mini span { flex: 1; display: flex; flex-direction: column; gap: 1px; background: var(--papel-2); border-radius: 8px; padding: 5px 6px; min-width: 0; }
.escada-mini small { font-size: 9px; color: var(--suave); white-space: nowrap; }
.escada-mini b { font-family: var(--titulo); font-size: 11.5px; }
.escada-mini .melhor { background: var(--tinta); color: var(--sobre-tinta); }
.escada-mini .melhor small { color: inherit; opacity: .8; }
.f-a4 .rodape { height: 54px; padding: 0 40px; font-size: 12.5px; }
.f-a4 .contracapa { padding: 80px 72px 48px; }
.f-a4 .contracapa h2 { font-size: 60px; max-width: 600px; }
.f-a4 .contracapa .contra-texto > p { font-size: 18px; max-width: 520px; }
.f-a4 .contra-whats { height: 74px; font-size: 24px; padding: 0 32px 0 24px; }
.f-a4 .contra-whats .ic { width: 34px; height: 34px; }
.f-a4 .contra-qr { max-width: 520px; padding: 22px; }
.f-a4 .contra-qr .qr { width: 150px; height: 150px; }
.f-a4 .contra-qr-texto b { font-size: 22px; }
.f-a4 .contra-qr-texto small, .f-a4 .contra-qr-texto em { font-size: 15px; }
.f-a4 .contra-contatos { font-size: 15px; }
.f-a4 .contra-letras { font-size: 12px; }
.f-a4 .feito-na { margin-top: 14px; font-size: 12px; padding: 6px 13px 6px 11px; }
.f-a4 .feito-na .ic { width: 19px; height: 14px; }
${loja.fontes.soPesoNormal ? "html { font-synthesis: none; }" : ""}
</style></head>
<body class="f-${opcoes.formato}">
${corpo}
</body></html>`;
}
