    wrap.appendChild(svg);

    // Label overlay (fixed, doesn't interfere with zoom)
    var lbl = document.createElement("div");
    lbl.style.cssText = "position:absolute; top:6px; left:8px; font-size:11px;" +
      " font-weight:600; color:#ddd; pointer-events:none; z-index:10;" +
      " text-shadow:0 1px 2px rgba(0,0,0,.7);";
    lbl.textContent = sheet.name + "\u2002" + W + "\u00d7" + H + " mm";
    wrap.appendChild(lbl);

    // ── ViewBox zoom toward cursor ──
    function onWheel(e) {
      e.preventDefault();
      var rect  = svg.getBoundingClientRect();
      // cursor position in mm-space
      var mx_mm = vbX + (e.clientX - rect.left)  / rect.width  * vbW;
      var my_mm = vbY + (e.clientY - rect.top)    / rect.height * vbH;
      var factor = e.deltaY > 0 ? 1.18 : (1 / 1.18);
      var nW = Math.max(W * 0.01, Math.min(vbW0 * 6, vbW * factor));
      var nH = vbH * (nW / vbW); // keep aspect ratio
      vbX = mx_mm - (e.clientX - rect.left)  / rect.width  * nW;
      vbY = my_mm - (e.clientY - rect.top)    / rect.height * nH;
      vbW = nW; vbH = nH;
      setVB();
    }
    svg.addEventListener("wheel", onWheel, { passive: false });

    // ── ViewBox drag-to-pan ──
    var dragging = false, dsx, dsy, vbX0d, vbY0d;
    function onMouseDown(e) {
      if (e.button !== 0) return;
      dragging = true;
      dsx = e.clientX; dsy = e.clientY;
      vbX0d = vbX; vbY0d = vbY;
      wrap.style.cursor = "grabbing";
      e.preventDefault();
    }
    function onMouseMove(e) {
      if (!dragging) return;
      var rect = svg.getBoundingClientRect();
      vbX = vbX0d - (e.clientX - dsx) / rect.width  * vbW;
      vbY = vbY0d - (e.clientY - dsy) / rect.height * vbH;
      setVB();
    }
    function onMouseUp() {
      if (!dragging) return;
      dragging = false;
      wrap.style.cursor = "grab";
    }
    svg.addEventListener("mousedown", onMouseDown);
    document.addEventListener("mousemove", onMouseMove);
    document.addEventListener("mouseup",   onMouseUp);

    // ── Zoom buttons ──
    var controls = document.createElement("div");
    controls.style.cssText =
      "position:absolute; top:8px; right:8px; display:flex; gap:3px; z-index:20;";
    function zBtn(label, fn) {
      var b = document.createElement("button");
      b.textContent = label; b.className = "btn btn-xs btn-light";
      b.style.cssText = "opacity:.82; min-width:26px; box-shadow:0 1px 3px rgba(0,0,0,.3);";
      b.addEventListener("click", fn);
      b.addEventListener("mousedown", function(e) { e.stopPropagation(); });
      return b;
    }
    controls.appendChild(zBtn("+", function() {
      var cx = vbX + vbW / 2, cy = vbY + vbH / 2;
      vbW = Math.max(W * 0.01, vbW / 1.35);
      vbH = Math.max(H * 0.01, vbH / 1.35);
      vbX = cx - vbW / 2; vbY = cy - vbH / 2;
      setVB();
    }));
    controls.appendChild(zBtn("−", function() {
      var cx = vbX + vbW / 2, cy = vbY + vbH / 2;
      vbW = Math.min(vbW0 * 6, vbW * 1.35);
      vbH = Math.min(vbH0 * 6, vbH * 1.35);
      vbX = cx - vbW / 2; vbY = cy - vbH / 2;
      setVB();
    }));
    controls.appendChild(zBtn("⟳", function() {
      vbX = vbX0; vbY = vbY0; vbW = vbW0; vbH = vbH0;
      setVB();
    }));
    wrap.appendChild(controls);

    this._zoomCleanup = function() {
      document.removeEventListener("mousemove", onMouseMove);
      document.removeEventListener("mouseup",   onMouseUp);
    };
  },
});
