HEX
Server: Apache
System: Linux d5123.usc1.stableserver.net 5.14.0-570.17.1.el9_6.x86_64 #1 SMP PREEMPT_DYNAMIC Sat May 24 12:53:17 EDT 2025 x86_64
User: d5123 (1001)
PHP: 8.4.21
Disabled: NONE
Upload Files
File: /home/d5123/myboofola_com/wp-content/plugins/mxchat-basic/includes/admin-onboarding-page.php
<?php
/**
 * MxChat → Onboarding admin page (linear wizard).
 *
 * Plan: plan-mxchat-20260527-905439 — SUPERSEDES the 704e25 checklist UI.
 *
 * Five-step wizard:
 *   1. Choose chat provider + model + API key
 *   2. Choose embedding provider + model + API key (dedup if same as chat)
 *   3. Seed the knowledge base (live-poll the KB row count)
 *   4. Try Actions (optional)
 *   5. Congrats + PRO add-ons (auto-graduates the menu item)
 *
 * Preserved from plan-f7c7d4: menu item, "Onboarding" naming, dismiss button,
 * auto-graduate via mxchat_onboarding_dismissed, 301 from old slug, Stuck?
 * Get help footer URLs, brand tokens, responsive 1280x800 / 390x844 quality bar.
 *
 * State storage:
 *   mxchat_onboarding_progress   — assoc array { chat_model, embedding_model,
 *                                  knowledge_base, actions } booleans. Drives
 *                                  resume-where-you-left-off on reload.
 *   mxchat_onboarding_dismissed  — reused from f7c7d4. Set when the user
 *                                  lands on Step 5 (auto-graduate) OR clicks
 *                                  Dismiss anywhere.
 *   mxchat_onboarding_auto_graduated — companion flag from f7c7d4; set when
 *                                  graduation was automatic rather than
 *                                  user-initiated.
 *   Provider/model/key options are the SAME ones Settings already uses
 *   (mxchat_options sub-keys: api_key for OpenAI, claude_api_key,
 *   xai_api_key, deepseek_api_key, gemini_api_key, openrouter_api_key,
 *   voyage_api_key, custom_provider_api_key + perplexity_api_key if/when
 *   that provider lands). No parallel key storage.
 *
 * Admin-chrome surgery (Onboarding page only): adds body class
 * `mxchat-onboarding-focused` from class-mxchat-admin.php's admin_body_class
 * hook so admin-onboarding-wizard.css can collapse the WP admin sidebar and
 * suppress the bottom dashboard cards on THIS page only.
 *
 * @package MxChat
 * @since   3.2.7
 */

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

/**
 * Read the persistent onboarding-dismissed flag.
 */
function mxchat_onboarding_is_dismissed() {
    return (bool) get_option('mxchat_onboarding_dismissed', 0);
}

/**
 * Was the dismiss caused by auto-graduation rather than a user click?
 */
function mxchat_onboarding_is_auto_graduated() {
    return (bool) get_option('mxchat_onboarding_auto_graduated', 0);
}

/**
 * Read the wizard progress state. Returns the four step booleans.
 */
function mxchat_onboarding_get_progress() {
    $defaults = array(
        'chat_model'      => false,
        'behavior'        => false,
        'embedding_model' => false,
        'knowledge_base'  => false,
        'actions'         => false,
    );
    $stored = get_option('mxchat_onboarding_progress', array());
    if (!is_array($stored)) {
        $stored = array();
    }
    $out = array();
    foreach ($defaults as $k => $v) {
        $out[$k] = isset($stored[$k]) ? (bool) $stored[$k] : $v;
    }
    return $out;
}

/**
 * Update one or more wizard progress flags. Merges into the stored array.
 */
function mxchat_onboarding_set_progress($changes) {
    $current = mxchat_onboarding_get_progress();
    foreach ((array) $changes as $k => $v) {
        if (array_key_exists($k, $current)) {
            $current[$k] = (bool) $v;
        }
    }
    update_option('mxchat_onboarding_progress', $current);
    return $current;
}

/**
 * Existing AJAX: user-initiated dismiss. Preserved verbatim from f7c7d4.
 */
add_action('wp_ajax_mxchat_dismiss_onboarding', 'mxchat_handle_dismiss_onboarding');
function mxchat_handle_dismiss_onboarding() {
    if (!current_user_can('manage_options')) {
        wp_send_json_error(array('message' => __('You do not have permission to do this.', 'mxchat')), 403);
    }
    check_ajax_referer('mxchat_dismiss_onboarding', 'nonce');

    update_option('mxchat_onboarding_dismissed', 1);
    update_option('mxchat_onboarding_auto_graduated', 0);

    wp_send_json_success(array('dismissed' => true));
}

/**
 * admin_post: "Show MxChat Onboarding again" — clears both dismissed flag
 * AND wizard progress so the user gets a fresh wizard. Preserved from f7c7d4
 * with the added progress-reset.
 */
add_action('admin_post_mxchat_unhide_onboarding', 'mxchat_handle_unhide_onboarding');
function mxchat_handle_unhide_onboarding() {
    if (!current_user_can('manage_options')) {
        wp_die(esc_html__('You do not have permission to do this.', 'mxchat'));
    }
    check_admin_referer('mxchat_unhide_onboarding');

    delete_option('mxchat_onboarding_dismissed');
    delete_option('mxchat_onboarding_auto_graduated');

    wp_safe_redirect(admin_url('admin.php?page=mxchat-onboarding'));
    exit;
}

/**
 * admin_init: legacy slug 301 redirect (preserved from f7c7d4).
 */
add_action('admin_init', 'mxchat_onboarding_legacy_slug_redirect');
function mxchat_onboarding_legacy_slug_redirect() {
    if (!isset($_GET['page'])) {
        return;
    }
    if ($_GET['page'] !== 'mxchat-dashboard') {
        return;
    }
    wp_safe_redirect(admin_url('admin.php?page=mxchat-onboarding'), 301);
    exit;
}

/**
 * Provider catalog used by Steps 1 and 2. Wraps the canonical catalog in
 * includes/class-mxchat-model-catalog.php (plan-d14e89) so a single edit
 * there flows through to the Onboarding wizard's dropdowns. Shape preserved
 * for back-compat:
 *   [ slug => [ label, key_option, chat_models{}, embedding_models{} ] ]
 * Plus an extra `requires_key_to_load_models` flag per provider (true for
 * OpenRouter) so the wizard can disable that provider in its picker.
 */
function mxchat_onboarding_provider_catalog() {
    if (!class_exists('MxChat_Model_Catalog')) {
        require_once plugin_dir_path(__FILE__) . 'class-mxchat-model-catalog.php';
    }
    $chat = MxChat_Model_Catalog::chat_models();
    $emb  = MxChat_Model_Catalog::embedding_models();

    $out = array();
    $all_slugs = array_unique(array_merge(array_keys($chat), array_keys($emb)));
    foreach ($all_slugs as $slug) {
        $chat_models  = array();
        $requires_key = false;
        $disable_onb  = false;
        if (isset($chat[$slug])) {
            foreach ($chat[$slug]['models'] as $id => $entry) {
                $chat_models[$id] = $entry['label'];
            }
            $requires_key = !empty($chat[$slug]['requires_key_to_load_models']);
            $disable_onb  = !empty($chat[$slug]['disable_in_onboarding']);
        }
        $embed_models = array();
        if (isset($emb[$slug])) {
            foreach ($emb[$slug]['models'] as $id => $entry) {
                $embed_models[$id] = $entry['label'];
            }
        }
        $out[$slug] = array(
            'label'                       => MxChat_Model_Catalog::provider_label($slug),
            'key_option'                  => MxChat_Model_Catalog::key_option_for_provider($slug),
            'chat_models'                 => $chat_models,
            'embedding_models'            => $embed_models,
            'requires_key_to_load_models' => $requires_key,
            'disable_in_onboarding'       => ($disable_onb || $requires_key),
        );
    }
    return $out;
}

/**
 * Infer the provider slug from a chat model id, mirroring the rule of thumb
 * the model picker uses. Returns 'openai' / 'claude' / 'gemini' / 'xai' /
 * 'deepseek' / 'openrouter' / 'custom' or '' if unknown.
 */
function mxchat_onboarding_provider_from_model($model_id) {
    $m = strtolower((string) $model_id);
    if ($m === '') return '';
    if (strpos($m, 'gpt-') === 0 || strpos($m, 'o1-') === 0 || strpos($m, 'o3-') === 0) return 'openai';
    if (strpos($m, 'claude-') === 0) return 'claude';
    if (strpos($m, 'gemini-') === 0) return 'gemini';
    if (strpos($m, 'grok') === 0) return 'xai';
    if (strpos($m, 'deepseek') === 0) return 'deepseek';
    if (strpos($m, 'sonar') === 0 || strpos($m, 'pplx-') === 0) return 'perplexity';
    if ($m === 'openrouter' || strpos($m, '/') !== false) return 'openrouter';
    if (strpos($m, 'custom') === 0) return 'custom';
    return '';
}

/**
 * Mirror for embedding models.
 */
function mxchat_onboarding_provider_from_embedding_model($model_id) {
    $m = strtolower((string) $model_id);
    if ($m === '') return '';
    if (strpos($m, 'text-embedding-') === 0) return 'openai';
    if (strpos($m, 'voyage') === 0) return 'voyage';
    if (strpos($m, 'gemini-embedding') === 0) return 'gemini';
    return '';
}

/**
 * Whether the given provider has a non-empty API key saved.
 */
function mxchat_onboarding_provider_has_key($provider_slug) {
    $catalog = mxchat_onboarding_provider_catalog();
    if (!isset($catalog[$provider_slug])) return false;
    $opts = get_option('mxchat_options', array());
    if (!is_array($opts)) $opts = array();
    $field = $catalog[$provider_slug]['key_option'];
    return !empty($opts[$field]) && trim((string) $opts[$field]) !== '';
}

/**
 * KB row count. The canonical KB content table is
 * {$wpdb->prefix}mxchat_system_prompt_content — see mxchat-basic.php:716
 * where the table is created. An earlier draft of this function queried
 * mxchat_embeddings (which doesn't exist on most installs), causing Step 3
 * to always report "No knowledge base items yet" even after items had been
 * added. Plan-d14e89 Issue 6.
 */
function mxchat_onboarding_kb_count() {
    global $wpdb;
    $table = $wpdb->prefix . 'mxchat_system_prompt_content';
    $exists = (bool) $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $table));
    if (!$exists) return 0;
    return (int) $wpdb->get_var("SELECT COUNT(*) FROM {$table}");
}

/**
 * AJAX: live KB status poll for Step 3. Returns { count: N }.
 * Nonce-protected per plan spec (use per-request nonce path from 6a68c9 —
 * here the nonce is issued fresh in the page renderer, NOT cached, since
 * admin pages aren't page-cached).
 */
add_action('wp_ajax_mxchat_onboarding_kb_status', 'mxchat_onboarding_ajax_kb_status');
function mxchat_onboarding_ajax_kb_status() {
    if (!current_user_can('manage_options')) {
        wp_send_json_error(array('message' => __('You do not have permission.', 'mxchat')), 403);
    }
    check_ajax_referer('mxchat_onboarding_nonce', 'nonce');
    wp_send_json_success(array('count' => mxchat_onboarding_kb_count()));
}

/**
 * AJAX: save Step 1 (chat) or Step 2 (embedding) selection. Persists
 * provider/model/key into the SAME mxchat_options sub-keys Settings uses
 * (no parallel storage), then flips the corresponding progress flag.
 *
 * Expected POST: which=chat|embedding, provider=<slug>, model=<id>,
 * api_key=<string optional — only set if a fresh key was entered>.
 */
add_action('wp_ajax_mxchat_onboarding_save_step', 'mxchat_onboarding_ajax_save_step');
function mxchat_onboarding_ajax_save_step() {
    if (!current_user_can('manage_options')) {
        wp_send_json_error(array('message' => __('You do not have permission.', 'mxchat')), 403);
    }
    check_ajax_referer('mxchat_onboarding_nonce', 'nonce');

    $which    = isset($_POST['which']) ? sanitize_key($_POST['which']) : '';

    // Behavior step branch (plan-a2e4d6) — saves system_prompt_instructions
    // into the SAME mxchat_options sub-key Settings uses, no parallel storage.
    if ($which === 'behavior') {
        $instructions = isset($_POST['system_prompt_instructions'])
            ? sanitize_textarea_field(wp_unslash($_POST['system_prompt_instructions']))
            : '';
        $opts = get_option('mxchat_options', array());
        if (!is_array($opts)) $opts = array();
        $opts['system_prompt_instructions'] = $instructions;
        update_option('mxchat_options', $opts);
        mxchat_onboarding_set_progress(array('behavior' => true));
        wp_send_json_success(array(
            'progress' => mxchat_onboarding_get_progress(),
        ));
    }

    $provider = isset($_POST['provider']) ? sanitize_key($_POST['provider']) : '';
    $model    = isset($_POST['model']) ? sanitize_text_field(wp_unslash($_POST['model'])) : '';
    $api_key  = isset($_POST['api_key']) ? sanitize_text_field(wp_unslash($_POST['api_key'])) : '';

    $catalog = mxchat_onboarding_provider_catalog();
    if (!in_array($which, array('chat', 'embedding'), true)) {
        wp_send_json_error(array('message' => __('Invalid step.', 'mxchat')), 400);
    }
    if (!isset($catalog[$provider])) {
        wp_send_json_error(array('message' => __('Unknown provider.', 'mxchat')), 400);
    }
    $model_list = $which === 'chat' ? $catalog[$provider]['chat_models'] : $catalog[$provider]['embedding_models'];
    if (!isset($model_list[$model])) {
        wp_send_json_error(array('message' => __('Model not valid for this provider.', 'mxchat')), 400);
    }

    $opts = get_option('mxchat_options', array());
    if (!is_array($opts)) $opts = array();

    // Persist the key if a fresh one was sent. Empty string means "no change"
    // (the UI sends '' when the user is reusing an already-saved key).
    if ($api_key !== '') {
        $opts[$catalog[$provider]['key_option']] = $api_key;
    }

    if ($which === 'chat') {
        $opts['model'] = $model;
    } else {
        $opts['embedding_model'] = $model;
    }
    update_option('mxchat_options', $opts);

    $progress_key = $which === 'chat' ? 'chat_model' : 'embedding_model';
    mxchat_onboarding_set_progress(array($progress_key => true));

    wp_send_json_success(array(
        'progress' => mxchat_onboarding_get_progress(),
    ));
}

/**
 * AJAX: mark a step done (used by Step 4 actions Skip/Continue, and Step 3
 * Continue once KB is populated). No-op if the step name is unknown.
 */
add_action('wp_ajax_mxchat_onboarding_mark_step', 'mxchat_onboarding_ajax_mark_step');
function mxchat_onboarding_ajax_mark_step() {
    if (!current_user_can('manage_options')) {
        wp_send_json_error(array('message' => __('You do not have permission.', 'mxchat')), 403);
    }
    check_ajax_referer('mxchat_onboarding_nonce', 'nonce');

    $step  = isset($_POST['step']) ? sanitize_key($_POST['step']) : '';
    $valid = array('chat_model', 'behavior', 'embedding_model', 'knowledge_base', 'actions');
    if (!in_array($step, $valid, true)) {
        wp_send_json_error(array('message' => __('Unknown step.', 'mxchat')), 400);
    }
    mxchat_onboarding_set_progress(array($step => true));
    wp_send_json_success(array('progress' => mxchat_onboarding_get_progress()));
}

/**
 * AJAX: auto-graduate on Step 5 land. Sets dismissed + auto_graduated flags
 * (same flags f7c7d4 used) so the menu item disappears on next admin nav.
 */
add_action('wp_ajax_mxchat_onboarding_auto_graduate', 'mxchat_onboarding_ajax_auto_graduate');
function mxchat_onboarding_ajax_auto_graduate() {
    if (!current_user_can('manage_options')) {
        wp_send_json_error(array('message' => __('You do not have permission.', 'mxchat')), 403);
    }
    check_ajax_referer('mxchat_onboarding_nonce', 'nonce');

    update_option('mxchat_onboarding_dismissed', 1);
    update_option('mxchat_onboarding_auto_graduated', 1);
    wp_send_json_success(array('graduated' => true));
}

/**
 * Render the Onboarding page — wizard layout. Entry point wired from
 * class-mxchat-admin.php.
 */
function mxchat_render_onboarding_page() {
    if (!current_user_can('manage_options')) {
        wp_die(esc_html__('You do not have permission to access this page.', 'mxchat'));
    }

    $opts = get_option('mxchat_options', array());
    if (!is_array($opts)) $opts = array();

    $progress = mxchat_onboarding_get_progress();
    $catalog  = mxchat_onboarding_provider_catalog();

    // Compute saved-key state per provider so the JS can short-circuit the
    // API-key input to the "already saved" checkmark on initial render.
    $key_state = array();
    foreach ($catalog as $slug => $entry) {
        $key_state[$slug] = mxchat_onboarding_provider_has_key($slug);
    }

    // Current selections (pre-populate the wizard if user already had values
    // in Settings before opening Onboarding).
    $current_chat_model      = isset($opts['model']) ? (string) $opts['model'] : '';
    $current_chat_provider   = mxchat_onboarding_provider_from_model($current_chat_model);
    $current_embed_model     = isset($opts['embedding_model']) ? (string) $opts['embedding_model'] : '';
    $current_embed_provider  = mxchat_onboarding_provider_from_embedding_model($current_embed_model);

    // Pre-credit logic — run BEFORE deciding the initial step so the landing
    // step reflects pre-existing Settings values. The wizard is six steps now
    // (plan-a2e4d6 inserted "AI Behavior" at position 2):
    //   1. Chat model    → progress.chat_model
    //   2. AI Behavior   → progress.behavior  (NEW)
    //   3. Embedding     → progress.embedding_model
    //   4. Knowledge base→ progress.knowledge_base
    //   5. Actions       → progress.actions
    //   6. Congrats      → no progress flag (all-five-complete view)

    // Pre-credit Step 1 (chat) if a chat model + key are already saved.
    if (!$progress['chat_model'] && $current_chat_model !== '' && $current_chat_provider !== '' && !empty($key_state[$current_chat_provider])) {
        mxchat_onboarding_set_progress(array('chat_model' => true));
        $progress['chat_model'] = true;
    }
    // Pre-credit Step 2 (behavior) if system_prompt_instructions is non-empty
    // — the user already set this in Settings before opening Onboarding.
    $current_instructions = isset($opts['system_prompt_instructions']) ? (string) $opts['system_prompt_instructions'] : '';
    if (!$progress['behavior'] && trim($current_instructions) !== '') {
        mxchat_onboarding_set_progress(array('behavior' => true));
        $progress['behavior'] = true;
    }
    // Pre-credit Step 3 (embedding) if model + key already saved.
    if (!$progress['embedding_model'] && $current_embed_model !== '' && $current_embed_provider !== '' && !empty($key_state[$current_embed_provider])) {
        mxchat_onboarding_set_progress(array('embedding_model' => true));
        $progress['embedding_model'] = true;
    }
    // Pre-credit Step 4 (KB) if rows already exist.
    if (!$progress['knowledge_base'] && mxchat_onboarding_kb_count() > 0) {
        mxchat_onboarding_set_progress(array('knowledge_base' => true));
        $progress['knowledge_base'] = true;
    }

    // First-not-done step is where we land on load. With all five flags true,
    // we land on Step 6 (Congrats).
    if (!$progress['chat_model'])           $initial_step = 1;
    elseif (!$progress['behavior'])         $initial_step = 2;
    elseif (!$progress['embedding_model'])  $initial_step = 3;
    elseif (!$progress['knowledge_base'])   $initial_step = 4;
    elseif (!$progress['actions'])          $initial_step = 5;
    else                                    $initial_step = 6;

    $plugin_url    = plugin_dir_url(dirname(__FILE__));
    $dismiss_nonce = wp_create_nonce('mxchat_dismiss_onboarding');
    $wizard_nonce  = wp_create_nonce('mxchat_onboarding_nonce');

    $current_slug = isset($_GET['page']) ? sanitize_key($_GET['page']) : 'mxchat-onboarding';
    $nav_items = array(
        array('slug' => 'mxchat-onboarding',  'label' => __('Onboarding',      'mxchat'), 'svg' => '<polyline points="3 9 12 2 21 9 21 21 14 21 14 14 10 14 10 21 3 21 3 9"/>'),
        array('slug' => 'mxchat-settings',    'label' => __('Settings',        'mxchat'), 'svg' => '<circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33h.01a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>'),
        array('slug' => 'mxchat-prompts',     'label' => __('Knowledge',       'mxchat'), 'svg' => '<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/>'),
        array('slug' => 'mxchat-transcripts', 'label' => __('Transcripts',     'mxchat'), 'svg' => '<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>'),
        array('slug' => 'mxchat-actions',     'label' => __('Actions',         'mxchat'), 'svg' => '<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/>'),
        array('slug' => 'mxchat-content',     'label' => __('Content',         'mxchat'), 'svg' => '<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/>'),
        array('slug' => 'mxchat-api-access',  'label' => __('API Access',      'mxchat'), 'svg' => '<path d="m21 2-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0 3 3L22 7l-3-3m-3.5 3.5L19 4"/>'),
        array('slug' => 'mxchat-activation',  'label' => __('Pro & Extensions','mxchat'), 'svg' => '<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>'),
    );

    // Build a JS-shaped catalog for the wizard's client-side step machine.
    $js_catalog = array();
    foreach ($catalog as $slug => $entry) {
        $js_catalog[$slug] = array(
            'label'                   => $entry['label'],
            'chatModels'              => $entry['chat_models'],
            'embeddingModels'         => $entry['embedding_models'],
            'hasKey'                  => $key_state[$slug],
            'requiresKeyToLoadModels' => !empty($entry['requires_key_to_load_models']),
        );
    }

    // Step metadata for the clickable pill indicator (plan-a2e4d6). Each entry:
    //   - id:      progress flag this step gates (null for Congrats)
    //   - label:   short pill label
    //   - title:   full step heading (also exposed for the legacy "Step N of M"
    //              text-fallback)
    $steps_meta = array(
        array('num' => 1, 'flag' => 'chat_model',      'label' => __('Chat model',  'mxchat'), 'title' => __('Choose your chat model',           'mxchat')),
        array('num' => 2, 'flag' => 'behavior',        'label' => __('Behavior',    'mxchat'), 'title' => __('Tell your chatbot how to behave',  'mxchat')),
        array('num' => 3, 'flag' => 'embedding_model', 'label' => __('Embedding',   'mxchat'), 'title' => __('Choose your embedding model',      'mxchat')),
        array('num' => 4, 'flag' => 'knowledge_base',  'label' => __('Knowledge',   'mxchat'), 'title' => __('Add to your knowledge base',       'mxchat')),
        array('num' => 5, 'flag' => 'actions',         'label' => __('Actions',     'mxchat'), 'title' => __('Try MxChat Actions',               'mxchat')),
        array('num' => 6, 'flag' => null,              'label' => __('Done',        'mxchat'), 'title' => __('You\'re set up',                   'mxchat')),
    );

    $wizard_config = array(
        'ajaxUrl'             => admin_url('admin-ajax.php'),
        'nonce'               => $wizard_nonce,
        'catalog'             => $js_catalog,
        'initialStep'         => (int) $initial_step,
        'progress'            => $progress,
        'currentChatProvider' => $current_chat_provider,
        'currentChatModel'    => $current_chat_model,
        'currentEmbedProvider'=> $current_embed_provider,
        'currentEmbedModel'   => $current_embed_model,
        'currentInstructions' => $current_instructions,
        'kbCount'             => mxchat_onboarding_kb_count(),
        'stepsMeta'           => $steps_meta,
        'urls'                => array(
            'kb'                 => admin_url('admin.php?page=mxchat-prompts'),
            'actions'            => admin_url('admin.php?page=mxchat-actions'),
            'apiKeys'            => admin_url('admin.php?page=mxchat-settings&tab=api-keys'),
            'homepage'           => home_url('/'),
            'proAddons'          => 'https://mxchat.ai/add-ons/',
            'settingsTesting'    => admin_url('admin.php?page=mxchat-settings#testing'),
            'settingsDisplay'    => admin_url('admin.php?page=mxchat-settings#chatbot-display'),
        ),
        'strings'             => array(
            'keyAlreadySaved'   => __('%s API key already saved.', 'mxchat'),
            'embedKeyReused'    => __('You\'ve already added your %s API key — using it for embeddings too.', 'mxchat'),
            'replaceKey'        => __('Replace key', 'mxchat'),
            'saveKey'           => __('Save key', 'mxchat'),
            'saving'            => __('Saving…', 'mxchat'),
            'saved'             => __('Saved', 'mxchat'),
            'saveError'         => __('Save failed. Try again or set the key in Settings → API Keys.', 'mxchat'),
            'kbNone'            => __('No knowledge base items yet.', 'mxchat'),
            /* translators: %d = number of KB items */
            'kbFoundOne'        => __('Found 1 knowledge base item.', 'mxchat'),
            /* translators: %d = number of KB items */
            'kbFoundMany'       => __('Found %d knowledge base items.', 'mxchat'),
            'manageAllKeys'     => __('You can also manage all your keys later in API Keys settings.', 'mxchat'),
            'selectProvider'    => __('— Select a provider —', 'mxchat'),
            'selectModel'       => __('— Select a model —', 'mxchat'),
            'disabledHintOpenrouter' => __('OpenRouter requires setup in the main Settings page — finish onboarding, then configure it there.', 'mxchat'),
            'disabledHintCustom'     => __('Custom (OpenAI-compatible) providers need a Base URL and model configured in Settings → API Keys — finish onboarding, then set it up there.', 'mxchat'),
            'shortcodeCopied'        => __('Copied!', 'mxchat'),
            'shortcodeCopy'          => __('Copy', 'mxchat'),
        ),
    );
    ?>
    <div class="mxch-onboarding-wrapper mxch-onboarding-wizard-wrapper">

        <main class="mxch-content">

            <div class="mxch-section active">
                <div class="mxch-content-header">
                    <h1 class="mxch-content-title"><?php esc_html_e('Onboarding', 'mxchat'); ?></h1>
                    <p class="mxch-content-subtitle">
                        <?php esc_html_e('Six quick steps to get your MxChat chatbot live.', 'mxchat'); ?>
                    </p>
                </div>

                <div class="mxch-card mxch-wizard-card" id="mxch-onboarding-wizard">
                    <div class="mxch-wizard-progress" aria-hidden="false">
                        <!-- Clickable pill step indicator (plan-a2e4d6). The JS attaches
                             click handlers + sets aria-current="step" on the active pill +
                             toggles .is-complete / .is-current / .is-future as the user
                             advances. Future steps are non-clickable. -->
                        <nav class="mxch-wizard-pillnav" role="tablist" aria-label="<?php esc_attr_e('Onboarding steps', 'mxchat'); ?>">
                            <?php foreach ($steps_meta as $sm):
                                $is_complete = ($sm['flag'] !== null && !empty($progress[$sm['flag']]))
                                              || ($sm['flag'] === null && (int) $initial_step >= 6);
                                $is_current  = ((int) $initial_step === (int) $sm['num']);
                                $cls = 'mxch-wizard-pill';
                                if ($is_complete && !$is_current) $cls .= ' is-complete';
                                if ($is_current) $cls .= ' is-current';
                                if (!$is_complete && !$is_current) $cls .= ' is-future';
                                ?>
                                <button type="button"
                                        class="<?php echo esc_attr($cls); ?>"
                                        data-mxch-pill-step="<?php echo (int) $sm['num']; ?>"
                                        <?php if ($is_current) echo 'aria-current="step"'; ?>
                                        <?php if (!$is_complete && !$is_current) echo 'disabled aria-disabled="true"'; ?>>
                                    <span class="mxch-wizard-pill-num" aria-hidden="true">
                                        <svg class="mxch-wizard-pill-check" xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
                                        <span class="mxch-wizard-pill-num-text"><?php echo (int) $sm['num']; ?></span>
                                    </span>
                                    <span class="mxch-wizard-pill-label"><?php echo esc_html($sm['label']); ?></span>
                                </button>
                            <?php endforeach; ?>
                        </nav>
                        <div class="mxch-wizard-progress-label">
                            <span class="mxch-wizard-step-label"><?php esc_html_e('Step', 'mxchat'); ?> <span data-mxch-current-step>1</span> <?php esc_html_e('of', 'mxchat'); ?> 6</span>
                            <span class="mxch-wizard-step-name" data-mxch-step-name></span>
                        </div>
                        <div class="mxch-wizard-progress-bar" role="progressbar" aria-valuemin="0" aria-valuemax="100">
                            <div class="mxch-wizard-progress-fill" data-mxch-progress-fill></div>
                        </div>
                    </div>

                    <!-- STEP 1 — chat provider + model + key -->
                    <section class="mxch-wizard-step" data-step="1" hidden>
                        <h2 class="mxch-wizard-step-title"><?php esc_html_e('Choose your chat model', 'mxchat'); ?></h2>
                        <p class="mxch-wizard-step-explainer">
                            <?php esc_html_e('This is the AI that will write replies in your chatbot. Different providers have different strengths and pricing. You can change this any time.', 'mxchat'); ?>
                        </p>

                        <div class="mxch-field">
                            <label class="mxch-field-label" for="mxch-wiz-chat-provider"><?php esc_html_e('Provider', 'mxchat'); ?></label>
                            <select class="mxch-wiz-select" id="mxch-wiz-chat-provider" data-mxch-which="chat" data-mxch-role="provider">
                                <option value=""><?php echo esc_html($wizard_config['strings']['selectProvider']); ?></option>
                                <?php foreach ($catalog as $slug => $entry):
                                    if (empty($entry['chat_models'])) continue;
                                    // Plan-23987f — OpenRouter (requires-key flow) AND
                                    // Custom (needs Base URL + model id in API Keys tab)
                                    // are both disabled in the wizard's static dropdown
                                    // via the unified `disable_in_onboarding` flag.
                                    $opt_disabled = !empty($entry['disable_in_onboarding']);
                                    $opt_label    = $entry['label'];
                                    if ($opt_disabled) {
                                        /* translators: %s = provider label, e.g. OpenRouter */
                                        $opt_label = sprintf(__('%s — configure in Settings', 'mxchat'), $entry['label']);
                                    }
                                    ?>
                                    <option value="<?php echo esc_attr($slug); ?>" data-mxch-disabled-onboarding="<?php echo $opt_disabled ? '1' : '0'; ?>" <?php selected($current_chat_provider, $slug); ?><?php echo $opt_disabled ? ' disabled' : ''; ?>><?php echo esc_html($opt_label); ?></option>
                                <?php endforeach; ?>
                            </select>
                            <p class="mxch-field-hint mxch-wiz-disabled-provider-hint">
                                <?php esc_html_e('OpenRouter and Custom (OpenAI-compatible) providers need extra configuration — finish onboarding, then set them up in Settings → API Keys.', 'mxchat'); ?>
                            </p>
                        </div>

                        <div class="mxch-field mxch-wiz-model-field" data-mxch-which="chat" hidden>
                            <label class="mxch-field-label" for="mxch-wiz-chat-model"><?php esc_html_e('Model', 'mxchat'); ?></label>
                            <select class="mxch-wiz-select" id="mxch-wiz-chat-model" data-mxch-which="chat" data-mxch-role="model"></select>
                        </div>

                        <div class="mxch-field mxch-wiz-key-field" data-mxch-which="chat" hidden>
                            <label class="mxch-field-label" data-mxch-key-label></label>
                            <p class="mxch-field-description"><?php esc_html_e('An API key is a password from your AI provider that lets MxChat talk to them.', 'mxchat'); ?></p>
                            <div class="mxch-wiz-key-row">
                                <input type="password" class="mxch-wiz-key-input" data-mxch-which="chat" autocomplete="new-password" data-lpignore="true" />
                                <button type="button" class="mxch-btn mxch-btn-primary mxch-btn-sm mxch-wiz-key-save" data-mxch-which="chat"><?php echo esc_html($wizard_config['strings']['saveKey']); ?></button>
                            </div>
                            <p class="mxch-field-hint"><?php echo wp_kses_post(sprintf(
                                /* translators: %s = link to API Keys settings */
                                __('You can also manage all your keys later in %s.', 'mxchat'),
                                '<a href="' . esc_url($wizard_config['urls']['apiKeys']) . '">' . esc_html__('API Keys settings', 'mxchat') . '</a>'
                            )); ?></p>
                        </div>

                        <div class="mxch-wiz-key-saved" data-mxch-which="chat" hidden>
                            <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
                            <span data-mxch-key-saved-text></span>
                            <button type="button" class="mxch-wiz-replace-key-link" data-mxch-which="chat"><?php echo esc_html($wizard_config['strings']['replaceKey']); ?></button>
                        </div>

                        <div class="mxch-wiz-error" data-mxch-which="chat" hidden></div>

                        <div class="mxch-wizard-actions">
                            <button type="button" class="mxch-btn mxch-btn-primary mxch-wiz-continue" data-mxch-from-step="1" disabled><?php esc_html_e('Continue', 'mxchat'); ?></button>
                        </div>
                    </section>

                    <!-- STEP 2 — AI Behavior (system_prompt_instructions) — plan-a2e4d6.
                         Re-uses the SAME mxchat_options['system_prompt_instructions']
                         binding Settings → Behavior uses. No parallel storage. The
                         Sample Instructions modal is rendered once at the bottom of
                         this page (after the wizard card) and shares the same DOM
                         ids (mxchatViewSampleBtn / mxchatSampleModal) so the existing
                         modal CSS in admin-style.css just works. -->
                    <section class="mxch-wizard-step" data-step="2" hidden>
                        <h2 class="mxch-wizard-step-title"><?php esc_html_e('Tell your chatbot how to behave', 'mxchat'); ?></h2>
                        <p class="mxch-wizard-step-explainer">
                            <?php esc_html_e('These are the instructions your AI follows for every reply. Think of it as the chatbot\'s job description — what role it plays, what tone it uses, what topics it stays on or avoids. You can edit this any time from Settings → Behavior.', 'mxchat'); ?>
                        </p>

                        <div class="mxch-field">
                            <label class="mxch-field-label" for="mxch-wiz-behavior-textarea"><?php esc_html_e('AI Instructions', 'mxchat'); ?></label>
                            <textarea id="mxch-wiz-behavior-textarea" class="mxch-wiz-behavior-textarea" rows="6" placeholder="<?php esc_attr_e('Describe how your chatbot should respond — its role, tone, and topics to focus on or avoid.', 'mxchat'); ?>"><?php echo esc_textarea($current_instructions); ?></textarea>
                            <p class="mxch-field-hint">
                                <?php esc_html_e('Optional — leave blank to use sensible defaults. You can refine this later.', 'mxchat'); ?>
                            </p>
                        </div>

                        <div class="mxch-wiz-behavior-actions-row">
                            <button type="button" class="mxchat-instructions-btn" id="mxchatViewSampleBtn">
                                <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                                    <path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/>
                                    <path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/>
                                </svg>
                                <?php esc_html_e('View Sample Instructions', 'mxchat'); ?>
                            </button>
                        </div>

                        <p class="mxch-wiz-behavior-examples-label">
                            <?php esc_html_e('Or start from one of these:', 'mxchat'); ?>
                        </p>
                        <div class="mxch-wiz-behavior-examples">
                            <button type="button" class="mxch-wiz-behavior-example" data-mxch-example="helpful">
                                <span class="mxch-wiz-behavior-example-title"><?php esc_html_e('Helpful website assistant', 'mxchat'); ?></span>
                                <span class="mxch-wiz-behavior-example-desc"><?php esc_html_e('General-purpose, concise, sticks to your site\'s content.', 'mxchat'); ?></span>
                            </button>
                            <button type="button" class="mxch-wiz-behavior-example" data-mxch-example="sales">
                                <span class="mxch-wiz-behavior-example-title"><?php esc_html_e('Sales-focused product expert', 'mxchat'); ?></span>
                                <span class="mxch-wiz-behavior-example-desc"><?php esc_html_e('Highlights features, suggests products, drives toward CTAs.', 'mxchat'); ?></span>
                            </button>
                            <button type="button" class="mxch-wiz-behavior-example" data-mxch-example="support">
                                <span class="mxch-wiz-behavior-example-title"><?php esc_html_e('Friendly customer support agent', 'mxchat'); ?></span>
                                <span class="mxch-wiz-behavior-example-desc"><?php esc_html_e('Patient, empathetic, troubleshoots, escalates when stuck.', 'mxchat'); ?></span>
                            </button>
                        </div>

                        <div class="mxch-wiz-error" data-mxch-which="behavior" hidden></div>

                        <div class="mxch-wizard-actions">
                            <button type="button" class="mxch-btn mxch-btn-secondary mxch-wiz-back" data-mxch-from-step="2"><?php esc_html_e('Back', 'mxchat'); ?></button>
                            <button type="button" class="mxch-btn mxch-btn-primary mxch-wiz-continue" data-mxch-from-step="2"><?php esc_html_e('Continue', 'mxchat'); ?></button>
                        </div>
                    </section>

                    <!-- STEP 3 — embedding provider + model + (maybe) key -->
                    <section class="mxch-wizard-step" data-step="3" hidden>
                        <h2 class="mxch-wizard-step-title"><?php esc_html_e('Choose your embedding model', 'mxchat'); ?></h2>
                        <p class="mxch-wizard-step-explainer">
                            <?php esc_html_e('Embeddings turn your website content and knowledge base into a format MxChat can search through — this is what makes your chatbot "know" your stuff. You only need this if you\'ll use a knowledge base, but most users do.', 'mxchat'); ?>
                        </p>

                        <div class="mxch-field">
                            <label class="mxch-field-label" for="mxch-wiz-embed-provider"><?php esc_html_e('Provider', 'mxchat'); ?></label>
                            <select class="mxch-wiz-select" id="mxch-wiz-embed-provider" data-mxch-which="embedding" data-mxch-role="provider">
                                <option value=""><?php echo esc_html($wizard_config['strings']['selectProvider']); ?></option>
                                <?php foreach ($catalog as $slug => $entry):
                                    if (empty($entry['embedding_models'])) continue; ?>
                                    <option value="<?php echo esc_attr($slug); ?>" <?php selected($current_embed_provider, $slug); ?>><?php echo esc_html($entry['label']); ?></option>
                                <?php endforeach; ?>
                            </select>
                        </div>

                        <div class="mxch-field mxch-wiz-model-field" data-mxch-which="embedding" hidden>
                            <label class="mxch-field-label" for="mxch-wiz-embed-model"><?php esc_html_e('Model', 'mxchat'); ?></label>
                            <select class="mxch-wiz-select" id="mxch-wiz-embed-model" data-mxch-which="embedding" data-mxch-role="model"></select>
                        </div>

                        <!-- Dedup case: same provider as Step 1 + key already saved -->
                        <div class="mxch-wiz-key-dedup" data-mxch-which="embedding" hidden>
                            <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
                            <span data-mxch-dedup-text></span>
                        </div>

                        <div class="mxch-field mxch-wiz-key-field" data-mxch-which="embedding" hidden>
                            <label class="mxch-field-label" data-mxch-key-label></label>
                            <p class="mxch-field-description"><?php esc_html_e('An API key is a password from your AI provider that lets MxChat talk to them.', 'mxchat'); ?></p>
                            <div class="mxch-wiz-key-row">
                                <input type="password" class="mxch-wiz-key-input" data-mxch-which="embedding" autocomplete="new-password" data-lpignore="true" />
                                <button type="button" class="mxch-btn mxch-btn-primary mxch-btn-sm mxch-wiz-key-save" data-mxch-which="embedding"><?php echo esc_html($wizard_config['strings']['saveKey']); ?></button>
                            </div>
                            <p class="mxch-field-hint"><?php echo wp_kses_post(sprintf(
                                __('You can also manage all your keys later in %s.', 'mxchat'),
                                '<a href="' . esc_url($wizard_config['urls']['apiKeys']) . '">' . esc_html__('API Keys settings', 'mxchat') . '</a>'
                            )); ?></p>
                        </div>

                        <div class="mxch-wiz-key-saved" data-mxch-which="embedding" hidden>
                            <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
                            <span data-mxch-key-saved-text></span>
                            <button type="button" class="mxch-wiz-replace-key-link" data-mxch-which="embedding"><?php echo esc_html($wizard_config['strings']['replaceKey']); ?></button>
                        </div>

                        <div class="mxch-wiz-error" data-mxch-which="embedding" hidden></div>

                        <!-- Vector-store informational note (plan-23987f). Pinecone and
                             OpenAI Vector Store are alternative *databases* (not embedding
                             models) — configured under Knowledge after onboarding. -->
                        <div class="mxch-wiz-vector-store-note">
                            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
                            <span><?php echo wp_kses_post(sprintf(
                                /* translators: %s = link to Knowledge page */
                                __('By default MxChat stores embeddings in your WordPress database. After onboarding you can switch to %s for larger knowledge bases.', 'mxchat'),
                                '<a href="' . esc_url($wizard_config['urls']['kb']) . '" target="_blank" rel="noopener noreferrer">' . esc_html__('Pinecone or OpenAI Vector Store', 'mxchat') . '</a>'
                            )); ?></span>
                        </div>

                        <div class="mxch-wizard-actions">
                            <button type="button" class="mxch-btn mxch-btn-secondary mxch-wiz-back" data-mxch-from-step="3"><?php esc_html_e('Back', 'mxchat'); ?></button>
                            <button type="button" class="mxch-btn mxch-btn-primary mxch-wiz-continue" data-mxch-from-step="3" disabled><?php esc_html_e('Continue', 'mxchat'); ?></button>
                        </div>
                    </section>

                    <!-- STEP 4 — KB seed (optional, mirrors Actions) -->
                    <section class="mxch-wizard-step" data-step="4" hidden>
                        <h2 class="mxch-wizard-step-title"><?php esc_html_e('Add something to your knowledge base', 'mxchat'); ?></h2>
                        <p class="mxch-wizard-step-explainer">
                            <?php esc_html_e('Your knowledge base is the content MxChat uses to answer questions about your site — pages, posts, PDFs, or custom text. Add some now if you\'d like, or skip this and build it later from the Knowledge page.', 'mxchat'); ?>
                        </p>

                        <div class="mxch-wiz-cta-row">
                            <a class="mxch-btn mxch-btn-primary" href="<?php echo esc_url($wizard_config['urls']['kb']); ?>" target="_blank" rel="noopener noreferrer">
                                <?php esc_html_e('Open Knowledge Base', 'mxchat'); ?>
                                <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-left:6px;"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
                            </a>
                        </div>

                        <div class="mxch-wizard-actions">
                            <button type="button" class="mxch-btn mxch-btn-secondary mxch-wiz-back" data-mxch-from-step="4"><?php esc_html_e('Back', 'mxchat'); ?></button>
                            <button type="button" class="mxch-btn mxch-btn-secondary mxch-wiz-continue" data-mxch-from-step="4"><?php esc_html_e('I\'ll skip this for now — Continue', 'mxchat'); ?></button>
                        </div>
                    </section>

                    <!-- STEP 5 — Actions (optional) -->
                    <section class="mxch-wizard-step" data-step="5" hidden>
                        <h2 class="mxch-wizard-step-title"><?php esc_html_e('Try MxChat Actions', 'mxchat'); ?></h2>
                        <p class="mxch-wizard-step-explainer">
                            <?php esc_html_e('Actions let your chatbot do things, not just answer. When a visitor\'s message matches phrases you choose, MxChat can capture their email to a Loops list, search the web and images with Brave, generate an image with OpenAI or Gemini, answer questions about a PDF you\'ve uploaded, or hand the conversation off to a human agent on Slack or Telegram. This step is optional — skip it now and set up Actions any time.', 'mxchat'); ?>
                        </p>

                        <div class="mxch-wiz-cta-row">
                            <a class="mxch-btn mxch-btn-primary" href="<?php echo esc_url($wizard_config['urls']['actions']); ?>" target="_blank" rel="noopener noreferrer">
                                <?php esc_html_e('Open Actions', 'mxchat'); ?>
                                <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-left:6px;"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
                            </a>
                        </div>

                        <div class="mxch-wizard-actions">
                            <button type="button" class="mxch-btn mxch-btn-secondary mxch-wiz-back" data-mxch-from-step="5"><?php esc_html_e('Back', 'mxchat'); ?></button>
                            <button type="button" class="mxch-btn mxch-btn-secondary mxch-wiz-continue" data-mxch-from-step="5"><?php esc_html_e('I\'ll skip this for now — Continue', 'mxchat'); ?></button>
                        </div>
                    </section>

                    <!-- STEP 6 — Congrats (plan-23987f rebuild: 3 next-step cards) -->
                    <section class="mxch-wizard-step mxch-wizard-step-congrats" data-step="6" hidden>
                        <div class="mxch-wiz-congrats-icon">
                            <svg xmlns="http://www.w3.org/2000/svg" width="56" height="56" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>
                        </div>
                        <h2 class="mxch-wizard-step-title mxch-wizard-step-title-congrats">🎉 <?php esc_html_e('You\'re set up.', 'mxchat'); ?></h2>

                        <div class="mxch-wiz-nextsteps-grid">

                            <!-- Card 1 — Test on Settings → Testing tab -->
                            <a class="mxch-wiz-nextstep-card" href="<?php echo esc_url($wizard_config['urls']['settingsTesting']); ?>">
                                <div class="mxch-wiz-nextstep-icon">
                                    <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
                                </div>
                                <h3 class="mxch-wiz-nextstep-title"><?php esc_html_e('Test your chatbot', 'mxchat'); ?></h3>
                                <p class="mxch-wiz-nextstep-desc"><?php esc_html_e('Try it right inside your dashboard — no need to visit your site.', 'mxchat'); ?></p>
                                <span class="mxch-wiz-nextstep-cta"><?php esc_html_e('Open Testing tab', 'mxchat'); ?>
                                    <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>
                                </span>
                            </a>

                            <!-- Card 2 — Show it on the site -->
                            <a class="mxch-wiz-nextstep-card" href="<?php echo esc_url($wizard_config['urls']['settingsDisplay']); ?>">
                                <div class="mxch-wiz-nextstep-icon">
                                    <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
                                </div>
                                <h3 class="mxch-wiz-nextstep-title"><?php esc_html_e('Show it on your site', 'mxchat'); ?></h3>
                                <p class="mxch-wiz-nextstep-desc"><?php esc_html_e('Turn the chatbot on for all pages, or hide it — your choice.', 'mxchat'); ?></p>
                                <span class="mxch-wiz-nextstep-cta"><?php esc_html_e('Open Display settings', 'mxchat'); ?>
                                    <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>
                                </span>
                            </a>

                            <!-- Card 3 — Embed code shortcodes -->
                            <div class="mxch-wiz-nextstep-card mxch-wiz-nextstep-card-embed">
                                <div class="mxch-wiz-nextstep-icon">
                                    <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>
                                </div>
                                <h3 class="mxch-wiz-nextstep-title"><?php esc_html_e('Or embed it manually', 'mxchat'); ?></h3>
                                <p class="mxch-wiz-nextstep-desc"><?php esc_html_e('Prefer to place it yourself? Paste a shortcode anywhere.', 'mxchat'); ?></p>

                                <div class="mxch-wiz-shortcode-row">
                                    <code class="mxch-wiz-shortcode" data-mxch-shortcode='[mxchat_chatbot floating="yes"]'>[mxchat_chatbot floating="yes"]</code>
                                    <button type="button" class="mxch-wiz-shortcode-copy" data-mxch-copy-shortcode='[mxchat_chatbot floating="yes"]' aria-label="<?php esc_attr_e('Copy floating widget shortcode', 'mxchat'); ?>">
                                        <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
                                        <span class="mxch-wiz-shortcode-copy-text"><?php esc_html_e('Copy', 'mxchat'); ?></span>
                                    </button>
                                </div>
                                <p class="mxch-wiz-shortcode-caption"><?php esc_html_e('Floating widget (bottom corner)', 'mxchat'); ?></p>

                                <div class="mxch-wiz-shortcode-row">
                                    <code class="mxch-wiz-shortcode" data-mxch-shortcode='[mxchat_chatbot floating="no"]'>[mxchat_chatbot floating="no"]</code>
                                    <button type="button" class="mxch-wiz-shortcode-copy" data-mxch-copy-shortcode='[mxchat_chatbot floating="no"]' aria-label="<?php esc_attr_e('Copy inline widget shortcode', 'mxchat'); ?>">
                                        <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
                                        <span class="mxch-wiz-shortcode-copy-text"><?php esc_html_e('Copy', 'mxchat'); ?></span>
                                    </button>
                                </div>
                                <p class="mxch-wiz-shortcode-caption"><?php esc_html_e('Inline embedded chat', 'mxchat'); ?></p>
                            </div>

                        </div>

                        <!-- PRO add-ons conversion block (plan-9451be) -->
                        <a class="mxch-wiz-pro-promo" href="<?php echo esc_url($wizard_config['urls']['proAddons']); ?>" target="_blank" rel="noopener noreferrer">
                            <span class="mxch-wiz-pro-promo-badge"><?php esc_html_e('PRO add-ons', 'mxchat'); ?></span>
                            <div class="mxch-wiz-pro-promo-body">
                                <h3 class="mxch-wiz-pro-promo-title"><?php esc_html_e('Do more with PRO add-ons', 'mxchat'); ?></h3>
                                <p class="mxch-wiz-pro-promo-desc">
                                    <?php esc_html_e('Sell directly in chat with WooCommerce, run multiple specialized bots on one site, generate full SEO-ready posts with Advanced Content, and more.', 'mxchat'); ?>
                                </p>
                            </div>
                            <span class="mxch-wiz-pro-promo-cta">
                                <?php esc_html_e('Explore PRO add-ons', 'mxchat'); ?>
                                <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>
                            </span>
                        </a>

                        <p class="mxch-wiz-congrats-graduated" id="mxch-wiz-graduated-line">
                            <?php
                            $mxch_wiz_tutorials_url = esc_url(admin_url('admin.php?page=mxchat-settings#tutorials'));
                            printf(
                                /* translators: %s: bold link to "Settings → Tutorials" */
                                wp_kses(
                                    __('This setup guide moves out of the way once you\'re done — reopen it any time under %s.', 'mxchat'),
                                    array('strong' => array(), 'a' => array('href' => array()))
                                ),
                                '<strong><a href="' . $mxch_wiz_tutorials_url . '">' . esc_html__('Settings → Tutorials', 'mxchat') . '</a></strong>'
                            );
                            ?>
                        </p>

                        <div class="mxch-wiz-congrats-footer">
                            <button type="button" class="mxch-wiz-congrats-footer-link mxch-wiz-back" data-mxch-from-step="6"><?php esc_html_e('Review earlier steps', 'mxchat'); ?></button>
                            <a class="mxch-wiz-congrats-footer-link" href="<?php echo esc_url($wizard_config['urls']['homepage']); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e('Open my live site', 'mxchat'); ?></a>
                        </div>
                    </section>

                </div>

                <!-- Need help? — escape hatch (preserved from f7c7d4) -->
                <div class="mxch-card mxch-onboarding-help" id="mxch-onboarding-help">
                    <div class="mxch-card-body">
                        <div class="mxch-help-row">
                            <div>
                                <h3 class="mxch-help-title"><?php esc_html_e('Stuck? Get help.', 'mxchat'); ?></h3>
                                <p class="mxch-help-subtitle"><?php esc_html_e('Ask the docs bot for an answer, or open a ticket if something\'s broken.', 'mxchat'); ?></p>
                            </div>
                            <div class="mxch-help-buttons">
                                <a class="mxch-btn mxch-btn-secondary mxch-btn-sm" href="https://mxchat.ai/documentation-bot/" target="_blank" rel="noopener noreferrer">
                                    <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right:6px;"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/></svg>
                                    <?php esc_html_e('Ask the docs bot', 'mxchat'); ?>
                                </a>
                                <a class="mxch-btn mxch-btn-secondary mxch-btn-sm" href="https://wordpress.org/support/plugin/mxchat-basic/" target="_blank" rel="noopener noreferrer">
                                    <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right:6px;"><path d="M14 9a2 2 0 0 1-2 2H6l-4 4V4c0-1.1.9-2 2-2h8a2 2 0 0 1 2 2v5Z"/><path d="M18 9h2a2 2 0 0 1 2 2v11l-4-4h-6a2 2 0 0 1-2-2v-1"/></svg>
                                    <?php esc_html_e('Open a support ticket', 'mxchat'); ?>
                                </a>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- Dismiss onboarding — bottom of page, ghost-styled, low visual weight
                     so users don't tap it by accident. Plan-d14e89 Issue 7. -->
                <p class="mxch-onboarding-dismiss-row">
                    <button type="button"
                            class="mxch-onboarding-dismiss-link mxch-onboarding-dismiss"
                            data-mxch-dismiss-nonce="<?php echo esc_attr($dismiss_nonce); ?>"
                            aria-describedby="mxch-onboarding-dismiss-hint">
                        <?php esc_html_e('Dismiss onboarding', 'mxchat'); ?>
                    </button>
                    <span class="mxch-onboarding-dismiss-hint" id="mxch-onboarding-dismiss-hint">
                        <?php esc_html_e('Hide the setup guide from the menu — reopen it any time under Settings → Tutorials.', 'mxchat'); ?>
                    </span>
                </p>
            </div>

        </main>
    </div>

    <?php
    // Render the Sample Instructions modal markup once at the end of the page,
    // matching the Settings modal exactly (same DOM ids → same admin-style.css
    // styling + same UX expectations). admin-onboarding-wizard.js wires the
    // show/hide handlers locally so we don't need to enqueue the heavy
    // mxchat-admin.js on this page just for the modal.
    // Content kept verbatim with class-mxchat-admin.php::render_sample_instructions_modal()
    // so users see the same sample no matter where they invoked the modal from.
    ?>
    <div class="mxchat-instructions-modal-overlay" id="mxchatSampleModal">
        <div class="mxchat-instructions-modal-content">
            <div class="mxchat-instructions-modal-header">
                <h3 class="mxchat-instructions-modal-title">
                    <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                        <path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/>
                        <path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/>
                    </svg>
                    <?php esc_html_e('Sample AI Instructions', 'mxchat'); ?>
                </h3>
                <button type="button" class="mxchat-instructions-modal-close" id="mxchatModalClose">
                    <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                        <line x1="18" y1="6" x2="6" y2="18"/>
                        <line x1="6" y1="6" x2="18" y2="18"/>
                    </svg>
                </button>
            </div>
            <div class="mxchat-instructions-modal-body">
                <div class="mxchat-instructions-content"><?php echo esc_html('You are an AI Chatbot assistant for this website. Your main goal is to assist visitors with questions and provide helpful information. Here are your key guidelines:

# Response Style - CRITICALLY IMPORTANT
- MAXIMUM LENGTH: 1-3 short sentences per response
- Ultra-concise: Get straight to the answer with no filler
- No introductions like "Sure!" or "I\'d be happy to help"
- No phrases like "based on my knowledge" or "according to information"
- No explanatory text before giving the answer
- No summaries or repetition
- Hyperlink all URLs
- Respond in user\'s language
- Minor chit chat or conversation is okay, but try to keep it focused on [insert topic]

# Knowledge Base Requirements - PREVENT HALLUCINATIONS
- ONLY answer using information explicitly provided in OFFICIAL KNOWLEDGE DATABASE CONTENT sections marked with ===== delimiters
- If required information is NOT in the knowledge database: "I don\'t have enough information in my knowledge base to answer that question accurately."
- NEVER invent or hallucinate URLs, links, product specs, procedures, dates, statistics, names, contacts, or company information
- When knowledge base information is unclear or contradictory, acknowledge the limitation rather than guessing
- Better to admit insufficient information than provide inaccurate answers'); ?></div>
                <button type="button" class="mxchat-instructions-copy-btn" id="mxchatCopyBtn">
                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                        <rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>
                        <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
                    </svg>
                    <?php esc_html_e('Copy to clipboard', 'mxchat'); ?>
                </button>
            </div>
        </div>
    </div>

    <script>
        window.MxChatOnboardingWizard = <?php echo wp_json_encode($wizard_config); ?>;
    </script>
    <?php
}