/*
 * Carrosséis no jeito do Instagram de agora (out/2026), cinco páginas cada,
 * cada um com uma linguagem que está em alta: o fio no estilo do X, o bloco
 * de notas do celular, as janelas Y2K, o scrapbook de papel e fita, o
 * neobrutalismo de borda preta, o editorial de revista, a linha contínua que
 * atravessa as páginas e o antes e depois. Todos começam por uma capa forte,
 * levam o contador "01/05" fixo e terminam numa chamada com o contato.
 *
 * As fotos são as do depósito da Ktalogu (Unsplash e Pexels, uso comercial
 * livre); as figurinhas são do Fluent Emoji (MIT) e os ícones do Lucide (ISC).
 * Fora de 1080 × 1350 a composição encaixa inteira (`encaixar`).
 */
import { documentoDasPaginas, fonteDaChave, htmlDoTextoLimpo, novoId, paginasDoDocumento, solida, type DocumentoDoBanner, type Peca, type PecaDeForma, type PecaDeIcone, type PecaDeImagem, type PecaDeTexto, type PecaDeTextura, type PecaDeTraco, type Pintura } from "./documento";
import { ICONES_EXTRAS } from "./icones-extras";
import { documento, fundoDoBanner, imagem, texto, type CamposDoTexto, type PedidoDoModelo } from "./modelos-base";
import { encaixar } from "./modelos-colecao";
import { DEPOSITO_DAS_FIGURINHAS } from "./pecas-novas";

const DEPOSITO = "https://ptpstwltddugnnlewvbw.supabase.co/storage/v1/object/public/products/editor-modelos";
const foto$ = (nome: string) => `${DEPOSITO}/ramos/${nome}.webp`;
const W = 1080;
const H = 1350;

/* ------------------------------------------------------------ peças curtas */

type Lugar = { x: number; y: number; w: number; h: number; rot?: number };

function t(nome: string, l: Lugar, campos: CamposDoTexto): PecaDeTexto {
  return texto({ nome, ...l, rot: l.rot ?? 0, vertical: "topo", ...campos });
}

function f(nome: string, forma: PecaDeForma["forma"], l: Lugar, pintura: Pintura | string, extra: Partial<PecaDeForma> = {}): PecaDeForma {
  return { id: novoId("f"), tipo: "forma", nome, ...l, rot: l.rot ?? 0, opacidade: 1, forma, pintura: typeof pintura === "string" ? solida(pintura) : pintura, raio: 0, borda: null, sombra: null, pontas: 5, profundidade: 0.55, ...extra };
}

function foto(nome: string, src: string, l: Lugar, extra: Partial<PecaDeImagem> = {}): PecaDeImagem {
  return { ...imagem({ nome, src, ...l, rot: l.rot ?? 0, sombra: false, ajuste: "cobrir" }), ...extra };
}

/* Ícone da casa ou do Lucide (os do Lucide vão com o desenho na peça). */
function ic(nome: string, chave: string, x: number, y: number, lado: number, cor: string, extra: Partial<PecaDeIcone> = {}): PecaDeIcone {
  const desenho = ICONES_EXTRAS[chave];
  return { id: novoId("ic"), tipo: "icone", nome, x, y, w: lado, h: lado, rot: 0, opacidade: 1, icone: desenho ? `lucide-${chave}` : chave, ...(desenho ? { desenho } : {}), pintura: solida(cor), espessura: 2, preenchido: false, sombra: null, ...extra };
}

function fig(nome: string, chave: string, x: number, y: number, lado: number, extra: Partial<PecaDeImagem> = {}): PecaDeImagem {
  return foto(nome, `${DEPOSITO_DAS_FIGURINHAS}/${chave}.webp`, { x, y, w: lado, h: lado, rot: extra.rot ?? 0 }, { ajuste: "conter", ...extra });
}

function tex(nome: string, estilo: PecaDeTextura["estilo"], l: Lugar, cor: string, extra: Partial<PecaDeTextura> = {}): PecaDeTextura {
  return { id: novoId("tex"), tipo: "textura", nome, ...l, rot: l.rot ?? 0, opacidade: 0.1, bloqueada: true, estilo, cor, quantidade: 18, tamanho: 0, centroX: 50, centroY: 50, giro: 0, ...extra };
}

const linear = (cor: string, cor2: string, angulo: number): Pintura => ({ tipo: "linear", cor, cor2, angulo });
const nada: Pintura = { tipo: "nenhuma", cor: "#FFFFFF", cor2: "#FFFFFF", angulo: 0 };
const sombraDe = (cor: string, x: number, y: number, desfoque: number, opacidade: number) => ({ cor, x, y, desfoque, opacidade });

function trecho(conteudo: string, o: { cor?: string; fonte?: string; italico?: boolean; vazado?: { cor: string; largura: number } }) {
  const estilo = [
    o.cor ? `color:${o.cor}` : "",
    o.fonte ? `font-family:'${fonteDaChave(o.fonte).familia}'` : "",
    o.italico ? "font-style:italic" : "",
    o.vazado ? `color:transparent;-webkit-text-stroke:${o.vazado.largura}px ${o.vazado.cor}` : "",
  ]
    .filter(Boolean)
    .join(";");
  return `<span style="${estilo}">${conteudo}</span>`;
}
const html = (partes: string) => htmlDoTextoLimpo(partes);

/* O logo da loja; sem logo, o nome (a pessoa troca). */
function marca(p: PedidoDoModelo, x: number, y: number, h: number, cor: string, alinhamento: PecaDeTexto["alinhamento"] = "esquerda", larguraMaxima = 420, fonte = "bricolage-grotesque"): Peca {
  if (p.logo) {
    const w = Math.min(larguraMaxima, h * Math.min(6, Math.max(0.6, p.proporcaoDoLogo || 3)));
    const xx = alinhamento === "direita" ? x + larguraMaxima - w : alinhamento === "centro" ? x + (larguraMaxima - w) / 2 : x;
    return foto("Logo", p.logo, { x: xx, y, w, h }, { papel: "logo", ajuste: "conter" });
  }
  return t("Marca", { x, y, w: larguraMaxima, h }, { texto: "SUA MARCA", fonte, peso: 800, tamanho: h * 0.6, cor, espaco: 0.06, alinhamento, vertical: "meio" });
}

function contato(x: number, y: number, cor: string, tamanho = 30, fonte = "manrope"): Peca[] {
  return [ic("WhatsApp", "whatsapp-cor", x, y - tamanho * 0.05, tamanho * 1.45, cor), t("Contato", { x: x + tamanho * 1.75, y: y - tamanho * 0.15, w: tamanho * 12, h: tamanho * 1.65 }, { texto: "(00) 00000-0000", fonte, peso: 700, tamanho, cor, vertical: "meio" })];
}

/* O contador "01/05": a mesma peça em todas as páginas (mudou numa, muda em todas). */
function contador(x: number, y: number, cor: string, campos: Partial<CamposDoTexto> = {}): PecaDeTexto {
  return { ...t("Contador de páginas", { x, y, w: 150, h: 54 }, { texto: "{pagina}/{total}", fonte: "space-grotesk", peso: 700, tamanho: 24, cor, alinhamento: "centro", espaco: 0.08, vertical: "meio", ...campos }), fixa: true };
}

const carrossel = (paginas: DocumentoDoBanner[]) => documentoDasPaginas(paginas);

/* Um traço (caminho com nós) em px da página: a caixa justa em volta. */
function caminho(nome: string, pontos: Array<{ x: number; y: number; e?: { x: number; y: number }; s?: { x: number; y: number } }>, cor: string, espessura: number, extra: Partial<PecaDeTraco> = {}): PecaDeTraco {
  const todos = pontos.flatMap((q) => [q, q.e, q.s].filter(Boolean) as Array<{ x: number; y: number }>);
  const folga = espessura * 2;
  const x0 = Math.min(...todos.map((q) => q.x)) - folga;
  const y0 = Math.min(...todos.map((q) => q.y)) - folga;
  const w = Math.max(...todos.map((q) => q.x)) + folga - x0;
  const h = Math.max(...todos.map((q) => q.y)) + folga - y0;
  const fr = (q: { x: number; y: number }) => ({ x: (q.x - x0) / w, y: (q.y - y0) / h });
  return {
    id: novoId("tr"),
    tipo: "traco",
    nome,
    x: x0,
    y: y0,
    w,
    h,
    rot: 0,
    opacidade: 1,
    pontos: pontos.map((q) => ({ ...fr(q), ...(q.e ? { e: fr(q.e) } : {}), ...(q.s ? { s: fr(q.s) } : {}) })),
    fechado: false,
    suave: false,
    cor,
    espessura,
    tracejado: "solido",
    inicio: "nada",
    fim: "nada",
    preenchimento: solida(cor),
    sombra: null,
    ...extra,
  };
}

/* ================================================== 1. FIO NO ESTILO DO X */

function fioNoEstiloDoX(p: PedidoDoModelo): DocumentoDoBanner {
  const AZUL = "#1D9BF0";
  const TINTA = "#0F1419";
  const CINZA = "#536471";
  const LINHA = "#EFF3F4";
  const cnt = contador(880, 64, CINZA, { fonte: "hanken-grotesk" });
  const cabecalho = (y: number): Peca[] => [
    f("Avatar", "circulo", { x: 80, y, w: 128, h: 128 }, linear(p.cor, "#111827", 140)),
    p.logo ? foto("Logo no avatar", p.logo, { x: 102, y: y + 22, w: 84, h: 84 }, { papel: "logo", ajuste: "conter" }) : t("Inicial", { x: 80, y, w: 128, h: 128 }, { texto: "SM", fonte: "hanken-grotesk", peso: 800, tamanho: 50, cor: "#FFFFFF", alinhamento: "centro", vertical: "meio" }),
    t("Nome", { x: 236, y: y + 14, w: 520, h: 56 }, { texto: "Sua Marca", fonte: "hanken-grotesk", peso: 800, tamanho: 44, cor: TINTA }),
    ic("Selo verificado", "selo-check", 470, y + 22, 44, AZUL, { espessura: 2.6 }),
    t("Usuário", { x: 236, y: y + 70, w: 520, h: 48 }, { texto: "@suamarca", fonte: "hanken-grotesk", peso: 500, tamanho: 36, cor: CINZA }),
    ic("Mais", "mais-opcoes", 930, y + 30, 56, CINZA),
  ];
  const rodape = (y: number, numeros: [string, string, string, string]): Peca[] => [
    t("Data", { x: 80, y, w: 920, h: 44 }, { texto: `9:41 · 27 out 26 · ${numeros[3]} visualizações`, fonte: "hanken-grotesk", peso: 500, tamanho: 30, cor: CINZA }),
    f("Divisória", "retangulo", { x: 80, y: y + 74, w: 920, h: 2 }, LINHA),
    ...(
      [
        ["balao-lucide", numeros[0]],
        ["repostar", numeros[1]],
        ["coracao-cheio", numeros[2]],
        ["marcador-lucide", ""],
      ] as const
    ).flatMap(([icone, n], i) => [ic(`Ação ${i + 1}`, icone, 80 + i * 240, y + 110, 46, i === 2 ? "#F91880" : CINZA, i === 2 ? { preenchido: true, espessura: 1.4 } : { espessura: 2 }), ...(n ? [t(`Número ${i + 1}`, { x: 140 + i * 240, y: y + 110, w: 160, h: 46 }, { texto: n, fonte: "hanken-grotesk", peso: 600, tamanho: 30, cor: i === 2 ? "#F91880" : CINZA, vertical: "meio" })] : [])]),
    ic("Compartilhar", "compartilhar", 952, y + 110, 46, CINZA),
  ];
  const fundo = fundoDoBanner({ cor: "#FFFFFF", textura: "nenhuma" });
  const capa = documento(W, H, fundo, [
    cnt,
    ...cabecalho(250),
    t("Fio", {
      x: 80,
      y: 430,
      w: 930,
      h: 520,
    }, {
      texto: "Ninguém te conta isso antes de você encomendar uma caneca personalizada.\nUm fio:",
      html: html(`Ninguém te conta isso antes de você encomendar uma ${trecho("caneca personalizada", { cor: AZUL })}.<br><br>Um fio:`),
      fonte: "hanken-grotesk",
      peso: 600,
      tamanho: 66,
      linha: 1.18,
      cor: TINTA,
    }),
    ...rodape(1010, ["482", "1,2 mil", "8,9 mil", "212 mil"]),
  ]);
  const dica = (numero: number, titulo: string, corpo: string, comFoto?: string): DocumentoDoBanner =>
    documento(W, H, fundo, [
      cnt,
      ...cabecalho(comFoto ? 120 : 220),
      t("Fio", { x: 80, y: comFoto ? 290 : 400, w: 930, h: comFoto ? 380 : 540 }, {
        texto: `${numero}. ${titulo}\n${corpo}`,
        html: html(`${trecho(`${numero}. ${titulo}`, { cor: TINTA })}<br><br>${trecho(corpo, { cor: "#2B3640" })}`),
        fonte: "hanken-grotesk",
        peso: 600,
        tamanho: comFoto ? 48 : 58,
        linha: 1.2,
        cor: TINTA,
      }),
      ...(comFoto ? [foto("Foto do post", foto$(comFoto), { x: 80, y: 690, w: 920, h: 430 }, { raio: 32, borda: { cor: LINHA, largura: 3 }, enquadre: { zoom: 1, x: 50, y: 45 } })] : []),
      ...rodape(comFoto ? 1150 : 1010, [["96", "301", "45"][numero - 1], ["210", "640", "88"][numero - 1], ["2,4 mil", "5,1 mil", "1,7 mil"][numero - 1], ["48 mil", "91 mil", "33 mil"][numero - 1]]),
    ]);
  const final = documento(W, H, fundo, [
    cnt,
    ...cabecalho(250),
    t("Fio", { x: 80, y: 430, w: 930, h: 330 }, {
      texto: "Gostou? Salva este fio e chama a gente no direct pra fazer a sua.",
      html: html(`Gostou? ${trecho("Salva este fio", { cor: AZUL })} e chama a gente no direct pra fazer a sua.`),
      fonte: "hanken-grotesk",
      peso: 600,
      tamanho: 64,
      linha: 1.18,
      cor: TINTA,
    }),
    t("Botão", { x: 80, y: 820, w: 440, h: 104 }, { texto: "Pedir a minha", fonte: "hanken-grotesk", peso: 800, tamanho: 40, cor: "#FFFFFF", alinhamento: "centro", vertical: "meio", fundo: { forma: "pilula", cor: TINTA } }),
    t("Botão 2", { x: 550, y: 820, w: 330, h: 104 }, { texto: "Seguir", fonte: "hanken-grotesk", peso: 800, tamanho: 40, cor: TINTA, alinhamento: "centro", vertical: "meio", fundo: { forma: "pilula", cor: LINHA } }),
    ...contato(84, 1000, CINZA, 34, "hanken-grotesk"),
    ...rodape(1130, ["57", "130", "980", "21 mil"]).slice(0, 2),
  ]);
  return carrossel([
    capa,
    dica(1, "Foto de celular serve, sim.", "Mas mande o arquivo original, nunca o print da conversa. O print perde metade da qualidade."),
    dica(2, "Caneca branca deixa a cor viva.", "O fundo colorido muda o tom da arte. Quer a cor fiel? Peça a prova antes.", "caneca-roxo"),
    dica(3, "Sublimação não descasca.", "A tinta entra na porcelana: pode ir ao micro-ondas e à lava-louças sem medo."),
    final,
  ]);
}

/* ===================================================== 2. BLOCO DE NOTAS */

function blocoDeNotas(p: PedidoDoModelo): DocumentoDoBanner {
  const OURO = "#E0A100";
  const TINTA = "#1C1C1E";
  const CINZA = "#8E8E93";
  const PAPEL = "#FFFDF7";
  const cnt = contador(905, 52, CINZA, { fonte: "inter", tamanho: 22 });
  const barra = (): Peca[] => [
    t("Hora", { x: 70, y: 46, w: 200, h: 56 }, { texto: "9:41", fonte: "inter", peso: 700, tamanho: 34, cor: TINTA, vertical: "meio" }),
    ic("Sinal", "barra-de-sinal", 760, 52, 42, TINTA, { espessura: 2.4 }),
    ic("Bateria", "bateria", 818, 50, 48, TINTA, { espessura: 2 }),
    ic("Voltar", "voltar", 52, 140, 64, OURO, { espessura: 2.6 }),
    t("Notas", { x: 112, y: 140, w: 260, h: 64 }, { texto: "Notas", fonte: "inter", peso: 500, tamanho: 40, cor: OURO, vertical: "meio" }),
    ic("Compartilhar", "compartilhar", 860, 142, 56, OURO, { espessura: 2.2 }),
    ic("Mais", "mais-opcoes", 960, 142, 56, OURO, { espessura: 2.2 }),
  ];
  const data = (y: number) => t("Data", { x: 70, y, w: 940, h: 40 }, { texto: "27 de outubro de 2026 às 09:41", fonte: "inter", peso: 500, tamanho: 26, cor: CINZA, alinhamento: "centro" });
  const item = (texto_: string, y: number, feito: boolean, i: number): Peca[] => [
    feito ? f(`Marcado ${i}`, "circulo", { x: 76, y: y + 4, w: 56, h: 56 }, OURO) : f(`Bolinha ${i}`, "circulo", { x: 76, y: y + 4, w: 56, h: 56 }, nada, { borda: { cor: "#C7C7CC", largura: 4 } }),
    ...(feito ? [ic(`Check ${i}`, "check", 86, y + 14, 36, "#FFFFFF", { espessura: 3.4 })] : []),
    t(`Item ${i}`, { x: 160, y, w: 860, h: 64 }, { texto: texto_, fonte: "inter", peso: 500, tamanho: 42, cor: feito ? CINZA : TINTA, riscado: feito, vertical: "meio" }),
  ];
  const fundo = fundoDoBanner({ cor: PAPEL, textura: "nenhuma" });
  const pagina = (titulo: string, itens: string[], feitos: number, nota: string): DocumentoDoBanner =>
    documento(W, H, fundo, [
      cnt,
      ...barra(),
      data(262),
      t("Título", { x: 70, y: 330, w: 940, h: 180 }, { texto: titulo, fonte: "inter", peso: 800, tamanho: 76, linha: 1.08, cor: TINTA }),
      ...itens.flatMap((texto_, i) => item(texto_, 540 + i * 118, i < feitos, i + 1)),
      f("Marca-texto", "retangulo", { x: 64, y: 1046, w: 952, h: 150 }, "#FFE58A", { raio: 18, opacidade: 0.85 }),
      t("Nota", { x: 96, y: 1066, w: 890, h: 112 }, { texto: nota, fonte: "inter", peso: 600, tamanho: 36, linha: 1.25, cor: TINTA, vertical: "meio" }),
    ]);
  const capa = documento(W, H, fundo, [
    cnt,
    ...barra(),
    data(262),
    t("Título", { x: 70, y: 340, w: 940, h: 420 }, { texto: "Antes de mandar seu arquivo pra gráfica", html: html(`Antes de mandar seu arquivo ${trecho("pra gráfica", { cor: OURO })}`), fonte: "inter", peso: 800, tamanho: 104, linha: 1.04, cor: TINTA }),
    t("Texto", { x: 70, y: 800, w: 900, h: 130 }, { texto: "Salva esta nota. Ela te poupa retrabalho e dinheiro.", fonte: "inter", peso: 500, tamanho: 44, linha: 1.3, cor: "#3A3A3C" }),
    fig("Lápis", "lapis", 760, 960, 230, { rot: -18 }),
    t("Arraste", { x: 70, y: 1160, w: 560, h: 70 }, { texto: "arraste para o lado →", fonte: "caveat", peso: 700, tamanho: 50, cor: OURO }),
    marca(p, 70, 1250, 54, TINTA, "esquerda", 360, "inter"),
  ]);
  const final = documento(W, H, fundo, [
    cnt,
    ...barra(),
    data(262),
    t("Título", { x: 70, y: 330, w: 940, h: 90 }, { texto: "Tudo certo?", fonte: "inter", peso: 800, tamanho: 76, cor: TINTA }),
    ...["Tamanho e sangria", "Cor e resolução", "Fontes e arquivo"].flatMap((texto_, i) => item(texto_, 470 + i * 118, true, i + 1)),
    f("Marca-texto", "retangulo", { x: 64, y: 860, w: 952, h: 190 }, "#FFE58A", { raio: 18, opacidade: 0.85 }),
    t("Nota", { x: 96, y: 880, w: 890, h: 150 }, { texto: "Manda pra gente que a gente confere o arquivo de graça antes de imprimir.", fonte: "inter", peso: 700, tamanho: 40, linha: 1.25, cor: TINTA, vertical: "meio" }),
    ...contato(76, 1120, TINTA, 36, "inter"),
    marca(p, 640, 1240, 60, TINTA, "direita", 370, "inter"),
  ]);
  return carrossel([
    capa,
    pagina("Tamanho e sangria", ["Arquivo no tamanho final", "3 mm de sangria em cada lado", "Textos a 5 mm do corte", "Marcas de corte, se pedirem"], 0, "Sangria é a sobra da cor para fora do corte: sem ela, sobra filete branco."),
    pagina("Cor e resolução", ["Modo de cor em CMYK", "Fotos com 300 dpi", "Preto rico só em áreas grandes", "Nada de print de tela"], 0, "Tela usa RGB e a gráfica imprime em CMYK: o neon da tela não existe no papel."),
    pagina("Fontes e arquivo", ["Fontes convertidas em curvas", "PDF em alta resolução", "Um arquivo por modelo", "A medida no nome do arquivo"], 0, "Fonte sem curva vira outra letra no computador da gráfica."),
    final,
  ]);
}

/* ========================================================= 3. JANELAS Y2K */

function janelasY2k(p: PedidoDoModelo): DocumentoDoBanner {
  const CINZA = "#C3C3C3";
  const ESCURO = "#7B7B7B";
  const AZUL = "#0A246A";
  const ROSA = "#FF4FB4";
  const cnt = contador(890, 50, "#FFFFFF", { fonte: "vt323", tamanho: 40, peso: 400, fundo: { forma: "retangulo", cor: AZUL, raio: 0 } });
  /* Uma janela do Windows antigo: moldura com relevo, barra de título azul e os três botões. */
  const janela = (nome: string, x: number, y: number, w: number, h: number): Peca[] => [
    f(`${nome}: sombra`, "retangulo", { x: x + 16, y: y + 16, w, h }, "#000000", { opacidade: 0.35 }),
    f(`${nome}: moldura`, "retangulo", { x, y, w, h }, CINZA, { borda: { cor: "#FFFFFF", largura: 4 } }),
    f(`${nome}: relevo`, "retangulo", { x: x + 4, y: y + 4, w: w - 4, h: h - 4 }, nada, { borda: { cor: ESCURO, largura: 3 } }),
    f(`${nome}: barra`, "retangulo", { x: x + 10, y: y + 10, w: w - 20, h: 60 }, linear(AZUL, "#3A6EA5", 90)),
    t(`${nome}: título`, { x: x + 26, y: y + 12, w: w - 260, h: 56 }, { texto: nome, fonte: "vt323", peso: 400, tamanho: 42, cor: "#FFFFFF", vertical: "meio" }),
    ...["_", "□", "X"].flatMap((letra, i) => [
      f(`${nome}: botão ${i + 1}`, "retangulo", { x: x + w - 176 + i * 54, y: y + 20, w: 44, h: 40 }, CINZA, { borda: { cor: "#FFFFFF", largura: 2 } }),
      t(`${nome}: letra ${i + 1}`, { x: x + w - 176 + i * 54, y: y + 16, w: 44, h: 44 }, { texto: letra, fonte: "vt323", peso: 400, tamanho: 38, cor: "#000000", alinhamento: "centro", vertical: "meio" }),
    ]),
    f(`${nome}: área`, "retangulo", { x: x + 18, y: y + 82, w: w - 36, h: h - 100 }, "#FFFFFF", { borda: { cor: ESCURO, largura: 3 } }),
  ];
  const botao = (rotulo: string, x: number, y: number, w = 220): Peca[] => [
    f(`Botão ${rotulo}`, "retangulo", { x, y, w, h: 76 }, CINZA, { borda: { cor: "#000000", largura: 3 } }),
    f(`Botão ${rotulo}: luz`, "retangulo", { x: x + 4, y: y + 4, w: w - 8, h: 68 }, nada, { borda: { cor: "#FFFFFF", largura: 3 } }),
    t(`Botão ${rotulo}: texto`, { x, y: y + 4, w, h: 68 }, { texto: rotulo, fonte: "vt323", peso: 400, tamanho: 44, cor: "#000000", alinhamento: "centro", vertical: "meio" }),
  ];
  const alerta = (x: number, y: number, lado = 120): Peca[] => [
    f("Alerta", "triangulo", { x, y, w: lado, h: lado * 0.9 }, "#FFD400", { borda: { cor: "#000000", largura: 4 } }),
    t("Exclamação", { x, y: y + lado * 0.18, w: lado, h: lado * 0.7 }, { texto: "!", fonte: "vt323", peso: 400, tamanho: lado * 0.7, cor: "#000000", alinhamento: "centro", vertical: "meio" }),
  ];
  const brilhos = (lista: Array<[number, number, number]>): Peca[] => lista.map(([x, y, lado], i) => ic(`Brilho ${i + 1}`, "estrela-4", x, y, lado, "#FFFFFF", { preenchido: true, espessura: 0.5, pintura: linear("#FFFFFF", "#B8E1FF", 160) }));
  const ceu = fundoDoBanner({ cor: "#2F7BFF", cor2: "#9BD3FF", angulo: 180, textura: "nenhuma" });
  const grade = () => tex("Grade", "xadrez", { x: 0, y: 0, w: W, h: H }, "#FFFFFF", { opacidade: 0.08, tamanho: 60 });
  const capa = documento(W, H, ceu, [
    grade(),
    cnt,
    t("Título", { x: 60, y: 120, w: 960, h: 360 }, { texto: "SUA ESTAMPA\nSAIU BORRADA?", fonte: "rubik-mono-one", peso: 400, tamanho: 96, linha: 1.08, cor: "#FFFFFF", sombra: "dura" }),
    ...janela("erro_estampa.exe", 110, 560, 860, 470),
    ...alerta(170, 690),
    t("Mensagem", { x: 330, y: 680, w: 600, h: 200 }, { texto: "Não foi possível imprimir: a imagem tem resolução muito baixa.", fonte: "vt323", peso: 400, tamanho: 50, linha: 1.05, cor: "#000000" }),
    ...botao("OK", 330, 910),
    ...botao("Ajuda", 580, 910),
    ic("Cursor", "cursor", 470, 960, 90, "#000000", { preenchido: true, pintura: solida("#FFFFFF"), espessura: 1.6 }),
    ...brilhos([
      [880, 470, 90],
      [70, 1080, 70],
      [930, 1130, 110],
    ]),
    t("Arraste", { x: 60, y: 1190, w: 700, h: 70 }, { texto: "> arraste para consertar_", fonte: "vt323", peso: 400, tamanho: 54, cor: "#FFFFFF" }),
  ]);
  const erro = (n: number, titulo: string, solucao: string, figurinha: string): DocumentoDoBanner =>
    documento(W, H, ceu, [
      grade(),
      cnt,
      t("Erro", { x: 70, y: 120, w: 940, h: 90 }, { texto: `ERRO 0${n}`, fonte: "press-start-2p", peso: 400, tamanho: 58, cor: ROSA, sombra: "dura" }),
      ...janela(`erro_0${n}.exe`, 70, 250, 940, 440),
      ...alerta(130, 380),
      t("Problema", { x: 290, y: 370, w: 680, h: 280 }, { texto: titulo, fonte: "vt323", peso: 400, tamanho: 62, linha: 1.02, cor: "#000000" }),
      ...janela("solucao.txt", 130, 760, 880, 420),
      t("Solução", { x: 180, y: 880, w: 780, h: 270 }, { texto: solucao, fonte: "vt323", peso: 400, tamanho: 54, linha: 1.08, cor: AZUL }),
      fig("Figurinha", figurinha, 40, 1080, 200, { rot: -12 }),
      ...brilhos([
        [930, 170, 80],
        [980, 1210, 70],
      ]),
    ]);
  const progresso = Array.from({ length: 14 }, (_, i) => f(`Progresso ${i + 1}`, "retangulo", { x: 150 + i * 56, y: 690, w: 44, h: 60 }, AZUL));
  const final = documento(W, H, ceu, [
    grade(),
    cnt,
    ...janela("instalar_pedido.exe", 90, 260, 900, 640),
    t("Instalando", { x: 150, y: 380, w: 780, h: 220 }, { texto: "Pedido pronto para instalar na sua vida.", fonte: "vt323", peso: 400, tamanho: 66, linha: 1.02, cor: "#000000" }),
    t("Cem por cento", { x: 150, y: 620, w: 780, h: 56 }, { texto: "100% concluído", fonte: "vt323", peso: 400, tamanho: 44, cor: "#008000" }),
    f("Trilho", "retangulo", { x: 140, y: 680, w: 800, h: 80 }, "#FFFFFF", { borda: { cor: ESCURO, largura: 3 } }),
    ...progresso,
    ...botao("Chamar no WhatsApp", 150, 790, 520),
    ...contato(150, 990, "#FFFFFF", 38, "vt323"),
    marca(p, 560, 1200, 50, "#FFFFFF", "direita", 460, "press-start-2p"),
    fig("Foguete", "foguete", 760, 940, 230, { rot: 8 }),
    ...brilhos([
      [920, 150, 100],
      [80, 1150, 80],
    ]),
  ]);
  return carrossel([
    capa,
    erro(1, "Imagem de 72 dpi, tirada da internet.", "Use a foto original, com 300 dpi no tamanho real da estampa.", "computador"),
    erro(2, "Arte colada na borda da caneca.", "Deixe 5 mm de folga dentro da área de impressão.", "tesoura"),
    erro(3, "Cor neon ou dourado na arte.", "A sublimação não faz neon nem metálico. Escolha cores firmes.", "paleta-de-pintura"),
    final,
  ]);
}

/* ========================================================== 4. SCRAPBOOK */

function scrapbook(p: PedidoDoModelo): DocumentoDoBanner {
  const PAPEL = "#EFE3CC";
  const TINTA = "#2B2118";
  const VERMELHO = "#C8452D";
  const cnt = contador(890, 56, TINTA, { fonte: "special-elite", peso: 400, tamanho: 26 });
  const fundo = fundoDoBanner({ cor: PAPEL, cor2: "#E6D6B8", angulo: 160, textura: "grao", corDaTextura: "#5A4630" });
  const fita = (x: number, y: number, w: number, rot: number, cor: string): PecaDeForma => f("Fita adesiva", "retangulo", { x, y, w, h: 64, rot }, cor, { opacidade: 0.72 });
  /* Polaroid: o papel branco com sombra, a foto em cima e a legenda escrita à mão embaixo. */
  const polaroid = (src: string, x: number, y: number, w: number, rot: number, legenda: string): Peca[] => {
    const h = w * 1.18;
    const papel = f("Polaroid", "retangulo", { x, y, w, h, rot }, "#FFFDF8", { sombra: sombraDe("#3B2A17", 0, 18, 30, 0.35) });
    return [
      papel,
      foto("Foto da polaroid", src, { x: x + w * 0.06, y: y + w * 0.06, w: w * 0.88, h: w * 0.88, rot }, { dentroDe: papel.id }),
      t("Legenda", { x: x + w * 0.06, y: y + w * 0.97, w: w * 0.88, h: h - w * 1.0, rot }, { texto: legenda, fonte: "caveat", peso: 700, tamanho: w * 0.085, cor: TINTA, alinhamento: "centro", vertical: "meio" }),
    ];
  };
  const etiqueta = (conteudo: string, x: number, y: number, w: number, h: number, rot: number, tamanho = 54): Peca[] => [
    f("Papel rasgado", "rasgado", { x, y, w, h, rot }, "#FFFDF8", { pontas: 7, profundidade: 0.3, sombra: sombraDe("#3B2A17", 0, 8, 16, 0.25) }),
    t("Etiqueta", { x: x + 40, y: y + 20, w: w - 80, h: h - 40, rot }, { texto: conteudo, fonte: "special-elite", peso: 400, tamanho, linha: 1.15, cor: TINTA, alinhamento: "centro", vertical: "meio" }),
  ];
  const capa = documento(W, H, fundo, [
    cnt,
    ...polaroid(foto$("menina-presente"), 330, 150, 620, 5, "o dia em que ela abriu"),
    fita(560, 120, 200, -8, "#F2B8A0"),
    ...etiqueta("como nasce um\npresente personalizado", 60, 860, 760, 280, -3, 58),
    fita(80, 850, 150, 30, "#A8C8B8"),
    t("Bastidores", { x: 70, y: 150, w: 300, h: 220, rot: -10 }, { texto: "bastidores\nda nossa\noficina", fonte: "caveat", peso: 700, tamanho: 64, linha: 0.95, cor: VERMELHO }),
    ic("Seta rabiscada", "seta-rabisco", 200, 400, 150, VERMELHO, { espessura: 2.2, rot: 20 }),
    fig("Coração", "coracao-vermelho", 860, 1080, 150, { rot: 14 }),
    t("Arraste", { x: 560, y: 1230, w: 460, h: 70 }, { texto: "vira a página →", fonte: "caveat", peso: 700, tamanho: 52, cor: TINTA, alinhamento: "direita" }),
  ]);
  const etapa = (n: number, titulo: string, nota: string, src: string, figurinha: string, corDaFita: string, rot: number): DocumentoDoBanner =>
    documento(W, H, fundo, [
      cnt,
      t("Número", { x: 70, y: 70, w: 300, h: 200 }, { texto: `${n}.`, fonte: "dm-serif-display", peso: 400, tamanho: 190, cor: VERMELHO, vertical: "meio" }),
      t("Título", { x: 70, y: 250, w: 900, h: 110 }, { texto: titulo, fonte: "dm-serif-display", peso: 400, italico: true, tamanho: 96, cor: TINTA }),
      ...polaroid(src, 120 + (rot < 0 ? 0 : 160), 400, 640, rot, ["a primeira conversa", "a prova da arte", "a prensa quentinha"][n - 1]),
      fita(rot < 0 ? 330 : 490, 370, 220, rot < 0 ? 6 : -6, corDaFita),
      ...etiqueta(nota, rot < 0 ? 520 : 60, 1170, 500, 160, rot < 0 ? 2 : -3, 34),
      fig("Figurinha", figurinha, 830, 380, 180, { rot: 12 }),
    ]);
  const final = documento(W, H, fundo, [
    cnt,
    ...polaroid(foto$("presente-rosa"), 90, 130, 480, -6, "embalado com laço e cartão"),
    fita(220, 110, 190, 4, "#F2D16B"),
    t("Título", { x: 610, y: 260, w: 410, h: 330, rot: 4 }, { texto: "4.\no carinho", fonte: "dm-serif-display", peso: 400, italico: true, tamanho: 92, linha: 1, cor: TINTA, alinhamento: "direita" }),
    ...etiqueta("encomende o seu\ne a gente cuida do resto", 90, 830, 900, 250, 2, 48),
    ...contato(300, 1150, TINTA, 40, "special-elite"),
    marca(p, 640, 1240, 64, TINTA, "direita", 380, "special-elite"),
    fig("Presente", "presente", 840, 690, 170, { rot: -10 }),
  ]);
  return carrossel([
    capa,
    etapa(1, "a ideia", "você manda a foto,\no nome e a data", foto$("lembrancinhas"), "lapis", "#F2B8A0", -5),
    etapa(2, "a arte", "a gente monta e\nte manda a prova", foto$("lupa-cmyk"), "paleta-de-pintura", "#A8C8B8", 5),
    etapa(3, "a produção", "prensa a 200 °C,\num minuto e pronto", foto$("prensa-amarelo"), "fogo", "#F2D16B", -4),
    final,
  ]);
}

/* ======================================================= 5. NEOBRUTALISMO */

function mitoOuVerdade(p: PedidoDoModelo): DocumentoDoBanner {
  const PRETO = "#111111";
  const CREME = "#FFF4D6";
  const ROSA = "#FF6FB5";
  const AMARELO = "#FFD23F";
  const VERDE = "#5CE18B";
  const LILAS = "#B69CFF";
  const duro = sombraDe(PRETO, 14, 14, 0, 1);
  const borda = { cor: PRETO, largura: 7 };
  const cnt = contador(870, 60, PRETO, { fonte: "space-grotesk", tamanho: 26, fundo: { forma: "pilula", cor: "#FFFFFF" } });
  const cartao = (nome: string, l: Lugar, cor: string): PecaDeForma => f(nome, "retangulo", l, cor, { raio: 28, borda, sombra: duro });
  const fundo = fundoDoBanner({ cor: CREME, textura: "nenhuma" });
  const pontos = () => tex("Pontos", "pontos", { x: 0, y: 0, w: W, h: H }, PRETO, { opacidade: 0.08, tamanho: 34 });
  const capa = documento(W, H, fundo, [
    pontos(),
    cnt,
    cartao("Faixa", { x: 60, y: 160, w: 380, h: 90, rot: -4 }, LILAS),
    t("Assunto", { x: 60, y: 168, w: 380, h: 74, rot: -4 }, { texto: "SUBLIMAÇÃO", fonte: "space-grotesk", peso: 700, tamanho: 38, espaco: 0.08, cor: PRETO, alinhamento: "centro", vertical: "meio" }),
    t("Título", { x: 60, y: 300, w: 960, h: 640 }, { texto: "MITO\nOU\nVERDADE?", html: html(`MITO<br>${trecho("OU", { vazado: { cor: PRETO, largura: 5 } })}<br>VERDADE?`), fonte: "archivo-black", peso: 400, tamanho: 158, linha: 1.02, cor: PRETO }),
    f("Estrela", "estrela", { x: 790, y: 800, w: 210, h: 210, rot: 12 }, AMARELO, { borda, pontas: 8, profundidade: 0.6 }),
    f("Círculo", "circulo", { x: 850, y: 1070, w: 140, h: 140 }, ROSA, { borda, sombra: duro }),
    cartao("Botão", { x: 60, y: 1060, w: 560, h: 120 }, VERDE),
    t("Arraste", { x: 60, y: 1070, w: 560, h: 100 }, { texto: "ARRASTA PRO LADO →", fonte: "space-grotesk", peso: 700, tamanho: 40, cor: PRETO, alinhamento: "centro", vertical: "meio" }),
    marca(p, 60, 60, 60, PRETO, "esquerda", 360, "archivo-black"),
  ]);
  const pagina = (n: number, frase: string, verdade: boolean, explicacao: string, corDoCartao: string): DocumentoDoBanner =>
    documento(W, H, fundo, [
      pontos(),
      cnt,
      t("Número", { x: 60, y: 60, w: 300, h: 100 }, { texto: `#0${n}`, fonte: "archivo-black", peso: 400, tamanho: 72, cor: PRETO, vertical: "meio" }),
      cartao("Frase", { x: 60, y: 210, w: 960, h: 420 }, corDoCartao),
      t("Frase", { x: 110, y: 250, w: 860, h: 340 }, { texto: `“${frase}”`, fonte: "archivo-black", peso: 400, tamanho: 72, linha: 1.08, cor: PRETO, vertical: "meio" }),
      cartao("Selo", { x: verdade ? 560 : 520, y: 580, w: verdade ? 440 : 360, h: 140, rot: -6 }, verdade ? VERDE : ROSA),
      t("Veredito", { x: verdade ? 560 : 520, y: 590, w: verdade ? 440 : 360, h: 120, rot: -6 }, { texto: verdade ? "VERDADE" : "MITO", fonte: "archivo-black", peso: 400, tamanho: 76, cor: PRETO, alinhamento: "centro", vertical: "meio" }),
      cartao("Explicação", { x: 60, y: 790, w: 960, h: 400 }, "#FFFFFF"),
      t("Explicação", { x: 110, y: 830, w: 860, h: 320 }, { texto: explicacao, fonte: "space-grotesk", peso: 700, tamanho: 44, linha: 1.25, cor: PRETO, vertical: "meio" }),
    ]);
  const final = documento(W, H, fundo, [
    pontos(),
    cnt,
    t("Título", { x: 60, y: 190, w: 960, h: 420 }, { texto: "FICOU COM OUTRA DÚVIDA?", fonte: "archivo-black", peso: 400, tamanho: 120, linha: 1, cor: PRETO }),
    cartao("Cartão", { x: 60, y: 660, w: 960, h: 250 }, AMARELO),
    t("Texto", { x: 110, y: 690, w: 860, h: 190 }, { texto: "Manda no direct ou no WhatsApp. A gente responde rapidinho e sem enrolação.", fonte: "space-grotesk", peso: 700, tamanho: 44, linha: 1.25, cor: PRETO, vertical: "meio" }),
    cartao("Botão", { x: 60, y: 980, w: 620, h: 130 }, VERDE),
    t("Botão", { x: 60, y: 990, w: 620, h: 110 }, { texto: "QUERO A MINHA", fonte: "archivo-black", peso: 400, tamanho: 54, cor: PRETO, alinhamento: "centro", vertical: "meio" }),
    f("Estrela", "estrela", { x: 780, y: 950, w: 220, h: 220, rot: -10 }, LILAS, { borda, pontas: 8, profundidade: 0.6 }),
    ...contato(64, 1200, PRETO, 38, "space-grotesk"),
    marca(p, 60, 60, 56, PRETO, "esquerda", 380, "archivo-black"),
  ]);
  return carrossel([
    capa,
    pagina(1, "Caneca sublimada desbota na lava-louças.", false, "A tinta entra no verniz da porcelana. Água e detergente não tiram a estampa.", AMARELO),
    pagina(2, "Dá pra sublimar em camiseta preta.", false, "Sublimação pede tecido claro com poliéster. No escuro, a gente usa outra técnica.", LILAS),
    pagina(3, "Foto de celular fica boa na caneca.", true, "Se for o arquivo original, nítido e bem iluminado. Print de conversa não vale.", ROSA),
    final,
  ]);
}

/* ===================================================== 6. EDITORIAL DE REVISTA */

function editorialDeRevista(p: PedidoDoModelo): DocumentoDoBanner {
  const PAPEL = "#F4F1EA";
  const TINTA = "#141414";
  const CINZA = "#6B655C";
  const TERRA = "#B4542F";
  const cnt = contador(880, 52, TINTA, { fonte: "inter-tight", tamanho: 24 });
  const fundo = fundoDoBanner({ cor: PAPEL, textura: "grao", corDaTextura: "#000000" });
  const rodape = (pagina: string): Peca[] => [
    f("Fio", "retangulo", { x: 70, y: 1250, w: 940, h: 2 }, TINTA),
    t("Rodapé", { x: 70, y: 1266, w: 600, h: 40 }, { texto: "TENDÊNCIAS 2027 · PRESENTES", fonte: "inter-tight", peso: 600, tamanho: 22, espaco: 0.2, cor: CINZA }),
    t("Página", { x: 710, y: 1266, w: 300, h: 40 }, { texto: pagina, fonte: "inter-tight", peso: 600, tamanho: 22, espaco: 0.2, cor: CINZA, alinhamento: "direita" }),
  ];
  const capa = documento(W, H, fundo, [
    t("Título da revista", { x: 40, y: 110, w: 1000, h: 170 }, { texto: "PRESENTE", fonte: "bodoni-moda", peso: 900, tamanho: 158, espaco: -0.02, cor: TINTA, alinhamento: "centro" }),
    t("Edição", { x: 70, y: 286, w: 940, h: 40 }, { texto: "EDIÇÃO Nº 07   ·   OUTUBRO 2026   ·   R$ 0,00", fonte: "inter-tight", peso: 600, tamanho: 22, espaco: 0.24, cor: CINZA, alinhamento: "centro" }),
    foto("Capa", foto$("presente-verde"), { x: 70, y: 340, w: 940, h: 730 }, { enquadre: { zoom: 1.05, x: 50, y: 50 } }),
    f("Sombra da foto", "retangulo", { x: 70, y: 700, w: 940, h: 370 }, { tipo: "linear", cor: "#000000", cor2: "#000000", angulo: 180, alfa: 0, alfa2: 0.62 }),
    t("Manchete", { x: 70, y: 860, w: 780, h: 260 }, { texto: "O que vai ser\npresente em 2027", html: html(`O que vai ser<br>${trecho("presente", { italico: true })} em 2027`), fonte: "instrument-serif", peso: 400, tamanho: 112, linha: 0.98, cor: "#FFFFFF", sombra: "suave" }),
    t("Chamadas", { x: 70, y: 1100, w: 640, h: 130 }, { texto: "3 tendências que já estão nas vitrines\nE o que os clientes pedem de presente", fonte: "inter-tight", peso: 600, tamanho: 28, linha: 1.35, cor: TINTA }),
    t("Arraste", { x: 720, y: 1150, w: 290, h: 60 }, { texto: "Leia →", fonte: "instrument-serif", peso: 400, italico: true, tamanho: 52, cor: TERRA, alinhamento: "direita" }),
    cnt,
  ]);
  const materia = (n: string, titulo: string, italico: string, texto_: string, src: string, olho: string, fotoADireita: boolean): DocumentoDoBanner =>
    documento(W, H, fundo, [
      cnt,
      t("Número", { x: fotoADireita ? 70 : 560, y: 90, w: 450, h: 300 }, { texto: n, fonte: "bodoni-moda", peso: 900, tamanho: 250, linha: 1, cor: TERRA, vertical: "meio" }),
      t("Título", { x: fotoADireita ? 70 : 560, y: 400, w: 450, h: 330 }, { texto: `${titulo}\n${italico}`, html: html(`${titulo}<br>${trecho(italico, { italico: true })}`), fonte: "instrument-serif", peso: 400, tamanho: 84, linha: 1, cor: TINTA }),
      t("Texto", { x: fotoADireita ? 70 : 560, y: 760, w: 450, h: 330 }, { texto: texto_, fonte: "newsreader", peso: 400, tamanho: 32, linha: 1.45, cor: "#33302B" }),
      foto("Foto", src, { x: fotoADireita ? 560 : 70, y: 90, w: 450, h: 1000 }, { enquadre: { zoom: 1, x: 50, y: 50 } }),
      t("Olho", { x: fotoADireita ? 560 : 70, y: 1110, w: 450, h: 120 }, { texto: olho, fonte: "instrument-serif", peso: 400, italico: true, tamanho: 38, linha: 1.15, cor: TERRA }),
      ...rodape(`0${Number(n) + 1}`),
    ]);
  const final = documento(W, H, fundo, [
    cnt,
    t("Aspas", { x: 70, y: 100, w: 300, h: 300 }, { texto: "“", fonte: "bodoni-moda", peso: 900, tamanho: 300, cor: TERRA, vertical: "meio" }),
    t("Frase", { x: 70, y: 380, w: 940, h: 420 }, { texto: "Presente bom é aquele que tem o nome de quem recebe.", html: html(`Presente bom é aquele que tem ${trecho("o nome", { italico: true, cor: TERRA })} de quem recebe.`), fonte: "instrument-serif", peso: 400, tamanho: 104, linha: 1.02, cor: TINTA }),
    t("Assinatura", { x: 70, y: 830, w: 940, h: 50 }, { texto: "— SUA MARCA, ATELIÊ DE PERSONALIZADOS", fonte: "inter-tight", peso: 600, tamanho: 24, espaco: 0.2, cor: CINZA }),
    t("Botão", { x: 70, y: 950, w: 600, h: 110 }, { texto: "Monte o seu com a gente", fonte: "inter-tight", peso: 700, tamanho: 36, cor: PAPEL, alinhamento: "centro", vertical: "meio", fundo: { forma: "pilula", cor: TINTA } }),
    ...contato(74, 1120, TINTA, 32, "inter-tight"),
    marca(p, 640, 1100, 70, TINTA, "direita", 370, "bodoni-moda"),
    ...rodape("05"),
  ]);
  return carrossel([
    capa,
    materia("01", "Personalizado", "de verdade", "Nada de só o nome: a foto do momento, a frase da família, a data que ninguém esquece. É o que faz o presente ir para a estante, não para a gaveta.", foto$("menina-presente"), "O presente que conta uma história.", true),
    materia("02", "Útil no", "dia a dia", "Caneca, garrafa, caderno: o presente que a pessoa usa toda manhã lembra de você toda manhã. A personalização entra discreta e bonita.", foto$("caneca-roxo"), "Lembrado a cada café.", false),
    materia("03", "Kit que vira", "experiência", "Caixa montada, papel de seda, cartão escrito à mão. Abrir o presente virou parte do presente — e vira post na hora.", foto$("lembrancinhas"), "Abrir também é presente.", true),
    final,
  ]);
}

/* ===================================================== 7. LINHA CONTÍNUA */

function linhaContinua(p: PedidoDoModelo): DocumentoDoBanner {
  const FUNDO = "#0B1B3F";
  const LARANJA = "#FF7A2F";
  const CREME = "#FFF3E6";
  const AZUL = "#7FB2FF";
  const cnt = contador(880, 56, CREME, { fonte: "space-grotesk", tamanho: 24 });
  const fundo = fundoDoBanner({ cor: FUNDO, cor2: "#081430", angulo: 180, textura: "nenhuma" });
  /* A linha que atravessa as cinco páginas, numa tira de 5 × 1080: cada página leva o mesmo desenho deslocado. */
  const nos: Array<{ x: number; y: number }> = [
    { x: -60, y: 980 },
    { x: 540, y: 1060 },
    { x: 1080 + 540, y: 760 },
    { x: 2160 + 540, y: 1040 },
    { x: 3240 + 540, y: 760 },
    { x: 4320 + 540, y: 900 },
    { x: 5460, y: 880 },
  ];
  const curva = nos.map((q, i) => {
    const anterior = nos[i - 1];
    const proximo = nos[i + 1];
    const k = 300;
    return { ...q, ...(anterior ? { e: { x: q.x - k, y: q.y } } : {}), ...(proximo ? { s: { x: q.x + k, y: q.y } } : {}) };
  });
  const linhaDaPagina = (i: number): Peca[] => {
    const base = caminho("Linha que atravessa", curva, LARANJA, 26);
    const sombra = caminho("Brilho da linha", curva, LARANJA, 70, { opacidade: 0.18 });
    return [
      { ...sombra, id: novoId("tr"), x: sombra.x - i * W },
      { ...base, id: novoId("tr"), x: base.x - i * W },
    ];
  };
  /* O ponto de cada etapa (com o anel) e o número grande vazado. */
  const marco = (cx: number, cy: number, n: number): Peca[] => [
    f(`Anel ${n}`, "circulo", { x: cx - 70, y: cy - 70, w: 140, h: 140 }, nada, { borda: { cor: LARANJA, largura: 6 }, opacidade: 0.6 }),
    f(`Ponto ${n}`, "circulo", { x: cx - 42, y: cy - 42, w: 84, h: 84 }, CREME, { borda: { cor: LARANJA, largura: 10 } }),
  ];
  const etapa = (i: number, titulo: string, texto_: string, icone: string): DocumentoDoBanner => {
    const ponto = nos[i + 1];
    const cx = ponto.x - i * W;
    return documento(W, H, fundo, [
      cnt,
      ...linhaDaPagina(i),
      ...marco(cx, ponto.y, i),
      t("Próxima", { x: 70, y: 1230, w: 940, h: 50 }, { texto: i < 3 ? "próxima etapa →" : "falta pouco →", fonte: "space-grotesk", peso: 700, tamanho: 30, cor: AZUL, alinhamento: "direita" }),
      t("Número", { x: 70, y: 110, w: 520, h: 300 }, { texto: `0${i}`, fonte: "unbounded", peso: 800, tamanho: 250, cor: "#FFFFFF", html: html(trecho(`0${i}`, { vazado: { cor: AZUL, largura: 4 } })) }),
      ic("Ícone", icone, 860, 180, 140, LARANJA, { espessura: 1.8 }),
      t("Título", { x: 70, y: 420, w: 940, h: 130 }, { texto: titulo, fonte: "unbounded", peso: 800, tamanho: 76, linha: 1, cor: CREME }),
      t("Texto", { x: 70, y: 560, w: 880, h: 160 }, { texto: texto_, fonte: "manrope", peso: 600, tamanho: 38, linha: 1.35, cor: "#C9D6F2" }),
    ]);
  };
  const capa = documento(W, H, fundo, [
    cnt,
    ...linhaDaPagina(0),
    ...marco(540, 1060, 0),
    t("Etiqueta", { x: 70, y: 140, w: 560, h: 60 }, { texto: "COMO FUNCIONA", fonte: "space-grotesk", peso: 700, tamanho: 30, espaco: 0.3, cor: LARANJA }),
    t("Título", { x: 70, y: 220, w: 960, h: 520 }, { texto: "Do arquivo à porta da sua casa", html: html(`Do arquivo à ${trecho("porta da sua casa", { cor: LARANJA })}`), fonte: "unbounded", peso: 800, tamanho: 112, linha: 1.02, cor: CREME }),
    t("Arraste", { x: 70, y: 780, w: 760, h: 60 }, { texto: "siga a linha →", fonte: "space-grotesk", peso: 700, tamanho: 38, cor: AZUL }),
    marca(p, 70, 60, 56, CREME, "esquerda", 360, "unbounded"),
  ]);
  const final = documento(W, H, fundo, [
    cnt,
    ...linhaDaPagina(4),
    ...marco(540, 900, 5),
    t("Título", { x: 70, y: 150, w: 940, h: 380 }, { texto: "Bora começar o seu?", html: html(`Bora começar ${trecho("o seu?", { cor: LARANJA })}`), fonte: "unbounded", peso: 800, tamanho: 110, linha: 1.02, cor: CREME }),
    t("Texto", { x: 70, y: 560, w: 900, h: 110 }, { texto: "Manda a arte ou a ideia. A gente cuida do resto.", fonte: "manrope", peso: 600, tamanho: 40, linha: 1.3, cor: "#C9D6F2" }),
    t("Botão", { x: 70, y: 1060, w: 560, h: 110 }, { texto: "PEDIR ORÇAMENTO", fonte: "space-grotesk", peso: 700, tamanho: 38, espaco: 0.06, cor: FUNDO, alinhamento: "centro", vertical: "meio", fundo: { forma: "pilula", cor: LARANJA } }),
    ...contato(70, 1220, CREME, 34),
    marca(p, 650, 1210, 60, CREME, "direita", 360, "unbounded"),
  ]);
  return carrossel([capa, etapa(1, "Você manda a arte", "Pelo WhatsApp ou pelo site. Sem arte? A gente cria pra você.", "caneta-lucide"), etapa(2, "Prova digital", "Você aprova a prova antes de qualquer impressão.", "olho"), etapa(3, "Produção", "Impressão, corte e acabamento com conferência em cada etapa.", "impressora"), final]);
}

/* ===================================================== 8. ANTES E DEPOIS */

function antesEDepois(p: PedidoDoModelo): DocumentoDoBanner {
  const PRETO = "#0E0E10";
  const BRANCO = "#FFFFFF";
  const AMARELO = "#FFE14D";
  const cnt = contador(880, 52, BRANCO, { fonte: "inter", tamanho: 24, fundo: { forma: "pilula", cor: "#26262B" } });
  const fundo = fundoDoBanner({ cor: PRETO, textura: "nenhuma" });
  const filtrosDoAntes = { brilho: 92, contraste: 78, saturacao: 25, desfoque: 4 };
  /* A mesma foto inteira; a metade da esquerda é a versão "antes", dentro de um retângulo que recorta. */
  const comparacao = (src: string, y: number, h: number, divisa = 540): Peca[] => {
    const recorte = f("Metade do antes", "retangulo", { x: 0, y, w: divisa, h }, nada);
    return [
      foto("Depois", src, { x: 0, y, w: W, h }, { enquadre: { zoom: 1, x: 50, y: 50 } }),
      recorte,
      foto("Antes", src, { x: 0, y, w: W, h }, { dentroDe: recorte.id, filtros: filtrosDoAntes, enquadre: { zoom: 1, x: 50, y: 50 } }),
      f("Divisa", "retangulo", { x: divisa - 4, y, w: 8, h }, BRANCO),
      f("Puxador", "circulo", { x: divisa - 56, y: y + h / 2 - 56, w: 112, h: 112 }, BRANCO, { sombra: sombraDe("#000000", 0, 10, 24, 0.4) }),
      ic("Seta esquerda", "voltar", divisa - 52, y + h / 2 - 26, 52, PRETO, { espessura: 3 }),
      ic("Seta direita", "voltar", divisa, y + h / 2 - 26, 52, PRETO, { espessura: 3, espelharX: true }),
      t("Rótulo antes", { x: 40, y: y + h - 100, w: 220, h: 64 }, { texto: "ANTES", fonte: "inter", peso: 800, tamanho: 28, espaco: 0.18, cor: BRANCO, alinhamento: "centro", vertical: "meio", fundo: { forma: "pilula", cor: "#0E0E10" } }),
      t("Rótulo depois", { x: W - 260, y: y + h - 100, w: 220, h: 64 }, { texto: "DEPOIS", fonte: "inter", peso: 800, tamanho: 28, espaco: 0.18, cor: PRETO, alinhamento: "centro", vertical: "meio", fundo: { forma: "pilula", cor: AMARELO } }),
    ];
  };
  const capa = documento(W, H, fundo, [
    ...comparacao(foto$("cartoes-marmore"), 0, 860),
    cnt,
    t("Título", { x: 60, y: 900, w: 960, h: 290 }, { texto: "Arte amadora × arte profissional", html: html(`Arte amadora ${trecho("×", { cor: AMARELO })} arte ${trecho("profissional", { cor: AMARELO })}`), fonte: "inter", peso: 800, tamanho: 96, linha: 1.02, cor: BRANCO }),
    t("Arraste", { x: 60, y: 1220, w: 700, h: 60 }, { texto: "arraste e compare →", fonte: "inter", peso: 600, tamanho: 34, cor: "#A1A1AA" }),
    marca(p, 700, 1210, 60, BRANCO, "direita", 320, "inter"),
  ]);
  const caso = (titulo: string, antes: string, depois: string, src: string): DocumentoDoBanner =>
    documento(W, H, fundo, [
      ...comparacao(src, 0, 760),
      cnt,
      t("Título", { x: 60, y: 800, w: 960, h: 100 }, { texto: titulo, fonte: "inter", peso: 800, tamanho: 72, cor: BRANCO }),
      f("Coluna antes", "retangulo", { x: 60, y: 930, w: 465, h: 340 }, "#1C1C21", { raio: 28 }),
      f("Coluna depois", "retangulo", { x: 555, y: 930, w: 465, h: 340 }, AMARELO, { raio: 28 }),
      ic("Xis", "mais", 92, 962, 52, "#F87171", { rot: 45, espessura: 3 }),
      ic("Certo", "check", 587, 962, 52, PRETO, { espessura: 3.2 }),
      t("Antes", { x: 92, y: 1030, w: 410, h: 220 }, { texto: antes, fonte: "inter", peso: 600, tamanho: 34, linha: 1.3, cor: "#D4D4D8" }),
      t("Depois", { x: 587, y: 1030, w: 410, h: 220 }, { texto: depois, fonte: "inter", peso: 700, tamanho: 34, linha: 1.3, cor: PRETO }),
    ]);
  const final = documento(W, H, fundo, [
    cnt,
    f("Brilho", "circulo", { x: 140, y: 160, w: 800, h: 800 }, { tipo: "radial", cor: "#FFE14D", cor2: PRETO, angulo: 0, alfa: 0.35, alfa2: 0 }),
    t("Título", { x: 60, y: 300, w: 960, h: 420 }, { texto: "Sua marca merece o depois.", html: html(`Sua marca merece ${trecho("o depois.", { cor: AMARELO })}`), fonte: "inter", peso: 800, tamanho: 120, linha: 1, cor: BRANCO, alinhamento: "centro" }),
    t("Texto", { x: 140, y: 760, w: 800, h: 110 }, { texto: "Arte revisada, cor conferida e impressão que valoriza o seu produto.", fonte: "inter", peso: 500, tamanho: 36, linha: 1.35, cor: "#A1A1AA", alinhamento: "centro" }),
    t("Botão", { x: 240, y: 940, w: 600, h: 110 }, { texto: "Quero o depois", fonte: "inter", peso: 800, tamanho: 40, cor: PRETO, alinhamento: "centro", vertical: "meio", fundo: { forma: "pilula", cor: AMARELO } }),
    ...contato(380, 1120, BRANCO, 34, "inter"),
    marca(p, 340, 1220, 64, BRANCO, "centro", 400, "inter"),
  ]);
  return carrossel([
    capa,
    caso("Cartão de visita", "Foto escura, fonte fina que some, sem margem.", "Papel encorpado, letra legível, laminação fosca.", foto$("cartoes-branco")),
    caso("Adesivo", "Recorte torto e cor lavada.", "Corte no contorno e cor viva que não desbota.", foto$("adesivos-amarelo")),
    caso("Cores", "Arte em RGB direto da tela.", "Cores convertidas e prova antes da tiragem.", foto$("tintas-cmyk")),
    final,
  ]);
}

/* =============================================================== a lista */

function emQualquerTamanho(montar: (p: PedidoDoModelo) => DocumentoDoBanner) {
  return (p: PedidoDoModelo): DocumentoDoBanner => {
    const doc = montar(p);
    if (p.largura === doc.largura && p.altura === doc.altura) return doc;
    return documentoDasPaginas(paginasDoDocumento(doc).map((pagina) => encaixar(pagina, p.largura, p.altura)));
  };
}

export const MODELOS_DE_CARROSSEL = (
  [
    { chave: "carrossel-fio-x", nome: "Fio no estilo do X", descricao: "Post de texto com avatar, selo e números", montar: fioNoEstiloDoX, ramo: "sublimacao", feitoPara: "carrossel", paginas: 5 },
    { chave: "carrossel-notas", nome: "Bloco de notas", descricao: "Checklist no jeito do app de notas", montar: blocoDeNotas, ramo: "grafica", feitoPara: "carrossel", paginas: 5 },
    { chave: "carrossel-y2k", nome: "Janelas Y2K", descricao: "Erros e soluções em janelas retrô", montar: janelasY2k, ramo: "sublimacao", feitoPara: "carrossel", paginas: 5 },
    { chave: "carrossel-scrapbook", nome: "Scrapbook", descricao: "Polaroid, fita e papel rasgado", montar: scrapbook, ramo: "personalizados", feitoPara: "carrossel", paginas: 5 },
    { chave: "carrossel-mito-verdade", nome: "Mito ou verdade", descricao: "Neobrutalismo: borda preta e cores vivas", montar: mitoOuVerdade, ramo: "sublimacao", feitoPara: "carrossel", paginas: 5 },
    { chave: "carrossel-revista", nome: "Editorial de revista", descricao: "Capa, matérias numeradas e citação", montar: editorialDeRevista, ramo: "personalizados", feitoPara: "carrossel", paginas: 5 },
    { chave: "carrossel-linha", nome: "Linha contínua", descricao: "Uma linha que atravessa as páginas", montar: linhaContinua, ramo: "grafica", feitoPara: "carrossel", paginas: 5 },
    { chave: "carrossel-antes-depois", nome: "Antes e depois", descricao: "Comparação com o puxador no meio", montar: antesEDepois, ramo: "grafica", feitoPara: "carrossel", paginas: 5 },
  ] as const
).map((m) => ({ ...m, montar: emQualquerTamanho(m.montar) }));
