"use client";

import Link from "next/link";
import { useMemo, useState, type CSSProperties, type ReactNode } from "react";
import {
  ArrowRight,
  CalendarClock,
  Check,
  ChevronDown,
  Clock,
  Copy,
  ImagePlus,
  MapPin,
  Navigation,
  Phone,
  Play,
  Plus,
  Radio,
  ShoppingBag,
  Ticket,
  Timer,
  Zap,
} from "lucide-react";
import { configDaSecao, destinoDaSecao, lerLink, modoDaSecao } from "@/lib/pagina-inicial";
import {
  PROPORCOES_DO_WIDGET,
  PROPORCOES_DOS_PONTOS,
  SEGUNDOS_DA_FAIXA,
  capaDoVideo,
  condicoesDoCupom,
  cupomAutomatico,
  contaDoCorte,
  cupomValeAgora,
  descontoDoCupom,
  emReais,
  enderecoDaRota,
  enderecoDigitado,
  enderecoDoMapa,
  enderecoDoPlayer,
  fotoDoProdutoDoWidget,
  horaEmBrasilia,
  lerAntesEDepois,
  lerAvisoDoCorte,
  lerCupomEmDestaque,
  lerFaixa,
  lerImagemComPontos,
  lerKits,
  lerListaAutomatica,
  lerOferta,
  lerOndeEstamos,
  lerPerguntas,
  lerProximaLive,
  lerTextoComImagem,
  lerTextoSimples,
  lerVideo,
  lerVistos,
  liveDaVez,
  ofertaNoAr,
  partesDaContagem,
  precoComDesconto,
  precoDoCartao,
  precoFixo,
  produtosNaOrdem,
  quandoDaLive,
  relogioDaContagem,
  seloDoCombo,
  type BlocoDoTexto,
  type EspacoDoWidget,
  type PedacoDoTexto,
} from "@/lib/widgets-da-home";
import { useNoEditor } from "@/components/editor-da-loja/contexto";
import { useVisaoDaLoja } from "@/components/VisaoDaLojaContext";
import { useAgora, useDadosDosWidgets } from "./contexto-dos-widgets";
import { useBarraDeComparacao, useCopiar, useMovimentoReduzido, useVistos } from "./ganchos-dos-widgets";

/*
  Os blocos novos da página inicial nos temas Padrão e Vitrine (o Vendor tem
  os dele em templates/vendor/VendorWidgetsDaHome.tsx). Entram pelo mesmo
  caminho das seções novas (SecoesNovasDaHome → ehSecaoNovaDaHome), só em
  loja que pôs o bloco pelo editor.

  As listas automáticas (lançamentos, mais vendidos) não passam por aqui
  quando têm produto: viram uma seção de produtos com os cards de sempre da
  loja (secoesParaOsTemasAntigos). Aqui fica só o lugar vazio delas.
*/

type Variante = "padrao" | "vitrine";
type Categoria = { id: string; slug?: string | null };
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type Produto = { id: string; name: string } & Record<string, any>;

export type SecaoDoWidget = {
  id: string;
  title?: string | null;
  text_color?: string | null;
  layout_width?: string | null;
  title_align?: string | null;
  title_size?: string | null;
  config?: unknown;
};

type Props = {
  secao: SecaoDoWidget;
  variante: Variante;
  slug: string;
  categorias: Categoria[];
  corDaLoja: string;
  produtos: Produto[];
};

const MARGEM: Record<EspacoDoWidget, string> = { nenhum: "py-0", pequeno: "py-3 md:py-5", normal: "py-8 md:py-12" };

function caixa(variante: Variante) {
  return variante === "vitrine" ? "mx-auto w-full max-w-[1400px] px-4 md:px-8" : "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8";
}
function raio(variante: Variante) {
  return variante === "vitrine" ? "rounded-[18px]" : "rounded-2xl md:rounded-3xl";
}

/* A cor da loja escurecida, para o fundo forte dos blocos (sem pastel). */
function tom(cor: string, quanto: number) {
  return `color-mix(in srgb, ${cor} ${100 - quanto}%, #000000)`;
}

function Titulo({ secao, variante, alinharPadrao = "left", className = "" }: { secao: SecaoDoWidget; variante: Variante; alinharPadrao?: "left" | "center"; className?: string }) {
  const titulo = String(secao.title || "").trim();
  if (!titulo) return null;
  const alinhamento = (secao.title_align || alinharPadrao) === "center" ? "text-center" : secao.title_align === "right" ? "text-right" : "text-left";
  const tamanho =
    variante === "vitrine"
      ? "text-2xl md:text-3xl font-semibold tracking-tight"
      : secao.title_size === "sm"
        ? "text-xl md:text-2xl font-bold"
        : secao.title_size === "md"
          ? "text-2xl md:text-3xl font-bold"
          : secao.title_size === "xl"
            ? "text-4xl md:text-5xl font-bold"
            : "text-3xl md:text-4xl font-bold";
  return (
    <h2 className={`catalog-section-title mb-5 md:mb-7 ${alinhamento} ${tamanho} ${className}`} style={{ color: secao.text_color || undefined }}>
      {titulo}
    </h2>
  );
}

function Vazio({ texto, detalhe, variante, icone }: { texto: string; detalhe?: string; variante: Variante; icone?: ReactNode }) {
  return (
    <div className={`flex min-h-[150px] flex-col items-center justify-center gap-2 border-2 border-dashed border-violet-300 bg-violet-50/70 px-6 py-8 text-center text-violet-700 ${raio(variante)}`}>
      {icone ?? <ImagePlus className="h-7 w-7" strokeWidth={1.8} />}
      <span className="text-sm font-bold">{texto}</span>
      {detalhe ? <span className="max-w-md text-xs font-medium text-violet-600/90">{detalhe}</span> : null}
    </div>
  );
}

function Moldura({ modo, margem, variante, children, larga = false }: { modo: string; margem: EspacoDoWidget; variante: Variante; children: ReactNode; larga?: boolean }) {
  return (
    <section className={`catalog-section catalog-section-${modo} ${MARGEM[margem]}`}>
      <div className={larga ? "w-full" : caixa(variante)}>{children}</div>
    </section>
  );
}

/* O cartão pequeno de produto dos blocos: foto, nome e o preço de verdade. */
function CartaoDoProduto({ produto, slug, variante, selo, corDaLoja, compacto = false }: { produto: Produto; slug: string; variante: Variante; selo?: string; corDaLoja: string; compacto?: boolean }) {
  const visao = useVisaoDaLoja();
  const preco = precoDoCartao(produto, visao.textoNoLugarDoPreco);
  const foto = fotoDoProdutoDoWidget(produto);
  return (
    <Link
      href={`/${slug}/p/${encodeURIComponent(produto.id)}`}
      className={`group flex h-full flex-col overflow-hidden border border-gray-100 bg-white text-gray-900 shadow-[0_1px_2px_rgba(0,0,0,0.04)] transition hover:-translate-y-0.5 hover:shadow-[0_10px_28px_rgba(0,0,0,0.10)] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ${variante === "vitrine" ? "rounded-[18px]" : "rounded-2xl"}`}
      style={{ outlineColor: corDaLoja }}
    >
      <span className="relative block aspect-square overflow-hidden bg-gray-50">
        {foto ? (
          /* eslint-disable-next-line @next/next/no-img-element */
          <img src={foto} alt="" loading="lazy" decoding="async" className="h-full w-full object-cover transition-transform duration-500 group-hover:scale-105" />
        ) : (
          <span className="flex h-full w-full items-center justify-center">
            <ShoppingBag className="h-9 w-9 text-gray-200" />
          </span>
        )}
        {selo ? (
          <span className="absolute left-2.5 top-2.5 inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-[10px] font-extrabold uppercase tracking-wide text-white shadow-md" style={{ backgroundColor: corDaLoja }}>
            <Zap className="h-3 w-3" strokeWidth={2.6} />
            {selo}
          </span>
        ) : null}
      </span>
      <span className={`flex flex-1 flex-col gap-1 ${compacto ? "p-3" : "p-3.5 md:p-4"}`}>
        <span className={`line-clamp-2 font-semibold leading-snug ${compacto ? "text-[13px]" : "text-sm"}`}>{produto.name}</span>
        <span className={`mt-auto pt-1 font-extrabold tabular-nums ${compacto ? "text-sm" : "text-base"}`} style={{ color: preco.valor === null ? undefined : tom(corDaLoja, 10) }}>
          {preco.texto}
        </span>
      </span>
    </Link>
  );
}

/* Trilho que desliza no celular e vira grade no computador. */
function Trilho({ children, colunas = 4 }: { children: ReactNode; colunas?: 3 | 4 | 5 | 6 }) {
  const grade = { 3: "md:grid-cols-3", 4: "md:grid-cols-4", 5: "md:grid-cols-4 lg:grid-cols-5", 6: "md:grid-cols-4 lg:grid-cols-6" }[colunas];
  return (
    <div className={`-mx-4 flex snap-x snap-mandatory scroll-px-4 gap-3 overflow-x-auto px-4 pb-2 [scrollbar-width:none] md:mx-0 md:grid md:gap-5 md:overflow-visible md:px-0 md:pb-0 [&::-webkit-scrollbar]:hidden ${grade}`}>
      {children}
    </div>
  );
}
function ItemDoTrilho({ children }: { children: ReactNode }) {
  return <div className="w-[46%] shrink-0 snap-start sm:w-[34%] md:w-auto">{children}</div>;
}

/* ------------------------------------------------- oferta relâmpago */

function Digitos({ valor, rotulo }: { valor: number; rotulo: string }) {
  return (
    <span className="flex flex-col items-center">
      <span className="flex h-12 min-w-[3rem] items-center justify-center rounded-xl bg-white px-2 text-2xl font-black tabular-nums text-gray-950 shadow-[0_6px_16px_rgba(0,0,0,0.25)] md:h-14 md:min-w-[3.5rem] md:text-3xl" suppressHydrationWarning>
        {String(valor).padStart(2, "0")}
      </span>
      <span className="mt-1 text-[10px] font-bold uppercase tracking-[0.14em] text-white/80">{rotulo}</span>
    </span>
  );
}

function OfertaRelampago({ secao, variante, slug, corDaLoja, produtos }: Props) {
  const editor = useNoEditor();
  const agora = useAgora(1000);
  const oferta = lerOferta(configDaSecao(secao.config));
  const lista = produtosNaOrdem(oferta.produtos, produtos);
  const noAr = ofertaNoAr(oferta, agora);
  if (!editor && (!noAr || !lista.length)) return null;
  if (editor && !lista.length) {
    return (
      <Moldura modo="flash_offer" margem={oferta.margem} variante={variante}>
        <Vazio variante={variante} texto="Oferta relâmpago: escolha os produtos e a hora do fim no painel" icone={<Zap className="h-7 w-7" />} />
      </Moldura>
    );
  }
  const falta = oferta.terminaEm ? oferta.terminaEm - agora : 0;
  const partes = partesDaContagem(falta);
  const fim = oferta.terminaEm ? horaEmBrasilia(oferta.terminaEm) : null;
  return (
    <Moldura modo="flash_offer" margem={oferta.margem} variante={variante}>
      <div
        className={`relative overflow-hidden px-5 py-6 text-white md:px-10 md:py-9 ${raio(variante)}`}
        style={{ background: `linear-gradient(120deg, ${tom(corDaLoja, 18)} 0%, ${corDaLoja} 55%, ${tom(corDaLoja, 30)} 100%)` }}
      >
        <span aria-hidden className="pointer-events-none absolute -right-16 -top-20 h-64 w-64 rounded-full bg-white/10 blur-2xl" />
        <div className="relative flex flex-col gap-5 md:flex-row md:items-end md:justify-between">
          <div className="min-w-0">
            <span className="inline-flex items-center gap-1.5 rounded-full bg-white px-3 py-1 text-[11px] font-black uppercase tracking-[0.14em]" style={{ color: tom(corDaLoja, 15) }}>
              <Zap className="h-3.5 w-3.5" strokeWidth={2.8} />
              {oferta.selo}
            </span>
            {secao.title ? <h2 className="catalog-section-title mt-3 text-3xl font-black leading-tight tracking-tight md:text-4xl">{secao.title}</h2> : null}
            {oferta.subtitulo ? <p className="mt-1.5 max-w-xl text-sm font-medium text-white/85 md:text-base">{oferta.subtitulo}</p> : null}
          </div>
          {noAr ? (
            <div className="shrink-0" role="timer" aria-label={`A oferta termina em ${relogioDaContagem(falta)}`}>
              <p className="mb-2 text-xs font-bold uppercase tracking-[0.16em] text-white/85 md:text-right">Termina em</p>
              <div className="flex items-start gap-2" aria-hidden>
                {partes.dias > 0 ? <Digitos valor={partes.dias} rotulo="dias" /> : null}
                <Digitos valor={partes.horas} rotulo="horas" />
                <Digitos valor={partes.minutos} rotulo="min" />
                <Digitos valor={partes.segundos} rotulo="seg" />
              </div>
            </div>
          ) : (
            <p className="rounded-xl bg-black/30 px-4 py-3 text-sm font-bold">
              {oferta.terminaEm ? "Esta oferta já terminou: na loja ela não aparece mais." : "Escolha no painel quando a oferta termina."}
            </p>
          )}
        </div>
        <div className="relative mt-6">
          <Trilho colunas={lista.length >= 5 ? 5 : 4}>
            {lista.map((produto) => (
              <ItemDoTrilho key={produto.id}>
                <CartaoDoProduto produto={produto} slug={slug} variante={variante} corDaLoja={corDaLoja} selo={oferta.selo} />
              </ItemDoTrilho>
            ))}
          </Trilho>
        </div>
        {fim && noAr ? (
          <p className="relative mt-4 text-xs font-semibold text-white/75" suppressHydrationWarning>
            Até {String(fim.dia).padStart(2, "0")}/{String(fim.mes).padStart(2, "0")} às {String(fim.hora).padStart(2, "0")}h{fim.minuto ? String(fim.minuto).padStart(2, "0") : ""} (horário de Brasília) ou enquanto durar.
          </p>
        ) : null}
      </div>
    </Moldura>
  );
}

/* ---------------------------------------------------- cupom em destaque */

function CupomEmDestaque({ secao, variante, corDaLoja }: Props) {
  const editor = useNoEditor();
  const dados = useDadosDosWidgets();
  const agora = useAgora(30000);
  const { estado, copiar } = useCopiar();
  const ajuste = lerCupomEmDestaque(configDaSecao(secao.config));
  const cupom = dados?.cupons.find((c) => c.id === ajuste.cupomId) ?? null;
  const vale = cupomValeAgora(cupom, agora);
  if (!cupom || !vale) {
    if (!editor) return null;
    return (
      <Moldura modo="coupon_highlight" margem={ajuste.margem} variante={variante}>
        <Vazio
          variante={variante}
          icone={<Ticket className="h-7 w-7" />}
          texto={cupom ? "Este cupom não vale agora (desligado, vencido ou ainda não começou)" : "Cupom em destaque: escolha um cupom ativo no painel"}
          detalhe="Na loja, o bloco só aparece enquanto o cupom pode ser usado."
        />
      </Moldura>
    );
  }
  const condicoes = condicoesDoCupom(cupom, ajuste.mostrarValidade);
  const forte = tom(corDaLoja, 22);
  return (
    <Moldura modo="coupon_highlight" margem={ajuste.margem} variante={variante}>
      <div className={`relative flex flex-col overflow-hidden text-white md:flex-row ${raio(variante)}`} style={{ backgroundColor: corDaLoja }}>
        <div className="relative flex flex-col justify-center gap-1 px-6 py-6 md:w-[38%] md:px-10 md:py-8" style={{ backgroundColor: forte }}>
          <span className="inline-flex items-center gap-1.5 text-[11px] font-black uppercase tracking-[0.18em] text-white/80">
            <Ticket className="h-4 w-4" /> Cupom
          </span>
          <span className="text-4xl font-black leading-none tracking-tight md:text-5xl">{descontoDoCupom(cupom)}</span>
          {secao.title ? <span className="mt-1 text-sm font-semibold text-white/85">{secao.title}</span> : null}
          {/* Os furos do ticket. */}
          <span aria-hidden className="absolute -bottom-3 left-1/2 hidden h-6 w-6 -translate-x-1/2 rounded-full bg-[var(--catalog-page-bg,#fff)] md:-right-3 md:bottom-auto md:left-auto md:top-1/2 md:block md:-translate-y-1/2 md:translate-x-0" />
        </div>
        <div className="flex flex-1 flex-col gap-4 px-6 py-6 md:flex-row md:items-center md:justify-between md:px-10">
          <div className="min-w-0">
            {ajuste.chamada ? <p className="text-lg font-extrabold leading-snug md:text-xl">{ajuste.chamada}</p> : null}
            <ul className="mt-1 space-y-0.5 text-sm font-medium text-white/85">
              {condicoes.map((c) => (
                <li key={c} className="flex items-center gap-1.5" suppressHydrationWarning>
                  <Check className="h-3.5 w-3.5 shrink-0" strokeWidth={3} /> {c}
                </li>
              ))}
            </ul>
          </div>
          <div className="flex shrink-0 flex-col items-stretch gap-2 sm:flex-row sm:items-center">
            {cupomAutomatico(cupom) ? (
            <span className="inline-flex h-12 items-center justify-center gap-2 rounded-xl bg-white px-5 text-sm font-extrabold shadow-lg" style={{ color: forte }}>
              <Check className="h-4 w-4" strokeWidth={3} /> Desconto automático no carrinho
            </span>
            ) : (
            <>
            <span className="flex h-12 items-center justify-center rounded-xl border-2 border-dashed border-white/70 bg-white/10 px-5 font-mono text-xl font-black tracking-[0.12em] select-all" aria-label={`Código do cupom: ${cupom.code}`}>
              {cupom.code}
            </span>
            <button
              type="button"
              onClick={() => copiar(cupom.code)}
              className="inline-flex h-12 items-center justify-center gap-2 rounded-xl bg-white px-5 text-sm font-extrabold shadow-lg transition hover:brightness-95 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white"
              style={{ color: forte }}
            >
              {estado === "copiado" ? <Check className="h-4 w-4" strokeWidth={3} /> : <Copy className="h-4 w-4" />}
              {estado === "copiado" ? "Copiado!" : estado === "falhou" ? "Selecione e copie" : "Copiar cupom"}
            </button>
            <span className="sr-only" aria-live="polite">
              {estado === "copiado" ? "Cupom copiado." : estado === "falhou" ? "Não deu para copiar: selecione o código e copie." : ""}
            </span>
            </>
            )}
          </div>
        </div>
      </div>
    </Moldura>
  );
}

/* --------------------------------------------- peça até as 16h */

function CorteDeProducao({ secao, variante, corDaLoja }: Props) {
  const editor = useNoEditor();
  const dados = useDadosDosWidgets();
  const agora = useAgora(1000);
  const ajuste = lerAvisoDoCorte(configDaSecao(secao.config));
  const corte = dados?.corte;
  const conta = corte?.ligado && corte.hora ? contaDoCorte(corte.hora, agora) : null;
  if (!conta) {
    if (!editor) return null;
    return (
      <Moldura modo="order_cutoff" margem={ajuste.margem} variante={variante}>
        <Vazio
          variante={variante}
          icone={<Timer className="h-7 w-7" />}
          texto="Ligue o corte de produção para este aviso aparecer"
          detalhe="Catálogo > Personalização > Corte de produção: a hora até a qual o pedido entra na produção do dia."
        />
      </Moldura>
    );
  }
  const forte = tom(corDaLoja, 12);
  return (
    <Moldura modo="order_cutoff" margem={ajuste.margem} variante={variante}>
      <div className={`flex flex-col gap-4 overflow-hidden px-5 py-5 text-white sm:flex-row sm:items-center md:px-8 ${raio(variante)}`} style={{ background: `linear-gradient(100deg, ${forte}, ${corDaLoja})` }}>
        <span className="flex h-14 w-14 shrink-0 items-center justify-center rounded-2xl bg-white/15 ring-1 ring-white/25">
          <Timer className="h-7 w-7" strokeWidth={2.2} />
        </span>
        <div className="min-w-0 flex-1">
          {conta.hoje ? (
            <>
              <p className="text-lg font-extrabold leading-snug md:text-2xl">{ajuste.frase || `Peça até as ${conta.hora} e o seu pedido entra na produção de hoje`}</p>
              <p className="mt-0.5 text-sm font-medium text-white/85">{ajuste.destaque || "Dias úteis, horário de Brasília."}</p>
            </>
          ) : (
            <>
              <p className="text-lg font-extrabold leading-snug md:text-2xl">
                Pedidos de agora entram no lote {conta.amanha ? "de amanhã" : `de ${conta.proximoDia}`}
              </p>
              <p className="mt-0.5 text-sm font-medium text-white/85">A produção do dia fecha às {conta.hora}, de segunda a sexta (horário de Brasília).</p>
            </>
          )}
        </div>
        {conta.hoje ? (
          <div className="shrink-0 rounded-2xl bg-white px-5 py-3 text-center shadow-lg" role="timer" aria-label={`Faltam ${relogioDaContagem(conta.faltaMs)} para o corte`}>
            <p className="text-[10px] font-black uppercase tracking-[0.16em]" style={{ color: forte }}>
              Faltam
            </p>
            <p className="text-2xl font-black tabular-nums text-gray-950 md:text-3xl" suppressHydrationWarning>
              {relogioDaContagem(conta.faltaMs)}
            </p>
          </div>
        ) : null}
      </div>
    </Moldura>
  );
}

/* --------------------------------------------------------- próxima live */

function ProximaLive({ secao, variante, slug, corDaLoja }: Props) {
  const editor = useNoEditor();
  const dados = useDadosDosWidgets();
  const agora = useAgora(1000);
  const ajuste = lerProximaLive(configDaSecao(secao.config));
  const vez = liveDaVez(dados?.lives ?? [], agora);
  if (!vez) {
    if (!editor && !ajuste.mostrarSemLive) return null;
    if (editor && !ajuste.mostrarSemLive) {
      return (
        <Moldura modo="next_live" margem={ajuste.margem} variante={variante}>
          <Vazio
            variante={variante}
            icone={<Radio className="h-7 w-7" />}
            texto="Nenhuma live de venda marcada na vitrine"
            detalhe="Na loja o bloco fica escondido até haver uma. Marque a live em Produtos digitais > Lives, com “Mostrar na vitrine” ligado."
          />
        </Moldura>
      );
    }
    return (
      <Moldura modo="next_live" margem={ajuste.margem} variante={variante}>
        <div className={`flex items-center gap-4 bg-gray-950 px-6 py-6 text-white md:px-10 ${raio(variante)}`}>
          <span className="flex h-12 w-12 shrink-0 items-center justify-center rounded-full" style={{ backgroundColor: corDaLoja }}>
            <Radio className="h-6 w-6" />
          </span>
          <div>
            {secao.title ? <p className="text-lg font-extrabold">{secao.title}</p> : null}
            <p className="text-sm font-medium text-white/75">{ajuste.semLive}</p>
          </div>
        </div>
      </Moldura>
    );
  }
  const { live, momento } = vez;
  const comeca = new Date(live.comeca_em).getTime();
  const noAr = momento === "ao_vivo";
  const aberta = momento === "espera";
  const href = `/${slug}/live/${encodeURIComponent(live.id)}`;
  return (
    <Moldura modo="next_live" margem={ajuste.margem} variante={variante}>
      <div className={`relative grid overflow-hidden bg-gray-950 text-white md:grid-cols-[minmax(0,5fr)_minmax(0,7fr)] ${raio(variante)}`}>
        <div className="relative aspect-[16/9] md:aspect-auto md:min-h-[260px]" style={{ background: `linear-gradient(135deg, ${corDaLoja}, ${tom(corDaLoja, 45)})` }}>
          {live.capa ? (
            /* eslint-disable-next-line @next/next/no-img-element */
            <img src={live.capa} alt="" loading="lazy" className="absolute inset-0 h-full w-full object-cover opacity-90" />
          ) : (
            <Radio aria-hidden className="absolute left-1/2 top-1/2 h-16 w-16 -translate-x-1/2 -translate-y-1/2 text-white/40" />
          )}
          <span className="absolute inset-0 bg-gradient-to-t from-gray-950/70 via-transparent to-transparent md:bg-gradient-to-r md:from-transparent md:via-transparent md:to-gray-950/80" />
          <span className={`absolute left-4 top-4 inline-flex items-center gap-1.5 rounded-full px-3 py-1 text-[11px] font-black uppercase tracking-[0.14em] ${noAr ? "bg-red-600" : "bg-white text-gray-950"}`}>
            {noAr ? <span className="h-2 w-2 animate-pulse rounded-full bg-white motion-reduce:animate-none" /> : <CalendarClock className="h-3.5 w-3.5" />}
            {noAr ? "Ao vivo agora" : aberta ? "A sala já abriu" : "Próxima live"}
          </span>
        </div>
        <div className="flex flex-col justify-center gap-3 px-6 py-6 md:px-10 md:py-8">
          {secao.title ? <p className="text-xs font-black uppercase tracking-[0.18em]" style={{ color: `color-mix(in srgb, ${corDaLoja} 60%, #ffffff)` }}>{secao.title}</p> : null}
          <h3 className="text-2xl font-black leading-tight tracking-tight md:text-3xl">{live.titulo}</h3>
          <p className="text-sm font-semibold text-white/75" suppressHydrationWarning>
            {noAr ? "Está acontecendo agora. Entre e compre ao vivo." : quandoDaLive(comeca)}
          </p>
          {!noAr && comeca > agora ? (
            <p className="text-sm font-bold text-white/90" role="timer" suppressHydrationWarning>
              Começa em <span className="tabular-nums">{relogioDaContagem(comeca - agora)}</span>
            </p>
          ) : null}
          <div className="pt-1">
            <Link
              href={href}
              className="inline-flex h-12 items-center gap-2 rounded-xl px-6 text-sm font-extrabold text-white shadow-lg transition hover:brightness-110 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white"
              style={{ backgroundColor: noAr ? "#dc2626" : corDaLoja }}
            >
              {noAr ? "Entrar agora" : aberta ? "Entrar na sala" : "Ver a live"}
              <ArrowRight className="h-4 w-4" />
            </Link>
          </div>
        </div>
      </div>
    </Moldura>
  );
}

/* ---------------------------------------------- listas automáticas (vazia) */

function ListaVazia({ secao, variante }: Props) {
  const editor = useNoEditor();
  if (!editor) return null;
  const lista = lerListaAutomatica(configDaSecao(secao.config));
  return (
    <Moldura modo="auto_list" margem={lista.margem} variante={variante}>
      <Titulo secao={secao} variante={variante} />
      <Vazio
        variante={variante}
        icone={<ShoppingBag className="h-7 w-7" />}
        texto={lista.lista === "mais_vendidos" ? `Ainda sem vendas nos últimos ${lista.dias} dias` : "A loja ainda não tem produtos à mostra"}
        detalhe={lista.lista === "mais_vendidos" ? "A lista conta os pedidos de verdade (sem os cancelados). Sem venda no período, o bloco fica escondido na loja." : undefined}
      />
    </Moldura>
  );
}

/* --------------------------------------------------------- kits e combos */

function KitsECombos({ secao, variante, slug, corDaLoja, produtos }: Props) {
  const editor = useNoEditor();
  const dados = useDadosDosWidgets();
  const visao = useVisaoDaLoja();
  const ajuste = lerKits(configDaSecao(secao.config));
  const porId = useMemo(() => new Map(produtos.map((p) => [String(p.id), p])), [produtos]);
  const kits = (dados?.combos ?? [])
    .filter((c) => !ajuste.combos.length || ajuste.combos.includes(c.id))
    .sort((a, b) => (ajuste.combos.length ? ajuste.combos.indexOf(a.id) - ajuste.combos.indexOf(b.id) : 0))
    .map((combo) => ({ combo, principal: porId.get(combo.main_product_id), junto: porId.get(combo.combo_product_id) }))
    .filter((k): k is { combo: typeof k.combo; principal: Produto; junto: Produto } => Boolean(k.principal && k.junto))
    .slice(0, ajuste.quantidade);
  if (!kits.length) {
    if (!editor) return null;
    return (
      <Moldura modo="combo_highlight" margem={ajuste.margem} variante={variante}>
        <Titulo secao={secao} variante={variante} />
        <Vazio variante={variante} icone={<Plus className="h-7 w-7" />} texto="Nenhum kit para mostrar" detalhe="Os kits saem do “Compre junto” dos produtos (Produtos > editar > Compre junto). Os dois produtos precisam estar à mostra na loja." />
      </Moldura>
    );
  }
  return (
    <Moldura modo="combo_highlight" margem={ajuste.margem} variante={variante}>
      <Titulo secao={secao} variante={variante} />
      <Trilho colunas={3}>
        {kits.map(({ combo, principal, junto }) => {
          const p1 = precoFixo(principal);
          const p2 = precoFixo(junto);
          const somaSemDesconto = p1 !== null && p2 !== null ? p1 + p2 : null;
          const comDesconto = p1 !== null && p2 !== null ? p1 + precoComDesconto(p2, combo) : null;
          const selo = dados?.semPreco ? null : seloDoCombo(combo);
          const mostraTotal = !dados?.semPreco && visao.mostrarPreco && comDesconto !== null;
          return (
            <div key={combo.id} className="w-[84%] shrink-0 snap-start sm:w-[60%] md:w-auto">
              <Link
                href={`/${slug}/p/${encodeURIComponent(principal.id)}`}
                className={`group flex h-full flex-col overflow-hidden border border-gray-100 bg-white text-gray-900 transition hover:-translate-y-0.5 hover:shadow-[0_12px_30px_rgba(0,0,0,0.10)] ${variante === "vitrine" ? "rounded-[18px]" : "rounded-2xl"}`}
              >
                <span className="relative grid grid-cols-2 gap-px bg-gray-100">
                  {[principal, junto].map((p) => {
                    const foto = fotoDoProdutoDoWidget(p);
                    return (
                      <span key={p.id} className="relative block aspect-square bg-gray-50">
                        {foto ? (
                          /* eslint-disable-next-line @next/next/no-img-element */
                          <img src={foto} alt="" loading="lazy" className="h-full w-full object-cover" />
                        ) : (
                          <ShoppingBag className="absolute left-1/2 top-1/2 h-8 w-8 -translate-x-1/2 -translate-y-1/2 text-gray-200" />
                        )}
                      </span>
                    );
                  })}
                  <span className="absolute left-1/2 top-1/2 flex h-10 w-10 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full text-white shadow-lg ring-4 ring-white" style={{ backgroundColor: corDaLoja }}>
                    <Plus className="h-5 w-5" strokeWidth={3} />
                  </span>
                  {selo ? (
                    <span className="absolute left-2.5 top-2.5 rounded-full bg-gray-950 px-2.5 py-1 text-[10px] font-black uppercase tracking-wide text-white">{selo}</span>
                  ) : null}
                </span>
                <span className="flex flex-1 flex-col gap-1.5 p-4">
                  <span className="text-[11px] font-black uppercase tracking-[0.14em]" style={{ color: tom(corDaLoja, 8) }}>
                    {combo.title || "Leve junto"}
                  </span>
                  <span className="line-clamp-2 text-sm font-semibold leading-snug">
                    {principal.name} <span className="text-gray-400">+</span> {junto.name}
                  </span>
                  <span className="mt-auto flex items-end justify-between gap-2 pt-2">
                    {mostraTotal ? (
                      <span>
                        {somaSemDesconto !== null && comDesconto !== null && comDesconto < somaSemDesconto ? (
                          <span className="block text-xs font-semibold text-gray-400 line-through">{emReais(somaSemDesconto)}</span>
                        ) : null}
                        <span className="text-lg font-black tabular-nums" style={{ color: tom(corDaLoja, 10) }}>
                          {emReais(comDesconto as number)}
                        </span>
                        <span className="block text-[11px] font-medium text-gray-500">os dois juntos</span>
                      </span>
                    ) : (
                      <span className="text-sm font-semibold text-gray-600">Veja o kit</span>
                    )}
                    <span className="inline-flex h-9 items-center gap-1 rounded-full px-3.5 text-xs font-extrabold text-white transition group-hover:brightness-110" style={{ backgroundColor: corDaLoja }}>
                      Montar <ArrowRight className="h-3.5 w-3.5" />
                    </span>
                  </span>
                </span>
              </Link>
            </div>
          );
        })}
      </Trilho>
    </Moldura>
  );
}

/* --------------------------------------------- vistos recentemente */

function VistosRecentemente({ secao, variante, slug, corDaLoja, produtos }: Props) {
  const editor = useNoEditor();
  const ajuste = lerVistos(configDaSecao(secao.config));
  const ids = useVistos(slug);
  const lista = produtosNaOrdem(ids, produtos).slice(0, ajuste.quantidade);
  if (!lista.length) {
    if (!editor) return null;
    return (
      <Moldura modo="recently_viewed" margem={ajuste.margem} variante={variante}>
        <Titulo secao={secao} variante={variante} />
        <Vazio variante={variante} icone={<Clock className="h-7 w-7" />} texto="Os produtos que o visitante abriu aparecem aqui" detalhe="Fica guardado só no navegador de cada pessoa. Para quem chega pela primeira vez, o bloco não aparece." />
      </Moldura>
    );
  }
  return (
    <Moldura modo="recently_viewed" margem={ajuste.margem} variante={variante}>
      <Titulo secao={secao} variante={variante} />
      <Trilho colunas={6}>
        {lista.map((produto) => (
          <ItemDoTrilho key={produto.id}>
            <CartaoDoProduto produto={produto} slug={slug} variante={variante} corDaLoja={corDaLoja} compacto />
          </ItemDoTrilho>
        ))}
      </Trilho>
    </Moldura>
  );
}

/* --------------------------------------------- texto com negrito e link */

function Pedacos({ pedacos, corDaLoja }: { pedacos: PedacoDoTexto[]; corDaLoja: string }) {
  return (
    <>
      {pedacos.map((p, i) => {
        if (p.tipo === "negrito") return <strong key={i} className="font-extrabold">{p.valor}</strong>;
        if (p.tipo === "link") {
          const classe = "font-bold underline decoration-2 underline-offset-2";
          return p.externo ? (
            <a key={i} href={p.href} target="_blank" rel="noopener noreferrer" className={classe} style={{ color: tom(corDaLoja, 10) }}>
              {p.valor}
            </a>
          ) : (
            <Link key={i} href={p.href} className={classe} style={{ color: tom(corDaLoja, 10) }}>
              {p.valor}
            </Link>
          );
        }
        return <span key={i}>{p.valor}</span>;
      })}
    </>
  );
}

function TextoRico({ blocos, corDaLoja, className = "" }: { blocos: BlocoDoTexto[]; corDaLoja: string; className?: string }) {
  return (
    <div className={`space-y-3 text-[15px] leading-relaxed md:text-base ${className}`}>
      {blocos.map((bloco, i) =>
        bloco.tipo === "lista" ? (
          <ul key={i} className="space-y-1.5">
            {bloco.itens.map((item, j) => (
              <li key={j} className="flex gap-2">
                <span className="mt-[0.55em] h-1.5 w-1.5 shrink-0 rounded-full" style={{ backgroundColor: corDaLoja }} />
                <span>
                  <Pedacos pedacos={item} corDaLoja={corDaLoja} />
                </span>
              </li>
            ))}
          </ul>
        ) : (
          <p key={i}>
            {bloco.linhas.map((l, j) => (
              <span key={j}>
                {j > 0 ? <br /> : null}
                <Pedacos pedacos={l} corDaLoja={corDaLoja} />
              </span>
            ))}
          </p>
        )
      )}
    </div>
  );
}

function BotaoDoBloco({ texto, link, slug, categorias, corDaLoja }: { texto: string; link: Record<string, unknown> | null; slug: string; categorias: Categoria[]; corDaLoja: string }) {
  if (!texto || !link) return null;
  const destino = destinoDaSecao(lerLink(link), slug, categorias);
  if (!destino) return null;
  const classe = "inline-flex h-12 items-center gap-2 rounded-xl px-6 text-sm font-extrabold text-white shadow-lg transition hover:brightness-110 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2";
  const alvo = destino.novaAba ? { target: "_blank", rel: "noopener noreferrer" } : {};
  const conteudo = (
    <>
      {texto} <ArrowRight className="h-4 w-4" />
    </>
  );
  return destino.externo ? (
    <a href={destino.href} className={classe} style={{ backgroundColor: corDaLoja, outlineColor: corDaLoja }} {...alvo}>
      {conteudo}
    </a>
  ) : (
    <Link href={destino.href} className={classe} style={{ backgroundColor: corDaLoja, outlineColor: corDaLoja }} {...alvo}>
      {conteudo}
    </Link>
  );
}

/* ------------------------------------------------------------- vídeo */

function PlayerComCapa({ secao, corDaLoja, variante }: { secao: SecaoDoWidget; corDaLoja: string; variante: Variante }) {
  const video = lerVideo(configDaSecao(secao.config));
  const [tocando, setTocando] = useState(false);
  const editor = useNoEditor();
  if (!video.link) return null;
  const capa = video.capa || capaDoVideo(video.link);
  const titulo = String(secao.title || "Vídeo");
  return (
    <div className={`relative aspect-video w-full overflow-hidden bg-gray-950 shadow-[0_18px_40px_-18px_rgba(0,0,0,0.45)] ${raio(variante)}`}>
      {tocando && !editor ? (
        <iframe
          src={enderecoDoPlayer(video.link)}
          title={titulo}
          className="absolute inset-0 h-full w-full"
          allow="autoplay; encrypted-media; picture-in-picture; fullscreen"
          allowFullScreen
          loading="lazy"
          referrerPolicy="strict-origin-when-cross-origin"
        />
      ) : (
        <button type="button" onClick={() => setTocando(true)} className="group absolute inset-0 h-full w-full" aria-label={`Assistir: ${titulo}`}>
          {capa ? (
            /* eslint-disable-next-line @next/next/no-img-element */
            <img src={capa} alt="" loading="lazy" className="absolute inset-0 h-full w-full object-cover transition-transform duration-700 group-hover:scale-[1.03]" />
          ) : (
            <span className="absolute inset-0" style={{ background: `linear-gradient(135deg, ${corDaLoja}, ${tom(corDaLoja, 55)})` }} />
          )}
          <span className="absolute inset-0 bg-black/25 transition group-hover:bg-black/15" />
          <span className="absolute left-1/2 top-1/2 flex h-16 w-16 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full text-white shadow-2xl ring-8 ring-white/25 transition group-hover:scale-110 md:h-20 md:w-20" style={{ backgroundColor: corDaLoja }}>
            <Play className="ml-1 h-7 w-7 md:h-9 md:w-9" fill="currentColor" />
          </span>
        </button>
      )}
    </div>
  );
}

function SecaoDeVideo({ secao, variante, corDaLoja }: Props) {
  const editor = useNoEditor();
  const video = lerVideo(configDaSecao(secao.config));
  if (!video.link) {
    if (!editor) return null;
    return (
      <Moldura modo="video_section" margem={video.margem} variante={variante}>
        <Vazio variante={variante} icone={<Play className="h-7 w-7" />} texto={video.url ? "Esse link não é de um vídeo do YouTube ou do Vimeo" : "Vídeo: cole o link do YouTube ou do Vimeo no painel"} />
      </Moldura>
    );
  }
  const blocos = lerTextoSimples(video.texto);
  if (video.lado === "inteiro" || (!blocos.length && !secao.title)) {
    return (
      <Moldura modo="video_section" margem={video.margem} variante={variante}>
        <Titulo secao={secao} variante={variante} alinharPadrao="center" />
        <div className="mx-auto max-w-5xl">
          <PlayerComCapa secao={secao} corDaLoja={corDaLoja} variante={variante} />
          {blocos.length ? <TextoRico blocos={blocos} corDaLoja={corDaLoja} className="mx-auto mt-5 max-w-3xl text-center text-gray-700" /> : null}
        </div>
      </Moldura>
    );
  }
  return (
    <Moldura modo="video_section" margem={video.margem} variante={variante}>
      <div className={`grid items-center gap-6 md:grid-cols-2 md:gap-12`}>
        <div className={video.lado === "direita" ? "md:order-2" : ""}>
          <PlayerComCapa secao={secao} corDaLoja={corDaLoja} variante={variante} />
        </div>
        <div>
          <Titulo secao={secao} variante={variante} className="!mb-3" />
          <TextoRico blocos={blocos} corDaLoja={corDaLoja} className="text-gray-700" />
        </div>
      </div>
    </Moldura>
  );
}

/* ------------------------------------------------- texto com imagem */

function TextoComImagemDaLoja({ secao, variante, slug, categorias, corDaLoja }: Props) {
  const editor = useNoEditor();
  const bloco = lerTextoComImagem(configDaSecao(secao.config));
  const blocos = lerTextoSimples(bloco.texto);
  if (!bloco.imagem && !blocos.length && !editor) return null;
  return (
    <Moldura modo="text_image" margem={bloco.margem} variante={variante}>
      <div className="grid items-center gap-6 md:grid-cols-2 md:gap-14">
        <div className={bloco.lado === "direita" ? "md:order-2" : ""}>
          {bloco.imagem ? (
            <div className={`relative overflow-hidden bg-gray-100 shadow-[0_24px_50px_-24px_rgba(0,0,0,0.35)] ${raio(variante)}`} style={{ aspectRatio: String(PROPORCOES_DO_WIDGET[bloco.proporcao]) }}>
              {/* eslint-disable-next-line @next/next/no-img-element */}
              <img src={bloco.imagem} alt={secao.title || ""} loading="lazy" className="absolute inset-0 h-full w-full object-cover" />
            </div>
          ) : editor ? (
            <div style={{ aspectRatio: String(PROPORCOES_DO_WIDGET[bloco.proporcao]) }} className="flex">
              <div className="flex-1">
                <Vazio variante={variante} texto="Escolha a imagem no painel" />
              </div>
            </div>
          ) : null}
        </div>
        <div className="min-w-0">
          {bloco.chamada ? (
            <p className="mb-2 text-xs font-black uppercase tracking-[0.2em]" style={{ color: tom(corDaLoja, 5) }}>
              {bloco.chamada}
            </p>
          ) : null}
          <Titulo secao={secao} variante={variante} className="!mb-4" />
          {blocos.length ? (
            <TextoRico blocos={blocos} corDaLoja={corDaLoja} className="text-gray-700" />
          ) : editor ? (
            <p className="text-sm font-semibold text-violet-600">Escreva o texto no painel.</p>
          ) : null}
          {bloco.botao.texto ? (
            <div className="mt-6">
              <BotaoDoBloco texto={bloco.botao.texto} link={bloco.botao.link} slug={slug} categorias={categorias} corDaLoja={corDaLoja} />
            </div>
          ) : null}
        </div>
      </div>
    </Moldura>
  );
}

/* --------------------------------------------------- perguntas frequentes */

function PerguntasFrequentes({ secao, variante, corDaLoja }: Props) {
  const editor = useNoEditor();
  const ajuste = lerPerguntas(configDaSecao(secao.config));
  const [aberta, setAberta] = useState<number | null>(ajuste.abrirPrimeira ? 0 : null);
  if (!ajuste.itens.length) {
    if (!editor) return null;
    return (
      <Moldura modo="faq" margem={ajuste.margem} variante={variante}>
        <Titulo secao={secao} variante={variante} />
        <Vazio variante={variante} icone={<ChevronDown className="h-7 w-7" />} texto="Perguntas frequentes: escreva as perguntas e respostas no painel" />
      </Moldura>
    );
  }
  return (
    <Moldura modo="faq" margem={ajuste.margem} variante={variante}>
      <div className="grid gap-6 md:grid-cols-[minmax(0,4fr)_minmax(0,8fr)] md:gap-12">
        <div>
          <Titulo secao={secao} variante={variante} className="!mb-2" />
          <p className="text-sm font-medium text-gray-500">{ajuste.itens.length === 1 ? "1 pergunta" : `${ajuste.itens.length} perguntas`} respondidas pela loja.</p>
        </div>
        <div className="divide-y divide-gray-200 border-y border-gray-200">
          {ajuste.itens.map((item, indice) => {
            const aberto = aberta === indice;
            const id = `faq-${secao.id}-${indice}`;
            return (
              <div key={indice}>
                <h3>
                  <button
                    type="button"
                    id={`${id}-botao`}
                    aria-expanded={aberto}
                    aria-controls={`${id}-resposta`}
                    onClick={() => setAberta(aberto ? null : indice)}
                    className="flex w-full items-center justify-between gap-4 py-4 text-left text-base font-bold text-gray-900 transition hover:opacity-80 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 md:py-5 md:text-lg"
                    style={{ outlineColor: corDaLoja }}
                  >
                    <span>{item.pergunta}</span>
                    <span
                      aria-hidden
                      className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-white transition-transform duration-200 motion-reduce:transition-none"
                      style={{ backgroundColor: corDaLoja, transform: aberto ? "rotate(45deg)" : undefined }}
                    >
                      <Plus className="h-4 w-4" strokeWidth={3} />
                    </span>
                  </button>
                </h3>
                <div id={`${id}-resposta`} role="region" aria-labelledby={`${id}-botao`} hidden={!aberto} className="pb-5 pr-12">
                  <TextoRico blocos={lerTextoSimples(item.resposta)} corDaLoja={corDaLoja} className="text-gray-600" />
                </div>
              </div>
            );
          })}
        </div>
      </div>
    </Moldura>
  );
}

/* --------------------------------------------------------- onde estamos */

function OndeEstamosDaLoja({ secao, variante, corDaLoja }: Props) {
  const editor = useNoEditor();
  const dados = useDadosDosWidgets();
  const ajuste = lerOndeEstamos(configDaSecao(secao.config));
  const endereco = ajuste.usarDaLoja ? dados?.local.endereco ?? null : enderecoDigitado(ajuste.endereco);
  const retiradas = ajuste.mostrarRetiradas ? dados?.local.retiradas ?? [] : [];
  if (!endereco) {
    if (!editor) return null;
    return (
      <Moldura modo="store_location" margem={ajuste.margem} variante={variante}>
        <Titulo secao={secao} variante={variante} />
        <Vazio variante={variante} icone={<MapPin className="h-7 w-7" />} texto={ajuste.usarDaLoja ? "A empresa ainda não tem endereço cadastrado" : "Escreva o endereço no painel"} detalhe={ajuste.usarDaLoja ? "Preencha em Catálogo > Personalização > Rodapé, ou escreva o endereço direto no bloco." : undefined} />
      </Moldura>
    );
  }
  const horarios = ajuste.horarios.split("\n").map((l) => l.trim()).filter(Boolean);
  const telefone = dados?.local.telefone ?? null;
  return (
    <Moldura modo="store_location" margem={ajuste.margem} variante={variante}>
      <div className={`grid overflow-hidden border border-gray-200 bg-white md:grid-cols-[minmax(0,5fr)_minmax(0,7fr)] ${raio(variante)}`}>
        <div className="flex flex-col gap-5 p-6 md:p-10">
          <Titulo secao={secao} variante={variante} className="!mb-0" />
          <div className="flex gap-3">
            <span className="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl text-white" style={{ backgroundColor: corDaLoja }}>
              <MapPin className="h-5 w-5" />
            </span>
            <address className="not-italic text-[15px] font-medium leading-relaxed text-gray-800">
              {endereco.linhas.map((l) => (
                <span key={l} className="block">
                  {l}
                </span>
              ))}
            </address>
          </div>
          {horarios.length ? (
            <div className="flex gap-3">
              <span className="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl text-white" style={{ backgroundColor: corDaLoja }}>
                <Clock className="h-5 w-5" />
              </span>
              <ul className="text-[15px] font-medium leading-relaxed text-gray-800">
                {horarios.map((h) => (
                  <li key={h}>{h}</li>
                ))}
              </ul>
            </div>
          ) : null}
          {telefone ? (
            <div className="flex items-center gap-3 text-[15px] font-medium text-gray-800">
              <span className="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl text-white" style={{ backgroundColor: corDaLoja }}>
                <Phone className="h-5 w-5" />
              </span>
              {telefone}
            </div>
          ) : null}
          <div>
            <a
              href={enderecoDaRota(endereco.busca)}
              target="_blank"
              rel="noopener noreferrer"
              className="inline-flex h-12 items-center gap-2 rounded-xl px-6 text-sm font-extrabold text-white shadow-lg transition hover:brightness-110"
              style={{ backgroundColor: corDaLoja }}
            >
              <Navigation className="h-4 w-4" /> Traçar rota
            </a>
          </div>
          {retiradas.length ? (
            <div className="border-t border-gray-100 pt-4">
              <p className="mb-2 text-xs font-black uppercase tracking-[0.16em] text-gray-500">Pontos de retirada</p>
              <ul className="space-y-2.5">
                {retiradas.map((r) => (
                  <li key={r.nome + r.endereco.busca} className="text-sm text-gray-700">
                    <span className="font-bold text-gray-900">{r.nome}</span>
                    <span className="block">{r.endereco.linhas.slice(0, 2).join(" · ")}</span>
                    <a href={enderecoDaRota(r.endereco.busca)} target="_blank" rel="noopener noreferrer" className="text-xs font-bold underline" style={{ color: tom(corDaLoja, 10) }}>
                      Rota até aqui
                    </a>
                  </li>
                ))}
              </ul>
            </div>
          ) : null}
        </div>
        {ajuste.mostrarMapa ? (
          <div className="relative min-h-[260px] bg-gray-100 md:min-h-[380px]">
            {editor ? (
              <div className="absolute inset-0 flex flex-col items-center justify-center gap-2 text-gray-500" style={{ background: `linear-gradient(135deg, color-mix(in srgb, ${corDaLoja} 18%, #f3f4f6), #f3f4f6)` }}>
                <MapPin className="h-10 w-10" style={{ color: corDaLoja }} />
                <span className="text-xs font-bold">O mapa do Google aparece aqui na loja publicada</span>
              </div>
            ) : (
              <iframe
                src={enderecoDoMapa(endereco.busca)}
                title={`Mapa: ${endereco.linhas[0] || "endereço da loja"}`}
                className="absolute inset-0 h-full w-full border-0"
                loading="lazy"
                referrerPolicy="no-referrer-when-downgrade"
              />
            )}
          </div>
        ) : null}
      </div>
    </Moldura>
  );
}

/* --------------------------------------------- faixa de texto que desliza */

function FaixaQueDesliza({ secao, corDaLoja }: Props) {
  const editor = useNoEditor();
  const reduzido = useMovimentoReduzido();
  const faixa = lerFaixa(configDaSecao(secao.config), corDaLoja);
  if (!faixa.itens.length) {
    if (!editor) return null;
    return (
      <section className="catalog-section catalog-section-marquee py-3">
        <div className="max-w-7xl mx-auto px-4">
          <Vazio variante="padrao" texto="Faixa que desliza: escreva as frases no painel" />
        </div>
      </section>
    );
  }
  const tamanho = faixa.tamanho === "g" ? "text-xl md:text-3xl py-4 md:py-5" : faixa.tamanho === "p" ? "text-xs md:text-sm py-2" : "text-sm md:text-lg py-3";
  const grupo = (copia: boolean) => (
    <span className="flex shrink-0 items-center" aria-hidden={copia || undefined}>
      {faixa.itens.map((item, i) => (
        <span key={`${copia ? "c" : "o"}-${i}`} className="flex items-center whitespace-nowrap font-extrabold uppercase tracking-[0.06em]">
          <span className="px-5 md:px-8">{item}</span>
          <span aria-hidden className="opacity-70">•</span>
        </span>
      ))}
    </span>
  );
  return (
    <section className="catalog-section catalog-section-marquee" style={{ backgroundColor: faixa.fundo, color: faixa.cor }}>
      {reduzido ? (
        <div className={`flex flex-wrap items-center justify-center gap-y-1 px-4 text-center ${tamanho}`}>{grupo(false)}</div>
      ) : (
        <div className={`ks-faixa-desliza flex overflow-hidden ${tamanho}`} role="marquee" aria-label={faixa.itens.join(" • ")}>
          <div className="ks-faixa-desliza-trilho flex" style={{ animationDuration: `${SEGUNDOS_DA_FAIXA[faixa.velocidade]}s` } as CSSProperties}>
            {grupo(false)}
            {grupo(true)}
          </div>
        </div>
      )}
      <style>{`@keyframes ks-faixa-desliza{from{transform:translateX(0)}to{transform:translateX(-50%)}}.ks-faixa-desliza-trilho{animation-name:ks-faixa-desliza;animation-timing-function:linear;animation-iteration-count:infinite;will-change:transform}.ks-faixa-desliza:hover .ks-faixa-desliza-trilho{animation-play-state:paused}@media (prefers-reduced-motion: reduce){.ks-faixa-desliza-trilho{animation:none}}`}</style>
    </section>
  );
}

/* -------------------------------------------- imagem com pontos clicáveis */

function ImagemComPontosDaLoja({ secao, variante, slug, corDaLoja, produtos }: Props) {
  const editor = useNoEditor();
  const visao = useVisaoDaLoja();
  const ajuste = lerImagemComPontos(configDaSecao(secao.config));
  const [aberto, setAberto] = useState<number | null>(null);
  const porId = useMemo(() => new Map(produtos.map((p) => [String(p.id), p])), [produtos]);
  const pontos = ajuste.pontos.map((p) => ({ ...p, produto: porId.get(p.produtoId) })).filter((p) => p.produto);
  if (!ajuste.imagem) {
    if (!editor) return null;
    return (
      <Moldura modo="shoppable_image" margem={ajuste.margem} variante={variante}>
        <Titulo secao={secao} variante={variante} />
        <Vazio variante={variante} texto="Imagem com pontos: escolha a imagem e toque nela no painel para marcar os produtos" />
      </Moldura>
    );
  }
  return (
    <Moldura modo="shoppable_image" margem={ajuste.margem} variante={variante}>
      <Titulo secao={secao} variante={variante} />
      <div
        className={`relative w-full overflow-visible ${raio(variante)}`}
        style={{ aspectRatio: String(PROPORCOES_DOS_PONTOS[ajuste.proporcao]) }}
        onMouseLeave={() => setAberto(null)}
      >
        <div className={`absolute inset-0 overflow-hidden bg-gray-100 ${raio(variante)}`}>
          {/* eslint-disable-next-line @next/next/no-img-element */}
          <img src={ajuste.imagem} alt={secao.title || ""} loading="lazy" className="h-full w-full object-cover" />
        </div>
        {pontos.map((ponto, indice) => {
          const produto = ponto.produto as Produto;
          const ativo = aberto === indice;
          const preco = precoDoCartao(produto, visao.textoNoLugarDoPreco);
          const foto = fotoDoProdutoDoWidget(produto);
          const paraEsquerda = ponto.x > 60;
          const paraCima = ponto.y > 55;
          return (
            <div key={indice} className="absolute" style={{ left: `${ponto.x}%`, top: `${ponto.y}%`, zIndex: ativo ? 30 : 10 }} onMouseEnter={() => setAberto(indice)}>
              <button
                type="button"
                aria-label={`Ver ${produto.name}`}
                aria-expanded={ativo}
                onClick={() => setAberto(ativo ? null : indice)}
                onFocus={() => setAberto(indice)}
                className="relative -ml-4 -mt-4 flex h-8 w-8 items-center justify-center rounded-full text-white shadow-[0_4px_14px_rgba(0,0,0,0.35)] ring-4 ring-white/70 transition hover:scale-110 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white"
                style={{ backgroundColor: corDaLoja }}
              >
                <span aria-hidden className="absolute inset-0 animate-ping rounded-full opacity-40 motion-reduce:animate-none" style={{ backgroundColor: corDaLoja }} />
                <Plus className="relative h-4 w-4" strokeWidth={3} />
              </button>
              {ativo ? (
                <Link
                  href={`/${slug}/p/${encodeURIComponent(produto.id)}`}
                  className={`absolute flex w-56 items-center gap-3 rounded-2xl bg-white p-2.5 text-gray-900 shadow-[0_18px_40px_-10px_rgba(0,0,0,0.45)] ${paraEsquerda ? "right-6" : "left-6"} ${paraCima ? "bottom-2" : "top-2"}`}
                >
                  {foto ? (
                    /* eslint-disable-next-line @next/next/no-img-element */
                    <img src={foto} alt="" className="h-14 w-14 shrink-0 rounded-xl object-cover" />
                  ) : (
                    <span className="h-14 w-14 shrink-0 rounded-xl bg-gray-100" />
                  )}
                  <span className="min-w-0">
                    <span className="line-clamp-2 text-[13px] font-bold leading-snug">{produto.name}</span>
                    <span className="mt-0.5 block text-sm font-black" style={{ color: tom(corDaLoja, 10) }}>
                      {preco.texto}
                    </span>
                    <span className="text-[11px] font-bold text-gray-500">Ver produto →</span>
                  </span>
                </Link>
              ) : null}
            </div>
          );
        })}
      </div>
    </Moldura>
  );
}

/* ---------------------------------------------------------- antes e depois */

function AntesEDepoisDaLoja({ secao, variante, corDaLoja }: Props) {
  const editor = useNoEditor();
  const ajuste = lerAntesEDepois(configDaSecao(secao.config));
  const { posicao, caixa: refDaCaixa, eventosDaCaixa, eventosDaAlca } = useBarraDeComparacao(ajuste.inicio);
  if (!ajuste.antes || !ajuste.depois) {
    if (!editor) return null;
    return (
      <Moldura modo="before_after" margem={ajuste.margem} variante={variante}>
        <Titulo secao={secao} variante={variante} />
        <Vazio variante={variante} texto="Antes e depois: escolha as duas imagens no painel" />
      </Moldura>
    );
  }
  return (
    <Moldura modo="before_after" margem={ajuste.margem} variante={variante}>
      <Titulo secao={secao} variante={variante} alinharPadrao="center" />
      <div
        ref={refDaCaixa}
        {...eventosDaCaixa}
        className={`relative w-full touch-pan-y select-none overflow-hidden bg-gray-100 ${raio(variante)}`}
        style={{ aspectRatio: String(PROPORCOES_DOS_PONTOS[ajuste.proporcao]), cursor: "ew-resize" }}
      >
        {/* eslint-disable-next-line @next/next/no-img-element */}
        <img src={ajuste.antes} alt={ajuste.rotuloAntes} draggable={false} className="pointer-events-none absolute inset-0 h-full w-full object-cover" />
        {/* eslint-disable-next-line @next/next/no-img-element */}
        <img
          src={ajuste.depois}
          alt={ajuste.rotuloDepois}
          draggable={false}
          className="pointer-events-none absolute inset-0 h-full w-full object-cover"
          style={{ clipPath: `inset(0 0 0 ${posicao}%)` }}
        />
        <span className="pointer-events-none absolute left-3 top-3 rounded-full bg-black/65 px-3 py-1 text-xs font-black uppercase tracking-wide text-white">{ajuste.rotuloAntes}</span>
        <span className="pointer-events-none absolute right-3 top-3 rounded-full px-3 py-1 text-xs font-black uppercase tracking-wide text-white" style={{ backgroundColor: corDaLoja }}>
          {ajuste.rotuloDepois}
        </span>
        <span className="pointer-events-none absolute inset-y-0 w-1 -translate-x-1/2 bg-white shadow-[0_0_12px_rgba(0,0,0,0.4)]" style={{ left: `${posicao}%` }} />
        <span
          role="slider"
          tabIndex={0}
          aria-label={`Comparar ${ajuste.rotuloAntes} e ${ajuste.rotuloDepois}`}
          aria-valuemin={0}
          aria-valuemax={100}
          aria-valuenow={Math.round(posicao)}
          aria-valuetext={`${Math.round(posicao)}% ${ajuste.rotuloAntes.toLowerCase()}`}
          {...eventosDaAlca}
          className="absolute top-1/2 flex h-12 w-12 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full bg-white text-gray-900 shadow-[0_6px_20px_rgba(0,0,0,0.35)] focus-visible:outline focus-visible:outline-4 focus-visible:outline-offset-2"
          style={{ left: `${posicao}%`, outlineColor: corDaLoja }}
        >
          <span aria-hidden className="flex items-center gap-0.5 text-lg font-black" style={{ color: corDaLoja }}>
            ‹›
          </span>
        </span>
      </div>
      <p className="mt-3 text-center text-xs font-semibold text-gray-500">Arraste a barra para comparar.</p>
    </Moldura>
  );
}

/* ------------------------------------------------------------- o bloco */

/** Desenha o bloco novo (ver ehWidget em lib/widgets-da-home). */
export function WidgetDaHome(props: Props) {
  const modo = modoDaSecao(props.secao);
  switch (modo) {
    case "flash_offer":
      return <OfertaRelampago {...props} />;
    case "coupon_highlight":
      return <CupomEmDestaque {...props} />;
    case "order_cutoff":
      return <CorteDeProducao {...props} />;
    case "next_live":
      return <ProximaLive {...props} />;
    case "auto_list":
      return <ListaVazia {...props} />;
    case "combo_highlight":
      return <KitsECombos {...props} />;
    case "recently_viewed":
      return <VistosRecentemente {...props} />;
    case "video_section":
      return <SecaoDeVideo {...props} />;
    case "text_image":
      return <TextoComImagemDaLoja {...props} />;
    case "faq":
      return <PerguntasFrequentes {...props} />;
    case "store_location":
      return <OndeEstamosDaLoja {...props} />;
    case "marquee":
      return <FaixaQueDesliza {...props} />;
    case "shoppable_image":
      return <ImagemComPontosDaLoja {...props} />;
    case "before_after":
      return <AntesEDepoisDaLoja {...props} />;
    default:
      return null;
  }
}
