(function () {
  'use strict';
	var translatedMessages = window.MPAB_WALL_ART && window.MPAB_WALL_ART.messages ? window.MPAB_WALL_ART.messages : {};
	function message(key, fallback, values) {
		var output = translatedMessages[key] || fallback;
		(values || []).forEach(function (value, index) { output = output.replace(new RegExp('%' + (index + 1) + '\\$[sd]|%[sd]'), String(value)); });
		return output.replace(/%%/g, '%');
	}

  function escapeHtml(value) {
    return String(value || '').replace(/[&<>'"]/g, function (character) {
      return { '&': '&amp;', '<': '&lt;', '>': '&gt;', "'": '&#039;', '"': '&quot;' }[character];
    });
  }

  function studioRouter(root) {
    if (root.dataset.wbReady) return;
    root.dataset.wbReady = '1';
    var intro = root.querySelector('.wb-studio-choice__intro');
    var cards = root.querySelector('.wb-studio-choice__cards');
    var basket = window.WBStudioBasket;
    var basketBar = root.querySelector('[data-wb-basket-bar]');
    var basketButton = root.querySelector('[data-wb-view-basket]');
    var basketCount = root.querySelector('[data-wb-basket-count]');
    var basketPanel = root.querySelector('[data-wb-panel="basket"]');
    var basketSummary = root.querySelector('[data-wb-basket-page-summary]');
    var basketForm = root.querySelector('[data-wb-basket-form]');
    var basketConfirmation = root.querySelector('[data-wb-basket-confirmation]');
    var basketError = root.querySelector('[data-wb-basket-error]');
    var basketSubmit = root.querySelector('[data-wb-basket-submit]');
		var returnPanel = null;

    function openPanel(panel) {
      if (!panel) return;
      intro.hidden = true;
      cards.hidden = true;
      root.querySelectorAll('[data-wb-panel]').forEach(function (item) { item.hidden = item !== panel; });
      panel.hidden = false;
			if (basketBar) basketBar.hidden = panel === basketPanel || !basket || basket.count() < 1;
      panel.scrollIntoView({ behavior: 'smooth', block: 'start' });
    }

    function showStudioStart() {
      root.querySelectorAll('[data-wb-panel]').forEach(function (panel) { panel.hidden = true; });
      intro.hidden = false;
      cards.hidden = false;
			if (basketBar) basketBar.hidden = !basket || basket.count() < 1;
      root.scrollIntoView({ behavior: 'smooth', block: 'start' });
    }

		function visibleProductPanel() {
			return Array.prototype.find.call(root.querySelectorAll('[data-wb-panel]'), function (panel) { return panel !== basketPanel && !panel.hidden; }) || null;
		}

		function returnFromBasket() {
			if (returnPanel && root.contains(returnPanel)) openPanel(returnPanel); else showStudioStart();
			returnPanel = null;
		}

		root.wbOpenPanel = openPanel;
		root.wbShowStart = showStudioStart;

    function updateBasketAccess() {
      if (!basket || !basketBar || !basketCount) return;
      var total = basket.count();
			if (basketPanel && !basketPanel.hidden) {
				if (total < 1) { showStudioStart(); return; }
				basket.render(basketSummary, null, { force: true, actions: true });
			}
			basketBar.hidden = total < 1 || (basketPanel && !basketPanel.hidden);
      basketCount.textContent = String(total);
    }

    root.querySelectorAll('[data-wb-open]').forEach(function (button) {
      button.addEventListener('click', function (event) {
        event.preventDefault();
        var panel = root.querySelector('[data-wb-panel="' + button.dataset.wbOpen + '"]');
				if (panel) panel.dispatchEvent(new CustomEvent('wb:start-new-item'));
        openPanel(panel);
      });
    });
    root.querySelectorAll('[data-wb-back]').forEach(function (button) {
      button.addEventListener('click', function (event) {
        event.preventDefault();
        showStudioStart();
      });
    });

    if (basket && basketButton && basketPanel && basketSummary && basketForm) {
      basket.subscribe(updateBasketAccess);
      basketButton.addEventListener('click', function () {
				returnPanel = visibleProductPanel();
				basket.render(basketSummary, null, { force: true, actions: true });
        basketConfirmation.hidden = true; basketForm.hidden = false; basketError.hidden = true;
        openPanel(basketPanel);
      });
			root.querySelectorAll('[data-wb-basket-continue]').forEach(function (button) { button.addEventListener('click', returnFromBasket); });
      basketForm.addEventListener('submit', function (event) {
        event.preventDefault();
        if (!basketForm.checkValidity()) { basketForm.reportValidity(); return; }
        basketSubmit.disabled = true; basketSubmit.textContent = message('sendingOrder', 'Sending your order…'); basketError.hidden = true;
        basket.checkout(null, { name: basketForm.elements.client_name.value, email: basketForm.elements.client_email.value }).then(function (references) {
          basketForm.hidden = true; basketConfirmation.hidden = false;
          basketConfirmation.querySelector('[data-wb-basket-confirmation-copy]').textContent = message(references.length > 1 ? 'orderNumbers' : 'orderNumber', references.length > 1 ? 'Order numbers %s.' : 'Order number %s.', [references.join(', ')]) + ' ' + message('contactAfterOrder', 'I will be in touch to confirm payment, production and delivery.');
          basketPanel.scrollIntoView({ behavior: 'smooth', block: 'start' });
        }).catch(function (error) {
          basketError.textContent = error.message || message('orderFailed', 'Your order could not be sent. Please check your connection and try again.'); basketError.hidden = false;
        }).finally(function () { basketSubmit.disabled = false; basketSubmit.textContent = message('confirmSendOrder', 'Confirm and send order'); });
      });
    }
  }

  function initBuilder(root) {
    if (root.dataset.wallReady || !window.MPAB_WALL_ART) return;
    root.dataset.wallReady = '1';
    var data = window.MPAB_WALL_ART;
    var form = root.querySelector('form');
    var productsBox = root.querySelector('[data-wall-products]');
    var orientationsBox = root.querySelector('[data-wall-orientations]');
    var sizesBox = root.querySelector('[data-wall-sizes]');
    var finishesBox = root.querySelector('[data-wall-finishes]');
    var reviewBox = root.querySelector('[data-wall-review]');
    var nextButton = root.querySelector('[data-wall-next]');
    var previousButton = root.querySelector('[data-wall-prev]');
    var addBasketButton = root.querySelector('[data-wall-add-basket]');
    var revealButton = root.querySelector('[data-wall-reveal-details]');
    var submitButton = root.querySelector('[data-wall-submit]');
    var clientBox = root.querySelector('[data-wall-client]');
    var confirmation = root.querySelector('[data-wall-confirmation]');
    var quantityInput = form.elements.quantity;
    var basketSummary = root.querySelector('[data-wall-basket-summary]');
    var basket = window.WBStudioBasket;
    var errorBox = root.querySelector('[data-wall-error]');
    var fileInput = root.querySelector('[data-wall-file]');
    var dropzone = root.querySelector('[data-wall-dropzone]');
    var emptyUpload = root.querySelector('[data-wall-empty]');
    var canvas = root.querySelector('[data-wall-canvas]');
    var context = canvas.getContext('2d');
    var editor = root.querySelector('[data-wall-editor]');
    var zoomInput = root.querySelector('[data-wall-zoom]');
    var quality = root.querySelector('[data-wall-quality]');
    var promotion = data.promotion && data.promotion.active ? data.promotion : { active: false, percent: 0, endDate: '', endLabel: '' };
    var state = { step: 1, product: null, item: null, finish: '', file: null, image: null, zoom: 1, rotation: 0, x: 0, y: 0, dragging: false, pointerX: 0, pointerY: 0, qualityOkay: false };
		var editingItemId = '';

		function updateAddBasketLabel() {
			if (addBasketButton) addBasketButton.textContent = editingItemId ? message('updateItem', 'Update item') : message('addBasket', 'Add to basket and order more');
		}

		function openWallArtPanel() {
			var studio = root.closest('[data-wb-studio]');
			var panel = root.closest('[data-wb-panel="wall-art"]');
			if (studio && panel && typeof studio.wbOpenPanel === 'function') studio.wbOpenPanel(panel);
		}

    function productById(id) {
      return (data.catalogue.products || []).find(function (product) { return product.id === id; });
    }

    function updateUploadPresentation() {
      var framed = Boolean(state.product && state.product.id === 'framed-photo');
      var frameColours = {
        'Black matte': '#302d2a',
        'White': '#eeeae2',
        'Vintage silver': '#aaa9a3',
        'Walnut flair': '#6d4b35',
        'Oak vintage flair': '#b49368'
      };
      dropzone.classList.toggle('is-framed-photo', framed);
      dropzone.style.setProperty('--wall-frame-colour', frameColours[state.finish] || '#302d2a');
    }

    function optionButton(name, value, label, selected, extraClass, mockup) {
      return '<label class="mpab-wall-option ' + (extraClass || '') + '"><input type="radio" name="' + escapeHtml(name) + '" value="' + escapeHtml(value) + '" ' + (selected ? 'checked' : '') + '><span>' + (mockup || '') + '<strong>' + escapeHtml(label) + '</strong></span></label>';
    }

    function renderProducts() {
      productsBox.innerHTML = (data.catalogue.products || []).map(function (product) {
        var mockup = '<i class="mpab-wall-mockup mpab-wall-mockup--' + escapeHtml(product.mockup) + '"><b></b></i>';
        return '<label class="mpab-wall-option mpab-wall-option--product"><input type="radio" name="wall_product" value="' + escapeHtml(product.id) + '" ' + (state.product && state.product.id === product.id ? 'checked' : '') + '><span>' + mockup + '<strong>' + escapeHtml(product.label) + '</strong><small class="mpab-wall-product-description">' + escapeHtml(product.description) + '</small></span></label>';
      }).join('');
      productsBox.querySelectorAll('input').forEach(function (input) {
        input.addEventListener('change', function () {
          state.product = productById(input.value);
          state.item = null; state.finish = ''; resetUpload(); updateUploadPresentation();
        });
      });
    }

    function renderSizes() {
      var orientations = [];
      state.product.items.forEach(function (item) { if (orientations.indexOf(item.orientation) < 0) orientations.push(item.orientation); });
      var selectedOrientation = state.item ? state.item.orientation : orientations[0];
      orientationsBox.innerHTML = orientations.map(function (orientation) { return optionButton('wall_orientation', orientation, orientation, orientation === selectedOrientation, 'mpab-wall-option--text'); }).join('');
      function drawSizeList(orientation) {
        var items = state.product.items.filter(function (item) { return item.orientation === orientation; });
        sizesBox.innerHTML = items.map(function (item) {
          var size = item.width_cm + 'x' + item.height_cm + ' cm';
          var inches = item.width_in + 'x' + item.height_in + ' in';
          var profile = state.product.id === 'canvas' && item.profile ? '<small>' + escapeHtml(item.profile) + '</small>' : '';
          var shape = '<i class="mpab-wall-shape mpab-wall-shape--' + escapeHtml(state.product.id) + '" style="--wall-ratio:' + Number(item.width_cm / item.height_cm).toFixed(4) + '"></i>';
          return '<label class="mpab-wall-option mpab-wall-option--size"><input type="radio" name="wall_item" value="' + escapeHtml(item.id) + '" ' + (state.item && state.item.id === item.id ? 'checked' : '') + '><span>' + shape + '<strong>' + escapeHtml(size) + '</strong><em>' + escapeHtml(inches) + '</em>' + profile + '</span></label>';
        }).join('');
        sizesBox.querySelectorAll('input').forEach(function (input) {
          input.addEventListener('change', function () {
            state.item = state.product.items.find(function (item) { return item.id === input.value; });
            state.finish = ''; resetUpload();
          });
        });
      }
      orientationsBox.querySelectorAll('input').forEach(function (input) { input.addEventListener('change', function () { state.item = null; drawSizeList(input.value); }); });
      drawSizeList(selectedOrientation);
    }

    function renderFinishes() {
      var options = state.product.options || [];
      if (!options.length) {
        state.finish = '';
        finishesBox.innerHTML = '<p class="mpab-wall-included">' + escapeHtml(message('everythingIncluded', 'Everything needed for this finish is already included.')) + '</p>';
        return;
      }
			var frameImages = {
				'Black matte': 'frames/black-matte.png',
				'White': 'frames/white.png',
				'Vintage silver': 'frames/vintage-silver.png',
				'Walnut flair': 'frames/walnut-flair.png',
				'Oak vintage flair': 'frames/oak-vintage-flair.png'
			};
			finishesBox.innerHTML = options.map(function (finish) {
				var frameImage = state.product.id === 'framed-photo' ? frameImages[finish] : '';
				var preview = frameImage ? '<img class="mpab-wall-frame-swatch" src="' + escapeHtml(data.assetBase + frameImage) + '" alt="">' : '';
				var finishLabel = state.product.option_labels && state.product.option_labels[finish] ? state.product.option_labels[finish] : finish;
				return optionButton('wall_finish', finish, finishLabel, finish === state.finish, 'mpab-wall-option--finish' + (frameImage ? ' has-image' : ''), preview);
			}).join('');
      finishesBox.querySelectorAll('input').forEach(function (input) { input.addEventListener('change', function () { state.finish = input.value; updateUploadPresentation(); }); });
    }

    function hasFinishStep() {
      return Boolean(state.product && state.product.options && state.product.options.length);
    }

    function logicalStep(step) {
      if (hasFinishStep()) return { current: step, total: 5 };
      return { current: step > 3 ? step - 1 : step, total: 4 };
    }

    function setStep(step) {
      state.step = step;
      root.querySelectorAll('[data-wall-step]').forEach(function (section) {
        var active = Number(section.dataset.wallStep) === step;
        section.hidden = !active; section.classList.toggle('is-active', active);
      });
      var progress = logicalStep(step);
      root.querySelector('[data-wall-progress]').textContent = progress.current + ' / ' + progress.total;
      root.querySelector('[data-wall-progress-bar]').style.width = ((progress.current / progress.total) * 100) + '%';
      var activeStep = root.querySelector('[data-wall-step="' + step + '"]');
      if (activeStep) {
        var kicker = activeStep.querySelector('.mpab-wall-kicker');
        if (kicker) kicker.textContent = message('step', 'Step %d', [progress.current]);
      }
      previousButton.hidden = step === 1;
      nextButton.hidden = step === 5;
      revealButton.hidden = step !== 5;
      addBasketButton.hidden = step !== 5;
      submitButton.hidden = true;
      clientBox.hidden = true;
      errorBox.hidden = true;
      if (step === 2) renderSizes();
      if (step === 3) renderFinishes();
      if (step === 4) {
        sizeCanvas();
        if (state.image) { draw(); assessQuality(); }
      }
      if (step === 5) renderReview();
      root.scrollIntoView({ behavior: 'smooth', block: 'start' });
    }

    function fail(message) { errorBox.textContent = message; errorBox.hidden = false; }
    function clearError() { errorBox.textContent = ''; errorBox.hidden = true; }

    function validStep() {
      if (state.step === 1 && !state.product) { fail(message('chooseProduct', 'Choose a wall art product to continue.')); return false; }
      if (state.step === 2 && !state.item) { fail(message('chooseSize', 'Choose a size to continue.')); return false; }
      if (state.step === 3 && state.product.options.length && !state.finish) { fail(message('chooseFinish', 'Choose a finish to continue.')); return false; }
      if (state.step === 4 && !state.file) { fail(message('addJpg', 'Add a JPG before continuing.')); return false; }
      if (state.step === 4 && !state.qualityOkay) { clearError(); quality.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); return false; }
      return true;
    }

    nextButton.addEventListener('click', function () {
      if (!validStep()) return;
      var next = state.step === 2 && !hasFinishStep() ? 4 : Math.min(5, state.step + 1);
      setStep(next);
    });
    previousButton.addEventListener('click', function () {
      var previous = state.step === 4 && !hasFinishStep() ? 2 : Math.max(1, state.step - 1);
      setStep(previous);
    });
    revealButton.addEventListener('click', function () {
      clientBox.hidden = false;
      revealButton.hidden = true;
      submitButton.hidden = false;
      clientBox.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
    });
    quantityInput.addEventListener('change', function () { quantityInput.value = String(Math.max(1, Math.min(20, Number(quantityInput.value) || 1))); renderReview(); });

    function sizeCanvas() {
      if (!state.item) return;
      var max = 760;
      var ratio = state.item.width_cm / state.item.height_cm;
      canvas.width = ratio >= 1 ? max : Math.round(max * ratio);
      canvas.height = ratio >= 1 ? Math.round(max / ratio) : max;
      // Use an explicit ratio rather than a decimal so mobile Safari keeps the
      // CSS preview box and the canvas bitmap at exactly the same proportions.
      dropzone.style.setProperty('--wall-upload-ratio', state.item.width_cm + ' / ' + state.item.height_cm);
      dropzone.style.setProperty('--wall-upload-width', String(68 * ratio) + 'vh');
      canvas.style.aspectRatio = canvas.width + ' / ' + canvas.height;
      updateUploadPresentation();
    }

    function imageDimensions() {
      var rotated = state.rotation % 180 !== 0;
      return { width: rotated ? state.image.naturalHeight : state.image.naturalWidth, height: rotated ? state.image.naturalWidth : state.image.naturalHeight };
    }

    function constrainPosition() {
      if (!state.image || !canvas.width || !canvas.height) return;
      var dims = imageDimensions();
      var base = Math.max(canvas.width / dims.width, canvas.height / dims.height);
      var scale = base * state.zoom;
      var maxX = Math.max(0, ((dims.width * scale) - canvas.width) / 2);
      var maxY = Math.max(0, ((dims.height * scale) - canvas.height) / 2);
      state.x = Math.max(-maxX, Math.min(maxX, state.x));
      state.y = Math.max(-maxY, Math.min(maxY, state.y));
    }

    function draw(target, width, height) {
      target = target || context; width = width || canvas.width; height = height || canvas.height;
      if (!state.image) return;
      var dims = imageDimensions();
      var base = Math.max(width / dims.width, height / dims.height);
      var scale = base * state.zoom;
      target.save(); target.clearRect(0, 0, width, height); target.fillStyle = '#f4f0eb'; target.fillRect(0, 0, width, height);
      target.translate(width / 2 + state.x * (width / canvas.width), height / 2 + state.y * (height / canvas.height));
      target.rotate(state.rotation * Math.PI / 180); target.scale(scale, scale);
      target.drawImage(state.image, -state.image.naturalWidth / 2, -state.image.naturalHeight / 2);
      target.restore();
    }

    function availableCropPixels() {
      if (!state.image || !state.item) return { width: 0, height: 0 };
      var dims = imageDimensions();
      var base = Math.max(canvas.width / dims.width, canvas.height / dims.height);
      return {
        width: Math.floor(canvas.width / (base * state.zoom)),
        height: Math.floor(canvas.height / (base * state.zoom))
      };
    }

    function assessQuality() {
      if (!state.image || !state.item) return;
      clearError();
      var available = availableCropPixels();
      state.qualityOkay = available.width >= state.item.min_width && available.height >= state.item.min_height;
      quality.hidden = state.qualityOkay;
      quality.className = 'mpab-wall-quality' + (state.qualityOkay ? '' : ' is-poor');
      quality.textContent = state.qualityOkay ? '' : message('qualityTooLow', 'This crop contains about %1$dx%2$d px, but the selected size needs at least %3$dx%4$d px. Reduce the zoom, choose a smaller size or use a larger photograph.', [available.width, available.height, state.item.min_width, state.item.min_height]);
    }

    function resetUpload() {
      if (state.image && state.image.src && state.image.src.indexOf('blob:') === 0) URL.revokeObjectURL(state.image.src);
      state.file = null; state.image = null; state.zoom = 1; state.rotation = 0; state.x = 0; state.y = 0; state.qualityOkay = false;
      if (fileInput) fileInput.value = '';
      if (zoomInput) zoomInput.value = 1;
      if (canvas) { context.clearRect(0, 0, canvas.width, canvas.height); canvas.hidden = true; }
      if (emptyUpload) emptyUpload.hidden = false;
      if (editor) editor.hidden = true;
      if (quality) { quality.textContent = ''; quality.className = 'mpab-wall-quality'; quality.hidden = true; }
      clearError();
    }

    function loadFile(file) {
      if (!file || !/^image\/jpeg$/i.test(file.type || '') || file.size > Number(data.maxBytes)) { fail(message('invalidJpg', 'Please choose a JPG within this website’s upload limit.')); return; }
      var url = URL.createObjectURL(file); var image = new Image();
      image.onload = function () { if (state.image && state.image.src.indexOf('blob:') === 0) URL.revokeObjectURL(state.image.src); state.file = file; state.image = image; state.zoom = 1; state.rotation = 0; state.x = 0; state.y = 0; zoomInput.value = 1; sizeCanvas(); canvas.hidden = false; emptyUpload.hidden = true; editor.hidden = false; draw(); assessQuality(); };
      image.onerror = function () { URL.revokeObjectURL(url); fail(message('unreadableJpg', 'That JPG could not be opened. Please choose another photograph.')); };
      image.src = url;
    }

    fileInput.addEventListener('change', function () { loadFile(fileInput.files[0]); });
    dropzone.addEventListener('click', function (event) { if (event.target !== canvas) fileInput.click(); });
    dropzone.addEventListener('keydown', function (event) { if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); fileInput.click(); } });
    ['dragenter', 'dragover'].forEach(function (type) { dropzone.addEventListener(type, function (event) { event.preventDefault(); dropzone.classList.add('is-dragging'); }); });
    ['dragleave', 'drop'].forEach(function (type) { dropzone.addEventListener(type, function (event) { event.preventDefault(); dropzone.classList.remove('is-dragging'); }); });
    dropzone.addEventListener('drop', function (event) { loadFile(event.dataTransfer.files[0]); });
    zoomInput.addEventListener('input', function () { state.zoom = Number(zoomInput.value); constrainPosition(); draw(); assessQuality(); });
    root.querySelector('[data-wall-rotate]').addEventListener('click', function () { state.rotation = (state.rotation + 90) % 360; state.x = 0; state.y = 0; draw(); assessQuality(); });
    root.querySelector('[data-wall-reset]').addEventListener('click', function () { state.zoom = 1; state.rotation = 0; state.x = 0; state.y = 0; zoomInput.value = 1; draw(); assessQuality(); });
    root.querySelector('[data-wall-replace]').addEventListener('click', function () { fileInput.click(); });
    canvas.addEventListener('pointerdown', function (event) { state.dragging = true; state.pointerX = event.clientX; state.pointerY = event.clientY; canvas.setPointerCapture(event.pointerId); });
    canvas.addEventListener('pointermove', function (event) {
      if (!state.dragging) return;
      var bounds = canvas.getBoundingClientRect();
      var scaleX = bounds.width ? canvas.width / bounds.width : 1;
      var scaleY = bounds.height ? canvas.height / bounds.height : 1;
      state.x += (event.clientX - state.pointerX) * scaleX;
      state.y += (event.clientY - state.pointerY) * scaleY;
      state.pointerX = event.clientX;
      state.pointerY = event.clientY;
      constrainPosition();
      draw();
    });
    canvas.addEventListener('pointerup', function () { state.dragging = false; });

    function renderReview() {
			var selectedFinishLabel = state.finish && state.product.option_labels && state.product.option_labels[state.finish] ? state.product.option_labels[state.finish] : state.finish;
			var finish = state.finish ? '<li><span>' + escapeHtml(message('finish', 'Finish')) + '</span><strong>' + escapeHtml(selectedFinishLabel) + '</strong><button type="button" data-review-edit="3">' + escapeHtml(message('edit', 'Edit')) + '</button></li>' : '';
      var quantity = Math.max(1, Number(quantityInput.value) || 1);
      var usualTotal = Number(state.item.price) * quantity;
      var discount = promotion.active ? Math.round(usualTotal * Number(promotion.percent) ) / 100 : 0;
      var total = Math.max(0, usualTotal - discount);
      var money = function (amount) { return data.catalogue.currency_symbol + amount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }); };
      var priceRows = promotion.active ? '<li class="mpab-wall-review__usual"><span>' + escapeHtml(message('usualTotal', 'Usual total')) + '</span><strong>' + escapeHtml(money(usualTotal)) + '</strong></li><li class="mpab-wall-review__saving"><span>' + escapeHtml(message('saving', '%d%% saving', [promotion.percent])) + '</span><strong>−' + escapeHtml(money(discount)) + '</strong></li>' : '';
      reviewBox.innerHTML = '<div class="mpab-wall-review__visual"><i class="mpab-wall-mockup mpab-wall-mockup--' + escapeHtml(state.product.mockup) + '"><b></b></i></div><ul><li><span>' + escapeHtml(message('product', 'Product')) + '</span><strong>' + escapeHtml(state.product.label) + '</strong><button type="button" data-review-edit="1">' + escapeHtml(message('edit', 'Edit')) + '</button></li><li><span>' + escapeHtml(message('size', 'Size')) + '</span><strong>' + escapeHtml(state.item.width_cm + 'x' + state.item.height_cm + ' cm · ' + state.item.width_in + 'x' + state.item.height_in + ' in') + '</strong><button type="button" data-review-edit="2">' + escapeHtml(message('edit', 'Edit')) + '</button></li>' + finish + '<li><span>' + escapeHtml(message('numberCopies', 'Number of copies')) + '</span><strong>' + quantity + '</strong></li>' + priceRows + '<li class="mpab-wall-review__total"><span>' + escapeHtml(promotion.active ? message('promotionalTotal', 'Promotional total') : message('total', 'Total')) + '</span><strong>' + escapeHtml(money(total)) + '</strong></li>' + (promotion.active && promotion.endLabel ? '<li class="mpab-wall-review__deadline">' + escapeHtml(message('offerEnds', 'Offer ends %s', [promotion.endLabel])) + '</li>' : '') + '</ul>';
      basket.render(basketSummary, { label: state.product.label, detail: state.item.width_cm + 'x' + state.item.height_cm + ' cm', quantity: quantity, total: total, currency: data.catalogue.currency_symbol });
      reviewBox.querySelectorAll('[data-review-edit]').forEach(function (button) { button.addEventListener('click', function () { setStep(Number(button.dataset.reviewEdit)); }); });
    }

    function cropBlob() {
      return new Promise(function (resolve) {
        var output = document.createElement('canvas');
        output.width = state.item.min_width; output.height = state.item.min_height;
        draw(output.getContext('2d'), output.width, output.height);
        output.toBlob(resolve, 'image/jpeg', 0.94);
      });
    }

    function makeEntry(crop) {
      var product = state.product; var item = state.item; var finish = state.finish; var original = state.file;
      var quantity = Math.max(1, Number(quantityInput.value) || 1);
			var snapshot = { productId: product.id, itemId: item.id, finish: finish, file: original, zoom: state.zoom, rotation: state.rotation, x: state.x, y: state.y, quantity: quantity };
			var productImages = { canvas: 'canvas-print.webp', metal: 'metal-print.webp', acrylic: 'acrylic-print.webp', 'hanging-canvas': 'hanging-canvas.webp', 'framed-photo': 'framed-photo.webp' };
      return {
        kind: 'wall-art', label: product.label, detail: item.width_cm + 'x' + item.height_cm + ' cm' + (finish ? ' · ' + (product.option_labels && product.option_labels[finish] ? product.option_labels[finish] : finish) : ''), quantity: quantity, total: Math.round(Math.max(0, (Number(item.price) * quantity) * (1 - (promotion.active ? Number(promotion.percent) / 100 : 0))) * 100) / 100, currency: data.catalogue.currency_symbol,
				image: productImages[product.id] ? data.assetBase + 'product-cards/' + productImages[product.id] : '',
				edit: function (id) { restoreEntry(id, snapshot); },
        submit: function (details) {
          var body = new FormData(); body.append('token', data.token); body.append('locale', data.locale || ''); body.append('product', product.id); body.append('item', item.id); body.append('finish', finish); body.append('quantity', String(quantity)); body.append('promotion_percent', promotion.active ? String(promotion.percent) : '0'); body.append('promotion_end_date', promotion.active ? String(promotion.endDate || '') : ''); body.append('client_name', details.name); body.append('client_email', details.email); body.append('consent', '1'); body.append('original', original, original.name); body.append('crop', crop, 'approved-crop.jpg');
          return fetch(data.endpoint, { method: 'POST', body: body, credentials: 'same-origin' }).then(function (response) { return response.json().then(function (result) { if (!response.ok) throw new Error(result && result.message ? result.message : message('orderFailed', 'Your order could not be sent. Please check your connection and try again.')); return result; }); });
        }
      };
    }

		function restoreEntry(id, snapshot) {
			var product = productById(snapshot.productId);
			var item = product && product.items ? product.items.find(function (candidate) { return candidate.id === snapshot.itemId; }) : null;
			if (!product || !item || !snapshot.file) return;
			resetUpload(); form.reset(); editingItemId = id; state.product = product; state.item = item; state.finish = snapshot.finish || ''; state.file = snapshot.file;
			state.zoom = snapshot.zoom; state.rotation = snapshot.rotation; state.x = snapshot.x; state.y = snapshot.y;
			quantityInput.value = String(snapshot.quantity || 1); renderProducts(); renderSizes(); renderFinishes(); updateUploadPresentation(); openWallArtPanel(); updateAddBasketLabel();
			var url = URL.createObjectURL(snapshot.file); var image = new Image();
			image.onload = function () {
				URL.revokeObjectURL(url);
				state.image = image; zoomInput.value = String(state.zoom); sizeCanvas(); canvas.hidden = false; emptyUpload.hidden = true; editor.hidden = false; draw(); assessQuality(); setStep(5); updateAddBasketLabel();
			};
			image.onerror = function () { URL.revokeObjectURL(url); fail(message('unreadableJpg', 'That JPG could not be opened. Please choose another photograph.')); };
			image.src = url;
		}

    function returnToStudioStart() {
			editingItemId = ''; resetUpload(); form.reset(); state.product = null; state.item = null; state.finish = ''; state.step = 1; confirmation.hidden = true; form.hidden = false; renderProducts(); setStep(1); updateAddBasketLabel();
      var studio = root.closest('[data-wb-studio]');
      if (studio) { studio.querySelectorAll('[data-wb-panel]').forEach(function (panel) { panel.hidden = true; }); studio.querySelector('.wb-studio-choice__intro').hidden = false; studio.querySelector('.wb-studio-choice__cards').hidden = false; studio.scrollIntoView({ behavior: 'smooth', block: 'start' }); }
    }

    addBasketButton.addEventListener('click', async function () {
      addBasketButton.disabled = true; addBasketButton.textContent = message('addingBasket', 'Adding to basket…');
			try { var crop = await cropBlob(); if (!crop) throw new Error(message('cropFailed', 'The image crop could not be generated. Please re-position your photograph and try again.')); if (editingItemId) basket.replace(editingItemId, makeEntry(crop)); else basket.add(makeEntry(crop)); returnToStudioStart(); }
      catch (error) { fail(error.message || message('basketAddFailed', 'This item could not be added to your basket. Please refresh the page and try again.')); }
			finally { addBasketButton.disabled = false; updateAddBasketLabel(); }
    });

    form.addEventListener('submit', async function (event) {
      event.preventDefault();
      if (!form.checkValidity()) { form.reportValidity(); return; }
      submitButton.disabled = true; submitButton.textContent = message('sendingChoices', 'Sending your choices…'); errorBox.hidden = true;
      try {
        var crop = await cropBlob(); if (!crop) throw new Error(message('cropFailed', 'The image crop could not be generated. Please re-position your photograph and try again.'));
        var references = await basket.checkout(makeEntry(crop), { name: form.elements.client_name.value, email: form.elements.client_email.value });
        form.hidden = true; confirmation.hidden = false; confirmation.querySelector('[data-wall-confirmation-copy]').textContent = message(references.length > 1 ? 'orderNumbers' : 'orderNumber', references.length > 1 ? 'Order numbers %s.' : 'Order number %s.', [references.join(', ')]) + ' ' + message('contactAfterOrder', 'I will be in touch to confirm payment, production and delivery.'); root.scrollIntoView({ behavior: 'smooth', block: 'start' });
      } catch (error) { fail(error.message || message('choicesFailed', 'Your choices could not be sent. Please check your connection and try again.')); submitButton.disabled = false; submitButton.textContent = message('confirmSendOrder', 'Confirm and send order'); }
    });

		var wallArtPanel = root.closest('[data-wb-panel]');
		if (wallArtPanel) wallArtPanel.addEventListener('wb:start-new-item', function () {
			if (!editingItemId) return;
			editingItemId = ''; resetUpload(); form.reset(); state.product = null; state.item = null; state.finish = ''; renderProducts(); setStep(1); updateAddBasketLabel();
		});

    renderProducts(); setStep(1); updateAddBasketLabel();
  }

  function boot() {
    document.querySelectorAll('[data-wb-studio]').forEach(studioRouter);
    document.querySelectorAll('[data-mpab-wall-builder]').forEach(initBuilder);
  }
  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot); else boot();
}());
