<?php

/**
 * @package QuickStockForWooCommerce
 * @license GPL-2.0-or-later (https://www.gnu.org/licenses/gpl-2.0.html)
 */
if ( !defined( 'ABSPATH' ) ) {
    exit;
}
class QSFW_Settings_Page {
    const GENERAL_OPTION = 'qsfw_general_settings';

    /**
     * Default-Werte für die gebündelte Option qsfw_general_settings.
     * Konsumenten greifen über get_general_setting() darauf zu.
     */
    public static function general_defaults() {
        return array(
            'default_per_page'        => '50',
            'default_tab'             => 'all',
            'default_sort_all'        => 'newest',
            'default_sort_reorder'    => 'open_first',
            'lazy_load_images'        => 1,
            'row_density'             => 'normal',
            'sticky_header'           => 1,
            'group_variations'        => 1,
            'margin_threshold_high'   => 40,
            'margin_threshold_med'    => 20,
            'autosave_mode'           => 'auto',
            'bulk_confirm_mode'       => 'always',
            'bulk_confirm_threshold'  => 50,
            'csv_delimiter'           => ';',
            'csv_bom'                 => 1,
            'csv_date_format'         => 'Y-m-d',
            'currency_override'       => 0,
            'currency_symbol'         => '',
            'currency_position'       => 'left',
            'currency_decimal'        => '.',
            'currency_thousands'      => "'",
            'scanner_cache_ttl'       => 86400,
            'keyboard_shortcuts'      => 1,
            'log_enabled'             => 1,
            'log_retention_days'      => 90,
            'reorder_pdf_logo_id'     => 0,
            'reorder_pdf_title'       => '',
            'reorder_pdf_date_format' => 'locale',
            'pdf_columns'             => array(
                'sku',
                'supplier_sku',
                'title',
                'stock',
                'limit'
            ),
            'default_restock_target'  => 0,
            'reorder_sold_days'       => 14,
        );
    }

    /**
     * Liest einen einzelnen Wert aus der gebündelten Option mit Fallback
     * auf das Default-Array. Verhindert verstreute get_option()-Aufrufe.
     */
    public static function get_general_setting( $key, $default = null ) {
        static $cache = null;
        if ( $cache === null ) {
            $stored = get_option( self::GENERAL_OPTION, array() );
            $cache = ( is_array( $stored ) ? array_merge( self::general_defaults(), $stored ) : self::general_defaults() );
        }
        if ( array_key_exists( $key, $cache ) ) {
            return $cache[$key];
        }
        if ( $default !== null ) {
            return $default;
        }
        $d = self::general_defaults();
        return ( isset( $d[$key] ) ? $d[$key] : null );
    }

    public static function render() {
        self::process_columns_forms();
        self::process_general_forms();
        self::process_label_forms();
        // Preset-Formulare/-Aktionen laufen via admin_init
        // (QSFW_Presets::maybe_handle_settings_post / maybe_handle_tab_actions).
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- reine Auswahl des anzuzeigenden Einstellungs-Tabs
        $subtab = ( isset( $_REQUEST['settings_subtab'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['settings_subtab'] ) ) : 'general' );
        $subtab = ( in_array( $subtab, array(
            'presets',
            'custom_fields',
            'suppliers',
            'general',
            'labels'
        ), true ) ? $subtab : 'general' );
        $base = admin_url( 'admin.php?page=quickstock-for-woocommerce&mode=settings' );
        $url_pre = $base . '&settings_subtab=presets';
        $url_cf = $base . '&settings_subtab=custom_fields';
        $url_sup = $base . '&settings_subtab=suppliers';
        $url_gen = $base . '&settings_subtab=general';
        $url_lbl = $base . '&settings_subtab=labels';
        $sup_pro = ( qsfw_can_use( 'suppliers' ) ? '' : QSFW_Renderer::pro_tab_marker() );
        self::render_settings_shell_open( $subtab, array(
            'general'       => array(
                'url'   => $url_gen,
                'label' => __( 'General', 'quickstock-for-woocommerce' ),
                'icon'  => 'sliders',
            ),
            'custom_fields' => array(
                'url'   => $url_cf,
                'label' => __( 'Columns', 'quickstock-for-woocommerce' ),
                'icon'  => 'columns',
            ),
            'suppliers'     => array(
                'url'   => $url_sup,
                'label' => __( 'Suppliers', 'quickstock-for-woocommerce' ) . $sup_pro,
                'icon'  => 'truck',
            ),
            'labels'        => array(
                'url'   => $url_lbl,
                'label' => __( 'Labels', 'quickstock-for-woocommerce' ),
                'icon'  => 'tag',
            ),
            'presets'       => array(
                'url'   => $url_pre,
                'label' => __( 'Views', 'quickstock-for-woocommerce' ),
                'icon'  => 'bookmark',
            ),
        ) );
        if ( $subtab === 'suppliers' ) {
            echo '<div class="hb-settings-wrap">';
            self::render_suppliers_upsell();
            echo '</div>';
            self::render_settings_shell_close();
            return;
        }
        if ( $subtab === 'labels' ) {
            echo '<div class="hb-settings-wrap">';
            self::render_labels_section();
            echo '</div>';
            self::render_settings_shell_close();
            return;
        }
        if ( $subtab === 'general' ) {
            echo '<div class="hb-settings-wrap">';
            self::render_general_section();
            echo '</div>';
            self::render_settings_shell_close();
            return;
        }
        if ( $subtab === 'presets' ) {
            $all = QSFW_Columns::get_all();
            $groups = QSFW_Columns::get_groups();
            $enabled = QSFW_Columns::get_enabled();
            echo '<div class="hb-settings-wrap">';
            self::render_presets_section( $all, $groups, $enabled );
            echo '</div>';
            self::render_settings_shell_close();
            return;
        }
        echo '<div class="hb-settings-wrap">';
        self::render_columns_section();
        // Custom-Fields-Upsell nur in der Spaltenliste zeigen, nicht in der
        // Einzelspalten-Bearbeitung (dort gibt es nichts freizuschalten).
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- reiner Anzeigeparameter; dieser Zweig schreibt keinen Zustand
        if ( empty( $_REQUEST['edit_col'] ) ) {
            self::render_custom_fields_upsell();
        }
        echo '</div>';
        self::render_settings_shell_close();
    }

    private static function render_settings_shell_open( $active, $items ) {
        echo '<div class="qsfw-settings-shell">';
        echo '<aside class="qsfw-settings-sidebar">';
        echo '<div class="qsfw-settings-sidebar-head">';
        echo '<span class="qsfw-settings-icon-tile">';
        QSFW_Renderer::echo_icon( 'gear' );
        echo '</span>';
        echo '<span><strong>' . esc_html__( 'Settings', 'quickstock-for-woocommerce' ) . '</strong><small>for WooCommerce</small></span>';
        echo '</div>';
        echo '<nav class="qsfw-settings-subnav" aria-label="Settings">';
        foreach ( $items as $key => $item ) {
            $cls = ( $active === $key ? ' is-active' : '' );
            echo '<a class="qsfw-settings-subnav-item' . esc_attr( $cls ) . '" href="' . esc_url( $item['url'] ) . '">';
            QSFW_Renderer::echo_icon( $item['icon'] );
            echo '<span>' . wp_kses( $item['label'], array(
                'span' => array(
                    'class' => array(),
                ),
            ) ) . '</span>';
            echo '</a>';
        }
        echo '</nav>';
        echo '</aside>';
        echo '<main class="qsfw-settings-main">';
    }

    private static function render_settings_shell_close() {
        echo '</main></div>';
    }

    /* ===================================================================
     * SEKTION 3: ANSICHT-PRESETS
     * =================================================================== */
    private static function render_presets_section( $all, $groups, $enabled ) {
        $presets = QSFW_Presets::all();
        $defaults = QSFW_Presets::get_defaults();
        // Welches Preset wird gerade bearbeitet? ('new' = neues)
        // phpcs:disable WordPress.Security.NonceVerification.Recommended -- reine Auswahl eines Presets fuer die schreibfreie Bearbeitungsansicht
        $edit = ( isset( $_REQUEST['edit_preset'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['edit_preset'] ) ) : '' );
        // phpcs:enable WordPress.Security.NonceVerification.Recommended
        $editing = ( $edit === 'new' ? array(
            'name'          => '',
            'cols'          => array(),
            'sort'          => '',
            'per_page'      => '50',
            'status_filter' => array(
                'publish',
                'draft',
                'private',
                'pending'
            ),
        ) : QSFW_Presets::get( $edit ) );
        $edit_id = ( $edit !== 'new' && $editing ? $edit : '' );
        $base_url = admin_url( 'admin.php?page=quickstock-for-woocommerce&mode=settings&settings_subtab=presets' );
        $sort_labels = array(
            'open_first' => __( '📋 Open first', 'quickstock-for-woocommerce' ),
            'newest'     => __( '🆕 Newest first', 'quickstock-for-woocommerce' ),
            'stock_asc'  => __( 'Stock ↑', 'quickstock-for-woocommerce' ),
            'stock_desc' => __( 'Stock ↓', 'quickstock-for-woocommerce' ),
            'title_asc'  => __( 'Name A-Z', 'quickstock-for-woocommerce' ),
            'sku_asc'    => __( 'SKU ↑', 'quickstock-for-woocommerce' ),
        );
        $status_labels = array(
            'publish' => __( 'Published', 'quickstock-for-woocommerce' ),
            'draft'   => __( 'Draft', 'quickstock-for-woocommerce' ),
            'private' => __( 'Private', 'quickstock-for-woocommerce' ),
            'pending' => __( 'Pending', 'quickstock-for-woocommerce' ),
        );
        ?>
        <div class="hb-settings-intro" style="margin-top:40px;">
            <h2><?php 
        esc_html_e( 'View presets', 'quickstock-for-woocommerce' );
        ?></h2>
            <p><?php 
        echo wp_kses( __( 'Save complete views (columns + order + sort + per page + status) as named presets. These appear in the <strong>“View” dropdown</strong> inside QuickStock. Per tab you can set a <strong>default preset</strong> that loads automatically on tab switch.', 'quickstock-for-woocommerce' ), array(
            'strong' => array(),
        ) );
        ?></p>
        </div>

        <?php 
        // Ergebnis-Meldung nach Import (Transient, einmalig).
        $import_msg = get_transient( 'qsfw_preset_import_msg' );
        if ( is_array( $import_msg ) && !empty( $import_msg['text'] ) ) {
            delete_transient( 'qsfw_preset_import_msg' );
            $cls = ( $import_msg['type'] === 'success' ? 'notice-success' : 'notice-error' );
            echo '<div class="notice ' . esc_attr( $cls ) . ' is-dismissible"><p>' . esc_html( $import_msg['text'] ) . '</p></div>';
        }
        ?>

        <?php 
        if ( empty( $presets ) ) {
            ?>
            <div class="hb-empty-hint"><?php 
            esc_html_e( 'No presets yet.', 'quickstock-for-woocommerce' );
            ?></div>
        <?php 
        } else {
            ?>
            <div class="hb-preset-list">
                <?php 
            foreach ( $presets as $pid => $p ) {
                $is_def_all = $defaults['all'] === $pid;
                $is_def_reo = $defaults['reorder'] === $pid;
                $del_url = wp_nonce_url( $base_url . '&preset_delete=' . $pid, 'qsfw_preset_delete_' . $pid );
                ?>
                    <div class="hb-preset-card">
                        <div class="hb-preset-head">
                            <strong><?php 
                echo esc_html( $p['name'] );
                ?></strong>
                            <span class="hb-preset-actions">
                                <a class="button button-small" href="<?php 
                echo esc_url( $base_url . '&edit_preset=' . $pid );
                ?>">✏️ <?php 
                esc_html_e( 'Edit', 'quickstock-for-woocommerce' );
                ?></a>
                                <a class="button button-small hb-preset-delete" href="<?php 
                echo esc_url( $del_url );
                ?>">🗑</a>
                            </span>
                        </div>
                        <div class="hb-preset-chips">
                            <?php 
                $names = array();
                foreach ( (array) $p['cols'] as $ck ) {
                    if ( isset( $all[$ck] ) ) {
                        $names[] = $all[$ck]['label'];
                    }
                }
                echo ( $names ? esc_html( implode( ' · ', $names ) ) : '<em>' . esc_html__( 'No columns', 'quickstock-for-woocommerce' ) . '</em>' );
                ?>
                        </div>
                        <div class="hb-preset-meta">
                            <?php 
                esc_html_e( 'Sort:', 'quickstock-for-woocommerce' );
                ?> <?php 
                echo esc_html( ( isset( $sort_labels[$p['sort']] ) ? $sort_labels[$p['sort']] : '—' ) );
                ?>
                            · <?php 
                echo ( $p['per_page'] === 'all' ? esc_html__( 'All', 'quickstock-for-woocommerce' ) : esc_html( $p['per_page'] ) . '/' . esc_html__( 'page', 'quickstock-for-woocommerce' ) );
                ?>
                            · <?php 
                esc_html_e( 'Status:', 'quickstock-for-woocommerce' );
                ?> <?php 
                echo ( count( (array) $p['status_filter'] ) === 4 ? esc_html__( 'all', 'quickstock-for-woocommerce' ) : esc_html( count( (array) $p['status_filter'] ) ) . '/4' );
                ?>
                        </div>
                        <?php 
                if ( $is_def_all || $is_def_reo ) {
                    ?>
                            <div class="hb-preset-defaults">
                                <?php 
                    if ( $is_def_all ) {
                        ?><span class="hb-preset-badge">★ <?php 
                        esc_html_e( 'Default: 📦 All Products', 'quickstock-for-woocommerce' );
                        ?></span><?php 
                    }
                    ?>
                                <?php 
                    if ( $is_def_reo ) {
                        ?><span class="hb-preset-badge">★ <?php 
                        esc_html_e( 'Default: 📋 Reorder', 'quickstock-for-woocommerce' );
                        ?></span><?php 
                    }
                    ?>
                            </div>
                        <?php 
                }
                ?>
                    </div>
                <?php 
            }
            ?>
            </div>
        <?php 
        }
        ?>

        <?php 
        if ( !$editing ) {
            ?>
            <div class="hb-settings-actions">
                <a class="button button-primary" href="<?php 
            echo esc_url( $base_url . '&edit_preset=new' );
            ?>">➕ <?php 
            esc_html_e( 'New preset', 'quickstock-for-woocommerce' );
            ?></a>

                <?php 
            if ( !empty( $presets ) ) {
                ?>
                    <form method="get" action="<?php 
                echo esc_url( admin_url( 'admin.php' ) );
                ?>" style="display:inline-block;margin-left:8px;">
                        <input type="hidden" name="page" value="quickstock-for-woocommerce" />
                        <input type="hidden" name="mode" value="settings" />
                        <input type="hidden" name="settings_subtab" value="presets" />
                        <input type="hidden" name="preset_export" value="1" />
                        <?php 
                wp_nonce_field( 'qsfw_preset_export' );
                ?>
                        <button type="submit" class="button">⬇️ <?php 
                esc_html_e( 'Export presets (JSON)', 'quickstock-for-woocommerce' );
                ?></button>
                    </form>
                <?php 
            }
            ?>

                <form method="post" enctype="multipart/form-data" action="<?php 
            echo esc_url( admin_url( 'admin.php?page=quickstock-for-woocommerce&mode=settings&settings_subtab=presets' ) );
            ?>" style="display:inline-block;margin-left:8px;">
                    <input type="hidden" name="preset_import_submitted" value="1" />
                    <?php 
            wp_nonce_field( 'qsfw_preset_import' );
            ?>
                    <input type="file" name="preset_import_file" accept="application/json,.json" required />
                    <button type="submit" class="button">⬆️ <?php 
            esc_html_e( 'Import presets', 'quickstock-for-woocommerce' );
            ?></button>
                </form>
            </div>
        <?php 
        } else {
            // Spalten für den Editor: zuerst die im Preset (in Reihenfolge), dann restliche enabled
            $editor_keys = array();
            foreach ( (array) $editing['cols'] as $ck ) {
                if ( in_array( $ck, $enabled, true ) ) {
                    $editor_keys[] = $ck;
                }
            }
            foreach ( $enabled as $ck ) {
                if ( !in_array( $ck, $editor_keys, true ) ) {
                    $editor_keys[] = $ck;
                }
            }
            $preset_cols = (array) $editing['cols'];
            ?>
            <form method="post" action="<?php 
            echo esc_url( admin_url( 'admin.php?page=quickstock-for-woocommerce' ) );
            ?>" class="hb-preset-editor" id="hb-preset-form">
                <?php 
            wp_nonce_field( 'qsfw_preset_save' );
            ?>
                <input type="hidden" name="mode" value="settings" />
                <input type="hidden" name="settings_subtab" value="presets" />
                <input type="hidden" name="preset_submitted" value="1" />
                <input type="hidden" name="preset_id" value="<?php 
            echo esc_attr( $edit_id );
            ?>" />
                <input type="hidden" name="preset_cols" id="hb-preset-cols-input" value="<?php 
            echo esc_attr( implode( ',', array_values( array_intersect( $preset_cols, $enabled ) ) ) );
            ?>" />

                <h3><?php 
            echo ( $edit_id ? esc_html__( 'Edit preset', 'quickstock-for-woocommerce' ) : esc_html__( 'New preset', 'quickstock-for-woocommerce' ) );
            ?></h3>

                <p>
                    <label><strong><?php 
            esc_html_e( 'Name', 'quickstock-for-woocommerce' );
            ?></strong><br>
                    <input type="text" name="preset_name" value="<?php 
            echo esc_attr( $editing['name'] );
            ?>" class="regular-text" placeholder="<?php 
            esc_attr_e( 'e.g. Reorder', 'quickstock-for-woocommerce' );
            ?>" required /></label>
                </p>

                <p><strong><?php 
            esc_html_e( 'Columns & order', 'quickstock-for-woocommerce' );
            ?></strong> <span style="color:#777;"><?php 
            esc_html_e( '(drag to reorder, checkmark = visible)', 'quickstock-for-woocommerce' );
            ?></span></p>
                <?php 
            if ( empty( $editor_keys ) ) {
                ?>
                    <div class="hb-empty-hint"><?php 
                esc_html_e( 'No columns enabled in the library (see section 1).', 'quickstock-for-woocommerce' );
                ?></div>
                <?php 
            } else {
                ?>
                    <div class="hb-sortable-wrap">
                        <ul id="hb-preset-sortable" class="hb-sortable-list">
                            <?php 
                foreach ( $editor_keys as $key ) {
                    if ( !isset( $all[$key] ) ) {
                        continue;
                    }
                    $cfg = $all[$key];
                    $glabel = ( isset( $groups[$cfg['group']] ) ? $groups[$cfg['group']] : '' );
                    ?>
                                <li class="hb-sortable-item" data-key="<?php 
                    echo esc_attr( $key );
                    ?>">
                                    <span class="hb-drag-handle" title="<?php 
                    esc_attr_e( 'Drag to reorder', 'quickstock-for-woocommerce' );
                    ?>">⋮⋮</span>
                                    <label class="hb-preset-check-lbl"><input type="checkbox" class="hb-preset-check" <?php 
                    checked( in_array( $key, $preset_cols, true ) );
                    ?> /></label>
                                    <span class="hb-item-label"><?php 
                    echo esc_html( $cfg['label'] );
                    ?></span>
                                    <span class="hb-item-group"><?php 
                    echo esc_html( $glabel );
                    ?></span>
                                </li>
                            <?php 
                }
                ?>
                        </ul>
                    </div>
                <?php 
            }
            ?>

                <div class="hb-preset-controls">
                    <label><?php 
            esc_html_e( 'Sort', 'quickstock-for-woocommerce' );
            ?>
                        <select name="preset_sort">
                            <?php 
            foreach ( $sort_labels as $sk => $sl ) {
                ?>
                                <option value="<?php 
                echo esc_attr( $sk );
                ?>" <?php 
                selected( $editing['sort'], $sk );
                ?>><?php 
                echo esc_html( $sl );
                ?></option>
                            <?php 
            }
            ?>
                        </select>
                    </label>
                    <label><?php 
            esc_html_e( 'Per page', 'quickstock-for-woocommerce' );
            ?>
                        <select name="preset_per_page">
                            <?php 
            foreach ( array(
                '25',
                '50',
                '100',
                '200',
                'all'
            ) as $opt ) {
                if ( $opt === 'all' ) {
                    $lbl = __( 'All', 'quickstock-for-woocommerce' );
                } else {
                    /* translators: %s is a page size, e.g. "25" */
                    $lbl = sprintf( __( '%s / page', 'quickstock-for-woocommerce' ), $opt );
                }
                ?>
                                <option value="<?php 
                echo esc_attr( $opt );
                ?>" <?php 
                selected( $editing['per_page'], $opt );
                ?>><?php 
                echo esc_html( $lbl );
                ?></option>
                            <?php 
            }
            ?>
                        </select>
                    </label>
                    <details class="hb-dropdown">
                        <summary><?php 
            esc_html_e( 'Status:', 'quickstock-for-woocommerce' );
            ?> <?php 
            echo count( (array) $editing['status_filter'] );
            ?>/4</summary>
                        <div class="hb-dropdown-panel">
                            <?php 
            foreach ( $status_labels as $sk => $sl ) {
                ?>
                                <label><input type="checkbox" name="preset_status[]" value="<?php 
                echo esc_attr( $sk );
                ?>" <?php 
                checked( in_array( $sk, (array) $editing['status_filter'], true ) );
                ?> /> <?php 
                echo esc_html( $sl );
                ?></label>
                            <?php 
            }
            ?>
                        </div>
                    </details>
                </div>

                <fieldset class="hb-preset-default-box">
                    <legend><?php 
            esc_html_e( 'Use as default', 'quickstock-for-woocommerce' );
            ?></legend>
                    <label><input type="checkbox" name="preset_default_all" value="1" <?php 
            checked( $edit_id && QSFW_Presets::get_defaults()['all'] === $edit_id );
            ?> /> <?php 
            esc_html_e( '📦 Default for “All Products”', 'quickstock-for-woocommerce' );
            ?></label>
                    <label><input type="checkbox" name="preset_default_reorder" value="1" <?php 
            checked( $edit_id && QSFW_Presets::get_defaults()['reorder'] === $edit_id );
            ?> /> <?php 
            esc_html_e( '📋 Default for “Reorder”', 'quickstock-for-woocommerce' );
            ?></label>
                </fieldset>

                <div class="hb-settings-actions">
                    <button type="submit" class="button button-primary">💾 <?php 
            esc_html_e( 'Save preset', 'quickstock-for-woocommerce' );
            ?></button>
                    <a class="button button-secondary" href="<?php 
            echo esc_url( $base_url );
            ?>" style="margin-left:8px;"><?php 
            esc_html_e( 'Cancel', 'quickstock-for-woocommerce' );
            ?></a>
                </div>
            </form>
        <?php 
        }
    }

    /* ===================================================================
     * FORMULAR-VERARBEITUNG: CUSTOM FIELDS
     * =================================================================== */
    private static function process_columns_forms() {
        if ( !current_user_can( 'manage_woocommerce' ) ) {
            return;
        }
        if ( !isset( $_REQUEST['page'] ) || $_REQUEST['page'] !== 'quickstock-for-woocommerce' ) {
            return;
        }
        if ( !isset( $_REQUEST['settings_subtab'] ) || $_REQUEST['settings_subtab'] !== 'custom_fields' ) {
            return;
        }
        $base_url = admin_url( 'admin.php?page=quickstock-for-woocommerce&mode=settings&settings_subtab=custom_fields' );
        if ( !empty( $_REQUEST['col_submitted'] ) ) {
            check_admin_referer( 'qsfw_col_save' );
            $key = ( isset( $_REQUEST['col_key'] ) ? sanitize_key( wp_unslash( $_REQUEST['col_key'] ) ) : '' );
            $label = ( isset( $_REQUEST['col_label'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['col_label'] ) ) : '' );
            $width = ( isset( $_REQUEST['col_width'] ) ? preg_replace( '/[^0-9]/', '', sanitize_text_field( wp_unslash( $_REQUEST['col_width'] ) ) ) : '' );
            $all = QSFW_Columns::get_all();
            if ( $key !== '' && isset( $all[$key] ) && empty( $all[$key]['fixed'] ) ) {
                QSFW_Columns::set_override( $key, $label, $width );
            }
            wp_safe_redirect( $base_url );
            exit;
        }
        if ( !empty( $_REQUEST['enabled_submitted'] ) ) {
            check_admin_referer( 'qsfw_enabled_cols' );
            $all = QSFW_Columns::get_all();
            $allowed = array();
            foreach ( $all as $key => $cfg ) {
                if ( empty( $cfg['fixed'] ) ) {
                    $allowed[] = $key;
                }
            }
            $selected = ( isset( $_REQUEST['enabled_cols'] ) ? array_map( 'sanitize_text_field', (array) wp_unslash( $_REQUEST['enabled_cols'] ) ) : array() );
            update_option( 'qsfw_enabled_cols', array_values( array_intersect( $selected, $allowed ) ) );
            QSFW_Columns::invalidate_cache();
            wp_safe_redirect( $base_url );
            exit;
        }
    }

    private static function render_columns_section() {
        $all = QSFW_Columns::get_all();
        $enabled = QSFW_Columns::get_enabled();
        $base_url = admin_url( 'admin.php?page=quickstock-for-woocommerce&mode=settings&settings_subtab=custom_fields' );
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- reine Auswahl der schreibfreien Spalten-Bearbeitungsansicht
        $edit_key = ( isset( $_REQUEST['edit_col'] ) ? sanitize_key( wp_unslash( $_REQUEST['edit_col'] ) ) : '' );
        if ( $edit_key !== '' && isset( $all[$edit_key] ) && empty( $all[$edit_key]['fixed'] ) ) {
            $cfg = $all[$edit_key];
            ?>
            <div class="hb-settings-intro"><h2><?php 
            esc_html_e( 'Edit column', 'quickstock-for-woocommerce' );
            ?></h2></div>
            <form method="get" action="<?php 
            echo esc_url( admin_url( 'admin.php' ) );
            ?>" class="hb-cf-form">
                <input type="hidden" name="page" value="quickstock-for-woocommerce" />
                <input type="hidden" name="mode" value="settings" />
                <input type="hidden" name="settings_subtab" value="custom_fields" />
                <input type="hidden" name="col_submitted" value="1" />
                <input type="hidden" name="col_key" value="<?php 
            echo esc_attr( $edit_key );
            ?>" />
                <?php 
            wp_nonce_field( 'qsfw_col_save' );
            ?>
                <table class="form-table">
                    <tr><th scope="row"><label for="col_label"><?php 
            esc_html_e( 'Display name', 'quickstock-for-woocommerce' );
            ?></label></th><td><input type="text" id="col_label" name="col_label" class="regular-text" value="<?php 
            echo esc_attr( wp_strip_all_tags( str_replace( '<br>', ' ', $cfg['label'] ) ) );
            ?>" /></td></tr>
                    <tr><th scope="row"><label for="col_width"><?php 
            esc_html_e( 'Width (px)', 'quickstock-for-woocommerce' );
            ?></label></th><td><input type="number" id="col_width" name="col_width" min="0" value="<?php 
            echo esc_attr( $cfg['width'] );
            ?>" /><p class="description"><?php 
            esc_html_e( 'Empty = automatic width.', 'quickstock-for-woocommerce' );
            ?></p></td></tr>
                </table>
                <div class="hb-settings-actions"><button type="submit" class="button button-primary"><?php 
            esc_html_e( 'Save', 'quickstock-for-woocommerce' );
            ?></button> <a class="button button-secondary" href="<?php 
            echo esc_url( $base_url );
            ?>"><?php 
            esc_html_e( 'Cancel', 'quickstock-for-woocommerce' );
            ?></a></div>
            </form>
            <?php 
            return;
        }
        ?>
        <div class="hb-settings-intro">
            <h2><?php 
        esc_html_e( 'Manage columns', 'quickstock-for-woocommerce' );
        ?></h2>
            <p><?php 
        esc_html_e( 'Columns & order', 'quickstock-for-woocommerce' );
        ?></p>
        </div>
        <form method="get" action="<?php 
        echo esc_url( admin_url( 'admin.php' ) );
        ?>">
            <input type="hidden" name="page" value="quickstock-for-woocommerce" />
            <input type="hidden" name="mode" value="settings" />
            <input type="hidden" name="settings_subtab" value="custom_fields" />
            <input type="hidden" name="enabled_submitted" value="1" />
            <?php 
        wp_nonce_field( 'qsfw_enabled_cols' );
        ?>
            <table class="widefat striped"><thead><tr><th><?php 
        esc_html_e( 'Column', 'quickstock-for-woocommerce' );
        ?></th><th><?php 
        esc_html_e( 'Available', 'quickstock-for-woocommerce' );
        ?></th><th><?php 
        esc_html_e( 'Actions', 'quickstock-for-woocommerce' );
        ?></th></tr></thead><tbody>
            <?php 
        foreach ( $all as $key => $cfg ) {
            if ( !empty( $cfg['fixed'] ) ) {
                continue;
            }
            ?>
                <tr><td><?php 
            echo esc_html( wp_strip_all_tags( str_replace( '<br>', ' ', $cfg['label'] ) ) );
            ?></td><td><label><input type="checkbox" name="enabled_cols[]" value="<?php 
            echo esc_attr( $key );
            ?>" <?php 
            checked( in_array( $key, $enabled, true ) );
            ?> /> <?php 
            esc_html_e( 'Enabled', 'quickstock-for-woocommerce' );
            ?></label></td><td><a class="button button-small" href="<?php 
            echo esc_url( $base_url . '&edit_col=' . $key );
            ?>"><?php 
            esc_html_e( 'Edit', 'quickstock-for-woocommerce' );
            ?></a></td></tr>
            <?php 
        }
        ?>
            </tbody></table>
            <p class="hb-settings-actions"><button type="submit" class="button button-primary"><?php 
        esc_html_e( 'Save', 'quickstock-for-woocommerce' );
        ?></button></p>
        </form>
        <?php 
    }

    private static function render_custom_fields_upsell() {
        QSFW_Renderer::echo_pro_upsell_panel( '🧩', __( 'Custom fields', 'quickstock-for-woocommerce' ), __( 'Define your own product fields (text, number, URL, date, checkbox or multiline) and use them as sortable, filterable columns with inline editing — right here in the table and in bulk edit. Available in QuickStock Pro.', 'quickstock-for-woocommerce' ) );
    }

    /* ===================================================================
     * FORMULAR-VERARBEITUNG: ALLGEMEINE EINSTELLUNGEN
     * =================================================================== */
    private static function process_general_forms() {
        if ( !current_user_can( 'manage_woocommerce' ) ) {
            return;
        }
        if ( !isset( $_REQUEST['page'] ) || $_REQUEST['page'] !== 'quickstock-for-woocommerce' ) {
            return;
        }
        if ( !isset( $_REQUEST['settings_subtab'] ) || $_REQUEST['settings_subtab'] !== 'general' ) {
            return;
        }
        $base_url = admin_url( 'admin.php?page=quickstock-for-woocommerce&mode=settings&settings_subtab=general' );
        if ( !empty( $_REQUEST['qsfw_general_submitted'] ) ) {
            check_admin_referer( 'qsfw_general_save' );
            // Bestehende Einzel-Optionen (unverändert)
            $reset_on_restock = ( !empty( $_REQUEST['qsfw_done_reset_on_restock'] ) ? 1 : 0 );
            update_option( 'qsfw_done_reset_on_restock', $reset_on_restock );
            $chunk = ( isset( $_REQUEST['qsfw_bulk_chunk_size'] ) ? absint( $_REQUEST['qsfw_bulk_chunk_size'] ) : 25 );
            $chunk = max( 1, min( 200, $chunk ) );
            update_option( 'qsfw_bulk_chunk_size', $chunk );
            // Neue gebündelte Option qsfw_general_settings (Phase 1)
            $defaults = self::general_defaults();
            $per_page = ( isset( $_REQUEST['qsfw_default_per_page'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['qsfw_default_per_page'] ) ) : $defaults['default_per_page'] );
            $tab = ( isset( $_REQUEST['qsfw_default_tab'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['qsfw_default_tab'] ) ) : $defaults['default_tab'] );
            $sort_all = ( isset( $_REQUEST['qsfw_default_sort_all'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['qsfw_default_sort_all'] ) ) : $defaults['default_sort_all'] );
            $sort_reord = ( isset( $_REQUEST['qsfw_default_sort_reorder'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['qsfw_default_sort_reorder'] ) ) : $defaults['default_sort_reorder'] );
            $density = ( isset( $_REQUEST['qsfw_row_density'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['qsfw_row_density'] ) ) : $defaults['row_density'] );
            $allowed_pp = array(
                '25',
                '50',
                '100',
                '200',
                'all'
            );
            $allowed_tab = array('all', 'reorder', 'last_visited');
            $allowed_density = array('compact', 'normal', 'comfortable');
            // Marge-Schwellen (Farbe der Margin-Badge). med darf nicht über high liegen.
            $margin_high = ( isset( $_REQUEST['qsfw_margin_threshold_high'] ) ? (float) str_replace( ',', '.', sanitize_text_field( wp_unslash( $_REQUEST['qsfw_margin_threshold_high'] ) ) ) : $defaults['margin_threshold_high'] );
            $margin_med = ( isset( $_REQUEST['qsfw_margin_threshold_med'] ) ? (float) str_replace( ',', '.', sanitize_text_field( wp_unslash( $_REQUEST['qsfw_margin_threshold_med'] ) ) ) : $defaults['margin_threshold_med'] );
            $margin_high = max( 0, min( 100, $margin_high ) );
            $margin_med = max( 0, min( 100, $margin_med ) );
            if ( $margin_med > $margin_high ) {
                $margin_med = $margin_high;
            }
            // Phase 2: Auto-Save
            $autosave_mode = ( isset( $_REQUEST['qsfw_autosave_mode'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['qsfw_autosave_mode'] ) ) : $defaults['autosave_mode'] );
            $autosave_mode = ( in_array( $autosave_mode, array('auto', 'manual'), true ) ? $autosave_mode : $defaults['autosave_mode'] );
            // Phase 2: Bulk-Confirm
            $bulk_confirm_mode = ( isset( $_REQUEST['qsfw_bulk_confirm_mode'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['qsfw_bulk_confirm_mode'] ) ) : $defaults['bulk_confirm_mode'] );
            $bulk_confirm_mode = ( in_array( $bulk_confirm_mode, array('off', 'always', 'threshold'), true ) ? $bulk_confirm_mode : $defaults['bulk_confirm_mode'] );
            $bulk_confirm_threshold = ( isset( $_REQUEST['qsfw_bulk_confirm_threshold'] ) ? absint( $_REQUEST['qsfw_bulk_confirm_threshold'] ) : $defaults['bulk_confirm_threshold'] );
            $bulk_confirm_threshold = max( 1, min( 9999, $bulk_confirm_threshold ) );
            // Phase 2: CSV-Defaults
            $csv_delimiter = ( isset( $_REQUEST['qsfw_csv_delimiter'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['qsfw_csv_delimiter'] ) ) : $defaults['csv_delimiter'] );
            $csv_delimiter = ( in_array( $csv_delimiter, array(';', ',', 'tab'), true ) ? $csv_delimiter : $defaults['csv_delimiter'] );
            $csv_bom = ( !empty( $_REQUEST['qsfw_csv_bom'] ) ? 1 : 0 );
            $csv_date_fmt = ( isset( $_REQUEST['qsfw_csv_date_format'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['qsfw_csv_date_format'] ) ) : $defaults['csv_date_format'] );
            $csv_date_fmt = ( in_array( $csv_date_fmt, array('Y-m-d', 'd.m.Y', 'locale'), true ) ? $csv_date_fmt : $defaults['csv_date_format'] );
            // Phase 2: Währungs-Override
            $currency_override = ( !empty( $_REQUEST['qsfw_currency_override'] ) ? 1 : 0 );
            $currency_symbol = ( isset( $_REQUEST['qsfw_currency_symbol'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['qsfw_currency_symbol'] ) ) : $defaults['currency_symbol'] );
            $currency_position = ( isset( $_REQUEST['qsfw_currency_position'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['qsfw_currency_position'] ) ) : $defaults['currency_position'] );
            $currency_position = ( in_array( $currency_position, array(
                'left',
                'right',
                'left_space',
                'right_space'
            ), true ) ? $currency_position : $defaults['currency_position'] );
            $currency_decimal = ( isset( $_REQUEST['qsfw_currency_decimal'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['qsfw_currency_decimal'] ) ) : $defaults['currency_decimal'] );
            $currency_thousands = ( isset( $_REQUEST['qsfw_currency_thousands'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['qsfw_currency_thousands'] ) ) : $defaults['currency_thousands'] );
            // Phase 2: Scanner-Cache-TTL (Cache leeren, wenn sich der Wert ändert)
            $scanner_cache_ttl = ( isset( $_REQUEST['qsfw_scanner_cache_ttl'] ) ? absint( $_REQUEST['qsfw_scanner_cache_ttl'] ) : $defaults['scanner_cache_ttl'] );
            $allowed_ttls = array(
                3600,
                21600,
                86400,
                0
            );
            $scanner_cache_ttl = ( in_array( $scanner_cache_ttl, $allowed_ttls, true ) ? $scanner_cache_ttl : $defaults['scanner_cache_ttl'] );
            $old_bundle = get_option( self::GENERAL_OPTION, array() );
            $old_ttl = ( isset( $old_bundle['scanner_cache_ttl'] ) ? (int) $old_bundle['scanner_cache_ttl'] : $defaults['scanner_cache_ttl'] );
            if ( $scanner_cache_ttl !== $old_ttl ) {
            }
            // Phase 2: Tastatur-Shortcuts
            $keyboard_shortcuts = ( !empty( $_REQUEST['qsfw_keyboard_shortcuts'] ) ? 1 : 0 );
            // Verlauf / Log
            $log_enabled = ( !empty( $_REQUEST['qsfw_log_enabled'] ) ? 1 : 0 );
            $log_retention = ( isset( $_REQUEST['qsfw_log_retention_days'] ) ? absint( $_REQUEST['qsfw_log_retention_days'] ) : $defaults['log_retention_days'] );
            $log_retention = ( in_array( $log_retention, array(
                30,
                90,
                365,
                0
            ), true ) ? $log_retention : $defaults['log_retention_days'] );
            $premium_bundle = array();
            // Schnellbestellung: globaler Ziel-Auffüllbestand (Fallback für order_qty-Vorschlag)
            $restock_target = ( isset( $_REQUEST['qsfw_default_restock_target'] ) ? absint( $_REQUEST['qsfw_default_restock_target'] ) : $defaults['default_restock_target'] );
            // Nachbestellung: Standard-Zeitraum „Verkauft seit" in Tagen (1–365)
            $reorder_sold_days = ( isset( $_REQUEST['qsfw_reorder_sold_days'] ) ? absint( $_REQUEST['qsfw_reorder_sold_days'] ) : $defaults['reorder_sold_days'] );
            if ( $reorder_sold_days < 1 || $reorder_sold_days > 365 ) {
                $reorder_sold_days = $defaults['reorder_sold_days'];
            }
            $bundle = array(
                'default_per_page'       => ( in_array( $per_page, $allowed_pp, true ) ? $per_page : $defaults['default_per_page'] ),
                'default_tab'            => ( in_array( $tab, $allowed_tab, true ) ? $tab : $defaults['default_tab'] ),
                'default_sort_all'       => QSFW_Columns::sanitize_sort( $sort_all, 'all' ),
                'default_sort_reorder'   => QSFW_Columns::sanitize_sort( $sort_reord, 'reorder' ),
                'lazy_load_images'       => ( !empty( $_REQUEST['qsfw_lazy_load_images'] ) ? 1 : 0 ),
                'row_density'            => ( in_array( $density, $allowed_density, true ) ? $density : $defaults['row_density'] ),
                'sticky_header'          => ( !empty( $_REQUEST['qsfw_sticky_header'] ) ? 1 : 0 ),
                'group_variations'       => ( !empty( $_REQUEST['qsfw_group_variations'] ) ? 1 : 0 ),
                'margin_threshold_high'  => $margin_high,
                'margin_threshold_med'   => $margin_med,
                'autosave_mode'          => $autosave_mode,
                'bulk_confirm_mode'      => $bulk_confirm_mode,
                'bulk_confirm_threshold' => $bulk_confirm_threshold,
                'csv_delimiter'          => $csv_delimiter,
                'csv_bom'                => $csv_bom,
                'csv_date_format'        => $csv_date_fmt,
                'currency_override'      => $currency_override,
                'currency_symbol'        => $currency_symbol,
                'currency_position'      => $currency_position,
                'currency_decimal'       => $currency_decimal,
                'currency_thousands'     => $currency_thousands,
                'scanner_cache_ttl'      => $scanner_cache_ttl,
                'keyboard_shortcuts'     => $keyboard_shortcuts,
                'log_enabled'            => $log_enabled,
                'log_retention_days'     => $log_retention,
                'default_restock_target' => $restock_target,
                'reorder_sold_days'      => $reorder_sold_days,
            );
            $bundle = array_merge( $bundle, $premium_bundle );
            update_option( self::GENERAL_OPTION, $bundle );
            wp_safe_redirect( $base_url . '&qsfw_saved=1' );
            exit;
        }
    }

    /* ===================================================================
     * SEKTION: ALLGEMEINE EINSTELLUNGEN
     * =================================================================== */
    private static function render_general_section() {
        $reset_on_restock = (int) get_option( 'qsfw_done_reset_on_restock', 0 );
        $bulk_chunk = max( 1, min( 200, (int) get_option( 'qsfw_bulk_chunk_size', 25 ) ) );
        // Phase-1-Settings (gebündelt)
        $g_per_page = self::get_general_setting( 'default_per_page' );
        $g_tab = self::get_general_setting( 'default_tab' );
        $g_sort_all = self::get_general_setting( 'default_sort_all' );
        $g_sort_reord = self::get_general_setting( 'default_sort_reorder' );
        $g_lazy = (int) self::get_general_setting( 'lazy_load_images' );
        $g_density = self::get_general_setting( 'row_density' );
        $g_sticky = (int) self::get_general_setting( 'sticky_header' );
        $g_group_var = (int) self::get_general_setting( 'group_variations' );
        $g_margin_high = (float) self::get_general_setting( 'margin_threshold_high' );
        $g_margin_med = (float) self::get_general_setting( 'margin_threshold_med' );
        // Phase-2-Settings
        $g_autosave = self::get_general_setting( 'autosave_mode' );
        $g_bc_mode = self::get_general_setting( 'bulk_confirm_mode' );
        $g_bc_thresh = (int) self::get_general_setting( 'bulk_confirm_threshold' );
        $g_csv_delim = self::get_general_setting( 'csv_delimiter' );
        $g_csv_bom = (int) self::get_general_setting( 'csv_bom' );
        $g_csv_date = self::get_general_setting( 'csv_date_format' );
        $g_cur_ovr = (int) self::get_general_setting( 'currency_override' );
        $g_cur_sym = self::get_general_setting( 'currency_symbol' );
        $g_cur_pos = self::get_general_setting( 'currency_position' );
        $g_cur_dec = self::get_general_setting( 'currency_decimal' );
        $g_cur_thou = self::get_general_setting( 'currency_thousands' );
        $g_scanner_ttl = (int) self::get_general_setting( 'scanner_cache_ttl' );
        $g_kbd = (int) self::get_general_setting( 'keyboard_shortcuts' );
        // Verlauf / Log
        $g_log_enabled = (int) self::get_general_setting( 'log_enabled' );
        $g_log_retention = (int) self::get_general_setting( 'log_retention_days' );
        // Nachbestell-PDF (kleiner Designer)
        $g_pdf_logo_id = (int) self::get_general_setting( 'reorder_pdf_logo_id' );
        $g_pdf_title = self::get_general_setting( 'reorder_pdf_title' );
        $g_pdf_date_fmt = self::get_general_setting( 'reorder_pdf_date_format' );
        $g_pdf_logo_url = ( $g_pdf_logo_id ? wp_get_attachment_image_url( $g_pdf_logo_id, 'medium' ) : '' );
        // PDF-Spalten: gespeicherte Auswahl; alle verfügbaren Spalten für die UI
        $g_pdf_cols = self::get_general_setting( 'pdf_columns', array() );
        if ( empty( $g_pdf_cols ) ) {
            $g_pdf_cols = array(
                'sku',
                'supplier_sku',
                'title',
                'stock',
                'limit'
            );
        }
        $excluded_pdf = array(
            'bulk_select',
            'check',
            'image',
            'supplier',
            'permalink',
            'post_status',
            'sale_from',
            'sale_to',
            'excerpt',
            'content'
        );
        $all_pdf_cols = array_diff_key( QSFW_Columns::get_all(), array_flip( $excluded_pdf ) );
        // Reihenfolge: gespeicherte Spalten zuerst (in Sortier-Reihenfolge), dann Rest
        $pdf_col_ordered = array();
        foreach ( $g_pdf_cols as $ck ) {
            if ( isset( $all_pdf_cols[$ck] ) ) {
                $pdf_col_ordered[$ck] = $all_pdf_cols[$ck];
            }
        }
        foreach ( $all_pdf_cols as $ck => $cfg ) {
            if ( !isset( $pdf_col_ordered[$ck] ) ) {
                $pdf_col_ordered[$ck] = $cfg;
            }
        }
        // Schnellbestellung / Bestellmengen
        $g_restock_target = (int) self::get_general_setting( 'default_restock_target' );
        $g_sold_days = (int) self::get_general_setting( 'reorder_sold_days' );
        $per_page_opts = array(
            '25'  => '25',
            '50'  => '50',
            '100' => '100',
            '200' => '200',
            'all' => __( 'All', 'quickstock-for-woocommerce' ),
        );
        $tab_opts = array(
            'all'          => __( '📦 All Products', 'quickstock-for-woocommerce' ),
            'reorder'      => __( '📋 Reorder', 'quickstock-for-woocommerce' ),
            'last_visited' => __( '↩ Last visited', 'quickstock-for-woocommerce' ),
        );
        $density_opts = array(
            'compact'     => __( 'Compact', 'quickstock-for-woocommerce' ),
            'normal'      => __( 'Normal', 'quickstock-for-woocommerce' ),
            'comfortable' => __( 'Comfortable', 'quickstock-for-woocommerce' ),
        );
        $sort_labels = array(
            'open_first'           => __( '📋 Open first', 'quickstock-for-woocommerce' ),
            'newest'               => __( '🆕 Newest first', 'quickstock-for-woocommerce' ),
            'oldest'               => __( '🕰 Oldest first', 'quickstock-for-woocommerce' ),
            'col__title__asc'      => __( 'Name A → Z', 'quickstock-for-woocommerce' ),
            'col__sku__asc'        => __( 'SKU ↑', 'quickstock-for-woocommerce' ),
            'col__stock__asc'      => __( 'Stock ↑', 'quickstock-for-woocommerce' ),
            'col__stock__desc'     => __( 'Stock ↓', 'quickstock-for-woocommerce' ),
            'col__price_reg__asc'  => __( 'Price ↑', 'quickstock-for-woocommerce' ),
            'col__price_reg__desc' => __( 'Price ↓', 'quickstock-for-woocommerce' ),
        );
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- reine Erfolgsanzeige nach einem bereits nonce-geprueften PRG-Redirect.
        $show_saved_notice = !empty( $_GET['qsfw_saved'] );
        ?>
        <div class="hb-settings-intro">
            <h2><?php 
        esc_html_e( 'General settings', 'quickstock-for-woocommerce' );
        ?></h2>
            <p><?php 
        esc_html_e( 'Global behaviour and appearance of QuickStock. Sections are collapsible.', 'quickstock-for-woocommerce' );
        ?></p>
        </div>

        <?php 
        if ( $show_saved_notice ) {
            ?>
            <div class="notice notice-success inline"><p><?php 
            esc_html_e( 'Settings saved.', 'quickstock-for-woocommerce' );
            ?></p></div>
        <?php 
        }
        ?>

        <form method="get" action="<?php 
        echo esc_url( admin_url( 'admin.php' ) );
        ?>" class="qsfw-general-form">
            <input type="hidden" name="page" value="quickstock-for-woocommerce" />
            <input type="hidden" name="mode" value="settings" />
            <input type="hidden" name="settings_subtab" value="general" />
            <input type="hidden" name="qsfw_general_submitted" value="1" />
            <?php 
        wp_nonce_field( 'qsfw_general_save' );
        ?>

            <details class="qsfw-accordion" open>
                <summary>🚦 <?php 
        esc_html_e( 'Behaviour & workflow', 'quickstock-for-woocommerce' );
        ?></summary>
                <div class="qsfw-accordion-body">
                    <table class="form-table" style="max-width:760px;">
                        <tr>
                            <th scope="row"><?php 
        esc_html_e( 'Default tab on open', 'quickstock-for-woocommerce' );
        ?></th>
                            <td>
                                <select name="qsfw_default_tab">
                                    <?php 
        foreach ( $tab_opts as $k => $lbl ) {
            ?>
                                        <option value="<?php 
            echo esc_attr( $k );
            ?>" <?php 
            selected( $g_tab, $k );
            ?>><?php 
            echo esc_html( $lbl );
            ?></option>
                                    <?php 
        }
        ?>
                                </select>
                                <p class="description">
                                    <?php 
        esc_html_e( 'Which tab is shown first when opening the plugin. “Last visited” remembers the last tab per user.', 'quickstock-for-woocommerce' );
        ?>
                                </p>
                            </td>
                        </tr>
                        <tr>
                            <th scope="row"><?php 
        esc_html_e( 'Reorder', 'quickstock-for-woocommerce' );
        ?></th>
                            <td>
                                <label>
                                    <input type="checkbox" name="qsfw_done_reset_on_restock" value="1" <?php 
        checked( $reset_on_restock, 1 );
        ?> />
                                    <?php 
        esc_html_e( 'Automatically clear the Done flag when stock is increased', 'quickstock-for-woocommerce' );
        ?>
                                </label>
                                <p class="description">
                                    <?php 
        esc_html_e( 'When enabled: if the stock of a product marked “done” is increased (inline), the Done flag is automatically cleared and the row becomes active again.', 'quickstock-for-woocommerce' );
        ?>
                                </p>
                                <p style="margin-top:12px;">
                                    <label for="qsfw_reorder_sold_days"><?php 
        esc_html_e( 'Default “sold since” period:', 'quickstock-for-woocommerce' );
        ?></label>
                                    <input type="number" id="qsfw_reorder_sold_days" name="qsfw_reorder_sold_days" min="1" max="365" step="1"
                                           value="<?php 
        echo esc_attr( $g_sold_days );
        ?>" class="small-text" />
                                    <?php 
        esc_html_e( 'days', 'quickstock-for-woocommerce' );
        ?>
                                </p>
                                <p class="description">
                                    <?php 
        esc_html_e( 'How far back the Reorder tab looks for sales by default. You can still adjust the date on the tab itself.', 'quickstock-for-woocommerce' );
        ?>
                                </p>
                            </td>
                        </tr>
                        <tr>
                            <th scope="row"><?php 
        esc_html_e( 'Inline editing', 'quickstock-for-woocommerce' );
        ?></th>
                            <td>
                                <select name="qsfw_autosave_mode">
                                    <option value="auto"   <?php 
        selected( $g_autosave, 'auto' );
        ?>><?php 
        esc_html_e( 'Auto-save – save immediately after each change', 'quickstock-for-woocommerce' );
        ?></option>
                                    <option value="manual" <?php 
        selected( $g_autosave, 'manual' );
        ?>><?php 
        esc_html_e( 'Manual – collect changes, then save in batch', 'quickstock-for-woocommerce' );
        ?></option>
                                </select>
                                <p class="description">
                                    <?php 
        echo wp_kses( __( '<strong>Auto-save</strong> (default): every inline change is saved immediately via AJAX.<br><strong>Manual</strong>: edited fields are flagged and only saved via the “💾 Save all” button.', 'quickstock-for-woocommerce' ), array(
            'strong' => array(),
            'br'     => array(),
        ) );
        ?>
                                </p>
                            </td>
                        </tr>
                        <tr>
                            <th scope="row"><?php 
        esc_html_e( 'Bulk confirmation dialog', 'quickstock-for-woocommerce' );
        ?></th>
                            <td>
                                <select name="qsfw_bulk_confirm_mode" id="qsfw_bulk_confirm_mode">
                                    <option value="always"    <?php 
        selected( $g_bc_mode, 'always' );
        ?>><?php 
        esc_html_e( 'Always show', 'quickstock-for-woocommerce' );
        ?></option>
                                    <option value="threshold" <?php 
        selected( $g_bc_mode, 'threshold' );
        ?>><?php 
        esc_html_e( 'Show above N products', 'quickstock-for-woocommerce' );
        ?></option>
                                    <option value="off"       <?php 
        selected( $g_bc_mode, 'off' );
        ?>><?php 
        esc_html_e( 'Never show (run immediately)', 'quickstock-for-woocommerce' );
        ?></option>
                                </select>
                                <span id="qsfw_bc_thresh_wrap" style="<?php 
        echo ( $g_bc_mode === 'threshold' ? '' : 'display:none;' );
        ?>">
                                    &nbsp;<?php 
        esc_html_e( 'above', 'quickstock-for-woocommerce' );
        ?>
                                    <input type="number" name="qsfw_bulk_confirm_threshold" min="1" max="9999" step="1"
                                           value="<?php 
        echo esc_attr( $g_bc_thresh );
        ?>" style="width:80px;" />
                                    <?php 
        esc_html_e( 'products', 'quickstock-for-woocommerce' );
        ?>
                                </span>
                                <p class="description"><?php 
        esc_html_e( 'Controls when a confirmation dialog appears before bulk edits.', 'quickstock-for-woocommerce' );
        ?></p>
                            </td>
                        </tr>
                    </table>
                </div>
            </details>

            <details class="qsfw-accordion">
                <summary>⚡ <?php 
        esc_html_e( 'Performance & data', 'quickstock-for-woocommerce' );
        ?></summary>
                <div class="qsfw-accordion-body">
                    <table class="form-table" style="max-width:760px;">
                        <tr>
                            <th scope="row"><?php 
        esc_html_e( 'Default “Per page”', 'quickstock-for-woocommerce' );
        ?></th>
                            <td>
                                <select name="qsfw_default_per_page">
                                    <?php 
        foreach ( $per_page_opts as $k => $lbl ) {
            ?>
                                        <option value="<?php 
            echo esc_attr( $k );
            ?>" <?php 
            selected( $g_per_page, $k );
            ?>><?php 
            echo esc_html( $lbl );
            ?></option>
                                    <?php 
        }
        ?>
                                </select>
                                <p class="description">
                                    <?php 
        esc_html_e( 'Fallback page size when neither preset nor user has chosen one.', 'quickstock-for-woocommerce' );
        ?>
                                </p>
                            </td>
                        </tr>
                        <tr>
                            <th scope="row"><?php 
        esc_html_e( 'Lazy load images', 'quickstock-for-woocommerce' );
        ?></th>
                            <td>
                                <label>
                                    <input type="checkbox" name="qsfw_lazy_load_images" value="1" <?php 
        checked( $g_lazy, 1 );
        ?> />
                                    <?php 
        echo wp_kses( __( 'Enable <code>loading="lazy"</code> on product images', 'quickstock-for-woocommerce' ), array(
            'code' => array(),
        ) );
        ?>
                                </label>
                                <p class="description">
                                    <?php 
        esc_html_e( 'Noticeably faster on long lists with “All per page”. Images load only when scrolled into the viewport.', 'quickstock-for-woocommerce' );
        ?>
                                </p>
                            </td>
                        </tr>
                        <tr>
                            <th scope="row"><?php 
        esc_html_e( 'Bulk editing', 'quickstock-for-woocommerce' );
        ?></th>
                            <td>
                                <label>
                                    <?php 
        esc_html_e( 'Chunk size', 'quickstock-for-woocommerce' );
        ?>
                                    <input type="number" name="qsfw_bulk_chunk_size" min="1" max="200" step="1"
                                           value="<?php 
        echo esc_attr( $bulk_chunk );
        ?>" style="width:90px;" />
                                    <?php 
        esc_html_e( 'products per processing chunk', 'quickstock-for-woocommerce' );
        ?>
                                </label>
                                <p class="description">
                                    <?php 
        esc_html_e( 'Bulk edits are processed in chunks of this size (with a progress bar). Smaller values are gentler on slow servers, larger values are faster. Default: 25 (range 1–200).', 'quickstock-for-woocommerce' );
        ?>
                                </p>
                            </td>
                        </tr>
                        <?php 
        ?>
                    </table>
                </div>
            </details>

            <details class="qsfw-accordion">
                <summary>🎨 <?php 
        esc_html_e( 'Appearance', 'quickstock-for-woocommerce' );
        ?></summary>
                <div class="qsfw-accordion-body">
                    <table class="form-table" style="max-width:760px;">
                        <tr>
                            <th scope="row"><?php 
        esc_html_e( 'Row height', 'quickstock-for-woocommerce' );
        ?></th>
                            <td>
                                <select name="qsfw_row_density">
                                    <?php 
        foreach ( $density_opts as $k => $lbl ) {
            ?>
                                        <option value="<?php 
            echo esc_attr( $k );
            ?>" <?php 
            selected( $g_density, $k );
            ?>><?php 
            echo esc_html( $lbl );
            ?></option>
                                    <?php 
        }
        ?>
                                </select>
                                <p class="description"><?php 
        esc_html_e( 'Density of table rows (padding). “Normal” matches the previous behaviour.', 'quickstock-for-woocommerce' );
        ?></p>
                            </td>
                        </tr>
                        <tr>
                            <th scope="row"><?php 
        esc_html_e( 'Sticky header', 'quickstock-for-woocommerce' );
        ?></th>
                            <td>
                                <label>
                                    <input type="checkbox" name="qsfw_sticky_header" value="1" <?php 
        checked( $g_sticky, 1 );
        ?> />
                                    <?php 
        esc_html_e( 'Pin column headers at the top while scrolling', 'quickstock-for-woocommerce' );
        ?>
                                </label>
                                <p class="description">
                                    <?php 
        esc_html_e( 'Essential for long lists. Enabled by default.', 'quickstock-for-woocommerce' );
        ?>
                                </p>
                            </td>
                        </tr>
                        <tr>
                            <th scope="row"><?php 
        esc_html_e( 'Group variations', 'quickstock-for-woocommerce' );
        ?></th>
                            <td>
                                <label>
                                    <input type="checkbox" name="qsfw_group_variations" value="1" <?php 
        checked( $g_group_var, 1 );
        ?> />
                                    <?php 
        esc_html_e( 'Group variations under their parent product in the “All Products” tab', 'quickstock-for-woocommerce' );
        ?>
                                </label>
                                <p class="description">
                                    <?php 
        esc_html_e( 'Variable products appear as one collapsible row; click it to expand and edit the variations. When off, every variation is shown as its own flat row.', 'quickstock-for-woocommerce' );
        ?>
                                </p>
                            </td>
                        </tr>
                        <?php 
        ?>
                        <tr>
                            <th scope="row"><?php 
        esc_html_e( 'Default sorting', 'quickstock-for-woocommerce' );
        ?></th>
                            <td>
                                <label>
                                    📦 <?php 
        esc_html_e( 'All products:', 'quickstock-for-woocommerce' );
        ?>
                                    <select name="qsfw_default_sort_all">
                                        <?php 
        foreach ( $sort_labels as $k => $lbl ) {
            if ( $k === 'open_first' ) {
                continue;
            }
            // nicht für 'all'
            if ( !QSFW_Columns::is_valid_sort( $k, 'all' ) ) {
                continue;
            }
            ?>
                                            <option value="<?php 
            echo esc_attr( $k );
            ?>" <?php 
            selected( $g_sort_all, $k );
            ?>><?php 
            echo esc_html( $lbl );
            ?></option>
                                        <?php 
        }
        ?>
                                    </select>
                                </label>
                                <br>
                                <label style="margin-top:6px; display:inline-block;">
                                    📋 <?php 
        esc_html_e( 'Reorder:', 'quickstock-for-woocommerce' );
        ?>
                                    <select name="qsfw_default_sort_reorder">
                                        <?php 
        foreach ( $sort_labels as $k => $lbl ) {
            if ( in_array( $k, array('newest', 'oldest'), true ) ) {
                continue;
            }
            if ( !QSFW_Columns::is_valid_sort( $k, 'reorder' ) ) {
                continue;
            }
            ?>
                                            <option value="<?php 
            echo esc_attr( $k );
            ?>" <?php 
            selected( $g_sort_reord, $k );
            ?>><?php 
            echo esc_html( $lbl );
            ?></option>
                                        <?php 
        }
        ?>
                                    </select>
                                </label>
                                <p class="description">
                                    <?php 
        esc_html_e( 'Fallback sort order per tab, when neither preset nor user has chosen a sort.', 'quickstock-for-woocommerce' );
        ?>
                                </p>
                            </td>
                        </tr>
                    </table>
                </div>
            </details>

            <details class="qsfw-accordion">
                <summary>📤 <?php 
        esc_html_e( 'Export &amp; format', 'quickstock-for-woocommerce' );
        ?></summary>
                <div class="qsfw-accordion-body">
                    <table class="form-table" style="max-width:760px;">
                        <tr>
                            <th scope="row"><?php 
        esc_html_e( 'CSV delimiter', 'quickstock-for-woocommerce' );
        ?></th>
                            <td>
                                <select name="qsfw_csv_delimiter">
                                    <option value=";"   <?php 
        selected( $g_csv_delim, ';' );
        ?>><?php 
        esc_html_e( 'Semicolon ; (default, Excel DE)', 'quickstock-for-woocommerce' );
        ?></option>
                                    <option value=","   <?php 
        selected( $g_csv_delim, ',' );
        ?>><?php 
        esc_html_e( 'Comma , (international)', 'quickstock-for-woocommerce' );
        ?></option>
                                    <option value="tab" <?php 
        selected( $g_csv_delim, 'tab' );
        ?>><?php 
        esc_html_e( 'Tab ⇥', 'quickstock-for-woocommerce' );
        ?></option>
                                </select>
                            </td>
                        </tr>
                        <tr>
                            <th scope="row">UTF-8 BOM</th>
                            <td>
                                <label>
                                    <input type="checkbox" name="qsfw_csv_bom" value="1" <?php 
        checked( $g_csv_bom, 1 );
        ?> />
                                    <?php 
        esc_html_e( 'Insert BOM at file start (recommended for Excel compatibility)', 'quickstock-for-woocommerce' );
        ?>
                                </label>
                            </td>
                        </tr>
                        <tr>
                            <th scope="row"><?php 
        esc_html_e( 'Date format in export', 'quickstock-for-woocommerce' );
        ?></th>
                            <td>
                                <select name="qsfw_csv_date_format">
                                    <option value="Y-m-d" <?php 
        selected( $g_csv_date, 'Y-m-d' );
        ?>><?php 
        esc_html_e( 'ISO: 2026-05-21', 'quickstock-for-woocommerce' );
        ?></option>
                                    <option value="d.m.Y" <?php 
        selected( $g_csv_date, 'd.m.Y' );
        ?>><?php 
        esc_html_e( 'DE: 21.05.2026', 'quickstock-for-woocommerce' );
        ?></option>
                                    <option value="locale" <?php 
        selected( $g_csv_date, 'locale' );
        ?>><?php 
        esc_html_e( 'System format (locale)', 'quickstock-for-woocommerce' );
        ?></option>
                                </select>
                            </td>
                        </tr>
                        <tr>
                            <th scope="row"><?php 
        esc_html_e( 'Currency display', 'quickstock-for-woocommerce' );
        ?></th>
                            <td>
                                <label>
                                    <input type="checkbox" name="qsfw_currency_override" value="1" id="qsfw_cur_ovr" <?php 
        checked( $g_cur_ovr, 1 );
        ?> />
                                    <?php 
        esc_html_e( 'Override WooCommerce currency settings for this plugin', 'quickstock-for-woocommerce' );
        ?>
                                </label>
                                <div id="qsfw_cur_fields" style="<?php 
        echo ( $g_cur_ovr ? '' : 'display:none;' );
        ?> margin-top:10px;">
                                    <table class="form-table" style="margin:0;">
                                        <tr>
                                            <th scope="row" style="padding-left:0;"><?php 
        esc_html_e( 'Symbol', 'quickstock-for-woocommerce' );
        ?></th>
                                            <td><input type="text" name="qsfw_currency_symbol" value="<?php 
        echo esc_attr( $g_cur_sym );
        ?>" style="width:80px;" placeholder="<?php 
        esc_attr_e( 'e.g. CHF or €', 'quickstock-for-woocommerce' );
        ?>" /></td>
                                        </tr>
                                        <tr>
                                            <th scope="row" style="padding-left:0;"><?php 
        esc_html_e( 'Position', 'quickstock-for-woocommerce' );
        ?></th>
                                            <td>
                                                <select name="qsfw_currency_position">
                                                    <option value="left"        <?php 
        selected( $g_cur_pos, 'left' );
        ?>><?php 
        esc_html_e( 'Left (€10.00)', 'quickstock-for-woocommerce' );
        ?></option>
                                                    <option value="right"       <?php 
        selected( $g_cur_pos, 'right' );
        ?>><?php 
        esc_html_e( 'Right (10.00€)', 'quickstock-for-woocommerce' );
        ?></option>
                                                    <option value="left_space"  <?php 
        selected( $g_cur_pos, 'left_space' );
        ?>><?php 
        esc_html_e( 'Left with space (€ 10.00)', 'quickstock-for-woocommerce' );
        ?></option>
                                                    <option value="right_space" <?php 
        selected( $g_cur_pos, 'right_space' );
        ?>><?php 
        esc_html_e( 'Right with space (10.00 €)', 'quickstock-for-woocommerce' );
        ?></option>
                                                </select>
                                            </td>
                                        </tr>
                                        <tr>
                                            <th scope="row" style="padding-left:0;"><?php 
        esc_html_e( 'Decimal separator', 'quickstock-for-woocommerce' );
        ?></th>
                                            <td><input type="text" name="qsfw_currency_decimal" value="<?php 
        echo esc_attr( $g_cur_dec );
        ?>" style="width:50px;" placeholder="." maxlength="1" /></td>
                                        </tr>
                                        <tr>
                                            <th scope="row" style="padding-left:0;"><?php 
        esc_html_e( 'Thousands separator', 'quickstock-for-woocommerce' );
        ?></th>
                                            <td><input type="text" name="qsfw_currency_thousands" value="<?php 
        echo esc_attr( $g_cur_thou );
        ?>" style="width:50px;" placeholder="'" maxlength="1" /></td>
                                        </tr>
                                    </table>
                                </div>
                                <p class="description"><?php 
        esc_html_e( 'Affects price formatting in CSV export and bulk form.', 'quickstock-for-woocommerce' );
        ?></p>
                            </td>
                        </tr>
                    </table>
                </div>
            </details>

            <details class="qsfw-accordion">
                <summary>⌨️ <?php 
        esc_html_e( 'Controls', 'quickstock-for-woocommerce' );
        ?></summary>
                <div class="qsfw-accordion-body">
                    <table class="form-table" style="max-width:760px;">
                        <tr>
                            <th scope="row"><?php 
        esc_html_e( 'Keyboard shortcuts', 'quickstock-for-woocommerce' );
        ?></th>
                            <td>
                                <label>
                                    <input type="checkbox" name="qsfw_keyboard_shortcuts" value="1" <?php 
        checked( $g_kbd, 1 );
        ?> />
                                    <?php 
        esc_html_e( 'Enable keyboard shortcuts', 'quickstock-for-woocommerce' );
        ?>
                                </label>
                                <p class="description">
                                    <?php 
        echo wp_kses( __( 'When enabled: <kbd>?</kbd> opens the shortcut cheat sheet as an overlay. <kbd>Esc</kbd> closes search, filter drawer and menus. Shortcuts do not fire inside input fields.', 'quickstock-for-woocommerce' ), array(
            'kbd' => array(),
        ) );
        ?>
                                </p>
                            </td>
                        </tr>
                    </table>
                </div>
            </details>

            <details class="qsfw-accordion">
                <summary>📜 <?php 
        esc_html_e( 'Stock log', 'quickstock-for-woocommerce' );
        ?></summary>
                <div class="qsfw-accordion-body">
                    <table class="form-table" style="max-width:760px;">
                        <tr>
                            <th scope="row"><?php 
        esc_html_e( 'Log history', 'quickstock-for-woocommerce' );
        ?></th>
                            <td>
                                <label>
                                    <input type="checkbox" name="qsfw_log_enabled" value="1" <?php 
        checked( $g_log_enabled, 1 );
        ?> />
                                    <?php 
        esc_html_e( 'Record stock changes', 'quickstock-for-woocommerce' );
        ?>
                                </label>
                                <p class="description">
                                    <?php 
        echo wp_kses( __( 'Logs every stock change (manual via the plugin as well as from orders) in the <strong>“📜 Log”</strong> tab: timestamp, product, value before → after, source and user.', 'quickstock-for-woocommerce' ), array(
            'strong' => array(),
        ) );
        ?>
                                </p>
                            </td>
                        </tr>
                        <tr>
                            <th scope="row"><?php 
        esc_html_e( 'Retention period', 'quickstock-for-woocommerce' );
        ?></th>
                            <td>
                                <select name="qsfw_log_retention_days">
                                    <option value="30"  <?php 
        selected( $g_log_retention, 30 );
        ?>><?php 
        esc_html_e( '30 days', 'quickstock-for-woocommerce' );
        ?></option>
                                    <option value="90"  <?php 
        selected( $g_log_retention, 90 );
        ?>><?php 
        esc_html_e( '90 days (default)', 'quickstock-for-woocommerce' );
        ?></option>
                                    <option value="365" <?php 
        selected( $g_log_retention, 365 );
        ?>><?php 
        esc_html_e( '365 days', 'quickstock-for-woocommerce' );
        ?></option>
                                    <option value="0"   <?php 
        selected( $g_log_retention, 0 );
        ?>><?php 
        esc_html_e( 'Unlimited', 'quickstock-for-woocommerce' );
        ?></option>
                                </select>
                                <p class="description">
                                    <?php 
        esc_html_e( 'Entries older than this are deleted automatically every day. “Unlimited” keeps all entries permanently – the table then grows continuously.', 'quickstock-for-woocommerce' );
        ?>
                                </p>
                            </td>
                        </tr>
                    </table>
                </div>
            </details>

            <?php 
        ?>

            <details class="qsfw-accordion">
                <summary>🧾 <?php 
        esc_html_e( 'Quick order', 'quickstock-for-woocommerce' );
        ?></summary>
                <div class="qsfw-accordion-body">
                    <table class="form-table" style="max-width:760px;">
                        <tr>
                            <th scope="row"><?php 
        esc_html_e( 'Default restock target', 'quickstock-for-woocommerce' );
        ?></th>
                            <td>
                                <input type="number" name="qsfw_default_restock_target" min="0" step="1"
                                       value="<?php 
        echo esc_attr( $g_restock_target );
        ?>" class="small-text" />
                                <p class="description">
                                    <?php 
        esc_html_e( 'Stock level products should be replenished to when no per-product target is set. Used to suggest the order quantity (target − current stock). 0 disables the suggestion.', 'quickstock-for-woocommerce' );
        ?>
                                </p>
                            </td>
                        </tr>
                    </table>
                </div>
            </details>

            <p><button type="submit" class="button button-primary">💾 <?php 
        esc_html_e( 'Save', 'quickstock-for-woocommerce' );
        ?></button></p>
        </form>
        <?php 
    }

    /* ===================================================================
     * SEKTION: ETIKETTEN-DESIGNER
     * =================================================================== */
    private static function process_label_forms() {
        if ( !current_user_can( 'manage_woocommerce' ) ) {
            return;
        }
        if ( !isset( $_REQUEST['page'] ) || $_REQUEST['page'] !== 'quickstock-for-woocommerce' ) {
            return;
        }
        if ( !isset( $_REQUEST['settings_subtab'] ) || $_REQUEST['settings_subtab'] !== 'labels' ) {
            return;
        }
        $base_url = admin_url( 'admin.php?page=quickstock-for-woocommerce&mode=settings&settings_subtab=labels' );
        // Link-Aktionen: objektgebundener Nonce (gleiche Konvention wie
        // qsfw_supplier_delete_<id> / qsfw_cf_delete_<slug> / qsfw_col_reset_<key>),
        // damit ein abgefangener Link nicht auf eine andere Vorlage umgebogen werden
        // kann. Ohne Nonce liessen sich diese Option-Writes per GET auslösen.
        if ( isset( $_REQUEST['label_delete'] ) ) {
            $tid = sanitize_text_field( wp_unslash( $_REQUEST['label_delete'] ) );
            check_admin_referer( 'qsfw_label_delete_' . $tid );
            QSFW_Label_Templates::delete( $tid );
            wp_safe_redirect( $base_url );
            exit;
        }
        if ( isset( $_REQUEST['label_duplicate'] ) ) {
            $tid = sanitize_text_field( wp_unslash( $_REQUEST['label_duplicate'] ) );
            check_admin_referer( 'qsfw_label_duplicate_' . $tid );
            QSFW_Label_Templates::duplicate( $tid );
            wp_safe_redirect( $base_url );
            exit;
        }
        if ( isset( $_REQUEST['label_set_default'] ) ) {
            $tid = sanitize_text_field( wp_unslash( $_REQUEST['label_set_default'] ) );
            check_admin_referer( 'qsfw_label_default_' . $tid );
            QSFW_Label_Templates::set_default( $tid );
            wp_safe_redirect( $base_url );
            exit;
        }
        if ( !empty( $_POST['qsfw_label_submitted'] ) ) {
            check_admin_referer( 'qsfw_label_save' );
            $id = ( isset( $_POST['label_id'] ) ? sanitize_text_field( wp_unslash( $_POST['label_id'] ) ) : '' );
            $name = ( isset( $_POST['label_name'] ) ? sanitize_text_field( wp_unslash( $_POST['label_name'] ) ) : '' );
            if ( $name === '' ) {
                $name = __( 'Untitled', 'quickstock-for-woocommerce' );
            }
            $tpl = QSFW_Label_Templates::blank_template();
            $tpl['name'] = $name;
            $tpl['width_mm'] = ( isset( $_POST['lbl_width'] ) ? (float) $_POST['lbl_width'] : 54.0 );
            $tpl['height_mm'] = ( isset( $_POST['lbl_height'] ) ? (float) $_POST['lbl_height'] : 17.0 );
            $tpl['dpi'] = ( isset( $_POST['lbl_dpi'] ) ? (int) $_POST['lbl_dpi'] : 300 );
            // Verschachtelte Element-Struktur ($_POST['el'][typ][feld]) NICHT am
            // Stueck einlesen: pro Feld typgerecht sanitisieren (Sniff-neutral).
            // Zahlen ueber Cast, Schalter ueber empty(); Whitelist-Strings
            // (align/format) NICHT ueber sanitize_key (radierte 'EAN13' aus) —
            // die finale Whitelist steht in normalize(). prefix/text ueber
            // wp_kses($v, array()): entfernt Tags, trimmt NICHT ("CHF " bleibt).
            $float_keys = array(
                'x',
                'y',
                'w',
                'h',
                'font',
                'letterspacing',
                'gap',
                'height_mm'
            );
            $int_keys = array('maxlines', 'modulewidth');
            foreach ( array_keys( QSFW_Label_Templates::element_types() ) as $type ) {
                $def = QSFW_Label_Templates::element_defaults( $type );
                $el = array();
                foreach ( $def as $k => $dv ) {
                    $has = isset( $_POST['el'][$type][$k] );
                    if ( $k === 'enabled' || $k === 'bold' || $k === 'strike' ) {
                        $el[$k] = ( $has && !empty( $_POST['el'][$type][$k] ) ? 1 : 0 );
                    } elseif ( in_array( $k, $float_keys, true ) ) {
                        $el[$k] = ( $has ? (float) $_POST['el'][$type][$k] : $dv );
                    } elseif ( in_array( $k, $int_keys, true ) ) {
                        $el[$k] = ( $has ? (int) $_POST['el'][$type][$k] : $dv );
                    } elseif ( $k === 'prefix' || $k === 'text' ) {
                        $el[$k] = ( $has ? wp_kses( wp_unslash( $_POST['el'][$type][$k] ), array() ) : $dv );
                    } else {
                        $el[$k] = ( $has ? sanitize_text_field( wp_unslash( $_POST['el'][$type][$k] ) ) : $dv );
                    }
                }
                // 'after' kommt als Checkbox (price ja/nein)
                if ( $type === 'title' ) {
                    $el['after'] = ( !empty( $_POST['el'][$type]['after'] ) ? 'price' : '' );
                }
                $tpl['elements'][$type] = $el;
            }
            // normalize() in save() übernimmt Typ-/Whitelist-Sanitizing
            $id = QSFW_Label_Templates::save( $id, $tpl );
            if ( !empty( $_POST['label_is_default'] ) ) {
                QSFW_Label_Templates::set_default( $id );
            }
            wp_safe_redirect( $base_url . '&qsfw_saved=1' );
            exit;
        }
    }

    private static function render_labels_section() {
        $templates = QSFW_Label_Templates::all();
        $default_id = QSFW_Label_Templates::get_default_id();
        $base_url = admin_url( 'admin.php?page=quickstock-for-woocommerce&mode=settings&settings_subtab=labels' );
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- reine Auswahl einer Vorlage fuer die schreibfreie Bearbeitungsansicht
        $edit = ( isset( $_REQUEST['edit_label'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['edit_label'] ) ) : '' );
        if ( $edit === 'new' ) {
            $editing = QSFW_Label_Templates::blank_template();
            $edit_id = '';
        } elseif ( $edit !== '' && isset( $templates[$edit] ) ) {
            $editing = $templates[$edit];
            $edit_id = $edit;
        } else {
            $editing = null;
            $edit_id = '';
        }
        $type_labels = QSFW_Label_Templates::element_types();
        $aligns = QSFW_Label_Templates::aligns();
        $formats = QSFW_Label_Templates::barcode_formats();
        $size_presets = QSFW_Label_Templates::size_presets();
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- reine Erfolgsanzeige nach einem bereits nonce-geprueften PRG-Redirect.
        $show_saved_notice = !empty( $_GET['qsfw_saved'] );
        ?>
        <div class="hb-settings-intro">
            <h2><?php 
        esc_html_e( 'Label designer', 'quickstock-for-woocommerce' );
        ?></h2>
            <p><?php 
        printf(
            /* translators: 1: <strong> tag, 2: </strong> tag, 3: <strong> tag, 4: </strong> tag */
            esc_html__( 'Create as many label templates as you like (size, fields and layout). The template marked as %1$sdefault%2$s is used when you click the label icon in the product list. All dimensions in %3$smm%4$s; the position is the top-left corner of each element.', 'quickstock-for-woocommerce' ),
            '<strong>',
            '</strong>',
            '<strong>',
            '</strong>'
        );
        ?></p>
        </div>

        <?php 
        if ( $show_saved_notice ) {
            ?>
            <div class="notice notice-success inline"><p><?php 
            esc_html_e( 'Template saved.', 'quickstock-for-woocommerce' );
            ?></p></div>
        <?php 
        }
        ?>

        <?php 
        if ( empty( $templates ) ) {
            ?>
            <div class="hb-empty-hint"><?php 
            esc_html_e( 'No label template created yet.', 'quickstock-for-woocommerce' );
            ?></div>
        <?php 
        } else {
            ?>
            <div class="hb-preset-list">
                <?php 
            foreach ( $templates as $tid => $tpl ) {
                $is_def = $tid === $default_id;
                $def_url = wp_nonce_url( $base_url . '&label_set_default=' . $tid, 'qsfw_label_default_' . $tid );
                $dup_url = wp_nonce_url( $base_url . '&label_duplicate=' . $tid, 'qsfw_label_duplicate_' . $tid );
                $del_url = wp_nonce_url( $base_url . '&label_delete=' . $tid, 'qsfw_label_delete_' . $tid );
                ?>
                    <div class="hb-preset-card">
                        <div class="hb-preset-head">
                            <strong><?php 
                echo esc_html( $tpl['name'] );
                ?></strong>
                            <span class="hb-preset-actions">
                                <?php 
                if ( !$is_def ) {
                    ?>
                                    <a class="button button-small" href="<?php 
                    echo esc_url( $def_url );
                    ?>">★ <?php 
                    esc_html_e( 'Default', 'quickstock-for-woocommerce' );
                    ?></a>
                                <?php 
                }
                ?>
                                <a class="button button-small" href="<?php 
                echo esc_url( $base_url . '&edit_label=' . $tid );
                ?>">✏️ <?php 
                esc_html_e( 'Edit', 'quickstock-for-woocommerce' );
                ?></a>
                                <a class="button button-small" href="<?php 
                echo esc_url( $dup_url );
                ?>">⧉ <?php 
                esc_html_e( 'Duplicate', 'quickstock-for-woocommerce' );
                ?></a>
                                <a class="button button-small hb-preset-delete" href="<?php 
                echo esc_url( $del_url );
                ?>">🗑</a>
                            </span>
                        </div>
                        <div class="hb-preset-meta">
                            <?php 
                echo esc_html( rtrim( rtrim( (string) $tpl['width_mm'], '0' ), '.' ) );
                ?> ×
                            <?php 
                echo esc_html( rtrim( rtrim( (string) $tpl['height_mm'], '0' ), '.' ) );
                ?> mm
                            · <?php 
                echo esc_html( $tpl['dpi'] );
                ?> dpi
                            <?php 
                $on = array();
                foreach ( $type_labels as $tk => $tl ) {
                    if ( !empty( $tpl['elements'][$tk]['enabled'] ) ) {
                        $on[] = $tl;
                    }
                }
                echo ' · ' . (( $on ? esc_html( implode( ', ', $on ) ) : '<em>' . esc_html__( 'no fields', 'quickstock-for-woocommerce' ) . '</em>' ));
                ?>
                        </div>
                        <?php 
                if ( $is_def ) {
                    ?>
                            <div class="hb-preset-defaults">
                                <span class="hb-preset-badge">★ <?php 
                    esc_html_e( 'Default template', 'quickstock-for-woocommerce' );
                    ?></span>
                            </div>
                        <?php 
                }
                ?>
                    </div>
                <?php 
            }
            ?>
            </div>
        <?php 
        }
        ?>

        <?php 
        if ( !$editing ) {
            ?>
            <div class="hb-settings-actions">
                <a class="button button-primary" href="<?php 
            echo esc_url( $base_url . '&edit_label=new' );
            ?>">➕ <?php 
            esc_html_e( 'New template', 'quickstock-for-woocommerce' );
            ?></a>
            </div>
        <?php 
        } else {
            $els = $editing['elements'];
            ?>
            <form method="post" action="<?php 
            echo esc_url( $base_url );
            ?>" class="hb-preset-editor hb-label-editor">
                <?php 
            wp_nonce_field( 'qsfw_label_save' );
            ?>
                <input type="hidden" name="qsfw_label_submitted" value="1" />
                <input type="hidden" name="label_id" value="<?php 
            echo esc_attr( $edit_id );
            ?>" />

                <h3><?php 
            echo esc_html( ( $edit_id ? __( 'Edit template', 'quickstock-for-woocommerce' ) : __( 'New template', 'quickstock-for-woocommerce' ) ) );
            ?></h3>

                <p>
                    <label><strong><?php 
            esc_html_e( 'Name', 'quickstock-for-woocommerce' );
            ?></strong><br>
                    <input type="text" name="label_name" value="<?php 
            echo esc_attr( $editing['name'] );
            ?>" class="regular-text" placeholder="<?php 
            esc_attr_e( 'e.g. Shelf 54×17', 'quickstock-for-woocommerce' );
            ?>" required /></label>
                </p>

                <div class="hb-label-grid">
                    <div class="hb-label-form">
                        <fieldset class="hb-label-fs">
                            <legend><?php 
            esc_html_e( 'Label size', 'quickstock-for-woocommerce' );
            ?></legend>
                            <label><?php 
            esc_html_e( 'Choose preset', 'quickstock-for-woocommerce' );
            ?>
                                <select id="qsfw-size-preset">
                                    <option value="">— <?php 
            esc_html_e( 'Custom', 'quickstock-for-woocommerce' );
            ?> —</option>
                                    <?php 
            foreach ( $size_presets as $sp ) {
                ?>
                                        <option value="<?php 
                echo esc_attr( $sp['w'] . 'x' . $sp['h'] );
                ?>"
                                            <?php 
                selected( (float) $sp['w'] === (float) $editing['width_mm'] && (float) $sp['h'] === (float) $editing['height_mm'] );
                ?>>
                                            <?php 
                echo esc_html( $sp['label'] );
                ?>
                                        </option>
                                    <?php 
            }
            ?>
                                </select>
                            </label>
                            <label><?php 
            esc_html_e( 'Width (mm)', 'quickstock-for-woocommerce' );
            ?>
                                <input type="number" step="0.1" min="5" name="lbl_width" value="<?php 
            echo esc_attr( $editing['width_mm'] );
            ?>" />
                            </label>
                            <label><?php 
            esc_html_e( 'Height (mm)', 'quickstock-for-woocommerce' );
            ?>
                                <input type="number" step="0.1" min="5" name="lbl_height" value="<?php 
            echo esc_attr( $editing['height_mm'] );
            ?>" />
                            </label>
                            <label><?php 
            esc_html_e( 'Resolution (dpi)', 'quickstock-for-woocommerce' );
            ?>
                                <input type="number" step="1" min="72" max="1200" name="lbl_dpi" value="<?php 
            echo esc_attr( $editing['dpi'] );
            ?>" />
                            </label>
                        </fieldset>

                        <?php 
            foreach ( $type_labels as $type => $label ) {
                $e = $els[$type];
                ?>
                            <fieldset class="hb-label-fs hb-label-el" data-el="<?php 
                echo esc_attr( $type );
                ?>">
                                <legend>
                                    <label><input type="checkbox" name="el[<?php 
                echo esc_attr( $type );
                ?>][enabled]" data-f="enabled" value="1" <?php 
                checked( !empty( $e['enabled'] ) );
                ?> /> <?php 
                echo esc_html( $label );
                ?></label>
                                </legend>
                                <div class="hb-label-row">
                                    <label>X (mm)<input type="number" step="0.1" name="el[<?php 
                echo esc_attr( $type );
                ?>][x]" data-f="x" value="<?php 
                echo esc_attr( $e['x'] );
                ?>" /></label>
                                    <label>Y (mm)<input type="number" step="0.1" name="el[<?php 
                echo esc_attr( $type );
                ?>][y]" data-f="y" value="<?php 
                echo esc_attr( $e['y'] );
                ?>" /></label>
                                    <?php 
                if ( $type !== 'barcode' ) {
                    ?>
                                        <label title="<?php 
                    esc_attr_e( '0 = automatic (content)', 'quickstock-for-woocommerce' );
                    ?>"><?php 
                    esc_html_e( 'Width (mm)', 'quickstock-for-woocommerce' );
                    ?><input type="number" step="0.1" min="0" name="el[<?php 
                    echo esc_attr( $type );
                    ?>][w]" data-f="w" value="<?php 
                    echo esc_attr( $e['w'] );
                    ?>" /></label>
                                        <label title="<?php 
                    esc_attr_e( '0 = automatic (content)', 'quickstock-for-woocommerce' );
                    ?>"><?php 
                    esc_html_e( 'Height (mm)', 'quickstock-for-woocommerce' );
                    ?><input type="number" step="0.1" min="0" name="el[<?php 
                    echo esc_attr( $type );
                    ?>][h]" data-f="h" value="<?php 
                    echo esc_attr( $e['h'] );
                    ?>" /></label>
                                        <label><?php 
                    esc_html_e( 'Font (mm)', 'quickstock-for-woocommerce' );
                    ?><input type="number" step="0.1" min="0.5" name="el[<?php 
                    echo esc_attr( $type );
                    ?>][font]" data-f="font" value="<?php 
                    echo esc_attr( $e['font'] );
                    ?>" /></label>
                                        <label class="hb-label-chk"><input type="checkbox" name="el[<?php 
                    echo esc_attr( $type );
                    ?>][bold]" data-f="bold" value="1" <?php 
                    checked( !empty( $e['bold'] ) );
                    ?> /> <?php 
                    esc_html_e( 'Bold', 'quickstock-for-woocommerce' );
                    ?></label>
                                        <label class="hb-label-chk"><input type="checkbox" name="el[<?php 
                    echo esc_attr( $type );
                    ?>][strike]" data-f="strike" value="1" <?php 
                    checked( !empty( $e['strike'] ) );
                    ?> /> <?php 
                    esc_html_e( 'Strikethrough', 'quickstock-for-woocommerce' );
                    ?></label>
                                        <label><?php 
                    esc_html_e( 'Letter spacing (mm)', 'quickstock-for-woocommerce' );
                    ?><input type="number" step="0.1" min="0" name="el[<?php 
                    echo esc_attr( $type );
                    ?>][letterspacing]" data-f="letterspacing" value="<?php 
                    echo esc_attr( $e['letterspacing'] );
                    ?>" /></label>
                                        <label><?php 
                    esc_html_e( 'Alignment', 'quickstock-for-woocommerce' );
                    ?>
                                            <select name="el[<?php 
                    echo esc_attr( $type );
                    ?>][align]" data-f="align">
                                                <?php 
                    foreach ( $aligns as $al ) {
                        ?>
                                                    <option value="<?php 
                        echo esc_attr( $al );
                        ?>" <?php 
                        selected( $e['align'], $al );
                        ?>><?php 
                        echo esc_html( $al );
                        ?></option>
                                                <?php 
                    }
                    ?>
                                            </select>
                                        </label>
                                    <?php 
                }
                ?>
                                </div>
                                <div class="hb-label-row">
                                    <?php 
                if ( $type === 'price' ) {
                    ?>
                                        <label><?php 
                    esc_html_e( 'Prefix', 'quickstock-for-woocommerce' );
                    ?><input type="text" name="el[<?php 
                    echo esc_attr( $type );
                    ?>][prefix]" data-f="prefix" value="<?php 
                    echo esc_attr( $e['prefix'] );
                    ?>" /></label>
                                    <?php 
                }
                ?>
                                    <?php 
                ?>
                                    <?php 
                if ( $type === 'title' ) {
                    ?>
                                        <label><?php 
                    esc_html_e( 'Max. lines', 'quickstock-for-woocommerce' );
                    ?><input type="number" step="1" min="1" max="4" name="el[title][maxlines]" data-f="maxlines" value="<?php 
                    echo esc_attr( $e['maxlines'] );
                    ?>" /></label>
                                        <label class="hb-label-chk"><input type="checkbox" name="el[title][after]" data-f="after" value="price" <?php 
                    checked( $e['after'] === 'price' );
                    ?> /> <?php 
                    esc_html_e( 'Right next to price', 'quickstock-for-woocommerce' );
                    ?></label>
                                        <label><?php 
                    esc_html_e( 'Gap (mm)', 'quickstock-for-woocommerce' );
                    ?><input type="number" step="0.1" name="el[title][gap]" data-f="gap" value="<?php 
                    echo esc_attr( $e['gap'] );
                    ?>" /></label>
                                    <?php 
                }
                ?>
                                    <?php 
                if ( $type === 'barcode' ) {
                    ?>
                                        <label><?php 
                    esc_html_e( 'Height (mm)', 'quickstock-for-woocommerce' );
                    ?><input type="number" step="0.1" min="1" name="el[barcode][height_mm]" data-f="height_mm" value="<?php 
                    echo esc_attr( $e['height_mm'] );
                    ?>" /></label>
                                        <label><?php 
                    esc_html_e( 'Module width', 'quickstock-for-woocommerce' );
                    ?><input type="number" step="1" min="1" max="8" name="el[barcode][modulewidth]" data-f="modulewidth" value="<?php 
                    echo esc_attr( $e['modulewidth'] );
                    ?>" /></label>
                                        <label><?php 
                    esc_html_e( 'Format', 'quickstock-for-woocommerce' );
                    ?>
                                            <select name="el[barcode][format]" data-f="format">
                                                <?php 
                    foreach ( $formats as $fmt ) {
                        ?>
                                                    <option value="<?php 
                        echo esc_attr( $fmt );
                        ?>" <?php 
                        selected( $e['format'], $fmt );
                        ?>><?php 
                        echo esc_html( $fmt );
                        ?></option>
                                                <?php 
                    }
                    ?>
                                            </select>
                                        </label>
                                    <?php 
                }
                ?>
                                    <?php 
                ?>
                                </div>
                            </fieldset>
                        <?php 
            }
            ?>

                        <?php 
            if ( !qsfw_is_pro() ) {
                ?>
                            <fieldset class="hb-label-fs hb-label-pro-hint">
                                <legend><?php 
                esc_html_e( 'More label fields', 'quickstock-for-woocommerce' );
                ?> <?php 
                echo wp_kses_post( QSFW_Renderer::pro_badge() );
                ?></legend>
                                <p class="description" style="margin-top:0;">
                                    <?php 
                esc_html_e( 'QuickStock Pro adds more freely placeable fields to your labels:', 'quickstock-for-woocommerce' );
                ?>
                                </p>
                                <ul style="margin:6px 0 12px 18px;list-style:disc;color:#646970;">
                                    <li><?php 
                esc_html_e( 'Sale price', 'quickstock-for-woocommerce' );
                ?></li>
                                    <li><?php 
                esc_html_e( 'SKU as text', 'quickstock-for-woocommerce' );
                ?></li>
                                    <li><?php 
                esc_html_e( 'Free text (e.g. website)', 'quickstock-for-woocommerce' );
                ?></li>
                                    <li><?php 
                esc_html_e( 'Date', 'quickstock-for-woocommerce' );
                ?></li>
                                </ul>
                                <?php 
                $pro_url = QSFW_Renderer::pro_upgrade_url();
                if ( $pro_url !== '' ) {
                    ?>
                                    <a class="button button-secondary" href="<?php 
                    echo esc_url( $pro_url );
                    ?>" target="_blank" rel="noopener"><?php 
                    esc_html_e( 'Upgrade to Pro', 'quickstock-for-woocommerce' );
                    ?></a>
                                <?php 
                }
                ?>
                            </fieldset>
                        <?php 
            }
            ?>

                        <fieldset class="hb-preset-default-box">
                            <legend><?php 
            esc_html_e( 'Default', 'quickstock-for-woocommerce' );
            ?></legend>
                            <label><input type="checkbox" name="label_is_default" value="1" <?php 
            checked( $edit_id !== '' && $edit_id === $default_id );
            ?> /> <?php 
            esc_html_e( 'Use this template as the default for label printing', 'quickstock-for-woocommerce' );
            ?></label>
                        </fieldset>

                        <div class="hb-settings-actions">
                            <button type="submit" class="button button-primary">💾 <?php 
            esc_html_e( 'Save template', 'quickstock-for-woocommerce' );
            ?></button>
                            <a class="button button-secondary" href="<?php 
            echo esc_url( $base_url );
            ?>" style="margin-left:8px;"><?php 
            esc_html_e( 'Cancel', 'quickstock-for-woocommerce' );
            ?></a>
                        </div>
                    </div>

                    <div class="hb-label-preview-wrap">
                        <p class="description"><?php 
            esc_html_e( 'Live preview (sample data)', 'quickstock-for-woocommerce' );
            ?></p>
                        <canvas id="qsfw-label-preview"></canvas>
                        <p class="hb-label-hint"><?php 
            esc_html_e( 'Click an element to select &amp; move · drag the edges to resize', 'quickstock-for-woocommerce' );
            ?></p>
                    </div>
                </div>
            </form>
        <?php 
        }
    }

    /* ===================================================================
     * SEKTION: LIEFERANTEN (Mini-CRM)
     * =================================================================== */
    /** Upsell-Panel für den Lieferanten-Subtab im Free-Plan (statt der Verwaltung). */
    private static function render_suppliers_upsell() {
        QSFW_Renderer::echo_pro_upsell_panel( '🚚', __( 'Suppliers', 'quickstock-for-woocommerce' ), __( 'Manage suppliers, assign products and supplier SKUs, track lead times and turn your reorder list into purchase orders — available in QuickStock Pro.', 'quickstock-for-woocommerce' ) );
    }

}
