{"id":36282,"date":"2025-09-17T10:48:53","date_gmt":"2025-09-17T08:48:53","guid":{"rendered":"https:\/\/pnpplast.it\/catalog\/"},"modified":"2026-07-09T17:52:37","modified_gmt":"2026-07-09T15:52:37","slug":"catalog","status":"publish","type":"page","link":"https:\/\/pnpplast.it\/en\/catalog\/","title":{"rendered":"Catalog"},"content":{"rendered":"<p><!-- ====== CATALOG PDF VIEWER (filter sidebar + fixed 2-page spread + 100% zoom + pan) ====== --><\/p>\n<div class=\"catalog-switcher pdf-mode\">\n  <!-- ===== Layout: filter sidebar + viewer ===== --><\/p>\n<div class=\"catalog-layout\">\n    <!-- Filter sidebar --><\/p>\n<aside class=\"catalog-filters\" aria-label=\"Catalogs\">\n<div class=\"filters-title\">Catalogs<\/div>\n<div class=\"filters-group\" role=\"radiogroup\" aria-label=\"Select catalog\">\n  <button class=\"filter-item\" type=\"button\" data-cat=\"c4\">EVERYDAY 2026<\/button><br \/>\n  <button class=\"filter-item\" type=\"button\" data-cat=\"c5\">PASTICCERIA NATALE 2026 &amp; 2027<\/button><br \/>\n  <button class=\"filter-item\" type=\"button\" data-cat=\"c1\">CARTARIA AW 2026 &amp; 2027<\/button><br \/>\n  <button class=\"filter-item\" type=\"button\" data-cat=\"c11\">CHRISTMAS COLLECTION AUTUMN &amp; WINTER 2026\/2027<\/button><br \/>\n  <button class=\"filter-item\" type=\"button\" data-cat=\"c2\">DISNEY &amp; MARVEL 2026<\/button><br \/>\n  <button class=\"filter-item\" type=\"button\" data-cat=\"c9\">CUSTOM SHOPPERS<\/button><br \/>\n  <button class=\"filter-item\" type=\"button\" data-cat=\"c7\">YRISS20 AW 2026 &amp; 2027<\/button><br \/>\n  <button class=\"filter-item\" type=\"button\" data-cat=\"c10\">EASYPACK<\/button>\n<\/div>\n<\/aside>\n<p>    <!-- Viewer area --><\/p>\n<div class=\"catalog-main\">\n      <!-- Toolbar (outside viewer) --><\/p>\n<div class=\"pdf-toolbar\" role=\"toolbar\" aria-label=\"Viewer tools\">\n        <button class=\"tb-btn\" id=\"btnZoomOut\" type=\"button\" title=\"Zoom out (\u2212)\" aria-label=\"Zoom out\">\u2212<\/button><\/p>\n<div class=\"tb-readout\" aria-live=\"polite\"><span id=\"zoomPct\">100<\/span>%<\/div>\n<p>        <button class=\"tb-btn\" id=\"btnZoomIn\" type=\"button\" title=\"Zoom in (+)\" aria-label=\"Zoom in\">+<\/button><br \/>\n        <span class=\"tb-sep\" aria-hidden=\"true\"><\/span><br \/>\n        <button class=\"tb-btn\" id=\"btnActual\" type=\"button\" title=\"Actual size 100%\" aria-label=\"Actual size\">Actual 100%<\/button><br \/>\n        <button class=\"tb-btn\" id=\"btnFitWidth\" type=\"button\" title=\"Fit width\" aria-label=\"Fit width\">Fit Width<\/button><br \/>\n        <button class=\"tb-btn\" id=\"btnFitPage\" type=\"button\" title=\"Fit page\" aria-label=\"Fit page\">Fit Page<\/button><br \/>\n        <button class=\"tb-btn\" id=\"btnReset\" type=\"button\" title=\"Reset zoom\" aria-label=\"Reset zoom\">Reset<\/button>\n      <\/div>\n<p>      <!-- Viewer --><\/p>\n<div class=\"pdf-viewer\" role=\"region\" aria-label=\"PDF viewer\">\n<div class=\"pdf-hint\" aria-live=\"polite\">\n          <span class=\"kbd\">\u2190<\/span>\/<span class=\"kbd\">\u2192<\/span> page \u2014 <span class=\"kbd\">Ctrl\/\u2318<\/span> + wheel to zoom \u2014 drag to pan\n        <\/div>\n<p>        <!-- Navigation arrows --><br \/>\n        <button class=\"pdf-arrow left\" type=\"button\" aria-label=\"Previous page\" title=\"Previous page (\u2190)\"><br \/>\n          <svg viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" aria-hidden=\"true\">\n            <path d=\"M15.41 7.41 14 6l-6 6 6 6 1.41-1.41L10.83 12z\"\/>\n          <\/svg><br \/>\n        <\/button><br \/>\n        <button class=\"pdf-arrow right\" type=\"button\" aria-label=\"Next page\" title=\"Next page (\u2192)\"><br \/>\n          <svg viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" aria-hidden=\"true\">\n            <path d=\"m8.59 16.59 1.41 1.41 6-6-6-6-1.41 1.41L13.17 12z\"\/>\n          <\/svg><br \/>\n        <\/button><br \/>\n        <!-- Loader --><\/p>\n<div class=\"pdf-loader\" aria-live=\"polite\">Loading\u2026<\/div>\n<p>        <!-- Stage + pan container (2 canvases) --><\/p>\n<div class=\"pdf-stage\">\n<div class=\"pdf-pan\" id=\"pan\">\n            <canvas class=\"pdf-canvas\" id=\"canvasL\" aria-label=\"Left page\"><\/canvas><br \/>\n            <canvas class=\"pdf-canvas\" id=\"canvasR\" aria-label=\"Right page\"><\/canvas>\n          <\/div>\n<\/p><\/div>\n<p>        <!-- Click hotspots --><\/p>\n<div class=\"pdf-hotspot left\" aria-hidden=\"true\"><\/div>\n<div class=\"pdf-hotspot right\" aria-hidden=\"true\"><\/div>\n<p>        <!-- Page badge --><\/p>\n<div class=\"pdf-pagebadge\" aria-live=\"polite\">\n          <span class=\"current\">1\u20132<\/span> \/ <span class=\"total\">1<\/span>\n        <\/div>\n<\/p><\/div>\n<p>      <!-- SUB-CATALOGS --><\/p>\n<div class=\"subcatalogs\" aria-live=\"polite\" hidden>\n<div class=\"subcatalogs-title\">Browse by section<\/div>\n<div class=\"subcatalogs-grid\" id=\"subcatalogButtons\"><\/div>\n<\/p><\/div>\n<p>      <!-- Footer --><\/p>\n<footer class=\"pdf-footer\">\n        <a class=\"btn-download\" id=\"pdfDirectLink\" href=\"#\" target=\"_blank\" rel=\"noopener\"><br \/>\n          <img decoding=\"async\" class=\"icon\" src=\"https:\/\/pnpplast.it\/wp-content\/uploads\/2025\/09\/DOWNLOAD-icon.svg\" alt=\"\" aria-hidden=\"true\"><br \/>\n          Open original PDF<br \/>\n        <\/a><br \/>\n      <\/footer>\n<\/p><\/div>\n<\/p><\/div>\n<\/div>\n<p><!-- PDF.js --><br \/>\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/pdf.js\/3.11.174\/pdf.min.js\" defer><\/script><\/p>\n<style>\n\/* Wrapper *\/\n.catalog-switcher.pdf-mode{\n  margin:0 auto;\n  padding:0 16px;\n  font-family:system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;\n}\n\/* ===== Layout sidebar filtri ===== *\/\n.catalog-layout{\n  display:grid;\n  grid-template-columns: 280px minmax(0,1fr);\n  gap:16px;\n  align-items:start;\n}\n\/* Sidebar stile \"filtri\" *\/\n.catalog-filters{\n  background:#fff;\n  border:1px solid #e7e7e7;\n  border-radius:12px;\n  padding:14px;\n  position: sticky;\n  top: 12px;\n}\n.filters-title{\n  font-weight:900;\n  font-size:14px;\n  margin-bottom:10px;\n}\n.filters-group{\n  display:flex;\n  flex-direction:column;\n  gap:8px;\n}\n.filter-item{\n  width:100%;\n  text-align:left;\n  padding:10px 10px;\n  border-radius:10px;\n  border:1px solid #e1e1e1;\n  background:#fff;\n  cursor:pointer;\n  font-weight:700;\n  font-size:13px;\n  line-height:1.2;\n  transition: background .15s ease, border-color .15s ease, transform .05s ease;\n}\n.filter-item:hover{\n  background:#fafafa;\n  transform: translateY(-1px);\n}\n.filter-item.is-active{\n  border-color:#ff3d8a;\n  box-shadow: 0 0 0 2px rgba(255,61,138,.15);\n}\n\/* Viewer & stage *\/\n.pdf-viewer{\n  width:100%;\n  position:relative;\n  background:#f7f7f7;\n  border-radius:12px;\n  overflow:hidden;\n  box-shadow:0 6px 24px rgba(0,0,0,.06);\n}\n.pdf-stage{\n  width:100%;\n  height:76vh;\n  min-height:520px;\n  box-sizing:border-box;\n  overflow:hidden;\n  position:relative;\n}\n.pdf-pan{\n  position:absolute;\n  left:50%;\n  top:50%;\n  transform:translate3d(var(--tx, -50%), var(--ty, -50%), 0);\n  display:flex;\n  gap:16px;\n  cursor:grab;\n}\n.pdf-pan.grabbing{ cursor:grabbing; }\n.pdf-canvas{\n  display:block;\n  background:#fff;\n  border-radius:4px;\n  user-select:none;\n  -webkit-user-drag:none;\n}\n\/* Toolbar \u2014 ESTERNA (non sovrapposta) *\/\n.pdf-toolbar{\n  position: static;\n  z-index: 1;\n  display:flex;\n  align-items:center;\n  gap:6px;\n  background:rgba(255,255,255,.92);\n  padding:6px;\n  border-radius:999px;\n  box-shadow:0 2px 8px rgba(0,0,0,.12);\n  width:fit-content;\n  margin:8px auto 12px;\n}\n@supports (position: sticky){\n  .pdf-toolbar{ position: sticky; top:8px; }\n}\n.tb-btn{\n  border:1px solid #d0d0d0;\n  background:#fff;\n  border-radius:8px;\n  padding:6px 10px;\n  font-weight:700;\n  cursor:pointer;\n}\n.tb-btn:hover{ background:#f9f9f9; }\n.tb-readout{ min-width:44px; text-align:center; font-weight:800; }\n.tb-sep{ width:1px; height:20px; background:#ddd; }\n\/* Hotspot *\/\n.pdf-hotspot{ position:absolute; top:0; bottom:0; width:12%; }\n.pdf-hotspot.left{ left:0; } .pdf-hotspot.right{ right:0; }\n\/* Hint, arrows, loader, badge *\/\n.pdf-hint{\n  position:absolute;\n  left:50%;\n  top:10px;\n  transform:translateX(-50%);\n  background:rgba(0,0,0,.65);\n  color:#fff;\n  padding:6px 10px;\n  border-radius:999px;\n  font-size:12px;\n  display:flex;\n  align-items:center;\n  gap:6px;\n  z-index:3;\n  pointer-events:none;\n  opacity:1;\n  transition:opacity .25s ease;\n}\n.kbd{ background:#fff; color:#000; border-radius:4px; padding:1px 6px; font-weight:700; }\n.pdf-arrow{\n  position:absolute;\n  top:50%;\n  transform:translateY(-50%);\n  width:40px;\n  height:40px;\n  border:0;\n  border-radius:999px;\n  background:#ff3d8a;\n  color:#fff;\n  display:grid;\n  place-items:center;\n  cursor:pointer;\n  z-index:4;\n  box-shadow:0 2px 8px rgba(0,0,0,.15);\n}\n.pdf-arrow.left{ left:10px; } .pdf-arrow.right{ right:10px; }\n.pdf-arrow:hover{ filter:brightness(0.95); }\n.pdf-arrow svg{ filter:brightness(0) invert(1); }\n.pdf-loader{\n  position:absolute;\n  inset:0;\n  display:flex;\n  align-items:center;\n  justify-content:center;\n  z-index:2;\n  font-size:14px;\n  color:#555;\n  background:linear-gradient(90deg,#f5f5f5,#ececec,#f5f5f5);\n  background-size:200% 100%;\n  animation:sheen 1.2s infinite;\n}\n@keyframes sheen{ 0%{background-position:0 0} 100%{background-position:200% 0} }\n.pdf-pagebadge{\n  position:absolute;\n  right:10px;\n  bottom:10px;\n  z-index:3;\n  background:rgba(0,0,0,.7);\n  color:#fff;\n  font-size:12px;\n  padding:4px 8px;\n  border-radius:6px;\n}\n\/* Sotto-cataloghi + footer *\/\n.subcatalogs{ margin:8px 0 14px; }\n.subcatalogs[hidden]{ display:none !important; }\n.subcatalogs-title{ font-weight:800; font-size:14px; margin-bottom:6px; }\n.subcatalogs-grid{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:8px; }\n@media (min-width:560px){ .subcatalogs-grid{ grid-template-columns:repeat(3,minmax(0,1fr)); } }\n.subcat-btn{\n  display:flex;\n  align-items:center;\n  justify-content:center;\n  gap:.5rem;\n  padding:10px 12px;\n  border-radius:12px;\n  background:#ffffff;\n  border:1px solid #d7d7d7;\n  cursor:pointer;\n  font-weight:700;\n  font-size:13px;\n  text-align:center;\n  transition:transform .05s ease, background .2s ease;\n}\n.subcat-btn:hover{ background:#fff; transform:translateY(-1px); }\n.subcat-btn .actions{ margin-left:auto; display:flex; gap:8px; }\n.subcat-btn .mini{\n  display:inline-flex;\n  align-items:center;\n  gap:6px;\n  padding:6px 8px;\n  border-radius:999px;\n  font-weight:800;\n  font-size:12px;\n  background:#ff3d8a;\n  color:#fff;\n  text-decoration:none;\n  border:0;\n}\n.subcat-btn .mini.secondary{ background:#111; }\n.pdf-footer{ display:flex; justify-content:center; margin:8px 0 24px; }\n.btn-download{\n  display:inline-flex;\n  align-items:center;\n  gap:.5rem;\n  padding:12px 18px;\n  border-radius:999px;\n  font-weight:800;\n  text-decoration:none;\n  background:#ff3d8a;\n  color:#ffffff !important;\n  flex-direction:row-reverse;\n}\n.btn-download .icon{ width:18px; height:18px; display:block; filter:brightness(0) invert(1); }\n.btn-download:hover{ filter:brightness(0.95); }\n\/* Accessibilit\u00e0 *\/\n.sr-only{\n  position:absolute !important;\n  width:1px;\n  height:1px;\n  padding:0;\n  margin:-1px;\n  overflow:hidden;\n  clip:rect(0,0,0,0);\n  white-space:nowrap;\n  border:0;\n}\n\/* ===== Mobile: sidebar diventa barra orizzontale + toolbar minimale + niente hint ===== *\/\n@media (max-width: 900px){\n  .catalog-layout{ grid-template-columns: 1fr; }\n  .catalog-filters{ position: static; }\n  .filters-group{\n    flex-direction:row;\n    overflow:auto;\n    padding-bottom:6px;\n    gap:8px;\n  }\n  .filter-item{\n    width:auto;\n    white-space:nowrap;\n  }\n}\n@media (max-width: 768px), (pointer: coarse) {\n  \/* mostra solo - [readout] + *\/\n  #btnActual,\n  #btnFitWidth,\n  #btnFitPage,\n  #btnReset,\n  .pdf-toolbar .tb-sep {\n    display: none !important;\n  }\n  .pdf-toolbar{\n    gap: 4px;\n    padding: 6px 8px;\n    margin: 8px auto 10px;\n  }\n  .pdf-toolbar .tb-readout{\n    min-width: 40px;\n    font-size: 14px;\n  }\n  .pdf-toolbar .tb-btn{\n    padding: 6px 10px;\n    font-size: 16px;\n  }\n  \/* niente avviso su mobile\/touch *\/\n  .pdf-hint{\n    display: none !important;\n  }\n}\n<\/style>\n<p><script>\ndocument.addEventListener('DOMContentLoaded', async function(){\n  \/* ====== Mapping ID -> URL PDF ====== *\/\n  const PDF_MAP = {\n  c4: 'https:\/\/pnpplast.it\/wp-content\/uploads\/2026\/01\/EVERYDAY-2026.pdf',\n  c5: 'https:\/\/pnpplast.it\/wp-content\/uploads\/2026\/07\/PASTICCERIA-NATALE-2026-2027.pdf',\n  c1: 'https:\/\/pnpplast.it\/wp-content\/uploads\/2026\/07\/CARTARIA-AW-2026-2027.pdf',\n  c2: 'https:\/\/pnpplast.it\/wp-content\/uploads\/2026\/01\/DISNEY-MARVEL-2026.pdf',\n  c9: 'https:\/\/pnpplast.it\/wp-content\/uploads\/2026\/01\/SHOPPER-PERSONALIZZATI.pdf',\n  c7: 'https:\/\/pnpplast.it\/wp-content\/uploads\/2026\/07\/YRISS20-AW-2026-2027.pdf',\n  c11: 'https:\/\/pnpplast.it\/wp-content\/uploads\/2026\/07\/CHRISTMAS-COLLECTION-AUTUMN-WINTER-2026_2027.pdf',\n  c10:'https:\/\/pnpplast.it\/wp-content\/uploads\/2026\/02\/EASYPACK-CATALOGO-2025-NEW-MD-1.pdf'\n};\n  \/* ====== Sotto-cataloghi (opzionali) ====== *\/\n  const SUBCATS = {\n    \/\/ richieste: sottosezioni del catalogo EVERYDAY 2026\n    c4: [\n      { id:'c4_s0',  label:'Bobine e Fogli PP',              url:'https:\/\/pnpplast.it\/wp-content\/uploads\/2026\/01\/BOBINE-E-FOGLI-PP.pdf' },\n      { id:'c4_s1',  label:'Bobine Tessuto',                url:'https:\/\/pnpplast.it\/wp-content\/uploads\/2026\/01\/BOBINE-TESSUTO.pdf' },\n      { id:'c4_s2',  label:'Buste Quadra e Coni',           url:'https:\/\/pnpplast.it\/wp-content\/uploads\/2026\/01\/BUSTE-QUADRA-E-CONI.pdf' },\n      { id:'c4_s3',  label:'Buste Regalo Carta',            url:'https:\/\/pnpplast.it\/wp-content\/uploads\/2026\/01\/BUSTE-REGALO-CARTA.pdf' },\n      { id:'c4_s4',  label:'Buste Regalo PP',               url:'https:\/\/pnpplast.it\/wp-content\/uploads\/2026\/01\/BUSTE-REGALO-PP.pdf' },\n      { id:'c4_s5',  label:'Nastri e Accessori',            url:'https:\/\/pnpplast.it\/wp-content\/uploads\/2026\/01\/NASTRI-E-ACCESSORI.pdf' },\n      { id:'c4_s6',  label:'Rotolini e Buste Disney & Marvel', url:'https:\/\/pnpplast.it\/wp-content\/uploads\/2026\/01\/ROTOLINI-E-BUSTE-DISNEY-MARVEL.pdf' },\n      { id:'c4_s7',  label:'Shopping',                      url:'https:\/\/pnpplast.it\/wp-content\/uploads\/2026\/01\/SHOPPING.pdf' },\n      { id:'c4_s8',  label:'Sottovasi Carta e PP',          url:'https:\/\/pnpplast.it\/wp-content\/uploads\/2026\/01\/SOTTOVASI-CARTA-E-PP.pdf' },\n      { id:'c4_s9',  label:'Spezzoni e Bobine Tubolari',    url:'https:\/\/pnpplast.it\/wp-content\/uploads\/2026\/01\/SPEZZONI-E-BOBINE-TUBOLARI.pdf' },\n      { id:'c4_s10', label:'Bobine e Fogli Carta',          url:'https:\/\/pnpplast.it\/wp-content\/uploads\/2026\/01\/BOBINE-E-FOGLI-CARTA.pdf' }\n    ]\n  };\n  \/* ====== PDF.js ====== *\/\n  const pdfjsLib = window['pdfjs-dist\/build\/pdf'];\n  pdfjsLib.GlobalWorkerOptions.workerSrc =\n    'https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/pdf.js\/3.11.174\/pdf.worker.min.js';\n  \/* ====== DOM ====== *\/\n  const viewer    = document.querySelector('.pdf-viewer');\n  const stage     = viewer.querySelector('.pdf-stage');\n  const panEl     = document.getElementById('pan');\n  const canvasL   = document.getElementById('canvasL');\n  const canvasR   = document.getElementById('canvasR');\n  const ctxL      = canvasL.getContext('2d');\n  const ctxR      = canvasR.getContext('2d');\n  const leftHS    = viewer.querySelector('.pdf-hotspot.left');\n  const rightHS   = viewer.querySelector('.pdf-hotspot.right');\n  const direct    = document.getElementById('pdfDirectLink');\n  const loader    = viewer.querySelector('.pdf-loader');\n  const hint      = viewer.querySelector('.pdf-hint');\n  const arrowL    = viewer.querySelector('.pdf-arrow.left');\n  const arrowR    = viewer.querySelector('.pdf-arrow.right');\n  const pageBadge = viewer.querySelector('.pdf-pagebadge');\n  const pageNow   = pageBadge.querySelector('.current');\n  const pageTot   = pageBadge.querySelector('.total');\n  \/\/ Toolbar\n  const btnZoomIn   = document.getElementById('btnZoomIn');\n  const btnZoomOut  = document.getElementById('btnZoomOut');\n  const btnReset    = document.getElementById('btnReset');\n  const btnActual   = document.getElementById('btnActual');\n  const btnFitWidth = document.getElementById('btnFitWidth');\n  const btnFitPage  = document.getElementById('btnFitPage');\n  const zoomPct     = document.getElementById('zoomPct');\n  \/\/ Filtri laterali\n  const filterBtns = Array.from(document.querySelectorAll('.filter-item'));\n  function setActiveFilter(id){\n    filterBtns.forEach(b => b.classList.toggle('is-active', b.dataset.cat === id));\n  }\n  \/* ====== Stato ====== *\/\n  let pdfDoc = null;\n  let pageNum = 1;                \/\/ pagina sinistra in doppia\n  let isRendering = false;\n  let pending = false;\n  let mode = 'actual';            \/\/ 'actual' | 'fitWidth' | 'fitPage'\n  let baseScale = 1;              \/\/ dipende da mode\n  let userScale = 1;              \/\/ zoom utente (0.25\u20136)\n  const MIN_Z = 0.25, MAX_Z = 6, Z_STEP = 0.1;\n  \/\/ Pan\/drag\n  let panX = 0, panY = 0;\n  let minX = 0, minY = 0, maxX = 0, maxY = 0;\n  let dragging = false, dragStartX = 0, dragStartY = 0, panStartX = 0, panStartY = 0;\n  function showLoader(s){ loader.style.display = s ? 'flex' : 'none'; }\n  function hideHint(){ if (hint && hint.style.opacity!=='0'){ hint.style.opacity='0'; setTimeout(()=>hint.style.display='none', 250); } }\n  function clamp(v,a,b){ return Math.max(a, Math.min(b, v)); }\n  function zoomFactor(){ return baseScale * userScale; }\n  function isZoomed(){ return zoomFactor() !== baseScale || mode==='actual'; }\n  function updateBadge(){\n    if (!pdfDoc) { pageNow.textContent='0'; pageTot.textContent='0'; return; }\n    const right = Math.min(pageNum + 1, pdfDoc.numPages);\n    pageNow.textContent = `${pageNum}\u2013${right}`;\n    pageTot.textContent = String(pdfDoc.numPages);\n  }\n  function updateZoomReadout(){ zoomPct.textContent = Math.round(zoomFactor()*100); }\n  \/\/ Calcolo baseScale in base alla modalit\u00e0\n  function computeBaseScaleFor(pageViewport){\n    const gap = 16; \/\/ come in CSS\n    const stageW = stage.clientWidth;\n    const stageH = stage.clientHeight;\n    if (mode === 'actual') return 1;\n    const totalW = pageViewport.width*2 + gap; \/\/ due pagine\n    if (mode === 'fitWidth'){\n      return stageW \/ totalW;\n    }\n    if (mode === 'fitPage'){\n      const sW = stageW \/ totalW;\n      const sH = stageH \/ pageViewport.height;\n      return Math.min(sW, sH);\n    }\n    return 1;\n  }\n  async function renderSingle(pageIndex, ctx, canvas, scale){\n    const page = await pdfDoc.getPage(pageIndex);\n    const viewport = page.getViewport({ scale });\n    canvas.width  = Math.floor(viewport.width);\n    canvas.height = Math.floor(viewport.height);\n    await page.render({ canvasContext: ctx, viewport }).promise;\n  }\n  function updatePanBounds(){\n    const gap = 16;\n    const contentW = canvasL.width + gap + canvasR.width;\n    const contentH = Math.max(canvasL.height, canvasR.height);\n    const stageW = stage.clientWidth;\n    const stageH = stage.clientHeight;\n    const halfExtraW = Math.max(0, (contentW - stageW) \/ 2);\n    const halfExtraH = Math.max(0, (contentH - stageH) \/ 2);\n    minX = -halfExtraW; maxX = halfExtraW;\n    minY = -halfExtraH; maxY = halfExtraH;\n    panX = clamp(panX, minX, maxX);\n    panY = clamp(panY, minY, maxY);\n    panEl.style.setProperty('--tx', `calc(-50% + ${panX}px)`);\n    panEl.style.setProperty('--ty', `calc(-50% + ${panY}px)`);\n  }\n  function centerPan(){ panX = 0; panY = 0; updatePanBounds(); }\n  function render(){\n    if (!pdfDoc) return;\n    if (isRendering){ pending = true; return; }\n    isRendering = true; showLoader(true);\n    pdfDoc.getPage(pageNum).then(p=>{\n      const vp1 = p.getViewport({ scale: 1 });\n      baseScale = computeBaseScaleFor(vp1);\n      const s = baseScale * userScale;\n      const left = pageNum;\n      const right = Math.min(pageNum + 1, pdfDoc.numPages);\n      return Promise.all([\n        renderSingle(left,  ctxL, canvasL, s),\n        renderSingle(right, ctxR, canvasR, s)\n      ]);\n    }).then(()=>{\n      isRendering = false; showLoader(false);\n      updateBadge(); updateZoomReadout();\n      centerPan();\n      if (pending){ pending = false; render(); }\n    }).catch(err=>{\n      const url = direct.href;\n      viewer.innerHTML = `<iframe title=\"PDF\" style=\"width:100%;height:80vh;border:0\" src=\"${url}#toolbar=0&#038;navpanes=0&#038;scrollbar=0\"><\/iframe>`;\n    });\n  }\n  function nextPage(){\n    if (!pdfDoc) return;\n    if (pageNum + 2 <= pdfDoc.numPages){ pageNum += 2; render(); }\n    else if (pageNum + 1 <= pdfDoc.numPages){ pageNum += 1; render(); }\n  }\n  function prevPage(){\n    if (!pdfDoc) return;\n    pageNum = Math.max(1, pageNum - 2);\n    render();\n  }\n  \/\/ Controlli pagina\n  const hideAndPrev = ()=>{ hideHint(); prevPage(); };\n  const hideAndNext = ()=>{ hideHint(); nextPage(); };\n  leftHS.addEventListener('click', hideAndPrev);\n  rightHS.addEventListener('click', hideAndNext);\n  arrowL.addEventListener('click', hideAndPrev);\n  arrowR.addEventListener('click', hideAndNext);\n  document.addEventListener('keydown', (e)=>{\n    if (e.key === 'ArrowLeft')  hideAndPrev();\n    if (e.key === 'ArrowRight') hideAndNext();\n    if (e.key === '+' || e.key === '='){ userScale = clamp(userScale + Z_STEP, MIN_Z, MAX_Z); render(); }\n    if (e.key === '-' || e.key === '_'){ userScale = clamp(userScale - Z_STEP, MIN_Z, MAX_Z); render(); }\n    if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase()==='0'){ userScale = 1; render(); }\n  });\n  \/\/ Zoom buttons\n  btnZoomIn .addEventListener('click', ()=>{ userScale = clamp(userScale + Z_STEP, MIN_Z, MAX_Z); render(); });\n  btnZoomOut.addEventListener('click', ()=>{ userScale = clamp(userScale - Z_STEP, MIN_Z, MAX_Z); render(); });\n  btnReset  .addEventListener('click', ()=>{ userScale = 1; render(); });\n  \/\/ Modalit\u00e0 scala\n  btnActual  .addEventListener('click', ()=>{ mode='actual';  render(); });\n  btnFitWidth.addEventListener('click', ()=>{ mode='fitWidth'; userScale=1; render(); });\n  btnFitPage .addEventListener('click', ()=>{ mode='fitPage';  userScale=1; render(); });\n  \/\/ Wheel zoom (solo con Ctrl\/\u2318)\n  viewer.addEventListener('wheel', (e)=>{\n    if (!(e.ctrlKey || e.metaKey)) return;\n    e.preventDefault();\n    const delta = -Math.sign(e.deltaY) * Z_STEP;\n    userScale = clamp(userScale + delta, MIN_Z, MAX_Z);\n    render();\n  }, { passive:false });\n  \/\/ Pan mouse\n  panEl.addEventListener('mousedown', (e)=>{\n    if (!isZoomed()) return;\n    dragging = true; panEl.classList.add('grabbing');\n    dragStartX = e.clientX; dragStartY = e.clientY;\n    panStartX = panX; panStartY = panY;\n  });\n  window.addEventListener('mousemove', (e)=>{\n    if (!dragging) return;\n    const dx = e.clientX - dragStartX;\n    const dy = e.clientY - dragStartY;\n    panX = clamp(panStartX + dx, minX, maxX);\n    panY = clamp(panStartY + dy, minY, maxY);\n    panEl.style.setProperty('--tx', `calc(-50% + ${panX}px)`);\n    panEl.style.setProperty('--ty', `calc(-50% + ${panY}px)`);\n  });\n  window.addEventListener('mouseup', ()=>{\n    if (!dragging) return;\n    dragging = false; panEl.classList.remove('grabbing');\n  });\n  \/\/ Pan touch (a un dito quando zoommato) + swipe pagina se non zoommato\n  let touchStartX = 0, touchStartY = 0, panningTouch = false;\n  viewer.addEventListener('touchstart', e=>{\n    if (e.touches.length===1){\n      const t = e.touches[0];\n      touchStartX = t.clientX; touchStartY = t.clientY;\n      if (isZoomed()){\n        panningTouch = true; panStartX = panX; panStartY = panY;\n      } else { panningTouch = false; }\n    }\n    if (e.touches.length===2){\n      const dx = e.touches[0].clientX - e.touches[1].clientX;\n      const dy = e.touches[0].clientY - e.touches[1].clientX;\n      viewer._pinchDist = Math.hypot(dx, dy);\n    }\n  }, {passive:true});\n  viewer.addEventListener('touchmove', e=>{\n    if (e.touches.length===2){\n      e.preventDefault();\n      const dx = e.touches[0].clientX - e.touches[1].clientX;\n      const dy = e.touches[0].clientY - e.touches[1].clientY;\n      const nd = Math.hypot(dx, dy);\n      const factor = nd \/ (viewer._pinchDist || nd);\n      viewer._pinchDist = nd;\n      userScale = clamp(userScale * factor, MIN_Z, MAX_Z);\n      render();\n      return;\n    }\n    if (panningTouch && e.touches.length===1){\n      e.preventDefault();\n      const t = e.touches[0];\n      const dx = t.clientX - touchStartX;\n      const dy = t.clientY - touchStartY;\n      panX = clamp(panStartX + dx, minX, maxX);\n      panY = clamp(panStartY + dy, minY, maxY);\n      panEl.style.setProperty('--tx', `calc(-50% + ${panX}px)`);\n      panEl.style.setProperty('--ty', `calc(-50% + ${panY}px)`);\n    }\n  }, {passive:false});\n  viewer.addEventListener('touchend', e=>{\n    if (!panningTouch && e.changedTouches.length===1){\n      const dx = e.changedTouches[0].clientX - touchStartX;\n      if (Math.abs(dx) > 40){ hideHint(); (dx < 0 ? nextPage() : prevPage()); }\n    }\n    panningTouch = false;\n  }, {passive:true});\n  \/\/ Resize -> rerender\n  let raf = null;\n  window.addEventListener('resize', ()=>{\n    if (!pdfDoc) return;\n    cancelAnimationFrame(raf);\n    raf = requestAnimationFrame(()=> render());\n  });\n  \/\/ Carica PDF da URL\n  async function loadPdfUrl(url){\n    direct.href = url;\n    if (pdfDoc){ try{ pdfDoc.destroy(); }catch(e){} pdfDoc = null; }\n    showLoader(true);\n    try{\n      const doc = await pdfjsLib.getDocument({ url, withCredentials:false }).promise;\n      pdfDoc = doc;\n      \/\/ doppia pagina: pagina sinistra dispari\n      if (pageNum % 2 === 0) pageNum = Math.max(1, pageNum - 1);\n      \/\/ impostazioni iniziali: 100% reale\n      mode = 'actual'; userScale = 1;\n      updateBadge(); render();\n    }catch(err){\n      viewer.innerHTML = `<iframe title=\"PDF\" style=\"width:100%;height:80vh;border:0\" src=\"${url}#toolbar=0&#038;navpanes=0&#038;scrollbar=0\"><\/iframe>`;\n    }\n  }\n  \/\/ Sotto-cataloghi\n  const subwrap  = document.querySelector('.subcatalogs');\n  const subgrid  = document.getElementById('subcatalogButtons');\n  function buildSubcatalogsFor(id){\n    const groups = SUBCATS[id]; subgrid.innerHTML='';\n    if (groups && groups.length){\n      subwrap.hidden = false;\n      groups.forEach(item=>{\n        const card = document.createElement('div');\n        card.className = 'subcat-btn';\n        card.setAttribute('role','group');\n        card.innerHTML = `\n          <span class=\"label\">${item.label}<\/span>\n          <span class=\"actions\">\n            <a class=\"mini secondary\" href=\"${item.url}\" target=\"_blank\" rel=\"noopener\" aria-label=\"Scarica ${item.label} (PDF)\">Download<\/a>\n            <button class=\"mini\" type=\"button\" aria-label=\"Apri ${item.label} nel viewer\">Apri<\/button>\n          <\/span>`;\n        card.querySelector('button.mini').addEventListener('click', ()=>{ hideHint(); loadPdfUrl(item.url); });\n        subgrid.appendChild(card);\n      });\n    } else {\n      subwrap.hidden = true;\n    }\n  }\n  \/\/ Carica per ID\n  async function loadPdfById(id){\n    const url = PDF_MAP[id]; if (!url) return;\n    setActiveFilter(id);\n    if (hint){ hint.style.display='block'; hint.style.opacity='1'; }\n    buildSubcatalogsFor(id);\n    await loadPdfUrl(url);\n    history.replaceState(null, '', '#' + id);\n  }\n  \/\/ Init\n  const defaultId = 'c4';\n  const hashId = location.hash ? location.hash.substring(1) : '';\n  const initialId = (hashId && PDF_MAP[hashId]) ? hashId : defaultId;\n  setActiveFilter(initialId);\n  await loadPdfById(initialId);\n  \/\/ Click sui filtri\n  filterBtns.forEach(btn=>{\n    btn.addEventListener('click', ()=> {\n      const id = btn.dataset.cat;\n      setActiveFilter(id);\n      loadPdfById(id);\n    });\n  });\n  \/\/ Dopo ogni render aggiorniamo i limiti di pan\n  const observer = new ResizeObserver(()=> updatePanBounds());\n  observer.observe(stage);\n  const canvObs = new ResizeObserver(()=> updatePanBounds());\n  canvObs.observe(canvasL); canvObs.observe(canvasR);\n});\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Catalogs EVERYDAY 2026 PASTICCERIA NATALE 2026 &amp; 2027 CARTARIA AW 2026 &amp; 2027 CHRISTMAS COLLECTION AUTUMN &amp; WINTER 2026\/2027 DISNEY &amp; MARVEL 2026 CUSTOM SHOPPERS YRISS20 AW 2026 &amp; 2027 EASYPACK \u2212 100% + Actual 100% Fit Width Fit Page Reset \u2190\/\u2192 page \u2014 Ctrl\/\u2318 + wheel to zoom \u2014 drag to pan Loading\u2026 1\u20132 [&hellip;]<\/p>\n","protected":false},"author":6337,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"footnotes":""},"class_list":["post-36282","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/pnpplast.it\/en\/wp-json\/wp\/v2\/pages\/36282","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pnpplast.it\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/pnpplast.it\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/pnpplast.it\/en\/wp-json\/wp\/v2\/users\/6337"}],"replies":[{"embeddable":true,"href":"https:\/\/pnpplast.it\/en\/wp-json\/wp\/v2\/comments?post=36282"}],"version-history":[{"count":30,"href":"https:\/\/pnpplast.it\/en\/wp-json\/wp\/v2\/pages\/36282\/revisions"}],"predecessor-version":[{"id":39857,"href":"https:\/\/pnpplast.it\/en\/wp-json\/wp\/v2\/pages\/36282\/revisions\/39857"}],"wp:attachment":[{"href":"https:\/\/pnpplast.it\/en\/wp-json\/wp\/v2\/media?parent=36282"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}