{
  "version": 3,
  "sources": ["/cdn/shop/t/6/assets/pb-pdp.js?nc=3409"],
  "sourcesContent": ["/* ==========================================================================\n   Peru Balloons \u00B7 Redise\u00F1o \u2014 P\u00E1gina de producto (pb-pdp.js)\n   Galer\u00EDa, combinaciones de color (productos hermanos), tabs, personalizaci\u00F3n con vista previa,\n   calendario de entrega, WhatsApp con el pedido armado y agregar al carrito de Shopify.\n   Los datos salen de Liquid: #pdp-data (el producto y sus colores, con sus metacampos).\n   ========================================================================== */\n(() => {\n  const PB = window.PB || {};\n  const $ = (sel, root = document) => root.querySelector(sel);\n  const $$ = (sel, root = document) => [...root.querySelectorAll(sel)];\n  const esc = (s) => String(s).replace(/[&<>\"']/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' }[c]));\n  const desktop = window.matchMedia('(min-width: 960px)');\n  const money = (n) => `S/ ${Math.round(Number(n) * 100) % 100 ? Number(n).toFixed(2) : Math.round(Number(n))}`;\n  // Precio regular tachado: solo si es mayor que el precio que se cobra (una oferta con compare-at en Shopify)\n  const setCompare = (price, compare) => {\n    const el = $('[data-compare-price]');\n    if (!el) return;\n    el.hidden = !(Number(compare) > Number(price));\n    if (!el.hidden) $('[data-compare-value]', el).textContent = money(compare);\n    $$('[data-discount]').forEach((off) => { // sobre el nombre y en la barra fija\n      off.hidden = el.hidden;\n      if (!off.hidden) off.textContent = `-${Math.round((compare - price) * 100 / compare)}%`;\n    });\n  };\n\n  const dataEl = $('#pdp-data');\n  if (!dataEl) return;\n  const data = JSON.parse(dataEl.textContent);\n  // Centro de masa visual de cada d\u00EDgito por color (medido en las fotos de los globos n\u00FAmero): centra el par sobre el coraz\u00F3n\n  data.digitCenters = data.digitCenters || {\"plata\":{\"0\":[0.5257,0.4031],\"1\":[0.533,0.2538],\"2\":[0.4676,0.4043],\"3\":[0.5368,0.3925],\"4\":[0.5522,0.3789],\"5\":[0.4959,0.4036],\"6\":[0.5062,0.4148],\"7\":[0.5948,0.297],\"8\":[0.5016,0.422],\"9\":[0.4942,0.4073]},\"oro-rosa\":{\"0\":[0.5257,0.4031],\"1\":[0.533,0.2538],\"2\":[0.4676,0.4043],\"3\":[0.5368,0.3925],\"4\":[0.5522,0.3789],\"5\":[0.4959,0.4036],\"6\":[0.5062,0.4148],\"7\":[0.5948,0.297],\"8\":[0.5016,0.422],\"9\":[0.4942,0.4073]},\"crema\":{\"0\":[0.5018,0.456],\"1\":[0.5193,0.2847],\"2\":[0.4739,0.4079],\"3\":[0.5323,0.4247],\"4\":[0.5381,0.4135],\"5\":[0.4741,0.4298],\"6\":[0.4953,0.4309],\"7\":[0.5755,0.3182],\"8\":[0.4988,0.4632],\"9\":[0.5238,0.4263]},\"dorado\":{\"0\":[0.4971,0.4688],\"1\":[0.5292,0.3031],\"2\":[0.4827,0.4153],\"3\":[0.5413,0.4159],\"4\":[0.5398,0.4154],\"5\":[0.4865,0.4539],\"6\":[0.4948,0.439],\"7\":[0.5711,0.3259],\"8\":[0.4963,0.4632],\"9\":[0.5027,0.4431]},\"violeta\":{\"0\":[0.5062,0.4393],\"1\":[0.5207,0.2531],\"2\":[0.4963,0.4283],\"3\":[0.5307,0.4356],\"4\":[0.542,0.4177],\"5\":[0.4849,0.4339],\"6\":[0.4987,0.4291],\"7\":[0.5813,0.3077],\"8\":[0.5039,0.4536],\"9\":[0.5155,0.4461]}};\n  let current = data.products[data.current];\n\n  const header = $('[data-header]');\n  // Alto de lo que queda fijo arriba: barra de anuncio + header\n  const topChrome = () => header.offsetHeight + ($('.announcement')?.offsetHeight || 0);\n  const grid = $('[data-pdp-grid]');\n  const info = $('[data-pdp-info]');\n  const form = $('[data-product-form]');\n\n  /* ---------- Galer\u00EDa ---------- */\n  const gallery = $('[data-gallery]');\n  const track = $('[data-gallery-track]');\n  const countEl = $('[data-gallery-count]');\n  const liveEl = $('[data-gallery-live]');\n  const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');\n  const idle = window.requestIdleCallback || ((cb) => setTimeout(cb, 200));\n  const PLAY_SVG = '<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M8 5.5v13l10.5-6.5z\" fill=\"currentColor\"/></svg>';\n  const isVideo = (img) => img && img.type === 'video';\n  const slides = () => [...track.children];\n\n  const slideHTML = (img, i, n) => {\n    if (isVideo(img)) {\n      return `<li class=\"pdp-media__slide pdp-media__slide--video\">\n        <button type=\"button\" class=\"pdp-media__zoom\" data-zoom=\"${i}\" aria-label=\"Ver video ${i + 1} de ${n}\">\n          <video class=\"pdp-media__video\" src=\"${esc(img.video)}\" poster=\"${esc(img.src + '&width=1024')}\" muted playsinline loop preload=\"none\" aria-hidden=\"true\" data-inline-video></video>\n          <span class=\"pdp-media__play\" aria-hidden=\"true\">${PLAY_SVG}</span>\n        </button>\n      </li>`;\n    }\n    const srcset = [512, 768, 1024, 1280, 1536].map((w) => `${img.src}&width=${w} ${w}w`).join(', '); // hasta 1536: la foto entera en pantallas retina\n    return `<li class=\"pdp-media__slide\">\n      <button type=\"button\" class=\"pdp-media__zoom\" data-zoom=\"${i}\" aria-label=\"Ampliar foto ${i + 1} de ${n}\">\n        <img src=\"${esc(img.src + '&width=1024')}\" srcset=\"${esc(srcset)}\" sizes=\"(min-width: 960px) 50vw, 100vw\" alt=\"${esc(img.alt)}\" width=\"1024\" height=\"1024\"${i ? ' loading=\"lazy\"' : ''}>\n      </button>\n    </li>`;\n  };\n\n  // Desktop: miniaturas verticales a la izquierda y una foto grande; en m\u00F3vil se ocultan (carrusel)\n  const thumbs = document.createElement('div');\n  thumbs.className = 'pdp-media__thumbs';\n  thumbs.setAttribute('role', 'group');\n  thumbs.setAttribute('aria-label', 'Miniaturas de las fotos');\n  $('.pdp-media__stage').before(thumbs);\n\n  const scene = $('[data-number-preview]');\n\n  function renderThumbs(product) {\n    const n = product.images.length;\n    thumbs.innerHTML = product.images.map((img, i) =>\n      `<button type=\"button\" class=\"pdp-media__thumb${isVideo(img) ? ' pdp-media__thumb--video' : ''}\" data-thumb=\"${i}\" aria-label=\"${isVideo(img) ? 'Ver video' : 'Ver foto'} ${i + 1} de ${n}\">\n        <img src=\"${esc(img.src + '&width=160')}\" alt=\"\" width=\"72\" height=\"72\">${isVideo(img) ? `<span class=\"pdp-media__thumb-play\">${PLAY_SVG}</span>` : ''}\n      </button>`).join('');\n  }\n\n  function renderGallery(product) {\n    const n = product.images.length;\n    track.innerHTML = product.images.map((img, i) => slideHTML(img, i, n)).join('');\n    track.scrollLeft = 0;\n    gallery.classList.toggle('is-single', n < 2);\n    renderThumbs(product);\n    focusSlides(product);\n    setActiveSlide(0);\n  }\n\n  // Punto focal del recorte en desktop (si la foto grande queda m\u00E1s alta que ancha se recortan los costados):\n  // cada foto de ambiente trae su \"focus\" (d\u00F3nde est\u00E1 el bouquet o el r\u00F3tulo), como el punto focal de Shopify\n  function focusSlides(product = current) {\n    slides().forEach((slide, k) => {\n      const img = slide.querySelector('img');\n      const f = product.images[k] && product.images[k].focus;\n      if (img) img.style.objectPosition = f ? `${f} 50%` : '';\n    });\n  }\n\n  // Precarga: la foto que viene ya est\u00E1 lista cuando se pide (sin hueco al cambiar)\n  const warm = (i) => {\n    const slide = track.children[i];\n    const img = slide && slide.querySelector('img[loading=\"lazy\"]');\n    if (img) img.loading = 'eager';\n  };\n  const warmAround = (i) => {\n    const n = track.children.length;\n    if (n > 1) { warm((i + 1) % n); warm((i - 1 + n) % n); }\n  };\n\n  // Videos: en la ficha se ven sin sonido y en bucle mientras son la foto activa (no con movimiento reducido)\n  function syncVideos(paused = false) {\n    slides().forEach((slide, k) => {\n      const v = slide.querySelector('[data-inline-video]');\n      if (!v) return;\n      if (!paused && k === activeIndex && !reducedMotion.matches) {\n        v.preload = 'auto';\n        v.play().catch(() => {});\n      } else v.pause();\n    });\n  }\n  track.addEventListener('playing', (e) => e.target.closest('.pdp-media__slide')?.classList.add('is-playing'), true);\n  track.addEventListener('pause', (e) => e.target.closest('.pdp-media__slide')?.classList.remove('is-playing'), true);\n\n  // Foto activa: la grande en desktop (con fundido), el contador en m\u00F3vil\n  let activeIndex = 0;\n  function setActiveSlide(i, { animate = false, announce = false } = {}) {\n    const list = slides();\n    const n = list.length;\n    if (!list[i]) return;\n    const prev = list.find((s) => s.classList.contains('is-active'));\n    if (animate && desktop.matches && !reducedMotion.matches && prev && prev !== list[i]) {\n      list.forEach((s) => s.classList.remove('is-leaving'));\n      prev.classList.add('is-leaving');\n      clearTimeout(prev.leaveTimer);\n      prev.leaveTimer = setTimeout(() => prev.classList.remove('is-leaving'), 420);\n      list[i].classList.add('is-entering');\n      list[i].addEventListener('animationend', () => list[i].classList.remove('is-entering'), { once: true });\n    }\n    activeIndex = i;\n    list.forEach((slide, k) => slide.classList.toggle('is-active', k === i));\n    countEl.textContent = `${i + 1} / ${n}`;\n    $$('[data-thumb]', thumbs).forEach((t) => t.setAttribute('aria-current', String(t.dataset.thumb === String(i))));\n    if (announce && liveEl) liveEl.textContent = `${isVideo(current.images[i]) ? 'Video' : 'Foto'} ${i + 1} de ${n}`;\n    // La vista previa flotante se minimiza en las otras fotos (ambientes, empaque) para no taparlas\n    if (setPip) setPip(i !== 0);\n    syncVideos();\n    warmAround(i);\n  }\n  let setPip = null;\n\n  // Cambio con espera corta a que la foto est\u00E9 decodificada: nunca se ve el hueco vac\u00EDo\n  let navToken = 0;\n  async function showSlide(i, opts) {\n    const token = ++navToken;\n    const img = track.children[i] && track.children[i].querySelector('img');\n    if (img && !(img.complete && img.naturalWidth)) {\n      img.loading = 'eager';\n      await Promise.race([img.decode().catch(() => {}), new Promise((r) => setTimeout(r, 700))]);\n    }\n    if (token === navToken) setActiveSlide(i, opts);\n  }\n  const step = (delta) => {\n    const n = track.children.length;\n    return (activeIndex + delta + n) % n;\n  };\n\n  renderThumbs(current);\n  gallery.classList.toggle('is-single', current.images.length < 2);\n  focusSlides();\n  setActiveSlide(0);\n\n  // Desktop: con la p\u00E1gina ya cargada se precargan todas las fotos de la galer\u00EDa (son pocas)\n  const warmAll = () => { if (desktop.matches) slides().forEach((_, k) => warm(k)); };\n  if (document.readyState === 'complete') idle(warmAll);\n  else window.addEventListener('load', () => idle(warmAll), { once: true });\n\n  // Miga de pan: en desktop va arriba de la galer\u00EDa; en m\u00F3vil, al final de la columna de compra\n  const crumbs = $('.pdp-crumbs');\n  const crumbsHome = $('.pdp-info__inner');\n  const placeCrumbs = () => {\n    if (!crumbs) return;\n    if (desktop.matches) gallery.prepend(crumbs);\n    else crumbsHome.append(crumbs);\n  };\n  placeCrumbs();\n  desktop.addEventListener('change', placeCrumbs);\n\n  thumbs.addEventListener('click', (e) => {\n    const t = e.target.closest('[data-thumb]');\n    if (t) showSlide(+t.dataset.thumb, { animate: true, announce: true });\n  });\n  thumbs.addEventListener('pointerover', (e) => {\n    const t = e.target.closest('[data-thumb]');\n    if (t) warm(+t.dataset.thumb);\n  });\n\n  // Flechas sobre la foto grande y teclado (\u2190/\u2192) en miniaturas y foto grande\n  $('[data-gallery-prev]')?.addEventListener('click', () => showSlide(step(-1), { animate: true, announce: true }));\n  $('[data-gallery-next]')?.addEventListener('click', () => showSlide(step(1), { animate: true, announce: true }));\n  gallery.addEventListener('keydown', (e) => {\n    if (!desktop.matches || (e.key !== 'ArrowLeft' && e.key !== 'ArrowRight')) return;\n    if (!e.target.closest('.pdp-media__thumbs, .pdp-media__stage')) return;\n    e.preventDefault();\n    const i = step(e.key === 'ArrowLeft' ? -1 : 1);\n    showSlide(i, { animate: true, announce: true });\n    if (e.target.closest('[data-thumb]')) $(`[data-thumb=\"${i}\"]`, thumbs)?.focus();\n  });\n\n  // Desktop: la vista previa flota fija abajo a la derecha de la foto grande; en m\u00F3vil vuelve junto al teclado\n  if (scene) {\n    const sceneHome = scene.parentElement;\n    const slot = document.createElement('div');\n    slot.className = 'pdp-media__preview';\n    // Una sola pieza que cambia de forma: la pastilla \"Tu dise\u00F1o\" se estira a lo ancho y luego se abre hacia\n    // arriba hasta ser la tarjeta con la vista previa; al minimizar hace el camino inverso.\n    slot.innerHTML = `<div class=\"pdp-pip is-open\">\n        <button type=\"button\" class=\"pdp-pip__chip\" aria-label=\"Ver la vista previa de tu dise\u00F1o\" aria-expanded=\"true\" tabindex=\"-1\"><svg aria-hidden=\"true\"><use href=\"#i-sparkle\"/></svg>Tu dise\u00F1o</button>\n      </div>`;\n    gallery.append(slot);\n    const pip = $('.pdp-pip', slot);\n    const chip = $('.pdp-pip__chip', pip);\n    const minBtn = Object.assign(document.createElement('button'), { type: 'button', className: 'pdp-pip-min', innerHTML: '<span aria-hidden=\"true\"></span>' });\n    minBtn.setAttribute('aria-label', 'Minimizar la vista previa');\n    // \"+\" bajo el \"\u2013\": la tarjeta se ve 50 % m\u00E1s grande; con la tarjeta ampliada el \u00EDcono pasa a \"achicar\"\n    const zoomBtn = Object.assign(document.createElement('button'), { type: 'button', className: 'pdp-pip-min pdp-pip-zoom' });\n    const setZoom = (big) => {\n      pip.classList.toggle('is-big', big);\n      zoomBtn.setAttribute('aria-label', big ? 'Achicar la vista previa' : 'Ampliar la vista previa');\n      zoomBtn.setAttribute('aria-pressed', String(big));\n      zoomBtn.innerHTML = big\n        ? '<svg viewBox=\"0 0 10 10\" aria-hidden=\"true\"><path d=\"M1.5 1.5 8 8M8.5 3.5v5h-5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>'\n        : '<svg viewBox=\"0 0 10 10\" aria-hidden=\"true\"><path d=\"M5 1v8M1 5h8\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/></svg>';\n    };\n    setZoom(false);\n    // Desktop: ampl\u00EDa la tarjeta; celular: abre la vista previa en grande (el mismo visor de la galer\u00EDa)\n    zoomBtn.addEventListener('click', (e) => {\n      e.stopPropagation();\n      if (desktop.matches) setZoom(!pip.classList.contains('is-big'));\n      else openScenePswp();\n    });\n    setPip = (collapsed) => {\n      if (collapsed) setZoom(false);\n      pip.classList.toggle('is-open', !collapsed);\n      chip.setAttribute('aria-expanded', String(!collapsed));\n      chip.tabIndex = collapsed ? 0 : -1;\n    };\n    chip.addEventListener('click', () => setPip(false));\n    minBtn.addEventListener('click', () => setPip(true));\n    // Clic en la tarjeta: abre Personalizaci\u00F3n (aunque se est\u00E9 viendo Medidas u otra pesta\u00F1a) para editar el dise\u00F1o\n    scene.addEventListener('click', (e) => {\n      if (!desktop.matches || e.target.closest('.pdp-pip-min')) return; // tambi\u00E9n el \"+\" (misma clase)\n      const tab = $('#tab-personalizacion');\n      activateTab(tab);\n      scrollIntoInfo(tab);\n    });\n    $('[data-numbers]').addEventListener('click', (e) => {\n      if (e.target.closest('[data-digit], [data-number-preset], [data-slot], [data-number-clear], [data-number-count]')) setPip(false);\n    });\n    // Medidas reales de las dos formas (la animaci\u00F3n va de una a otra) y cu\u00E1nto sobresale la tarjeta abierta\n    // de la foto: lo que permita el espacio libre antes de la columna de compra, hasta 42 % de su ancho\n    const infoInner = $('.pdp-info__inner');\n    const fitCard = () => {\n      if (!desktop.matches) return;\n      const w = Math.round(Math.min(236, Math.max(160, track.offsetWidth * 0.27)));\n      pip.style.setProperty('--pip-w', `${w}px`);\n      pip.style.setProperty('--pip-h', `${scene.offsetHeight}px`);\n      pip.style.setProperty('--chip-w', `${chip.offsetWidth}px`);\n      const free = infoInner.getBoundingClientRect().left - 16 - track.getBoundingClientRect().right;\n      pip.style.setProperty('--pip-right', `${-Math.round(Math.max(0, Math.min(w * 0.42, free)))}px`);\n    };\n    const placeScene = () => {\n      if (desktop.matches) { pip.append(scene); scene.append(minBtn, zoomBtn); } // el \"\u2013\" y el \"+\" van dentro de la tarjeta\n      else { sceneHome.append(scene); minBtn.remove(); scene.append(zoomBtn); setZoom(false); }\n      fitCard();\n    };\n    placeScene();\n    // Las transiciones se activan despu\u00E9s de la primera medici\u00F3n (al cargar no se anima)\n    requestAnimationFrame(() => requestAnimationFrame(() => pip.classList.add('is-ready')));\n    desktop.addEventListener('change', placeScene);\n    new ResizeObserver(fitCard).observe(gallery);\n    window.addEventListener('resize', () => requestAnimationFrame(fitCard));\n  }\n\n  // Carrusel m\u00F3vil: contador al deslizar\n  let slideRaf;\n  track.addEventListener('scroll', () => {\n    cancelAnimationFrame(slideRaf);\n    slideRaf = requestAnimationFrame(() => {\n      const i = Math.round(track.scrollLeft / track.clientWidth);\n      if (i !== activeIndex) setActiveSlide(i);\n    });\n  }, { passive: true });\n\n  function goToImage(i) {\n    if (!track.children[i]) return;\n    // Desktop: la galer\u00EDa es fija, basta con mostrar esa foto grande\n    if (desktop.matches) { showSlide(i, { animate: true, announce: true }); return; }\n    track.scrollTo({ left: i * track.clientWidth, behavior: reducedMotion.matches ? 'auto' : 'smooth' });\n    window.scrollTo({ top: gallery.getBoundingClientRect().top + window.scrollY - topChrome(), behavior: 'smooth' });\n  }\n  // data-goto-image=\"medidas\": busca la foto por su nombre (el orden cambia entre colores)\n  $$('[data-goto-image]').forEach((btn) => btn.addEventListener('click', () => {\n    const i = current.images.findIndex((img) => img.src.includes(btn.dataset.gotoImage));\n    goToImage(i < 0 ? 1 : i);\n  }));\n\n  /* ---------- Vista ampliada (PhotoSwipe 5) ----------\n     Zoom con dos dedos o doble toque, deslizar que sigue al dedo, cerrar deslizando hacia abajo, fotos en alta\n     resoluci\u00F3n (srcset hasta 2048 px) y la siguiente ya precargada. La librer\u00EDa se descarga al primer uso\n     (pasar el mouse o tocar la galer\u00EDa la adelanta), as\u00ED la ficha no carga nada extra al abrirse. */\n  let pswpLoad = null;\n  const loadPswp = () => {\n    if (!pswpLoad) {\n      const css = new Promise((resolve) => {\n        const l = Object.assign(document.createElement('link'), { rel: 'stylesheet', href: gallery.dataset.pswpCss });\n        l.onload = resolve; l.onerror = resolve;\n        document.head.append(l);\n      });\n      const js = new Promise((resolve, reject) => {\n        const s = Object.assign(document.createElement('script'), { src: gallery.dataset.pswpJs, async: true });\n        s.onload = () => (window.PhotoSwipe ? resolve(window.PhotoSwipe) : reject(new Error('PhotoSwipe no carg\u00F3')));\n        s.onerror = reject;\n        document.head.append(s);\n      });\n      pswpLoad = Promise.all([js, css]).then(([PhotoSwipe]) => PhotoSwipe).catch((err) => { pswpLoad = null; throw err; });\n    }\n    return pswpLoad;\n  };\n  ['pointerenter', 'touchstart', 'focusin'].forEach((ev) => gallery.addEventListener(ev, () => loadPswp().catch(() => {}), { once: true, passive: true }));\n\n  const icon = (id) => `<svg aria-hidden=\"true\" class=\"pswp__icn\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><use href=\"#${id}\"/></svg>`;\n  const MAX_W = 2048;\n  function pswpItem(img, i) {\n    const zoom = track.children[i] && track.children[i].querySelector('.pdp-media__zoom');\n    const media = zoom && zoom.querySelector('img, video');\n    if (isVideo(img)) {\n      return {\n        html: `<div class=\"pb-pswp-video\"><video src=\"${esc(img.videoHd || img.video)}\" poster=\"${esc(img.src + '&width=1024')}\" controls playsinline loop preload=\"metadata\" aria-label=\"${esc(img.alt)}\"></video></div>`,\n        element: media,\n      };\n    }\n    const ow = img.w || 1024;\n    const oh = img.h || 1024;\n    const w = Math.min(ow, MAX_W);\n    const h = Math.round(oh * (w / ow));\n    const widths = [800, 1200, 1600].filter((x) => x < w).concat(w);\n    return {\n      src: `${img.src}&width=${w}`,\n      srcset: widths.map((x) => `${img.src}&width=${x} ${x}w`).join(', '),\n      width: w,\n      height: h,\n      alt: img.alt,\n      msrc: (media && media.currentSrc) || `${img.src}&width=512`, // la foto que ya se ve: aparece al instante\n      element: media,\n      thumbCropped: true, // en la ficha la foto est\u00E1 recortada (object-fit: cover): la animaci\u00F3n parte del recorte\n    };\n  }\n\n  // Al pasar de foto en la vista ampliada, la galer\u00EDa de la ficha la sigue (al cerrar vuelve a la misma)\n  function syncInline(i) {\n    if (desktop.matches) setActiveSlide(i);\n    else {\n      track.scrollTo({ left: i * track.clientWidth, behavior: 'auto' });\n      setActiveSlide(i);\n    }\n  }\n\n  // Celular: la vista previa del dise\u00F1o en grande, en el visor de la galer\u00EDa. Se muestra una copia de la escena a su\n  // tama\u00F1o real, escalada (los n\u00FAmeros y el texto se miden en p\u00EDxeles: as\u00ED nada se reacomoda y se ve igual, m\u00E1s grande)\n  async function openScenePswp() {\n    const stage = $('[data-number-preview] .number-scene__stage');\n    if (!stage) return;\n    let PhotoSwipe;\n    try { PhotoSwipe = await loadPswp(); } catch (err) { return; }\n    const fast = reducedMotion.matches;\n    const pswp = new PhotoSwipe({\n      dataSource: [{ html: '<div class=\"pb-pswp-scene\"><div class=\"pb-pswp-scene__box\"></div><p class=\"pb-pswp-scene__caption\">Vista referencial</p></div>' }],\n      mainClass: 'pb-pswp pb-pswp--scene',\n      bgOpacity: 0.82,\n      showHideAnimationType: fast ? 'none' : 'fade',\n      showAnimationDuration: fast ? 0 : 260,\n      hideAnimationDuration: fast ? 0 : 220,\n      counter: false,\n      zoom: false,\n      arrowPrev: false,\n      arrowNext: false,\n      closeTitle: 'Cerrar',\n      closeSVG: icon('i-close'),\n      tapAction: 'close',\n      bgClickAction: 'close',\n    });\n    pswp.on('contentAppend', ({ content }) => {\n      const box = content.element && $('.pb-pswp-scene__box', content.element);\n      if (!box || box.firstChild) return;\n      const w = stage.offsetWidth;\n      const size = Math.min(window.innerWidth - 32, window.innerHeight - 180);\n      const copy = stage.cloneNode(true);\n      copy.removeAttribute('data-preview-stage');\n      Object.assign(copy.style, { width: `${w}px`, height: `${w}px`, transform: `scale(${size / w})`, transformOrigin: '0 0' });\n      Object.assign(box.style, { width: `${size}px`, height: `${size}px` });\n      box.append(copy);\n    });\n    pswp.on('firstUpdate', () => pswp.element.setAttribute('aria-label', 'Vista previa de tu dise\u00F1o'));\n    pswp.init();\n  }\n\n  async function openPswp(index) {\n    let PhotoSwipe;\n    try {\n      PhotoSwipe = await loadPswp();\n    } catch (err) {\n      const img = current.images[index];\n      window.open(isVideo(img) ? img.videoHd || img.video : `${img.src}&width=${MAX_W}`, '_blank', 'noopener');\n      return;\n    }\n    const fast = reducedMotion.matches;\n    const items = current.images.map(pswpItem);\n    const pswp = new PhotoSwipe({\n      dataSource: items,\n      index,\n      mainClass: 'pb-pswp',\n      bgOpacity: 0.82, // velo sutil: la foto resalta sobre la p\u00E1gina (el fondo crema se mezclaba con las fotos)\n      showHideAnimationType: fast ? 'none' : 'zoom',\n      showAnimationDuration: fast ? 0 : 340,\n      hideAnimationDuration: fast ? 0 : 300,\n      zoomAnimationDuration: fast ? 0 : 300,\n      padding: desktop.matches ? { top: 64, bottom: 64, left: 88, right: 88 } : { top: 60, bottom: items.length > 1 ? 96 : 52, left: 0, right: 0 },\n      preload: [1, 2],\n      counter: false,\n      imageClickAction: 'zoom-or-close',\n      // Celular: tocar la foto muestra u oculta los controles; tocar el velo cierra (como el clic en desktop)\n      tapAction: (point, e) => {\n        if (e.target.closest('.pb-pswp__thumbs')) return;\n        if (e.target.classList.contains('pswp__img')) pswp.element.classList.toggle('pswp--ui-visible');\n        else pswp.close();\n      },\n      doubleTapAction: 'zoom',\n      bgClickAction: 'close',\n      closeTitle: 'Cerrar',\n      zoomTitle: 'Acercar o alejar',\n      arrowPrevTitle: 'Foto anterior',\n      arrowNextTitle: 'Foto siguiente',\n      errorMsg: 'No se pudo cargar esta foto.',\n      returnFocus: false, // se devuelve a mano: a la foto que qued\u00F3 activa (la del inicio puede estar oculta)\n      arrowPrevSVG: icon('i-chevron-left'),\n      arrowNextSVG: icon('i-chevron-right'),\n      closeSVG: icon('i-close'),\n      // Lupa de Iconoir (como el resto de la UI); las clases de las barras dejan que PhotoSwipe pase de \u00AB+\u00BB a \u00AB\u2212\u00BB\n      zoomSVG: '<svg aria-hidden=\"true\" class=\"pswp__icn\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M17 17l4 4\"/><path d=\"M3 11a8 8 0 1 0 16 0a8 8 0 1 0-16 0z\"/><path class=\"pswp__zoom-icn-bar-h\" d=\"M8 11h6\"/><path class=\"pswp__zoom-icn-bar-v\" d=\"M11 8v6\"/></svg>',\n    });\n    pswp.addFilter('thumbEl', (thumbEl, data) => data.element || thumbEl);\n    pswp.on('uiRegister', () => {\n      pswp.ui.registerElement({\n        name: 'pb-counter',\n        className: 'pb-pswp__counter',\n        appendTo: 'root',\n        order: 6,\n        onInit: (el) => {\n          el.setAttribute('aria-hidden', 'true');\n          const update = () => { el.textContent = items.length > 1 ? `${pswp.currIndex + 1} / ${items.length}` : ''; };\n          pswp.on('change', update);\n          update();\n        },\n      });\n      // Miniaturas (en el celular, CSS): tocar una salta a esa foto; la actual queda marcada y centrada en la fila\n      pswp.ui.registerElement({\n        name: 'pb-thumbs',\n        className: 'pb-pswp__thumbs',\n        appendTo: 'root',\n        order: 7,\n        onInit: (el) => {\n          if (items.length < 2) { el.hidden = true; return; }\n          el.setAttribute('role', 'group');\n          el.setAttribute('aria-label', 'Miniaturas de las fotos');\n          el.innerHTML = current.images.map((img, i) =>\n            `<button type=\"button\" class=\"pb-pswp__thumb\" data-i=\"${i}\" aria-label=\"${isVideo(img) ? 'Ver video' : 'Ver foto'} ${i + 1} de ${items.length}\">\n              <img src=\"${esc(img.src + '&width=160')}\" alt=\"\" width=\"52\" height=\"52\">${isVideo(img) ? `<span class=\"pb-pswp__thumb-play\">${PLAY_SVG}</span>` : ''}\n            </button>`).join('');\n          el.addEventListener('click', (e) => {\n            const b = e.target.closest('[data-i]');\n            if (b) pswp.goTo(+b.dataset.i);\n          });\n          const mark = (smooth = true) => {\n            $$('[data-i]', el).forEach((b) => {\n              const on = +b.dataset.i === pswp.currIndex;\n              b.setAttribute('aria-current', String(on));\n              if (on) el.scrollTo({ left: b.offsetLeft - (el.clientWidth - b.offsetWidth) / 2, behavior: smooth && !fast ? 'smooth' : 'auto' });\n            });\n          };\n          pswp.on('change', () => mark());\n          mark(false);\n        },\n      });\n    });\n    // Deslizar la fila de miniaturas es scroll normal, no un gesto de la galer\u00EDa\n    pswp.on('pointerDown', (e) => {\n      if (e.originalEvent.target.closest && e.originalEvent.target.closest('.pb-pswp__thumbs')) e.preventDefault();\n    });\n    // Accesible: el di\u00E1logo se anuncia con el producto y cada cambio de foto se lee una vez\n    pswp.on('firstUpdate', () => {\n      pswp.element.setAttribute('aria-label', `Fotos de ${current.title || data.name || ''}`.trim());\n    });\n    pswp.on('change', () => {\n      syncInline(pswp.currIndex);\n      if (liveEl) liveEl.textContent = `${isVideo(current.images[pswp.currIndex]) ? 'Video' : 'Foto'} ${pswp.currIndex + 1} de ${items.length}`;\n    });\n    // Videos: suenan en la vista ampliada (el toque que la abri\u00F3 lo permite); al salir de esa foto se pausan\n    pswp.on('contentActivate', ({ content }) => {\n      const v = content.element && content.element.querySelector && content.element.querySelector('video');\n      if (v) v.play().catch(() => { v.muted = true; v.play().catch(() => {}); });\n    });\n    pswp.on('contentDeactivate', ({ content }) => {\n      const v = content.element && content.element.querySelector && content.element.querySelector('video');\n      if (v) v.pause();\n    });\n    pswp.on('close', () => syncVideos());\n    // En los videos el contenedor cubre toda la pantalla: el clic fuera del video tambi\u00E9n cierra\n    pswp.on('bindEvents', () => {\n      pswp.element.addEventListener('click', (e) => { if (e.target.classList.contains('pb-pswp-video')) pswp.close(); });\n    });\n    pswp.on('destroy', () => {\n      const btn = track.children[activeIndex] && track.children[activeIndex].querySelector('.pdp-media__zoom');\n      if (btn) btn.focus({ preventScroll: true });\n    });\n    syncVideos(true);\n    pswp.init();\n  }\n\n  track.addEventListener('click', (e) => {\n    const zoom = e.target.closest('[data-zoom]');\n    if (zoom) openPswp(+zoom.dataset.zoom);\n  });\n\n  /* ---------- Combinaciones de color (productos hermanos) ---------- */\n  const swatches = $$('[data-swatch]');\n  // Los colores elegidos ya van bajo el t\u00EDtulo: la etiqueta dice \"Elige tus colores\" y, al pasar por una miniatura,\n  // muestra el nombre de esa combinaci\u00F3n. Se borra al salir de toda la fila (no entre miniatura y miniatura: no titila).\n  const colorHover = $('[data-color-hover]');\n  const swatchList = $('.pdp-colors__list');\n  const hideHover = () => { colorHover.textContent = ''; };\n  swatches.forEach((sw) => {\n    const show = () => { colorHover.textContent = sw.getAttribute('aria-label'); };\n    sw.addEventListener('mouseenter', show);\n    sw.addEventListener('focus', show);\n  });\n  if (swatchList) {   // productos de un solo color: no hay fila de colores\n    swatchList.addEventListener('mouseleave', hideHover);\n    swatchList.addEventListener('focusout', (e) => { if (!swatchList.contains(e.relatedTarget)) hideHover(); });\n  }\n  const includesEl = $('[data-includes]');\n  const measuresEl = $('[data-measures]');\n  const preview = $('[data-star-preview], [data-number-preview], [data-bubble-preview]');\n\n  const includesHTML = (items) => items.map(([qty, text, sub]) =>\n    `<li class=\"includes__item\"><span class=\"includes__qty\">${esc(qty) || '<svg aria-hidden=\"true\"><use href=\"#i-check\"/></svg>'}</span><span class=\"includes__text\">${esc(text)}${sub ? `<span class=\"includes__sub\">${esc(sub)}</span>` : ''}</span></li>`\n  ).join('');\n\n  // highlights: [[valor, unidad, etiqueta]]; si no hay, se arman con measures [alto en m, ancho en cm]\n  const measuresHTML = (p) => {\n    const highlights = p.highlights || [];\n    return `<div class=\"measures\">${highlights.map(([v, unit, label]) =>\n      `<div class=\"measures__item\"><p class=\"measures__value\">${esc(v)}<small>${esc(unit)}</small></p><p class=\"measures__label\">${esc(label)}</p></div>`).join('')}</div>` +\n      (p.sizes && p.sizes.length ? `<ul class=\"measures-list\">${p.sizes.map(([a, b]) => `<li><span>${esc(a)}</span><span>${esc(b)}</span></li>`).join('')}</ul>` : '');\n  };\n\n  function selectProduct(key) {\n    const next = data.products[key];\n    if (!next || next === current) return;\n    const prev = current;\n    current = next;\n    data.current = key;\n\n    $$('[data-swatch]').forEach((s) => s.setAttribute('aria-current', String(s.dataset.swatch === key)));\n    $('[data-variant-name]').textContent = next.color;\n    $('[data-sticky-color]').textContent = next.color;\n    const stickyImg = $('[data-sticky-img]');\n    if (stickyImg) stickyImg.src = `${next.thumb || next.images[0].src}&width=200`;\n    $('[data-pdp-variant-id]').value = next.variantId;\n    $$('[data-price]').forEach((el) => { el.textContent = money(next.price); });\n    setCompare(next.price, next.compare);\n    setAvailability(next);\n    document.title = document.title.replace(prev.color, next.color);\n    // Modelos cuyos colores son productos con distinto t\u00EDtulo (p. ej. burbujas): H1 y barra fija lo siguen\n    if (next.title && prev.title) {\n      $$('[data-pdp-name]').forEach((el) => { el.textContent = next.name || data.name || next.title; });\n      $$('[data-product-kicker]').forEach((el) => { el.textContent = next.title; });\n      document.title = document.title.replace(prev.title, next.title);\n    }\n    if (includesEl) {\n      includesEl.innerHTML = next.includes && next.includes.length\n        ? `<ul class=\"includes\">${includesHTML(next.includes)}</ul>`\n        : `<div class=\"includes-rich\">${next.includesHtml || ''}</div>`;\n    }\n    if (measuresEl) {\n      measuresEl.innerHTML = (next.highlights && next.highlights.length) || (next.sizes && next.sizes.length) ? measuresHTML(next) : '';\n      const note = $('[data-height-note]');\n      if (note) note.hidden = !next.height;\n      if (next.height) $$('[data-height-min]').forEach((el) => { el.textContent = next.height[0]; });\n      if (next.height) $$('[data-height-max]').forEach((el) => { el.textContent = next.height[1]; });\n    }\n    if (preview && next.theme) preview.dataset.theme = next.theme;\n    if (preview) preview.classList.toggle('bubble-preview--stacked', !!next.phraseStacked);\n    perso.onProductChange(prev, next);\n    try { history.replaceState(history.state, '', next.url); } catch (e) { /* sin historial */ }\n    document.dispatchEvent(new CustomEvent('pb:productchange', { detail: { key } }));\n\n    // Cambio de color inmediato: sin fundido de la galer\u00EDa\n    renderGallery(next);\n    updateWhatsApp();\n  }\n\n  // Precarga la foto principal de cada color para que el cambio sea instant\u00E1neo\n  const preloadColors = () => Object.values(data.products).forEach((p) => {\n    const img = new Image();\n    img.sizes = '(min-width: 960px) 50vw, 100vw';\n    img.srcset = [512, 768, 1024].map((w) => `${p.images[0].src}&width=${w} ${w}w`).join(', ');\n    img.src = `${p.images[0].src}&width=1024`;\n  });\n  if ('requestIdleCallback' in window) requestIdleCallback(preloadColors, { timeout: 2500 });\n  else window.addEventListener('load', preloadColors, { once: true });\n\n  swatches.forEach((s) => s.addEventListener('click', (e) => {\n    e.preventDefault();\n    selectProduct(s.dataset.swatch);\n  }));\n\n  // M\u00F3vil: los colores quedan muy arriba cuando uno est\u00E1 personalizando. Al final de Personalizaci\u00F3n, un enlace\n  // chico \"Ver m\u00E1s colores\" despliega las mismas miniaturas para cambiar de color sin volver a subir.\n  const persoPanel = $('#panel-personalizacion');\n  if (persoPanel && swatches.length > 1) {\n    const quick = document.createElement('div');\n    quick.className = 'quick-colors';\n    quick.innerHTML = `<button type=\"button\" class=\"link-btn quick-colors__toggle\" aria-expanded=\"false\">Ver m\u00E1s colores <svg aria-hidden=\"true\"><use href=\"#i-chevron-down\"/></svg></button>\n      <div class=\"quick-colors__list\" role=\"group\" aria-label=\"Colores\" hidden></div>`;\n    const toggle = $('.quick-colors__toggle', quick);\n    const list = $('.quick-colors__list', quick);\n    swatches.forEach((sw) => {\n      const mini = sw.cloneNode(true);\n      mini.classList.add('pdp-swatch--mini');\n      list.append(mini);\n    });\n    list.addEventListener('click', (e) => {\n      const mini = e.target.closest('[data-swatch]');\n      if (!mini) return;\n      e.preventDefault();\n      selectProduct(mini.dataset.swatch);\n    });\n    toggle.addEventListener('click', () => {\n      const open = list.hidden;\n      list.hidden = !open;\n      toggle.setAttribute('aria-expanded', String(open));\n      toggle.firstChild.textContent = open ? 'Ocultar colores ' : 'Ver m\u00E1s colores ';\n    });\n    persoPanel.append(quick);\n  }\n\n  /* ---------- Variantes que no son colores (p. ej. tama\u00F1os de una decoraci\u00F3n) ---------- */\n  const variantSelect = $('[data-variant-select]');\n  if (variantSelect) {\n    variantSelect.addEventListener('change', () => {\n      const opt = variantSelect.selectedOptions[0];\n      current.variantId = Number(variantSelect.value);\n      current.price = Number(opt.dataset.price);\n      current.compare = Number(opt.dataset.compare || 0);\n      $('[data-pdp-variant-id]').value = variantSelect.value;\n      $$('[data-price]').forEach((el) => { el.textContent = money(current.price); });\n      setCompare(current.price, current.compare);\n    });\n  }\n\n  /* ---------- Tabs ---------- */\n  const tabs = $$('[role=\"tab\"]');\n\n  function activateTab(tab, focus = false) {\n    tabs.forEach((t) => {\n      const selected = t === tab;\n      const panel = document.getElementById(t.getAttribute('aria-controls'));\n      if (selected && panel.hidden) panel.classList.add('is-entering');\n      if (!selected) panel.classList.remove('is-entering');\n      t.setAttribute('aria-selected', String(selected));\n      t.tabIndex = selected ? 0 : -1;\n      panel.hidden = !selected;\n    });\n    if (focus) tab.focus();\n    if (tab.id === 'tab-personalizacion') perso.fit();\n  }\n\n  tabs.forEach((tab, i) => {\n    tab.addEventListener('click', () => activateTab(tab));\n    tab.addEventListener('keydown', (e) => {\n      const step = { ArrowRight: 1, ArrowLeft: -1 }[e.key];\n      if (!step) return;\n      e.preventDefault();\n      activateTab(tabs[(i + step + tabs.length) % tabs.length], true);\n    });\n  });\n\n  $$('[data-goto-tab]').forEach((btn) => btn.addEventListener('click', () => {\n    const tab = document.getElementById('tab-' + btn.dataset.gotoTab);\n    activateTab(tab);\n    scrollIntoInfo(tab);\n  }));\n\n  // Lleva un elemento de la columna de compra a la vista, considerando que en desktop es sticky\n  function scrollIntoInfo(el) {\n    const rect = el.getBoundingClientRect();\n    const topLimit = topChrome() + 16;\n    if (rect.top >= topLimit && rect.bottom <= window.innerHeight - 16) return;\n    const y = desktop.matches\n      ? grid.getBoundingClientRect().top + window.scrollY + (rect.top - info.getBoundingClientRect().top)\n      : rect.top + window.scrollY;\n    window.scrollTo({ top: Math.max(0, y - topLimit - 24), behavior: 'smooth' });\n  }\n\n  /* ---------- Personalizaci\u00F3n ----------\n     Dos modos seg\u00FAn el producto: frase + nombre (bouquet estrella) o n\u00FAmeros (bouquet de n\u00FAmeros).\n     Cada modo devuelve lo mismo: fit, checks, props, wa, onProductChange e init. */\n  const previewStage = $('[data-preview-stage]');\n\n  // Reduce el tama\u00F1o hasta que el texto quepa en una l\u00EDnea\n  function fitLine(el, max, min) {\n    let size = max;\n    el.style.fontSize = `${size}px`;\n    while (el.scrollWidth > el.clientWidth + 0.5 && size > min) {\n      size -= 0.25;\n      el.style.fontSize = `${size}px`;\n    }\n    return el.scrollWidth <= el.clientWidth + 0.5;\n  }\n\n  function phrasePersonalization() {\n    const phraseInput = $('[data-phrase-input]');\n    const nameInput = $('[data-name-input]');\n    const chips = $$('[data-phrase]');\n    const customChip = $('[data-phrase-custom]');\n    const previewPhrase = $('[data-preview-phrase]');\n    const previewName = $('[data-preview-name]');\n    const linesBox = $('[data-name-lines]');\n    let customMode = false;\n    let nameLines = 0; // 0: autom\u00E1tico (dos l\u00EDneas si no entra bien en una); 1 o 2: lo eligi\u00F3 el cliente\n    let canWrap = false; // el nombre actual admite pasar a dos l\u00EDneas\n    let nameWrapped = false;\n\n    function syncChips() {\n      const value = phraseInput.value.trim().toLowerCase();\n      let matched = false;\n      chips.forEach((chip) => {\n        const on = value !== '' && chip.dataset.phrase.toLowerCase() === value;\n        chip.setAttribute('aria-pressed', String(on));\n        matched = matched || on;\n      });\n      customChip.setAttribute('aria-pressed', String(!matched && (customMode || value !== '')));\n      // En la fila deslizable, la frase elegida queda a la vista\n      const pressed = $('[aria-pressed=\"true\"]', customChip.parentElement);\n      const row = customChip.parentElement;\n      if (pressed && row.scrollWidth > row.clientWidth) {\n        const r = row.getBoundingClientRect(), c = pressed.getBoundingClientRect();\n        if (c.left < r.left || c.right > r.right - 28) row.scrollLeft += c.left - r.left - 16;\n      }\n    }\n\n    // La frase sugerida del color elegido va primera en la fila\n    function leadWith(phrase) {\n      const chip = chips.find((c) => c.dataset.phrase === phrase);\n      if (!chip) return;\n      const row = chip.parentElement;\n      row.prepend(chip, ...chips.filter((c) => c !== chip)); // el resto mantiene su orden; \"Otra frase\" queda al final\n      row.scrollLeft = 0;\n    }\n\n    function setPhrase(text) {\n      phraseInput.value = text;\n      phraseInput.dispatchEvent(new Event('input', { bubbles: true }));\n    }\n\n    function fit() {\n      const w = previewStage.clientWidth;\n      if (!w) return; // tab oculto: se ajusta al volver a mostrarse\n      // Proporciones del texto seg\u00FAn la pieza (estrella por defecto; la burbuja las define en su CSS)\n      const css = getComputedStyle(previewStage);\n      const r = (name, fallback) => parseFloat(css.getPropertyValue(name)) || fallback;\n      const hasName = !previewName.hidden;\n      previewPhrase.classList.remove('is-wrapped');\n      // Frase apilada: ya viene en dos l\u00EDneas (stackPhrase), se ajusta la m\u00E1s larga sin pasar a otro corte\n      const stacked = !!previewStage.closest('.bubble-preview--stacked');\n      if (!fitLine(previewPhrase, w * (hasName ? r('--fit-phrase', 0.085) : r('--fit-phrase-solo', 0.115)), w * r('--fit-phrase-min', 0.05)) && !stacked) {\n        previewPhrase.classList.add('is-wrapped');\n        previewPhrase.style.fontSize = `${w * (hasName ? r('--fit-wrap', 0.05) : r('--fit-wrap-solo', 0.064))}px`;\n      }\n      previewName.classList.remove('is-wrapped');\n      previewName.textContent = previewName.textContent.replace(/\\n/g, ' ');\n      canWrap = false;\n      nameWrapped = false;\n      if (!hasName) return syncLines();\n      fitLine(previewName, w * r('--fit-name', 0.2), w * r('--fit-name-min', 0.085));\n      requestAnimationFrame(() => syncLinesInput && syncLinesInput());\n      // Nombres largos (p. ej. nombre y apellido): en vez de quedar chiquitos en una l\u00EDnea, pasan a dos\n      // l\u00EDneas equilibradas y m\u00E1s grandes, achic\u00E1ndose solo lo necesario para entrar en el globo.\n      // El cliente puede volver a una sola l\u00EDnea con \"1 l\u00EDnea \u00B7 2 l\u00EDneas\".\n      const wrapAt = r('--fit-name-wrap-at', 0);\n      canWrap = !!wrapAt && !!nameInput.value.trim() && parseFloat(previewName.style.fontSize) < w * wrapAt && /\\s/.test(previewName.textContent.trim());\n      syncLines();\n      if (canWrap && nameLines !== 1) {\n        nameWrapped = true;\n        // Salto fijo: al achicarse para entrar en el globo, el nombre no vuelve a juntarse en una l\u00EDnea\n        previewName.textContent = twoLines(previewName.textContent.trim());\n        previewName.classList.add('is-wrapped');\n        const box = previewName.parentElement;\n        let size = w * r('--fit-name-wrap', 0.12);\n        const min = w * r('--fit-name-min', 0.085);\n        const over = () => previewName.scrollWidth > previewName.clientWidth + 0.5 || box.scrollHeight > box.clientHeight + 0.5;\n        previewName.style.fontSize = `${size}px`;\n        while (over() && size > min) { size -= 0.25; previewName.style.fontSize = `${size}px`; }\n      }\n    }\n\n    function syncLines() {\n      if (!linesBox) return;\n      linesBox.classList.toggle('is-shown', canWrap);\n      linesBox.querySelectorAll('[data-lines]').forEach((b) => b.setAttribute('aria-pressed', String(+b.dataset.lines === (nameLines === 1 ? 1 : 2))));\n    }\n    linesBox?.addEventListener('click', (e) => {\n      const btn = e.target.closest('[data-lines]');\n      if (!btn) return;\n      nameLines = +btn.dataset.lines;\n      fit();\n    });\n    // Solo cuando el nombre admite dos l\u00EDneas se anota c\u00F3mo va en el globo\n    const linesNote = () => (canWrap ? (nameWrapped ? '2 l\u00EDneas' : '1 l\u00EDnea') : '');\n    const linesInput = $('[data-name-lines-value]');\n    const syncLinesInput = () => { if (linesInput) linesInput.value = linesNote(); };\n\n    // Parte un texto en dos l\u00EDneas equilibradas (salto con \\n, se ve con white-space: pre)\n    function twoLines(text) {\n      const words = text.split(/\\s+/);\n      if (words.length < 2) return text;\n      let best = 1;\n      for (let i = 1; i < words.length; i++) {\n        const worst = (k) => Math.max(words.slice(0, k).join(' ').length, words.slice(k).join(' ').length);\n        if (worst(i) < worst(best)) best = i;\n      }\n      return `${words.slice(0, best).join(' ')}\\n${words.slice(best).join(' ')}`;\n    }\n\n    // Frase apilada (ficha.frase_apilada): en dos l\u00EDneas, como la foto (\u00ABHAPPY / BIRTHDAY\u00BB); las cortas van en una\n    const stackPhrase = (text) => (previewStage.closest('.bubble-preview--stacked') && text.length >= 10 ? twoLines(text) : text);\n\n    function renderPreview() {\n      const phrase = phraseInput.value.trim();\n      const name = nameInput.value.trim();\n      previewPhrase.textContent = stackPhrase(phrase || 'Tu frase');\n      previewPhrase.style.opacity = phrase ? '' : '.35';\n      // Con data-ghost-name, sin nombre se ve el de ejemplo en tenue (como en la foto del producto)\n      const ghost = !name && 'ghostName' in previewStage.dataset;\n      previewName.textContent = name || (ghost ? current.nameExample : '');\n      previewName.hidden = !name && !ghost;\n      previewName.classList.toggle('is-ghost', ghost);\n      fit();\n    }\n\n    chips.forEach((chip) => chip.addEventListener('click', () => {\n      customMode = false;\n      setPhrase(chip.dataset.phrase);\n    }));\n    customChip.addEventListener('click', () => {\n      customMode = true;\n      setPhrase('');\n      phraseInput.focus();\n    });\n    phraseInput.addEventListener('input', () => {\n      syncChips();\n      if (phraseInput.value.trim()) clearError('frase', phraseInput);\n      renderPreview();\n    });\n    nameInput.addEventListener('input', () => {\n      if (nameInput.value.trim()) clearError('nombre', nameInput);\n      renderPreview();\n    });\n    // El nombre es obligatorio solo donde el campo lo pide (burbuja); en la estrella sigue opcional\n    const nameRequired = nameInput.required;\n\n    return {\n      fit,\n      checks: () => [\n        ['frase', phraseInput, !!phraseInput.value.trim()],\n        ...(nameRequired ? [['nombre', nameInput, !!nameInput.value.trim()]] : []),\n      ],\n      props: () => [['Frase', phraseInput.value.trim()], ['Nombre', nameInput.value.trim()], ['Nombre en', linesNote()]],\n      wa: () => [['Frase', phraseInput.value.trim()], ['Nombre en el globo', nameInput.value.trim()], ['Nombre en', linesNote()]],\n      onProductChange(prev, next) {\n        nameInput.placeholder = `Ej: ${next.nameExample}`;\n        leadWith(next.phrase);\n        // Si la frase sigue siendo la sugerida del color anterior, usar la del nuevo\n        if (phraseInput.value.trim() === prev.phrase) setPhrase(next.phrase);\n        else renderPreview();\n      },\n      init() {\n        leadWith(current.phrase);\n        syncChips();\n        renderPreview();\n      },\n    };\n  }\n\n  function numberPersonalization() {\n    const root = $('[data-numbers]');\n    const slotsBox = $('[data-number-slots]', root);\n    const slots = $$('[data-slot]', root);\n    const presets = $$('[data-number-preset]', root);\n    const valueInput = $('[data-number-value]', root);\n    const previewNumber = $('[data-preview-number]');\n    const digits = slots.map(() => null);\n    const errorText = $('[data-error=\"numero\"]');\n    const title = $('[data-number-title]', root);\n    const hint = $('[data-number-hint]', root);\n    const hintText = $('[data-number-hint-text]', root);\n    const clearBtn = $('[data-number-clear]', root);\n    const countSwitch = $('.count-switch', root);\n    const countBtns = $$('[data-number-count]', root);\n    let active = 0;\n    let editing = false; // toc\u00F3 una casilla ya llena para cambiarla: se marca aunque el n\u00FAmero est\u00E9 completo\n    // 1 o 2 globos n\u00FAmero (con 1 es m\u00E1s barato). En Shopify ser\u00EDa la variante \"1 n\u00FAmero\".\n    let count = slots.length;\n    const setCount = (n) => {\n      count = n;\n      while (digits.length > n) digits.pop();\n      while (digits.length < n) digits.push(null);\n    };\n\n    const value = () => (digits.every((d) => d !== null) ? digits.join('') : '');\n    const price = () => (count < slots.length && current.priceOne ? current.priceOne : current.price);\n\n    function render() {\n      const filled = digits.filter((d) => d !== null).length;\n      const done = !!value() && !editing;\n      slots.forEach((slot, i) => {\n        slot.hidden = i >= count;\n        slot.textContent = digits[i] ?? '';\n        slot.classList.toggle('is-active', i === active && !done);\n        slot.setAttribute('aria-label', `${count > 1 ? `${i ? 'Segundo' : 'Primer'} n\u00FAmero` : 'Tu n\u00FAmero'}${digits[i] != null ? `: ${digits[i]}` : ', vac\u00EDo'}`);\n      });\n      if (countSwitch) countSwitch.dataset.count = count;   // sin variante \u00AB1 n\u00FAmero\u00BB no hay switch\n      root.dataset.count = count; // edades populares de 1 o de 2 n\u00FAmeros seg\u00FAn la cantidad\n      countBtns.forEach((b) => b.setAttribute('aria-checked', String(+b.dataset.numberCount === count)));\n      // Precio de cada opci\u00F3n dentro del switch, discreto (1 n\u00FAmero cuesta menos)\n      $$('[data-count-price]', root).forEach((el) => {\n        const p = +el.dataset.countPrice < slots.length ? current.priceOne : current.price;\n        el.textContent = p ? money(p) : '';\n      });\n      // La gu\u00EDa dice siempre el siguiente paso; al terminar confirma y lleva al siguiente campo (la fecha)\n      hintText.textContent = done ? '\u00A1Listo! Ahora elige la fecha'\n        : editing ? 'Toca el nuevo n\u00FAmero'\n        : !filled ? (count > 1 ? 'Toca el primer n\u00FAmero' : 'Toca tu n\u00FAmero')\n        : active === 1 ? 'Ahora el segundo' : 'Elige el primero';\n      hint.classList.toggle('is-done', done);\n      $('use', hint).setAttribute('href', done ? '#i-check' : '#i-arrow-right');\n      title.textContent = value() ? `Tu n\u00FAmero: ${value()}` : '\u00BFQu\u00E9 n\u00FAmero celebras?';\n      clearBtn.hidden = !filled;\n      errorText.textContent = count > 1 ? `Elige los ${count} n\u00FAmeros` : 'Elige tu n\u00FAmero';\n      $$('[data-price]').forEach((el) => { el.textContent = money(price()); });\n      setCompare(price(), price() === current.price ? current.compare : 0); // la variante \u00AB1 n\u00FAmero\u00BB no hereda el tachado\n      valueInput.value = value();\n      presets.forEach((p) => p.setAttribute('aria-pressed', String(p.dataset.numberPreset === value())));\n      keys.forEach((key) => key.classList.toggle('is-picked', digits.includes(key.dataset.digit)));\n      // Fotos reales de los globos n\u00FAmero (insumos de pb-estudio-catalogo) en el color del bouquet\n      // ?v=: cambia cuando se rehacen las fotos de los n\u00FAmeros (mate crema y plata sin arco\u00EDris, 2026-11-01) para no ver la versi\u00F3n en cach\u00E9.\n      const src = (d) => (data.digitImages[current.digits] || data.digitImages.plata || [])[d];\n      // Teclado: cada n\u00FAmero cambia de color reci\u00E9n cuando la imagen nueva est\u00E1 lista (sin parpadeo)\n      keys.forEach((key) => {\n        const img = key.querySelector('img');\n        const next = src(key.dataset.digit);\n        if (!img || img.src.endsWith(next)) return;\n        const tmp = makeImg({ src: next });\n        ready(tmp).then(() => { img.src = next; });\n      });\n      paintPreview(src);\n      if (exampleTag) exampleTag.hidden = filled > 0;\n      if (value()) clearError('numero', slotsBox);\n      updateWhatsApp();\n    }\n\n    // Piezas del bouquet alrededor de los n\u00FAmeros (fotos de insumos), con la composici\u00F3n medida\n    // sobre la foto 1:1 de cada color: posici\u00F3n, ancho, giro y capa de cada pieza.\n    const piecesBox = $('[data-scene-pieces]');\n    const exampleTag = $('[data-preview-example]');\n    let sceneFor = null;\n\n    // Punta de la boquilla/nudo de cada pieza (medida en los recortes, en proporci\u00F3n a la imagen)\n    const TIPS = {\n      'corazon-champana': [0.497, 0.997], 'corazon-dorado': [0.505, 0.997], 'corazon-oro-rosa': [0.504, 0.997],\n      'corazon-plata': [0.519, 0.997], 'corazon-rosa-palo': [0.496, 0.997], 'estrella-dorado': [0.481, 0.997],\n      'estrella-oro-rosa': [0.481, 0.997], 'estrella-oro-rosa-intenso': [0.487, 0.997], 'estrella-plata': [0.487, 0.997], burbuja: [0.5, 0.885],\n    };\n\n    // Punto de amarre en coordenadas del cuadro (%), respetando el giro de la pieza\n    function tipOf(img) {\n      const [fx, fy] = TIPS[img.dataset.slug] || [0.5, 0.995];\n      const w = img.offsetWidth, h = img.offsetHeight;\n      const t = getComputedStyle(img).transform;\n      const m = new DOMMatrix(t === 'none' ? undefined : t);\n      const dx = w * (fx - 0.5), dy = h * (fy - 0.5);\n      const cx = img.offsetLeft + w / 2 + m.a * dx + m.c * dy;\n      const cy = img.offsetTop + h / 2 + m.b * dx + m.d * dy;\n      return [(cx / previewStage.offsetWidth) * 100, (cy / previewStage.offsetHeight) * 100];\n    }\n\n    // Mo\u00F1o de cinta (como en la foto): lazos de raso con sombra suave, un poco asim\u00E9tricos, el nudo y dos puntas que caen\n    const bowSvg = (x, y) => {\n      const P = (dx, dy) => `${(x + dx).toFixed(2)} ${(y + dy).toFixed(2)}`;\n      return `<defs><linearGradient id=\"bow-satin\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"#FFFFFF\"/><stop offset=\"1\" stop-color=\"#E2E2E7\"/></linearGradient></defs>\n      <g fill=\"url(#bow-satin)\" stroke=\"rgba(130, 130, 140, .4)\" stroke-width=\".13\" stroke-linejoin=\"round\">\n        <path d=\"M${P(-0.25, 0.35)}C${P(-0.8, 1.7)} ${P(-1.5, 3.1)} ${P(-2.4, 4.7)}L${P(-1.5, 4.5)}C${P(-0.9, 3.1)} ${P(-0.4, 1.8)} ${P(0.1, 0.5)}Z\"/>\n        <path d=\"M${P(0.25, 0.35)}C${P(0.8, 1.8)} ${P(1.3, 3.3)} ${P(1.8, 5)}L${P(2.6, 4.5)}C${P(1.9, 3.1)} ${P(1.1, 1.7)} ${P(0.5, 0.35)}Z\"/>\n        <path d=\"M${P(0, 0)}C${P(-1.2, -2.2)} ${P(-4.5, -2.9)} ${P(-4.8, -1)}C${P(-5, 0.6)} ${P(-2.3, 1.2)} ${P(0, 0)}Z\"/>\n        <path d=\"M${P(0, 0)}C${P(1.3, -2)} ${P(4.2, -2.5)} ${P(4.5, -0.8)}C${P(4.7, 0.8)} ${P(2.1, 1.1)} ${P(0, 0)}Z\"/>\n        <ellipse cx=\"${x}\" cy=\"${(y + 0.1).toFixed(2)}\" rx=\".65\" ry=\".8\"/>\n      </g>\n      <path d=\"M${P(-0.9, -0.5)}c-1-.7-2.3-1-3.3-.6M${P(0.9, -0.4)}c1-.6 2-.8 2.9-.5\" fill=\"none\" stroke=\"rgba(130, 130, 140, .3)\" stroke-width=\".12\" stroke-linecap=\"round\"/>`;\n    };\n\n    // Cintas: rectas desde cada boquilla hacia un mismo punto bajo el cuadro (como el atado de la foto)\n    function drawStrings() {\n      const pieces = $$('.number-scene__piece', piecesBox);\n      if (!previewStage.offsetWidth || !pieces.length || pieces.some((img) => img.tagName === 'IMG' && !img.naturalWidth)) return;\n      const ribbon = current.scene.ribbon || '#8C8C8C';\n      const bow = current.scene.lazo && layout(current.scene.lazo); // con \u00ABlazo\u00BB en la ficha, las cintas se juntan en un mo\u00F1o\n      const paths = pieces.map((img) => {\n        const [x, y] = tipOf(img);\n        if (!bow) return `<line x1=\"${x.toFixed(2)}\" y1=\"${y.toFixed(2)}\" x2=\"${(49 + (x - 49) * 0.25).toFixed(2)}\" y2=\"122\" stroke=\"${ribbon}\" stroke-width=\".3\" opacity=\".6\"/>`;\n        // Con mo\u00F1o: cada cinta cae con una curva leve hasta el nudo (rectas se ve\u00EDan tiesas)\n        const cx = x + (bow.x - x) * 0.3;\n        const cy = y + (bow.y - y) * 0.7;\n        return `<path d=\"M${x.toFixed(2)} ${y.toFixed(2)}Q${cx.toFixed(2)} ${cy.toFixed(2)} ${bow.x} ${(bow.y + 0.2).toFixed(2)}\" fill=\"none\" stroke=\"${ribbon}\" stroke-width=\".26\" stroke-linecap=\"round\" opacity=\".95\"/>`;\n      }).join('');\n      $('.number-scene__strings', piecesBox).innerHTML = paths + (bow ? bowSvg(bow.x, bow.y) : '');\n    }\n\n    const pieceSrc = (p) => data.pieceImages[p.src];\n\n    // Texto de la burbuja de la escena: mismas proporciones que la vista previa de los bouquets burbuja\n    // (respecto del ancho del globo); sin nombre se ve el de ejemplo en tenue, como en la foto\n    const bubbleTpl = $('[data-bubble-piece]');\n    const phraseField = $('[data-generic-field=\"frase\"]');\n    const nameField = $('[data-generic-field=\"nombre\"]');\n    function fitBubble() {\n      const bubble = $('.number-scene__bubble', piecesBox);\n      if (!bubble || !bubble.offsetWidth) return;\n      const w = bubble.offsetWidth;\n      const css = getComputedStyle(bubble);\n      const r = (prop, fallback) => parseFloat(css.getPropertyValue(prop)) || fallback;\n      const phraseEl = $('[data-bubble-phrase]', bubble);\n      const nameEl = $('[data-bubble-name]', bubble);\n      const phrase = phraseField ? phraseField.value.trim() : '';\n      const name = nameField ? nameField.value.trim() : '';\n      phraseEl.textContent = phrase || (phraseField ? 'Tu frase' : '');\n      phraseEl.style.opacity = phrase ? '' : '.35';\n      phraseEl.hidden = !phraseField;\n      nameEl.textContent = name || current.nameExample || '';\n      nameEl.hidden = !nameField;\n      nameEl.classList.toggle('is-ghost', !name);\n      const hasName = !nameEl.hidden;\n      phraseEl.classList.remove('is-wrapped');\n      if (!phraseEl.hidden && !fitLine(phraseEl, w * (hasName ? r('--fit-phrase', 0.066) : r('--fit-phrase-solo', 0.08)), w * r('--fit-phrase-min', 0.042))) {\n        phraseEl.classList.add('is-wrapped');\n        phraseEl.style.fontSize = `${w * (hasName ? 0.046 : 0.056)}px`;\n      }\n      if (hasName) fitLine(nameEl, w * r('--fit-name', 0.165), w * r('--fit-name-min', 0.075));\n    }\n    [phraseField, nameField].forEach((field) => field && field.addEventListener('input', fitBubble));\n    // La caligraf\u00EDa se descarga reci\u00E9n cuando aparece la burbuja: al llegar, se vuelve a medir el texto\n    if (bubbleTpl && document.fonts) document.fonts.load('400 40px \"Brittany Signature\"').then(fitBubble).catch(() => {});\n    const makeImg = (attrs) => Object.assign(new Image(), attrs);\n    // Lista para pintar: cargada (y decodificada si el navegador lo permite); nunca bloquea m\u00E1s de 1,5 s\n    const ready = (img) => new Promise((resolve) => {\n      const done = () => (img.decode ? Promise.race([img.decode().catch(() => {}), new Promise((r) => setTimeout(r, 150))]).then(resolve) : resolve());\n      if (img.complete && img.naturalWidth) done();\n      else {\n        img.addEventListener('load', done, { once: true });\n        img.addEventListener('error', resolve, { once: true });\n      }\n      setTimeout(resolve, 1500);\n    });\n\n    // Doble b\u00FAfer: la escena nueva (piezas del color y n\u00FAmeros) se arma fuera de la p\u00E1gina, se espera a que\n    // todas las im\u00E1genes est\u00E9n decodificadas y reci\u00E9n ah\u00ED se cambia todo junto. As\u00ED al cambiar de color o\n    // de n\u00FAmero no se ve un cuadro a medio cargar (piezas faltantes o n\u00FAmeros a tama\u00F1o natural).\n    let paintToken = 0;\n    async function paintPreview(src) {\n      const token = ++paintToken;\n      const product = current;\n      const sceneChanged = product.scene && sceneFor !== product;\n      const example = String(product.number || '00').padStart(slots.length, '0').slice(0, count);\n      const digitImgs = digits.map((d, i) => {\n        const img = makeImg({ className: `number-preview__img${d === null ? ' is-ghost' : ''}`, src: src(d ?? example[i]), alt: '' });\n        img.dataset.glyph = d ?? example[i];\n        return img;\n      });\n      const pieceImgs = sceneChanged ? product.scene.pieces.map((p) => {\n        // La burbuja no es foto: es la de los bouquets burbuja (SVG), con la frase y el nombre que escriben\n        const img = p.kind === 'bubble' && bubbleTpl ? bubbleTpl.content.firstElementChild.cloneNode(true)\n          : makeImg({ className: `number-scene__piece number-scene__piece--${p.kind}`, src: pieceSrc(p), alt: '' });\n        img.dataset.slug = p.src;\n        img.piece = p;\n        return img;\n      }) : [];\n      await Promise.all([...digitImgs, ...pieceImgs].filter((img) => img.tagName === 'IMG').map(ready));\n      if (token !== paintToken) return; // lleg\u00F3 un cambio m\u00E1s nuevo mientras cargaba\n      if (sceneChanged) {\n        sceneFor = product;\n        piecesBox.innerHTML = '<svg class=\"number-scene__strings\" viewBox=\"0 0 100 100\" preserveAspectRatio=\"none\" aria-hidden=\"true\"></svg>';\n        piecesBox.append(...pieceImgs);\n      }\n      placeScene(product);\n      previewNumber.replaceChildren(...digitImgs);\n      fit(); // mide y dibuja cintas en el mismo cuadro, antes de que el navegador pinte\n    }\n\n    // Composici\u00F3n: la de la foto (2 n\u00FAmeros) o, con 1 n\u00FAmero, la variante \u00ABuno\u00BB de la ficha si la tiene\n    // (p. ej. la burbuja, que con 2 n\u00FAmeros va entre los dos, al lado del n\u00FAmero en vez de taparlo)\n    const layout = (base) => (count === 1 && base.uno ? { ...base, ...base.uno } : base);\n    function placeScene(product) {\n      const n = layout(product.scene.numbers);\n      Object.assign(previewNumber.style, { left: `${n.cx - n.maxW / 2}%`, width: `${n.maxW}%`, top: `${n.top}%`, height: `${n.h}%` });\n      $$('.number-scene__piece', piecesBox).forEach((img) => {\n        const p = layout(img.piece);\n        Object.assign(img.style, { left: `${p.x}%`, top: `${p.y}%`, width: `${p.w}%`, zIndex: p.z, transform: `rotate(${p.r}deg)` });\n      });\n    }\n\n    // Precarga (en reposo) los n\u00FAmeros del teclado y las piezas de todos los colores\n    const preloadScenes = () => Object.values(data.products).forEach((p) => {\n      for (let d = 0; d < 10; d += 1) if (data.digitImages[p.digits]) makeImg({ src: data.digitImages[p.digits][d] });\n      (p.scene ? p.scene.pieces : []).filter((pc) => pc.kind !== 'bubble').forEach((pc) => makeImg({ src: pieceSrc(pc) }));\n    });\n    if ('requestIdleCallback' in window) requestIdleCallback(preloadScenes, { timeout: 3000 });\n    else window.addEventListener('load', preloadScenes, { once: true });\n\n    // Todos los n\u00FAmeros a la misma altura (como los globos reales de 32\"): el par se escala junto\n    // para que entre en la vista previa, sin achicar solo los d\u00EDgitos anchos.\n    const OVERLAP = 0.03; // cu\u00E1nto se superponen, en proporci\u00F3n a la altura (en la foto casi se tocan)\n    // Todo con medidas de maquetaci\u00F3n (offset*), no con getBoundingClientRect: as\u00ED no le afectan las\n    // transformaciones (p. ej. la tarjeta flotante encogida al minimizarse) y los n\u00FAmeros nunca quedan chicos.\n    function fit() {\n      fitBubble();\n      drawStrings();\n      const imgs = $$('img', previewNumber);\n      const boxW = previewNumber.offsetWidth;\n      const boxH = previewNumber.offsetHeight;\n      if (!boxW || imgs.some((img) => !img.naturalWidth)) return;\n      const ratios = imgs.map((img) => img.naturalWidth / img.naturalHeight);\n      const widthPerHeight = ratios.reduce((a, b) => a + b, 0) - OVERLAP * (imgs.length - 1);\n      const h = Math.min(boxH, boxW / widthPerHeight);\n      imgs.forEach((img, i) => {\n        img.style.height = `${h}px`;\n        img.style.marginLeft = i ? `${-OVERLAP * h}px` : '0';\n      });\n      // Centrado visual: el centro de masa del par (no su caja) va sobre el eje del coraz\u00F3n, como en la foto.\n      // As\u00ED \"10\" o \"12\" no se ven corridos por el bander\u00EDn del 1 o la panza del 2.\n      const centers = (data.digitCenters || {})[current.digits];\n      const axis = current.scene && layout(current.scene.numbers).axis;\n      previewNumber.style.transform = '';\n      if (!centers || axis == null) return;\n      let sum = 0;\n      let mass = 0;\n      imgs.forEach((img) => {\n        const [cx, m] = centers[img.dataset.glyph];\n        sum += m * (previewNumber.offsetLeft + img.offsetLeft + cx * img.offsetWidth);\n        mass += m;\n      });\n      previewNumber.style.transform = `translateX(${((axis / 100) * previewStage.offsetWidth - sum / mass).toFixed(1)}px)`;\n    }\n\n    const keys = $$('[data-digit]', root);\n    // Las casillas calzan con la grilla del teclado: mismo ancho, alto y separaci\u00F3n que una tecla (cambia seg\u00FAn el\n    // ancho: 5 columnas en desktop, 2 junto a la vista previa en el celular)\n    const keypadGrid = $('.number-keys', root);\n    const syncSlots = () => {\n      const { width, height } = keys[0].getBoundingClientRect(); // con decimales: calza al p\u00EDxel\n      if (!width) return; // pesta\u00F1a oculta: se mide al mostrarse\n      root.style.setProperty('--slot-w', `${width}px`);\n      root.style.setProperty('--slot-h', `${height}px`);\n      root.style.setProperty('--slot-gap', getComputedStyle(keypadGrid).columnGap);\n    };\n    new ResizeObserver(syncSlots).observe(keypadGrid);\n    syncSlots();\n    keys.forEach((key) => key.addEventListener('click', () => {\n      digits[active] = key.dataset.digit;\n      editing = false;\n      if (active < count - 1) active += 1;\n      render();\n    }));\n    slots.forEach((slot, i) => slot.addEventListener('click', () => {\n      active = i;\n      editing = digits[i] !== null; // casilla llena: queda marcada para reemplazar ese n\u00FAmero\n      render();\n    }));\n    countBtns.forEach((b) => b.addEventListener('click', () => {\n      const n = +b.dataset.numberCount;\n      if (n === count) return;\n      setCount(n);\n      editing = false;\n      active = Math.max(0, Math.min(digits.indexOf(null), n - 1));\n      render();\n    }));\n    // Invitaci\u00F3n: la primera vez que el teclado entra en pantalla, los globos se elevan uno tras otro\n    if ('IntersectionObserver' in window && !matchMedia('(prefers-reduced-motion: reduce)').matches) {\n      const keypad = $('.number-keys', root);\n      keys.forEach((key, i) => key.style.setProperty('--i', i));\n      const io = new IntersectionObserver(([entry]) => {\n        if (!entry.isIntersecting) return;\n        io.disconnect();\n        if (digits.some((d) => d !== null)) return;\n        keypad.classList.add('is-inviting');\n        setTimeout(() => keypad.classList.remove('is-inviting'), 1800);\n      }, { threshold: 0.6 });\n      io.observe(keypad);\n    }\n    presets.forEach((p) => p.addEventListener('click', () => {\n      setCount(p.dataset.numberPreset.length);\n      p.dataset.numberPreset.split('').forEach((d, i) => { digits[i] = d; });\n      editing = false;\n      active = count - 1;\n      render();\n    }));\n    clearBtn.addEventListener('click', () => {\n      digits.fill(null);\n      editing = false;\n      active = 0;\n      render();\n    });\n\n    return {\n      fit,\n      checks: () => [['numero', slotsBox, !!value()]],\n      price,\n      variant: () => (count < slots.length && current.variantOne ? current.variantOne : current.variantId),\n      props: () => [['N\u00FAmero', value()]],\n      wa: () => [['N\u00FAmeros', value()]],\n      onProductChange: () => render(),\n      init: render,\n    };\n  }\n\n  // Con las frases de la foto (p. ej. \u00ABBlack Friday y Sale\u00BB) o con el logo del negocio: el selector cambia de variante (precio, tachado, descuento) y\n  // muestra el pedido con logo: archivo opcional (viaja como propiedad \u00ABLogo\u00BB) y c\u00F3mo agrupar los globos.\n  const LOGO_MAX_MB = 10;\n  function logoPersonalization() {\n    const box = $('[data-logo]');\n    const sw = $('.logo-switch', box);\n    const choices = $$('[data-logo-choice]', box);\n    const panel = $('[data-logo-panel]', box);\n    const baseNote = $('[data-logo-base]', box);\n    const file = $('[data-logo-file]', box);\n    const drop = $('[data-logo-drop]', box);\n    const name = $('[data-logo-name]', box);\n    const meta = $('[data-logo-meta]', box);\n    const action = $('[data-logo-action]', box);\n    const group = $('[data-logo-group]', box);\n    const ids = { base: Number(box.dataset.baseVariant), logo: Number(box.dataset.logoVariant) };\n    const phrases = phraseRepeater(); // frase de cada globo, solo con la opci\u00F3n de las frases de la foto\n    let choice = 'base';\n    const tooBig = () => !!(file.files[0] && file.files[0].size > LOGO_MAX_MB * 1024 * 1024);\n\n    const select = (key, focus = false) => {\n      choice = key;\n      choices.forEach((b) => {\n        const on = b.dataset.logoChoice === key;\n        b.setAttribute('aria-checked', String(on));\n        b.tabIndex = on ? 0 : -1;\n        if (on && focus) b.focus();\n      });\n      sw.dataset.count = key === 'logo' ? '2' : '1';\n      const btn = choices.find((b) => b.dataset.logoChoice === key);\n      current.variantId = ids[key];\n      current.price = Number(btn.dataset.choicePrice);\n      current.compare = Number(btn.dataset.choiceCompare || 0);\n      $('[data-pdp-variant-id]').value = String(ids[key]);\n      $$('[data-price]').forEach((el) => { el.textContent = money(current.price); });\n      setCompare(current.price, current.compare);\n      const incLogo = $('[data-includes-logo]');\n      if (incLogo) { // \u00ABQu\u00E9 incluye\u00BB de la opci\u00F3n elegida\n        incLogo.hidden = key !== 'logo';\n        $('[data-includes-base]').hidden = key === 'logo';\n      }\n      panel.hidden = panel.disabled = key !== 'logo'; // deshabilitado: el logo y la agrupaci\u00F3n solo viajan con la opci\u00F3n del logo\n      baseNote.hidden = baseNote.disabled = key === 'logo';\n      updateWhatsApp();\n    };\n    choices.forEach((b) => b.addEventListener('click', () => select(b.dataset.logoChoice)));\n    sw.addEventListener('keydown', (e) => { // flechas como en un grupo de radios\n      if (!['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(e.key)) return;\n      e.preventDefault();\n      select(choice === 'logo' ? 'base' : 'logo', true);\n    });\n\n    file.addEventListener('change', () => {\n      const f = file.files[0];\n      drop.classList.toggle('has-file', !!f);\n      name.textContent = f ? f.name : 'Sube tu logo';\n      meta.textContent = f ? `${(f.size / 1024 / 1024).toFixed(f.size > 1048576 ? 1 : 2)} MB` : `PNG, JPG, PDF o AI \u00B7 hasta ${LOGO_MAX_MB} MB`;\n      action.textContent = f ? 'Cambiar' : 'Elegir archivo';\n      if (tooBig()) showError('logo', drop); else clearError('logo', drop);\n    });\n    group.addEventListener('input', updateWhatsApp);\n\n    return {\n      fit() {},\n      checks: () => (choice === 'logo' ? [['logo', drop, !tooBig()]] : []),\n      variant: () => current.variantId,\n      wa: () => (choice === 'logo'\n        ? [['Pedido', `Con el logo de mi negocio${file.files[0] ? ' (adjunt\u00E9 el logo en el pedido)' : ''}`], ['Agrupaci\u00F3n', group.value.trim()]]\n        : phrases ? phrases.wa() : []),\n      onProductChange() {},\n      init() { if (phrases) phrases.sync(); },\n    };\n  }\n\n  // Una frase por globo (bouquets impresos): filas que se agregan y quitan, contador \u00AB4/7\u00BB con globitos\n  // y una nota amable cuando pasan de la mitad. Las frases viajan juntas en la propiedad \u00ABFrase\u00BB.\n  function phraseRepeater() {\n    const box = $('[data-phrases]');\n    if (!box) return null;\n    const max = Number(box.dataset.max);\n    const suggest = Number(box.dataset.suggest);\n    const list = $('[data-phrases-list]', box);\n    const tpl = $('[data-phrase-template]', box);\n    const addBtn = $('[data-phrase-add]', box);\n    const note = $('[data-phrases-note]', box);\n    const count = $('[data-phrases-count]', box);\n    const dots = $$('.phrases__dot', box);\n    const value = $('[data-phrases-value]', box);\n    const total = $('[data-phrases-total]', box);\n    const texts = () => $$('[data-phrase-input]', list).map((i) => i.value.trim()).filter(Boolean);\n    const sync = () => {\n      const rows = $$('.phrases__row', list);\n      rows.forEach((row, i) => {\n        $('.phrases__num', row).textContent = i + 1;\n        ($('[data-phrase-pick]', row) || $('[data-phrase-input]', row)).setAttribute('aria-label', `Frase del globo ${i + 1}`);\n        const counter = $('.phrases__counter', row); // frase libre: caracteres usados de los permitidos\n        if (counter) {\n          const input = $('[data-phrase-input]', row);\n          counter.textContent = `${input.value.length}/${input.maxLength}`;\n          counter.classList.toggle('is-limit', input.value.length >= input.maxLength);\n        }\n        $('[data-phrase-remove]', row).setAttribute('aria-label', `Quitar la frase del globo ${i + 1}`);\n      });\n      const n = rows.length;\n      const filled = texts().length; // las filas vac\u00EDas (frase libre sin escribir) no cuentan como globo con frase\n      count.textContent = `${filled}/${max} globos con frase`; // \u00AB1/3 globos\u00BB: se lee como \u00AB1 de 3 globos\u00BB\n      dots.forEach((d, i) => d.classList.toggle('is-on', i < filled));\n      addBtn.hidden = n >= max;\n      addBtn.textContent = n ? '+ Agregar frase a otro globo' : '+ Agregar frase a un globo';\n      note.hidden = filled <= suggest;\n      value.value = texts().join(' \u00B7 ');\n      total.value = texts().length ? `${texts().length} de ${max}` : '';\n      updateWhatsApp();\n    };\n    // Frases para elegir: el selector de cada fila escribe la frase en su input oculto\n    const pick = (btn) => {\n      const group = btn.closest('[data-phrase-pick]');\n      const opts = $$('[data-pick]', group);\n      opts.forEach((o) => {\n        o.setAttribute('aria-checked', String(o === btn));\n        o.tabIndex = o === btn ? 0 : -1;\n      });\n      group.style.setProperty('--i', opts.indexOf(btn));\n      $('[data-phrase-input]', group.parentElement).value = btn.dataset.pick;\n    };\n    // Un globo nuevo lleva la frase menos usada hasta ahora, para que el bouquet quede parejo\n    const leastUsed = (row) => {\n      const used = texts();\n      const opts = $$('[data-pick]', row);\n      return opts.reduce((best, o) => (used.filter((t) => t === o.dataset.pick).length\n        < used.filter((t) => t === best.dataset.pick).length ? o : best), opts[0]);\n    };\n    const addRow = () => {\n      if (list.children.length >= max) return;\n      const row = tpl.content.firstElementChild.cloneNode(true);\n      if ($('[data-phrase-pick]', row)) pick(leastUsed(row));\n      list.append(row);\n      sync();\n      ($('[aria-checked=\"true\"]', row) || $('[data-phrase-input]', row)).focus();\n    };\n    addBtn.addEventListener('click', addRow);\n    list.addEventListener('input', sync);\n    list.addEventListener('click', (e) => {\n      const btn = e.target.closest('[data-pick]');\n      if (!btn) return;\n      pick(btn);\n      sync();\n    });\n    list.addEventListener('keydown', (e) => {\n      const btn = e.target.closest('[data-pick]');\n      const step = { ArrowRight: 1, ArrowDown: 1, ArrowLeft: -1, ArrowUp: -1 }[e.key];\n      if (!btn || !step) return;\n      e.preventDefault();\n      const opts = $$('[data-pick]', btn.parentElement);\n      const next = opts[(opts.indexOf(btn) + step + opts.length) % opts.length];\n      pick(next);\n      next.focus();\n      sync();\n    });\n    list.addEventListener('click', (e) => {\n      const btn = e.target.closest('[data-phrase-remove]');\n      if (!btn) return;\n      const row = btn.closest('.phrases__row');\n      const next = row.nextElementSibling || row.previousElementSibling;\n      row.remove();\n      sync();\n      const target = next && ($('[aria-checked=\"true\"]', next) || $('[data-phrase-input]', next));\n      (target || addBtn).focus();\n    });\n    return { sync, wa: () => [['Frases', texts().join(' \u00B7 ')]] };\n  }\n\n  // Personalizaci\u00F3n gen\u00E9rica (esculturales, cajas florales): frase y/o nombre con contador, sin vista previa\n  function genericPersonalization() {\n    const fields = $$('[data-generic-field]');\n    const phrases = phraseRepeater();\n    fields.forEach((input) => input.addEventListener('input', () => {\n      if (input.value.trim()) clearError(input.dataset.genericField, input);\n    }));\n    return {\n      fit() {},\n      checks: () => fields.filter((f) => f.required).map((f) => [f.dataset.genericField, f, !!f.value.trim()]),\n      wa: () => [...(phrases ? phrases.wa() : []), ...fields.map((f) => [f.dataset.waLabel || f.dataset.genericField, f.value.trim()])],\n      onProductChange() {},\n      init() { if (phrases) phrases.sync(); },\n    };\n  }\n  const noPersonalization = { fit() {}, checks: () => [], wa: () => [], onProductChange() {}, init() {} };\n  // N\u00FAmeros con frase y nombre en campos normales (bouquets con burbuja): las dos partes validan y van al WhatsApp\n  const both = (a, b) => ({\n    fit() { a.fit(); b.fit(); },\n    checks: () => [...a.checks(), ...b.checks()],\n    wa: () => [...a.wa(), ...b.wa()],\n    onProductChange(...args) { a.onProductChange(...args); b.onProductChange(...args); },\n    init() { a.init(); b.init(); },\n  });\n  const perso = $('[data-logo]') ? logoPersonalization()\n    : $('[data-numbers]') ? ($('[data-generic-field]') ? both(numberPersonalization(), genericPersonalization()) : numberPersonalization())\n    : $('[data-preview-phrase]') ? phrasePersonalization()\n    : $('[data-generic-field], [data-phrases]') ? genericPersonalization()\n    : noPersonalization;\n\n  /* ---------- Fila deslizable de frases: flechas para que se note que hay m\u00E1s ---------- */\n  $$('[data-phrase-options]').forEach((row) => {\n    const wrap = document.createElement('div');\n    wrap.className = 'phrase-scroller';\n    row.before(wrap);\n    wrap.append(row);\n    const arrow = (dir, label) => {\n      const btn = document.createElement('button');\n      btn.type = 'button';\n      btn.className = `phrase-scroller__btn phrase-scroller__btn--${dir}`;\n      btn.setAttribute('aria-label', label);\n      btn.tabIndex = -1; // con teclado ya se recorren los chips\n      btn.innerHTML = `<svg aria-hidden=\"true\"><use href=\"#i-chevron-${dir === 'prev' ? 'left' : 'right'}\"/></svg>`;\n      btn.addEventListener('click', () => row.scrollBy({ left: (dir === 'prev' ? -1 : 1) * row.clientWidth * 0.7, behavior: 'smooth' }));\n      wrap.append(btn);\n    };\n    arrow('prev', 'Ver frases anteriores');\n    arrow('next', 'Ver m\u00E1s frases');\n    const update = () => {\n      const max = row.scrollWidth - row.clientWidth;\n      wrap.classList.toggle('has-prev', row.scrollLeft > 4);\n      wrap.classList.toggle('has-next', row.scrollLeft < max - 4);\n    };\n    row.addEventListener('scroll', update, { passive: true });\n    new ResizeObserver(update).observe(row);\n    update();\n  });\n  if (previewStage) new ResizeObserver(() => perso.fit()).observe(previewStage);\n  if (document.fonts) document.fonts.ready.then(() => perso.fit());\n\n  // Contadores de caracteres\n  $$('[data-counter]').forEach((counter) => {\n    const input = document.getElementById(counter.dataset.counter);\n    const sep = counter.textContent.includes(' / ') ? ' / ' : '/';\n    const update = () => {\n      counter.textContent = input.value.length + sep + input.maxLength;\n      counter.classList.toggle('is-limit', input.value.length >= input.maxLength);\n    };\n    input.addEventListener('input', update);\n    update();\n  });\n\n  /* ---------- Entrega: calendario + horarios (misma config que el tema actual) ---------- */\n  const delivery = $('[data-delivery]');\n  const dateTrigger = $('[data-date-trigger]');\n  const dateText = $('[data-date-text]');\n  const dateValue = $('[data-date-value]');\n  const calendar = $('[data-calendar]');\n  const timeSelect = $('[data-time-select]');\n\n  const MONTHS = ['enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', 'julio', 'agosto', 'setiembre', 'octubre', 'noviembre', 'diciembre'];\n  const MONTHS_SHORT = ['ene', 'feb', 'mar', 'abr', 'may', 'jun', 'jul', 'ago', 'set', 'oct', 'nov', 'dic'];\n  const DAYS = ['domingo', 'lunes', 'martes', 'mi\u00E9rcoles', 'jueves', 'viernes', 's\u00E1bado'];\n  const DAYS_SHORT = ['Dom', 'Lun', 'Mar', 'Mi\u00E9', 'Jue', 'Vie', 'S\u00E1b'];\n  const cap = (s) => s.charAt(0).toUpperCase() + s.slice(1);\n  const pad = (n) => String(n).padStart(2, '0');\n  const iso = (d) => `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;\n  const addDays = (d, n) => new Date(d.getFullYear(), d.getMonth(), d.getDate() + n);\n  const friendlyDate = (d) => `${DAYS_SHORT[d.getDay()]}, ${d.getDate()} ${MONTHS_SHORT[d.getMonth()]}`;\n  const longDate = (d) => `${cap(DAYS[d.getDay()])} ${d.getDate()} de ${MONTHS[d.getMonth()]}`;\n\n  const anticipation = parseInt(delivery.dataset.anticipation, 10) || 0;\n  const ranges = delivery.dataset.ranges.split(',').map((r) => r.trim()).filter(Boolean);\n  const disabledDays = delivery.dataset.disabledDays.split(',').filter(Boolean).map(Number);\n  const excludedDates = delivery.dataset.excludedDates.split(',').map((s) => s.trim()).filter(Boolean);\n  const today = addDays(new Date(), 0);\n  const minDate = addDays(today, anticipation);\n  const maxDate = addDays(today, 90);\n  let viewMonth = new Date(minDate.getFullYear(), minDate.getMonth(), 1);\n  let selectedDate = null;\n\n  const isDisabled = (d) => d < minDate || d > maxDate || disabledDays.includes(d.getDay()) || excludedDates.includes(iso(d));\n\n  function renderCalendar() {\n    const y = viewMonth.getFullYear();\n    const m = viewMonth.getMonth();\n    const offset = (new Date(y, m, 1).getDay() + 6) % 7; // la semana empieza en lunes\n    const days = new Date(y, m + 1, 0).getDate();\n    const canPrev = new Date(y, m, 0) >= minDate;\n    const canNext = new Date(y, m + 1, 1) <= maxDate;\n    let cells = '<span></span>'.repeat(offset);\n    for (let d = 1; d <= days; d++) {\n      const date = new Date(y, m, d);\n      const selected = selectedDate && +date === +selectedDate;\n      cells += `<button type=\"button\" class=\"calendar__day${+date === +today ? ' is-today' : ''}\" data-day=\"${iso(date)}\" aria-label=\"${longDate(date)}\" aria-pressed=\"${!!selected}\"${isDisabled(date) ? ' disabled' : ''}>${d}</button>`;\n    }\n    const foot = anticipation === 0 ? 'Puedes pedir para hoy'\n      : anticipation === 1 ? 'Agenda con al menos un d\u00EDa de anticipaci\u00F3n'\n      : `Agenda con al menos ${anticipation} d\u00EDas de anticipaci\u00F3n`;\n    calendar.innerHTML = `\n      <div class=\"calendar__head\">\n        <p class=\"calendar__month\" aria-live=\"polite\">${cap(MONTHS[m])} ${y}</p>\n        <div class=\"calendar__nav\">\n          <button type=\"button\" data-cal-step=\"-1\" aria-label=\"Mes anterior\"${canPrev ? '' : ' disabled'}><svg aria-hidden=\"true\"><use href=\"#i-chevron-left\"/></svg></button>\n          <button type=\"button\" data-cal-step=\"1\" aria-label=\"Mes siguiente\"${canNext ? '' : ' disabled'}><svg aria-hidden=\"true\"><use href=\"#i-chevron-right\"/></svg></button>\n        </div>\n      </div>\n      <div class=\"calendar__grid\">\n        ${['L', 'M', 'M', 'J', 'V', 'S', 'D'].map((d) => `<span class=\"calendar__dow\" aria-hidden=\"true\">${d}</span>`).join('')}\n        ${cells}\n      </div>\n      <p class=\"calendar__foot\">${foot}</p>`;\n  }\n\n  function openCalendar() {\n    if (selectedDate) viewMonth = new Date(selectedDate.getFullYear(), selectedDate.getMonth(), 1);\n    renderCalendar();\n    calendar.hidden = false;\n    dateTrigger.setAttribute('aria-expanded', 'true');\n    const day = $('.calendar__day[aria-pressed=\"true\"]', calendar) || $('.calendar__day:not(:disabled)', calendar);\n    if (day) day.focus({ preventScroll: true });\n  }\n\n  function closeCalendar(returnFocus) {\n    if (calendar.hidden) return;\n    calendar.hidden = true;\n    dateTrigger.setAttribute('aria-expanded', 'false');\n    if (returnFocus) dateTrigger.focus({ preventScroll: true });\n  }\n\n  dateTrigger.addEventListener('click', () => (calendar.hidden ? openCalendar() : closeCalendar()));\n\n  calendar.addEventListener('click', (e) => {\n    // El re-render saca del DOM el bot\u00F3n clicado: que no cuente como \"clic afuera\"\n    e.stopPropagation();\n    const step = e.target.closest('[data-cal-step]');\n    if (step) {\n      viewMonth = new Date(viewMonth.getFullYear(), viewMonth.getMonth() + +step.dataset.calStep, 1);\n      renderCalendar();\n      const again = $(`[data-cal-step=\"${step.dataset.calStep}\"]`, calendar);\n      (again.disabled ? $('.calendar__day:not(:disabled)', calendar) : again)?.focus();\n      return;\n    }\n    const day = e.target.closest('[data-day]');\n    if (day && !day.disabled) {\n      const [y, m, d] = day.dataset.day.split('-').map(Number);\n      selectDate(new Date(y, m - 1, d));\n      closeCalendar(true);\n    }\n  });\n\n  document.addEventListener('click', (e) => {\n    if (!calendar.hidden && !dateTrigger.contains(e.target)) closeCalendar();\n  });\n  document.addEventListener('keydown', (e) => {\n    if (e.key === 'Escape' && !calendar.hidden) closeCalendar(true);\n  });\n\n  function selectDate(date) {\n    selectedDate = date;\n    dateValue.value = iso(date);\n    dateText.textContent = friendlyDate(date);\n    dateTrigger.classList.remove('is-placeholder');\n    clearError('fecha', dateTrigger);\n    populateSlots();\n    updateWhatsApp();\n  }\n\n  function populateSlots() {\n    const previous = timeSelect.value;\n    const now = new Date();\n    const isToday = selectedDate && +selectedDate === +today;\n    timeSelect.innerHTML = '<option value=\"\" disabled>Elige un horario</option>' + ranges.map((range) => {\n      const [start, end] = range.split('-').map((s) => s.trim());\n      const [h, min] = start.split(':').map(Number);\n      const startsAt = new Date(now);\n      startsAt.setHours(h, min || 0, 0, 0);\n      const past = isToday && startsAt <= now;\n      return `<option value=\"${start} - ${end}\"${past ? ' disabled' : ''}>${start} \u2013 ${end} h</option>`;\n    }).join('');\n    const keep = [...timeSelect.options].some((o) => o.value === previous && previous && !o.disabled);\n    if (keep) timeSelect.value = previous;\n    else timeSelect.selectedIndex = 0;\n  }\n\n  timeSelect.addEventListener('change', () => clearError('horario', timeSelect));\n\n  /* ---------- Dedicatoria ---------- */\n  const dedToggle = $('[data-dedication-toggle]');\n  const dedField = $('[data-dedication-field]');\n  const dedInput = $('[data-dedication-input]');\n  dedToggle.addEventListener('change', () => {\n    dedField.hidden = !dedToggle.checked;\n    dedInput.disabled = !dedToggle.checked;\n    if (dedToggle.checked) dedInput.focus();\n  });\n\n  /* ---------- Validaci\u00F3n + agregar al carrito ---------- */\n  const atcBtn = $('[data-atc]');\n\n  function showError(key, field) {\n    const msg = $(`[data-error=\"${key}\"]`);\n    if (msg) msg.hidden = false;\n    field.classList.add('is-invalid');\n    field.setAttribute('aria-invalid', 'true');\n  }\n  function clearError(key, field) {\n    const msg = $(`[data-error=\"${key}\"]`); // los campos opcionales (p. ej. la frase) no tienen aviso\n    if (msg) msg.hidden = true;\n    field.classList.remove('is-invalid');\n    field.removeAttribute('aria-invalid');\n  }\n\n  function validate() {\n    const checks = [\n      ...perso.checks(),\n      ['fecha', dateTrigger, !!dateValue.value],\n      ['horario', timeSelect, !!timeSelect.value],\n    ];\n    checks.forEach(([key, field, ok]) => (ok ? clearError(key, field) : showError(key, field)));\n    return checks.filter(([, , ok]) => !ok);\n  }\n\n  form.addEventListener('submit', (e) => {\n    e.preventDefault();\n    const errors = validate();\n    if (errors.length) {\n      const [key, field] = errors[0];\n      if (field.closest('#panel-personalizacion')) activateTab($('#tab-personalizacion'));\n      scrollIntoInfo(field);\n      field.focus({ preventScroll: true });\n      return;\n    }\n    addToCart();\n  });\n\n  const cartError = $('[data-error=\"cart\"]');\n  async function addToCart() {\n    if (atcBtn.classList.contains('is-loading')) return;\n    const properties = {};\n    new FormData(form).forEach((value, name) => {\n      if (value instanceof File) return; // los archivos van aparte (ver abajo)\n      const m = name.match(/^properties\\[(.+)\\]$/);\n      const v = String(value).trim();\n      if (m && v) properties[m[1]] = v;\n    });\n    const id = Number(perso.variant ? perso.variant() : current.variantId);\n    const drawer = document.querySelector('cart-drawer');\n    const body = { items: [{ id, quantity: 1, properties }] };\n    if (drawer) {\n      body.sections = ['cart-drawer', 'cart-icon-bubble'];\n      body.sections_url = window.location.pathname;\n    }\n    // Con un archivo adjunto (el logo) va como formulario multipart: Shopify lo sube y guarda su enlace en la propiedad\n    const files = $$('input[type=\"file\"]', form).filter((f) => !f.disabled && f.files[0]);\n    let request = { headers: { 'Content-Type': 'application/json', Accept: 'application/json' }, body: JSON.stringify(body) };\n    if (files.length) {\n      const fd = new FormData();\n      fd.append('id', String(id));\n      fd.append('quantity', '1');\n      Object.entries(properties).forEach(([k, v]) => fd.append(`properties[${k}]`, v));\n      files.forEach((f) => fd.append(f.name, f.files[0]));\n      if (drawer) {\n        fd.append('sections', body.sections.join(','));\n        fd.append('sections_url', body.sections_url);\n      }\n      request = { headers: { Accept: 'application/json' }, body: fd };\n    }\n    atcBtn.classList.add('is-loading');\n    atcBtn.setAttribute('aria-busy', 'true');\n    if (cartError) cartError.hidden = true;\n    try {\n      const res = await fetch(`${(window.routes && window.routes.cart_add_url) || '/cart/add'}.js`, {\n        method: 'POST',\n        ...request,\n      });\n      const json = await res.json();\n      if (!res.ok || json.status) throw new Error(json.description || json.message || 'No se pudo agregar');\n      if (!drawer) { window.location.href = (window.routes && window.routes.cart_url) || '/cart'; return; }\n      drawer.classList.remove('is-empty');\n      drawer.renderContents(json);\n      if (typeof publish === 'function' && typeof PUB_SUB_EVENTS !== 'undefined') {\n        publish(PUB_SUB_EVENTS.cartUpdate, { source: 'product-form', productVariantId: id, cartData: json });\n      }\n      openDistrictStep();\n    } catch (err) {\n      if (cartError) {\n        cartError.textContent = err.message && err.message !== 'No se pudo agregar' ? err.message : 'No pudimos agregarlo al carrito. Int\u00E9ntalo de nuevo.';\n        cartError.hidden = false;\n      }\n      atcBtn.classList.remove('is-loading');\n      atcBtn.removeAttribute('aria-busy');\n    }\n  }\n\n  // Como en el tema anterior: tras agregar se abre el carrito y, enseguida, el paso del distrito (pre-checkout)\n  function openDistrictStep() {\n    let tries = 0;\n    (function wait() {\n      const drawer = document.querySelector('cart-drawer');\n      const trigger = drawer && drawer.querySelector('[data-enova-minicart-checkout]');\n      if (drawer && drawer.classList.contains('active') && trigger && !trigger.disabled) {\n        trigger.click();\n        atcBtn.classList.remove('is-loading');\n        atcBtn.removeAttribute('aria-busy');\n        return;\n      }\n      if (++tries < 40) setTimeout(wait, 100);\n      else { atcBtn.classList.remove('is-loading'); atcBtn.removeAttribute('aria-busy'); }\n    })();\n  }\n\n  // Agotado: bot\u00F3n deshabilitado con el texto de Shopify\n  function setAvailability(p) {\n    const label = $('[data-atc-label]');\n    atcBtn.disabled = p.available === false;\n    if (label) label.textContent = p.available === false ? (atcBtn.dataset.soldOut || 'Agotado') : (atcBtn.dataset.addLabel || 'Agregar al carrito');\n    const stickyBtn = $('[data-sticky-atc-btn]');\n    if (stickyBtn) stickyBtn.disabled = p.available === false;\n  }\n\n  /* ---------- Barra fija de compra (m\u00F3vil) ---------- */\n  const sticky = $('[data-sticky-atc]');\n\n  function updateSticky() {\n    // Solo aparece cuando el bot\u00F3n principal ya qued\u00F3 arriba (el usuario baj\u00F3 m\u00E1s all\u00E1 de \u00E9l)\n    // (tambi\u00E9n en \"Explora m\u00E1s modelos\" y el resto de la p\u00E1gina: en escritorio es una tarjeta chica bajo el header)\n    const show = atcBtn.getBoundingClientRect().bottom < 0;\n    sticky.classList.toggle('is-visible', show);\n    sticky.setAttribute('aria-hidden', String(!show));\n    sticky.inert = !show;\n    // El WhatsApp flotante sube sobre la barra de compra (desktop: tarjeta a 24px del borde; celular: barra al ras)\n    const lift = show ? sticky.offsetHeight + (desktop.matches ? 14 : 0) : 0;\n    document.documentElement.style.setProperty('--float-lift', `${lift}px`);\n  }\n  window.addEventListener('scroll', updateSticky, { passive: true });\n  $('[data-sticky-atc-btn]').addEventListener('click', () => form.requestSubmit());\n\n  /* ---------- WhatsApp: mensaje con lo que el cliente ya eligi\u00F3 ---------- */\n  const waLink = $('[data-wa-link]');\n  const waHeight = $('[data-wa-height]');\n  const waFloat = $('[data-wa-float]');\n\n  function updateWhatsApp() {\n    const details = [\n      ...perso.wa(),\n      ['Fecha', selectedDate ? longDate(selectedDate) : ''],\n      ['Horario', timeSelect.value],\n    ].filter(([, v]) => v);\n    const named = `${current.title || data.title}${current.color ? ` (${current.color})` : ''}`;\n    const lines = [\n      `Hola, Peru Balloons. Me interesa el ${named} y quisiera hacerles una consulta o pedir algo m\u00E1s personalizado.`,\n      current.url,\n    ];\n    if (details.length) lines.push('', 'Lo que eleg\u00ED en la web:', ...details.map(([k, v]) => `\u2022 ${k}: ${v}`));\n    // api.whatsapp.com directo: wa.me + WhatsApp Desktop convierten algunos caracteres en \u00AB\uFFFD\u00BB (lo resolvi\u00F3 el tema anterior)\n    waLink.href = `https://api.whatsapp.com/send?phone=${waLink.dataset.waPhone}&text=${encodeURIComponent(lines.join('\\n'))}`;\n    if (waFloat) waFloat.href = waLink.href; // el flotante lleva la misma consulta, con el producto\n    // \"Altura regulable\" (pesta\u00F1a Medidas): consulta lista para pedir otra altura\n    if (waHeight) {\n      const ask = [\n        `Hola, Peru Balloons. Me interesa el ${named} y quisiera ajustar la altura del arreglo. Me gustar\u00EDa que mida aprox. ___ m.`,\n        current.url,\n      ];\n      waHeight.href = `https://api.whatsapp.com/send?phone=${waLink.dataset.waPhone}&text=${encodeURIComponent(ask.join('\\n'))}`;\n    }\n  }\n  form.addEventListener('input', updateWhatsApp);\n  form.addEventListener('change', updateWhatsApp);\n\n  /* ---------- Columna sticky (desktop) ---------- */\n  // Si la columna entra en la pantalla se fija bajo el header; si es m\u00E1s alta,\n  // se desplaza completa y luego se fija por abajo mientras sigue la galer\u00EDa.\n  function updateInfoTop() {\n    if (!desktop.matches) {\n      info.style.removeProperty('--info-top');\n      return;\n    }\n    const headerH = topChrome();\n    const h = info.offsetHeight;\n    info.style.setProperty('--info-top', `${h <= window.innerHeight - headerH ? headerH : window.innerHeight - h}px`);\n  }\n  new ResizeObserver(updateInfoTop).observe(info);\n  window.addEventListener('resize', updateInfoTop);\n  desktop.addEventListener('change', () => {\n    updateInfoTop();\n    updateSticky();\n  });\n\n  /* ---------- Inicio ---------- */\n  populateSlots();\n  perso.init();\n  updateWhatsApp();\n  setAvailability(current);\n})();\n"],
  "mappings": "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",
  "names": ["data", "step"]
}
