/**
 * Checkout Pro
 * 1. Panel lateral del carrito: se abre al añadir y al pulsar el carrito de la cabecera.
 *    Los cambios van al controlador de carrito del núcleo; el panel se repinta desde el módulo.
 * 2. Carrito y pago: total dentro del botón de pagar, línea de confianza, aviso de pago
 *    solo al intentar pagar y barra fija en móvil en la página del carrito.
 * Sin jQuery: vale para temas de 1.7 a Hummingbird (9.x).
 */
(function () {
    'use strict';

    var cfg = window.checkoutpro;
    var ps = window.prestashop;
    if (!cfg || !ps) {
        return;
    }

    /* 1. Panel lateral
       ===================================================================== */

    var drawer;
    var overlay;
    var lastFocus;
    var loading = null;
    var undoTimer;

    function build() {
        overlay = document.createElement('div');
        overlay.className = 'ckp-overlay js-ckp-close';
        drawer = document.createElement('aside');
        drawer.className = 'ckp-drawer';
        drawer.setAttribute('role', 'dialog');
        drawer.setAttribute('aria-modal', 'true');
        drawer.setAttribute('aria-label', 'Cart');
        drawer.tabIndex = -1;
        document.body.appendChild(overlay);
        document.body.appendChild(drawer);

        document.addEventListener('click', onDrawerClick);
        drawer.addEventListener('change', onDrawerChange);
        document.addEventListener('keydown', function (e) {
            if (e.key === 'Escape' && isOpen()) {
                close();
            }
        });
    }

    function isOpen() {
        return document.body.classList.contains('ckp-open');
    }

    function open() {
        if (!drawer) {
            build();
        }
        if (!isOpen()) {
            lastFocus = document.activeElement;
            document.body.classList.add('ckp-open');
            drawer.focus();
        }
        return refresh();
    }

    function close() {
        document.body.classList.remove('ckp-open');
        if (lastFocus && lastFocus.focus) {
            lastFocus.focus();
        }
    }

    function refresh(extra) {
        if (loading) {
            return loading;
        }
        drawer.classList.add('is-loading');
        var url = cfg.url + (cfg.url.indexOf('?') === -1 ? '?' : '&') + 'ajax=1&action=drawer&_=' + Date.now() + (extra || '');
        loading = fetch(url, {credentials: 'same-origin', headers: {Accept: 'application/json'}})
            .then(function (r) {
                return r.json();
            })
            .then(function (data) {
                var notice = drawer.querySelector('.js-ckp-notice');
                var keep = notice && !notice.hidden ? notice : null;
                var oldBar = drawer.querySelector('.ckp-bar');
                var from = oldBar ? oldBar.getAttribute('aria-valuenow') : null;
                drawer.innerHTML = data.html;
                animateBar(from);
                recoArrows();
                if (keep) {
                    drawer.querySelector('.js-ckp-notice').replaceWith(keep);
                }
            })
            .catch(function () {
                // Si el panel falla, que el cliente pueda seguir: al carrito del tema
                window.location.href = ps.urls.pages.cart + (ps.urls.pages.cart.indexOf('?') === -1 ? '?' : '&') + 'action=show';
            })
            .then(function () {
                drawer.classList.remove('is-loading');
                loading = null;
            });
        return loading;
    }

    /** La barra de envío gratis avanza desde donde estaba (el panel se repinta entero) */
    function animateBar(from) {
        var bar = drawer.querySelector('.ckp-bar');
        if (!bar || from === null || from === bar.getAttribute('aria-valuenow')) {
            return;
        }
        var fill = bar.querySelector('.ckp-bar-fill');
        if (!fill) {
            return;
        }
        fill.style.width = from + '%';
        bar.getBoundingClientRect(); // fija el punto de partida antes de animar
        fill.style.width = bar.getAttribute('aria-valuenow') + '%';
    }

    /** Flechas ‹ › bajo los recomendados, como en Shopify; se apagan en los extremos */
    function recoArrows() {
        var track = drawer.querySelector('.ckp-reco-track');
        if (!track || track.children.length < 2) {
            return;
        }
        var nav = document.createElement('div');
        nav.className = 'ckp-reco-nav';
        nav.innerHTML = '<button type="button" aria-label="‹"><svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" aria-hidden="true"><path d="M15 18l-6-6 6-6"/></svg></button>'
            + '<button type="button" aria-label="›"><svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg></button>';
        track.parentNode.insertBefore(nav, track.nextSibling);
        var prev = nav.children[0];
        var next = nav.children[1];
        var step = function () {
            return track.children[0].getBoundingClientRect().width + 8;
        };
        var sync = function () {
            prev.disabled = track.scrollLeft <= 2;
            next.disabled = track.scrollLeft + track.clientWidth >= track.scrollWidth - 2;
        };
        prev.addEventListener('click', function () {
            track.scrollBy({left: -step(), behavior: 'smooth'});
        });
        next.addEventListener('click', function () {
            track.scrollBy({left: step(), behavior: 'smooth'});
        });
        track.addEventListener('scroll', sync, {passive: true});
        track.scrollLeft = 0;
        sync();
    }

    /** Llamada al controlador de carrito del núcleo (el mismo que usan los botones del tema). */
    function cartAction(params, product) {
        var body = new URLSearchParams();
        body.append('token', ps.static_token);
        body.append('ajax', '1');
        body.append('action', 'update');
        Object.keys(params).forEach(function (k) {
            body.append(k, params[k]);
        });
        drawer.classList.add('is-loading');
        return fetch(ps.urls.pages.cart, {
            method: 'POST',
            credentials: 'same-origin',
            headers: {'Content-Type': 'application/x-www-form-urlencoded', Accept: 'application/json'},
            body: body.toString()
        })
            .then(function (r) {
                return r.json();
            })
            .then(function (resp) {
                if (resp.hasError) {
                    showNotice([].concat(resp.errors || []).join(' '));
                }
                // Para que el tema actualice el contador de la cabecera (y el carrito/pago si está abierto)
                ps.emit('updateCart', {
                    reason: {idProduct: product.id, idProductAttribute: product.ipa, linkAction: 'checkoutpro'},
                    resp: resp
                });
                return refresh();
            })
            .catch(function () {
                drawer.classList.remove('is-loading');
            });
    }

    function productOf(el) {
        var box = el.closest('[data-id-product]');
        return {
            id: box.getAttribute('data-id-product'),
            ipa: box.getAttribute('data-id-product-attribute') || '0',
            customization: box.getAttribute('data-id-customization') || '0',
            qty: parseInt(box.getAttribute('data-qty'), 10) || 1,
            name: box.getAttribute('data-name') || ''
        };
    }

    function lineParams(p) {
        return {
            id_product: p.id,
            id_product_attribute: p.ipa,
            id_customization: p.customization
        };
    }

    function remove(p) {
        var params = lineParams(p);
        params['delete'] = '1';
        return cartAction(params, p).then(function () {
            if (cfg.undo && p.customization === '0') {
                showUndo(p);
            }
        });
    }

    function add(p, qty) {
        var params = lineParams(p);
        params.add = '1';
        params.qty = String(qty);
        return cartAction(params, p);
    }

    function change(p, op) {
        var params = lineParams(p);
        params.update = '1';
        params.op = op;
        params.qty = '1';
        return cartAction(params, p);
    }

    function showNotice(html, undo) {
        var notice = drawer.querySelector('.js-ckp-notice');
        if (!notice) {
            return;
        }
        notice.textContent = html;
        if (undo) {
            var btn = document.createElement('button');
            btn.type = 'button';
            btn.className = 'ckp-link';
            btn.textContent = cfg.texts.undo;
            btn.addEventListener('click', function () {
                clearTimeout(undoTimer);
                notice.hidden = true;
                add(undo, undo.qty);
            });
            notice.appendChild(btn);
        }
        notice.hidden = false;
        clearTimeout(undoTimer);
        undoTimer = setTimeout(function () {
            var current = drawer.querySelector('.js-ckp-notice');
            if (current) {
                current.hidden = true;
            }
        }, 8000);
    }

    function showUndo(p) {
        showNotice(cfg.texts.removed.replace('{product}', p.name) + ' ', p);
    }

    function onDrawerClick(e) {
        var t = e.target;
        if (!t.closest) {
            return;
        }
        if (t.closest('.js-ckp-close')) {
            close();
            return;
        }
        if (!drawer.contains(t)) {
            return;
        }
        var btn = t.closest('.js-ckp-remove, .js-ckp-remove-qty, .js-ckp-up, .js-ckp-down, .js-ckp-add');
        if (!btn || drawer.classList.contains('is-loading')) {
            return;
        }
        var p = productOf(btn);
        if (btn.matches('.js-ckp-remove, .js-ckp-remove-qty')) {
            remove(p);
        } else if (btn.matches('.js-ckp-up')) {
            change(p, 'up');
        } else if (btn.matches('.js-ckp-down')) {
            change(p, 'down');
        } else {
            add(p, 1);
        }
    }

    function onDrawerChange(e) {
        // Provincia para calcular el envío gratis sin dirección
        if (e.target.matches('.js-ckp-state')) {
            refresh('&id_state=' + encodeURIComponent(e.target.value || '0'));
            return;
        }
        var box = e.target.closest('.js-ckp-insurance');
        if (!box) {
            return;
        }
        var p = {id: box.getAttribute('data-id-product'), ipa: '0', customization: '0', qty: 1};
        if (box.checked) {
            add(p, 1);
        } else {
            var params = lineParams(p);
            params['delete'] = '1';
            cartAction(params, p);
        }
    }

    function initDrawer() {
        // Punto de enganche estándar de ps_shoppingcart: sin él, el tema abriría su propia ventana
        ps.blockcart = ps.blockcart || {};
        ps.blockcart.showModal = function () {};

        ps.on('updateCart', function (event) {
            var action = event && event.reason && event.reason.linkAction;
            if (action === 'checkoutpro') {
                return;
            }
            if (action === 'add-to-cart') {
                open();
            } else if (isOpen()) {
                refresh();
            }
        });

        // Viene de la página del carrito (ver skipCartPage en el módulo)
        if (/[?&]checkoutpro_open=1/.test(window.location.search)) {
            var url = window.location.href.replace(/([?&])checkoutpro_open=1(&|$)/, '$1').replace(/[?&]$/, '');
            window.history.replaceState(null, '', url);
            open();
        }

        if (cfg.openSelectors) {
            document.addEventListener('click', function (e) {
                var hit;
                try {
                    hit = e.target.closest && e.target.closest(cfg.openSelectors);
                } catch (err) {
                    return; // selector mal escrito en la configuración
                }
                if (hit) {
                    e.preventDefault();
                    e.stopPropagation();
                    open();
                }
            }, true);
        }
    }

    /* 2. Carrito y pago
       ===================================================================== */

    var LOCK = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="5" y="11" width="14" height="10" rx="2"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/></svg>';

    function cartTotal() {
        var total = document.querySelector('.cart-summary-line.cart-total .value');
        return total ? total.textContent.trim() : '';
    }

    var WHATSAPP = '<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2a10 10 0 0 0-8.6 15.1L2 22l5-1.3A10 10 0 1 0 12 2zm0 18.2a8.2 8.2 0 0 1-4.2-1.2l-.3-.2-3 .8.8-2.9-.2-.3A8.2 8.2 0 1 1 12 20.2zm4.5-6.1c-.2-.1-1.5-.7-1.7-.8s-.4-.1-.6.1-.6.8-.8 1-.3.2-.5.1a6.7 6.7 0 0 1-3.3-2.9c-.2-.4.2-.4.7-1.3.1-.2 0-.3 0-.4l-.8-1.8c-.2-.5-.4-.4-.6-.4h-.5a1 1 0 0 0-.7.3 3 3 0 0 0-.9 2.2 5.2 5.2 0 0 0 1.1 2.7 11.8 11.8 0 0 0 4.5 4c1.7.7 2.3.8 3.2.6a2.7 2.7 0 0 0 1.8-1.3 2.2 2.2 0 0 0 .1-1.3c0-.1-.2-.2-.4-.3z"/></svg>';

    function whatsappLink(text) {
        var a = document.createElement('a');
        a.href = 'https://wa.me/' + cfg.whatsapp;
        a.target = '_blank';
        a.rel = 'noopener';
        a.textContent = text;
        return a;
    }

    /** Línea de ayuda por WhatsApp bajo el resumen del pedido */
    function helpLine() {
        var summary = document.getElementById('js-checkout-summary');
        if (!cfg.whatsapp || !summary || document.querySelector('.ckp-help')) {
            return;
        }
        var line = document.createElement('p');
        line.className = 'ckp-help';
        line.innerHTML = WHATSAPP;
        var title = document.createElement('strong');
        title.textContent = cfg.texts.helpTitle;
        line.appendChild(title);
        line.appendChild(document.createTextNode(' · '));
        line.appendChild(whatsappLink(cfg.texts.helpText));
        summary.parentNode.insertBefore(line, summary.nextSibling);
    }

    function trustLines() {
        if (!cfg.texts.trust) {
            return;
        }
        ['.cart-detailed-actions', '#payment-confirmation'].forEach(function (sel) {
            var zone = document.querySelector(sel);
            if (zone && !zone.querySelector('.ckp-trust')) {
                var line = document.createElement('p');
                line.className = 'ckp-trust';
                line.innerHTML = LOCK;
                line.appendChild(document.createTextNode(cfg.texts.trust));
                zone.appendChild(line);
            }
        });
    }

    /** «Pagar ahora · 124,98 €» en el botón final */
    function payButton() {
        var btn = document.querySelector('#payment-confirmation button');
        var total = cartTotal();
        if (!btn || !total || !cfg.texts.payNow) {
            return;
        }
        var label = cfg.texts.payNow + ' · ' + total;
        if (btn.textContent.trim() !== label) {
            btn.textContent = label;
        }
    }

    /** El aviso de condiciones solo aparece si se intenta pagar sin estar listo */
    function paymentNotice() {
        document.addEventListener('click', function (e) {
            var zone = e.target.closest && e.target.closest('#payment-confirmation');
            var btn = zone && zone.querySelector('button');
            if (btn && btn.disabled) {
                document.body.classList.add('ckp-show-payment-alert');
            }
        });
    }

    /** Página del carrito en móvil: barra fija con total; se esconde cuando el botón real está a la vista */
    function mobileBar() {
        var bar = document.createElement('div');
        bar.className = 'ckp-mbar';
        bar.innerHTML = '<span class="ckp-mbar-total"></span><a class="ckp-btn ckp-btn--primary" href="#"></a>';
        document.body.appendChild(bar);
        document.body.classList.add('ckp-has-mbar');

        var watched = null;
        var io = 'IntersectionObserver' in window ? new IntersectionObserver(function (entries) {
            bar.classList.toggle('is-hidden', entries[0].isIntersecting);
        }) : null;

        function sync() {
            var real = document.querySelector('.cart-detailed-actions a, .cart-detailed-actions .btn');
            var total = cartTotal();
            bar.hidden = !real || !total;
            if (bar.hidden) {
                return;
            }
            setText(bar.querySelector('.ckp-mbar-total'), total);
            var link = bar.querySelector('a');
            link.href = real.getAttribute('href') || ps.urls.pages.order;
            setText(link, real.textContent.trim());
            if (io && watched !== real) {
                if (watched) {
                    io.unobserve(watched);
                }
                io.observe(real);
                watched = real;
            }
        }

        watchMain(sync);
        sync();
    }

    /** Escribir solo si cambia: si no, el vigilante de #main se dispararía a sí mismo sin fin */
    function setText(el, text) {
        if (el && el.textContent !== text) {
            el.textContent = text;
        }
    }

    function watchMain(fn) {
        var pending;
        new MutationObserver(function () {
            clearTimeout(pending);
            pending = setTimeout(fn, 50);
        }).observe(document.getElementById('main') || document.body, {childList: true, subtree: true, characterData: true});
    }

    /** Título de la página del carrito y del pago, si la tienda lo ha cambiado */
    function pageTitle(page) {
        var text = page === 'cart' ? cfg.texts.cartTitle : (page === 'checkout' ? cfg.texts.checkoutTitle : '');
        var title = document.querySelector('#main .page-title, #main h1');
        if (!text || !title) {
            return;
        }
        var inner = title.querySelector('span') || title;
        inner.textContent = text;
    }

    /* 3. Pago por pasos al estilo Shopify
       Solo el paso actual a la vista; arriba la ruta de pasos y una caja con lo ya
       elegido (contacto, dirección, envío) con «Cambiar». Los pasos son los del núcleo:
       «Cambiar» pulsa su título, como haría el cliente.
       ===================================================================== */

    function stepName(step) {
        var title = step.querySelector('.step-title');
        if (!title) {
            return '';
        }
        var clone = title.cloneNode(true);
        [].forEach.call(clone.querySelectorAll('.step-number, .step-edit, .done, i'), function (n) {
            n.remove();
        });
        return clone.textContent.replace(/\s+/g, ' ').trim();
    }

    function goToStep(step, event) {
        // El núcleo escucha los clics en cada paso: si este subiera hasta el paso actual, lo volvería a abrir
        if (event) {
            event.stopPropagation();
        }
        var title = step.querySelector('.step-title');
        if (title) {
            title.click();
        }
    }

    /** Lo ya elegido en un paso completado, en una línea */
    function stepSummary(step) {
        var t = cfg.texts;
        if (step.id === 'checkout-personal-information-step') {
            return {label: t.contact, value: (ps.customer && ps.customer.email) || ''};
        }
        if (step.id === 'checkout-addresses-step') {
            var address = step.querySelector('.address-item.selected .address');
            // El bloque está oculto (sin saltos en innerText): se parte por los <br> del formato de dirección
            return {label: t.shipTo, value: address ? address.innerHTML.split(/<br\s*\/?>/i).map(function (l) {
                return new DOMParser().parseFromString(l, 'text/html').body.textContent.trim();
            }).filter(Boolean).join(', ') : ''};
        }
        if (step.id === 'checkout-delivery-step') {
            var radio = step.querySelector('.delivery-option input[type="radio"]:checked');
            var option = radio && radio.closest('.delivery-option');
            var name = option && option.querySelector('.carrier-name');
            var price = option && option.querySelector('.carrier-price');
            return {label: t.method, value: [name && name.textContent.trim(), price && price.textContent.trim()].filter(Boolean).join(' · ')};
        }
        return {label: stepName(step), value: ''};
    }

    function link(text, onClick) {
        var a = document.createElement('button');
        a.type = 'button';
        a.className = 'ckp-link';
        a.textContent = text;
        a.addEventListener('click', onClick);
        return a;
    }

    var renderedKey = '';

    function renderSteps() {
        var steps = [].slice.call(document.querySelectorAll('section.checkout-step'));
        var current = document.querySelector('section.checkout-step.-current');
        if (!steps.length || !current) {
            return;
        }
        var index = steps.indexOf(current);
        var summaries = steps.slice(0, index).map(stepSummary);
        var key = index + JSON.stringify(summaries);
        if (key === renderedKey && document.querySelector('.ckp-crumbs')) {
            return;
        }
        renderedKey = key;

        // Ruta: Carrito › Paso 1 › Paso 2 …
        var crumbs = document.querySelector('.ckp-crumbs') || document.createElement('nav');
        crumbs.className = 'ckp-crumbs';
        crumbs.setAttribute('aria-label', 'Checkout');
        crumbs.innerHTML = '';
        var cart = document.createElement('button');
        cart.type = 'button';
        cart.className = 'ckp-link';
        cart.textContent = cfg.texts.cart;
        cart.addEventListener('click', function () {
            if (cfg.drawer) {
                open();
            } else {
                window.location.href = ps.urls.pages.cart + '?action=show';
            }
        });
        crumbs.appendChild(cart);
        steps.forEach(function (step, i) {
            var item;
            // Atrás, o adelante si ese paso ya está completo (se vuelve a él sin rehacer nada)
            if (i !== index && step.classList.contains('-reachable') && (i < index || step.classList.contains('-complete'))) {
                item = link(stepName(step), goToStep.bind(null, step));
            } else {
                item = document.createElement('span');
                item.textContent = stepName(step);
                if (i === index) {
                    item.setAttribute('aria-current', 'step');
                }
            }
            crumbs.appendChild(item);
        });

        // Caja con lo ya elegido
        var review = document.querySelector('.ckp-review') || document.createElement('div');
        review.className = 'ckp-review';
        review.innerHTML = '';
        steps.slice(0, index).forEach(function (step, i) {
            var s = summaries[i];
            var row = document.createElement('div');
            row.className = 'ckp-review-row';
            var label = document.createElement('span');
            label.className = 'ckp-review-label';
            label.textContent = s.label;
            var value = document.createElement('span');
            value.className = 'ckp-review-value';
            value.textContent = s.value;
            row.appendChild(label);
            row.appendChild(value);
            row.appendChild(link(cfg.texts.change, goToStep.bind(null, step)));
            review.appendChild(row);
        });
        review.hidden = index === 0;

        // «‹ Volver a …» al final del paso
        var back = document.querySelector('.ckp-back') || document.createElement('div');
        back.className = 'ckp-back';
        back.innerHTML = '';
        // Paso sin botón propio (p. ej. «Datos personales» con la sesión iniciada): sin esto no hay salida
        var next = steps[index + 1];
        var hasSubmit = current.querySelector('.content button[type="submit"], .content .continue, #payment-confirmation');
        if (!hasSubmit && next && next.classList.contains('-reachable')) {
            var go = document.createElement('button');
            go.type = 'button';
            go.className = 'btn btn-primary continue ckp-next';
            go.textContent = cfg.texts.continueTo.replace('{step}', stepName(next));
            go.addEventListener('click', goToStep.bind(null, next));
            back.appendChild(go);
        }
        if (index > 0) {
            back.appendChild(link('‹ ' + cfg.texts.backTo.replace('{step}', stepName(steps[index - 1])), goToStep.bind(null, steps[index - 1])));
        }

        var first = steps[0];
        first.parentNode.insertBefore(crumbs, first);
        first.parentNode.insertBefore(review, first);
        current.appendChild(back);
        document.body.classList.add('ckp-steps');
    }

    /**
     * Lo que pintan los módulos en displayAfterCarrier (casillas de aviso, etc.) va fuera del
     * formulario y debajo de «Continuar»: se sube encima del botón, que queda el último.
     */
    function afterCarrierAboveButton() {
        var hook = document.getElementById('hook-display-after-carrier');
        var btn = document.querySelector('#js-delivery button.continue');
        if (hook && btn && hook.textContent.trim() !== ''
            && (btn.compareDocumentPosition(hook) & Node.DOCUMENT_POSITION_FOLLOWING)) {
            btn.parentNode.insertBefore(hook, btn);
        }
    }

    /** Móvil: el resumen del pedido plegado arriba, con el total, como en Shopify */
    function summaryToggle() {
        var column = document.querySelector('.cart-grid-right');
        if (!column || column.querySelector('.ckp-summary-toggle')) {
            return;
        }
        var btn = document.createElement('button');
        btn.type = 'button';
        btn.className = 'ckp-summary-toggle';
        btn.setAttribute('aria-expanded', 'false');
        btn.innerHTML = '<span class="ckp-summary-label"></span><strong class="ckp-summary-total"></strong>';
        btn.addEventListener('click', function () {
            var isOpen = column.classList.toggle('is-open');
            btn.setAttribute('aria-expanded', String(isOpen));
            sync();
        });
        column.insertBefore(btn, column.firstChild);

        function sync() {
            setText(btn.querySelector('.ckp-summary-label'), column.classList.contains('is-open') ? cfg.texts.summaryHide : cfg.texts.summaryShow);
            setText(btn.querySelector('.ckp-summary-total'), cartTotal());
        }
        sync();
        watchMain(sync);
    }

    /** Cantidad como globo sobre la foto, igual que Shopify */
    function summaryBadges() {
        [].forEach.call(document.querySelectorAll('.cart-summary-product'), function (item) {
            var qty = item.querySelector('.product-quantity');
            var img = item.querySelector('.media-left');
            if (!qty || !img || img.querySelector('.ckp-badge')) {
                return;
            }
            var badge = document.createElement('span');
            badge.className = 'ckp-badge';
            badge.textContent = qty.textContent.replace(/[^\d]/g, '') || '1';
            img.appendChild(badge);
        });
    }

    /** Columna gris del resumen hasta el borde derecho: se mide dónde empieza */
    function splitBackground() {
        var column = document.querySelector('.cart-grid-right');
        if (!column) {
            return;
        }
        var set = function () {
            var left = column.getBoundingClientRect().left;
            document.documentElement.style.setProperty('--ckp-split', Math.round(left) + 'px');
        };
        set();
        window.addEventListener('resize', set);
    }

    /**
     * Bajo «Transporte» en el resumen del pago: «Te faltan X para el envío gratis», con el mismo
     * cálculo que la barra (el envío gratis cuenta después de descuentos y puede no cuadrar a simple vista)
     */
    var hint = null;

    var TRUCK = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M1 4h13v12H1zM14 8h4l4 4v4h-8z"/><circle cx="5.5" cy="18.5" r="2"/><circle cx="17.5" cy="18.5" r="2"/></svg>';

    function placeShippingHint() {
        var line = document.getElementById('cart-subtotal-shipping');
        var box = document.querySelector('.ckp-ship-hint');
        if (!hint || !line) {
            if (box) {
                box.remove();
            }
            return;
        }
        if (!box) {
            box = document.createElement('div');
            box.className = 'ckp-ship-hint';
            box.innerHTML = '<div class="ckp-ship-hint-head"><span class="ckp-ship-hint-icon">' + TRUCK + '</span>'
                + '<span class="ckp-ship-hint-body"><span class="ckp-ship-hint-text"></span>'
                + '<span class="ckp-ship-hint-bar"><span></span></span></span></div>'
                + '<ul class="ckp-ship-hint-reco"></ul>';
            box.addEventListener('click', onHintAdd);
        }
        renderHintReco(box.querySelector('.ckp-ship-hint-reco'));
        if (box.previousElementSibling !== line) {
            line.parentNode.insertBefore(box, line.nextSibling);
        }
        // «Te faltan {amount}…» con el importe en negrita, sin meter HTML de fuera
        var parts = hint.text.split('{amount}');
        var text = box.querySelector('.ckp-ship-hint-text');
        if (text.getAttribute('data-key') !== hint.amount) {
            text.textContent = '';
            parts.forEach(function (part, i) {
                if (i > 0) {
                    var strong = document.createElement('strong');
                    strong.textContent = hint.amount;
                    text.appendChild(strong);
                }
                text.appendChild(document.createTextNode(part));
            });
            text.setAttribute('data-key', hint.amount);
        }
        var fill = box.querySelector('.ckp-ship-hint-bar span');
        if (fill.style.width !== hint.percent + '%') {
            fill.style.width = hint.percent + '%';
        }
    }

    /** Sugerencias para llegar al envío gratis sin salir del pago */
    function renderHintReco(list) {
        var key = (hint.reco || []).map(function (r) {
            return r.id_product;
        }).join(',');
        if (list.getAttribute('data-key') === key) {
            return;
        }
        list.setAttribute('data-key', key);
        list.textContent = '';
        (hint.reco || []).forEach(function (r) {
            var li = document.createElement('li');
            li.className = 'ckp-ship-hint-item';
            var img = document.createElement('img');
            img.src = r.image;
            img.alt = '';
            var name = document.createElement('span');
            name.className = 'ckp-ship-hint-name';
            name.textContent = r.name;
            var price = document.createElement('span');
            price.className = 'ckp-ship-hint-price';
            price.textContent = r.price;
            var btn = document.createElement('button');
            btn.type = 'button';
            btn.className = 'ckp-link ckp-ship-hint-add';
            btn.setAttribute('data-id-product', r.id_product);
            btn.setAttribute('data-id-product-attribute', r.id_product_attribute);
            btn.textContent = hint.add + '+';
            if (r.image) {
                li.appendChild(img);
            }
            li.appendChild(name);
            li.appendChild(price);
            li.appendChild(btn);
            list.appendChild(li);
        });
        list.hidden = !list.children.length;
    }

    /** Añade al carrito con el controlador del núcleo y recarga el pago con todo recalculado */
    function onHintAdd(e) {
        var btn = e.target.closest && e.target.closest('.ckp-ship-hint-add');
        if (!btn || btn.disabled) {
            return;
        }
        btn.disabled = true;
        var body = new URLSearchParams();
        body.append('token', ps.static_token);
        body.append('ajax', '1');
        body.append('action', 'update');
        body.append('add', '1');
        body.append('qty', '1');
        body.append('id_product', btn.getAttribute('data-id-product'));
        body.append('id_product_attribute', btn.getAttribute('data-id-product-attribute') || '0');
        fetch(ps.urls.pages.cart, {
            method: 'POST',
            credentials: 'same-origin',
            headers: {'Content-Type': 'application/x-www-form-urlencoded', Accept: 'application/json'},
            body: body.toString()
        }).then(function () {
            window.location.reload();
        }).catch(function () {
            btn.disabled = false;
        });
    }

    function loadShippingHint() {
        var url = cfg.url + (cfg.url.indexOf('?') === -1 ? '?' : '&') + 'ajax=1&action=drawer&_=' + Date.now();
        fetch(url, {credentials: 'same-origin', headers: {Accept: 'application/json'}})
            .then(function (r) {
                return r.json();
            })
            .then(function (data) {
                hint = data.shipping_hint || null;
                placeShippingHint();
            })
            .catch(function () {});
    }

    function initSteps() {
        document.body.classList.add('ckp-shopify');
        renderSteps();
        afterCarrierAboveButton();
        helpLine();
        loadShippingHint();
        ps.on('updatedCart', loadShippingHint);
        ps.on('updateCart', loadShippingHint);
        summaryToggle();
        summaryBadges();
        splitBackground();
        var pending;
        // El núcleo cambia de paso sin recargar (clases) o repinta el bloque (AJAX)
        new MutationObserver(function () {
            clearTimeout(pending);
            pending = setTimeout(function () {
                renderSteps();
                afterCarrierAboveButton();
                placeShippingHint();
                summaryBadges();
            }, 50);
        }).observe(document.getElementById('main') || document.body, {subtree: true, childList: true, attributes: true, attributeFilter: ['class']});
    }

    function initCheckout() {
        var page = document.body.id;
        pageTitle(page);
        if (page === 'checkout') {
            initSteps();
        }
        trustLines();
        payButton();
        watchMain(function () {
            trustLines();
            payButton();
        });
        if (page === 'checkout') {
            paymentNotice();
        }
        if (page === 'cart') {
            mobileBar();
        }
    }

    function start() {
        if (cfg.drawer) {
            initDrawer();
        }
        if (cfg.checkout) {
            initCheckout();
        }
    }

    // ps_shoppingcart lee showModal en su «ready»: hay que dejarlo puesto antes
    if (cfg.drawer) {
        ps.blockcart = ps.blockcart || {};
        ps.blockcart.showModal = function () {};
    }
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', start);
    } else {
        start();
    }
}());
