<?php
/**
 * Admin Dashboard
 *
 * Handles the main admin menu, submenus, dashboard widgets, and asset enqueuing.
 * Main menu with submenus (Dashboard, General, Advanced, Tools).
 *
 * @package SEOvaultSEO
 */

namespace SEOvaultSEO\Admin;

use SEOvaultSEO\Core\Options;
use SEOvaultSEO\Compatibility\Detector;
use SEOvaultSEO\Utils\Sanitizer;
use SEOvaultSEO\Monitor404\Db as Monitor404Db;
use SEOvaultSEO\Monitor404\AdminTable as Monitor404Table;
use SEOvaultSEO\Api\AuditLog;
use SEOvaultSEO\Api\RateLimiter;
use SEOvaultSEO\Api\CorsPolicy;

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

class Dashboard {

	private static $instance = null;

	public static function get_instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	private function __construct() {}

	private static $show_404_redirect_form = false;
	private static $redirect_form_log_id   = 0;

	private static function get_general_tab_ids() {
		$built_in = self::get_built_in_general_tab_ids();
		$extra    = array_keys( self::get_extension_general_tabs( $built_in ) );
		return array_values( array_unique( array_merge( $built_in, $extra ) ) );
	}

	/**
	 * Built-in General Settings tab ids (not filterable for replacement).
	 *
	 * @return string[]
	 */
	private static function get_built_in_general_tab_ids() {
		return array(
			'vtab-connection',
			'vtab-security',
			'vtab-output',
			'vtab-robots',
			'vtab-llms',
			'vtab-homepage',
			'vtab-templates',
			'vtab-schema',
			'vtab-social',
			'vtab-breadcrumbs',
			'vtab-404-monitor',
			'vtab-redirects',
			'vtab-image-seo',
			'vtab-local-seo',
			'vtab-frontend-score',
			'vtab-woocommerce',
			'vtab-analytics',
			'vtab-indexnow',
			'vtab-sitemap',
			'vtab-tools',
		);
	}

	/**
	 * Extension-registered General Settings tabs (sanitized).
	 *
	 * @param string[]|null $built_in Built-in ids.
	 * @return array<string,array{id:string,label:string,icon:string,callback:?callable}>
	 */
	private static function get_extension_general_tabs( $built_in = null ) {
		if ( null === $built_in ) {
			$built_in = self::get_built_in_general_tab_ids();
		}

		/**
		 * Filter: seovaultseo_general_settings_tabs
		 *
		 * @param array $tabs Tab descriptors keyed by id.
		 */
		// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- Hook name is a prefixed ExtensionApi public constant.
		$tabs = apply_filters( \SEOvaultSEO\Extension\ExtensionApi::FILTER_GENERAL_SETTINGS_TABS, array() );

		return \SEOvaultSEO\Extension\ExtensionApi::sanitize_general_tabs( $tabs, $built_in );
	}

	private static function get_general_active_tab() {
		$raw_tab = '';

		// phpcs:disable WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing -- Read-only active tab for admin UI; no settings mutation.
		if ( isset( $_POST['seovaultseo_active_tab'] ) ) {
			$raw_tab = sanitize_text_field( wp_unslash( $_POST['seovaultseo_active_tab'] ) );
		} elseif ( isset( $_GET['tab'] ) ) {
			$raw_tab = sanitize_text_field( wp_unslash( $_GET['tab'] ) );
		}
		// phpcs:enable WordPress.Security.NonceVerification.Recommended

		return self::sanitize_general_tab( $raw_tab );
	}

	/**
	 * Sanitize a general settings tab id.
	 *
	 * @param string $tab Raw tab id (with or without leading #).
	 * @return string
	 */
	public static function sanitize_general_tab( $tab ) {
		$tab = ltrim( trim( (string) $tab ), '#' );
		if ( in_array( $tab, self::get_general_tab_ids(), true ) ) {
			return $tab;
		}
		return 'vtab-connection';
	}

	/**
	 * CSS classes for a vertical tab nav link.
	 *
	 * @param string $tab_id     Tab id.
	 * @param string $active_tab Active tab id.
	 * @return string
	 */
	private static function vtab_link_classes( $tab_id, $active_tab ) {
		$class = 'seovaultseo-vtab-link';
		if ( $tab_id === $active_tab ) {
			$class .= ' seovaultseo-vtab-active';
		}
		return $class;
	}

	/**
	 * CSS classes for a vertical tab panel.
	 *
	 * @param string $tab_id     Tab id.
	 * @param string $active_tab Active tab id.
	 * @return string
	 */
	private static function vtab_panel_classes( $tab_id, $active_tab ) {
		$class = 'seovaultseo-vtab-panel';
		if ( $tab_id === $active_tab ) {
			$class .= ' is-active';
		}
		return $class;
	}

	public static function init() {
		$instance = self::get_instance();
		add_action( 'admin_menu', array( __CLASS__, 'add_menu_page' ), 9 );
		add_action( 'admin_menu', array( __CLASS__, 'add_support_menu' ), 25 );
		add_action( 'admin_init', array( __CLASS__, 'redirect_to_dashboard' ) );
		add_action( 'admin_init', array( __CLASS__, 'handle_404_monitor_actions' ) );
		add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueue_assets' ) );
		add_action( 'admin_enqueue_scripts', array( __CLASS__, 'menu_icon_css' ) );
		add_filter( 'plugin_action_links_' . SEOVAULT_SEO_BASENAME, array( __CLASS__, 'plugin_action_links' ) );
		add_filter( 'plugin_row_meta', array( __CLASS__, 'plugin_row_meta' ), 10, 2 );
		add_filter( 'admin_body_class', array( __CLASS__, 'add_admin_body_class' ) );
	}

	/**
	 * Add a body class to all SEOvault AI admin pages.
	 *
	 * @param string $classes Current body classes.
	 * @return string
	 */
	public static function add_admin_body_class( $classes ) {
		$screen         = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
		$is_plugin_page = false;
		if ( $screen && false !== strpos( $screen->id, 'seovault-ai' ) ) {
			$is_plugin_page = true;
		// phpcs:disable WordPress.Security.NonceVerification.Recommended -- Read-only $_GET['page'] check for admin body class.
		} elseif ( isset( $_GET['page'] ) && false !== strpos( sanitize_text_field( wp_unslash( $_GET['page'] ) ), 'seovault-ai' ) ) {
			$is_plugin_page = true;
		}
		// phpcs:enable WordPress.Security.NonceVerification.Recommended
		if ( $is_plugin_page ) {
			$classes .= ' seovaultseo-admin';
		}
		return $classes;
	}

	public static function plugin_action_links( $links ) {
		$settings_link = '<a href="' . esc_url( admin_url( 'admin.php?page=seovault-ai' ) ) . '">' . __( 'Settings', 'seovault-ai' ) . '</a>';
		array_unshift( $links, $settings_link );
		return $links;
	}

	public static function plugin_row_meta( $links, $file ) {
		if ( SEOVAULT_SEO_BASENAME !== $file ) {
			return $links;
		}
		$links[] = '<a href="' . esc_url( 'https://seovaultai.com/docs/' ) . '" target="_blank" rel="noopener noreferrer">' . __( 'Documentation', 'seovault-ai' ) . '</a>';
		$links[] = '<a href="' . esc_url( 'https://seovaultai.com/support/' ) . '" target="_blank" rel="noopener noreferrer">' . __( 'Support', 'seovault-ai' ) . '</a>';
		return $links;
	}

	public static function redirect_to_dashboard() {
		if ( defined( 'WP_CLI' ) && \WP_CLI ) {
			return;
		}
		if ( wp_doing_ajax() ) {
			return;
		}

		$do_redirect = get_option( 'seovaultseo_redirect_on_activation' );
		if ( 'yes' === $do_redirect ) {
			update_option( 'seovaultseo_redirect_on_activation', 'no', false );
			if ( ! is_multisite() ) {
				$onboarding_completed = get_option( 'seovaultseo_onboarding_completed', false );
				$onboarding_skipped   = get_option( 'seovaultseo_onboarding_skipped', false );
				$force_onboarding     = apply_filters( 'seovaultseo_force_onboarding', false );
				$onboarding_done      = ( $onboarding_completed || $onboarding_skipped ) && ! $force_onboarding;
				$url                  = \SEOvaultSEO\Schema\SchemaOnboardingGuidance::activation_redirect_url( (bool) $onboarding_done );
				if ( $force_onboarding && ! \SEOvaultSEO\Schema\SchemaOnboardingGuidance::should_route_to_migration() ) {
					$url = admin_url( 'admin.php?page=seovault-ai-onboarding' );
				}
				wp_safe_redirect( $url );
				exit;
			}
		}

		if ( isset( $_GET['skip_onboarding'], $_GET['_wpnonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'seovaultseo_skip_onboarding' ) && 'true' === sanitize_text_field( wp_unslash( $_GET['skip_onboarding'] ) ) ) {
			if ( ! current_user_can( 'manage_options' ) ) {
				return;
			}
			update_option( 'seovaultseo_onboarding_skipped', true, false );
			update_option( 'seovaultseo_onboarding_completed', true, false );
			wp_safe_redirect( admin_url( 'admin.php?page=seovault-ai' ) );
			exit;
		}
	}

	public static function add_menu_page() {
		$capability = apply_filters( 'seovaultseo_main_menu_capability', 'manage_options' );
		if ( ! current_user_can( $capability ) ) {
			return;
		}

		$menu_slug = 'seovault-ai';

		add_menu_page(
			__( 'SEOvault AI', 'seovault-ai' ),
			__( 'SEOvault AI', 'seovault-ai' ),
			$capability,
			$menu_slug,
			array( __CLASS__, 'render_dashboard' ),
			'none',
			30
		);

		$submenus = array(
			array(
				'id'         => $menu_slug,
				'page_title' => __( 'Dashboard', 'seovault-ai' ),
				'callback'   => array( __CLASS__, 'render_dashboard' ),
			),
			array(
				'id'         => 'seovault-ai-general',
				'page_title' => __( 'General', 'seovault-ai' ),
				'callback'   => array( __CLASS__, 'render_general' ),
			),
			array(
				'id'         => 'seovault-ai-analyzer',
				'page_title' => __( 'SEO Analyzer', 'seovault-ai' ),
				'callback'   => array( __CLASS__, 'render_seo_analyzer' ),
			),
			array(
				'id'         => 'seovault-ai-status',
				'page_title' => __( 'Status', 'seovault-ai' ),
				'callback'   => array( __CLASS__, 'render_status' ),
			),
		);

		$submenus = apply_filters( 'seovaultseo_admin_submenus', $submenus );

		$seen = array();
		foreach ( $submenus as $sub ) {
			if ( isset( $seen[ $sub['id'] ] ) ) {
				continue;
			}
			$seen[ $sub['id'] ] = true;

			$cap      = $sub['capability'] ?? $capability;
			$callback = $sub['callback'] ?? array( __CLASS__, 'render_dashboard' );
			add_submenu_page(
				$menu_slug,
				$sub['page_title'],
				$sub['page_title'],
				$cap,
				$sub['id'],
				$callback
			);
		}
	}

	public static function add_support_menu() {
		$capability = apply_filters( 'seovaultseo_main_menu_capability', 'manage_options' );
		if ( ! current_user_can( $capability ) ) {
			return;
		}

		$menu_slug   = 'seovault-ai';
		$support_url = 'https://seovaultai.com/contact/';

		add_submenu_page(
			$menu_slug,
			__( 'Support', 'seovault-ai' ),
			__( 'Support', 'seovault-ai' ) . ' <span class="dashicons dashicons-external-links-alt" style="font-size:13px;width:13px;height:13px;vertical-align:middle;margin-left:3px;color:#50575e;"></span>',
			$capability,
			'seovault-ai-support',
			'__return_empty_string'
		);

		global $submenu;
		if ( isset( $submenu[ $menu_slug ] ) ) {
			foreach ( $submenu[ $menu_slug ] as &$item ) {
				if ( 'seovault-ai-support' === $item[2] ) {
					$item[2] = $support_url;
				}
			}
		}
	}

	public static function enqueue_assets( $hook ) {
		if ( false === strpos( $hook, 'seovault-ai' ) ) {
			return;
		}

		\SEOvaultSEO\Extension\Assets::enqueue_admin_shell();

		// phpcs:disable WordPress.Security.NonceVerification.Recommended -- Read-only $_GET['page'] for conditional asset loading.
		$current_page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
		// phpcs:enable WordPress.Security.NonceVerification.Recommended

		/**
		 * Fires after Free admin shell assets so extensions can enqueue module assets.
		 *
		 * @param string $hook Admin hook suffix.
		 * @param string $page Current seovault-ai page slug.
		 */
		// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- Hook name is a prefixed ExtensionApi public constant.
		do_action( \SEOvaultSEO\Extension\ExtensionApi::ACTION_ENQUEUE_ADMIN_ASSETS, $hook, $current_page );

		if ( in_array( $current_page, array( 'seovault-ai-general', 'seovault-ai-status' ), true ) ) {
			wp_enqueue_script(
				'seovaultseo-sidebar-cards',
				SEOVAULT_SEO_URL . 'assets/js/sidebar-cards.js',
				array(),
				SEOVAULT_SEO_VERSION . '-1',
				true
			);

			wp_enqueue_script(
				'seovaultseo-action-center',
				SEOVAULT_SEO_URL . 'assets/js/action-center.js',
				array(),
				SEOVAULT_SEO_VERSION . '-1',
				true
			);

			wp_localize_script(
				'seovaultseo-action-center',
				'seovaultseo_action_center',
				array(
					'ajax_url' => admin_url( 'admin-ajax.php' ),
					'nonce'    => wp_create_nonce( 'seovaultseo_admin' ),
				)
			);

			wp_enqueue_style(
				'seovaultseo-action-center',
				SEOVAULT_SEO_URL . 'assets/css/action-center.css',
				array( \SEOvaultSEO\Extension\ExtensionApi::HANDLE_ADMIN_FOUNDATION ),
				SEOVAULT_SEO_VERSION . '-1'
			);
		}

		if ( 'seovault-ai-general' === $current_page || 'seovault-ai_page_seovault-ai-general' === $hook ) {
			CacheCompatibilityNotice::enqueue();
			wp_enqueue_script(
				'seovaultseo-local-seo-admin',
				SEOVAULT_SEO_URL . 'assets/js/local-seo-admin.js',
				array( 'jquery' ),
				SEOVAULT_SEO_VERSION,
				true
			);
			wp_enqueue_script(
				'seovaultseo-redirect-manager',
				SEOVAULT_SEO_URL . 'assets/js/redirect-manager.js',
				array(),
				SEOVAULT_SEO_VERSION,
				true
			);
			wp_localize_script(
				'seovaultseo-redirect-manager',
				'seovaultseo_redirect',
				array(
					'ajax_url' => admin_url( 'admin-ajax.php' ),
					'nonce'    => wp_create_nonce( 'seovaultseo_redirect_admin' ),
					'i18n'     => array(
						'origin_required'  => __( 'Origin is required.', 'seovault-ai' ),
						'add_failed'       => __( 'Failed to add redirect.', 'seovault-ai' ),
						'request_failed'   => __( 'Request failed.', 'seovault-ai' ),
						'update_redirect'  => __( 'Update Redirect', 'seovault-ai' ),
						'editing'          => __( 'Editing redirect. Click Update to save.', 'seovault-ai' ),
						'update_failed'    => __( 'Failed to update redirect.', 'seovault-ai' ),
						'confirm_delete'   => __( 'Delete this redirect?', 'seovault-ai' ),
						'deleted'          => __( 'Redirect deleted.', 'seovault-ai' ),
						'delete_failed'    => __( 'Failed to delete.', 'seovault-ai' ),
						'select_one'       => __( 'Select at least one redirect to delete.', 'seovault-ai' ),
						'confirm_bulk'     => __( 'Delete selected redirects?', 'seovault-ai' ),
						'bulk_failed'      => __( 'Failed to delete redirects.', 'seovault-ai' ),
						'select_csv'       => __( 'Please select a CSV file.', 'seovault-ai' ),
						'importing'        => __( 'Importing...', 'seovault-ai' ),
						'import_failed'    => __( 'Import failed.', 'seovault-ai' ),
					)
				)
			);
			wp_enqueue_script(
				'seovaultseo-general-settings',
				SEOVAULT_SEO_URL . 'assets/js/general-settings.js',
				array( 'jquery' ),
				SEOVAULT_SEO_VERSION,
				true
			);
			wp_localize_script(
				'seovaultseo-general-settings',
				'seovaultseo_general',
				array(
					'ajax_url'       => admin_url( 'admin-ajax.php' ),
					'robots_nonce'   => wp_create_nonce( 'seovaultseo_robots_preview' ),
					'indexnow_nonce' => wp_create_nonce( 'seovaultseo_indexnow_admin' ),
					'i18n'           => array(
						'contains'          => __( 'Contains', 'seovault-ai' ),
						'exact'             => __( 'Exact Match', 'seovault-ai' ),
						'starts'            => __( 'Starts With', 'seovault-ai' ),
						'ends'              => __( 'Ends With', 'seovault-ai' ),
						'regex'             => __( 'Regex', 'seovault-ai' ),
						'remove'            => __( 'Remove', 'seovault-ai' ),
						'no_custom_rules'   => __( 'No custom robots.txt rules will be added with the current policy.', 'seovault-ai' ),
						'preview_failed'    => __( 'Preview failed.', 'seovault-ai' ),
						'request_failed'    => __( 'Request failed.', 'seovault-ai' ),
						'enter_url'         => __( 'Please enter at least one URL.', 'seovault-ai' ),
						'submitting'        => __( 'Submitting...', 'seovault-ai' ),
						'submission_failed' => __( 'Submission failed.', 'seovault-ai' ),
					)
				)
			);
			wp_enqueue_style(
				'seovaultseo-metabox',
				SEOVAULT_SEO_URL . 'assets/css/seo-metabox.css',
				array(),
				SEOVAULT_SEO_VERSION . '-13'
			);

			wp_enqueue_script(
				'seovaultseo-settings-vars',
				SEOVAULT_SEO_URL . 'assets/js/seo-settings-vars.js',
				array( 'jquery' ),
				SEOVAULT_SEO_VERSION . '-10',
				true
			);

			wp_set_script_translations( 'seovaultseo-settings-vars', 'seovault-ai', SEOVAULT_SEO_DIR . 'languages/' );

			wp_enqueue_script(
				'seovaultseo-not-found-admin',
				SEOVAULT_SEO_URL . 'assets/js/not-found-admin.js',
				array(),
				SEOVAULT_SEO_VERSION . '-2',
				true
			);

			$variables = \SEOvaultSEO\ReplaceVariables\Manager::get_instance()->get_variables_for_js();

			wp_localize_script(
				'seovaultseo-settings-vars',
				'seovaultseo_metabox',
				\SEOvaultSEO\Core\I18n::merge_admin_script_strings(
					array(
						'variables' => $variables,
						'site'      => array(
							'name'        => wp_strip_all_tags( get_bloginfo( 'name' ) ),
							'description' => wp_strip_all_tags( get_bloginfo( 'description' ) ),
							'url'         => home_url(),
							'favicon'     => get_site_icon_url( 32 ),
						),
					)
				)
			);

			// Media library only needed for social/schema image pickers on General Settings.
			wp_enqueue_media();
		}

		// SEO Analyzer page assets
		if ( 'seovault-ai-analyzer' === $current_page || 'seovault-ai_page_seovault-ai-analyzer' === $hook ) {
			wp_enqueue_style(
				'seovaultseo-analyzer',
				SEOVAULT_SEO_URL . 'assets/css/seo-analyzer.css',
				array( \SEOvaultSEO\Extension\ExtensionApi::HANDLE_ADMIN_LEGACY ),
				SEOVAULT_SEO_VERSION . '-1'
			);

			wp_enqueue_script(
				'seovaultseo-analyzer',
				SEOVAULT_SEO_URL . 'assets/js/seo-analyzer.js',
				array( 'jquery', \SEOvaultSEO\Extension\ExtensionApi::HANDLE_ADMIN_LEGACY ),
				SEOVAULT_SEO_VERSION . '-1',
				true
			);

			wp_set_script_translations( 'seovaultseo-analyzer', 'seovault-ai', SEOVAULT_SEO_DIR . 'languages/' );

			wp_localize_script(
				'seovaultseo-analyzer',
				'seovaultseo_analyzer',
				\SEOvaultSEO\Core\I18n::get_analyzer_script_strings()
			);
		}
	}

	public static function menu_icon_css() {
		if ( ! is_admin() ) {
			return;
		}
		wp_enqueue_style( 'seovaultseo-admin-menu', SEOVAULT_SEO_URL . 'assets/css/admin-menu.css', array(), SEOVAULT_SEO_VERSION );
		wp_enqueue_script( 'seovaultseo-admin-menu', SEOVAULT_SEO_URL . 'assets/js/admin-menu.js', array(), SEOVAULT_SEO_VERSION, true );
	}

	public static function render_global_header( $page_title = '', $back_url = '' ) {
		?>
		<div class="wrap seovaultseo-settings-page seovaultseo-global-wrap">
			<?php if ( ! empty( $page_title ) ) : ?>
			<div class="seovaultseo-page-header">
				<h1><?php echo esc_html( $page_title ); ?></h1>
				<?php if ( ! empty( $back_url ) ) : ?>
				<a href="<?php echo esc_url( $back_url ); ?>" class="button button-secondary">
					<span class="dashicons dashicons-arrow-left-alt"></span>
					<?php esc_html_e( 'Back to Dashboard', 'seovault-ai' ); ?>
				</a>
				<?php endif; ?>
			</div>
			<?php endif; ?>
			<div class="seovaultseo-global-canvas">
				<div class="seovaultseo-main-content">
		<?php
	}

	public static function render_global_footer() {
		$is_connected = Options::is_connection_verified() && ! empty( Options::get_connected_at() );
		?>
				</div>
				<div class="seovaultseo-sidebar">
					<?php SidebarCards::render( $is_connected ); ?>
					<?php echo ActionCenter::render(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Method returns sanitized HTML. ?>
				</div>
			</div>
		</div>
		<?php
	}

	public static function render_dashboard() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'seovault-ai' ) );
		}

		$status          = Detector::get_status();
		$site_key        = Options::get_site_key();
		$connected_at    = Options::get_connected_at();
		$is_connected    = Options::is_connection_verified() && ! empty( $connected_at );
		$output_mode     = Options::get_output_mode();
		$active_provider = Detector::detect_active_provider();
		$has_competitor  = Detector::PROVIDER_NONE !== $active_provider;
		$post_count      = self::get_seo_post_count();
		$sitemap_url     = home_url( '/sitemap.xml' );
		$llms_enabled    = Options::is_llms_enabled();
		$mode_labels     = array(
			'auto'     => __( 'Autopilot', 'seovault-ai' ),
			'manual'   => __( 'Manual', 'seovault-ai' ),
			'disabled' => __( 'Disabled', 'seovault-ai' ),
		);

		?>
		<div class="wrap seovaultseo-dashboard">
			<div class="seovaultseo-dashboard-header">
				<h1 class="seovaultseo-brand-title">
					<span class="seovaultseo-brand-seo">SEO</span><span class="seovaultseo-brand-vault">vault</span> <span class="seovaultseo-brand-seo">AI</span>
					<span class="seovaultseo-brand-sub">Dashboard</span>
				</h1>
				<span class="seovaultseo-version-badge">v<?php echo esc_html( SEOVAULT_SEO_VERSION ); ?></span>
			</div>

			<?php settings_errors( 'seovault_seo_settings' ); ?>

			<?php echo ActionCenter::render_dashboard(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Method returns sanitized HTML. ?>

			<div class="seovaultseo-dashboard-panel">
				<!-- Status Strip -->
				<div class="seovaultseo-status-strip">
					<div class="seovaultseo-strip-item">
						<span class="dashicons dashicons-admin-links"></span>
						<div class="seovaultseo-strip-text">
							<span class="seovaultseo-strip-label"><?php esc_html_e( 'Connection', 'seovault-ai' ); ?></span>
							<?php if ( $is_connected ) : ?>
								<span class="seovaultseo-strip-value seovaultseo-strip-ok">
									<span class="seovaultseo-status-dot seovaultseo-dot-success"></span>
									<?php esc_html_e( 'Connected', 'seovault-ai' ); ?>
								</span>
							<?php else : ?>
								<span class="seovaultseo-strip-value seovaultseo-strip-waiting">
									<span class="seovaultseo-status-dot seovaultseo-dot-warning"></span>
									<?php esc_html_e( 'Waiting', 'seovault-ai' ); ?>
								</span>
							<?php endif; ?>
						</div>
						<a href="<?php echo esc_url( admin_url( 'admin.php?page=seovault-ai-general' ) ); ?>" class="seovaultseo-strip-link"><?php esc_html_e( 'Manage', 'seovault-ai' ); ?></a>
					</div>

					<div class="seovaultseo-strip-divider"></div>

					<div class="seovaultseo-strip-item">
						<span class="dashicons dashicons-admin-customizer"></span>
						<div class="seovaultseo-strip-text">
							<span class="seovaultseo-strip-label"><?php esc_html_e( 'Output Mode', 'seovault-ai' ); ?></span>
							<span class="seovaultseo-strip-value">
								<span class="seovaultseo-mode-badge seovaultseo-mode-<?php echo esc_attr( $output_mode ); ?>">
									<?php echo esc_html( $mode_labels[ $output_mode ] ?? ucfirst( $output_mode ) ); ?>
								</span>
							</span>
						</div>
						<a href="<?php echo esc_url( admin_url( 'admin.php?page=seovault-ai-general' ) ); ?>" class="seovaultseo-strip-link"><?php esc_html_e( 'Configure', 'seovault-ai' ); ?></a>
					</div>

					<div class="seovaultseo-strip-divider"></div>

					<div class="seovaultseo-strip-item">
						<span class="dashicons dashicons-media-text"></span>
						<div class="seovaultseo-strip-text">
							<span class="seovaultseo-strip-label"><?php esc_html_e( 'llms.txt', 'seovault-ai' ); ?></span>
							<span class="seovaultseo-strip-value">
								<?php
								echo $llms_enabled
									? '<span class="seovaultseo-badge seovaultseo-badge-success">' . esc_html__( 'Enabled', 'seovault-ai' ) . '</span>'
									: '<span class="seovaultseo-badge seovaultseo-badge-muted">' . esc_html__( 'Disabled', 'seovault-ai' ) . '</span>';
								?>
							</span>
						</div>
						<a href="<?php echo esc_url( admin_url( 'admin.php?page=seovault-ai-general&tab=vtab-llms' ) ); ?>" class="seovaultseo-strip-link"><?php esc_html_e( 'Configure', 'seovault-ai' ); ?></a>
					</div>
				</div>

				<!-- Content Overview -->
				<div class="seovaultseo-dashboard-section">
					<h3><span class="dashicons dashicons-analytics"></span> <?php esc_html_e( 'Content Overview', 'seovault-ai' ); ?></h3>
					<div class="seovaultseo-overview-grid">
						<div class="seovaultseo-overview-stat">
							<span class="seovaultseo-overview-number"><?php echo esc_html( number_format_i18n( $post_count ) ); ?></span>
							<span class="seovaultseo-overview-label"><?php esc_html_e( 'Posts with SEO Meta', 'seovault-ai' ); ?></span>
						</div>
						<div class="seovaultseo-overview-stat">
							<span class="seovaultseo-overview-number"><?php echo $has_competitor ? esc_html( ucfirst( $active_provider ) ) : esc_html__( 'None', 'seovault-ai' ); ?></span>
							<span class="seovaultseo-overview-label"><?php esc_html_e( 'Detected SEO Plugin', 'seovault-ai' ); ?></span>
						</div>
						<div class="seovaultseo-overview-stat">
							<span class="seovaultseo-overview-number"><?php echo esc_html( SEOVAULT_SEO_VERSION ); ?></span>
							<span class="seovaultseo-overview-label"><?php esc_html_e( 'Plugin Version', 'seovault-ai' ); ?></span>
						</div>
					</div>
				</div>

				<!-- Site Key -->
				<div class="seovaultseo-dashboard-section">
					<h3><span class="dashicons dashicons-key"></span> <?php esc_html_e( 'Site Key', 'seovault-ai' ); ?></h3>
					<div class="seovaultseo-key-row">
						<code class="seovaultseo-site-key"><?php echo esc_html( self::mask_key( $site_key ) ); ?></code>
						<button type="button" class="button button-small seovaultseo-copy-key" data-key="<?php echo esc_attr( $site_key ); ?>">
							<span class="dashicons dashicons-clipboard"></span>
							<?php esc_html_e( 'Copy', 'seovault-ai' ); ?>
						</button>
						<details class="seovaultseo-key-reveal">
							<summary><?php esc_html_e( 'Show full key', 'seovault-ai' ); ?></summary>
							<input type="text" value="<?php echo esc_attr( $site_key ); ?>" readonly class="seovaultseo-select-on-click" />
						</details>
					</div>
				</div>

				<!-- Quick Links -->
				<div class="seovaultseo-dashboard-section">
					<h3><span class="dashicons dashicons-screenoptions"></span> <?php esc_html_e( 'Quick Links', 'seovault-ai' ); ?></h3>
					<div class="seovaultseo-quick-links">
						<a href="<?php echo esc_url( admin_url( 'admin.php?page=seovault-ai-general' ) ); ?>" class="seovaultseo-quick-link">
							<span class="dashicons dashicons-admin-generic"></span>
							<span><?php esc_html_e( 'General Settings', 'seovault-ai' ); ?></span>
						</a>
						<a href="<?php echo esc_url( admin_url( 'admin.php?page=seovault-ai-general&tab=vtab-llms' ) ); ?>" class="seovaultseo-quick-link">
							<span class="dashicons dashicons-media-text"></span>
							<span><?php esc_html_e( 'llms.txt', 'seovault-ai' ); ?></span>
						</a>
						<a href="<?php echo esc_url( admin_url( 'admin.php?page=seovault-ai-general&tab=vtab-schema' ) ); ?>" class="seovaultseo-quick-link">
							<span class="dashicons dashicons-list-view"></span>
							<span><?php esc_html_e( 'Schema', 'seovault-ai' ); ?></span>
						</a>
						<a href="<?php echo esc_url( admin_url( 'admin.php?page=seovault-ai-general&tab=vtab-tools' ) ); ?>" class="seovaultseo-quick-link">
							<span class="dashicons dashicons-migrate"></span>
							<span><?php esc_html_e( 'Import / Export', 'seovault-ai' ); ?></span>
						</a>
						<a href="<?php echo esc_url( admin_url( 'admin.php?page=seovault-ai-status' ) ); ?>" class="seovaultseo-quick-link">
							<span class="dashicons dashicons-info-outline"></span>
							<span><?php esc_html_e( 'Status', 'seovault-ai' ); ?></span>
						</a>
						<a href="<?php echo esc_url( admin_url( 'admin.php?page=seovault-ai-analyzer' ) ); ?>" class="seovaultseo-quick-link">
							<span class="dashicons dashicons-search"></span>
							<span><?php esc_html_e( 'SEO Analyzer', 'seovault-ai' ); ?></span>
						</a>
						<a href="<?php echo esc_url( $sitemap_url ); ?>" target="_blank" rel="noopener" class="seovaultseo-quick-link">
							<span class="dashicons dashicons-list-view"></span>
							<span><?php esc_html_e( 'Sitemap', 'seovault-ai' ); ?></span>
						</a>
						<a href="<?php echo esc_url( home_url( '/llms.txt' ) ); ?>" target="_blank" rel="noopener" class="seovaultseo-quick-link">
							<span class="dashicons dashicons-media-text"></span>
							<span><?php esc_html_e( 'llms.txt', 'seovault-ai' ); ?></span>
						</a>
					</div>
				</div>

				<?php self::render_extension_dashboard_sections(); ?>
			</div>
		</div>
		<?php
	}

	/**
	 * Render extension dashboard cards/sections.
	 *
	 * @return void
	 */
	private static function render_extension_dashboard_sections() {
		// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- Hook name is a prefixed ExtensionApi public constant.
		$cards = apply_filters( \SEOvaultSEO\Extension\ExtensionApi::FILTER_DASHBOARD_CARDS, array() );
		$cards = \SEOvaultSEO\Extension\ExtensionApi::sanitize_dashboard_cards( $cards );

		foreach ( $cards as $card ) {
			echo '<div class="seovaultseo-dashboard-section seovaultseo-extension-dashboard-card" data-card-id="' . esc_attr( $card['id'] ) . '">';
			echo '<h3>' . esc_html( $card['title'] ) . '</h3>';
			call_user_func( $card['callback'], $card );
			echo '</div>';
		}

		/**
		 * Fires after Free dashboard content for extension sections.
		 */
		// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- Hook name is a prefixed ExtensionApi public constant.
		do_action( \SEOvaultSEO\Extension\ExtensionApi::ACTION_DASHBOARD_SECTIONS );
	}

	/**
	 * Backward-compatible entry point for the 404 monitor settings UI.
	 *
	 * The 404 monitor is rendered inside General Settings; this wrapper preserves
	 * the legacy render method used by older admin code and tests.
	 */
	public static function render_404_monitor() {
		self::render_general();
	}

	public static function render_general() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'seovault-ai' ) );
		}

		$site_key     = Options::get_site_key();
		$connected_at = Options::get_connected_at();
		$is_connected = Options::is_connection_verified() && ! empty( $connected_at );
		$rest_url     = rest_url( 'seovaultai/v1/verify' );
		$output_mode  = Options::get_output_mode();
		$llms_enabled = Options::is_llms_enabled();
		$active_tab   = self::get_general_active_tab();
		$audit_rows   = AuditLog::get_recent_rows( 50 );

		self::render_global_header( __( 'General Settings', 'seovault-ai' ), admin_url( 'admin.php?page=seovault-ai' ) );
		?>

			<?php settings_errors( 'seovault_seo_settings' ); ?>
			<?php settings_errors( 'seovault_seo_redirects' ); ?>

			<div class="seovaultseo-vtab-wrapper">
				<nav class="seovaultseo-vtab-nav">
					<a href="#vtab-connection" class="<?php echo esc_attr( self::vtab_link_classes( 'vtab-connection', $active_tab ) ); ?>">
						<span class="dashicons dashicons-admin-links"></span>
						<?php esc_html_e( 'Connection', 'seovault-ai' ); ?>
					</a>
					<a href="#vtab-security" class="<?php echo esc_attr( self::vtab_link_classes( 'vtab-security', $active_tab ) ); ?>">
						<span class="dashicons dashicons-shield"></span>
						<?php esc_html_e( 'Security', 'seovault-ai' ); ?>
					</a>
					<a href="#vtab-output" class="<?php echo esc_attr( self::vtab_link_classes( 'vtab-output', $active_tab ) ); ?>">
						<span class="dashicons dashicons-admin-customizer"></span>
						<?php esc_html_e( 'Output Mode', 'seovault-ai' ); ?>
					</a>
					<a href="#vtab-robots" class="<?php echo esc_attr( self::vtab_link_classes( 'vtab-robots', $active_tab ) ); ?>">
						<span class="dashicons dashicons-shield-alt"></span>
						<?php esc_html_e( 'Robots', 'seovault-ai' ); ?>
					</a>
					<a href="#vtab-llms" class="<?php echo esc_attr( self::vtab_link_classes( 'vtab-llms', $active_tab ) ); ?>">
						<span class="dashicons dashicons-media-text"></span>
						<?php esc_html_e( 'llms.txt', 'seovault-ai' ); ?>
					</a>
					<a href="#vtab-homepage" class="<?php echo esc_attr( self::vtab_link_classes( 'vtab-homepage', $active_tab ) ); ?>">
						<span class="dashicons dashicons-admin-home"></span>
						<?php esc_html_e( 'Homepage', 'seovault-ai' ); ?>
					</a>
					<a href="#vtab-templates" class="<?php echo esc_attr( self::vtab_link_classes( 'vtab-templates', $active_tab ) ); ?>">
						<span class="dashicons dashicons-format-quote"></span>
						<?php esc_html_e( 'Templates', 'seovault-ai' ); ?>
					</a>
					<a href="#vtab-schema" class="<?php echo esc_attr( self::vtab_link_classes( 'vtab-schema', $active_tab ) ); ?>">
						<span class="dashicons dashicons-list-view"></span>
						<?php esc_html_e( 'Schema', 'seovault-ai' ); ?>
					</a>
					<a href="#vtab-social" class="<?php echo esc_attr( self::vtab_link_classes( 'vtab-social', $active_tab ) ); ?>">
						<span class="dashicons dashicons-share"></span>
						<?php esc_html_e( 'Social', 'seovault-ai' ); ?>
					</a>
					<a href="#vtab-breadcrumbs" class="<?php echo esc_attr( self::vtab_link_classes( 'vtab-breadcrumbs', $active_tab ) ); ?>">
						<span class="dashicons dashicons-admin-appearance"></span>
						<?php esc_html_e( 'Breadcrumbs', 'seovault-ai' ); ?>
					</a>
					<a href="#vtab-404-monitor" class="<?php echo esc_attr( self::vtab_link_classes( 'vtab-404-monitor', $active_tab ) ); ?>">
						<span class="dashicons dashicons-warning"></span>
						<?php esc_html_e( '404 Monitor', 'seovault-ai' ); ?>
					</a>

				<a href="#vtab-redirects" class="<?php echo esc_attr( self::vtab_link_classes( 'vtab-redirects', $active_tab ) ); ?>">
					<span class="dashicons dashicons-migrate"></span>
					<?php esc_html_e( 'Redirects', 'seovault-ai' ); ?>
				</a>

				<a href="#vtab-image-seo" class="<?php echo esc_attr( self::vtab_link_classes( 'vtab-image-seo', $active_tab ) ); ?>">
					<span class="dashicons dashicons-format-image"></span>
					<?php esc_html_e( 'Image SEO', 'seovault-ai' ); ?>
				</a>

				<a href="#vtab-local-seo" class="<?php echo esc_attr( self::vtab_link_classes( 'vtab-local-seo', $active_tab ) ); ?>">
					<span class="dashicons dashicons-location"></span>
					<?php esc_html_e( 'Local SEO', 'seovault-ai' ); ?>
				</a>

				<a href="#vtab-frontend-score" class="<?php echo esc_attr( self::vtab_link_classes( 'vtab-frontend-score', $active_tab ) ); ?>">
					<span class="dashicons dashicons-awards"></span>
					<?php esc_html_e( 'Frontend Score', 'seovault-ai' ); ?>
				</a>

				<a href="#vtab-woocommerce" class="<?php echo esc_attr( self::vtab_link_classes( 'vtab-woocommerce', $active_tab ) ); ?>">
					<span class="dashicons dashicons-products"></span>
					<?php esc_html_e( 'WooCommerce', 'seovault-ai' ); ?>
				</a>
				<a href="#vtab-analytics" class="<?php echo esc_attr( self::vtab_link_classes( 'vtab-analytics', $active_tab ) ); ?>">
					<span class="dashicons dashicons-chart-area"></span>
					<?php esc_html_e( 'Analytics', 'seovault-ai' ); ?>
				</a>
				<a href="#vtab-indexnow" class="<?php echo esc_attr( self::vtab_link_classes( 'vtab-indexnow', $active_tab ) ); ?>">
					<span class="dashicons dashicons-search"></span>
					<?php esc_html_e( 'IndexNow', 'seovault-ai' ); ?>
				</a>
				<a href="#vtab-sitemap" class="<?php echo esc_attr( self::vtab_link_classes( 'vtab-sitemap', $active_tab ) ); ?>">
					<span class="dashicons dashicons-list-view"></span>
					<?php esc_html_e( 'Sitemap', 'seovault-ai' ); ?>
				</a>
				<a href="#vtab-tools" class="<?php echo esc_attr( self::vtab_link_classes( 'vtab-tools', $active_tab ) ); ?>">
					<span class="dashicons dashicons-migrate"></span>
					<?php esc_html_e( 'Tools', 'seovault-ai' ); ?>
				</a>
				<?php
				foreach ( self::get_extension_general_tabs() as $ext_tab ) :
					$icon_class = 'dashicons ' . $ext_tab['icon'];
					?>
				<a href="#<?php echo esc_attr( $ext_tab['id'] ); ?>" class="<?php echo esc_attr( self::vtab_link_classes( $ext_tab['id'], $active_tab ) ); ?>">
					<span class="<?php echo esc_attr( $icon_class ); ?>"></span>
					<?php echo esc_html( $ext_tab['label'] ); ?>
				</a>
					<?php
				endforeach;

				/**
				 * Fires after built-in + filtered General Settings tab nav links.
				 *
				 * @param string $active_tab Active tab id.
				 */
				// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- Hook name is a prefixed ExtensionApi public constant.
				do_action( \SEOvaultSEO\Extension\ExtensionApi::ACTION_GENERAL_TAB_NAV, $active_tab );
				?>
				</nav>

				<div class="seovaultseo-vtab-content">
					<form id="seovaultseo-general-form" method="post" action="<?php echo esc_url( admin_url( 'admin.php?page=seovault-ai-general' ) ); ?>" novalidate>
						<?php wp_nonce_field( 'seovaultseo_save_all_settings_action' ); ?>
						<input type="hidden" name="seovaultseo_active_tab" id="seovaultseo-active-tab" value="<?php echo esc_attr( $active_tab ); ?>" />

						<div id="vtab-connection" class="<?php echo esc_attr( self::vtab_panel_classes( 'vtab-connection', $active_tab ) ); ?>">
							<h2><?php esc_html_e( 'Connection', 'seovault-ai' ); ?></h2>
							<table class="form-table">
								<tr>
									<th scope="row"><?php esc_html_e( 'Status', 'seovault-ai' ); ?></th>
									<td>
										<?php if ( $is_connected ) : ?>
											<span class="seovaultseo-badge seovaultseo-badge-success">
												<span class="seovaultseo-status-dot seovaultseo-dot-success"></span>
												<?php esc_html_e( 'Connected', 'seovault-ai' ); ?>
											</span>
											<p class="description"><?php echo esc_html( sprintf( /* translators: %s: verification timestamp */ __( 'Last verified: %s UTC', 'seovault-ai' ), $connected_at ) ); ?></p>
										<?php else : ?>
											<span class="seovaultseo-badge seovaultseo-badge-warning">
												<span class="seovaultseo-status-dot seovaultseo-dot-warning"></span>
												<?php esc_html_e( 'Waiting for connection', 'seovault-ai' ); ?>
											</span>
											<p class="description"><?php esc_html_e( 'Copy the site key below and add this site in the SEOvault AI web app.', 'seovault-ai' ); ?></p>
										<?php endif; ?>
									</td>
								</tr>
								<tr>
									<th scope="row"><?php esc_html_e( 'Site Key', 'seovault-ai' ); ?></th>
									<td>
										<code class="seovaultseo-site-key"><?php echo esc_html( self::mask_key( $site_key ) ); ?></code>
										<button type="button" class="button button-small seovaultseo-copy-key" data-key="<?php echo esc_attr( $site_key ); ?>">
											<span class="dashicons dashicons-clipboard"></span>
											<?php esc_html_e( 'Copy', 'seovault-ai' ); ?>
										</button>
										<details style="margin-top: 8px;">
											<summary style="cursor: pointer; color: #0D9488;"><?php esc_html_e( 'Show full key', 'seovault-ai' ); ?></summary>
											<input type="text" value="<?php echo esc_attr( $site_key ); ?>" readonly class="seovaultseo-select-on-click" style="width: 100%; max-width: 400px; margin-top: 6px; font-family: monospace; font-size: 12px;" />
										</details>
									</td>
								</tr>
								<tr>
									<th scope="row"><?php esc_html_e( 'API Endpoint', 'seovault-ai' ); ?></th>
									<td>
										<code class="seovaultseo-code-inline"><?php echo esc_html( $rest_url ); ?></code>
										<p class="description"><?php /* translators: %s: link to web app */ printf( esc_html__( 'The %s uses this URL to communicate with your site.', 'seovault-ai' ), '<a href="https://app.seovaultai.com/" target="_blank" rel="noopener">' . esc_html__( 'web app', 'seovault-ai' ) . '</a>' ); ?></p>
									</td>
								</tr>
								<tr>
									<th scope="row"><?php esc_html_e( 'Plugin Version', 'seovault-ai' ); ?></th>
									<td><?php echo esc_html( SEOVAULT_SEO_VERSION ); ?></td>
								</tr>
								<tr>
									<th scope="row"><?php esc_html_e( 'Extension API', 'seovault-ai' ); ?></th>
									<td><code><?php echo esc_html( defined( 'SEOVAULT_SEO_EXTENSION_API_VERSION' ) ? SEOVAULT_SEO_EXTENSION_API_VERSION : '' ); ?></code></td>
								</tr>
							</table>
							<?php \SEOvaultSEO\Extension\ExternalServices::render_connection_disclosure(); ?>
						</div>

						<div id="vtab-security" class="<?php echo esc_attr( self::vtab_panel_classes( 'vtab-security', $active_tab ) ); ?>">
							<h2><?php esc_html_e( 'Security', 'seovault-ai' ); ?></h2>
							<p class="description"><?php esc_html_e( 'Manage connector credentials, review API protection settings, clear lockouts, and inspect recent API activity. The main site key is a high-privilege secret — treat it like a password.', 'seovault-ai' ); ?></p>

							<div class="seovaultseo-security-section" id="seovaultseo-security-site-key">
								<h3><?php esc_html_e( 'Site Key', 'seovault-ai' ); ?></h3>
								<p><?php esc_html_e( 'If you suspect your site key has been compromised, regenerate it below. You will need to update the key in your web app settings.', 'seovault-ai' ); ?></p>
								<p>
									<button type="submit" form="seovaultseo-regenerate-site-key-form" class="button button-secondary seovaultseo-btn-danger" data-seovaultseo-confirm="<?php echo esc_attr__( 'This will disconnect any apps using the current key. Continue?', 'seovault-ai' ); ?>">
										<span class="dashicons dashicons-controls-repeat"></span>
										<?php esc_html_e( 'Regenerate Site Key', 'seovault-ai' ); ?>
									</button>
								</p>
							</div>

							<hr>

							<?php
							$flash_read_key  = get_transient( 'seovaultseo_flash_site_read_key' );
							$flash_write_key = get_transient( 'seovaultseo_flash_site_write_key' );
							$has_read_key    = '' !== (string) Options::get_site_read_key();
							$has_write_key   = '' !== (string) Options::get_site_write_key();
							if ( is_string( $flash_read_key ) && '' !== $flash_read_key ) {
								delete_transient( 'seovaultseo_flash_site_read_key' );
							} else {
								$flash_read_key = '';
							}
							if ( is_string( $flash_write_key ) && '' !== $flash_write_key ) {
								delete_transient( 'seovaultseo_flash_site_write_key' );
							} else {
								$flash_write_key = '';
							}
							?>
							<div class="seovaultseo-security-section" id="seovaultseo-security-scoped-keys">
								<h3><?php esc_html_e( 'Optional Read / Write API Keys', 'seovault-ai' ); ?></h3>
								<p class="description"><?php esc_html_e( 'Optional scoped keys for limited integrations. The main site key remains full-access. The web app continues to use the main site key unless you opt into scoped keys later.', 'seovault-ai' ); ?></p>
								<p>
									<button type="submit" form="seovaultseo-generate-read-key-form" class="button button-secondary" data-seovaultseo-confirm="<?php echo esc_attr__( 'Generate a new read-only API key? Any previous read key will stop working.', 'seovault-ai' ); ?>">
										<span class="dashicons dashicons-visibility"></span>
										<?php echo $has_read_key ? esc_html__( 'Regenerate Read-Only Key', 'seovault-ai' ) : esc_html__( 'Generate Read-Only Key', 'seovault-ai' ); ?>
									</button>
									<button type="submit" form="seovaultseo-generate-write-key-form" class="button button-secondary" data-seovaultseo-confirm="<?php echo esc_attr__( 'Generate a new write API key? Any previous write key will stop working.', 'seovault-ai' ); ?>">
										<span class="dashicons dashicons-edit"></span>
										<?php echo $has_write_key ? esc_html__( 'Regenerate Write Key', 'seovault-ai' ) : esc_html__( 'Generate Write Key', 'seovault-ai' ); ?>
									</button>
								</p>
								<?php if ( '' !== $flash_read_key ) : ?>
									<div class="notice notice-success inline" style="margin:12px 0;padding:8px 12px;">
										<p><strong><?php esc_html_e( 'New read-only key (copy now — shown once):', 'seovault-ai' ); ?></strong></p>
										<p>
											<code style="word-break:break-all;"><?php echo esc_html( $flash_read_key ); ?></code>
											<button type="button" class="button button-small seovaultseo-copy-key" data-key="<?php echo esc_attr( $flash_read_key ); ?>">
												<span class="dashicons dashicons-clipboard"></span>
												<?php esc_html_e( 'Copy', 'seovault-ai' ); ?>
											</button>
										</p>
									</div>
								<?php elseif ( $has_read_key ) : ?>
									<p class="description"><?php esc_html_e( 'A read-only key is configured (value hidden). Generate again to replace it.', 'seovault-ai' ); ?></p>
								<?php endif; ?>
								<?php if ( '' !== $flash_write_key ) : ?>
									<div class="notice notice-success inline" style="margin:12px 0;padding:8px 12px;">
										<p><strong><?php esc_html_e( 'New write key (copy now — shown once):', 'seovault-ai' ); ?></strong></p>
										<p>
											<code style="word-break:break-all;"><?php echo esc_html( $flash_write_key ); ?></code>
											<button type="button" class="button button-small seovaultseo-copy-key" data-key="<?php echo esc_attr( $flash_write_key ); ?>">
												<span class="dashicons dashicons-clipboard"></span>
												<?php esc_html_e( 'Copy', 'seovault-ai' ); ?>
											</button>
										</p>
									</div>
								<?php elseif ( $has_write_key ) : ?>
									<p class="description"><?php esc_html_e( 'A write key is configured (value hidden). Generate again to replace it.', 'seovault-ai' ); ?></p>
								<?php endif; ?>
							</div>

							<hr>

							<?php
							$rate_limits  = RateLimiter::get_limits();
							$limit_labels = array(
								RateLimiter::KEY_AUTH_FAIL_IP => __( 'Failed auth attempts (per IP)', 'seovault-ai' ),
								RateLimiter::KEY_GLOBAL_IP => __( 'All API requests (per IP)', 'seovault-ai' ),
								RateLimiter::KEY_READ      => __( 'Authenticated reads (per key)', 'seovault-ai' ),
								RateLimiter::KEY_WRITE     => __( 'Authenticated writes (per key)', 'seovault-ai' ),
								RateLimiter::KEY_IMPORT    => __( 'SEO import (per key)', 'seovault-ai' ),
								RateLimiter::KEY_MEDIA     => __( 'Media upload (per key)', 'seovault-ai' ),
								RateLimiter::KEY_AUTH_LOCKOUT_WARNING => __( 'Lockout warning threshold (per IP)', 'seovault-ai' ),
								RateLimiter::KEY_AUTH_LOCKOUT_IP => __( 'Hard lockout threshold (per IP)', 'seovault-ai' ),
							);
							?>
							<div class="seovaultseo-security-section" id="seovaultseo-security-rate-limits">
								<h3><?php esc_html_e( 'API Rate Limits', 'seovault-ai' ); ?></h3>
								<p class="description"><?php esc_html_e( 'Effective limits currently applied to the connector API. These values are read-only here; developers can override them with the filter below.', 'seovault-ai' ); ?></p>
								<table class="widefat striped" style="max-width:720px;margin:12px 0;">
									<thead>
										<tr>
											<th><?php esc_html_e( 'Limit', 'seovault-ai' ); ?></th>
											<th><?php esc_html_e( 'Max requests', 'seovault-ai' ); ?></th>
											<th><?php esc_html_e( 'Window (seconds)', 'seovault-ai' ); ?></th>
										</tr>
									</thead>
									<tbody>
										<?php foreach ( $limit_labels as $limit_key => $limit_label ) : ?>
											<?php
											$entry  = isset( $rate_limits[ $limit_key ] ) && is_array( $rate_limits[ $limit_key ] ) ? $rate_limits[ $limit_key ] : array();
											$limit  = isset( $entry['limit'] ) ? (int) $entry['limit'] : 0;
											$window = isset( $entry['window'] ) ? (int) $entry['window'] : 0;
											?>
											<tr>
												<td>
													<?php echo esc_html( $limit_label ); ?>
													<br><code style="font-size:11px;"><?php echo esc_html( $limit_key ); ?></code>
												</td>
												<td><?php echo esc_html( (string) $limit ); ?></td>
												<td><?php echo esc_html( (string) $window ); ?></td>
											</tr>
										<?php endforeach; ?>
									</tbody>
								</table>
								<p class="description">
									<?php
									printf(
										/* translators: %s: WordPress filter hook name */
										esc_html__( 'Developers: override limits with the %s filter.', 'seovault-ai' ),
										'<code>' . esc_html( RateLimiter::LIMITS_FILTER ) . '</code>'
									);
									?>
									<?php
									printf(
										/* translators: %s: WordPress filter hook name */
										esc_html__( 'CORS allowlist: %s.', 'seovault-ai' ),
										'<code>' . esc_html( CorsPolicy::ORIGINS_FILTER ) . '</code>'
									);
									?>
								</p>
							</div>

							<hr>

							<div class="seovaultseo-security-section" id="seovaultseo-security-protection">
								<?php
								$audit_summary       = AuditLog::summarize_rows_for_display( $audit_rows );
								$audit_display_rows  = AuditLog::collapse_consecutive_rows_for_display( $audit_rows );
								?>
								<h3><?php esc_html_e( 'API Protection &amp; Activity', 'seovault-ai' ); ?></h3>
								<p class="description"><?php esc_html_e( 'Too many wrong API keys can temporarily lock an IP. Clear lockouts if your SEOVault AI app got blocked, then review recent events below.', 'seovault-ai' ); ?></p>

								<h4 id="seovaultseo-security-lockouts"><?php esc_html_e( 'Lockouts', 'seovault-ai' ); ?></h4>
								<p class="description"><?php esc_html_e( 'Clears temporary lockout and rate-limit counters only. It does not delete the activity log.', 'seovault-ai' ); ?></p>
								<p class="seovaultseo-security-actions">
									<a href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?page=seovault-ai-general&action=clear_api_lockouts&tab=vtab-security#seovaultseo-security-lockouts' ), 'seovaultseo_clear_api_lockouts_action' ) ); ?>" class="button button-secondary seovaultseo-security-action-btn" data-seovaultseo-confirm="<?php echo esc_attr__( 'Clear all API lockouts and rate-limit counters for this site?', 'seovault-ai' ); ?>">
										<span class="dashicons dashicons-unlock" aria-hidden="true"></span>
										<?php esc_html_e( 'Clear API Lockouts', 'seovault-ai' ); ?>
									</a>
									<?php if ( empty( $audit_rows ) ) : ?>
										<button type="button" class="button button-secondary seovaultseo-security-action-btn" disabled title="<?php esc_attr_e( 'No API activity recorded yet.', 'seovault-ai' ); ?>">
											<span class="dashicons dashicons-list-view" aria-hidden="true"></span>
											<?php esc_html_e( 'No API activity yet', 'seovault-ai' ); ?>
										</button>
									<?php else : ?>
										<a href="#seovaultseo-security-activity" class="button button-secondary seovaultseo-security-action-btn seovaultseo-jump-to-api-activity">
											<span class="dashicons dashicons-list-view" aria-hidden="true"></span>
											<?php esc_html_e( 'Jump to API Activity', 'seovault-ai' ); ?>
										</a>
									<?php endif; ?>
								</p>

								<div id="seovaultseo-security-activity" class="seovaultseo-security-activity">
									<h4><?php esc_html_e( 'API Activity', 'seovault-ai' ); ?></h4>
									<p class="description"><?php esc_html_e( 'A recent sample of API requests (up to 50). Identical consecutive events are grouped. IP addresses are never shown. Older events are pruned automatically.', 'seovault-ai' ); ?></p>
									<?php if ( empty( $audit_rows ) ) : ?>
										<p><?php esc_html_e( 'No API activity recorded yet.', 'seovault-ai' ); ?></p>
									<?php else : ?>
										<?php if ( ! $is_connected ) : ?>
											<div class="notice notice-info inline seovaultseo-api-activity-disconnected">
												<p>
													<?php esc_html_e( 'This site is not connected to SEOVault AI yet. Failed or blocked API calls below are expected protection (wrong or missing key), not a site outage. Connect from the Connection tab when ready. Use Clear API Lockouts only if a real connect attempt is stuck.', 'seovault-ai' ); ?>
												</p>
											</div>
										<?php endif; ?>
										<?php
										$summary_parts = array();
										if ( $audit_summary['auth_fail'] > 0 ) {
											$summary_parts[] = sprintf(
												/* translators: %d: number of failed authentication events */
												_n( '%d failed auth', '%d failed auth', $audit_summary['auth_fail'], 'seovault-ai' ),
												$audit_summary['auth_fail']
											);
										}
										if ( $audit_summary['lockout'] > 0 ) {
											$summary_parts[] = sprintf(
												/* translators: %d: number of lockout events */
												_n( '%d lockout', '%d lockouts', $audit_summary['lockout'], 'seovault-ai' ),
												$audit_summary['lockout']
											);
										}
										if ( $audit_summary['rate_limit'] > 0 ) {
											$summary_parts[] = sprintf(
												/* translators: %d: number of rate-limit events */
												_n( '%d rate limit', '%d rate limits', $audit_summary['rate_limit'], 'seovault-ai' ),
												$audit_summary['rate_limit']
											);
										}
										if ( $audit_summary['success'] > 0 ) {
											$summary_parts[] = sprintf(
												/* translators: %d: number of successful events */
												_n( '%d success', '%d successes', $audit_summary['success'], 'seovault-ai' ),
												$audit_summary['success']
											);
										}
										$summary_parts[] = sprintf(
											/* translators: %d: number of recent events shown */
											_n( 'last %d event', 'last %d events', $audit_summary['total'], 'seovault-ai' ),
											$audit_summary['total']
										);
										?>
										<p class="seovaultseo-api-activity-summary description"><?php echo esc_html( implode( ' · ', $summary_parts ) ); ?></p>
										<table class="widefat striped seovaultseo-api-activity-table" style="max-width:900px;">
											<thead>
												<tr>
													<th><?php esc_html_e( 'Time', 'seovault-ai' ); ?></th>
													<th><?php esc_html_e( 'Count', 'seovault-ai' ); ?></th>
													<th><?php esc_html_e( 'Route', 'seovault-ai' ); ?></th>
													<th><?php esc_html_e( 'Method', 'seovault-ai' ); ?></th>
													<th><?php esc_html_e( 'Success', 'seovault-ai' ); ?></th>
													<th><?php esc_html_e( 'Event', 'seovault-ai' ); ?></th>
													<th><?php esc_html_e( 'Reason', 'seovault-ai' ); ?></th>
												</tr>
											</thead>
											<tbody>
												<?php foreach ( $audit_display_rows as $audit_row ) : ?>
													<?php
													$event_code  = (string) ( $audit_row[ AuditLog::COL_EVENT_TYPE ] ?? '' );
													$reason_code = (string) ( $audit_row[ AuditLog::COL_FAILURE_REASON ] ?? '' );
													$row_count   = isset( $audit_row['count'] ) ? max( 1, (int) $audit_row['count'] ) : 1;
													?>
													<tr>
														<td><?php echo esc_html( $audit_row[ AuditLog::COL_CREATED_AT ] ); ?></td>
														<td class="seovaultseo-api-activity-count">
															<?php
															if ( $row_count > 1 ) {
																echo esc_html( '×' . $row_count );
															} else {
																echo esc_html( '1' );
															}
															?>
														</td>
														<td style="word-break:break-all;"><?php echo esc_html( $audit_row[ AuditLog::COL_ROUTE ] ); ?></td>
														<td><?php echo esc_html( $audit_row[ AuditLog::COL_METHOD ] ); ?></td>
														<td>
															<?php if ( '1' === (string) $audit_row[ AuditLog::COL_SUCCESS ] ) : ?>
																<span style="color:#00a32a;"><?php esc_html_e( 'Yes', 'seovault-ai' ); ?></span>
															<?php else : ?>
																<span style="color:#d63638;"><?php esc_html_e( 'No', 'seovault-ai' ); ?></span>
															<?php endif; ?>
														</td>
														<td>
															<span title="<?php echo esc_attr( $event_code ); ?>"><?php echo esc_html( AuditLog::label_event_type( $event_code ) ); ?></span>
														</td>
														<td>
															<?php if ( '' !== $reason_code ) : ?>
																<span title="<?php echo esc_attr( $reason_code ); ?>"><?php echo esc_html( AuditLog::label_failure_reason( $reason_code ) ); ?></span>
															<?php endif; ?>
														</td>
													</tr>
												<?php endforeach; ?>
											</tbody>
										</table>
									<?php endif; ?>
								</div>
							</div>
						</div>

						<div id="vtab-output" class="<?php echo esc_attr( self::vtab_panel_classes( 'vtab-output', $active_tab ) ); ?>">
							<h2><?php esc_html_e( 'Output Mode', 'seovault-ai' ); ?></h2>
							<table class="form-table">
								<tr>
									<th scope="row">
										<label for="seovaultseo_output_mode"><?php esc_html_e( 'Output Mode', 'seovault-ai' ); ?></label>
									</th>
									<td>
										<select name="seovaultseo_output_mode" id="seovaultseo_output_mode" class="seovaultseo-select">
											<option value="auto" <?php selected( $output_mode, 'auto' ); ?>>
												<?php esc_html_e( 'Autopilot — Set & Run (Recommended)', 'seovault-ai' ); ?>
											</option>
											<option value="manual" <?php selected( $output_mode, 'manual' ); ?>>
												<?php esc_html_e( 'Manual — You control every field', 'seovault-ai' ); ?>
											</option>
											<option value="disabled" <?php selected( $output_mode, 'disabled' ); ?>>
												<?php esc_html_e( 'Disabled — Pause SEOvault AI', 'seovault-ai' ); ?>
											</option>
										</select>
										<p class="description">
											<strong><?php esc_html_e( 'Autopilot', 'seovault-ai' ); ?></strong> —
											<?php esc_html_e( 'SEOvault AI automatically generates all SEO meta tags, schema, sitemaps, Open Graph, Twitter cards, and robots directives using smart zero-config defaults. You can override any field per-post. This is the recommended mode for most sites.', 'seovault-ai' ); ?>
										</p>
										<p class="description">
											<strong><?php esc_html_e( 'Manual', 'seovault-ai' ); ?></strong> —
											<?php esc_html_e( 'SEOvault AI does not auto-generate any values. All SEO fields start empty — you fill in titles, descriptions, and meta tags yourself. SEOvault only outputs tags for fields you have explicitly set.', 'seovault-ai' ); ?>
										</p>
										<p class="description">
											<strong><?php esc_html_e( 'Disabled', 'seovault-ai' ); ?></strong> —
											<?php esc_html_e( 'SEOvault AI goes to sleep. No frontend SEO output, no meta box in the post editor, no sitemap, no schema — nothing. Use this when you want to try another SEO plugin while keeping SEOvault AI installed. Your data is preserved. Re-enable anytime from this settings page.', 'seovault-ai' ); ?>
										</p>
										<?php if ( 'auto' === $output_mode ) : ?>
										<div class="seovaultseo-autopilot-banner notice notice-info inline">
											<p>
												<span class="dashicons dashicons-airplane" style="vertical-align: middle; margin-right: 6px;"></span>
												<strong><?php esc_html_e( 'Autopilot is active.', 'seovault-ai' ); ?></strong>
												<?php esc_html_e( 'SEOvault AI is running in install-and-forget mode. All SEO output is handled automatically with smart defaults. You can still override any setting per-post or per-archive.', 'seovault-ai' ); ?>
											</p>
										</div>
										<?php endif; ?>
									</td>
								</tr>
							</table>
						</div>

						<div id="vtab-robots" class="<?php echo esc_attr( self::vtab_panel_classes( 'vtab-robots', $active_tab ) ); ?>">
							<h2><?php esc_html_e( 'Robots', 'seovault-ai' ); ?></h2>

							<?php if ( 'auto' !== $output_mode ) : ?>
							<div class="notice notice-info inline"><p><?php esc_html_e( 'Robots settings are only active in Autopilot mode.', 'seovault-ai' ); ?></p></div>
							<?php endif; ?>

							<h3><?php esc_html_e( 'Indexing Controls', 'seovault-ai' ); ?></h3>
							<table class="form-table">
								<tr>
									<th scope="row"><?php esc_html_e( 'Noindex search result pages', 'seovault-ai' ); ?></th>
									<td>
										<?php self::render_toggle( 'robots_search_noindex', __( 'Prevent search result pages from being indexed by search engines.', 'seovault-ai' ), Options::is_search_noindex() ); ?>
									</td>
								</tr>
								<tr>
									<th scope="row"><?php esc_html_e( 'Noindex date archives', 'seovault-ai' ); ?></th>
									<td>
										<?php self::render_toggle( 'robots_date_archives_noindex', __( 'Prevent date-based archive pages from being indexed.', 'seovault-ai' ), Options::is_date_archives_noindex() ); ?>
									</td>
								</tr>
								<tr>
									<th scope="row"><?php esc_html_e( 'Noindex attachment pages', 'seovault-ai' ); ?></th>
									<td>
										<?php self::render_toggle( 'robots_attachment_noindex', __( 'Prevent individual attachment (media) pages from being indexed.', 'seovault-ai' ), Options::is_attachment_noindex() ); ?>
									</td>
								</tr>
								<tr>
									<th scope="row"><?php esc_html_e( 'Noindex post format archives', 'seovault-ai' ); ?></th>
									<td>
										<?php self::render_toggle( 'robots_post_format_noindex', __( 'Prevent post format archive pages from being indexed.', 'seovault-ai' ), Options::is_post_format_noindex() ); ?>
									</td>
								</tr>
								<tr>
									<th scope="row"><?php esc_html_e( 'Noindex empty archives', 'seovault-ai' ); ?></th>
									<td>
										<?php self::render_toggle( 'robots_empty_archives_noindex', __( 'Add noindex to archive pages that contain no posts.', 'seovault-ai' ), Options::is_empty_archives_noindex() ); ?>
									</td>
								</tr>
								<tr>
									<th scope="row"><?php esc_html_e( 'Noindex post types', 'seovault-ai' ); ?></th>
									<td>
										<?php
										$noindex_post_types = Options::get_noindex_post_types();
										$public_post_types  = get_post_types( array( 'public' => true ), 'objects' );
										foreach ( $public_post_types as $pt ) {
											if ( 'attachment' === $pt->name ) {
												continue;
											}
											?>
											<label style="display:block;margin-bottom:4px;">
												<input type="checkbox" name="robots_noindex_post_types[]" value="<?php echo esc_attr( $pt->name ); ?>" <?php checked( in_array( $pt->name, $noindex_post_types, true ) ); ?> />
												<?php echo esc_html( $pt->labels->singular_name ); ?>
											</label>
											<?php
										}
										?>
										<p class="description"><?php esc_html_e( 'Singular posts of selected types get noindex unless a per-post robots override is set. Imported posts without explicit robots keep this default.', 'seovault-ai' ); ?></p>
									</td>
								</tr>
								<tr>
									<th scope="row"><?php esc_html_e( 'Advanced query protection', 'seovault-ai' ); ?></th>
									<td>
										<?php self::render_toggle( 'robots_advanced_query_protection', __( 'Detect and block indexing of exploited query strings (e.g. invalid page IDs, malformed parameters).', 'seovault-ai' ), Options::is_advanced_query_protection() ); ?>
									</td>
								</tr>
							</table>

							<h3><?php esc_html_e( 'Copyright Directives', 'seovault-ai' ); ?></h3>
							<table class="form-table">
								<tr>
									<th scope="row"><label for="robots_max_snippet"><?php esc_html_e( 'Max Snippet', 'seovault-ai' ); ?></label></th>
									<td>
										<input type="number" name="robots_max_snippet" id="robots_max_snippet" value="<?php echo esc_attr( Options::get_robots_max_snippet() ); ?>" min="-1" step="1" class="small-text" />
										<p class="description"><?php esc_html_e( '-1 = Unlimited (default), 0 = Disabled, positive = character limit. Controls the maximum text snippet length Google may show in search results.', 'seovault-ai' ); ?></p>
									</td>
								</tr>
								<tr>
									<th scope="row"><label for="robots_max_image_preview"><?php esc_html_e( 'Max Image Preview', 'seovault-ai' ); ?></label></th>
									<td>
										<select name="robots_max_image_preview" id="robots_max_image_preview" class="seovaultseo-select">
											<?php
											$img_preview = Options::get_robots_max_image_preview();
											$img_options = array(
												'none'     => __( 'None', 'seovault-ai' ),
												'standard' => __( 'Standard', 'seovault-ai' ),
												'large'    => __( 'Large', 'seovault-ai' ),
											);
											foreach ( $img_options as $val => $label ) {
												printf( '<option value="%s"%s>%s</option>', esc_attr( $val ), selected( $img_preview, $val, false ), esc_html( $label ) );
											}
											?>
										</select>
										<p class="description"><?php esc_html_e( 'Controls the maximum image preview size in search results.', 'seovault-ai' ); ?></p>
									</td>
								</tr>
								<tr>
									<th scope="row"><label for="robots_max_video_preview"><?php esc_html_e( 'Max Video Preview', 'seovault-ai' ); ?></label></th>
									<td>
										<input type="number" name="robots_max_video_preview" id="robots_max_video_preview" value="<?php echo esc_attr( Options::get_robots_max_video_preview() ); ?>" min="-1" step="1" class="small-text" />
										<p class="description"><?php esc_html_e( '-1 = Unlimited (default), 0 = Disabled, positive = seconds limit. Controls the maximum video preview duration in seconds.', 'seovault-ai' ); ?></p>
									</td>
								</tr>
							</table>

							<h3><?php esc_html_e( 'robots.txt Crawl Policy', 'seovault-ai' ); ?></h3>
							<table class="form-table">
								<tr>
									<th scope="row"><label for="robots_policy"><?php esc_html_e( 'Crawl Policy', 'seovault-ai' ); ?></label></th>
									<td>
										<select name="robots_policy" id="robots_policy" class="seovaultseo-select">
											<?php
											$cur_policy = Options::get_robots_policy();
											$policies   = array(
												''         => __( 'None (default)', 'seovault-ai' ),
												'balanced' => __( 'Balanced', 'seovault-ai' ),
												'maximum_visibility' => __( 'Maximum Visibility', 'seovault-ai' ),
												'strict'   => __( 'Strict', 'seovault-ai' ),
												'custom'   => __( 'Custom', 'seovault-ai' ),
											);
											foreach ( $policies as $val => $label ) {
												printf( '<option value="%s"%s>%s</option>', esc_attr( $val ), selected( $cur_policy, $val, false ), esc_html( $label ) );
											}
											?>
										</select>
										<p class="description"><?php esc_html_e( 'Select a robots.txt crawl policy or use custom rules.', 'seovault-ai' ); ?></p>
									</td>
								</tr>
								<tr id="robots-custom-content-row" style="<?php echo 'custom' === Options::get_robots_policy() ? '' : 'display:none;'; ?>">
									<th scope="row"><label for="robots_custom_content"><?php esc_html_e( 'Custom robots.txt content', 'seovault-ai' ); ?></label></th>
									<td>
										<textarea name="robots_custom_content" id="robots_custom_content" rows="8" class="large-text code"><?php echo esc_textarea( Options::get_robots_custom_content() ); ?></textarea>
										<p class="description"><?php esc_html_e( 'Enter custom robots.txt rules. The plugin will inject these between BEGIN/END markers.', 'seovault-ai' ); ?></p>
									</td>
								</tr>
								<tr>
									<th scope="row"><?php esc_html_e( 'Preview', 'seovault-ai' ); ?></th>
									<td>
										<button type="button" class="button button-secondary" id="seovaultseo-robots-preview-btn"><?php esc_html_e( 'Preview robots.txt', 'seovault-ai' ); ?></button>
										<pre id="seovaultseo-robots-preview-output" style="display:none;margin-top:10px;background:#f6f7f7;border:1px solid #c3c4c7;padding:12px;border-radius:4px;font-size:12px;white-space:pre-wrap;overflow-x:auto;"></pre>
										<p id="seovaultseo-robots-preview-link" style="display:none;margin-top:8px;"><a href="<?php echo esc_url( home_url( '/robots.txt' ) ); ?>" target="_blank"><?php esc_html_e( 'View your live robots.txt', 'seovault-ai' ); ?> &rarr;</a></p>
									</td>
								</tr>
							</table>
						</div>
						<div id="vtab-llms" class="<?php echo esc_attr( self::vtab_panel_classes( 'vtab-llms', $active_tab ) ); ?>">
							<h2><?php esc_html_e( 'AI-readable llms.txt', 'seovault-ai' ); ?></h2>
							<table class="form-table">
								<tr>
									<th scope="row"><?php esc_html_e( 'Serve AI-readable llms.txt files from SEOvault AI', 'seovault-ai' ); ?></th>
									<td>
										<div class="seovaultseo-toggle-row">
											<label class="seovaultseo-switch">
												<input type="checkbox" name="seovaultseo_llms_enabled" id="seovaultseo_llms_enabled" value="1" <?php checked( $llms_enabled ); ?> />
												<span class="seovaultseo-slider"></span>
											</label>
											<label for="seovaultseo_llms_enabled" class="seovaultseo-toggle-label"><?php esc_html_e( 'Allow SEOvault AI to manage llms.txt', 'seovault-ai' ); ?></label>
										</div>
										<p class="description"><?php esc_html_e( 'When enabled, the plugin serves virtual /llms.txt and /llms-full.txt routes. The content of these files is generated on the SEOvault AI web app; go to the AI Visibility page in your web app dashboard, generate the llms.txt content, and publish it to your site. The plugin will then serve it at /llms.txt and /llms-full.txt automatically.', 'seovault-ai' ); ?></p>
									</td>
								</tr>
							</table>
						</div>
						<div id="vtab-homepage" class="<?php echo esc_attr( self::vtab_panel_classes( 'vtab-homepage', $active_tab ) ); ?>">
							<h2><?php esc_html_e( 'Homepage', 'seovault-ai' ); ?></h2>
							<p class="description" style="margin-bottom:16px;"><?php esc_html_e( 'Set a custom title and description for your homepage to control how it appears in search engine results.', 'seovault-ai' ); ?></p>

							<div class="seovaultseo-homepage-field">
								<div class="seovaultseo-homepage-field-header">
									<label for="seovaultseo_home_title" class="seovaultseo-homepage-label"><?php esc_html_e( 'Search Engine Title', 'seovault-ai' ); ?></label>
									<span class="seovaultseo-char-counter" data-target="seovaultseo_home_title" data-max="60">
										<span class="seovaultseo-char-count">0</span> / 60
									</span>
								</div>
								<div class="seovaultseo-homepage-input-wrap">
									<input type="text" name="seovaultseo_home_title" id="seovaultseo_home_title" value="<?php echo esc_attr( Options::get_home_title() ); ?>" class="regular-text seovaultseo-var-target seovaultseo-homepage-title-input" placeholder="<?php echo esc_attr( Options::get_home_title() ? '' : wp_strip_all_tags( get_bloginfo( 'name' ) ) ); ?>" />
									<button type="button" class="button button-secondary seovaultseo-var-picker-btn" data-target="seovaultseo_home_title" title="<?php esc_attr_e( 'Insert variable', 'seovault-ai' ); ?>"><span class="dashicons dashicons-arrow-down-alt2"></span></button>
								</div>
								<p class="description"><?php esc_html_e( 'Click the dropdown button to insert variables. Leave empty to use the site name.', 'seovault-ai' ); ?></p>
							</div>

							<div class="seovaultseo-homepage-field">
								<div class="seovaultseo-homepage-field-header">
									<label for="seovaultseo_home_description" class="seovaultseo-homepage-label"><?php esc_html_e( 'Search Engine Description', 'seovault-ai' ); ?></label>
									<span class="seovaultseo-char-counter" data-target="seovaultseo_home_description" data-max="160">
										<span class="seovaultseo-char-count">0</span> / 160
									</span>
								</div>
								<div class="seovaultseo-homepage-input-wrap">
									<textarea name="seovaultseo_home_description" id="seovaultseo_home_description" rows="3" class="large-text seovaultseo-var-target seovaultseo-homepage-desc-input" placeholder="<?php echo esc_attr( Options::get_home_description() ? '' : wp_strip_all_tags( get_bloginfo( 'description' ) ) ); ?>"><?php echo esc_textarea( Options::get_home_description() ); ?></textarea>
								</div>
								<p class="description"><?php esc_html_e( 'Leave empty to use the site description.', 'seovault-ai' ); ?></p>
							</div>

							<div class="seovaultseo-google-preview-wrap">
								<h3 class="seovaultseo-google-preview-title"><?php esc_html_e( 'Search Engine Preview', 'seovault-ai' ); ?></h3>
								<div class="seovaultseo-google-preview" id="seovaultseo-google-preview">
									<div class="seovaultseo-google-preview-site">
										<?php if ( get_site_icon_url( 32 ) ) : ?>
											<img src="<?php echo esc_url( get_site_icon_url( 32 ) ); ?>" alt="" class="seovaultseo-google-preview-favicon" />
										<?php else : ?>
											<span class="dashicons dashicons-search seovaultseo-google-preview-favicon-icon"></span>
										<?php endif; ?>
										<div class="seovaultseo-google-preview-site-info">
											<span class="seovaultseo-google-preview-site-name"><?php echo esc_html( wp_strip_all_tags( get_bloginfo( 'name' ) ) ); ?></span>
											<span class="seovaultseo-google-preview-url"><?php echo esc_html( wp_parse_url( home_url(), PHP_URL_HOST ) ); ?></span>
										</div>
									</div>
									<p class="seovaultseo-google-preview-page-title" id="seovaultseo-google-preview-title-text"><?php echo esc_html( Options::get_home_title() ? Options::get_home_title() : wp_strip_all_tags( get_bloginfo( 'name' ) ) ); ?></p>
									<p class="seovaultseo-google-preview-page-desc" id="seovaultseo-google-preview-desc-text"><?php echo esc_html( Options::get_home_description() ? Options::get_home_description() : wp_strip_all_tags( get_bloginfo( 'description' ) ) ); ?></p>
								</div>
							</div>
						</div>

						<div id="vtab-templates" class="<?php echo esc_attr( self::vtab_panel_classes( 'vtab-templates', $active_tab ) ); ?>">
							<h2><?php esc_html_e( 'Templates', 'seovault-ai' ); ?></h2>
							<table class="form-table">
										<tr>
											<th scope="row">
												<?php esc_html_e( 'Enable Templates', 'seovault-ai' ); ?>
											</th>
											<td>
												<?php self::render_toggle( 'seovaultseo_templates_enabled', __( 'Apply title and description templates automatically', 'seovault-ai' ), Options::is_templates_enabled(), 'seovaultseo_templates_enabled', 'yes' ); ?>
												<p class="description"><?php esc_html_e( 'When enabled, posts without a custom SEO title or description will use these templates. Disable to use raw post titles and auto-generated descriptions.', 'seovault-ai' ); ?></p>
											</td>
										</tr>
										<tr id="seovaultseo-template-row-separator">
											<th scope="row">
												<label for="seovaultseo_title_separator"><?php esc_html_e( 'Title Separator', 'seovault-ai' ); ?></label>
											</th>
											<td>
												<select name="seovaultseo_title_separator" id="seovaultseo_title_separator" class="seovaultseo-select">
													<?php
													$current_sep = Options::get_title_separator();
													$separators  = array(
														'-' => __( '— (Dash)', 'seovault-ai' ),
														'|' => __( '| (Pipe)', 'seovault-ai' ),
														'·' => __( '· (Middot)', 'seovault-ai' ),
														'»' => __( '» (Guillemet)', 'seovault-ai' ),
														':' => __( ': (Colon)', 'seovault-ai' ),
														'/' => __( '/ (Slash)', 'seovault-ai' ),
														'–' => __( '– (En-dash)', 'seovault-ai' ),
														'—' => __( '— (Em-dash)', 'seovault-ai' ),
														'•' => __( '• (Bullet)', 'seovault-ai' ),
													);
													foreach ( $separators as $char => $label ) {
														printf(
															'<option value="%s"%s>%s</option>',
															esc_attr( $char ),
															selected( $current_sep, $char, false ),
															esc_html( $label )
														);
													}
													?>
												</select>
												<p class="description"><?php esc_html_e( 'Character used by the %%sep%% variable in templates.', 'seovault-ai' ); ?></p>
											</td>
										</tr>
										<tr id="seovaultseo-template-row-title">
											<th scope="row">
												<label for="seovaultseo_title_template"><?php esc_html_e( 'Title Template', 'seovault-ai' ); ?></label>
											</th>
											<td>
												<div class="seovaultseo-input-row seovaultseo-template-input-row">
													<input type="text" name="seovaultseo_title_template" id="seovaultseo_title_template" value="<?php echo esc_attr( Options::get_title_template() ); ?>" class="large-text seovaultseo-var-target" placeholder="%title% %sep% %sitename%" />
													<button type="button" class="seovaultseo-var-picker-btn" data-target="seovaultseo_title_template" aria-label="<?php esc_attr_e( 'Insert variable', 'seovault-ai' ); ?>">
														<span class="dashicons dashicons-plus-alt2"></span>
													</button>
												</div>
												<p class="description"><?php esc_html_e( 'Click + to insert a variable. Default: %%title%% %%sep%% %%sitename%%', 'seovault-ai' ); ?></p>
											</td>
										</tr>
										<tr id="seovaultseo-template-row-description">
											<th scope="row">
												<label for="seovaultseo_description_template"><?php esc_html_e( 'Description Template', 'seovault-ai' ); ?></label>
											</th>
											<td>
												<div class="seovaultseo-input-row seovaultseo-template-input-row">
													<textarea name="seovaultseo_description_template" id="seovaultseo_description_template" rows="5" class="large-text seovaultseo-var-target" placeholder="%excerpt%"><?php echo esc_textarea( Options::get_description_template() ); ?></textarea>
													<button type="button" class="seovaultseo-var-picker-btn" data-target="seovaultseo_description_template" aria-label="<?php esc_attr_e( 'Insert variable', 'seovault-ai' ); ?>">
														<span class="dashicons dashicons-plus-alt2"></span>
													</button>
												</div>
												<p class="description"><?php esc_html_e( 'Click + to insert a variable. Default: %%excerpt%%', 'seovault-ai' ); ?></p>
											</td>
										</tr>
							</table>
						</div>

						<div id="vtab-schema" class="<?php echo esc_attr( self::vtab_panel_classes( 'vtab-schema', $active_tab ) ); ?>">
							<?php self::render_schema_tab(); ?>
						</div>

						<div id="vtab-social" class="<?php echo esc_attr( self::vtab_panel_classes( 'vtab-social', $active_tab ) ); ?>">
							<h2><?php esc_html_e( 'Social', 'seovault-ai' ); ?></h2>

							<!-- Section 1: Default Social Image -->
							<h3><?php esc_html_e( 'Default Social Image', 'seovault-ai' ); ?></h3>
							<div class="seovaultseo-social-image-section">
								<input type="hidden" name="seovaultseo_default_social_image" id="seovaultseo_default_social_image" value="<?php echo esc_attr( Options::get_default_social_image() ); ?>" />
								<div class="seovaultseo-social-image-preview" id="seovaultseo-social-image-preview">
									<?php $social_image_url = Options::get_default_social_image(); ?>
									<?php if ( ! empty( $social_image_url ) ) : ?>
										<img src="<?php echo esc_url( $social_image_url ); ?>" alt="<?php esc_attr_e( 'Social Image', 'seovault-ai' ); ?>" />
									<?php else : ?>
										<span class="dashicons dashicons-format-image"></span>
									<?php endif; ?>
								</div>
								<div class="seovaultseo-social-image-actions">
									<button type="button" class="button button-secondary" id="seovaultseo-social-image-upload"><span class="dashicons dashicons-upload"></span> <?php esc_html_e( 'Upload Image', 'seovault-ai' ); ?></button>
									<button type="button" class="button button-secondary seovaultseo-social-image-remove" id="seovaultseo-social-image-remove"<?php echo empty( Options::get_default_social_image() ) ? ' style="display:none;"' : ''; ?>><span class="dashicons dashicons-no"></span> <?php esc_html_e( 'Remove Image', 'seovault-ai' ); ?></button>
								</div>
								<div class="seovaultseo-social-image-url-row">
									<input type="url" id="seovaultseo-social-image-url" value="<?php echo esc_attr( Options::get_default_social_image() ); ?>" class="regular-text" placeholder="https://example.com/social-image.jpg" />
								</div>
								<p class="description"><?php esc_html_e( 'Recommended size: 1200 x 630 px. Use JPG or PNG format for best results.', 'seovault-ai' ); ?></p>
							</div>

							<!-- Section 2: Facebook -->
							<h3><?php esc_html_e( 'Facebook', 'seovault-ai' ); ?></h3>
							<table class="form-table">
								<tr>
									<th scope="row">
										<label for="seovaultseo_facebook_page_url"><?php esc_html_e( 'Site Facebook Page', 'seovault-ai' ); ?></label>
									</th>
									<td>
										<input type="url" name="seovaultseo_facebook_page_url" id="seovaultseo_facebook_page_url" value="<?php echo esc_attr( Options::get_facebook_page_url() ); ?>" class="regular-text" placeholder="https://www.facebook.com/YourPage" />
										<p class="description"><?php esc_html_e( 'Provide the full URL of your official Facebook Page. This URL will be used in your site\'s structured data under Schema → Organization → SameAs.', 'seovault-ai' ); ?></p>
									</td>
								</tr>
								<tr>
									<th scope="row">
										<label for="seovaultseo_facebook_author_fallback"><?php esc_html_e( 'Author Facebook Page', 'seovault-ai' ); ?></label>
									</th>
									<td>
										<input type="url" name="seovaultseo_facebook_author_fallback" id="seovaultseo_facebook_author_fallback" value="<?php echo esc_attr( Options::get_facebook_author_fallback() ); ?>" class="regular-text" placeholder="https://www.facebook.com/YourPersonalProfile" />
										<p class="description"><?php esc_html_e( 'Default Facebook author page URL. Used when a post doesn\'t have a specific author profile set.', 'seovault-ai' ); ?></p>
									</td>
								</tr>
							</table>

							<!-- Section 3: X (Twitter) -->
							<h3><?php esc_html_e( 'X (Twitter)', 'seovault-ai' ); ?></h3>
							<table class="form-table">
								<tr>
									<th scope="row"><?php esc_html_e( 'X Card Type', 'seovault-ai' ); ?></th>
									<td>
										<label><input type="radio" name="seovaultseo_twitter_card_type" value="summary_large_image" <?php checked( Options::get_twitter_card_type(), 'summary_large_image' ); ?> /> <?php esc_html_e( 'Summary Large Image', 'seovault-ai' ); ?></label><br>
										<label><input type="radio" name="seovaultseo_twitter_card_type" value="summary" <?php checked( Options::get_twitter_card_type(), 'summary' ); ?> /> <?php esc_html_e( 'Summary', 'seovault-ai' ); ?></label>
										<p class="description"><?php esc_html_e( 'Choose how your content appears when shared on X.', 'seovault-ai' ); ?></p>
									</td>
								</tr>
								<tr>
									<th scope="row">
										<label for="seovaultseo_twitter_profile_username"><?php esc_html_e( 'Site\'s X Profile', 'seovault-ai' ); ?></label>
									</th>
									<td>
										<input type="url" name="seovaultseo_twitter_profile_username" id="seovaultseo_twitter_profile_username" value="<?php echo esc_attr( Options::get_twitter_profile_username() ); ?>" class="regular-text" placeholder="https://www.x.com/your-site-username" />
										<p class="description"><?php esc_html_e( 'Full URL of your official X profile. Used in structured data SameAs field.', 'seovault-ai' ); ?></p>
									</td>
								</tr>
								<tr>
									<th scope="row">
										<label for="seovaultseo_twitter_profile_fallback"><?php esc_html_e( 'Author\'s X Profile', 'seovault-ai' ); ?></label>
									</th>
									<td>
										<input type="url" name="seovaultseo_twitter_profile_fallback" id="seovaultseo_twitter_profile_fallback" value="<?php echo esc_attr( Options::get_twitter_profile_fallback() ); ?>" class="regular-text" placeholder="https://www.x.com/your-personal-username" />
										<p class="description"><?php esc_html_e( 'Fallback X author profile URL. Used when an individual author URL is not provided.', 'seovault-ai' ); ?></p>
									</td>
								</tr>
							</table>

							<!-- Section 4: Other Accounts -->
							<h3><?php esc_html_e( 'Other Accounts', 'seovault-ai' ); ?></h3>
							<p class="description"><?php esc_html_e( 'Enter the full URLs of your official profiles. These will be added to the Organization schema under SameAs to help search engines verify your online presence.', 'seovault-ai' ); ?></p>
							<div id="seovaultseo-social-profiles-container" style="margin-top:12px;">
								<?php foreach ( Options::get_social_profiles() as $profile_url ) : ?>
									<div class="seovaultseo-social-profile-row">
										<input type="url" name="seovaultseo_social_profiles[]" value="<?php echo esc_attr( $profile_url ); ?>" class="regular-text" placeholder="https://..." />
										<button type="button" class="button button-secondary seovaultseo-remove-profile"><span class="dashicons dashicons-trash"></span></button>
									</div>
								<?php endforeach; ?>
								<?php if ( empty( Options::get_social_profiles() ) ) : ?>
									<div class="seovaultseo-social-profile-row">
										<input type="url" name="seovaultseo_social_profiles[]" value="" class="regular-text" placeholder="https://..." />
										<button type="button" class="button button-secondary seovaultseo-remove-profile"><span class="dashicons dashicons-trash"></span></button>
									</div>
								<?php endif; ?>
							</div>
							<button type="button" class="button button-secondary" id="seovaultseo-add-profile"><span class="dashicons dashicons-plus-alt2"></span> <?php esc_html_e( 'Add Another', 'seovault-ai' ); ?></button>
						</div>

						<div id="vtab-breadcrumbs" class="<?php echo esc_attr( self::vtab_panel_classes( 'vtab-breadcrumbs', $active_tab ) ); ?>">
							<h2><?php esc_html_e( 'Breadcrumbs', 'seovault-ai' ); ?></h2>
							<?php
								$bc_enabled        = Options::is_breadcrumbs_enabled();
								$bc_separator      = Options::get_breadcrumbs_separator();
								$bc_home_label     = Options::get_breadcrumbs_home_label();
								$bc_prefix         = Options::get_breadcrumbs_prefix();
								$bc_404_label      = Options::get_breadcrumbs_404_label();
								$bc_search_format  = Options::get_breadcrumbs_search_format();
								$bc_archive_format = Options::get_breadcrumbs_archive_format();
								$bc_show_home      = Options::breadcrumbs_show_home();
								$bc_remove_title   = Options::breadcrumbs_remove_post_title();
								$bc_show_ancestors = Options::breadcrumbs_show_ancestors();
								$bc_hide_tax_name  = Options::breadcrumbs_hide_taxonomy_name();
								$bc_show_blog      = Options::breadcrumbs_show_blog();
							?>
								<table class="form-table">
									<tr>
										<th scope="row"><?php esc_html_e( 'Enable Breadcrumbs', 'seovault-ai' ); ?></th>
										<td>
											<?php self::render_toggle( 'breadcrumbs_enabled', __( 'Enable breadcrumb trail generation', 'seovault-ai' ), $bc_enabled ); ?>
											<p class="description"><?php esc_html_e( 'Use the shortcode [seovault_breadcrumb] or the template tag seovault_the_breadcrumbs() in your theme.', 'seovault-ai' ); ?></p>
										</td>
									</tr>
									<tr>
										<th scope="row"><label for="breadcrumbs_separator"><?php esc_html_e( 'Separator', 'seovault-ai' ); ?></label></th>
										<td>
											<select name="breadcrumbs_separator" id="breadcrumbs_separator" class="seovaultseo-select">
												<option value="&raquo;" <?php selected( $bc_separator, '&raquo;' ); ?>>&raquo;</option>
												<option value="&rsaquo;" <?php selected( $bc_separator, '&rsaquo;' ); ?>>&rsaquo;</option>
												<option value="/" <?php selected( $bc_separator, '/' ); ?>>/</option>
												<option value="-" <?php selected( $bc_separator, '-' ); ?>>-</option>
												<option value="|" <?php selected( $bc_separator, '|' ); ?>>|</option>
												<option value="&gt;" <?php selected( $bc_separator, '&gt;' ); ?>>&gt;</option>
											</select>
										</td>
									</tr>
									<tr>
										<th scope="row"><label for="breadcrumbs_home_label"><?php esc_html_e( 'Homepage Label', 'seovault-ai' ); ?></label></th>
										<td>
											<input type="text" name="breadcrumbs_home_label" id="breadcrumbs_home_label" value="<?php echo esc_attr( $bc_home_label ); ?>" class="regular-text" />
										</td>
									</tr>
									<tr>
										<th scope="row"><label for="breadcrumbs_prefix"><?php esc_html_e( 'Prefix', 'seovault-ai' ); ?></label></th>
										<td>
											<input type="text" name="breadcrumbs_prefix" id="breadcrumbs_prefix" value="<?php echo esc_attr( $bc_prefix ); ?>" class="regular-text" />
											<p class="description"><?php esc_html_e( 'Text shown before the breadcrumb trail.', 'seovault-ai' ); ?></p>
										</td>
									</tr>
									<tr>
										<th scope="row"><label for="breadcrumbs_404_label"><?php esc_html_e( '404 Label', 'seovault-ai' ); ?></label></th>
										<td>
											<input type="text" name="breadcrumbs_404_label" id="breadcrumbs_404_label" value="<?php echo esc_attr( $bc_404_label ); ?>" class="regular-text" />
										</td>
									</tr>
									<tr>
										<th scope="row"><label for="breadcrumbs_search_format"><?php esc_html_e( 'Search Format', 'seovault-ai' ); ?></label></th>
										<td>
											<input type="text" name="breadcrumbs_search_format" id="breadcrumbs_search_format" value="<?php echo esc_attr( $bc_search_format ); ?>" class="regular-text" />
											<p class="description">
											<?php
											/* translators: %s: placeholder token inserted into the breadcrumb label for the search query. */
											esc_html_e( 'Use %s as placeholder for the search query.', 'seovault-ai' );
											?>
											</p>
										</td>
									</tr>
									<tr>
										<th scope="row"><label for="breadcrumbs_archive_format"><?php esc_html_e( 'Archive Format', 'seovault-ai' ); ?></label></th>
										<td>
											<input type="text" name="breadcrumbs_archive_format" id="breadcrumbs_archive_format" value="<?php echo esc_attr( $bc_archive_format ); ?>" class="regular-text" />
											<p class="description">
											<?php
											/* translators: %s: placeholder token inserted into the breadcrumb label for the archive title. */
											esc_html_e( 'Use %s as placeholder for the archive title.', 'seovault-ai' );
											?>
											</p>
										</td>
									</tr>
									<tr>
										<th scope="row"><?php esc_html_e( 'Show Homepage Link', 'seovault-ai' ); ?></th>
										<td>
											<?php self::render_checkbox( 'breadcrumbs_show_home', '1', __( 'Display homepage link in trail', 'seovault-ai' ), $bc_show_home ); ?>
										</td>
									</tr>
									<tr>
										<th scope="row"><?php esc_html_e( 'Hide Post Title', 'seovault-ai' ); ?></th>
										<td>
											<?php self::render_toggle( 'breadcrumbs_remove_post_title', __( 'Remove the current post title from the trail', 'seovault-ai' ), $bc_remove_title ); ?>
										</td>
									</tr>
									<tr>
										<th scope="row"><?php esc_html_e( 'Show Ancestor Categories', 'seovault-ai' ); ?></th>
										<td>
											<?php self::render_checkbox( 'breadcrumbs_show_ancestors', '1', __( 'Show all ancestor categories for child terms', 'seovault-ai' ), $bc_show_ancestors ); ?>
										</td>
									</tr>
									<tr>
										<th scope="row"><?php esc_html_e( 'Hide Taxonomy Name', 'seovault-ai' ); ?></th>
										<td>
											<?php self::render_toggle( 'breadcrumbs_hide_taxonomy_name', __( 'Hide the taxonomy name from the trail', 'seovault-ai' ), $bc_hide_tax_name ); ?>
										</td>
									</tr>
									<?php if ( 'page' === get_option( 'show_on_front' ) && get_option( 'page_for_posts' ) ) : ?>
									<tr>
										<th scope="row"><?php esc_html_e( 'Show Blog Page', 'seovault-ai' ); ?></th>
										<td>
											<?php self::render_toggle( 'breadcrumbs_show_blog', __( 'Show the blog page in the trail', 'seovault-ai' ), $bc_show_blog ); ?>
										</td>
									</tr>
									<?php endif; ?>
								</table>
						</div>

						<div id="vtab-404-monitor" class="<?php echo esc_attr( self::vtab_panel_classes( 'vtab-404-monitor', $active_tab ) ); ?>">
							<h2><?php esc_html_e( '404 Monitor', 'seovault-ai' ); ?></h2>
							<?php
								$m404_enabled  = Options::is_monitor404_enabled();
								$m404_mode     = Options::get_monitor404_mode();
								$m404_limit    = Options::get_monitor404_limit();
								$m404_ignore   = Options::is_monitor404_ignore_query_params();
								$m404_excludes = Options::get_monitor404_excludes();
							?>
								<table class="form-table">
									<tr>
										<th scope="row"><?php esc_html_e( 'Enable 404 Monitor', 'seovault-ai' ); ?></th>
										<td>
											<?php self::render_toggle( 'monitor404_enabled', __( 'Log 404 errors on your site', 'seovault-ai' ), $m404_enabled ); ?>
											<p class="description"><?php esc_html_e( 'When enabled, requests that result in a 404 error will be logged for analysis and redirect creation.', 'seovault-ai' ); ?></p>
										</td>
									</tr>
									<tr>
										<th scope="row"><label for="monitor404_mode"><?php esc_html_e( 'Logging Mode', 'seovault-ai' ); ?></label></th>
										<td>
											<select name="monitor404_mode" id="monitor404_mode" class="seovaultseo-select">
												<option value="simple" <?php selected( $m404_mode, 'simple' ); ?>><?php esc_html_e( 'Simple (URL only)', 'seovault-ai' ); ?></option>
												<option value="advanced" <?php selected( $m404_mode, 'advanced' ); ?>><?php esc_html_e( 'Advanced (URL + Referrer + User Agent)', 'seovault-ai' ); ?></option>
											</select>
											<p class="description"><?php esc_html_e( 'Simple mode groups identical URLs and counts hits. Advanced mode logs each visit with referrer and user agent data.', 'seovault-ai' ); ?></p>
										</td>
									</tr>
									<tr>
										<th scope="row"><label for="monitor404_limit"><?php esc_html_e( 'Log Limit', 'seovault-ai' ); ?></label></th>
										<td>
											<input type="number" name="monitor404_limit" id="monitor404_limit" value="<?php echo esc_attr( $m404_limit ); ?>" min="0" step="100" class="small-text" />
											<p class="description"><?php esc_html_e( 'Maximum number of log entries to keep. When the limit is reached, all logs are cleared. Set to 0 for unlimited.', 'seovault-ai' ); ?></p>
										</td>
									</tr>
									<tr>
										<th scope="row"><?php esc_html_e( 'Ignore Query Parameters', 'seovault-ai' ); ?></th>
										<td>
											<?php self::render_toggle( 'monitor404_ignore_query_params', __( 'Strip query string (?...) from URLs before logging', 'seovault-ai' ), $m404_ignore ); ?>
										</td>
									</tr>
								</table>

								<?php \SEOvaultSEO\NotFound\AdminSettings::render_fallback_fields(); ?>
								<?php \SEOvaultSEO\NotFound\AdminSettings::render_recovery_fields(); ?>

								<h3><?php esc_html_e( 'Exclusion Patterns', 'seovault-ai' ); ?></h3>
								<p class="description"><?php esc_html_e( 'URLs matching these patterns will not be logged. Leave empty to log all 404s.', 'seovault-ai' ); ?></p>
								<div id="seovaultseo-404-excludes">
									<?php if ( ! empty( $m404_excludes ) ) : ?>
										<?php foreach ( $m404_excludes as $i => $rule ) : ?>
											<div class="seovaultseo-404-exclude-row" style="display:flex;gap:8px;margin-bottom:8px;align-items:center;">
												<input type="text" name="monitor404_excludes[<?php echo esc_attr( $i ); ?>][pattern]" value="<?php echo esc_attr( $rule['pattern'] ?? '' ); ?>" placeholder="e.g. /wp-content/" class="regular-text" />
												<select name="monitor404_excludes[<?php echo esc_attr( $i ); ?>][comparison]" class="seovaultseo-select seovaultseo-select-small">
													<option value="contains" <?php selected( $rule['comparison'] ?? '', 'contains' ); ?>><?php esc_html_e( 'Contains', 'seovault-ai' ); ?></option>
													<option value="exact" <?php selected( $rule['comparison'] ?? '', 'exact' ); ?>><?php esc_html_e( 'Exact Match', 'seovault-ai' ); ?></option>
													<option value="starts" <?php selected( $rule['comparison'] ?? '', 'starts' ); ?>><?php esc_html_e( 'Starts With', 'seovault-ai' ); ?></option>
													<option value="ends" <?php selected( $rule['comparison'] ?? '', 'ends' ); ?>><?php esc_html_e( 'Ends With', 'seovault-ai' ); ?></option>
													<option value="regex" <?php selected( $rule['comparison'] ?? '', 'regex' ); ?>><?php esc_html_e( 'Regex', 'seovault-ai' ); ?></option>
												</select>
												<button type="button" class="button seovaultseo-404-exclude-remove"><?php esc_html_e( 'Remove', 'seovault-ai' ); ?></button>
											</div>
										<?php endforeach; ?>
									<?php endif; ?>
								</div>
								<p>
									<button type="button" class="button button-secondary" id="seovaultseo-404-add-exclude"><?php esc_html_e( 'Add Exclusion', 'seovault-ai' ); ?></button>
								</p>

								<hr style="margin:30px 0;border:none;border-top:1px solid #e0e0e0;" />

								<?php settings_errors( 'seovault_seo_404' ); ?>

								<?php if ( self::$show_404_redirect_form && self::$redirect_form_log_id ) : ?>
									<?php self::render_404_redirect_form_inline( self::$redirect_form_log_id ); ?>
								<?php endif; ?>

								<?php if ( ! $m404_enabled ) : ?>
									<div class="notice notice-warning inline">
										<p><?php esc_html_e( '404 Monitor is currently disabled. Enable it above to start logging 404 errors.', 'seovault-ai' ); ?></p>
									</div>
								<?php else : ?>
									<h3><?php esc_html_e( '404 Log Entries', 'seovault-ai' ); ?></h3>
									<?php
									$m404_stats = Monitor404Db::get_stats();
									?>
									<div class="seovaultseo-404-stats" style="display:flex;gap:20px;margin:15px 0;">
										<div class="seovaultseo-stat-box" style="background:#fff;border:1px solid #c3c4c7;border-radius:4px;padding:12px 20px;min-width:120px;">
											<div style="font-size:24px;font-weight:600;"><?php echo esc_html( number_format_i18n( (int) $m404_stats->total ) ); ?></div>
											<div style="color:#646970;font-size:13px;"><?php esc_html_e( 'Unique URLs', 'seovault-ai' ); ?></div>
										</div>
										<div class="seovaultseo-stat-box" style="background:#fff;border:1px solid #c3c4c7;border-radius:4px;padding:12px 20px;min-width:120px;">
											<div style="font-size:24px;font-weight:600;"><?php echo esc_html( number_format_i18n( (int) $m404_stats->hits ) ); ?></div>
											<div style="color:#646970;font-size:13px;"><?php esc_html_e( 'Total Hits', 'seovault-ai' ); ?></div>
										</div>
										<div style="flex:1;"></div>
										<div style="display:flex;align-items:center;gap:10px;">
										<a href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?page=seovault-ai-general&tab=vtab-404-monitor&action=clear_log' ), 'seovaultseo_404_clear_log' ) ); ?>" class="button button-secondary" data-seovaultseo-confirm="<?php echo esc_attr__( 'Delete all 404 log entries?', 'seovault-ai' ); ?>"><?php esc_html_e( 'Clear All Logs', 'seovault-ai' ); ?></a>
										</div>
									</div>

									<div id="seovaultseo-404-filter">
										<?php
										$m404_table = new Monitor404Table();
										$m404_table->prepare_items();
										$m404_table->search_box( __( 'Search URLs', 'seovault-ai' ), 'seovaultseo-404-search' );
										$m404_table->display();
										?>
									</div>
								<?php endif; ?>
							</div>

				<div id="vtab-redirects" class="<?php echo esc_attr( self::vtab_panel_classes( 'vtab-redirects', $active_tab ) ); ?>">
					<?php \SEOvaultSEO\RedirectManager\AdminPage::render_tab(); ?>
				</div>

				<div id="vtab-image-seo" class="<?php echo esc_attr( self::vtab_panel_classes( 'vtab-image-seo', $active_tab ) ); ?>">
					<h2><?php esc_html_e( 'Image SEO', 'seovault-ai' ); ?></h2>
					<?php
						$img_enabled         = Options::is_image_seo_enabled();
						$img_alt_format      = Options::get_image_seo_alt_format();
						$img_title_format    = Options::get_image_seo_title_format();
						$img_override        = Options::is_image_seo_override_empty_alt();
						$img_webapp_priority = Options::is_image_seo_webapp_priority();
					?>
						<table class="form-table">
							<tr>
								<th scope="row"><?php esc_html_e( 'Enable Image SEO', 'seovault-ai' ); ?></th>
								<td>
									<?php self::render_toggle( 'image_seo_enabled', __( 'Automatically add missing ALT and title attributes to images', 'seovault-ai' ), $img_enabled ); ?>
									<p class="description"><?php esc_html_e( 'When enabled, images in post content that are missing alt or title attributes will have them auto-generated based on the format strings below. The stored content is not modified - attributes are applied dynamically on display..', 'seovault-ai' ); ?></p>
								</td>
							</tr>
							<tr>
								<th scope="row"><label for="image_seo_alt_format"><?php esc_html_e( 'ALT Attribute Format', 'seovault-ai' ); ?></label></th>
								<td>
									<input type="text" name="image_seo_alt_format" id="image_seo_alt_format" value="<?php echo esc_attr( $img_alt_format ?: '' ); ?>" class="regular-text" placeholder="%filename%" />
									<p class="description"><?php esc_html_e( 'Format used for auto-generated ALT attributes. Available variables: %%filename%%, %%title%%, %%focuskw%%, %%sitename%%, %%category%%, %%tags%%. Default: %%filename%%', 'seovault-ai' ); ?></p>
							</td>
							</tr>
							<tr>
								<th scope="row"><label for="image_seo_title_format"><?php esc_html_e( 'Title Attribute Format', 'seovault-ai' ); ?></label></th>
								<td>
									<input type="text" name="image_seo_title_format" id="image_seo_title_format" value="<?php echo esc_attr( $img_title_format ?: '' ); ?>" class="regular-text" placeholder="%title%" />
									<p class="description"><?php esc_html_e( 'Format used for auto-generated title attributes. Leave empty to disable title attribute generation. Default: %%title%%', 'seovault-ai' ); ?></p>
							</td>
							</tr>
							<tr>
								<th scope="row"><?php esc_html_e( 'Override Empty ALT', 'seovault-ai' ); ?></th>
								<td>
									<?php self::render_toggle( 'image_seo_override_empty_alt', __( 'Override existing empty ALT attributes (alt="")', 'seovault-ai' ), $img_override ); ?>
									<p class="description"><?php esc_html_e( 'If checked, images with an explicit empty alt attribute (alt="") will also get auto-generated ALT text. Images with non-empty alt attributes are never modified.', 'seovault-ai' ); ?></p>
							</td>
							</tr>
							<tr>
								<th scope="row"><?php esc_html_e( 'Web App Priority', 'seovault-ai' ); ?></th>
								<td>
									<?php self::render_toggle( 'image_seo_webapp_priority', __( 'Let the SEOvault web app override auto-generated ALT text', 'seovault-ai' ), $img_webapp_priority ); ?>
									<p class="description"><?php esc_html_e( 'When enabled, ALT text set by the SEOvault AI web app (via the inject-image-alt REST endpoint) takes priority over auto-generated values. Disable if you want auto-generated ALT to always be used.', 'seovault-ai' ); ?></p>
							</td>
							</tr>
						</table>
				</div>

				<div id="vtab-local-seo" class="<?php echo esc_attr( self::vtab_panel_classes( 'vtab-local-seo', $active_tab ) ); ?>">
					<?php \SEOvaultSEO\LocalSEO\AdminPage::render_tab(); ?>
				</div>

				<div id="vtab-frontend-score" class="<?php echo esc_attr( self::vtab_panel_classes( 'vtab-frontend-score', $active_tab ) ); ?>">
					<h2><?php esc_html_e( 'Frontend SEO Score', 'seovault-ai' ); ?></h2>
					<?php
						$fs_enabled  = Options::is_frontend_score_enabled();
						$fs_position = Options::get_frontend_score_position();
						$fs_types    = Options::get_frontend_score_post_types();
						$public_pts  = get_post_types( array( 'public' => true ), 'objects' );
						$excluded    = apply_filters( 'seovaultseo_excluded_post_types', array( 'attachment' ) );
					?>
						<table class="form-table">
							<tr>
								<th scope="row"><?php esc_html_e( 'Enable Frontend Score', 'seovault-ai' ); ?></th>
								<td>
									<?php self::render_toggle( 'frontend_score_enabled', __( 'Display an SEO score badge on the frontend for supported posts', 'seovault-ai' ), $fs_enabled ); ?>
									<p class="description"><?php esc_html_e( 'When enabled, a circular score badge is injected into post content. You can also use the [seovault_seo_score] shortcode in any post.', 'seovault-ai' ); ?></p>
								</td>
							</tr>
							<tr>
								<th scope="row"><label for="frontend_score_position"><?php esc_html_e( 'Badge Position', 'seovault-ai' ); ?></label></th>
								<td>
									<select name="frontend_score_position" id="frontend_score_position" class="seovaultseo-select">
										<option value="top" <?php selected( $fs_position, 'top' ); ?>><?php esc_html_e( 'Above content', 'seovault-ai' ); ?></option>
										<option value="bottom" <?php selected( $fs_position, 'bottom' ); ?>><?php esc_html_e( 'Below content', 'seovault-ai' ); ?></option>
										<option value="both" <?php selected( $fs_position, 'both' ); ?>><?php esc_html_e( 'Both (above and below)', 'seovault-ai' ); ?></option>
										<option value="custom" <?php selected( $fs_position, 'custom' ); ?>><?php esc_html_e( 'Custom (shortcode only)', 'seovault-ai' ); ?></option>
									</select>
									<p class="description"><?php esc_html_e( 'Choose where the score badge appears relative to the post content. Use "Custom" to place it manually via the [seovault_seo_score] shortcode.', 'seovault-ai' ); ?></p>
									<div id="seovault-seo-score-shortcode-info" class="notice notice-info inline" style="display:none; margin:10px 0 0; padding:10px 12px;">
										<p style="margin:0 0 6px;"><strong><?php esc_html_e( 'Custom Position — Shortcode', 'seovault-ai' ); ?></strong></p>
										<p style="margin:0 0 8px;"><?php esc_html_e( 'Copy and paste this shortcode into any post or page where you want the SEO score badge to appear:', 'seovault-ai' ); ?></p>
									<p style="margin:0;"><code class="seovaultseo-copy-shortcode" style="font-size:14px; background:#f0f0f1; padding:4px 8px; border-radius:3px; cursor:pointer; user-select:all;">[seovault_seo_score]</code></p>
									</div>
								</td>
							</tr>
							<tr>
								<th scope="row"><?php esc_html_e( 'Post Types', 'seovault-ai' ); ?></th>
								<td>
									<fieldset>
										<?php
										foreach ( $public_pts as $pt ) :
											if ( in_array( $pt->name, $excluded, true ) ) {
												continue;
											}
											?>
											<label class="seovaultseo-check" style="display:inline-block; margin-right:20px;">
												<input type="checkbox" name="frontend_score_post_types[]" value="<?php echo esc_attr( $pt->name ); ?>" <?php checked( in_array( $pt->name, $fs_types, true ) ); ?> />
												<span><?php echo esc_html( $pt->labels->name ); ?></span>
											</label>
										<?php endforeach; ?>
									</fieldset>
									<p class="description"><?php esc_html_e( 'Select which post types should display the frontend SEO score badge.', 'seovault-ai' ); ?></p>
								</td>
							</tr>
						</table>
				</div>

				<div id="vtab-woocommerce" class="<?php echo esc_attr( self::vtab_panel_classes( 'vtab-woocommerce', $active_tab ) ); ?>">
					<h2><?php esc_html_e( 'WooCommerce SEO', 'seovault-ai' ); ?></h2>
					<?php if ( ! \SEOvaultSEO\WooCommerce\WooCommerce::is_woocommerce_active() ) : ?>
						<div class="notice notice-warning inline" style="margin:10px 0 20px; padding:10px 12px;">
							<p style="margin:0;"><?php esc_html_e( 'WooCommerce is not currently active. Install and activate WooCommerce to use these SEO features. Settings saved here will be applied automatically once WooCommerce is activated.', 'seovault-ai' ); ?></p>
						</div>
					<?php endif; ?>
					<?php
						$wc_remove_product_base  = Options::is_wc_remove_product_base();
						$wc_remove_category_base = Options::is_wc_remove_category_base();
						$wc_remove_parent_slugs  = Options::is_wc_remove_parent_slugs();
						$wc_remove_generator     = Options::is_wc_remove_generator();
						$wc_remove_shop_schema   = Options::is_wc_remove_shop_schema();
						$wc_brand_taxonomy       = Options::get_wc_brand_taxonomy();
						$wc_gtin_type            = Options::get_wc_gtin_type();
						$wc_gtin_label           = Options::get_wc_gtin_label();
						$wc_show_gtin_frontend   = Options::is_wc_show_gtin_frontend();
						$wc_noindex_hidden       = Options::is_wc_noindex_hidden_products();
						$wc_custom_brand         = Options::get_wc_custom_brand();
						$wc_additional_schema    = Options::is_wc_additional_schema();
						$wc_multicurrency        = implode( ', ', Options::get_wc_multicurrency_currencies() );
						$wc_per_product_ids      = Options::is_wc_per_product_identifiers();
						$wc_import_export        = Options::is_wc_import_export_enabled();
						$wc_enhanced_schema      = Options::is_wc_enhanced_schema();
						$wc_remove_breadcrumb    = Options::is_wc_remove_breadcrumb_schema();
						$wc_variation_images     = Options::is_wc_schema_variation_images();
						$wc_product_attributes   = Options::is_wc_schema_product_attributes();
						$wc_return_policy_page   = Options::get_wc_schema_return_policy_page();
						$product_taxonomies      = \SEOvaultSEO\WooCommerce\WooCommerce::is_woocommerce_active() ? get_object_taxonomies( 'product', 'objects' ) : array();
						$pages                   = get_pages( array( 'sort_column' => 'post_title' ) );
					?>
						<table class="form-table">
							<tr>
								<th scope="row"><?php esc_html_e( 'Remove Product Base', 'seovault-ai' ); ?></th>
								<td>
									<?php self::render_toggle( 'wc_remove_product_base', __( 'Remove prefix (e.g. /shop/ or /product/) from product URLs.', 'seovault-ai' ), $wc_remove_product_base ); ?>
									<p class="description"><?php esc_html_e( 'Default: /product/accessories/item/ becomes: /accessories/item/', 'seovault-ai' ); ?></p>
								</td>
							</tr>
							<tr>
								<th scope="row"><?php esc_html_e( 'Remove Category Base', 'seovault-ai' ); ?></th>
								<td>
									<?php self::render_toggle( 'wc_remove_category_base', __( 'Remove prefix from product category URLs.', 'seovault-ai' ), $wc_remove_category_base ); ?>
									<p class="description"><?php esc_html_e( 'Default: /product-category/accessories/ becomes: /accessories/', 'seovault-ai' ); ?></p>
								</td>
							</tr>
							<tr>
								<th scope="row"><?php esc_html_e( 'Remove Parent Slugs', 'seovault-ai' ); ?></th>
								<td>
									<?php self::render_toggle( 'wc_remove_parent_slugs', __( 'Remove parent category slugs from product category URLs.', 'seovault-ai' ), $wc_remove_parent_slugs ); ?>
									<p class="description"><?php esc_html_e( 'Default: /product-category/accessories/action-figures/ becomes: /product-category/action-figures/', 'seovault-ai' ); ?></p>
								</td>
							</tr>
							<tr>
								<th scope="row"><?php esc_html_e( 'Remove Generator Tag', 'seovault-ai' ); ?></th>
								<td>
									<?php self::render_toggle( 'wc_remove_generator', __( 'Remove WooCommerce generator meta tag from page source.', 'seovault-ai' ), $wc_remove_generator ); ?>
								</td>
							</tr>
							<tr>
								<th scope="row"><?php esc_html_e( 'Remove Shop Archive Schema', 'seovault-ai' ); ?></th>
								<td>
									<?php self::render_toggle( 'wc_remove_shop_schema', __( 'Remove schema markup from WooCommerce shop archive pages.', 'seovault-ai' ), $wc_remove_shop_schema ); ?>
								</td>
							</tr>
							<tr>
								<th scope="row"><label for="wc_brand_taxonomy"><?php esc_html_e( 'Product Brand Taxonomy', 'seovault-ai' ); ?></label></th>
								<td>
									<select name="wc_brand_taxonomy" id="wc_brand_taxonomy" class="seovaultseo-select">
										<option value=""><?php esc_html_e( '— Select —', 'seovault-ai' ); ?></option>
										<?php foreach ( $product_taxonomies as $tax ) : ?>
											<option value="<?php echo esc_attr( $tax->name ); ?>" <?php selected( $wc_brand_taxonomy, $tax->name ); ?>><?php echo esc_html( $tax->label ); ?></option>
										<?php endforeach; ?>
									</select>
									<p class="description"><?php esc_html_e( 'Select which taxonomy to use as the product brand in schema and Open Graph markup.', 'seovault-ai' ); ?></p>
								</td>
							</tr>
							<tr>
								<th scope="row"><label for="wc_custom_brand"><?php esc_html_e( 'Custom Brand Text', 'seovault-ai' ); ?></label></th>
								<td>
									<input type="text" name="wc_custom_brand" id="wc_custom_brand" value="<?php echo esc_attr( $wc_custom_brand ); ?>" class="regular-text" placeholder="<?php esc_attr_e( 'e.g. Acme Corp', 'seovault-ai' ); ?>" />
									<p class="description"><?php esc_html_e( 'Override the brand taxonomy with a fixed brand name for all products. Leave empty to use the selected taxonomy.', 'seovault-ai' ); ?></p>
								</td>
							</tr>
							<tr>
								<th scope="row"><label for="wc_gtin_type"><?php esc_html_e( 'Product Identifier Type', 'seovault-ai' ); ?></label></th>
								<td>
									<select name="wc_gtin_type" id="wc_gtin_type" class="seovaultseo-select">
										<option value="gtin8" <?php selected( $wc_gtin_type, 'gtin8' ); ?>><?php esc_html_e( 'GTIN-8', 'seovault-ai' ); ?></option>
										<option value="gtin12" <?php selected( $wc_gtin_type, 'gtin12' ); ?>><?php esc_html_e( 'GTIN-12 (UPC)', 'seovault-ai' ); ?></option>
										<option value="gtin13" <?php selected( $wc_gtin_type, 'gtin13' ); ?>><?php esc_html_e( 'GTIN-13 (EAN)', 'seovault-ai' ); ?></option>
										<option value="gtin14" <?php selected( $wc_gtin_type, 'gtin14' ); ?>><?php esc_html_e( 'GTIN-14', 'seovault-ai' ); ?></option>
										<option value="mpn" <?php selected( $wc_gtin_type, 'mpn' ); ?>><?php esc_html_e( 'MPN', 'seovault-ai' ); ?></option>
										<option value="isbn" <?php selected( $wc_gtin_type, 'isbn' ); ?>><?php esc_html_e( 'ISBN', 'seovault-ai' ); ?></option>
									</select>
									<p class="description"><?php esc_html_e( 'Select the product identifier type used in schema markup. The field will appear on the product edit page under the Inventory tab.', 'seovault-ai' ); ?></p>
								</td>
							</tr>
							<tr>
								<th scope="row"><label for="wc_gtin_label"><?php esc_html_e( 'Custom Identifier Label', 'seovault-ai' ); ?></label></th>
								<td>
									<input type="text" name="wc_gtin_label" id="wc_gtin_label" value="<?php echo esc_attr( $wc_gtin_label ); ?>" class="regular-text" placeholder="<?php esc_attr_e( 'e.g. Barcode', 'seovault-ai' ); ?>" />
									<p class="description"><?php esc_html_e( 'Custom label for the identifier field. Leave empty to use the default label (GTIN, MPN, or ISBN).', 'seovault-ai' ); ?></p>
								</td>
							</tr>
							<tr>
								<th scope="row"><?php esc_html_e( 'Show Identifier on Frontend', 'seovault-ai' ); ?></th>
								<td>
									<?php self::render_toggle( 'wc_show_gtin_frontend', __( 'Display the product identifier (GTIN/MPN/ISBN) on the frontend product page.', 'seovault-ai' ), $wc_show_gtin_frontend ); ?>
								</td>
							</tr>
							<tr>
								<th scope="row"><?php esc_html_e( 'Per-Product Identifiers', 'seovault-ai' ); ?></th>
								<td>
									<?php self::render_toggle( 'wc_per_product_identifiers', __( 'Enable individual fields for GTIN-8, GTIN-12, GTIN-13, GTIN-14, MPN, and ISBN on each product and variation. When enabled, all non-empty identifiers are included in schema markup simultaneously.', 'seovault-ai' ), $wc_per_product_ids ); ?>
									<p class="description"><?php esc_html_e( 'When disabled, only the single identifier type selected above is used (backward compatible).', 'seovault-ai' ); ?></p>
								</td>
							</tr>
							<tr>
								<th scope="row"><?php esc_html_e( 'CSV Import/Export', 'seovault-ai' ); ?></th>
								<td>
									<?php self::render_toggle( 'wc_import_export', __( 'Add GTIN, MPN, and ISBN columns to WooCommerce product CSV export and import. Supports automatic column mapping for common header names (UPC, EAN, ITF-14, etc.).', 'seovault-ai' ), $wc_import_export ); ?>
									<p class="description"><?php esc_html_e( 'When enabled, product identifiers are included in WooCommerce\'s native Product CSV Import/Export under WooCommerce > Products > Import/Export.', 'seovault-ai' ); ?></p>
								</td>
							</tr>
							<tr>
								<th scope="row"><?php esc_html_e( 'Noindex Hidden Products', 'seovault-ai' ); ?></th>
								<td>
									<?php self::render_toggle( 'wc_noindex_hidden_products', __( 'Set noindex for products with catalog visibility set to "hidden".', 'seovault-ai' ), $wc_noindex_hidden ); ?>
								</td>
							</tr>
							<tr>
								<th scope="row"><?php esc_html_e( 'Additional Schema Properties', 'seovault-ai' ); ?></th>
								<td>
									<?php self::render_toggle( 'wc_additional_schema', __( 'Add manufacturer reference and brand URL to the product schema.', 'seovault-ai' ), $wc_additional_schema ); ?>
								</td>
							</tr>
							<tr>
								<th scope="row"><label for="wc_multicurrency_currencies"><?php esc_html_e( 'Multi-Currency Currencies', 'seovault-ai' ); ?></label></th>
								<td>
									<input type="text" name="wc_multicurrency_currencies" id="wc_multicurrency_currencies" value="<?php echo esc_attr( $wc_multicurrency ); ?>" class="regular-text" placeholder="<?php esc_attr_e( 'e.g. EUR, GBP, CAD', 'seovault-ai' ); ?>" />
									<p class="description"><?php esc_html_e( 'Comma-separated list of additional currency codes for the product schema offers. Use a multi-currency plugin filter to convert prices.', 'seovault-ai' ); ?></p>
								</td>
							</tr>
						</table>

						<h3 style="margin-top:30px;"><?php esc_html_e( 'Enhanced Product Schema', 'seovault-ai' ); ?></h3>
						<p class="description" style="margin-bottom:15px;"><?php esc_html_e( 'Filter and enhance WooCommerce\'s native structured data output. Merges brand, GTIN, manufacturer, variation images, and product attributes into WC\'s schema, and removes duplicate breadcrumb schema.', 'seovault-ai' ); ?></p>
						<table class="form-table">
							<tr>
								<th scope="row"><?php esc_html_e( 'Enable Enhanced Schema', 'seovault-ai' ); ?></th>
								<td>
									<?php self::render_toggle( 'wc_enhanced_schema', __( 'Filter WooCommerce\'s native product structured data and merge with our enhanced schema fields.', 'seovault-ai' ), $wc_enhanced_schema ); ?>
									<p class="description"><?php esc_html_e( 'When enabled, WooCommerce\'s native JSON-LD product schema is enhanced with brand, GTIN/MPN/ISBN, manufacturer, and more. This prevents duplicate schema output by merging rather than duplicating.', 'seovault-ai' ); ?></p>
								</td>
							</tr>
							<tr>
								<th scope="row"><?php esc_html_e( 'Remove WC Breadcrumb Schema', 'seovault-ai' ); ?></th>
								<td>
									<?php self::render_toggle( 'wc_remove_breadcrumb_schema', __( 'Remove WooCommerce\'s breadcrumb schema and use our breadcrumb schema instead.', 'seovault-ai' ), $wc_remove_breadcrumb ); ?>
									<p class="description"><?php esc_html_e( 'Prevents duplicate breadcrumb schema output. Recommended when enhanced schema is enabled.', 'seovault-ai' ); ?></p>
								</td>
							</tr>
							<tr>
								<th scope="row"><?php esc_html_e( 'Variation Images in Schema', 'seovault-ai' ); ?></th>
								<td>
									<?php self::render_toggle( 'wc_schema_variation_images', __( 'Include product variation images in the product schema image property.', 'seovault-ai' ), $wc_variation_images ); ?>
									<p class="description"><?php esc_html_e( 'Adds each variation\'s image to the main product schema image list for variable products.', 'seovault-ai' ); ?></p>
								</td>
							</tr>
							<tr>
								<th scope="row"><?php esc_html_e( 'Product Attributes in Schema', 'seovault-ai' ); ?></th>
								<td>
									<?php self::render_toggle( 'wc_schema_product_attributes', __( 'Include allowed product attributes (color, pattern, material, size) in the product schema.', 'seovault-ai' ), $wc_product_attributes ); ?>
									<p class="description"><?php esc_html_e( 'Adds single-value product attributes to the schema output for better product visibility in search results.', 'seovault-ai' ); ?></p>
								</td>
							</tr>
							<tr>
								<th scope="row"><label for="wc_schema_return_policy_page"><?php esc_html_e( 'Return Policy Page', 'seovault-ai' ); ?></label></th>
								<td>
									<select name="wc_schema_return_policy_page" id="wc_schema_return_policy_page" class="seovaultseo-select">
										<option value="0"><?php esc_html_e( '— None —', 'seovault-ai' ); ?></option>
										<?php foreach ( $pages as $page ) : ?>
											<option value="<?php echo esc_attr( $page->ID ); ?>" <?php selected( $wc_return_policy_page, $page->ID ); ?>><?php echo esc_html( $page->post_title ); ?></option>
										<?php endforeach; ?>
									</select>
									<p class="description"><?php esc_html_e( 'Select a page to add a MerchantReturnPolicy to the organization schema on shop pages.', 'seovault-ai' ); ?></p>
								</td>
							</tr>
						</table>
				</div>

				<div id="vtab-analytics" class="<?php echo esc_attr( self::vtab_panel_classes( 'vtab-analytics', $active_tab ) ); ?>">
					<h2><?php esc_html_e( 'Analytics', 'seovault-ai' ); ?></h2>
					<?php
						$ga_enabled      = Options::is_ga_tracking_enabled();
						$ga_measurement  = Options::get_ga_measurement_id();
						$ga_track_logged = Options::is_ga_track_logged_in();
						$ga_anonymize    = Options::is_ga_anonymize_ip();
					?>
					<table class="form-table">
						<tr>
							<th scope="row"><?php esc_html_e( 'Enable Tracking', 'seovault-ai' ); ?></th>
							<td>
								<?php self::render_toggle( 'ga_tracking_enabled', __( 'Inject analytics tracking code into the page header', 'seovault-ai' ), $ga_enabled ); ?>
								<p class="description"><?php esc_html_e( 'When enabled, the gtag.js tracking code is inserted into your site header. No need to edit theme files or use another plugin.', 'seovault-ai' ); ?></p>
							</td>
						</tr>
						<?php
						// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- Hook name is the prefixed public API constant declared in ExtensionApi.
						do_action( \SEOvaultSEO\Extension\ExtensionApi::ACTION_ANALYTICS_FIELDS_BEFORE_MEASUREMENT );
						?>
						<tr id="seovaultseo-ga-measurement-row">
							<th scope="row"><label for="ga_measurement_id"><?php esc_html_e( 'Measurement ID', 'seovault-ai' ); ?></label></th>
							<td>
								<input type="text" name="ga_measurement_id" id="ga_measurement_id" value="<?php echo esc_attr( $ga_measurement ); ?>" class="regular-text" placeholder="G-XXXXXXXXXX" />
								<p class="description"><?php esc_html_e( 'Enter your GA4 Measurement ID (e.g. G-XXXXXXXXXX). Find this in your analytics account under Admin > Data Streams.', 'seovault-ai' ); ?></p>
							</td>
						</tr>
						<?php
						// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- Hook name is the prefixed public API constant declared in ExtensionApi.
						do_action( \SEOvaultSEO\Extension\ExtensionApi::ACTION_ANALYTICS_FIELDS_AFTER_MEASUREMENT );
						?>
						<tr>
							<th scope="row"><?php esc_html_e( 'Track Logged-in Users', 'seovault-ai' ); ?></th>
							<td>
								<?php self::render_toggle( 'ga_track_logged_in', __( 'Include tracking code for logged-in users', 'seovault-ai' ), $ga_track_logged ); ?>
								<p class="description"><?php esc_html_e( 'When unchecked, the tracking code is not output for logged-in users. This prevents admin activity from inflating your analytics data.', 'seovault-ai' ); ?></p>
							</td>
						</tr>
						<tr>
							<th scope="row"><?php esc_html_e( 'Anonymize IP', 'seovault-ai' ); ?></th>
							<td>
								<?php self::render_toggle( 'ga_anonymize_ip', __( 'Anonymize visitor IP addresses', 'seovault-ai' ), $ga_anonymize ); ?>
								<p class="description"><?php esc_html_e( 'When enabled, the last octet of the IP address is masked for privacy compliance (GDPR).', 'seovault-ai' ); ?></p>
							</td>
						</tr>
					</table>
				</div>

				<div id="vtab-indexnow" class="<?php echo esc_attr( self::vtab_panel_classes( 'vtab-indexnow', $active_tab ) ); ?>">
					<h2><?php esc_html_e( 'IndexNow — Instant Indexing', 'seovault-ai' ); ?></h2>
					<p class="description"><?php esc_html_e( 'IndexNow notifies search engines (Bing, Yandex, Seznam, and more) when your content is published or updated, so they can crawl and index it faster.', 'seovault-ai' ); ?></p>
					<?php
						$indexnow_key      = Options::get_indexnow_key();
						$indexnow_enabled  = Options::is_indexnow_enabled();
						$indexnow_types    = Options::get_indexnow_post_types();
						$public_post_types = get_post_types( array( 'public' => true ), 'objects' );
						$api               = \SEOvaultSEO\IndexNow\IndexNowApi::get_instance();
						$indexnow_log      = $api->get_log();
						$key_file_exists   = '' !== $indexnow_key && file_exists( $api->get_key_file_path( $indexnow_key ) );
					?>
					<table class="form-table">
						<tr>
							<th scope="row"><?php esc_html_e( 'API Key Status', 'seovault-ai' ); ?></th>
							<td>
								<?php if ( '' !== $indexnow_key ) : ?>
									<span class="seovaultseo-badge seovaultseo-badge-success"><?php esc_html_e( 'Key configured', 'seovault-ai' ); ?></span>
									<?php if ( $key_file_exists ) : ?>
										<span class="seovaultseo-badge seovaultseo-badge-success" style="margin-left:8px;"><?php esc_html_e( 'Key file accessible', 'seovault-ai' ); ?></span>
									<?php else : ?>
										<span class="seovaultseo-badge seovaultseo-badge-error" style="margin-left:8px;"><?php esc_html_e( 'Key file missing', 'seovault-ai' ); ?></span>
									<?php endif; ?>
									<p class="description">
										<code class="seovaultseo-code-inline"><?php echo esc_html( $indexnow_key ); ?></code><br>
										<?php esc_html_e( 'Key location:', 'seovault-ai' ); ?>
										<code class="seovaultseo-code-inline"><?php echo esc_url( trailingslashit( home_url() ) . $indexnow_key . '.txt' ); ?></code>
									</p>
								<?php else : ?>
									<span class="seovaultseo-badge seovaultseo-badge-warning"><?php esc_html_e( 'No API key set', 'seovault-ai' ); ?></span>
									<p class="description"><?php esc_html_e( 'A key will be generated automatically when you save settings below.', 'seovault-ai' ); ?></p>
								<?php endif; ?>
							</td>
						</tr>
						<tr>
							<th scope="row"><label for="indexnow_enabled"><?php esc_html_e( 'Auto-Submit on Publish', 'seovault-ai' ); ?></label></th>
							<td>
								<?php self::render_toggle( 'indexnow_enabled', __( 'Automatically submit URLs to IndexNow when posts are published or updated.', 'seovault-ai' ), $indexnow_enabled, 'indexnow_enabled' ); ?>
							</td>
						</tr>
						<tr>
							<th scope="row"><?php esc_html_e( 'Post Types to Auto-Submit', 'seovault-ai' ); ?></th>
							<td>
								<fieldset>
									<?php foreach ( $public_post_types as $pt ) : ?>
										<?php
										if ( 'attachment' === $pt->name ) {
											continue;}
										?>
										<label class="seovaultseo-check" style="display:inline-block; margin-right:20px;">
											<input type="checkbox" name="indexnow_post_types[]" value="<?php echo esc_attr( $pt->name ); ?>" <?php checked( in_array( $pt->name, $indexnow_types, true ) ); ?> />
											<span><?php echo esc_html( $pt->labels->name ); ?></span>
										</label>
									<?php endforeach; ?>
								</fieldset>
								<p class="description"><?php esc_html_e( 'Select which post types should be auto-submitted to IndexNow.', 'seovault-ai' ); ?></p>
							</td>
						</tr>
					</table>

					<hr>

					<h3><?php esc_html_e( 'Regenerate API Key', 'seovault-ai' ); ?></h3>
					<p class="description"><?php esc_html_e( 'Generate a new IndexNow API key. The old key file will be deleted.', 'seovault-ai' ); ?></p>
					<p>
					<button type="submit" form="seovaultseo-regenerate-indexnow-key-form" class="button button-secondary" data-seovaultseo-confirm="<?php echo esc_attr__( 'This will invalidate the old key. Continue?', 'seovault-ai' ); ?>">
							<?php esc_html_e( 'Regenerate Key', 'seovault-ai' ); ?>
						</button>
					</p>

					<hr>

					<h3><?php esc_html_e( 'Manual URL Submission', 'seovault-ai' ); ?></h3>
					<p class="description"><?php esc_html_e( 'Submit individual URLs to IndexNow manually. Enter one URL per line.', 'seovault-ai' ); ?></p>
					<textarea id="seovaultseo-indexnow-urls" rows="5" style="width:100%;max-width:600px;font-family:monospace;" placeholder="<?php esc_attr_e( 'https://example.com/page-1/', 'seovault-ai' ); ?>&#10;<?php esc_attr_e( 'https://example.com/page-2/', 'seovault-ai' ); ?>"></textarea>
					<p>
						<button type="button" class="button button-primary" id="seovaultseo-indexnow-submit-btn"><?php esc_html_e( 'Submit URLs', 'seovault-ai' ); ?></button>
						<span id="seovaultseo-indexnow-submit-result" style="margin-left:12px;"></span>
					</p>

					<hr>

					<h3><?php esc_html_e( 'Submission History', 'seovault-ai' ); ?></h3>
					<?php if ( empty( $indexnow_log ) ) : ?>
						<p><?php esc_html_e( 'No submissions yet.', 'seovault-ai' ); ?></p>
					<?php else : ?>
						<table class="widefat striped" style="max-width:800px;">
							<thead>
								<tr>
									<th><?php esc_html_e( 'URL', 'seovault-ai' ); ?></th>
									<th><?php esc_html_e( 'Status', 'seovault-ai' ); ?></th>
									<th><?php esc_html_e( 'Type', 'seovault-ai' ); ?></th>
									<th><?php esc_html_e( 'Message', 'seovault-ai' ); ?></th>
									<th><?php esc_html_e( 'Date', 'seovault-ai' ); ?></th>
								</tr>
							</thead>
							<tbody>
								<?php foreach ( array_reverse( $indexnow_log ) as $entry ) : ?>
									<tr>
										<td style="word-break:break-all;"><?php echo esc_html( $entry['url'] ); ?></td>
										<td>
											<?php if ( in_array( (int) $entry['status'], array( 200, 202, 204 ), true ) ) : ?>
												<span style="color:#00a32a;"><?php echo esc_html( $entry['status'] ); ?></span>
											<?php else : ?>
												<span style="color:#d63638;"><?php echo esc_html( $entry['status'] ); ?></span>
											<?php endif; ?>
										</td>
										<td><?php echo $entry['manual_submission'] ? esc_html__( 'Manual', 'seovault-ai' ) : esc_html__( 'Auto', 'seovault-ai' ); ?></td>
										<td><?php echo esc_html( $entry['message'] ); ?></td>
										<td><?php echo esc_html( gmdate( 'Y-m-d H:i:s', (int) $entry['time'] ) ); ?></td>
									</tr>
								<?php endforeach; ?>
							</tbody>
						</table>
						<p style="margin-top:10px;">
							<button type="button" class="button button-secondary" id="seovaultseo-indexnow-clear-log-btn"><?php esc_html_e( 'Clear Log', 'seovault-ai' ); ?></button>
						</p>
					<?php endif; ?>
				</div>

					<div id="vtab-sitemap" class="<?php echo esc_attr( self::vtab_panel_classes( 'vtab-sitemap', $active_tab ) ); ?>">
						<?php \SEOvaultSEO\Sitemap\Admin::render_tab(); ?>
					</div>

					<div id="vtab-tools" class="<?php echo esc_attr( self::vtab_panel_classes( 'vtab-tools', $active_tab ) ); ?>">
						<?php self::render_tools_tab(); ?>
					</div>

					<?php
					foreach ( self::get_extension_general_tabs() as $ext_tab ) :
						?>
					<div id="<?php echo esc_attr( $ext_tab['id'] ); ?>" class="<?php echo esc_attr( self::vtab_panel_classes( $ext_tab['id'], $active_tab ) ); ?>">
						<h2><?php echo esc_html( $ext_tab['label'] ); ?></h2>
						<?php
						if ( is_callable( $ext_tab['callback'] ) ) {
							call_user_func( $ext_tab['callback'], $ext_tab['id'], $active_tab );
						}
						?>
					</div>
						<?php
					endforeach;

					/**
					 * Fires after built-in + filtered General Settings tab panels.
					 *
					 * @param string $active_tab Active tab id.
					 */
					// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- Hook name is a prefixed ExtensionApi public constant.
					do_action( \SEOvaultSEO\Extension\ExtensionApi::ACTION_GENERAL_TAB_PANELS, $active_tab );
					?>

					<p class="submit">
					<button type="submit" name="seovaultseo_save_all_settings" id="seovaultseo-save-all-settings-btn" class="seovaultseo-save-btn" value="1">
						<span><?php esc_html_e( 'Save', 'seovault-ai' ); ?></span>
					</button>
				</p>
										</form>
				</div>
			</div>

			<form id="seovaultseo-404-filter-form" method="get" action="<?php echo esc_url( admin_url( 'admin.php' ) ); ?>" class="screen-reader-text" aria-hidden="true" tabindex="-1">
				<input type="hidden" name="page" value="seovault-ai-general" />
				<input type="hidden" name="tab" value="vtab-404-monitor" />
			</form>

			<?php
			// P6-001: Standalone POST forms (HTML5 form= attribute) so key actions are not nested in the settings form.
			$key_form_action = admin_url( 'admin.php?page=seovault-ai-general' );
			?>
			<form id="seovaultseo-regenerate-site-key-form" method="post" action="<?php echo esc_url( $key_form_action . '&tab=vtab-security#vtab-security' ); ?>" class="screen-reader-text" aria-hidden="true" tabindex="-1">
				<?php wp_nonce_field( 'seovaultseo_regenerate_key_action' ); ?>
				<input type="hidden" name="seovaultseo_regenerate_key" value="1" />
			</form>
			<form id="seovaultseo-generate-read-key-form" method="post" action="<?php echo esc_url( $key_form_action . '&tab=vtab-security#vtab-security' ); ?>" class="screen-reader-text" aria-hidden="true" tabindex="-1">
				<?php wp_nonce_field( 'seovaultseo_generate_read_key_action' ); ?>
				<input type="hidden" name="seovaultseo_generate_site_read_key" value="1" />
			</form>
			<form id="seovaultseo-generate-write-key-form" method="post" action="<?php echo esc_url( $key_form_action . '&tab=vtab-security#vtab-security' ); ?>" class="screen-reader-text" aria-hidden="true" tabindex="-1">
				<?php wp_nonce_field( 'seovaultseo_generate_write_key_action' ); ?>
				<input type="hidden" name="seovaultseo_generate_site_write_key" value="1" />
			</form>
			<form id="seovaultseo-regenerate-indexnow-key-form" method="post" action="<?php echo esc_url( $key_form_action . '&tab=vtab-indexnow#vtab-indexnow' ); ?>" class="screen-reader-text" aria-hidden="true" tabindex="-1">
				<?php wp_nonce_field( 'seovaultseo_indexnow_regenerate_key_action' ); ?>
				<input type="hidden" name="seovaultseo_indexnow_regenerate_key" value="1" />
			</form>
			<form id="seovaultseo-restart-onboarding-form" method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="screen-reader-text" aria-hidden="true" tabindex="-1">
				<?php wp_nonce_field( Onboarding::RESTART_NONCE ); ?>
				<input type="hidden" name="action" value="<?php echo esc_attr( Onboarding::RESTART_ACTION ); ?>" />
			</form>


		<?php
		self::render_global_footer();
	}

	public static function render_seo_analyzer() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'seovault-ai' ) );
		}

		\SEOvaultSEO\SeoAnalyzer\AdminPage::render();
	}

	public static function handle_404_monitor_actions() {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		$page = isset( $_REQUEST['page'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['page'] ) ) : '';
		if ( 'seovault-ai-general' !== $page ) {
			return;
		}

		if ( ! isset( $_GET['action'] ) ) {
			return;
		}

		$action = sanitize_key( wp_unslash( $_GET['action'] ) );
		$log_id = 0;
		switch ( $action ) {
			case 'clear_log':
				$nonce_action = 'seovaultseo_404_clear_log';
				break;
			case 'delete':
			case 'redirect':
			case 'redirect_form':
				if ( ! isset( $_GET['log'] ) ) {
					return;
				}
				$log_id = absint( wp_unslash( $_GET['log'] ) );
				if ( ! $log_id ) {
					return;
				}
				$nonce_action = 'seovaultseo_404_' . ( 'delete' === $action ? 'delete' : ( 'redirect' === $action ? 'redirect' : 'redirect_form' ) ) . '_' . $log_id;
				break;
			default:
				return;
		}

		$nonce = isset( $_GET['_wpnonce'] )
			? sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) )
			: '';
		if ( '' === $nonce || ! wp_verify_nonce( $nonce, $nonce_action ) ) {
			return;
		}

		switch ( $action ) {
			case 'clear_log':
				$count = Monitor404Db::get_count();
				Monitor404Db::clear_logs();
				add_settings_error(
					'seovault_seo_404',
					'cleared',
					sprintf(
						/* translators: %d: number of deleted entries */
						__( 'All 404 logs cleared — %d entries deleted.', 'seovault-ai' ),
						$count
					),
					'updated'
				);
				break;
			case 'delete':
				Monitor404Db::delete_log( $log_id );
				add_settings_error( 'seovault_seo_404', 'deleted', __( 'Log entry deleted.', 'seovault-ai' ), 'updated' );
				break;
			case 'redirect':
				$url = admin_url( 'admin.php?page=seovault-ai-general&tab=vtab-404-monitor&action=redirect_form&log=' . $log_id . '&_wpnonce=' . wp_create_nonce( 'seovaultseo_404_redirect_form_' . $log_id ) );
				wp_safe_redirect( $url );
				exit;
			case 'redirect_form':
				self::handle_404_redirect_post( $log_id );
				self::$show_404_redirect_form = true;
				self::$redirect_form_log_id   = $log_id;
				break;
		}
	}

	private static function handle_404_redirect_post( $log_id ) {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		$nonce = isset( $_POST['_wpnonce'] )
			? sanitize_text_field( wp_unslash( $_POST['_wpnonce'] ) )
			: '';
		if ( '' === $nonce || ! wp_verify_nonce( $nonce, 'seovaultseo_404_redirect_save_' . $log_id ) ) {
			return;
		}
		if ( ! isset( $_POST['seovaultseo_404_redirect_submit'] ) ) {
			return;
		}

		global $wpdb;
		$table = Monitor404Db::table_name();
		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Plugin-owned table name.
		$row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$table} WHERE id = %d", $log_id ) );
		// phpcs:enable
		if ( ! $row ) {
			add_settings_error( 'seovault_seo_404', 'not_found', __( 'Log entry not found.', 'seovault-ai' ), 'error' );
			return;
		}

		$target_url    = esc_url_raw( wp_unslash( $_POST['redirect_target_url'] ?? '' ) );
		$redirect_type = absint( $_POST['redirect_type'] ?? 301 );

		if ( ! empty( $target_url ) ) {
			$redirects              = get_option( 'seovaultseo_404_redirects', array() );
			$redirects[ $row->uri ] = array(
				'url'  => $target_url,
				'type' => in_array( $redirect_type, array( 301, 302 ), true ) ? $redirect_type : 301,
			);
			update_option( 'seovaultseo_404_redirects', $redirects, false );
			Monitor404Db::delete_log( $log_id );
			add_settings_error( 'seovault_seo_404', 'redirect_created', __( 'Redirect created and log entry removed.', 'seovault-ai' ), 'updated' );
			wp_safe_redirect( admin_url( 'admin.php?page=seovault-ai-general&tab=vtab-404-monitor' ) );
			exit;
		}
	}

	private static function render_404_redirect_form_inline( $log_id ) {
		global $wpdb;
		$table = Monitor404Db::table_name();
		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Plugin-owned table name.
		$row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$table} WHERE id = %d", $log_id ) );
		// phpcs:enable
		if ( ! $row ) {
			return;
		}
		?>
		<h3><?php esc_html_e( 'Create Redirect for 404', 'seovault-ai' ); ?></h3>
		<form method="post">
			<?php wp_nonce_field( 'seovaultseo_404_redirect_save_' . $log_id ); ?>
			<table class="form-table">
				<tr>
					<th scope="row"><?php esc_html_e( '404 URL', 'seovault-ai' ); ?></th>
					<td><code><?php echo esc_html( $row->uri ); ?></code></td>
				</tr>
				<tr>
					<th scope="row"><label for="redirect_target_url"><?php esc_html_e( 'Redirect To', 'seovault-ai' ); ?></label></th>
					<td>
						<input type="url" name="redirect_target_url" id="redirect_target_url" value="" class="large-text" placeholder="https://example.com/target-page/" />
						<p class="description"><?php esc_html_e( 'Enter the full URL that this 404 should redirect to.', 'seovault-ai' ); ?></p>
					</td>
				</tr>
				<tr>
					<th scope="row"><label for="redirect_type"><?php esc_html_e( 'Redirect Type', 'seovault-ai' ); ?></label></th>
					<td>
						<select name="redirect_type" id="redirect_type" class="seovaultseo-select">
							<option value="301"><?php esc_html_e( '301 Permanent', 'seovault-ai' ); ?></option>
							<option value="302"><?php esc_html_e( '302 Temporary', 'seovault-ai' ); ?></option>
						</select>
					</td>
				</tr>
			</table>
			<p>
				<input type="submit" name="seovaultseo_404_redirect_submit" class="button button-primary" value="<?php esc_attr_e( 'Create Redirect', 'seovault-ai' ); ?>" />
				<a href="<?php echo esc_url( admin_url( 'admin.php?page=seovault-ai-general&tab=vtab-404-monitor' ) ); ?>" class="button button-secondary"><?php esc_html_e( 'Cancel', 'seovault-ai' ); ?></a>
			</p>
		</form>
		<?php
	}

	/**
	 * Render an animated toggle switch (reusable across all settings tabs).
	 *
	 * @param string $name        The input name attribute.
	 * @param string $label       The visible label text.
	 * @param bool   $checked     Whether the toggle is on.
	 * @param string $id          Optional. The input id attribute (defaults to $name).
	 * @param string $value       Optional. The input value attribute (defaults to '1').
	 * @param string $description Optional. Description text below the toggle.
	 */
	public static function render_toggle( $name, $label, $checked, $id = '', $value = '1', $description = '' ) {
		if ( empty( $id ) ) {
			$id = $name;
		}
		?>
		<div class="seovaultseo-toggle-row">
			<label class="seovaultseo-switch">
				<input type="checkbox" name="<?php echo esc_attr( $name ); ?>" id="<?php echo esc_attr( $id ); ?>" value="<?php echo esc_attr( $value ); ?>" <?php checked( $checked ); ?> />
				<span class="seovaultseo-slider"></span>
			</label>
			<label for="<?php echo esc_attr( $id ); ?>" class="seovaultseo-toggle-label"><?php echo esc_html( $label ); ?></label>
		</div>
		<?php if ( ! empty( $description ) ) : ?>
			<p class="description"><?php echo esc_html( $description ); ?></p>
			<?php
		endif;
	}

	/**
	 * Render a styled checkbox (reusable across all settings tabs).
	 * Uses the .seovaultseo-check class for the animated checkmark style.
	 *
	 * @param string $name    The input name attribute.
	 * @param string $value   The input value attribute.
	 * @param string $label   The visible label text.
	 * @param bool   $checked Whether the checkbox is checked.
	 * @param string $id      Optional. The input id attribute (defaults to $name + $value).
	 */
	public static function render_checkbox( $name, $value, $label, $checked, $id = '' ) {
		if ( empty( $id ) ) {
			$id = $name . '_' . $value;
		}
		?>
		<label class="seovaultseo-check" style="display:block;margin-bottom:6px;">
			<input type="checkbox" name="<?php echo esc_attr( $name ); ?>" value="<?php echo esc_attr( $value ); ?>" id="<?php echo esc_attr( $id ); ?>" <?php checked( $checked ); ?> />
			<span><?php echo esc_html( $label ); ?></span>
		</label>
		<?php
	}

	public static function render_schema_tab() {
		SchemaSettingsTab::render();
	}

	public static function render_tools_tab() {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		$migration_status = \SEOvaultSEO\Migration\MigrationManager::get_status();
		?>

			<?php settings_errors( 'seovault_seo_settings' ); ?>

			<h2><span class="dashicons dashicons-migrate"></span> <?php esc_html_e( 'Import SEO Data from Other Plugins', 'seovault-ai' ); ?></h2>
			<p><?php esc_html_e( 'Migrate SEO meta data from other SEO plugins into SEOvault. This will not delete the source plugin\'s data.', 'seovault-ai' ); ?></p>

			<?php if ( ! $migration_status['available'] ) : ?>
				<div class="notice notice-info inline">
					<p><?php echo esc_html( $migration_status['message'] ?? __( 'No supported SEO plugins detected for migration.', 'seovault-ai' ) ); ?></p>
				</div>
			<?php else : ?>
				<div id="seovault-migration-providers">
					<?php foreach ( $migration_status['providers'] as $slug => $provider ) : ?>
						<div class="seovaultseo-migration-provider" data-provider="<?php echo esc_attr( $slug ); ?>">
							<div class="seovaultseo-migration-provider-header">
								<h3>
									<span class="dashicons dashicons-plugins-check"></span>
									<?php echo esc_html( $provider['name'] ); ?>
								</h3>
								<span class="seovaultseo-badge seovaultseo-badge-info">
									<?php
									echo esc_html(
										sprintf(
										/* translators: 1: total items */
											_n( '%d item', '%d items', $provider['total_items'], 'seovault-ai' ),
											$provider['total_items']
										)
									);
									?>
								</span>
							</div>
							<div class="seovaultseo-migration-provider-stats">
								<span><?php echo esc_html( sprintf( /* translators: %d: post count */ __( 'Posts: %d', 'seovault-ai' ), $provider['post_total'] ) ); ?></span>
								<span><?php echo esc_html( sprintf( /* translators: %d: term count */ __( 'Terms: %d', 'seovault-ai' ), $provider['term_total'] ) ); ?></span>
							</div>
							<?php if ( $provider['total_items'] > 0 ) : ?>
								<button type="button"
									class="button button-primary seovaultseo-migrate-btn"
									data-provider="<?php echo esc_attr( $slug ); ?>"
									data-total="<?php echo esc_attr( $provider['total_items'] ); ?>">
									<span class="dashicons dashicons-download"></span>
									<?php esc_html_e( 'Start Migration', 'seovault-ai' ); ?>
								</button>
								<button type="button"
									class="button button-secondary seovaultseo-migrate-global-btn"
									data-provider="<?php echo esc_attr( $slug ); ?>">
									<?php esc_html_e( 'Import Global Settings', 'seovault-ai' ); ?>
								</button>
							<?php else : ?>
								<p class="description"><?php esc_html_e( 'No data found to import from this plugin.', 'seovault-ai' ); ?></p>
							<?php endif; ?>
							<div class="seovaultseo-migration-progress" style="display:none;">
								<div class="seovaultseo-progress-bar">
									<div class="seovaultseo-progress-fill" style="width:0%"></div>
								</div>
								<span class="seovaultseo-progress-text">0 / 0</span>
								<div class="seovaultseo-migration-log"></div>
							</div>
						</div>
					<?php endforeach; ?>
				</div>
			<?php endif; ?>

			<hr style="margin: 28px 0;" />

			<div class="seovaultseo-thirdparty-blocks-tool" style="margin-bottom: 32px;">
				<h2><span class="dashicons dashicons-editor-table"></span> <?php esc_html_e( 'Convert FAQ & How-To Blocks', 'seovault-ai' ); ?></h2>
				<p>
					<?php esc_html_e( 'When another SEO plugin is deactivated, its FAQ and How-to Gutenberg blocks can become broken or unsupported. Scan your content and convert them to SEOvault FAQ and How-to blocks. Original content is backed up per post so you can roll back.', 'seovault-ai' ); ?>
				</p>
				<p>
					<button type="button" class="button button-secondary" id="seovault-thirdparty-block-scan-btn">
						<span class="dashicons dashicons-search" style="margin-top:3px;"></span>
						<?php esc_html_e( 'Scan for Blocks', 'seovault-ai' ); ?>
					</button>
					<button type="button" class="button button-primary" id="seovault-thirdparty-block-convert-btn" disabled>
						<span class="dashicons dashicons-update" style="margin-top:3px;"></span>
						<?php esc_html_e( 'Convert All Found Blocks', 'seovault-ai' ); ?>
					</button>
				</p>
				<div id="seovault-thirdparty-block-summary" style="display:none; margin-top: 12px;"></div>
				<div id="seovault-thirdparty-block-progress" style="display: none; margin: 16px 0 8px;">
					<p style="margin-bottom: 8px;"><strong><?php esc_html_e( 'Conversion Progress:', 'seovault-ai' ); ?></strong></p>
					<div id="seovault-thirdparty-block-log" class="seovaultseo-migration-log"></div>
				</div>
			</div>

			<h2><span class="dashicons dashicons-welcome-learn-more"></span> <?php esc_html_e( 'Onboarding', 'seovault-ai' ); ?></h2>
			<p><?php esc_html_e( 'Run the seven-step setup again. Your existing plugin settings and imported SEO data are preserved, and the wizard reopens at Step 1.', 'seovault-ai' ); ?></p>
			<p>
				<button type="submit" form="seovaultseo-restart-onboarding-form" class="button button-secondary">
					<?php esc_html_e( 'Restart onboarding', 'seovault-ai' ); ?>
				</button>
			</p>

			<div class="seovaultseo-danger-zone">
				<h2><span class="dashicons dashicons-warning"></span> <?php esc_html_e( 'Data & Uninstall', 'seovault-ai' ); ?></h2>
				<p><?php esc_html_e( 'By default, deleting this plugin removes API credentials and connection secrets only. Your SEO titles, descriptions, redirects, and other SEO data are kept so you can reinstall without losing work.', 'seovault-ai' ); ?></p>
				<table class="form-table" role="presentation">
					<tr>
						<th scope="row"><?php esc_html_e( 'Erase all data on uninstall', 'seovault-ai' ); ?></th>
						<td>
							<label for="seovaultseo_erase_on_uninstall">
								<input type="checkbox"
									name="seovaultseo_erase_on_uninstall"
									id="seovaultseo_erase_on_uninstall"
									value="1"
									<?php checked( Options::is_erase_on_uninstall() ); ?> />
								<?php esc_html_e( 'Permanently delete all SEOvault AI SEO data when this plugin is deleted', 'seovault-ai' ); ?>
							</label>
							<p class="description">
								<?php esc_html_e( 'When enabled, uninstall also removes SEO metadata, redirects, 404 logs, Local SEO locations, schema templates, sitemap cache files, and all plugin settings. This cannot be undone.', 'seovault-ai' ); ?>
							</p>
						</td>
					</tr>
				</table>
			</div>
		<?php
	}

	public static function render_status() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'seovault-ai' ) );
		}

		$status = Detector::get_status();

		self::render_global_header( __( 'Status', 'seovault-ai' ), admin_url( 'admin.php?page=seovault-ai' ) );
		?>

			<div class="seovaultseo-settings-sections">
				<div class="seovaultseo-settings-section">
					<h2><span class="dashicons dashicons-info-outline"></span> <?php esc_html_e( 'System Status', 'seovault-ai' ); ?></h2>
					<table class="form-table">
						<tr>
							<th scope="row"><?php esc_html_e( 'Active Provider', 'seovault-ai' ); ?></th>
							<td>
							<?php
							$provider_label = Detector::get_provider_label( $status['active_provider'] );
							$provider_class = ( Detector::PROVIDER_SEOVAULT === $status['active_provider'] ) ? 'seovaultseo-badge-success' : 'seovaultseo-badge-muted';
							echo '<span class="seovaultseo-badge ' . esc_attr( $provider_class ) . '">' . esc_html( $provider_label ) . '</span>';
							?>
						</td>
						</tr>
						<tr>
							<th scope="row"><?php esc_html_e( 'Detected Plugin', 'seovault-ai' ); ?></th>
							<td>
							<?php
							$detected_label = Detector::get_provider_label( $status['detected_competitor'] );
							$detected_class = ( Detector::PROVIDER_NONE !== $status['detected_competitor'] ) ? 'seovaultseo-badge-warning' : 'seovaultseo-badge-success';
							echo '<span class="seovaultseo-badge ' . esc_attr( $detected_class ) . '">' . esc_html( $detected_label ) . '</span>';
							?>
						</td>
						</tr>
						<tr>
							<th scope="row"><?php esc_html_e( 'Other SEO Plugins Detected', 'seovault-ai' ); ?></th>
							<td>
								<?php
								if ( $status['has_competitors'] ) {
									echo '<span class="seovaultseo-badge seovaultseo-badge-error"><span class="dashicons dashicons-warning"></span> ' . esc_html__( 'Yes', 'seovault-ai' ) . '</span>';
								} else {
									echo '<span class="seovaultseo-badge seovaultseo-badge-success"><span class="dashicons dashicons-yes-alt"></span> ' . esc_html__( 'No', 'seovault-ai' ) . '</span>';
								}
								?>
							</td>
						</tr>
						<?php if ( $status['has_competitors'] ) : ?>
						<tr>
							<th scope="row"><?php esc_html_e( 'Installed SEO Plugins', 'seovault-ai' ); ?></th>
							<td>
							<?php
							foreach ( $status['competitors'] as $plugin_name ) {
								echo '<span class="seovaultseo-badge seovaultseo-badge-warning">' . esc_html( $plugin_name ) . '</span> ';
							}
							?>
						</td>
						</tr>
						<?php endif; ?>
						<tr>
							<th scope="row"><?php esc_html_e( 'Should Output SEO', 'seovault-ai' ); ?></th>
							<td>
								<?php
								if ( $status['should_output_seo'] ) {
									echo '<span class="seovaultseo-badge seovaultseo-badge-success">' . esc_html__( 'Yes', 'seovault-ai' ) . '</span>';
								} else {
									echo '<span class="seovaultseo-badge seovaultseo-badge-error">' . esc_html__( 'No', 'seovault-ai' ) . '</span>';
								}
								?>
							</td>
						</tr>
						<tr>
							<th scope="row"><?php esc_html_e( 'Output Mode', 'seovault-ai' ); ?></th>
							<td>
							<?php
							$mode_label = Detector::get_output_mode_label( $status['output_mode'] );
							$mode_class = 'seovaultseo-badge-info';
							if ( 'disabled' === $status['output_mode'] ) {
								$mode_class = 'seovaultseo-badge-error';
							} elseif ( 'auto' === $status['output_mode'] ) {
								$mode_class = 'seovaultseo-badge-success';
							}
							echo '<span class="seovaultseo-badge ' . esc_attr( $mode_class ) . '">' . esc_html( $mode_label ) . '</span>';
							?>
						</td>
						</tr>
						<tr>
							<th scope="row"><?php esc_html_e( 'Old Connector Active', 'seovault-ai' ); ?></th>
							<td>
								<?php
								if ( $status['old_connector_active'] ) {
									echo '<span class="seovaultseo-badge seovaultseo-badge-warning">' . esc_html__( 'Yes', 'seovault-ai' ) . '</span>';
								} else {
									echo '<span class="seovaultseo-badge seovaultseo-badge-success">' . esc_html__( 'No', 'seovault-ai' ) . '</span>';
								}
								?>
							</td>
						</tr>
					</table>
				</div>
			</div>
		<?php
		self::render_global_footer();
	}

	public static function mask_key_public( $key ) {
		return self::mask_key( $key );
	}

	private static function mask_key( $key ) {
		if ( strlen( $key ) > 10 ) {
			return substr( $key, 0, 6 ) . str_repeat( '•', strlen( $key ) - 10 ) . substr( $key, -4 );
		}
		return $key;
	}

	private static function get_seo_post_count() {
		global $wpdb;
		$post_types = array_values( array_diff( get_post_types( array( 'public' => true ), 'names' ), array( 'attachment' ) ) );
		if ( empty( $post_types ) ) {
			return 0;
		}
		$placeholders = implode( ',', array_fill( 0, count( $post_types ), '%s' ) );
		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
		$count = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT COUNT(DISTINCT pm.post_id) FROM {$wpdb->postmeta} pm
				INNER JOIN {$wpdb->posts} p ON pm.post_id = p.ID
				WHERE pm.meta_key IN ('_seovault_seo_title','_seovault_seo_description','_seovault_focus_keyword')
				AND p.post_status = 'publish'
				AND p.post_type IN ($placeholders)",
				$post_types
			)
		);
		return (int) $count;
	}

	public static function render_sitemap() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'seovault-ai' ) );
		}
		wp_safe_redirect( admin_url( 'admin.php?page=seovault-ai-general#vtab-sitemap' ) );
		exit;
	}
}
