<?php
/**
 * Plugin Name: Titanium User Role Manager, Capabilities & Access Control
 * Plugin URI:  https://adminplugins.com/advanced-user-roles/
 * Description: Modern role editor, multi-role user filters, content control and smart role rules for WordPress.
 * Version:     1.0.3
 * Author:      AdminPlugins
 * Author URI:  https://adminplugins.com/
 * Text Domain: titanium-advanced-user-roles
 * Domain Path: /languages
 * Requires at least: 6.0
 * Requires PHP: 7.4
 * License:     GPLv2 or later
 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
 */

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

// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound, WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound, WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Freemius requires the shared Titanium User Roles SDK accessor for Free/Pro replacement handling.

if (function_exists('titanium_advanced_user_roles_fs')) {
    titanium_advanced_user_roles_fs()->set_basename(true, __FILE__);
} elseif (!function_exists('titanium_advanced_user_roles_fs')) {
    /**
     * Create a helper function for easy Freemius SDK access.
     */
    function titanium_advanced_user_roles_fs() {
        global $titanium_advanced_user_roles_fs;

        if (!isset($titanium_advanced_user_roles_fs)) {
            require_once dirname(__FILE__) . '/vendor/freemius/start.php';

            $titanium_advanced_user_roles_fs = fs_dynamic_init(array(
                'id'                  => '32243',
                'slug'                => 'titanium-advanced-user-roles',
                'premium_slug'        => 'titanium-advanced-user-roles-pro',
                'type'                => 'plugin',
                'public_key'          => 'pk_5c28c3a248e3f8b59b9c0c97f07e2',
                'is_premium'          => false,
                'premium_suffix'      => 'Pro',
                'has_premium_version' => true,
                'has_addons'          => false,
                'has_paid_plans'      => true,
                'is_org_compliant'    => true,
                'menu'                => array(
                    'slug'    => 'titanium-advanced-user-roles',
                    'account' => true,
                    'support' => false,
                ),
            ));
        }

        if (method_exists($titanium_advanced_user_roles_fs, 'add_filter')) {
            $titanium_advanced_user_roles_fs->add_filter('pricing_url', 'tiaur_custom_freemius_pricing_url');
        }

        return $titanium_advanced_user_roles_fs;
    }

    titanium_advanced_user_roles_fs();
    do_action('titanium_advanced_user_roles_fs_loaded');
}


if (!function_exists('tiaur_custom_freemius_pricing_url')) {
    /**
     * Keep Freemius Account upgrade links on the custom License & Plans page.
     */
    function tiaur_custom_freemius_pricing_url($url) {
        if (!is_admin()) {
            return $url;
        }

        return admin_url('admin.php?page=tiaur-pro');
    }
}


if (!function_exists('tiaur_fs_uninstall_cleanup')) {
    /**
     * Cleans Titanium User Roles data after Freemius has reported the uninstall event.
     *
     * Freemius deployment does not allow uninstall.php in the plugin root because it
     * prevents Freemius from receiving uninstall feedback/tracking data.
     */
    function tiaur_fs_uninstall_cleanup() {
        $settings = get_option('tiaur_plugin_settings', array());
        $delete_data = is_array($settings)
            && !empty($settings['delete_data_on_uninstall'])
            && $settings['delete_data_on_uninstall'] === '1';

        if (!$delete_data) {
            return;
        }

        $options = array(
            'tiaur_conflict_rules',
            'tiaur_role_backups',
            'tiaur_multi_role_enabled',
            'tiaur_role_tools_settings',
            'tiaur_content_post_types',
            'tiaur_plugin_settings',
            'tiaur_pro_scanner_settings',
            'tiaur_pro_scanner_results',
            'tiaur_pro_content_rules',
            'tiaur_pro_user_caps',
            'tiaur_pro_user_denies',
            'tiaur_pro_user_restrictions',
            'tiaur_pro_admin_ui_rules',
            'tiaur_pro_profile_screen_rules',
            'tiaur_pro_block_rules',
            'tiaur_pro_admin_cap_snapshot',
            'tiaur_pro_admin_cap_alerts',
            'tiaur_pro_custom_capabilities',
            'tiaur_user_filter_views',
        );

        foreach ($options as $option_name) {
            delete_option($option_name);
        }

        foreach (array('tiaur_public_pricing_payload_v1', 'tiaur_adminplugins_public_pricing_v6') as $transient_name) {
            delete_transient($transient_name);
        }

        $post_meta_keys = array(
            '_tiaur_content_enabled',
            '_tiaur_content_mode',
            '_tiaur_content_roles',
            '_tiaur_content_redirect',
            '_tiaur_content_message',
            '_tiaur_content_hide_from_lists',
            '_tiaur_content_rule',
        );

        foreach ($post_meta_keys as $meta_key) {
            delete_post_meta_by_key($meta_key);
        }
    }
}

if (function_exists('titanium_advanced_user_roles_fs')) {
    titanium_advanced_user_roles_fs()->add_action('after_uninstall', 'tiaur_fs_uninstall_cleanup');
}

if (!function_exists('tiaur_fs_hide_default_pricing_page')) {
    /**
     * Keep the SDK pricing submenu hidden until the custom pricing/license page is ready.
     */
    function tiaur_fs_hide_default_pricing_page() {
        return false;
    }
}

if (function_exists('titanium_advanced_user_roles_fs')) {
    titanium_advanced_user_roles_fs()->add_filter('is_pricing_page_visible', 'tiaur_fs_hide_default_pricing_page');
}

// Prevent warnings/fatals if a duplicate build is loaded at the same time.
if (defined('TIAUR_PLUGIN_FILE') || defined('TIAUR_PLUGIN_BASENAME')) {
    if (is_admin()) {
        add_action('admin_notices', static function () {
            echo '<div class="notice notice-error"><p>' . esc_html__('Another copy of Titanium User Roles is already loaded. Deactivate and delete the duplicate Pro plugin copy, then activate this one again.', 'titanium-advanced-user-roles') . '</p></div>';
        });
    }
    return;
}

define('TIAUR_VERSION', '1.0.3');
define('TIAUR_PLUGIN_FILE', __FILE__);
define('TIAUR_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('TIAUR_PLUGIN_URL', plugin_dir_url(__FILE__));
define('TIAUR_PLUGIN_BASENAME', plugin_basename(__FILE__));

require_once TIAUR_PLUGIN_DIR . 'includes/Admin/More_Plugins_Page.php';

if (!class_exists('TIAUR_Advanced_User_Roles')) :

final class TIAUR_Advanced_User_Roles {
    const VERSION = '1.0.3';
    const OPTION_CONFLICT_RULES = 'tiaur_conflict_rules';
    const OPTION_ROLE_BACKUPS = 'tiaur_role_backups';
    const OPTION_MULTI_ROLE_ENABLED = 'tiaur_multi_role_enabled';
    const OPTION_ROLE_TOOLS = 'tiaur_role_tools_settings';
    const OPTION_CONTENT_POST_TYPES = 'tiaur_content_post_types';
    const OPTION_PLUGIN_SETTINGS = 'tiaur_plugin_settings';
    const NONCE_ACTION = 'tiaur_admin_action';
    const MENU_SLUG = 'titanium-advanced-user-roles';

    private static $instance = null;
    private $enforcing_rules = false;
    private $restricted_ids_cache = array();

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

    private function __construct() {
        add_action('admin_menu', array($this, 'register_admin_menu'));
        add_action('admin_enqueue_scripts', array($this, 'print_upgrade_menu_css'));
        if ($this->is_module_enabled('frontend_tools')) {
            add_action('admin_menu', array($this, 'maybe_apply_admin_menu_restrictions'), 999);
            add_action('admin_init', array($this, 'maybe_block_admin_area_by_role'), 1);
            add_filter('show_admin_bar', array($this, 'maybe_hide_admin_bar'));
            add_filter('login_redirect', array($this, 'maybe_login_redirect_by_role'), 10, 3);
            add_filter('logout_redirect', array($this, 'maybe_logout_redirect_by_role'), 10, 3);
        }
        add_action('admin_notices', array($this, 'render_profile_role_rule_notice'));
        add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_assets'));
        if ($this->is_module_enabled('content_control')) {
            add_action('wp_enqueue_scripts', array($this, 'enqueue_frontend_assets'));
        }
        add_action('admin_init', array($this, 'handle_admin_actions'));
        add_action('admin_post_tiaur_export_data', array($this, 'handle_export_data'));
        add_action('admin_post_tiaur_import_data', array($this, 'handle_import_data'));
        add_action('wp_ajax_tiaur_toggle_multi_role', array($this, 'ajax_toggle_multi_role'));
        add_action('wp_ajax_tiaur_toggle_plugin_setting', array($this, 'ajax_toggle_plugin_setting'));
        add_action('wp_ajax_tiaur_toggle_delete_data_on_uninstall', array($this, 'ajax_toggle_delete_data_on_uninstall'));
        add_action('wp_ajax_tiaur_toggle_beta_updates', array($this, 'ajax_toggle_beta_updates'));
        add_action('wp_ajax_tiaur_get_freemius_pricing', array($this, 'ajax_get_freemius_pricing'));
        add_action('show_user_profile', array($this, 'render_user_profile_roles'), 1);
        add_action('edit_user_profile', array($this, 'render_user_profile_roles'), 1);
        add_action('user_new_form', array($this, 'render_user_profile_roles'), 1);
        add_action('personal_options_update', array($this, 'save_user_profile_roles'));
        add_action('edit_user_profile_update', array($this, 'save_user_profile_roles'));
        add_action('user_register', array($this, 'save_user_profile_roles'));
        if ($this->is_module_enabled('smart_rules')) {
            add_action('add_user_role', array($this, 'on_user_role_added'), 20, 2);
            add_action('set_user_role', array($this, 'on_user_role_set'), 20, 3);
            add_action('profile_update', array($this, 'on_profile_update'), 20, 2);
        }
        if ($this->is_module_enabled('content_control')) {
            add_action('add_meta_boxes', array($this, 'register_content_control_metabox'));
            add_action('save_post', array($this, 'save_content_control_metabox'), 10, 2);
            add_action('template_redirect', array($this, 'maybe_restrict_content'));
            add_filter('template_include', array($this, 'maybe_use_restricted_template'), 99);
            add_action('pre_get_posts', array($this, 'maybe_exclude_restricted_content_from_queries'));
        }
        add_shortcode('tiaur_show', array($this, 'shortcode_show_for_roles'));
        add_shortcode('tiaur_hide', array($this, 'shortcode_hide_for_roles'));
        add_shortcode('tiaur_logged_in', array($this, 'shortcode_logged_in'));
        add_shortcode('tiaur_logged_out', array($this, 'shortcode_logged_out'));
    }

    public static function activate() {
        if (!get_option(self::OPTION_CONFLICT_RULES, false)) {
            update_option(self::OPTION_CONFLICT_RULES, array(), false);
        }
        if (!get_option(self::OPTION_ROLE_BACKUPS, false)) {
            update_option(self::OPTION_ROLE_BACKUPS, array(), false);
        }
        if (get_option(self::OPTION_MULTI_ROLE_ENABLED, null) === null) {
            update_option(self::OPTION_MULTI_ROLE_ENABLED, '0', false);
        }
        if (get_option(self::OPTION_ROLE_TOOLS, null) === null) {
            update_option(self::OPTION_ROLE_TOOLS, array(
                'hide_admin_bar_roles' => array(),
                'block_admin_area_roles' => array(),
                'hidden_admin_menus' => array(),
                'login_redirects' => array(),
                'logout_redirects' => array(),
            ), false);
        }
        if (get_option(self::OPTION_CONTENT_POST_TYPES, null) === null) {
            update_option(self::OPTION_CONTENT_POST_TYPES, array('post', 'page'), false);
        }
        if (get_option(self::OPTION_PLUGIN_SETTINGS, null) === null) {
            update_option(self::OPTION_PLUGIN_SETTINGS, array('delete_data_on_uninstall' => '0', 'enable_content_control' => '1', 'enable_smart_rules' => '0', 'enable_frontend_tools' => '0', 'enable_role_shortcodes' => '1', 'color_scheme' => 'green'), false);
        }
    }

    public function print_upgrade_menu_css() {
        wp_register_style('tiaur-upgrade-menu-css', false, array(), self::VERSION);
        wp_enqueue_style('tiaur-upgrade-menu-css');
        wp_add_inline_style('tiaur-upgrade-menu-css', '#adminmenu a[href="admin.php?page=tiaur-pro"],#adminmenu a[href$="admin.php?page=tiaur-pro"]{color:#22c55e!important;font-weight:800!important;background:transparent!important;box-shadow:none!important;}#adminmenu a[href="admin.php?page=tiaur-pro"]:hover,#adminmenu a[href$="admin.php?page=tiaur-pro"]:hover,#adminmenu li.current a[href="admin.php?page=tiaur-pro"],#adminmenu li.current a[href$="admin.php?page=tiaur-pro"]{color:#16a34a!important;background:transparent!important;box-shadow:none!important;}#adminmenu a[href="admin.php?page=tiaur-pro-tools"],#adminmenu a[href$="admin.php?page=tiaur-pro-tools"]{background:transparent!important;box-shadow:none!important;}#adminmenu a[href="admin.php?page=tiaur-more-plugins"],#adminmenu a[href$="admin.php?page=tiaur-more-plugins"]{display:none!important;}');
    }

    public function register_admin_menu() {
        add_menu_page(
            __('Titanium User Roles', 'titanium-advanced-user-roles'),
            __('Titanium User Roles', 'titanium-advanced-user-roles'),
            'manage_options',
            self::MENU_SLUG,
            array($this, 'render_dashboard_page'),
            'dashicons-groups',
            58
        );

        add_submenu_page(self::MENU_SLUG, __('Dashboard', 'titanium-advanced-user-roles'), __('Dashboard', 'titanium-advanced-user-roles'), 'manage_options', self::MENU_SLUG, array($this, 'render_dashboard_page'));
        add_submenu_page(self::MENU_SLUG, __('Roles & Capabilities', 'titanium-advanced-user-roles'), __('Roles & Capabilities', 'titanium-advanced-user-roles'), 'manage_options', 'tiaur-roles', array($this, 'render_roles_page'));
        add_submenu_page(self::MENU_SLUG, __('User Filters', 'titanium-advanced-user-roles'), __('User Filters', 'titanium-advanced-user-roles'), 'manage_options', 'tiaur-user-filters', array($this, 'render_user_filters_page'));
        add_submenu_page(self::MENU_SLUG, __('Content Control', 'titanium-advanced-user-roles'), __('Content Control', 'titanium-advanced-user-roles'), 'manage_options', 'tiaur-content-control', array($this, 'render_content_control_page'));
        add_submenu_page(self::MENU_SLUG, __('Smart Rules', 'titanium-advanced-user-roles'), __('Smart Rules', 'titanium-advanced-user-roles'), 'manage_options', 'tiaur-conflict-rules', array($this, 'render_conflict_rules_page'));
        add_submenu_page(self::MENU_SLUG, __('Import / Export', 'titanium-advanced-user-roles'), __('Import / Export', 'titanium-advanced-user-roles'), 'manage_options', 'tiaur-backups', array($this, 'render_backups_page'));
        add_submenu_page(self::MENU_SLUG, __('More Plugins', 'titanium-advanced-user-roles'), __('More Plugins', 'titanium-advanced-user-roles'), 'manage_options', 'tiaur-more-plugins', array($this, 'render_more_plugins_page'));
        add_submenu_page(self::MENU_SLUG, __('Upgrade to Pro', 'titanium-advanced-user-roles'), __('Upgrade to Pro', 'titanium-advanced-user-roles'), 'manage_options', 'tiaur-pro', array($this, 'render_pro_page'));
        add_submenu_page(self::MENU_SLUG, __('Pro Tools', 'titanium-advanced-user-roles'), __('Pro Tools', 'titanium-advanced-user-roles'), 'manage_options', 'tiaur-pro-tools', array($this, 'render_pro_tools_page'));
        add_submenu_page(self::MENU_SLUG, __('Settings', 'titanium-advanced-user-roles'), __('Settings', 'titanium-advanced-user-roles'), 'manage_options', 'tiaur-settings', array($this, 'render_settings_page'));
    }

    private function asset_version($relative_path) {
        $file = plugin_dir_path(__FILE__) . ltrim((string) $relative_path, '/');
        if (file_exists($file)) {
            return self::VERSION . '-' . (string) filemtime($file);
        }
        return self::VERSION;
    }

    public function enqueue_admin_assets($hook) {
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only admin page detection for asset loading.
        $current_page = isset($_GET['page']) ? sanitize_key(wp_unslash($_GET['page'])) : '';
        $tiaur_admin_page = strpos((string) $hook, 'tiaur-') !== false
            || strpos((string) $hook, self::MENU_SLUG) !== false
            || $hook === 'toplevel_page_' . self::MENU_SLUG
            || $current_page === self::MENU_SLUG
            || strpos($current_page, 'tiaur-') === 0
            || strpos($current_page, 'titanium-advanced-user-roles') === 0;
        $post_edit_page = in_array($hook, array('post.php', 'post-new.php'), true);
        $user_edit_page = in_array($hook, array('profile.php', 'user-edit.php', 'user-new.php'), true);

        if (!$tiaur_admin_page && !$post_edit_page && !$user_edit_page) {
            return;
        }

        wp_enqueue_style('tiaur-admin', plugin_dir_url(__FILE__) . 'assets/admin.css', array(), $this->asset_version('assets/admin.css'));
        wp_enqueue_script('tiaur-admin', plugin_dir_url(__FILE__) . 'assets/admin.js', array(), $this->asset_version('assets/admin.js'), true);

        $current_page = isset($_GET['page']) ? sanitize_key(wp_unslash($_GET['page'])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only admin page check.
        if ('tiaur-pro' === $current_page) {
            wp_enqueue_script('tiaur-pricing', plugin_dir_url(__FILE__) . 'assets/pricing.js', array(), $this->asset_version('assets/pricing.js'), true);
            wp_localize_script('tiaur-pricing', 'tiaurPricing', array(
                'ajaxUrl' => admin_url('admin-ajax.php'),
                'action' => 'tiaur_get_freemius_pricing',
                'restUrl' => '',
                'remotePricingUrl' => '',
                'checkoutScriptUrl' => 'https://checkout.freemius.com/js/v1/',
                'cachedPricingPayload' => $this->get_cached_public_pricing_payload(),
                'productId' => 32243,
                'planId' => 52911,
                'currency' => 'gbp',
                'button' => __('UPGRADE NOW', 'titanium-advanced-user-roles'),
                'perYear' => __('/ year', 'titanium-advanced-user-roles'),
                'loadingPricesText' => __('Loading prices...', 'titanium-advanced-user-roles'),
                'priceUnavailableText' => __('Prices could not be downloaded. Secure checkout will show the current price.', 'titanium-advanced-user-roles'),
                'discountText' => __('Discount code applied:', 'titanium-advanced-user-roles'),
            ));
        }
        wp_localize_script('tiaur-admin', 'TIAURAdmin', array(
            'ajaxUrl' => admin_url('admin-ajax.php'),
            'toggleNonce' => wp_create_nonce('tiaur_toggle_multi_role'),
            'deleteDataNonce' => wp_create_nonce('tiaur_toggle_delete_data_on_uninstall'),
            'betaUpdatesNonce' => wp_create_nonce('tiaur_toggle_beta_updates'),
            'moduleNonce' => wp_create_nonce('tiaur_toggle_plugin_setting'),
            'typeMoreCharsText' => __('Type at least 3 characters.', 'titanium-advanced-user-roles'),
            'searchingText' => __('Searching...', 'titanium-advanced-user-roles'),
            'noResultsText' => __('No results found.', 'titanium-advanced-user-roles'),
            'removeText' => __('Remove', 'titanium-advanced-user-roles'),
            'conditionText' => __('Condition', 'titanium-advanced-user-roles'),
            'savingText' => __('Saving...', 'titanium-advanced-user-roles'),
            'savedText' => __('Saved', 'titanium-advanced-user-roles'),
            'failedText' => __('Could not save', 'titanium-advanced-user-roles'),
            'confirmDeleteDataOnText' => __('Store plugin data normally. Deleting saved data on uninstall is only needed if you want a full cleanup.', 'titanium-advanced-user-roles'),
            'confirmDeleteDataOffText' => __('Keep plugin data when uninstalling?', 'titanium-advanced-user-roles'),
            'moduleDisableConfirm' => __('Disable this module? Existing settings will be kept, but the module will stop running until you enable it again.', 'titanium-advanced-user-roles'),
        ));
    }



    public function enqueue_frontend_assets() {
        if (!$this->is_content_control_module_enabled()) {
            return;
        }
        if (!is_singular($this->content_control_post_types())) {
            return;
        }

        $post_id = get_queried_object_id();
        if (!$post_id || get_post_meta($post_id, '_tiaur_content_enabled', true) !== '1') {
            return;
        }

        wp_enqueue_style('tiaur-frontend', plugin_dir_url(__FILE__) . 'assets/frontend.css', array(), $this->asset_version('assets/frontend.css'));
    }

    private function current_roles() {
        global $wp_roles;
        if (!isset($wp_roles)) {
            $wp_roles = wp_roles();
        }
        return $wp_roles->roles;
    }

    private function role_label($role_key) {
        $roles = $this->current_roles();
        return isset($roles[$role_key]['name']) ? translate_user_role($roles[$role_key]['name']) : $role_key;
    }

    private function all_capabilities() {
        $caps = array();
        foreach ($this->current_roles() as $role) {
            if (!empty($role['capabilities'])) {
                foreach ($role['capabilities'] as $cap => $allowed) {
                    $caps[$cap] = true;
                }
            }
        }
        ksort($caps);
        return array_keys($caps);
    }


    private function is_multi_role_enabled() {
        return get_option(self::OPTION_MULTI_ROLE_ENABLED, '0') === '1';
    }

    private function default_plugin_settings() {
        return array(
            'delete_data_on_uninstall' => '0',
            'enable_content_control' => '1',
            'enable_smart_rules' => '0',
            'enable_frontend_tools' => '0',
            'enable_role_shortcodes' => '1',
            'beta_updates' => '0',
            'color_scheme' => 'green',
        );
    }

    private function plugin_settings() {
        $settings = get_option(self::OPTION_PLUGIN_SETTINGS, array());
        if (!is_array($settings)) {
            $settings = array();
        }
        $settings = array_merge($this->default_plugin_settings(), $settings);
        $boolean_keys = array('delete_data_on_uninstall', 'enable_content_control', 'enable_smart_rules', 'enable_frontend_tools', 'enable_role_shortcodes', 'beta_updates');
        foreach ($boolean_keys as $boolean_key) {
            $settings[$boolean_key] = !empty($settings[$boolean_key]) && $settings[$boolean_key] === '1' ? '1' : '0';
        }
        $settings['color_scheme'] = isset($settings['color_scheme']) ? sanitize_key((string) $settings['color_scheme']) : 'green';
        if (!isset($this->color_schemes()[$settings['color_scheme']])) {
            $settings['color_scheme'] = 'green';
        }
        return $settings;
    }

    private function color_schemes() {
        return array(
            'green' => __('Green', 'titanium-advanced-user-roles'),
            'blue' => __('Blue', 'titanium-advanced-user-roles'),
            'red' => __('Red', 'titanium-advanced-user-roles'),
            'burgundy' => __('Burgundy', 'titanium-advanced-user-roles'),
            'pink' => __('Pink', 'titanium-advanced-user-roles'),
            'purple' => __('Purple', 'titanium-advanced-user-roles'),
            'teal' => __('Teal', 'titanium-advanced-user-roles'),
            'orange' => __('Orange', 'titanium-advanced-user-roles'),
            'white' => __('White', 'titanium-advanced-user-roles'),
            'silver' => __('Silver', 'titanium-advanced-user-roles'),
            'titanium' => __('Titanium', 'titanium-advanced-user-roles'),
            'black' => __('Black', 'titanium-advanced-user-roles'),
        );
    }

    private function color_scheme_class() {
        $settings = $this->plugin_settings();
        return 'tiaur-theme-' . sanitize_html_class($settings['color_scheme']);
    }

    private function is_module_enabled($module) {
        if ($module === 'role_shortcodes') {
            return true;
        }

        $map = array(
            'content_control' => 'enable_content_control',
            'smart_rules' => 'enable_smart_rules',
            'frontend_tools' => 'enable_frontend_tools',
            'role_shortcodes' => 'enable_role_shortcodes',
        );
        if (!isset($map[$module])) {
            return false;
        }
        $settings = $this->plugin_settings();
        return isset($settings[$map[$module]]) && $settings[$map[$module]] === '1';
    }

    private function is_content_control_module_enabled() {
        return $this->is_module_enabled('content_control');
    }


    private function should_delete_data_on_uninstall() {
        $settings = $this->plugin_settings();
        return $settings['delete_data_on_uninstall'] === '1';
    }


    private function default_role_tools_settings() {
        return array(
            'hide_admin_bar_roles' => array(),
            'block_admin_area_roles' => array(),
            'hidden_admin_menus' => array(),
            'login_redirects' => array(),
            'logout_redirects' => array(),
        );
    }

    private function role_tools_settings() {
        $settings = get_option(self::OPTION_ROLE_TOOLS, array());
        if (!is_array($settings)) {
            $settings = array();
        }
        $settings = array_merge($this->default_role_tools_settings(), $settings);
        $settings['hide_admin_bar_roles'] = array_values(array_unique(array_filter(array_map('sanitize_key', (array) $settings['hide_admin_bar_roles']))));
        $settings['block_admin_area_roles'] = array_values(array_unique(array_filter(array_map('sanitize_key', (array) $settings['block_admin_area_roles']))));
        $hidden_admin_menus = array();
        if (!empty($settings['hidden_admin_menus']) && is_array($settings['hidden_admin_menus'])) {
            foreach ($settings['hidden_admin_menus'] as $role_key => $menu_slugs) {
                $role_key = sanitize_key($role_key);
                if ('administrator' === $role_key) {
                    continue;
                }
                $hidden_admin_menus[$role_key] = array_values(array_unique(array_filter(array_map(array($this, 'sanitize_admin_menu_slug'), (array) $menu_slugs))));
            }
        }
        $settings['hidden_admin_menus'] = $hidden_admin_menus;
        $settings['login_redirects'] = is_array($settings['login_redirects']) ? $settings['login_redirects'] : array();
        $settings['logout_redirects'] = is_array($settings['logout_redirects']) ? $settings['logout_redirects'] : array();
        return $settings;
    }


    private function sanitize_admin_menu_slug($slug) {
        $slug = sanitize_text_field((string) $slug);
        $slug = str_replace(array('\"', "\'"), '', $slug);
        return trim($slug);
    }

    private function admin_menu_items() {
        global $menu;
        $items = array();
        if (!is_array($menu)) {
            return $items;
        }
        foreach ($menu as $menu_item) {
            if (empty($menu_item[2])) {
                continue;
            }
            $slug = (string) $menu_item[2];
            if (strpos($slug, 'separator') === 0) {
                continue;
            }
            $label = isset($menu_item[0]) ? wp_strip_all_tags((string) $menu_item[0]) : $slug;
            $label = trim(preg_replace('/\s+/', ' ', $label));
            if ($label === '') {
                $label = $slug;
            }
            $items[$slug] = $label;
        }
        return $items;
    }

    private function current_admin_menu_slug() {
        global $pagenow;
        $pagenow = (string) $pagenow;
        if ($pagenow === 'admin.php' && isset($_GET['page'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only current admin screen detection.
            $current_page = sanitize_text_field(wp_unslash($_GET['page'])); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only current admin screen detection.
            return 'admin.php?page=' . $this->sanitize_admin_menu_slug($current_page);
        }
        if (($pagenow === 'edit.php' || $pagenow === 'post-new.php') && isset($_GET['post_type'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only current admin screen detection.
            return $pagenow . '?post_type=' . sanitize_key(wp_unslash($_GET['post_type'])); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only current admin screen detection.
        }
        return $pagenow;
    }

    private function current_user_roles_for_restrictions() {
        if (!is_user_logged_in()) {
            return array();
        }
        $user = wp_get_current_user();
        return $user && $user->exists() ? (array) $user->roles : array();
    }

    private function current_user_matches_roles_for_restriction($roles) {
        $roles = array_filter(array_map('sanitize_key', (array) $roles));
        if (empty($roles)) {
            return false;
        }
        return (bool) array_intersect($roles, $this->current_user_roles_for_restrictions());
    }

    public function maybe_apply_admin_menu_restrictions() {
        if (!$this->is_module_enabled('frontend_tools') || !is_admin() || !is_user_logged_in() || current_user_can('manage_options')) {
            return;
        }
        $settings = $this->role_tools_settings();
        if (empty($settings['hidden_admin_menus']) || !is_array($settings['hidden_admin_menus'])) {
            return;
        }
        foreach ($this->current_user_roles_for_restrictions() as $role_key) {
            if (empty($settings['hidden_admin_menus'][$role_key])) {
                continue;
            }
            foreach ((array) $settings['hidden_admin_menus'][$role_key] as $menu_slug) {
                remove_menu_page($menu_slug);
            }
        }
    }

    public function maybe_block_admin_area_by_role() {
        if (!$this->is_module_enabled('frontend_tools') || !is_admin() || wp_doing_ajax() || !is_user_logged_in() || current_user_can('manage_options')) {
            return;
        }
        $settings = $this->role_tools_settings();
        if ($this->current_user_matches_roles_for_restriction($settings['block_admin_area_roles'])) {
            wp_safe_redirect(home_url('/'));
            exit;
        }
        $current_slug = $this->current_admin_menu_slug();
        foreach ($this->current_user_roles_for_restrictions() as $role_key) {
            if (empty($settings['hidden_admin_menus'][$role_key]) || !is_array($settings['hidden_admin_menus'][$role_key])) {
                continue;
            }
            foreach ($settings['hidden_admin_menus'][$role_key] as $blocked_slug) {
                if ($blocked_slug === $current_slug || $blocked_slug === basename($current_slug)) {
                    wp_safe_redirect(admin_url('index.php'));
                    exit;
                }
            }
        }
    }

    private function public_custom_post_types() {
        $post_types = get_post_types(array('public' => true), 'objects');
        unset($post_types['attachment']);
        return $post_types;
    }

    private function content_control_post_types() {
        $available = $this->public_custom_post_types();
        $stored = get_option(self::OPTION_CONTENT_POST_TYPES, array('post', 'page'));
        $stored = array_values(array_unique(array_filter(array_map('sanitize_key', (array) $stored))));
        $stored = array_values(array_intersect($stored, array_keys($available)));
        return array_values(array_unique($stored));
    }

    private function users_filter_url_for_role($role_key) {
        return add_query_arg(array(
            'page' => 'tiaur-user-filters',
            'filter_field[]' => 'role',
            'filter_operator[]' => 'is',
            'filter_value[]' => sanitize_key($role_key),
        ), admin_url('admin.php'));
    }

    public function ajax_toggle_multi_role() {
        if (!current_user_can('manage_options')) {
            wp_send_json_error(array('message' => __('Permission denied.', 'titanium-advanced-user-roles')), 403);
        }

        check_ajax_referer('tiaur_toggle_multi_role', 'nonce');
        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce is verified centrally before handling admin actions, or this is a read-only admin filter.
        $enabled = !empty($_POST['enabled']) && sanitize_text_field(wp_unslash($_POST['enabled'])) === '1';
        update_option(self::OPTION_MULTI_ROLE_ENABLED, $enabled ? '1' : '0', false);

        wp_send_json_success(array(
            'enabled' => $enabled ? 1 : 0,
            'message' => $enabled ? __('Multiple roles enabled.', 'titanium-advanced-user-roles') : __('Multiple roles disabled.', 'titanium-advanced-user-roles'),
        ));
    }

    public function ajax_toggle_plugin_setting() {
        if (!current_user_can('manage_options')) {
            wp_send_json_error(array('message' => __('Permission denied.', 'titanium-advanced-user-roles')), 403);
        }

        check_ajax_referer('tiaur_toggle_plugin_setting', 'nonce');
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified immediately above.
        $setting = isset($_POST['setting']) ? sanitize_key(wp_unslash($_POST['setting'])) : '';
        $allowed = array('enable_content_control', 'enable_smart_rules', 'enable_frontend_tools', 'enable_role_shortcodes');
        if (!in_array($setting, $allowed, true)) {
            wp_send_json_error(array('message' => __('Invalid setting.', 'titanium-advanced-user-roles')), 400);
        }

        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified immediately above.
        $enabled = !empty($_POST['enabled']) && sanitize_text_field(wp_unslash($_POST['enabled'])) === '1';
        $settings = $this->plugin_settings();
        $settings[$setting] = $enabled ? '1' : '0';
        update_option(self::OPTION_PLUGIN_SETTINGS, $settings, false);

        wp_send_json_success(array(
            'enabled' => $enabled ? 1 : 0,
            'setting' => $setting,
        ));
    }

    private function beta_updates_mode() {
        if (!function_exists('titanium_advanced_user_roles_fs')) {
            return 'local';
        }

        $fs = titanium_advanced_user_roles_fs();
        if (!is_object($fs) || !method_exists($fs, 'is_premium') || !method_exists($fs, 'get_ajax_action') || !method_exists($fs, 'get_ajax_security') || !method_exists($fs, 'get_id')) {
            return 'local';
        }

        return $fs->is_premium() ? 'freemius' : 'local';
    }

    private function beta_updates_enabled() {
        if ($this->beta_updates_mode() === 'freemius' && function_exists('titanium_advanced_user_roles_fs')) {
            $fs = titanium_advanced_user_roles_fs();
            if (is_object($fs) && method_exists($fs, 'get_site')) {
                $site = $fs->get_site();
                if (is_object($site) && method_exists($site, 'is_beta')) {
                    return (bool) $site->is_beta();
                }
                if (is_object($site) && isset($site->is_beta)) {
                    return (bool) $site->is_beta;
                }
            }
        }

        $settings = $this->plugin_settings();
        return !empty($settings['beta_updates']) && $settings['beta_updates'] === '1';
    }

    private function beta_updates_freemius_payload() {
        if ($this->beta_updates_mode() !== 'freemius' || !function_exists('titanium_advanced_user_roles_fs')) {
            return array();
        }

        $fs = titanium_advanced_user_roles_fs();
        if (!is_object($fs) || !method_exists($fs, 'get_ajax_action') || !method_exists($fs, 'get_ajax_security') || !method_exists($fs, 'get_id')) {
            return array();
        }

        return array(
            'action' => (string) $fs->get_ajax_action('set_beta_mode'),
            'security' => (string) $fs->get_ajax_security('set_beta_mode'),
            'module_id' => (string) $fs->get_id(),
        );
    }

    public function ajax_toggle_delete_data_on_uninstall() {
        if (!current_user_can('manage_options')) {
            wp_send_json_error(array('message' => __('Permission denied.', 'titanium-advanced-user-roles')), 403);
        }

        check_ajax_referer('tiaur_toggle_delete_data_on_uninstall', 'nonce');
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified immediately above.
        $enabled = !empty($_POST['enabled']) && sanitize_text_field(wp_unslash($_POST['enabled'])) === '1';
        $settings = $this->plugin_settings();
        $settings['delete_data_on_uninstall'] = $enabled ? '1' : '0';
        update_option(self::OPTION_PLUGIN_SETTINGS, $settings, false);

        wp_send_json_success(array(
            'enabled' => $enabled ? 1 : 0,
            'message' => $enabled ? __('Plugin data will be deleted on uninstall.', 'titanium-advanced-user-roles') : __('Plugin data will be kept on uninstall.', 'titanium-advanced-user-roles'),
        ));
    }

    public function ajax_toggle_beta_updates() {
        if (!current_user_can('manage_options')) {
            wp_send_json_error(array('message' => __('Permission denied.', 'titanium-advanced-user-roles')), 403);
        }

        check_ajax_referer('tiaur_toggle_beta_updates', 'nonce');
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified immediately above.
        $enabled = !empty($_POST['enabled']) && sanitize_text_field(wp_unslash($_POST['enabled'])) === '1';
        $settings = $this->plugin_settings();
        $settings['beta_updates'] = $enabled ? '1' : '0';
        update_option(self::OPTION_PLUGIN_SETTINGS, $settings, false);

        wp_send_json_success(array(
            'enabled' => $enabled ? 1 : 0,
            'message' => $enabled ? __('Beta updates enabled.', 'titanium-advanced-user-roles') : __('Beta updates disabled.', 'titanium-advanced-user-roles'),
        ));
    }

    private function count_users_with_role($role_key) {
        $query = new WP_User_Query(array(
            'role' => $role_key,
            'fields' => 'ID',
            'number' => 1,
            'count_total' => true,
        ));
        return (int) $query->get_total();
    }

    private function role_capability_count($role_data) {
        return !empty($role_data['capabilities']) && is_array($role_data['capabilities']) ? count(array_filter($role_data['capabilities'])) : 0;
    }

    private function capability_group($cap) {
        if (strpos($cap, 'post') !== false || strpos($cap, 'blog') !== false) {
            return 'posts';
        }
        if (strpos($cap, 'page') !== false) {
            return 'pages';
        }
        if (strpos($cap, 'user') !== false || strpos($cap, 'role') !== false || $cap === 'promote_users') {
            return 'users';
        }
        if (strpos($cap, 'plugin') !== false) {
            return 'plugins';
        }
        if (strpos($cap, 'theme') !== false || $cap === 'edit_css' || $cap === 'customize') {
            return 'themes';
        }
        if (strpos($cap, 'comment') !== false || strpos($cap, 'moderate') !== false) {
            return 'comments';
        }
        if (strpos($cap, 'upload') !== false || strpos($cap, 'file') !== false || strpos($cap, 'media') !== false) {
            return 'media';
        }
        if (strpos($cap, 'option') !== false || strpos($cap, 'dashboard') !== false || strpos($cap, 'core') !== false || $cap === 'import' || $cap === 'export') {
            return 'admin';
        }
        return 'other';
    }

    private function capability_group_label($group) {
        $labels = array(
            'all' => __('All', 'titanium-advanced-user-roles'),
            'posts' => __('Posts', 'titanium-advanced-user-roles'),
            'pages' => __('Pages', 'titanium-advanced-user-roles'),
            'users' => __('Users', 'titanium-advanced-user-roles'),
            'plugins' => __('Plugins', 'titanium-advanced-user-roles'),
            'themes' => __('Themes', 'titanium-advanced-user-roles'),
            'media' => __('Media', 'titanium-advanced-user-roles'),
            'comments' => __('Comments', 'titanium-advanced-user-roles'),
            'admin' => __('Admin', 'titanium-advanced-user-roles'),
            'other' => __('Other', 'titanium-advanced-user-roles'),
        );
        return isset($labels[$group]) ? $labels[$group] : $group;
    }

    public function render_user_profile_roles($user_or_type = null) {
        if (!$this->is_multi_role_enabled()) {
            return;
        }

        if (!current_user_can('promote_users')) {
            return;
        }

        $roles = get_editable_roles();
        $user_roles = array();
        if ($user_or_type instanceof WP_User) {
            $user_roles = array_intersect(array_values((array) $user_or_type->roles), array_keys($roles));
        }

        echo '<div class="tiaur-profile-roles-template" style="display:none;">';
        echo '<div class="tiaur-profile-role-list">';
        foreach ($roles as $role_key => $role_data) {
            $checked = in_array($role_key, $user_roles, true);
            echo '<label class="tiaur-profile-role-line">';
            echo '<input type="checkbox" name="tiaur_user_roles[]" value="' . esc_attr($role_key) . '" ' . checked($checked, true, false) . ' />';
            echo '<span>' . esc_html(translate_user_role($role_data['name'])) . '</span>';
            echo '</label>';
        }
        echo '</div>';
        echo '<p class="description tiaur-profile-role-help">' . esc_html__('Select as many roles as this user needs.', 'titanium-advanced-user-roles') . '</p>';
        wp_nonce_field('tiaur_save_user_roles', '_tiaur_user_roles_nonce');
        echo '</div>';
    }

    public function save_user_profile_roles($user_id) {
        if (!$this->is_multi_role_enabled()) {
            return;
        }

        if (!current_user_can('promote_users', $user_id)) {
            return;
        }

        if (empty($_POST['_tiaur_user_roles_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['_tiaur_user_roles_nonce'])), 'tiaur_save_user_roles')) {
            return;
        }

        $roles = get_editable_roles();
        $valid_roles = array_keys($roles);
        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce is verified centrally before handling admin actions, or this is a read-only admin filter.
        $new_roles = isset($_POST['tiaur_user_roles']) && is_array($_POST['tiaur_user_roles']) ? array_map('sanitize_key', wp_unslash($_POST['tiaur_user_roles'])) : array();
        $new_roles = array_values(array_intersect(array_unique($new_roles), $valid_roles));

        $user = new WP_User($user_id);
        if (!$user || !$user->exists()) {
            return;
        }

        $old_roles = array_intersect(array_values((array) $user->roles), $valid_roles);

        // Safety: do not allow removing the last Administrator from the site.
        if (in_array('administrator', $old_roles, true) && !in_array('administrator', $new_roles, true)) {
            $admins = get_users(array('role' => 'administrator', 'fields' => 'ID', 'number' => 2));
            if (count($admins) <= 1) {
                $new_roles[] = 'administrator';
            }
        }

        foreach (array_diff($old_roles, $new_roles) as $role_to_remove) {
            $user->remove_role($role_to_remove);
        }

        foreach (array_diff($new_roles, array_values((array) $user->roles)) as $role_to_add) {
            $user->add_role($role_to_add);
            if ($this->is_module_enabled('smart_rules')) {
                $this->enforce_rules_for_user($user_id, $role_to_add);
            }
        }

        if ($this->is_module_enabled('smart_rules')) {
            $roles_before_smart_rules = array_values((array) $user->roles);
            foreach ((array) $user->roles as $role) {
                $this->enforce_rules_for_user($user_id, $role);
            }
            $user_after_smart_rules = get_user_by('id', $user_id);
            $roles_after_smart_rules = $user_after_smart_rules ? array_values((array) $user_after_smart_rules->roles) : array();
            $roles_removed_by_smart_rules = array_values(array_diff($roles_before_smart_rules, $roles_after_smart_rules));
            if (!empty($roles_removed_by_smart_rules)) {
                $this->store_profile_role_rule_notice($user_id, $new_roles, $roles_removed_by_smart_rules);
            }
        }
    }

    private function create_roles_backup($reason = '') {
        global $wp_roles;
        if (!isset($wp_roles)) {
            $wp_roles = wp_roles();
        }

        $backups = get_option(self::OPTION_ROLE_BACKUPS, array());
        if (!is_array($backups)) {
            $backups = array();
        }

        array_unshift($backups, array(
            'time' => current_time('mysql'),
            'user_id' => get_current_user_id(),
            'reason' => sanitize_text_field($reason),
            'roles' => $wp_roles->roles,
        ));

        $backups = array_slice($backups, 0, 15);
        update_option(self::OPTION_ROLE_BACKUPS, $backups, false);
    }

    public function handle_admin_actions() {
        if (!is_admin() || !current_user_can('manage_options')) {
            return;
        }

        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce is verified centrally before handling admin actions, or this is a read-only admin filter.
        if (empty($_POST['tiaur_action'])) {
            return;
        }

        check_admin_referer(self::NONCE_ACTION);
        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce is verified centrally before handling admin actions, or this is a read-only admin filter.
        $action = sanitize_key($_POST['tiaur_action']);

        switch ($action) {
            case 'save_role':
                $this->handle_save_role();
                break;
            case 'delete_role':
                $this->handle_delete_role();
                break;
            case 'clone_role':
                $this->handle_clone_role();
                break;
            case 'save_conflict_rules':
                $this->handle_save_conflict_rules();
                break;
            case 'restore_backup':
                $this->handle_restore_backup();
                break;
            case 'export_data':
                $this->handle_export_data();
                break;
            case 'import_data':
                $this->handle_import_data();
                break;
            case 'save_content_control_bulk':
                $this->handle_save_content_control_bulk();
                break;
            case 'save_default_role':
                $this->handle_save_default_role();
                break;
            case 'copy_role_caps':
                $this->handle_copy_role_caps();
                break;
            case 'reset_default_roles':
                $this->handle_reset_default_roles();
                break;
            case 'save_role_tools_settings':
                $this->handle_save_role_tools_settings();
                break;
            case 'save_content_post_types':
                $this->handle_save_content_post_types();
                break;
            case 'save_color_scheme':
                $this->handle_save_color_scheme();
                break;
        }
    }

    private function safe_redirect($page, $args = array()) {
        $args = array_merge(array('page' => $page, 'tiaur_notice' => 'saved'), $args);
        wp_safe_redirect(add_query_arg($args, admin_url('admin.php')));
        exit;
    }

    private function handle_save_role() {
        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce is verified centrally before handling admin actions, or this is a read-only admin filter.
        $role_key = isset($_POST['role_key']) ? sanitize_key($_POST['role_key']) : '';
        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce is verified centrally before handling admin actions, or this is a read-only admin filter.
        $role_name = isset($_POST['role_name']) ? sanitize_text_field(wp_unslash($_POST['role_name'])) : '';
        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce is verified centrally before handling admin actions, or this is a read-only admin filter.
        $caps = isset($_POST['caps']) && is_array($_POST['caps']) ? array_map('sanitize_key', wp_unslash($_POST['caps'])) : array();
        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce is verified centrally before handling admin actions, or this is a read-only admin filter.
        $new_caps_raw = isset($_POST['new_caps']) ? sanitize_textarea_field(wp_unslash($_POST['new_caps'])) : '';

        if ($role_key === '' || $role_name === '') {
            $this->safe_redirect('tiaur-roles', array('tiaur_notice' => 'missing'));
        }

        $this->create_roles_backup('save_role_' . $role_key);
        $role = get_role($role_key);

        if (!$role) {
            add_role($role_key, $role_name, array());
            $role = get_role($role_key);
        } else {
            global $wp_roles;
            $wp_roles->roles[$role_key]['name'] = $role_name;
            update_option($wp_roles->role_key, $wp_roles->roles);
        }

        if ($role) {
            // Safety: never remove capabilities from the built-in Administrator role.
            // Administrators may gain new capabilities here, but existing capabilities are preserved.
            if ($role_key !== 'administrator') {
                foreach ($role->capabilities as $cap => $allowed) {
                    $role->remove_cap($cap);
                }
            }

            foreach ($caps as $cap) {
                if ($cap !== '') {
                    $role->add_cap($cap, true);
                }
            }

            if ($new_caps_raw !== '') {
                $new_caps = preg_split('/[\r\n,]+/', $new_caps_raw);
                foreach ($new_caps as $cap) {
                    $cap = sanitize_key(trim($cap));
                    if ($cap !== '') {
                        $role->add_cap($cap, true);
                    }
                }
            }
        }

        $this->safe_redirect('tiaur-roles', array('edit_role' => $role_key));
    }

    private function handle_delete_role() {
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified in handle_admin_actions().
        $role_key = isset($_POST['role_key']) ? sanitize_key(wp_unslash($_POST['role_key'])) : '';
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified in handle_admin_actions().
        $force_delete = !empty($_POST['force_delete_used_role']) && sanitize_text_field(wp_unslash($_POST['force_delete_used_role'])) === '1';
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified in handle_admin_actions().
        $confirmed = !empty($_POST['confirm_delete_used_role']) && sanitize_text_field(wp_unslash($_POST['confirm_delete_used_role'])) === '1';
        $user_count = $role_key ? $this->count_users_with_role($role_key) : 0;
        $default_role = sanitize_key((string) get_option('default_role', 'subscriber'));
        $roles = $this->current_roles();

        if (!$role_key || $role_key === 'administrator' || $role_key === $default_role || ($user_count > 0 && (!$force_delete || !$confirmed))) {
            $this->safe_redirect('tiaur-roles', array('edit_role' => $role_key, 'tiaur_notice' => 'blocked'));
        }

        $this->create_roles_backup('delete_role_' . $role_key);

        if ($user_count > 0) {
            $user_ids = get_users(array(
                'role' => $role_key,
                'fields' => 'ID',
                'number' => -1,
            ));

            foreach ($user_ids as $user_id) {
                $user = new WP_User((int) $user_id);
                $user->remove_role($role_key);

                if ($default_role && isset($roles[$default_role]) && empty($user->roles)) {
                    $user->add_role($default_role);
                }
            }
        }

        remove_role($role_key);
        $this->safe_redirect('tiaur-roles');
    }


    private function handle_save_default_role() {
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified in handle_admin_actions().
        $role_key = isset($_POST['default_role']) ? sanitize_key(wp_unslash($_POST['default_role'])) : '';
        $roles = $this->current_roles();
        if (!$role_key || $role_key === 'administrator' || !isset($roles[$role_key])) {
            $this->safe_redirect('tiaur-roles', array('tiaur_notice' => 'blocked'));
        }
        update_option('default_role', $role_key);
        $this->safe_redirect('tiaur-roles');
    }

    private function handle_copy_role_caps() {
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified in handle_admin_actions().
        $target = isset($_POST['target_role']) ? sanitize_key(wp_unslash($_POST['target_role'])) : '';
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified in handle_admin_actions().
        $source = isset($_POST['copy_source_role']) ? sanitize_key(wp_unslash($_POST['copy_source_role'])) : '';
        $target_role = get_role($target);
        $source_role = get_role($source);
        if (!$target_role || !$source_role || $target === 'administrator') {
            $this->safe_redirect('tiaur-roles', array('tiaur_notice' => 'blocked'));
        }
        $this->create_roles_backup('copy_caps_' . $source . '_to_' . $target);
        foreach ((array) $source_role->capabilities as $cap => $allowed) {
            if ($allowed) {
                $target_role->add_cap($cap, true);
            }
        }
        $this->safe_redirect('tiaur-roles', array('edit_role' => $target));
    }

    private function handle_reset_default_roles() {
        $this->create_roles_backup('reset_default_roles');
        require_once ABSPATH . 'wp-admin/includes/schema.php';
        if (function_exists('populate_roles')) {
            populate_roles();
        }
        $this->safe_redirect('tiaur-roles');
    }


    private function handle_save_role_tools_settings() {
        $roles = $this->current_roles();
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified in handle_admin_actions().
        $hide_admin_bar = isset($_POST['hide_admin_bar_roles']) && is_array($_POST['hide_admin_bar_roles']) ? array_map('sanitize_key', wp_unslash($_POST['hide_admin_bar_roles'])) : array();
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified in handle_admin_actions().
        $block_admin_area = isset($_POST['block_admin_area_roles']) && is_array($_POST['block_admin_area_roles']) ? array_map('sanitize_key', wp_unslash($_POST['block_admin_area_roles'])) : array();
        $hidden_admin_menus = array();
        $login_redirects = array();
        $logout_redirects = array();
        $posted_hidden_admin_menus = array();
        if (isset($_POST['hidden_admin_menus']) && is_array($_POST['hidden_admin_menus'])) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified in handle_admin_actions().
            $posted_hidden_admin_menus = wp_unslash($_POST['hidden_admin_menus']); // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized per role below with sanitize_admin_menu_slug().
        }

        foreach ($roles as $role_key => $role_data) {
            // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified in handle_admin_actions().
            $login = isset($_POST['login_redirects'][$role_key]) ? esc_url_raw(wp_unslash($_POST['login_redirects'][$role_key])) : '';
            // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified in handle_admin_actions().
            $logout = isset($_POST['logout_redirects'][$role_key]) ? esc_url_raw(wp_unslash($_POST['logout_redirects'][$role_key])) : '';
            $role_hidden_menus = isset($posted_hidden_admin_menus[$role_key]) && is_array($posted_hidden_admin_menus[$role_key]) ? array_map(array($this, 'sanitize_admin_menu_slug'), $posted_hidden_admin_menus[$role_key]) : array();
            if ('administrator' === $role_key) {
                $role_hidden_menus = array();
            }
            if ($login !== '') {
                $login_redirects[$role_key] = $login;
            }
            if ($logout !== '') {
                $logout_redirects[$role_key] = $logout;
            }
            if (!empty($role_hidden_menus)) {
                $hidden_admin_menus[$role_key] = array_values(array_unique(array_filter($role_hidden_menus)));
            }
        }

        $valid_role_keys = array_keys($roles);
        update_option(self::OPTION_ROLE_TOOLS, array(
            'hide_admin_bar_roles' => array_values(array_unique(array_intersect($hide_admin_bar, $valid_role_keys))),
            'block_admin_area_roles' => array_values(array_diff(array_unique(array_intersect($block_admin_area, $valid_role_keys)), array('administrator'))),
            'hidden_admin_menus' => $hidden_admin_menus,
            'login_redirects' => $login_redirects,
            'logout_redirects' => $logout_redirects,
        ), false);

        $this->safe_redirect('tiaur-roles');
    }

    private function handle_save_content_post_types() {
        $available = $this->public_custom_post_types();
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified in handle_admin_actions().
        $selected = isset($_POST['content_post_types']) && is_array($_POST['content_post_types']) ? array_map('sanitize_key', wp_unslash($_POST['content_post_types'])) : array();
        $selected = array_values(array_intersect($selected, array_keys($available)));
        update_option(self::OPTION_CONTENT_POST_TYPES, array_values(array_unique($selected)), false);
        $this->safe_redirect('tiaur-content-control');
    }

    private function handle_clone_role() {
        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce is verified centrally before handling admin actions, or this is a read-only admin filter.
        $source = isset($_POST['source_role']) ? sanitize_key($_POST['source_role']) : '';
        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce is verified centrally before handling admin actions, or this is a read-only admin filter.
        $new_key = isset($_POST['new_role_key']) ? sanitize_key($_POST['new_role_key']) : '';
        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce is verified centrally before handling admin actions, or this is a read-only admin filter.
        $new_name = isset($_POST['new_role_name']) ? sanitize_text_field(wp_unslash($_POST['new_role_name'])) : '';
        $source_role = get_role($source);
        if (!$source_role || !$new_key || !$new_name || get_role($new_key)) {
            $this->safe_redirect('tiaur-roles', array('tiaur_notice' => 'missing'));
        }
        $this->create_roles_backup('clone_role_' . $source . '_to_' . $new_key);
        add_role($new_key, $new_name, $source_role->capabilities);
        $this->safe_redirect('tiaur-roles', array('edit_role' => $new_key));
    }

    private function handle_save_conflict_rules() {
        $rules = array();
        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce is verified centrally before handling admin actions, or this is a read-only admin filter.
        $raw = isset($_POST['rules']) && is_array($_POST['rules']) ? wp_unslash($_POST['rules']) : array();
        foreach ($raw as $role => $row) {
            $role = sanitize_key($role);
            if (!get_role($role)) {
                continue;
            }
            $remove = isset($row['remove']) && is_array($row['remove']) ? array_map('sanitize_key', $row['remove']) : array();
            $rules[$role] = array(
                'remove' => array_values(array_unique(array_filter($remove))),
            );
        }
        update_option(self::OPTION_CONFLICT_RULES, $rules, false);
        $this->safe_redirect('tiaur-conflict-rules');
    }



    private function download_csv($filename, $csv) {
        while (ob_get_level()) {
            ob_end_clean();
        }
        status_header(200);
        nocache_headers();
        header('Content-Description: File Transfer');
        header('Content-Type: text/csv; charset=utf-8');
        header('Content-Disposition: attachment; filename="' . $filename . '"');
        header('Content-Transfer-Encoding: binary');
        header('X-Content-Type-Options: nosniff');
        echo $csv; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- CSV fields are escaped by build_users_csv().
        exit;
    }

    private function get_content_control_export() {
        $items = array();
        // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Content Control export must find posts/pages with this plugin's access-control meta.
        $query = new WP_Query(array(
            'post_type' => $this->content_control_post_types(),
            'post_status' => 'any',
            'fields' => 'ids',
            'posts_per_page' => -1,
            // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Content Control export must find posts/pages with this plugin's access-control meta.
            'meta_query' => array(
                array(
                    'key' => '_tiaur_content_enabled',
                    'compare' => 'EXISTS',
                ),
            ),
        ));

        foreach ((array) $query->posts as $post_id) {
            $items[] = array(
                'post_id' => (int) $post_id,
                'post_type' => get_post_type($post_id),
                'post_title' => get_the_title($post_id),
                'enabled' => get_post_meta($post_id, '_tiaur_content_enabled', true),
                'mode' => get_post_meta($post_id, '_tiaur_content_mode', true),
                'roles' => (array) get_post_meta($post_id, '_tiaur_content_roles', true),
                'redirect' => get_post_meta($post_id, '_tiaur_content_redirect', true),
                'message' => get_post_meta($post_id, '_tiaur_content_message', true),
                'rule' => get_post_meta($post_id, '_tiaur_content_rule', true),
            );
        }
        return $items;
    }

    private function build_export_payload($scope = 'everything') {
        $scope = sanitize_key($scope);
        $payload = array(
            'export_type' => 'advanced_user_roles',
            'export_version' => 1,
            'plugin_version' => self::VERSION,
            'scope' => $scope,
            'site_url' => home_url('/'),
            'created_at' => current_time('mysql'),
        );

        if ($scope === 'everything' || $scope === 'roles') {
            $payload['roles'] = $this->current_roles();
        }
        if ($scope === 'everything' || $scope === 'smart_rules') {
            $payload['smart_rules'] = get_option(self::OPTION_CONFLICT_RULES, array());
        }
        if ($scope === 'everything' || $scope === 'content_control') {
            $payload['content_control'] = $this->get_content_control_export();
        }
        if ($scope === 'everything' || $scope === 'settings') {
            $payload['settings'] = array(
                self::OPTION_MULTI_ROLE_ENABLED => get_option(self::OPTION_MULTI_ROLE_ENABLED, '0'),
                self::OPTION_ROLE_TOOLS => $this->role_tools_settings(),
                self::OPTION_CONTENT_POST_TYPES => $this->content_control_post_types(),
                self::OPTION_PLUGIN_SETTINGS => $this->plugin_settings(),
            );
        }
        if ($scope === 'everything' || $scope === 'safety_backups') {
            $payload['safety_backups'] = get_option(self::OPTION_ROLE_BACKUPS, array());
        }

        return $payload;
    }

    public function handle_export_data() {
        if (!is_admin() || !current_user_can('manage_options')) {
            wp_die(esc_html__('You do not have permission to export Titanium User Roles data.', 'titanium-advanced-user-roles'));
        }
        check_admin_referer(self::NONCE_ACTION);
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified directly above.
        $scope = isset($_REQUEST['export_scope']) ? sanitize_key(wp_unslash($_REQUEST['export_scope'])) : 'everything';
        $allowed = array('everything', 'roles', 'smart_rules', 'content_control', 'settings', 'safety_backups');
        if (!in_array($scope, $allowed, true)) {
            $scope = 'everything';
        }

        $payload = $this->build_export_payload($scope);
        $filename = 'titanium-advanced-user-roles-' . $scope . '-' . gmdate('Y-m-d-His') . '.json';

        while (ob_get_level()) {
            ob_end_clean();
        }

        status_header(200);
        nocache_headers();
        header('Content-Description: File Transfer');
        header('Content-Type: application/json; charset=utf-8');
        header('Content-Disposition: attachment; filename="' . sanitize_file_name($filename) . '"; filename*=UTF-8\'\'' . rawurlencode(sanitize_file_name($filename)));
        header('Content-Transfer-Encoding: binary');
        header('X-Content-Type-Options: nosniff');
        echo wp_json_encode($payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
        exit;
    }

    public function handle_import_data() {
        if (!is_admin() || !current_user_can('manage_options')) {
            wp_die(esc_html__('You do not have permission to import Titanium User Roles data.', 'titanium-advanced-user-roles'));
        }
        check_admin_referer(self::NONCE_ACTION);
        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce is verified directly above; tmp_name is validated with is_uploaded_file().
        if (empty($_FILES['tiaur_import_file']['tmp_name']) || !is_uploaded_file($_FILES['tiaur_import_file']['tmp_name'])) {
            $this->safe_redirect('tiaur-backups', array('tiaur_notice' => 'missing'));
        }

        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce is verified centrally before handling admin actions, or this is a read-only admin filter.
        $raw = file_get_contents($_FILES['tiaur_import_file']['tmp_name']);
        $data = json_decode($raw, true);
        if (!is_array($data) || empty($data['export_type']) || $data['export_type'] !== 'advanced_user_roles') {
            $this->safe_redirect('tiaur-backups', array('tiaur_notice' => 'invalid'));
        }

        $this->create_roles_backup('before_import');

        global $wp_roles;
        if (!isset($wp_roles)) {
            $wp_roles = wp_roles();
        }

        if (!empty($data['roles']) && is_array($data['roles'])) {
            $current_admin = isset($wp_roles->roles['administrator']) ? $wp_roles->roles['administrator'] : null;
            foreach ($data['roles'] as $role_key => $role_data) {
                $role_key = sanitize_key($role_key);
                if (!$role_key || empty($role_data['name']) || !isset($role_data['capabilities']) || !is_array($role_data['capabilities'])) {
                    continue;
                }
                if ($role_key === 'administrator') {
                    // Keep the local Administrator role protected. It may gain imported capabilities, but existing capabilities are never removed.
                    if ($current_admin && isset($current_admin['capabilities']) && is_array($current_admin['capabilities'])) {
                        $role_data['capabilities'] = array_merge($role_data['capabilities'], $current_admin['capabilities']);
                    }
                }
                $clean_caps = array();
                foreach ($role_data['capabilities'] as $cap => $allowed) {
                    $cap = sanitize_key($cap);
                    if ($cap) {
                        $clean_caps[$cap] = (bool) $allowed;
                    }
                }
                $wp_roles->roles[$role_key] = array(
                    'name' => sanitize_text_field($role_data['name']),
                    'capabilities' => $clean_caps,
                );
            }
            update_option($wp_roles->role_key, $wp_roles->roles);
        }

        if (isset($data['smart_rules']) && is_array($data['smart_rules'])) {
            $clean_rules = array();
            foreach ($data['smart_rules'] as $role => $row) {
                $role = sanitize_key($role);
                $remove = isset($row['remove']) && is_array($row['remove']) ? array_map('sanitize_key', $row['remove']) : array();
                if ($role) {
                    $clean_rules[$role] = array('remove' => array_values(array_unique(array_filter($remove))));
                }
            }
            update_option(self::OPTION_CONFLICT_RULES, $clean_rules, false);
        }

        if (isset($data['settings']) && is_array($data['settings'])) {
            if (isset($data['settings'][self::OPTION_MULTI_ROLE_ENABLED])) {
                update_option(self::OPTION_MULTI_ROLE_ENABLED, $data['settings'][self::OPTION_MULTI_ROLE_ENABLED] === '1' ? '1' : '0', false);
            }
            if (isset($data['settings'][self::OPTION_ROLE_TOOLS]) && is_array($data['settings'][self::OPTION_ROLE_TOOLS])) {
                update_option(self::OPTION_ROLE_TOOLS, array_merge($this->default_role_tools_settings(), $data['settings'][self::OPTION_ROLE_TOOLS]), false);
            }
            if (isset($data['settings'][self::OPTION_CONTENT_POST_TYPES]) && is_array($data['settings'][self::OPTION_CONTENT_POST_TYPES])) {
                $available = array_keys($this->public_custom_post_types());
                $types = array_values(array_intersect(array_map('sanitize_key', $data['settings'][self::OPTION_CONTENT_POST_TYPES]), $available));
                $types[] = 'post';
                $types[] = 'page';
                update_option(self::OPTION_CONTENT_POST_TYPES, array_values(array_unique($types)), false);
            }
        }

        if (isset($data['content_control']) && is_array($data['content_control'])) {
            foreach ($data['content_control'] as $item) {
                $post_id = isset($item['post_id']) ? absint($item['post_id']) : 0;
                if (!$post_id || !get_post($post_id)) {
                    continue;
                }
                update_post_meta($post_id, '_tiaur_content_enabled', !empty($item['enabled']) && $item['enabled'] === '1' ? '1' : '0');
                update_post_meta($post_id, '_tiaur_content_mode', isset($item['mode']) ? sanitize_key($item['mode']) : 'allow');
                $roles = isset($item['roles']) && is_array($item['roles']) ? array_map('sanitize_key', $item['roles']) : array();
                update_post_meta($post_id, '_tiaur_content_roles', array_values(array_unique($roles)));
                update_post_meta($post_id, '_tiaur_content_redirect', isset($item['redirect']) ? esc_url_raw($item['redirect']) : '');
                update_post_meta($post_id, '_tiaur_content_message', isset($item['message']) ? wp_kses_post($item['message']) : '');
                if (isset($item['rule']) && is_array($item['rule'])) {
                    update_post_meta($post_id, '_tiaur_content_rule', $item['rule']);
                }
            }
        }

        if (isset($data['safety_backups']) && is_array($data['safety_backups'])) {
            update_option(self::OPTION_ROLE_BACKUPS, array_slice($data['safety_backups'], 0, 15), false);
        }

        $this->safe_redirect('tiaur-backups', array('tiaur_notice' => 'imported'));
    }

    private function handle_restore_backup() {
        global $wp_roles;
        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce is verified centrally before handling admin actions, or this is a read-only admin filter.
        $index = isset($_POST['backup_index']) ? absint($_POST['backup_index']) : -1;
        $backups = get_option(self::OPTION_ROLE_BACKUPS, array());
        if (!isset($backups[$index]['roles']) || !is_array($backups[$index]['roles'])) {
            $this->safe_redirect('tiaur-backups', array('tiaur_notice' => 'missing'));
        }
        $this->create_roles_backup('before_restore');
        $wp_roles->roles = $backups[$index]['roles'];
        update_option($wp_roles->role_key, $wp_roles->roles);
        $this->safe_redirect('tiaur-backups');
    }

    private function handle_save_content_control_bulk() {
        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce is verified centrally before handling admin actions, or this is a read-only admin filter.
        $post_id = isset($_POST['post_id']) ? absint($_POST['post_id']) : 0;
        if (!$post_id || !current_user_can('edit_post', $post_id)) {
            $this->safe_redirect('tiaur-content-control', array('tiaur_notice' => 'missing'));
        }
        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce is verified centrally before handling admin actions, or this is a read-only admin filter.
        $this->save_content_control_settings($post_id, $_POST);
        $this->safe_redirect('tiaur-content-control');
    }

    public function on_user_role_added($user_id, $role) {
        $this->enforce_rules_for_user($user_id, $role);
    }

    public function on_user_role_set($user_id, $role, $old_roles) {
        $this->enforce_rules_for_user($user_id, $role);
    }

    public function on_profile_update($user_id, $old_user_data) {
        if (!$this->is_module_enabled('smart_rules')) {
            return;
        }
        $user = get_user_by('id', $user_id);
        if (!$user || empty($user->roles)) {
            return;
        }
        foreach ($user->roles as $role) {
            $this->enforce_rules_for_user($user_id, $role);
        }
    }

    private function store_profile_role_rule_notice($edited_user_id, $requested_roles, $removed_roles) {
        if (!is_admin() || empty($removed_roles)) {
            return;
        }
        $requested_roles = array_values(array_unique(array_map('sanitize_key', (array) $requested_roles)));
        $removed_roles = array_values(array_unique(array_map('sanitize_key', (array) $removed_roles)));
        $payload = array(
            'edited_user_id' => absint($edited_user_id),
            'requested_roles' => $requested_roles,
            'removed_roles' => $removed_roles,
            'blocked_requested_roles' => array_values(array_intersect($requested_roles, $removed_roles)),
            'settings_url' => admin_url('admin.php?page=tiaur-conflict-rules'),
        );
        set_transient('tiaur_profile_role_notice_' . get_current_user_id(), $payload, MINUTE_IN_SECONDS * 5);
    }

    public function render_profile_role_rule_notice() {
        if (!$this->is_module_enabled('smart_rules')) {
            return;
        }
        $screen = function_exists('get_current_screen') ? get_current_screen() : null;
        if (!$screen || !in_array($screen->base, array('profile', 'user-edit'), true)) {
            return;
        }
        $key = 'tiaur_profile_role_notice_' . get_current_user_id();
        $notice = get_transient($key);
        if (empty($notice) || !is_array($notice)) {
            return;
        }
        delete_transient($key);

        $roles = wp_roles()->roles;
        $format_role = function($role_key) use ($roles) {
            $role_key = sanitize_key($role_key);
            return isset($roles[$role_key]['name']) ? translate_user_role($roles[$role_key]['name']) : $role_key;
        };
        $removed_labels = array_map($format_role, (array) $notice['removed_roles']);
        $blocked_labels = array_map($format_role, (array) $notice['blocked_requested_roles']);
        $settings_url = !empty($notice['settings_url']) ? esc_url($notice['settings_url']) : esc_url(admin_url('admin.php?page=tiaur-conflict-rules'));

        echo '<div class="notice notice-warning is-dismissible tiaur-profile-smart-rules-notice"><p><strong>' . esc_html__('Smart Rules changed this user’s roles.', 'titanium-advanced-user-roles') . '</strong></p>';
        if (!empty($removed_labels)) {
            echo '<p>' . esc_html__('Removed roles:', 'titanium-advanced-user-roles') . ' <strong>' . esc_html(implode(', ', $removed_labels)) . '</strong></p>';
        }
        if (!empty($blocked_labels)) {
            echo '<p>' . esc_html__('These selected roles could not stay assigned because they conflict with the Smart Rules:', 'titanium-advanced-user-roles') . ' <strong>' . esc_html(implode(', ', $blocked_labels)) . '</strong></p>';
        }
        echo '<p><a href="' . esc_url($settings_url) . '">' . esc_html__('Change Smart Rules settings', 'titanium-advanced-user-roles') . '</a></p></div>';
    }

    private function enforce_rules_for_user($user_id, $trigger_role = '') {
        if (!$this->is_module_enabled('smart_rules')) {
            return;
        }
        if ($this->enforcing_rules) {
            return;
        }
        $this->enforcing_rules = true;

        $user = get_user_by('id', $user_id);
        $rules = get_option(self::OPTION_CONFLICT_RULES, array());
        if (!$user || !is_array($rules)) {
            $this->enforcing_rules = false;
            return;
        }

        $roles = (array) $user->roles;
        foreach ($roles as $role) {
            if (empty($rules[$role]['remove']) || !is_array($rules[$role]['remove'])) {
                continue;
            }

            foreach (array_unique($rules[$role]['remove']) as $remove_role) {
                if ($remove_role !== $role && in_array($remove_role, (array) $user->roles, true)) {
                    $user->remove_role($remove_role);
                }
            }
        }

        $this->enforcing_rules = false;
    }


    private function get_role_conflicts_for_user($user) {
        if (!$this->is_module_enabled('smart_rules')) {
            return array();
        }
        $rules = get_option(self::OPTION_CONFLICT_RULES, array());
        $matches = array();
        if (!$user instanceof WP_User || !is_array($rules)) {
            return $matches;
        }
        $roles = (array) $user->roles;
        foreach ($roles as $role) {
            $remove_roles = isset($rules[$role]['remove']) && is_array($rules[$role]['remove']) ? $rules[$role]['remove'] : array();
            foreach ($remove_roles as $remove_role) {
                if (in_array($remove_role, $roles, true)) {
                    $matches[] = $role . ' removes ' . $remove_role;
                }
            }
        }
        return array_unique($matches);
    }

    private function detect_user_conflict_matches($user, $rules = array()) {
        $matches = array();

        if (!$this->is_module_enabled('smart_rules')) {
            return $matches;
        }

        if (!$user instanceof WP_User) {
            return $matches;
        }

        if (!is_array($rules) || empty($rules)) {
            $rules = get_option(self::OPTION_CONFLICT_RULES, array());
        }

        if (!is_array($rules) || empty($rules)) {
            return $matches;
        }

        $roles = (array) $user->roles;
        if (empty($roles)) {
            return $matches;
        }

        foreach ($roles as $role) {
            $remove_roles = isset($rules[$role]['remove']) && is_array($rules[$role]['remove']) ? $rules[$role]['remove'] : array();

            if (isset($rules[$role]['conflict']) && is_array($rules[$role]['conflict'])) {
                $remove_roles = array_merge($remove_roles, $rules[$role]['conflict']);
            }

            foreach (array_unique($remove_roles) as $remove_role) {
                if ($remove_role !== $role && in_array($remove_role, $roles, true)) {
                    $matches[] = $this->role_label($role) . ' removes ' . $this->role_label($remove_role);
                }
            }
        }

        return array_values(array_unique($matches));
    }


    private function render_shell_start($title, $subtitle = '') {
        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce is verified centrally before handling admin actions, or this is a read-only admin filter.
        if (!empty($_GET['tiaur_notice'])) {
            echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__('Changes saved.', 'titanium-advanced-user-roles') . '</p></div>';
        }
        echo '<div id="tiaur-admin-app" class="tiaur-wrap tiaur-ready ' . esc_attr($this->color_scheme_class()) . '">';
        echo '<div class="tiaur-hero"><div class="tiaur-hero-brand"><span class="tiaur-kicker">TITANIUM</span><h1 class="tiaur-product-title">' . esc_html__('User Role Manager, Capabilities & Access Control', 'titanium-advanced-user-roles') . '</h1>';
        if ($title && !in_array($title, array(__('Titanium User Roles', 'titanium-advanced-user-roles'), __('Titanium User Roles Pro', 'titanium-advanced-user-roles')), true)) {
            echo '<div class="tiaur-hero-page-title">' . esc_html($title) . '</div>';
        }
        if ($subtitle) {
            echo '<p>' . esc_html($subtitle) . '</p>';
        }
        echo '</div><div class="tiaur-version">' . esc_html($this->edition_label()) . '</div></div>';
        echo '<div class="tiaur-tabs">';
        $tabs = array(
            self::MENU_SLUG => __('Dashboard', 'titanium-advanced-user-roles'),
            'tiaur-roles' => __('Roles & Capabilities', 'titanium-advanced-user-roles'),
            'tiaur-user-filters' => __('User Filters', 'titanium-advanced-user-roles'),
            'tiaur-content-control' => __('Content Control', 'titanium-advanced-user-roles'),
            'tiaur-conflict-rules' => __('Smart Rules', 'titanium-advanced-user-roles'),
            'tiaur-backups' => __('Import / Export', 'titanium-advanced-user-roles'),
            'tiaur-pro' => __('Upgrade to Pro', 'titanium-advanced-user-roles'),
        );
        $tabs['tiaur-pro-tools'] = __('Pro Tools', 'titanium-advanced-user-roles');
        $tabs['tiaur-settings'] = __('Settings', 'titanium-advanced-user-roles');
        $tabs['tiaur-more-plugins'] = __('More Plugins', 'titanium-advanced-user-roles');
        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce is verified centrally before handling admin actions, or this is a read-only admin filter.
        $current = isset($_GET['page']) ? sanitize_key($_GET['page']) : self::MENU_SLUG;
        foreach ($tabs as $slug => $label) {
            $classes = array('tiaur-tab-' . sanitize_html_class($slug));
            if ($current === $slug) {
                $classes[] = 'active';
            }
            echo '<a class="' . esc_attr(implode(' ', $classes)) . '" href="' . esc_url(admin_url('admin.php?page=' . $slug)) . '">' . esc_html($label) . '</a>';
        }
        echo '</div>';
    }

    private function render_shell_end() {
        echo '</div>';
    }

    private function premium_feature_rows() {
        return array(
            array('label' => __('Roles and capabilities editor', 'titanium-advanced-user-roles'), 'free' => true, 'pro' => true),
            array('label' => __('Create, clone, edit and delete roles', 'titanium-advanced-user-roles'), 'free' => true, 'pro' => true),
            array('label' => __('Role comparison and capability copy tools', 'titanium-advanced-user-roles'), 'free' => true, 'pro' => true),
            array('label' => __('Multiple roles for users', 'titanium-advanced-user-roles'), 'free' => true, 'pro' => true),
            array('label' => __('Unlimited AND user role filters', 'titanium-advanced-user-roles'), 'free' => true, 'pro' => true),
            array('label' => __('Role-based post and page content control', 'titanium-advanced-user-roles'), 'free' => true, 'pro' => true),
            array('label' => __('Restricted post hiding from frontend lists', 'titanium-advanced-user-roles'), 'free' => true, 'pro' => true),
            array('label' => __('Smart role cleanup rules', 'titanium-advanced-user-roles'), 'free' => true, 'pro' => true),
            array('label' => __('Admin menu visibility by role', 'titanium-advanced-user-roles'), 'free' => true, 'pro' => true),
            array('label' => __('Dashboard blocking by role', 'titanium-advanced-user-roles'), 'free' => true, 'pro' => true),
            array('label' => __('Admin bar hide by role', 'titanium-advanced-user-roles'), 'free' => true, 'pro' => true),
            array('label' => __('Login and logout redirects by role', 'titanium-advanced-user-roles'), 'free' => true, 'pro' => true),
            array('label' => __('Visibility shortcodes', 'titanium-advanced-user-roles'), 'free' => true, 'pro' => true),
            array('label' => __('Import / Export plugin-managed settings', 'titanium-advanced-user-roles'), 'free' => true, 'pro' => true),
            array('label' => __('Role backups and restore tools', 'titanium-advanced-user-roles'), 'free' => true, 'pro' => true),
            array('label' => __('Theme color and module controls', 'titanium-advanced-user-roles'), 'free' => true, 'pro' => true),
            array('label' => __('Content type selector for post, page and public custom post types', 'titanium-advanced-user-roles'), 'free' => true, 'pro' => true),
            array('label' => __('Default registration role tools', 'titanium-advanced-user-roles'), 'free' => true, 'pro' => true),
            array('label' => __('Restore default WordPress roles', 'titanium-advanced-user-roles'), 'free' => true, 'pro' => true),
            array('label' => __('Shortcodes for logged-in, logged-out, show and hide by role', 'titanium-advanced-user-roles'), 'free' => true, 'pro' => true),
            array('label' => __('OR groups in user filters', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Membership-level user filters', 'titanium-advanced-user-roles'), 'detail' => __('Filters users by supported membership plugins when they are installed, without looping through every user.', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Saved user filter views and shortcuts', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Export current filtered users', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Filter-to-Smart-Rule automation', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Bulk actions from filtered results', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('User filter result row profile links', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Username and membership columns in user filters', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Primary Roles and role order control', 'titanium-advanced-user-roles'), 'detail' => __('Define mutually exclusive membership roles, grant helper roles safely and keep user role order consistent.', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('User-specific capabilities', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Explicit deny capabilities', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Capability origin explainer', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Custom capability manager', 'titanium-advanced-user-roles'), 'detail' => __('Create and delete custom capabilities. Delete is allowed only when the capability is not assigned directly to any user.', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Advanced AND / OR content rules', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Hide Advanced Content Rule matches from frontend lists', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Taxonomy and category content rules', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Membership plugin conditions', 'titanium-advanced-user-roles'), 'detail' => __('Paid Memberships Pro, MemberPress, WooCommerce Memberships,<br>Restrict Content / Restrict Content Pro, and Paid Member Subscriptions', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Gutenberg block visibility rules', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Reusable block / synced pattern restrictions', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Advanced shortcode condition groups', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Dashboard widget hide by role', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Admin notice hide by role', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Plugin, theme and site editor restrictions', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Post metabox hide by role', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Block editor panel restrictions', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Unlimited profile screen hide/lock rules', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Hide WordPress profile sections, Contact Info groups and fields by condition', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Lock selected profile fields and custom contact fields by condition', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Detected and manual custom user meta profile controls', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Disable WordPress Application Passwords', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Detailed per-user admin restrictions', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Filtered user export', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Full user data export/import without passwords', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Role audit log', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Admin capability change alert', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Administrator capability review and baseline reset', 'titanium-advanced-user-roles'), 'detail' => __('Review Administrator role changes, accept a safe baseline, and clean stale plugin capabilities without unlocking the Administrator role editor.', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Stale plugin capability cleanup', 'titanium-advanced-user-roles'), 'detail' => __('Remove unused capabilities left behind by deleted plugins when they are not assigned directly to users.', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Multisite role sync', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
            array('label' => __('Priority support', 'titanium-advanced-user-roles'), 'free' => false, 'pro' => true),
        );
    }

    private function edition_label() {
        /* translators: %s: plugin version number. */
        return sprintf(__('Free v%s', 'titanium-advanced-user-roles'), self::VERSION);
    }


    private function render_locked_pro_feature_card($title, $description) {
        echo '<div class="tiaur-card tiaur-pro-placeholder-card">';
        echo '<span class="tiaur-pro-badge">' . esc_html__('Pro', 'titanium-advanced-user-roles') . '</span>';
        echo '<h3>' . esc_html($title) . '</h3>';
        echo '<p>' . esc_html($description) . '</p>';
        echo '<button type="button" class="tiaur-button ghost compact" disabled>' . esc_html__('Available in Pro', 'titanium-advanced-user-roles') . '</button>';
        echo '</div>';
    }

    public function render_dashboard_page() {
        $roles = $this->current_roles();
        $users = count_users();
        $rules = get_option(self::OPTION_CONFLICT_RULES, array());
        $restricted = $this->count_restricted_content();
        $this->render_shell_start(__('Titanium User Roles', 'titanium-advanced-user-roles'), __('Modern role management, content control and multi-role safety without membership-plugin chaos.', 'titanium-advanced-user-roles'));
        ?>
        <div class="tiaur-grid four">
            <div class="tiaur-card stat"><span><?php esc_html_e('Roles', 'titanium-advanced-user-roles'); ?></span><strong><?php echo esc_html(count($roles)); ?></strong></div>
            <div class="tiaur-card stat"><span><?php esc_html_e('Users', 'titanium-advanced-user-roles'); ?></span><strong><?php echo esc_html(number_format_i18n($users['total_users'])); ?></strong></div>
            <div class="tiaur-card stat"><span><?php esc_html_e('Smart rules', 'titanium-advanced-user-roles'); ?></span><strong><?php echo esc_html(count(array_filter($rules))); ?></strong></div>
            <div class="tiaur-card stat"><span><?php esc_html_e('Controlled content', 'titanium-advanced-user-roles'); ?></span><strong><?php echo esc_html($restricted); ?></strong></div>
        </div>
        <?php
        $module_statuses = array(
            array(
                'label' => __('Multiple Roles', 'titanium-advanced-user-roles'),
                'enabled' => $this->is_multi_role_enabled(),
                'url' => admin_url('admin.php?page=tiaur-roles'),
            ),
            array(
                'label' => __('Content Control', 'titanium-advanced-user-roles'),
                'enabled' => $this->is_module_enabled('content_control'),
                'url' => admin_url('admin.php?page=tiaur-content-control'),
            ),
            array(
                'label' => __('Smart Rules', 'titanium-advanced-user-roles'),
                'enabled' => $this->is_module_enabled('smart_rules'),
                'url' => admin_url('admin.php?page=tiaur-conflict-rules'),
            ),
            array(
                'label' => __('Frontend & Login Tools', 'titanium-advanced-user-roles'),
                'enabled' => $this->is_module_enabled('frontend_tools'),
                'url' => admin_url('admin.php?page=tiaur-roles'),
            ),
            array(
                'label' => __('Role Shortcodes', 'titanium-advanced-user-roles'),
                'enabled' => $this->is_module_enabled('role_shortcodes'),
                'url' => admin_url('admin.php?page=tiaur-roles'),
            ),
        );
        ?>
        <div class="tiaur-card tiaur-dashboard-modules-card">
            <div class="tiaur-dashboard-modules-head">
                <h2><?php esc_html_e('Feature status', 'titanium-advanced-user-roles'); ?></h2>
                <p><?php esc_html_e('Click a feature to open the page where it can be changed.', 'titanium-advanced-user-roles'); ?></p>
            </div>
            <div class="tiaur-module-led-grid">
                <?php foreach ($module_statuses as $module_status): ?>
                    <a class="tiaur-module-led-item <?php echo $module_status['enabled'] ? 'is-enabled' : 'is-disabled'; ?>" href="<?php echo esc_url($module_status['url']); ?>">
                        <span class="tiaur-led-light" aria-hidden="true"></span>
                        <span class="tiaur-led-text">
                            <strong><?php echo esc_html($module_status['label']); ?></strong>
                            <small><?php echo $module_status['enabled'] ? esc_html__('Enabled', 'titanium-advanced-user-roles') : esc_html__('Disabled', 'titanium-advanced-user-roles'); ?></small>
                        </span>
                    </a>
                <?php endforeach; ?>
            </div>
        </div>
        <?php
        $this->render_shell_end();
    }

    public function render_roles_page() {
        $roles = $this->current_roles();
        $editable_roles = $roles;
        unset($editable_roles['administrator']);

        $default_edit_role = !empty($editable_roles) ? key($editable_roles) : key($roles);
        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce is verified centrally before handling admin actions, or this is a read-only admin filter.
        $edit_role = isset($_GET['edit_role']) ? sanitize_key($_GET['edit_role']) : $default_edit_role;
        if ($edit_role === 'administrator' || !isset($roles[$edit_role])) {
            $edit_role = $default_edit_role;
        }
        $selected = isset($roles[$edit_role]) ? $roles[$edit_role] : null;
        $all_caps = $this->all_capabilities();
        $total_caps = count($all_caps);
        $selected_cap_count = ($selected && !empty($selected['capabilities'])) ? count(array_filter($selected['capabilities'])) : 0;
        $role_user_counts = isset(count_users()['avail_roles']) ? count_users()['avail_roles'] : array();
        $selected_user_count = isset($role_user_counts[$edit_role]) ? (int) $role_user_counts[$edit_role] : 0;
        $default_role = get_option('default_role', 'subscriber');
        $protected_admin = ($edit_role === 'administrator');
        $clone_source_default = '';
        foreach ($roles as $role_key => $role_data) {
            if ($role_key !== 'administrator') {
                $clone_source_default = $role_key;
                break;
            }
        }

        $this->render_shell_start(__('Roles & Capabilities', 'titanium-advanced-user-roles'), __('Create, clone and edit WordPress roles from a clean visual interface.', 'titanium-advanced-user-roles'));
        $multi_enabled = $this->is_multi_role_enabled();
        ?>
        <div class="tiaur-card tiaur-settings-card">
            <div class="tiaur-setting-copy">
                <h2><?php esc_html_e('Multiple roles for users', 'titanium-advanced-user-roles'); ?></h2>
                <p><?php esc_html_e('Replace the default single-role dropdown on user profiles with clean checkboxes, so each user can have as many roles as needed.', 'titanium-advanced-user-roles'); ?></p>
            </div>
            <div class="tiaur-toggle-wrap">
                <button type="button" class="tiaur-switch <?php echo $multi_enabled ? 'is-on is-saved' : ''; ?>" data-tiaur-toggle="multi-role" data-enabled="<?php echo $multi_enabled ? '1' : '0'; ?>" aria-pressed="<?php echo $multi_enabled ? 'true' : 'false'; ?>">
                    <span class="tiaur-switch-track"><span class="tiaur-switch-thumb"></span></span>
                    <span class="tiaur-switch-label"><?php echo $multi_enabled ? esc_html__('Enabled', 'titanium-advanced-user-roles') : esc_html__('Disabled', 'titanium-advanced-user-roles'); ?></span>
                </button>
                <span class="tiaur-switch-status" aria-live="polite"></span>
            </div>
        </div>

        <?php $role_tools = $this->role_tools_settings(); ?>
        <?php $frontend_tools_enabled = $this->is_module_enabled('frontend_tools'); ?>
        <details class="tiaur-card tiaur-settings-card tiaur-module-toggle-card tiaur-frontend-role-tools-card <?php echo $frontend_tools_enabled ? '' : 'is-module-disabled'; ?>">
            <summary>
                <span>
                    <strong><?php esc_html_e('Frontend & login tools', 'titanium-advanced-user-roles'); ?></strong>
                    <small><?php esc_html_e('Frontend toolbar, dashboard access, admin menus, redirects and shortcodes.', 'titanium-advanced-user-roles'); ?></small>
                </span>
                <?php $this->render_module_switch('enable_frontend_tools', $frontend_tools_enabled); ?>
                <span class="tiaur-details-chevron" aria-hidden="true">▾</span>
            </summary>
            <div class="tiaur-module-content <?php echo $frontend_tools_enabled ? '' : 'is-disabled'; ?>">
                <form method="post" class="tiaur-role-tools-settings-form">
                    <?php wp_nonce_field(self::NONCE_ACTION); ?>
                    <input type="hidden" name="tiaur_action" value="save_role_tools_settings" />
                    <div class="tiaur-tools-table-wrap">
                        <table class="tiaur-rule-table tiaur-role-tools-table">
                            <thead>
                                <tr>
                                    <th><?php esc_html_e('Role', 'titanium-advanced-user-roles'); ?></th>
                                    <th><?php esc_html_e('Hide admin bar', 'titanium-advanced-user-roles'); ?></th>
                                    <th><?php esc_html_e('Block dashboard', 'titanium-advanced-user-roles'); ?></th>
                                    <th><?php esc_html_e('Login redirect URL', 'titanium-advanced-user-roles'); ?></th>
                                    <th><?php esc_html_e('Logout redirect URL', 'titanium-advanced-user-roles'); ?></th>
                                </tr>
                            </thead>
                            <tbody>
                                <?php foreach ($roles as $role_key => $role_data): ?>
                                    <tr>
                                        <td><strong><?php echo esc_html(translate_user_role($role_data['name'])); ?></strong><code><?php echo esc_html($role_key); ?></code></td>
                                        <td><label class="tiaur-mini-check"><input type="checkbox" name="hide_admin_bar_roles[]" value="<?php echo esc_attr($role_key); ?>" <?php checked(in_array($role_key, $role_tools['hide_admin_bar_roles'], true)); ?> /> <?php esc_html_e('Hide', 'titanium-advanced-user-roles'); ?></label></td>
                                        <td><?php if ('administrator' !== $role_key): ?><label class="tiaur-mini-check"><input type="checkbox" name="block_admin_area_roles[]" value="<?php echo esc_attr($role_key); ?>" <?php checked(in_array($role_key, $role_tools['block_admin_area_roles'], true)); ?> /> <?php esc_html_e('Block', 'titanium-advanced-user-roles'); ?></label><?php endif; ?></td>
                                        <td><input type="url" name="login_redirects[<?php echo esc_attr($role_key); ?>]" value="<?php echo esc_attr(isset($role_tools['login_redirects'][$role_key]) ? $role_tools['login_redirects'][$role_key] : ''); ?>" placeholder="<?php echo esc_attr(home_url('/')); ?>" /></td>
                                        <td><input type="url" name="logout_redirects[<?php echo esc_attr($role_key); ?>]" value="<?php echo esc_attr(isset($role_tools['logout_redirects'][$role_key]) ? $role_tools['logout_redirects'][$role_key] : ''); ?>" placeholder="<?php echo esc_attr(home_url('/')); ?>" /></td>
                                    </tr>
                                <?php endforeach; ?>
                            </tbody>
                        </table>
                    </div>

                    <section class="tiaur-admin-menu-visibility-panel tiaur-admin-menu-visibility-section">
                        <div class="tiaur-admin-menu-visibility-header">
                            <span>
                                <strong><?php esc_html_e('Admin menu visibility', 'titanium-advanced-user-roles'); ?></strong>
                                <small><?php esc_html_e('Hide left-side admin menu items by role and block direct access to those screens.', 'titanium-advanced-user-roles'); ?></small>
                            </span>
                        </div>
                        <?php $admin_menu_items = $this->admin_menu_items(); ?>
                        <div class="tiaur-admin-menu-role-list">
                            <?php foreach ($roles as $role_key => $role_data): ?>
                                <?php if ('administrator' === $role_key) { continue; } ?>
                                <?php $hidden_for_role = isset($role_tools['hidden_admin_menus'][$role_key]) ? (array) $role_tools['hidden_admin_menus'][$role_key] : array(); ?>
                                <details class="tiaur-admin-menu-role-item" data-role-key="<?php echo esc_attr($role_key); ?>">
                                    <summary>
                                        <span class="tiaur-admin-menu-role-title"><strong><?php echo esc_html(translate_user_role($role_data['name'])); ?></strong><code><?php echo esc_html($role_key); ?></code><span class="tiaur-admin-role-chevron" aria-hidden="true">▾</span></span>
                                        <span class="tiaur-menu-count"><?php echo esc_html(number_format_i18n(count($hidden_for_role))); ?></span>
                                    </summary>
                                    <div class="tiaur-admin-menu-checkbox-grid">
                                        <?php foreach ($admin_menu_items as $menu_slug => $menu_label): ?>
                                            <?php if ($menu_slug === self::MENU_SLUG || $menu_slug === 'tiaur-roles') { continue; } ?>
                                            <label class="tiaur-admin-menu-check">
                                                <input type="checkbox" name="hidden_admin_menus[<?php echo esc_attr($role_key); ?>][]" value="<?php echo esc_attr($menu_slug); ?>" <?php checked(in_array($menu_slug, $hidden_for_role, true)); ?> />
                                                <span><?php echo esc_html($menu_label); ?></span>
                                                <code><?php echo esc_html($menu_slug); ?></code>
                                            </label>
                                        <?php endforeach; ?>
                                    </div>
                                </details>
                            <?php endforeach; ?>
                        </div>
                    </section>

                    <div class="tiaur-actions tiaur-role-tools-bottom-actions"><button class="tiaur-button primary compact" type="submit"><?php esc_html_e('Save role tools', 'titanium-advanced-user-roles'); ?></button></div>
                </form>
                <div class="tiaur-shortcode-help">
                    <h3><?php esc_html_e('Free visibility shortcodes', 'titanium-advanced-user-roles'); ?></h3>
                    <code>[tiaur_show roles=&quot;editor,author&quot;]...[/tiaur_show]</code>
                    <code>[tiaur_hide roles=&quot;subscriber&quot;]...[/tiaur_hide]</code>
                    <code>[tiaur_logged_in]...[/tiaur_logged_in]</code>
                    <code>[tiaur_logged_out]...[/tiaur_logged_out]</code>
                </div>
            </div>
        </details>

        <details class="tiaur-card tiaur-role-maintenance-card">
            <summary>
                <span>
                    <strong><?php esc_html_e('Role defaults & safety tools', 'titanium-advanced-user-roles'); ?></strong>
                    <small><?php esc_html_e('Occasional settings for new users and emergency restore.', 'titanium-advanced-user-roles'); ?></small>
                </span>
                <span class="tiaur-details-chevron" aria-hidden="true">▾</span>
            </summary>
            <div class="tiaur-maintenance-grid">
                <section class="tiaur-maintenance-panel">
                    <span class="tiaur-section-kicker"><?php esc_html_e('Default role', 'titanium-advanced-user-roles'); ?></span>
                    <h3><?php esc_html_e('New user default role', 'titanium-advanced-user-roles'); ?></h3>
                    <p><?php esc_html_e('Choose the role WordPress gives to newly registered users.', 'titanium-advanced-user-roles'); ?></p>
                    <form method="post" class="tiaur-inline-tools-form tiaur-default-role-form tiaur-compact-tool-form">
                        <?php wp_nonce_field(self::NONCE_ACTION); ?>
                        <input type="hidden" name="tiaur_action" value="save_default_role" />
                        <label class="screen-reader-text"><?php esc_html_e('Default role for new users', 'titanium-advanced-user-roles'); ?></label>
                        <select name="default_role">
                            <?php foreach ($roles as $role_key => $role_data): ?>
                                <?php if ($role_key === 'administrator') { continue; } ?>
                                <option value="<?php echo esc_attr($role_key); ?>" <?php selected($default_role, $role_key); ?>><?php echo esc_html(translate_user_role($role_data['name'])); ?></option>
                            <?php endforeach; ?>
                        </select>
                        <button class="tiaur-button primary compact" type="submit"><?php esc_html_e('Save', 'titanium-advanced-user-roles'); ?></button>
                    </form>
                </section>
                <section class="tiaur-maintenance-panel tiaur-danger-panel">
                    <span class="tiaur-section-kicker danger"><?php esc_html_e('Danger zone', 'titanium-advanced-user-roles'); ?></span>
                    <h3><?php esc_html_e('Restore default WordPress roles', 'titanium-advanced-user-roles'); ?></h3>
                    <p><?php esc_html_e('This restores the built-in WordPress role capabilities. A safety backup is created first, but custom changes to default roles may be overwritten.', 'titanium-advanced-user-roles'); ?></p>
                    <form method="post" class="tiaur-inline-tools-form tiaur-reset-defaults tiaur-reset-defaults-form" onsubmit="return confirm('<?php echo esc_js(__('Restore WordPress default role capabilities? A safety backup will be created first.', 'titanium-advanced-user-roles')); ?>');">
                        <?php wp_nonce_field(self::NONCE_ACTION); ?>
                        <input type="hidden" name="tiaur_action" value="reset_default_roles" />
                        <label class="tiaur-confirm-line">
                            <input type="checkbox" class="tiaur-enable-danger-action" />
                            <span><?php esc_html_e('I understand this may overwrite custom capability changes on built-in WordPress roles.', 'titanium-advanced-user-roles'); ?></span>
                        </label>
                        <button class="tiaur-button danger compact tiaur-danger-action" type="submit" disabled><?php esc_html_e('Restore defaults', 'titanium-advanced-user-roles'); ?></button>
                    </form>
                </section>
            </div>
        </details>



        <div class="tiaur-card tiaur-role-tools-card">
            <div class="tiaur-role-tools-grid">
                <div class="tiaur-role-tool tiaur-role-browser">
                    <div class="tiaur-tool-heading">
                        <h2><?php esc_html_e('Edit role', 'titanium-advanced-user-roles'); ?></h2>
                        <span><?php echo esc_html(number_format_i18n(count($editable_roles))); ?></span>
                    </div>
                    <label class="tiaur-mini-label"><?php esc_html_e('Choose role to edit', 'titanium-advanced-user-roles'); ?></label>
                    <div class="tiaur-select-shell tiaur-role-select-shell tiaur-role-nav-picker" tabindex="0" role="button" aria-haspopup="listbox" aria-expanded="false">
                        <div class="tiaur-current-role-display">
                            <span class="tiaur-current-role-name"><?php echo $selected ? esc_html(translate_user_role($selected['name'])) : esc_html__('Choose role', 'titanium-advanced-user-roles'); ?></span>
                            <span class="tiaur-current-role-meta"><?php /* translators: 1: enabled capabilities, 2: total capabilities, 3: users with this role. */ echo esc_html(sprintf(__('%1$d/%2$d capabilities · %3$d users', 'titanium-advanced-user-roles'), $selected_cap_count, $total_caps, $selected_user_count)); ?></span>
                        </div>
                        <span class="tiaur-select-icon" aria-hidden="true">▾</span><span class="tiaur-select-spinner" aria-hidden="true"></span>
                        <div class="tiaur-role-nav-menu" role="listbox">
                            <?php foreach ($editable_roles as $role_key => $role_data): ?>
                                <?php
                                $role_cap_count = !empty($role_data['capabilities']) ? count(array_filter($role_data['capabilities'])) : 0;
                                $role_url = admin_url('admin.php?page=tiaur-roles&edit_role=' . rawurlencode($role_key));
                                ?>
                                <button type="button" class="tiaur-role-nav-option <?php echo $role_key === $edit_role ? 'is-current' : ''; ?>" data-url="<?php echo esc_url($role_url); ?>" role="option" aria-selected="<?php echo $role_key === $edit_role ? 'true' : 'false'; ?>">
                                    <span class="tiaur-nav-role-name"><?php echo esc_html(translate_user_role($role_data['name'])); ?></span>
                                    <span class="tiaur-nav-role-meta"><?php /* translators: 1: enabled capabilities, 2: total capabilities, 3: users with this role. */ echo esc_html(sprintf(__('%1$d/%2$d capabilities · %3$d users', 'titanium-advanced-user-roles'), $role_cap_count, $total_caps, isset($role_user_counts[$role_key]) ? (int) $role_user_counts[$role_key] : 0)); ?></span>
                                </button>
                            <?php endforeach; ?>
                        </div>
                    </div>
                </div>

                <div class="tiaur-role-tool">
                    <div class="tiaur-tool-heading">
                        <h2><?php esc_html_e('Add role', 'titanium-advanced-user-roles'); ?></h2>
                    </div>
                    <form method="post" class="tiaur-compact-form">
                        <?php wp_nonce_field(self::NONCE_ACTION); ?>
                        <input type="hidden" name="tiaur_action" value="save_role" />
                        <input type="hidden" name="caps[]" value="read" />
                        <input type="text" name="role_key" placeholder="<?php esc_attr_e('new_role_key', 'titanium-advanced-user-roles'); ?>" />
                        <input type="text" name="role_name" placeholder="<?php esc_attr_e('New Role Name', 'titanium-advanced-user-roles'); ?>" />
                        <button class="tiaur-button primary" type="submit"><?php esc_html_e('Add role', 'titanium-advanced-user-roles'); ?></button>
                    </form>
                    <p class="tiaur-help-text"><?php esc_html_e('New roles receive the safe read capability by default.', 'titanium-advanced-user-roles'); ?></p>
                </div>

                <div class="tiaur-role-tool">
                    <div class="tiaur-tool-heading">
                        <h2><?php esc_html_e('Clone role', 'titanium-advanced-user-roles'); ?></h2>
                    </div>
                    <form method="post" class="tiaur-compact-form">
                        <?php wp_nonce_field(self::NONCE_ACTION); ?>
                        <input type="hidden" name="tiaur_action" value="clone_role" />
                        <select name="source_role">
                            <?php foreach ($roles as $role_key => $role_data): ?>
                                <?php if ($role_key === 'administrator') { continue; } ?>
                                <option value="<?php echo esc_attr($role_key); ?>" <?php selected($role_key, $clone_source_default); ?>><?php echo esc_html(translate_user_role($role_data['name'])); ?></option>
                            <?php endforeach; ?>
                        </select>
                        <input type="text" name="new_role_key" placeholder="<?php esc_attr_e('new_role_key', 'titanium-advanced-user-roles'); ?>" />
                        <input type="text" name="new_role_name" placeholder="<?php esc_attr_e('New Role Name', 'titanium-advanced-user-roles'); ?>" />
                        <button class="tiaur-button" type="submit"><?php esc_html_e('Clone role', 'titanium-advanced-user-roles'); ?></button>
                    </form>
                    <p class="tiaur-help-text"><?php esc_html_e('Administrator is protected and cannot be selected as a clone source.', 'titanium-advanced-user-roles'); ?></p>
                </div>
            </div>
        </div>

        <div class="tiaur-grid two tiaur-role-extra-tools tiaur-role-utility-row">
            <div class="tiaur-card tiaur-tool-card">
                <h2><?php esc_html_e('Copy capabilities', 'titanium-advanced-user-roles'); ?></h2>
                <form method="post" class="tiaur-inline-tools-form">
                    <?php wp_nonce_field(self::NONCE_ACTION); ?>
                    <input type="hidden" name="tiaur_action" value="copy_role_caps" />
                    <input type="hidden" name="target_role" value="<?php echo esc_attr($edit_role); ?>" />
                    <label><?php esc_html_e('Add missing capabilities from', 'titanium-advanced-user-roles'); ?></label>
                    <select name="copy_source_role">
                        <?php foreach ($roles as $role_key => $role_data): ?>
                            <?php if ($role_key === $edit_role || $role_key === 'administrator') { continue; } ?>
                            <option value="<?php echo esc_attr($role_key); ?>"><?php echo esc_html(translate_user_role($role_data['name'])); ?></option>
                        <?php endforeach; ?>
                    </select>
                    <button class="tiaur-button primary compact" type="submit"><?php esc_html_e('Copy into current role', 'titanium-advanced-user-roles'); ?></button>
                </form>
                <p class="tiaur-help-text"><?php esc_html_e('This only adds missing capabilities. It does not remove anything from the current role.', 'titanium-advanced-user-roles'); ?></p>
            </div>
        </div>

        <?php
        // Basic role comparison, kept read-only and simple in the Free version.
        $compare_a = isset($_GET['compare_a']) ? sanitize_key(wp_unslash($_GET['compare_a'])) : $edit_role; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only comparison view.
        $compare_b = isset($_GET['compare_b']) ? sanitize_key(wp_unslash($_GET['compare_b'])) : '';// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only comparison view.
        ?>
        <div class="tiaur-card tiaur-tool-card tiaur-compare-card">
            <h2><?php esc_html_e('Compare roles', 'titanium-advanced-user-roles'); ?></h2>
            <form method="get" class="tiaur-inline-tools-form tiaur-compare-form">
                <input type="hidden" name="page" value="tiaur-roles" />
                <input type="hidden" name="edit_role" value="<?php echo esc_attr($edit_role); ?>" />
                <select name="compare_a">
                    <?php foreach ($roles as $role_key => $role_data): ?>
                        <?php if ($role_key === 'administrator') { continue; } ?>
                        <option value="<?php echo esc_attr($role_key); ?>" <?php selected($compare_a, $role_key); ?>><?php echo esc_html(translate_user_role($role_data['name'])); ?></option>
                    <?php endforeach; ?>
                </select>
                <select name="compare_b">
                    <option value=""><?php esc_html_e('Choose role to compare', 'titanium-advanced-user-roles'); ?></option>
                    <?php foreach ($roles as $role_key => $role_data): ?>
                        <?php if ($role_key === 'administrator') { continue; } ?>
                        <option value="<?php echo esc_attr($role_key); ?>" <?php selected($compare_b, $role_key); ?>><?php echo esc_html(translate_user_role($role_data['name'])); ?></option>
                    <?php endforeach; ?>
                </select>
                <button class="tiaur-button compact" type="submit"><?php esc_html_e('Compare', 'titanium-advanced-user-roles'); ?></button>
            </form>
            <?php if ($compare_b && isset($roles[$compare_a], $roles[$compare_b])): ?>
                <?php
                $a_caps = array_keys(array_filter((array) $roles[$compare_a]['capabilities']));
                $b_caps = array_keys(array_filter((array) $roles[$compare_b]['capabilities']));
                $only_a = array_diff($a_caps, $b_caps);
                $only_b = array_diff($b_caps, $a_caps);
                ?>
                <div class="tiaur-compare-results">
                    <div>
                        <h3><?php /* translators: %s: role name. */ echo esc_html(sprintf(__('Only in %s', 'titanium-advanced-user-roles'), translate_user_role($roles[$compare_a]['name']))); ?></h3>
                        <?php if ($only_a): ?>
                            <div class="tiaur-cap-chip-list"><?php foreach (array_slice($only_a, 0, 80) as $cap): ?><span><?php echo esc_html($cap); ?></span><?php endforeach; ?></div>
                        <?php else: ?>
                            <p><?php esc_html_e('No extra capabilities.', 'titanium-advanced-user-roles'); ?></p>
                        <?php endif; ?>
                    </div>
                    <div>
                        <h3><?php /* translators: %s: role name. */ echo esc_html(sprintf(__('Only in %s', 'titanium-advanced-user-roles'), translate_user_role($roles[$compare_b]['name']))); ?></h3>
                        <?php if ($only_b): ?>
                            <div class="tiaur-cap-chip-list"><?php foreach (array_slice($only_b, 0, 80) as $cap): ?><span><?php echo esc_html($cap); ?></span><?php endforeach; ?></div>
                        <?php else: ?>
                            <p><?php esc_html_e('No extra capabilities.', 'titanium-advanced-user-roles'); ?></p>
                        <?php endif; ?>
                    </div>
                </div>
            <?php endif; ?>
        </div>

        <div class="tiaur-pro-placeholder-grid">
            <?php $this->render_locked_pro_feature_card(__('Primary Roles & role order', 'titanium-advanced-user-roles'), __('Define membership-style primary roles, grant helper roles from the Users screen and keep user role order consistent.', 'titanium-advanced-user-roles')); ?>
            <?php $this->render_locked_pro_feature_card(__('User-specific capabilities', 'titanium-advanced-user-roles'), __('Add or deny individual permissions for a single user without changing the role for everyone.', 'titanium-advanced-user-roles')); ?>
            <?php $this->render_locked_pro_feature_card(__('Capability origin explainer', 'titanium-advanced-user-roles'), __('Show exactly which role or override gives a user a specific permission.', 'titanium-advanced-user-roles')); ?>
        </div>
        <div class="tiaur-card tiaur-role-editor-card <?php echo $protected_admin ? 'tiaur-admin-protected' : ''; ?>">
            <div class="tiaur-role-editor-head">
                <div>
                    <h2><span class="tiaur-role-title-name"><?php echo $selected ? esc_html(translate_user_role($selected['name'])) : esc_html__('New role', 'titanium-advanced-user-roles'); ?></span> <span class="tiaur-cap-count"><?php /* translators: 1: enabled capabilities, 2: total capabilities. */ echo esc_html(sprintf(__('%1$d/%2$d capabilities', 'titanium-advanced-user-roles'), $selected_cap_count, $total_caps)); ?></span> <a class="tiaur-user-count-link" href="<?php echo esc_url($this->users_filter_url_for_role($edit_role)); ?>"><?php /* translators: %d: users with this role. */ echo esc_html(sprintf(_n('%d user', '%d users', $selected_user_count, 'titanium-advanced-user-roles'), $selected_user_count)); ?></a></h2>
                    <?php if ($protected_admin): ?>
                        <p class="tiaur-safety-note"><?php esc_html_e('Administrator protection is enabled: existing Administrator capabilities cannot be removed from this screen.', 'titanium-advanced-user-roles'); ?></p>
                    <?php endif; ?>
                </div>
                <?php if ($edit_role && $edit_role !== 'administrator'): ?>
                    <?php if ($edit_role === $default_role): ?>
                        <div class="tiaur-delete-used-role-panel tiaur-default-role-protected">
                            <strong><?php esc_html_e('Default role protected', 'titanium-advanced-user-roles'); ?></strong>
                            <p><?php esc_html_e('This role is currently the default role for new users. Choose a different default role before deleting it.', 'titanium-advanced-user-roles'); ?></p>
                        </div>
                    <?php elseif ($selected_user_count > 0): ?>
                        <details class="tiaur-delete-used-role-panel">
                            <summary>
                                <?php /* translators: %d: number of users with this role. */ ?>
                                <?php echo esc_html(sprintf(__('Cannot delete normally: %d users have this role', 'titanium-advanced-user-roles'), $selected_user_count)); ?>
                            </summary>
                            <form method="post" class="tiaur-danger-form-inline tiaur-delete-used-role-form" onsubmit="return confirm('Delete this role, remove it from all users and assign the default role to users who would otherwise have no role?');">
                                <?php wp_nonce_field(self::NONCE_ACTION); ?>
                                <input type="hidden" name="tiaur_action" value="delete_role" />
                                <input type="hidden" name="role_key" value="<?php echo esc_attr($edit_role); ?>" />
                                <input type="hidden" name="force_delete_used_role" value="1" />
                                <label class="tiaur-danger-check">
                                    <input type="checkbox" name="confirm_delete_used_role" value="1" />
                                    <span>
                                        <?php
                                        /* translators: %s: current default role name. */
                                        echo esc_html(sprintf(__('I understand this role will be removed from every user who currently has it. Users who would have no role left will receive the current default role: %s.', 'titanium-advanced-user-roles'), isset($roles[$default_role]) ? translate_user_role($roles[$default_role]['name']) : $default_role));
                                        ?>
                                    </span>
                                </label>
                                <button class="tiaur-button danger" type="submit" disabled><?php esc_html_e('Delete used role', 'titanium-advanced-user-roles'); ?></button>
                            </form>
                        </details>
                    <?php else: ?>
                        <form method="post" class="tiaur-danger-form-inline" onsubmit="return confirm('Delete this role?');">
                            <?php wp_nonce_field(self::NONCE_ACTION); ?>
                            <input type="hidden" name="tiaur_action" value="delete_role" />
                            <input type="hidden" name="role_key" value="<?php echo esc_attr($edit_role); ?>" />
                            <button class="tiaur-button danger" type="submit"><?php esc_html_e('Delete role', 'titanium-advanced-user-roles'); ?></button>
                        </form>
                    <?php endif; ?>
                <?php endif; ?>
            </div>

            <form method="post">
                <?php wp_nonce_field(self::NONCE_ACTION); ?>
                <input type="hidden" name="tiaur_action" value="save_role" />
                <div class="tiaur-form-row two">
                    <label><?php esc_html_e('Role key', 'titanium-advanced-user-roles'); ?><input type="text" name="role_key" value="<?php echo esc_attr($edit_role); ?>" <?php echo $selected ? 'readonly' : ''; ?> /></label>
                    <label><?php esc_html_e('Role name', 'titanium-advanced-user-roles'); ?><input type="text" name="role_name" value="<?php echo esc_attr($selected ? translate_user_role($selected['name']) : ''); ?>" /></label>
                </div>
                <div class="tiaur-cap-toolbar">
                    <div class="tiaur-cap-groups" role="tablist" aria-label="<?php esc_attr_e('Capability groups', 'titanium-advanced-user-roles'); ?>">
                        <?php foreach (array('all', 'posts', 'pages', 'users', 'plugins', 'themes', 'media', 'comments', 'admin', 'other') as $group): ?>
                            <button type="button" class="tiaur-cap-group <?php echo $group === 'all' ? 'is-active' : ''; ?>" data-cap-group="<?php echo esc_attr($group); ?>"><?php echo esc_html($this->capability_group_label($group)); ?></button>
                        <?php endforeach; ?>
                    </div>
                    <div class="tiaur-search-wrap"><input type="search" class="tiaur-cap-search" placeholder="<?php esc_attr_e('Search capabilities...', 'titanium-advanced-user-roles'); ?>" /></div>
                </div>
                <div class="tiaur-cap-grid">
                    <?php foreach ($all_caps as $cap): ?>
                        <?php $has_cap = !empty($selected['capabilities'][$cap]); ?>
                        <label class="tiaur-cap-item <?php echo ($protected_admin && $has_cap) ? 'tiaur-cap-locked' : ''; ?>" data-cap="<?php echo esc_attr($cap); ?>" data-cap-group="<?php echo esc_attr($this->capability_group($cap)); ?>">
                            <input type="checkbox" name="caps[]" value="<?php echo esc_attr($cap); ?>" <?php checked($has_cap); ?> <?php disabled($protected_admin && $has_cap); ?> />
                            <?php if ($protected_admin && $has_cap): ?>
                                <input type="hidden" name="caps[]" value="<?php echo esc_attr($cap); ?>" />
                            <?php endif; ?>
                            <span><?php echo esc_html($cap); ?></span>
                            <?php if ($protected_admin && $has_cap): ?><em><?php esc_html_e('locked', 'titanium-advanced-user-roles'); ?></em><?php endif; ?>
                        </label>
                    <?php endforeach; ?>
                </div>
                <label class="tiaur-full-label"><?php esc_html_e('Add custom capabilities, one per line', 'titanium-advanced-user-roles'); ?>
                    <textarea name="new_caps" rows="3" placeholder="read_private_posts&#10;manage_custom_area"></textarea>
                </label>
                <div class="tiaur-actions">
                    <button class="tiaur-button primary" type="submit"><?php esc_html_e('Save role', 'titanium-advanced-user-roles'); ?></button>
                </div>
            </form>
        </div>
        <?php
        $this->render_shell_end();
    }

    public function render_user_filters_page() {
        $roles = $this->current_roles();
        $membership_filter_options = array();
        $filter_value_options = $this->user_filter_value_options($roles, $membership_filter_options);
        $conditions = $this->parse_filter_conditions_from_request();
        $display_conditions = $conditions ? $conditions : array(array('field' => 'role', 'operator' => 'is', 'value' => ''));
        $users = $conditions ? $this->query_users_by_role_conditions($conditions) : array();
        $this->render_shell_start(__('User Filters', 'titanium-advanced-user-roles'), __('Build unlimited AND role filters and review matching users.', 'titanium-advanced-user-roles'));
        ?>
        <div class="tiaur-card">
            <form method="get" class="tiaur-filter-builder">
                <input type="hidden" name="page" value="tiaur-user-filters" />
                <h2><?php esc_html_e('Match users where', 'titanium-advanced-user-roles'); ?></h2>
                
                <div id="tiaur-filter-conditions">
                    <?php foreach ($display_conditions as $condition): ?>
                        <div class="tiaur-condition-row">
                            <?php $this->render_user_filter_field_select(isset($condition['field']) ? $condition['field'] : 'role', $membership_filter_options); ?>
                            <select name="filter_operator[]">
                                <option value="is" <?php selected($condition['operator'], 'is'); ?>><?php esc_html_e('is', 'titanium-advanced-user-roles'); ?></option>
                                <option value="is_not" <?php selected($condition['operator'], 'is_not'); ?>><?php esc_html_e('is not', 'titanium-advanced-user-roles'); ?></option>
                            </select>
                            <?php $this->render_user_filter_value_select(isset($condition['field']) ? $condition['field'] : 'role', $condition['value'], $filter_value_options); ?>
                            <button type="button" class="tiaur-icon-button tiaur-remove-condition">×</button>
                        </div>
                    <?php endforeach; ?>
                </div>
                <template id="tiaur-condition-template">
                    <div class="tiaur-condition-row">
                        <?php $this->render_user_filter_field_select('role', $membership_filter_options); ?>
                        <select name="filter_operator[]"><option value="is"><?php esc_html_e('is', 'titanium-advanced-user-roles'); ?></option><option value="is_not"><?php esc_html_e('is not', 'titanium-advanced-user-roles'); ?></option></select>
                        <?php $this->render_user_filter_value_select('role', '', $filter_value_options); ?>
                        <button type="button" class="tiaur-icon-button tiaur-remove-condition">×</button>
                    </div>
                </template>
                <div class="tiaur-actions">
                    <button type="button" class="tiaur-button secondary" id="tiaur-add-condition">+ <?php esc_html_e('Add condition', 'titanium-advanced-user-roles'); ?></button>
                    <button type="submit" class="tiaur-button primary"><?php esc_html_e('Apply filter', 'titanium-advanced-user-roles'); ?></button>
                    <a class="tiaur-button ghost" href="<?php echo esc_url(admin_url('admin.php?page=tiaur-user-filters')); ?>"><?php esc_html_e('Reset', 'titanium-advanced-user-roles'); ?></a>
                </div>
            </form>
        </div>
        <?php // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Read-only admin filter. ?>
        <?php if ($conditions && !empty($_GET['filter_value'])): ?>
            <div class="tiaur-card">
                <h2><?php
                /* translators: %s: number of users matching the current filter. */
                printf(esc_html__('%s users matched', 'titanium-advanced-user-roles'), esc_html(number_format_i18n(count($users))));
                ?></h2>
                    <table class="widefat striped tiaur-table">
                        <thead>
                            <tr><th><?php esc_html_e('User', 'titanium-advanced-user-roles'); ?></th><th><?php esc_html_e('Email', 'titanium-advanced-user-roles'); ?></th><th><?php esc_html_e('Roles', 'titanium-advanced-user-roles'); ?></th><th><?php esc_html_e('Status', 'titanium-advanced-user-roles'); ?></th></tr>
                        </thead>
                        <tbody>
                        <?php foreach ($users as $user): $conflicts = $this->get_role_conflicts_for_user($user); ?>
                            <tr>
                                <td><strong><?php echo esc_html($user->display_name); ?></strong><br><small>#<?php echo esc_html($user->ID); ?></small></td>
                                <td><?php echo esc_html($user->user_email); ?></td>
                                <td><?php echo wp_kses_post($this->render_role_badges($user->roles)); ?></td>
                                <td><?php echo $conflicts ? '<span class="tiaur-badge danger tiaur-status-help" title="' . esc_attr__('This user matches at least one Smart Rule conflict or role cleanup warning.', 'titanium-advanced-user-roles') . '">' . esc_html(implode(', ', $conflicts)) . '</span>' : '<span class="tiaur-badge good tiaur-status-help" title="' . esc_attr__('OK means no role conflict or cleanup warning was detected for this user in the current filtered result.', 'titanium-advanced-user-roles') . '">' . esc_html__('OK', 'titanium-advanced-user-roles') . '</span>'; ?></td>
                            </tr>
                        <?php endforeach; ?>
                        </tbody>
                    </table>
            </div>
        <?php endif; ?>
        <?php
        $this->render_shell_end();
    }

    private function parse_filter_conditions_from_request() {
        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Read-only admin filter.
        if (empty($_GET['filter_value']) || !is_array($_GET['filter_value'])) {
            return array();
        }

        $allowed_fields = array('role');

        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Read-only admin filter.
        $fields = isset($_GET['filter_field']) && is_array($_GET['filter_field']) ? wp_unslash($_GET['filter_field']) : array();
        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Read-only admin filter.
        $operators = isset($_GET['filter_operator']) && is_array($_GET['filter_operator']) ? wp_unslash($_GET['filter_operator']) : array();
        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Read-only admin filter.
        $values = wp_unslash($_GET['filter_value']);
        $conditions = array();

        foreach ($values as $i => $value) {
            $field = isset($fields[$i]) ? sanitize_key($fields[$i]) : 'role';
            if (!in_array($field, $allowed_fields, true)) {
                $field = 'role';
            }

            $value = 'role' === $field ? sanitize_key($value) : sanitize_text_field($value);
            if ('' === $value) {
                continue;
            }

            $conditions[] = array(
                'field'    => $field,
                'operator' => isset($operators[$i]) && 'is_not' === $operators[$i] ? 'is_not' : 'is',
                'value'    => $value,
            );
        }
        return $conditions;
    }

    private function current_filter_query_args() {
        $args = array();
        foreach (array('filter_field', 'filter_operator', 'filter_value') as $key) {
            // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Read-only filter query copied into saved view/export action after nonce-protected submit.
            $raw_filter_value = isset($_GET[$key]) ? wp_unslash($_GET[$key]) : array();
            if (is_array($raw_filter_value)) {
                $args[$key] = array_map('sanitize_text_field', $raw_filter_value);
            }
        }
        return $args;
    }

    private function query_users_by_role_conditions($conditions) {
        $condition_sets = array();

        foreach ((array) $conditions as $condition) {
            $field = isset($condition['field']) ? sanitize_key($condition['field']) : 'role';
            $operator = isset($condition['operator']) && 'is_not' === $condition['operator'] ? 'is_not' : 'is';
            $value = isset($condition['value']) ? (string) $condition['value'] : '';

            if ('' === $value) {
                continue;
            }

            if ('role' === $field) {
                $ids = $this->query_role_condition_user_ids(sanitize_key($value), $operator);
            } else {
                $ids = array();
            }

            $condition_sets[] = array_map('intval', $ids);
        }

        if (!$condition_sets) {
            return array();
        }

        $user_ids = array_shift($condition_sets);
        foreach ($condition_sets as $set) {
            $user_ids = array_values(array_intersect($user_ids, $set));
            if (!$user_ids) {
                break;
            }
        }
        $user_ids = array_slice(array_values(array_unique(array_filter(array_map('intval', $user_ids)))), 0, 500);

        if (!$user_ids) {
            return array();
        }

        $query = new WP_User_Query(array(
            'include' => $user_ids,
            'number' => 500,
            'orderby' => 'display_name',
            'order' => 'ASC',
        ));
        return $query->get_results();
    }

    private function query_role_condition_user_ids($role, $operator = 'is') {
        global $wpdb;
        $cap_key = $wpdb->get_blog_prefix() . 'capabilities';
        $meta_query = array(
            array(
                'key'     => $cap_key,
                'value'   => '"' . $role . '"',
                'compare' => 'is_not' === $operator ? 'NOT LIKE' : 'LIKE',
            ),
        );

        // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- WordPress stores roles in user meta; user filters are capped to avoid large result rendering.
        $query = new WP_User_Query(array(
            'number' => 500,
            'fields' => 'ID',
            // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- WordPress stores roles in user meta; user filters are capped to avoid large result rendering.
            'meta_query' => $meta_query,
            'orderby' => 'ID',
            'order' => 'ASC',
        ));

        return array_map('intval', $query->get_results());
    }

    private function user_filter_value_options($roles, $membership_filter_options) {
        $options = array(
            'role' => array(
                'label' => __('Role', 'titanium-advanced-user-roles'),
                'values' => array(),
            ),
        );

        foreach ($roles as $role_key => $role_data) {
            $options['role']['values'][$role_key] = translate_user_role($role_data['name']);
        }

        foreach ($membership_filter_options as $field => $provider) {
            $options[$field] = $provider;
        }

        return $options;
    }

    private function render_user_filter_field_select($selected, $membership_filter_options) {
        $selected = sanitize_key($selected);
        ?>
        <select name="filter_field[]" class="tiaur-select tiaur-filter-field-select">
            <option value="role" <?php selected($selected, 'role'); ?>><?php esc_html_e('Role', 'titanium-advanced-user-roles'); ?></option>
            <?php foreach ($membership_filter_options as $field => $provider): ?>
                <option value="<?php echo esc_attr($field); ?>" <?php selected($selected, $field); ?>><?php echo esc_html($provider['label']); ?></option>
            <?php endforeach; ?>
        </select>
        <?php
    }

    private function render_user_filter_value_select($selected_field, $selected_value, $filter_value_options) {
        $selected_field = sanitize_key($selected_field);
        $selected_value = (string) $selected_value;
        ?>
        <select name="filter_value[]" class="tiaur-select tiaur-filter-value-select">
            <option value="" data-field=""><?php esc_html_e('Select value', 'titanium-advanced-user-roles'); ?></option>
            <?php foreach ($filter_value_options as $field => $group): ?>
                <optgroup label="<?php echo esc_attr($group['label']); ?>" data-field="<?php echo esc_attr($field); ?>">
                    <?php foreach ((array) $group['values'] as $value => $label): ?>
                        <option value="<?php echo esc_attr($value); ?>" data-field="<?php echo esc_attr($field); ?>" <?php selected($selected_field === $field && $selected_value === (string) $value); ?>><?php echo esc_html($label); ?></option>
                    <?php endforeach; ?>
                </optgroup>
            <?php endforeach; ?>
        </select>
        <?php
    }

    private function render_membership_badges($labels) {
        $out = '';
        foreach (array_slice(array_unique(array_filter((array) $labels)), 0, 6) as $label) {
            $out .= '<span class="tiaur-badge tiaur-badge-soft">' . esc_html($label) . '</span> ';
        }
        return $out;
    }

    private function render_role_badges($roles) {
        $out = '';
        foreach ((array) $roles as $role) {
            $out .= '<span class="tiaur-badge">' . esc_html($this->role_label($role)) . '</span> ';
        }
        return $out ?: '<span class="tiaur-muted">No role</span>';
    }

    private function render_role_picker($input_name, $roles, $selected, $exclude_role = '') {
        $selected = array_values(array_unique(array_filter(array_map('sanitize_key', (array) $selected))));
        ?>
        <div class="tiaur-role-picker" data-input-name="<?php echo esc_attr($input_name); ?>">
            <div class="tiaur-role-picker-control" tabindex="0" role="button" aria-haspopup="listbox" aria-expanded="false">
                <div class="tiaur-role-picker-tags">
                    <span class="tiaur-role-picker-placeholder"><?php esc_html_e('Select role', 'titanium-advanced-user-roles'); ?></span>
                    <?php foreach ($selected as $role_key):
                        if ($role_key === $exclude_role || !isset($roles[$role_key])) {
                            continue;
                        }
                        ?>
                        <span class="tiaur-role-tag" data-role="<?php echo esc_attr($role_key); ?>">
                            <span><?php echo esc_html(translate_user_role($roles[$role_key]['name'])); ?></span>
                            <button type="button" class="tiaur-role-tag-remove" aria-label="<?php esc_attr_e('Remove role', 'titanium-advanced-user-roles'); ?>">×</button>
                            <input type="hidden" name="<?php echo esc_attr($input_name); ?>[]" value="<?php echo esc_attr($role_key); ?>" />
                        </span>
                    <?php endforeach; ?>
                </div>
                <span class="tiaur-role-picker-arrow" aria-hidden="true">⌄</span>
            </div>
            <div class="tiaur-role-picker-menu" role="listbox">
                <?php foreach ($roles as $role_key => $role_data): if ($role_key === $exclude_role) continue; ?>
                    <button type="button" class="tiaur-role-picker-option" data-role="<?php echo esc_attr($role_key); ?>" data-label="<?php echo esc_attr(translate_user_role($role_data['name'])); ?>" role="option">
                        <?php echo esc_html(translate_user_role($role_data['name'])); ?>
                    </button>
                <?php endforeach; ?>
            </div>
        </div>
        <?php
    }

    public function render_conflict_rules_page() {
        $roles = $this->current_roles();
        $rules = get_option(self::OPTION_CONFLICT_RULES, array());
        $smart_rules_enabled = $this->is_module_enabled('smart_rules');
        $this->render_shell_start(__('Smart Rules', 'titanium-advanced-user-roles'), __('Automatically clean up roles when another role is added.', 'titanium-advanced-user-roles'));
        ?>
        <div class="tiaur-card tiaur-settings-card tiaur-module-header-card <?php echo $smart_rules_enabled ? '' : 'is-module-disabled'; ?>">
            <div class="tiaur-setting-copy">
                <h2><?php esc_html_e('Enable Smart Rules', 'titanium-advanced-user-roles'); ?></h2>
                <p><?php esc_html_e('Automatically remove selected roles when another role is added.', 'titanium-advanced-user-roles'); ?></p>
            </div>
            <?php $this->render_module_switch('enable_smart_rules', $smart_rules_enabled); ?>
        </div>
        <div class="tiaur-module-content <?php echo $smart_rules_enabled ? '' : 'is-disabled'; ?>">
        <form method="post">
            <?php wp_nonce_field(self::NONCE_ACTION); ?>
            <input type="hidden" name="tiaur_action" value="save_conflict_rules" />
            <div class="tiaur-card">
                <h2><?php esc_html_e('Automatic role cleanup', 'titanium-advanced-user-roles'); ?></h2>
                <p><?php esc_html_e('For each role, choose which other roles should be removed automatically when that role is added to a user.', 'titanium-advanced-user-roles'); ?></p>
                <div class="tiaur-rule-table-wrap tiaur-smart-rules-wrap">
                    <table class="tiaur-rule-table tiaur-smart-rules-table">
                        <thead>
                            <tr>
                                <th><?php esc_html_e('When this role is added', 'titanium-advanced-user-roles'); ?></th>
                                <th><?php esc_html_e('Remove these roles automatically', 'titanium-advanced-user-roles'); ?></th>
                            </tr>
                        </thead>
                        <tbody>
                            <?php foreach ($roles as $role_key => $role_data):
                                $remove = isset($rules[$role_key]['remove']) ? (array) $rules[$role_key]['remove'] : array();
                                if (isset($rules[$role_key]['conflict']) && is_array($rules[$role_key]['conflict'])) {
                                    $remove = array_values(array_unique(array_merge($remove, (array) $rules[$role_key]['conflict'])));
                                }
                                ?>
                                <tr>
                                    <td class="tiaur-rule-name"><strong><?php echo esc_html(translate_user_role($role_data['name'])); ?></strong><code><?php echo esc_html($role_key); ?></code></td>
                                    <td><?php $this->render_role_picker('rules[' . $role_key . '][remove]', $roles, $remove, $role_key); ?></td>
                                </tr>
                            <?php endforeach; ?>
                        </tbody>
                    </table>
                </div>
                <div class="tiaur-actions"><button class="tiaur-button primary" type="submit"><?php esc_html_e('Save smart rules', 'titanium-advanced-user-roles'); ?></button></div>
            </div>
        </form>
        </div>
        <?php
        $this->render_shell_end();
    }


    public function render_content_control_page() {
        $roles = $this->current_roles();
        $content_control_enabled = $this->is_module_enabled('content_control');
        $content_post_types = $this->content_control_post_types();
        $available_post_types = $this->public_custom_post_types();
        $advanced_rule_type_usage = array();
        $advanced_rule_type_usage_labels = array();
        $posts = get_posts(array('post_type' => $content_post_types, 'post_status' => array('publish', 'private', 'draft'), 'numberposts' => 100, 'orderby' => 'date', 'order' => 'DESC'));
        $this->render_shell_start(__('Content Control', 'titanium-advanced-user-roles'), __('Simple role-based access control for posts and pages.', 'titanium-advanced-user-roles'));
        ?>
        <div class="tiaur-card tiaur-settings-card tiaur-module-header-card <?php echo $content_control_enabled ? '' : 'is-module-disabled'; ?>">
            <div class="tiaur-setting-copy">
                <h2><?php esc_html_e('Enable Content Control', 'titanium-advanced-user-roles'); ?></h2>
                <p><?php esc_html_e('Restrict posts, pages and selected public custom post types by role.', 'titanium-advanced-user-roles'); ?></p>
            </div>
            <?php $this->render_module_switch('enable_content_control', $content_control_enabled); ?>
        </div>
        <div class="tiaur-module-content <?php echo $content_control_enabled ? '' : 'is-disabled'; ?>">
        <details class="tiaur-card tiaur-role-maintenance-card tiaur-content-types-card">
            <summary>
                <span>
                    <strong><?php esc_html_e('Content types', 'titanium-advanced-user-roles'); ?></strong>
                    <small><?php esc_html_e('Choose which content types should be controlled by this plugin.', 'titanium-advanced-user-roles'); ?></small>
                </span>
                <span class="tiaur-details-chevron" aria-hidden="true">▾</span>
            </summary>
            <form method="post" class="tiaur-content-types-form" data-rule-type-usage="<?php echo esc_attr(wp_json_encode($advanced_rule_type_usage_labels)); ?>">
                <?php wp_nonce_field(self::NONCE_ACTION); ?>
                <input type="hidden" name="tiaur_action" value="save_content_post_types" />
                <div class="tiaur-cpt-grid">
                    <?php foreach ($available_post_types as $type_key => $type_obj): ?>
                        <label class="tiaur-cpt-option">
                            <input type="checkbox" name="content_post_types[]" value="<?php echo esc_attr($type_key); ?>" <?php checked(in_array($type_key, $content_post_types, true)); ?> />
                            <span><strong><?php echo esc_html($type_obj->labels->name); ?></strong><code><?php echo esc_html($type_key); ?></code><?php if (!empty($advanced_rule_type_usage[$type_key])): ?><small class="tiaur-cpt-rule-use">Used by <?php echo esc_html(absint($advanced_rule_type_usage[$type_key])); ?> advanced rule(s)</small><?php endif; ?></span>
                        </label>
                    <?php endforeach; ?>
                </div>
                <p class="tiaur-note tiaur-compact-note"><?php esc_html_e('Only enabled content types can use the standard Content Control metabox and Advanced Content Rules.', 'titanium-advanced-user-roles'); ?></p>
                <div class="tiaur-actions"><button class="tiaur-button primary compact" type="submit"><?php esc_html_e('Save content types', 'titanium-advanced-user-roles'); ?></button></div>
            </form>
        </details>

        <div class="tiaur-card">
            <h2><?php esc_html_e('Recent posts and pages', 'titanium-advanced-user-roles'); ?></h2>
            <table class="widefat striped tiaur-table">
                <thead><tr><th><?php esc_html_e('Content', 'titanium-advanced-user-roles'); ?></th><th><?php esc_html_e('Status', 'titanium-advanced-user-roles'); ?></th><th><?php esc_html_e('Control', 'titanium-advanced-user-roles'); ?></th><th><?php esc_html_e('Roles', 'titanium-advanced-user-roles'); ?></th><th><?php esc_html_e('Action', 'titanium-advanced-user-roles'); ?></th></tr></thead>
                <tbody>
                <?php foreach ($posts as $post):
                    $enabled = get_post_meta($post->ID, '_tiaur_content_enabled', true) === '1';
                    $mode = get_post_meta($post->ID, '_tiaur_content_mode', true) ?: 'allow';
                    $selected_roles = (array) get_post_meta($post->ID, '_tiaur_content_roles', true);
                    $hide_from_lists = get_post_meta($post->ID, '_tiaur_content_hide_from_lists', true);
                    $hide_from_lists = ($hide_from_lists === '') ? '1' : $hide_from_lists;
                ?>
                    <tr>
                        <td><strong><?php echo esc_html(get_the_title($post)); ?></strong><br><small><?php echo esc_html($post->post_type); ?> #<?php echo esc_html($post->ID); ?></small></td>
                        <td><?php echo esc_html($post->post_status); ?></td>
                        <td>
                            <?php echo $enabled ? '<span class="tiaur-badge good">Enabled</span>' : '<span class="tiaur-badge">Off</span>'; ?>
                            <span class="tiaur-badge"><?php echo esc_html($mode); ?></span>
                            <?php if ($enabled && $post->post_type !== 'page'): ?>
                                <?php echo $hide_from_lists === '1' ? '<span class="tiaur-badge good">Hidden from lists</span>' : '<span class="tiaur-badge">Content only</span>'; ?>
                            <?php endif; ?>
                        </td>
                        <td><?php echo wp_kses_post($this->render_role_badges($selected_roles)); ?></td>
                        <td>
                            <a class="tiaur-button small tiaur-content-edit-link <?php echo $content_control_enabled ? '' : 'is-disabled'; ?>" href="<?php echo esc_url(get_edit_post_link($post->ID)); ?>#tiaur-content-control-box" aria-disabled="<?php echo $content_control_enabled ? 'false' : 'true'; ?>"><?php esc_html_e('Edit', 'titanium-advanced-user-roles'); ?></a>
                        </td>
                    </tr>
                <?php endforeach; ?>
                </tbody>
            </table>
            <p class="tiaur-muted"><?php esc_html_e('Open any post or page to edit its Titanium User Roles Content Control box.', 'titanium-advanced-user-roles'); ?></p>
        </div>
        </div>
        <?php
        $this->render_shell_end();
    }

    private function count_restricted_content() {
        // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key, WordPress.DB.SlowDBQuery.slow_db_query_meta_value -- Counting this plugin's Content Control entries requires checking its post meta.
        $q = new WP_Query(array(
            'post_type' => $this->content_control_post_types(),
            'post_status' => 'any',
            'fields' => 'ids',
            'posts_per_page' => 1,
            // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Counting this plugin's Content Control entries requires checking its post meta.
            'meta_key' => '_tiaur_content_enabled',
            // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value -- Counting this plugin's Content Control entries requires checking its post meta.
            'meta_value' => '1',
        ));
        return (int) $q->found_posts;
    }

    public function register_content_control_metabox() {
        add_meta_box('tiaur-content-control-box', __('Access Control', 'titanium-advanced-user-roles'), array($this, 'render_content_control_metabox'), $this->content_control_post_types(), 'side', 'high');
    }

    public function render_content_control_metabox($post) {
        wp_nonce_field('tiaur_content_control_' . $post->ID, 'tiaur_content_control_nonce');
        $roles = $this->current_roles();
        $enabled = get_post_meta($post->ID, '_tiaur_content_enabled', true) === '1';
        $mode = get_post_meta($post->ID, '_tiaur_content_mode', true) ?: 'allow';
        $selected_roles = (array) get_post_meta($post->ID, '_tiaur_content_roles', true);
        $redirect = get_post_meta($post->ID, '_tiaur_content_redirect', true);
        $message = get_post_meta($post->ID, '_tiaur_content_message', true);
        $hide_from_lists = get_post_meta($post->ID, '_tiaur_content_hide_from_lists', true);
        $hide_from_lists = ($hide_from_lists === '') ? '1' : $hide_from_lists;
        ?>
        <div class="tiaur-content-metabox">
            <label class="tiaur-content-toggle">
                <input type="checkbox" name="tiaur_content_enabled" value="1" <?php checked($enabled); ?> />
                <span><?php esc_html_e('Restrict who can view this content', 'titanium-advanced-user-roles'); ?></span>
            </label>
            <p class="tiaur-content-help"><?php esc_html_e('When this is off, the post or page is public and the settings below are ignored.', 'titanium-advanced-user-roles'); ?></p>

            <fieldset class="tiaur-content-fields" <?php disabled(!$enabled); ?>>
                <p><label><?php esc_html_e('Mode', 'titanium-advanced-user-roles'); ?><br>
                    <select name="tiaur_content_mode" class="tiaur-content-input">
                        <option value="allow" <?php selected($mode, 'allow'); ?>><?php esc_html_e('Allow selected roles only', 'titanium-advanced-user-roles'); ?></option>
                        <option value="block" <?php selected($mode, 'block'); ?>><?php esc_html_e('Block selected roles', 'titanium-advanced-user-roles'); ?></option>
                        <option value="logged_in" <?php selected($mode, 'logged_in'); ?>><?php esc_html_e('Logged-in users only', 'titanium-advanced-user-roles'); ?></option>
                        <option value="logged_out" <?php selected($mode, 'logged_out'); ?>><?php esc_html_e('Logged-out visitors only', 'titanium-advanced-user-roles'); ?></option>
                    </select>
                </label></p>
                <p><strong><?php esc_html_e('Roles', 'titanium-advanced-user-roles'); ?></strong></p>
                <div class="tiaur-content-roles">
                    <?php foreach ($roles as $role_key => $role_data): ?>
                        <label><input type="checkbox" name="tiaur_content_roles[]" value="<?php echo esc_attr($role_key); ?>" <?php checked(in_array($role_key, $selected_roles, true)); ?> /> <?php echo esc_html(translate_user_role($role_data['name'])); ?></label>
                    <?php endforeach; ?>
                </div>
                <?php if ($post->post_type !== 'page'): ?>
                    <p class="tiaur-content-visibility-title"><strong><?php esc_html_e('Frontend visibility', 'titanium-advanced-user-roles'); ?></strong></p>
                    <label class="tiaur-content-toggle tiaur-content-subtoggle">
                        <input type="checkbox" name="tiaur_content_hide_from_lists" value="1" <?php checked($hide_from_lists, '1'); ?> />
                        <span><?php esc_html_e('Hide from frontend lists, archives and search results', 'titanium-advanced-user-roles'); ?></span>
                    </label>
                    <p class="tiaur-content-help"><?php esc_html_e('Turn this off if you want posts to be listed publicly but blocked after clicking.', 'titanium-advanced-user-roles'); ?></p>
                <?php else: ?>
                    <input type="hidden" name="tiaur_content_hide_from_lists" value="1" />
                <?php endif; ?>
                <p><label><?php esc_html_e('Redirect URL (optional)', 'titanium-advanced-user-roles'); ?><input type="url" name="tiaur_content_redirect" value="<?php echo esc_attr($redirect); ?>" class="tiaur-content-input" /></label></p>
                <p><label><?php esc_html_e('Denied message', 'titanium-advanced-user-roles'); ?><textarea name="tiaur_content_message" rows="3" class="tiaur-content-input"><?php echo esc_textarea($message); ?></textarea></label></p>
            </fieldset>
        </div>
        <?php
    }

    public function save_content_control_metabox($post_id, $post) {
        if (!isset($_POST['tiaur_content_control_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['tiaur_content_control_nonce'])), 'tiaur_content_control_' . $post_id)) {
            return;
        }
        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
            return;
        }
        if (!current_user_can('edit_post', $post_id)) {
            return;
        }
        // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce is verified centrally before handling admin actions, or this is a read-only admin filter.
        $this->save_content_control_settings($post_id, $_POST);
    }

    private function save_content_control_settings($post_id, $source) {
        $enabled = !empty($source['tiaur_content_enabled']) ? '1' : '0';
        $allowed_modes = array('allow', 'block', 'logged_in', 'logged_out');
        $mode = isset($source['tiaur_content_mode']) ? sanitize_key(wp_unslash($source['tiaur_content_mode'])) : 'allow';
        if (!in_array($mode, $allowed_modes, true)) {
            $mode = 'allow';
        }
        $roles = isset($source['tiaur_content_roles']) && is_array($source['tiaur_content_roles']) ? array_map('sanitize_key', wp_unslash($source['tiaur_content_roles'])) : array();
        $redirect = isset($source['tiaur_content_redirect']) ? esc_url_raw(wp_unslash($source['tiaur_content_redirect'])) : '';
        $message = isset($source['tiaur_content_message']) ? wp_kses_post(wp_unslash($source['tiaur_content_message'])) : '';
        $post_type = get_post_type($post_id);
        $hide_from_lists = ($post_type === 'page') ? '1' : (!empty($source['tiaur_content_hide_from_lists']) ? '1' : '0');
        update_post_meta($post_id, '_tiaur_content_enabled', $enabled);
        update_post_meta($post_id, '_tiaur_content_mode', $mode);
        update_post_meta($post_id, '_tiaur_content_roles', array_values(array_unique($roles)));
        update_post_meta($post_id, '_tiaur_content_redirect', $redirect);
        update_post_meta($post_id, '_tiaur_content_message', $message);
        update_post_meta($post_id, '_tiaur_content_hide_from_lists', $hide_from_lists);

        // Keep a normalized rules array now so Pro can extend this later with
        // unlimited AND/OR groups without changing the saved-data foundation.
        $rule = array(
            'version' => 1,
            'logic' => 'legacy_single_rule',
            'mode' => $mode,
            'roles' => array_values(array_unique($roles)),
            'hide_from_lists' => $hide_from_lists,
        );
        update_post_meta($post_id, '_tiaur_content_rule', $rule);
    }

    private function current_user_has_content_access($post_id) {
        if (!$this->is_content_control_module_enabled()) {
            return true;
        }
        if (get_post_meta($post_id, '_tiaur_content_enabled', true) !== '1') {
            return true;
        }
        $mode = get_post_meta($post_id, '_tiaur_content_mode', true) ?: 'allow';
        $stored_rule = get_post_meta($post_id, '_tiaur_content_rule', true);
        if (!is_array($stored_rule)) {
            $stored_rule = array(
                'version' => 1,
                'logic' => 'legacy_single_rule',
                'mode' => $mode,
                'roles' => (array) get_post_meta($post_id, '_tiaur_content_roles', true),
            );
        }

        /**
         * Premium extensions can evaluate advanced AND/OR content rules here.
         * Return true/false to override the free single-rule evaluator, or null
         * to let the free evaluator continue.
         */
        $premium_decision = apply_filters('tiaur_content_access_decision', null, $post_id, $stored_rule, wp_get_current_user());
        if ($premium_decision !== null) {
            return (bool) $premium_decision;
        }

        if ($mode === 'logged_in') {
            return is_user_logged_in();
        }
        if ($mode === 'logged_out') {
            return !is_user_logged_in();
        }

        $roles = (array) get_post_meta($post_id, '_tiaur_content_roles', true);
        $user = wp_get_current_user();
        $user_roles = $user && $user->exists() ? (array) $user->roles : array();
        $has_selected_role = (bool) array_intersect($roles, $user_roles);
        if ($mode === 'block') {
            return !$has_selected_role;
        }
        return $has_selected_role;
    }


    private function restricted_post_ids_for_current_user($post_types = array()) {
        if (!$this->is_content_control_module_enabled()) {
            return array();
        }
        if (empty($post_types)) {
            $post_types = $this->content_control_post_types();
        }
        $post_types = array_values(array_unique(array_filter((array) $post_types)));
        sort($post_types);
        $cache_key = md5(implode('|', $post_types) . '|' . get_current_user_id() . '|' . (is_user_logged_in() ? '1' : '0'));
        if (isset($this->restricted_ids_cache[$cache_key])) {
            return $this->restricted_ids_cache[$cache_key];
        }

        // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Content Control must find posts/pages with this plugin's access-control meta to hide them from public listings.
        $query = new WP_Query(array(
            'post_type' => $post_types,
            'post_status' => 'publish',
            'fields' => 'ids',
            'posts_per_page' => -1,
            'no_found_rows' => true,
            'update_post_meta_cache' => false,
            'update_post_term_cache' => false,
            // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Content Control must hide restricted posts/pages from archive listings.
            'meta_query' => array(
                array(
                    'key' => '_tiaur_content_enabled',
                    'value' => '1',
                    'compare' => '=',
                ),
            ),
        ));

        $restricted = array();
        foreach ((array) $query->posts as $post_id) {
            $post_id = (int) $post_id;
            if (get_post_meta($post_id, '_tiaur_content_enabled', true) !== '1') {
                continue;
            }
            $post_type = get_post_type($post_id);
            $hide_from_lists = get_post_meta($post_id, '_tiaur_content_hide_from_lists', true);
            $hide_from_lists = ($hide_from_lists === '') ? '1' : $hide_from_lists;
            if ($post_type === 'page') {
                $hide_from_lists = '1';
            }
            if ($hide_from_lists === '1' && !$this->current_user_has_content_access($post_id)) {
                $restricted[] = $post_id;
            }
        }
        $this->restricted_ids_cache[$cache_key] = $restricted;
        return $restricted;
    }

    public function maybe_exclude_restricted_content_from_queries($query) {
        if (!$this->is_content_control_module_enabled() || is_admin() || !$query instanceof WP_Query || !$query->is_main_query() || $query->is_singular()) {
            return;
        }

        $query_post_type = $query->get('post_type');
        if (empty($query_post_type)) {
            $post_types = $query->is_search() ? $this->content_control_post_types() : array('post');
        } else {
            $post_types = (array) $query_post_type;
        }

        if (in_array('any', $post_types, true)) {
            $post_types = $this->content_control_post_types();
        }
        $post_types = array_values(array_intersect($post_types, $this->content_control_post_types()));
        if (!$post_types) {
            return;
        }

        $restricted_ids = $this->restricted_post_ids_for_current_user($post_types);
        if (!$restricted_ids) {
            return;
        }

        $existing = (array) $query->get('post__not_in');
        $query->set('post__not_in', array_values(array_unique(array_merge(array_map('absint', $existing), $restricted_ids))));
    }

    public function maybe_restrict_content() {
        if (!$this->is_content_control_module_enabled()) {
            return;
        }
        if (!is_singular($this->content_control_post_types())) {
            return;
        }
        $post_id = get_queried_object_id();
        if (!$post_id || $this->current_user_has_content_access($post_id)) {
            return;
        }
        $redirect = get_post_meta($post_id, '_tiaur_content_redirect', true);
        if ($redirect) {
            wp_safe_redirect($redirect);
            exit;
        }

    }


    public function maybe_use_restricted_template($template) {
        if (!$this->is_content_control_module_enabled()) {
            return $template;
        }
        if (!is_singular($this->content_control_post_types())) {
            return $template;
        }

        $post_id = get_queried_object_id();
        if (!$post_id || $this->current_user_has_content_access($post_id)) {
            return $template;
        }

        $redirect = get_post_meta($post_id, '_tiaur_content_redirect', true);
        if ($redirect) {
            return $template;
        }

        $restricted_template = plugin_dir_path(__FILE__) . 'templates/restricted-content.php';
        return file_exists($restricted_template) ? $restricted_template : $template;
    }

    public function render_restricted_template_notice() {
        $post_id = get_queried_object_id();
        if (!$post_id) {
            $post_id = get_the_ID();
        }
        echo $this->render_restricted_content_notice((int) $post_id); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- The notice renderer escapes all dynamic output and returns controlled HTML.
    }

    public function maybe_replace_restricted_content($content) {
        if (!$this->is_content_control_module_enabled() || !is_singular($this->content_control_post_types()) || !in_the_loop() || !is_main_query()) {
            return $content;
        }
        $post_id = get_the_ID();
        if (!$post_id || $this->current_user_has_content_access($post_id)) {
            return $content;
        }
        return $this->render_restricted_content_notice($post_id);
    }


    private function render_restricted_content_notice($post_id) {
        $message = get_post_meta($post_id, '_tiaur_content_message', true);
        $is_logged_in = is_user_logged_in();

        if (!$message) {
            $message = $is_logged_in
                ? __('You do not have permission to view this content.', 'titanium-advanced-user-roles')
                : __('Please log in to view this content.', 'titanium-advanced-user-roles');
        }

        $current_url = get_permalink($post_id);
        $login_url = wp_login_url($current_url ? $current_url : home_url('/'));
        ob_start();
        ?>
        <div class="tiaur-restricted-wrap">
            <div class="tiaur-restricted-card">
                <div class="tiaur-restricted-icon" aria-hidden="true">🔒</div>
                <h2><?php echo esc_html($is_logged_in ? __('Access restricted', 'titanium-advanced-user-roles') : __('Login required', 'titanium-advanced-user-roles')); ?></h2>
                <div class="tiaur-restricted-text"><?php echo wp_kses_post(wpautop($message)); ?></div>
                <div class="tiaur-restricted-actions">
                    <?php if (!$is_logged_in): ?>
                        <a class="tiaur-restricted-button primary" href="<?php echo esc_url($login_url); ?>"><?php esc_html_e('Login', 'titanium-advanced-user-roles'); ?></a>
                        <a class="tiaur-restricted-button" href="<?php echo esc_url(home_url('/')); ?>"><?php esc_html_e('Back', 'titanium-advanced-user-roles'); ?></a>
                        <a class="tiaur-restricted-button" href="<?php echo esc_url(home_url('/')); ?>"><?php esc_html_e('Homepage', 'titanium-advanced-user-roles'); ?></a>
                    <?php else: ?>
                        <a class="tiaur-restricted-button primary" href="<?php echo esc_url(home_url('/')); ?>"><?php esc_html_e('Back', 'titanium-advanced-user-roles'); ?></a>
                        <a class="tiaur-restricted-button" href="<?php echo esc_url(home_url('/')); ?>"><?php esc_html_e('Homepage', 'titanium-advanced-user-roles'); ?></a>
                    <?php endif; ?>
                </div>
            </div>
        </div>
        <?php
        return ob_get_clean();
    }

    private function current_user_has_any_role($roles) {
        $roles = array_values(array_filter(array_map('sanitize_key', (array) $roles)));
        if (!$roles) {
            return false;
        }
        $user = wp_get_current_user();
        if (!$user || !$user->exists()) {
            return false;
        }
        return (bool) array_intersect($roles, (array) $user->roles);
    }

    public function shortcode_show_for_roles($atts, $content = '') {
        if (!$this->is_module_enabled('role_shortcodes')) {
            return '';
        }
        $atts = shortcode_atts(array('roles' => ''), $atts, 'tiaur_show');
        $roles = array_map('trim', explode(',', (string) $atts['roles']));
        return $this->current_user_has_any_role($roles) ? wp_kses_post(do_shortcode((string) $content)) : '';
    }

    public function shortcode_hide_for_roles($atts, $content = '') {
        if (!$this->is_module_enabled('role_shortcodes')) {
            return '';
        }
        $atts = shortcode_atts(array('roles' => ''), $atts, 'tiaur_hide');
        $roles = array_map('trim', explode(',', (string) $atts['roles']));
        return $this->current_user_has_any_role($roles) ? '' : wp_kses_post(do_shortcode((string) $content));
    }

    public function shortcode_logged_in($atts, $content = '') {
        if (!$this->is_module_enabled('role_shortcodes')) {
            return '';
        }
        return is_user_logged_in() ? wp_kses_post(do_shortcode((string) $content)) : '';
    }

    public function shortcode_logged_out($atts, $content = '') {
        if (!$this->is_module_enabled('role_shortcodes')) {
            return '';
        }
        return is_user_logged_in() ? '' : wp_kses_post(do_shortcode((string) $content));
    }

    public function maybe_hide_admin_bar($show) {
        if (!$this->is_module_enabled('frontend_tools') || is_admin() || !is_user_logged_in()) {
            return $show;
        }
        $settings = $this->role_tools_settings();
        if ($this->current_user_has_any_role($settings['hide_admin_bar_roles'])) {
            return false;
        }
        return $show;
    }

    private function redirect_url_for_user_roles($user, $type) {
        if (!$user instanceof WP_User || !$user->exists()) {
            return '';
        }
        $settings = $this->role_tools_settings();
        $map_key = $type === 'logout' ? 'logout_redirects' : 'login_redirects';
        $map = isset($settings[$map_key]) && is_array($settings[$map_key]) ? $settings[$map_key] : array();
        foreach ((array) $user->roles as $role) {
            if (!empty($map[$role])) {
                return esc_url_raw($map[$role]);
            }
        }
        return '';
    }

    public function maybe_login_redirect_by_role($redirect_to, $requested_redirect_to, $user) {
        if (!$this->is_module_enabled('frontend_tools')) {
            return $redirect_to;
        }
        if ($user instanceof WP_User) {
            $custom = $this->redirect_url_for_user_roles($user, 'login');
            if ($custom) {
                return $custom;
            }
        }
        return $redirect_to;
    }

    public function maybe_logout_redirect_by_role($redirect_to, $requested_redirect_to, $user) {
        if (!$this->is_module_enabled('frontend_tools')) {
            return $redirect_to;
        }
        if ($user instanceof WP_User) {
            $custom = $this->redirect_url_for_user_roles($user, 'logout');
            if ($custom) {
                return $custom;
            }
        }
        return $redirect_to;
    }

    public function render_backups_page() {
        $backups = get_option(self::OPTION_ROLE_BACKUPS, array());
        $this->render_shell_start(__('Import / Export', 'titanium-advanced-user-roles'), __('Export and restore roles, settings, Smart Rules, Content Control data and Pro user migration packages.', 'titanium-advanced-user-roles'));
        ?>
        <div class="tiaur-tools-grid tiaur-import-export-grid">
            <div class="tiaur-card tiaur-export-card">
                <h2><?php esc_html_e('Export', 'titanium-advanced-user-roles'); ?></h2>
                <p class="tiaur-muted"><?php esc_html_e('Download a JSON backup of everything managed by this plugin, or export only one section.', 'titanium-advanced-user-roles'); ?></p>
                <form method="get" action="<?php echo esc_url(admin_url('admin-post.php')); ?>" class="tiaur-export-form">
                    <input type="hidden" name="action" value="tiaur_export_data" />
                    <input type="hidden" name="_wpnonce" value="<?php echo esc_attr(wp_create_nonce(self::NONCE_ACTION)); ?>" />
                    <label class="tiaur-field-label"><?php esc_html_e('Export type', 'titanium-advanced-user-roles'); ?></label>
                    <input type="hidden" name="export_scope" value="everything" class="tiaur-export-scope-input" />
                    <div class="tiaur-export-picker" tabindex="0" role="button" aria-haspopup="listbox" aria-expanded="false">
                        <span class="tiaur-export-current"><?php esc_html_e('Everything managed by this plugin', 'titanium-advanced-user-roles'); ?></span>
                        <span class="tiaur-export-arrow" aria-hidden="true">▾</span>
                        <div class="tiaur-export-options" role="listbox">
                            <button type="button" class="tiaur-export-option is-selected" data-value="everything"><?php esc_html_e('Everything managed by this plugin', 'titanium-advanced-user-roles'); ?></button>
                            <button type="button" class="tiaur-export-option" data-value="roles"><?php esc_html_e('Roles and capabilities only', 'titanium-advanced-user-roles'); ?></button>
                            <button type="button" class="tiaur-export-option" data-value="smart_rules"><?php esc_html_e('Smart Rules only', 'titanium-advanced-user-roles'); ?></button>
                            <button type="button" class="tiaur-export-option" data-value="content_control"><?php esc_html_e('Content Control settings only', 'titanium-advanced-user-roles'); ?></button>
                            <button type="button" class="tiaur-export-option" data-value="settings"><?php esc_html_e('Plugin settings only', 'titanium-advanced-user-roles'); ?></button>
                            <button type="button" class="tiaur-export-option" data-value="safety_backups"><?php esc_html_e('Safety backups only', 'titanium-advanced-user-roles'); ?></button>
                        </div>
                    </div>
                    <button class="tiaur-button primary tiaur-export-button" type="submit"><?php esc_html_e('Download export file', 'titanium-advanced-user-roles'); ?></button>
                </form>
                <p class="tiaur-note"><?php esc_html_e('Passwords and full user data are not included in the Free export. Users can reset their password if needed.', 'titanium-advanced-user-roles'); ?></p>
            </div>

            <div class="tiaur-card tiaur-import-card">
                <h2><?php esc_html_e('Import', 'titanium-advanced-user-roles'); ?></h2>
                <p class="tiaur-muted"><?php esc_html_e('Import a JSON file created by this plugin. A safety backup is created before importing.', 'titanium-advanced-user-roles'); ?></p>
                <form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>" enctype="multipart/form-data" onsubmit="return confirm('<?php echo esc_js(__('Import this file? A safety backup will be created first.', 'titanium-advanced-user-roles')); ?>');">
                    <?php wp_nonce_field(self::NONCE_ACTION); ?>
                    <input type="hidden" name="action" value="tiaur_import_data" />
                    <input type="file" name="tiaur_import_file" accept="application/json,.json" class="tiaur-input" required />
                    <button class="tiaur-button primary" type="submit"><?php esc_html_e('Import file', 'titanium-advanced-user-roles'); ?></button>
                </form>
            </div>
        </div>

        <div class="tiaur-card">
            <h2><?php esc_html_e('Safety Backups', 'titanium-advanced-user-roles'); ?></h2>
            <p class="tiaur-muted"><?php esc_html_e('Recent automatic role backups. These are created before role changes, restores and imports.', 'titanium-advanced-user-roles'); ?></p>
            <table class="widefat striped tiaur-table">
                <thead><tr><th><?php esc_html_e('Time', 'titanium-advanced-user-roles'); ?></th><th><?php esc_html_e('Reason', 'titanium-advanced-user-roles'); ?></th><th><?php esc_html_e('User', 'titanium-advanced-user-roles'); ?></th><th><?php esc_html_e('Action', 'titanium-advanced-user-roles'); ?></th></tr></thead>
                <tbody>
                    <?php if (!$backups): ?>
                        <tr><td colspan="4"><?php esc_html_e('No backups yet.', 'titanium-advanced-user-roles'); ?></td></tr>
                    <?php endif; ?>
                    <?php foreach ($backups as $index => $backup): ?>
                        <tr>
                            <td><?php echo esc_html($backup['time']); ?></td>
                            <td><?php echo esc_html($backup['reason']); ?></td>
                            <td><?php echo esc_html(isset($backup['user_id']) ? $backup['user_id'] : ''); ?></td>
                            <td>
                                <form method="post" onsubmit="return confirm('<?php echo esc_js(__('Restore this role backup?', 'titanium-advanced-user-roles')); ?>');">
                                    <?php wp_nonce_field(self::NONCE_ACTION); ?>
                                    <input type="hidden" name="tiaur_action" value="restore_backup" />
                                    <input type="hidden" name="backup_index" value="<?php echo esc_attr($index); ?>" />
                                    <button class="tiaur-button small" type="submit"><?php esc_html_e('Restore', 'titanium-advanced-user-roles'); ?></button>
                                </form>
                            </td>
                        </tr>
                    <?php endforeach; ?>
                </tbody>
            </table>
        </div>
        <?php
        $this->render_shell_end();
    }


    private function render_module_switch($setting_key, $enabled) {
        $switch_class = $enabled ? 'tiaur-switch is-on is-saved' : 'tiaur-switch';
        $enabled_attr = $enabled ? '1' : '0';
        $aria_pressed = $enabled ? 'true' : 'false';
        $switch_label = $enabled ? __('Enabled', 'titanium-advanced-user-roles') : __('Disabled', 'titanium-advanced-user-roles');
        ?>
        <div class="tiaur-toggle-wrap tiaur-module-toggle-wrap">
            <button type="button" class="<?php echo esc_attr($switch_class); ?>" data-tiaur-toggle="module" data-setting="<?php echo esc_attr($setting_key); ?>" data-enabled="<?php echo esc_attr($enabled_attr); ?>" aria-pressed="<?php echo esc_attr($aria_pressed); ?>">
                <span class="tiaur-switch-track"><span class="tiaur-switch-thumb"></span></span>
                <span class="tiaur-switch-label"><?php echo esc_html($switch_label); ?></span>
            </button>
            <span class="tiaur-switch-status" aria-live="polite"><?php esc_html_e('Saved', 'titanium-advanced-user-roles'); ?></span>
        </div>
        <?php
    }

    private function handle_save_color_scheme() {
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified in handle_admin_actions().
        $scheme = isset($_POST['color_scheme']) ? sanitize_key(wp_unslash($_POST['color_scheme'])) : 'green';
        $schemes = $this->color_schemes();
        if (!isset($schemes[$scheme])) {
            $scheme = 'green';
        }
        $settings = $this->plugin_settings();
        $settings['color_scheme'] = $scheme;
        update_option(self::OPTION_PLUGIN_SETTINGS, $settings, false);
        $this->safe_redirect('tiaur-settings');
    }


    private function get_current_license_key() {
        if (!function_exists('titanium_advanced_user_roles_fs')) {
            return '';
        }

        $fs = titanium_advanced_user_roles_fs();

        if (!is_object($fs) || !method_exists($fs, '_get_license')) {
            return '';
        }

        $license = $fs->_get_license();

        if (!is_object($license) || empty($license->secret_key)) {
            return '';
        }

        return (string) $license->secret_key;
    }

    private function get_current_license_marker() {
        return array(
            'pricing_id' => '',
            'licenses'   => '',
        );
    }

    private function get_hosted_checkout_url($plan_id, $pricing_id) {
        $plan_id = absint($plan_id);
        $pricing_id = (string) $pricing_id;

        if ($plan_id <= 0 || '' === $pricing_id) {
            return '';
        }

        return add_query_arg(
            array(
                'pricing_id'    => $pricing_id,
                'billing_cycle' => 'annual',
                'currency'      => 'gbp',
            ),
            'https://checkout.freemius.com/product/32243/plan/' . $plan_id . '/'
        );
    }

    private function get_checkout_url($licenses = '1', $pricing_id = '', $plan_id = '') {
        $hosted_checkout_url = $this->get_hosted_checkout_url($plan_id, $pricing_id);

        if ('' !== $hosted_checkout_url) {
            return $hosted_checkout_url;
        }

        if (function_exists('titanium_advanced_user_roles_fs')) {
            $fs = titanium_advanced_user_roles_fs();

            if (is_object($fs) && method_exists($fs, 'checkout_url')) {
                $extra = array(
                    'currency' => 'gbp',
                );

                $plan_id_int = absint($plan_id);
                if ($plan_id_int > 0) {
                    $extra['plan_id'] = (string) $plan_id_int;
                }

                if ('unlimited' !== $licenses) {
                    $license_count = absint($licenses);

                    if ($license_count > 0) {
                        $extra['licenses'] = $license_count;
                    }
                }

                $checkout_url = $fs->checkout_url('annual', false, $extra);

                if (is_string($checkout_url) && '' !== $checkout_url && false === strpos($checkout_url, 'page=tiaur-pro')) {
                    return $checkout_url;
                }
            }
        }

        return (string) apply_filters('tiaur/pro_url', 'https://adminplugins.com/advanced-user-roles/');
    }

    private function get_hosted_upgrade_url($plan_id, $pricing_id) {
        $license_key = $this->get_current_license_key();
        $plan_id = absint($plan_id);
        $pricing_id = (string) $pricing_id;

        if ('' === $license_key || $plan_id <= 0 || '' === $pricing_id) {
            return $this->get_plan_change_url();
        }

        return add_query_arg(
            array(
                'license_key'   => $license_key,
                'pricing_id'    => $pricing_id,
                'billing_cycle' => 'annual',
                'currency'      => 'gbp',
            ),
            'https://checkout.freemius.com/product/32243/plan/' . $plan_id . '/'
        );
    }

    private function get_plan_change_url() {
        if (function_exists('titanium_advanced_user_roles_fs')) {
            $fs = titanium_advanced_user_roles_fs();

            if (is_object($fs) && method_exists($fs, 'get_upgrade_url')) {
                $url = $fs->get_upgrade_url('annual', false);

                if (is_string($url) && '' !== $url) {
                    return add_query_arg('currency', 'gbp', $url);
                }
            }

            if (is_object($fs) && method_exists($fs, 'pricing_url')) {
                $url = $fs->pricing_url('annual', false);

                if (is_string($url) && '' !== $url) {
                    return add_query_arg('currency', 'gbp', $url);
                }
            }
        }

        return $this->get_checkout_url('1');
    }

    private function get_freemius_account_url_if_connected() {
        if (!function_exists('titanium_advanced_user_roles_fs')) {
            return '';
        }

        $fs = titanium_advanced_user_roles_fs();

        if (!is_object($fs) || !method_exists($fs, 'get_account_url')) {
            return '';
        }

        if (method_exists($fs, 'is_registered') && !$fs->is_registered()) {
            return '';
        }

        $account_url = $fs->get_account_url();

        return is_string($account_url) ? $account_url : '';
    }

    public function ajax_get_freemius_pricing() {
        if (!current_user_can('manage_options')) {
            wp_send_json_error(array(
                'message' => __('You do not have permission to view pricing.', 'titanium-advanced-user-roles'),
            ), 403);
        }

        check_ajax_referer('tiaur_pricing_nonce', 'nonce');

        $remote_payload = $this->get_public_pricing_payload();
        if (is_array($remote_payload) && !empty($remote_payload['pricing']) && is_array($remote_payload['pricing'])) {
            wp_send_json_success(array(
                'pricingPayload' => $remote_payload,
                'proActive'      => false,
            ));
        }

        $plans = $this->get_freemius_pricing_cards();

        if (empty($plans)) {
            wp_send_json_error(array(
                'message' => __('Prices could not be downloaded. Secure checkout will show the current price.', 'titanium-advanced-user-roles'),
            ));
        }

        wp_send_json_success(array(
            'plans'     => $plans,
            'proActive' => false,
        ));
    }

    private function get_cached_public_pricing_payload() {
        $cached = get_transient('tiaur_public_pricing_payload_v1');

        return is_array($cached) ? $cached : array();
    }

    private function get_public_pricing_payload() {
        $cache_key = 'tiaur_public_pricing_payload_v1';
        $cached = get_transient($cache_key);
        if (is_array($cached)) {
            return $cached;
        }

        $urls = array(
            'https://adminplugins.com/wp-json/aur-freemius/v1/pricing?source=plugin',
            'https://adminplugins.com/?rest_route=/aur-freemius/v1/pricing&source=plugin',
        );

        $payload = array();
        foreach ($urls as $url) {
            $response = wp_remote_get($url, array(
                'timeout' => 15,
                'redirection' => 3,
                'headers' => array(
                    'Accept'     => 'application/json',
                    'User-Agent' => 'Titanium-Advanced-User-Roles-Pricing/1.0',
                ),
            ));

            if (is_wp_error($response)) {
                continue;
            }

            $status = (int) wp_remote_retrieve_response_code($response);
            if ($status < 200 || $status >= 300) {
                continue;
            }

            $payload = json_decode(wp_remote_retrieve_body($response), true);
            if (is_array($payload) && !empty($payload['pricing']) && is_array($payload['pricing'])) {
                break;
            }
        }
        if (!is_array($payload) || empty($payload['pricing']) || !is_array($payload['pricing'])) {
            return array();
        }

        $clean = array(
            'product_id' => isset($payload['product_id']) ? absint($payload['product_id']) : 32243,
            'plan_id'    => isset($payload['plan_id']) ? absint($payload['plan_id']) : 52911,
            'currency'   => isset($payload['currency']) ? sanitize_key((string) $payload['currency']) : 'gbp',
            'pricing'    => array(),
            'coupon'     => null,
        );

        foreach ((array) $payload['pricing'] as $pricing_id => $item) {
            if (!is_array($item)) {
                continue;
            }
            $id = sanitize_text_field((string) (isset($item['id']) ? $item['id'] : $pricing_id));
            $annual = isset($item['annual_price']) ? $item['annual_price'] : '';
            if ('' === $id || '' === (string) $annual || !is_numeric($annual)) {
                continue;
            }
            $clean['pricing'][(string) sanitize_key((string) $pricing_id)] = array(
                'id'           => $id,
                'currency'     => isset($item['currency']) ? sanitize_key((string) $item['currency']) : $clean['currency'],
                'licenses'     => isset($item['licenses']) ? sanitize_text_field((string) $item['licenses']) : '',
                'annual_price' => (string) $annual,
            );
        }

        if (!empty($payload['coupon']) && is_array($payload['coupon'])) {
            $coupon = $payload['coupon'];
            $discount = 0.0;
            foreach (array('discount', 'discount_amount', 'amount', 'coupon_discount') as $discount_key) {
                if (isset($coupon[$discount_key]) && is_numeric($coupon[$discount_key])) {
                    $discount = (float) $coupon[$discount_key];
                    break;
                }
            }

            $raw_type = isset($coupon['discount_type']) ? (string) $coupon['discount_type'] : (isset($coupon['type']) ? (string) $coupon['type'] : '');
            $raw_type = strtolower(trim($raw_type));
            if (in_array($raw_type, array('percentage', 'percent', '%'), true)) {
                $type = 'percentage';
            } elseif (in_array($raw_type, array('fixed', 'money', 'amount', 'currency'), true)) {
                $type = 'fixed';
            } else {
                $type = sanitize_key($raw_type);
            }

            $code = isset($coupon['code']) ? sanitize_text_field((string) $coupon['code']) : '';
            $active = true;

            foreach (array('is_active', 'active') as $active_key) {
                if (array_key_exists($active_key, $coupon)) {
                    $active_value = $coupon[$active_key];
                    if (is_bool($active_value)) {
                        $active = $active_value;
                    } elseif (is_numeric($active_value)) {
                        $active = 1 === (int) $active_value;
                    } else {
                        $active = in_array(strtolower(trim((string) $active_value)), array('1', 'true', 'yes', 'on', 'active', 'enabled', 'published'), true);
                    }
                    break;
                }
            }

            foreach (array('status', 'state') as $status_key) {
                if (!empty($coupon[$status_key])) {
                    $status_value = strtolower(trim((string) $coupon[$status_key]));
                    if (in_array($status_value, array('inactive', 'disabled', 'deleted', 'archived', 'draft', 'expired'), true)) {
                        $active = false;
                    }
                    if (in_array($status_value, array('active', 'enabled', 'published'), true)) {
                        $active = true;
                    }
                }
            }

            foreach (array('is_deleted', 'deleted', 'is_disabled', 'disabled', 'is_archived', 'archived') as $inactive_key) {
                if (array_key_exists($inactive_key, $coupon)) {
                    $inactive_value = $coupon[$inactive_key];
                    $inactive = is_bool($inactive_value) ? $inactive_value : in_array(strtolower(trim((string) $inactive_value)), array('1', 'true', 'yes', 'on'), true);
                    if ($inactive) {
                        $active = false;
                        break;
                    }
                }
            }

            if ($active && '' !== $code && $discount > 0 && in_array($type, array('percentage', 'fixed'), true)) {
                $clean['coupon'] = array(
                    'code'          => $code,
                    'discount'      => $discount,
                    'discount_type' => $type,
                    'is_active'     => true,
                );
            }
        }

        if (!empty($clean['pricing'])) {
            set_transient($cache_key, $clean, DAY_IN_SECONDS);
            return $clean;
        }

        return array();
    }

    private function get_freemius_pricing_cards() {
        if (!function_exists('titanium_advanced_user_roles_fs')) {
            return array();
        }

        $fs = titanium_advanced_user_roles_fs();

        if (!is_object($fs) || !method_exists($fs, 'get_api_plugin_scope') || !method_exists($fs, 'add_show_pending')) {
            return array();
        }

        $api = $fs->get_api_plugin_scope();

        if (!is_object($api) || !method_exists($api, 'get')) {
            return array();
        }

        $path = $fs->add_show_pending('pricing.json?' . http_build_query(array(
            'is_enriched' => 'true',
            'currency'    => 'gbp',
        )));

        $response = $api->get($path);

        if (is_object($response) && isset($response->error)) {
            return array();
        }

        return $this->build_pricing_cards_from_freemius_response($response);
    }

    private function build_pricing_cards_from_freemius_response($response) {
        $plans = $this->pricing_value($response, 'plans');

        if (!is_array($plans)) {
            return array();
        }

        $pro_plan = null;

        foreach ($plans as $plan) {
            $plan_name = strtolower((string) $this->pricing_value($plan, 'name'));
            $pricing = $this->pricing_value($plan, 'pricing');

            if ('pro' === $plan_name && is_array($pricing) && !empty($pricing)) {
                $pro_plan = $plan;
                break;
            }
        }

        if (null === $pro_plan) {
            foreach ($plans as $plan) {
                $pricing = $this->pricing_value($plan, 'pricing');

                if (is_array($pricing) && !empty($pricing)) {
                    $pro_plan = $plan;
                    break;
                }
            }
        }

        if (null === $pro_plan) {
            return array();
        }

        $plan_id = (string) $this->pricing_value($pro_plan, 'id');
        $pricing_rows = $this->pricing_value($pro_plan, 'pricing');

        if (!is_array($pricing_rows)) {
            return array();
        }

        $cards = array();

        foreach ($pricing_rows as $pricing) {
            $billing_cycle = strtolower((string) $this->pricing_value($pricing, 'billing_cycle'));
            $currency      = strtolower((string) $this->pricing_value($pricing, 'currency'));
            $licenses      = $this->normalize_freemius_licenses($this->pricing_value($pricing, 'licenses'));
            $pricing_id    = (string) $this->pricing_value($pricing, 'id');

            if ('' !== $currency && 'gbp' !== $currency) {
                continue;
            }

            if ('' !== $billing_cycle && !in_array($billing_cycle, array('annual', 'yearly', 'year'), true)) {
                continue;
            }

            $amount = $this->pricing_value($pricing, 'annual_price');

            if (null === $amount || '' === $amount) {
                $amount = $this->pricing_value($pricing, 'annual');
            }

            if (null === $amount || '' === $amount) {
                $amount = $this->pricing_value($pricing, 'price');
            }

            if (null === $amount || '' === $amount || !is_numeric($amount)) {
                continue;
            }

            $cards[] = array(
                'label'      => $this->format_license_label($licenses),
                'licenses'   => $licenses,
                'price'      => $this->format_price((float) $amount, '' !== $currency ? $currency : 'gbp'),
                'pricing_id' => $pricing_id,
                'checkout'   => $this->get_checkout_url($licenses, $pricing_id, $plan_id),
            );
        }

        usort($cards, function (array $a, array $b) {
            return $this->license_sort_weight($a['licenses']) <=> $this->license_sort_weight($b['licenses']);
        });

        return $cards;
    }

    private function pricing_value($value, $key) {
        if (is_array($value) && array_key_exists($key, $value)) {
            return $value[$key];
        }

        if (is_object($value) && isset($value->{$key})) {
            return $value->{$key};
        }

        return null;
    }

    private function normalize_freemius_licenses($licenses) {
        if (null === $licenses || '' === $licenses) {
            return 'unlimited';
        }

        $licenses_string = strtolower((string) $licenses);

        if (in_array($licenses_string, array('unlimited', 'inf', 'infinite', '0'), true)) {
            return 'unlimited';
        }

        return (string) max(1, absint($licenses_string));
    }

    private function format_license_label($licenses) {
        if ('unlimited' === $licenses) {
            return __('Unlimited Sites', 'titanium-advanced-user-roles');
        }

        if ('1' === $licenses) {
            return __('Single Site', 'titanium-advanced-user-roles');
        }

        return sprintf(
            /* translators: %s: number of websites included in the license. */
            __('%s Sites', 'titanium-advanced-user-roles'),
            number_format_i18n((int) $licenses)
        );
    }

    private function license_sort_weight($licenses) {
        if ('unlimited' === $licenses) {
            return PHP_INT_MAX;
        }

        return (int) $licenses;
    }

    private function format_price($amount, $currency) {
        $symbols = array(
            'gbp' => '£',
            'usd' => '$',
            'eur' => '€',
        );
        $currency = strtolower((string) $currency);
        $symbol = isset($symbols[$currency]) ? $symbols[$currency] : strtoupper($currency) . ' ';

        return $symbol . number_format_i18n($amount, 2);
    }


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

        $this->render_shell_start(__('More Plugins', 'titanium-advanced-user-roles'), __('Free WordPress tools from AdminPlugins.', 'titanium-advanced-user-roles'));
        if (class_exists('TIAUR_More_Plugins_Page')) {
            TIAUR_More_Plugins_Page::render();
        }
        $this->render_shell_end();
    }

    private function render_pricing_plan_placeholders($current_license_marker = array(), $pro_active = false) {
        $plan_id = 52911;
        $plans = array(
            array('pricing_id' => '69616', 'label' => __('Single Site', 'titanium-advanced-user-roles'), 'licenses' => '1', 'short' => __('Single site license', 'titanium-advanced-user-roles')),
            array('pricing_id' => '69617', 'label' => __('3 Sites', 'titanium-advanced-user-roles'), 'licenses' => '3', 'short' => __('3 site license', 'titanium-advanced-user-roles')),
            array('pricing_id' => '69618', 'label' => __('5 Sites', 'titanium-advanced-user-roles'), 'licenses' => '5', 'short' => __('5 site license', 'titanium-advanced-user-roles')),
            array('pricing_id' => '69619', 'label' => __('10 Sites', 'titanium-advanced-user-roles'), 'licenses' => '10', 'short' => __('10 site license', 'titanium-advanced-user-roles')),
            array('pricing_id' => '69622', 'label' => __('20 Sites', 'titanium-advanced-user-roles'), 'licenses' => '20', 'short' => __('20 site license', 'titanium-advanced-user-roles')),
            array('pricing_id' => '69623', 'label' => __('Unlimited Sites', 'titanium-advanced-user-roles'), 'licenses' => 'unlimited', 'short' => __('Unlimited site license', 'titanium-advanced-user-roles')),
        );
        $current_licenses = isset($current_license_marker['licenses']) ? (string) $current_license_marker['licenses'] : '';

        foreach ($plans as $plan) {
            $is_active = $pro_active && '' !== $current_licenses && (string) $plan['licenses'] === $current_licenses;
            $button_class = $is_active ? 'tiaur-upgrade-card-button tiaur-upgrade-card-button--active' : 'tiaur-upgrade-card-button';
            $button_text = $is_active ? __('ACTIVE', 'titanium-advanced-user-roles') : __('UPGRADE NOW', 'titanium-advanced-user-roles');
            $checkout_url = $pro_active ? $this->get_hosted_upgrade_url($plan_id, $plan['pricing_id']) : $this->get_checkout_url($plan['licenses'], $plan['pricing_id'], $plan_id);
            ?>
            <div class="tiaur-pricing-card-premium<?php echo $is_active ? ' tiaur-pricing-card-premium--active' : ''; ?>" data-tiaur-pricing-id="<?php echo esc_attr($plan['pricing_id']); ?>">
                <div class="tiaur-pricing-shine"></div>
                <div class="tiaur-pricing-card-head"><span class="tiaur-plan-pro-badge"><?php esc_html_e('PRO', 'titanium-advanced-user-roles'); ?></span><span class="tiaur-plan-cycle"><?php esc_html_e('ANNUAL', 'titanium-advanced-user-roles'); ?></span></div>
                <h3><?php echo esc_html($plan['label']); ?></h3>
                <div class="tiaur-pricing-price-premium tiaur-pricing-price-premium--loading"><span class="tiaur-pricing-spinner" aria-hidden="true"></span><span><?php esc_html_e('Loading prices...', 'titanium-advanced-user-roles'); ?></span></div>
                <span class="tiaur-plan-license-pill"><?php echo esc_html($plan['short']); ?></span>
                <div class="tiaur-plan-includes"><span><?php esc_html_e('All Pro features', 'titanium-advanced-user-roles'); ?></span><span><?php esc_html_e('Updates and support', 'titanium-advanced-user-roles'); ?></span><span><?php esc_html_e('License managed by Freemius', 'titanium-advanced-user-roles'); ?></span></div>
                <?php if ($is_active): ?>
                    <button class="<?php echo esc_attr($button_class); ?>" type="button" disabled><?php echo esc_html($button_text); ?></button>
                <?php else: ?>
                    <a class="<?php echo esc_attr($button_class); ?>" href="<?php echo esc_url($checkout_url); ?>"><?php echo esc_html($button_text); ?></a>
                <?php endif; ?>
            </div>
            <?php
        }
    }

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

        $pricing_heading = __('Choose your Pro license', 'titanium-advanced-user-roles');
        $pricing_intro = __('Every license unlocks the same Pro features. Pick only the number of websites you need.', 'titanium-advanced-user-roles');
        $pro_active = false;
        $current_license_marker = $this->get_current_license_marker();

        $this->render_shell_start(__('Titanium User Roles Pro', 'titanium-advanced-user-roles'), __('Upgrade, license and Pro feature overview.', 'titanium-advanced-user-roles'));
        ?>
        <div class="tiaur-pro-page">
            <div class="tiaur-card tiaur-plan-compare-card tiaur-pro-compare-card">
                <div class="tiaur-compare-plan-label"><?php esc_html_e('Compare plans', 'titanium-advanced-user-roles'); ?></div>
                <table class="tiaur-plan-compare-table">
                    <thead>
                        <tr>
                            <th><?php esc_html_e('Feature', 'titanium-advanced-user-roles'); ?></th>
                            <th><?php esc_html_e('Free', 'titanium-advanced-user-roles'); ?></th>
                            <th><?php esc_html_e('Pro', 'titanium-advanced-user-roles'); ?></th>
                        </tr>
                    </thead>
                    <tbody>
                        <?php foreach ($this->premium_feature_rows() as $feature_row): ?>
                            <tr>
                                <td><?php echo esc_html($feature_row['label']); ?><?php if (!empty($feature_row['detail'])): ?><span class="tiaur-feature-detail"><?php echo wp_kses_post($feature_row['detail']); ?></span><?php endif; ?></td>
                                <td><?php echo $feature_row['free'] ? '<span class="tiaur-plan-check">✓</span>' : '<span class="tiaur-plan-cross">×</span>'; ?></td>
                                <td><span class="tiaur-plan-check">✓</span></td>
                            </tr>
                        <?php endforeach; ?>
                    </tbody>
                </table>
            </div>

            <div class="tiaur-pro-section tiaur-pricing-section">
                <div class="tiaur-pro-section-header">
                    <span class="tiaur-pro-kicker"><?php esc_html_e('License & Plans', 'titanium-advanced-user-roles'); ?></span>
                    <h2><?php echo esc_html($pricing_heading); ?></h2>
                    <p><?php echo esc_html($pricing_intro); ?></p>
                </div>
                <div
                    id="tiaur-dynamic-pricing"
                    class="tiaur-pricing-grid tiaur-pricing-grid--dynamic"
                    data-nonce="<?php echo esc_attr(wp_create_nonce('tiaur_pricing_nonce')); ?>"
                    data-button="<?php esc_attr_e('UPGRADE NOW', 'titanium-advanced-user-roles'); ?>"
                    data-error="<?php esc_attr_e('Prices could not be downloaded. Secure checkout will show the current price.', 'titanium-advanced-user-roles'); ?>"
                    data-current-licenses="<?php echo esc_attr($current_license_marker['licenses']); ?>"
                >
                    <?php $this->render_pricing_plan_placeholders($current_license_marker, $pro_active); ?>
                </div>
            </div>

            <div class="tiaur-pro-placeholder-grid">
                <?php $this->render_locked_pro_feature_card(__('Advanced AND / OR content rules', 'titanium-advanced-user-roles'), __('Build complex access rules with grouped conditions instead of custom snippets.', 'titanium-advanced-user-roles')); ?>
                <?php $this->render_locked_pro_feature_card(__('Role audit log', 'titanium-advanced-user-roles'), __('Track important role and capability changes with history and restore context.', 'titanium-advanced-user-roles')); ?>
                <?php $this->render_locked_pro_feature_card(__('Unsafe role scanner', 'titanium-advanced-user-roles'), __('Detect risky non-admin roles, users without roles and conflicting role combinations.', 'titanium-advanced-user-roles')); ?>
            </div>
        </div>
        <?php
        $this->render_shell_end();
    }

    private function locked_pro_scanner_preview_items() {
        return array(
            array(
                'title' => __('Unsafe non-admin roles', 'titanium-advanced-user-roles'),
                'note'  => __('Pro can scan non-admin roles for sensitive capabilities before they become a security risk.', 'titanium-advanced-user-roles'),
            ),
            array(
                'title' => __('Users without roles', 'titanium-advanced-user-roles'),
                'note'  => __('Pro can help find user accounts that no longer have any assigned WordPress role.', 'titanium-advanced-user-roles'),
            ),
            array(
                'title' => __('Conflicting role combinations', 'titanium-advanced-user-roles'),
                'note'  => __('Pro can compare users against your Smart Rules and highlight role combinations that need review.', 'titanium-advanced-user-roles'),
            ),
            array(
                'title' => __('User-specific capabilities', 'titanium-advanced-user-roles'),
                'note'  => __('Pro can report direct capabilities assigned to individual users outside normal role permissions.', 'titanium-advanced-user-roles'),
            ),
        );
    }

    private function render_locked_pro_scanners_preview() {
        echo '<div id="tiaur-pro-scanners" class="tiaur-pro-section tiaur-pro-scanner-section"><div class="tiaur-pro-section-header compact"><span class="tiaur-pro-kicker">' . esc_html__('Pro safety scans', 'titanium-advanced-user-roles') . '</span><h2>' . esc_html__('Permission safety scanners', 'titanium-advanced-user-roles') . '</h2><p>' . esc_html__('Available in Titanium User Roles Pro. The WordPress.org Free build shows this preview only; the scanner engine is included in the separate Pro plugin.', 'titanium-advanced-user-roles') . '</p></div><div class="tiaur-grid two tiaur-pro-scan-grid">';
        foreach ($this->locked_pro_scanner_preview_items() as $item) {
            echo '<div class="tiaur-card tiaur-pro-scan-card tiaur-pro-placeholder-card tiaur-pro-scan-card--locked">';
            echo '<div class="tiaur-card-head tiaur-pro-scanner-head"><div><h2>' . esc_html($item['title']) . '</h2><p class="tiaur-muted tiaur-pro-card-note">' . esc_html($item['note']) . '</p></div><span class="tiaur-pro-badge">' . esc_html__('Pro', 'titanium-advanced-user-roles') . '</span></div>';
            echo '<p class="tiaur-note">' . esc_html__('Preview only in Free. Install the Pro plugin to run this scanner.', 'titanium-advanced-user-roles') . '</p>';
            echo '</div>';
        }
        echo '</div></div>';
    }

    private function pro_tool_packages() {
        return array(
            array(
                'id' => 'advanced-user-control',
                'title' => __('Advanced User Control', 'titanium-advanced-user-roles'),
                'summary' => __('Handle user-level exceptions without changing whole roles.', 'titanium-advanced-user-roles'),
                'items' => array(
                    __('Primary Roles and role order', 'titanium-advanced-user-roles'),
                    __('User-specific capabilities', 'titanium-advanced-user-roles'),
                    __('Explicit deny capabilities', 'titanium-advanced-user-roles'),
                    __('Permission explainer', 'titanium-advanced-user-roles'),
                    __('User-specific role restrictions', 'titanium-advanced-user-roles'),
                    __('Profile field hide/lock', 'titanium-advanced-user-roles'),
                    __('Per-user admin restrictions', 'titanium-advanced-user-roles'),
                ),
            ),
            array(
                'id' => 'advanced-content-rules',
                'title' => __('Advanced Content Rules', 'titanium-advanced-user-roles'),
                'summary' => __('Build grouped access logic for serious content control.', 'titanium-advanced-user-roles'),
                'items' => array(
                    __('AND/OR rule builder', 'titanium-advanced-user-roles'),
                    __('Role is / role is not', 'titanium-advanced-user-roles'),
                    __('Logged-in / logged-out rules', 'titanium-advanced-user-roles'),
                    __('User-specific access', 'titanium-advanced-user-roles'),
                    __('Category and taxonomy rules', 'titanium-advanced-user-roles'),
                    __('Custom post type rules', 'titanium-advanced-user-roles'),
                    __('Global rules and per-content overrides', 'titanium-advanced-user-roles'),
                    __('Redirect and list behavior rules', 'titanium-advanced-user-roles'),
                ),
            ),
            array(
                'id' => 'advanced-admin-area-control',
                'title' => __('Advanced Admin Area Control', 'titanium-advanced-user-roles'),
                'summary' => __('Control the WordPress admin area for roles, users and clients.', 'titanium-advanced-user-roles'),
                'items' => array(
                    __('Admin submenu restrictions', 'titanium-advanced-user-roles'),
                    __('Admin menu rename/reorder/icons', 'titanium-advanced-user-roles'),
                    __('Admin menu groups', 'titanium-advanced-user-roles'),
                    __('Dashboard widget hide', 'titanium-advanced-user-roles'),
                    __('Metabox hide', 'titanium-advanced-user-roles'),
                    __('Block editor panel hide', 'titanium-advanced-user-roles'),
                    __('Toolbar item hide', 'titanium-advanced-user-roles'),
                    __('Direct URL block and client mode', 'titanium-advanced-user-roles'),
                ),
            ),
            array(
                'id' => 'audit-safety-scanner',
                'title' => __('Audit, Safety & Scanner', 'titanium-advanced-user-roles'),
                'summary' => __('Know who changed permissions, when, and how to roll back.', 'titanium-advanced-user-roles'),
                'items' => array(
                    __('Role audit log', 'titanium-advanced-user-roles'),
                    __('Who changed what', 'titanium-advanced-user-roles'),
                    __('Restore previous role version', 'titanium-advanced-user-roles'),
                    __('Compare snapshots', 'titanium-advanced-user-roles'),
                    __('External role change detection', 'titanium-advanced-user-roles'),
                    __('Administrator capability alerts', 'titanium-advanced-user-roles'),
                    __('Dangerous capability scanner', 'titanium-advanced-user-roles'),
                    __('Scheduled scans', 'titanium-advanced-user-roles'),
                ),
            ),
            array(
                'id' => 'migration-tools',
                'title' => __('Import, Export & Migration', 'titanium-advanced-user-roles'),
                'summary' => __('Move role and user-access setups safely between sites.', 'titanium-advanced-user-roles'),
                'items' => array(
                    __('Full user data export/import without passwords', 'titanium-advanced-user-roles'),
                    __('User role assignments export/import', 'titanium-advanced-user-roles'),
                    __('Filtered user export', 'titanium-advanced-user-roles'),
                    __('Import preview and dry run', 'titanium-advanced-user-roles'),
                    __('Rollback import', 'titanium-advanced-user-roles'),
                    __('Role migration tools', 'titanium-advanced-user-roles'),
                    __('Multisite role sync', 'titanium-advanced-user-roles'),
                ),
            ),
        );
    }

    private function render_pro_package_card($package) {
        echo '<div id="tiaur-pro-package-' . esc_attr($package['id']) . '" class="tiaur-card tiaur-pro-package-card">';
        echo '<div class="tiaur-card-head"><div><span class="tiaur-pro-badge">' . esc_html__('Pro package', 'titanium-advanced-user-roles') . '</span><h2>' . esc_html($package['title']) . '</h2></div><span class="tiaur-pro-package-status">' . esc_html__('Planned Pro module', 'titanium-advanced-user-roles') . '</span></div>';
        echo '<p class="tiaur-pro-package-summary">' . esc_html($package['summary']) . '</p>';
        echo '<div class="tiaur-pro-feature-chip-grid">';
        foreach ($package['items'] as $item) {
            echo '<span class="tiaur-pro-feature-chip">' . esc_html($item) . '</span>';
        }
        echo '</div>';
        echo '</div>';
    }

    private function render_pro_metric_card($label, $value, $sub_label) {
        $value = (int) $value;
        $status_class = $value > 0 ? 'has-warning' : 'is-clean';
        echo '<div class="tiaur-card tiaur-pro-metric-card ' . esc_attr($status_class) . '">';
        echo '<span>' . esc_html($label) . '</span>';
        echo '<strong>' . esc_html(number_format_i18n($value)) . '</strong>';
        echo '<small>' . esc_html($sub_label) . '</small>';
        echo '</div>';
    }

    private function render_pro_package_card_compact($package) {
        $items = isset($package['items']) && is_array($package['items']) ? array_slice($package['items'], 0, 4) : array();
        echo '<div id="tiaur-pro-package-' . esc_attr($package['id']) . '" class="tiaur-card tiaur-pro-package-card compact">';
        echo '<div class="tiaur-card-head"><div><span class="tiaur-pro-badge">' . esc_html__('Pro', 'titanium-advanced-user-roles') . '</span><h2>' . esc_html($package['title']) . '</h2></div></div>';
        echo '<p class="tiaur-pro-package-summary">' . esc_html($package['summary']) . '</p>';
        echo '<div class="tiaur-pro-feature-chip-grid compact">';
        foreach ($items as $item) {
            echo '<span class="tiaur-pro-feature-chip">' . esc_html($item) . '</span>';
        }
        echo '</div>';
        echo '</div>';
    }

    private function render_locked_pro_tools_preview() {
        $this->render_shell_start(__('Pro Tools', 'titanium-advanced-user-roles'), __('Locked Pro control center preview.', 'titanium-advanced-user-roles'));
        echo '<div class="tiaur-pro-page tiaur-pro-tools-page tiaur-pro-tools-page--locked">';
        echo '<div class="tiaur-pro-tools-header tiaur-card tiaur-pro-placeholder-card">';
        echo '<div><span class="tiaur-pro-kicker">' . esc_html__('Titanium User Roles Pro', 'titanium-advanced-user-roles') . '</span><h2>' . esc_html__('Pro control center', 'titanium-advanced-user-roles') . '</h2><p>' . esc_html__('This page shows a Pro preview. Install the separate Pro plugin to activate the extra tools, scanners and restrictions.', 'titanium-advanced-user-roles') . '</p></div>';
        echo '<span class="tiaur-pro-license-pill">' . esc_html__('Locked', 'titanium-advanced-user-roles') . '</span>';
        echo '</div>';

        echo '<div class="tiaur-card tiaur-module-header-card tiaur-pro-app-passwords-switch tiaur-pro-placeholder-card"><div><h2>' . esc_html__('Disable Application Passwords', 'titanium-advanced-user-roles') . '</h2><p>' . esc_html__('Turn off WordPress Application Passwords completely and hide the profile section for everyone.', 'titanium-advanced-user-roles') . '</p></div><div class="tiaur-switch-wrap"><button type="button" class="tiaur-switch" disabled><span class="tiaur-switch-track"><span class="tiaur-switch-thumb"></span></span><span class="tiaur-switch-label">' . esc_html__('Available in Pro', 'titanium-advanced-user-roles') . '</span></button></div></div>';

        echo '<div class="tiaur-grid four tiaur-pro-metric-grid">';
        $this->render_pro_metric_card(__('Risky roles', 'titanium-advanced-user-roles'), 0, __('non-admin roles', 'titanium-advanced-user-roles'));
        $this->render_pro_metric_card(__('Users without role', 'titanium-advanced-user-roles'), 0, __('users', 'titanium-advanced-user-roles'));
        $this->render_pro_metric_card(__('Role conflicts', 'titanium-advanced-user-roles'), 0, __('users', 'titanium-advanced-user-roles'));
        $this->render_pro_metric_card(__('Direct user caps', 'titanium-advanced-user-roles'), 0, __('users', 'titanium-advanced-user-roles'));
        echo '</div>';

        $this->render_locked_pro_scanners_preview();

        echo '<div class="tiaur-pro-section tiaur-pro-user-control-section" id="tiaur-pro-user-control"><div class="tiaur-pro-section-header compact"><span class="tiaur-pro-kicker">' . esc_html__('Advanced User Control', 'titanium-advanced-user-roles') . '</span><h2>' . esc_html__('User-specific permissions', 'titanium-advanced-user-roles') . '</h2><p>' . esc_html__('Grant direct user capabilities, hard deny capabilities and personal admin restrictions.', 'titanium-advanced-user-roles') . '</p></div><div class="tiaur-card tiaur-pro-compact-card"><label><strong>' . esc_html__('Select user', 'titanium-advanced-user-roles') . '</strong><select class="tiaur-select" disabled><option>' . esc_html__('Choose a user', 'titanium-advanced-user-roles') . '</option></select></label><button class="tiaur-button primary compact" type="button" disabled>' . esc_html__('Open user', 'titanium-advanced-user-roles') . '</button></div><div class="tiaur-grid two"><div class="tiaur-card"><span class="tiaur-pro-kicker">' . esc_html__('Permission explainer', 'titanium-advanced-user-roles') . '</span><h3>' . esc_html__('Why does this user have access?', 'titanium-advanced-user-roles') . '</h3><p><strong>' . esc_html__('Roles:', 'titanium-advanced-user-roles') . '</strong> —</p><p><strong>' . esc_html__('Direct user capabilities:', 'titanium-advanced-user-roles') . '</strong> —</p><p><strong>' . esc_html__('Explicit deny capabilities:', 'titanium-advanced-user-roles') . '</strong> —</p></div><div class="tiaur-card"><span class="tiaur-pro-kicker">' . esc_html__('Per-user restrictions', 'titanium-advanced-user-roles') . '</span><h3>' . esc_html__('User-specific restrictions', 'titanium-advanced-user-roles') . '</h3><label class="tiaur-check-line"><input type="checkbox" disabled> <span>' . esc_html__('Block dashboard/admin area for this user', 'titanium-advanced-user-roles') . '</span></label><label class="tiaur-check-line"><input type="checkbox" disabled> <span>' . esc_html__('Hide admin bar for this user', 'titanium-advanced-user-roles') . '</span></label><label class="tiaur-check-line"><input type="checkbox" disabled> <span>' . esc_html__('Lock profile fields visually for this user', 'titanium-advanced-user-roles') . '</span></label></div></div><details class="tiaur-card tiaur-pro-details" open><summary><strong>' . esc_html__('User-specific capabilities', 'titanium-advanced-user-roles') . '</strong><span class="tiaur-details-chevron" aria-hidden="true">▾</span></summary><p class="tiaur-muted">' . esc_html__('Grant direct capabilities to this user only.', 'titanium-advanced-user-roles') . '</p><div class="tiaur-capability-list compact"><label><input type="checkbox" disabled> <span>edit_posts</span></label><label><input type="checkbox" disabled> <span>upload_files</span></label><label><input type="checkbox" disabled> <span>custom_example</span></label></div></details><details class="tiaur-card tiaur-pro-details"><summary><strong>' . esc_html__('Explicit deny capabilities', 'titanium-advanced-user-roles') . '</strong><span class="tiaur-details-chevron" aria-hidden="true">▾</span></summary><p class="tiaur-muted">' . esc_html__('Force selected capabilities to false for this user, even if a role gives them.', 'titanium-advanced-user-roles') . '</p><div class="tiaur-capability-list compact"><label><input type="checkbox" disabled> <span>manage_options</span></label><label><input type="checkbox" disabled> <span>delete_users</span></label></div></details></div>';

        echo '<div class="tiaur-pro-section" id="tiaur-pro-admin-ui-rules"><div class="tiaur-pro-section-header compact"><span class="tiaur-pro-kicker">' . esc_html__('Admin UI Rules', 'titanium-advanced-user-roles') . '</span><h2>' . esc_html__('Admin and editor restrictions', 'titanium-advanced-user-roles') . '</h2><p>' . esc_html__('Control dashboard widgets, notices, editor panels, metaboxes, profile screens and dangerous admin screens by role.', 'titanium-advanced-user-roles') . '</p></div><div class="tiaur-pro-admin-ui-grid">';
        $locked_admin_cards = array(__('Hide dashboard widgets', 'titanium-advanced-user-roles'), __('Hide admin notices', 'titanium-advanced-user-roles'), __('Block Plugin File Editor', 'titanium-advanced-user-roles'), __('Block Theme File Editor', 'titanium-advanced-user-roles'), __('Block Site Editor', 'titanium-advanced-user-roles'), __('Hide post metaboxes', 'titanium-advanced-user-roles'), __('Hide block editor panels', 'titanium-advanced-user-roles'), __('Detailed per-user restrictions', 'titanium-advanced-user-roles'));
        foreach ($locked_admin_cards as $locked_admin_card) {
            echo '<div class="tiaur-card tiaur-pro-compact-card"><h3>' . esc_html($locked_admin_card) . '</h3><p class="tiaur-muted tiaur-pro-card-note">' . esc_html__('Role-based Pro restriction preview.', 'titanium-advanced-user-roles') . '</p><div class="tiaur-pro-role-checks"><label><input type="checkbox" disabled> <span>Administrator</span></label><label><input type="checkbox" disabled> <span>Editor</span></label><label><input type="checkbox" disabled> <span>Subscriber</span></label></div></div>';
        }
        echo '</div></div>';

        echo '<div class="tiaur-pro-profile-rule-panel"><div class="tiaur-pro-section-header compact"><span class="tiaur-pro-kicker">' . esc_html__('Profile Screen Control', 'titanium-advanced-user-roles') . '</span><h2>' . esc_html__('Profile hide / lock rules', 'titanium-advanced-user-roles') . '</h2><p>' . esc_html__('Create profile screen rules with conditions, action and selected profile fields.', 'titanium-advanced-user-roles') . '</p></div><div class="tiaur-card tiaur-profile-rules-list"><div class="tiaur-profile-rules-header"><h3>' . esc_html__('Existing profile rules', 'titanium-advanced-user-roles') . '</h3><button type="button" class="tiaur-button primary" disabled>+ ' . esc_html__('Add profile rule', 'titanium-advanced-user-roles') . '</button></div><table class="widefat striped tiaur-table"><thead><tr><th>' . esc_html__('Rule', 'titanium-advanced-user-roles') . '</th><th>' . esc_html__('Summary', 'titanium-advanced-user-roles') . '</th><th>' . esc_html__('Status', 'titanium-advanced-user-roles') . '</th></tr></thead><tbody><tr><td><strong>' . esc_html__('Profile screen rule', 'titanium-advanced-user-roles') . '</strong></td><td>' . esc_html__('Hide / Lock selected profile fields by role', 'titanium-advanced-user-roles') . '</td><td>' . esc_html__('Locked', 'titanium-advanced-user-roles') . '</td></tr></tbody></table></div></div>';

        echo '<div class="tiaur-pro-section tiaur-admin-capability-review tiaur-pro-placeholder-card" id="tiaur-pro-admin-capability-review"><div class="tiaur-pro-section-header compact"><span class="tiaur-pro-kicker">' . esc_html__('Administrator Safety', 'titanium-advanced-user-roles') . '</span><h2>' . esc_html__('Administrator capability review', 'titanium-advanced-user-roles') . '</h2><p>' . esc_html__('Review Administrator capability changes, reset the safety baseline and remove stale plugin capabilities. Pro preview in Free.', 'titanium-advanced-user-roles') . '</p></div><div class="tiaur-grid two tiaur-admin-capability-grid"><div class="tiaur-card tiaur-admin-capability-status-card"><h3>' . esc_html__('Current status', 'titanium-advanced-user-roles') . '</h3><p class="tiaur-admin-capability-alert-text">' . esc_html__('Administrator capability alert review is available in Pro.', 'titanium-advanced-user-roles') . '</p><div class="tiaur-admin-capability-actions"><span class="tiaur-button compact tiaur-button-disabled" aria-disabled="true">' . esc_html__('Available in Pro', 'titanium-advanced-user-roles') . '</span><span class="tiaur-button compact tiaur-button-disabled" aria-disabled="true">' . esc_html__('Re-check now', 'titanium-advanced-user-roles') . '</span></div></div><div class="tiaur-card tiaur-admin-capability-status-card"><h3>' . esc_html__('Custom / plugin capabilities', 'titanium-advanced-user-roles') . '</h3><p class="tiaur-muted">' . esc_html__('Pro can show non-core capabilities left behind by deleted plugins and remove selected safe items.', 'titanium-advanced-user-roles') . '</p></div></div></div>';

        echo '<details class="tiaur-pro-section tiaur-pro-details tiaur-custom-capability-manager tiaur-pro-placeholder-card" id="tiaur-pro-custom-capabilities"><summary class="tiaur-pro-section-header compact tiaur-custom-capability-summary"><span class="tiaur-pro-kicker">' . esc_html__('Custom Capabilities', 'titanium-advanced-user-roles') . '</span><h2>' . esc_html__('Custom capability manager', 'titanium-advanced-user-roles') . '</h2><p>' . esc_html__('Create custom capabilities and delete unused or stale plugin capabilities safely. Pro preview, collapsed by default.', 'titanium-advanced-user-roles') . '</p><span class="tiaur-details-chevron" aria-hidden="true">▾</span></summary><div class="tiaur-custom-capability-body"><div class="tiaur-grid two"><div class="tiaur-card tiaur-pro-compact-card"><h3>' . esc_html__('Create capability', 'titanium-advanced-user-roles') . '</h3><p class="tiaur-muted tiaur-pro-card-note">' . esc_html__('Add a custom capability so it appears in role and user permission tools.', 'titanium-advanced-user-roles') . '</p><input type="text" class="regular-text" disabled placeholder="custom_capability_name"><div class="tiaur-actions"><button class="tiaur-button primary" type="button" disabled>' . esc_html__('Create capability', 'titanium-advanced-user-roles') . '</button></div></div><div class="tiaur-card tiaur-pro-compact-card"><h3>' . esc_html__('Delete capability', 'titanium-advanced-user-roles') . '</h3><p class="tiaur-muted tiaur-pro-card-note">' . esc_html__('Delete is available only when a capability is not assigned directly to any user.', 'titanium-advanced-user-roles') . '</p><table class="widefat striped tiaur-table"><thead><tr><th>' . esc_html__('Capability', 'titanium-advanced-user-roles') . '</th><th>' . esc_html__('Status', 'titanium-advanced-user-roles') . '</th><th>' . esc_html__('Action', 'titanium-advanced-user-roles') . '</th></tr></thead><tbody><tr><td><code>custom_example</code></td><td>' . esc_html__('Preview only', 'titanium-advanced-user-roles') . '</td><td><button class="tiaur-button compact" disabled>' . esc_html__('Delete', 'titanium-advanced-user-roles') . '</button></td></tr></tbody></table></div></div></div></details>';

        echo '<div class="tiaur-pro-section" id="tiaur-pro-block-rules"><div class="tiaur-pro-section-header compact"><span class="tiaur-pro-kicker">' . esc_html__('Block Visibility', 'titanium-advanced-user-roles') . '</span><h2>' . esc_html__('Gutenberg block visibility rules', 'titanium-advanced-user-roles') . '</h2><p>' . esc_html__('Hide selected Gutenberg block types for selected roles on the frontend.', 'titanium-advanced-user-roles') . '</p></div><div class="tiaur-card tiaur-block-rules-card"><div class="tiaur-block-rules-layout"><div class="tiaur-block-rule-main"><h3>' . esc_html__('1. Block types to hide', 'titanium-advanced-user-roles') . '</h3><textarea class="tiaur-textarea" rows="5" disabled placeholder="core/group
core/buttons"></textarea></div><div class="tiaur-block-rule-side"><div class="tiaur-block-rule-box"><h3>' . esc_html__('2. Apply to roles', 'titanium-advanced-user-roles') . '</h3><div class="tiaur-pro-role-checks"><label><input type="checkbox" disabled> <span>Administrator</span></label><label><input type="checkbox" disabled> <span>Editor</span></label><label><input type="checkbox" disabled> <span>Subscriber</span></label></div></div></div></div></div></div>';

        echo '<div class="tiaur-pro-section tiaur-pro-multisite-section tiaur-pro-placeholder-card" id="tiaur-pro-multisite-sync"><div class="tiaur-pro-section-header compact"><span class="tiaur-pro-kicker">' . esc_html__('Multisite', 'titanium-advanced-user-roles') . '</span><h2>' . esc_html__('Multisite role sync', 'titanium-advanced-user-roles') . '</h2><p>' . esc_html__('Copy this site’s roles and capabilities to every other site in a multisite network. Pro preview in Free.', 'titanium-advanced-user-roles') . '</p></div><div class="tiaur-card tiaur-pro-multisite-card"><div class="tiaur-pro-multisite-copy"><h3>' . esc_html__('Network role sync', 'titanium-advanced-user-roles') . '</h3><p class="tiaur-muted">' . esc_html__('Keep role names and capabilities consistent across every site in the network.', 'titanium-advanced-user-roles') . '</p></div><button class="tiaur-button secondary" type="button" disabled>' . esc_html__('Sync roles across multisite', 'titanium-advanced-user-roles') . '</button></div></div>';

        echo '<div class="tiaur-pro-section tiaur-pro-audit-section" id="tiaur-pro-audit"><div class="tiaur-pro-section-header compact"><span class="tiaur-pro-kicker">' . esc_html__('Audit', 'titanium-advanced-user-roles') . '</span><h2>' . esc_html__('Pro audit log', 'titanium-advanced-user-roles') . '</h2><p>' . esc_html__('Changes made by Pro modules are logged here.', 'titanium-advanced-user-roles') . '</p></div><div class="tiaur-card"><table class="widefat striped tiaur-table"><thead><tr><th>' . esc_html__('Time', 'titanium-advanced-user-roles') . '</th><th>' . esc_html__('Admin', 'titanium-advanced-user-roles') . '</th><th>' . esc_html__('Action', 'titanium-advanced-user-roles') . '</th><th>' . esc_html__('Context', 'titanium-advanced-user-roles') . '</th></tr></thead><tbody><tr><td colspan="4">' . esc_html__('Pro preview. Install the Pro plugin to enable the audit log.', 'titanium-advanced-user-roles') . '</td></tr></tbody></table></div></div>';

        echo '</div>';
        $this->render_shell_end();
    }

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

        $this->render_locked_pro_tools_preview();
    }

    public function render_settings_page() {
        $settings = $this->plugin_settings();
        $delete_enabled = $settings['delete_data_on_uninstall'] === '1';
        $switch_class = $delete_enabled ? 'tiaur-switch is-on is-saved' : 'tiaur-switch';
        $enabled_attr = $delete_enabled ? '1' : '0';
        $aria_pressed = $delete_enabled ? 'true' : 'false';
        $switch_label = $delete_enabled ? __('Enabled', 'titanium-advanced-user-roles') : __('Disabled', 'titanium-advanced-user-roles');
        $beta_switch_class = 'tiaur-switch tiaur-switch-dummy';
        $beta_switch_label = __('Disabled', 'titanium-advanced-user-roles');
        $this->render_shell_start(__('Settings', 'titanium-advanced-user-roles'), __('Plugin-level settings for cleanup.', 'titanium-advanced-user-roles'));
        ?>
        <div class="tiaur-settings-page-stack">
            <div class="tiaur-card tiaur-settings-panel tiaur-color-settings-card">
                <div class="tiaur-settings-panel-copy">
                    <h2><?php esc_html_e('Color theme', 'titanium-advanced-user-roles'); ?></h2>
                    <p><?php esc_html_e('Choose the admin color style used by this plugin.', 'titanium-advanced-user-roles'); ?></p>
                </div>
                <form method="post" class="tiaur-color-scheme-form">
                    <?php wp_nonce_field(self::NONCE_ACTION); ?>
                    <input type="hidden" name="tiaur_action" value="save_color_scheme" />
                    <?php $current_scheme = $settings['color_scheme']; ?>
                    <div class="tiaur-color-grid">
                        <?php foreach ($this->color_schemes() as $scheme_key => $scheme_label): ?>
                            <label class="tiaur-color-option tiaur-theme-<?php echo esc_attr($scheme_key); ?> <?php echo $current_scheme === $scheme_key ? 'is-selected' : ''; ?>">
                                <input type="radio" name="color_scheme" value="<?php echo esc_attr($scheme_key); ?>" <?php checked($current_scheme, $scheme_key); ?> />
                                <span class="tiaur-color-swatch"></span>
                                <span><?php echo esc_html($scheme_label); ?></span>
                            </label>
                        <?php endforeach; ?>
                    </div>
                    <div class="tiaur-actions"><button class="tiaur-button primary compact" type="submit"><?php esc_html_e('Save color theme', 'titanium-advanced-user-roles'); ?></button></div>
                </form>
            </div>


            <div class="tiaur-card tiaur-settings-panel tiaur-beta-updates-card">
                <div class="tiaur-settings-panel-copy">
                    <span class="tiaur-mini-kicker"><?php esc_html_e('Beta updates', 'titanium-advanced-user-roles'); ?></span>
                    <h2><?php esc_html_e('Join the beta updates program', 'titanium-advanced-user-roles'); ?></h2>
                    <p><?php esc_html_e('Free beta updates are not delivered automatically through WordPress.org. Pro users can join beta updates through Freemius.', 'titanium-advanced-user-roles'); ?></p>
                </div>
                <div class="tiaur-toggle-wrap tiaur-settings-toggle-wrap">
                    <button type="button" class="<?php echo esc_attr($beta_switch_class); ?>" disabled="disabled" aria-disabled="true" aria-pressed="false">
                        <span class="tiaur-switch-track"><span class="tiaur-switch-thumb"></span></span>
                        <span class="tiaur-switch-label"><?php echo esc_html($beta_switch_label); ?></span>
                    </button>
                    <span class="tiaur-switch-status"><?php esc_html_e('Pro only', 'titanium-advanced-user-roles'); ?></span>
                </div>
            </div>

            <div class="tiaur-card tiaur-settings-panel tiaur-primary-roles-settings-card tiaur-pro-placeholder-card">
                <div class="tiaur-settings-panel-copy">
                    <span class="tiaur-mini-kicker"><?php esc_html_e('Primary Roles', 'titanium-advanced-user-roles'); ?></span>
                    <h2><?php esc_html_e('Primary Roles & role order', 'titanium-advanced-user-roles'); ?></h2>
                    <p><?php esc_html_e('Enable a Pro-only Primary Roles system only when selected roles must be treated as mutually exclusive membership-style roles. When disabled, role editing stays as simple checkboxes.', 'titanium-advanced-user-roles'); ?></p>
                    <p class="tiaur-note tiaur-settings-note"><?php esc_html_e('Role order uses the saved WordPress role order, not alphabetical order. Administrator is protected and cannot be selected here. This is a Pro preview.', 'titanium-advanced-user-roles'); ?></p>
                </div>
                <div class="tiaur-toggle-wrap tiaur-settings-toggle-wrap tiaur-primary-roles-master-toggle-wrap">
                    <button type="button" class="tiaur-switch is-disabled" disabled="disabled" aria-disabled="true" data-enabled="0" aria-pressed="false">
                        <span class="tiaur-switch-track"><span class="tiaur-switch-thumb"></span></span>
                        <span class="tiaur-switch-label"><?php esc_html_e('Disabled', 'titanium-advanced-user-roles'); ?></span>
                    </button>
                    <span class="tiaur-switch-status"><?php esc_html_e('Pro only', 'titanium-advanced-user-roles'); ?></span>
                </div>
                <div class="tiaur-setting-field-stack tiaur-primary-roles-dependent is-disabled">
                    <label><strong><?php esc_html_e('Primary Roles', 'titanium-advanced-user-roles'); ?></strong></label>
                    <p class="tiaur-note tiaur-primary-disabled-note"><?php esc_html_e('Upgrade to Pro and enable the Primary Roles system first to edit this list.', 'titanium-advanced-user-roles'); ?></p>
                    <select class="tiaur-select" disabled="disabled" aria-disabled="true">
                        <option><?php esc_html_e('Activate Pro license to configure', 'titanium-advanced-user-roles'); ?></option>
                    </select>
                    <label class="tiaur-check-line tiaur-primary-role-order-line">
                        <input type="checkbox" disabled="disabled" aria-disabled="true" />
                        <span><?php esc_html_e('Keep user roles saved in WordPress role order whenever a user profile is saved.', 'titanium-advanced-user-roles'); ?></span>
                    </label>
                    <button class="tiaur-button ghost compact" type="button" disabled="disabled" aria-disabled="true"><?php esc_html_e('Available in Pro', 'titanium-advanced-user-roles'); ?></button>
                </div>
            </div>

            <div class="tiaur-card tiaur-settings-panel tiaur-danger-aware-card">
                <div class="tiaur-settings-panel-copy">
                    <span class="tiaur-mini-kicker"><?php esc_html_e('Cleanup', 'titanium-advanced-user-roles'); ?></span>
                    <h2><?php esc_html_e('Delete plugin data on uninstall', 'titanium-advanced-user-roles'); ?></h2>
                    <p><?php esc_html_e('When enabled, uninstalling the plugin deletes Titanium User Roles settings, Smart Rules, safety backups and Content Control metadata.', 'titanium-advanced-user-roles'); ?></p>
                    <p class="tiaur-note tiaur-settings-note"><?php esc_html_e('Role and capability changes are WordPress data and are not automatically reverted. Use Safety Backups or Import / Export if you need to restore roles.', 'titanium-advanced-user-roles'); ?></p>
                </div>
                <div class="tiaur-toggle-wrap tiaur-settings-toggle-wrap">
                    <button type="button" class="<?php echo esc_attr($switch_class); ?>" data-tiaur-toggle="delete-data" data-enabled="<?php echo esc_attr($enabled_attr); ?>" aria-pressed="<?php echo esc_attr($aria_pressed); ?>">
                        <span class="tiaur-switch-track"><span class="tiaur-switch-thumb"></span></span>
                        <span class="tiaur-switch-label"><?php echo esc_html($switch_label); ?></span>
                    </button>
                    <span class="tiaur-switch-status"><?php esc_html_e('Saved', 'titanium-advanced-user-roles'); ?></span>
                </div>
            </div>
        </div>
        <?php
        $this->render_shell_end();
    }

}


endif;

if (!function_exists('tiaur')) {
    /**
     * Returns the bundled Titanium User Roles core instance.
     *
     * @return TIAUR_Advanced_User_Roles
     */
    function tiaur() {
        return TIAUR_Advanced_User_Roles::instance();
    }
}

register_activation_hook(__FILE__, array('TIAUR_Advanced_User_Roles', 'activate'));

add_action('init', static function () {
    if (!class_exists('TIAUR_Advanced_User_Roles')) {
        return;
    }

    TIAUR_Advanced_User_Roles::instance();

}, 1);
