<?php

if (!defined('ABSPATH')) { exit; }

class AIEO_DMM_Product_Archive_Card extends AIEO_DMM_Module_Base {

    
    const OPTION_KEY = 'aieo_dmm_archive_card_layout';

    public function get_id()       { return 'product_archive_card'; }
    public function get_label()    { return __('Product Archive Cards', 'ai-eshop-optimizer'); }
    public function get_priority() { return 3; } 
    public function get_group()    { return 'visuals'; }

    public function register_hooks() {
        add_action('wp_ajax_aieo_dmm_archive_card_save', array($this, 'ajax_save'));
        add_action('wp_enqueue_scripts', array($this, 'enqueue_layout_css'));
    }

    
    public function is_active() { return true; }

    
    public static function element_catalog() {
        return array(
            'image'      => array('label' => __('Product image', 'ai-eshop-optimizer'),    'sel' => '.wp-block-woocommerce-product-image'),
            'title'      => array('label' => __('Product title', 'ai-eshop-optimizer'),    'sel' => '.wp-block-post-title'),
            'price'      => array('label' => __('Price', 'ai-eshop-optimizer'),            'sel' => '.wp-block-woocommerce-product-price'),
            
            
            
            'rating'     => array('label' => __('Star rating', 'ai-eshop-optimizer'),      'sel' => '.aieo-rating-stars--archive', 'pin' => true),
            'quick_view' => array('label' => __('Quick-View button (“Discover it”)', 'ai-eshop-optimizer'), 'sel' => '.aieo-quick-view-trigger', 'is_quick_view' => true, 'pin' => true),
            'buy'        => array('label' => __('Buy button', 'ai-eshop-optimizer'),       'sel' => '.wp-block-aieo-product-card-swatches', 'is_buy' => true, 'pin' => true),
        );
    }

    
    public static function default_order() {
        return array('image', 'title', 'price', 'rating', 'quick_view', 'buy');
    }

    
    public function get_settings() {
        $stored = get_option(self::OPTION_KEY, array());
        if (!is_array($stored)) { $stored = array(); }
        $catalog = self::element_catalog();
        $ids     = array_keys($catalog);

        
        $order = (isset($stored['order']) && is_array($stored['order'])) ? $stored['order'] : array();
        $order = array_values(array_intersect(array_map('strval', $order), $ids));
        foreach (self::default_order() as $id) { if (!in_array($id, $order, true)) { $order[] = $id; } }
        foreach ($ids as $id) { if (!in_array($id, $order, true)) { $order[] = $id; } }

        $sv = (isset($stored['visible']) && is_array($stored['visible'])) ? $stored['visible'] : array();
        $sd = (isset($stored['device'])  && is_array($stored['device']))  ? $stored['device']  : array();

        
        $qv_enabled_default = class_exists('AIEO_DMM_Settings') ? (bool) AIEO_DMM_Settings::get('side_cart_quick_view_enabled', false) : false;
        $qv_label_default   = class_exists('AIEO_DMM_Settings') ? (string) AIEO_DMM_Settings::get('side_cart_quick_view_label', '') : '';

        $out = array(
            'order'            => $order,
            'visible'          => array(),
            'device'           => array(),
            'pin_buy_bottom'   => array_key_exists('pin_buy_bottom', $stored) ? !empty($stored['pin_buy_bottom']) : true,
            
            
            
            'equalize_rows'    => array_key_exists('equalize_rows', $stored) ? !empty($stored['equalize_rows']) : true,
            'quick_view_label' => array_key_exists('quick_view_label', $stored) ? (string) $stored['quick_view_label'] : $qv_label_default,
            
            
            
            
            'title_width'      => array_key_exists('title_width', $stored)   ? (string) $stored['title_width']   : '70%',
            'title_width_m'    => array_key_exists('title_width_m', $stored) ? (string) $stored['title_width_m'] : '70%',
            'buy_width'        => array_key_exists('buy_width', $stored)     ? (string) $stored['buy_width']     : '70%',
            'buy_width_m'      => array_key_exists('buy_width_m', $stored)   ? (string) $stored['buy_width_m']   : '70%',
            
            
            'qv_width'         => array_key_exists('qv_width', $stored)      ? (string) $stored['qv_width']      : '70%',
            'qv_width_m'       => array_key_exists('qv_width_m', $stored)    ? (string) $stored['qv_width_m']    : '',
            
            'var_font'         => array_key_exists('var_font', $stored)     ? (string) $stored['var_font']     : '',
            'var_font_m'       => array_key_exists('var_font_m', $stored)   ? (string) $stored['var_font_m']   : '',
        );

        foreach ($catalog as $id => $meta) {
            if (array_key_exists($id, $sv)) {
                $out['visible'][$id] = !empty($sv[$id]);
            } elseif (!empty($meta['is_quick_view'])) {
                $out['visible'][$id] = $qv_enabled_default;
            } else {
                $out['visible'][$id] = true;
            }
            $dev = isset($sd[$id]) ? (string) $sd[$id] : '';
            if (!in_array($dev, array('all', 'desktop', 'mobile'), true)) {
                
                $dev = !empty($meta['is_quick_view']) ? 'desktop' : 'all';
            }
            $out['device'][$id] = $dev;
        }
        return $out;
    }

    
    private function sanitize_width($v) {
        $v = trim((string) $v);
        if ($v === '') { return ''; }
        if (is_numeric($v)) { return $v . 'px'; }
        return preg_match('/^[0-9]*\.?[0-9]+\s*(%|px|rem|em|vw|vh)$/i', $v) ? $v : '';
    }

    
    
    

    
    private function is_product_archive() {
        if (!function_exists('is_shop')) { return false; }
        if (is_shop()) { return true; }
        if (function_exists('is_product_taxonomy') && is_product_taxonomy()) { return true; }
        if (function_exists('is_post_type_archive') && is_post_type_archive('product')) { return true; }
        return false;
    }

    
    public function enqueue_layout_css() {
        if (is_admin() || !$this->is_product_archive()) { return; }

        $s       = $this->get_settings();
        $catalog = self::element_catalog();
        
        $scopes  = array('.wc-block-product-template', '.wp-block-woocommerce-product-template');

        $rules = array();

        
        
        foreach ($scopes as $sc) {
            $rules[] = $sc . ' > li{display:flex !important;flex-direction:column !important;height:100% !important;}';
        }

        $pinned_seen = false;
        foreach ($s['order'] as $i => $id) {
            if (!isset($catalog[$id])) { continue; }
            $sel = (string) $catalog[$id]['sel'];
            $ord = ($i + 1) * 10;

            foreach ($scopes as $sc) {
                $rules[] = sprintf('%s %s{order:%d !important;}', $sc, $sel, $ord);
            }

            
            
            
            
            
            
            
            if (!empty($s['pin_buy_bottom']) && !empty($catalog[$id]['pin'])) {
                
                
                
                
                
                
                foreach ($scopes as $sc) {
                    $rules[] = $pinned_seen
                        ? sprintf('%s %s{margin-top:10px !important;margin-bottom:0 !important;}', $sc, $sel)
                        : sprintf('%s %s{margin-top:auto !important;margin-bottom:0 !important;}', $sc, $sel);
                }
                $pinned_seen = true;
            }

            if (empty($s['visible'][$id])) {
                
                
                foreach ($scopes as $sc) {
                    $rules[] = sprintf('%s %s{display:none !important;}', $sc, $sel);
                }
                continue;
            }

            
            $dev = isset($s['device'][$id]) ? $s['device'][$id] : 'all';
            if ($dev === 'desktop') {
                foreach ($scopes as $sc) {
                    $rules[] = sprintf('@media (max-width:767px){%s %s{display:none !important;}}', $sc, $sel);
                }
            } elseif ($dev === 'mobile') {
                foreach ($scopes as $sc) {
                    $rules[] = sprintf('@media (min-width:768px){%s %s{display:none !important;}}', $sc, $sel);
                }
            }
        }

        
        
        
        
        
        
        
        
        $title_sel = '.wp-block-post-title';
        $buy_box   = '.wp-block-aieo-product-card-swatches';
        $buy_btn   = $buy_box . ' .aieo-archive-add-to-cart';
        $qv_sel    = '.aieo-quick-view-trigger';
        $var_sel   = $buy_box . ' .om-variation-item';
        $tw  = trim((string) $s['title_width']);  $twm = trim((string) $s['title_width_m']);
        $bw  = trim((string) $s['buy_width']);    $bwm = trim((string) $s['buy_width_m']);
        $qw  = trim((string) $s['qv_width']);     $qwm = trim((string) $s['qv_width_m']);
        $vf  = trim((string) $s['var_font']);     $vfm = trim((string) $s['var_font_m']);

        $buy_rule = function ($sc, $w) use ($buy_btn) {
            
            
            
            
            
            
            
            return $sc . ' ' . $buy_btn . '{display:flex !important;align-items:center !important;justify-content:center !important;width:' . $w . ' !important;margin-inline:auto !important;box-sizing:border-box !important;text-align:center !important;line-height:1 !important;padding-top:calc(var(--aieo-btn-archive-pad-t, 8px) + 0.1em) !important;}';
        };

        $mobile = array();
        foreach ($scopes as $sc) {
            if ($tw !== '') { $rules[] = $sc . ' ' . $title_sel . '{max-width:' . $tw . ' !important;margin-inline:auto !important;}'; }
            
            
            
            
            
            if ($bw !== '' || $bwm !== '') {
                $rules[] = $sc . ' ' . $buy_box . '{width:100% !important;box-sizing:border-box !important;}';
                $rules[] = $sc . ' ' . $buy_box . ' .om-product-swatches--archive{width:100% !important;}';

                
                
                
                
                $arc = $sc . ' ' . $buy_box . ' .om-product-swatches--archive';
                $svf = ($vf !== '') ? $vf : '12px';
                $rules[] = $arc . ' .om-variation-type-button{justify-content:center !important;}';
                $rules[] = $arc . ' .om-variation-type-button a{font-size:' . $svf . ' !important;line-height:1.1 !important;border-radius:0 !important;padding:5px 8px !important;}';

                
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                $rules[] = $arc . ' .variations_form{margin:0 !important;padding:0 !important;}';
                $rules[] = $arc . ' .single_variation_wrap{display:none !important;}';
                $rules[] = $arc . ' .reset_variations_alert{display:none !important;}';

                
                
                
                
                
                
                
                
                $img = $arc . ':has(.om-variation-type-image)';
                $clr = $arc . ':has(.om-variation-type-color)';
                $rules[] = $img . ' .variations_form,' . $clr . ' .variations_form{height:0 !important;min-height:0 !important;overflow:visible !important;}';
                $rules[] = $img . ' .variations,' . $clr . ' .variations{height:0 !important;}';

                
                
                
                
                $rules[] = $arc . ' .variations tr:has(.om-variation-type-button){margin-bottom:10px !important;}';
            }
            if ($bw !== '') { $rules[] = $buy_rule($sc, $bw); }
            if ($qw !== '') { $rules[] = $sc . ' ' . $qv_sel . '{width:' . $qw . ' !important;margin-inline:auto !important;box-sizing:border-box !important;}'; }
            if ($vf !== '') { $rules[] = $sc . ' ' . $var_sel . '{font-size:' . $vf . ' !important;}'; }
            if ($twm !== '') { $mobile[] = $sc . ' ' . $title_sel . '{max-width:' . $twm . ' !important;margin-inline:auto !important;}'; }
            if ($bwm !== '') { $mobile[] = $buy_rule($sc, $bwm); }
            if ($qwm !== '') { $mobile[] = $sc . ' ' . $qv_sel . '{width:' . $qwm . ' !important;margin-inline:auto !important;box-sizing:border-box !important;}'; }
            if ($vfm !== '') { $mobile[] = $sc . ' ' . $var_sel . '{font-size:' . $vfm . ' !important;}'; }
        }
        if (!empty($mobile)) {
            $rules[] = '@media (max-width:767px){' . implode('', $mobile) . '}';
        }

        
        
        
        
        if (!empty($s['equalize_rows'])) {
            foreach ($scopes as $sc) {
                $rules[] = $sc . ' .wp-block-woocommerce-product-price{display:flex !important;flex-direction:column !important;justify-content:center !important;align-items:center !important;}';
            }
        }

        $css = implode('', $rules);
        wp_register_style('aieo-dmm-archive-card', false, array(), defined('AIEO_VERSION') ? AIEO_VERSION : '1.0');
        wp_enqueue_style('aieo-dmm-archive-card');
        wp_add_inline_style('aieo-dmm-archive-card', $css);

        if (!empty($s['equalize_rows'])) {
            wp_register_script('aieo-dmm-archive-card', false, array(), defined('AIEO_VERSION') ? AIEO_VERSION : '1.0', true);
            wp_enqueue_script('aieo-dmm-archive-card');
            wp_add_inline_script('aieo-dmm-archive-card', $this->equalize_js());
        }
    }

    
    private function equalize_js() {
        return <<<'JS'
(function(){
    "use strict";
    var SEL = [".wp-block-post-title", ".wp-block-woocommerce-product-price", ".aieo-rating-stars--archive"];
    var GRIDS = ".wc-block-product-template, .wp-block-woocommerce-product-template";
    // Anchor the absolute-positioned image-swatch column to the product image's
    // actual vertical centre. The theme pins it to 25% of the CARD, which drifts
    // down into the title as the card grows (longer titles) — so the "+N" tail
    // spilled past the image. offsetTop/offsetHeight are both relative to the
    // position:relative card <li>, so this re-centres it on the image regardless
    // of card height.
    function centerSwatchColumns(li){
        var imgCol = li.querySelector(".om-product-swatches--archive .om-variation-type-image");
        if (!imgCol) { return; }
        var tr = imgCol.closest("tr");
        var img = li.querySelector(".wp-block-woocommerce-product-image");
        if (!tr || !img) { return; }
        var h = img.offsetHeight;
        if (h > 0) { tr.style.top = Math.round(img.offsetTop + h / 2) + "px"; }
    }
    function run(){
        document.querySelectorAll(GRIDS).forEach(function(grid){
            var cards = Array.prototype.filter.call(grid.children, function(n){ return n.tagName === "LI"; });
            if (!cards.length) { return; }
            cards.forEach(function(li){ SEL.forEach(function(s){ var el = li.querySelector(s); if (el) { el.style.minHeight = ""; } }); });
            var rows = {};
            cards.forEach(function(li){ var k = Math.round(li.offsetTop); (rows[k] = rows[k] || []).push(li); });
            Object.keys(rows).forEach(function(k){
                var row = rows[k];
                SEL.forEach(function(s){
                    var max = 0;
                    row.forEach(function(li){ var el = li.querySelector(s); if (el) { var h = el.offsetHeight; if (h > max) { max = h; } } });
                    if (max > 0) { row.forEach(function(li){ var el = li.querySelector(s); if (el) { el.style.minHeight = max + "px"; } }); }
                });
            });
            cards.forEach(centerSwatchColumns);
        });
    }
    var t;
    function schedule(){ clearTimeout(t); t = setTimeout(run, 60); }
    if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", run); } else { run(); }
    window.addEventListener("load", run);
    window.addEventListener("resize", schedule);
    if (document.fonts && document.fonts.ready && document.fonts.ready.then) { document.fonts.ready.then(run); }
    if (window.MutationObserver) {
        document.querySelectorAll(GRIDS).forEach(function(grid){
            try { new MutationObserver(schedule).observe(grid, { childList: true }); } catch (e) {}
        });
    }
})();
JS;
    }

    
    
    

    public function ajax_save() {
        AIEO_DMM::verify_ajax_request();
        $catalog = self::element_catalog();
        $allowed = array_keys($catalog);

        
        $raw = isset($_POST['order']) ? wp_unslash($_POST['order']) : array();
        if (!is_array($raw)) { $raw = array(); }
        $order = array();
        foreach ($raw as $id) {
            $id = sanitize_key($id);
            if (in_array($id, $allowed, true) && !in_array($id, $order, true)) { $order[] = $id; }
        }
        if (empty($order)) { $order = self::default_order(); }

        
        $rawvis = (isset($_POST['visible']) && is_array($_POST['visible'])) ? wp_unslash($_POST['visible']) : array();
        $rawdev = (isset($_POST['device'])  && is_array($_POST['device']))  ? wp_unslash($_POST['device'])  : array();
        $visible = array();
        $device  = array();
        foreach ($allowed as $id) {
            $visible[$id] = !empty($rawvis[$id]);
            $dev = isset($rawdev[$id]) ? sanitize_key((string) $rawdev[$id]) : 'all';
            $device[$id]  = in_array($dev, array('all', 'desktop', 'mobile'), true) ? $dev : 'all';
        }

        $pin      = !empty($_POST['pin_buy_bottom']);
        $equalize = !empty($_POST['equalize_rows']);
        $qv_label = isset($_POST['quick_view_label']) ? sanitize_text_field(wp_unslash((string) $_POST['quick_view_label'])) : '';

        
        $tw  = $this->sanitize_width(isset($_POST['title_width'])   ? wp_unslash((string) $_POST['title_width'])   : '');
        $twm = $this->sanitize_width(isset($_POST['title_width_m']) ? wp_unslash((string) $_POST['title_width_m']) : '');
        $bw  = $this->sanitize_width(isset($_POST['buy_width'])     ? wp_unslash((string) $_POST['buy_width'])     : '');
        $bwm = $this->sanitize_width(isset($_POST['buy_width_m'])   ? wp_unslash((string) $_POST['buy_width_m'])   : '');
        $qw  = $this->sanitize_width(isset($_POST['qv_width'])      ? wp_unslash((string) $_POST['qv_width'])      : '');
        $qwm = $this->sanitize_width(isset($_POST['qv_width_m'])    ? wp_unslash((string) $_POST['qv_width_m'])    : '');
        $vf  = $this->sanitize_width(isset($_POST['var_font'])      ? wp_unslash((string) $_POST['var_font'])      : '');
        $vfm = $this->sanitize_width(isset($_POST['var_font_m'])    ? wp_unslash((string) $_POST['var_font_m'])    : '');

        update_option(self::OPTION_KEY, array(
            'order'            => $order,
            'visible'          => $visible,
            'device'           => $device,
            'pin_buy_bottom'   => $pin,
            'equalize_rows'    => $equalize,
            'quick_view_label' => $qv_label,
            'title_width'      => $tw,
            'title_width_m'    => $twm,
            'buy_width'        => $bw,
            'buy_width_m'      => $bwm,
            'qv_width'         => $qw,
            'qv_width_m'       => $qwm,
            'var_font'         => $vf,
            'var_font_m'       => $vfm,
        ), false);

        
        
        
        
        if (class_exists('AIEO_DMM_Settings')) {
            $patch = array('side_cart_quick_view_enabled' => !empty($visible['quick_view']));
            if ($qv_label !== '') { $patch['side_cart_quick_view_label'] = $qv_label; }
            AIEO_DMM_Settings::update($patch);
        }

        wp_send_json_success(array(
            'order'   => $order,
            'message' => __('Archive card layout saved.', 'ai-eshop-optimizer'),
        ));
    }

    
    
    

    public function render_subtab() {
        $s       = $this->get_settings();
        $catalog = self::element_catalog();
        $nonce   = wp_create_nonce(AIEO_DMM::NONCE_ACTION);
        $ajax    = admin_url('admin-ajax.php');

        $device_labels = array(
            'all'     => __('Desktop + mobile', 'ai-eshop-optimizer'),
            'desktop' => __('Desktop only', 'ai-eshop-optimizer'),
            'mobile'  => __('Mobile only', 'ai-eshop-optimizer'),
        );

        echo '<div class="aieo-dmm-section">';
        echo '<h2>' . esc_html__('Product Archive Cards', 'ai-eshop-optimizer') . '</h2>';
        echo '<p class="description" style="max-width:860px;">'
            . esc_html__('Lay out the product cards on your shop, category, tag and brand archives — the same way the single-product page is managed. Drag to set the vertical ORDER of each element, tick to SHOW or hide it, and choose whether it appears on desktop, mobile, or both. The buy button can be pinned to the bottom so cards in a row stay equal-height and their buttons line up regardless of title length.', 'ai-eshop-optimizer')
            . '</p>';

        
        echo '<div class="aieo-dmm-card" style="margin-top:16px;max-width:720px;">';
        echo '<h3 style="margin-top:0;">' . esc_html__('Card behaviour', 'ai-eshop-optimizer') . '</h3>';
        echo '<label style="display:flex;align-items:center;gap:10px;margin:0 0 14px;">';
        echo '<input type="checkbox" id="aieo-arch-pin" ' . checked(!empty($s['pin_buy_bottom']), true, false) . '>';
        echo '<span><strong>' . esc_html__('Pin the stars + buy button to the bottom of each card', 'ai-eshop-optimizer') . '</strong><br>';
        echo '<span class="description">' . esc_html__('The star rating and the buy button drop together to the card bottom, so they line up across a row even when titles differ in length.', 'ai-eshop-optimizer') . '</span></span>';
        echo '</label>';
        echo '<label style="display:flex;align-items:center;gap:10px;margin:0 0 14px;">';
        echo '<input type="checkbox" id="aieo-arch-equalize" ' . checked(!empty($s['equalize_rows']), true, false) . '>';
        echo '<span><strong>' . esc_html__('Equalize title &amp; price heights across each row', 'ai-eshop-optimizer') . '</strong><br>';
        echo '<span class="description">' . esc_html__('For the products sitting in the same row, the titles share one height (so they end together) and the prices share one band — a single price is vertically centred where a neighbour has a was/now sale price. Keeps the whole row visually level.', 'ai-eshop-optimizer') . '</span></span>';
        echo '</label>';
        echo '<p style="margin:0 0 16px;"><label for="aieo-arch-qv-label"><strong>' . esc_html__('Quick-View button label', 'ai-eshop-optimizer') . '</strong></label><br>';
        echo '<input type="text" id="aieo-arch-qv-label" value="' . esc_attr($s['quick_view_label']) . '" placeholder="' . esc_attr__('Discover it', 'ai-eshop-optimizer') . '" style="width:280px;margin-top:4px;">';
        echo '<br><span class="description">' . esc_html__('Text on the Quick-View button (leave blank for the default). Toggle the button itself on/off in the list below.', 'ai-eshop-optimizer') . '</span></p>';

        
        echo '<p style="margin:0;"><strong>' . esc_html__('Sizes', 'ai-eshop-optimizer') . '</strong><br>';
        echo '<span class="description">' . esc_html__('Element sizes (e.g. 70%, 60%, 220px, 13px), centred where applicable. Leave blank for the natural size. The buy-button width applies to BOTH the simple “Αγορά” and the variable “see options” button, so they harmonise — set the Quick-View to the same value for a fully matched stack.', 'ai-eshop-optimizer') . '</span></p>';
        echo '<table class="form-table" style="margin-top:2px;"><tbody>';
        $width_rows = array(
            array('id' => 'title',   'label' => __('Product title (max-width)', 'ai-eshop-optimizer'),    'd' => $s['title_width'], 'm' => $s['title_width_m'], 'ph_d' => '70%',  'ph_m' => '70%'),
            array('id' => 'buy',     'label' => __('Buy button (width)', 'ai-eshop-optimizer'),            'd' => $s['buy_width'],   'm' => $s['buy_width_m'],   'ph_d' => '70%',  'ph_m' => '70%'),
            array('id' => 'qv',      'label' => __('Quick-View button (width)', 'ai-eshop-optimizer'),     'd' => $s['qv_width'],    'm' => $s['qv_width_m'],    'ph_d' => '70%',  'ph_m' => '—'),
            array('id' => 'varfont', 'label' => __('Variation buttons (font size)', 'ai-eshop-optimizer'),'d' => $s['var_font'],    'm' => $s['var_font_m'],    'ph_d' => '13px', 'ph_m' => '13px'),
        );
        foreach ($width_rows as $wr) {
            echo '<tr><th scope="row" style="padding:6px 0;font-weight:500;">' . esc_html($wr['label']) . '</th><td style="padding:6px 0;">';
            echo '<label style="font-size:11px;color:#6b7280;margin-right:14px;">' . esc_html__('Desktop', 'ai-eshop-optimizer') . ' <input type="text" class="aieo-arch-w" data-w="' . esc_attr($wr['id']) . '" data-dev="d" value="' . esc_attr($wr['d']) . '" placeholder="' . esc_attr($wr['ph_d']) . '" style="width:90px;"></label>';
            echo '<label style="font-size:11px;color:#6b7280;">' . esc_html__('Mobile', 'ai-eshop-optimizer') . ' <input type="text" class="aieo-arch-w" data-w="' . esc_attr($wr['id']) . '" data-dev="m" value="' . esc_attr($wr['m']) . '" placeholder="' . esc_attr($wr['ph_m']) . '" style="width:90px;"></label>';
            echo '</td></tr>';
        }
        echo '</tbody></table>';
        echo '</div>';

        
        echo '<div class="aieo-dmm-card" style="margin-top:16px;max-width:720px;">';
        echo '<h3 style="margin-top:0;">' . esc_html__('Card elements — order, visibility & device', 'ai-eshop-optimizer') . '</h3>';
        echo '<p class="description" style="margin-bottom:12px;">' . esc_html__('Drag the rows to reorder. Top of the list = top of the card.', 'ai-eshop-optimizer') . '</p>';

        echo '<ul id="aieo-arch-order-list" style="margin:0;padding:0;list-style:none;">';
        foreach ($s['order'] as $id) {
            if (!isset($catalog[$id])) { continue; }
            $L       = $catalog[$id];
            $vis     = !empty($s['visible'][$id]);
            $dev     = isset($s['device'][$id]) ? $s['device'][$id] : 'all';
            echo '<li class="aieo-arch-order-item" data-id="' . esc_attr($id) . '" style="display:flex;align-items:center;gap:12px;padding:10px 12px;margin:0 0 6px;background:#fff;border:1px solid #e5e7eb;border-radius:4px;cursor:grab;">';
            echo '<span class="dashicons dashicons-menu" style="color:#9ca3af;"></span>';
            echo '<strong style="flex:1;min-width:0;">' . esc_html($L['label']) . '</strong>';
            
            echo '<label style="display:inline-flex;align-items:center;gap:6px;font-size:12px;white-space:nowrap;">';
            echo '<input type="checkbox" class="aieo-arch-visible" data-id="' . esc_attr($id) . '" ' . checked($vis, true, false) . '> ' . esc_html__('Show', 'ai-eshop-optimizer');
            echo '</label>';
            
            echo '<select class="aieo-arch-device" data-id="' . esc_attr($id) . '" style="font-size:12px;max-width:160px;">';
            foreach ($device_labels as $dval => $dlabel) {
                echo '<option value="' . esc_attr($dval) . '"' . selected($dev, $dval, false) . '>' . esc_html($dlabel) . '</option>';
            }
            echo '</select>';
            echo '</li>';
        }
        echo '</ul>';
        echo '<p style="margin:12px 0 0;display:flex;align-items:center;gap:12px;">';
        echo '<button type="button" class="button button-primary" id="aieo-arch-save">' . esc_html__('Save layout', 'ai-eshop-optimizer') . '</button>';
        echo '<button type="button" class="button" id="aieo-arch-reset">' . esc_html__('Reset to default', 'ai-eshop-optimizer') . '</button>';
        echo '<span id="aieo-arch-status" style="color:#646970;font-size:13px;"></span>';
        echo '</p>';
        echo '</div>';

        echo '</div>'; 

        
        ?>
        <style>
            .aieo-arch-order-item.is-dragging { opacity: 0.4; }
            .aieo-arch-order-item.is-drag-over { border-color: #1565c0; background: #eff6ff; }
        </style>
        <script>
        (function(){
            var list   = document.getElementById("aieo-arch-order-list");
            var status = document.getElementById("aieo-arch-status");
            var saveBtn= document.getElementById("aieo-arch-save");
            var resetBtn=document.getElementById("aieo-arch-reset");
            var pin    = document.getElementById("aieo-arch-pin");
            var equalize = document.getElementById("aieo-arch-equalize");
            var qvLabel= document.getElementById("aieo-arch-qv-label");
            if (!list) { return; }
            var ajax   = <?php echo wp_json_encode($ajax); ?>;
            var nonce  = <?php echo wp_json_encode($nonce); ?>;
            var defaultOrder = <?php echo wp_json_encode(self::default_order()); ?>;

            // Native HTML5 drag-and-drop reorder.
            list.querySelectorAll(".aieo-arch-order-item").forEach(function(li){
                li.setAttribute("draggable", "true");
                li.addEventListener("dragstart", function(e){
                    li.classList.add("is-dragging");
                    e.dataTransfer.effectAllowed = "move";
                    e.dataTransfer.setData("text/plain", li.dataset.id);
                });
                li.addEventListener("dragend", function(){
                    li.classList.remove("is-dragging");
                    list.querySelectorAll(".aieo-arch-order-item").forEach(function(n){ n.classList.remove("is-drag-over"); });
                });
                li.addEventListener("dragover", function(e){
                    e.preventDefault();
                    e.dataTransfer.dropEffect = "move";
                    li.classList.add("is-drag-over");
                });
                li.addEventListener("dragleave", function(){ li.classList.remove("is-drag-over"); });
                li.addEventListener("drop", function(e){
                    e.preventDefault();
                    li.classList.remove("is-drag-over");
                    var dragging = list.querySelector(".aieo-arch-order-item.is-dragging");
                    if (!dragging || dragging === li) { return; }
                    var rect = li.getBoundingClientRect();
                    var above = (e.clientY - rect.top) < (rect.height / 2);
                    list.insertBefore(dragging, above ? li : li.nextSibling);
                });
            });
            // Don't start a drag when interacting with the row's controls.
            list.querySelectorAll(".aieo-arch-visible, .aieo-arch-device").forEach(function(c){
                c.addEventListener("mousedown", function(e){ e.stopPropagation(); });
            });

            function collect(order){
                var fd = new FormData();
                fd.set("action", "aieo_dmm_archive_card_save");
                fd.set("nonce", nonce);
                (order || Array.prototype.map.call(list.querySelectorAll(".aieo-arch-order-item"), function(n){ return n.dataset.id; }))
                    .forEach(function(id){ fd.append("order[]", id); });
                list.querySelectorAll(".aieo-arch-order-item").forEach(function(li){
                    var id = li.dataset.id;
                    var cb = li.querySelector(".aieo-arch-visible");
                    var sl = li.querySelector(".aieo-arch-device");
                    fd.set("visible[" + id + "]", (cb && cb.checked) ? "1" : "0");
                    fd.set("device[" + id + "]", sl ? sl.value : "all");
                });
                fd.set("pin_buy_bottom", (pin && pin.checked) ? "1" : "0");
                fd.set("equalize_rows", (equalize && equalize.checked) ? "1" : "0");
                fd.set("quick_view_label", qvLabel ? qvLabel.value : "");
                // Widths: data-w (title|buy|qv) + data-dev (d|m) → POST key.
                var keyMap = { title: "title_width", buy: "buy_width", qv: "qv_width", varfont: "var_font" };
                document.querySelectorAll(".aieo-arch-w").forEach(function(inp){
                    var base = keyMap[inp.dataset.w]; if (!base) { return; }
                    fd.set(inp.dataset.dev === "m" ? base + "_m" : base, inp.value);
                });
                return fd;
            }
            function save(order, done){
                if (status) { status.style.color = "#646970"; status.textContent = <?php echo wp_json_encode(__('Saving…', 'ai-eshop-optimizer')); ?>; }
                fetch(ajax, { method: "POST", credentials: "same-origin", body: collect(order) })
                    .then(function(r){ return r.json(); })
                    .then(function(j){
                        if (!status) { return; }
                        if (j && j.success) { status.style.color = "#15803d"; status.textContent = j.data.message; }
                        else { status.style.color = "#b91c1c"; status.textContent = (j && j.data && j.data.message) || <?php echo wp_json_encode(__('Save failed.', 'ai-eshop-optimizer')); ?>; }
                        if (done) { done(); }
                    })
                    .catch(function(){ if (status) { status.style.color = "#b91c1c"; status.textContent = "Network error."; } });
            }
            if (saveBtn) { saveBtn.addEventListener("click", function(){ save(null); }); }
            if (resetBtn) {
                resetBtn.addEventListener("click", function(){
                    save(defaultOrder, function(){ setTimeout(function(){ location.reload(); }, 400); });
                });
            }
        })();
        </script>
        <?php
    }
}
