<?php
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * OpsGate Admin:
 * - Top-level OpsGate menu in wp-admin.
 * - Overview tab: badges, telemetry, inbound token, export.
 * - Services tab: per-service enabled + plan (opsgate_services).
 * - Schedules tab: per-service schedules (opsgate_schedules).
 * - Pricing tab (Day-7): plan display + Stripe Test Mode configuration + plan mapping (UI + safe sanitation only).
 * - Identity (Day-8):
 *   - email capture, site label, stable site id, reserved site token (options only)
 *   - 8.2 MCP payload visibility single log line (safe, no tokens)
 *   - 8.3 Site linking / token storage flow (local-first: proof generated from stored site token)
 *   - 8.4 Confirmation workflow (stored proof + verifier)
 * - Licensing Engine (Day-9):
 *   - License schema definition (JSON, local-only)
 *   - License loader (safe parsing, error handling)
 *   - License validator (site binding, expiry check)
 *   - Admin UI status panel (read-only)
 *   - Import/validate actions (no enforcement)
 */
class OpsGate_Admin {
    /**
     * WordPress admin hook suffixes that belong to the OpsGate dashboard.
     *
     * @var array<int,string>
     */
    private static $admin_page_hooks = array();

    /**
     * Bootstrap admin hooks.
     *
     * @return void
     */
    public static function init() {
        // Bootstrap defaults safely (create missing only; never overwrite user values).
        add_action( 'admin_init', array( __CLASS__, 'bootstrap_defaults' ), 1 );

        add_action( 'admin_menu', array( __CLASS__, 'menu' ) );
        add_action( 'admin_init', array( __CLASS__, 'settings' ) );

        add_action( 'admin_post_opsgate_save_license', array( __CLASS__, 'handle_save_license' ) );
        add_action( 'admin_post_opsgate_reset_license', array( __CLASS__, 'handle_reset_license' ) );
        add_action( 'admin_post_opsgate_run_weekly_now', array(__CLASS__, 'handle_run_weekly_now'));
        add_action( 'admin_post_opsgate_run_monthly_now', array( __CLASS__, 'handle_run_monthly_now' ) );

        // Day-11: Agency Mode (Phase 1) — storage + visibility only.
        add_action( 'admin_post_opsgate_save_agency_settings', array( __CLASS__, 'handle_save_agency_settings' ) );
        add_action( 'admin_post_opsgate_agency_create_group', array( __CLASS__, 'handle_agency_create_group' ) );
        add_action( 'admin_post_opsgate_agency_delete_group', array( __CLASS__, 'handle_agency_delete_group' ) );
        add_action( 'admin_post_opsgate_agency_add_site', array( __CLASS__, 'handle_agency_add_site' ) );
        add_action( 'admin_post_opsgate_agency_remove_site', array( __CLASS__, 'handle_agency_remove_site' ) );
        add_action( 'admin_post_opsgate_agency_export_state', array( __CLASS__, 'handle_agency_export_state' ) );
        add_action( 'admin_post_opsgate_agency_reset_state', array( __CLASS__, 'handle_agency_reset_state' ) );


        add_action( 'admin_notices', array( __CLASS__, 'maybe_show_license_admin_notices' ) );
        add_action( 'admin_notices', array( __CLASS__, 'maybe_show_agency_admin_notices' ) );
        add_action( 'admin_notices', array( __CLASS__, 'maybe_show_pricing_admin_notices' ) );

        add_action( 'admin_post_opsgate_save_schedule_settings', array( __CLASS__, 'handle_schedule_settings_save' ) );
        wp_clear_scheduled_hook( self::SCHEDULE_CRON_HOOK );
        add_action( 'admin_post_opsgate_save_pricing_settings', array( __CLASS__, 'handle_pricing_settings_save' ) );
        add_action( 'admin_post_opsgate_apply_plan_defaults', array( __CLASS__, 'handle_apply_plan_defaults' ) );
        add_action( 'admin_post_opsgate_change_entitlement_plan', array( __CLASS__, 'handle_change_entitlement_plan' ) );


        // Day-8: site linking / proof actions (local-first, no MCP dependency).
        add_action( 'admin_post_opsgate_generate_link_proof', array( __CLASS__, 'handle_generate_link_proof' ) );
        add_action( 'admin_post_opsgate_clear_link_proof', array( __CLASS__, 'handle_clear_link_proof' ) );

        add_action( 'admin_post_opsgate_export_logs', array( __CLASS__, 'export_logs' ) );

        add_action( 'admin_post_opsgate_download_triage_artifact', array( __CLASS__, 'handle_download_triage_artifact' ) );
        add_action( 'admin_post_opsgate_export_triage_csv', array( __CLASS__, 'handle_export_triage_csv' ) );
        add_action( 'admin_post_opsgate_export_report_html', array( __CLASS__, 'handle_export_report_html' ) );
        add_action( 'admin_post_opsgate_export_report_pdf', array( __CLASS__, 'handle_export_report_pdf' ) );
        add_action( 'admin_post_opsgate_export_report_xlsx', array( __CLASS__, 'handle_export_report_xlsx' ) );
        add_action( 'admin_post_opsgate_export_triage_json', array( __CLASS__, 'handle_export_triage_json' ) );
        add_action( 'admin_post_opsgate_export_triage_xml', array( __CLASS__, 'handle_export_triage_xml' ) );
        add_action( 'wp_ajax_opsgate_export_record_status', array( __CLASS__, 'handle_export_record_status' ) );
        add_action( 'wp_ajax_opsgate_export_start', array( __CLASS__, 'handle_export_start_ajax' ) );
        add_action( 'wp_ajax_opsgate_triage_live_status', array( __CLASS__, 'handle_triage_live_status' ) );
        add_action( 'wp_ajax_opsgate_run_portfolio_triage_live', array( __CLASS__, 'handle_run_portfolio_triage_live' ) );
        add_action( 'admin_post_opsgate_run_portfolio_triage', ['OpsGate_Admin', 'handle_run_portfolio_triage']);
        add_action( 'admin_post_opsgate_download_export', array( __CLASS__, 'handle_download_export' ) );


        add_action( 'admin_post_opsgate_run_backup', array( __CLASS__, 'handle_run_backup' ) );
        add_action( 'admin_post_opsgate_download_backup', array( __CLASS__, 'handle_download_backup' ) );
        add_action( 'admin_post_opsgate_toggle_activity_dashboard', array( __CLASS__, 'handle_toggle_activity_dashboard' ) );
        add_action( 'admin_post_opsgate_save_configuration', array( __CLASS__, 'handle_save_configuration' ) );
        add_action( 'admin_post_opsgate_save_firm_name', array( __CLASS__, 'handle_save_firm_name' ) );
        add_action( 'admin_post_opsgate_save_agency_branding', array( __CLASS__, 'handle_save_agency_branding' ) );
        add_action( 'admin_post_opsgate_claim_remote_site', array( __CLASS__, 'handle_claim_remote_site' ) );
        add_action( 'admin_post_opsgate_set_plan_override', array( __CLASS__, 'handle_set_plan_override' ) );
        add_action( 'admin_post_opsgate_clear_plan_override', array( __CLASS__, 'handle_clear_plan_override' ) );
        add_action( 'admin_post_opsgate_operator_soft_reset', array( __CLASS__, 'handle_operator_soft_reset' ) );
        add_action( 'admin_post_opsgate_run_free_public_onboarding', array( __CLASS__, 'handle_run_free_public_onboarding' ) );
        add_action( 'admin_post_opsgate_dismiss_setup_wizard', array( __CLASS__, 'handle_dismiss_setup_wizard' ) );
        add_action( 'admin_post_opsgate_create_pairing_session', array( __CLASS__, 'handle_create_pairing_session' ) );
        add_action( 'admin_post_opsgate_complete_pairing', array( __CLASS__, 'handle_complete_pairing' ) );
        add_action( 'admin_post_opsgate_rotate_connector_credential', array( __CLASS__, 'handle_rotate_connector_credential' ) );
        add_action( 'admin_post_opsgate_revoke_connector_credential', array( __CLASS__, 'handle_revoke_connector_credential' ) );
        add_action( 'admin_post_opsgate_validation_remediation_apply', array( __CLASS__, 'handle_validation_remediation_apply' ) );
        add_action( 'admin_post_opsgate_validation_remediation_revert', array( __CLASS__, 'handle_validation_remediation_revert' ) );
        add_action( 'admin_post_opsgate_notification_rule_create', array( __CLASS__, 'handle_notification_rule_create' ) );
        add_action( 'admin_post_opsgate_notification_rule_enable', array( __CLASS__, 'handle_notification_rule_enable' ) );
        add_action( 'admin_post_opsgate_notification_rule_disable', array( __CLASS__, 'handle_notification_rule_disable' ) );
        add_action( 'admin_post_opsgate_notification_rule_delete', array( __CLASS__, 'handle_notification_rule_delete' ) );
        add_action( 'admin_post_opsgate_notification_destination_create', array( __CLASS__, 'handle_notification_destination_create' ) );
        add_action( 'admin_post_opsgate_notification_destination_update', array( __CLASS__, 'handle_notification_destination_update' ) );
        add_action( 'admin_post_opsgate_notification_destination_enable', array( __CLASS__, 'handle_notification_destination_enable' ) );
        add_action( 'admin_post_opsgate_notification_destination_disable', array( __CLASS__, 'handle_notification_destination_disable' ) );
        add_action( 'admin_post_opsgate_notification_destination_test', array( __CLASS__, 'handle_notification_destination_test' ) );
        add_action( 'admin_post_opsgate_notification_destination_delete', array( __CLASS__, 'handle_notification_destination_delete' ) );
        add_action( 'wp_ajax_opsgate_notification_rule_toggle', array( __CLASS__, 'handle_notification_rule_toggle_ajax' ) );
        add_action( 'wp_ajax_opsgate_notification_rule_create', array( __CLASS__, 'handle_notification_rule_create_ajax' ) );
        add_action( 'wp_ajax_opsgate_notification_rule_delete', array( __CLASS__, 'handle_notification_rule_delete_ajax' ) );
        add_action( 'wp_ajax_opsgate_notification_destination_mutation', array( __CLASS__, 'handle_notification_destination_mutation_ajax' ) );
        add_action( 'wp_ajax_opsgate_report_deliver', array( __CLASS__, 'handle_report_deliver_ajax' ) );
        add_action( 'wp_ajax_opsgate_set_ui_theme', array( __CLASS__, 'handle_set_ui_theme_ajax' ) );
        // Day 18.1: .htaccess Hardening (Wordfence baseline) — apply/revert + evidence downloads.
        add_action( 'admin_post_opsgate_htaccess_apply', array( __CLASS__, 'handle_htaccess_apply' ) );
        add_action( 'admin_post_opsgate_htaccess_revert', array( __CLASS__, 'handle_htaccess_revert' ) );
        add_action( 'admin_post_opsgate_htaccess_download_pdf', array( __CLASS__, 'handle_htaccess_download_pdf' ) );
        add_action( 'admin_post_opsgate_htaccess_download_evidence', array( __CLASS__, 'handle_htaccess_download_evidence' ) );
        add_action( 'admin_post_opsgate_run_scheduled_now', array( __CLASS__, 'handle_run_scheduled_now' ) );
        add_action( 'admin_post_opsgate_cdn_check_run', array( __CLASS__, 'handle_cdn_check_run' ) );
        add_action( 'admin_post_opsgate_cdn_check_prepare', array( __CLASS__, 'handle_cdn_check_prepare' ) );
        add_action( 'admin_post_opsgate_cdn_download_json', array( __CLASS__, 'handle_cdn_download_json' ) );

        add_action( 'admin_post_opsgate_recovery_request_submit', array( __CLASS__, 'handle_recovery_request_submit' ) );
        add_action( 'admin_post_opsgate_recovery_download_json', array( __CLASS__, 'handle_recovery_download_json' ) );

        add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueue_admin_styles' ) );
    }

    /**
     * Day-9.4: Admin-post handler to reset local license storage.
     *
     * Deletes:
     * - opsgate_license_json
     *
     * Redirects back to OpsGate settings page with a query flag.
     *
     * @return void
     */
    public static function handle_reset_license() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        $action = 'opsgate_reset_license';
        check_admin_referer( $action, '_wpnonce' );

        delete_option( 'opsgate_license_json' );

        $redirect = admin_url( 'admin.php?page=opsgate&opsgate_license_reset=1' );
        wp_safe_redirect( $redirect );
        exit;
    }

    public static function handle_save_license() {

        // 1) Capability check
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Unauthorized', 403 );
        }

        // 2) Nonce check
        check_admin_referer( 'opsgate_save_license', 'opsgate_license_nonce' );

        // 3) Read input
        $json = isset( $_POST['opsgate_license_json_input'] )
            ? (string) wp_unslash( $_POST['opsgate_license_json_input'] )
            : '';

        // 4) Store via canonical path
        $result = self::store_license_from_json_string( $json );

        // 5) Redirect back to OpsGate (ALWAYS)
        $redirect = admin_url( 'admin.php?page=opsgate' );

        if ( isset( $result['ok'] ) && true === $result['ok'] ) {
            $redirect = add_query_arg( 'opsgate_license_saved', '1', $redirect );
        } else {
            $redirect = add_query_arg( 'opsgate_license_error', '1', $redirect );
        }

        wp_safe_redirect( $redirect );
        exit;
    }

    public static function handle_run_weekly_now(): void {
        if ( ! current_user_can('manage_options') ) {
            wp_die('Forbidden', 403);
        }

        check_admin_referer('opsgate_run_weekly_now');

        $state = self::monthly_state_read();
	self::post_api_proof_event( 'weekly_run_now' );

        // Deterministic UTC ISO8601 Z timestamp
        $now = gmdate('Y-m-d\TH:i:s\Z');

        // Visibility-only writeback (no MCP / no enforcement)
        $state['weekly']['last_run_at_utc'] = $now;
        $state['weekly']['status']          = 'ok';
        $state['weekly']['created'] = (int) ($state['weekly']['created'] ?? 0);
        $state['weekly']['updated'] = (int) ($state['weekly']['updated'] ?? 0);
        $state['weekly']['notes']           = 'manual_run';

        // For Step B we do not fabricate counts. We just prove the write path works.
        // Counts stay as-is unless later workflow returns real stats.

        $ok = self::monthly_state_write($state);
        self::activity_timeline_add(
            'Weekly Check ran',
            $ok ? 'completed' : 'attention',
            $ok ? 'Your weekly check was recorded successfully.' : 'Your weekly check could not be recorded. Please try again.'
        );


        $base = admin_url('admin.php?page=opsgate&tab=overview');
        $flag = $ok ? 'opsgate_weekly_run=success' : 'opsgate_weekly_run=error';

        wp_safe_redirect($base . '&' . $flag);
        exit;
    }

    public static function handle_run_monthly_now(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_run_monthly_now' );

        $state = self::monthly_state_read();
	self::post_api_proof_event( 'monthly_run_now' );

        $now = gmdate( 'Y-m-d\TH:i:s\Z' );

        // Visibility-only writeback (no MCP / no enforcement)
        $state['monthly']['last_consolidated_at_utc'] = $now;
        $state['monthly']['status']                   = 'ok';

        // For Step C, deterministic + truthful defaults.
        // Weeks included: set to 4 as a reasonable placeholder for “monthly rollup”
        // until real weekly artifacts drive this number.
        $state['monthly']['weeks_included'] = 4;

        // Do not fabricate created/updated until workflows return real stats.
        $state['monthly']['created'] = (int) ( $state['monthly']['created'] ?? 0 );
        $state['monthly']['updated'] = (int) ( $state['monthly']['updated'] ?? 0 );

        $state['monthly']['notes'] = 'manual_consolidation';

        $ok = self::monthly_state_write( $state );
	self::activity_timeline_add(
            'Monthly Summary ran',
            $ok ? 'completed' : 'attention',
            $ok ? 'Your monthly summary was recorded successfully.' : 'Your monthly summary could not be recorded. Please try again.'
        );


        $base = admin_url( 'admin.php?page=opsgate&tab=overview' );
        $flag = $ok ? 'opsgate_monthly_run=success' : 'opsgate_monthly_run=error';

        wp_safe_redirect( $base . '&' . $flag );
        exit;
    }

    /**
     * Week-10: Download a stored triage artifact as an attachment (thin client).
     *
     * Query:
     * - job_id (string)
     * - kind (json_receipt|score_summary|score_breakdown|run_delta|inventory_snapshot|update_posture|vulnerability_posture|reachability_posture|availability_snapshot|performance_snapshot|configuration_validation|uptime_window|operational_log_intelligence|safe_update_smoke_check|hardening_guidance)
     *
     * @return void
     */
    public static function handle_download_triage_artifact(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_download_triage_artifact' );

        $job_id = isset( $_GET['job_id'] ) ? sanitize_text_field( wp_unslash( $_GET['job_id'] ) ) : '';
        $kind   = isset( $_GET['kind'] ) ? sanitize_text_field( wp_unslash( $_GET['kind'] ) ) : '';
        $mode   = isset( $_GET['mode'] ) ? sanitize_text_field( wp_unslash( $_GET['mode'] ) ) : 'download';
        $mode   = 'view' === strtolower( trim( $mode ) ) ? 'view' : 'download';

        $allowed = array( 'json_receipt', 'score_summary', 'score_breakdown', 'run_delta', 'inventory_snapshot', 'update_posture', 'vulnerability_posture', 'reachability_posture', 'availability_snapshot', 'performance_snapshot', 'configuration_validation', 'uptime_window', 'operational_log_intelligence', 'safe_update_smoke_check', 'hardening_guidance' );
        if ( '' === $job_id || '' === $kind || ! in_array( $kind, $allowed, true ) ) {
            wp_die( 'Invalid request.', 400 );
        }

        $detail = self::mcp_get_json( '/v1/triage/' . rawurlencode( $job_id ) );
        if ( ! isset( $detail['ok'] ) || true !== $detail['ok'] ) {
            $msg = isset( $detail['error'] ) && is_string( $detail['error'] ) ? $detail['error'] : 'Could not load triage details.';
            wp_die( esc_html( $msg ), 502 );
        }

        $data = $detail['data'] ?? array();
        $arts = isset( $data['artifacts'] ) && is_array( $data['artifacts'] ) ? $data['artifacts'] : array();

        if ( ! isset( $arts[ $kind ] ) || ! is_array( $arts[ $kind ] ) ) {
            wp_die( 'Artifact not found for this job.', 404 );
        }

        $node = $arts[ $kind ];
        $body = isset( $node['body'] ) ? $node['body'] : null;

        if ( null === $body ) {
            $note = isset( $node['redaction_note'] ) && is_string( $node['redaction_note'] ) ? trim( $node['redaction_note'] ) : '';
            $visibility_state = isset( $node['visibility_state'] ) ? trim( (string) $node['visibility_state'] ) : '';
            $status_code = 'tombstoned' === $visibility_state ? 410 : 403;
            wp_die( '' !== $note ? esc_html( $note ) : 'Artifact body is unavailable for download.', $status_code );
        }

        $filename = sprintf( 'opsgate_%s_%s.json', $job_id, $kind );

        $json_body = wp_json_encode( $body, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );

        nocache_headers();
        if ( 'view' === $mode ) {
            header( 'Content-Type: text/html; charset=utf-8' );
            header( 'Content-Disposition: inline; filename="' . $filename . '.html"' );
            echo '<!doctype html><html><head><meta charset="utf-8"><title>' . esc_html( $filename ) . '</title><style>body{margin:0;padding:24px;font:14px/1.5 ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;background:#f5f9ff;color:#0f2540;}pre{white-space:pre-wrap;word-break:break-word;background:#fff;border:1px solid #d7e2ee;border-radius:12px;padding:18px;box-shadow:0 8px 18px rgba(16,39,67,.06);}</style></head><body><pre>' . esc_html( (string) $json_body ) . '</pre></body></html>';
            exit;
        }

        header( 'Content-Type: application/json; charset=utf-8' );
        header( 'Content-Disposition: attachment; filename="' . $filename . '"' );

        echo $json_body;
        exit;
    }

    private static function dispatch_portfolio_triage_job_request(): array {
        self::bootstrap_defaults();

        $scope      = self::get_mcp_scope_snapshot();
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id    = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';

        if ( '' === $account_id || '' === $site_id ) {
            return array(
                'ok'      => false,
                'message' => 'Missing account and site identifiers. Set them first in Settings.',
                'error'   => 'missing_scope',
            );
        }

        $selected_site = self::current_selected_site_summary();
        $selected_site_url = isset( $selected_site['site_url'] ) ? trim( (string) $selected_site['site_url'] ) : '';
        if ( '' !== $selected_site_url && self::scope_targets_local_wordpress( $selected_site_url ) && '' !== self::connector_site_credential() ) {
            $register = self::register_local_connector();
            if ( empty( $register['ok'] ) ) {
                return array(
                    'ok'      => false,
                    'message' => 'The connector could not refresh its canonical registration. Rotate or reconnect the site credential in Settings.',
                    'error'   => 'connector_registration_failed',
                );
            }
        }

        $payload_basis = self::canonical_portfolio_triage_payload_basis();
        $site_url = isset( $payload_basis['site_url'] ) ? trim( (string) $payload_basis['site_url'] ) : '';
        $site_host = isset( $payload_basis['site_host'] ) ? trim( (string) $payload_basis['site_host'] ) : '';

        if ( '' === $site_host ) {
            return array(
                'ok'      => false,
                'message' => 'Could not determine the site host for this run.',
                'error'   => 'missing_site_host',
            );
        }

        $payload = array(
            'account_id' => $account_id,
            'site_id'    => $site_id,
            'job_type'   => 'portfolio_triage',
            'payload'    => $payload_basis,
        );

        $resp = self::mcp_post_json( '/v1/jobs/dispatch', $payload );

        if ( ! is_array( $resp ) || empty( $resp['ok'] ) ) {
            return array(
                'ok'      => false,
                'message' => 'Could not start Security Scan. Please try again. If this continues, check the API service health.',
                'error'   => 'dispatch_failed',
                'detail'  => isset( $resp['error'] ) ? (string) $resp['error'] : '',
            );
        }

        $data   = isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array();
        $job_id = isset( $data['job_id'] ) ? sanitize_text_field( (string) $data['job_id'] ) : '';

        if ( '' === $job_id ) {
            return array(
                'ok'      => false,
                'message' => 'Security Scan started, but no run ID was returned.',
                'error'   => 'missing_job_id',
            );
        }

        self::update_scope_runtime_refs(
            $scope,
            array(
                'last_triage_job_id' => $job_id,
            )
        );

        return array(
            'ok'      => true,
            'job_id'  => $job_id,
            'message' => 'Security Scan started. Latest/current surfaces will refresh from the canonical live run record.',
            'error'   => '',
        );
    }

    public static function handle_run_portfolio_triage() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Unauthorized', 403 );
        }

        check_admin_referer( 'opsgate_run_portfolio_triage' );

        $result = self::dispatch_portfolio_triage_job_request();
        if ( empty( $result['ok'] ) ) {
            update_option( 'opsgate_last_admin_error', (string) ( $result['message'] ?? 'Could not start Security Scan.' ) );
            wp_safe_redirect( self::admin_tab_url( 'triage' ) );
            exit;
        }

        wp_safe_redirect(
            self::admin_tab_url(
                'triage',
                array(
                    'opsgate_notice' => 'triage_started',
                )
            )
        );
        exit;
    }

    public static function handle_run_portfolio_triage_live(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error(
                array(
                    'message' => 'Forbidden',
                    'error'   => 'forbidden',
                ),
                403
            );
        }

        check_ajax_referer( 'opsgate_run_portfolio_triage', 'nonce' );

        $result = self::dispatch_portfolio_triage_job_request();
        if ( empty( $result['ok'] ) ) {
            wp_send_json_error(
                array(
                    'message' => (string) ( $result['message'] ?? 'Could not start Security Scan.' ),
                    'error'   => (string) ( $result['error'] ?? 'triage_start_failed' ),
                ),
                502
            );
        }

        $payload = self::triage_live_status_snapshot();
        if ( empty( $payload['ok'] ) ) {
            $payload = array();
        }
        if ( empty( $payload['run_state'] ) ) {
            $selected_site = self::current_selected_site_summary();
            $connected_truth_available = 'connected' === strtolower( trim( (string) ( $selected_site['connection_status'] ?? '' ) ) )
                && 'wp_connector' === strtolower( trim( (string) ( $selected_site['connection_mode'] ?? '' ) ) );
            $payload = array_merge(
                array(
                    'ok' => true,
                    'run_state' => 'QUEUED',
                    'export_state' => '',
                    'live_states' => array( 'QUEUED' ),
                    'run_visual_key' => 'queued',
                    'progress_tone' => 'warn',
                    'progress_title' => $connected_truth_available ? 'Run Site Triage is queued' : 'Run Public Check is queued',
                    'progress_copy' => 'The canonical run request was accepted and is waiting for worker execution.',
                    'progress_percent' => 8,
                    'progress_phase_label' => 'Queued',
                    'progress_phase_copy' => 'Accepted behind the API and waiting on worker execution.',
                    'progress_meter_label' => '8% of the current truthful run path is complete',
                    'elapsed_label' => 'Run request accepted just now',
                    'evidence_label' => 'Recording live truth',
                    'phase_items' => $connected_truth_available
                        ? array(
                            array( 'key' => 'queued', 'state' => 'current', 'state_label' => 'Active now' ),
                            array( 'key' => 'collecting_wordpress_evidence', 'state' => 'pending', 'state_label' => 'Waiting' ),
                            array( 'key' => 'checking_vulnerabilities', 'state' => 'pending', 'state_label' => 'Waiting' ),
                            array( 'key' => 'checking_uptime_performance', 'state' => 'pending', 'state_label' => 'Waiting' ),
                            array( 'key' => 'finalizing', 'state' => 'pending', 'state_label' => 'Waiting' ),
                            array( 'key' => 'complete', 'state' => 'pending', 'state_label' => 'Waiting' ),
                        )
                        : array(
                            array( 'key' => 'queued', 'state' => 'current', 'state_label' => 'Active now' ),
                            array( 'key' => 'checking_public_site', 'state' => 'pending', 'state_label' => 'Waiting' ),
                            array( 'key' => 'finalizing', 'state' => 'pending', 'state_label' => 'Waiting' ),
                            array( 'key' => 'complete', 'state' => 'pending', 'state_label' => 'Waiting' ),
                        ),
                    'should_refresh' => false,
                    'terminal' => false,
                ),
                $payload
            );
        }
        $payload['job_id'] = (string) ( $result['job_id'] ?? '' );
        $payload['message'] = (string) ( $result['message'] ?? '' );

        wp_send_json_success( $payload );
    }

    /**
     * Week-10: Dispatch triage CSV export (worker lane).
     *
     * @return void
     */
    private static function start_export_request( string $export_type, string $source_job_id ): array {
        $source_job_id = trim( $source_job_id );
        if ( '' === $source_job_id ) {
            return array(
                'ok' => false,
                'error' => 'missing_source_job_id',
                'message' => 'Select a recorded run before starting a packaged output.',
            );
        }

        $scope = self::get_mcp_scope_snapshot();
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id    = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';
        if ( '' === $account_id || '' === $site_id ) {
            return array(
                'ok' => false,
                'error' => 'missing_scope',
                'message' => 'Connect this canonical site in Settings before generating reports.',
            );
        }

        $path = '';
        $payload = array(
            'account_id'    => $account_id,
            'site_id'       => $site_id,
            'source_job_id' => $source_job_id,
        );
        if ( 'csv' === $export_type ) {
            $path = '/v1/exports/csv';
            $payload['job_type'] = 'portfolio_triage';
            $payload['include_previous'] = true;
            $payload['kind'] = 'triage_csv';
        } elseif ( 'html' === $export_type ) {
            $path = '/v1/exports/report-html';
        } elseif ( 'pdf' === $export_type ) {
            $path = '/v1/exports/report-pdf';
        } elseif ( 'xlsx' === $export_type ) {
            $path = '/v1/exports/report-xlsx';
        } elseif ( 'json' === $export_type ) {
            $path = '/v1/exports/triage-json';
        } elseif ( 'xml' === $export_type ) {
            $path = '/v1/exports/triage-xml';
        } else {
            return array(
                'ok' => false,
                'error' => 'unsupported_export_type',
                'message' => 'Unsupported export type.',
            );
        }

        $resp = self::mcp_post_json( $path, $payload );
        if ( ! is_array( $resp ) || empty( $resp['ok'] ) || empty( $resp['data'] ) || ! is_array( $resp['data'] ) ) {
            return array(
                'ok' => false,
                'error' => 'start_failed',
                'message' => 'Could not start the packaged output. Please try again.',
            );
        }

        $data = $resp['data'];
        $export_job_id = isset( $data['export_job_id'] ) ? sanitize_text_field( (string) $data['export_job_id'] ) : '';
        if ( '' !== $export_job_id ) {
            self::update_scope_runtime_refs(
                $scope,
                array(
                    'last_export_job_id'        => $export_job_id,
                    'last_export_source_job_id' => $source_job_id,
                )
            );
        }

        return array(
            'ok' => true,
            'export_job_id' => $export_job_id,
            'source_job_id' => $source_job_id,
            'message' => 'Packaged output started. Availability and trust state will update in place.',
        );
    }

    public static function handle_set_ui_theme_ajax(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => 'Forbidden' ), 403 );
            return;
        }
        $theme = isset( $_POST['theme'] ) ? sanitize_key( wp_unslash( $_POST['theme'] ) ) : 'light';
        $theme = in_array( $theme, array( 'light', 'dark' ), true ) ? $theme : 'light';
        update_option( 'opsgate_ui_theme', $theme, false );
        wp_send_json_success( array( 'theme' => $theme ) );
    }

    public static function handle_export_start_ajax(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => 'Forbidden' ), 403 );
        }

        check_ajax_referer( 'opsgate_export_start_ajax', 'nonce' );

        $export_type = isset( $_POST['export_type'] ) ? sanitize_text_field( wp_unslash( $_POST['export_type'] ) ) : '';
        $source_job_id = isset( $_POST['source_job_id'] ) ? sanitize_text_field( wp_unslash( $_POST['source_job_id'] ) ) : '';
        $result = self::start_export_request( $export_type, $source_job_id );
        if ( empty( $result['ok'] ) ) {
            wp_send_json_error(
                array(
                    'message' => isset( $result['message'] ) ? (string) $result['message'] : 'Could not start the packaged output.',
                    'error' => isset( $result['error'] ) ? (string) $result['error'] : 'start_failed',
                ),
                502
            );
        }

        wp_send_json_success( $result );
    }

    public static function handle_export_triage_csv(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_export_triage_csv' );

        $source_job_id = isset( $_POST['source_job_id'] ) ? sanitize_text_field( wp_unslash( $_POST['source_job_id'] ) ) : '';
        $result = self::start_export_request( 'csv', $source_job_id );
        if ( empty( $result['ok'] ) ) {
            update_option( 'opsgate_last_admin_error', 'Could not start the CSV export. Please try again.' );
            wp_safe_redirect(
                self::admin_tab_url(
                    'reports',
                    array(
                        'opsgate_export_error' => 'start_failed',
                    )
                )
            );
            exit;
        }

        wp_safe_redirect(
            self::admin_tab_url(
                'reports',
                array(
                    'opsgate_export_started' => '1',
                )
            )
        );
        exit;
    }

    /**
     * Week 10–12: Dispatch HTML report export for a selected triage run.
     */
    public static function handle_export_report_html(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_export_report_html' );

        $source_job_id = isset( $_POST['source_job_id'] ) ? sanitize_text_field( wp_unslash( $_POST['source_job_id'] ) ) : '';
        $result = self::start_export_request( 'html', $source_job_id );
        if ( empty( $result['ok'] ) ) {
            update_option( 'opsgate_last_admin_error', 'Could not start the HTML report. Please try again.' );
            wp_safe_redirect( self::admin_tab_url( 'reports', array( 'source_job_id' => $source_job_id, 'opsgate_export_error' => 'start_failed' ) ) );
            exit;
        }

        wp_safe_redirect(
            add_query_arg(
                array(
                    'page'                  => 'opsgate',
                    'tab'                   => 'reports',
                    'source_job_id'         => $source_job_id,
                    'opsgate_export_started'=> '1',
                ),
                admin_url( 'admin.php' )
            )
        );
        exit;
    }

    /**
     * Week 10–12: Dispatch PDF report export for a selected triage run.
     */
    public static function handle_export_report_pdf(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_export_report_pdf' );

        $source_job_id = isset( $_POST['source_job_id'] ) ? sanitize_text_field( wp_unslash( $_POST['source_job_id'] ) ) : '';
        $result = self::start_export_request( 'pdf', $source_job_id );
        if ( empty( $result['ok'] ) ) {
            update_option( 'opsgate_last_admin_error', 'Could not start the PDF report. Please try again.' );
            wp_safe_redirect( self::admin_tab_url( 'reports', array( 'source_job_id' => $source_job_id, 'opsgate_export_error' => 'start_failed' ) ) );
            exit;
        }

        wp_safe_redirect( self::admin_tab_url( 'reports', array( 'source_job_id' => $source_job_id, 'opsgate_export_started' => '1' ) ) );
        exit;
    }

    public static function handle_export_report_xlsx(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_export_report_xlsx' );

        $source_job_id = isset( $_POST['source_job_id'] ) ? sanitize_text_field( wp_unslash( $_POST['source_job_id'] ) ) : '';
        $result = self::start_export_request( 'xlsx', $source_job_id );
        if ( empty( $result['ok'] ) ) {
            update_option( 'opsgate_last_admin_error', 'Could not start the Excel report. Please try again.' );
            wp_safe_redirect( self::admin_tab_url( 'reports', array( 'source_job_id' => $source_job_id, 'opsgate_export_error' => 'start_failed' ) ) );
            exit;
        }

        wp_safe_redirect( self::admin_tab_url( 'reports', array( 'source_job_id' => $source_job_id, 'opsgate_export_started' => '1' ) ) );
        exit;
    }

    public static function handle_export_triage_json(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }
        check_admin_referer( 'opsgate_export_triage_json' );
        $source_job_id = isset( $_POST['source_job_id'] ) ? sanitize_text_field( wp_unslash( $_POST['source_job_id'] ) ) : '';
        $result = self::start_export_request( 'json', $source_job_id );
        if ( empty( $result['ok'] ) ) {
            update_option( 'opsgate_last_admin_error', 'Could not start the JSON export. Please try again.' );
            wp_safe_redirect( self::admin_tab_url( 'reports', array( 'source_job_id' => $source_job_id, 'opsgate_export_error' => 'start_failed' ) ) );
            exit;
        }
        wp_safe_redirect( self::admin_tab_url( 'reports', array( 'source_job_id' => $source_job_id, 'opsgate_export_started' => '1' ) ) );
        exit;
    }

    public static function handle_export_triage_xml(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }
        check_admin_referer( 'opsgate_export_triage_xml' );
        $source_job_id = isset( $_POST['source_job_id'] ) ? sanitize_text_field( wp_unslash( $_POST['source_job_id'] ) ) : '';
        $result = self::start_export_request( 'xml', $source_job_id );
        if ( empty( $result['ok'] ) ) {
            update_option( 'opsgate_last_admin_error', 'Could not start the XML export. Please try again.' );
            wp_safe_redirect( self::admin_tab_url( 'reports', array( 'source_job_id' => $source_job_id, 'opsgate_export_error' => 'start_failed' ) ) );
            exit;
        }
        wp_safe_redirect( self::admin_tab_url( 'reports', array( 'source_job_id' => $source_job_id, 'opsgate_export_started' => '1' ) ) );
        exit;
    }

    /**
     * Day-18 Step 1: Run Backup (manual).
     * - Creates a downloadable ZIP artifact (wp-content + database.sql)
     * - Writes backup history evidence (ring buffer)
     * - Records Activity Timeline entry (plain language, no internals)
     */
    public static function handle_run_backup(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_run_backup', 'opsgate_run_backup_nonce' );

        $result = self::backup_run_now();

        // Evidence-first activity record (respects telemetry gate).
        self::activity_timeline_add(
            'Backup ran',
            $result['ok'] ? 'completed' : 'attention',
            $result['ok'] ? 'Your backup was created successfully.' : ( $result['message'] ?? 'Your backup could not be created. Please try again.' )
        );

        // Redirect back to Security tab with a simple flag (no internals).
        $redirect = admin_url( 'admin.php?page=opsgate&tab=security' );
        $redirect = add_query_arg( 'opsgate_backup_run', $result['ok'] ? 'success' : 'error', $redirect );

        wp_safe_redirect( $redirect );
        exit;
    }

    /**
     * Day-18 Step 1: Download a backup artifact.
     * Uses wp_nonce_url() with action: opsgate_download_backup
     */
    public static function handle_download_backup(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_download_backup' );

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $file = isset( $_GET['file'] ) ? sanitize_file_name( wp_unslash( $_GET['file'] ) ) : '';
        if ( '' === $file || false !== strpos( $file, '..' ) ) {
            wp_die( 'Invalid file', 400 );
        }

        $path = self::backup_dir_abs() . $file;
        if ( ! file_exists( $path ) || ! is_readable( $path ) ) {
            wp_die( 'File not found', 404 );
        }

        header( 'Content-Type: application/zip' );
        header( 'Content-Disposition: attachment; filename="' . basename( $file ) . '"' );
        header( 'Content-Length: ' . filesize( $path ) );
        header( 'X-Content-Type-Options: nosniff' );

        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_readfile
        readfile( $path );
        exit;
    }

    /**
     * Load bundled TCPDF (WordPress.org-friendly).
     *
     * Safety:
     * - Uses plugin-bundled library only (no system dependency).
     * - Loads only when needed (PDF download handlers).
     */
    private static function tcpdf_require(): void {
        if ( class_exists( 'TCPDF', false ) ) {
            return;
        }

        $tcpdf = plugin_dir_path( __FILE__ ) . 'lib/tcpdf/tcpdf.php';

        if ( ! file_exists( $tcpdf ) ) {
            wp_die( esc_html__( 'PDF engine is missing. Please reinstall OpsGate.', 'opsgate' ), 500 );
        }

        require_once $tcpdf;
    }

    // =========================================================================
    // Day 18.1 — .htaccess Hardening (Wordfence baseline)
    // Deterministic snapshot + apply/revert + activity + evidence (downloads added next step)
    // =========================================================================

    /**
     * Absolute path to the site's .htaccess (root).
     */
    private static function htaccess_path(): string {
        // WordPress root (same directory where wp-config.php lives).
        return trailingslashit( ABSPATH ) . '.htaccess';
    }

    /**
     * Marker-wrapped hardening block (OpsGate-managed and reversible).
     *
     * The block is intentionally conservative: deny direct access to sensitive files
     * and disable directory listing. It avoids rewrite rules and avoids assumptions
     * about existing permalink structures.
     */
    private static function htaccess_hardening_block(): string {
        $lines = array(
            '# BEGIN OPSGATE HARDENING',
            '<IfModule mod_autoindex.c>',
            'Options -Indexes',
            '</IfModule>',
            '',
            '<FilesMatch "^(wp-config\\.php|readme\\.html|license\\.txt|php\\.ini|\\.env)$">',
            'Require all denied',
            '</FilesMatch>',
            '',
            '<FilesMatch "\\.(log|sql|sqlite|sqlite3|bak|backup|old|orig|swp)$">',
            'Require all denied',
            '</FilesMatch>',
            '# END OPSGATE HARDENING',
        );

        return implode( "\n", $lines ) . "\n";
    }

    /**
     * Read .htaccess state (deterministic).
     *
     * @return array{exists:bool,readable:bool,writable:bool,has_block:bool,sha256:string,size:int,mtime:int,excerpt:string}
     */
    private static function htaccess_read_state(): array {
        $path = self::htaccess_path();

        $exists   = file_exists( $path );
        $readable = $exists && is_readable( $path );
        $writable = ( $exists && is_writable( $path ) ) || ( ! $exists && is_writable( ABSPATH ) );

        $content = '';
        if ( $readable ) {
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_file_get_contents
            $content = (string) @file_get_contents( $path );
        }

        $has_block = ( false !== strpos( $content, '# BEGIN OPSGATE HARDENING' ) )
            && ( false !== strpos( $content, '# END OPSGATE HARDENING' ) );

        $sha = $readable ? hash( 'sha256', $content ) : '';
        $sz  = $readable ? strlen( $content ) : 0;
        $mt  = ( $exists ) ? (int) @filemtime( $path ) : 0;

        // Small excerpt for evidence (first 800 chars max, no secrets are expected in .htaccess).
        $excerpt = $readable ? substr( $content, 0, 800 ) : '';

        return array(
            'exists'    => (bool) $exists,
            'readable'  => (bool) $readable,
            'writable'  => (bool) $writable,
            'has_block' => (bool) $has_block,
            'sha256'    => (string) $sha,
            'size'      => (int) $sz,
            'mtime'     => (int) $mt,
            'excerpt'   => (string) $excerpt,
        );
    }

    /**
     * Remove only the OpsGate hardening block (safe revert).
     */
    private static function htaccess_remove_hardening_block( string $content ): string {
        $pattern = '/\# BEGIN OPSGATE HARDENING.*?\# END OPSGATE HARDENING\s*/s';
        $cleaned = (string) preg_replace( $pattern, '', $content );

        // Normalize: ensure trailing newline.
        $cleaned = rtrim( $cleaned ) . "\n";

        return $cleaned;
    }

    /**
     * Apply hardening: adds the OpsGate block if missing.
     *
     * @return array{ok:bool,message:string,before:array,after:array}
     */
    private static function htaccess_apply_internal(): array {
        $before = self::htaccess_read_state();

        if ( ! $before['writable'] ) {
            return array(
                'ok'      => false,
                'message' => 'OpsGate could not update .htaccess because the server does not allow writing in the site root.',
                'before'  => $before,
                'after'   => $before,
            );
        }

        $path = self::htaccess_path();

        // Read existing content (if exists).
        $content = '';
        if ( file_exists( $path ) && is_readable( $path ) ) {
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_file_get_contents
            $content = (string) @file_get_contents( $path );
        }

        // Idempotent: if already applied, return success with same content.
        if ( false !== strpos( $content, '# BEGIN OPSGATE HARDENING' ) ) {
            $after = self::htaccess_read_state();
            return array(
                'ok'      => true,
                'message' => 'Protection is already applied.',
                'before'  => $before,
                'after'   => $after,
            );
        }

        $new_content = rtrim( $content ) . "\n\n" . self::htaccess_hardening_block();

        // Atomic write via temp file in same directory.
        $tmp = $path . '.opsgate.tmp';

        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_write_file_put_contents
        $wrote = ( false !== @file_put_contents( $tmp, $new_content, LOCK_EX ) );
        if ( ! $wrote ) {
            return array(
                'ok'      => false,
                'message' => 'OpsGate could not write the protection update. Please try again.',
                'before'  => $before,
                'after'   => $before,
            );
        }

        $moved = @rename( $tmp, $path );
        if ( ! $moved ) {
            @unlink( $tmp );
            return array(
                'ok'      => false,
                'message' => 'OpsGate could not finalize the protection update. Please try again.',
                'before'  => $before,
                'after'   => $before,
            );
        }

        @chmod( $path, 0644 );

        $after = self::htaccess_read_state();

        return array(
            'ok'      => true,
            'message' => 'Protection applied successfully.',
            'before'  => $before,
            'after'   => $after,
        );
    }

    /**
     * Revert hardening: removes only the OpsGate block.
     *
     * @return array{ok:bool,message:string,before:array,after:array}
     */
    private static function htaccess_revert_internal(): array {
        $before = self::htaccess_read_state();

        if ( ! $before['exists'] ) {
            return array(
                'ok'      => true,
                'message' => 'No .htaccess file was found, so there is nothing to revert.',
                'before'  => $before,
                'after'   => $before,
            );
        }

        if ( ! $before['writable'] ) {
            return array(
                'ok'      => false,
                'message' => 'OpsGate could not revert .htaccess because the server does not allow writing in the site root.',
                'before'  => $before,
                'after'   => $before,
            );
        }

        $path = self::htaccess_path();

        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_file_get_contents
        $content = (string) @file_get_contents( $path );

        // If not present, idempotent success.
        if ( false === strpos( $content, '# BEGIN OPSGATE HARDENING' ) ) {
            $after = self::htaccess_read_state();
            return array(
                'ok'      => true,
                'message' => 'Protection is already reverted.',
                'before'  => $before,
                'after'   => $after,
            );
        }

        $new_content = self::htaccess_remove_hardening_block( $content );

        $tmp = $path . '.opsgate.tmp';

        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_write_file_put_contents
        $wrote = ( false !== @file_put_contents( $tmp, $new_content, LOCK_EX ) );
        if ( ! $wrote ) {
            return array(
                'ok'      => false,
                'message' => 'OpsGate could not write the revert change. Please try again.',
                'before'  => $before,
                'after'   => $before,
            );
        }

        $moved = @rename( $tmp, $path );
        if ( ! $moved ) {
            @unlink( $tmp );
            return array(
                'ok'      => false,
                'message' => 'OpsGate could not finalize the revert change. Please try again.',
                'before'  => $before,
                'after'   => $before,
            );
        }

        @chmod( $path, 0644 );

        $after = self::htaccess_read_state();

        return array(
            'ok'      => true,
            'message' => 'Protection reverted successfully.',
            'before'  => $before,
            'after'   => $after,
        );
    }

    /**
     * Hardening evidence directory under uploads.
     */
    private static function hardening_dir_abs(): string {
        $uploads = wp_upload_dir();
        return trailingslashit( $uploads['basedir'] ) . 'opsgate/hardening/';
    }

    /**
     * Ensure hardening evidence directory exists.
     */
    private static function ensure_hardening_dir(): bool {
        return self::ensure_dir( self::hardening_dir_abs() );
    }

    /**
     * Record a hardening run: write PDF/CSV/JSON evidence and append to history.
     *
     * @param string $action 'apply'|'revert'
     * @param array  $result return from htaccess_apply_internal / htaccess_revert_internal
     *
     * @return array{pdf_file:string,csv_file:string,json_file:string}
     */
    private static function hardening_write_evidence( string $action, array $result ): array {
        $action = ( 'revert' === $action ) ? 'revert' : 'apply';

        if ( ! self::ensure_hardening_dir() ) {
            return array( 'pdf_file' => '', 'csv_file' => '', 'xlsx_file'=> '', 'json_file' => '' );
        }

        $before = isset( $result['before'] ) && is_array( $result['before'] ) ? $result['before'] : array();
        $after  = isset( $result['after'] ) && is_array( $result['after'] ) ? $result['after'] : array();
        $ok     = ! empty( $result['ok'] );

        $ts    = time();
        $stamp = gmdate( 'Ymd-His', $ts );

        $base = "hardening_{$action}_{$stamp}";
        $dir  = self::hardening_dir_abs();

        $json_file = $base . '.json';
        $csv_file  = $base . '.csv';
        $pdf_file  = $base . '.pdf';
	$xlsx_file = $base . '.xlsx';

        // JSON evidence (machine-readable)
        $payload = array(
            'ts_utc'   => gmdate( 'c', $ts ),
            'action'   => $action,
            'ok'       => (bool) $ok,
            'message'  => isset( $result['message'] ) ? (string) $result['message'] : '',
            'site_url' => home_url(),
            'before'   => $before,
            'after'    => $after,
        );

        $json = wp_json_encode( $payload, JSON_PRETTY_PRINT );
        if ( false !== $json ) {
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_write_file_put_contents
            @file_put_contents( $dir . $json_file, $json, LOCK_EX );
        } else {
            $json_file = '';
        }

        // CSV evidence (reviewer-friendly)
        $csv_rows = array(
            array( 'Field', 'Before', 'After' ),
            array( 'Has OpsGate hardening block', ( ! empty( $before['has_block'] ) ? 'yes' : 'no' ), ( ! empty( $after['has_block'] ) ? 'yes' : 'no' ) ),
            array( 'SHA-256', (string) ( $before['sha256'] ?? '' ), (string) ( $after['sha256'] ?? '' ) ),
            array( 'Size (bytes)', (string) ( $before['size'] ?? '' ), (string) ( $after['size'] ?? '' ) ),
            array( 'Modified time (unix)', (string) ( $before['mtime'] ?? '' ), (string) ( $after['mtime'] ?? '' ) ),
        );

        $fh = @fopen( $dir . $csv_file, 'w' );
        if ( $fh ) {
            foreach ( $csv_rows as $row ) {
                fputcsv( $fh, $row );
            }
            fclose( $fh );
        } else {
            $csv_file = '';
        }

        // XLSX evidence (Excel-friendly, real .xlsx)
        $xlsx_rows = array(
            array( 'Field', 'Before', 'After' ),
            array( 'Has OpsGate hardening block', ( ! empty( $before['has_block'] ) ? 'yes' : 'no' ), ( ! empty( $after['has_block'] ) ? 'yes' : 'no' ) ),
            array( 'SHA-256', (string) ( $before['sha256'] ?? '' ), (string) ( $after['sha256'] ?? '' ) ),
            array( 'Size (bytes)', (string) ( $before['size'] ?? '' ), (string) ( $after['size'] ?? '' ) ),
            array( 'Modified time (unix)', (string) ( $before['mtime'] ?? '' ), (string) ( $after['mtime'] ?? '' ) ),
        );

        $xlsx_ok = self::hardening_write_xlsx( $dir . $xlsx_file, $xlsx_rows );
        if ( ! $xlsx_ok ) {
            $xlsx_file = '';
        }
        // PDF evidence (customer-ready, real PDF via bundled TCPDF)
        $pdf_ok = self::hardening_render_pdf( $dir . $pdf_file, $payload );
        if ( ! $pdf_ok ) {
            $pdf_file = '';
        }

        // Append to history (ring buffer)
        $history = get_option( 'opsgate_hardening_history', array() );
        if ( ! is_array( $history ) ) {
            $history = array();
        }

        array_unshift(
            $history,
            array(
                'ts'       => $ts,
                'action'   => $action,
                'status'   => $ok ? 'completed' : 'attention',
                'message'  => isset( $result['message'] ) ? (string) $result['message'] : '',
                'pdf_file' => $pdf_file,
                'csv_file' => $csv_file,
                'json_file'=> $json_file,
		'xlsx_file'=> $xlsx_file,
                'before'   => $before,
                'after'    => $after,
            )
        );

        $history = array_slice( $history, 0, 25 );
        update_option( 'opsgate_hardening_history', $history, false );

        return array(
            'pdf_file'  => (string) $pdf_file,
            'csv_file'  => (string) $csv_file,
            'json_file' => (string) $json_file,
	    'xlsx_file' => (string) $xlsx_file,
        );
    }

    /**
     * Render a real PDF evidence file using bundled TCPDF.
     */
    private static function hardening_render_pdf( string $abs_path, array $payload ): bool {
        try {
            self::tcpdf_require();

            if ( ! class_exists( 'TCPDF', false ) ) {
                return false;
            }

            $pdf = new TCPDF( 'P', 'mm', 'A4', true, 'UTF-8', false );
            $pdf->SetCreator( 'OpsGate' );
            $pdf->SetAuthor( 'OpsGate' );
            $pdf->SetTitle( 'OpsGate Hardening Evidence' );
            $pdf->SetMargins( 15, 15, 15 );
            $pdf->SetAutoPageBreak( true, 15 );
            $pdf->AddPage();

            $pdf->SetFont( 'helvetica', 'B', 14 );
            $pdf->Write( 0, 'OpsGate — Hardening Evidence', '', 0, 'L', true, 0, false, false, 0 );

            $pdf->SetFont( 'helvetica', '', 11 );
            $pdf->Write( 0, 'This report proves what protection was applied (or reverted), when it happened, and the before/after state.', '', 0, 'L', true, 0, false, false, 0 );

            $pdf->Ln( 2 );

            $site = isset( $payload['site_url'] ) ? (string) $payload['site_url'] : '';
            $ts   = isset( $payload['ts_utc'] ) ? (string) $payload['ts_utc'] : '';
            $act  = isset( $payload['action'] ) ? (string) $payload['action'] : '';
            $ok   = ! empty( $payload['ok'] ) ? 'completed' : 'attention';

            $pdf->SetFont( 'helvetica', 'B', 11 );
            $pdf->Write( 0, 'Summary', '', 0, 'L', true, 0, false, false, 0 );
            $pdf->SetFont( 'helvetica', '', 11 );
            $pdf->Write( 0, "Site: {$site}", '', 0, 'L', true, 0, false, false, 0 );
            $pdf->Write( 0, "Time (UTC): {$ts}", '', 0, 'L', true, 0, false, false, 0 );
            $pdf->Write( 0, "Action: {$act}", '', 0, 'L', true, 0, false, false, 0 );
            $pdf->Write( 0, "Result: {$ok}", '', 0, 'L', true, 0, false, false, 0 );

            $before = isset( $payload['before'] ) && is_array( $payload['before'] ) ? $payload['before'] : array();
            $after  = isset( $payload['after'] ) && is_array( $payload['after'] ) ? $payload['after'] : array();

            $pdf->Ln( 2 );
            $pdf->SetFont( 'helvetica', 'B', 11 );
            $pdf->Write( 0, 'Before / After', '', 0, 'L', true, 0, false, false, 0 );
            $pdf->SetFont( 'helvetica', '', 10 );

            $rows = array(
                array( 'Has OpsGate hardening block', ( ! empty( $before['has_block'] ) ? 'yes' : 'no' ), ( ! empty( $after['has_block'] ) ? 'yes' : 'no' ) ),
                array( 'SHA-256', (string) ( $before['sha256'] ?? '' ), (string) ( $after['sha256'] ?? '' ) ),
                array( 'Size (bytes)', (string) ( $before['size'] ?? '' ), (string) ( $after['size'] ?? '' ) ),
                array( 'Modified time (unix)', (string) ( $before['mtime'] ?? '' ), (string) ( $after['mtime'] ?? '' ) ),
            );

            $tbl = '<table border="1" cellpadding="4">'
                 . '<tr><th><b>Field</b></th><th><b>Before</b></th><th><b>After</b></th></tr>';

            foreach ( $rows as $r ) {
                $tbl .= '<tr>'
                     . '<td>' . htmlspecialchars( (string) $r[0], ENT_QUOTES, 'UTF-8' ) . '</td>'
                     . '<td>' . htmlspecialchars( (string) $r[1], ENT_QUOTES, 'UTF-8' ) . '</td>'
                     . '<td>' . htmlspecialchars( (string) $r[2], ENT_QUOTES, 'UTF-8' ) . '</td>'
                     . '</tr>';
            }

            $tbl .= '</table>';

            $pdf->writeHTML( $tbl, true, false, false, false, '' );

            // Write real PDF file to disk.
            $pdf->Output( $abs_path, 'F' );

            return file_exists( $abs_path ) && filesize( $abs_path ) > 0;
        } catch ( Exception $e ) {
            return false;
        }
    }

    /**
     * Write a minimal single-sheet XLSX file (no external libraries).
     *
     * @param string $abs_path Full path where .xlsx will be written
     * @param array  $rows     Array of rows, each row is array of cell strings
     */
    private static function hardening_write_xlsx( string $abs_path, array $rows ): bool {
        if ( ! class_exists( 'ZipArchive' ) ) {
            return false;
        }

        // Build sheet XML
        $sheet_rows = '';
        $r = 1;

        foreach ( $rows as $row ) {
            if ( ! is_array( $row ) ) {
                continue;
            }

            $sheet_rows .= '<row r="' . $r . '">';
            $c = 0;

            foreach ( $row as $cell ) {
                $c++;
                $col = self::xlsx_col_letter( $c );
                $ref = $col . $r;

                $v = (string) $cell;
                $v = htmlspecialchars( $v, ENT_QUOTES | ENT_XML1, 'UTF-8' );

                // Inline string cell
                $sheet_rows .= '<c r="' . $ref . '" t="inlineStr"><is><t>' . $v . '</t></is></c>';
            }

            $sheet_rows .= '</row>';
            $r++;
        }

        $sheet_xml =
            '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' .
            '<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">' .
            '<sheetData>' . $sheet_rows . '</sheetData>' .
            '</worksheet>';

        $workbook_xml =
            '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' .
            '<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" ' .
            'xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">' .
            '<sheets><sheet name="Hardening Evidence" sheetId="1" r:id="rId1"/></sheets>' .
            '</workbook>';

        $rels_xml =
            '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' .
            '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">' .
            '<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/>' .
            '</Relationships>';

        $root_rels_xml =
            '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' .
            '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">' .
            '<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>' .
            '</Relationships>';

        $content_types_xml =
            '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' .
            '<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">' .
            '<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>' .
            '<Default Extension="xml" ContentType="application/xml"/>' .
            '<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>' .
            '<Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>' .
            '</Types>';

        // Write zip
        $zip = new ZipArchive();
        if ( true !== $zip->open( $abs_path, ZipArchive::CREATE | ZipArchive::OVERWRITE ) ) {
            return false;
        }

        $zip->addFromString( '[Content_Types].xml', $content_types_xml );
        $zip->addFromString( '_rels/.rels', $root_rels_xml );
        $zip->addFromString( 'xl/workbook.xml', $workbook_xml );
        $zip->addFromString( 'xl/_rels/workbook.xml.rels', $rels_xml );
        $zip->addFromString( 'xl/worksheets/sheet1.xml', $sheet_xml );

        $zip->close();

        return file_exists( $abs_path ) && filesize( $abs_path ) > 0;
    }

    /**
     * Convert 1-based column index to Excel column letters (A, B, ... Z, AA, AB...).
     */
    private static function xlsx_col_letter( int $index ): string {
        $index = max( 1, $index );
        $letters = '';

        while ( $index > 0 ) {
            $mod = ( $index - 1 ) % 26;
            $letters = chr( 65 + $mod ) . $letters;
            $index = (int) ( ( $index - $mod ) / 26 );
            $index--;
        }

        return $letters;
    }

    /**
     * Admin-post: Download hardening PDF.
     */
    public static function handle_htaccess_download_pdf(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_htaccess_download_pdf' );

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $file = isset( $_GET['file'] ) ? sanitize_file_name( wp_unslash( $_GET['file'] ) ) : '';
        if ( '' === $file || false !== strpos( $file, '..' ) || ! str_ends_with( $file, '.pdf' ) ) {
            wp_die( 'Invalid file', 400 );
        }

        $path = self::hardening_dir_abs() . $file;
        if ( ! file_exists( $path ) || ! is_readable( $path ) ) {
            wp_die( 'File not found', 404 );
        }

        nocache_headers();
        header( 'Content-Type: application/pdf' );
        header( 'Content-Disposition: attachment; filename="' . basename( $file ) . '"' );
        header( 'Content-Length: ' . filesize( $path ) );
        header( 'X-Content-Type-Options: nosniff' );

        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_readfile
        readfile( $path );
        exit;
    }

    /**
     * Admin-post: Download hardening evidence file (CSV or JSON).
     */
    public static function handle_htaccess_download_evidence(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_htaccess_download_evidence' );

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $file = isset( $_GET['file'] ) ? sanitize_file_name( wp_unslash( $_GET['file'] ) ) : '';
        if ( '' === $file || false !== strpos( $file, '..' ) ) {
            wp_die( 'Invalid file', 400 );
        }

        $is_csv  = str_ends_with( $file, '.csv' );
        $is_json = str_ends_with( $file, '.json' );
	$is_xlsx = str_ends_with( $file, '.xlsx' );

        if ( ! $is_csv && ! $is_json && ! $is_xlsx ) {
            wp_die( 'Invalid file type', 400 );
        }

        $path = self::hardening_dir_abs() . $file;
        if ( ! file_exists( $path ) || ! is_readable( $path ) ) {
            wp_die( 'File not found', 404 );
        }

        nocache_headers();

        if ( $is_csv ) {
            header( 'Content-Type: text/csv; charset=utf-8' );
         } elseif ( $is_json ) {
            header( 'Content-Type: application/json; charset=utf-8' );
	} else {
            header( 'Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' );
        }

        header( 'Content-Disposition: attachment; filename="' . basename( $file ) . '"' );
        header( 'Content-Length: ' . filesize( $path ) );
        header( 'X-Content-Type-Options: nosniff' );

        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_readfile
        readfile( $path );
        exit;
    }

    /**
      * Day 19.1: Malware Check — baseline placeholder (UI + evidence + activity).
      *
      * Important:
      * - This does NOT claim deep malware detection.
      * - It records a deterministic “check completed” result so customers have visible proof.
      * - A real scanning engine is added later in Day 19.
      *
      * @return void
      */
      public static function handle_run_malware_check(): void {
    	  if ( ! current_user_can( 'manage_options' ) ) {
              wp_die( 'Forbidden', 403 );
          }

	  check_admin_referer( 'opsgate_run_malware_check', 'opsgate_malware_nonce' );

	  $site_id   = (string) self::evidence_site_label();
     	  $scope     = isset( $_POST['opsgate_malware_scope'] ) ? sanitize_text_field( wp_unslash( $_POST['opsgate_malware_scope'] ) ) : 'full';
    	  $scan_mode = isset( $_POST['opsgate_malware_scan_mode'] ) ? sanitize_text_field( wp_unslash( $_POST['opsgate_malware_scan_mode'] ) ) : 'standard';
    	  $run_id    = isset( $_POST['opsgate_malware_run_id'] ) ? sanitize_text_field( wp_unslash( $_POST['opsgate_malware_run_id'] ) ) : '';

    	  $input = array(
              'site_id'    => $site_id,
              'scope'      => $scope,
              'scan_mode'  => $scan_mode,
              'run_id'     => $run_id,
       	  );

    	  $result = self::malware_runner_execute( $input );

      	  $status = isset( $result['status'] ) ? (string) $result['status'] : 'error';

           $notice_type = 'error';
           $title       = 'Malware Check could not run';
           $level       = 'attention';
           $note        = isset( $result['notes'] ) ? (string) $result['notes'] : 'Malware check could not run.';

           if ( 'ok' === $status ) {
               $notice_type = 'success';
               $title       = 'Malware Check completed';
               $level       = 'completed';
           } elseif ( 'attention' === $status ) {
               $notice_type = 'warning';
               $title       = 'Malware Check needs review';
               $level       = 'attention';
           } elseif ( 'never' === $status ) {
               $notice_type = 'info';
               $title       = 'Malware Check not enabled yet';
               $level       = 'info';
           }

           if ( method_exists( __CLASS__, 'activity_timeline_add' ) ) {
               self::activity_timeline_add( $title, $level, $note );
           }

           $redirect = admin_url( 'admin.php?page=opsgate&tab=security' );
           $redirect = add_query_arg( 'opsgate_malware_run', $notice_type, $redirect );


          wp_safe_redirect( $redirect );
          exit;
    }

    /**
     * Day 19.3.1: Malware Runner Interface (STUB / STOP).
     *
     * Contract boundary:
     * - Always returns the full contract shape.
     * - Does not scan anything.
     * - Stores last result + history and writes evidence files to uploads.
     */
    private static function malware_runner_execute( array $input ): array {
    	$t0 = microtime( true );

    	$allowed_scopes = array( 'full', 'wp-content' );
    	$allowed_modes  = array( 'quick', 'standard', 'deep' );

	$site_id   = isset( $input['site_id'] ) ? (string) $input['site_id'] : '';
    	$scope     = isset( $input['scope'] ) ? (string) $input['scope'] : '';
    	$scan_mode = isset( $input['scan_mode'] ) ? (string) $input['scan_mode'] : '';
    	$run_id    = isset( $input['run_id'] ) ? (string) $input['run_id'] : '';

    	$site_id   = sanitize_text_field( $site_id );
    	$scope     = sanitize_text_field( $scope );
    	$scan_mode = sanitize_text_field( $scan_mode );
    	$run_id    = sanitize_text_field( $run_id );

    	if ( '' === $run_id ) {
            $run_id = wp_generate_uuid4();
    	}

    	$now_iso = gmdate( 'Y-m-d\TH:i:s\Z' );

          // Day 19 Step D1:
          // Default state is NOT an error. "Not connected yet" is not a runtime failure.
          // Error is reserved for fatal failures (missing identity, invalid scope/mode, unreadable paths, exceptions).
          $status = 'never';
          $notes  = 'Quick Malware Check is not enabled yet. No scan was performed.';

          if ( '' === $site_id ) {
              $status = 'error';
              $notes  = 'Malware check could not run because the site identity is missing. No scan was performed.';
          } elseif ( '' === $scope || ! in_array( $scope, $allowed_scopes, true ) ) {
              $status = 'error';
              $notes  = 'Malware check could not run because the requested scope is invalid. No scan was performed.';
          } elseif ( '' === $scan_mode || ! in_array( $scan_mode, $allowed_modes, true ) ) {
              $status = 'error';
              $notes  = 'Malware check could not run because the requested scan mode is invalid. No scan was performed.';
          }

          $files_checked = 0;
          $suspicious_found = 0;
          $findings = array();

          // D2: Local “Suspicious Indicators” scan (WP.org-safe, no network).
          // Performance caps (non-negotiable for runtime safety).
	  // D4.2: scan_mode + scope must actually change behavior (WP.org-safe, no network).
	  $max_findings = 50;

	  // Caps vary by mode (runtime safety first).
	  $mode = $scan_mode;
	  $max_files = 500;
	  $max_bytes_per_file = 256 * 1024; // 256 KB

	  if ( 'standard' === $mode ) {
              $max_files = 1500;
              $max_bytes_per_file = 512 * 1024; // 512 KB
	  } elseif ( 'deep' === $mode ) {
    	      $max_files = 3000;
    	      $max_bytes_per_file = 1024 * 1024; // 1 MB
	  }

          $indicators = array(
              'eval('          => 'eval(',
              'base64_decode(' => 'base64_decode(',
              'gzinflate('     => 'gzinflate(',
              'shell_exec('    => 'shell_exec(',
              'passthru('      => 'passthru(',
              'system('        => 'system(',
              'assert('        => 'assert(',
          );

	  // Scan roots vary by scope.
	  // - wp-content: plugins + themes (default safe scope)
	  // - full: still bounded; includes mu-plugins and selected core entrypoints, but never outside ABSPATH.
	  $scan_dirs = array();

	  $plugins_dir = WP_CONTENT_DIR . '/plugins';
	  $themes_dir  = WP_CONTENT_DIR . '/themes';
	  $mu_dir      = WP_CONTENT_DIR . '/mu-plugins';

          // D5: Default exclusions to reduce false positives from known benign sources.
          // These are relative to wp-content/ and only affect local scanning.
          $excluded_prefixes = array(
              'wp-content/plugins/opsgate/',
              'wp-content/plugins/opsgate/includes/lib/tcpdf/_license_docs/',
          );


	  if ( 'wp-content' === $scope ) {
              $scan_dirs = array( $plugins_dir, $themes_dir );
	      $exclusions = array(
	          wp_normalize_path( WP_CONTENT_DIR . '/plugins/opsgate/' ),
	          wp_normalize_path( WP_CONTENT_DIR . '/plugins/opsgate/includes/lib/tcpdf/_license_docs/' ),
	      );

	  } else {
    	      // "full" still means WordPress install only (bounded).
    	      $scan_dirs = array( $plugins_dir, $themes_dir );

    	      if ( is_dir( $mu_dir ) ) {
                  $scan_dirs[] = $mu_dir;
    	      }

	     // Optional: include a few core PHP entrypoints if present (still capped heavily).
	     // These are single files, not full directory walks.
    	     $core_files = array(
	         ABSPATH . 'wp-config.php',
        	 ABSPATH . 'wp-settings.php',
	         ABSPATH . 'wp-load.php',
    	     );

    	     foreach ( $core_files as $cf ) {
        	 if ( is_file( $cf ) && is_readable( $cf ) ) {
            	     $scan_dirs[] = $cf;
        	 }
    	     }
	  }

	  // D4: Transparent exclusions to reduce known-safe noise.
	  // - We never want OpsGate to flag itself.
	  // - We also ignore vendor documentation/examples that may contain “suspicious-looking” example snippets.
	  // This does not imply cleanliness; it reduces false positives.
	  $exclude_prefixes = array(
	      wp_normalize_path( WP_CONTENT_DIR . '/plugins/opsgate/' ),
	      wp_normalize_path( WP_CONTENT_DIR . '/plugins/opsgate/includes/lib/tcpdf/_license_docs/' ),
	  );

          // Validate scan roots (fatal error only if both roots are unusable).
          $readable_roots = array();
          foreach ( $scan_dirs as $d ) {
              if ( is_dir( $d ) && is_readable( $d ) ) {
                  $readable_roots[] = $d;
              }
          }

          if ( 0 === count( $readable_roots ) ) {
              $status = 'error';
              $notes  = 'Quick Malware Check could not run because the scan directories are not readable. No scan was performed.';
          } else {
              try {
                  foreach ( $readable_roots as $root ) {
	             // Allow both directory walks and single-file checks (for "full" scope core entrypoints).
	             if ( is_file( $root ) ) {
        		 $fileinfo = new SplFileInfo( $root );

		        // Reuse the same file-processing logic by wrapping the single file in an array.
		         $single = array( $fileinfo );
		         foreach ( $single as $fileinfo ) {
	                // (the existing inner file-processing logic continues unchanged)
		         }
        		continue;
    		   }

    		   $it = new RecursiveIteratorIterator(
        		new RecursiveDirectoryIterator(
            		    $root,
		            FilesystemIterator::SKIP_DOTS | FilesystemIterator::FOLLOW_SYMLINKS
		        ),
		        RecursiveIteratorIterator::LEAVES_ONLY
		    );

		    foreach ( $it as $fileinfo ) {
        		// (existing logic)
                          if ( $files_checked >= $max_files ) {
                              break 2;
                          }

                          if ( ! $fileinfo instanceof SplFileInfo ) {
                              continue;
                          }

                          if ( ! $fileinfo->isFile() ) {
                              continue;
                          }

                          $path = (string) $fileinfo->getPathname();
			  $path_norm = wp_normalize_path( $path );

			  $excluded = false;
			  foreach ( $exclusions as $ex ) {
			      if ( '' !== $ex && 0 === strpos( $path_norm, $ex ) ) {
			          $excluded = true;
			          break;
			      }
			  }

			  if ( $excluded ) {
			      continue;
			  }

                          $rel = wp_normalize_path( $path );
                          $root_norm = wp_normalize_path( ABSPATH );
                          if ( '' !== $root_norm && 0 === strpos( $rel, $root_norm ) ) {
                              $rel = ltrim( substr( $rel, strlen( $root_norm ) ), '/' );
                          }

                          $is_excluded = false;
                          foreach ( $excluded_prefixes as $prefix ) {
                              if ( '' !== $prefix && 0 === strpos( $rel, $prefix ) ) {
                                  $is_excluded = true;
                                  break;
                                }
                          }
                          if ( $is_excluded ) {
                              continue;
                          }

			  $path_norm = wp_normalize_path( $path );
			  $skip = false;

			  foreach ( $exclude_prefixes as $prefix ) {
    			      if ( '' !== $prefix && 0 === strpos( $path_norm, $prefix ) ) {
        			  $skip = true;
        			  break;
    			      }
			  }

			  if ( $skip ) {
    			      continue;
			  }


                          // Extension filter (PHP only for now).
                          $ext = strtolower( (string) pathinfo( $path, PATHINFO_EXTENSION ) );
                          if ( 'php' !== $ext && 'phtml' !== $ext ) {
                              continue;
                          }

                          // Size cap.
                          $size = (int) $fileinfo->getSize();
                          if ( $size <= 0 || $size > $max_bytes_per_file ) {
                              continue;
                          }

                          if ( ! is_readable( $path ) ) {
                              continue;
                          }

                          // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
                          $contents = @file_get_contents( $path );
                          if ( false === $contents || '' === $contents ) {
                              continue;
                          }

                          $files_checked++;

                          foreach ( $indicators as $label => $needle ) {
                              if ( false !== strpos( $contents, $needle ) ) {
                                  $suspicious_found++;

                                  // Safe relative path (no absolute paths in evidence).
                                  $rel = wp_normalize_path( $path );
                                  $root_norm = wp_normalize_path( ABSPATH );
                                  if ( '' !== $root_norm && 0 === strpos( $rel, $root_norm ) ) {
                                      $rel = ltrim( substr( $rel, strlen( $root_norm ) ), '/' );
                                  }

                                  $findings[] = array(
                                      'path'      => $rel,
                                      'indicator' => $label,
                                  );

                                  if ( count( $findings ) >= $max_findings ) {
                                      break 3;
                                  }

                                  // Only store one finding per file (avoid noisy duplicates).
                                  break;
                              }
                          }
                      }
                  }

                  if ( $suspicious_found > 0 ) {
                      $status = 'attention';
                      $notes  = 'Attention: suspicious indicators were found. Review the evidence and investigate. This check does not guarantee the site is clean.';
                  } else {
                      $status = 'ok';
                      $notes  = 'Quick Malware Check completed. No suspicious indicators were found in the scanned scope. This check does not guarantee the site is clean.';
                  }
              } catch ( Exception $e ) {
                  $status = 'error';
                  $notes  = 'Quick Malware Check could not run due to an unexpected error. No scan was performed.';
              }
          }



    	$result = array(
            'status'           => $status,
            'last_run_at_utc'   => $now_iso,
            'files_checked'     => $files_checked,
            'suspicious_found'  => $suspicious_found,
	    'findings'          => $findings,
            'artifacts'         => array(),
            'notes'             => $notes,
            'run_id'            => $run_id,
            'duration_ms'       => 0,
            'engine'            => 'local_indicators',
            'site_id'           => $site_id,
            'scope'             => $scope,
            'scan_mode'         => $scan_mode,
    	);

    	// Persist last result (full contract keys).
    	update_option( 'opsgate_malware_last_result', $result );

    	// Append history (bounded).
    	$history = get_option( 'opsgate_malware_history', array() );
    	if ( ! is_array( $history ) ) {
            $history = array();
    	}

    	array_unshift(
            $history,
            array(
            	'ts_utc'  => $now_iso,
            	'status'  => $status,
            	'summary' => array(
                    'files_checked'    => $files_checked,
                    'suspicious_found' => $suspicious_found,
            	),
            	'note'    => $notes,
            	'run_id'  => $run_id,
            )
    	);

    	$history = array_slice( $history, 0, 30 );
    	update_option( 'opsgate_malware_history', $history );

    	// Write evidence files under uploads and attach artifacts.
    	$artifacts = self::malware_write_run_evidence_files( $result, $history );
	$duration_ms = (int) round( ( microtime( true ) - $t0 ) * 1000 );
	$duration_ms = max( 1, $duration_ms );
	$result['duration_ms'] = $duration_ms;

    	$result['artifacts'] = $artifacts;

    	// Update last result again with artifact references (still full shape).
    	update_option( 'opsgate_malware_last_result', $result );

    	return $result;
    }

    private static function malware_uploads_dir_abs(): string {
    	$u = wp_upload_dir();
        $base = isset( $u['basedir'] ) ? (string) $u['basedir'] : '';
    	$base = rtrim( $base, '/\\' );
    	return $base . '/opsgate/malware/';
    }

    private static function malware_uploads_dir_url(): string {
    	$u = wp_upload_dir();
    	$base = isset( $u['baseurl'] ) ? (string) $u['baseurl'] : '';
    	$base = rtrim( $base, '/\\' );
    	return $base . '/opsgate/malware/';
    }

    private static function malware_ensure_uploads_dir(): bool {
    	$dir = self::malware_uploads_dir_abs();

    	if ( '' === $dir ) {
            return false;
    	}

    	if ( ! file_exists( $dir ) ) {
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_mkdir
            @mkdir( $dir, 0755, true );
    	}

    	return ( file_exists( $dir ) && is_dir( $dir ) && is_writable( $dir ) );
    }

    private static function malware_run_filename( string $run_id, string $ext ): string {
    	$rid = sanitize_file_name( $run_id );
    	$ext = ltrim( strtolower( trim( $ext ) ), '.' );
    	return 'opsgate-malware-' . $rid . '.' . $ext;
    }

      /**
       * D3: Normalized evidence payload (single source of truth).
       * This is the meaning contract used by JSON/CSV/XLSX/PDF.
       *
       * @param array $result
       * @return array<string, mixed>
       */
      private static function malware_normalized_payload( array $result ): array {
          $status = isset( $result['status'] ) ? (string) $result['status'] : 'never';

          $ts_utc = isset( $result['last_run_at_utc'] ) ? (string) $result['last_run_at_utc'] : '';
          if ( '' === $ts_utc ) {
              $ts_utc = gmdate( 'Y-m-d\TH:i:s\Z' );
          }

          $files_checked    = (int) ( $result['files_checked'] ?? 0 );
          $suspicious_found = (int) ( $result['suspicious_found'] ?? 0 );

          $ok = ( 'ok' === $status );
          $outcome = 'Not run yet';

          if ( 'ok' === $status ) {
              $outcome = 'Completed';
          } elseif ( 'attention' === $status ) {
              $outcome = 'Attention';
          } elseif ( 'error' === $status ) {
              $outcome = 'Error';
          }

          $note = isset( $result['notes'] ) ? (string) $result['notes'] : '';
          if ( '' === $note ) {
              $note = 'This check searches for common suspicious patterns. It does not guarantee the site is clean.';
          }

          $findings_in = ( isset( $result['findings'] ) && is_array( $result['findings'] ) ) ? $result['findings'] : array();
          $findings = array();

          foreach ( $findings_in as $f ) {
              if ( ! is_array( $f ) ) {
                  continue;
              }

              $path = isset( $f['path'] ) ? (string) $f['path'] : '';
              $ind  = isset( $f['indicator'] ) ? (string) $f['indicator'] : '';

              $path = ltrim( str_replace( array( '\\', "\0" ), array( '/', '' ), $path ), '/' );
              if ( '' === $path || false !== strpos( $path, '..' ) ) {
                  continue;
              }

              $findings[] = array(
                  'path'      => $path,
                  'indicator' => $ind,
              );

              if ( count( $findings ) >= 50 ) {
                  break;
              }
          }

          return array(
              'type'    => 'malware_check',
              'service' => 'malware',
              'ts_utc'  => $ts_utc,
              'ok'      => $ok,
              'outcome' => $outcome,
              'summary' => array(
                  'files_checked'    => $files_checked,
                  'suspicious_found' => $suspicious_found,
              ),

              'findings' => $findings,
              'note'     => $note,
	      'exclusions' => array(
    	      	  'wp-content/plugins/opsgate/',
    	          'wp-content/plugins/opsgate/includes/lib/tcpdf/_license_docs/',
	      ),

          );
      }


    /**
     * Writes JSON/CSV/PDF/XLSX evidence files for a run (even minimal, but truthful).
     * Returns artifact descriptors suitable for storing on the result.
     *
     * @param array $result
     * @param array $history
     * @return array<int, array<string, mixed>>
     */
    private static function malware_write_run_evidence_files( array $result, array $history ): array {
    	$artifacts = array();

    	$ok_dir = self::malware_ensure_uploads_dir();
    	if ( ! $ok_dir ) {
            return $artifacts;
    	}

        $run_id = isset( $result['run_id'] ) ? (string) $result['run_id'] : '';
    	if ( '' === $run_id ) {
            return $artifacts;
        }

    	$dir_abs = self::malware_uploads_dir_abs();
    	$dir_url = self::malware_uploads_dir_url();

       	// JSON
          $normalized = self::malware_normalized_payload( $result );

          $json_payload = $normalized;
          $json_payload['exported_utc']  = gmdate( 'Y-m-d\TH:i:s\Z' );
          $json_payload['evidence_for']  = self::evidence_site_label();
          $json_payload['run_id']        = isset( $result['run_id'] ) ? (string) $result['run_id'] : '';
          $json_payload['engine']        = isset( $result['engine'] ) ? (string) $result['engine'] : '';
          $json_payload['history_count'] = is_array( $history ) ? count( $history ) : 0;

    	$json = wp_json_encode( $json_payload, JSON_PRETTY_PRINT );
    	if ( false !== $json ) {
            $name = self::malware_run_filename( $run_id, 'json' );
            $path = $dir_abs . $name;
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_write_file_put_contents
            $w = @file_put_contents( $path, $json );
            if ( false !== $w ) {
                $artifacts[] = array(
                    'type' => 'json',
                    'name' => $name,
                    'path' => $path,
                    'url'  => $dir_url . $name,
            	);
            }
    	}

          // CSV/XLSX rows must reflect the normalized meaning contract (D3).
          $rows = self::malware_export_rows(
              array(
                  'ts_utc'      => gmdate( 'Y-m-d\TH:i:s\Z' ),
                  'normalized'  => self::malware_normalized_payload( $result ),
              )
          );


    	$fh = fopen( 'php://temp', 'w+' );
    	if ( false !== $fh ) {
            foreach ( $rows as $r ) {
                fputcsv( $fh, $r );
           }
           rewind( $fh );
           $csv = stream_get_contents( $fh );
           fclose( $fh );

           if ( false !== $csv ) {
               $name = self::malware_run_filename( $run_id, 'csv' );
               $path = $dir_abs . $name;
               // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_write_file_put_contents
               $w = @file_put_contents( $path, $csv );
               if ( false !== $w ) {
                   $artifacts[] = array(
                       'type' => 'csv',
                       'name' => $name,
                       'path' => $path,
                       'url'  => $dir_url . $name,
                    );
            	}
            }
    	}

    	// XLSX (minimal, using existing builder)
    	$bin = self::malware_build_xlsx( $rows );
    	if ( is_string( $bin ) && '' !== $bin ) {
            $name = self::malware_run_filename( $run_id, 'xlsx' );
            $path = $dir_abs . $name;
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_write_file_put_contents
            $w = @file_put_contents( $path, $bin );
            if ( false !== $w ) {
                $artifacts[] = array(
                    'type' => 'xlsx',
                    'name' => $name,
                    'path' => $path,
                    'url'  => $dir_url . $name,
            	);
            }
    	}

    	// PDF (minimal placeholder but truthful)
    	$tcpdf = dirname( __FILE__ ) . '/lib/tcpdf/tcpdf.php';
    	if ( file_exists( $tcpdf ) ) {
            require_once $tcpdf;

            $pdf = new TCPDF();
            $pdf->SetCreator( 'OpsGate' );
            $pdf->SetAuthor( 'OpsGate' );
            $pdf->SetTitle( 'Malware Check Report' );
            $pdf->setPrintHeader( false );
            $pdf->setPrintFooter( false );
            $pdf->AddPage();

            $normalized = self::malware_normalized_payload( $result );

            $type     = isset( $normalized['type'] ) ? (string) $normalized['type'] : 'malware_check';
            $service  = isset( $normalized['service'] ) ? (string) $normalized['service'] : 'malware';
            $ts_utc   = isset( $normalized['ts_utc'] )
                ? (string) $normalized['ts_utc']
                : (string) ( $result['last_run_at_utc'] ?? '' );
            $ok       = isset( $normalized['ok'] ) ? (bool) $normalized['ok'] : false;
            $outcome  = isset( $normalized['outcome'] ) ? (string) $normalized['outcome'] : '';
            $summary  = isset( $normalized['summary'] ) && is_array( $normalized['summary'] )
                ? $normalized['summary']
                : array();
            $files    = (int) ( $summary['files_checked'] ?? 0 );
            $hits     = (int) ( $summary['suspicious_found'] ?? 0 );
            $note     = isset( $normalized['note'] ) ? (string) $normalized['note'] : '';
            $findings = isset( $normalized['findings'] ) && is_array( $normalized['findings'] )
                ? $normalized['findings']
                : array();

            $exclusions = isset( $normalized['exclusions'] ) && is_array( $normalized['exclusions'] )
                ? $normalized['exclusions']
                : array();

            $findings_count = count( $findings );

            $html  = '<h2>Malware Check</h2>';
            $html .= '<p><strong>Report for:</strong> ' . esc_html( self::evidence_site_label() ) . '</p>';
            $html .= '<p><strong>Last run (UTC):</strong> ' . esc_html( $ts_utc ) . '</p>';
            $html .= '<p><strong>Status:</strong> ' . esc_html( $ok ? 'ok' : 'attention' ) . '</p>';
            $html .= '<p><strong>Outcome:</strong> ' . esc_html( $outcome ) . '</p>';
            $html .= '<p><strong>Files checked:</strong> ' . esc_html( (string) $files ) .
                ' &nbsp; <strong>Findings:</strong> ' . esc_html( (string) $hits ) . '</p>';

            if ( '' !== $note ) {
                $html .= '<p style="color:#555;">' . esc_html( $note ) . '</p>';
            }

            if ( $findings_count > 0 ) {
                $html .= '<h3>Findings (bounded)</h3>';
                $html .= '<table border="1" cellpadding="6" cellspacing="0">';
                $html .= '<thead><tr><th><strong>Path</strong></th><th><strong>Indicator</strong></th></tr></thead><tbody>';

                $max_rows = 50;
                $i = 0;
                foreach ( $findings as $f ) {
                    if ( $i >= $max_rows ) {
                        break;
                    }
                    if ( ! is_array( $f ) ) {
                        continue;
                    }
                    $p   = isset( $f['path'] ) ? (string) $f['path'] : '';
                    $ind = isset( $f['indicator'] ) ? (string) $f['indicator'] : '';
                    $html .= '<tr><td>' . esc_html( $p ) . '</td><td>' . esc_html( $ind ) . '</td></tr>';
                    $i++;
                }

                $html .= '</tbody></table>';
            }

            if ( ! empty( $exclusions ) ) {
                $html .= '<h3>Exclusions</h3><ul>';
                foreach ( $exclusions as $ex ) {
                    $html .= '<li>' . esc_html( (string) $ex ) . '</li>';
                }
                $html .= '</ul>';
            }

            $html .= '<p style="color:#666; font-size:10px;">This check looks for common suspicious indicators and does not guarantee the site is clean.</p>';

            $pdf->writeHTML( $html, true, false, true, false, '' );

            $pdf_bin = $pdf->Output( '', 'S' );
            if ( is_string( $pdf_bin ) && '' !== $pdf_bin ) {
                $name = self::malware_run_filename( $run_id, 'pdf' );
            	$path = $dir_abs . $name;
            	// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_write_file_put_contents
            	$w = @file_put_contents( $path, $pdf_bin );
            	if ( false !== $w ) {
                    $artifacts[] = array(
                    	'type' => 'pdf',
                    	'name' => $name,
                    	'path' => $path,
                    	'url'  => $dir_url . $name,
                     );
            	}
            }
    	}

    	return $artifacts;
    }


    /**
     * Day 19.1: Malware exports — PDF/JSON/CSV/XLSX
     * WordPress.org-safe:
     * - Capability + nonce protected.
     * - No external network calls.
     * - No internal tooling exposed.
     */

    private static function malware_export_snapshot(): array {
    	$snap = get_option( 'opsgate_malware_export_snapshot', array() );

        if ( ! is_array( $snap ) ) {
    	    $snap = array();
        }

    	$last = get_option( 'opsgate_malware_last_result', array() );
	$hist = get_option( 'opsgate_malware_history', array() );

    	$snap_last = isset( $snap['last'] ) && is_array( $snap['last'] ) ? $snap['last'] : ( is_array( $last ) ? $last : array() );
        $snap_hist = isset( $snap['history'] ) && is_array( $snap['history'] ) ? $snap['history'] : ( is_array( $hist ) ? $hist : array() );

          return array(
              'ts_utc'     => gmdate( 'Y-m-d\TH:i:s\Z' ),
              'normalized' => self::malware_normalized_payload( $snap_last ),
              'last'       => $snap_last,
              'history'    => $snap_hist,
          );

    }


      private static function malware_export_rows( array $snapshot ): array {
          $rows = array();

          $normalized = isset( $snapshot['normalized'] ) && is_array( $snapshot['normalized'] )
              ? $snapshot['normalized']
              : array();

          $type    = isset( $normalized['type'] ) ? (string) $normalized['type'] : 'malware_check';
          $service = isset( $normalized['service'] ) ? (string) $normalized['service'] : 'malware';
          $ts_utc  = isset( $normalized['ts_utc'] ) ? (string) $normalized['ts_utc'] : '';
          $ok      = isset( $normalized['ok'] ) ? (bool) $normalized['ok'] : false;
          $outcome = isset( $normalized['outcome'] ) ? (string) $normalized['outcome'] : '';

          $summary = isset( $normalized['summary'] ) && is_array( $normalized['summary'] )
              ? $normalized['summary']
              : array();

          $files_checked    = (int) ( $summary['files_checked'] ?? 0 );
          $suspicious_found = (int) ( $summary['suspicious_found'] ?? 0 );

          $note = isset( $normalized['note'] ) ? (string) $normalized['note'] : '';

          $findings = isset( $normalized['findings'] ) && is_array( $normalized['findings'] )
              ? $normalized['findings']
              : array();

          $findings_count = count( $findings );

          // Row set is meaning-stable across CSV and XLSX.
          $rows[] = array(
              'type',
              'service',
              'ts_utc',
              'ok',
              'outcome',
              'files_checked',
              'suspicious_found',
              'findings_count',
              'note',
          );

          $rows[] = array(
              $type,
              $service,
              $ts_utc,
              $ok ? 'true' : 'false',
              $outcome,
              (string) $files_checked,
              (string) $suspicious_found,
              (string) $findings_count,
              $note,
          );

          // Append a bounded findings table (still meaning-stable).
          $rows[] = array( 'finding_path', 'indicator' );

          $max_rows = 50;
          $i = 0;

          foreach ( $findings as $f ) {
              if ( $i >= $max_rows ) {
                  break;
              }

              if ( ! is_array( $f ) ) {
                  continue;
              }

              $path = isset( $f['path'] ) ? (string) $f['path'] : '';
              $ind  = isset( $f['indicator'] ) ? (string) $f['indicator'] : '';

              $rows[] = array( $path, $ind );
              $i++;
          }

          return $rows;
      }

    private static function malware_export_filename( string $ext ): string {
    	$stamp = gmdate( 'Ymd-His' );
    	$ext   = ltrim( strtolower( trim( $ext ) ), '.' );
    	return 'opsgate-malware-check-' . $stamp . '.' . $ext;
    }

    private static function malware_send_download( string $filename, string $content_type, string $body ): void {
    	nocache_headers();
    	header( 'Content-Type: ' . $content_type );
    	header( 'Content-Disposition: attachment; filename="' . sanitize_file_name( $filename ) . '"' );
    	header( 'X-Content-Type-Options: nosniff' );
    	echo $body; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
    	exit;
    }

    public static function handle_malware_download_json(): void {
    	if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
    	}

    	check_admin_referer( 'opsgate_malware_download_json' );

    	$snapshot = self::malware_export_snapshot();
    	$payload  = array(
            'type'     => 'malware_check',
            'exported' => $snapshot['ts_utc'],
            'evidence_for' => self::evidence_site_label(),
            'data'     => $snapshot,
    	);

    	$json = wp_json_encode( $payload, JSON_PRETTY_PRINT );
    	if ( false === $json ) {
            wp_die( 'Could not generate JSON.', 500 );
    	}

        self::malware_send_download( self::malware_export_filename( 'json' ), 'application/json; charset=utf-8', $json );
    }

    public static function handle_malware_download_csv(): void {
    	if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
    	}

    	check_admin_referer( 'opsgate_malware_download_csv' );

    	$snapshot = self::malware_export_snapshot();
     	$rows     = self::malware_export_rows( $snapshot );

        $fh = fopen( 'php://temp', 'w+' );
    	if ( false === $fh ) {
            wp_die( 'Could not generate CSV.', 500 );
    	}

        foreach ( $rows as $r ) {
    	    fputcsv( $fh, $r );
    	}

    	rewind( $fh );
	$csv = stream_get_contents( $fh );
	fclose( $fh );

    	if ( false === $csv ) {
            wp_die( 'Could not generate CSV.', 500 );
    	}

	self::malware_send_download( self::malware_export_filename( 'csv' ), 'text/csv; charset=utf-8', $csv );
    }

    /**
     * Minimal XLSX writer (single sheet) using ZipArchive.
     * WordPress.org-safe: no external libs.
     */
    private static function malware_build_xlsx( array $rows ): string {
    	if ( ! class_exists( 'ZipArchive' ) ) {
            return '';
    	}

    	$sheet_rows_xml = '';
    	$r_index = 1;

    	foreach ( $rows as $row ) {
            $c_index = 1;
            $sheet_rows_xml .= '<row r="' . $r_index . '">';

            foreach ( $row as $cell ) {
            	$val = (string) $cell;
            	$ref = self::malware_xlsx_col( $c_index ) . $r_index;

            	$sheet_rows_xml .= '<c r="' . $ref . '" t="inlineStr"><is><t>'
                    . htmlspecialchars( $val, ENT_QUOTES | ENT_XML1, 'UTF-8' )
                    . '</t></is></c>';
            	$c_index++;
            }

            $sheet_rows_xml .= '</row>';
            $r_index++;
        }

    	$sheet_xml =
            '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
            . '<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">'
            . '<sheetData>' . $sheet_rows_xml . '</sheetData>'
            . '</worksheet>';

    	$workbook_xml =
            '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
            . '<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" '
            . 'xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">'
            . '<sheets><sheet name="Malware Check" sheetId="1" r:id="rId1"/></sheets>'
            . '</workbook>';

    	$rels_xml =
            '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
            . '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'
            . '<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>'
            . '</Relationships>';

        $workbook_rels_xml =
            '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
            . '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'
            . '<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/>'
            . '</Relationships>';

    	$content_types_xml =
            '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
            . '<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">'
            . '<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>'
            . '<Default Extension="xml" ContentType="application/xml"/>'
            . '<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>'
            . '<Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>'
            . '</Types>';

    	$tmp = wp_tempnam( 'opsgate-malware-xlsx' );
        if ( ! is_string( $tmp ) || '' === $tmp ) {
            return '';
        }

    	$zip = new ZipArchive();
    	$ok  = $zip->open( $tmp, ZipArchive::OVERWRITE );
    	if ( true !== $ok ) {
            @unlink( $tmp );
            return '';
    	}

    	$zip->addFromString( '[Content_Types].xml', $content_types_xml );
    	$zip->addFromString( '_rels/.rels', $rels_xml );
    	$zip->addFromString( 'xl/workbook.xml', $workbook_xml );
    	$zip->addFromString( 'xl/_rels/workbook.xml.rels', $workbook_rels_xml );
    	$zip->addFromString( 'xl/worksheets/sheet1.xml', $sheet_xml );
    	$zip->close();

    	$bin = file_get_contents( $tmp );
    	@unlink( $tmp );

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

    private static function malware_xlsx_col( int $n ): string {
    	$n = max( 1, $n );
    	$s = '';
    	while ( $n > 0 ) {
            $n--;
            $s = chr( 65 + ( $n % 26 ) ) . $s;
            $n = (int) floor( $n / 26 );
    	}
        return $s;
    }

    public static function handle_malware_download_xlsx(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
    	}

    	check_admin_referer( 'opsgate_malware_download_xlsx' );

    	$snapshot = self::malware_export_snapshot();
    	$rows     = self::malware_export_rows( $snapshot );

    	$bin = self::malware_build_xlsx( $rows );
        if ( '' === $bin ) {
            wp_die( 'Could not generate Excel file.', 500 );
        }

    	self::malware_send_download(
            self::malware_export_filename( 'xlsx' ),
            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            $bin
        );
    }

    public static function handle_malware_download_pdf(): void {
    	if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
    	}

    	check_admin_referer( 'opsgate_malware_download_pdf' );

    	// TCPDF bundling is locked (Day 18). We only require the bundled file.
    	$tcpdf = dirname( __FILE__ ) . '/lib/tcpdf/tcpdf.php';
    	if ( ! file_exists( $tcpdf ) ) {
            wp_die( 'PDF generator is not available.', 500 );
    	}

    	require_once $tcpdf;

    	$snapshot = self::malware_export_snapshot();
    	$last     = isset( $snapshot['last'] ) && is_array( $snapshot['last'] ) ? $snapshot['last'] : array();

    	$last_run = isset( $last['last_run_at_utc'] ) ? (string) $last['last_run_at_utc'] : '';
    	$status   = isset( $last['status'] ) ? (string) $last['status'] : 'never';
    	$files    = (int) ( $last['files_checked'] ?? 0 );
    	$hits     = (int) ( $last['suspicious_found'] ?? 0 );

    	$display_run = $last_run;
    	if ( '' !== $last_run ) {
            try {
            	$dt = new DateTimeImmutable( $last_run, new DateTimeZone( 'UTC' ) );
            	$display_run = $dt->format( 'M d, Y H:i' ) . ' UTC';
            } catch ( Exception $e ) {
                $display_run = $last_run;
            }
        }

    	$pdf = new TCPDF();
    	$pdf->SetCreator( 'OpsGate' );
    	$pdf->SetAuthor( 'OpsGate' );
    	$pdf->SetTitle( 'Malware Check Report' );
    	$pdf->setPrintHeader( false );
    	$pdf->setPrintFooter( false );
    	$pdf->AddPage();

    	$html  = '<h2>Malware Check</h2>';
    	$html .= '<p><strong>Report for:</strong> ' . esc_html( self::evidence_site_label() ) . '</p>';
    	$html .= '<p><strong>Last run (UTC):</strong> ' . esc_html( $display_run ?: 'Not yet' ) . '</p>';
    	$html .= '<p><strong>Status:</strong> ' . esc_html( $status ) . '</p>';
    	$html .= '<p><strong>Files checked:</strong> ' . esc_html( (string) $files ) . ' &nbsp; <strong>Findings:</strong> ' . esc_html( (string) $hits ) . '</p>';
    	$html .= '<p style="color:#555;">This report records your malware check outcome and keeps proof available for sharing.</p>';

    	$pdf->writeHTML( $html, true, false, true, false, '' );

    	$bin = $pdf->Output( '', 'S' );
    	if ( ! is_string( $bin ) || '' === $bin ) {
            wp_die( 'Could not generate PDF.', 500 );
    	}

    	self::malware_send_download( self::malware_export_filename( 'pdf' ), 'application/pdf', $bin );
    }

    // =========================================================================
    // Day 19.4 (Step C): Scheduled Runs export handlers (PDF/JSON/CSV/XLSX).
    // On-demand only. Local files only. No external calls.
    // =========================================================================

    private static function scheduled_receipts_dir_abs(): string {
        $uploads = wp_upload_dir( null, false );
        $base    = isset( $uploads['basedir'] ) ? (string) $uploads['basedir'] : '';
        if ( '' === $base ) {
            return '';
        }
        return trailingslashit( $base ) . 'opsgate/scheduled/';
    }

    private static function scheduled_validate_receipt_file( string $file ): string {
        $file = sanitize_file_name( $file );

        if ( '' === $file ) {
            return '';
        }
        if ( false !== strpos( $file, '..' ) ) {
            return '';
        }
        if ( ! str_ends_with( $file, '.json' ) ) {
            return '';
        }
        // Must be a scheduled receipt filename.
        if ( 0 !== strpos( $file, 'scheduled_' ) ) {
            return '';
        }

        return $file;
    }

    private static function scheduled_load_receipt_payload( string $file ): array {
        $dir = self::scheduled_receipts_dir_abs();
        if ( '' === $dir ) {
            return array();
        }

        $path = $dir . $file;
        if ( ! file_exists( $path ) || ! is_readable( $path ) ) {
            return array();
        }

        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_file_get_contents
        $raw = file_get_contents( $path );
        if ( ! is_string( $raw ) || '' === $raw ) {
            return array();
        }

        $decoded = json_decode( $raw, true );
        return is_array( $decoded ) ? $decoded : array();
    }

    private static function scheduled_normalize_receipt_payload( array $payload, string $receipt_file ): array {
        if ( ! is_array( $payload ) ) {
            $payload = array();
        }

        // Filename format: scheduled_{service}_{YYYYMMDD-HHMMSS}.json
    	$service_from_file = '';
    	$stamp_from_file   = '';

    	if ( preg_match( '/^scheduled_(.+)_(\d{8}-\d{6})\.json$/', $receipt_file, $m ) ) {
            $service_from_file = isset( $m[1] ) ? (string) $m[1] : '';
            $stamp_from_file   = isset( $m[2] ) ? (string) $m[2] : '';
        }

    	if ( ! isset( $payload['type'] ) || '' === (string) $payload['type'] ) {
            $payload['type'] = 'scheduled_run_receipt';
    	}

    	if ( ( ! isset( $payload['service'] ) || '' === (string) $payload['service'] ) && '' !== $service_from_file ) {
            $payload['service'] = $service_from_file;
    	}

    	// If ts_utc is missing, derive from stamp and convert to ISO UTC.
    	if ( ! isset( $payload['ts_utc'] ) || '' === (string) $payload['ts_utc'] ) {
            if ( preg_match( '/^\d{8}-\d{6}$/', $stamp_from_file ) ) {
                $yyyy = substr( $stamp_from_file, 0, 4 );
            	$mm   = substr( $stamp_from_file, 4, 2 );
            	$dd   = substr( $stamp_from_file, 6, 2 );
            	$hh   = substr( $stamp_from_file, 9, 2 );
            	$mi   = substr( $stamp_from_file, 11, 2 );
            	$ss   = substr( $stamp_from_file, 13, 2 );

            	$payload['ts_utc'] = $yyyy . '-' . $mm . '-' . $dd . 'T' . $hh . ':' . $mi . ':' . $ss . 'Z';
            }
    	}

    	return $payload;
    }


    private static function scheduled_export_filename( string $receipt_file, string $ext ): string {
        $ext = ltrim( strtolower( trim( $ext ) ), '.' );

        $base = preg_replace( '/\.json$/', '', $receipt_file );
        $base = is_string( $base ) ? $base : 'scheduled-receipt';

        // Keep filenames short + safe.
        $base = substr( sanitize_file_name( $base ), 0, 140 );
        if ( '' === $base ) {
            $base = 'scheduled-receipt';
        }

        return $base . '.' . $ext;
    }

    private static function scheduled_send_download( string $filename, string $content_type, string $body ): void {
        nocache_headers();
        header( 'Content-Type: ' . $content_type );
        header( 'Content-Disposition: attachment; filename="' . sanitize_file_name( $filename ) . '"' );
        header( 'X-Content-Type-Options: nosniff' );
        echo $body; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
        exit;
    }

    private static function scheduled_export_rows_from_receipt( array $receipt, string $receipt_file ): array {
        $rows = array();

        $type = isset( $receipt['type'] ) ? (string) $receipt['type'] : 'scheduled_run_receipt';
        $ts   = isset( $receipt['ts_utc'] ) ? (string) $receipt['ts_utc'] : '';
        $svc  = isset( $receipt['service'] ) ? (string) $receipt['service'] : '';
        $ok   = isset( $receipt['ok'] ) ? ( $receipt['ok'] ? 'true' : 'false' ) : '';
        $note = isset( $receipt['note'] ) ? (string) $receipt['note'] : '';

        $rows[] = array( 'field', 'value' );
        $rows[] = array( 'receipt_file', $receipt_file );
        $rows[] = array( 'type', $type );
        $rows[] = array( 'ts_utc', $ts );
        $rows[] = array( 'service', $svc );
        $rows[] = array( 'ok', $ok );
        $rows[] = array( 'note', $note );
        $rows[] = array( 'evidence_for', self::evidence_site_label() );

        // If receipt contains a summary array, flatten it as key/value.
        if ( isset( $receipt['summary'] ) && is_array( $receipt['summary'] ) ) {
            foreach ( $receipt['summary'] as $k => $v ) {
                if ( is_scalar( $v ) || null === $v ) {
                    $rows[] = array( 'summary.' . (string) $k, (string) ( $v ?? '' ) );
                } else {
                    $rows[] = array( 'summary.' . (string) $k, wp_json_encode( $v ) ?: '' );
                }
            }
        }

        return $rows;
    }


    public static function handle_run_scheduled_now(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_run_scheduled_now' );
        wp_safe_redirect( self::admin_tab_url( 'settings' ) );
        exit;
    }

    /**
     * Day 20.3: Recovery Request (manual, local-only).
     * WordPress.org compliance:
     * - No network calls
     * - No background work
     * - Creates a local receipt artifact for audit and proof
     */
    public static function handle_recovery_request_submit(): void {

        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_recovery_request_submit', 'opsgate_recovery_request_nonce' );

        $ts_utc = gmdate( 'Y-m-d\TH:i:s\Z' );
        $stamp  = gmdate( 'Ymd-His' );

        // phpcs:ignore WordPress.Security.NonceVerification.Missing
        $reason = isset( $_POST['opsgate_recovery_reason'] ) ? (string) wp_unslash( $_POST['opsgate_recovery_reason'] ) : '';
        $reason = sanitize_textarea_field( $reason );

        // phpcs:ignore WordPress.Security.NonceVerification.Missing
        $urgency = isset( $_POST['opsgate_recovery_urgency'] ) ? (string) wp_unslash( $_POST['opsgate_recovery_urgency'] ) : 'normal';
        $urgency = sanitize_key( $urgency );

        $allowed_urgency = array( 'low', 'normal', 'high' );
        if ( ! in_array( $urgency, $allowed_urgency, true ) ) {
            $urgency = 'normal';
        }

        $run = self::core_run_action(
            'recovery_request',
            array(
                'urgency' => $urgency,
            ),
            function() use ( $ts_utc, $stamp, $reason, $urgency ) {

                $uploads = wp_upload_dir( null, false );
                $basedir = isset( $uploads['basedir'] ) ? (string) $uploads['basedir'] : '';

                if ( '' === $basedir ) {
                    return array(
                        'ok'   => false,
                        'note' => 'Uploads directory is not available.',
                    );
                }

                $dir = rtrim( $basedir, '/\\' ) . '/opsgate/recovery/';
                if ( ! is_dir( $dir ) ) {
                    // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_mkdir
                    if ( ! mkdir( $dir, 0755, true ) ) {
                        return array(
                            'ok'   => false,
                            'note' => 'Could not create recovery receipts directory.',
                        );
                    }
                }

                $file = 'recovery_request_' . $stamp . '.json';

                $payload = array(
                    'type'       => 'recovery_request',
                    'ts_utc'     => $ts_utc,
                    'urgency'    => $urgency,
                    'reason'     => $reason,
                    'note'       => 'Manual request recorded (no recovery executed).',
                    'evidence_for' => self::evidence_site_label(),
                );

                $json = wp_json_encode( $payload, JSON_PRETTY_PRINT );
                if ( false === $json ) {
                    return array(
                        'ok'   => false,
                        'note' => 'Could not encode recovery request JSON.',
                    );
                }

                $path = $dir . $file;

                // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_write_file_put_contents
                $written = file_put_contents( $path, $json );
                if ( false === $written ) {
                    return array(
                        'ok'   => false,
                        'note' => 'Could not write recovery request receipt.',
                    );
                }

                @chmod( $path, 0644 );

                $rel = 'opsgate/recovery/' . $file;

                return array(
                    'ok'   => true,
                    'note' => 'Recovery request recorded.',
                    'artifacts' => array(
                        array(
                            'type'    => 'recovery_request',
                            'service' => 'recovery',
                            'file'    => $file,
                            'rel'     => $rel,
                            'ts_utc'  => $ts_utc,
                        ),
                    ),
                );
            }
        );

        $ok = isset( $run['ok'] ) ? (bool) $run['ok'] : false;

        if ( ! $ok ) {
            $note = isset( $run['note'] ) ? (string) $run['note'] : 'Recovery request could not be recorded.';
            wp_die( esc_html( $note ), 500 );
        }

        $back = wp_get_referer();
        if ( ! is_string( $back ) || '' === $back ) {
            $back = admin_url( 'admin.php?page=opsgate-reports' );
        }

        $back = add_query_arg(
            array(
                'recovery_requested' => 1,
            ),
            $back
        );

        wp_safe_redirect( $back );
        exit;

    }


        /**
         * Day 20.4: CDN Check (manual, local-only).
         * Produces an auditable JSON receipt and indexes it through core_run_action.
         */
        public static function handle_cdn_check_run(): void {

            if ( ! current_user_can( 'manage_options' ) ) {
                wp_die( 'Forbidden', 403 );
            }

            check_admin_referer( 'opsgate_cdn_check_run' );

            $ts_utc = gmdate( 'Y-m-d\TH:i:s\Z' );
            $stamp  = gmdate( 'Ymd-His' );

            $run = self::core_run_action(
                'cdn_check',
                array(),
                function() use ( $ts_utc, $stamp ) {

                    $uploads = wp_upload_dir( null, false );
                    $basedir = isset( $uploads['basedir'] ) ? (string) $uploads['basedir'] : '';

                    if ( '' === $basedir ) {
                        return array(
                            'ok'   => false,
                            'note' => 'Uploads directory is not available.',
                        );
                    }

                    $dir = rtrim( $basedir, '/\\' ) . '/opsgate/cdn/';
                    if ( ! is_dir( $dir ) ) {
                        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_mkdir
                        if ( ! mkdir( $dir, 0755, true ) ) {
                            return array(
                                'ok'   => false,
                                'note' => 'Could not create CDN receipts directory.',
                            );
                        }
                    }

                    $active_plugins = get_option( 'active_plugins', array() );
                    $active_plugins = is_array( $active_plugins ) ? $active_plugins : array();

                    $plugins_seen = array();
                    foreach ( $active_plugins as $p ) {
                        if ( is_string( $p ) && '' !== $p ) {
                            $plugins_seen[] = $p;
                        }
                    }

                    $signals = array();

                    // Conservative, local-only signals (no assumptions, no network).
                    $cdn_candidates = array(
                        'cloudflare',
                        'wp-cloudflare',
                        'wp-cloudflare-page-cache',
                        'wp-super-cache',
                        'w3-total-cache',
                        'litespeed-cache',
                        'wp-rocket',
                        'autoptimize',
                        'cache-enabler',
                        'swift-performance',
                        'wp-fastest-cache',
                        'sg-cachepress',
                    );

                    foreach ( $plugins_seen as $slug ) {
                        foreach ( $cdn_candidates as $needle ) {
                            if ( false !== stripos( $slug, $needle ) ) {
                                $signals[] = 'plugin:' . $needle;
                                break;
                            }
                        }
                    }

                    // Optional local URL cues (no claims; just recorded).
                    $home = (string) home_url();
                    $site = (string) site_url();

                    if ( '' !== $home ) {
                        $signals[] = 'home_url:' . ( 0 === stripos( $home, 'https://' ) ? 'https' : 'non_https_or_unknown' );
                    }
                    if ( '' !== $site ) {
                        $signals[] = 'site_url:' . ( 0 === stripos( $site, 'https://' ) ? 'https' : 'non_https_or_unknown' );
                    }

                    $headers_seen = array(); // Local-only. No remote fetch.

                    $outcome = 'inconclusive';
                    if ( ! empty( $signals ) ) {
                        // If we found any local signals, we report "detected" conservatively.
                        // Detection here means "signals consistent with", not "verified edge headers".
                        $outcome = 'detected';
                    } else {
                        $outcome = 'not_detected';
                    }

                    $payload = array(
                        'type'    => 'cdn_check',
                        'ts_utc'  => $ts_utc,
                        'ok'      => true,
                        'outcome' => $outcome,
                        'summary' => array(
                            'signals'      => array_values( array_unique( $signals ) ),
                            'headers_seen' => $headers_seen,
                            'plugins_seen' => $plugins_seen,
                            'notes'        => 'Local-only posture signals derived from WordPress configuration. No external requests were performed.',
                        ),
                        'note'         => 'CDN posture check recorded. No configuration changes were made.',
                        'evidence_for' => self::evidence_site_label(),
                    );

                    $json = wp_json_encode( $payload, JSON_PRETTY_PRINT );
                    if ( false === $json ) {
                        return array(
                            'ok'   => false,
                            'note' => 'Could not encode CDN check JSON.',
                        );
                    }

                    $file = 'cdn_check_' . $stamp . '.json';
                    $path = $dir . $file;

                    // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_write_file_put_contents
                    $written = file_put_contents( $path, $json );
                    if ( false === $written ) {
                        return array(
                            'ok'   => false,
                            'note' => 'Could not write CDN check receipt.',
                        );
                    }

                    @chmod( $path, 0644 );

                    $rel = 'opsgate/cdn/' . $file;

                    return array(
                        'ok'   => true,
                        'note' => 'CDN check recorded.',
                        'artifacts' => array(
                            array(
                                'type'    => 'cdn_check',
                                'service' => 'cdn',
                                'file'    => $file,
                                'rel'     => $rel,
                                'ts_utc'  => $ts_utc,
                            ),
                        ),
                        'outcome' => $outcome,
                    );
                }
            );

            $ok = isset( $run['ok'] ) ? (bool) $run['ok'] : false;

            if ( ! $ok ) {
                $note = isset( $run['note'] ) ? (string) $run['note'] : 'CDN check could not be recorded.';
                wp_die( esc_html( $note ), 500 );
            }

            $cdn_file = '';
            if ( isset( $run['artifacts'] ) && is_array( $run['artifacts'] ) && ! empty( $run['artifacts'] ) ) {
                $first = $run['artifacts'][0];
                if ( is_array( $first ) && isset( $first['file'] ) ) {
                    $cdn_file = (string) $first['file'];
                }
            }

            $outcome = isset( $run['outcome'] ) ? (string) $run['outcome'] : '';

            $back = wp_get_referer();
            if ( ! is_string( $back ) || '' === $back ) {
                $back = admin_url( 'admin.php?page=opsgate&tab=security' );
            }

            $back = add_query_arg(
                array(
                    'cdn_checked' => 1,
                    'cdn_file'    => $cdn_file,
                    'cdn_outcome' => sanitize_key( $outcome ),
                ),
                $back
            );

            wp_safe_redirect( $back );
            exit;
        }


        /**
         * Day 20.4: CDN Check — Prepare (redirect into confirm view).
         * Keeps the execution user-triggered and intentional without checkbox friction.
         */
        public static function handle_cdn_check_prepare(): void {

            if ( ! current_user_can( 'manage_options' ) ) {
                wp_die( 'Forbidden', 403 );
            }

            check_admin_referer( 'opsgate_cdn_check_prepare' );

            $back = wp_get_referer();
            if ( ! is_string( $back ) || '' === $back ) {
                $back = admin_url( 'admin.php?page=opsgate&tab=security' );
            }

            $back = add_query_arg(
                array(
                    'opsgate_cdn_confirm' => 1,
                ),
                $back
            );

            wp_safe_redirect( $back );
            exit;
        }

        /**
         * Day 20.4: List CDN receipt JSON files (most recent first).
         * Pure listing only. No background work. No network calls.
         *
         * @param int $limit
         * @return array<int, array<string, string|int>>
         */
        private static function cdn_receipts_list( $limit = 20 ) {
            $limit = is_numeric( $limit ) ? (int) $limit : 20;
            if ( $limit < 1 ) {
                $limit = 1;
            }
            if ( $limit > 200 ) {
                $limit = 200;
            }

            $uploads = wp_upload_dir( null, false );
            $baseurl = isset( $uploads['baseurl'] ) ? (string) $uploads['baseurl'] : '';
            $basedir = isset( $uploads['basedir'] ) ? (string) $uploads['basedir'] : '';

            if ( '' === $baseurl || '' === $basedir ) {
                return array();
            }

            $dir = rtrim( $basedir, '/\\' ) . '/opsgate/cdn';
            if ( ! is_dir( $dir ) || ! is_readable( $dir ) ) {
                return array();
            }

            $files = glob( $dir . '/cdn_check_*.json' );
            if ( false === $files || empty( $files ) ) {
                return array();
            }

            usort(
                $files,
                function( $a, $b ) {
                    $ta = is_string( $a ) ? (int) ( filemtime( $a ) ?: 0 ) : 0;
                    $tb = is_string( $b ) ? (int) ( filemtime( $b ) ?: 0 ) : 0;
                    return $tb <=> $ta;
                }
            );

            $rows = array();

            foreach ( $files as $abs ) {
                if ( count( $rows ) >= $limit ) {
                    break;
                }
                if ( ! is_string( $abs ) || '' === $abs ) {
                    continue;
                }

                $basename = basename( $abs );
                if ( ! preg_match( '/^cdn_check_\d{8}-\d{6}\.json$/', $basename ) ) {
                    continue;
                }

                $ts = filemtime( $abs );
                $ts = $ts ? (int) $ts : 0;

                $payload = self::cdn_load_receipt_payload( $basename );
                $outcome = isset( $payload['outcome'] ) ? (string) $payload['outcome'] : '';

                $rows[] = array(
                    'file'    => $basename,
                    'ts'      => $ts,
                    'when'    => $ts > 0 ? gmdate( 'Y-m-d H:i:s', $ts ) . ' UTC' : '—',
                    'outcome' => '' !== $outcome ? $outcome : '—',
                );
            }

            return $rows;
        }

        /**
         * Validate a CDN receipt filename (basename only).
         */
        private static function cdn_validate_receipt_file( string $file ): string {
            $file = trim( $file );
            $file = basename( $file );

            if ( '' === $file ) {
                return '';
            }

            if ( ! preg_match( '/^cdn_check_\d{8}-\d{6}\.json$/', $file ) ) {
                return '';
            }

            return $file;
        }

        /**
         * Load CDN receipt JSON payload (local).
         *
         * @return array<string,mixed>
         */
        private static function cdn_load_receipt_payload( string $file ): array {
            $uploads = wp_upload_dir( null, false );
            $basedir = isset( $uploads['basedir'] ) ? (string) $uploads['basedir'] : '';
            if ( '' === $basedir ) {
                return array();
            }

            $abs = rtrim( $basedir, '/\\' ) . '/opsgate/cdn/' . $file;

            if ( ! file_exists( $abs ) || ! is_readable( $abs ) ) {
                return array();
            }

            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
            $raw = file_get_contents( $abs );
            if ( ! is_string( $raw ) || '' === $raw ) {
                return array();
            }

            $decoded = json_decode( $raw, true );
            return is_array( $decoded ) ? $decoded : array();
        }

        /**
         * Send a local download (small payloads only).
         */
        private static function cdn_send_download( string $filename, string $content_type, string $body ): void {
            nocache_headers();
            header( 'Content-Type: ' . $content_type );
            header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
            header( 'Content-Length: ' . (string) strlen( $body ) );
            echo $body; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
            exit;
        }

        /**
         * Admin-post: Download CDN Check receipt JSON (validated local file).
         */
        public static function handle_cdn_download_json(): void {
            if ( ! current_user_can( 'manage_options' ) ) {
                wp_die( 'Forbidden', 403 );
            }

            check_admin_referer( 'opsgate_cdn_download_json' );

            // phpcs:ignore WordPress.Security.NonceVerification.Recommended
            $file = isset( $_GET['file'] ) ? (string) wp_unslash( $_GET['file'] ) : '';
            $file = self::cdn_validate_receipt_file( $file );
            if ( '' === $file ) {
                wp_die( 'Invalid file', 400 );
            }

            $payload = self::cdn_load_receipt_payload( $file );
            if ( empty( $payload ) ) {
                wp_die( 'Receipt not found', 404 );
            }

            $json = wp_json_encode( $payload, JSON_PRETTY_PRINT );
            if ( false === $json ) {
                wp_die( 'Could not generate JSON.', 500 );
            }

            $export = str_replace( '.json', '', $file ) . '.json';
            self::cdn_send_download( $export, 'application/json; charset=utf-8', $json );
        }


    /**
     * Admin-post: Download Scheduled Runs receipt JSON (validated local file).
     */
    public static function handle_scheduled_download_json(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_scheduled_download_json' );

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $file = isset( $_GET['file'] ) ? (string) wp_unslash( $_GET['file'] ) : '';
        $file = self::scheduled_validate_receipt_file( $file );
        if ( '' === $file ) {
            wp_die( 'Invalid file', 400 );
        }

        $payload = self::scheduled_load_receipt_payload( $file );
	$payload = self::scheduled_normalize_receipt_payload( $payload, $file );
        if ( empty( $payload ) ) {
            wp_die( 'Receipt not found', 404 );
        }

        // Re-encode for consistent export.
        $json = wp_json_encode( $payload, JSON_PRETTY_PRINT );
        if ( false === $json ) {
            wp_die( 'Could not generate JSON.', 500 );
        }

        self::scheduled_send_download( self::scheduled_export_filename( $file, 'json' ), 'application/json; charset=utf-8', $json );
    }

    /**
     * Admin-post: Download Scheduled Runs receipt CSV.
     */
    public static function handle_scheduled_download_csv(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_scheduled_download_csv' );

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $file = isset( $_GET['file'] ) ? (string) wp_unslash( $_GET['file'] ) : '';
        $file = self::scheduled_validate_receipt_file( $file );
        if ( '' === $file ) {
            wp_die( 'Invalid file', 400 );
        }

        $payload = self::scheduled_load_receipt_payload( $file );
	$payload = self::scheduled_normalize_receipt_payload( $payload, $file );
        if ( empty( $payload ) ) {
            wp_die( 'Receipt not found', 404 );
        }

        $rows = self::scheduled_export_rows_from_receipt( $payload, $file );

        $fh = fopen( 'php://temp', 'w+' );
        if ( false === $fh ) {
            wp_die( 'Could not generate CSV.', 500 );
        }

        foreach ( $rows as $r ) {
            fputcsv( $fh, $r );
        }

        rewind( $fh );
        $csv = stream_get_contents( $fh );
        fclose( $fh );

        if ( false === $csv ) {
            wp_die( 'Could not generate CSV.', 500 );
        }

        self::scheduled_send_download( self::scheduled_export_filename( $file, 'csv' ), 'text/csv; charset=utf-8', $csv );
    }

    /**
     * Minimal XLSX writer (single sheet) using ZipArchive.
     * WordPress.org-safe: no external libs.
     */
    private static function scheduled_build_xlsx( array $rows ): string {
        if ( ! class_exists( 'ZipArchive' ) ) {
            return '';
        }

        $sheet_rows_xml = '';
        $r_index = 1;

        foreach ( $rows as $row ) {
            $c_index = 1;
            $sheet_rows_xml .= '<row r="' . $r_index . '">';

            foreach ( $row as $cell ) {
                $val = (string) $cell;
                $ref = self::malware_xlsx_col( $c_index ) . $r_index;

                $sheet_rows_xml .= '<c r="' . $ref . '" t="inlineStr"><is><t>'
                    . htmlspecialchars( $val, ENT_QUOTES | ENT_XML1, 'UTF-8' )
                    . '</t></is></c>';
                $c_index++;
            }

            $sheet_rows_xml .= '</row>';
            $r_index++;
        }

        $sheet_xml =
            '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
            . '<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">'
            . '<sheetData>' . $sheet_rows_xml . '</sheetData>'
            . '</worksheet>';

        $workbook_xml =
            '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
            . '<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" '
            . 'xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">'
            . '<sheets><sheet name="Scheduled Run" sheetId="1" r:id="rId1"/></sheets>'
            . '</workbook>';

        $rels_xml =
            '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
            . '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'
            . '<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>'
            . '</Relationships>';

        $workbook_rels_xml =
            '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
            . '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'
            . '<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/>'
            . '</Relationships>';

        $content_types_xml =
            '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
            . '<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">'
            . '<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>'
            . '<Default Extension="xml" ContentType="application/xml"/>'
            . '<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>'
            . '<Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>'
            . '</Types>';

        $tmp = wp_tempnam( 'opsgate-scheduled-xlsx' );
        if ( ! is_string( $tmp ) || '' === $tmp ) {
            return '';
        }

        $zip = new ZipArchive();
        $ok  = $zip->open( $tmp, ZipArchive::OVERWRITE );
        if ( true !== $ok ) {
            @unlink( $tmp );
            return '';
        }

        $zip->addFromString( '[Content_Types].xml', $content_types_xml );
        $zip->addFromString( '_rels/.rels', $rels_xml );
        $zip->addFromString( 'xl/workbook.xml', $workbook_xml );
        $zip->addFromString( 'xl/_rels/workbook.xml.rels', $workbook_rels_xml );
        $zip->addFromString( 'xl/worksheets/sheet1.xml', $sheet_xml );
        $zip->close();

        $bin = file_get_contents( $tmp );
        @unlink( $tmp );

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

    /**
     * Admin-post: Download Scheduled Runs receipt XLSX.
     */
    public static function handle_scheduled_download_xlsx(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_scheduled_download_xlsx' );

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $file = isset( $_GET['file'] ) ? (string) wp_unslash( $_GET['file'] ) : '';
        $file = self::scheduled_validate_receipt_file( $file );
        if ( '' === $file ) {
            wp_die( 'Invalid file', 400 );
        }

        $payload = self::scheduled_load_receipt_payload( $file );
	$payload = self::scheduled_normalize_receipt_payload( $payload, $file );
        if ( empty( $payload ) ) {
            wp_die( 'Receipt not found', 404 );
        }

        $rows = self::scheduled_export_rows_from_receipt( $payload, $file );

        $bin = self::scheduled_build_xlsx( $rows );
        if ( '' === $bin ) {
            wp_die( 'Could not generate Excel file.', 500 );
        }

        self::scheduled_send_download(
            self::scheduled_export_filename( $file, 'xlsx' ),
            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            $bin
        );
    }

    /**
     * Admin-post: Download Scheduled Runs receipt PDF.
     */
    public static function handle_scheduled_download_pdf(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_scheduled_download_pdf' );

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $file = isset( $_GET['file'] ) ? (string) wp_unslash( $_GET['file'] ) : '';
        $file = self::scheduled_validate_receipt_file( $file );
        if ( '' === $file ) {
            wp_die( 'Invalid file', 400 );
        }

        $payload = self::scheduled_load_receipt_payload( $file );
	$payload = self::scheduled_normalize_receipt_payload( $payload, $file );
        if ( empty( $payload ) ) {
            wp_die( 'Receipt not found', 404 );
        }

        // TCPDF bundling is locked (Day 18). We only require the bundled file.
        $tcpdf = dirname( __FILE__ ) . '/lib/tcpdf/tcpdf.php';
        if ( ! file_exists( $tcpdf ) ) {
            wp_die( 'PDF generator is not available.', 500 );
        }

        require_once $tcpdf;

        $type = isset( $payload['type'] ) ? (string) $payload['type'] : 'scheduled_run_receipt';
        $ts   = isset( $payload['ts_utc'] ) ? (string) $payload['ts_utc'] : '';
        $svc  = isset( $payload['service'] ) ? (string) $payload['service'] : '';
        $ok   = isset( $payload['ok'] ) ? ( $payload['ok'] ? 'Completed' : 'Attention' ) : '—';
        $note = isset( $payload['note'] ) ? (string) $payload['note'] : '';

        $display_ts = $ts;
        if ( '' !== $ts ) {
            try {
                $dt = new DateTimeImmutable( $ts, new DateTimeZone( 'UTC' ) );
                $display_ts = $dt->format( 'M d, Y H:i' ) . ' UTC';
            } catch ( Exception $e ) {
                $display_ts = $ts;
            }
        }

        $pdf = new TCPDF();
        $pdf->SetCreator( 'OpsGate' );
        $pdf->SetAuthor( 'OpsGate' );
        $pdf->SetTitle( 'Scheduled Run Receipt' );
        $pdf->setPrintHeader( false );
        $pdf->setPrintFooter( false );
        $pdf->AddPage();

        $html  = '<h2>Scheduled Run Receipt</h2>';
        $html .= '<p><strong>Report for:</strong> ' . esc_html( self::evidence_site_label() ) . '</p>';
        $html .= '<p><strong>Service:</strong> ' . esc_html( self::service_display_name( $svc ?: '—' ) ) . '</p>';
        $html .= '<p><strong>Timestamp (UTC):</strong> ' . esc_html( $display_ts ?: '—' ) . '</p>';
        $html .= '<p><strong>Outcome:</strong> ' . esc_html( $ok ) . '</p>';

        if ( '' !== $note ) {
            $html .= '<p><strong>Notes:</strong> ' . esc_html( $note ) . '</p>';
        }

        $html .= '<p style="color:#555;">This receipt records that a scheduled run was evaluated and saved for audit and proof.</p>';
        $html .= '<p style="color:#777;font-size:10px;">Receipt type: ' . esc_html( $type ) . ' · File: ' . esc_html( $file ) . '</p>';

        $pdf->writeHTML( $html, true, false, true, false, '' );

        $bin = $pdf->Output( '', 'S' );
        if ( ! is_string( $bin ) || '' === $bin ) {
            wp_die( 'Could not generate PDF.', 500 );
        }

        self::scheduled_send_download( self::scheduled_export_filename( $file, 'pdf' ), 'application/pdf', $bin );
    }


    /**
     * Admin-post: Apply .htaccess hardening.
     */
    public static function handle_htaccess_apply(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_htaccess_apply', 'opsgate_htaccess_apply_nonce' );

        $result   = self::htaccess_apply_internal();
        $evidence = self::hardening_write_evidence( 'apply', $result );

        self::activity_timeline_add(
            $result['ok'] ? 'Protection applied' : 'Protection needs attention',
            $result['ok'] ? 'completed' : 'attention',
            $result['ok']
                ? 'OpsGate applied a protection update to reduce exposure to common file-based attacks.'
                : ( $result['message'] ?? 'OpsGate could not apply the protection update. Please try again.' )
        );

        $redirect = admin_url( 'admin.php?page=opsgate&tab=security' );
        $redirect = add_query_arg( 'opsgate_hardening', $result['ok'] ? 'applied' : 'error', $redirect );

        wp_safe_redirect( $redirect );
        exit;
    }

    /**
     * Admin-post: Revert .htaccess hardening.
     */
    public static function handle_htaccess_revert(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_htaccess_revert', 'opsgate_htaccess_revert_nonce' );

        $result   = self::htaccess_revert_internal();
        $evidence = self::hardening_write_evidence( 'revert', $result );

        self::activity_timeline_add(
            $result['ok'] ? 'Protection reverted' : 'Protection needs attention',
            $result['ok'] ? 'completed' : 'attention',
            $result['ok']
                ? 'OpsGate reverted the protection update and restored your previous configuration.'
                : ( $result['message'] ?? 'OpsGate could not revert the protection update. Please try again.' )
        );

        $redirect = admin_url( 'admin.php?page=opsgate&tab=security' );
        $redirect = add_query_arg( 'opsgate_hardening', $result['ok'] ? 'reverted' : 'error', $redirect );

        wp_safe_redirect( $redirect );
        exit;
    }

    /**
     * Backup engine (local-first).
     * @return array{ok:bool,file:string,size:int,message:string}
     */
    private static function backup_run_now(): array {
        @set_time_limit( 300 );

        $dir = self::backup_dir_abs();
        if ( ! self::ensure_dir( $dir ) ) {
            return self::backup_record( false, '', 0, 'Failed to create backup directory.' );
        }

        $ts    = time();
        $stamp = gmdate( 'Ymd-His', $ts );

        $zip_file = "backup_{$stamp}.zip";
        $zip_path = $dir . $zip_file;

        $tmp_sql = $dir . "database_{$stamp}.sql";

        // 1) Export database to temp SQL file
        if ( ! self::backup_dump_database_sql( $tmp_sql ) ) {
            return self::backup_record( false, '', 0, 'Database export failed.' );
        }

        // 2) Create ZIP (wp-content + database.sql)
        if ( ! class_exists( 'ZipArchive' ) ) {
            @unlink( $tmp_sql );
            return self::backup_record( false, '', 0, 'ZIP support is not available on this server.' );
        }

        $zip = new ZipArchive();
        if ( true !== $zip->open( $zip_path, ZipArchive::CREATE | ZipArchive::OVERWRITE ) ) {
            @unlink( $tmp_sql );
            return self::backup_record( false, '', 0, 'Failed to create ZIP archive.' );
        }

        $zip->addFile( $tmp_sql, 'database.sql' );

	// Full restore scope (Wordfence-style): DB + uploads + plugins + themes.
	// NOTE: OpsGate proprietary code + OpsGate internal artifacts are excluded in backup_zip_add_directory().
	$uploads_dir = wp_upload_dir();
	$uploads_abs = isset( $uploads_dir['basedir'] ) ? (string) $uploads_dir['basedir'] : '';
	$plugins_abs = defined( 'WP_PLUGIN_DIR' ) ? (string) WP_PLUGIN_DIR : '';
	$themes_abs  = function_exists( 'get_theme_root' ) ? (string) get_theme_root() : '';


	// 1) Uploads (customer content: media + site assets)
	if ( '' !== $uploads_abs && is_dir( $uploads_abs ) ) {
	    self::backup_zip_add_directory( $zip, $uploads_abs, 'wp-content/uploads' );
	}

	// 2) Plugins (site functionality)
	if ( '' !== $plugins_abs && is_dir( $plugins_abs ) ) {
	    self::backup_zip_add_directory( $zip, $plugins_abs, 'wp-content/plugins' );
	}

	// 3) Themes (site theme)
	if ( '' !== $themes_abs && is_dir( $themes_abs ) ) {
	    self::backup_zip_add_directory( $zip, $themes_abs, 'wp-content/themes' );
	}


        // Add a small customer-readable manifest (no internals).
	$readme = "OpsGate Backup\n"
	    . "Generated: " . gmdate( 'c' ) . " UTC\n"
	    . "Includes:\n"
	    . "- database.sql\n"
	    . "- wp-content/uploads (media)\n"
	    . "- wp-content/plugins (site functionality)\n"
	    . "- wp-content/themes (site theme)\n"
	    . "Note: This is a restore package for your site content and data.\n";
        $zip->addFromString( 'README.txt', $readme );


        $zip->close();

        // Cleanup temp sql (kept inside ZIP)
        @unlink( $tmp_sql );

        $size = file_exists( $zip_path ) ? (int) filesize( $zip_path ) : 0;
        if ( $size <= 0 ) {
            @unlink( $zip_path );
            return self::backup_record( false, '', 0, 'Backup created but file size was invalid.' );
        }

        return self::backup_record( true, $zip_file, $size, 'Backup completed successfully.' );
    }

    /**
     * Day-18 Step 3: Toggle Activity Dashboard (customer-facing).
     * Source of truth: opsgate_telemetry_enabled (do not rename).
     *
     * @return void
     */
    public static function handle_toggle_activity_dashboard(): void {
    	if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( esc_html__( 'You do not have permission to perform this action.', 'opsgate' ) );
    	}

    	check_admin_referer( 'opsgate_toggle_activity_dashboard', 'opsgate_toggle_activity_dashboard_nonce' );

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
	$enable_raw = isset( $_POST['enable'] ) ? sanitize_text_field( wp_unslash( $_POST['enable'] ) ) : '0';
        $enable     = ( '1' === (string) $enable_raw ) ? '1' : '0';

        update_option( 'opsgate_telemetry_enabled', $enable, false );

        wp_safe_redirect( admin_url( 'admin.php?page=opsgate&tab=overview' ) );
    	exit;
    }

    /**
     * Day-18 Step 3.6: Save Configuration (manual render, customer-first UI).
     * Keeps Settings as a secondary/advanced surface while staying WP-native and safe.
     *
     * @return void
     */
    /**
     * Operator test-plan override: write plan to API/DB and cache locally.
     * Hidden in Operator billing settings. Affects all plan-gated surfaces immediately.
     * API is the authority — both central and remote plugin read the same source.
     */
    public static function handle_set_plan_override(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( esc_html__( 'Forbidden', 'opsgate' ), 403 );
        }
        check_admin_referer( 'opsgate_set_plan_override', 'opsgate_plan_override_nonce' );

        // phpcs:ignore WordPress.Security.NonceVerification.Missing
        $raw = isset( $_POST['opsgate_plan_override'] ) ? sanitize_key( wp_unslash( $_POST['opsgate_plan_override'] ) ) : '';
        $plan = self::normalize_plan( trim( $raw ) );

        if ( in_array( $plan, array( 'free', 'starter', 'pro', 'agency' ), true ) ) {
            // Write through to API/DB so remote plugin reads the same canonical plan.
            $scope      = self::get_mcp_scope_snapshot();
            $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
            $site_id    = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';

            if ( '' !== $account_id && '' !== $site_id ) {
                self::mcp_post_json(
                    '/v1/entitlements/update',
                    array(
                        'account_id' => $account_id,
                        'site_id'    => $site_id,
                        'plan'       => $plan,
                        'source'     => 'operator_override',
                    )
                );
            }

            // Local WP option mirrors the written plan so central reads it immediately
            // without a round-trip to the API on the same request.
            update_option( 'opsgate_plan_operator_override', $plan, false );
        } else {
            delete_option( 'opsgate_plan_operator_override' );
        }

        wp_safe_redirect( self::admin_tab_url( 'billing', array( 'settings-updated' => '1' ) ) );
        exit;
    }

    public static function handle_clear_plan_override(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( esc_html__( 'Forbidden', 'opsgate' ), 403 );
        }
        check_admin_referer( 'opsgate_clear_plan_override', 'opsgate_clear_plan_override_nonce' );
        delete_option( 'opsgate_plan_operator_override' );
        wp_safe_redirect( self::admin_tab_url( 'billing', array( 'settings-updated' => '1' ) ) );
        exit;
    }

    /**
     * Operator soft reset for a selected test site.
     *
     * Central side: calls POST /v1/operator/site-reset on the backend API.
     * Backend revokes credentials, expires pairing sessions, resets
     * connection_status → external_only, connection_mode → public_scan,
     * and records an audit event.
     *
     * Local side: clears opsgate_plan_operator_override, clears the local
     * credential cache and connection summary cache, clears the pairing token.
     * This removes stale local state so the next plugin refresh re-reads
     * clean canonical state from the API.
     *
     * Gate: manage_options only. Nonce-protected. Not customer-facing.
     */
    public static function handle_operator_soft_reset(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( esc_html__( 'Forbidden', 'opsgate' ), 403 );
        }

        check_admin_referer( 'opsgate_operator_soft_reset', 'opsgate_operator_soft_reset_nonce' );

        $scope      = self::get_mcp_scope_snapshot();
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id    = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';

        if ( '' === $account_id || '' === $site_id ) {
            wp_safe_redirect( self::admin_tab_url( 'settings', array(
                'opsgate_settings_error' => rawurlencode( 'Select a canonical site before running Operator Soft Reset.' ),
            ) ) );
            exit;
        }

        // phpcs:ignore WordPress.Security.NonceVerification.Missing
        $raw_reason = isset( $_POST['opsgate_reset_reason'] )
            ? sanitize_text_field( wp_unslash( $_POST['opsgate_reset_reason'] ) )
            : '';
        $reason = '' !== trim( $raw_reason ) ? trim( $raw_reason ) : 'operator_soft_reset';

        $resp = self::mcp_post_json(
            '/v1/operator/site-reset',
            array(
                'account_id' => $account_id,
                'site_id'    => $site_id,
                'reason'     => $reason,
            )
        );

        if ( empty( $resp['ok'] ) ) {
            $error_detail = isset( $resp['error'] ) ? (string) $resp['error'] : 'Operator Soft Reset failed on the backend.';
            wp_safe_redirect( self::admin_tab_url( 'settings', array(
                'opsgate_settings_error' => rawurlencode( $error_detail ),
            ) ) );
            exit;
        }

        // Clear local operator override — the site is now reset to canonical state.
        delete_option( 'opsgate_plan_operator_override' );

        // Clear local credential cache so plugin re-reads fresh canonical state.
        self::clear_connector_site_credential();

        // clear_connector_site_credential() already calls clear_connector_connection_summary_cache(),
        // but be explicit for clarity.
        delete_option( 'opsgate_connector_connection_summary' );

        // Clear pairing token — reset state means no token is valid.
        update_option( OPSGATE_OPTION_CONNECTOR_PAIRING_TOKEN, '', false );

        wp_safe_redirect( self::admin_tab_url( 'settings', array(
            'opsgate_settings_saved'        => '1',
            'opsgate_operator_reset_result' => 'soft_reset_complete',
        ) ) );
        exit;
    }

    /**
     * Claim/resolve a remote site into the current central session from the Requested Site Handoff screen.
     * POSTed from the "Start setup for this site" form on the handoff gate.
     */
    public static function handle_claim_remote_site(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( esc_html__( 'Forbidden', 'opsgate' ), 403 );
        }

        check_admin_referer( 'opsgate_claim_remote_site', 'opsgate_claim_remote_site_nonce' );

        // phpcs:ignore WordPress.Security.NonceVerification.Missing
        $site_url   = isset( $_POST['opsgate_site_url'] ) ? esc_url_raw( wp_unslash( $_POST['opsgate_site_url'] ) ) : '';
        // phpcs:ignore WordPress.Security.NonceVerification.Missing
        $site_label = isset( $_POST['opsgate_site_label'] ) ? trim( sanitize_text_field( wp_unslash( $_POST['opsgate_site_label'] ) ) ) : '';
        // phpcs:ignore WordPress.Security.NonceVerification.Missing
        $return_url = isset( $_POST['opsgate_return_url'] ) ? esc_url_raw( wp_unslash( $_POST['opsgate_return_url'] ) ) : '';
        // phpcs:ignore WordPress.Security.NonceVerification.Missing
        $requested_tab     = isset( $_POST['opsgate_requested_tab'] ) ? sanitize_text_field( wp_unslash( $_POST['opsgate_requested_tab'] ) ) : 'overview';
        // phpcs:ignore WordPress.Security.NonceVerification.Missing
        $requested_section = isset( $_POST['opsgate_requested_section'] ) ? sanitize_key( wp_unslash( $_POST['opsgate_requested_section'] ) ) : '';
        // phpcs:ignore WordPress.Security.NonceVerification.Missing
        $requested_panel   = isset( $_POST['opsgate_requested_panel'] ) ? sanitize_key( wp_unslash( $_POST['opsgate_requested_panel'] ) ) : '';
        // phpcs:ignore WordPress.Security.NonceVerification.Missing
        $intended_action   = isset( $_POST['opsgate_intended_action'] ) ? sanitize_key( wp_unslash( $_POST['opsgate_intended_action'] ) ) : '';
        // phpcs:ignore WordPress.Security.NonceVerification.Missing
        $onboarding_session_id = isset( $_POST['opsgate_onboarding_session_id'] ) ? sanitize_text_field( wp_unslash( $_POST['opsgate_onboarding_session_id'] ) ) : '';
        // phpcs:ignore WordPress.Security.NonceVerification.Missing
        $onboarding_token = isset( $_POST['opsgate_onboarding_token'] ) ? sanitize_text_field( wp_unslash( $_POST['opsgate_onboarding_token'] ) ) : '';

        $account_id = trim( (string) get_option( 'opsgate_account_id', '' ) );
        // phpcs:ignore WordPress.Security.NonceVerification.Missing
        $url_account = isset( $_POST['opsgate_scope_account'] ) ? trim( sanitize_text_field( wp_unslash( $_POST['opsgate_scope_account'] ) ) ) : '';
        // The scope account from the handoff is the authoritative account for the remote site.
        // Prefer it over the locally-stored account so cross-account handoffs resolve correctly.
        if ( '' !== $url_account ) {
            $account_id = $url_account;
        }

        $normalized_tab = self::normalize_admin_tab_request( $requested_tab );
        $redirect_args = array_filter( array(
            'page'                   => 'opsgate',
            'tab'                    => $normalized_tab,
            'opsgate_return_url'     => $return_url,
            'opsgate_requested_tab'  => $requested_tab,
        ), static function ( $v ) { return null !== $v && '' !== $v; } );

        if ( '' === $site_url ) {
            $redirect_args['opsgate_settings_error'] = rawurlencode( 'No site URL provided for this handoff.' );
            wp_safe_redirect( self::admin_tab_url( 'settings', $redirect_args ) );
            exit;
        }

        // First: attempt to resolve via the onboarding session if params are present.
        $resolved_site = array();
        if ( '' !== $onboarding_session_id && '' !== $onboarding_token && '' !== $account_id ) {
            $resolve_resp = self::mcp_post_json(
                '/v1/onboarding/sessions/resolve',
                array(
                    'account_id'    => $account_id,
                    'session_token' => $onboarding_token,
                )
            );
            if ( ! empty( $resolve_resp['ok'] ) && isset( $resolve_resp['data']['site'] ) && is_array( $resolve_resp['data']['site'] ) ) {
                $resolved_site = $resolve_resp['data']['site'];
            }
        }

        // Fall back: create/resolve the canonical site directly.
        $claim_error_raw = '';
        if ( empty( $resolved_site ) && '' !== $account_id && '' !== $site_url ) {
            $is_pairing = in_array( $intended_action, array( 'get_pairing', 'start_setup', 'connect_paid' ), true )
                || ( 'settings' === $normalized_tab && 'site-configuration' === $requested_section && 'pairing-material' === $requested_panel );
            $create_resp = self::mcp_post_json(
                '/v1/sites',
                array(
                    'account_id'      => $account_id,
                    'site_url'        => $site_url,
                    'site_label'      => '' !== $site_label ? $site_label : $site_url,
                    'connection_mode' => $is_pairing ? 'wp_connector' : 'public_scan',
                )
            );
            if ( ! empty( $create_resp['ok'] ) ) {
                $resp_data = isset( $create_resp['data'] ) && is_array( $create_resp['data'] ) ? $create_resp['data'] : array();
                $resolved_site = isset( $resp_data['site'] ) && is_array( $resp_data['site'] ) ? $resp_data['site'] : $resp_data;
            } else {
                $claim_error_raw = isset( $create_resp['error'] ) ? (string) $create_resp['error'] : '';
            }
        }

        if ( empty( $resolved_site ) || empty( $resolved_site['site_id'] ) ) {
            // When the account's site limit is reached and the remote plugin provided a
            // return_url, send the user back to the remote plugin with a clear message —
            // do not drop them into central Settings showing a stale unrelated site.
            $is_limit_error = false !== stripos( $claim_error_raw, 'site_limit_reached' )
                || false !== stripos( $claim_error_raw, 'limit_reached' );
            if ( $is_limit_error && '' !== $return_url ) {
                $limit_msg = 'Your current plan supports 1 connected site. To connect ' . ( '' !== $site_label ? $site_label : 'this site' ) . ', upgrade your plan or disconnect the existing site from OpsGate Settings.';
                wp_safe_redirect( add_query_arg( array(
                    'opsgate_pairing_error' => rawurlencode( $limit_msg ),
                    'opsgate_pairing_open'  => '1',
                ), $return_url ) );
                exit;
            }
            $error_tab = ( 'settings' === $normalized_tab && 'site-configuration' === $requested_section ) ? 'settings' : $normalized_tab;
            $human_error = $is_limit_error
                ? 'Your current plan supports 1 connected site. Disconnect the existing site or upgrade to connect this one.'
                : 'OpsGate could not resolve this site right now. Enter the site URL below and save.';
            $err_args = array_merge( $redirect_args, array(
                'section'                    => $requested_section,
                'panel'                      => $requested_panel,
                'opsgate_source'             => 'remote-onboarding',
                'opsgate_prefill_site_url'   => $site_url,
                'opsgate_prefill_site_label' => $site_label,
                'opsgate_settings_error'     => rawurlencode( $human_error ),
            ) );
            wp_safe_redirect( self::admin_tab_url( $error_tab, array_filter( $err_args, static function ( $v ) { return null !== $v && '' !== $v; } ) ) );
            exit;
        }

        // Persist the resolved site as the active scope.
        self::sync_active_site_scope_options( $resolved_site );
        self::sync_scope_runtime_refs_for_scope( $resolved_site );

        $resolved_account = isset( $resolved_site['account_id'] ) ? (string) $resolved_site['account_id'] : $account_id;
        if ( '' !== $resolved_account ) {
            update_option( 'opsgate_account_id', $resolved_account, false );
        }

        // Redirect to the requested destination with the resolved scope.
        $scope_args = array_filter( array(
            'opsgate_scope_account'    => $resolved_account,
            'opsgate_scope_site_id'    => isset( $resolved_site['site_id'] ) ? (string) $resolved_site['site_id'] : '',
            'opsgate_scope_site_url'   => isset( $resolved_site['site_url'] ) ? (string) $resolved_site['site_url'] : $site_url,
            'opsgate_scope_site_label' => isset( $resolved_site['site_label'] ) ? (string) $resolved_site['site_label'] : $site_label,
        ), static function ( $v ) { return null !== $v && '' !== $v; } );

        $dest_tab = $normalized_tab;
        $dest_args = array_merge( $scope_args, array_filter( array(
            'page'                     => 'opsgate',
            'tab'                      => $dest_tab,
            'section'                  => 'settings' === $dest_tab && 'site-configuration' === $requested_section ? $requested_section : '',
            'panel'                    => 'settings' === $dest_tab && 'site-configuration' === $requested_section ? $requested_panel : '',
            'opsgate_return_url'       => $return_url,
            'opsgate_settings_saved'   => '1',
        ), static function ( $v ) { return null !== $v && '' !== $v; } ) );

        wp_safe_redirect( self::admin_tab_url( $dest_tab, $dest_args ) );
        exit;
    }

    public static function handle_save_configuration(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( esc_html__( 'Forbidden', 'opsgate' ), 403 );
        }

        check_admin_referer( 'opsgate_save_configuration', 'opsgate_save_configuration_nonce' );

        $current_selected_site = self::current_selected_site_summary();
        $stored_account_id = trim( (string) get_option( 'opsgate_account_id', '' ) );

        // Checkbox: present => enabled, absent => disabled.
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $telemetry_enabled = isset( $_POST['opsgate_telemetry_enabled'] ) ? '1' : '0';

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    	$inbound_token = isset( $_POST['opsgate_inbound_token'] )
            ? trim( sanitize_text_field( wp_unslash( $_POST['opsgate_inbound_token'] ) ) )
            : trim( (string) get_option( 'opsgate_inbound_token', '' ) );

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $api_base_url = isset( $_POST['opsgate_api_base_url'] )
            ? trim( esc_url_raw( wp_unslash( $_POST['opsgate_api_base_url'] ) ) )
            : trim( (string) get_option( 'opsgate_api_base_url', '' ) );

        // Identity fields (already part of OpsGate settings; keep available here).
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $account_id = isset( $_POST['opsgate_account_id'] )
            ? trim( sanitize_text_field( wp_unslash( $_POST['opsgate_account_id'] ) ) )
            : $stored_account_id;

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
      	$identity_email = isset( $_POST['opsgate_identity_email'] )
            ? sanitize_email( wp_unslash( $_POST['opsgate_identity_email'] ) )
            : trim( (string) ( $current_selected_site['contact_email'] ?? '' ) );

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    	$site_label = isset( $_POST['opsgate_site_label'] )
            ? trim( sanitize_text_field( wp_unslash( $_POST['opsgate_site_label'] ) ) )
            : trim( (string) ( $current_selected_site['site_label'] ?? '' ) );

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $site_url = isset( $_POST['opsgate_site_url'] )
            ? esc_url_raw( wp_unslash( $_POST['opsgate_site_url'] ) )
            : trim( (string) ( $current_selected_site['site_url'] ?? '' ) );
        $local_identity = self::get_identity_snapshot();
        $local_site_id = isset( $local_identity['site_id'] ) ? trim( (string) $local_identity['site_id'] ) : '';
        $site_targets_local = self::scope_targets_local_wordpress( $site_url );
        $current_plan = self::get_current_plan();
        $onboarding_path = self::onboarding_path_from_post();
        $requested_handoff_args = self::raw_requested_handoff_query_args();
        // When arriving via an API-issued onboarding session handoff, the form carries
        // session context as hidden POST fields (no GET params). Reconstruct handoff args
        // from POST so the redirect after save carries the correct destination.
        if ( empty( $requested_handoff_args ) ) {
            // phpcs:ignore WordPress.Security.NonceVerification.Missing
            $post_intended_action   = isset( $_POST['opsgate_intended_action'] ) ? sanitize_key( wp_unslash( $_POST['opsgate_intended_action'] ) ) : '';
            // phpcs:ignore WordPress.Security.NonceVerification.Missing
            $post_requested_section = isset( $_POST['opsgate_requested_section'] ) ? sanitize_key( wp_unslash( $_POST['opsgate_requested_section'] ) ) : '';
            // phpcs:ignore WordPress.Security.NonceVerification.Missing
            $post_requested_panel   = isset( $_POST['opsgate_requested_panel'] ) ? sanitize_key( wp_unslash( $_POST['opsgate_requested_panel'] ) ) : '';
            if ( '' !== $post_intended_action || '' !== $post_requested_section ) {
                $requested_handoff_args = array_filter(
                    array(
                        'opsgate_intended_action'   => $post_intended_action,
                        'opsgate_requested_section' => $post_requested_section,
                        'opsgate_requested_panel'   => $post_requested_panel,
                    ),
                    static function ( $v ) { return null !== $v && '' !== $v; }
                );
            }
        }
        // Preserve onboarding session identity through the save-redirect so the pairing panel
        // can render the correct form hidden fields and Create Connection Code can resolve the
        // correct site (not the stale WP-options site) when clicked.
        // phpcs:ignore WordPress.Security.NonceVerification.Missing
        $save_obs_id    = isset( $_POST['opsgate_onboarding_session_id'] ) ? sanitize_text_field( wp_unslash( $_POST['opsgate_onboarding_session_id'] ) ) : '';
        // phpcs:ignore WordPress.Security.NonceVerification.Missing
        $save_obs_token = isset( $_POST['opsgate_onboarding_token'] ) ? sanitize_text_field( wp_unslash( $_POST['opsgate_onboarding_token'] ) ) : '';
        if ( '' !== $save_obs_id ) {
            $requested_handoff_args['opsgate_onboarding_session_id'] = $save_obs_id;
        }
        if ( '' !== $save_obs_token ) {
            $requested_handoff_args['opsgate_onboarding_token'] = $save_obs_token;
        }
        $requested_connection_mode = isset( $requested_handoff_args['opsgate_requested_connection_mode'] ) ? sanitize_key( (string) $requested_handoff_args['opsgate_requested_connection_mode'] ) : '';
        $intended_action = isset( $requested_handoff_args['opsgate_intended_action'] ) ? sanitize_key( (string) $requested_handoff_args['opsgate_intended_action'] ) : '';
        $requested_handoff_is_pairing = 'wp_connector' === $requested_connection_mode || in_array( $intended_action, array( 'get_pairing', 'start_setup', 'connect_paid' ), true );
        $requested_plan = '';
        if ( 'free_public' === $onboarding_path ) {
            $requested_plan = 'free';
        } elseif ( 'connect_paid' === $onboarding_path ) {
            $requested_plan = self::requested_onboarding_plan_from_post( false );
            if ( '' === $requested_plan && in_array( $current_plan, array( 'starter', 'pro', 'agency' ), true ) ) {
                $requested_plan = $current_plan;
            }
        } elseif ( in_array( $current_plan, array( 'free', 'starter', 'pro', 'agency' ), true ) ) {
            $requested_plan = $current_plan;
        }

        $connection_mode = 'public_scan';
        if ( 'connect_paid' === $onboarding_path ) {
            $connection_mode = 'wp_connector';
        } elseif ( 'free_public' !== $onboarding_path && $site_targets_local && 'free' !== $current_plan ) {
            $connection_mode = 'wp_connector';
        } elseif ( 'free_public' !== $onboarding_path && $requested_handoff_is_pairing ) {
            $connection_mode = 'wp_connector';
        }

        update_option( 'opsgate_telemetry_enabled', $telemetry_enabled, false );
        update_option( 'opsgate_inbound_token', $inbound_token, false );
        update_option( 'opsgate_api_base_url', $api_base_url, false );
        if ( '' !== $account_id || '' !== $stored_account_id ) {
            update_option( 'opsgate_account_id', $account_id, false );
        }
        $previous_scope = self::get_active_site_scope_selector();
        $sync_error = '';

        if ( '' === $site_url ) {
            $sync_error = 'Enter a site URL before saving the selected site.';
        } elseif ( 'connect_paid' === $onboarding_path && '' === $requested_plan ) {
            $sync_error = 'Choose Starter, Pro, or Agency before saving the connected path.';
        } elseif ( 'free_public' === $onboarding_path && '' === $account_id ) {
            $bootstrap = self::bootstrap_free_public_site_scope(
                array(
                    'site_label'         => $site_label,
                    'site_url'           => $site_url,
                    'contact_email'      => $identity_email,
                    'local_site_id'      => $local_site_id,
                    'site_targets_local' => $site_targets_local,
                )
            );
            if ( empty( $bootstrap['ok'] ) ) {
                $sync_error = isset( $bootstrap['error'] ) ? (string) $bootstrap['error'] : 'Could not start the Free public check right now.';
            } else {
                $account_id = isset( $bootstrap['account_id'] ) ? trim( (string) $bootstrap['account_id'] ) : '';
            }
        }

        $resolved_scope_args = array();
        if ( '' === $sync_error && '' !== $account_id ) {
            $site_create_payload = array(
                'account_id'      => $account_id,
                'site_id'         => $site_targets_local ? $local_site_id : null,
                'site_label'      => $site_label,
                'site_url'        => $site_targets_local ? trim( (string) home_url() ) : $site_url,
                'contact_email'   => '' !== $identity_email ? $identity_email : null,
                'connection_mode' => $connection_mode,
                'requested_plan'  => '' !== $requested_plan ? $requested_plan : null,
            );

            $resp = self::mcp_post_json( '/v1/sites', $site_create_payload );

            if ( empty( $resp['ok'] ) ) {
                $sync_error = isset( $resp['error'] ) ? (string) $resp['error'] : 'Could not switch the active site scope.';
            } else {
                $response_data = isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array();
                $data = isset( $response_data['site'] ) && is_array( $response_data['site'] ) ? $response_data['site'] : $response_data;
                self::sync_active_site_scope_options( $data );
                self::sync_scope_runtime_refs_for_scope( $data );
                $resolved_scope_args = array_filter(
                    array(
                        'opsgate_scope_account'    => isset( $data['account_id'] ) ? (string) $data['account_id'] : $account_id,
                        'opsgate_scope_site_id'    => isset( $data['site_id'] ) ? (string) $data['site_id'] : '',
                        'opsgate_scope_site_url'   => isset( $data['site_url'] ) ? (string) $data['site_url'] : $site_url,
                        'opsgate_scope_site_label' => isset( $data['site_label'] ) ? (string) $data['site_label'] : $site_label,
                    ),
                    static function ( $value ): bool {
                        return null !== $value && '' !== $value;
                    }
                );
                if ( self::scope_selection_changed( $previous_scope, $data ) ) {
                    update_option( 'opsgate_last_admin_error', '', false );
                }
            }
        } elseif ( '' === $sync_error ) {
            $sync_error = 'Connect this installation to an OpsGate account before selecting a site.';
        }

        if ( '' === $sync_error && 'free_public' === $onboarding_path ) {
            $run_result = self::dispatch_portfolio_triage_job_request();
            if ( empty( $run_result['ok'] ) ) {
                $sync_error = self::remote_companion_client_safe_error(
                    isset( $run_result['message'] ) ? (string) $run_result['message'] : '',
                    'Could not start the Free public check right now.'
                );
            }
        }

        $args = array_merge( $requested_handoff_args, $resolved_scope_args );
        if ( '' !== $sync_error ) {
            $args['opsgate_settings_error'] = rawurlencode( $sync_error );
        } else {
            $args['opsgate_settings_saved'] = '1';
        }

        // When the save was submitted from the setup wizard, return to the wizard.
        $wizard_return = isset( $_POST['opsgate_wizard_return'] ) ? sanitize_key( wp_unslash( $_POST['opsgate_wizard_return'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
        if ( 'done' === $wizard_return ) {
            update_option( 'opsgate_setup_wizard_dismissed', '1', false );
            wp_safe_redirect( admin_url( 'admin.php?page=opsgate&tab=overview' ) );
            exit;
        }
        if ( '' !== $wizard_return ) {
            wp_safe_redirect( admin_url( 'admin.php?page=opsgate' ) );
            exit;
        }

        $redirect_tab = 'free_public' === $onboarding_path ? 'overview' : 'settings';
        if ( 'free_public' !== $onboarding_path && $requested_handoff_is_pairing ) {
            $args['section'] = 'site-configuration';
            $args['panel'] = 'pairing-material';
        }
        wp_safe_redirect( self::admin_tab_url( $redirect_tab, $args ) );
        exit;
    }

    public static function handle_save_firm_name(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( esc_html__( 'Forbidden', 'opsgate' ), 403 );
        }
        check_admin_referer( 'opsgate_save_firm_name', 'opsgate_save_firm_name_nonce' );
        // phpcs:ignore WordPress.Security.NonceVerification.Missing
        $firm_name = isset( $_POST['opsgate_firm_name'] )
            ? trim( sanitize_text_field( wp_unslash( $_POST['opsgate_firm_name'] ) ) )
            : trim( (string) get_option( 'opsgate_firm_name', '' ) );
        update_option( 'opsgate_firm_name', $firm_name, false );
        wp_safe_redirect( self::admin_tab_url( 'settings', array( 'opsgate_firm_name_saved' => '1' ) ) );
        exit;
    }

    public static function handle_save_agency_branding(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( esc_html__( 'Forbidden', 'opsgate' ), 403 );
        }
        check_admin_referer( 'opsgate_save_agency_branding', 'opsgate_save_agency_branding_nonce' );

        $firm_name     = isset( $_POST['opsgate_branding_firm_name'] ) ? sanitize_text_field( wp_unslash( $_POST['opsgate_branding_firm_name'] ) ) : '';
        $logo_url      = isset( $_POST['opsgate_branding_logo_url'] ) ? esc_url_raw( wp_unslash( $_POST['opsgate_branding_logo_url'] ) ) : '';
        $primary_hex   = isset( $_POST['opsgate_branding_primary_hex'] ) ? sanitize_text_field( wp_unslash( $_POST['opsgate_branding_primary_hex'] ) ) : '';
        $tagline       = isset( $_POST['opsgate_branding_tagline'] ) ? sanitize_text_field( wp_unslash( $_POST['opsgate_branding_tagline'] ) ) : '';
        $contact_email = isset( $_POST['opsgate_branding_contact_email'] ) ? sanitize_email( wp_unslash( $_POST['opsgate_branding_contact_email'] ) ) : '';
        $account_id    = isset( $_POST['opsgate_branding_account_id'] ) ? sanitize_text_field( wp_unslash( $_POST['opsgate_branding_account_id'] ) ) : '';
        $api_base      = isset( $_POST['opsgate_branding_api_base'] ) ? esc_url_raw( wp_unslash( $_POST['opsgate_branding_api_base'] ) ) : self::mcp_base_url();

        if ( ! preg_match( '/^#[0-9a-fA-F]{6}$/', $primary_hex ) ) {
            $primary_hex = '';
        }

        update_option( 'opsgate_branding_firm_name', $firm_name, false );
        update_option( 'opsgate_branding_logo_url', $logo_url, false );
        update_option( 'opsgate_branding_primary_hex', $primary_hex, false );
        update_option( 'opsgate_branding_tagline', $tagline, false );
        update_option( 'opsgate_branding_contact_email', $contact_email, false );

        if ( '' !== $account_id && '' !== $api_base ) {
            $api_token = self::connector_site_credential();
            $patch_url = trailingslashit( $api_base ) . 'v1/accounts/' . rawurlencode( $account_id ) . '/branding';
            wp_remote_request( $patch_url, array(
                'method'  => 'PATCH',
                'timeout' => 10,
                'headers' => array(
                    'Content-Type'       => 'application/json',
                    'X-OpsGate-Token'    => $api_token,
                ),
                'body'    => wp_json_encode( array(
                    'firm_name'     => $firm_name,
                    'logo_url'      => $logo_url,
                    'primary_hex'   => $primary_hex,
                    'tagline'       => $tagline,
                    'contact_email' => $contact_email,
                ) ),
            ) );
        }

        wp_safe_redirect( self::admin_tab_url( 'settings', array( 'opsgate_branding_saved' => '1' ) ) );
        exit;
    }

    /**
     * @param array{site_label:string,site_url:string,contact_email:string,local_site_id:string,site_targets_local:bool} $payload
     * @return array{ok:bool,account_id?:string,job_id?:string,error?:string}
     */
    private static function bootstrap_free_public_site_scope( array $payload ): array {
        $site_label = trim( (string) ( $payload['site_label'] ?? '' ) );
        $site_url = trim( (string) ( $payload['site_url'] ?? '' ) );
        $contact_email = trim( (string) ( $payload['contact_email'] ?? '' ) );
        $local_site_id = trim( (string) ( $payload['local_site_id'] ?? '' ) );
        $site_targets_local = ! empty( $payload['site_targets_local'] );

        if ( '' === $site_label || '' === $site_url || '' === $contact_email ) {
            return array(
                'ok'    => false,
                'error' => 'Free setup needs a site label, site URL, and contact email before the first public check can start.',
            );
        }

        $resp = self::mcp_post_json(
            '/v1/onboarding/free-site',
            array(
                'site_label'            => $site_label,
                'site_url'              => $site_targets_local ? trim( (string) home_url() ) : $site_url,
                'contact_email'         => $contact_email,
                'site_id'               => $site_targets_local && '' !== $local_site_id ? $local_site_id : null,
                'source'                => 'wordpress_plugin_onboarding',
                'plugin_version'        => defined( 'OPSGATE_VERSION' ) ? (string) OPSGATE_VERSION : '0.10.7',
                'installation_site_url' => trim( (string) home_url() ),
            )
        );

        if ( empty( $resp['ok'] ) ) {
            return array(
                'ok'    => false,
                'error' => self::remote_companion_client_safe_error(
                    isset( $resp['error'] ) ? (string) $resp['error'] : '',
                    'OpsGate could not start the Free public check right now. Open OpsGate or try again in a moment.'
                ),
            );
        }

        $data = isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array();
        $account_id = isset( $data['account_id'] ) ? trim( (string) $data['account_id'] ) : '';
        $site = isset( $data['site'] ) && is_array( $data['site'] ) ? $data['site'] : array();
        if ( '' === $account_id || empty( $site ) ) {
            return array(
                'ok'    => false,
                'error' => 'Free setup did not return a canonical account and site scope.',
            );
        }

        update_option( 'opsgate_account_id', $account_id, false );
        update_option( 'opsgate_plan', 'free', false );
        self::sync_active_site_scope_options( $site );
        self::sync_scope_runtime_refs_for_scope( $site );

        return array(
            'ok'         => true,
            'account_id' => $account_id,
            'job_id'     => isset( $data['job_id'] ) ? trim( (string) $data['job_id'] ) : '',
        );
    }

    public static function handle_dismiss_setup_wizard(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( esc_html__( 'Forbidden', 'opsgate' ), 403 );
        }
        check_admin_referer( 'opsgate_dismiss_setup_wizard' );
        update_option( 'opsgate_setup_wizard_dismissed', '1', false );
        wp_safe_redirect( admin_url( 'admin.php?page=opsgate&tab=overview' ) );
        exit;
    }

    public static function handle_run_free_public_onboarding(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( esc_html__( 'Forbidden', 'opsgate' ), 403 );
        }

        check_admin_referer( 'opsgate_run_free_public_onboarding', 'opsgate_run_free_public_onboarding_nonce' );

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $api_base_url = isset( $_POST['opsgate_api_base_url'] )
            ? trim( esc_url_raw( wp_unslash( $_POST['opsgate_api_base_url'] ) ) )
            : self::mcp_base_url();
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $site_url = isset( $_POST['opsgate_site_url'] )
            ? trim( esc_url_raw( wp_unslash( $_POST['opsgate_site_url'] ) ) )
            : trim( (string) home_url() );
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $site_label = isset( $_POST['opsgate_site_label'] )
            ? trim( sanitize_text_field( wp_unslash( $_POST['opsgate_site_label'] ) ) )
            : trim( (string) get_bloginfo( 'name' ) );
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $contact_email = isset( $_POST['opsgate_identity_email'] )
            ? trim( sanitize_email( wp_unslash( $_POST['opsgate_identity_email'] ) ) )
            : trim( (string) get_bloginfo( 'admin_email' ) );

        if ( '' !== $api_base_url ) {
            update_option( 'opsgate_api_base_url', $api_base_url, false );
        }
        if ( '' !== $site_label ) {
            update_option( 'opsgate_site_label', $site_label, false );
        }
        if ( '' !== $contact_email ) {
            update_option( 'opsgate_identity_email', $contact_email, false );
        }

        $local_identity = self::get_identity_snapshot();
        $local_site_id = isset( $local_identity['site_id'] ) ? trim( (string) $local_identity['site_id'] ) : '';
        $site_targets_local = self::scope_targets_local_wordpress( $site_url );
        $bootstrap = self::bootstrap_free_public_site_scope(
            array(
                'site_label'         => $site_label,
                'site_url'           => $site_url,
                'contact_email'      => $contact_email,
                'local_site_id'      => $local_site_id,
                'site_targets_local' => $site_targets_local,
            )
        );

        if ( empty( $bootstrap['ok'] ) ) {
            wp_safe_redirect(
                self::admin_tab_url(
                    'overview',
                    array(
                        'opsgate_settings_error' => rawurlencode( isset( $bootstrap['error'] ) ? (string) $bootstrap['error'] : 'Could not start the Free public check right now.' ),
                    )
                )
            );
            exit;
        }

        $job_id = isset( $bootstrap['job_id'] ) ? trim( (string) $bootstrap['job_id'] ) : '';
        if ( '' !== $job_id ) {
            self::update_scope_runtime_refs(
                self::get_mcp_scope_snapshot(),
                array(
                    'last_triage_job_id' => $job_id,
                )
            );
        } else {
            $run_result = self::dispatch_portfolio_triage_job_request();
            if ( empty( $run_result['ok'] ) ) {
                $detail = isset( $run_result['detail'] ) ? (string) $run_result['detail'] : ( isset( $run_result['message'] ) ? (string) $run_result['message'] : '' );
                wp_safe_redirect(
                    self::admin_tab_url(
                        'overview',
                        array(
                            'opsgate_settings_error' => rawurlencode(
                                self::remote_companion_client_safe_error(
                                    $detail,
                                    'OpsGate could not queue the Free public check right now. Open OpsGate or try again in a moment.'
                                )
                            ),
                        )
                    )
                );
                exit;
            }
        }

        wp_safe_redirect(
            self::admin_tab_url(
                'overview',
                array(
                    'opsgate_settings_saved' => '1',
                )
            )
        );
        exit;
    }

    public static function handle_create_pairing_session(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( esc_html__( 'Forbidden', 'opsgate' ), 403 );
        }

        check_admin_referer( 'opsgate_create_pairing_session', 'opsgate_create_pairing_session_nonce' );

        // Preserve onboarding session context through the redirect so the pairing panel
        // can show the correct return URL and the resolver can bind the pairing session.
        $onboarding_session_id = isset( $_POST['opsgate_onboarding_session_id'] ) ? sanitize_text_field( wp_unslash( $_POST['opsgate_onboarding_session_id'] ) ) : '';
        $onboarding_token = isset( $_POST['opsgate_onboarding_token'] ) ? sanitize_text_field( wp_unslash( $_POST['opsgate_onboarding_token'] ) ) : '';
        // phpcs:ignore WordPress.Security.NonceVerification.Missing
        $handoff_return_url = isset( $_POST['opsgate_return_url'] ) ? esc_url_raw( wp_unslash( $_POST['opsgate_return_url'] ) ) : '';

        $scope = self::get_mcp_scope_snapshot();
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';

        $args = array();
        if ( '' !== $onboarding_session_id ) {
            $args['opsgate_onboarding_session_id'] = $onboarding_session_id;
        }
        if ( '' !== $onboarding_token ) {
            $args['opsgate_onboarding_token'] = $onboarding_token;
        }
        if ( '' === $account_id ) {
            $args['opsgate_settings_error'] = rawurlencode( 'Connect this site to an OpsGate account to continue.' );
            $args['section'] = 'site-configuration';
            $args['panel'] = 'pairing-material';
            wp_safe_redirect( self::admin_tab_url( 'settings', $args ) );
            exit;
        }

        // When an onboarding session token is present in POST, resolve the canonical site
        // from that session — the session is the authoritative source for which site this
        // pairing is for. WP options may hold a stale/previous site (e.g. an expired sandbox)
        // that must not override the current onboarding intent.
        if ( '' !== $onboarding_session_id && '' !== $onboarding_token ) {
            $session_resolve_resp = self::mcp_post_json(
                '/v1/onboarding/sessions/resolve',
                array(
                    'account_id'    => $account_id,
                    'session_token' => $onboarding_token,
                )
            );
            if ( ! empty( $session_resolve_resp['ok'] ) ) {
                $session_site = isset( $session_resolve_resp['data']['site'] ) && is_array( $session_resolve_resp['data']['site'] )
                    ? $session_resolve_resp['data']['site']
                    : array();
                $session_site_id = isset( $session_site['site_id'] ) ? trim( (string) $session_site['site_id'] ) : '';
                if ( '' !== $session_site_id ) {
                    $site_id = $session_site_id;
                    self::sync_active_site_scope_options( $session_site );
                    $args['opsgate_scope_site_id'] = $site_id;
                }
            }
        }

        // Auto-resolve the canonical site if site_id is still absent but site_url is available.
        // Fallback for cases where no onboarding session token is present.
        if ( '' === $site_id ) {
            $scope_site_url = isset( $scope['site_url'] ) ? trim( (string) $scope['site_url'] ) : '';
            // Also accept site_url sent as a hidden POST field by the Create Connection Code form.
            // phpcs:ignore WordPress.Security.NonceVerification.Missing
            if ( '' === $scope_site_url && isset( $_POST['opsgate_scope_site_url'] ) ) {
                $scope_site_url = esc_url_raw( wp_unslash( $_POST['opsgate_scope_site_url'] ) );
            }
            if ( '' !== $scope_site_url ) {
                $resolve_resp = self::mcp_post_json(
                    '/v1/sites',
                    array(
                        'account_id'      => $account_id,
                        'site_url'        => $scope_site_url,
                        'site_label'      => isset( $scope['site_label'] ) ? trim( (string) $scope['site_label'] ) : $scope_site_url,
                        'connection_mode' => 'wp_connector',
                    )
                );
                if ( ! empty( $resolve_resp['ok'] ) ) {
                    $resolved_data = isset( $resolve_resp['data']['site'] ) && is_array( $resolve_resp['data']['site'] )
                        ? $resolve_resp['data']['site']
                        : ( isset( $resolve_resp['data'] ) && is_array( $resolve_resp['data'] ) ? $resolve_resp['data'] : array() );
                    $site_id = isset( $resolved_data['site_id'] ) ? trim( (string) $resolved_data['site_id'] ) : '';
                    if ( '' !== $site_id ) {
                        self::sync_active_site_scope_options( $resolved_data );
                        $args['opsgate_scope_site_id'] = $site_id;
                    }
                }
            }
        }

        if ( '' === $site_id ) {
            $args['opsgate_settings_error'] = rawurlencode( 'Save this site before creating connection material.' );
            $args['section'] = 'site-configuration';
            $args['panel'] = 'pairing-material';
            wp_safe_redirect( self::admin_tab_url( 'settings', $args ) );
            exit;
        }

        $resp = self::mcp_post_json(
            '/v1/sites/pairing-sessions',
            array(
                'account_id' => $account_id,
                'site_id' => $site_id,
            )
        );

        if ( empty( $resp['ok'] ) ) {
            $args['opsgate_settings_error'] = rawurlencode( isset( $resp['error'] ) ? (string) $resp['error'] : 'Could not create pairing material.' );
        } else {
            $data = isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array();
            $pairing_token = isset( $data['pairing_token'] ) ? (string) $data['pairing_token'] : '';
            $selected_site = self::current_selected_site_summary();
            $selected_site_url = isset( $selected_site['site_url'] ) ? trim( (string) $selected_site['site_url'] ) : '';
            if ( self::scope_targets_local_wordpress( $selected_site_url ) ) {
                self::store_connector_pairing_token( $pairing_token );
            } else {
                self::store_connector_pairing_token( '' );
            }

            // When this pairing was triggered from a remote-plugin handoff, redirect back
            // to the remote plugin with the token pre-filled. opsgate_auto_pair=1 signals the JS
            // to auto-submit the complete-pairing form without the user needing to copy and paste.
            if ( '' !== $handoff_return_url && '' !== $pairing_token ) {
                $auto_pair_url = add_query_arg(
                    array(
                        'opsgate_pairing_token' => rawurlencode( $pairing_token ),
                        'opsgate_auto_pair'     => '1',
                        'opsgate_pairing_open'  => '1',
                    ),
                    $handoff_return_url
                );
                wp_safe_redirect( $auto_pair_url );
                exit;
            }

            $args['opsgate_pairing_token'] = $pairing_token;
            $args['opsgate_settings_saved'] = '1';
        }

        // phpcs:ignore WordPress.Security.NonceVerification.Missing
        if ( ! empty( $_POST['opsgate_wizard_return'] ) ) {
            wp_safe_redirect( admin_url( 'admin.php?page=opsgate' ) );
            exit;
        }
        $args['section'] = 'site-configuration';
        $args['panel'] = 'pairing-material';
        wp_safe_redirect( self::admin_tab_url( 'settings', $args ) );
        exit;
    }

    public static function handle_complete_pairing(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( esc_html__( 'Forbidden', 'opsgate' ), 403 );
        }

        check_admin_referer( 'opsgate_complete_pairing', 'opsgate_complete_pairing_nonce' );

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $api_base_url = isset( $_POST['opsgate_api_base_url'] )
            ? trim( esc_url_raw( wp_unslash( $_POST['opsgate_api_base_url'] ) ) )
            : self::mcp_base_url();
        if ( '' !== $api_base_url ) {
            update_option( 'opsgate_api_base_url', $api_base_url, false );
        }

        $scope = self::get_mcp_scope_snapshot();
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $pairing_token = isset( $_POST['opsgate_pairing_code'] )
            ? trim( sanitize_text_field( wp_unslash( $_POST['opsgate_pairing_code'] ) ) )
            : ( isset( $_POST['opsgate_pairing_token'] ) ? trim( sanitize_text_field( wp_unslash( $_POST['opsgate_pairing_token'] ) ) ) : self::connector_pairing_token() );
        $current_selected_site = self::current_selected_site_summary();
        $site_label = isset( $current_selected_site['site_label'] ) ? trim( (string) $current_selected_site['site_label'] ) : trim( (string) get_option( 'opsgate_site_label', '' ) );
        $contact_email = isset( $current_selected_site['contact_email'] ) ? trim( (string) $current_selected_site['contact_email'] ) : trim( (string) get_option( 'opsgate_identity_email', '' ) );
        if ( '' === $site_label ) {
            $site_label = trim( (string) get_bloginfo( 'name' ) );
        }
        if ( '' === $contact_email ) {
            $contact_email = trim( (string) get_bloginfo( 'admin_email' ) );
        }

        $args = array();
        if ( '' === $pairing_token ) {
            $args['opsgate_pairing_open'] = '1';
            $args['opsgate_pairing_error'] = rawurlencode( 'Enter a pairing code.' );
            wp_safe_redirect( self::admin_tab_url( 'overview', $args ) );
            exit;
        }

        $payload = array(
            'pairing_code' => $pairing_token,
            'site_url' => trim( (string) home_url() ),
            'site_label' => $site_label,
            'connector_version' => defined( 'OPSGATE_VERSION' ) ? (string) OPSGATE_VERSION : '0.10.7',
            'connector_installation_id' => self::connector_installation_id(),
            'inventory_endpoint' => rest_url( 'opsgate/v1/inventory' ),
            'contact_email' => '' !== $contact_email ? $contact_email : null,
        );
        // Do not send account_id: the pairing token is self-contained and already bound to an
        // account. Sending a stale local account_id (e.g. from a prior free-bootstrap) would
        // cause _pairing_session_by_token to filter by the wrong account and return nothing.

        $resp = self::mcp_post_json( '/v1/sites/pairing/complete', $payload );

        if ( empty( $resp['ok'] ) ) {
            $args['opsgate_pairing_open'] = '1';
            $args['opsgate_pairing_error'] = rawurlencode(
                self::remote_companion_pairing_safe_error(
                    isset( $resp['error'] ) ? (string) $resp['error'] : '',
                    'Could not complete pairing right now.'
                )
            );
        } else {
            $data = isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array();
            $site_data = isset( $data['site'] ) && is_array( $data['site'] ) ? $data['site'] : array();
            $credential = isset( $data['credential'] ) && is_array( $data['credential'] ) ? $data['credential'] : array();
            if ( ! empty( $credential['credential'] ) ) {
                self::store_connector_site_credential( (string) $credential['credential'] );
            }
            self::store_connector_pairing_token( '' );
            if ( ! empty( $site_data ) ) {
                self::store_connector_connection_summary_cache( $site_data );
                if ( ! empty( $site_data['account_id'] ) ) {
                    update_option( 'opsgate_account_id', (string) $site_data['account_id'], false );
                }
                self::sync_active_site_scope_options( $site_data );
                self::sync_scope_runtime_refs_for_scope( $site_data );
            }
            // Store the plan from the pairing response so the tier badge shows correctly.
            $plan_from_pairing = isset( $data['plan'] ) ? self::normalize_plan( (string) $data['plan'] ) : '';
            if ( '' === $plan_from_pairing && isset( $site_data['plan'] ) ) {
                $plan_from_pairing = self::normalize_plan( (string) $site_data['plan'] );
            }
            if ( in_array( $plan_from_pairing, array( 'starter', 'pro', 'agency' ), true ) ) {
                update_option( 'opsgate_plan', $plan_from_pairing, false );
            }
            $args['opsgate_settings_saved'] = '1';
        }

        wp_safe_redirect( self::admin_tab_url( 'overview', $args ) );
        exit;
    }

    public static function handle_rotate_connector_credential(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( esc_html__( 'Forbidden', 'opsgate' ), 403 );
        }

        check_admin_referer( 'opsgate_rotate_connector_credential', 'opsgate_rotate_connector_credential_nonce' );

        $scope = self::get_mcp_scope_snapshot();
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';
        $args = array();

        if ( '' === $account_id || '' === $site_id ) {
            $args['opsgate_settings_error'] = rawurlencode( 'Select a canonical site before rotating its connector credential.' );
            wp_safe_redirect( self::admin_tab_url( 'settings', $args ) );
            exit;
        }

        $resp = self::mcp_post_json(
            '/v1/sites/credentials/rotate',
            array(
                'account_id' => $account_id,
                'site_id' => $site_id,
                'reason' => 'wordpress_plugin_rotation',
            )
        );

        if ( empty( $resp['ok'] ) ) {
            $args['opsgate_settings_error'] = rawurlencode( isset( $resp['error'] ) ? (string) $resp['error'] : 'Could not rotate the connector credential.' );
        } else {
            $data = isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array();
            $credential = isset( $data['credential'] ) && is_array( $data['credential'] ) ? $data['credential'] : array();
            if ( ! empty( $credential['credential'] ) ) {
                self::store_connector_site_credential( (string) $credential['credential'] );
            }
            if ( ! empty( $data['site'] ) && is_array( $data['site'] ) ) {
                self::store_connector_connection_summary_cache( $data['site'] );
            }
            $args['opsgate_settings_saved'] = '1';
        }

        wp_safe_redirect( self::admin_tab_url( 'settings', $args ) );
        exit;
    }

    public static function handle_revoke_connector_credential(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( esc_html__( 'Forbidden', 'opsgate' ), 403 );
        }

        check_admin_referer( 'opsgate_revoke_connector_credential', 'opsgate_revoke_connector_credential_nonce' );

        $scope = self::get_mcp_scope_snapshot();
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';
        $args = array();

        if ( '' === $account_id || '' === $site_id ) {
            $args['opsgate_settings_error'] = rawurlencode( 'Select a canonical site before revoking its connector credential.' );
            wp_safe_redirect( self::admin_tab_url( 'settings', $args ) );
            exit;
        }

        $resp = self::mcp_post_json(
            '/v1/sites/credentials/revoke',
            array(
                'account_id' => $account_id,
                'site_id' => $site_id,
                'reason' => 'wordpress_plugin_revoke',
            )
        );

        if ( empty( $resp['ok'] ) ) {
            $args['opsgate_settings_error'] = rawurlencode( isset( $resp['error'] ) ? (string) $resp['error'] : 'Could not revoke the connector credential.' );
        } else {
            self::clear_connector_site_credential();
            self::clear_connector_connection_summary_cache();
            $args['opsgate_settings_saved'] = '1';
        }

        wp_safe_redirect( self::admin_tab_url( 'settings', $args ) );
        exit;
    }

    public static function handle_validation_remediation_apply(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( esc_html__( 'Forbidden', 'opsgate' ), 403 );
        }

        check_admin_referer( 'opsgate_validation_remediation_apply', 'opsgate_validation_remediation_apply_nonce' );

        $scope = self::get_mcp_scope_snapshot();
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';
        $source_job_id = isset( $_POST['source_job_id'] ) ? trim( sanitize_text_field( wp_unslash( $_POST['source_job_id'] ) ) ) : '';
        $finding_code = isset( $_POST['finding_code'] ) ? trim( sanitize_text_field( wp_unslash( $_POST['finding_code'] ) ) ) : '';
        $args = array( 'opsgate_detail' => 'validation' );

        if ( '' === $account_id || '' === $site_id || '' === $source_job_id || '' === $finding_code ) {
            $args['opsgate_validation_notice'] = 'error';
            $args['opsgate_validation_notice_detail'] = rawurlencode( 'Validation remediation requires canonical account, site, run, and finding scope.' );
            wp_safe_redirect( self::admin_tab_url( 'triage', $args ) );
            exit;
        }

        $resp = self::mcp_post_json(
            '/v1/validation-remediations/apply',
            array(
                'account_id'    => $account_id,
                'site_id'       => $site_id,
                'source_job_id' => $source_job_id,
                'finding_code'  => $finding_code,
            )
        );

        if ( empty( $resp['ok'] ) ) {
            $args['opsgate_validation_notice'] = 'error';
            $args['opsgate_validation_notice_detail'] = rawurlencode( isset( $resp['error'] ) ? (string) $resp['error'] : 'Could not queue the remediation right now.' );
        } else {
            $args['opsgate_validation_notice'] = 'queued';
            $args['opsgate_validation_notice_detail'] = rawurlencode( 'Remediation queued through canonical OpsGate execution.' );
        }

        wp_safe_redirect( self::admin_tab_url( 'triage', $args ) );
        exit;
    }

    public static function handle_validation_remediation_revert(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( esc_html__( 'Forbidden', 'opsgate' ), 403 );
        }

        check_admin_referer( 'opsgate_validation_remediation_revert', 'opsgate_validation_remediation_revert_nonce' );

        $scope = self::get_mcp_scope_snapshot();
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';
        $remediation_id = isset( $_POST['remediation_id'] ) ? trim( sanitize_text_field( wp_unslash( $_POST['remediation_id'] ) ) ) : '';
        $args = array( 'opsgate_detail' => 'validation' );

        if ( '' === $account_id || '' === $site_id || '' === $remediation_id ) {
            $args['opsgate_validation_notice'] = 'error';
            $args['opsgate_validation_notice_detail'] = rawurlencode( 'Validation remediation revert requires canonical account, site, and remediation scope.' );
            wp_safe_redirect( self::admin_tab_url( 'triage', $args ) );
            exit;
        }

        $resp = self::mcp_post_json(
            '/v1/validation-remediations/' . rawurlencode( $remediation_id ) . '/revert',
            array(
                'account_id' => $account_id,
                'site_id'    => $site_id,
            )
        );

        if ( empty( $resp['ok'] ) ) {
            $args['opsgate_validation_notice'] = 'error';
            $args['opsgate_validation_notice_detail'] = rawurlencode( isset( $resp['error'] ) ? (string) $resp['error'] : 'Could not queue the remediation revert right now.' );
        } else {
            $args['opsgate_validation_notice'] = 'queued';
            $args['opsgate_validation_notice_detail'] = rawurlencode( 'Remediation revert queued through canonical OpsGate execution.' );
        }

        wp_safe_redirect( self::admin_tab_url( 'triage', $args ) );
        exit;
    }


    /**
     * Absolute backup directory path under uploads.
     */
    private static function backup_dir_abs(): string {
        $uploads = wp_upload_dir();
        return trailingslashit( $uploads['basedir'] ) . 'opsgate/backups/';
    }

    /**
     * Ensure directory exists.
     */
    private static function ensure_dir( string $dir ): bool {
        if ( is_dir( $dir ) ) {
            return true;
        }
        return wp_mkdir_p( $dir );
    }

    /**
     * Write backup history (evidence) as newest-first ring buffer.
     * Option: opsgate_backup_history
     */
    private static function backup_record( bool $ok, string $file, int $size, string $message ): array {
        $history = get_option( 'opsgate_backup_history', array() );
        if ( ! is_array( $history ) ) {
            $history = array();
        }

        $entry = array(
            'ts'      => time(),
            'status'  => $ok ? 'Completed' : 'Failed',
            'file'    => $file,
            'size'    => $size,
            'size_h'  => $size > 0 ? size_format( $size ) : '—',
            'summary' => $message,
            'type'    => 'backup',
        );

        array_unshift( $history, $entry );
        $history = array_slice( $history, 0, 20 );
        update_option( 'opsgate_backup_history', $history, false );

	        return array(
	            'ok'      => $ok,
	            'file'    => $file,
            'size'    => $size,
            'message' => $message,
        );
    }

    /**
     * Database export to SQL (simple, consistent).
     */
    private static function backup_dump_database_sql( string $out_file ): bool {
        global $wpdb;

        $fh = @fopen( $out_file, 'w' );
        if ( ! $fh ) {
            return false;
        }

        fwrite( $fh, "-- OpsGate Database Export\n" );
        fwrite( $fh, "-- Generated: " . gmdate( 'c' ) . " UTC\n\n" );

        $tables = $wpdb->get_col( 'SHOW TABLES' );
        if ( empty( $tables ) ) {
            fclose( $fh );
            return false;
        }

        foreach ( $tables as $table ) {
            $create = $wpdb->get_row( "SHOW CREATE TABLE `{$table}`", ARRAY_N );
            if ( ! empty( $create[1] ) ) {
                fwrite( $fh, "\n-- Table: {$table}\n" );
                fwrite( $fh, "DROP TABLE IF EXISTS `{$table}`;\n" );
                fwrite( $fh, $create[1] . ";\n\n" );
            }

            $rows = $wpdb->get_results( "SELECT * FROM `{$table}`", ARRAY_A );
            if ( ! empty( $rows ) ) {
                foreach ( $rows as $row ) {
                    $cols = array();
                    $vals = array();

                    foreach ( $row as $col => $val ) {
                        $cols[] = '`' . str_replace( '`', '``', $col ) . '`';
                        if ( is_null( $val ) ) {
                            $vals[] = 'NULL';
                        } else {
                            // esc_sql is sufficient here for string literal escaping in this export context.
                            $vals[] = "'" . esc_sql( (string) $val ) . "'";
                        }
                    }

                    $sql = "INSERT INTO `{$table}` (" . implode( ',', $cols ) . ') VALUES (' . implode( ',', $vals ) . ");\n";
                    fwrite( $fh, $sql );
                }
                fwrite( $fh, "\n" );
            }
        }

        fclose( $fh );
        return true;
    }

    /**
     * Add a directory recursively into a zip.
     */
    private static function backup_zip_add_directory( ZipArchive $zip, string $dir_path, string $zip_root ): void {
        $dir_path = rtrim( $dir_path, '/\\' );
        if ( ! is_dir( $dir_path ) ) {
            return;
        }

        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator( $dir_path, FilesystemIterator::SKIP_DOTS ),
            RecursiveIteratorIterator::SELF_FIRST
        );

	foreach ( $iterator as $item ) {
	    $full_path = $item->getPathname();

	    // Build ZIP-relative path FIRST (authoritative for filtering).
    	$rel = substr( $full_path, strlen( $dir_path ) + 1 );
	    if ( false === $rel ) {
        	continue;
	    }

	    $rel      = str_replace( '\\', '/', $rel );
	    $zip_path = $zip_root . '/' . $rel;

	    // Normalized ZIP path (leading slash for consistent prefix matching).
	    $z = '/' . ltrim( $zip_path, '/' );

	    /**
	     * HARD EXCLUDES — restore ZIP must NOT contain:
	     * - OpsGate internal artifacts under uploads
	     * - OpsGate proprietary plugin code
	     * - transient caches / upgrade / backup tool folders
	     * Exclude BOTH directory nodes and children.
	     */

	    // 1) OpsGate internal uploads (directory + children)
	    if ( $z === '/wp-content/uploads/opsgate' || 0 === strpos( $z, '/wp-content/uploads/opsgate/' ) ) {
        	continue;
	    }

	    // 2) OpsGate proprietary plugins (directory + children)
	    if ( $z === '/wp-content/plugins/opsgate' || 0 === strpos( $z, '/wp-content/plugins/opsgate/' ) ) {
        	continue;
	    }
	    if ( $z === '/wp-content/plugins/opsgate-scan.disabled' || 0 === strpos( $z, '/wp-content/plugins/opsgate-scan.disabled/' ) ) {
        	continue;
	    }

	    // 3) Transient caches / upgrades / backup tools (directory + children)
	    $skip_prefixes = array(
        	'/wp-content/cache/',
	        '/wp-content/upgrade/',

        	'/wp-content/uploads/cache/',
	        '/wp-content/uploads/updraft/',
        	'/wp-content/uploads/ai1wm-backups/',
	        '/wp-content/uploads/wp-rocket/',
        	'/wp-content/uploads/wpo-cache/',
	        '/wp-content/uploads/w3tc/',
        	'/wp-content/uploads/litespeed/',
	        '/wp-content/uploads/elementor/css/',
        	'/wp-content/uploads/backups/',
	        '/wp-content/uploads/backup/',
	    );

	    foreach ( $skip_prefixes as $p ) {
        	$p0 = rtrim( $p, '/' );
	        if ( $z === $p0 || 0 === strpos( $z, $p ) ) {
        	    continue 2;
	        }
	    }

	    // INCLUDE (safe payload only)
	    if ( $item->isDir() ) {
        	$zip->addEmptyDir( ltrim( $zip_path, '/' ) );
	    } else {
        	$zip->addFile( $full_path, ltrim( $zip_path, '/' ) );
	    }
	}

    }


    /**
     * Day-17: Activity Timeline (evidence-first, plain language).
     * Stored locally as a small ring-buffer option.
     */
    private static function activity_timeline_enabled(): bool {
        // Reuse existing telemetry switch if present; default OFF if not defined.
        // This avoids inventing new settings surfaces.
        return (bool) get_option( 'opsgate_telemetry_enabled', false );
    }

    private static function activity_timeline_option_key(): string {
        return 'opsgate_activity_timeline';
    }

    private static function activity_timeline_read(): array {
        $raw = get_option( self::activity_timeline_option_key(), array() );
        return is_array( $raw ) ? $raw : array();
    }

    private static function activity_timeline_write( array $items ): bool {
        // Keep newest-first, hard cap.
        $items = array_values( $items );
        $items = array_slice( $items, 0, 50 );
        return update_option( self::activity_timeline_option_key(), $items, false );
    }

    /**
     * Add one timeline entry (newest-first).
     *
     * @param string $label   Plain-language action label.
     * @param string $outcome completed|attention|in_progress
     * @param string $details Optional plain-language details (no internals).
     */
    private static function activity_timeline_add( string $label, string $outcome, string $details = '' ): void {
        if ( ! self::activity_timeline_enabled() ) {
            return;
        }

        $label   = trim( wp_strip_all_tags( $label ) );
        $details = trim( wp_strip_all_tags( $details ) );

        // Normalize outcome.
        $allowed = array( 'completed', 'attention', 'in_progress' );
        if ( ! in_array( $outcome, $allowed, true ) ) {
            $outcome = 'completed';
        }

        $items = self::activity_timeline_read();

        array_unshift( $items, array(
            'ts_utc'  => gmdate( 'Y-m-d\TH:i:s\Z' ),
            'label'   => $label,
            'outcome' => $outcome,
            'details' => $details,
        ) );

        self::activity_timeline_write( $items );
    }

    private static function activity_timeline_format_time( string $ts_utc ): string {
        $ts = strtotime( $ts_utc );
        if ( ! $ts ) {
            return '';
        }
        // Display in WP local time, human-readable.
        return wp_date( 'M j, Y g:i A', $ts );
    }

    private static function format_event_datetime( string $value ): string {
        $value = trim( $value );
        if ( '' === $value ) {
            return '';
        }

        $ts = strtotime( $value );
        if ( ! $ts ) {
            return $value;
        }

        return wp_date( 'M j, Y g:i A', $ts );
    }

    private static function activity_timeline_outcome_badge( string $outcome ): array {
        if ( 'completed' === $outcome ) {
            return array( 'label' => 'Completed', 'class' => 'opsgate-badge--good' );
        }
        if ( 'in_progress' === $outcome ) {
            return array( 'label' => 'In progress', 'class' => 'opsgate-badge--neutral' );
        }
        return array( 'label' => 'Attention needed', 'class' => 'opsgate-badge--warn' );
    }


    private static function render_license_paste_form() {
        if ( ! current_user_can( 'manage_options' ) ) {
            return;
        }

        $action_url = admin_url( 'admin-post.php' );

        echo '<div class="opsgate-card" style="margin-top:16px;">';
        echo '<h2><span class="dashicons dashicons-admin-network"></span> License &amp; Plan</h2>';
        echo '<p class="description" style="margin-top:6px;">Controls what this site is entitled to. License Stored on this site.</p>';

	// Premium status snapshot (Wordfence-style, Phase 1: visibility only).
        $snap = self::get_license_validation_snapshot();

        $status = isset( $snap['status'] ) ? strtolower( trim( (string) $snap['status'] ) ) : 'unknown';
        $tier   = isset( $snap['tier'] ) ? strtolower( trim( (string) $snap['tier'] ) ) : 'free';

        $expires_at      = isset( $snap['expires_at'] ) ? (string) $snap['expires_at'] : '';
        $last_checked_at = isset( $snap['last_checked_at'] ) ? (string) $snap['last_checked_at'] : '';
        $reason          = isset( $snap['reason'] ) ? (string) $snap['reason'] : '';

        // Human-friendly dates (customer-first).
        $expires_human = '—';
        if ( '' !== trim( (string) $expires_at ) ) {
            $ts = strtotime( (string) $expires_at );
            if ( $ts ) {
                $expires_human = wp_date( 'M j, Y', $ts );
            }
        }

        $checked_human = '—';
        if ( '' !== trim( (string) $last_checked_at ) ) {
            $ts = strtotime( (string) $last_checked_at );
            if ( $ts ) {
                $checked_human = wp_date( 'M j, Y g:i A', $ts );
            }
        }


        $type = 'info';
        if ( 'valid' === $status ) {
            $type = 'ok';
        } elseif ( in_array( $status, array( 'expired', 'unbound' ), true ) ) {
            $type = 'warn';
        } elseif ( in_array( $status, array( 'invalid', 'missing' ), true ) ) {
            $type = 'err';
        }

        $label_status = ( '' !== $status ) ? strtoupper( $status ) : 'UNKNOWN';
        $label_tier   = ( '' !== $tier ) ? strtoupper( $tier ) : 'FREE';

        echo '<div style="margin:12px 0; padding:12px; border:1px solid #e5e5e5; border-radius:10px; background:#fff;">';
        echo '<div style="display:flex; gap:8px; align-items:center; flex-wrap:wrap; margin-bottom:6px;">';
        echo self::badge( 'License', $label_status, $type );
        echo self::badge( 'Tier', $label_tier, ( 'valid' === $status ? 'ok' : 'info' ) );
        echo '</div>';

	// Customer-first guidance (no internal terms).
        if ( 'valid' === $status ) {
            echo '<p style="margin:10px 0 0 0;"><strong>Status:</strong> Your plan is active for this site.</p>';
        } elseif ( 'missing' === $status ) {
            echo '<p style="margin:10px 0 0 0;"><strong>Action:</strong> Paste your license to activate your plan on this site.</p>';
        } elseif ( 'invalid' === $status || 'malformed_json' === $status ) {
            echo '<p style="margin:10px 0 0 0;"><strong>Action:</strong> This license format is not valid. Re-issue the license and paste it again.</p>';
        } elseif ( 'expired' === $status ) {
            echo '<p style="margin:10px 0 0 0;"><strong>Action:</strong> This license has expired. Renew it, then paste the updated license here.</p>';
        } elseif ( 'unbound' === $status || 'mismatch' === $status ) {
            echo '<p style="margin:10px 0 0 0;"><strong>Action:</strong> This license was issued for a different site. Paste the license issued for this site.</p>';
        } else {
            echo '<p style="margin:10px 0 0 0;"><strong>Action:</strong> License status could not be verified. Please re-check the license and try again.</p>';
        }

        echo '<div style="display:flex; gap:14px; flex-wrap:wrap; margin-top:8px;">';
        echo '<p style="margin:6px 0 0 0;"><strong>Expires:</strong> ' . esc_html( $expires_human ) . '</p>';
        echo '<p style="margin:4px 0 0 0;"><strong>Last checked:</strong> ' . esc_html( $checked_human ) . '</p>';
        echo '</div>';

	// Do not show internal reason codes in the primary UI (customer-first).
        // Keep it only in admin details below.
	/*
        if ( '' !== trim( $reason ) ) {
            echo '<p style="margin:6px 0 0 0;"><strong>Reason:</strong> ' . esc_html( $reason ) . '</p>';
        }
	*/

        //echo '<p class="description" style="margin-top:10px;">Licence stored on this site.</p>';
        echo '</div>';

        echo '<form method="post" action="' . esc_url( $action_url ) . '">';
        echo '<input type="hidden" name="action" value="opsgate_save_license">';
        $reset_url = self::get_license_reset_url();
        echo '<p style="margin:8px 0 0 0;">';
        //echo '<a class="button button-secondary" href="' . esc_url( $reset_url ) . '" onclick="return confirm(\'Reset license on this site? This cannot be undone.\');">Reset License</a>';
	echo '<div style="margin: 0 0 10px 0;">';
	echo '<a class="button button-secondary" href="' . esc_url( $url ) . '" onclick="return confirm(\'Reset license on this site? This cannot be undone.\');">Reset License</a>';
	echo '</div>';

        echo '</p>';
        wp_nonce_field( 'opsgate_save_license', 'opsgate_license_nonce' );

        $raw = get_option( 'opsgate_license_json', '' );
        $raw = is_string( $raw ) ? trim( $raw ) : '';

        // Pretty-print if valid JSON, otherwise show raw safely.
        $pretty  = $raw;
        $decoded = json_decode( $raw, true );
        if ( '' !== $raw && JSON_ERROR_NONE === json_last_error() && is_array( $decoded ) ) {
            $pretty = wp_json_encode( $decoded, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );
        }

        echo '<textarea class="large-text code" rows="9" name="opsgate_license_json_input" style="font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;" placeholder="{&quot;license_key&quot;:&quot;...&quot;,&quot;tier&quot;:&quot;starter&quot;,&quot;site_id&quot;:&quot;...&quot;,&quot;expires_at&quot;:&quot;...&quot;}">' .
            esc_textarea( $pretty ) .
        '</textarea>';

        echo '<p style="margin-top:10px;"><button type="submit" class="button button-primary">Save License</button></p>';
        echo '</form>';

        echo '</div>';
        echo '</div>';
    }

    /**
     * Admin notices for licensing actions (save / error / reset).
     * - Gate: manage_options only
     * - No token leakage
     * - Reads only fixed query flags (value "1")
     */
    public static function maybe_show_license_admin_notices(): void
    {
        if ( ! current_user_can( 'manage_options' ) ) {
            return;
        }

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $saved = isset( $_GET['opsgate_license_saved'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_license_saved'] ) ) : '';
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $error = isset( $_GET['opsgate_license_error'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_license_error'] ) ) : '';
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $reset = isset( $_GET['opsgate_license_reset'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_license_reset'] ) ) : '';

        // Reset notice (keep existing behavior, but centralized).
        if ( '1' === $reset ) {
            echo '<div class="notice notice-success is-dismissible"><p>'
                . esc_html__( 'OpsGate license has been reset (cleared).', 'opsgate' )
                . '</p></div>';
        }

        // Save success.
        if ( '1' === $saved ) {
            echo '<div class="notice notice-success is-dismissible"><p>'
                . esc_html__( 'OpsGate license saved successfully.', 'opsgate' )
                . '</p></div>';
        }

        // Save error.
        if ( '1' === $error ) {
            echo '<div class="notice notice-error is-dismissible"><p>'
                . esc_html__( 'OpsGate license could not be saved. Please verify the JSON is valid and meets the required fields, then try again.', 'opsgate' )
                . '</p></div>';
        }

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        if ( isset($_GET['opsgate_weekly_run']) ) {
            $v_raw = sanitize_text_field( wp_unslash( $_GET['opsgate_weekly_run'] ) );
            $v = in_array( $v_raw, array( 'success', 'error' ), true ) ? $v_raw : '';
            if ( $v === 'success' ) {
                echo '<div class="notice notice-success is-dismissible"><p>Weekly run recorded.</p></div>';
            } elseif ( $v === 'error' ) {
                echo '<div class="notice notice-error is-dismissible"><p>Weekly run failed to record.</p></div>';
            }
        }

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        if ( isset( $_GET['opsgate_monthly_run'] ) ) {
            $v_raw = sanitize_text_field( wp_unslash( $_GET['opsgate_monthly_run'] ) );
            $v = in_array( $v_raw, array( 'success', 'error' ), true ) ? $v_raw : '';

            if ( 'success' === $v ) {
                echo '<div class="notice notice-success is-dismissible"><p>Monthly consolidation recorded.</p></div>';
            } elseif ( 'error' === $v ) {
                echo '<div class="notice notice-error is-dismissible"><p>Monthly consolidation failed to record.</p></div>';
            }
        }

    }

    /**
     * Day-9.4: Show a one-time notice after license reset.
     *
     * @return void
     */
    public static function maybe_show_license_reset_notice() {
        if ( ! current_user_can( 'manage_options' ) ) {
            return;
        }

        if ( empty( $_GET['opsgate_license_reset'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
            return;
        }

        if ( isset( $_GET['opsgate_license_save'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
            $ok = ( '1' === (string) $_GET['opsgate_license_save'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
            $code = isset( $_GET['opsgate_license_code'] ) ? (string) $_GET['opsgate_license_code'] : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
            $code = sanitize_text_field( $code );

            if ( $ok ) {
                echo '<div class="notice notice-success is-dismissible"><p><strong>OpsGate:</strong> License saved successfully.</p></div>';
            } else {
                echo '<div class="notice notice-error is-dismissible"><p><strong>OpsGate:</strong> License save failed (' . esc_html( $code ) . ').</p></div>';
            }
        }

        echo '<div class="notice notice-success is-dismissible"><p><strong>OpsGate:</strong> License reset completed (opsgate_license_json deleted).</p></div>';
    }


    /**
     * Ensure core plugin options exist with safe defaults.
     *
     * Safety rules:
     * - Only CREATE missing options (add_option).
     * - NEVER overwrite existing values (no update_option here unless generating required IDs/tokens when missing).
     *
     * @return void
     */
    public static function bootstrap_defaults() {
        // Core overview options.
        self::add_option_if_missing( 'opsgate_telemetry_enabled', '0' );
        self::add_option_if_missing( 'opsgate_last_triage_job_id', '' );
        self::add_option_if_missing( 'opsgate_last_export_job_id', '' );
        self::add_option_if_missing( 'opsgate_last_export_source_job_id', '' );
        self::add_option_if_missing( 'opsgate_scope_runtime_refs', array() );

        // Pricing options (Day-7).
        self::add_option_if_missing( 'opsgate_stripe_mode', 'test' );
        self::add_option_if_missing( 'opsgate_stripe_publishable_key', '' );
        self::add_option_if_missing( 'opsgate_stripe_payment_link_starter', '' );
        self::add_option_if_missing( 'opsgate_stripe_payment_link_pro', '' );

        // Services/Schedules option containers (do not force structure; only create if missing).
        self::add_option_if_missing( 'opsgate_services', array() );
        self::add_option_if_missing( 'opsgate_schedules', array() );

        // Day 19.4 (Option B): Scheduling master switch (OFF by default).
        // WP.org compliance: no background automation unless explicitly enabled by the admin.
        self::add_option_if_missing( 'opsgate_scheduling_enabled', '0' );

        // Day-8 Identity defaults (create missing only).
        self::bootstrap_identity_defaults();
        self::bootstrap_active_site_scope_defaults();

        // Day-9 Licensing (Phase 1): local license JSON storage (create missing only).
        self::add_option_if_missing( 'opsgate_license_json', '' );

    }

    /**
     * Add option only if missing.
     *
     * @param string $key Option key.
     * @param mixed  $default Default value.
     * @return void
     */
    private static function add_option_if_missing( $key, $default ) {
        $key = is_string( $key ) ? trim( $key ) : '';
        if ( '' === $key ) {
            return;
        }

        $existing = get_option( $key, null );

        // get_option returns false when not found; we treat only false as "missing".
        if ( false === $existing ) {
            add_option( $key, $default );
        }
    }

    /**
     * Ensure Day-8 Identity options exist (bootstrap defaults).
     *
     * Safety rules:
     * - NEVER overwrite existing non-empty values.
     * - Create missing values only.
     * - Generate site_id if missing (required).
     * - Generate site_token if missing (reserved for linking/licensing).
     * - Link proof fields created only; generated only via explicit admin action.
     *
     * @return void
     */
    private static function bootstrap_identity_defaults() {
        // Ensure the option keys exist even if user never opened the settings page.
        self::add_option_if_missing( 'opsgate_site_id', '' );
        self::add_option_if_missing( 'opsgate_site_label', '' );
        self::add_option_if_missing( 'opsgate_identity_email', '' );
        self::add_option_if_missing( 'opsgate_site_token', '' );
        self::add_option_if_missing( 'opsgate_connector_installation_id', '' );
        self::add_option_if_missing( OPSGATE_OPTION_CONNECTOR_PAIRING_TOKEN, '' );
        self::add_option_if_missing( OPSGATE_OPTION_CONNECTOR_SITE_CREDENTIAL, '' );

        // Day-8.3/8.4 linking proof storage (local-first).
        self::add_option_if_missing( 'opsgate_site_linked_at', '' );
        self::add_option_if_missing( 'opsgate_site_link_proof', '' );

        // 1) Site ID (required): generate if empty.
        $site_id = get_option( 'opsgate_site_id', '' );
        $site_id = is_string( $site_id ) ? trim( $site_id ) : '';
        if ( '' === $site_id ) {
            self::get_or_create_site_id();
        }

        // 2) Site Label default (do not overwrite if user set it).
        $label = get_option( 'opsgate_site_label', '' );
        $label = is_string( $label ) ? trim( $label ) : '';
        if ( '' === $label ) {
            $fallback_label = (string) get_bloginfo( 'name' );
            $fallback_label = trim( $fallback_label );
            if ( '' === $fallback_label ) {
                $fallback_label = (string) get_option( 'opsgate_site_id', '' );
                $fallback_label = is_string( $fallback_label ) ? trim( $fallback_label ) : '';
            }
            if ( '' === $fallback_label ) {
                $fallback_url = (string) home_url();
                $fallback_url = trim( $fallback_url );
                $fallback_host = (string) ( wp_parse_url( $fallback_url, PHP_URL_HOST ) ?: '' );
                $fallback_label = '' !== $fallback_host ? $fallback_host : 'local-wp';
            }
            update_option( 'opsgate_site_label', $fallback_label, true );
        }

        // 3) Identity Email default (do not overwrite if user set it).
        $email = get_option( 'opsgate_identity_email', '' );
        $email = is_string( $email ) ? trim( $email ) : '';
        if ( '' === $email ) {
            $fallback_email = (string) get_bloginfo( 'admin_email' );
            $fallback_email = trim( $fallback_email );
            if ( '' !== $fallback_email ) {
                update_option( 'opsgate_identity_email', $fallback_email, true );
            }
        }

        // 4) Site Token default (reserved): generate if empty.
        $token = get_option( 'opsgate_site_token', '' );
        $token = is_string( $token ) ? trim( $token ) : '';
        if ( '' === $token ) {
            $generated = wp_generate_password( 32, false, false );
            $generated = is_string( $generated ) ? trim( $generated ) : '';
            if ( '' !== $generated ) {
                update_option( 'opsgate_site_token', $generated, true );
            }
        }

        $connector_installation_id = get_option( 'opsgate_connector_installation_id', '' );
        $connector_installation_id = is_string( $connector_installation_id ) ? trim( $connector_installation_id ) : '';
        if ( '' === $connector_installation_id ) {
            $connector_installation_id = function_exists( 'wp_generate_uuid4' ) ? wp_generate_uuid4() : sha1( home_url() . '|' . microtime( true ) );
            update_option( 'opsgate_connector_installation_id', $connector_installation_id, true );
        }
    }

    /**
     * Ensure Day-9 Licensing options exist (bootstrap defaults).
     *
     * Safety rules:
     * - Create license option only if missing.
     * - Never overwrite existing license.
     *
     * @return void
     */
    private static function bootstrap_licensing_defaults() {
        // Day-9: License storage option (JSON string).
        self::add_option_if_missing( 'opsgate_license_json', '' );
        self::add_option_if_missing( 'opsgate_license_last_validated', '' );
    }

    /**
     * Get a safe identity snapshot for MCP payloads.
     *
     * @return array{site_id:string,site_label:string,identity_email:string,site_token:string,site_url:string,site_host:string}
     */
    private static function get_identity_snapshot() {
        self::bootstrap_identity_defaults();

        $site_id = get_option( 'opsgate_site_id', '' );
        $site_id = is_string( $site_id ) ? trim( $site_id ) : '';
        if ( '' === $site_id ) {
            $site_id = self::get_or_create_site_id();
        }

        $site_label = get_option( 'opsgate_site_label', (string) get_bloginfo( 'name' ) );
        $site_label = is_string( $site_label ) ? trim( $site_label ) : (string) get_bloginfo( 'name' );

        $identity_email = get_option( 'opsgate_identity_email', (string) get_bloginfo( 'admin_email' ) );
        $identity_email = is_string( $identity_email ) ? trim( $identity_email ) : (string) get_bloginfo( 'admin_email' );

        $site_token = get_option( 'opsgate_site_token', '' );
        $site_token = is_string( $site_token ) ? trim( $site_token ) : '';

        // Local install identity must always resolve to this WordPress host.
        $site_url = trim( (string) home_url() );
        $site_host = (string) ( wp_parse_url( $site_url, PHP_URL_HOST ) ?: 'local-wp' );
        if ( '' === $site_label ) {
            $site_label = '' !== $site_id ? $site_id : $site_host;
        }

        return array(
            'site_id'        => $site_id,
            'site_label'     => $site_label,
            'identity_email' => $identity_email,
            'site_token'     => $site_token,
            'site_url'       => $site_url,
            'site_host'      => $site_host,
        );
    }

    private static function connector_installation_id(): string {
        self::bootstrap_identity_defaults();
        $value = get_option( 'opsgate_connector_installation_id', '' );
        return is_string( $value ) ? trim( $value ) : '';
    }

    private static function connector_pairing_token(): string {
        $value = get_option( OPSGATE_OPTION_CONNECTOR_PAIRING_TOKEN, '' );
        return is_string( $value ) ? trim( $value ) : '';
    }

    private static function store_connector_pairing_token( string $token ): void {
        update_option( OPSGATE_OPTION_CONNECTOR_PAIRING_TOKEN, trim( $token ), false );
    }

    private static function connector_site_credential(): string {
        $value = get_option( OPSGATE_OPTION_CONNECTOR_SITE_CREDENTIAL, '' );
        if ( ! is_string( $value ) || '' === trim( $value ) ) {
            return '';
        }
        return function_exists( 'opsgate_decrypt_connector_secret' )
            ? (string) opsgate_decrypt_connector_secret( $value )
            : '';
    }

    /**
     * API-backed local readback cache for the current connector scope.
     *
     * This cache never becomes canonical truth. It only preserves the latest
     * API-returned site summary when the remote companion cannot immediately
     * reread canonical site config after pairing or connector registration.
     *
     * @return array<string,mixed>
     */
    private static function connector_connection_summary_cache(): array {
        $raw = get_option( 'opsgate_connector_connection_summary', '' );
        if ( ! is_string( $raw ) || '' === trim( $raw ) ) {
            return array();
        }

        $decoded = json_decode( $raw, true );
        return is_array( $decoded ) ? $decoded : array();
    }

    /**
     * @param array<string,mixed> $site
     */
    private static function store_connector_connection_summary_cache( array $site ): void {
        if ( empty( $site ) ) {
            return;
        }

        $payload = array_filter(
            array(
                'account_id' => isset( $site['account_id'] ) ? trim( (string) $site['account_id'] ) : '',
                'site_id' => isset( $site['site_id'] ) ? trim( (string) $site['site_id'] ) : '',
                'site_label' => isset( $site['site_label'] ) ? trim( (string) $site['site_label'] ) : '',
                'site_url' => isset( $site['site_url'] ) ? trim( (string) $site['site_url'] ) : '',
                'connection_status' => isset( $site['connection_status'] ) ? trim( (string) $site['connection_status'] ) : '',
                'connection_mode' => isset( $site['connection_mode'] ) ? trim( (string) $site['connection_mode'] ) : '',
                'connector_version' => isset( $site['connector_version'] ) ? trim( (string) $site['connector_version'] ) : '',
                'connector_installation_id' => isset( $site['connector_installation_id'] ) ? trim( (string) $site['connector_installation_id'] ) : '',
                'last_connection_error' => isset( $site['last_connection_error'] ) ? trim( (string) $site['last_connection_error'] ) : '',
                'inventory_source' => isset( $site['inventory_source'] ) ? trim( (string) $site['inventory_source'] ) : '',
                'paired_at_utc' => isset( $site['paired_at_utc'] ) ? trim( (string) $site['paired_at_utc'] ) : '',
                'last_handshake_at_utc' => isset( $site['last_handshake_at_utc'] ) ? trim( (string) $site['last_handshake_at_utc'] ) : '',
            ),
            static function ( $value ): bool {
                return null !== $value && '' !== $value;
            }
        );

        if ( empty( $payload ) ) {
            return;
        }

        update_option( 'opsgate_connector_connection_summary', wp_json_encode( $payload ), false );
    }

    private static function clear_connector_connection_summary_cache(): void {
        delete_option( 'opsgate_connector_connection_summary' );
    }

    private static function store_connector_site_credential( string $credential ): void {
        $encrypted = function_exists( 'opsgate_encrypt_connector_secret' )
            ? (string) opsgate_encrypt_connector_secret( $credential )
            : '';
        update_option( OPSGATE_OPTION_CONNECTOR_SITE_CREDENTIAL, $encrypted, false );
    }

    private static function clear_connector_site_credential(): void {
        update_option( OPSGATE_OPTION_CONNECTOR_SITE_CREDENTIAL, '', false );
        self::clear_connector_connection_summary_cache();
    }

    /**
     * Active connected site selector cached locally.
     *
     * @return array{site_id:string,site_label:string,site_url:string,site_host:string}
     */
    private static function get_active_site_scope_selector(): array {
        self::bootstrap_active_site_scope_defaults();

        $site_id = trim( (string) get_option( 'opsgate_active_site_id', '' ) );
        $site_label = trim( (string) get_option( 'opsgate_active_site_label', '' ) );
        $site_url = trim( (string) get_option( 'opsgate_active_site_url', '' ) );

        return array(
            'site_id'    => $site_id,
            'site_label' => $site_label,
            'site_url'   => $site_url,
            'site_host'  => (string) ( wp_parse_url( $site_url, PHP_URL_HOST ) ?: '' ),
        );
    }

    /**
     * Persist the active site selector after canonical resolution.
     *
     * @param array<string,mixed> $config
     * @return void
     */
    private static function sync_active_site_scope_options( array $config ): void {
        if ( array_key_exists( 'site_id', $config ) ) {
            update_option( 'opsgate_active_site_id', trim( (string) $config['site_id'] ), false );
        }
        if ( array_key_exists( 'site_label', $config ) ) {
            update_option( 'opsgate_active_site_label', trim( (string) $config['site_label'] ), false );
        }
        if ( array_key_exists( 'site_url', $config ) ) {
            update_option( 'opsgate_active_site_url', trim( (string) $config['site_url'] ), false );
        }
    }

    /**
     * Determine whether the selected scope points back to this local WordPress install.
     */
    private static function scope_targets_local_wordpress( string $site_url ): bool {
        $selected_host = (string) ( wp_parse_url( trim( $site_url ), PHP_URL_HOST ) ?: '' );
        $local_host = (string) ( wp_parse_url( (string) home_url(), PHP_URL_HOST ) ?: '' );
        return '' !== $selected_host && '' !== $local_host && strtolower( $selected_host ) === strtolower( $local_host );
    }

    /**
     * Runtime pointers for the currently selected canonical site scope.
     *
     * These refs are UI navigation/cache aids only. They must never replace
     * canonical API reads for latest run, export, or alert truth.
     *
     * @return string
     */
    private static function scope_runtime_refs_option_key(): string {
        return 'opsgate_scope_runtime_refs';
    }

    /**
     * @param array<string,mixed> $scope
     * @return string
     */
    private static function scope_runtime_refs_bucket_key( array $scope ): string {
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';
        if ( '' === $account_id || '' === $site_id ) {
            return '';
        }

        return $account_id . ':' . $site_id;
    }

    /**
     * @return array<string,array<string,string>>
     */
    private static function scope_runtime_refs_read_all(): array {
        $raw = get_option( self::scope_runtime_refs_option_key(), array() );
        return is_array( $raw ) ? $raw : array();
    }

    /**
     * @return array{last_triage_job_id:string,last_export_job_id:string,last_export_source_job_id:string}
     */
    private static function scope_runtime_refs_defaults(): array {
        return array(
            'last_triage_job_id'        => '',
            'last_export_job_id'        => '',
            'last_export_source_job_id' => '',
        );
    }

    /**
     * @param array<string,mixed> $scope
     * @return array{last_triage_job_id:string,last_export_job_id:string,last_export_source_job_id:string}
     */
    private static function scope_runtime_refs_for_scope( array $scope ): array {
        $bucket_key = self::scope_runtime_refs_bucket_key( $scope );
        if ( '' === $bucket_key ) {
            return self::scope_runtime_refs_defaults();
        }

        $all = self::scope_runtime_refs_read_all();
        $item = isset( $all[ $bucket_key ] ) && is_array( $all[ $bucket_key ] ) ? $all[ $bucket_key ] : array();

        return array(
            'last_triage_job_id'        => trim( (string) ( $item['last_triage_job_id'] ?? '' ) ),
            'last_export_job_id'        => trim( (string) ( $item['last_export_job_id'] ?? '' ) ),
            'last_export_source_job_id' => trim( (string) ( $item['last_export_source_job_id'] ?? '' ) ),
        );
    }

    /**
     * Keep legacy global refs aligned with the current selected site scope while
     * newer surfaces use site-scoped runtime refs directly.
     *
     * @param array{last_triage_job_id:string,last_export_job_id:string,last_export_source_job_id:string} $refs
     * @return void
     */
    private static function sync_legacy_runtime_refs( array $refs ): void {
        update_option( 'opsgate_last_triage_job_id', trim( (string) ( $refs['last_triage_job_id'] ?? '' ) ), false );
        update_option( 'opsgate_last_export_job_id', trim( (string) ( $refs['last_export_job_id'] ?? '' ) ), false );
        update_option( 'opsgate_last_export_source_job_id', trim( (string) ( $refs['last_export_source_job_id'] ?? '' ) ), false );
    }

    /**
     * @param array<string,mixed> $scope
     * @param array<string,string> $updates
     * @return void
     */
    private static function update_scope_runtime_refs( array $scope, array $updates ): void {
        $bucket_key = self::scope_runtime_refs_bucket_key( $scope );
        if ( '' === $bucket_key ) {
            return;
        }

        $all = self::scope_runtime_refs_read_all();
        $current = self::scope_runtime_refs_for_scope( $scope );

        foreach ( self::scope_runtime_refs_defaults() as $field => $default ) {
            if ( array_key_exists( $field, $updates ) ) {
                $current[ $field ] = trim( (string) $updates[ $field ] );
            }
        }

        $all[ $bucket_key ] = $current;
        update_option( self::scope_runtime_refs_option_key(), $all, false );
        self::sync_legacy_runtime_refs( $current );
    }

    /**
     * @param array<string,mixed> $scope
     * @return void
     */
    private static function sync_scope_runtime_refs_for_scope( array $scope ): void {
        self::sync_legacy_runtime_refs( self::scope_runtime_refs_for_scope( $scope ) );
    }

    /**
     * @param array<string,mixed> $before
     * @param array<string,mixed> $after
     * @return bool
     */
    private static function scope_selection_changed( array $before, array $after ): bool {
        $before_site_id = isset( $before['site_id'] ) ? trim( (string) $before['site_id'] ) : '';
        $after_site_id = isset( $after['site_id'] ) ? trim( (string) $after['site_id'] ) : '';
        $before_site_url = isset( $before['site_url'] ) ? trim( (string) $before['site_url'] ) : '';
        $after_site_url = isset( $after['site_url'] ) ? trim( (string) $after['site_url'] ) : '';

        return $before_site_id !== $after_site_id || $before_site_url !== $after_site_url;
    }

    /**
     * Snapshot: canonical MCP scope for API reads/writes from this site.
     *
     * This is intentionally separate from get_identity_snapshot():
     * - identity snapshot = site identity / claim / labeling concerns
     * - MCP scope snapshot = API authority scope (account_id + site_id)
     *
     * @return array{account_id:string,site_id:string,site_label?:string,site_url?:string,resolution_kind?:string,error?:string}
     */
    private static function get_mcp_scope_snapshot(): array {
        static $cache = null;

        if ( is_array( $cache ) ) {
            return $cache;
        }

        $requested_scope = self::resolve_requested_site_scope_from_query();
        if ( ! empty( $requested_scope['has_explicit_scope'] ) ) {
            if ( empty( $requested_scope['ok'] ) ) {
                $cache = array(
                    'account_id' => isset( $requested_scope['account_id'] ) ? trim( (string) $requested_scope['account_id'] ) : '',
                    'site_id'    => '',
                    'site_label' => isset( $requested_scope['site_label'] ) ? trim( (string) $requested_scope['site_label'] ) : '',
                    'site_url'   => isset( $requested_scope['site_url'] ) ? trim( (string) $requested_scope['site_url'] ) : '',
                    'error'      => isset( $requested_scope['error'] ) ? trim( (string) $requested_scope['error'] ) : 'scoped_site_authority_error',
                );
                return $cache;
            }

            $cache = array(
                'account_id'      => isset( $requested_scope['account_id'] ) ? trim( (string) $requested_scope['account_id'] ) : '',
                'site_id'         => isset( $requested_scope['site_id'] ) ? trim( (string) $requested_scope['site_id'] ) : '',
                'site_label'      => isset( $requested_scope['site_label'] ) ? trim( (string) $requested_scope['site_label'] ) : '',
                'site_url'        => isset( $requested_scope['site_url'] ) ? trim( (string) $requested_scope['site_url'] ) : '',
                'resolution_kind' => isset( $requested_scope['resolution_kind'] ) ? trim( (string) $requested_scope['resolution_kind'] ) : '',
            );
            return $cache;
        }

        $account_id   = (string) get_option( 'opsgate_account_id', '' );
        $active_scope = self::get_active_site_scope_selector();
        $site_id      = isset( $active_scope['site_id'] ) ? (string) $active_scope['site_id'] : '';
        $site_url     = isset( $active_scope['site_url'] ) ? trim( (string) $active_scope['site_url'] ) : trim( (string) home_url() );
        $local_site_id = trim( (string) get_option( 'opsgate_site_id', '' ) );

        $account_id = is_string( $account_id ) ? trim( $account_id ) : '';
        $site_id    = is_string( $site_id ) ? trim( $site_id ) : '';
        if ( '' !== $site_id && '' !== $site_url && ! self::scope_targets_local_wordpress( $site_url ) && $site_id === $local_site_id ) {
            // Auto-heal a stale local site_id pin when the selected site URL has
            // already moved to a different remote scope.
            $site_id = '';
        }

        $cache = array(
            'account_id' => $account_id,
            'site_id'    => $site_id,
        );

        if ( '' === $account_id ) {
            return $cache;
        }

        if ( '' === $site_id && '' === $site_url ) {
            $cache['error'] = 'site_scope_identity_missing';
            return $cache;
        }

        $site_label = isset( $active_scope['site_label'] ) ? trim( (string) $active_scope['site_label'] ) : trim( (string) get_bloginfo( 'name' ) );

        $resp = self::mcp_post_json(
            '/v1/sites/resolve',
            array(
                'account_id' => $account_id,
                'site_id'    => '' !== $site_id ? $site_id : null,
                'site_url'   => $site_url,
                'site_label' => $site_label,
            )
        );

        if ( empty( $resp['ok'] ) ) {
            $cache['error'] = isset( $resp['error'] ) ? trim( (string) $resp['error'] ) : 'site_scope_unavailable';
            return $cache;
        }

        $data = isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array();
        $resolved_site_id = isset( $data['site_id'] ) ? trim( (string) $data['site_id'] ) : '';
        if ( '' === $resolved_site_id ) {
            $cache['error'] = 'site_scope_missing';
            return $cache;
        }

        self::sync_active_site_scope_options( $data );

        $cache = array(
            'account_id'      => $account_id,
            'site_id'         => $resolved_site_id,
            'site_label'      => isset( $data['site_label'] ) ? trim( (string) $data['site_label'] ) : '',
            'site_url'        => isset( $data['site_url'] ) ? trim( (string) $data['site_url'] ) : '',
            'resolution_kind' => isset( $data['resolution_kind'] ) ? trim( (string) $data['resolution_kind'] ) : '',
        );
        self::sync_scope_runtime_refs_for_scope( $cache );

        return $cache;
    }

    /**
     * Synchronize locally cached identity options from canonical site config.
     *
     * @param array<string,mixed> $config
     * @return void
     */
    private static function sync_canonical_site_config_options( array $config ): void {
        self::sync_active_site_scope_options( $config );
    }

    /**
     * Ensure the active site-scope selector exists.
     *
     * This is only a local pointer to canonical site truth. It must never
     * replace the authority row in OpsGate.
     *
     * @return void
     */
    private static function bootstrap_active_site_scope_defaults(): void {
        self::add_option_if_missing( 'opsgate_active_site_id', '' );
        self::add_option_if_missing( 'opsgate_active_site_label', '' );
        self::add_option_if_missing( 'opsgate_active_site_url', '' );
    }

    /**
     * Canonical site identity/config for the connected scope.
     *
     * @return array{ok:bool,item:array<string,mixed>,error:string}
     */
    private static function canonical_site_config(): array {
        static $cache = null;

        if ( is_array( $cache ) ) {
            return $cache;
        }

        $scope      = self::get_mcp_scope_snapshot();
        $active_scope = self::get_active_site_scope_selector();
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id    = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';
        $site_url   = isset( $active_scope['site_url'] ) ? trim( (string) $active_scope['site_url'] ) : '';

        if ( '' === $account_id || '' === $site_id || '' === $site_url ) {
            $cache = array(
                'ok'    => false,
                'item'  => array(),
                'error' => 'Connect this site in Settings before reading canonical site identity.',
            );
            return $cache;
        }

        $resp = self::mcp_get_json(
            '/v1/sites/config',
            array(
                'account_id' => $account_id,
                'site_id'    => $site_id,
                'site_url'   => $site_url,
            )
        );

        if ( empty( $resp['ok'] ) ) {
            $cache = array(
                'ok'    => false,
                'item'  => array(),
                'error' => isset( $resp['error'] ) ? (string) $resp['error'] : 'Could not load canonical site identity.',
            );
            return $cache;
        }

        $item = isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array();
        self::sync_canonical_site_config_options( $item );

        $cache = array(
            'ok'    => true,
            'item'  => $item,
            'error' => '',
        );
        return $cache;
    }

    /**
     * Read canonical validation remediation state for a specific run.
     *
     * @param string $account_id
     * @param string $site_id
     * @param string $source_job_id
     * @return array{ok:bool,items:array<string,array<string,mixed>>,error:string}
     */
    private static function canonical_validation_remediation_state( string $account_id, string $site_id, string $source_job_id ): array {
        static $cache = array();

        $cache_key = implode( ':', array( $account_id, $site_id, $source_job_id ) );
        if ( isset( $cache[ $cache_key ] ) && is_array( $cache[ $cache_key ] ) ) {
            return $cache[ $cache_key ];
        }

        if ( '' === $account_id || '' === $site_id || '' === $source_job_id ) {
            $cache[ $cache_key ] = array(
                'ok'    => false,
                'items' => array(),
                'error' => 'Validation remediation state requires account, site, and run scope.',
            );
            return $cache[ $cache_key ];
        }

        $resp = self::mcp_get_json(
            '/v1/validation-remediations',
            array(
                'account_id'    => $account_id,
                'site_id'       => $site_id,
                'source_job_id' => $source_job_id,
            )
        );

        if ( empty( $resp['ok'] ) ) {
            $cache[ $cache_key ] = array(
                'ok'    => false,
                'items' => array(),
                'error' => isset( $resp['error'] ) ? (string) $resp['error'] : 'Could not read remediation state right now.',
            );
            return $cache[ $cache_key ];
        }

        $data = isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array();
        $items = isset( $data['items'] ) && is_array( $data['items'] ) ? $data['items'] : array();
        $indexed = array();
        foreach ( $items as $item ) {
            if ( ! is_array( $item ) ) {
                continue;
            }
            $finding_code = isset( $item['finding_code'] ) ? trim( (string) $item['finding_code'] ) : '';
            if ( '' === $finding_code ) {
                continue;
            }
            $indexed[ $finding_code ] = $item;
        }

        $cache[ $cache_key ] = array(
            'ok'    => true,
            'items' => $indexed,
            'error' => '',
        );
        return $cache[ $cache_key ];
    }

    /**
     * Resolve connected site label from canonical truth first, then current live identity.
     */
    private static function connected_site_label( array $site_config_item = array(), array $scope = array() ): string {
        $label = isset( $site_config_item['site_label'] ) ? trim( (string) $site_config_item['site_label'] ) : '';
        if ( '' !== $label ) {
            return $label;
        }

        $label = isset( $scope['site_label'] ) ? trim( (string) $scope['site_label'] ) : '';
        if ( '' !== $label ) {
            return $label;
        }

        $active_scope = self::get_active_site_scope_selector();
        $label        = isset( $active_scope['site_label'] ) ? trim( (string) $active_scope['site_label'] ) : '';
        if ( '' !== $label ) {
            return $label;
        }

        return isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';
    }

    /**
     * Resolve connected site URL from canonical truth first, then current live identity.
     */
    private static function connected_site_url( array $site_config_item = array(), array $scope = array() ): string {
        $site_url = isset( $site_config_item['site_url'] ) ? trim( (string) $site_config_item['site_url'] ) : '';
        if ( '' !== $site_url ) {
            return $site_url;
        }

        $site_url = isset( $scope['site_url'] ) ? trim( (string) $scope['site_url'] ) : '';
        if ( '' !== $site_url ) {
            return $site_url;
        }

        $active_scope = self::get_active_site_scope_selector();
        $site_url     = isset( $active_scope['site_url'] ) ? trim( (string) $active_scope['site_url'] ) : '';
        if ( '' !== $site_url ) {
            return $site_url;
        }

        return '';
    }

    /**
     * Resolve connected contact email from canonical truth first, then current live identity.
     */
    private static function connected_contact_email( array $site_config_item = array() ): string {
        $contact_email = isset( $site_config_item['contact_email'] ) ? trim( (string) $site_config_item['contact_email'] ) : '';
        if ( '' !== $contact_email ) {
            return $contact_email;
        }

        return '';
    }

    /**
     * Current canonical selected site support summary for Settings/UI readback.
     *
     * @return array{site_id:string,site_label:string,site_url:string,contact_email:string,resolution_kind:string}
     */
    private static function current_selected_site_summary(): array {
        $scope = self::get_mcp_scope_snapshot();
        $site_config = self::canonical_site_config();
        $site_config_item = ! empty( $site_config['ok'] ) && isset( $site_config['item'] ) && is_array( $site_config['item'] ) ? $site_config['item'] : array();
        if ( empty( $site_config_item ) ) {
            $cached_site = self::connector_connection_summary_cache();
            $cached_site_id = isset( $cached_site['site_id'] ) ? trim( (string) $cached_site['site_id'] ) : '';
            $cached_site_url = isset( $cached_site['site_url'] ) ? trim( (string) $cached_site['site_url'] ) : '';
            $scope_site_id = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';
            $scope_site_url = isset( $scope['site_url'] ) ? trim( (string) $scope['site_url'] ) : '';
            if (
                ! empty( $cached_site )
                && (
                    ( '' !== $cached_site_id && '' !== $scope_site_id && $cached_site_id === $scope_site_id )
                    || ( '' !== $cached_site_url && '' !== $scope_site_url && self::normalize_requested_site_scope_url( $cached_site_url ) === self::normalize_requested_site_scope_url( $scope_site_url ) )
                    || ( '' !== $cached_site_url && self::scope_targets_local_wordpress( $cached_site_url ) )
                )
            ) {
                $site_config_item = $cached_site;
            }
        }

        return array(
            'site_id'         => isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '',
            'site_label'      => self::connected_site_label( $site_config_item, $scope ),
            'site_url'        => self::connected_site_url( $site_config_item, $scope ),
            'contact_email'   => self::connected_contact_email( $site_config_item ),
            'resolution_kind' => isset( $scope['resolution_kind'] ) ? trim( (string) $scope['resolution_kind'] ) : '',
            'connection_status' => isset( $site_config_item['connection_status'] ) ? trim( (string) $site_config_item['connection_status'] ) : 'external_only',
            'connection_mode' => isset( $site_config_item['connection_mode'] ) ? trim( (string) $site_config_item['connection_mode'] ) : 'public_scan',
            'connector_version' => isset( $site_config_item['connector_version'] ) ? trim( (string) $site_config_item['connector_version'] ) : '',
            'last_connection_error' => isset( $site_config_item['last_connection_error'] ) ? trim( (string) $site_config_item['last_connection_error'] ) : '',
        );
    }

    private static function plugin_update_status(): array {
        if ( ! function_exists( 'get_plugin_data' ) ) {
            require_once ABSPATH . 'wp-admin/includes/plugin.php';
        }

        $plugin_file = defined( 'OPSGATE_PLUGIN_FILE' ) ? (string) OPSGATE_PLUGIN_FILE : dirname( __DIR__ ) . '/opsgate-wp.php';
        $plugin_basename = defined( 'OPSGATE_PLUGIN_BASENAME' ) ? (string) OPSGATE_PLUGIN_BASENAME : plugin_basename( $plugin_file );
        $plugin_data = file_exists( $plugin_file ) ? get_plugin_data( $plugin_file, false, false ) : array();
        $installed_version = isset( $plugin_data['Version'] ) ? trim( (string) $plugin_data['Version'] ) : ( defined( 'OPSGATE_VERSION' ) ? (string) OPSGATE_VERSION : 'Not recorded' );
        $update_metadata_url = function_exists( 'opsgate_get_update_metadata_url' ) ? trim( (string) opsgate_get_update_metadata_url() ) : '';
        $updates = get_site_transient( 'update_plugins' );
        $available_version = '';
        $update_available = false;
        $checked_at = '';
        if ( is_object( $updates ) ) {
            if ( isset( $updates->last_checked ) && is_numeric( $updates->last_checked ) && (int) $updates->last_checked > 0 ) {
                $checked_at = gmdate( 'Y-m-d\\TH:i:s\\Z', (int) $updates->last_checked );
            }
            if ( isset( $updates->response[ $plugin_basename ] ) ) {
                $update_item = (array) $updates->response[ $plugin_basename ];
                $available_version = isset( $update_item['new_version'] ) ? trim( (string) $update_item['new_version'] ) : '';
                $update_available = '' !== $available_version;
            } elseif ( isset( $updates->no_update[ $plugin_basename ] ) ) {
                $no_update_item = (array) $updates->no_update[ $plugin_basename ];
                $available_version = isset( $no_update_item['new_version'] ) ? trim( (string) $no_update_item['new_version'] ) : '';
            }
        }

        $auto_update_plugins = get_site_option( 'auto_update_plugins', array() );
        $auto_update_enabled = is_array( $auto_update_plugins ) && in_array( $plugin_basename, $auto_update_plugins, true );

        return array(
            'installed_version'   => '' !== $installed_version ? $installed_version : 'Not recorded',
            'available_version'   => $available_version,
            'update_available'    => $update_available,
            'auto_update_enabled' => $auto_update_enabled,
            'checked_at_utc'      => $checked_at,
            'metadata_url'        => $update_metadata_url,
        );
    }

    private static function canonical_connection_status_label( string $status ): string {
        $normalized = strtolower( trim( $status ) );
        $map = array(
            'external_only'      => 'External only',
            'pairing_pending'    => 'Pairing pending',
            'connected'          => 'Site verified and linked to OpsGate',
            'credential_invalid' => 'Credential invalid',
            'disconnected'       => 'Disconnected',
        );

        return $map[ $normalized ] ?? 'Unknown';
    }

    private static function canonical_connection_mode_label( string $mode ): string {
        $normalized = strtolower( trim( $mode ) );
        $map = array(
            'public_scan'  => 'Public scan',
            'wp_connector' => 'WordPress connector',
        );

        return $map[ $normalized ] ?? 'Unknown';
    }

    private static function canonical_connection_status_tone( string $status ): string {
        $normalized = strtolower( trim( $status ) );
        if ( 'connected' === $normalized ) {
            return 'good';
        }
        if ( in_array( $normalized, array( 'pairing_pending', 'disconnected' ), true ) ) {
            return 'warn';
        }
        if ( 'credential_invalid' === $normalized ) {
            return 'bad';
        }
        return 'info';
    }

    private static function canonical_connection_status_copy( string $status, string $mode, bool $is_local ): string {
        $normalized_status = strtolower( trim( $status ) );
        $normalized_mode = strtolower( trim( $mode ) );

        if ( 'connected' === $normalized_status ) {
            return 'Security scanning is active for this site through the WordPress connector. Reports, alerts, and activity read site-scoped results from OpsGate.';
        }

        if ( 'pairing_pending' === $normalized_status ) {
            return $is_local
                ? 'OpsGate has issued pairing material, but this WordPress installation has not completed the connector handshake yet.'
                : 'This canonical site is waiting for the connector installed on that remote WordPress host to complete the pairing handshake.';
        }

        if ( 'credential_invalid' === $normalized_status ) {
            return 'The connector credential is no longer valid. Rotate or reconnect the credential before relying on connected triage.';
        }

        if ( 'disconnected' === $normalized_status ) {
            return 'This site is currently disconnected. Public checks may still run, but authenticated connector truth is not active.';
        }

        if ( 'public_scan' === $normalized_mode || 'external_only' === $normalized_status ) {
            return 'This site is external-only. OpsGate records public checks only until a connector is paired through the API authority flow.';
        }

        return 'Canonical site connection truth is being read from the OpsGate API.';
    }

    /**
     * Customer-safe scoped readback for the Pairing Material panel.
     *
     * @return array{site_label:string,site_scope:string,connection_state:string,availability_reason:string,is_unavailable:bool,pairing_token:string}
     */
    private static function pairing_material_scope_summary(): array {
        $selected_site = self::current_selected_site_summary();
        $site_label = isset( $selected_site['site_label'] ) ? trim( (string) $selected_site['site_label'] ) : '';
        if ( '' === $site_label ) {
            $site_label = 'Not resolved yet';
        }

        $site_scope = isset( $selected_site['site_id'] ) ? trim( (string) $selected_site['site_id'] ) : '';
        if ( '' === $site_scope ) {
            $site_scope = 'Not resolved yet';
        }

        $site_url = isset( $selected_site['site_url'] ) ? trim( (string) $selected_site['site_url'] ) : '';
        $is_local = self::scope_targets_local_wordpress( $site_url );
        $connection_status = isset( $selected_site['connection_status'] ) ? (string) $selected_site['connection_status'] : 'external_only';
        $connection_state = self::canonical_connection_status_label( $connection_status );
        $pairing_token = isset( $_GET['opsgate_pairing_token'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_pairing_token'] ) ) : self::connector_pairing_token(); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $return_url = isset( $_GET['opsgate_return_url'] ) ? esc_url_raw( wp_unslash( $_GET['opsgate_return_url'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended

        $availability_reason = '';
        $is_unavailable = false;
        if ( '' !== $pairing_token ) {
            $availability_reason = $is_local
                ? 'Pairing material is ready for this canonical site. Use the token and actions below to complete the connector handshake.'
                : ( '' !== $return_url
                    ? 'Connection code is ready — click "Create Connection Code" to complete the pairing automatically.'
                    : 'Pairing material is ready for this requested site. Copy the pairing token and use it on the originating remote plugin to complete pairing.' );
        } else {
            $availability_reason = $is_local
                ? 'Create pairing material for this canonical site from the actions below.'
                : ( '' !== $return_url
                    ? 'Click "Create Connection Code" — you will be returned to the remote plugin automatically once the code is generated.'
                    : 'Create pairing material for this requested site here, then copy the token to the remote plugin to complete pairing.' );
        }
        if ( ! $is_local && '' === $return_url ) {
            $availability_reason .= ' Navigate back to the remote plugin after pairing is complete.';
        }

        return array(
            'site_label'           => $site_label,
            'site_scope'           => $site_scope,
            'connection_state'     => $connection_state,
            'availability_reason'  => $availability_reason,
            'is_unavailable'       => $is_unavailable,
            'pairing_token'        => $pairing_token,
        );
    }

    /**
     * Runtime execution context for the currently selected canonical site.
     *
     * Local-only secrets such as the WordPress inventory/operator token are only
     * attached when the selected site points back to this install.
     *
     * @return array{account_id:string,site_id:string,site_url:string,site_token:string,is_local:bool}
     */
    private static function current_site_execution_context(): array {
        $scope = self::get_mcp_scope_snapshot();
        $site_config = self::canonical_site_config();
        $site_config_item = ! empty( $site_config['ok'] ) && isset( $site_config['item'] ) && is_array( $site_config['item'] ) ? $site_config['item'] : array();
        $identity = self::get_identity_snapshot();
        $site_url = self::connected_site_url( $site_config_item, $scope );
        if ( '' === $site_url ) {
            $site_url = isset( $identity['site_url'] ) ? trim( (string) $identity['site_url'] ) : '';
        }
        $is_local = self::scope_targets_local_wordpress( $site_url );

        return array(
            'account_id' => isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '',
            'site_id'    => isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '',
            'site_url'   => $site_url,
            'site_token' => $is_local ? trim( (string) ( $identity['site_token'] ?? '' ) ) : '',
            'is_local'   => $is_local,
        );
    }

    private static function register_local_connector(): array {
        $scope = self::get_mcp_scope_snapshot();
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';
        $credential = self::connector_site_credential();
        if ( '' === $account_id || '' === $site_id || '' === $credential ) {
            return array(
                'ok' => false,
                'error' => 'connector_registration_identity_missing',
            );
        }

        $resp = self::mcp_post_json(
            '/v1/sites/connectors/register',
            array(
                'account_id' => $account_id,
                'site_id' => $site_id,
                'credential' => $credential,
                'connector_version' => defined( 'OPSGATE_VERSION' ) ? (string) OPSGATE_VERSION : '0.10.7',
                'connector_installation_id' => self::connector_installation_id(),
                'inventory_endpoint' => rest_url( 'opsgate/v1/inventory' ),
                'site_url' => trim( (string) home_url() ),
            )
        );

        if ( empty( $resp['ok'] ) ) {
            return array(
                'ok' => false,
                'error' => isset( $resp['error'] ) ? trim( (string) $resp['error'] ) : 'connector_registration_failed',
            );
        }

        $data = isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array();
        if ( ! empty( $data['site'] ) && is_array( $data['site'] ) ) {
            self::store_connector_connection_summary_cache( $data['site'] );
        }

        return array(
            'ok' => true,
            'data' => $data,
        );
    }

    /**
     * @param array<string,mixed> $job
     * @param array<string,mixed> $scope
     * @return bool
     */
    private static function job_matches_scope( array $job, array $scope ): bool {
        $scope_account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $scope_site_id = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';
        $job_account_id = isset( $job['account_id'] ) ? trim( (string) $job['account_id'] ) : '';
        $job_site_id = isset( $job['site_id'] ) ? trim( (string) $job['site_id'] ) : '';

        if ( '' !== $scope_account_id && '' !== $job_account_id && $scope_account_id !== $job_account_id ) {
            return false;
        }
        if ( '' !== $scope_site_id && '' !== $job_site_id && $scope_site_id !== $job_site_id ) {
            return false;
        }

        return true;
    }

    /**
     * Public wrapper for canonical MCP scope.
     *
     * @return array{account_id:string,site_id:string,site_label?:string,site_url?:string,resolution_kind?:string,error?:string}
     */
    public static function current_mcp_scope_snapshot(): array {
        return self::get_mcp_scope_snapshot();
    }

    /**
     * Explicitly connect this site identity to a canonical OpsGate site scope.
     *
     * @return array{ok:bool,account_id?:string,site_id?:string,site_label?:string,site_url?:string,resolution_kind?:string,created?:bool,error?:string}
     */
    private static function connect_current_site_scope(): array {
        self::bootstrap_defaults();

        $account_id = trim( (string) get_option( 'opsgate_account_id', '' ) );
        $identity   = self::get_identity_snapshot();
        $site_id    = isset( $identity['site_id'] ) ? trim( (string) $identity['site_id'] ) : '';
        $site_label = isset( $identity['site_label'] ) ? trim( (string) $identity['site_label'] ) : '';
        $site_url   = isset( $identity['site_url'] ) ? trim( (string) $identity['site_url'] ) : '';
        $site_token = isset( $identity['site_token'] ) ? trim( (string) $identity['site_token'] ) : '';

        if ( '' === $account_id || '' === $site_id || '' === $site_url || '' === $site_token ) {
            return array(
                'ok'    => false,
                'error' => 'site_connect_identity_missing',
            );
        }

        $resp = self::mcp_post_json(
            '/v1/sites/connect',
            array(
                'account_id' => $account_id,
                'site_id'    => $site_id,
                'site_label' => $site_label,
                'site_url'   => $site_url,
                'site_token' => $site_token,
                'contact_email' => ( isset( $identity['identity_email'] ) && '' !== trim( (string) $identity['identity_email'] ) ) ? trim( (string) $identity['identity_email'] ) : null,
            )
        );

        if ( empty( $resp['ok'] ) ) {
            return array(
                'ok'    => false,
                'error' => isset( $resp['error'] ) ? trim( (string) $resp['error'] ) : 'site_connect_failed',
            );
        }

        $data = isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array();
        $resolved_site_id = isset( $data['site_id'] ) ? trim( (string) $data['site_id'] ) : '';
        $resolved_site_label = isset( $data['site_label'] ) ? trim( (string) $data['site_label'] ) : '';
        $resolved_site_url = isset( $data['site_url'] ) ? trim( (string) $data['site_url'] ) : '';

        if ( '' === $resolved_site_id ) {
            return array(
                'ok'    => false,
                'error' => 'site_connect_missing',
            );
        }

        update_option( 'opsgate_site_id', $resolved_site_id, false );
        if ( '' !== $resolved_site_label ) {
            update_option( 'opsgate_site_label', $resolved_site_label, false );
        }
        if ( '' !== $resolved_site_url ) {
            update_option( 'opsgate_site_url', $resolved_site_url, false );
        }
        if ( array_key_exists( 'contact_email', $data ) ) {
            update_option( 'opsgate_identity_email', trim( (string) $data['contact_email'] ), false );
        }
        self::sync_active_site_scope_options( $data );
        self::sync_scope_runtime_refs_for_scope( $data );

        return array(
            'ok'              => true,
            'account_id'      => $account_id,
            'site_id'         => $resolved_site_id,
            'site_label'      => $resolved_site_label,
            'site_url'        => $resolved_site_url,
            'resolution_kind' => isset( $data['resolution_kind'] ) ? trim( (string) $data['resolution_kind'] ) : '',
            'created'         => ! empty( $data['created'] ),
        );
    }

    /**
     * Canonical selected-site scope for alert routing reads and mutations.
     *
     * @return array{ok:bool,body?:array<string,mixed>,error:string}
     */
    private static function notification_destination_scope_payload(): array {
        $scope      = self::get_mcp_scope_snapshot();
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id    = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';

        if ( '' === $account_id || '' === $site_id ) {
            return array(
                'ok'    => false,
                'error' => 'Select a canonical site in Settings before configuring alerts.',
            );
        }

        return array(
            'ok'    => true,
            'body'  => array(
                'account_id' => $account_id,
                'site_id'    => $site_id,
            ),
            'error' => '',
        );
    }

    /**
     * Canonical notification destinations for the connected site.
     *
     * @return array{ok:bool,items:array<int,array<string,mixed>>,error:string}
     */
    private static function notification_destinations_list(): array {
        $scope = self::notification_destination_scope_payload();
        if ( empty( $scope['ok'] ) ) {
            return array(
                'ok'    => false,
                'items' => array(),
                'error' => isset( $scope['error'] ) ? (string) $scope['error'] : 'Connect this site in Settings before configuring alert destinations.',
            );
        }

        $query = isset( $scope['body'] ) && is_array( $scope['body'] ) ? $scope['body'] : array();
        $resp  = self::mcp_get_json( '/v1/notification-destinations', $query );
        if ( empty( $resp['ok'] ) ) {
            return array(
                'ok'    => false,
                'items' => array(),
                'error' => isset( $resp['error'] ) ? (string) $resp['error'] : 'Could not load alert destinations.',
            );
        }

        $data  = isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array();
        $items = isset( $data['items'] ) && is_array( $data['items'] ) ? array_values( $data['items'] ) : array();

        return array(
            'ok'    => true,
            'items' => $items,
            'error' => '',
        );
    }

    /**
     * @return array<int,array<string,mixed>>
     */
    private static function notification_destination_family_fields( string $family ): array {
        $family = strtolower( trim( $family ) );

        if ( 'email' === $family ) {
            return array(
                array(
                    'key'         => 'recipient',
                    'label'       => 'Recipient email',
                    'placeholder' => 'name@example.com',
                    'help'        => 'Used for live email delivery.',
                    'type'        => 'email',
                    'required'    => true,
                ),
                array(
                    'key'         => 'cc',
                    'label'       => 'CC recipients',
                    'placeholder' => 'ops@example.com, team@example.com',
                    'help'        => 'Optional comma-separated CC recipients.',
                    'type'        => 'text',
                    'is_list'     => true,
                ),
                array(
                    'key'         => 'subject_prefix',
                    'label'       => 'Subject prefix',
                    'placeholder' => '[OpsGate]',
                    'help'        => 'Optional prefix for outgoing email subjects.',
                    'type'        => 'text',
                ),
            );
        }

        if ( 'webhook' === $family ) {
            return array(
                array(
                    'key'         => 'url',
                    'label'       => 'Webhook URL',
                    'placeholder' => 'https://example.com/webhook',
                    'help'        => 'Use the delivery URL for this webhook endpoint.',
                    'type'        => 'url',
                    'required'    => true,
                ),
            );
        }

        if ( 'slack' === $family ) {
            return array(
                array(
                    'key'         => 'url',
                    'label'       => 'Slack incoming webhook URL',
                    'placeholder' => 'https://hooks.slack.com/services/...',
                    'help'        => 'Use the incoming webhook URL for this Slack route.',
                    'type'        => 'url',
                    'required'    => true,
                ),
                array(
                    'key'         => 'channel',
                    'label'       => 'Channel context',
                    'placeholder' => '#ops-alerts',
                    'help'        => 'Optional customer-facing channel label for readback.',
                    'type'        => 'text',
                ),
                array(
                    'key'         => 'workspace',
                    'label'       => 'Workspace context',
                    'placeholder' => 'Ops',
                    'help'        => 'Optional workspace label for readback.',
                    'type'        => 'text',
                ),
            );
        }

        if ( 'teams' === $family ) {
            return array(
                array(
                    'key'         => 'url',
                    'label'       => 'Teams webhook URL',
                    'placeholder' => 'https://outlook.office.com/webhook/...',
                    'help'        => 'Use the Microsoft Teams webhook URL for this route.',
                    'type'        => 'url',
                    'required'    => true,
                ),
            );
        }

        if ( 'discord' === $family ) {
            return array(
                array(
                    'key'         => 'url',
                    'label'       => 'Discord webhook URL',
                    'placeholder' => 'https://discord.com/api/webhooks/...',
                    'help'        => 'Use the Discord webhook URL for this destination.',
                    'type'        => 'url',
                    'required'    => true,
                ),
                array(
                    'key'         => 'channel',
                    'label'       => 'Channel context',
                    'placeholder' => '#alerts',
                    'help'        => 'Optional customer-facing channel label for readback.',
                    'type'        => 'text',
                ),
                array(
                    'key'         => 'server',
                    'label'       => 'Server context',
                    'placeholder' => 'OpsGate',
                    'help'        => 'Optional server or workspace label for readback.',
                    'type'        => 'text',
                ),
            );
        }

        if ( 'telegram' === $family ) {
            return array(
                array(
                    'key'         => 'bot_token',
                    'label'       => 'Bot token',
                    'placeholder' => '123456:ABCDEF...',
                    'help'        => 'Required for live Telegram delivery.',
                    'type'        => 'password',
                    'required'    => true,
                    'secret'      => true,
                ),
                array(
                    'key'         => 'chat_id',
                    'label'       => 'Chat ID',
                    'placeholder' => '123456789',
                    'help'        => 'Use the Telegram chat ID that should receive this alert.',
                    'type'        => 'text',
                    'required'    => true,
                ),
                array(
                    'key'         => 'username',
                    'label'       => 'Bot username',
                    'placeholder' => 'opsproofbot',
                    'help'        => 'Optional bot username for readback.',
                    'type'        => 'text',
                ),
            );
        }

        if ( 'whatsapp' === $family ) {
            return array(
                array(
                    'key'         => 'recipient',
                    'label'       => 'WhatsApp recipient',
                    'placeholder' => '+14165550100',
                    'help'        => 'Use the phone or recipient identity that should receive WhatsApp alerts.',
                    'type'        => 'text',
                    'required'    => true,
                ),
                array(
                    'key'         => 'phone_number_id',
                    'label'       => 'Phone number ID',
                    'placeholder' => '123456789012345',
                    'help'        => 'Optional provider phone-number identifier for future live delivery.',
                    'type'        => 'text',
                ),
                array(
                    'key'         => 'access_token',
                    'label'       => 'Access token',
                    'placeholder' => 'Provider access token',
                    'help'        => 'Optional provider token. Stored safely and never echoed back raw.',
                    'type'        => 'password',
                    'secret'      => true,
                ),
                array(
                    'key'         => 'template_name',
                    'label'       => 'Template name',
                    'placeholder' => 'triage_alert',
                    'help'        => 'Optional provider template name for future live delivery.',
                    'type'        => 'text',
                ),
            );
        }

        if ( 'sns' === $family ) {
            return array(
                array(
                    'key'         => 'topic_arn',
                    'label'       => 'SNS topic ARN',
                    'placeholder' => 'arn:aws:sns:region:account:topic',
                    'help'        => 'Use the SNS topic ARN for this destination.',
                    'type'        => 'text',
                    'required'    => true,
                ),
                array(
                    'key'         => 'region',
                    'label'       => 'AWS region',
                    'placeholder' => 'us-east-1',
                    'help'        => 'Optional region override for future live delivery.',
                    'type'        => 'text',
                ),
            );
        }

        return array();
    }

    private static function notification_destination_family_setup_steps( string $family ): array {
        $family = strtolower( trim( $family ) );

        if ( 'slack' === $family ) {
            return array(
                'heading' => 'Get your Slack webhook URL',
                'steps'   => array(
                    'Go to api.slack.com/apps and click "Create New App" → "From scratch".',
                    'Choose a name and workspace, then go to "Incoming Webhooks" and toggle it on.',
                    'Click "Add New Webhook to Workspace", pick the channel, and click Allow.',
                    'Copy the webhook URL (starts with https://hooks.slack.com/services/) and paste it above.',
                ),
            );
        }

        if ( 'teams' === $family ) {
            return array(
                'heading' => 'Get your Microsoft Teams webhook URL',
                'steps'   => array(
                    'In Teams, open the channel you want alerts in.',
                    'Click the three-dot menu → "Connectors" (or "Manage channel" → Connectors).',
                    'Search for "Incoming Webhook", click "Configure", give it a name, and click "Create".',
                    'Copy the webhook URL (starts with https://outlook.office.com/webhook/ or https://*.webhook.office.com/) and paste it above.',
                ),
            );
        }

        if ( 'discord' === $family ) {
            return array(
                'heading' => 'Get your Discord webhook URL',
                'steps'   => array(
                    'Open your Discord server and go to Server Settings → Integrations → Webhooks.',
                    'Click "New Webhook", choose the channel, set a name, and click "Copy Webhook URL".',
                    'Paste the URL (starts with https://discord.com/api/webhooks/) above.',
                ),
            );
        }

        if ( 'telegram' === $family ) {
            return array(
                'heading' => 'Create a Telegram bot and get your chat ID',
                'steps'   => array(
                    'Open Telegram, search for @BotFather, and send /newbot.',
                    'Follow the prompts to choose a name and username — BotFather sends you a bot token.',
                    'Copy that token and paste it in the "Bot token" field above.',
                    'Start a conversation with your new bot (or add it to a group), then visit https://api.telegram.org/bot<TOKEN>/getUpdates — the "chat" object contains the chat_id.',
                    'Paste that chat ID (a number, e.g. 123456789) in the "Chat ID" field above.',
                ),
            );
        }

        if ( 'whatsapp' === $family ) {
            return array(
                'heading' => 'WhatsApp delivery — provider setup required',
                'steps'   => array(
                    'WhatsApp delivery uses the Meta Business API. You need a verified Meta Business account.',
                    'Go to developers.facebook.com → "My Apps" → Create an app of type "Business".',
                    'Add the WhatsApp product, complete the phone number registration, and note your Phone Number ID.',
                    'Generate a permanent system-user access token from your Business Manager → System Users.',
                    'Create an approved message template for alert notifications in the WhatsApp Manager.',
                    'Paste the phone number ID, access token, and template name in the fields above. The recipient is the WhatsApp number that will receive alerts.',
                ),
            );
        }

        if ( 'sns' === $family ) {
            return array(
                'heading' => 'Set up an AWS SNS topic',
                'steps'   => array(
                    'Log in to the AWS Console and navigate to Simple Notification Service (SNS).',
                    'Click "Topics" → "Create topic", choose Standard type, give it a name, and click "Create topic".',
                    'Copy the Topic ARN (starts with arn:aws:sns:) and paste it in the "SNS topic ARN" field above.',
                    'Add subscriptions to the topic (email, SQS, Lambda, etc.) from the topic detail page.',
                    'Ensure the IAM credentials used by OpsGate include the sns:Publish permission on this topic ARN.',
                ),
            );
        }

        return array();
    }

    /**
     * @param mixed $value
     * @return array<string,mixed>
     */
    private static function notification_destination_config_for_family( string $family, $value ): array {
        $family = strtolower( trim( $family ) );
        $source = is_array( $value ) ? $value : array();
        $config = array();

        if ( empty( $source ) ) {
            $fallback = is_scalar( $value ) ? trim( (string) $value ) : '';
            if ( '' === $fallback ) {
                return array();
            }

            if ( 'email' === $family ) {
                return array( 'recipient' => sanitize_email( $fallback ) );
            }

            if ( in_array( $family, array( 'webhook', 'slack', 'teams', 'discord' ), true ) ) {
                return array( 'url' => esc_url_raw( $fallback ) );
            }

            if ( 'telegram' === $family ) {
                return array( 'chat_id' => sanitize_text_field( $fallback ) );
            }

            if ( 'sns' === $family ) {
                return array( 'topic_arn' => sanitize_text_field( $fallback ) );
            }

            return array( 'recipient' => sanitize_text_field( $fallback ) );
        }

        foreach ( self::notification_destination_family_fields( $family ) as $field ) {
            if ( ! is_array( $field ) || empty( $field['key'] ) ) {
                continue;
            }
            $key = (string) $field['key'];
            if ( ! array_key_exists( $key, $source ) ) {
                continue;
            }

            $raw_value = $source[ $key ];
            if ( ! empty( $field['is_list'] ) ) {
                $items = is_array( $raw_value ) ? $raw_value : preg_split( '/[\r\n,;]+/', (string) $raw_value );
                $items = is_array( $items ) ? $items : array();
                $cleaned = array();
                foreach ( $items as $item ) {
                    $item = trim( (string) $item );
                    if ( '' === $item ) {
                        continue;
                    }
                    if ( 'cc' === $key ) {
                        $item = sanitize_email( $item );
                    } else {
                        $item = sanitize_text_field( $item );
                    }
                    if ( '' !== $item ) {
                        $cleaned[] = $item;
                    }
                }
                if ( ! empty( $cleaned ) ) {
                    $config[ $key ] = array_values( array_unique( $cleaned ) );
                }
                continue;
            }

            $string_value = trim( (string) $raw_value );
            if ( '' === $string_value ) {
                continue;
            }
            if ( ! empty( $field['secret'] ) && '***redacted***' === $string_value ) {
                continue;
            }

            $type = isset( $field['type'] ) ? (string) $field['type'] : 'text';
            if ( in_array( $type, array( 'url', 'webhook' ), true ) ) {
                $string_value = esc_url_raw( $string_value );
            } elseif ( 'email' === $type ) {
                $string_value = sanitize_email( $string_value );
            } else {
                $string_value = sanitize_text_field( $string_value );
            }

            if ( '' !== $string_value ) {
                $config[ $key ] = $string_value;
            }
        }

        return $config;
    }

    /**
     * @return array<string,mixed>
     */
    private static function notification_destination_config_from_request( string $family ): array {
        $posted_config = array();
        if ( isset( $_POST['destination_config'] ) && is_array( $_POST['destination_config'] ) ) {
            $posted_config = wp_unslash( $_POST['destination_config'] );
        }

        $config = self::notification_destination_config_for_family( $family, $posted_config );
        if ( ! empty( $config ) ) {
            return $config;
        }

        $legacy_value = isset( $_POST['destination_value'] ) ? wp_unslash( $_POST['destination_value'] ) : '';
        return self::notification_destination_config_for_family( $family, (string) $legacy_value );
    }

    private static function notification_destination_preflight_error( string $family, array $config ): string {
        $family = strtolower( trim( $family ) );
        $config = is_array( $config ) ? $config : array();

        if ( 'email' === $family ) {
            $recipient = isset( $config['recipient'] ) ? trim( (string) $config['recipient'] ) : '';
            if ( '' === $recipient ) {
                return self::notification_api_error_copy( 'notification_destination_email_recipient_required' );
            }
            if ( ! is_email( $recipient ) ) {
                return self::notification_api_error_copy( 'notification_destination_email_recipient_invalid' );
            }
            $cc_items = isset( $config['cc'] ) && is_array( $config['cc'] ) ? $config['cc'] : array();
            foreach ( $cc_items as $cc_item ) {
                $cc_item = trim( (string) $cc_item );
                if ( '' !== $cc_item && ! is_email( $cc_item ) ) {
                    return self::notification_api_error_copy( 'notification_destination_email_cc_invalid' );
                }
            }
            return '';
        }

        if ( 'webhook' === $family || 'slack' === $family || 'teams' === $family || 'discord' === $family ) {
            $url = isset( $config['url'] ) ? trim( (string) $config['url'] ) : '';
            if ( '' === $url ) {
                return self::notification_api_error_copy( 'notification_destination_webhook_url_required' );
            }
            if ( ! wp_http_validate_url( $url ) ) {
                return self::notification_api_error_copy( 'notification_destination_webhook_url_invalid' );
            }
            return '';
        }

        if ( 'telegram' === $family ) {
            $bot_token = isset( $config['bot_token'] ) ? trim( (string) $config['bot_token'] ) : '';
            $chat_id = isset( $config['chat_id'] ) ? trim( (string) $config['chat_id'] ) : '';
            if ( '' === $bot_token ) {
                return self::notification_api_error_copy( 'notification_destination_telegram_bot_token_required' );
            }
            if ( '' === $chat_id ) {
                return self::notification_api_error_copy( 'notification_destination_telegram_chat_id_required' );
            }
            return '';
        }

        if ( 'whatsapp' === $family ) {
            $recipient = isset( $config['recipient'] ) ? trim( (string) $config['recipient'] ) : '';
            if ( '' === $recipient ) {
                return self::notification_api_error_copy( 'notification_destination_whatsapp_recipient_required' );
            }
            return '';
        }

        if ( 'sns' === $family ) {
            $topic_arn = isset( $config['topic_arn'] ) ? trim( (string) $config['topic_arn'] ) : '';
            if ( '' === $topic_arn ) {
                return self::notification_api_error_copy( 'notification_destination_sns_topic_arn_required' );
            }
        }

        return '';
    }

    /**
     * @param array<string,mixed> $item
     */
    private static function notification_destination_item_config_value( array $item, string $key ): string {
        $config = isset( $item['config'] ) && is_array( $item['config'] ) ? $item['config'] : array();
        if ( ! array_key_exists( $key, $config ) ) {
            return '';
        }

        $value = $config[ $key ];
        if ( is_array( $value ) ) {
            return implode( ', ', array_map( 'strval', $value ) );
        }

        $value = trim( (string) $value );
        if ( '***redacted***' === $value ) {
            return '';
        }

        return $value;
    }

    /**
     * @param array<string,mixed> $item
     * @return array<int,string>
     */
    private static function notification_destination_config_summary_lines( array $item ): array {
        $family = isset( $item['family'] ) ? strtolower( trim( (string) $item['family'] ) ) : '';
        $config = isset( $item['config'] ) && is_array( $item['config'] ) ? $item['config'] : array();
        $lines  = array();

        if ( 'email' === $family ) {
            if ( ! empty( $config['cc'] ) && is_array( $config['cc'] ) ) {
                $lines[] = 'CC: ' . implode( ', ', array_map( 'strval', $config['cc'] ) );
            }
            if ( ! empty( $config['subject_prefix'] ) ) {
                $lines[] = 'Subject prefix: ' . (string) $config['subject_prefix'];
            }
        } elseif ( 'webhook' === $family ) {
            if ( ! empty( $config['method'] ) ) {
                $lines[] = 'Method: ' . strtoupper( (string) $config['method'] );
            }
        } elseif ( 'slack' === $family ) {
            if ( ! empty( $config['workspace'] ) ) {
                $lines[] = 'Workspace: ' . (string) $config['workspace'];
            }
            if ( ! empty( $config['channel'] ) ) {
                $lines[] = 'Channel: ' . (string) $config['channel'];
            }
        } elseif ( 'telegram' === $family ) {
            if ( ! empty( $config['username'] ) ) {
                $lines[] = 'Bot username: @' . ltrim( (string) $config['username'], '@' );
            }
            if ( array_key_exists( 'bot_token', $config ) ) {
                $lines[] = 'Bot token saved securely';
            }
        } elseif ( 'discord' === $family ) {
            if ( ! empty( $config['server'] ) ) {
                $lines[] = 'Server: ' . (string) $config['server'];
            }
            if ( ! empty( $config['channel'] ) ) {
                $lines[] = 'Channel: ' . (string) $config['channel'];
            }
        } elseif ( 'whatsapp' === $family ) {
            if ( ! empty( $config['phone_number_id'] ) ) {
                $lines[] = 'Phone number ID: ' . (string) $config['phone_number_id'];
            }
            if ( ! empty( $config['template_name'] ) ) {
                $lines[] = 'Template: ' . (string) $config['template_name'];
            }
            if ( array_key_exists( 'access_token', $config ) ) {
                $lines[] = 'Access token saved securely';
            }
        } elseif ( 'sns' === $family ) {
            if ( ! empty( $config['region'] ) ) {
                $lines[] = 'Region: ' . (string) $config['region'];
            }
        }

        return array_values( array_filter( $lines ) );
    }

    /**
     * @return array{ok:bool,error:string}
     */
    private static function notification_destination_create( string $family, string $label, array $config, bool $is_default ): array {
        $preflight_error = self::notification_destination_preflight_error( $family, $config );
        if ( '' !== $preflight_error ) {
            return array(
                'ok'    => false,
                'error' => $preflight_error,
            );
        }

        $scope = self::notification_destination_scope_payload();
        if ( empty( $scope['ok'] ) ) {
            return array(
                'ok'    => false,
                'error' => isset( $scope['error'] ) ? (string) $scope['error'] : 'Connect this site in Settings before configuring alert destinations.',
            );
        }

        $body = isset( $scope['body'] ) && is_array( $scope['body'] ) ? $scope['body'] : array();
        $body['family']     = strtolower( trim( $family ) );
        $body['label']      = trim( $label );
        $body['config']     = $config;
        $body['is_default'] = $is_default ? true : false;

        $resp = self::mcp_post_json( '/v1/notification-destinations', $body );

        return array(
            'ok'    => ! empty( $resp['ok'] ),
            'error' => ! empty( $resp['ok'] ) ? '' : self::notification_api_error_copy( isset( $resp['error'] ) ? (string) $resp['error'] : 'Could not create the destination.' ),
        );
    }

    /**
     * @param array<string,mixed> $item
     */
    private static function notification_destination_value_from_item( array $item ): string {
        $family = isset( $item['family'] ) ? strtolower( trim( (string) $item['family'] ) ) : '';
        $config = isset( $item['config'] ) && is_array( $item['config'] ) ? $item['config'] : array();

        if ( 'email' === $family ) {
            return isset( $config['recipient'] ) ? trim( (string) $config['recipient'] ) : '';
        }
        if ( in_array( $family, array( 'webhook', 'slack', 'teams', 'discord' ), true ) ) {
            return isset( $config['url'] ) ? trim( (string) $config['url'] ) : '';
        }
        if ( 'telegram' === $family ) {
            return isset( $config['chat_id'] ) ? trim( (string) $config['chat_id'] ) : '';
        }
        if ( 'sns' === $family ) {
            return isset( $config['topic_arn'] ) ? trim( (string) $config['topic_arn'] ) : '';
        }
        if ( 'whatsapp' === $family ) {
            return isset( $config['recipient'] ) ? trim( (string) $config['recipient'] ) : '';
        }

        return isset( $item['resolved_target'] ) ? trim( (string) $item['resolved_target'] ) : '';
    }

    /**
     * @param array<int,array<string,mixed>> $items
     * @return array<string,mixed>
     */
    private static function notification_destination_primary_for_family( array $items, string $family ): array {
        $family = strtolower( trim( $family ) );
        $matches = array();
        foreach ( $items as $item ) {
            if ( ! is_array( $item ) ) {
                continue;
            }
            if ( $family !== strtolower( trim( (string) ( $item['family'] ?? '' ) ) ) ) {
                continue;
            }
            $matches[] = $item;
        }

        if ( empty( $matches ) ) {
            return array();
        }

        usort(
            $matches,
            static function ( array $left, array $right ): int {
                $left_default  = ! empty( $left['is_default'] ) ? 0 : 1;
                $right_default = ! empty( $right['is_default'] ) ? 0 : 1;
                if ( $left_default !== $right_default ) {
                    return $left_default <=> $right_default;
                }
                $left_active  = 'active' === strtolower( trim( (string) ( $left['state'] ?? '' ) ) ) ? 0 : 1;
                $right_active = 'active' === strtolower( trim( (string) ( $right['state'] ?? '' ) ) ) ? 0 : 1;
                if ( $left_active !== $right_active ) {
                    return $left_active <=> $right_active;
                }
                return strcmp(
                    (string) ( $right['updated_at_utc'] ?? '' ),
                    (string) ( $left['updated_at_utc'] ?? '' )
                );
            }
        );

        return isset( $matches[0] ) && is_array( $matches[0] ) ? $matches[0] : array();
    }

    /**
     * @return array{ok:bool,error:string}
     */
    private static function notification_destination_update( string $destination_id, string $family, string $label, array $config, bool $is_default ): array {
        $preflight_error = self::notification_destination_preflight_error( $family, $config );
        if ( '' !== $preflight_error ) {
            return array(
                'ok'    => false,
                'error' => $preflight_error,
            );
        }

        $scope = self::notification_destination_scope_payload();
        if ( empty( $scope['ok'] ) ) {
            return array(
                'ok'    => false,
                'error' => isset( $scope['error'] ) ? (string) $scope['error'] : 'Connect this site in Settings before configuring alert destinations.',
            );
        }

        $destination_id = trim( $destination_id );
        if ( '' === $destination_id ) {
            return array(
                'ok'    => false,
                'error' => 'Missing alert destination identifier.',
            );
        }

        $body = isset( $scope['body'] ) && is_array( $scope['body'] ) ? $scope['body'] : array();
        $body['label']      = trim( $label );
        $body['config']     = $config;
        $body['is_default'] = $is_default ? true : false;

        $resp = self::mcp_patch_json( '/v1/notification-destinations/' . rawurlencode( $destination_id ), $body );

        return array(
            'ok'    => ! empty( $resp['ok'] ),
            'error' => ! empty( $resp['ok'] ) ? '' : self::notification_api_error_copy( isset( $resp['error'] ) ? (string) $resp['error'] : 'Could not update the destination.' ),
        );
    }

    /**
     * @return array{ok:bool,error:string}
     */
    private static function notification_destination_toggle( string $destination_id, bool $enable ): array {
        $scope = self::notification_destination_scope_payload();
        if ( empty( $scope['ok'] ) ) {
            return array(
                'ok'    => false,
                'error' => isset( $scope['error'] ) ? (string) $scope['error'] : 'Connect this site in Settings before configuring alert destinations.',
            );
        }

        $destination_id = trim( $destination_id );
        if ( '' === $destination_id ) {
            return array(
                'ok'    => false,
                'error' => 'Missing alert destination identifier.',
            );
        }

        $body = isset( $scope['body'] ) && is_array( $scope['body'] ) ? $scope['body'] : array();
        $path = $enable
            ? '/v1/notification-destinations/' . rawurlencode( $destination_id ) . '/enable'
            : '/v1/notification-destinations/' . rawurlencode( $destination_id ) . '/disable';
        $resp = self::mcp_post_json( $path, $body );

        return array(
            'ok'    => ! empty( $resp['ok'] ),
            'error' => ! empty( $resp['ok'] ) ? '' : self::notification_api_error_copy( isset( $resp['error'] ) ? (string) $resp['error'] : 'Could not update the destination.' ),
        );
    }

    /**
     * @return array{ok:bool,error:string}
     */
    private static function notification_destination_test( string $destination_id ): array {
        $scope = self::notification_destination_scope_payload();
        if ( empty( $scope['ok'] ) ) {
            return array(
                'ok'    => false,
                'error' => isset( $scope['error'] ) ? (string) $scope['error'] : 'Connect this site in Settings before configuring alert destinations.',
            );
        }

        $destination_id = trim( $destination_id );
        if ( '' === $destination_id ) {
            return array(
                'ok'    => false,
                'error' => 'Missing alert destination identifier.',
            );
        }

        $body = isset( $scope['body'] ) && is_array( $scope['body'] ) ? $scope['body'] : array();
        $resp = self::mcp_post_json(
            '/v1/notification-destinations/' . rawurlencode( $destination_id ) . '/test',
            $body
        );

        return array(
            'ok'    => ! empty( $resp['ok'] ),
            'error' => ! empty( $resp['ok'] ) ? '' : self::notification_api_error_copy( isset( $resp['error'] ) ? (string) $resp['error'] : 'Could not trigger the destination test.' ),
        );
    }

    /**
     * @return array{ok:bool,error:string}
     */
    private static function notification_destination_delete( string $destination_id ): array {
        $scope = self::notification_destination_scope_payload();
        if ( empty( $scope['ok'] ) ) {
            return array(
                'ok'    => false,
                'error' => isset( $scope['error'] ) ? (string) $scope['error'] : 'Connect this site in Settings before configuring alert destinations.',
            );
        }

        $destination_id = trim( $destination_id );
        if ( '' === $destination_id ) {
            return array(
                'ok'    => false,
                'error' => 'Missing alert destination identifier.',
            );
        }

        $body = isset( $scope['body'] ) && is_array( $scope['body'] ) ? $scope['body'] : array();
        $resp = self::mcp_delete_json( '/v1/notification-destinations/' . rawurlencode( $destination_id ), $body );

        return array(
            'ok'    => ! empty( $resp['ok'] ),
            'error' => ! empty( $resp['ok'] ) ? '' : self::notification_api_error_copy( isset( $resp['error'] ) ? (string) $resp['error'] : 'Could not remove the destination.' ),
        );
    }

    /**
     * Canonical notification rules for the connected site.
     *
     * @return array{ok:bool,items:array<int,array<string,mixed>>,error:string}
     */
    private static function notification_rules_list(): array {
        $scope = self::get_mcp_scope_snapshot();
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id    = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';

        if ( '' === $account_id || '' === $site_id ) {
            return array(
                'ok'    => false,
                'items' => array(),
                'error' => 'Connect this site in Settings before viewing alerts.',
            );
        }

        $resp = self::mcp_get_json(
            '/v1/notifications/rules',
            array(
                'account_id' => $account_id,
                'site_id'    => $site_id,
            )
        );

        if ( empty( $resp['ok'] ) ) {
            return array(
                'ok'    => false,
                'items' => array(),
                'error' => isset( $resp['error'] ) ? (string) $resp['error'] : 'Could not load alerts.',
            );
        }

        $data  = isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array();
        $items = isset( $data['items'] ) && is_array( $data['items'] ) ? array_values( $data['items'] ) : array();

        return array(
            'ok'    => true,
            'items' => $items,
            'error' => '',
        );
    }

    /**
     * Canonical notification event history for the connected site.
     *
     * @return array{ok:bool,items:array<int,array<string,mixed>>,error:string}
     */
    private static function notification_events_query( array $filters = array(), int $limit = 20 ): array {
        $scope = self::get_mcp_scope_snapshot();
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id    = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';

        if ( '' === $account_id || '' === $site_id ) {
            return array(
                'ok'    => false,
                'items' => array(),
                'error' => 'Connect this site in Settings before viewing alert history.',
            );
        }

        $query = array(
            'account_id' => $account_id,
            'site_id'    => $site_id,
            'limit'      => max( 1, min( 100, $limit ) ),
        );

        foreach ( array( 'source_id', 'destination_id', 'event_type' ) as $allowed_filter ) {
            if ( isset( $filters[ $allowed_filter ] ) && '' !== trim( (string) $filters[ $allowed_filter ] ) ) {
                $query[ $allowed_filter ] = trim( (string) $filters[ $allowed_filter ] );
            }
        }

        $resp = self::mcp_get_json( '/v1/notifications/events', $query );

        if ( empty( $resp['ok'] ) ) {
            return array(
                'ok'    => false,
                'items' => array(),
                'error' => isset( $resp['error'] ) ? (string) $resp['error'] : 'Could not load alert history.',
            );
        }

        $data  = isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array();
        $items = isset( $data['items'] ) && is_array( $data['items'] ) ? array_values( $data['items'] ) : array();

        return array(
            'ok'    => true,
            'items' => $items,
            'error' => '',
        );
    }

    /**
     * Canonical notification event history for the connected site.
     *
     * @return array{ok:bool,items:array<int,array<string,mixed>>,error:string}
     */
    private static function notification_events_list( int $limit = 20 ): array {
        return self::notification_events_query( array(), $limit );
    }

    /**
     * Notification events emitted from one canonical source id, usually a run/job id.
     *
     * @return array{ok:bool,items:array<int,array<string,mixed>>,error:string}
     */
    private static function notification_events_for_source_id( string $source_id, int $limit = 20 ): array {
        $source_id = trim( $source_id );
        if ( '' === $source_id ) {
            return array(
                'ok'    => true,
                'items' => array(),
                'error' => '',
            );
        }

        return self::notification_events_query(
            array(
                'source_id' => $source_id,
            ),
            $limit
        );
    }

    /**
     * @param array<int,array<string,mixed>> $events
     * @return array<string,mixed>
     */
    private static function notification_delivery_rollup( array $events ): array {
        $latest_event = ! empty( $events ) && is_array( $events[0] ) ? $events[0] : array();
        $counts = array(
            'total'      => 0,
            'delivered'  => 0,
            'queued'     => 0,
            'failed'     => 0,
            'suppressed' => 0,
        );

        foreach ( $events as $event ) {
            if ( ! is_array( $event ) ) {
                continue;
            }

            ++$counts['total'];
            $status = strtolower( trim( (string) ( $event['status'] ?? '' ) ) );
            if ( in_array( $status, array( 'delivered', 'completed' ), true ) ) {
                ++$counts['delivered'];
            } elseif ( in_array( $status, array( 'ready', 'queued', 'pending', 'running', 'in_progress' ), true ) ) {
                ++$counts['queued'];
            } elseif ( in_array( $status, array( 'suppressed', 'skipped' ), true ) ) {
                ++$counts['suppressed'];
            } else {
                ++$counts['failed'];
            }
        }

        $tone = 'neutral';
        $headline = 'No alert activity recorded';
        if ( $counts['delivered'] > 0 && 0 === $counts['failed'] && 0 === $counts['queued'] ) {
            $tone = 'good';
            $headline = sprintf( '%d delivered alert%s', $counts['delivered'], 1 === $counts['delivered'] ? '' : 's' );
        } elseif ( $counts['failed'] > 0 ) {
            $tone = 'bad';
            $headline = sprintf( '%d failed alert%s', $counts['failed'], 1 === $counts['failed'] ? '' : 's' );
        } elseif ( $counts['queued'] > 0 ) {
            $tone = 'warn';
            $headline = sprintf( '%d queued alert%s', $counts['queued'], 1 === $counts['queued'] ? '' : 's' );
        } elseif ( $counts['suppressed'] > 0 ) {
            $tone = 'neutral';
            $headline = sprintf( '%d suppressed alert%s', $counts['suppressed'], 1 === $counts['suppressed'] ? '' : 's' );
        }

        $latest_status = isset( $latest_event['status'] ) ? self::notification_status_label( (string) $latest_event['status'] ) : 'No alerts recorded';
        $latest_summary = ! empty( $latest_event ) ? self::notification_event_display_summary( $latest_event ) : 'No alert events were emitted for this run.';
        $latest_target = ! empty( $latest_event ) ? self::notification_target_display( (string) ( $latest_event['target'] ?? '' ), (string) ( $latest_event['channel'] ?? '' ) ) : '—';
        $latest_reference = ! empty( $latest_event['event_id'] ) ? self::canonical_activity_reference_copy( 'Event reference', (string) $latest_event['event_id'] ) : 'Event reference unavailable';
        $latest_attempt_reference = ! empty( $latest_event['attempt_count'] )
            ? sprintf( 'Attempts %d', (int) $latest_event['attempt_count'] )
            : 'No delivery attempts recorded yet';
        $latest_time = '';
        foreach ( array( 'finalized_at_utc', 'last_attempt_at_utc', 'triggered_at_utc', 'created_at_utc' ) as $time_key ) {
            if ( ! empty( $latest_event[ $time_key ] ) ) {
                $latest_time = self::notification_datetime_label( (string) $latest_event[ $time_key ] );
                break;
            }
        }

        return array(
            'events'                   => $events,
            'counts'                   => $counts,
            'tone'                     => $tone,
            'headline'                 => $headline,
            'latest_status'            => $latest_status,
            'latest_summary'           => $latest_summary,
            'latest_target'            => $latest_target,
            'latest_reference'         => $latest_reference,
            'latest_attempt_reference' => $latest_attempt_reference,
            'latest_time'              => $latest_time,
        );
    }

    /**
     * @return array<string,mixed>
     */
    private static function notification_destination_lookup( string $destination_id ): array {
        $destination_id = trim( $destination_id );
        if ( '' === $destination_id ) {
            return array();
        }

        $destinations = self::notification_destinations_list();
        $items = isset( $destinations['items'] ) && is_array( $destinations['items'] ) ? $destinations['items'] : array();
        foreach ( $items as $item ) {
            if ( ! is_array( $item ) ) {
                continue;
            }
            if ( $destination_id === trim( (string) ( $item['destination_id'] ?? '' ) ) ) {
                return $item;
            }
        }

        return array();
    }

    /**
     * @return array<string,string>
     */
    private static function notification_rule_event_options(): array {
        return array(
            'triage.run_completed_healthy'         => 'Scan complete — healthy',
            'triage.run_completed_medium_risk'     => 'Scan complete — needs attention',
            'triage.run_completed_high_risk'       => 'Scan complete — critical risk',
            'triage.run_failed'                    => 'Scan failed',
            'report.export_failed'                 => 'Report generation failed',
            'vulnerability.plugin_first_detected'  => 'New vulnerability found',
            'vulnerability.plugin_state_changed'   => 'Vulnerability updated',
            'update.available_with_security_fix'   => 'Security fix update available',
            'alert.test'                           => 'Test alert',
        );
    }

    private static function notification_rule_default_name( string $event_type ): string {
        $options = self::notification_rule_event_options();
        $event_type = trim( $event_type );

        return isset( $options[ $event_type ] ) ? $options[ $event_type ] : 'Alert rule';
    }

    private static function notification_rule_default_description( string $event_type ): string {
        $event_type = trim( $event_type );
        $map = array(
            'triage.run_completed_healthy'     => 'Send an alert when a Security Scan records a healthy score for this site.',
            'triage.run_completed_medium_risk' => 'Send an alert when a Security Scan records a warning score for this site.',
            'triage.run_completed_high_risk'   => 'Send an alert when a Security Scan records a critical score for this site.',
            'triage.run_failed'                => 'Send an alert when a Security Scan fails for this site.',
            'report.export_failed'             => 'Send an alert when a report export fails for this site.',
            'vulnerability.plugin_first_detected' => 'Send an alert when OpsGate records a vulnerable installed plugin for this site for the first time.',
            'vulnerability.plugin_state_changed'   => 'Send an alert when the installed plugin vulnerability state changes for this site.',
            'update.available_with_security_fix'   => 'Alert me when an update patches a known vulnerability — send an alert when OpsGate detects a plugin update that resolves a recorded CVE for this site.',
            'alert.test'                           => 'Send a delivery check for this site.',
        );

        return isset( $map[ $event_type ] ) ? $map[ $event_type ] : 'Alert delivery for this site.';
    }

    /**
     * @return array<int,string>
     */
    private static function notification_rule_destination_ids( array $rule ): array {
        $destination_ids = isset( $rule['destination_ids'] ) && is_array( $rule['destination_ids'] )
            ? array_map( 'trim', array_map( 'strval', $rule['destination_ids'] ) )
            : array();

        return array_values( array_unique( array_filter( $destination_ids ) ) );
    }

    /**
     * Collapse redundant live rules that share the same canonical event/channel/target path.
     *
     * @param array<int,array<string,mixed>> $rules
     * @return array<int,array<string,mixed>>
     */
    private static function notification_rule_dedupe_for_alerts( array $rules ): array {
        $deduped = array();

        foreach ( $rules as $rule ) {
            if ( ! is_array( $rule ) ) {
                continue;
            }

            $event_type = trim( (string) ( $rule['event_type'] ?? '' ) );
            $channel    = strtolower( trim( (string) ( $rule['channel'] ?? '' ) ) );
            $target     = trim( (string) ( $rule['target'] ?? '' ) );
            $rule_id    = trim( (string) ( $rule['rule_id'] ?? '' ) );
            $key        = strtolower( $event_type . '|' . $channel . '|' . $target );
            if ( '' === trim( $key, '|' ) ) {
                $key = 'rule:' . $rule_id;
            }

            $rule['member_rule_ids'] = '' !== $rule_id ? array( $rule_id ) : array();

            if ( ! isset( $deduped[ $key ] ) || ! is_array( $deduped[ $key ] ) ) {
                $deduped[ $key ] = $rule;
                continue;
            }

            $existing = $deduped[ $key ];
            $existing_created = trim( (string) ( $existing['created_at_utc'] ?? '' ) );
            $candidate_created = trim( (string) ( $rule['created_at_utc'] ?? '' ) );
            $base = $existing;
            $other = $rule;

            if ( '' !== $candidate_created && ( '' === $existing_created || strcmp( $candidate_created, $existing_created ) < 0 ) ) {
                $base = $rule;
                $other = $existing;
            }

            $merged_destination_ids = array_values(
                array_unique(
                    array_merge(
                        self::notification_rule_destination_ids( $base ),
                        self::notification_rule_destination_ids( $other )
                    )
                )
            );
            $merged_member_rule_ids = array_values(
                array_unique(
                    array_filter(
                        array_merge(
                            isset( $base['member_rule_ids'] ) && is_array( $base['member_rule_ids'] ) ? array_map( 'strval', $base['member_rule_ids'] ) : array(),
                            isset( $other['member_rule_ids'] ) && is_array( $other['member_rule_ids'] ) ? array_map( 'strval', $other['member_rule_ids'] ) : array()
                        )
                    )
                )
            );

            $base['destination_ids'] = $merged_destination_ids;
            $base['member_rule_ids'] = $merged_member_rule_ids;
            if ( empty( $base['is_enabled'] ) && ! empty( $other['is_enabled'] ) ) {
                $base['is_enabled'] = true;
            }

            $deduped[ $key ] = $base;
        }

        return array_values( $deduped );
    }

    /**
     * Resolve the canonical member rule identifiers represented by one alert-center row.
     *
     * @return array<int,string>
     */
    private static function notification_rule_member_ids( string $rule_id ): array {
        $rule_id = trim( $rule_id );
        if ( '' === $rule_id ) {
            return array();
        }

        $rules = self::notification_rules_list();
        $items = isset( $rules['items'] ) && is_array( $rules['items'] ) ? $rules['items'] : array();
        $deduped_items = self::notification_rule_dedupe_for_alerts(
            self::live_items_only( $items )
        );

        foreach ( $deduped_items as $item ) {
            if ( ! is_array( $item ) ) {
                continue;
            }

            $candidate_rule_id = isset( $item['rule_id'] ) ? trim( (string) $item['rule_id'] ) : '';
            $member_rule_ids = isset( $item['member_rule_ids'] ) && is_array( $item['member_rule_ids'] )
                ? array_values( array_filter( array_map( 'trim', array_map( 'strval', $item['member_rule_ids'] ) ) ) )
                : array();

            if ( $candidate_rule_id === $rule_id || in_array( $rule_id, $member_rule_ids, true ) ) {
                if ( empty( $member_rule_ids ) ) {
                    $member_rule_ids = array( $candidate_rule_id );
                }

                return array_values( array_unique( array_filter( $member_rule_ids ) ) );
            }
        }

        return array( $rule_id );
    }

    /**
     * Resolve one deduped alert-center row by any represented canonical member rule id.
     *
     * @return array<string,mixed>
     */
    private static function notification_rule_lookup_for_alerts( string $rule_id ): array {
        $rule_id = trim( $rule_id );
        if ( '' === $rule_id ) {
            return array();
        }

        $rules = self::notification_rules_list();
        $items = isset( $rules['items'] ) && is_array( $rules['items'] ) ? $rules['items'] : array();
        $deduped_items = self::notification_rule_dedupe_for_alerts(
            self::live_items_only( $items )
        );

        foreach ( $deduped_items as $item ) {
            if ( ! is_array( $item ) ) {
                continue;
            }

            $candidate_rule_id = isset( $item['rule_id'] ) ? trim( (string) $item['rule_id'] ) : '';
            $member_rule_ids = isset( $item['member_rule_ids'] ) && is_array( $item['member_rule_ids'] )
                ? array_values( array_filter( array_map( 'trim', array_map( 'strval', $item['member_rule_ids'] ) ) ) )
                : array();

            if ( $candidate_rule_id === $rule_id || in_array( $rule_id, $member_rule_ids, true ) ) {
                return $item;
            }
        }

        return array();
    }

    /**
     * @return array{ok:bool,rule:array<string,mixed>,error:string}
     */
    private static function notification_rule_reuse_candidate( string $event_type, string $channel, string $destination_id = '' ): array {
        $event_type = trim( $event_type );
        $channel = strtolower( trim( $channel ) );
        $destination_id = trim( $destination_id );
        $rules = self::notification_rules_list();
        $destination = '' !== $destination_id ? self::notification_destination_lookup( $destination_id ) : array();
        $destination_target = trim( (string) ( $destination['resolved_target'] ?? '' ) );

        if ( empty( $rules['ok'] ) ) {
            return array(
                'ok'    => false,
                'rule'  => array(),
                'error' => isset( $rules['error'] ) ? (string) $rules['error'] : 'Could not verify existing alert rules.',
            );
        }

        $matches = array();
        foreach ( isset( $rules['items'] ) && is_array( $rules['items'] ) ? $rules['items'] : array() as $rule ) {
            if ( ! is_array( $rule ) || self::item_is_proof( $rule ) ) {
                continue;
            }

            $rule_event_type = trim( (string) ( $rule['event_type'] ?? '' ) );
            $rule_channel = strtolower( trim( (string) ( $rule['channel'] ?? '' ) ) );
            if ( '' === $rule_event_type || '' === $rule_channel ) {
                continue;
            }
            if ( $rule_event_type !== $event_type || $rule_channel !== $channel ) {
                continue;
            }

            $matches[] = $rule;
        }

        if ( empty( $matches ) ) {
            return array(
                'ok'    => true,
                'rule'  => array(),
                'error' => '',
            );
        }

        usort(
            $matches,
            static function ( array $left, array $right ) use ( $destination_id, $destination_target ): int {
                $left_has_destination = '' !== $destination_id && in_array( $destination_id, self::notification_rule_destination_ids( $left ), true );
                $right_has_destination = '' !== $destination_id && in_array( $destination_id, self::notification_rule_destination_ids( $right ), true );
                if ( $left_has_destination !== $right_has_destination ) {
                    return $left_has_destination ? -1 : 1;
                }

                $left_target = trim( (string) ( $left['target'] ?? '' ) );
                $right_target = trim( (string) ( $right['target'] ?? '' ) );
                $left_has_target = '' !== $destination_target && 0 === strcasecmp( $left_target, $destination_target );
                $right_has_target = '' !== $destination_target && 0 === strcasecmp( $right_target, $destination_target );
                if ( $left_has_target !== $right_has_target ) {
                    return $left_has_target ? -1 : 1;
                }

                if ( ! empty( $left['is_enabled'] ) !== ! empty( $right['is_enabled'] ) ) {
                    return ! empty( $left['is_enabled'] ) ? -1 : 1;
                }

                $left_created = trim( (string) ( $left['created_at_utc'] ?? '' ) );
                $right_created = trim( (string) ( $right['created_at_utc'] ?? '' ) );
                if ( '' !== $left_created && '' !== $right_created && $left_created !== $right_created ) {
                    return strcmp( $left_created, $right_created );
                }

                return strcmp(
                    trim( (string) ( $left['rule_id'] ?? '' ) ),
                    trim( (string) ( $right['rule_id'] ?? '' ) )
                );
            }
        );

        return array(
            'ok'    => true,
            'rule'  => is_array( $matches[0] ) ? $matches[0] : array(),
            'error' => '',
        );
    }

    /**
     * @return array{ok:bool,error:string,notice:string}
     */
    private static function notification_rule_link_destination( array $rule, string $destination_id, bool $is_enabled ): array {
        $rule_id = trim( (string) ( $rule['rule_id'] ?? '' ) );
        $destination_id = trim( $destination_id );
        if ( '' === $rule_id || '' === $destination_id ) {
            return array(
                'ok'     => false,
                'error'  => 'Missing alert rule or destination.',
                'notice' => 'rule_error',
            );
        }

        $destination_ids = self::notification_rule_destination_ids( $rule );
        $already_linked = in_array( $destination_id, $destination_ids, true );
        if ( ! $already_linked ) {
            $destination_ids[] = $destination_id;
        }

        $body = array(
            'destination_ids' => $destination_ids,
        );

        if ( $is_enabled && empty( $rule['is_enabled'] ) ) {
            $body['is_enabled'] = true;
        }

        if ( $already_linked && ! array_key_exists( 'is_enabled', $body ) ) {
            return array(
                'ok'     => true,
                'error'  => '',
                'notice' => 'rule_updated',
            );
        }

        $resp = self::mcp_patch_json( '/v1/notifications/rules/' . rawurlencode( $rule_id ), $body );

        return array(
            'ok'     => ! empty( $resp['ok'] ),
            'error'  => ! empty( $resp['ok'] ) ? '' : ( isset( $resp['error'] ) ? (string) $resp['error'] : 'Could not update alert routing.' ),
            'notice' => 'rule_updated',
        );
    }

    /**
     * @return array{ok:bool,error:string,notice:string}
     */
    private static function notification_rule_create( string $event_type, string $destination_id, string $name, bool $is_enabled ): array {
        $scope = self::notification_destination_scope_payload();
        $event_type = trim( $event_type );
        $destination_id = trim( $destination_id );
        $name = trim( $name );

        if ( empty( $scope['ok'] ) ) {
            return array(
                'ok'    => false,
                'error' => isset( $scope['error'] ) ? (string) $scope['error'] : 'Select a canonical site in Settings before creating alerts.',
            );
        }

        if ( '' === $event_type || '' === $destination_id ) {
            return array(
                'ok'    => false,
                'error' => 'Select an alert type and destination.',
            );
        }

        $destination = self::notification_destination_lookup( $destination_id );
        $destination_family = strtolower( trim( (string) ( $destination['family'] ?? '' ) ) );
        if ( empty( $destination ) || '' === $destination_family ) {
            return array(
                'ok'     => false,
                'error'  => 'Select a valid alert destination.',
                'notice' => 'rule_error',
            );
        }

        $reuse_candidate = self::notification_rule_reuse_candidate( $event_type, $destination_family, $destination_id );
        if ( empty( $reuse_candidate['ok'] ) ) {
            return array(
                'ok'     => false,
                'error'  => isset( $reuse_candidate['error'] ) ? (string) $reuse_candidate['error'] : 'Could not verify existing alert rules before updating routing.',
                'notice' => 'rule_error',
            );
        }
        if ( ! empty( $reuse_candidate['rule'] ) ) {
            return self::notification_rule_link_destination( $reuse_candidate['rule'], $destination_id, $is_enabled );
        }

        $body = isset( $scope['body'] ) && is_array( $scope['body'] ) ? $scope['body'] : array();
        $body = array_merge(
            $body,
            array(
            'scope_type'      => 'site',
            'name'            => '' !== $name ? $name : self::notification_rule_default_name( $event_type ),
            'description'     => self::notification_rule_default_description( $event_type ),
            'event_type'      => $event_type,
            'destination_ids' => array( $destination_id ),
            'schedule_mode'   => 'immediate',
            'is_enabled'      => $is_enabled ? true : false,
            )
        );

        if ( ! empty( $destination ) ) {
            $body['channel'] = isset( $destination['family'] ) ? (string) $destination['family'] : '';
            $body['target']  = isset( $destination['resolved_target'] ) ? (string) $destination['resolved_target'] : '';
        }

        $resp = self::mcp_post_json( '/v1/notifications/rules', $body );

        return array(
            'ok'     => ! empty( $resp['ok'] ),
            'error'  => ! empty( $resp['ok'] ) ? '' : ( isset( $resp['error'] ) ? (string) $resp['error'] : 'Could not create the alert rule.' ),
            'notice' => 'rule_created',
        );
    }

    /**
     * Toggle a notification rule through the canonical API only.
     *
     * @return array{ok:bool,error:string}
     */
    private static function notification_rule_toggle( string $rule_id, bool $enable ): array {
        $rule_id = trim( $rule_id );
        if ( '' === $rule_id ) {
            return array(
                'ok'    => false,
                'error' => 'Missing alert rule identifier.',
            );
        }

        $scope = self::notification_destination_scope_payload();
        if ( empty( $scope['ok'] ) ) {
            return array(
                'ok'    => false,
                'error' => isset( $scope['error'] ) ? (string) $scope['error'] : 'Select a canonical site in Settings before updating alerts.',
            );
        }

        $path = $enable
            ? '/v1/notifications/rules/' . rawurlencode( $rule_id ) . '/enable'
            : '/v1/notifications/rules/' . rawurlencode( $rule_id ) . '/disable';

        $member_rule_ids = self::notification_rule_member_ids( $rule_id );
        $body = isset( $scope['body'] ) && is_array( $scope['body'] ) ? $scope['body'] : array();

        foreach ( $member_rule_ids as $member_rule_id ) {
            $resp = self::mcp_post_json(
                $enable
                    ? '/v1/notifications/rules/' . rawurlencode( $member_rule_id ) . '/enable'
                    : '/v1/notifications/rules/' . rawurlencode( $member_rule_id ) . '/disable',
                $body
            );

            if ( empty( $resp['ok'] ) ) {
                return array(
                    'ok'    => false,
                    'error' => isset( $resp['error'] ) ? (string) $resp['error'] : 'Could not update the alert.',
                );
            }
        }

        return array(
            'ok'    => true,
            'error' => '',
        );
    }

    /**
     * Delete a notification rule through the canonical API only.
     *
     * @return array{ok:bool,error:string}
     */
    private static function notification_rule_delete( string $rule_id ): array {
        $rule_id = trim( $rule_id );
        if ( '' === $rule_id ) {
            return array(
                'ok'    => false,
                'error' => 'Missing alert rule identifier.',
            );
        }

        $scope = self::notification_destination_scope_payload();
        if ( empty( $scope['ok'] ) ) {
            return array(
                'ok'    => false,
                'error' => isset( $scope['error'] ) ? (string) $scope['error'] : 'Select a canonical site in Settings before updating alerts.',
            );
        }

        $member_rule_ids = self::notification_rule_member_ids( $rule_id );
        $body = isset( $scope['body'] ) && is_array( $scope['body'] ) ? $scope['body'] : array();

        foreach ( $member_rule_ids as $member_rule_id ) {
            $resp = self::mcp_delete_json(
                '/v1/notifications/rules/' . rawurlencode( $member_rule_id ),
                $body
            );

            if ( empty( $resp['ok'] ) ) {
                return array(
                    'ok'    => false,
                    'error' => isset( $resp['error'] ) ? (string) $resp['error'] : 'Could not remove the alert rule.',
                );
            }
        }

        return array(
            'ok'    => true,
            'error' => '',
        );
    }

    private static function notification_datetime_label( string $value ): string {
        return self::canonical_report_datetime_label( $value );
    }

    /**
     * @return array{date:string,time:string}
     */
    private static function notification_datetime_parts( string $value ): array {
        $value = trim( $value );
        if ( '' === $value ) {
            return array(
                'date' => '—',
                'time' => '',
            );
        }

        $parts = self::ui_display_datetime_parts( $value );
        if ( '—' === $parts['date'] ) {
            return array(
                'date' => '—',
                'time' => '',
            );
        }

        return array(
            'date' => $parts['date'],
            'time' => $parts['time'],
        );
    }

    private static function notification_channel_label( string $channel ): string {
        $channel = trim( $channel );
        if ( '' === $channel ) {
            return '—';
        }

        return strtoupper( $channel );
    }

    private static function notification_schedule_label( string $schedule_mode ): string {
        $schedule_mode = trim( $schedule_mode );
        if ( '' === $schedule_mode ) {
            return '—';
        }

        return ucwords( str_replace( '_', ' ', $schedule_mode ) );
    }

    private static function notification_status_label( string $status ): string {
        $status = trim( $status );
        if ( '' === $status ) {
            return '—';
        }

        return ucwords( str_replace( '_', ' ', $status ) );
    }

    private static function item_provenance_kind( array $item ): string {
        $kind = isset( $item['provenance_kind'] ) ? strtolower( trim( (string) $item['provenance_kind'] ) ) : '';
        if ( '' !== $kind ) {
            return $kind;
        }

        return ! empty( $item['proof_run_id'] ) ? 'proof' : 'live';
    }

    private static function item_is_proof( array $item ): bool {
        return 'proof' === self::item_provenance_kind( $item );
    }

    private static function item_provenance_label( array $item ): string {
        if ( ! self::item_is_proof( $item ) ) {
            return '';
        }

        $label = isset( $item['provenance_label'] ) ? trim( (string) $item['provenance_label'] ) : '';
        return '' !== $label ? $label : 'Operator proof';
    }

    private static function item_provenance_note_copy( array $item, string $fallback = 'Recorded from an operator proof scenario.' ): string {
        if ( ! self::item_is_proof( $item ) ) {
            return '';
        }

        $label = self::item_provenance_label( $item );
        if ( '' === $label ) {
            return $fallback;
        }

        return $label . ' recorded for operator validation.';
    }

    private static function live_items_only( array $items ): array {
        return array_values(
            array_filter(
                $items,
                static function ( $item ) {
                    return is_array( $item ) && ! self::item_is_proof( $item );
                }
            )
        );
    }

    private static function operator_degradation_meta( array $score_summary ): array {
        return array(
        );
    }

    private static function notification_clean_copy( string $value ): string {
        $value = trim( wp_strip_all_tags( $value ) );
        if ( '' === $value ) {
            return '';
        }

        $replacements = array(
            '/\bWeeks?\s+\d+(?:-\d+)?\b\s*/i' => '',
            '/\bcanonical\b/i' => '',
            '/\bn8n\b/i' => 'workflow',
            '/\bMailHog\b/i' => 'mail delivery',
            '/\bpilot workflow\b/i' => 'workflow',
            '/\breliability test\b/i' => 'reliability alert',
        );

        $cleaned = preg_replace( array_keys( $replacements ), array_values( $replacements ), $value );
        $cleaned = is_string( $cleaned ) ? $cleaned : $value;
        $cleaned = preg_replace( '/\s{2,}/', ' ', $cleaned );
        $cleaned = preg_replace( '/\s+([,.!?:;])/', '$1', $cleaned );
        $cleaned = trim( (string) $cleaned, " \t\n\r\0\x0B-–—,." );

        return '' !== $cleaned ? $cleaned : $value;
    }

    private static function notification_api_error_copy( string $value ): string {
        $value = trim( wp_strip_all_tags( $value ) );
        if ( '' === $value ) {
            return '';
        }

        $map = array(
            'notification_destination_email_recipient_required'    => 'Enter a recipient email address before saving this email destination.',
            'notification_destination_email_recipient_invalid'     => 'Enter a valid recipient email address for this destination.',
            'notification_destination_email_cc_invalid'            => 'One or more CC email addresses are invalid. Use valid comma-separated email addresses.',
            'notification_destination_webhook_url_required'        => 'Enter the webhook URL before saving this destination.',
            'notification_destination_webhook_url_invalid'         => 'Enter a valid HTTPS webhook URL before saving this destination.',
            'notification_destination_url_required'                => 'Enter the destination URL before saving this route.',
            'notification_destination_whatsapp_recipient_required' => 'Enter the WhatsApp recipient before saving this destination.',
            'notification_destination_telegram_bot_token_required' => 'Enter the Telegram bot token before saving this destination.',
            'notification_destination_telegram_chat_id_required'   => 'Enter the Telegram chat ID before saving this destination.',
            'notification_destination_sns_topic_arn_required'      => 'Enter the SNS topic ARN before saving this destination.',
            'notification_destination_family_invalid'              => 'Choose a valid destination family before saving this route.',
            'notification_destination_site_id_required'            => 'Select a canonical site before creating this destination.',
        );

        if ( isset( $map[ $value ] ) ) {
            return $map[ $value ];
        }

        return self::notification_clean_copy( $value );
    }

    private static function notification_target_display( string $target, string $channel = '' ): string {
        $target = trim( $target );
        $channel = strtolower( trim( $channel ) );
        if ( '' === $target ) {
            return '—';
        }

        if ( false !== strpos( $target, '@' ) ) {
            return $target;
        }

        $host = (string) wp_parse_url( $target, PHP_URL_HOST );
        $path = (string) wp_parse_url( $target, PHP_URL_PATH );
        if ( 'proof.invalid' === strtolower( $host ) ) {
            return 'Operator proof delivery endpoint';
        }

        if ( '' !== $host ) {
            $normalized_host = strtolower( $host );
            if ( in_array( $normalized_host, array( '127.0.0.1', 'localhost' ), true ) || '.local' === substr( $normalized_host, -6 ) ) {
                return $target;
            }
            return $host . ( '' !== $path ? $path : '' );
        }

        return $target;
    }

    private static function notification_target_compact_display( string $target, string $channel = '' ): string {
        $display = self::notification_target_display( $target, $channel );
        if ( '—' === $display || false !== strpos( $display, '@' ) ) {
            return $display;
        }

        $host = (string) wp_parse_url( trim( $target ), PHP_URL_HOST );
        if ( '' === $host ) {
            return $display;
        }

        $normalized_host = strtolower( $host );
        if ( in_array( $normalized_host, array( '127.0.0.1', 'localhost' ), true ) || '.local' === substr( $normalized_host, -6 ) ) {
            return $display;
        }

        return $host;
    }

    private static function canonical_run_trigger_label( string $trigger ): string {
        $trigger = strtolower( trim( $trigger ) );
        if ( '' === $trigger || 'manual' === $trigger ) {
            return 'Started manually';
        }
        if ( 'schedule' === $trigger || false !== strpos( $trigger, 'schedule' ) ) {
            return 'Scheduled';
        }
        if ( false !== strpos( $trigger, 'proof' ) ) {
            return 'Proof';
        }
        if ( false !== strpos( $trigger, 'event' ) ) {
            return 'Event-driven';
        }

        return ucwords( str_replace( array( '_', '.' ), ' ', $trigger ) );
    }

    private static function notification_rule_display_name( array $rule ): string {
        $name = isset( $rule['name'] ) ? self::notification_clean_copy( (string) $rule['name'] ) : '';
        $event_type = isset( $rule['event_type'] ) ? (string) $rule['event_type'] : '';
        $proof_label = self::item_provenance_label( $rule );

        if ( 'alert.test' === $event_type ) {
            if ( self::item_is_proof( $rule ) ) {
                return '' !== $proof_label ? $proof_label : 'Alert delivery failure proof';
            }
            return 'Alert Delivery Check';
        }

        if ( '' !== $name ) {
            if ( false !== stripos( $name, 'report export failed' ) ) {
                return 'Report Export Alert';
            }
            return ucwords( $name );
        }

        return self::canonical_notification_event_label( $event_type );
    }

    private static function notification_rule_category_key( array $rule ): string {
        $event_type = strtolower( trim( (string) ( $rule['event_type'] ?? '' ) ) );
        $name       = strtolower( self::notification_rule_display_name( $rule ) );

        if ( false !== strpos( $event_type, 'high_risk' ) || false !== strpos( $name, 'critical' ) ) {
            return 'critical';
        }
        if ( false !== strpos( $event_type, 'vulnerability.plugin_' ) || false !== strpos( $name, 'vulnerable plugin' ) ) {
            return 'critical';
        }
        if ( false !== strpos( $event_type, 'medium_risk' ) || false !== strpos( $name, 'warning' ) ) {
            return 'warning';
        }
        if ( false !== strpos( $event_type, 'healthy' ) || false !== strpos( $name, 'healthy' ) ) {
            return 'healthy';
        }

        return 'support';
    }

    private static function notification_rule_category_label( string $category ): string {
        $category = strtolower( trim( $category ) );
        if ( 'critical' === $category ) {
            return 'Critical routing';
        }
        if ( 'warning' === $category ) {
            return 'Warning routing';
        }
        if ( 'healthy' === $category ) {
            return 'Healthy routing';
        }

        return 'Delivery & support routing';
    }

    /**
     * @param array<int,array<string,mixed>> $rules
     * @return array<int,array<string,mixed>>
     */
    private static function notification_rule_sort_for_alerts( array $rules ): array {
        usort(
            $rules,
            static function ( array $left, array $right ): int {
                $weights = array(
                    'critical' => 0,
                    'warning'  => 1,
                    'healthy'  => 2,
                    'support'  => 3,
                );
                $left_category  = self::notification_rule_category_key( $left );
                $right_category = self::notification_rule_category_key( $right );
                $left_weight    = $weights[ $left_category ] ?? 99;
                $right_weight   = $weights[ $right_category ] ?? 99;

                if ( $left_weight !== $right_weight ) {
                    return $left_weight <=> $right_weight;
                }

                $left_channel  = self::notification_channel_label( (string) ( $left['channel'] ?? '' ) );
                $right_channel = self::notification_channel_label( (string) ( $right['channel'] ?? '' ) );
                $channel_cmp   = strcmp( strtolower( $left_channel ), strtolower( $right_channel ) );
                if ( 0 !== $channel_cmp ) {
                    return $channel_cmp;
                }

                return strcmp(
                    strtolower( self::notification_rule_display_name( $left ) ),
                    strtolower( self::notification_rule_display_name( $right ) )
                );
            }
        );

        return array_values( $rules );
    }

    private static function notification_rule_display_description( array $rule ): string {
        $event_type = isset( $rule['event_type'] ) ? (string) $rule['event_type'] : '';
        $description = isset( $rule['description'] ) ? self::notification_clean_copy( (string) $rule['description'] ) : '';
        $provenance_note = self::item_provenance_note_copy( $rule );

        if ( 'alert.test' === $event_type ) {
            if ( self::item_is_proof( $rule ) ) {
                return trim( 'Deterministic operator delivery failure recorded for validation. ' . $provenance_note );
            }
            return trim( 'Send a delivery check for this site. ' . $provenance_note );
        }

        if ( 'report.export_failed' === $event_type ) {
            return trim( 'Send an alert when a report export fails for this site. ' . $provenance_note );
        }
        if ( 'triage.run_completed_healthy' === $event_type ) {
            return trim( 'Send an alert when a Security Scan records a healthy score for this site. ' . $provenance_note );
        }
        if ( 'triage.run_completed_medium_risk' === $event_type ) {
            return trim( 'Send an alert when a Security Scan records a warning score for this site. ' . $provenance_note );
        }
        if ( 'triage.run_completed_high_risk' === $event_type ) {
            return trim( 'Send an alert when a Security Scan records a critical score for this site. ' . $provenance_note );
        }
        if ( 'triage.run_failed' === $event_type ) {
            return trim( 'Send an alert when Security Scan fails for this site. ' . $provenance_note );
        }
        if ( 'vulnerability.plugin_first_detected' === $event_type ) {
            return trim( 'Send an alert when a vulnerable installed plugin is first recorded for this site. ' . $provenance_note );
        }
        if ( 'vulnerability.plugin_state_changed' === $event_type ) {
            return trim( 'Send an alert when installed plugin vulnerability findings change for this site. ' . $provenance_note );
        }
        if ( 'update.available_with_security_fix' === $event_type ) {
            return trim( 'Send an alert when a plugin update that patches a known CVE is available for this site. ' . $provenance_note );
        }

        $base = '' !== $description ? ucfirst( $description ) : 'Alert delivery for this site.';
        return trim( $base . ' ' . $provenance_note );
    }

    private static function notification_event_display_title( array $event ): string {
        $title = isset( $event['title'] ) ? self::notification_clean_copy( (string) $event['title'] ) : '';
        $event_type = isset( $event['event_type'] ) ? (string) $event['event_type'] : '';
        $proof_label = self::item_provenance_label( $event );

        if ( 'alert.test' === $event_type ) {
            if ( self::item_is_proof( $event ) ) {
                return '' !== $proof_label ? $proof_label : 'Alert delivery failure proof';
            }
            return 'Alert Delivery Check';
        }

        if ( '' !== $title ) {
            return ucwords( $title );
        }

        return self::canonical_notification_event_label( $event_type );
    }

    private static function notification_event_display_summary( array $event ): string {
        $summary = isset( $event['summary'] ) ? self::notification_clean_copy( (string) $event['summary'] ) : '';
        $event_type = isset( $event['event_type'] ) ? (string) $event['event_type'] : '';
        $status = strtolower( trim( (string) ( $event['status'] ?? '' ) ) );
        $provenance_note = self::item_provenance_note_copy( $event );
        $delivered = in_array( $status, array( 'delivered', 'completed' ), true );
        $queued = in_array( $status, array( 'ready', 'queued', 'pending', 'running', 'in_progress' ), true );

        if ( 'alert.test' === $event_type ) {
            if ( self::item_is_proof( $event ) ) {
                return trim( 'Deterministic operator delivery failure recorded for validation. ' . $provenance_note );
            }
            $base = $delivered
                ? 'Delivery check completed successfully.'
                : ( $queued ? 'Delivery check is queued for delivery.' : 'Delivery check was recorded.' );
            return trim( $base . ' ' . $provenance_note );
        }

        if ( 'report.export_failed' === $event_type ) {
            $base = $delivered
                ? 'Report export alert delivered successfully.'
                : ( $queued ? 'Report export alert is queued for delivery.' : 'Report export alert was recorded.' );
            return trim( $base . ' ' . $provenance_note );
        }
        if ( 'triage.run_completed_healthy' === $event_type ) {
            $base = $delivered
                ? 'Healthy posture alert delivered successfully.'
                : ( $queued ? 'Healthy posture alert is queued for delivery.' : 'Healthy posture alert was recorded.' );
            return trim( $base . ' ' . $provenance_note );
        }
        if ( 'triage.run_completed_medium_risk' === $event_type ) {
            $base = $delivered
                ? 'Warning posture alert delivered successfully.'
                : ( $queued ? 'Warning posture alert is queued for delivery.' : 'Warning posture alert was recorded.' );
            return trim( $base . ' ' . $provenance_note );
        }
        if ( 'triage.run_completed_high_risk' === $event_type ) {
            $base = $delivered
                ? 'Critical posture alert delivered successfully.'
                : ( $queued ? 'Critical posture alert is queued for delivery.' : 'Critical posture alert was recorded.' );
            return trim( $base . ' ' . $provenance_note );
        }
        if ( 'triage.run_failed' === $event_type ) {
            $base = $delivered
                ? 'Triage failure alert delivered successfully.'
                : ( $queued ? 'Triage failure alert is queued for delivery.' : 'Triage failure alert was recorded.' );
            return trim( $base . ' ' . $provenance_note );
        }
        if ( 'vulnerability.plugin_first_detected' === $event_type ) {
            if ( '' !== $summary ) {
                return trim( ucfirst( $summary ) . ' ' . $provenance_note );
            }
            $base = $delivered
                ? 'New vulnerable plugin alert delivered successfully.'
                : ( $queued ? 'New vulnerable plugin alert is queued for delivery.' : 'New vulnerable plugin alert was recorded.' );
            return trim( $base . ' ' . $provenance_note );
        }
        if ( 'vulnerability.plugin_state_changed' === $event_type ) {
            if ( '' !== $summary ) {
                return trim( ucfirst( $summary ) . ' ' . $provenance_note );
            }
            $base = $delivered
                ? 'Plugin vulnerability change alert delivered successfully.'
                : ( $queued ? 'Plugin vulnerability change alert is queued for delivery.' : 'Plugin vulnerability change alert was recorded.' );
            return trim( $base . ' ' . $provenance_note );
        }
        if ( 'update.available_with_security_fix' === $event_type ) {
            if ( '' !== $summary ) {
                return trim( ucfirst( $summary ) . ' ' . $provenance_note );
            }
            $base = $delivered
                ? 'Security fix update alert delivered successfully.'
                : ( $queued ? 'Security fix update alert is queued for delivery.' : 'Security fix update alert was recorded.' );
            return trim( $base . ' ' . $provenance_note );
        }

        if ( '' !== $summary ) {
            return trim( ucfirst( $summary ) . ' ' . $provenance_note );
        }

        return trim( 'Alert activity was recorded. ' . $provenance_note );
    }

    private static function notification_scope_label( array $item ): string {
        $scope_type  = isset( $item['scope_type'] ) ? trim( (string) $item['scope_type'] ) : '';
        $account_id  = isset( $item['account_id'] ) ? trim( (string) $item['account_id'] ) : '';
        $site_id     = isset( $item['site_id'] ) ? trim( (string) $item['site_id'] ) : '';
        $scope_parts = array();

        if ( '' !== $scope_type ) {
            $scope_parts[] = ucwords( $scope_type );
        }
        if ( '' !== $account_id ) {
            $scope_parts[] = 'Account: ' . $account_id;
        }
        if ( '' !== $site_id ) {
            $scope_parts[] = 'Site: ' . $site_id;
        }

        return ! empty( $scope_parts ) ? implode( ' | ', $scope_parts ) : '—';
    }

    private static function notification_rule_lookup( string $rule_id ): array {
        $rule_id = trim( $rule_id );
        if ( '' === $rule_id ) {
            return array();
        }

        $rules = self::notification_rules_list();
        $items = isset( $rules['items'] ) && is_array( $rules['items'] ) ? $rules['items'] : array();

        foreach ( $items as $item ) {
            if ( ! is_array( $item ) ) {
                continue;
            }

            $candidate = isset( $item['rule_id'] ) ? trim( (string) $item['rule_id'] ) : '';
            if ( '' !== $candidate && $candidate === $rule_id ) {
                return $item;
            }
        }

        return array();
    }

    public static function handle_notification_rule_enable(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_notification_rule_enable' );

        $rule_id = isset( $_POST['rule_id'] ) ? sanitize_text_field( wp_unslash( $_POST['rule_id'] ) ) : '';
        $result = self::notification_rule_toggle( $rule_id, true );

        $args = array(
            'opsgate_alerts_notice' => ! empty( $result['ok'] ) ? 'rule_updated' : 'rule_error',
        );

        if ( empty( $result['ok'] ) && ! empty( $result['error'] ) ) {
            $args['opsgate_alerts_error'] = rawurlencode( (string) $result['error'] );
        }

        wp_safe_redirect( self::admin_tab_url( 'alerts', $args ) );
        exit;
    }

    public static function handle_notification_rule_create(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_notification_rule_create' );

        $event_type     = isset( $_POST['rule_event_type'] ) ? sanitize_text_field( wp_unslash( $_POST['rule_event_type'] ) ) : '';
        $destination_id = isset( $_POST['rule_destination_id'] ) ? sanitize_text_field( wp_unslash( $_POST['rule_destination_id'] ) ) : '';
        $name           = isset( $_POST['rule_name'] ) ? sanitize_text_field( wp_unslash( $_POST['rule_name'] ) ) : '';
        $is_enabled     = ! empty( $_POST['rule_is_enabled'] );
        $result         = self::notification_rule_create( $event_type, $destination_id, $name, $is_enabled );
        $notice         = isset( $result['notice'] ) && is_string( $result['notice'] ) && '' !== trim( $result['notice'] )
            ? trim( $result['notice'] )
            : ( ! empty( $result['ok'] ) ? 'rule_created' : 'rule_error' );

        $args = array(
            'opsgate_alerts_notice' => $notice,
        );

        if ( empty( $result['ok'] ) && ! empty( $result['error'] ) ) {
            $args['opsgate_alerts_error'] = rawurlencode( (string) $result['error'] );
        }

        wp_safe_redirect( self::admin_tab_url( 'alerts', $args ) );
        exit;
    }

    public static function handle_notification_rule_delete(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_notification_rule_delete' );

        $rule_id = isset( $_POST['rule_id'] ) ? sanitize_text_field( wp_unslash( $_POST['rule_id'] ) ) : '';
        $result = self::notification_rule_delete( $rule_id );

        $args = array(
            'opsgate_alerts_notice' => ! empty( $result['ok'] ) ? 'rule_updated' : 'rule_error',
        );

        if ( empty( $result['ok'] ) && ! empty( $result['error'] ) ) {
            $args['opsgate_alerts_error'] = rawurlencode( (string) $result['error'] );
        }

        wp_safe_redirect( self::admin_tab_url( 'alerts', $args ) );
        exit;
    }

    public static function handle_notification_rule_toggle_ajax(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error(
                array(
                    'message' => 'Forbidden',
                ),
                403
            );
        }

        check_ajax_referer( 'opsgate_notification_rule_toggle_ajax', 'nonce' );

        $rule_id = isset( $_POST['rule_id'] ) ? sanitize_text_field( wp_unslash( $_POST['rule_id'] ) ) : '';
        $enabled_raw = isset( $_POST['enabled'] ) ? sanitize_text_field( wp_unslash( $_POST['enabled'] ) ) : '';
        $enable = in_array( strtolower( $enabled_raw ), array( '1', 'true', 'yes', 'on' ), true );

        $result = self::notification_rule_toggle( $rule_id, $enable );
        if ( empty( $result['ok'] ) ) {
            wp_send_json_error(
                array(
                    'message' => isset( $result['error'] ) ? (string) $result['error'] : 'Could not update the alert setting.',
                ),
                502
            );
        }

        $rule = self::notification_rule_lookup_for_alerts( $rule_id );
        if ( empty( $rule ) ) {
            $rule = self::notification_rule_lookup( $rule_id );
        }
        if ( empty( $rule ) ) {
            wp_send_json_error(
                array(
                    'message' => 'The alert was updated, but the latest rule state could not be loaded.',
                ),
                502
            );
        }

        $is_enabled = ! empty( $rule['is_enabled'] );

        wp_send_json_success(
            array(
                'rule_id'    => $rule_id,
                'is_enabled' => $is_enabled,
                'label'      => $is_enabled ? 'On' : 'Off',
                'message'    => $is_enabled ? 'Alert enabled.' : 'Alert disabled.',
            )
        );
    }

    public static function handle_notification_rule_create_ajax(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => 'Forbidden' ), 403 );
        }

        check_ajax_referer( 'opsgate_notification_rule_create', 'nonce' );

        $event_type     = isset( $_POST['rule_event_type'] ) ? sanitize_text_field( wp_unslash( $_POST['rule_event_type'] ) ) : '';
        $destination_id = isset( $_POST['rule_destination_id'] ) ? sanitize_text_field( wp_unslash( $_POST['rule_destination_id'] ) ) : '';
        $name           = isset( $_POST['rule_name'] ) ? sanitize_text_field( wp_unslash( $_POST['rule_name'] ) ) : '';
        $is_enabled     = ! empty( $_POST['rule_is_enabled'] );
        $result         = self::notification_rule_create( $event_type, $destination_id, $name, $is_enabled );

        if ( empty( $result['ok'] ) ) {
            wp_send_json_error(
                array(
                    'message' => isset( $result['error'] ) ? (string) $result['error'] : 'Could not create the alert rule.',
                ),
                502
            );
        }

        wp_send_json_success(
            array(
                'message' => 'Alert rule created.',
            )
        );
    }

    public static function handle_notification_rule_delete_ajax(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => 'Forbidden' ), 403 );
        }

        check_ajax_referer( 'opsgate_notification_rule_delete', 'nonce' );

        $rule_id = isset( $_POST['rule_id'] ) ? sanitize_text_field( wp_unslash( $_POST['rule_id'] ) ) : '';
        $result = self::notification_rule_delete( $rule_id );

        if ( empty( $result['ok'] ) ) {
            wp_send_json_error(
                array(
                    'message' => isset( $result['error'] ) ? (string) $result['error'] : 'Could not remove the alert rule.',
                ),
                502
            );
        }

        wp_send_json_success(
            array(
                'message' => 'Alert rule removed.',
            )
        );
    }

    public static function handle_notification_destination_mutation_ajax(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => 'Forbidden' ), 403 );
        }

        $mutation = isset( $_POST['mutation_action'] ) ? sanitize_text_field( wp_unslash( $_POST['mutation_action'] ) ) : '';
        $mutation = trim( $mutation );
        if ( '' === $mutation ) {
            wp_send_json_error( array( 'message' => 'Missing alert destination action.' ), 400 );
        }

        $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
        if ( ! wp_verify_nonce( $nonce, $mutation ) ) {
            wp_send_json_error( array( 'message' => 'Security check failed.' ), 403 );
        }

        $result = array( 'ok' => false, 'error' => 'unsupported_mutation' );
        $success_message = 'Alert destination updated.';

        if ( 'opsgate_notification_destination_create' === $mutation ) {
            $family     = isset( $_POST['destination_family'] ) ? sanitize_text_field( wp_unslash( $_POST['destination_family'] ) ) : '';
            $label      = isset( $_POST['destination_label'] ) ? sanitize_text_field( wp_unslash( $_POST['destination_label'] ) ) : '';
            $config     = self::notification_destination_config_from_request( $family );
            $is_default = ! empty( $_POST['destination_is_default'] );
            $result     = self::notification_destination_create( $family, $label, $config, $is_default );
            $success_message = 'Alert destination created.';
        } elseif ( 'opsgate_notification_destination_update' === $mutation ) {
            $destination_id = isset( $_POST['destination_id'] ) ? sanitize_text_field( wp_unslash( $_POST['destination_id'] ) ) : '';
            $family         = isset( $_POST['destination_family'] ) ? sanitize_text_field( wp_unslash( $_POST['destination_family'] ) ) : '';
            $label          = isset( $_POST['destination_label'] ) ? sanitize_text_field( wp_unslash( $_POST['destination_label'] ) ) : '';
            $config         = self::notification_destination_config_from_request( $family );
            $is_default     = ! empty( $_POST['destination_is_default'] );
            $result         = self::notification_destination_update( $destination_id, $family, $label, $config, $is_default );
            $success_message = 'Alert destination updated.';
        } elseif ( 'opsgate_notification_destination_enable' === $mutation || 'opsgate_notification_destination_disable' === $mutation ) {
            $destination_id = isset( $_POST['destination_id'] ) ? sanitize_text_field( wp_unslash( $_POST['destination_id'] ) ) : '';
            $result         = self::notification_destination_toggle( $destination_id, 'opsgate_notification_destination_enable' === $mutation );
            $success_message = 'opsgate_notification_destination_enable' === $mutation ? 'Alert destination enabled.' : 'Alert destination disabled.';
        } elseif ( 'opsgate_notification_destination_test' === $mutation ) {
            $destination_id = isset( $_POST['destination_id'] ) ? sanitize_text_field( wp_unslash( $_POST['destination_id'] ) ) : '';
            $result         = self::notification_destination_test( $destination_id );
            $success_message = 'Alert destination test queued.';
        } elseif ( 'opsgate_notification_destination_delete' === $mutation ) {
            $destination_id = isset( $_POST['destination_id'] ) ? sanitize_text_field( wp_unslash( $_POST['destination_id'] ) ) : '';
            $result         = self::notification_destination_delete( $destination_id );
            $success_message = 'Alert destination removed.';
        }

        if ( empty( $result['ok'] ) ) {
            wp_send_json_error(
                array(
                    'message' => isset( $result['error'] ) ? (string) $result['error'] : 'Could not update the alert destination.',
                ),
                502
            );
        }

        wp_send_json_success(
            array(
                'message' => $success_message,
            )
        );
    }

    public static function handle_report_deliver_ajax(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => 'Forbidden' ), 403 );
        }

        $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
        if ( ! wp_verify_nonce( $nonce, 'opsgate_report_deliver' ) ) {
            wp_send_json_error( array( 'message' => 'Security check failed.' ), 403 );
        }

        $site_id         = isset( $_POST['site_id'] ) ? sanitize_text_field( wp_unslash( $_POST['site_id'] ) ) : '';
        $job_id          = isset( $_POST['job_id'] ) ? sanitize_text_field( wp_unslash( $_POST['job_id'] ) ) : '';
        $recipient_email = isset( $_POST['recipient_email'] ) ? sanitize_email( wp_unslash( $_POST['recipient_email'] ) ) : '';

        if ( '' === $site_id || '' === $job_id ) {
            wp_send_json_error( array( 'message' => 'Site and run context are required.' ), 400 );
        }

        if ( '' === $recipient_email || ! is_email( $recipient_email ) ) {
            wp_send_json_error( array( 'message' => 'A valid recipient email address is required.' ), 400 );
        }

        $plan = self::normalize_plan( self::get_current_plan() );
        if ( ! in_array( $plan, array( 'starter', 'pro', 'agency' ), true ) ) {
            wp_send_json_error( array( 'message' => 'Report delivery requires a Starter or higher plan.' ), 403 );
        }

        $path   = '/v1/sites/' . rawurlencode( $site_id ) . '/reports/' . rawurlencode( $job_id ) . '/deliver';
        $result = self::mcp_post_json( $path, array(
            'recipient_email' => $recipient_email,
            'delivery_type'   => 'report',
            'requested_by'    => '',
        ) );

        if ( empty( $result['ok'] ) ) {
            $msg = isset( $result['error'] ) ? (string) $result['error'] : 'Report delivery could not be queued.';
            wp_send_json_error( array( 'message' => $msg ), 502 );
        }

        $delivery_id = isset( $result['data']['delivery_id'] ) ? (string) $result['data']['delivery_id'] : '';
        wp_send_json_success( array(
            'message'     => 'Report queued for delivery to ' . $recipient_email . '.',
            'delivery_id' => $delivery_id,
        ) );
    }

    public static function handle_notification_rule_disable(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_notification_rule_disable' );

        $rule_id = isset( $_POST['rule_id'] ) ? sanitize_text_field( wp_unslash( $_POST['rule_id'] ) ) : '';
        $result = self::notification_rule_toggle( $rule_id, false );

        $args = array(
            'opsgate_alerts_notice' => ! empty( $result['ok'] ) ? 'rule_updated' : 'rule_error',
        );

        if ( empty( $result['ok'] ) && ! empty( $result['error'] ) ) {
            $args['opsgate_alerts_error'] = rawurlencode( (string) $result['error'] );
        }

        wp_safe_redirect( self::admin_tab_url( 'alerts', $args ) );
        exit;
    }

    public static function handle_notification_destination_create(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_notification_destination_create' );

        $family     = isset( $_POST['destination_family'] ) ? sanitize_text_field( wp_unslash( $_POST['destination_family'] ) ) : '';
        $label      = isset( $_POST['destination_label'] ) ? sanitize_text_field( wp_unslash( $_POST['destination_label'] ) ) : '';
        $config     = self::notification_destination_config_from_request( $family );
        $is_default = ! empty( $_POST['destination_is_default'] );
        $result     = self::notification_destination_create( $family, $label, $config, $is_default );

        $args = array(
            'opsgate_alert_destinations_notice' => ! empty( $result['ok'] ) ? 'destination_created' : 'destination_error',
        );

        if ( empty( $result['ok'] ) && ! empty( $result['error'] ) ) {
            $args['opsgate_alert_destinations_error'] = rawurlencode( (string) $result['error'] );
        }

        wp_safe_redirect( self::admin_tab_url( 'alerts', $args ) );
        exit;
    }

    public static function handle_notification_destination_update(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_notification_destination_update' );

        $destination_id = isset( $_POST['destination_id'] ) ? sanitize_text_field( wp_unslash( $_POST['destination_id'] ) ) : '';
        $family         = isset( $_POST['destination_family'] ) ? sanitize_text_field( wp_unslash( $_POST['destination_family'] ) ) : '';
        $label          = isset( $_POST['destination_label'] ) ? sanitize_text_field( wp_unslash( $_POST['destination_label'] ) ) : '';
        $config         = self::notification_destination_config_from_request( $family );
        $is_default     = ! empty( $_POST['destination_is_default'] );
        $result         = self::notification_destination_update( $destination_id, $family, $label, $config, $is_default );

        $args = array(
            'opsgate_alert_destinations_notice' => ! empty( $result['ok'] ) ? 'destination_updated' : 'destination_error',
        );

        if ( empty( $result['ok'] ) && ! empty( $result['error'] ) ) {
            $args['opsgate_alert_destinations_error'] = rawurlencode( (string) $result['error'] );
        }

        wp_safe_redirect( self::admin_tab_url( 'alerts', $args ) );
        exit;
    }

    public static function handle_notification_destination_enable(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_notification_destination_enable' );

        $destination_id = isset( $_POST['destination_id'] ) ? sanitize_text_field( wp_unslash( $_POST['destination_id'] ) ) : '';
        $result         = self::notification_destination_toggle( $destination_id, true );
        $args           = array(
            'opsgate_alert_destinations_notice' => ! empty( $result['ok'] ) ? 'destination_updated' : 'destination_error',
        );

        if ( empty( $result['ok'] ) && ! empty( $result['error'] ) ) {
            $args['opsgate_alert_destinations_error'] = rawurlencode( (string) $result['error'] );
        }

        wp_safe_redirect( self::admin_tab_url( 'alerts', $args ) );
        exit;
    }

    public static function handle_notification_destination_disable(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_notification_destination_disable' );

        $destination_id = isset( $_POST['destination_id'] ) ? sanitize_text_field( wp_unslash( $_POST['destination_id'] ) ) : '';
        $result         = self::notification_destination_toggle( $destination_id, false );
        $args           = array(
            'opsgate_alert_destinations_notice' => ! empty( $result['ok'] ) ? 'destination_updated' : 'destination_error',
        );

        if ( empty( $result['ok'] ) && ! empty( $result['error'] ) ) {
            $args['opsgate_alert_destinations_error'] = rawurlencode( (string) $result['error'] );
        }

        wp_safe_redirect( self::admin_tab_url( 'alerts', $args ) );
        exit;
    }

    public static function handle_notification_destination_test(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_notification_destination_test' );

        $destination_id = isset( $_POST['destination_id'] ) ? sanitize_text_field( wp_unslash( $_POST['destination_id'] ) ) : '';
        $result         = self::notification_destination_test( $destination_id );
        $args           = array(
            'opsgate_alert_destinations_notice' => ! empty( $result['ok'] ) ? 'destination_tested' : 'destination_error',
        );

        if ( empty( $result['ok'] ) && ! empty( $result['error'] ) ) {
            $args['opsgate_alert_destinations_error'] = rawurlencode( (string) $result['error'] );
        }

        wp_safe_redirect( self::admin_tab_url( 'alerts', $args ) );
        exit;
    }

    public static function handle_notification_destination_delete(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_notification_destination_delete' );

        $destination_id = isset( $_POST['destination_id'] ) ? sanitize_text_field( wp_unslash( $_POST['destination_id'] ) ) : '';
        $result         = self::notification_destination_delete( $destination_id );
        $args           = array(
            'opsgate_alert_destinations_notice' => ! empty( $result['ok'] ) ? 'destination_removed' : 'destination_error',
        );

        if ( empty( $result['ok'] ) && ! empty( $result['error'] ) ) {
            $args['opsgate_alert_destinations_error'] = rawurlencode( (string) $result['error'] );
        }

        wp_safe_redirect( self::admin_tab_url( 'alerts', $args ) );
        exit;
    }

    /**
     * Day-18: Customer-facing site label for evidence scoping.
     * Never show internal IDs in UI.
     *
     * @return string
     */
    private static function evidence_site_label(): string {
        $scope = self::get_mcp_scope_snapshot();
        $site_config = self::canonical_site_config();
        $site_config_item = ! empty( $site_config['ok'] ) && isset( $site_config['item'] ) && is_array( $site_config['item'] ) ? $site_config['item'] : array();
        $label = self::connected_site_label( $site_config_item, $scope );
        if ( '' !== $label ) {
            return $label;
        }

        $host = wp_parse_url( home_url(), PHP_URL_HOST );
        $host = is_string( $host ) ? trim( $host ) : '';
        return ( '' !== $host ) ? $host : 'this site';
    }

        // ---------------------------------------------------------------------
        // OpsGate Core (Day 20.2): Minimal record ownership layer (option-backed)
        // ---------------------------------------------------------------------

        private static function core_option_key(): string {
            return 'opsgate_core';
        }

        private static function core_now_utc(): string {
            return gmdate( 'Y-m-d H:i:s' );
        }

        /**
         * Read the OpsGate Core record (option-backed).
         *
         * @return array<string, mixed>
         */
        private static function core_read(): array {
            $raw = get_option( self::core_option_key(), array() );
            return is_array( $raw ) ? $raw : array();
        }

        /**
         * Persist the OpsGate Core record (option-backed).
         *
         * @param array<string, mixed> $core
         * @return bool
         */
        private static function core_write( array $core ): bool {
            return update_option( self::core_option_key(), $core, false );
        }

        /**
         * Snapshot: client identity (owned by OpsGate).
         *
         * @return array<string, string>
         */
        private static function core_snapshot_client(): array {
            $site_id    = (string) get_option( 'opsgate_site_id', '' );
            $site_label = (string) get_option( 'opsgate_site_label', (string) get_bloginfo( 'name' ) );
            $email      = (string) get_option( 'opsgate_identity_email', (string) get_bloginfo( 'admin_email' ) );

            return array(
                'site_id'    => $site_id,
                'site_label' => $site_label,
                'email'      => $email,
            );
        }

       /**
         * Snapshot: effective plan + source (owned by OpsGate).
         *
         * PRIME LAW: Plan & entitlement truth lives in the OpsGate API.
         * WordPress displays a snapshot only.
         *
         * @return array<string, string>
         */
        private static function core_snapshot_plan(): array {

            // PRIME LAW: Plan & entitlement truth lives in the OpsGate API.
            // WordPress displays a snapshot only. No local fallbacks that pretend to be authoritative.

            if ( function_exists( 'opsgate_get_api_entitlement_snapshot' ) ) {
                $snap = opsgate_get_api_entitlement_snapshot();

                if ( is_array( $snap ) && isset( $snap['plan'] ) && is_array( $snap['plan'] ) ) {
                    $plan = isset( $snap['plan']['key'] ) ? trim( (string) $snap['plan']['key'] ) : '';
                    $source = isset( $snap['plan']['source'] ) ? trim( (string) $snap['plan']['source'] ) : 'api';
                    if ( '' !== $plan ) {
                        return array(
                            'plan'   => $plan,
                            'source' => '' !== $source ? $source : 'api',
                        );
                    }
                }

                return array(
                    'plan'   => 'unknown',
                    'source' => 'api_unavailable',
                );
            }

            return array(
                'plan'   => 'unknown',
                'source' => 'missing_function',
            );
        }


        /**
         * Snapshot: minimal settings (do not store secrets; store ownership visibility only).
         *
         * @return array<string, mixed>
         */
        private static function core_snapshot_settings_min(): array {
            $schedule_state       = self::canonical_portfolio_triage_schedule();
            $schedule             = isset( $schedule_state['schedule'] ) && is_array( $schedule_state['schedule'] ) ? $schedule_state['schedule'] : array();
            $scheduling_enabled   = ! empty( $schedule['is_enabled'] );
            $scheduling_frequency = 'api_owned';
            $telemetry_enabled   = ( '1' === (string) get_option( 'opsgate_telemetry_enabled', '0' ) );
            $schedules_settings  = self::canonical_schedule_rows_for_ui( $schedule_state );

            return array(
                'telemetry_enabled'     => $telemetry_enabled ? '1' : '0',
                'timing_enabled'        => $scheduling_enabled ? '1' : '0',
                'timing_frequency'      => $scheduling_frequency,
                'service_timing'        => $schedules_settings,
            );
        }

        /**
         * Ensure the OpsGate Core record exists with required top-level keys.
         *
         * @return array<string, mixed> Core record after initialization.
         */
        private static function core_init_if_missing(): array {
            $core = self::core_read();

            if ( ! isset( $core['meta'] ) || ! is_array( $core['meta'] ) ) {
                $core['meta'] = array();
            }
            if ( ! isset( $core['client'] ) || ! is_array( $core['client'] ) ) {
                $core['client'] = array();
            }
            if ( ! isset( $core['plan'] ) || ! is_array( $core['plan'] ) ) {
                $core['plan'] = array();
            }
            if ( ! isset( $core['settings'] ) || ! is_array( $core['settings'] ) ) {
                $core['settings'] = array();
            }
            if ( ! isset( $core['runs'] ) || ! is_array( $core['runs'] ) ) {
                $core['runs'] = array();
            }
            if ( ! isset( $core['artifacts'] ) || ! is_array( $core['artifacts'] ) ) {
                $core['artifacts'] = array();
            }

            $core['client']   = self::core_snapshot_client();
            $core['plan']     = self::core_snapshot_plan();
            $core['settings'] = self::core_snapshot_settings_min();

            $core['meta']['updated_at_utc'] = self::core_now_utc();
            if ( empty( $core['meta']['created_at_utc'] ) ) {
                $core['meta']['created_at_utc'] = $core['meta']['updated_at_utc'];
            }

            self::core_write( $core );
            return $core;
        }

        /**
         * Hard cap to keep core runs bounded (WordPress.org safe).
         */
        private static function core_runs_limit(): int {
            return 200;
        }

        /**
         * Hard cap to keep artifact index bounded (WordPress.org safe).
         */
        private static function core_artifacts_limit(): int {
            return 500;
        }

        /**
         * Append a run to core (most recent first), bounded.
         *
         * @param array<string, mixed> $core
         * @param array<string, mixed> $run
         * @return array<string, mixed>
         */
        private static function core_append_run( array $core, array $run ): array {
            if ( ! isset( $core['runs'] ) || ! is_array( $core['runs'] ) ) {
                $core['runs'] = array();
            }

            array_unshift( $core['runs'], $run );

            $limit = self::core_runs_limit();
            if ( count( $core['runs'] ) > $limit ) {
                $core['runs'] = array_slice( $core['runs'], 0, $limit );
            }

            return $core;
        }

        /**
         * Patch a run by ID, bounded scan (runs list is capped).
         *
         * @param string               $run_id
         * @param array<string, mixed> $patch
         * @return array<string, mixed>
         */
        private static function core_update_run_by_id( string $run_id, array $patch ): array {
            $core = self::core_read();
            if ( ! isset( $core['runs'] ) || ! is_array( $core['runs'] ) ) {
                $core['runs'] = array();
            }

            foreach ( $core['runs'] as $i => $r ) {
                if ( ! is_array( $r ) ) {
                    continue;
                }
                $id = isset( $r['id'] ) ? (string) $r['id'] : '';
                if ( '' !== $id && $id === $run_id ) {
                    $core['runs'][ $i ] = array_merge( $r, $patch );
                    break;
                }
            }

            self::core_write( $core );
            return $core;
        }

        /**
         * Index artifacts in OpsGate Core (pointers only; no absolute paths; bounded).
         *
         * @param array<int, array<string, mixed>> $artifacts
         * @return void
         */
        private static function core_index_artifacts( array $artifacts ): void {
            if ( empty( $artifacts ) ) {
                return;
            }

            $core = self::core_read();

            if ( ! isset( $core['artifacts'] ) || ! is_array( $core['artifacts'] ) ) {
                $core['artifacts'] = array();
            }
            if ( ! isset( $core['artifacts']['index'] ) || ! is_array( $core['artifacts']['index'] ) ) {
                $core['artifacts']['index'] = array();
            }

            foreach ( $artifacts as $a ) {
                if ( ! is_array( $a ) ) {
                    continue;
                }

                $type    = isset( $a['type'] ) ? (string) $a['type'] : '';
                $service = isset( $a['service'] ) ? (string) $a['service'] : '';
                $rel     = isset( $a['rel'] ) ? (string) $a['rel'] : '';
                $file    = isset( $a['file'] ) ? (string) $a['file'] : '';

                // Pointers only; require at least a type and rel/file.
                if ( '' === $type ) {
                    continue;
                }
                if ( '' === $rel && '' === $file ) {
                    continue;
                }

                $row = array(
                    'type'    => $type,
                    'service' => $service,
                    'rel'     => $rel,
                    'file'    => $file,
                    'ts_utc'  => self::core_now_utc(),
                );

                array_unshift( $core['artifacts']['index'], $row );

                $limit = self::core_artifacts_limit();
                if ( count( $core['artifacts']['index'] ) > $limit ) {
                    $core['artifacts']['index'] = array_slice( $core['artifacts']['index'], 0, $limit );
                }
            }

            $core['meta']['updated_at_utc'] = self::core_now_utc();
            self::core_write( $core );
        }

        /**
         * Single internal interface: run an OpsGate-owned action.
         * Executor is replaceable later; record ownership happens here.
         *
         * @param string               $action
         * @param array<string, mixed> $args
         * @param callable             $executor Must return array{ok:bool,note:string,artifacts?:array}
         * @return array<string, mixed> Run record
         */
        private static function core_run_action( string $action, array $args, callable $executor ): array {
            $core = self::core_init_if_missing();

            $run_id = function_exists( 'wp_generate_uuid4' ) ? (string) wp_generate_uuid4() : (string) md5( self::core_now_utc() . '|' . $action . '|' . wp_rand() );

            $run = array(
                'id'        => $run_id,
                'action'    => $action,
                'ts_utc'    => self::core_now_utc(),
                'ok'        => null,
                'note'      => '',
                'args'      => $args, // keep minimal; caller must not pass secrets.
                'client'    => self::core_snapshot_client(),
                'plan'      => self::core_snapshot_plan(),
                'artifacts' => array(),
            );

            $core = self::core_append_run( $core, $run );
            self::core_write( $core );

            try {
                $result = call_user_func( $executor );

                $ok   = isset( $result['ok'] ) ? (bool) $result['ok'] : false;
                $note = isset( $result['note'] ) ? (string) $result['note'] : '';

                $artifacts = array();
                if ( isset( $result['artifacts'] ) && is_array( $result['artifacts'] ) ) {
                    $artifacts = $result['artifacts'];
                }

                $patch = array(
                    'ok'        => $ok,
                    'note'      => $note,
                    'artifacts' => $artifacts,
                    'done_utc'  => self::core_now_utc(),
                );

                self::core_update_run_by_id( $run_id, $patch );

                if ( ! empty( $artifacts ) ) {
                    self::core_index_artifacts( $artifacts );
                }

                // Optional Activity line (respects existing telemetry gate).
                if ( method_exists( __CLASS__, 'activity_timeline_enabled' ) && self::activity_timeline_enabled() ) {
                    $label   = 'Action completed';
                    $outcome = $ok ? 'ok' : 'warn';
                    $details = ( '' !== $note ) ? $note : $action;

                    self::activity_timeline_add( $label, $outcome, $details );
                }

                return array_merge( $run, $patch );

            } catch ( Exception $e ) {
                $patch = array(
                    'ok'       => false,
                    'note'     => 'Unexpected error: ' . $e->getMessage(),
                    'done_utc' => self::core_now_utc(),
                );

                self::core_update_run_by_id( $run_id, $patch );

                return array_merge( $run, $patch );
            }
        }



    /**
     * Day-9 (Phase 1): Get the raw license JSON from local option storage.
     *
     * Storage:
     * - WordPress option: opsgate_license_json
     *
     * @return string Raw JSON string or empty string if missing.
     */
    private static function get_license_raw_json() {
        $raw = get_option( 'opsgate_license_json', '' );
        $raw = is_string( $raw ) ? trim( $raw ) : '';

        return $raw;
    }

    /**
     * Day-9 (Phase 1): Parse license JSON safely.
     *
     * @param string $raw Raw JSON string.
     * @return array{license:array|null,error:string|null}
     */
    private static function parse_license_json( $raw ): array {
        $raw = is_string( $raw ) ? trim( $raw ) : '';

        if ( $raw === '' ) {
            return array(
                'license' => null,
                'error'   => null,
            );
        }

        $decoded = json_decode( $raw, true );

        if ( ! is_array( $decoded ) ) {
            return array(
                'license' => null,
                'error'   => 'malformed_json',
            );
        }

        return array(
            'license' => $decoded,
            'error'   => null,
        );
    }

    // =========================
    // Day-9.5 — Licensing Guardrails (Phase-1, non-enforcing)
    // Canonical storage for opsgate_license_json:
    // - Always written with wp_json_encode()
    // - All write paths must use these helpers
    // =========================

    /**
     * Returns the raw stored license JSON (string) or '' if not present.
     */
    private static function license_get_raw_json(): string
    {
        $raw = get_option('opsgate_license_json', '');
        return is_string($raw) ? $raw : '';
    }

    /**
     * Deletes the stored license JSON option. Idempotent.
     */
    private static function license_delete(): bool
    {
        // delete_option returns true if option deleted, false if it did not exist.
        // We treat both as success (idempotent).
        $deleted = delete_option('opsgate_license_json');
        return ($deleted === true) || (get_option('opsgate_license_json', null) === null);
    }
    /**
     * Enforces canonical schema and prevents wp_json_encode() memory blow-ups.
     * Patch-mode guardrail: whitelist keys + clamp sizes + limit recursion.
     */
    private static function license_canonicalize_for_storage(array $license): array
    {
        // Whitelist only the fields we allow to persist.
        // Add/remove keys here as your Day-9 canonical JSON evolves.
        $allowed = [
            'status',
            'tier',
            'license_key',
            'license_id',
            'issued_at',
            'expires_at',
            'seats',
            'customer_email',
            'signature',
            'last_checked_at',
            'source',
            'error_code',
            'error_message',
        ];

        $out = [];
        foreach ($allowed as $k) {
            if (array_key_exists($k, $license)) {
                $out[$k] = $license[$k];
            }
        }

        // Normalize types + clamp.
        foreach ($out as $k => $v) {
            $out[$k] = self::license_scalarize($v, 0);
        }

        return $out;
    }

    /**
     * Turns arbitrary values into JSON-safe scalars/arrays with strict limits.
     * - Limits recursion depth
     * - Truncates long strings
     * - Prevents huge arrays
     * - Drops objects/resources safely
     */
    private static function license_scalarize($value, int $depth)
    {
        // Hard depth cap (prevents pathological nesting).
        if ($depth >= 6) {
            return '[depth_capped]';
        }

        // Scalars
        if (is_null($value) || is_bool($value) || is_int($value) || is_float($value)) {
            return $value;
        }

        // Strings: clamp hard (prevents base64 blobs, dumps, etc.)
        if (is_string($value)) {
            $max = 2048; // 2KB per field is plenty for license metadata
            if (strlen($value) > $max) {
                return substr($value, 0, $max) . '...[truncated]';
            }
            return $value;
        }

        // Arrays: clamp count and recurse safely
        if (is_array($value)) {
            $maxItems = 50;
            $out = [];
            $i = 0;
            foreach ($value as $k => $v) {
                $out[$k] = self::license_scalarize($v, $depth + 1);
                $i++;
                if ($i >= $maxItems) {
                    $out['__truncated__'] = true;
                    break;
                }
            }
            return $out;
        }

        // Objects/resources: do not attempt deep conversion in admin.
        return '[non_scalar_removed]';
    }

    /**
     * Canonical write path: takes an associative array and stores it using wp_json_encode().
     * Returns true on successful update_option().
     */
    private static function license_write_array(array $license): bool
    {
        // Hard safety rail: only store a small, scalar-only canonical shape.
        $allowed = array(
            'license_key' => 128,
            'tier'        => 32,
            'site_id'     => 128,
            'issued_at'   => 32,
            'expires_at'  => 32,
        );

        $clean = array();

        foreach ($allowed as $k => $maxLen) {
            if (!array_key_exists($k, $license)) {
                continue;
            }

            $v = $license[$k];

            // Scalar-only. Drop arrays/objects to prevent memory bloat / recursion.
            if (is_array($v) || is_object($v)) {
                continue;
            }

            $s = (string) $v;
            $s = trim($s);

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

            if (strlen($s) > $maxLen) {
                $s = substr($s, 0, $maxLen);
            }

            $clean[$k] = $s;
        }

        // Minimal required fields (fail closed).
        if (
            !isset($clean['license_key']) ||
            !isset($clean['tier']) ||
            !isset($clean['site_id']) ||
            !isset($clean['expires_at'])
        ) {
            return false;
        }

        $json = wp_json_encode($clean);

        if (!is_string($json) || $json === '') {
            return false;
        }

        // Size cap: we never expect this option to be large in Phase 1.
        if (strlen($json) > 4096) {
            return false;
        }

        $updated = update_option('opsgate_license_json', $json, false);

        if ($updated === true) {
            return true;
        }

        $current = get_option('opsgate_license_json', '');
        return is_string($current) && $current === $json;
    }


    /**
     * Normalizes any JSON string write into canonical storage (decode -> wp_json_encode -> store).
     * This is the safe bridge if any future code hands us a JSON string.
     *
     * @return array{ok:bool, code:string, message:string}
     */
    private static function license_write_normalized_json(string $json_input): array
    {
        $trimmed = trim($json_input);

        if ($trimmed === '') {
            return array('ok' => false, 'code' => 'empty', 'message' => 'Empty license JSON.');
        }

        $decoded = json_decode($trimmed, true);

        if (!is_array($decoded)) {
            return array('ok' => false, 'code' => 'malformed_json', 'message' => 'License JSON is malformed.');
        }

        $ok = self::license_write_array($decoded);

        if (!$ok) {
            return array('ok' => false, 'code' => 'write_failed', 'message' => 'Failed to store license JSON.');
        }

        return array('ok' => true, 'code' => 'stored', 'message' => 'License JSON stored (canonical).');
    }

    /**
     * Safe parser for the stored license JSON.
     *
     * @return array{
     *   ok:bool,
     *   code:string,
     *   raw:string,
     *   license:array<string,mixed>
     * }
     */
    private static function license_parse_stored(): array
    {
        $raw = self::license_get_raw_json();

        if ($raw === '') {
            return array('ok' => false, 'code' => 'no_license_stored', 'raw' => '', 'license' => array());
        }

        $decoded = json_decode($raw, true);

        if (!is_array($decoded)) {
            return array('ok' => false, 'code' => 'malformed_json', 'raw' => $raw, 'license' => array());
        }

        return array('ok' => true, 'code' => 'ok', 'raw' => $raw, 'license' => $decoded);
    }
    
    /**
     * Public canonical API (Phase-1, non-enforcing):
     * Store license data from an array using canonical encoding.
     *
     * @return array{ok:bool, code:string, message:string}
     */
    public static function store_license_from_array(array $license): array
    {
        if (empty($license)) {
            return array('ok' => false, 'code' => 'empty', 'message' => 'License payload is empty.');
        }

        $ok = self::license_write_array($license);

        if (!$ok) {
            return array('ok' => false, 'code' => 'write_failed', 'message' => 'Failed to store license JSON.');
        }

        return array('ok' => true, 'code' => 'stored', 'message' => 'License JSON stored (canonical).');
    }

    /**
     * Public canonical API (Phase-1, non-enforcing):
     * Store license data from a JSON string by normalizing it into canonical storage.
     *
     * @return array{ok:bool, code:string, message:string}
     */
    public static function store_license_from_json_string(string $json_input): array
    {
        return self::license_write_normalized_json($json_input);
    }
    /**
     * Day-9 (Phase 1): UI indicator for license status (non-enforcing).
     * Renders a small badge + message in the admin screen.
     */
    private static function render_license_status_indicator(): void
    {
        // Use the existing validator (single source of truth).
        // This method name MUST match your actual validator below.
        // If your validator is named differently, replace the call here accordingly.
        $result = self::license_validate_soft();

        $status  = isset($result['status']) ? (string) $result['status'] : 'unknown';
        $message = isset($result['message']) ? (string) $result['message'] : '';

        $label = strtoupper($status);

        // Minimal inline styling to avoid CSS churn.
        $bg = '#646970'; // default gray
        if ($status === 'valid') {
            $bg = '#008a20';
        } elseif ($status === 'expired') {
            $bg = '#b32d2e';
        } elseif ($status === 'mismatch') {
            $bg = '#dba617';
        } elseif ($status === 'missing' || $status === 'no_license_stored') {
            $bg = '#646970';
        } elseif ($status === 'invalid' || $status === 'malformed_json') {
            $bg = '#b32d2e';
        }

        echo '<div style="margin:10px 0 12px 0;">';
        echo '<span style="display:inline-block;padding:4px 10px;border-radius:999px;background:' . esc_attr($bg) . ';color:#fff;font-weight:600;font-size:12px;letter-spacing:0.3px;">';
        echo esc_html($label);
        echo '</span>';

        if ($message !== '') {
            echo '<span style="margin-left:10px;color:#1d2327;">' . esc_html($message) . '</span>';
        }
        echo '</div>';
    }


    // =========================================================================
    /**
     * Day-9 (Phase 1): Validate license against current identity (soft validation).
     *
     * Status enum:
     * - valid   : bound to this site_id and not expired
     * - expired : bound but expiry is in the past
     * - unbound : missing/empty site_id OR site_id does not match this site
     * - invalid : malformed JSON or required fields invalid
     * - missing : no license stored
     *
     * No enforcement in Phase 1.
     *
     * @return array{status:string,tier:string,expires_at:string,last_checked_at:string,reason:string}
     */
    public static function get_license_validation_snapshot() {
        // Ensure identity exists (Day-8 contract).
        $identity = self::get_identity_snapshot();

        $site_id = isset( $identity['site_id'] ) ? (string) $identity['site_id'] : '';
        $site_id = trim( $site_id );

        $checked_at = gmdate( 'c' );
        $parsed     = self::license_parse_stored();

        if ( isset( $parsed['code'] ) && $parsed['code'] === 'no_license_stored' ) {
            return array(
                'status'          => 'missing',
                'tier'            => 'free',
                'expires_at'      => '',
                'last_checked_at' => $checked_at,
                'reason'          => 'no_license_stored',
            );
        }

        if ( isset( $parsed['code'] ) && $parsed['code'] === 'malformed_json' ) {
            return array(
                'status'          => 'invalid',
                'tier'            => 'free',
                'expires_at'      => '',
                'last_checked_at' => $checked_at,
                'reason'          => 'malformed_json',
            );
        }

        $raw     = isset( $parsed['raw'] ) ? (string) $parsed['raw'] : '';
        $license = ( isset( $parsed['license'] ) && is_array( $parsed['license'] ) ) ? $parsed['license'] : array();

        // Extract fields from decoded license array (must exist before trim/lowercase).
        $license_key = isset( $license['license_key'] ) ? (string) $license['license_key'] : '';
        $tier       = isset( $license['tier'] ) ? (string) $license['tier'] : '';
        $lic_site   = isset( $license['site_id'] ) ? (string) $license['site_id'] : '';
        $expires_at = isset( $license['expires_at'] ) ? (string) $license['expires_at'] : '';

        $license_key = trim( $license_key );
        $tier       = strtolower( trim( $tier ) );
        $lic_site   = trim( $lic_site );
        $expires_at = trim( $expires_at );

    $allowed_tiers = array( 'free', 'starter', 'pro' );
    if ( '' === $license_key || '' === $tier || ! in_array( $tier, $allowed_tiers, true ) ) {
        return array(
            'status'          => 'invalid',
            'tier'            => 'free',
            'expires_at'      => '',
            'last_checked_at' => $checked_at,
            'reason'          => 'missing_or_invalid_fields',
        );
    }

    if ( '' === $site_id || '' === $lic_site || $lic_site !== $site_id ) {
        return array(
            'status'          => 'unbound',
            'tier'            => $tier,
            'expires_at'      => $expires_at,
            'last_checked_at' => $checked_at,
            'reason'          => 'site_id_mismatch_or_missing',
        );
    }

    // Expiry check (if provided). If empty => treat as non-expiring for Phase 1.
    if ( '' !== $expires_at ) {
            try {
                $exp = new DateTimeImmutable( $expires_at );
                $now = new DateTimeImmutable( 'now', new DateTimeZone( 'UTC' ) );

                if ( $exp < $now ) {
                    return array(
                        'status'          => 'expired',
                        'tier'            => $tier,
                        'expires_at'      => $expires_at,
                        'last_checked_at' => $checked_at,
                        'reason'          => 'license_expired',
                    );
                }
            } catch ( Exception $e ) {
                return array(
                    'status'          => 'invalid',
                    'tier'            => 'free',
                    'expires_at'      => '',
                    'last_checked_at' => $checked_at,
                    'reason'          => 'invalid_expires_at',
                );
            }
        }

        return array(
            'status'          => 'valid',
            'tier'            => $tier,
            'expires_at'      => $expires_at,
            'last_checked_at' => $checked_at,
            'reason'          => 'ok',
        );
    }

    /**
     * Build a local-first link claim (safe to export/share; contains no secrets).
     *
     * @return array{site_id:string,site_url:string,site_host:string,site_label:string,identity_email:string,linked_at:string,proof:string}
     */
    private static function get_link_claim_snapshot() {
        $identity   = self::get_identity_snapshot();
        $scope      = self::get_mcp_scope_snapshot();
        $linked_at  = get_option( 'opsgate_site_linked_at', '' );
        $link_proof = get_option( 'opsgate_site_link_proof', '' );

        $linked_at  = is_string( $linked_at ) ? trim( $linked_at ) : '';
        $link_proof = is_string( $link_proof ) ? trim( $link_proof ) : '';

        $resolved_site_id = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';
        $resolved_site_url = isset( $scope['site_url'] ) ? trim( (string) $scope['site_url'] ) : '';
        $resolved_site_label = isset( $scope['site_label'] ) ? trim( (string) $scope['site_label'] ) : '';
        $resolved_site_host = '' !== $resolved_site_url ? (string) ( wp_parse_url( $resolved_site_url, PHP_URL_HOST ) ?: '' ) : '';

        return array(
            'site_id'        => '' !== $resolved_site_id ? $resolved_site_id : $identity['site_id'],
            'site_url'       => '' !== $resolved_site_url ? $resolved_site_url : $identity['site_url'],
            'site_host'      => '' !== $resolved_site_host ? $resolved_site_host : $identity['site_host'],
            'site_label'     => '' !== $resolved_site_label ? $resolved_site_label : $identity['site_label'],
            'identity_email' => $identity['identity_email'],
            'linked_at'      => $linked_at,
            'proof'          => $link_proof,
        );
    }

    /**
     * Determine whether the site is "linked" (local-first).
     *
     * Definition:
     * - Identity fields present (site_id, email)
     * - Stored proof exists AND verifies against current identity snapshot
     *
     * @return bool
     */
    private static function is_site_linked() {
        $scope = self::get_mcp_scope_snapshot();
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id    = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';
        $error      = isset( $scope['error'] ) ? trim( (string) $scope['error'] ) : '';

        return '' !== $account_id && '' !== $site_id && '' === $error;
    }

    private static function mcp_error_message_from_payload( $payload, string $fallback = 'Request failed.' ): string {
        if ( is_string( $payload ) ) {
            $message = trim( $payload );
            return '' !== $message ? $message : $fallback;
        }

        if ( is_array( $payload ) ) {
            if ( isset( $payload['message'] ) && is_string( $payload['message'] ) && '' !== trim( $payload['message'] ) ) {
                return trim( $payload['message'] );
            }
            if ( isset( $payload['detail'] ) ) {
                return self::mcp_error_message_from_payload( $payload['detail'], $fallback );
            }
            $messages = array();
            foreach ( $payload as $item ) {
                if ( ! is_array( $item ) ) {
                    continue;
                }
                if ( isset( $item['msg'] ) && is_string( $item['msg'] ) && '' !== trim( $item['msg'] ) ) {
                    $messages[] = trim( $item['msg'] );
                } elseif ( isset( $item['message'] ) && is_string( $item['message'] ) && '' !== trim( $item['message'] ) ) {
                    $messages[] = trim( $item['message'] );
                }
            }
            if ( ! empty( $messages ) ) {
                return implode( ' ', array_unique( $messages ) );
            }
        }

        return $fallback;
    }

    private static function mcp_base_url(): string {
        return self::mcp_base_url_public();
    }

    public static function mcp_base_url_public(): string {
        if ( defined( 'OPSGATE_MCP_BASE_URL' ) && '' !== trim( (string) OPSGATE_MCP_BASE_URL ) ) {
            return trim( (string) OPSGATE_MCP_BASE_URL );
        }
        $stored = trim( (string) get_option( 'opsgate_api_base_url', '' ) );
        if ( '' !== $stored ) {
            return $stored;
        }
        // Production default: the OpsGate API endpoint for the public product.
        // No env or stored value — fall back to the canonical production API host.
        return 'https://api.opsgate.ca';
    }

    /**
     * Read JSON from OpsGate MCP API (thin client).
     *
     * @param string $path  Path starting with /v1/...
     * @param array  $query Query params
     * @return array{ok:bool,http:int,data?:array,error?:string}
     */
    private static function mcp_get_json( string $path, array $query = array() ): array {
        $base = self::mcp_base_url();
        if ( ! is_string( $base ) || '' === trim( $base ) ) {
            return array( 'ok' => false, 'http' => 0, 'error' => 'MCP base URL not configured.' );
        }

        $url = rtrim( $base, '/' ) . $path;
        if ( ! empty( $query ) ) {
            $url = add_query_arg( $query, $url );
        }

        $headers = array( 'Accept' => 'application/json' );
        if ( function_exists( 'opsgate_get_api_token' ) ) {
            $token = opsgate_get_api_token();
            if ( is_string( $token ) && '' !== trim( $token ) ) {
                $headers['X-Token'] = trim( $token );
            }
        }

        $resp = wp_remote_get(
            $url,
            array(
                'timeout'     => 10,
                'redirection' => 2,
                'headers'     => $headers,
            )
        );

        if ( is_wp_error( $resp ) ) {
            return array( 'ok' => false, 'http' => 0, 'error' => $resp->get_error_message() );
        }

        $http = (int) wp_remote_retrieve_response_code( $resp );
        $raw  = (string) wp_remote_retrieve_body( $resp );

        $data = json_decode( $raw, true );
        if ( ! is_array( $data ) ) {
            return array( 'ok' => false, 'http' => $http, 'error' => 'Invalid JSON from MCP.' );
        }

        if ( $http < 200 || $http >= 300 ) {
            $detail = self::mcp_error_message_from_payload( $data, 'Request failed.' );
            return array( 'ok' => false, 'http' => $http, 'error' => $detail, 'data' => $data );
        }

        return array( 'ok' => true, 'http' => $http, 'data' => $data );
    }

    private static function canonical_exports_history( int $limit = 20 ): array {
        $scope = self::get_mcp_scope_snapshot();

        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id    = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';

        if ( '' === $account_id || '' === $site_id ) {
            return array(
                'ok'    => false,
                'items' => array(),
                'error' => 'missing_scope',
            );
        }

        $resp = self::mcp_get_json(
            '/v1/exports/history',
            array(
                'account_id' => $account_id,
                'site_id'    => $site_id,
                'limit'      => max( 1, min( 100, $limit ) ),
            )
        );

        if ( ! is_array( $resp ) ) {
            return array(
                'ok'    => false,
                'items' => array(),
                'error' => 'history_unavailable',
            );
        }

        if ( empty( $resp['ok'] ) ) {
            return array(
                'ok'    => false,
                'items' => array(),
                'error' => isset( $resp['error'] ) ? (string) $resp['error'] : 'history_error',
            );
        }

        $data = isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array();
        $items = isset( $data['items'] ) && is_array( $data['items'] ) ? $data['items'] : array();

        return array(
            'ok'    => true,
            'items' => array_values( $items ),
            'error' => '',
        );
    }

    // Phase 4 delivery history — real backend truth from authority.report_deliveries
    private static function canonical_report_deliveries( string $job_id ): array {
        if ( '' === trim( $job_id ) ) {
            return array( 'ok' => false, 'items' => array(), 'error' => 'no_job_id' );
        }
        $scope      = self::get_mcp_scope_snapshot();
        $site_id    = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';
        if ( '' === $site_id ) {
            return array( 'ok' => false, 'items' => array(), 'error' => 'missing_scope' );
        }
        $resp = self::mcp_get_json(
            '/v1/sites/' . rawurlencode( $site_id ) . '/reports/' . rawurlencode( $job_id ) . '/deliveries'
        );
        if ( ! is_array( $resp ) || empty( $resp['ok'] ) ) {
            return array( 'ok' => false, 'items' => array(), 'error' => isset( $resp['error'] ) ? (string) $resp['error'] : 'delivery_unavailable' );
        }
        $items = isset( $resp['items'] ) && is_array( $resp['items'] ) ? $resp['items'] : array();
        return array( 'ok' => true, 'items' => array_values( $items ), 'error' => '' );
    }

    private static function canonical_portfolio_board(): array {
        $scope = self::get_mcp_scope_snapshot();
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';

        if ( '' === $account_id ) {
            return array(
                'ok'    => false,
                'data'  => array(),
                'error' => 'missing_scope',
            );
        }

        $resp = self::mcp_get_json(
            '/v1/portfolio/board',
            array(
                'account_id' => $account_id,
            )
        );

        if ( empty( $resp['ok'] ) ) {
            return array(
                'ok'    => false,
                'data'  => array(),
                'error' => isset( $resp['error'] ) ? (string) $resp['error'] : 'board_unavailable',
            );
        }

        return array(
            'ok'    => true,
            'data'  => isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array(),
            'error' => '',
        );
    }

    private static function canonical_local_board_row( array $board_state ): array {
        $scope = self::get_mcp_scope_snapshot();
        $site_id = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';
        $rows = isset( $board_state['data']['site_rows'] ) && is_array( $board_state['data']['site_rows'] ) ? $board_state['data']['site_rows'] : array();

        foreach ( $rows as $row ) {
            if ( is_array( $row ) && isset( $row['site_id'] ) && $site_id === trim( (string) $row['site_id'] ) ) {
                return $row;
            }
        }

        return array();
    }

    private static function proof_runs_list( int $limit = 10 ): array {
        $scope = self::get_mcp_scope_snapshot();
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';

        if ( '' === $account_id ) {
            return array(
                'ok'    => false,
                'items' => array(),
                'error' => 'missing_scope',
            );
        }

        $query = array(
            'account_id' => $account_id,
            'limit'      => max( 1, min( 100, $limit ) ),
        );
        if ( '' !== $site_id ) {
            $query['site_id'] = $site_id;
        }

        $resp = self::mcp_get_json( '/v1/proof-runs', $query );
        if ( empty( $resp['ok'] ) ) {
            return array(
                'ok'    => false,
                'items' => array(),
                'error' => isset( $resp['error'] ) ? (string) $resp['error'] : 'proof_runs_unavailable',
            );
        }

        $data = isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array();
        return array(
            'ok'    => true,
            'items' => isset( $data['items'] ) && is_array( $data['items'] ) ? array_values( $data['items'] ) : array(),
            'error' => '',
        );
    }

    private static function proof_run_get( string $proof_run_id ): array {
        $proof_run_id = trim( $proof_run_id );
        if ( '' === $proof_run_id ) {
            return array(
                'ok'    => false,
                'item'  => array(),
                'error' => 'missing_proof_run_id',
            );
        }

        $resp = self::mcp_get_json( '/v1/proof-runs/' . rawurlencode( $proof_run_id ) );
        if ( empty( $resp['ok'] ) ) {
            return array(
                'ok'    => false,
                'item'  => array(),
                'error' => isset( $resp['error'] ) ? (string) $resp['error'] : 'proof_run_unavailable',
            );
        }

        $data = isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array();
        return array(
            'ok'    => true,
            'item'  => isset( $data['proof_run'] ) && is_array( $data['proof_run'] ) ? $data['proof_run'] : array(),
            'error' => '',
        );
    }

    private static function proof_run_linked_job_id( array $item ): string {
        $links = isset( $item['links'] ) && is_array( $item['links'] ) ? $item['links'] : array();
        foreach ( $links as $link ) {
            if ( ! is_array( $link ) ) {
                continue;
            }
            if ( 'job' !== (string) ( $link['link_type'] ?? '' ) ) {
                continue;
            }
            $job_id = isset( $link['linked_job_id'] ) ? trim( (string) $link['linked_job_id'] ) : '';
            if ( '' !== $job_id ) {
                return $job_id;
            }
        }
        return '';
    }

    private static function current_operator_actor_payload(): array {
        $user = wp_get_current_user();
        if ( ! $user instanceof WP_User || 0 === (int) $user->ID ) {
            return array(
                'actor_display' => 'Unknown operator',
                'actor_role'    => 'administrator',
            );
        }

        $display_name = trim( (string) $user->display_name );
        if ( '' === $display_name ) {
            $display_name = trim( (string) $user->user_login );
        }

        $roles = isset( $user->roles ) && is_array( $user->roles ) ? array_values( array_filter( array_map( 'sanitize_key', $user->roles ) ) ) : array();

        return array(
            'actor_id'      => 'wp_user_' . (string) (int) $user->ID,
            'actor_email'   => trim( (string) $user->user_email ),
            'actor_display' => $display_name,
            'actor_role'    => ! empty( $roles ) ? (string) $roles[0] : 'administrator',
        );
    }

    private static function triage_bundle_for_job_id( string $job_id ): array {
        $job_id = trim( $job_id );
        if ( '' === $job_id ) {
            return array(
                'ok'        => false,
                'job'       => array(),
                'artifacts' => array(),
                'error'     => 'missing_job_id',
            );
        }

        $resp = self::mcp_get_json( '/v1/triage/' . rawurlencode( $job_id ) );
        if ( empty( $resp['ok'] ) ) {
            return array(
                'ok'        => false,
                'job'       => array(),
                'artifacts' => array(),
                'error'     => isset( $resp['error'] ) ? (string) $resp['error'] : 'triage_bundle_unavailable',
            );
        }

        $data = isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array();
        return array(
            'ok'        => true,
            'job'       => isset( $data['job'] ) && is_array( $data['job'] ) ? $data['job'] : array(),
            'artifacts' => isset( $data['artifacts'] ) && is_array( $data['artifacts'] ) ? $data['artifacts'] : array(),
            'error'     => '',
        );
    }

    private static function operator_degradation_scenarios(): array {
        return array(
            array(
                'scenario_id' => 'warning.core_version_drift',
                'label'       => 'Apply warning degradation',
                'tone'        => 'warn',
                'summary'     => 'Uses canonical backend degradation state so the next normal live triage records a warning posture everywhere.',
            ),
            array(
                'scenario_id' => 'critical.compound_failure',
                'label'       => 'Apply critical degradation',
                'tone'        => 'bad',
                'summary'     => 'Uses canonical backend degradation state so the next normal live triage records a critical posture everywhere.',
            ),
        );
    }

    private static function operator_degradation_status(): array {
        $execution = self::current_site_execution_context();
        $account_id = isset( $execution['account_id'] ) ? trim( (string) $execution['account_id'] ) : '';
        $site_id    = isset( $execution['site_id'] ) ? trim( (string) $execution['site_id'] ) : '';

        if ( '' === $account_id || '' === $site_id ) {
            return array(
                'ok'                  => false,
                'operator_harness_enabled' => false,
                'status'              => 'unavailable',
                'status_message'      => 'Connect this site in Settings before using the operator degradation harness.',
                'active_item'         => array(),
                'recent_items'        => array(),
                'catalog'             => self::operator_degradation_scenarios(),
                'error'               => 'operator_harness_scope_missing',
            );
        }

        $resp = self::mcp_get_json(
            '/v1/operator-degradations',
            array_filter(
                array(
                'account_id' => $account_id,
                'site_id'    => $site_id,
                ),
                static function ( $value ) {
                    return null !== $value && '' !== $value;
                }
            )
        );

        if ( empty( $resp['ok'] ) ) {
            return array(
                'ok'                       => false,
                'operator_harness_enabled' => false,
                'status'                   => 'unavailable',
                'status_message'           => 'Operator degradation state is unavailable right now.',
                'active_item'              => array(),
                'recent_items'             => array(),
                'catalog'                  => self::operator_degradation_scenarios(),
                'error'                    => isset( $resp['error'] ) ? (string) $resp['error'] : 'operator_degradation_status_unavailable',
            );
        }

        $data = isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array();
        return array(
            'ok'                       => true,
            'operator_harness_enabled' => ! empty( $data['operator_harness_enabled'] ),
            'status'                   => isset( $data['status'] ) ? (string) $data['status'] : 'inactive',
            'status_message'           => isset( $data['status_message'] ) ? (string) $data['status_message'] : 'No active degradation.',
            'active_item'              => isset( $data['active_item'] ) && is_array( $data['active_item'] ) ? $data['active_item'] : array(),
            'recent_items'             => isset( $data['recent_items'] ) && is_array( $data['recent_items'] ) ? $data['recent_items'] : array(),
            'catalog'                  => isset( $data['catalog'] ) && is_array( $data['catalog'] ) ? $data['catalog'] : self::operator_degradation_scenarios(),
            'result_code'              => isset( $data['result_code'] ) ? (string) $data['result_code'] : '',
            'error'                    => '',
        );
    }

    private static function operator_validation_scenarios(): array {
        return array(
            array(
                'scenario_id' => 'healthy.green.fixture',
                'label'       => 'Healthy / Green',
                'tone'        => 'good',
                'summary'     => 'Runs a deterministic healthy validation scenario through the API, worker, canonical artifacts, and score chain.',
            ),
            array(
                'scenario_id' => 'warning.yellow.fixture',
                'label'       => 'Warning / Yellow',
                'tone'        => 'warn',
                'summary'     => 'Runs a deterministic warning validation scenario with degraded posture and recorded evidence.',
            ),
            array(
                'scenario_id' => 'critical.red.fixture',
                'label'       => 'Critical / Red',
                'tone'        => 'bad',
                'summary'     => 'Runs a deterministic critical validation scenario with recorded evidence for high-risk posture.',
            ),
        );
    }

    private static function proof_run_status_copy( array $item ): string {
        $state = isset( $item['pass_fail_state'] ) ? strtolower( trim( (string) $item['pass_fail_state'] ) ) : '';
        if ( 'pass' === $state ) {
            return 'Validation confirmed';
        }
        if ( 'partial_fail' === $state ) {
            return 'Validation partially failed';
        }
        if ( 'fail' === $state ) {
            return 'Validation failed';
        }
        return 'Validation running';
    }

    private static function proof_run_scenario_label( array $item ): string {
        $scenario_id = isset( $item['scenario_id'] ) ? strtolower( trim( (string) $item['scenario_id'] ) ) : '';
        $labels = array(
            'healthy.green.fixture'                   => 'Healthy posture proof',
            'warning.yellow.fixture'                 => 'Warning posture proof',
            'critical.red.fixture'                   => 'Critical posture proof',
            'trigger.manual.operator'                => 'Manual trigger proof',
            'trigger.schedule.canonical'             => 'Scheduled trigger proof',
            'trigger.event.alert_rule'               => 'Event-driven trigger proof',
            'report.export_failure.invalid_source'   => 'Export failure proof',
            'alert.delivery_failure.test'            => 'Alert delivery failure proof',
            'trust.verified_signed_export'           => 'Verified export trust proof',
            'trust.legacy_supported_unsigned_export' => 'Legacy unsigned export proof',
            'trust.failed_verification.disposable'   => 'Failed verification proof',
        );

        if ( isset( $labels[ $scenario_id ] ) ) {
            return $labels[ $scenario_id ];
        }

        $scenario_id = trim( preg_replace( '/\s+/', ' ', str_replace( array( '.', '_' ), ' ', $scenario_id ) ) );
        return '' !== $scenario_id ? ucwords( $scenario_id ) : 'Proof scenario';
    }

    private static function proof_run_summary_copy( array $item ): string {
        $operator_note = isset( $item['operator_note'] ) ? trim( (string) $item['operator_note'] ) : '';
        if ( '' !== $operator_note ) {
            return $operator_note;
        }

        $summary = isset( $item['result_summary'] ) ? trim( (string) $item['result_summary'] ) : '';
        if ( '' !== $summary ) {
            return $summary;
        }

        return sprintf( '%s recorded in the validation ledger.', self::proof_run_scenario_label( $item ) );
    }

    private static function current_package_snapshot(): array {
        $snapshot = self::get_entitlement_plan_snapshot();
        return isset( $snapshot['package'] ) && is_array( $snapshot['package'] ) ? $snapshot['package'] : array();
    }

    private static function api_entitlement_eligibility_snapshot(): array {
        $snapshot = self::get_entitlement_plan_snapshot();
        return isset( $snapshot['eligibility'] ) && is_array( $snapshot['eligibility'] ) ? $snapshot['eligibility'] : array();
    }

    private static function output_availability_snapshot(): array {
        $eligibility = self::api_entitlement_eligibility_snapshot();
        return isset( $eligibility['outputs'] ) && is_array( $eligibility['outputs'] ) ? $eligibility['outputs'] : array();
    }

    private static function output_availability_key_for_kind( string $kind ): string {
        if ( 'report_pdf' === $kind ) {
            return 'report_pdf';
        }
        if ( 'report_html' === $kind ) {
            return 'report_html';
        }
        if ( 'report_xlsx' === $kind ) {
            return 'report_xlsx';
        }
        if ( in_array( $kind, array( 'triage_json', 'export_triage_json' ), true ) ) {
            return 'triage_json';
        }
        if ( in_array( $kind, array( 'triage_xml', 'export_triage_xml' ), true ) ) {
            return 'triage_xml';
        }
        return 'csv';
    }

    private static function output_availability_for_kind( string $kind ): array {
        $items = self::output_availability_snapshot();
        $key = self::output_availability_key_for_kind( $kind );
        return isset( $items[ $key ] ) && is_array( $items[ $key ] ) ? $items[ $key ] : array();
    }

    private static function alert_availability_snapshot(): array {
        $eligibility = self::api_entitlement_eligibility_snapshot();
        return isset( $eligibility['alerts'] ) && is_array( $eligibility['alerts'] ) ? $eligibility['alerts'] : array();
    }

    private static function alert_availability_for_channel( string $channel ): array {
        $channel = strtolower( trim( $channel ) );
        $items = self::alert_availability_snapshot();
        return isset( $items[ $channel ] ) && is_array( $items[ $channel ] ) ? $items[ $channel ] : array();
    }

    private static function notification_destination_is_live( array $destination ): bool {
        $state = strtolower( trim( (string) ( $destination['state'] ?? '' ) ) );
        $delivery_state = strtolower( trim( (string) ( $destination['delivery_state'] ?? '' ) ) );

        return 'active' === $state && 'live' === $delivery_state;
    }

    /**
     * Determine rule live-state from canonical API entitlement truth first, then from
     * linked canonical destination delivery truth when the entitlement snapshot does not
     * currently carry a family-specific item.
     */
    private static function notification_rule_channel_is_live( array $rule, array $destinations, array $live_channel_labels = array() ): bool {
        $channel = strtolower( trim( (string) ( $rule['channel'] ?? '' ) ) );
        $availability = self::alert_availability_for_channel( $channel );
        if ( ! empty( $availability ) ) {
            return ! empty( $availability['is_available'] );
        }

        foreach ( $destinations as $destination ) {
            if ( ! is_array( $destination ) || ! self::notification_rule_targets_destination( $rule, $destination ) ) {
                continue;
            }
            if ( self::notification_destination_is_live( $destination ) ) {
                return true;
            }
        }

        $channel_label = strtolower( trim( self::notification_channel_label( $channel ) ) );
        return '' !== $channel_label && in_array( $channel_label, $live_channel_labels, true );
    }

    private static function entitlement_limit_int( string $key, ?int $default = null ): ?int {
        $snapshot = self::get_entitlement_plan_snapshot();
        $limits = isset( $snapshot['limits'] ) && is_array( $snapshot['limits'] ) ? $snapshot['limits'] : array();
        if ( ! array_key_exists( $key, $limits ) ) {
            return $default;
        }
        $value = $limits[ $key ];
        if ( is_int( $value ) ) {
            return $value;
        }
        if ( is_float( $value ) ) {
            return (int) $value;
        }
        if ( is_string( $value ) && preg_match( '/^\d+$/', trim( $value ) ) ) {
            return (int) trim( $value );
        }
        return $default;
    }

    private static function webhook_destination_limit_label( int $limit, bool $is_available ): string {
        if ( ! $is_available || $limit <= 0 ) {
            return 'No webhook destinations';
        }
        if ( 1 === $limit ) {
            return '1 webhook destination';
        }
        return sprintf( '%d webhook destinations', $limit );
    }

    private static function webhook_destination_limit_fallback(): int {
        $snapshot = self::get_entitlement_plan_snapshot();
        $plan     = self::entitlement_plan_key_from_snapshot( $snapshot );

        if ( in_array( $plan, array( 'agency', 'agency_monthly', 'agency_yearly' ), true ) ) {
            return 25;
        }
        if ( in_array( $plan, array( 'pro', 'pro_monthly', 'pro_yearly' ), true ) ) {
            return 5;
        }
        if ( in_array( $plan, array( 'starter', 'starter_monthly', 'starter_yearly' ), true ) ) {
            return 1;
        }

        return 0;
    }

    private static function webhook_destination_allowance(): array {
        $availability = self::alert_availability_for_channel( 'webhook' );
        $is_available = ! empty( $availability['is_available'] );
        $limit = self::entitlement_limit_int( 'limits.alerts.webhook_destinations.max', null );
        if ( null === $limit ) {
            $limit = self::webhook_destination_limit_fallback();
        }
        $label = isset( $availability['destination_limit_label'] ) ? trim( (string) $availability['destination_limit_label'] ) : '';
        if ( '' === $label ) {
            $label = self::webhook_destination_limit_label( (int) $limit, $is_available );
        }
        $summary = isset( $availability['allowance_summary'] ) ? trim( (string) $availability['allowance_summary'] ) : '';
        if ( '' === $summary ) {
            $summary = $is_available && $limit > 0
                ? ( 1 === (int) $limit ? 'Current package allows exactly 1 configured webhook destination.' : sprintf( 'Current package allows up to %d configured webhook destinations.', (int) $limit ) )
                : ( isset( $availability['reason_message'] ) && '' !== trim( (string) $availability['reason_message'] ) ? (string) $availability['reason_message'] : 'Webhook delivery is not included in the current package.' );
        }
        return array(
            'is_available' => $is_available,
            'limit'        => (int) $limit,
            'label'        => $label,
            'summary'      => $summary,
        );
    }

    private static function package_scope_allowances_for_entry( array $package_entry ): array {
        if ( isset( $package_entry['scope_allowances'] ) && is_array( $package_entry['scope_allowances'] ) ) {
            $scope = $package_entry['scope_allowances'];
        } elseif (
            isset( $package_entry['accounts'] ) ||
            isset( $package_entry['sites'] ) ||
            isset( $package_entry['emails'] ) ||
            isset( $package_entry['webhooks'] ) ||
            isset( $package_entry['summary_label'] )
        ) {
            $scope = $package_entry;
        } else {
            $scope = array();
        }

        return array(
            'accounts'      => isset( $scope['accounts'] ) ? (int) $scope['accounts'] : 0,
            'sites'         => isset( $scope['sites'] ) ? (int) $scope['sites'] : 0,
            'emails'        => isset( $scope['emails'] ) ? (int) $scope['emails'] : 0,
            'webhooks'      => isset( $scope['webhooks'] ) ? (int) $scope['webhooks'] : 0,
            'summary_label' => isset( $scope['summary_label'] ) ? trim( (string) $scope['summary_label'] ) : '',
            'summary_copy'  => isset( $scope['summary_copy'] ) ? trim( (string) $scope['summary_copy'] ) : '',
        );
    }

    private static function package_scope_allowance_label_for_entry( array $package_entry ): string {
        $scope = self::package_scope_allowances_for_entry( $package_entry );
        if ( '' !== $scope['summary_label'] ) {
            return $scope['summary_label'];
        }

        $parts = array();
        if ( $scope['accounts'] > 0 ) {
            $parts[] = sprintf( '%d account%s', $scope['accounts'], 1 === $scope['accounts'] ? '' : 's' );
        }
        if ( $scope['sites'] > 0 ) {
            $parts[] = sprintf( '%d site%s', $scope['sites'], 1 === $scope['sites'] ? '' : 's' );
        }
        if ( $scope['webhooks'] > 0 ) {
            $parts[] = sprintf( '%d webhook%s', $scope['webhooks'], 1 === $scope['webhooks'] ? '' : 's' );
        } elseif ( $scope['emails'] > 0 ) {
            $parts[] = sprintf( '%d email%s', $scope['emails'], 1 === $scope['emails'] ? '' : 's' );
        }

        return ! empty( $parts ) ? implode( ' • ', $parts ) : 'Plan details loading';
    }

    private static function package_scope_allowance_summary_for_entry( array $package_entry ): string {
        $scope = self::package_scope_allowances_for_entry( $package_entry );
        if ( '' !== $scope['summary_copy'] ) {
            return $scope['summary_copy'];
        }

        $label = self::package_scope_allowance_label_for_entry( $package_entry );
        if ( 'Plan details loading' === $label ) {
            return 'Plan details are read from your current plan.';
        }

        return 'Your plan includes: ' . $label . '.';
    }

    private static function package_scope_allowance(): array {
        return self::package_scope_allowances_for_entry( self::current_package_entry() );
    }

    private static function package_scope_allowance_label(): string {
        return self::package_scope_allowance_label_for_entry( self::current_package_entry() );
    }

    private static function package_scope_allowance_summary(): string {
        return self::package_scope_allowance_summary_for_entry( self::current_package_entry() );
    }

    private static function alerts_plan_slug(): string {
        $snapshot = self::get_entitlement_plan_snapshot();
        return self::entitlement_plan_key_from_snapshot( $snapshot );
    }

    private static function alerts_full_family_creation_enabled(): bool {
        return in_array( self::alerts_plan_slug(), array( 'pro', 'agency' ), true );
    }

    /**
     * @return array<int,string>
     */
    private static function alerts_canonical_families(): array {
        return array( 'email', 'webhook', 'slack', 'teams', 'whatsapp', 'telegram', 'discord', 'sns' );
    }

    /**
     * @return array{value_label:string,placeholder:string,help:string}
     */
    private static function notification_destination_family_meta( string $family ): array {
        $family = strtolower( trim( $family ) );

        if ( 'webhook' === $family ) {
            return array(
                'value_label' => 'Webhook URL',
                'placeholder' => 'https://example.com/webhook',
                'help'        => 'Use the delivery URL for this webhook endpoint.',
            );
        }

        if ( 'slack' === $family ) {
            return array(
                'value_label' => 'Slack routing',
                'placeholder' => 'https://hooks.slack.com/services/...',
                'help'        => 'Slack uses an incoming webhook URL and can also carry optional workspace/channel context.',
            );
        }

        if ( 'teams' === $family ) {
            return array(
                'value_label' => 'Teams routing',
                'placeholder' => 'https://outlook.office.com/webhook/...',
                'help'        => 'Teams uses a webhook URL and follows the same canonical routing model as the other HTTP families.',
            );
        }

        if ( 'discord' === $family ) {
            return array(
                'value_label' => 'Discord routing',
                'placeholder' => 'https://discord.com/api/webhooks/...',
                'help'        => 'Discord uses a webhook URL and can also carry optional server/channel context for readback.',
            );
        }

        if ( 'telegram' === $family ) {
            return array(
                'value_label' => 'Telegram routing',
                'placeholder' => '123456789',
                'help'        => 'Telegram requires a bot token plus the chat ID that should receive this alert.',
            );
        }

        if ( 'whatsapp' === $family ) {
            return array(
                'value_label' => 'WhatsApp routing',
                'placeholder' => '+14165550100',
                'help'        => 'WhatsApp stores the recipient now and optional provider credentials for future live delivery.',
            );
        }

        if ( 'sns' === $family ) {
            return array(
                'value_label' => 'SNS routing',
                'placeholder' => 'arn:aws:sns:region:account:topic',
                'help'        => 'SNS stores the topic ARN now and optional region context for future live delivery.',
            );
        }

        return array(
            'value_label' => 'Recipient address',
            'placeholder' => 'name@example.com',
            'help'        => 'Use the recipient email address for this destination.',
        );
    }

    private static function notification_rule_targets_destination( array $rule, array $destination ): bool {
        $destination_id = trim( (string) ( $destination['destination_id'] ?? '' ) );
        $rule_destination_ids = isset( $rule['destination_ids'] ) && is_array( $rule['destination_ids'] ) ? array_values( array_filter( array_map( 'trim', $rule['destination_ids'] ) ) ) : array();

        if ( '' !== $destination_id && ! empty( $rule_destination_ids ) ) {
            return in_array( $destination_id, $rule_destination_ids, true );
        }

        $destination_family = strtolower( trim( (string) ( $destination['family'] ?? '' ) ) );
        $destination_target = trim( (string) ( $destination['resolved_target'] ?? '' ) );
        $rule_channel       = strtolower( trim( (string) ( $rule['channel'] ?? '' ) ) );
        $rule_target        = trim( (string) ( $rule['target'] ?? '' ) );

        if ( '' === $destination_family || '' === $destination_target || '' === $rule_channel || '' === $rule_target ) {
            return false;
        }

        return $destination_family === $rule_channel && $destination_target === $rule_target;
    }

    private static function update_posture_counts( array $update_posture ): array {
        $summary = isset( $update_posture['summary'] ) && is_array( $update_posture['summary'] ) ? $update_posture['summary'] : array();
        $core_outdated = ! empty( $summary['core_outdated'] ) || ( isset( $summary['core_updates'] ) && (int) $summary['core_updates'] > 0 );
        $plugin_outdated_count = isset( $summary['plugin_outdated_count'] ) ? (int) $summary['plugin_outdated_count'] : (int) ( $summary['plugin_updates'] ?? 0 );
        $theme_outdated_count = isset( $summary['theme_outdated_count'] ) ? (int) $summary['theme_outdated_count'] : (int) ( $summary['theme_updates'] ?? 0 );
        $outdated_total = isset( $summary['outdated_total'] )
            ? (int) $summary['outdated_total']
            : ( $core_outdated ? 1 : 0 ) + $plugin_outdated_count + $theme_outdated_count;

        return array(
            'outdated_total'         => $outdated_total,
            'core_outdated'          => $core_outdated,
            'plugin_outdated_count'  => $plugin_outdated_count,
            'theme_outdated_count'   => $theme_outdated_count,
            'evidence_state'         => isset( $summary['evidence_state'] ) ? (string) $summary['evidence_state'] : '',
        );
    }

    private static function update_detail_items( array $update_posture, array $vulnerability_posture = array() ): array {
        $items = array();
        $counts = self::update_posture_counts( $update_posture );

        $vuln_slugs = array();
        foreach ( ( isset( $vulnerability_posture['matches'] ) && is_array( $vulnerability_posture['matches'] ) ? $vulnerability_posture['matches'] : array() ) as $vm ) {
            if ( is_array( $vm ) && ! empty( $vm['component_slug'] ) ) {
                $vuln_slugs[ strtolower( trim( (string) $vm['component_slug'] ) ) ] = true;
            }
        }

        $core = isset( $update_posture['core'] ) && is_array( $update_posture['core'] ) ? $update_posture['core'] : array();
        if ( ! empty( $core['update_available'] ) || ! empty( $counts['core_outdated'] ) ) {
            $installed_version = (string) ( $core['installed_version'] ?? '—' );
            $available_version = (string) ( $core['available_version'] ?? '—' );
            $items[] = array(
                'label' => 'Core',
                'name'  => 'WordPress core',
                'meta'  => sprintf(
                    'Installed %s -> Latest %s',
                    $installed_version,
                    $available_version
                ),
                'facts' => array_filter(
                    array(
                        'Component type: WordPress core',
                        'Installed version: ' . $installed_version,
                        'Latest available: ' . $available_version,
                    )
                ),
                'reason' => 'Recorded inventory shows a newer WordPress core version is available for this site.',
                'action' => '—' !== $available_version ? 'Update WordPress core to ' . $available_version . '.' : 'Review the recorded core update requirement.',
            );
        }

        $plugins = isset( $update_posture['plugins']['items'] ) && is_array( $update_posture['plugins']['items'] ) ? $update_posture['plugins']['items'] : array();
        foreach ( $plugins as $plugin ) {
            if ( ! is_array( $plugin ) ) {
                continue;
            }
            $plugin_name = (string) ( $plugin['name'] ?? $plugin['slug'] ?? 'Plugin' );
            $plugin_slug = strtolower( trim( (string) ( $plugin['slug'] ?? '' ) ) );
            $installed_version = (string) ( $plugin['installed_version'] ?? '—' );
            $available_version = (string) ( $plugin['available_version'] ?? '—' );
            $is_security_fix = '' !== $plugin_slug && isset( $vuln_slugs[ $plugin_slug ] );
            $item = array(
                'label'                => 'Plugin',
                'name'                 => $plugin_name,
                'meta'                 => sprintf(
                    'Installed %s -> Latest %s',
                    $installed_version,
                    $available_version
                ),
                'facts'                => array_filter(
                    array(
                        'Component type: Plugin',
                        'Installed version: ' . $installed_version,
                        'Latest available: ' . $available_version,
                        isset( $plugin['active'] ) ? 'Active on site: ' . ( ! empty( $plugin['active'] ) ? 'Yes' : 'No' ) : '',
                    )
                ),
                'reason'               => 'Recorded inventory marked this plugin as outdated during the triage run.',
                'action'               => '—' !== $available_version ? 'Update ' . $plugin_name . ' to ' . $available_version . '.' : 'Review the recorded plugin update requirement.',
                'security_update_badge' => $is_security_fix,
            );
            $items[] = $item;
        }

        $themes = isset( $update_posture['themes']['items'] ) && is_array( $update_posture['themes']['items'] ) ? $update_posture['themes']['items'] : array();
        foreach ( $themes as $theme ) {
            if ( ! is_array( $theme ) ) {
                continue;
            }
            $theme_name = (string) ( $theme['name'] ?? $theme['stylesheet'] ?? 'Theme' );
            $installed_version = (string) ( $theme['installed_version'] ?? '—' );
            $available_version = (string) ( $theme['available_version'] ?? '—' );
            $items[] = array(
                'label' => 'Theme',
                'name'  => $theme_name,
                'meta'  => sprintf(
                    'Installed %s -> Latest %s',
                    $installed_version,
                    $available_version
                ),
                'facts' => array_filter(
                    array(
                        'Component type: Theme',
                        'Installed version: ' . $installed_version,
                        'Latest available: ' . $available_version,
                        isset( $theme['active'] ) ? 'Active on site: ' . ( ! empty( $theme['active'] ) ? 'Yes' : 'No' ) : '',
                    )
                ),
                'reason' => 'Recorded inventory marked this theme as outdated during the triage run.',
                'action' => '—' !== $available_version ? 'Update ' . $theme_name . ' to ' . $available_version . '.' : 'Review the recorded theme update requirement.',
            );
        }

        if ( empty( $items ) && ! empty( $counts['outdated_total'] ) ) {
            $items[] = array(
                'label'  => 'Updates',
                'name'   => (string) $counts['outdated_total'] . ' update item(s) recorded',
                'meta'   => 'This older proof receipt did not store per-component update rows.',
                'facts'  => array_filter(
                    array(
                        'Core updates: ' . ( ! empty( $counts['core_outdated'] ) ? '1' : '0' ),
                        'Plugin updates: ' . (string) $counts['plugin_outdated_count'],
                        'Theme updates: ' . (string) $counts['theme_outdated_count'],
                    )
                ),
                'reason' => 'The recorded artifact confirms update pressure, but this older receipt does not include component-level update rows.',
                'action' => 'Run a new operator validation receipt to capture component-level update drilldown.',
            );
        }

        return $items;
    }

    private static function vulnerability_detail_items( array $vulnerability_posture ): array {
        $items = array();
        $matches = isset( $vulnerability_posture['matches'] ) && is_array( $vulnerability_posture['matches'] ) ? $vulnerability_posture['matches'] : array();
        $unresolved_components = isset( $vulnerability_posture['unresolved_components'] ) && is_array( $vulnerability_posture['unresolved_components'] ) ? $vulnerability_posture['unresolved_components'] : array();
        $checked_components = isset( $vulnerability_posture['checked_components'] ) && is_array( $vulnerability_posture['checked_components'] ) ? $vulnerability_posture['checked_components'] : array();

        foreach ( $matches as $match ) {
            if ( ! is_array( $match ) ) {
                continue;
            }
            $component_type = (string) ( $match['component_type'] ?? 'component' );
            $component_name = (string) ( $match['component_name'] ?? $match['component_slug'] ?? 'Component' );
            $installed_version = (string) ( $match['installed_version'] ?? '—' );
            $fixed_in = trim( (string) ( $match['fixed_in'] ?? '' ) );
            $fixed_in_label = '' !== $fixed_in ? $fixed_in : 'Not recorded';
            $entry_id = (string) ( $match['entry_id'] ?? '—' );
            $severity = ucfirst( (string) ( $match['severity'] ?? 'match' ) );
            $title = (string) ( $match['title'] ?? '' );
            $match_reason = (string) ( $match['match_reason'] ?? '' );
            $source_documents = isset( $match['source_documents'] ) && is_array( $match['source_documents'] ) ? array_values( array_filter( array_map( 'strval', $match['source_documents'] ) ) ) : array();
            $normalized_result = (string) ( $match['normalized_result'] ?? '' );
            $fix_path_exists = ! empty( $match['fix_path_exists'] );
            $closed = ! empty( $match['closed'] );
            $unfixed = ! empty( $match['unfixed'] );
            $severity_label = 'medium' === strtolower( $severity ) && 'closed_review' === $normalized_result ? 'Warning' : $severity;
            $items[] = array(
                'label' => $severity_label,
                'name'  => $component_name,
                'meta'  => '' !== $title ? $title : 'Advisory entry ' . $entry_id,
                'facts' => array_filter(
                    array(
                        'Affected component: ' . ucfirst( str_replace( '_', ' ', $component_type ) ),
                        'Installed version: ' . $installed_version,
                        'Fixed version: ' . $fixed_in_label,
                        'Severity: ' . $severity_label,
                        'Advisory entry: ' . $entry_id,
                        $unfixed ? 'Fix path: No supported fix is recorded upstream.' : '',
                        $closed ? 'Component status: Closed upstream.' : '',
                        $fix_path_exists ? 'Review path: Update path is available for operator review.' : 'Review path: Manual review is required before acting.',
                        ! empty( $source_documents ) ? 'Source count: ' . (string) count( $source_documents ) : '',
                        ! empty( $source_documents ) ? 'Primary source: ' . (string) $source_documents[0] : '',
                        '' !== $match_reason ? 'Why it matched: ' . $match_reason : '',
                    )
                ),
                'reason' => '' !== $match_reason ? $match_reason : 'The installed component version matched the recorded advisory range.',
                'action' => '' !== $fixed_in ? 'Review updating ' . $component_name . ' to ' . $fixed_in . ' or later.' : ( $closed ? 'Review replacement options because this plugin is closed upstream.' : 'Review the advisory and confirm the vendor-supported update or replacement path before changing this plugin.' ),
            );
        }

        foreach ( $unresolved_components as $component ) {
            if ( ! is_array( $component ) ) {
                continue;
            }
            $component_name = (string) ( $component['component_name'] ?? $component['component_slug'] ?? 'Plugin' );
            $installed_version = (string) ( $component['installed_version'] ?? '—' );
            $reason = (string) ( $component['match_reason'] ?? 'This plugin could not be resolved by the live vulnerability source for this run.' );
            $items[] = array(
                'label' => 'Unresolved',
                'name'  => $component_name,
                'meta'  => 'Live plugin vulnerability lookup could not resolve this component.',
                'facts' => array_filter(
                    array(
                        'Installed version: ' . $installed_version,
                        ! empty( $component['component_slug'] ) ? 'Plugin slug: ' . (string) $component['component_slug'] : '',
                        ! empty( $component['source_url'] ) ? 'Lookup source: ' . (string) $component['source_url'] : '',
                        '' !== $reason ? 'Why it is unresolved: ' . $reason : '',
                    )
                ),
                'reason' => $reason,
                'action' => 'Review the plugin identity and vendor update path manually. Premium, private, or custom plugins may need operator review.',
            );
        }

        foreach ( $checked_components as $component ) {
            if ( ! is_array( $component ) ) {
                continue;
            }
            $normalized_result = strtolower( trim( (string) ( $component['normalized_result'] ?? '' ) ) );
            if ( 'no_match' !== $normalized_result ) {
                continue;
            }
            $component_name = (string) ( $component['component_name'] ?? $component['component_slug'] ?? 'Plugin' );
            $installed_version = (string) ( $component['installed_version'] ?? '—' );
            $items[] = array(
                'label' => 'Checked',
                'name'  => $component_name,
                'meta'  => 'Live advisory coverage checked this installed plugin and did not confirm an affected version.',
                'facts' => array_filter(
                    array(
                        'Installed version: ' . $installed_version,
                        ! empty( $component['component_slug'] ) ? 'Plugin slug: ' . (string) $component['component_slug'] : '',
                        ! empty( $component['source_provider'] ) ? 'Source provider: ' . (string) $component['source_provider'] : '',
                        ! empty( $component['source_updated_at_utc'] ) ? 'Source updated: ' . self::format_event_datetime( (string) $component['source_updated_at_utc'] ) : '',
                    )
                ),
                'reason' => 'OpsGate resolved this installed plugin through the live advisory source and did not record an affected installed-version match in this run.',
                'action' => 'No vulnerability action is required from this plugin in this recorded run.',
            );
        }

        if ( empty( $items ) ) {
            $summary = isset( $vulnerability_posture['summary'] ) && is_array( $vulnerability_posture['summary'] ) ? $vulnerability_posture['summary'] : array();
            $posture = strtolower( trim( (string) ( $vulnerability_posture['posture'] ?? '' ) ) );
            $evidence_state = strtolower( trim( (string) ( $summary['evidence_state'] ?? '' ) ) );
            $checked_component_count = isset( $summary['checked_plugin_count'] ) ? (int) $summary['checked_plugin_count'] : 0;
            $clean_component_count = isset( $summary['clean_plugin_count'] ) ? (int) $summary['clean_plugin_count'] : 0;
            $unresolved_component_count = isset( $summary['unresolved_plugin_count'] ) ? (int) $summary['unresolved_plugin_count'] : 0;
            $source_provider = trim( (string) ( $vulnerability_posture['source_provider'] ?? '' ) );
            $source_mode = trim( (string) ( $vulnerability_posture['source_mode'] ?? '' ) );
            $source_updated_at = trim( (string) ( $vulnerability_posture['source_updated_at_utc'] ?? '' ) );
            $coverage_scope = trim( (string) ( $summary['coverage_scope'] ?? '' ) );
            if ( 'evidence_limited' === $posture || ( '' !== $evidence_state && 'complete' !== $evidence_state ) ) {
                $errors = isset( $vulnerability_posture['errors'] ) && is_array( $vulnerability_posture['errors'] ) ? $vulnerability_posture['errors'] : array();
                $items[] = array(
                    'label' => 'Coverage',
                    'name'  => 'Vulnerability evidence coverage',
                    'meta'  => 'No direct advisory matches were recorded, but vulnerability evidence coverage was limited for this run.',
                    'facts' => array_filter(
                        array(
                            '' !== $evidence_state ? 'Evidence state: ' . ucfirst( str_replace( '_', ' ', $evidence_state ) ) : '',
                            $checked_component_count > 0 ? 'Checked plugins: ' . (string) $checked_component_count : '',
                            $clean_component_count > 0 ? 'Checked with no match: ' . (string) $clean_component_count : '',
                            $unresolved_component_count > 0 ? 'Unresolved plugins: ' . (string) $unresolved_component_count : '',
                            '' !== $source_provider ? 'Source provider: ' . $source_provider : '',
                            '' !== $coverage_scope ? 'Coverage scope: ' . str_replace( '_', ' ', $coverage_scope ) : '',
                            ! empty( $errors ) ? 'Recorded issue: ' . trim( (string) $errors[0] ) : '',
                        )
                    ),
                    'reason' => 'OpsGate could not treat this run as fully green because live plugin vulnerability coverage was limited for the recorded component set.',
                    'action' => 'Review unresolved plugins or lookup issues, then rerun the security scan when the live source can be resolved cleanly.',
                );
            } elseif ( $checked_component_count > 0 || '' !== $source_provider || '' !== $source_mode ) {
                $items[] = array(
                    'label' => 'Coverage proven',
                    'name'  => 'Live plugin advisory coverage was recorded for this run',
                    'meta'  => 'No vulnerable installed-version matches were confirmed in the recorded plugin inventory.',
                    'facts' => array_filter(
                        array(
                            $checked_component_count > 0 ? 'Checked plugins: ' . (string) $checked_component_count : '',
                            $clean_component_count > 0 ? 'Checked with no match: ' . (string) $clean_component_count : '',
                            'Unresolved plugins: ' . (string) $unresolved_component_count,
                            '' !== $source_provider ? 'Source provider: ' . $source_provider : '',
                            '' !== $source_mode ? 'Lookup path: ' . ucfirst( str_replace( '_', ' ', $source_mode ) ) : '',
                            '' !== $coverage_scope ? 'Coverage scope: ' . str_replace( '_', ' ', $coverage_scope ) : '',
                            '' !== $source_updated_at ? 'Source updated: ' . self::format_event_datetime( $source_updated_at ) : '',
                            '' !== $evidence_state ? 'Evidence state: ' . ucfirst( str_replace( '_', ' ', $evidence_state ) ) : '',
                        )
                    ),
                    'reason' => 'OpsGate checked the recorded plugin inventory against live advisory coverage and did not confirm any affected installed versions in this run.',
                    'action' => $unresolved_component_count > 0
                        ? 'Review the unresolved plugin identities before treating this run as fully cleared.'
                        : 'No vulnerability follow-up is required from this run unless the plugin inventory changes materially.',
                );
            }
        }

        return $items;
    }

    private static function configuration_validation_detail_items( array $validation, array $context = array() ): array {
        $items = array();
        $summary = isset( $validation['summary'] ) && is_array( $validation['summary'] ) ? $validation['summary'] : array();
        $families = isset( $validation['families'] ) && is_array( $validation['families'] ) ? $validation['families'] : array();
        $htaccess_family = isset( $families['htaccess'] ) && is_array( $families['htaccess'] ) ? $families['htaccess'] : array();
        $folder_family = isset( $families['folder_structure'] ) && is_array( $families['folder_structure'] ) ? $families['folder_structure'] : array();
        $account_id = isset( $context['account_id'] ) ? trim( (string) $context['account_id'] ) : '';
        $site_id = isset( $context['site_id'] ) ? trim( (string) $context['site_id'] ) : '';
        $source_job_id = isset( $context['source_job_id'] ) ? trim( (string) $context['source_job_id'] ) : '';
        $remediation_state = self::canonical_validation_remediation_state( $account_id, $site_id, $source_job_id );
        $remediation_items = isset( $remediation_state['items'] ) && is_array( $remediation_state['items'] ) ? $remediation_state['items'] : array();
        if ( ! empty( $htaccess_family ) ) {
            $htaccess_ran = array_key_exists( 'ran', $htaccess_family ) ? (bool) $htaccess_family['ran'] : true;
            $htaccess_exists = array_key_exists( 'exists', $htaccess_family ) ? (bool) $htaccess_family['exists'] : null;
            $htaccess_readable = array_key_exists( 'readable', $htaccess_family ) ? (bool) $htaccess_family['readable'] : null;
            $htaccess_writable = array_key_exists( 'writable', $htaccess_family ) ? (bool) $htaccess_family['writable'] : null;
            $htaccess_posture = strtolower( trim( (string) ( $htaccess_family['posture'] ?? 'passed' ) ) );
            $htaccess_review_state = strtolower( trim( (string) ( $htaccess_family['review_state'] ?? '' ) ) );
            $htaccess_review_reason = strtolower( trim( (string) ( $htaccess_family['review_reason'] ?? '' ) ) );
            $htaccess_label = 'Review';
            if ( 'passed' === $htaccess_posture && in_array( $htaccess_review_state, array( '', 'complete' ), true ) ) {
                $htaccess_label = 'Checked';
            } elseif ( 'partial' === $htaccess_review_state ) {
                $htaccess_label = 'Partial';
            } elseif ( 'unavailable' === $htaccess_review_state || ! $htaccess_ran ) {
                $htaccess_label = 'Unavailable';
            }
            $htaccess_meta = 'passed' === $htaccess_posture
                ? 'The root .htaccess review completed and no risky pattern was recorded.'
                : 'The root .htaccess review recorded a condition that needs follow-up.';
            if ( 'partial' === $htaccess_review_state || 'not_readable' === $htaccess_review_reason ) {
                $htaccess_meta = 'OpsGate found the root .htaccess path, but the file could not be fully read during this run.';
            } elseif ( 'missing_file' === $htaccess_review_reason ) {
                $htaccess_meta = 'OpsGate checked the root path and confirmed that .htaccess is missing for this run.';
            }
            $items[] = array(
                'label' => $htaccess_label,
                'name'  => '.htaccess review',
                'meta'  => $htaccess_meta,
                'facts' => array_filter(
                    array(
                        'Review ran: ' . ( $htaccess_ran ? 'Yes' : 'No' ),
                        null !== $htaccess_exists ? '.htaccess present: ' . ( $htaccess_exists ? 'Yes' : 'No' ) : '',
                        null !== $htaccess_readable ? 'Readable: ' . ( $htaccess_readable ? 'Yes' : 'No' ) : '',
                        null !== $htaccess_writable ? 'Writable: ' . ( $htaccess_writable ? 'Yes' : 'No' ) : '',
                        '' !== $htaccess_review_state ? 'Review state: ' . ucfirst( str_replace( '_', ' ', $htaccess_review_state ) ) : '',
                        '' !== $htaccess_review_reason ? 'Recorded reason: ' . ucfirst( str_replace( '_', ' ', $htaccess_review_reason ) ) : '',
                        '' !== $htaccess_posture ? 'Recorded posture: ' . ucfirst( str_replace( '_', ' ', $htaccess_posture ) ) : '',
                    )
                ),
                'reason' => 'passed' === $htaccess_posture && 'partial' !== $htaccess_review_state ? 'OpsGate recorded a clean .htaccess review for this run.' : 'OpsGate recorded .htaccess review limitations or risk that should be reviewed before treating the host as hardened.',
                'action' => 'passed' === $htaccess_posture && 'partial' !== $htaccess_review_state ? 'No .htaccess follow-up is currently required from this run.' : 'Open the recorded findings below and review the root configuration state before the next share-out.',
            );
        }
        if ( ! empty( $folder_family ) ) {
            $folder_ran = array_key_exists( 'ran', $folder_family ) ? (bool) $folder_family['ran'] : true;
            $folder_posture = strtolower( trim( (string) ( $folder_family['posture'] ?? 'passed' ) ) );
            $folder_review_state = strtolower( trim( (string) ( $folder_family['review_state'] ?? '' ) ) );
            $folder_review_reason = strtolower( trim( (string) ( $folder_family['review_reason'] ?? '' ) ) );
            $folder_uploads_exists = array_key_exists( 'uploads_dir_exists', $folder_family ) ? (bool) $folder_family['uploads_dir_exists'] : null;
            $folder_uploads_readable = array_key_exists( 'uploads_dir_readable', $folder_family ) ? (bool) $folder_family['uploads_dir_readable'] : null;
            $folder_label = 'Review';
            if ( 'passed' === $folder_posture && in_array( $folder_review_state, array( '', 'complete' ), true ) ) {
                $folder_label = 'Checked';
            } elseif ( 'partial' === $folder_review_state ) {
                $folder_label = 'Partial';
            } elseif ( 'unavailable' === $folder_review_state || ! $folder_ran ) {
                $folder_label = 'Unavailable';
            }
            $folder_meta = 'passed' === $folder_posture ? 'The uploads and public file-pattern review recorded no risky structure findings.' : 'The uploads and public file-pattern review recorded items that need follow-up.';
            if ( 'partial' === $folder_review_state || 'uploads_not_readable' === $folder_review_reason ) {
                $folder_meta = 'OpsGate found the uploads tree, but it could not be fully read during this run.';
            } elseif ( 'uploads_directory_missing' === $folder_review_reason ) {
                $folder_meta = 'OpsGate checked the expected uploads path and did not find a readable uploads directory for this run.';
            }
            $items[] = array(
                'label' => $folder_label,
                'name'  => 'Folder-structure review',
                'meta'  => $folder_meta,
                'facts' => array_filter(
                    array(
                        'Review ran: ' . ( $folder_ran ? 'Yes' : 'No' ),
                        null !== $folder_uploads_exists ? 'Uploads directory present: ' . ( $folder_uploads_exists ? 'Yes' : 'No' ) : '',
                        null !== $folder_uploads_readable ? 'Uploads directory readable: ' . ( $folder_uploads_readable ? 'Yes' : 'No' ) : '',
                        '' !== $folder_review_state ? 'Review state: ' . ucfirst( str_replace( '_', ' ', $folder_review_state ) ) : '',
                        '' !== $folder_review_reason ? 'Recorded reason: ' . ucfirst( str_replace( '_', ' ', $folder_review_reason ) ) : '',
                        '' !== $folder_posture ? 'Recorded posture: ' . ucfirst( str_replace( '_', ' ', $folder_posture ) ) : '',
                    )
                ),
                'reason' => 'passed' === $folder_posture && 'partial' !== $folder_review_state ? 'OpsGate checked for risky exposed file patterns in the connected site structure and did not record any finding.' : 'OpsGate recorded file-placement risk or review limitations that can affect how confidently this host can be treated as clean.',
                'action' => 'passed' === $folder_posture && 'partial' !== $folder_review_state ? 'No folder-structure follow-up is currently required from this run.' : 'Review the recorded file-path findings or review limitations below before treating the host as clean.',
            );
        }
        $findings = isset( $validation['findings'] ) && is_array( $validation['findings'] ) ? $validation['findings'] : array();
        foreach ( $findings as $finding ) {
            if ( ! is_array( $finding ) ) {
                continue;
            }
            $details = isset( $finding['details'] ) && is_array( $finding['details'] ) ? $finding['details'] : array();
            $finding_code = isset( $finding['finding_code'] ) ? (string) $finding['finding_code'] : 'not-recorded';
            $remediation_item = isset( $remediation_items[ $finding_code ] ) && is_array( $remediation_items[ $finding_code ] ) ? $remediation_items[ $finding_code ] : array();
            $capability_copy = isset( $remediation_item['capability_copy'] ) ? trim( (string) $remediation_item['capability_copy'] ) : '';
            $capability_state = isset( $remediation_item['capability_state'] ) ? trim( (string) $remediation_item['capability_state'] ) : '';
            $plan_mode = isset( $remediation_item['plan_mode'] ) ? trim( (string) $remediation_item['plan_mode'] ) : '';
            $remediation_state_value = isset( $remediation_item['remediation_state'] ) ? trim( (string) $remediation_item['remediation_state'] ) : '';
            $remediation_result = isset( $remediation_item['result_json'] ) && is_array( $remediation_item['result_json'] ) ? $remediation_item['result_json'] : array();
            $controls = array();
            if ( ! empty( $remediation_item['auto_fix_available'] ) && '' !== $source_job_id && ! in_array( $remediation_state_value, array( 'queued_apply', 'queued_revert', 'applied' ), true ) ) {
                $controls[] = array(
                    'kind'          => 'apply',
                    'label'         => 'Apply reversible fix',
                    'finding_code'  => $finding_code,
                    'source_job_id' => $source_job_id,
                );
            }
            if ( ! empty( $remediation_item['revert_available'] ) && ! empty( $remediation_item['remediation_id'] ) ) {
                $controls[] = array(
                    'kind'           => 'revert',
                    'label'          => 'Revert last fix',
                    'remediation_id' => (string) $remediation_item['remediation_id'],
                );
            }
            $finding_reason = (string) ( $finding['summary'] ?? 'A configuration review item was recorded for this run.' );
            if ( '' !== $capability_copy ) {
                $finding_reason .= ' ' . $capability_copy;
            }
            $finding_action = (string) ( $finding['action_hint'] ?? 'Review the recorded configuration finding before treating this site as hardened.' );
            if ( ! empty( $remediation_item['auto_fix_available'] ) ) {
                $finding_action = ! empty( $controls )
                    ? 'Use the reversible OpsGate fix control below, then rerun the security scan to confirm the changed state.'
                    : 'OpsGate can auto-fix this issue on eligible connected tiers after the current run scope is selected.';
            } elseif ( 'guidance_only' === $capability_state || 'detect_only' === $capability_state || ! empty( $remediation_item['manual_review_required'] ) ) {
                $finding_action = $capability_copy ?: $finding_action;
            }
            if ( ! empty( $remediation_result['applied_copy'] ) && 'applied' === $remediation_state_value ) {
                $finding_action = (string) $remediation_result['applied_copy'];
            } elseif ( 'queued_apply' === $remediation_state_value ) {
                $finding_action = 'OpsGate queued the corrective change through the connected worker path. Keep this page open while the remediation job completes, then rerun the security scan to confirm the new state.';
            } elseif ( 'queued_revert' === $remediation_state_value ) {
                $finding_action = 'OpsGate queued the revert through the connected worker path. Rerun Security Scan after the revert finishes to confirm the restored state.';
            }
            $items[] = array(
                'label' => ucfirst( (string) ( $finding['severity'] ?? 'Finding' ) ),
                'name'  => (string) ( $finding['title'] ?? 'Configuration finding' ),
                'meta'  => (string) ( $finding['summary'] ?? 'Configuration validation recorded a review item.' ),
                'facts' => array_filter(
                    array(
                        'Family: ' . ucfirst( str_replace( '_', ' ', (string) ( $finding['family'] ?? 'configuration' ) ) ),
                        'Finding code: ' . $finding_code,
                        isset( $details['path'] ) ? 'Path: ' . (string) $details['path'] : '',
                        isset( $details['size_bytes'] ) ? 'Size: ' . (string) $details['size_bytes'] . ' bytes' : '',
                        '' !== $plan_mode ? 'Remediation lane: ' . ucfirst( str_replace( '_', ' ', $plan_mode ) ) : '',
                        '' !== $capability_state ? 'Capability state: ' . ucfirst( str_replace( '_', ' ', $capability_state ) ) : '',
                        '' !== $remediation_state_value ? 'Latest fix state: ' . ucfirst( str_replace( '_', ' ', $remediation_state_value ) ) : '',
                        ! empty( $remediation_item['last_applied_at_utc'] ) ? 'Last applied: ' . self::format_event_datetime( (string) $remediation_item['last_applied_at_utc'] ) : '',
                        ! empty( $remediation_item['last_reverted_at_utc'] ) ? 'Last reverted: ' . self::format_event_datetime( (string) $remediation_item['last_reverted_at_utc'] ) : '',
                    )
                ),
                'reason' => $finding_reason,
                'action' => $finding_action,
                'controls' => $controls,
            );
        }
        return $items;
    }

    private static function uptime_window_detail_items( array $uptime_window ): array {
        $items = array();
        $summary = isset( $uptime_window['summary'] ) && is_array( $uptime_window['summary'] ) ? $uptime_window['summary'] : array();
        $history_label = trim( (string) ( $summary['history_label'] ?? '' ) );
        $history_copy = trim( (string) ( $summary['history_copy'] ?? '' ) );
        $history_state = trim( (string) ( $summary['history_state'] ?? '' ) );
        $observation_count = isset( $summary['observation_count'] ) ? (int) $summary['observation_count'] : 0;
        $failure_count = isset( $summary['failure_count'] ) ? (int) $summary['failure_count'] : 0;
        $uptime_percent = isset( $summary['uptime_percent'] ) ? $summary['uptime_percent'] : null;
        if ( '' !== $history_label || ! empty( $summary ) ) {
            $items[] = array(
                'label' => '' !== $history_label ? $history_label : 'History state',
                'name'  => 'Recent uptime window',
                'meta'  => '' !== $history_copy ? $history_copy : 'OpsGate is recording uptime observations over time for this site.',
                'facts' => array_filter(
                    array(
                        'Observations: ' . (string) $observation_count,
                        'Failures: ' . (string) $failure_count,
                        null !== $uptime_percent ? 'Recorded uptime: ' . (string) $uptime_percent . '%' : '',
                        '' !== $history_state ? 'Window state: ' . ucfirst( str_replace( '_', ' ', $history_state ) ) : '',
                    )
                ),
                'reason' => '' !== $history_copy ? $history_copy : 'OpsGate is still building uptime-over-time truth for this site.',
                'action' => $failure_count > 0
                    ? 'Review the failed observations below before treating uptime as historically stable.'
                    : ( $observation_count > 0 ? 'Keep recording observations so the recent window stays representative.' : 'Allow more uptime observations to accumulate before treating this signal as mature.' ),
            );
        }
        $observations = isset( $uptime_window['observations'] ) && is_array( $uptime_window['observations'] ) ? $uptime_window['observations'] : array();
        foreach ( array_slice( $observations, 0, 8 ) as $observation ) {
            if ( ! is_array( $observation ) ) {
                continue;
            }
            $status_code = isset( $observation['status_code'] ) ? (string) $observation['status_code'] : '—';
            $duration_ms = isset( $observation['duration_ms'] ) ? (string) $observation['duration_ms'] : '—';
            $ok = ! empty( $observation['ok'] );
            $observed_at = isset( $observation['observed_at_utc'] ) ? self::canonical_report_datetime_label( (string) $observation['observed_at_utc'] ) : '—';
            $items[] = array(
                'label' => $ok ? 'Available' : 'Failed',
                'name'  => 'Observation ' . $observed_at,
                'meta'  => 'HTTP ' . $status_code . ' in ' . $duration_ms . ' ms',
                'facts' => array_filter(
                    array(
                        'Status code: ' . $status_code,
                        'Duration: ' . $duration_ms . ' ms',
                        ! empty( $observation['failure_class'] ) ? 'Failure class: ' . (string) $observation['failure_class'] : '',
                    )
                ),
                'reason' => $ok ? 'This recorded observation completed successfully inside the uptime window.' : 'This recorded observation failed inside the uptime window.',
                'action' => $ok ? 'No uptime action is currently required for this specific observation.' : 'Review the recent failure pattern before treating uptime as stable.',
            );
        }
        return $items;
    }

    private static function operational_log_intelligence_detail_items( array $intelligence ): array {
        $items = array();
        $summary = isset( $intelligence['summary'] ) && is_array( $intelligence['summary'] ) ? $intelligence['summary'] : array();
        $sources = isset( $intelligence['sources'] ) && is_array( $intelligence['sources'] ) ? $intelligence['sources'] : array();
        $available_source_count = isset( $summary['available_source_count'] ) ? (int) $summary['available_source_count'] : 0;
        $unavailable_source_count = isset( $summary['unavailable_source_count'] ) ? (int) $summary['unavailable_source_count'] : 0;
        $source_state = strtolower( trim( (string) ( $summary['source_state'] ?? '' ) ) );
        $source_family_labels = array();
        foreach ( $sources as $source ) {
            if ( ! is_array( $source ) ) {
                continue;
            }
            $source_family = trim( (string) ( $source['source_family'] ?? '' ) );
            if ( '' === $source_family ) {
                continue;
            }
            if ( 'wordpress_debug' === $source_family ) {
                $source_family_labels[ $source_family ] = 'WordPress debug log';
            } elseif ( 'woocommerce_log' === $source_family ) {
                $source_family_labels[ $source_family ] = 'WooCommerce runtime log';
            } else {
                $source_family_labels[ $source_family ] = ucwords( str_replace( '_', ' ', $source_family ) );
            }
        }
        if ( ! empty( $summary ) || ! empty( $sources ) ) {
            $runtime_log_label = 'Normalized';
            $runtime_log_meta = 'OpsGate checked the connected runtime log sources and normalized recurring patterns instead of dumping raw log lines.';
            $runtime_log_reason = 'WordPress and WooCommerce runtime logs are treated as operational evidence, then normalized into customer-safe signal rows.';
            $runtime_log_action = 'Open the normalized signals below when you need the exact recurring patterns behind runtime pressure.';
            if ( 'unavailable' === $source_state || ( empty( $sources ) && 0 === $available_source_count ) ) {
                $runtime_log_label = 'Unavailable';
                $runtime_log_meta = 'No readable WordPress or WooCommerce runtime log source was recorded for this run.';
                $runtime_log_reason = 'This run did not capture a readable runtime log source, so no normalized signal view could be built.';
                $runtime_log_action = 'Verify whether debug logging or WooCommerce logging is available on the connected site before expecting log-intelligence output.';
            } elseif ( 'available_no_signals' === $source_state ) {
                $runtime_log_label = 'Reviewed';
                $runtime_log_meta = 'Readable WordPress or WooCommerce log sources were reviewed and no recurring normalized signal was recorded.';
                $runtime_log_reason = 'OpsGate reviewed the available runtime logs and did not detect a recurring signal pattern worth surfacing to the main product surface.';
                $runtime_log_action = 'No runtime log follow-up is required from this run unless the site begins emitting repeat errors later.';
            }
            $items[] = array(
                'label' => $runtime_log_label,
                'name'  => 'Runtime log source review',
                'meta'  => $runtime_log_meta,
                'facts' => array_filter(
                    array(
                        'Sources reviewed: ' . (string) (int) ( $summary['source_count'] ?? count( $sources ) ),
                        'Readable sources: ' . (string) $available_source_count,
                        'Unavailable sources: ' . (string) $unavailable_source_count,
                        'Signals recorded: ' . (string) (int) ( $summary['signal_count'] ?? 0 ),
                        '' !== $source_state ? 'Recorded state: ' . ucfirst( str_replace( '_', ' ', $source_state ) ) : '',
                        ! empty( $source_family_labels ) ? 'Source families: ' . implode( ', ', array_values( $source_family_labels ) ) : '',
                    )
                ),
                'reason' => $runtime_log_reason,
                'action' => $runtime_log_action,
            );
        }
        $signals = isset( $intelligence['signals'] ) && is_array( $intelligence['signals'] ) ? $intelligence['signals'] : array();
        foreach ( $signals as $signal ) {
            if ( ! is_array( $signal ) ) {
                continue;
            }
            $items[] = array(
                'label' => ucfirst( (string) ( $signal['severity'] ?? 'Signal' ) ),
                'name'  => ucwords( str_replace( '_', ' ', (string) ( $signal['signal_key'] ?? 'log_signal' ) ) ),
                'meta'  => (string) ( $signal['latest_message'] ?? 'A normalized operational log signal was recorded.' ),
                'facts' => array_filter(
                    array(
                        'Source family: ' . ucfirst( str_replace( '_', ' ', (string) ( $signal['source_family'] ?? 'log' ) ) ),
                        'Event count: ' . (string) (int) ( $signal['event_count'] ?? 0 ),
                        ! empty( $signal['source_file'] ) ? 'Source file: ' . (string) $signal['source_file'] : '',
                    )
                ),
                'reason' => 'OpsGate normalized a repeated operational log pattern instead of surfacing raw log lines as the customer-facing product.',
                'action' => 'Review the source system behind this signal and resolve the recurring runtime error before the next share-out.',
            );
        }
        if ( empty( $signals ) && ! empty( $sources ) ) {
            foreach ( array_slice( $sources, 0, 4 ) as $source ) {
                if ( ! is_array( $source ) ) {
                    continue;
                }
                $source_family = trim( (string) ( $source['source_family'] ?? '' ) );
                $source_label = trim( (string) ( $source['label'] ?? '' ) );
                $availability_status = strtolower( trim( (string) ( $source['availability_status'] ?? '' ) ) );
                $availability_reason = strtolower( trim( (string) ( $source['availability_reason'] ?? '' ) ) );
                if ( '' === $source_label ) {
                    $source_label = '' !== $source_family ? ucwords( str_replace( '_', ' ', $source_family ) ) : 'Runtime log source';
                }
                $source_meta = 'No recurring runtime signal was normalized from this source for the recorded run.';
                $source_reason = 'OpsGate reviewed this source and did not detect a recurring signal pattern worth surfacing to the main product surface.';
                $source_action = 'No runtime log follow-up is required from this source unless the site starts emitting repeat errors later.';
                if ( 'unavailable' === $availability_status ) {
                    $source_meta = 'This runtime log source was not readable for the recorded run.';
                    if ( 'no_log_files' === $availability_reason ) {
                        $source_meta = 'OpsGate looked for this runtime log family, but no log file was present to review during the run.';
                    } elseif ( 'log_directory_missing' === $availability_reason ) {
                        $source_meta = 'OpsGate looked for this runtime log family, but the expected log directory was not present during the run.';
                    } elseif ( 'source_not_readable' === $availability_reason ) {
                        $source_meta = 'OpsGate found this runtime log source, but it was not readable during the run.';
                    }
                    $source_reason = 'OpsGate could not normalize this runtime log family because the source was unavailable for the recorded run.';
                    $source_action = 'Enable or restore the runtime log source if you want this signal family to participate in future triage runs.';
                }
                $items[] = array(
                    'label' => 'unavailable' === $availability_status ? 'Unavailable' : 'Reviewed',
                    'name'  => $source_label,
                    'meta'  => $source_meta,
                    'facts' => array_filter(
                        array(
                            '' !== $source_family ? 'Source family: ' . ucwords( str_replace( '_', ' ', $source_family ) ) : '',
                            ! empty( $source['source_file'] ) ? 'Source file: ' . (string) $source['source_file'] : '',
                            '' !== $availability_status ? 'Availability: ' . ucfirst( str_replace( '_', ' ', $availability_status ) ) : '',
                            '' !== $availability_reason ? 'Recorded reason: ' . ucfirst( str_replace( '_', ' ', $availability_reason ) ) : '',
                            isset( $source['line_count_sampled'] ) ? 'Sampled lines: ' . (string) (int) $source['line_count_sampled'] : '',
                            ! empty( $source['latest_at_utc'] ) ? 'Latest activity: ' . self::canonical_report_datetime_label( (string) $source['latest_at_utc'] ) : '',
                        )
                    ),
                    'reason' => $source_reason,
                    'action' => $source_action,
                );
            }
        }
        return $items;
    }

    private static function hardening_guidance_detail_items( array $guidance ): array {
        $items = array();
        $summary = isset( $guidance['summary'] ) && is_array( $guidance['summary'] ) ? $guidance['summary'] : array();
        if ( ! empty( $summary ) ) {
            $items[] = array(
                'label' => isset( $summary['guidance_title'] ) ? (string) $summary['guidance_title'] : 'Recorded guidance',
                'name'  => 'Hardening and remediation posture',
                'meta'  => isset( $summary['guidance_copy'] ) ? (string) $summary['guidance_copy'] : 'OpsGate recorded review-first hardening guidance for this run.',
                'facts' => array_filter(
                    array(
                        'Guidance state: ' . ucfirst( str_replace( '_', ' ', (string) ( $summary['guidance_state'] ?? 'not_recorded' ) ) ),
                        'Guidance items: ' . (string) (int) ( $summary['item_count'] ?? 0 ),
                        'Critical actions: ' . (string) (int) ( $summary['critical_count'] ?? 0 ),
                        'Warning actions: ' . (string) (int) ( $summary['warning_count'] ?? 0 ),
                        'Monitoring actions: ' . (string) (int) ( $summary['monitor_count'] ?? 0 ),
                        'Auto-applied: No',
                    )
                ),
                'reason' => isset( $summary['support_boundary_copy'] ) ? (string) $summary['support_boundary_copy'] : 'OpsGate keeps hardening guidance explicit, auditable, and non-silent.',
                'action' => 'Review the recorded guidance items below, complete the WordPress or host follow-up explicitly, and rerun the security scan to confirm the new state.',
            );
        }

        $guidance_items = isset( $guidance['items'] ) && is_array( $guidance['items'] ) ? $guidance['items'] : array();
        foreach ( $guidance_items as $guidance_item ) {
            if ( ! is_array( $guidance_item ) ) {
                continue;
            }
            $facts = isset( $guidance_item['facts'] ) && is_array( $guidance_item['facts'] ) ? array_values( array_filter( array_map( 'strval', $guidance_item['facts'] ) ) ) : array();
            $facts[] = 'OpsGate role: ' . (string) ( $guidance_item['opsgate_role'] ?? 'Evidence and packaging only.' );
            $facts[] = 'Auto-applied: ' . ( ! empty( $guidance_item['not_auto_applied'] ) ? 'No' : 'Yes' );
            if ( ! empty( $guidance_item['evidence_ref'] ) ) {
                $facts[] = 'Evidence reference: ' . (string) $guidance_item['evidence_ref'];
            }
            $items[] = array(
                'label' => ucfirst( str_replace( '_', ' ', (string) ( $guidance_item['priority'] ?? 'review' ) ) ),
                'name'  => (string) ( $guidance_item['title'] ?? 'Hardening guidance item' ),
                'meta'  => (string) ( $guidance_item['summary'] ?? 'OpsGate recorded a hardening/remediation guidance item for this run.' ),
                'facts' => array_values( array_unique( array_filter( $facts ) ) ),
                'reason' => (string) ( $guidance_item['why_it_matters'] ?? 'This recorded issue affects how confidently the site can be treated as hardened.' ),
                'action' => (string) ( $guidance_item['recommended_action'] ?? 'Review the recorded evidence and complete the follow-up explicitly before the next run.' ),
            );
        }

        return $items;
    }

    private static function posture_detail_items( string $detail_type, array $recorded_posture, array $context = array() ): array {
        if ( 'updates' === $detail_type ) {
            $vuln_ctx = isset( $context['vulnerability_posture'] ) && is_array( $context['vulnerability_posture'] ) ? $context['vulnerability_posture'] : array();
            return self::update_detail_items( $recorded_posture, $vuln_ctx );
        }

        if ( 'vulnerabilities' === $detail_type ) {
            return self::vulnerability_detail_items( $recorded_posture );
        }

        if ( 'validation' === $detail_type ) {
            return self::configuration_validation_detail_items( $recorded_posture, $context );
        }

        if ( 'uptime' === $detail_type ) {
            return self::uptime_window_detail_items( $recorded_posture );
        }

        if ( 'logs' === $detail_type ) {
            return self::operational_log_intelligence_detail_items( $recorded_posture );
        }

        if ( 'hardening' === $detail_type ) {
            return self::hardening_guidance_detail_items( $recorded_posture );
        }

        return array();
    }

    private static function posture_reason_items( array $score_summary, array $update_posture, array $vulnerability_posture, array $reachability_posture, array $availability_snapshot ): array {
        $items = array();
        $grade = ucfirst( trim( (string) ( $score_summary['grade'] ?? 'Unknown' ) ) );
        $score = isset( $score_summary['score'] ) ? (string) (int) $score_summary['score'] : '—';
        $update_counts = self::update_posture_counts( $update_posture );
        $score_components = isset( $score_summary['components'] ) && is_array( $score_summary['components'] ) ? $score_summary['components'] : array();
        $vulnerability_summary = isset( $vulnerability_posture['summary'] ) && is_array( $vulnerability_posture['summary'] ) ? $vulnerability_posture['summary'] : array();
        $reachability_summary = isset( $reachability_posture['summary'] ) && is_array( $reachability_posture['summary'] ) ? $reachability_posture['summary'] : array();
        $availability_summary = isset( $availability_snapshot['summary'] ) && is_array( $availability_snapshot['summary'] ) ? $availability_snapshot['summary'] : array();
        $performance_component = isset( $score_components['performance']['details'] ) && is_array( $score_components['performance']['details'] ) ? $score_components['performance']['details'] : array();

        $match_count = isset( $vulnerability_summary['match_count'] ) ? (int) $vulnerability_summary['match_count'] : 0;
        $critical_count = isset( $vulnerability_summary['critical_count'] ) ? (int) $vulnerability_summary['critical_count'] : 0;
        $high_count = isset( $vulnerability_summary['high_count'] ) ? (int) $vulnerability_summary['high_count'] : 0;
        $checked_plugin_count = isset( $vulnerability_summary['checked_plugin_count'] ) ? (int) $vulnerability_summary['checked_plugin_count'] : 0;
        $unresolved_plugin_count = isset( $vulnerability_summary['unresolved_plugin_count'] ) ? (int) $vulnerability_summary['unresolved_plugin_count'] : 0;
        $vulnerability_posture_value = strtolower( trim( (string) ( $vulnerability_posture['posture'] ?? 'pending' ) ) );
        $vulnerability_evidence_state = strtolower( trim( (string) ( $vulnerability_summary['evidence_state'] ?? '' ) ) );
        $vulnerability_source_provider = trim( (string) ( $vulnerability_posture['source_provider'] ?? '' ) );
        $reachability_posture = (string) ( $reachability_posture['posture'] ?? 'pending' );
        $reachability_status = isset( $reachability_summary['http_status'] ) ? (string) $reachability_summary['http_status'] : '—';
        $reachability_duration = isset( $reachability_summary['duration_ms'] ) ? (string) $reachability_summary['duration_ms'] : '—';
        $reachability_failure = isset( $reachability_summary['failure_class'] ) ? (string) $reachability_summary['failure_class'] : '';
        $availability_posture = strtolower( trim( (string) ( $availability_snapshot['posture'] ?? 'pending' ) ) );
        $availability_attempts = isset( $availability_summary['attempt_count'] ) ? (int) $availability_summary['attempt_count'] : 0;
        $availability_failures = isset( $availability_summary['failed_attempts'] ) ? (int) $availability_summary['failed_attempts'] : 0;
        $performance_posture = strtolower( trim( (string) ( $performance_component['posture'] ?? 'pending' ) ) );
        $performance_status = isset( $performance_component['status_code'] ) ? (string) $performance_component['status_code'] : '—';
        $performance_total_duration = isset( $performance_component['total_duration_ms'] ) ? (string) $performance_component['total_duration_ms'] : '—';
        $performance_first_byte = isset( $performance_component['first_byte_ms'] ) ? (string) $performance_component['first_byte_ms'] : '—';

        $overall_reason_parts = array();
        if ( $match_count > 0 ) {
            $reason = (string) $match_count . ( 1 === (int) $match_count ? ' vulnerability found' : ' vulnerabilities found' );
            if ( $critical_count > 0 || $high_count > 0 ) {
                $reason .= ', including ' . (string) $critical_count . ' critical and ' . (string) $high_count . ' high finding(s)';
            }
            $overall_reason_parts[] = $reason;
        }
        if ( ! empty( $update_counts['outdated_total'] ) ) {
            $overall_reason_parts[] = (string) $update_counts['outdated_total'] . ' update' . ( 1 === (int) $update_counts['outdated_total'] ? '' : 's' ) . ' need action';
        }
        if ( 'evidence_limited' === $vulnerability_posture_value || ( '' !== $vulnerability_evidence_state && 'complete' !== $vulnerability_evidence_state ) ) {
            $overall_reason_parts[] = 'vulnerability evidence coverage was ' . str_replace( '_', ' ', '' !== $vulnerability_evidence_state ? $vulnerability_evidence_state : $vulnerability_posture_value );
        }
        if ( 'unreachable' === $reachability_posture || 'degraded' === $reachability_posture ) {
            $reachability_reason = 'reachability was ' . str_replace( '_', ' ', $reachability_posture );
            if ( '' !== $reachability_failure ) {
                $reachability_reason .= ' (' . str_replace( '_', ' ', $reachability_failure ) . ')';
            }
            $overall_reason_parts[] = $reachability_reason;
        }
        if ( $availability_failures > 0 ) {
            $overall_reason_parts[] = (string) $availability_failures . ' of ' . (string) $availability_attempts . ' availability probe(s) failed';
        }
        if ( in_array( $performance_posture, array( 'degraded', 'poor', 'failed_probe' ), true ) ) {
            $overall_reason_parts[] = 'performance posture was ' . str_replace( '_', ' ', $performance_posture );
        }

        $overall_reason = 'This run is ' . strtolower( $grade ) . ' because ';
        if ( ! empty( $overall_reason_parts ) ) {
            $overall_reason .= implode( '; ', $overall_reason_parts ) . '.';
        } else {
            $overall_reason .= 'no pending updates or vulnerability matches were recorded and the site remained reachable.';
        }

        $items[] = array(
            'label' => 'Overall',
            'name'  => $grade . ' posture',
            'meta'  => $overall_reason,
            'facts' => array_filter(
                array(
                    'Score: ' . $score,
                    'Updates needing action: ' . (string) $update_counts['outdated_total'],
                    'Vulnerability matches: ' . (string) $match_count,
                    '' !== $vulnerability_evidence_state ? 'Vulnerability evidence: ' . ucfirst( str_replace( '_', ' ', $vulnerability_evidence_state ) ) : '',
                    'Reachability posture: ' . ucfirst( str_replace( '_', ' ', $reachability_posture ) ),
                    $availability_attempts > 0 ? 'Availability failures: ' . (string) $availability_failures . ' / ' . (string) $availability_attempts : '',
                    'pending' !== $performance_posture ? 'Performance posture: ' . ucfirst( str_replace( '_', ' ', $performance_posture ) ) : '',
                )
            ),
        );

        $items[] = array(
            'label' => 'Updates',
            'name'  => 0 === (int) $update_counts['outdated_total'] ? 'No updates needed.' : (string) $update_counts['outdated_total'] . ' update' . ( 1 === (int) $update_counts['outdated_total'] ? '' : 's' ) . ' need action',
            'meta'  => 0 === (int) $update_counts['outdated_total']
                ? 'No core, plugin, or theme updates were recorded for this run.'
                : 'Recorded update posture shows where version drift is contributing pressure.',
            'facts' => array(
                'Core outdated: ' . ( ! empty( $update_counts['core_outdated'] ) ? 'Yes' : 'No' ),
                'Plugin updates: ' . (string) $update_counts['plugin_outdated_count'],
                'Theme updates: ' . (string) $update_counts['theme_outdated_count'],
            ),
            'action' => 0 === (int) $update_counts['outdated_total'] ? 'No update action is currently required.' : 'Review the update drilldown and patch the listed components.',
        );

        $items[] = array(
            'label' => 'Vulnerabilities',
            'name'  => 0 === $match_count ? 'No vulnerabilities found.' : (string) $match_count . ( 1 === $match_count ? ' vulnerability found' : ' vulnerabilities found' ),
            'meta'  => 0 === $match_count
                ? (
                    ( 'evidence_limited' === $vulnerability_posture_value || ( '' !== $vulnerability_evidence_state && 'complete' !== $vulnerability_evidence_state ) )
                        ? 'No direct advisory matches were recorded, but vulnerability evidence coverage was limited for this run.'
                        : 'No vulnerability matches were recorded for the tracked component set.'
                )
                : 'Active vulnerabilities are affecting this site\'s score.',
            'facts' => array_filter(
                array(
                    'Critical findings: ' . (string) $critical_count,
                    'High findings: ' . (string) $high_count,
                    $checked_plugin_count > 0 ? 'Checked plugins: ' . (string) $checked_plugin_count : '',
                    $unresolved_plugin_count > 0 ? 'Unresolved plugins: ' . (string) $unresolved_plugin_count : '',
                    '' !== $vulnerability_evidence_state ? 'Evidence state: ' . ucfirst( str_replace( '_', ' ', $vulnerability_evidence_state ) ) : '',
                    '' !== $vulnerability_source_provider ? 'Source provider: ' . $vulnerability_source_provider : '',
                )
            ),
            'action' => 0 === $match_count
                ? (
                    ( 'evidence_limited' === $vulnerability_posture_value || ( '' !== $vulnerability_evidence_state && 'complete' !== $vulnerability_evidence_state ) )
                        ? 'Review the vulnerability drilldown and rerun live Security Scan after coverage limits are resolved.'
                        : 'No vulnerability remediation is currently required.'
                )
                : 'Review the vulnerability drilldown and update each affected component to its fixed version.',
        );

        $items[] = array(
            'label' => 'Reachability',
            'name'  => ucfirst( str_replace( '_', ' ', $reachability_posture ) ),
            'meta'  => 'HTTP ' . $reachability_status . ' in ' . $reachability_duration . ' ms.',
            'facts' => array_filter(
                array(
                    '' !== $reachability_failure ? 'Failure class: ' . $reachability_failure : '',
                    isset( $reachability_summary['tls_ok'] ) ? 'TLS OK: ' . ( ! empty( $reachability_summary['tls_ok'] ) ? 'Yes' : 'No' ) : '',
                    isset( $reachability_summary['transport_ok'] ) ? 'Transport OK: ' . ( ! empty( $reachability_summary['transport_ok'] ) ? 'Yes' : 'No' ) : '',
                )
            ),
            'action' => 'reachable' === $reachability_posture ? 'No reachability action is currently required.' : 'Resolve the reachability failure before treating this site as healthy.',
        );

        if ( $availability_attempts > 0 ) {
            $items[] = array(
                'label' => 'Availability',
                'name'  => (string) $availability_attempts . ' probe' . ( 1 === $availability_attempts ? '' : 's' ),
                'meta'  => 0 === $availability_failures ? 'No failures recorded.' : (string) $availability_failures . ' failure' . ( 1 === $availability_failures ? '' : 's' ) . ' recorded.',
                'facts' => array(
                    'Availability: ' . ( 'available' === $availability_posture ? 'OK' : ucfirst( str_replace( '_', ' ', $availability_posture ) ) ),
                    'Probes: ' . (string) $availability_attempts,
                    'Failures: ' . (string) $availability_failures,
                ),
            );
        }

        if ( 'pending' !== $performance_posture || '—' !== $performance_status || '—' !== $performance_total_duration ) {
            $items[] = array(
                'label' => 'Performance',
                'name'  => ucfirst( str_replace( '_', ' ', $performance_posture ) ),
                'meta'  => 'HTTP ' . $performance_status . ' in ' . $performance_total_duration . ' ms.',
                'facts' => array_filter(
                    array(
                        'Status code: ' . $performance_status,
                        'Total duration: ' . $performance_total_duration . ' ms',
                        '—' !== $performance_first_byte ? 'First byte: ' . $performance_first_byte . ' ms' : '',
                    )
                ),
                'action' => in_array( $performance_posture, array( 'degraded', 'poor', 'failed_probe' ), true )
                    ? 'Resolve the performance failure or degraded probe result before treating this site as healthy.'
                    : 'No performance action is currently required.',
            );
        }

        return $items;
    }

    private static function detail_surface_url( string $tab, string $detail_type ): string {
        $args = array(
            'opsgate_detail' => $detail_type,
        );

        if ( 'reports' === $tab ) {
            foreach ( array( 'source_job_id', 'view_kind', 'view_export_job_id', 'opsgate_export_started', 'opsgate_export_error' ) as $query_key ) {
                // phpcs:ignore WordPress.Security.NonceVerification.Recommended
                if ( isset( $_GET[ $query_key ] ) && '' !== (string) $_GET[ $query_key ] ) {
                    $args[ $query_key ] = sanitize_text_field( wp_unslash( $_GET[ $query_key ] ) );
                }
            }
        }

        return self::admin_tab_url( $tab, $args ) . '#opsgate-detail-' . rawurlencode( $detail_type );
    }

    private static function render_posture_detail_items_list( array $items, string $empty_message ): void {
        if ( empty( $items ) ) {
            echo '<p class="opsgate-posture-detail-empty">' . esc_html( $empty_message ) . '</p>';
            return;
        }

        echo '<div class="opsgate-posture-detail-list">';
        foreach ( $items as $item ) {
            if ( ! is_array( $item ) ) {
                continue;
            }

            echo '<article class="opsgate-posture-detail-item">';
            echo '<span class="opsgate-overview-eyebrow">' . esc_html( (string) ( $item['label'] ?? 'Item' ) ) . '</span>';
            echo '<div class="opsgate-pricing-hero-side-title">' . esc_html( (string) ( $item['name'] ?? 'Unnamed item' ) ) . '</div>';
            echo '<p>' . esc_html( (string) ( $item['meta'] ?? 'Detail unavailable.' ) ) . '</p>';

            $facts = isset( $item['facts'] ) && is_array( $item['facts'] ) ? array_values( array_filter( array_map( 'strval', $item['facts'] ) ) ) : array();
            if ( ! empty( $facts ) ) {
                echo '<ul class="opsgate-posture-detail-facts">';
                foreach ( $facts as $fact ) {
                    echo '<li>' . esc_html( $fact ) . '</li>';
                }
                echo '</ul>';
            }

            if ( ! empty( $item['reason'] ) ) {
                echo '<p class="opsgate-posture-detail-reason"><strong>Why:</strong> ' . esc_html( (string) $item['reason'] ) . '</p>';
            }

            if ( ! empty( $item['action'] ) ) {
                echo '<p class="opsgate-posture-detail-action"><strong>Recommended action:</strong> ' . esc_html( (string) $item['action'] ) . '</p>';
            }

            echo '</article>';
        }
        echo '</div>';
    }

    private static function render_triage_detail_items_list( array $items, string $empty_message ): void {
        if ( empty( $items ) ) {
            echo '<p class="opsgate-posture-detail-empty">' . esc_html( $empty_message ) . '</p>';
            return;
        }

        echo '<div class="opsgate-triage-detail-card-grid">';
        foreach ( $items as $item ) {
            if ( ! is_array( $item ) ) {
                continue;
            }

            $label                = isset( $item['label'] ) ? (string) $item['label'] : 'Item';
            $name                 = isset( $item['name'] ) ? (string) $item['name'] : 'Unnamed item';
            $meta                 = isset( $item['meta'] ) ? (string) $item['meta'] : 'Detail unavailable.';
            $reason               = isset( $item['reason'] ) ? trim( (string) $item['reason'] ) : '';
            $action               = isset( $item['action'] ) ? trim( (string) $item['action'] ) : '';
            $facts                = isset( $item['facts'] ) && is_array( $item['facts'] ) ? array_values( array_filter( array_map( 'strval', $item['facts'] ) ) ) : array();
            $security_update_badge = ! empty( $item['security_update_badge'] );

            echo '<article class="opsgate-triage-detail-card' . ( $security_update_badge ? ' opsgate-triage-detail-card-security-update' : '' ) . '">';
            echo '<div class="opsgate-triage-detail-card-eyebrow-row">';
            echo '<span class="opsgate-triage-eyebrow">' . esc_html( $label ) . '</span>';
            if ( $security_update_badge ) {
                echo '<span class="opsgate-triage-security-badge">Security update</span>';
            }
            echo '</div>';
            echo '<div class="opsgate-triage-detail-card-title">' . esc_html( $name ) . '</div>';
            echo '<p class="opsgate-triage-detail-card-copy">' . esc_html( $meta ) . '</p>';

            if ( ! empty( $facts ) ) {
                echo '<ul class="opsgate-triage-card-facts">';
                foreach ( array_slice( $facts, 0, 4 ) as $fact ) {
                    echo '<li>' . esc_html( $fact ) . '</li>';
                }
                echo '</ul>';
            }

            if ( '' !== $reason ) {
                echo '<p class="opsgate-triage-detail-card-note"><strong>Why</strong> ' . esc_html( $reason ) . '</p>';
            }

            if ( '' !== $action ) {
                echo '<p class="opsgate-triage-detail-card-note"><strong>Action</strong> ' . esc_html( $action ) . '</p>';
            }

            $controls = isset( $item['controls'] ) && is_array( $item['controls'] ) ? $item['controls'] : array();
            if ( ! empty( $controls ) ) {
                echo '<div class="opsgate-validation-remediation-actions">';
                foreach ( $controls as $control ) {
                    if ( ! is_array( $control ) ) {
                        continue;
                    }
                    $kind = isset( $control['kind'] ) ? (string) $control['kind'] : '';
                    $label = isset( $control['label'] ) ? (string) $control['label'] : 'Run action';
                    if ( 'apply' === $kind ) {
                        echo '<form method="post" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '" class="opsgate-validation-remediation-form">';
                        wp_nonce_field( 'opsgate_validation_remediation_apply', 'opsgate_validation_remediation_apply_nonce' );
                        echo '<input type="hidden" name="action" value="opsgate_validation_remediation_apply" />';
                        echo '<input type="hidden" name="source_job_id" value="' . esc_attr( (string) ( $control['source_job_id'] ?? '' ) ) . '" />';
                        echo '<input type="hidden" name="finding_code" value="' . esc_attr( (string) ( $control['finding_code'] ?? '' ) ) . '" />';
                        submit_button( $label, 'secondary', 'submit', false );
                        echo '</form>';
                    } elseif ( 'revert' === $kind ) {
                        echo '<form method="post" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '" class="opsgate-validation-remediation-form">';
                        wp_nonce_field( 'opsgate_validation_remediation_revert', 'opsgate_validation_remediation_revert_nonce' );
                        echo '<input type="hidden" name="action" value="opsgate_validation_remediation_revert" />';
                        echo '<input type="hidden" name="remediation_id" value="' . esc_attr( (string) ( $control['remediation_id'] ?? '' ) ) . '" />';
                        submit_button( $label, 'secondary', 'submit', false );
                        echo '</form>';
                    }
                }
                echo '</div>';
            }

            echo '</article>';
        }
        echo '</div>';
    }

    private static function render_posture_detail_module( string $tab, string $detail_type, string $title, array $items ): void {
        $detail_type = trim( $detail_type );
        $is_open = isset( $_GET['opsgate_detail'] ) && $detail_type === sanitize_text_field( wp_unslash( $_GET['opsgate_detail'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $card_class = 'opsgate-settings-module opsgate-posture-detail-module';
        if ( $is_open ) {
            $card_class .= ' is-open';
        }

        echo '<div id="opsgate-detail-' . esc_attr( $detail_type ) . '" class="' . esc_attr( $card_class ) . '">';
        echo '<div class="opsgate-settings-module-head">';
        echo '<div>';
        echo '<strong>' . esc_html( $title ) . '</strong>';
        echo '<p class="description">Recorded artifact items are active for this detail list.</p>';
        echo '</div>';
        echo '<a class="button button-secondary" href="' . esc_url( self::detail_surface_url( $tab, $detail_type ) ) . '" aria-expanded="' . esc_attr( $is_open ? 'true' : 'false' ) . '">' . esc_html( 'View ' . $title ) . '</a>';
        echo '</div>';

        echo '<div class="opsgate-posture-detail-body"' . ( $is_open ? '' : ' hidden="hidden"' ) . '>';
        self::render_posture_detail_items_list( $items, 'No ' . strtolower( $title ) . ' are listed for this state.' );
        echo '</div>';

        echo '</div>';
    }

    private static function report_item_sort_timestamp( array $item ): int {
        $verified_at = isset( $item['verified_at_utc'] ) ? strtotime( (string) $item['verified_at_utc'] ) : 0;
        if ( $verified_at > 0 ) {
            return $verified_at;
        }

        return isset( $item['created_at_utc'] ) ? (int) strtotime( (string) $item['created_at_utc'] ) : 0;
    }

    private static function report_item_verification_priority( array $item ): int {
        $signature_state = strtolower( trim( (string) ( $item['signature_state'] ?? '' ) ) );
        $verification_status = strtolower( trim( (string) ( $item['verification_status'] ?? '' ) ) );
        $verification_state = strtolower( trim( (string) ( $item['verification_state'] ?? '' ) ) );

        if ( 'verified' === $signature_state || 'verified' === $verification_status || 'verified' === $verification_state ) {
            return 4;
        }
        if ( 'signed' === $signature_state ) {
            return 3;
        }
        if ( 'failed' === $signature_state || 'failed' === $verification_status || 'failed' === $verification_state ) {
            return 1;
        }

        return 2;
    }

    private static function best_report_verification_item( array $items ): array {
        $best = array();
        $best_priority = -1;
        $best_timestamp = -1;

        foreach ( $items as $item ) {
            if ( ! is_array( $item ) || self::item_is_proof( $item ) ) {
                continue;
            }

            $priority = self::report_item_verification_priority( $item );
            $timestamp = self::report_item_sort_timestamp( $item );
            if ( $priority > $best_priority || ( $priority === $best_priority && $timestamp > $best_timestamp ) ) {
                $best = $item;
                $best_priority = $priority;
                $best_timestamp = $timestamp;
            }
        }

        return $best;
    }

    private static function current_package_entry(): array {
        $package = self::current_package_snapshot();
        return isset( $package['current'] ) && is_array( $package['current'] ) ? $package['current'] : array();
    }

    private static function package_comparison_entries(): array {
        $package = self::current_package_snapshot();
        return isset( $package['comparison'] ) && is_array( $package['comparison'] ) ? array_values( $package['comparison'] ) : array();
    }

    private static function package_channel_families(): array {
        $package = self::current_package_snapshot();
        return isset( $package['channel_families'] ) && is_array( $package['channel_families'] ) ? array_values( $package['channel_families'] ) : array();
    }

    private static function package_evidence_governance(): array {
        $package = self::current_package_snapshot();
        return isset( $package['evidence_governance'] ) && is_array( $package['evidence_governance'] ) ? $package['evidence_governance'] : array();
    }

    private static function hybrid_product_snapshot(): array {
        $snapshot = self::get_entitlement_plan_snapshot();
        return isset( $snapshot['hybrid'] ) && is_array( $snapshot['hybrid'] ) ? $snapshot['hybrid'] : array();
    }

    private static function package_visibility_state_label( $state ) {
        $state = strtolower( trim( (string) $state ) );
        if ( 'current_mode' === $state ) {
            return 'Current mode';
        }
        if ( 'available_on_package' === $state ) {
            return 'Available on package';
        }
        if ( 'configured_while_disabled' === $state ) {
            return 'Saved while disabled';
        }
        if ( 'live_now' === $state ) {
            return 'Live now';
        }
        if ( 'visible_locked' === $state ) {
            return 'Locked until upgrade';
        }
        if ( 'planned_direction' === $state ) {
            return 'Planned direction';
        }
        if ( 'integration_ready' === $state || 'ready_to_connect' === $state ) {
            return 'Integration-ready';
        }
        return 'Hidden';
    }

    private static function current_package_display_name(): string {
        $current_package = self::current_package_entry();
        if ( isset( $current_package['display_name'] ) && '' !== trim( (string) $current_package['display_name'] ) ) {
            return (string) $current_package['display_name'];
        }

        $snapshot = self::get_entitlement_plan_snapshot();
        $plan = self::entitlement_plan_key_from_snapshot( $snapshot );
        return ucfirst( trim( $plan ) );
    }

    private static function package_channel_family_groups(): array {
        $groups = array(
            'live_now' => array(),
            'visible_locked' => array(),
            'planned_direction' => array(),
            'integration_ready' => array(),
            'hidden' => array(),
        );

        foreach ( self::package_channel_families() as $family ) {
            if ( ! is_array( $family ) ) {
                continue;
            }
            $state = isset( $family['state'] ) ? strtolower( trim( (string) $family['state'] ) ) : 'hidden';
            if ( ! isset( $groups[ $state ] ) ) {
                $state = 'hidden';
            }
            $groups[ $state ][] = $family;
        }

        return $groups;
    }

    private static function package_capability_items( string $bucket ): array {
        $current_package = self::current_package_entry();
        if ( isset( $current_package[ $bucket ] ) && is_array( $current_package[ $bucket ] ) ) {
            return array_values( $current_package[ $bucket ] );
        }
        return array();
    }

    private static function schedule_mode_story( array $allowed_modes, string $selected_mode = 'off', bool $scheduling_enabled = false ): array {
        $current_package_name = self::current_package_display_name();
        $stories = array();
        $all_modes = array(
            'daily' => array(
                'label' => 'Daily',
                'meaning' => 'Best for routine monitoring and fast recurring security scans.',
            ),
            'weekly' => array(
                'label' => 'Weekly',
                'meaning' => 'Best for regular security review.',
            ),
            'monthly' => array(
                'label' => 'Monthly',
                'meaning' => 'Best for lower-frequency security monitoring.',
            ),
        );

        foreach ( $all_modes as $mode_key => $meta ) {
            $is_allowed = in_array( $mode_key, $allowed_modes, true );
            $state      = 'visible_locked';
            $summary    = sprintf( '%s plan does not include %s scheduling. Upgrade to unlock.', $current_package_name, strtolower( $meta['label'] ) );

            if ( $is_allowed ) {
                if ( $scheduling_enabled && $mode_key === $selected_mode ) {
                    $state   = 'current_mode';
                    $summary = 'Current recurring cadence for this site.';
                } elseif ( ! $scheduling_enabled && $mode_key === $selected_mode && 'off' !== $selected_mode ) {
                    $state   = 'configured_while_disabled';
                    $summary = 'Saved cadence remains available here, but automated checks are currently disabled.';
                } else {
                    $state   = 'available_on_package';
                    $summary = $meta['meaning'];
                }
            }
            $stories[] = array(
                'key' => $mode_key,
                'label' => $meta['label'],
                'state' => $state,
                'summary' => $summary,
            );
        }

        return $stories;
    }

    private static function canonical_report_trust_badge( array $item ): array {
        $signature_state = strtolower( trim( (string) ( $item['signature_state'] ?? '' ) ) );
        $verification_status = strtolower( trim( (string) ( $item['verification_status'] ?? '' ) ) );
        $visibility_state = strtolower( trim( (string) ( $item['visibility_state'] ?? '' ) ) );

        if ( 'verified' === $signature_state || 'verified' === $verification_status ) {
            return array(
                'tone' => 'good',
                'label' => 'Verified export',
            );
        }

        if ( 'signed' === $signature_state ) {
            return array(
                'tone' => 'info',
                'label' => 'Signed export',
            );
        }

        if ( 'failed' === $signature_state || 'failed' === $verification_status ) {
            return array(
                'tone' => 'bad',
                'label' => 'Needs trust review',
            );
        }

        if ( 'tombstoned' === $visibility_state ) {
            return array(
                'tone' => 'warn',
                'label' => 'Metadata retained',
            );
        }

        return array(
            'tone' => 'neutral',
            'label' => 'Supported export',
        );
    }

    private static function canonical_report_governance_badges( array $item ): array {
        $badges = array();
        $retention_policy = trim( (string) ( $item['retention_policy_key'] ?? '' ) );
        $visibility_state = strtolower( trim( (string) ( $item['visibility_state'] ?? '' ) ) );
        $redaction_state = strtolower( trim( (string) ( $item['redaction_state'] ?? '' ) ) );

        if ( '' !== $retention_policy ) {
            $badges[] = array(
                'tone' => 'info',
                'label' => 'Retention: ' . $retention_policy,
            );
        }

        if ( 'redacted' === $redaction_state ) {
            $badges[] = array(
                'tone' => 'warn',
                'label' => 'Privacy-aware handling',
            );
        }

        if ( 'tombstoned' === $visibility_state ) {
            $badges[] = array(
                'tone' => 'neutral',
                'label' => 'Lifecycle retained',
            );
        } else {
            $badges[] = array(
                'tone' => 'neutral',
                'label' => 'Controlled evidence lifecycle',
            );
        }

        return $badges;
    }

    private static function canonical_report_supports_inline_view( string $kind ): bool {
        return in_array( trim( $kind ), array( 'report_html', 'report_pdf', 'report_xlsx', 'csv', 'export_csv', 'triage_csv' ), true );
    }

    private static function canonical_customer_explanation_cards(): array {
        return array(
            array(
                'title' => 'Posture states',
                'copy'  => 'Healthy means risk stayed within target. Needs attention means warning signals were recorded. Action required means the run captured urgent pressure that needs follow-up.',
            ),
            array(
                'title' => 'Runs and reports',
                'copy'  => 'A run is the recorded assessment. A report is a packaged view of that run. Reports never replace the canonical run record behind the API.',
            ),
            array(
                'title' => 'Evidence',
                'copy'  => 'Evidence is the recorded inventory, checks, artifacts, and verification metadata tied to one canonical site and one run reference.',
            ),
            array(
                'title' => 'Connection states',
                'copy'  => 'External-only sites use public checks only. Connected sites use authenticated connector truth. Pairing pending, credential invalid, and disconnected states tell you when connected triage is not ready.',
            ),
            array(
                'title' => 'Alerts and destinations',
                'copy'  => 'Alerts are delivery records linked to a site and run. Destinations and routing rules decide where messages go, but they do not become the source of truth.',
            ),
            array(
                'title' => 'Routing and support detail',
                'copy'  => 'Support evidence packages keep JSON, datasets, and support references available for export or operator review without taking over the primary customer view.',
            ),
        );
    }

    private static function canonical_report_view_action_label( string $kind ): string {
        return 'View';
    }

    private static function canonical_report_view_unavailable_copy( string $kind, string $state ): string {
        $state = strtoupper( trim( $state ) );
        if ( 'FAILED' === $state ) {
            return 'View unavailable';
        }
        return 'Generate first to view';
    }

    private static function canonical_export_item_lookup( string $export_job_id ): array {
        $export_job_id = trim( $export_job_id );
        if ( '' === $export_job_id ) {
            return array();
        }

        $history = self::canonical_exports_history( 120 );
        $items = isset( $history['items'] ) && is_array( $history['items'] ) ? $history['items'] : array();
        foreach ( $items as $item ) {
            if ( ! is_array( $item ) ) {
                continue;
            }

            $candidate = isset( $item['export_job_id'] ) ? trim( (string) $item['export_job_id'] ) : '';
            if ( '' !== $candidate && $candidate === $export_job_id ) {
                return $item;
            }
        }

        return array();
    }

    private static function canonical_latest_completed_export_for_source_kind( string $source_job_id, string $kind ): array {
        $source_job_id = trim( $source_job_id );
        $kind = trim( $kind );
        if ( '' === $source_job_id || '' === $kind ) {
            return array();
        }

        $history = self::canonical_exports_history( 120 );
        $items = isset( $history['items'] ) && is_array( $history['items'] ) ? $history['items'] : array();
        foreach ( $items as $item ) {
            if ( ! is_array( $item ) ) {
                continue;
            }

            $item_kind = isset( $item['kind'] ) ? trim( (string) $item['kind'] ) : '';
            $item_source_job_id = isset( $item['source_job_id'] ) ? trim( (string) $item['source_job_id'] ) : '';
            $item_state = isset( $item['state'] ) ? strtoupper( trim( (string) $item['state'] ) ) : '';
            if ( $item_kind === $kind && $item_source_job_id === $source_job_id && 'COMPLETED' === $item_state && ! self::item_is_proof( $item ) ) {
                return $item;
            }
        }

        return array();
    }

    private static function xlsx_preview_column_index( string $cell_ref ): int {
        $letters = preg_replace( '/[^A-Z]/', '', strtoupper( $cell_ref ) );
        if ( '' === $letters ) {
            return 0;
        }

        $index = 0;
        foreach ( str_split( $letters ) as $letter ) {
            $index = ( $index * 26 ) + ( ord( $letter ) - 64 );
        }

        return max( 0, $index - 1 );
    }

    /**
     * @param array<int,string> $shared_strings
     */
    private static function xlsx_preview_cell_value( SimpleXMLElement $cell, string $namespace, array $shared_strings = array() ): string {
        $cell->registerXPathNamespace( 'main', $namespace );
        $type = isset( $cell['t'] ) ? (string) $cell['t'] : '';
        if ( 'inlineStr' === $type ) {
            $parts = $cell->xpath( './/main:t' );
            if ( empty( $parts ) && isset( $cell->is->t ) ) {
                return trim( (string) $cell->is->t );
            }

            $value = '';
            foreach ( (array) $parts as $part ) {
                $value .= (string) $part;
            }
            return trim( $value );
        }

        if ( 's' === $type && isset( $cell->v ) ) {
            $shared_string_index = (int) trim( (string) $cell->v );
            return isset( $shared_strings[ $shared_string_index ] ) ? trim( (string) $shared_strings[ $shared_string_index ] ) : '';
        }

        if ( isset( $cell->v ) ) {
            return trim( (string) $cell->v );
        }

        return trim( (string) $cell );
    }

    /**
     * @param array<int,string> $shared_strings
     */
    private static function xlsx_preview_rows_from_xml( string $sheet_xml, array $shared_strings = array() ): array {
        $sheet = @simplexml_load_string( $sheet_xml );
        if ( ! ( $sheet instanceof SimpleXMLElement ) ) {
            return array();
        }

        $namespaces = $sheet->getNamespaces( true );
        $main_namespace = isset( $namespaces[''] ) ? (string) $namespaces[''] : 'http://schemas.openxmlformats.org/spreadsheetml/2006/main';
        $sheet->registerXPathNamespace( 'main', $main_namespace );

        $rows = array();
        $row_nodes = $sheet->xpath( '//main:sheetData/main:row' );
        if ( ! is_array( $row_nodes ) ) {
            return array();
        }

        foreach ( $row_nodes as $row_node ) {
            $indexed = array();
            $row_node->registerXPathNamespace( 'main', $main_namespace );
            $cells = $row_node->xpath( './main:c' );
            if ( ! is_array( $cells ) ) {
                continue;
            }

            foreach ( $cells as $cell ) {
                if ( ! ( $cell instanceof SimpleXMLElement ) ) {
                    continue;
                }

                $cell_ref = isset( $cell['r'] ) ? (string) $cell['r'] : '';
                $index = self::xlsx_preview_column_index( $cell_ref );
                $indexed[ $index ] = self::xlsx_preview_cell_value( $cell, $main_namespace, $shared_strings );
            }

            if ( empty( $indexed ) ) {
                continue;
            }

            ksort( $indexed );
            $max_index = (int) max( array_keys( $indexed ) );
            $row = array_fill( 0, $max_index + 1, '' );
            foreach ( $indexed as $column_index => $value ) {
                $row[ $column_index ] = $value;
            }
            $rows[] = $row;
        }

        return $rows;
    }

    /**
     * @return array<int,string>
     */
    private static function xlsx_preview_shared_strings( ZipArchive $zip ): array {
        $shared_xml = (string) $zip->getFromName( 'xl/sharedStrings.xml' );
        if ( '' === $shared_xml ) {
            return array();
        }

        $shared = @simplexml_load_string( $shared_xml );
        if ( ! ( $shared instanceof SimpleXMLElement ) ) {
            return array();
        }

        $namespaces = $shared->getNamespaces( true );
        $main_namespace = isset( $namespaces[''] ) ? (string) $namespaces[''] : 'http://schemas.openxmlformats.org/spreadsheetml/2006/main';
        $shared->registerXPathNamespace( 'main', $main_namespace );

        $items = array();
        $nodes = $shared->xpath( '//main:si' );
        if ( ! is_array( $nodes ) ) {
            return array();
        }

        foreach ( $nodes as $node ) {
            if ( ! ( $node instanceof SimpleXMLElement ) ) {
                continue;
            }

            $parts = $node->xpath( './/main:t' );
            if ( ! is_array( $parts ) || empty( $parts ) ) {
                $items[] = trim( (string) $node );
                continue;
            }

            $value = '';
            foreach ( $parts as $part ) {
                $value .= (string) $part;
            }
            $items[] = trim( $value );
        }

        return $items;
    }

    private static function xlsx_preview_document( string $xlsx_bytes, string $report_title ): string {
        if ( '' === $xlsx_bytes || ! class_exists( 'ZipArchive', false ) ) {
            return '';
        }

        $temp_file = function_exists( 'wp_tempnam' )
            ? wp_tempnam( 'opsgate-xlsx-preview.xlsx' )
            : tempnam( sys_get_temp_dir(), 'opsgate-xlsx-preview-' );
        if ( ! is_string( $temp_file ) || '' === $temp_file ) {
            return '';
        }

        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_write_file_put_contents
        if ( false === @file_put_contents( $temp_file, $xlsx_bytes ) ) {
            @unlink( $temp_file );
            return '';
        }

        $zip = new ZipArchive();
        $opened = $zip->open( $temp_file );
        if ( true !== $opened ) {
            @unlink( $temp_file );
            return '';
        }

        $sheet_paths = array();
        $workbook_xml = (string) $zip->getFromName( 'xl/workbook.xml' );
        $rels_xml = (string) $zip->getFromName( 'xl/_rels/workbook.xml.rels' );
        $shared_strings = self::xlsx_preview_shared_strings( $zip );
        if ( '' !== $workbook_xml && '' !== $rels_xml ) {
            $workbook = @simplexml_load_string( $workbook_xml );
            $rels = @simplexml_load_string( $rels_xml );
            if ( $workbook instanceof SimpleXMLElement && $rels instanceof SimpleXMLElement ) {
                $rel_map = array();
                $rels_namespaces = $rels->getNamespaces( true );
                $rels_namespace = isset( $rels_namespaces[''] ) ? (string) $rels_namespaces[''] : 'http://schemas.openxmlformats.org/package/2006/relationships';
                $rels->registerXPathNamespace( 'rel', $rels_namespace );
                $relationship_nodes = $rels->xpath( '//rel:Relationship' );
                foreach ( is_array( $relationship_nodes ) ? $relationship_nodes : array() as $relationship ) {
                    $attrs = $relationship->attributes();
                    $rel_id = isset( $attrs['Id'] ) ? (string) $attrs['Id'] : '';
                    $target = isset( $attrs['Target'] ) ? (string) $attrs['Target'] : '';
                    if ( '' !== $rel_id && '' !== $target ) {
                        $rel_map[ $rel_id ] = 0 === strpos( $target, 'xl/' ) ? $target : 'xl/' . ltrim( $target, '/' );
                    }
                }

                $namespaces = $workbook->getNamespaces( true );
                $relationship_namespace = isset( $namespaces['r'] ) ? (string) $namespaces['r'] : 'http://schemas.openxmlformats.org/officeDocument/2006/relationships';
                $workbook->registerXPathNamespace( 'main', isset( $namespaces[''] ) ? (string) $namespaces[''] : 'http://schemas.openxmlformats.org/spreadsheetml/2006/main' );
                $sheet_nodes = $workbook->xpath( '//main:sheets/main:sheet' );
                if ( is_array( $sheet_nodes ) ) {
                    foreach ( $sheet_nodes as $sheet ) {
                        $attrs = $sheet->attributes();
                        $rel_attrs = $sheet->attributes( 'r', true );
                        $name = isset( $attrs['name'] ) ? (string) $attrs['name'] : 'Worksheet';
                        $rel_id = isset( $rel_attrs['id'] ) ? (string) $rel_attrs['id'] : '';
                        if ( '' !== $rel_id && isset( $rel_map[ $rel_id ] ) ) {
                            $sheet_paths[ $name ] = $rel_map[ $rel_id ];
                        }
                    }
                }
            }
        }

        if ( empty( $sheet_paths ) ) {
            for ( $index = 1; $index <= 6; $index++ ) {
                $path = 'xl/worksheets/sheet' . $index . '.xml';
                if ( false !== $zip->locateName( $path ) ) {
                    $sheet_paths[ 'Sheet ' . $index ] = $path;
                }
            }
        }

        $sheets = array();
        foreach ( $sheet_paths as $sheet_name => $sheet_path ) {
            $sheet_xml = $zip->getFromName( $sheet_path );
            if ( ! is_string( $sheet_xml ) || '' === $sheet_xml ) {
                continue;
            }
            $sheets[ $sheet_name ] = self::xlsx_preview_rows_from_xml( $sheet_xml, $shared_strings );
        }

        $zip->close();
        @unlink( $temp_file );

        if ( empty( $sheets ) ) {
            return '';
        }

        ob_start();
        ?>
<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title><?php echo esc_html( $report_title ); ?> Workbook Preview</title>
    <style>
        body{margin:0;padding:32px;font:15px/1.6 "Segoe UI","Helvetica Neue",Arial,sans-serif;background:#eef4fb;color:#12304a;}
        main{max-width:1180px;margin:0 auto;}
        h1{margin:0 0 8px;font-size:30px;color:#0d2940;}
        h2{margin:26px 0 12px;font-size:22px;color:#153b61;}
        p{margin:0 0 14px;}
        section{margin-top:22px;padding:22px;border:1px solid #d7e2ee;border-radius:18px;background:#fff;box-shadow:0 10px 24px rgba(16,39,67,.06);}
        table{width:100%;border-collapse:collapse;background:#fff;}
        th,td{text-align:left;padding:10px 12px;border-bottom:1px solid #e3ebf3;vertical-align:top;}
        th{background:#f7fbff;color:#12304a;font-size:12px;letter-spacing:.08em;text-transform:uppercase;}
        tr:last-child td{border-bottom:none;}
    </style>
</head>
<body>
<main>
    <h1><?php echo esc_html( $report_title ); ?></h1>
    <p>Security findings, posture scores, and recommendations — each worksheet below corresponds to a tab in the downloaded Excel file.</p>
    <?php foreach ( $sheets as $sheet_name => $sheet_rows ) : ?>
        <section>
            <h2><?php echo esc_html( (string) $sheet_name ); ?></h2>
            <?php if ( empty( $sheet_rows ) ) : ?>
                <p>No worksheet rows were recorded for this sheet.</p>
            <?php else : ?>
                <?php $sheet_header = array_shift( $sheet_rows ); ?>
                <table>
                    <thead>
                        <tr>
                            <?php foreach ( $sheet_header as $sheet_header_cell ) : ?>
                                <th><?php echo esc_html( (string) $sheet_header_cell ); ?></th>
                            <?php endforeach; ?>
                        </tr>
                    </thead>
                    <tbody>
                        <?php foreach ( $sheet_rows as $sheet_row ) : ?>
                            <tr>
                                <?php foreach ( $sheet_header as $sheet_index => $unused_sheet_header ) : ?>
                                    <td><?php echo esc_html( isset( $sheet_row[ $sheet_index ] ) ? (string) $sheet_row[ $sheet_index ] : '' ); ?></td>
                                <?php endforeach; ?>
                            </tr>
                        <?php endforeach; ?>
                    </tbody>
                </table>
            <?php endif; ?>
        </section>
    <?php endforeach; ?>
</main>
</body>
</html>
        <?php

        return (string) ob_get_clean();
    }

    private static function render_client_pdf_from_html( string $html, string $title ): string {
        $html = trim( $html );
        if ( '' === $html ) {
            return '';
        }

        self::tcpdf_require();
        if ( ! class_exists( 'TCPDF', false ) ) {
            return '';
        }

        $pdf = new TCPDF( 'P', 'mm', 'A4', true, 'UTF-8', false );
        $pdf->SetCreator( 'OpsGate' );
        $pdf->SetAuthor( 'OpsGate' );
        $pdf->SetTitle( $title );
        $pdf->setPrintHeader( false );
        $pdf->setPrintFooter( false );
        $pdf->SetMargins( 12, 12, 12 );
        $pdf->SetAutoPageBreak( true, 14 );
        $pdf->AddPage();
        $pdf->SetFont( 'helvetica', '', 10 );

        $sanitized_html = preg_replace( '#<script\b[^>]*>.*?</script>#is', '', $html );
        $sanitized_html = is_string( $sanitized_html ) ? $sanitized_html : $html;
        $sanitized_html = preg_replace( '#<(iframe|object|embed)[^>]*>.*?</\\1>#is', '', $sanitized_html );
        $sanitized_html = is_string( $sanitized_html ) ? $sanitized_html : $html;
        $sanitized_html = preg_replace( '#<(link|meta)[^>]*/?\s*>#is', '', $sanitized_html );
        $sanitized_html = is_string( $sanitized_html ) ? $sanitized_html : $html;
        $wrapped_html = '<style>
            body{font-family:helvetica,arial,sans-serif;font-size:10pt;color:#12304a;background:#fff;margin:0;padding:0;}
            .shell,main,article,.report,.report-body,.report-content{padding:10pt;}
            h1{font-size:20pt;color:#0d2940;margin:0 0 6pt;font-weight:900;}
            h2{font-size:14pt;color:#153b61;margin:12pt 0 5pt;font-weight:700;border-bottom:0.5pt solid #d7e2ee;padding-bottom:2pt;}
            h3{font-size:11pt;color:#1a4b7a;margin:8pt 0 3pt;font-weight:700;}
            h4,h5,h6{font-size:9pt;color:#1a4b7a;margin:5pt 0 2pt;font-weight:700;}
            p{margin:0 0 5pt;line-height:1.45;}
            .summary-chart,.report-chart,.metrics,svg,canvas{display:none;}
            table{border-collapse:collapse;width:100%;margin-bottom:8pt;}
            th,td{text-align:left;border:0.5pt solid #d7e2ee;padding:3pt 5pt;vertical-align:top;font-size:9pt;}
            th{background-color:#eef6ff;color:#0d2940;font-weight:700;font-size:8pt;text-transform:uppercase;letter-spacing:0.03em;}
            tr:nth-child(even) td{background-color:#f8fbff;}
            .badge,.chip,.tag,.label{display:inline;padding:1pt 3pt;border:0.5pt solid #d0e4f7;color:#1a4b7a;font-size:7pt;}
            .good,.status-good,.status-ok,.grade-a,.grade-b,.pass{color:#15803d !important;}
            .warn,.status-warn,.grade-c,.warning{color:#92400e !important;}
            .bad,.status-bad,.critical,.fail,.grade-d,.grade-f{color:#b91c1c !important;}
            .score,.posture-score,.security-score{font-size:22pt;font-weight:900;color:#0d2940;}
            [class*="job-id"],[class*="run-id"],[class*="evidence-id"],[class*="export-id"],
            [class*="job_id"],[class*="run_id"],[class*="evidence_id"],[class*="export_id"]{font-size:6pt;color:#b0b8c4;word-break:break-all;}
            .hero-meta,.hero-meta-card,.hero-meta-label,.hero-meta-value{display:block;font-size:7pt;color:#6b7280;margin-bottom:1pt;max-width:40ch;overflow:hidden;}
            .hero{background:#eef6ff;padding:8pt;margin-bottom:8pt;border:0.5pt solid #d7e2ee;}
            .meta,.report-meta,.reference-block{background:#f8fbff;border:0.5pt solid #e3ebf3;padding:6pt;margin-top:8pt;font-size:8pt;color:#6b7280;}
            .meta table th,.report-meta table th{font-size:7pt;color:#6b7280;font-weight:600;background:none;text-transform:none;letter-spacing:0;border:none;}
            .meta table td,.report-meta table td{font-size:7pt;color:#4b6478;word-break:break-all;border:none;}
            code,pre{font-size:7pt;background:#f3f8ff;padding:1pt 2pt;}
            section,.report-section,.card,.widget{margin-bottom:8pt;padding:7pt;border:0.5pt solid #d7e2ee;}
            .executive-summary,.key-findings,.recommendations{padding:7pt;margin-bottom:7pt;border-left:2pt solid #2563eb;}
            .key-findings{border-left-color:#f59e0b;}
            .recommendations{border-left-color:#10b981;}
        </style>' . $sanitized_html;
        $pdf->writeHTML( $wrapped_html, true, false, true, false, '' );

        $binary = $pdf->Output( '', 'S' );
        return is_string( $binary ) ? $binary : '';
    }

    private static function client_column_label( string $raw ): string {
        $map = array(
            'section'          => 'Section',
            'finding'          => 'Finding',
            'status'           => 'Status',
            'severity'         => 'Severity',
            'recommendation'   => 'Recommendation',
            'evidence'         => 'Evidence Summary',
            'evidence_summary' => 'Evidence Summary',
            'report_date'      => 'Report Date',
            'date'             => 'Report Date',
            'site'             => 'Site',
            'site_name'        => 'Site',
            'site_url'         => 'Site URL',
            'value'            => 'Value',
            'detail'           => 'Detail',
            'score'            => 'Score',
            'grade'            => 'Grade',
            'category'         => 'Category',
            'type'             => 'Type',
            'component'        => 'Component',
            'run_id'           => 'Run Reference',
            'job_id'           => 'Run Reference',
            'export_job_id'    => 'Export Reference',
        );
        $key = strtolower( trim( (string) $raw ) );
        $key = (string) preg_replace( '/[^a-z0-9_]/', '_', $key );
        return $map[ $key ] ?? ucwords( str_replace( '_', ' ', $key ) );
    }

    private static function render_client_xlsx_from_bytes( string $xlsx_bytes ): string {
        if ( '' === $xlsx_bytes || ! class_exists( 'ZipArchive', false ) ) {
            return $xlsx_bytes;
        }

        $temp_in = function_exists( 'wp_tempnam' )
            ? wp_tempnam( 'opsgate-xlsx-in.xlsx' )
            : tempnam( sys_get_temp_dir(), 'opsgate-xlsx-in-' );
        if ( ! is_string( $temp_in ) || '' === $temp_in ) {
            return $xlsx_bytes;
        }

        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_write_file_put_contents
        if ( false === @file_put_contents( $temp_in, $xlsx_bytes ) ) {
            @unlink( $temp_in );
            return $xlsx_bytes;
        }

        $zip_in = new ZipArchive();
        if ( true !== $zip_in->open( $temp_in ) ) {
            @unlink( $temp_in );
            return $xlsx_bytes;
        }

        $shared_strings = self::xlsx_preview_shared_strings( $zip_in );

        $workbook_xml = (string) $zip_in->getFromName( 'xl/workbook.xml' );
        $rels_xml     = (string) $zip_in->getFromName( 'xl/_rels/workbook.xml.rels' );
        $sheet_paths  = array();
        if ( '' !== $workbook_xml && '' !== $rels_xml ) {
            $workbook = @simplexml_load_string( $workbook_xml );
            $rels     = @simplexml_load_string( $rels_xml );
            if ( $workbook instanceof SimpleXMLElement && $rels instanceof SimpleXMLElement ) {
                $rel_map   = array();
                $rel_nodes = $rels->xpath( '//*[local-name()="Relationship"]' );
                foreach ( is_array( $rel_nodes ) ? $rel_nodes : array() as $rel ) {
                    $attrs  = $rel->attributes();
                    $rel_id = isset( $attrs['Id'] ) ? (string) $attrs['Id'] : '';
                    $target = isset( $attrs['Target'] ) ? (string) $attrs['Target'] : '';
                    if ( '' !== $rel_id && '' !== $target ) {
                        $rel_map[ $rel_id ] = 0 === strpos( $target, 'xl/' ) ? $target : 'xl/' . ltrim( $target, '/' );
                    }
                }
                $sheet_nodes = $workbook->xpath( '//*[local-name()="sheet"]' );
                foreach ( is_array( $sheet_nodes ) ? $sheet_nodes : array() as $sn ) {
                    $attrs   = $sn->attributes();
                    $r_attrs = $sn->attributes( 'r', true );
                    $name    = isset( $attrs['name'] ) ? (string) $attrs['name'] : 'Report';
                    $rel_id  = isset( $r_attrs['id'] ) ? (string) $r_attrs['id'] : '';
                    if ( '' !== $rel_id && isset( $rel_map[ $rel_id ] ) ) {
                        $sheet_paths[ $name ] = $rel_map[ $rel_id ];
                    }
                }
            }
        }
        if ( empty( $sheet_paths ) ) {
            for ( $si = 1; $si <= 6; $si++ ) {
                $sp = 'xl/worksheets/sheet' . $si . '.xml';
                if ( false !== $zip_in->locateName( $sp ) ) {
                    $sheet_paths[ 'Security Report' ] = $sp;
                    break;
                }
            }
        }

        $all_data = array();
        foreach ( $sheet_paths as $sheet_name => $sheet_path ) {
            $xml = $zip_in->getFromName( $sheet_path );
            if ( ! is_string( $xml ) || '' === $xml ) {
                continue;
            }
            $rows = self::xlsx_preview_rows_from_xml( $xml, $shared_strings );
            if ( ! empty( $rows ) ) {
                $all_data[ $sheet_name ] = $rows;
            }
        }
        $zip_in->close();
        @unlink( $temp_in );

        if ( empty( $all_data ) ) {
            return $xlsx_bytes;
        }

        $id_columns = array( 'run reference', 'export reference', 'run_id', 'job_id', 'export_job_id', 'run id', 'export id' );

        $rebuilt_sheets = array();
        foreach ( $all_data as $sheet_name => $rows ) {
            if ( empty( $rows ) ) {
                continue;
            }
            $raw_header = array_shift( $rows );
            $mapped_header = array_map( array( 'self', 'client_column_label' ), is_array( $raw_header ) ? $raw_header : array() );

            $primary_indices = array();
            $id_indices      = array();
            foreach ( $mapped_header as $ci => $label ) {
                $lc = strtolower( $label );
                $is_id = false;
                foreach ( $id_columns as $id_col ) {
                    if ( false !== strpos( $lc, $id_col ) ) {
                        $is_id = true;
                        break;
                    }
                }
                if ( $is_id ) {
                    $id_indices[] = $ci;
                } else {
                    $primary_indices[] = $ci;
                }
            }

            $ordered_indices  = array_merge( $primary_indices, $id_indices );
            $ordered_header   = array_map( static function ( $i ) use ( $mapped_header ) { return $mapped_header[ $i ] ?? ''; }, $ordered_indices );
            $sheet_rows_out   = array( $ordered_header );
            foreach ( $rows as $row ) {
                $ordered_row = array_map( static function ( $i ) use ( $row ) { return isset( $row[ $i ] ) ? (string) $row[ $i ] : ''; }, $ordered_indices );
                $sheet_rows_out[] = $ordered_row;
            }

            $human_name = $sheet_name;
            if ( preg_match( '/^sheet\s*\d+$/i', trim( $sheet_name ) ) ) {
                $human_name = 'Security Report';
            }
            $rebuilt_sheets[ $human_name ] = $sheet_rows_out;
        }

        if ( empty( $rebuilt_sheets ) ) {
            return $xlsx_bytes;
        }

        $styles_xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
            . '<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">'
            . '<fonts count="2">'
            . '<font><sz val="11"/><name val="Calibri"/></font>'
            . '<font><b/><sz val="11"/><color rgb="FFFFFFFF"/><name val="Calibri"/></font>'
            . '</fonts>'
            . '<fills count="3">'
            . '<fill><patternFill patternType="none"/></fill>'
            . '<fill><patternFill patternType="gray125"/></fill>'
            . '<fill><patternFill patternType="solid"><fgColor rgb="FF0D2940"/></patternFill></fill>'
            . '</fills>'
            . '<borders count="1"><border><left/><right/><top/><bottom/><diagonal/></border></borders>'
            . '<cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs>'
            . '<cellXfs count="2">'
            . '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0"/>'
            . '<xf numFmtId="0" fontId="1" fillId="2" borderId="0" xfId="0" applyFont="1" applyFill="1"/>'
            . '</cellXfs>'
            . '</styleSheet>';

        $sheet_names = array_keys( $rebuilt_sheets );
        $sheet_xml_blocks = array();
        $workbook_sheets_xml = '';
        $workbook_rels_xml   = '<Relationship Id="rIdStyles" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>';
        $content_overrides   = '<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>';
        $rid = 1;
        foreach ( $rebuilt_sheets as $sname => $srows ) {
            $sheet_xml_inner = '';
            $row_idx = 1;
            foreach ( $srows as $row ) {
                $is_header = ( 1 === $row_idx );
                $style_idx = $is_header ? '1' : '0';
                $sheet_xml_inner .= '<row r="' . $row_idx . '">';
                $col_idx = 1;
                foreach ( $row as $cell ) {
                    $col_letter = self::xlsx_col_letter( $col_idx );
                    $cell_ref   = $col_letter . $row_idx;
                    $cell_val   = htmlspecialchars( (string) $cell, ENT_QUOTES | ENT_XML1, 'UTF-8' );
                    $sheet_xml_inner .= '<c r="' . $cell_ref . '" t="inlineStr" s="' . $style_idx . '"><is><t>' . $cell_val . '</t></is></c>';
                    $col_idx++;
                }
                $sheet_xml_inner .= '</row>';
                $row_idx++;
            }
            $max_cols = max( 1, count( $srows[0] ?? array() ) );
            $col_widths = '';
            for ( $ci = 1; $ci <= $max_cols; $ci++ ) {
                $w = 1 === $ci ? 28 : ( 2 === $ci ? 40 : 50 );
                $col_widths .= '<col min="' . $ci . '" max="' . $ci . '" width="' . $w . '" bestFit="1" customWidth="1"/>';
            }
            $full_sheet_xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
                . '<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">'
                . '<sheetViews><sheetView tabSelected="1" workbookViewId="0"><pane ySplit="1" topLeftCell="A2" activePane="bottomLeft" state="frozen"/></sheetView></sheetViews>'
                . '<cols>' . $col_widths . '</cols>'
                . '<sheetData>' . $sheet_xml_inner . '</sheetData>'
                . '</worksheet>';
            $sheet_xml_blocks[ 'rId' . $rid ] = array(
                'path' => 'xl/worksheets/sheet' . $rid . '.xml',
                'xml'  => $full_sheet_xml,
                'name' => $sname,
            );
            $safe_name = htmlspecialchars( $sname, ENT_QUOTES | ENT_XML1, 'UTF-8' );
            $workbook_sheets_xml .= '<sheet name="' . $safe_name . '" sheetId="' . $rid . '" r:id="rId' . $rid . '"/>';
            $workbook_rels_xml   .= '<Relationship Id="rId' . $rid . '" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet' . $rid . '.xml"/>';
            $content_overrides   .= '<Override PartName="/xl/worksheets/sheet' . $rid . '.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>';
            $rid++;
        }

        $new_workbook = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
            . '<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">'
            . '<sheets>' . $workbook_sheets_xml . '</sheets>'
            . '</workbook>';
        $new_rels = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
            . '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'
            . $workbook_rels_xml
            . '</Relationships>';
        $new_root_rels = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
            . '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'
            . '<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>'
            . '</Relationships>';
        $new_content_types = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
            . '<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">'
            . '<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>'
            . '<Default Extension="xml" ContentType="application/xml"/>'
            . '<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>'
            . $content_overrides
            . '</Types>';

        $temp_out = function_exists( 'wp_tempnam' )
            ? wp_tempnam( 'opsgate-xlsx-out.xlsx' )
            : tempnam( sys_get_temp_dir(), 'opsgate-xlsx-out-' );
        if ( ! is_string( $temp_out ) || '' === $temp_out ) {
            return $xlsx_bytes;
        }
        @unlink( $temp_out );

        $zip_out = new ZipArchive();
        if ( true !== $zip_out->open( $temp_out, ZipArchive::CREATE | ZipArchive::OVERWRITE ) ) {
            return $xlsx_bytes;
        }

        $zip_out->addFromString( '[Content_Types].xml', $new_content_types );
        $zip_out->addFromString( '_rels/.rels', $new_root_rels );
        $zip_out->addFromString( 'xl/workbook.xml', $new_workbook );
        $zip_out->addFromString( 'xl/_rels/workbook.xml.rels', $new_rels );
        $zip_out->addFromString( 'xl/styles.xml', $styles_xml );
        foreach ( $sheet_xml_blocks as $block ) {
            $zip_out->addFromString( $block['path'], $block['xml'] );
        }
        $zip_out->close();

        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
        $rebuilt = @file_get_contents( $temp_out );
        @unlink( $temp_out );

        return ( is_string( $rebuilt ) && '' !== $rebuilt ) ? $rebuilt : $xlsx_bytes;
    }

    private static function render_client_csv_from_bytes( string $csv_bytes ): string {
        if ( '' === $csv_bytes ) {
            return $csv_bytes;
        }

        $lines = preg_split( '/\r\n|\r|\n/', $csv_bytes );
        if ( ! is_array( $lines ) || empty( $lines ) ) {
            return $csv_bytes;
        }

        $rows = array();
        foreach ( $lines as $line ) {
            if ( '' === trim( (string) $line ) ) {
                continue;
            }
            $parsed = str_getcsv( (string) $line );
            if ( is_array( $parsed ) && ! empty( $parsed ) ) {
                $rows[] = $parsed;
            }
        }

        if ( count( $rows ) < 1 ) {
            return $csv_bytes;
        }

        $raw_header = array_shift( $rows );
        $mapped_header = array_map( array( 'self', 'client_column_label' ), is_array( $raw_header ) ? $raw_header : array() );

        $id_columns     = array( 'run reference', 'export reference', 'run id', 'export id' );
        $primary_indices = array();
        $id_indices      = array();
        foreach ( $mapped_header as $ci => $label ) {
            $lc    = strtolower( $label );
            $is_id = false;
            foreach ( $id_columns as $id_col ) {
                if ( false !== strpos( $lc, $id_col ) ) {
                    $is_id = true;
                    break;
                }
            }
            if ( $is_id ) {
                $id_indices[] = $ci;
            } else {
                $primary_indices[] = $ci;
            }
        }

        $ordered_indices = array_merge( $primary_indices, $id_indices );

        $out_rows = array();
        $out_header = array_map( static function ( $i ) use ( $mapped_header ) { return $mapped_header[ $i ] ?? ''; }, $ordered_indices );
        $out_rows[] = $out_header;

        foreach ( $rows as $row ) {
            $out_row = array_map( static function ( $i ) use ( $row ) { return isset( $row[ $i ] ) ? (string) $row[ $i ] : ''; }, $ordered_indices );
            $out_rows[] = $out_row;
        }

        $output_lines = array();
        foreach ( $out_rows as $out_row ) {
            $escaped = array_map( static function ( $cell ) {
                $cell = (string) $cell;
                if ( false !== strpos( $cell, ',' ) || false !== strpos( $cell, '"' ) || false !== strpos( $cell, "\n" ) ) {
                    $cell = '"' . str_replace( '"', '""', $cell ) . '"';
                }
                return $cell;
            }, $out_row );
            $output_lines[] = implode( ',', $escaped );
        }

        return implode( "\r\n", $output_lines );
    }

    private static function render_client_html_view( string $html ): string {
        $html = trim( $html );
        $sanitized = preg_replace( '#<script\b[^>]*>.*?</script>#is', '', $html );
        $sanitized = is_string( $sanitized ) ? $sanitized : $html;
        $sanitized = preg_replace( '#<(iframe|object|embed)[^>]*>.*?</\\1>#is', '', $sanitized );
        $sanitized = is_string( $sanitized ) ? $sanitized : $html;

        // Remove duplicate hero copy paragraphs (API sometimes emits the summary paragraph twice).
        $sanitized = (string) preg_replace_callback(
            '#(<p\b[^>]*class="[^"]*hero-copy[^"]*"[^>]*>)(.*?)(</p>)#is',
            static function ( array $m ) {
                static $seen = array();
                $key = md5( $m[2] );
                if ( isset( $seen[ $key ] ) ) {
                    return '';
                }
                $seen[ $key ] = true;
                return $m[0];
            },
            $sanitized
        );

        $firm_name = trim( (string) get_option( 'opsgate_firm_name', '' ) );
        $firm_banner = '';
        if ( '' !== $firm_name ) {
            $firm_banner = '<div style="background:#0d2940;color:#e8f4fd;padding:8px 24px;font-family:\'Segoe UI\',\'Helvetica Neue\',Arial,sans-serif;font-size:13px;font-weight:600;letter-spacing:0.03em;">'
                . esc_html( $firm_name )
                . '</div>';
        }

        // Worker-generated HTML already has a complete, self-contained <style> block.
        // Injecting a generic override destroys the intentional color system (e.g. the dark
        // navy .hero background becomes light blue while hero text stays white → unreadable).
        // When the HTML already has its own styles, inject only the firm banner (if set) after <body>.
        if ( false !== stripos( $sanitized, '<style' ) ) {
            if ( '' !== $firm_banner ) {
                if ( false !== stripos( $sanitized, '<body' ) ) {
                    $sanitized = (string) preg_replace( '#(<body\b[^>]*>)#i', '$1' . $firm_banner, $sanitized, 1 );
                } else {
                    $sanitized = $firm_banner . $sanitized;
                }
            }
            return $sanitized;
        }

        // Fallback: inject a safe base stylesheet only for unstyled legacy HTML.
        $client_css = '
<style id="opsgate-client-override">
*{box-sizing:border-box;}
html,body{margin:0;padding:0;background:#eef4fb;color:#12304a;font-family:"Segoe UI","Helvetica Neue",Arial,sans-serif;font-size:15px;line-height:1.6;}
body>*:first-child,main,article,.report,.report-body,.report-content{max-width:1080px;margin:0 auto;padding:32px 24px;}
h1{font-size:28px;font-weight:900;color:#0d2940;margin:0 0 6px;}
h2{font-size:20px;font-weight:700;color:#153b61;margin:28px 0 10px;padding-bottom:6px;border-bottom:2px solid #d7e2ee;}
h3{font-size:16px;font-weight:700;color:#1a4b7a;margin:18px 0 6px;}
p{margin:0 0 10px;}
table{width:100%;border-collapse:collapse;background:#fff;border-radius:12px;overflow:hidden;box-shadow:0 4px 16px rgba(16,39,67,.07);margin-bottom:20px;}
th,td{text-align:left;padding:10px 14px;border-bottom:1px solid #e3ebf3;vertical-align:top;}
th{background:#eef6ff;color:#0d2940;font-weight:700;font-size:12px;text-transform:uppercase;letter-spacing:.06em;}
svg,canvas{max-width:100%;height:auto;}
</style>';

        if ( false !== stripos( $sanitized, '</head>' ) ) {
            $output = str_ireplace( '</head>', $client_css . '</head>', $sanitized );
        } else {
            $output = $client_css . $sanitized;
        }

        if ( '' !== $firm_banner ) {
            if ( false !== stripos( $output, '<body' ) ) {
                $output = (string) preg_replace( '#(<body\b[^>]*>)#i', '$1' . $firm_banner, $output, 1 );
            } else {
                $output = $firm_banner . $output;
            }
        }

        return $output;
    }

    private static function canonical_report_download_url( string $kind, string $export_job_id, string $mode = 'download' ): string {
        $kind = trim( $kind );
        $export_job_id = trim( $export_job_id );
        $mode = 'view' === trim( strtolower( $mode ) ) ? 'view' : 'download';

        if ( '' === $kind || '' === $export_job_id ) {
            return '';
        }

        $url = add_query_arg(
            array(
                'action'        => 'opsgate_download_export',
                'kind'          => $kind,
                'export_job_id' => $export_job_id,
                'mode'          => $mode,
            ),
            admin_url( 'admin-post.php' )
        );

        return wp_nonce_url( $url, 'opsgate_download_export' );
    }


    private static function canonical_report_kind_label( string $kind ): string {
        if ( 'report_html' === $kind ) {
            return 'HTML Report';
        }

        if ( 'report_pdf' === $kind ) {
            return 'PDF Report';
        }

        if ( 'report_xlsx' === $kind ) {
            return 'Excel Report';
        }

        if ( 'csv' === $kind || 'export_csv' === $kind || 'triage_csv' === $kind ) {
            return 'CSV Report';
        }

        return ucwords( str_replace( array( '_', ':' ), ' ', $kind ) );
    }

    private static function canonical_report_status_copy( string $state ): string {
        $state = strtoupper( trim( $state ) );

        if ( 'QUEUED' === $state ) {
            return 'Queued — preparing your report.';
        }

        if ( 'RUNNING' === $state ) {
            return 'Running — generating your report.';
        }

        if ( 'COMPLETED' === $state ) {
            return 'Completed — ready to download.';
        }

        if ( 'FAILED' === $state ) {
            return 'Failed — this report could not be generated.';
        }

        return 'Status: ' . $state;
    }

    private static function canonical_report_trust_copy( array $item ): string {
        $signature_state = isset( $item['signature_state'] ) ? strtolower( trim( (string) $item['signature_state'] ) ) : '';
        if ( 'verified' === $signature_state ) {
            return 'Cryptographic signature verified against the stored export manifest.';
        }
        if ( 'signed' === $signature_state ) {
            return 'Cryptographic signature is present for this export.';
        }
        if ( 'failed' === $signature_state ) {
            $detail = isset( $item['verification_reason_detail'] ) ? trim( (string) $item['verification_reason_detail'] ) : '';
            return '' !== $detail ? $detail : 'Cryptographic signature verification failed for this export.';
        }

        $visibility_state = isset( $item['visibility_state'] ) ? strtolower( trim( (string) $item['visibility_state'] ) ) : '';
        if ( 'tombstoned' === $visibility_state ) {
            return 'Metadata retained; file no longer available.';
        }

        $redaction_state = isset( $item['redaction_state'] ) ? strtolower( trim( (string) $item['redaction_state'] ) ) : '';
        if ( 'redacted' === $redaction_state ) {
            return isset( $item['redaction_note'] ) && is_string( $item['redaction_note'] ) && '' !== trim( $item['redaction_note'] )
                ? trim( (string) $item['redaction_note'] )
                : 'Redacted for safe sharing.';
        }

        $verification_status = isset( $item['verification_status'] ) ? strtolower( trim( (string) $item['verification_status'] ) ) : '';
        if ( 'verified' === $verification_status ) {
            return 'Verification available from stored export evidence.';
        }

        if ( 'failed' === $verification_status ) {
            return 'Verification needs operator review.';
        }

        return 'Verification unavailable.';
    }

    private static function canonical_report_governance_copy( array $item ): string {
        $retention_policy = isset( $item['retention_policy_key'] ) ? trim( (string) $item['retention_policy_key'] ) : '';
        $visibility_state = isset( $item['visibility_state'] ) ? strtolower( trim( (string) $item['visibility_state'] ) ) : '';
        $redaction_state = isset( $item['redaction_state'] ) ? strtolower( trim( (string) $item['redaction_state'] ) ) : '';

        $parts = array( 'Controlled evidence lifecycle is active for this export.' );
        if ( '' !== $retention_policy ) {
            $parts[] = 'Retention policy: ' . $retention_policy . '.';
        }
        if ( 'tombstoned' === $visibility_state ) {
            $parts[] = 'Retention-aware reporting keeps metadata visible after file expiry.';
        } elseif ( 'active' === $visibility_state ) {
            $parts[] = 'Retention-aware reporting keeps the current export visible while active.';
        }
        if ( 'redacted' === $redaction_state ) {
            $parts[] = 'Privacy-aware evidence handling is applied to this export.';
        }

        return implode( ' ', $parts );
    }

    private static function api_export_eligibility_snapshot(): array {
        if ( function_exists( 'opsgate_get_api_entitlement_snapshot' ) ) {
            $snapshot = opsgate_get_api_entitlement_snapshot();
            if ( is_array( $snapshot ) ) {
                $eligibility = isset( $snapshot['eligibility'] ) && is_array( $snapshot['eligibility'] ) ? $snapshot['eligibility'] : array();
                $exports = isset( $eligibility['exports'] ) && is_array( $eligibility['exports'] ) ? $eligibility['exports'] : array();
                return $exports;
            }
        }

        return array();
    }

    private static function export_capability_key_for_kind( string $kind ): string {
        if ( 'report_html' === $kind ) {
            return 'reports.export.html';
        }
        if ( 'report_pdf' === $kind ) {
            return 'reports.export.pdf';
        }
        if ( 'report_xlsx' === $kind ) {
            return 'reports.export.xlsx';
        }
        if ( in_array( $kind, array( 'triage_json', 'export_triage_json' ), true ) ) {
            return 'reports.export.json';
        }
        if ( in_array( $kind, array( 'triage_xml', 'export_triage_xml' ), true ) ) {
            return 'reports.export.xml';
        }
        return 'reports.export.csv';
    }

    private static function export_kind_allowed_now( string $kind ): bool {
        $output = self::output_availability_for_kind( $kind );
        if ( ! empty( $output ) ) {
            return ! empty( $output['is_available'] );
        }

        $exports = self::api_export_eligibility_snapshot();
        $capability_key = self::export_capability_key_for_kind( $kind );
        if ( isset( $exports[ $capability_key ] ) && is_array( $exports[ $capability_key ] ) ) {
            if ( array_key_exists( 'allowed', $exports[ $capability_key ] ) ) {
                return ! empty( $exports[ $capability_key ]['allowed'] );
            }
            return ! empty( $exports[ $capability_key ]['is_enabled'] );
        }

        // Eligibility snapshot is empty (operator_override active or API unavailable).
        // Derive from the current effective plan using the canonical capability tier map.
        $plan = self::normalize_plan( (string) ( self::get_entitlement_plan_snapshot()['plan'] ?? '' ) );
        return self::plan_has_export_capability( $plan, $capability_key );
    }

    private static function plan_has_export_capability( string $plan, string $capability_key ): bool {
        // Free: no structured exports. Starter/Pro/Agency: all export formats enabled.
        if ( 'free' === $plan ) {
            return false;
        }
        if ( in_array( $plan, array( 'starter', 'pro', 'agency' ), true ) ) {
            $paid_capabilities = array(
                'reports.export.pdf',
                'reports.export.html',
                'reports.export.csv',
                'reports.export.xlsx',
                'reports.export.json',
                'reports.export.xml',
            );
            return in_array( $capability_key, $paid_capabilities, true );
        }
        return false;
    }

    private static function export_kind_unavailable_copy( string $kind ): string {
        $output = self::output_availability_for_kind( $kind );
        if ( ! empty( $output ) ) {
            $message = isset( $output['reason_message'] ) ? trim( (string) $output['reason_message'] ) : '';
            if ( '' !== $message ) {
                return $message;
            }
        }

        $exports = self::api_export_eligibility_snapshot();
        $capability_key = self::export_capability_key_for_kind( $kind );
        if ( isset( $exports[ $capability_key ] ) && is_array( $exports[ $capability_key ] ) ) {
            $message = isset( $exports[ $capability_key ]['reason_message'] ) ? trim( (string) $exports[ $capability_key ]['reason_message'] ) : '';
            if ( '' !== $message ) {
                return $message;
            }
        }

        $plan = self::normalize_plan( (string) ( self::get_entitlement_plan_snapshot()['plan'] ?? '' ) );
        if ( 'free' === $plan ) {
            return 'Requires a Starter, Pro, or Agency plan.';
        }
        return 'Not available on this plan.';
    }

    private static function ui_display_timezone_name(): string {
        return 'America/Montreal';
    }

    private static function ui_display_timezone_label(): string {
        return 'Eastern';
    }

    /**
     * @return array{date:string,time:string,timezone_name:string}
     */
    private static function ui_display_datetime_parts( string $value ): array {
        $value = trim( $value );
        if ( '' === $value ) {
            return array(
                'date'          => '—',
                'time'          => '',
                'timezone_name' => self::ui_display_timezone_name(),
            );
        }

        try {
            $dt = new DateTimeImmutable( $value, new DateTimeZone( 'UTC' ) );
            $timezone_name = self::ui_display_timezone_name();
            $local = $dt->setTimezone( new DateTimeZone( $timezone_name ) );
            return array(
                'date'          => $local->format( 'Y-m-d' ),
                'time'          => $local->format( 'H:i:s T' ),
                'timezone_name' => $timezone_name,
            );
        } catch ( Exception $e ) {
            return array(
                'date'          => str_replace( 'T', ' ', rtrim( $value, 'Z' ) ),
                'time'          => '',
                'timezone_name' => self::ui_display_timezone_name(),
            );
        }
    }

    private static function report_datetime_label( string $value ): string {
        return self::canonical_report_datetime_label( $value );
    }

    private static function canonical_report_datetime_label( string $value ): string {
        $value = trim( $value );
        if ( '' === $value ) {
            return '—';
        }

        $parts = self::ui_display_datetime_parts( $value );
        if ( '—' === $parts['date'] ) {
            return '—';
        }

        return trim( $parts['date'] . ' ' . $parts['time'] );
    }

    private static function human_relative_datetime_label( string $value ): string {
        $value = trim( $value );
        if ( '' === $value ) {
            return '—';
        }
        try {
            $dt = new DateTimeImmutable( $value, new DateTimeZone( 'UTC' ) );
            $diff = time() - $dt->getTimestamp();
            if ( $diff < 60 ) {
                return 'just now';
            }
            return human_time_diff( $dt->getTimestamp(), time() ) . ' ago';
        } catch ( Exception $e ) {
            return self::canonical_report_datetime_label( $value );
        }
    }

    /**
     * @param array<string,mixed> $schedule_settings
     */
    private static function schedule_timezone_name( array $schedule_settings ): string {
        $timezone = isset( $schedule_settings['timezone'] ) ? trim( (string) $schedule_settings['timezone'] ) : '';
        if ( '' === $timezone || 'UTC' === strtoupper( $timezone ) ) {
            return self::ui_display_timezone_name();
        }
        return $timezone;
    }

    /**
     * @param array<string,mixed> $schedule_settings
     */
    private static function schedule_datetime_label( string $value, array $schedule_settings ): string {
        $value = trim( $value );
        if ( '' === $value ) {
            return '—';
        }

        $timezone_name = self::schedule_timezone_name( $schedule_settings );
        try {
            $dt = new DateTimeImmutable( $value, new DateTimeZone( 'UTC' ) );
            $local = $dt->setTimezone( new DateTimeZone( $timezone_name ) );
            return $local->format( 'Y-m-d H:i:s T' ) . ' (' . $timezone_name . ')';
        } catch ( Exception $e ) {
            return self::canonical_report_datetime_label( $value );
        }
    }

    private static function browser_safe_url( string $url ): string {
        return set_url_scheme( $url, 'relative' );
    }

    private static function browser_safe_admin_url( string $path = 'admin.php', array $args = array() ): string {
        $url = admin_url( $path );
        if ( ! empty( $args ) ) {
            $url = add_query_arg( $args, $url );
        }
        return self::browser_safe_url( $url );
    }

    private static function browser_safe_plugins_url( string $path ): string {
        return self::browser_safe_url( plugins_url( $path, __FILE__ ) );
    }

    private static function admin_tab_url( string $tab, array $args = array() ): string {
        $args = array_merge(
            array(
                'page' => 'opsgate',
                'tab'  => $tab,
            ),
            self::current_request_scope_query_args(),
            $args
        );
        $args = array_filter(
            $args,
            static function ( $value ): bool {
                return null !== $value;
            }
        );

        return self::browser_safe_admin_url( 'admin.php', $args );
    }

    /**
     * Read the latest canonical portfolio triage bundle for the connected site.
     *
     * @return array{ok:bool,job:array<string,mixed>,artifacts:array<string,mixed>,error:string}
     */
    private static function canonical_latest_triage_bundle(): array {
        $scope = self::get_mcp_scope_snapshot();
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id    = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';

        if ( '' === $account_id || '' === $site_id ) {
            return array(
                'ok'        => false,
                'job'       => array(),
                'artifacts' => array(),
                'error'     => 'Connect this site in Settings before viewing the Run Ledger dashboard.',
            );
        }

        $resp = self::mcp_get_json(
            '/v1/triage/latest',
            array(
                'account_id' => $account_id,
                'site_id'    => $site_id,
                'job_type'   => 'portfolio_triage',
            )
        );

        if ( empty( $resp['ok'] ) ) {
            return array(
                'ok'        => false,
                'job'       => array(),
                'artifacts' => array(),
                'error'     => isset( $resp['error'] ) ? (string) $resp['error'] : 'Could not load the latest triage bundle.',
            );
        }

        $data = isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array();
        $latest = isset( $data['latest'] ) && is_array( $data['latest'] ) ? $data['latest'] : array();

        return array(
            'ok'        => true,
            'job'       => isset( $latest['job'] ) && is_array( $latest['job'] ) ? $latest['job'] : array(),
            'artifacts' => isset( $latest['artifacts'] ) && is_array( $latest['artifacts'] ) ? $latest['artifacts'] : array(),
            'error'     => '',
        );
    }

    /**
     * Read canonical uptime-over-time truth for the selected site.
     *
     * @return array{ok:bool,summary:array<string,mixed>,observations:array<int,array<string,mixed>>,error:string}
     */
    private static function canonical_uptime_window( int $window_hours = 24, int $limit = 48 ): array {
        $scope = self::get_mcp_scope_snapshot();
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id    = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';

        if ( '' === $account_id || '' === $site_id ) {
            return array(
                'ok'           => false,
                'summary'      => array(),
                'observations' => array(),
                'error'        => 'missing_scope',
            );
        }

        $resp = self::mcp_get_json(
            '/v1/sites/uptime-window',
            array(
                'account_id'   => $account_id,
                'site_id'      => $site_id,
                'window_hours' => max( 1, min( 720, $window_hours ) ),
                'limit'        => max( 1, min( 200, $limit ) ),
            )
        );

        if ( empty( $resp['ok'] ) ) {
            return array(
                'ok'           => false,
                'summary'      => array(),
                'observations' => array(),
                'error'        => isset( $resp['error'] ) ? (string) $resp['error'] : 'uptime_unavailable',
            );
        }

        $data = isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array();
        return array(
            'ok'           => true,
            'summary'      => isset( $data['summary'] ) && is_array( $data['summary'] ) ? $data['summary'] : array(),
            'observations' => isset( $data['observations'] ) && is_array( $data['observations'] ) ? $data['observations'] : array(),
            'error'        => '',
        );
    }

    /**
     * Build a small canonical activity feed from existing Run Ledger truth.
     *
     * @return array<int,array<string,string>>
     */
    private static function canonical_activity_feed( int $limit = 12 ): array {
        $items = array();

        $latest = self::canonical_latest_triage_bundle();
        if ( ! empty( $latest['ok'] ) ) {
            $job = isset( $latest['job'] ) && is_array( $latest['job'] ) ? $latest['job'] : array();
            $score_summary_artifact = isset( $latest['artifacts']['score_summary']['body'] ) && is_array( $latest['artifacts']['score_summary']['body'] )
                ? $latest['artifacts']['score_summary']['body']
                : array();
            $job_trigger_label = self::canonical_run_trigger_label( isset( $job['trigger'] ) ? (string) $job['trigger'] : '' );
            $job_reference = isset( $job['job_id'] ) ? self::canonical_activity_reference_copy( 'Run reference', (string) $job['job_id'] ) : '';
            if ( '' !== $job_reference && '' !== $job_trigger_label ) {
                $job_reference .= ' • ' . $job_trigger_label;
            } elseif ( '' === $job_reference && '' !== $job_trigger_label ) {
                $job_reference = $job_trigger_label;
            }
            $items[] = array(
                'label'   => 'Security Scan',
                'when'    => isset( $job['finished_at_utc'] ) ? self::human_relative_datetime_label( (string) $job['finished_at_utc'] ) : '—',
                'status'  => self::canonical_activity_status_copy( isset( $job['state'] ) ? (string) $job['state'] : '' ),
                'details' => sprintf(
                    'Security scan completed with score %s (%s).',
                    isset( $score_summary_artifact['score'] ) ? (string) $score_summary_artifact['score'] : '—',
                    isset( $score_summary_artifact['grade'] ) ? strtolower( (string) $score_summary_artifact['grade'] ) : 'unrated'
                ),
                'supporting' => $job_reference,
                'ts'      => isset( $job['finished_at_utc'] ) ? (string) $job['finished_at_utc'] : '',
            );
        }

        $history = self::canonical_exports_history( 10 );
        if ( ! empty( $history['ok'] ) ) {
            $history_items = isset( $history['items'] ) && is_array( $history['items'] ) ? self::live_items_only( $history['items'] ) : array();
            $history_groups = array();
            foreach ( $history_items as $item ) {
                if ( ! is_array( $item ) ) {
                    continue;
                }
                $group_key = isset( $item['source_job_id'] ) && '' !== trim( (string) $item['source_job_id'] )
                    ? (string) $item['source_job_id']
                    : ( isset( $item['export_job_id'] ) ? (string) $item['export_job_id'] : '' );
                if ( '' === $group_key ) {
                    $group_key = 'export-' . md5( wp_json_encode( $item ) );
                }
                if ( ! isset( $history_groups[ $group_key ] ) ) {
                    $history_groups[ $group_key ] = array();
                }
                $history_groups[ $group_key ][] = $item;
            }

            foreach ( $history_groups as $group_key => $group_items ) {
                if ( empty( $group_items ) ) {
                    continue;
                }
                $latest_export = $group_items[0];
                $output_labels = array();
                foreach ( $group_items as $group_item ) {
                    if ( ! is_array( $group_item ) ) {
                        continue;
                    }
                    $output_labels[] = self::canonical_report_kind_label( isset( $group_item['kind'] ) ? (string) $group_item['kind'] : '' );
                }
                $output_labels = array_values( array_unique( array_filter( $output_labels ) ) );
                $items[] = array(
                    'label'   => 'Report ready',
                    'when'    => isset( $latest_export['created_at_utc'] ) ? self::human_relative_datetime_label( (string) $latest_export['created_at_utc'] ) : '—',
                    'status'  => self::canonical_activity_status_copy( isset( $latest_export['state'] ) ? (string) $latest_export['state'] : '' ),
                    'details' => sprintf(
                        '%s ready for this run. %s',
                        ! empty( $output_labels ) ? implode( ', ', $output_labels ) : 'Packaged outputs',
                        self::canonical_report_trust_copy( $latest_export )
                    ),
                    'supporting' => isset( $latest_export['source_job_id'] ) ? self::canonical_activity_reference_copy( 'Source run', (string) $latest_export['source_job_id'] ) : '',
                    'ts'      => isset( $latest_export['created_at_utc'] ) ? (string) $latest_export['created_at_utc'] : '',
                );
            }
        }

        $events = self::notification_events_list( 6 );
        if ( ! empty( $events['ok'] ) ) {
            $event_items = isset( $events['items'] ) && is_array( $events['items'] ) ? self::live_items_only( $events['items'] ) : array();
            foreach ( $event_items as $event ) {
                if ( ! is_array( $event ) ) {
                    continue;
                }
                $items[] = array(
                    'label'   => self::canonical_notification_event_label( isset( $event['event_type'] ) ? (string) $event['event_type'] : '' ),
                    'when'    => isset( $event['created_at_utc'] ) ? self::canonical_report_datetime_label( (string) $event['created_at_utc'] ) : '—',
                    'status'  => self::canonical_activity_status_copy( isset( $event['status'] ) ? (string) $event['status'] : '' ),
                    'details' => self::notification_event_display_summary( $event ),
                    'supporting' => isset( $event['event_id'] ) ? self::canonical_activity_reference_copy( 'Event reference', (string) $event['event_id'] ) : '',
                    'ts'      => isset( $event['created_at_utc'] ) ? (string) $event['created_at_utc'] : '',
                );
            }
        }

        $proof_runs = self::proof_runs_list( 6 );
        if ( ! empty( $proof_runs['ok'] ) ) {
            $proof_items = isset( $proof_runs['items'] ) && is_array( $proof_runs['items'] ) ? $proof_runs['items'] : array();
            foreach ( $proof_items as $proof ) {
                if ( ! is_array( $proof ) ) {
                    continue;
                }
                $items[] = array(
                    'label'      => 'Validation receipt',
                    'when'       => isset( $proof['completed_at_utc'] ) && '' !== (string) $proof['completed_at_utc']
                        ? self::canonical_report_datetime_label( (string) $proof['completed_at_utc'] )
                        : ( isset( $proof['started_at_utc'] ) ? self::canonical_report_datetime_label( (string) $proof['started_at_utc'] ) : '—' ),
                    'status'     => self::proof_run_status_copy( $proof ),
                    'details'    => self::proof_run_summary_copy( $proof ),
                    'supporting' => isset( $proof['proof_run_id'] ) ? self::canonical_activity_reference_copy( 'Proof receipt', (string) $proof['proof_run_id'] ) : '',
                    'ts'         => isset( $proof['completed_at_utc'] ) && '' !== (string) $proof['completed_at_utc'] ? (string) $proof['completed_at_utc'] : ( isset( $proof['started_at_utc'] ) ? (string) $proof['started_at_utc'] : '' ),
                );
            }
        }

        usort(
            $items,
            static function ( $a, $b ) {
                $a_ts = isset( $a['ts'] ) ? strtotime( (string) $a['ts'] ) : 0;
                $b_ts = isset( $b['ts'] ) ? strtotime( (string) $b['ts'] ) : 0;
                return $b_ts <=> $a_ts;
            }
        );

        return array_slice( $items, 0, max( 1, min( 50, $limit ) ) );
    }

    private static function canonical_activity_status_copy( string $status ): string {
        $status = strtolower( trim( $status ) );

        $map = array(
            'completed'   => 'Complete',
            'recorded'    => 'Complete',
            'delivered'   => 'Delivered',
            'running'     => 'Running',
            'in_progress' => 'Running',
            'queued'      => 'Queued',
            'pending'     => 'Queued',
            'ready'       => 'Ready',
            'failed'      => 'Needs attention',
            'timeout'     => 'Needs attention',
            'rejected'    => 'Needs attention',
            'suppressed'  => 'Suppressed',
            'cancelled'   => 'Cancelled',
        );

        return isset( $map[ $status ] ) ? $map[ $status ] : 'Complete';
    }

    private static function canonical_activity_status_badge( string $status ): array {
        $status = strtolower( trim( $status ) );

        if ( in_array( $status, array( 'completed', 'recorded', 'delivered' ), true ) ) {
            return array(
                'class' => 'success',
                'label' => self::canonical_activity_status_copy( $status ),
            );
        }

        if ( in_array( $status, array( 'failed', 'timeout', 'rejected' ), true ) ) {
            return array(
                'class' => 'danger',
                'label' => self::canonical_activity_status_copy( $status ),
            );
        }

        if ( in_array( $status, array( 'ready', 'queued', 'pending', 'running', 'in_progress' ), true ) ) {
            return array(
                'class' => 'warning',
                'label' => self::canonical_activity_status_copy( $status ),
            );
        }

        return array(
            'class' => 'info',
            'label' => self::canonical_activity_status_copy( $status ),
        );
    }

    private static function canonical_notification_event_label( string $event_type ): string {
        $event_type = trim( $event_type );

        $map = array(
            'triage.run_failed' => 'Scan failed',
            'triage.run_completed_healthy' => 'Scan complete — healthy',
            'triage.run_completed_high_risk' => 'Scan complete — critical risk',
            'triage.run_completed_medium_risk' => 'Scan complete — needs attention',
            'report.export_failed' => 'Report generation failed',
            'vulnerability.plugin_first_detected'  => 'New vulnerability found',
            'vulnerability.plugin_state_changed'   => 'Vulnerability updated',
            'update.available_with_security_fix'   => 'Security fix update available',
            'alert.test' => 'Test alert',
        );

        return isset( $map[ $event_type ] ) ? $map[ $event_type ] : 'Alert event';
    }

    private static function canonical_notification_issue_copy( string $error_code, string $error_message ): string {
        $error_code = trim( $error_code );
        $error_message = trim( $error_message );

        $code_map = array(
            'source_job_not_found' => 'The linked run record could not be found.',
            'report_html_failed'   => 'The HTML report could not be generated.',
            'report_pdf_failed'    => 'The PDF report could not be generated.',
            'probe_failed_once'    => 'The first delivery attempt failed and was retried.',
            'proof_delivery_failed' => 'Operator proof delivery failed as expected for this validation scenario.',
            'notification_destination_disabled' => 'This destination is disabled.',
            'notification_destination_family_not_live' => 'This destination family is configured but does not have an active live delivery adapter yet.',
        );

        if ( '' !== $error_code && isset( $code_map[ $error_code ] ) ) {
            return $code_map[ $error_code ];
        }

        if ( '' !== $error_message ) {
            $cleaned = self::notification_clean_copy( $error_message );
            return $cleaned;
        }

        return '—';
    }

    private static function canonical_notification_channel_label( string $channel ): string {
        $channel = strtolower( trim( $channel ) );

        $map = array(
            'email' => 'email',
            'webhook' => 'webhook',
            'slack' => 'slack',
            'teams' => 'teams',
            'whatsapp' => 'whatsapp',
            'telegram' => 'telegram',
            'discord' => 'discord',
            'sns' => 'sns',
        );

        return isset( $map[ $channel ] ) ? $map[ $channel ] : 'delivery';
    }

    private static function canonical_activity_reference_copy( string $label, string $value ): string {
        $value = trim( $value );
        if ( '' === $value ) {
            return '';
        }

        $normalized = preg_replace( '/[^a-z0-9]+/i', ' ', $value );
        $normalized = is_string( $normalized ) ? trim( strtolower( $normalized ) ) : '';
        if ( false !== strpos( $normalized, 'closure proof' ) || false !== strpos( $normalized, 'proof' ) ) {
            return $label . ' available for operator support.';
        }

        if ( strlen( $value ) > 18 ) {
            $value = substr( $value, 0, 6 ) . '…' . substr( $value, -8 );
        }

        return $label . ': ' . $value;
    }

    /**
     * Site roster switcher rendered at the top of the central Overview tab.
     * Only shown on the central console when the account has 2+ sites.
     *
     * @param string $account_id    Current account.
     * @param string $active_site_id Currently-scoped site.
     */
    private static function render_central_site_roster_switcher( string $account_id, string $active_site_id ): void {
        if ( '' === $account_id ) {
            return;
        }
        // Suppress the switcher during any remote onboarding/companion flow — the active site must
        // stay locked to the requested onboarding site; showing other account sites would be misleading.
        $opsgate_source = isset( $_GET['opsgate_source'] ) ? sanitize_key( wp_unslash( $_GET['opsgate_source'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $has_onboarding_session = isset( $_GET['opsgate_onboarding_session_id'] ) && '' !== (string) $_GET['opsgate_onboarding_session_id']; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        if ( in_array( $opsgate_source, array( 'remote-companion', 'remote-onboarding' ), true ) || $has_onboarding_session ) {
            return;
        }
        // Also suppress when the scope was resolved via an onboarding session (the session params
        // may no longer be in the URL after redirect, but the resolution_kind is still available).
        $resolved_scope = self::get_mcp_scope_snapshot();
        if ( isset( $resolved_scope['resolution_kind'] ) && 'onboarding_session' === $resolved_scope['resolution_kind'] ) {
            return;
        }
        $roster_resp = self::mcp_get_json( '/v1/accounts/' . rawurlencode( $account_id ) . '/sites/roster' );
        if ( empty( $roster_resp['ok'] ) ) {
            return;
        }
        $sites = isset( $roster_resp['data']['sites'] ) && is_array( $roster_resp['data']['sites'] ) ? $roster_resp['data']['sites'] : array();
        if ( count( $sites ) < 2 ) {
            return;
        }
        ?>
        <div class="opsgate-card opsgate-site-roster-switcher" style="margin-bottom:12px;">
            <div style="padding:10px 16px;display:flex;align-items:center;flex-wrap:wrap;gap:8px;">
                <span style="font-weight:600;margin-right:4px;">Site:</span>
                <?php foreach ( $sites as $site ) : ?>
                    <?php
                    $s_id    = isset( $site['site_id'] ) ? trim( (string) $site['site_id'] ) : '';
                    $s_label = isset( $site['site_label'] ) ? trim( (string) $site['site_label'] ) : $s_id;
                    $s_url   = isset( $site['site_url'] ) ? trim( (string) $site['site_url'] ) : '';
                    $is_active = '' !== $s_id && $s_id === $active_site_id;
                    $switch_url = self::admin_tab_url(
                        'overview',
                        array(
                            'opsgate_scope_account'    => $account_id,
                            'opsgate_scope_site_id'    => $s_id,
                            'opsgate_scope_site_url'   => $s_url,
                            'opsgate_scope_site_label' => $s_label,
                        )
                    );
                    ?>
                    <?php if ( $is_active ) : ?>
                        <span class="button button-primary" style="cursor:default;" aria-current="true"><?php echo esc_html( $s_label ); ?></span>
                    <?php else : ?>
                        <a class="button button-secondary" href="<?php echo esc_url( $switch_url ); ?>" data-opsgate-no-ajax="1"><?php echo esc_html( $s_label ); ?></a>
                    <?php endif; ?>
                <?php endforeach; ?>
            </div>
        </div>
        <?php
    }

    private static function render_clients_dashboard_panel(): void {
        $scope = self::get_mcp_scope_snapshot();
        $site_config = self::canonical_site_config();
        $site_config_item = ! empty( $site_config['ok'] ) && isset( $site_config['item'] ) && is_array( $site_config['item'] ) ? $site_config['item'] : array();
        $latest = self::canonical_latest_triage_bundle();
        $board_state = self::canonical_portfolio_board();
        $local_board_row = self::canonical_local_board_row( $board_state );
        $package = self::current_package_entry();
        $job = isset( $latest['job'] ) && is_array( $latest['job'] ) ? $latest['job'] : array();
        $score_summary = isset( $latest['artifacts']['score_summary']['body'] ) && is_array( $latest['artifacts']['score_summary']['body'] )
            ? $latest['artifacts']['score_summary']['body']
            : array();
        if ( ! empty( $local_board_row ) ) {
            $board_posture = isset( $local_board_row['latest_posture'] ) && is_array( $local_board_row['latest_posture'] ) ? $local_board_row['latest_posture'] : array();
            $board_run     = isset( $local_board_row['latest_run'] ) && is_array( $local_board_row['latest_run'] ) ? $local_board_row['latest_run'] : array();
            if ( ! empty( $board_posture ) ) {
                $score_summary = array(
                    'score' => isset( $board_posture['score'] ) ? $board_posture['score'] : ( $score_summary['score'] ?? null ),
                    'grade' => isset( $board_posture['grade'] ) ? $board_posture['grade'] : ( $score_summary['grade'] ?? '' ),
                );
            }
            if ( ! empty( $board_run ) ) {
                $job = array_merge( $job, $board_run );
            }
        }

        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';
        $portfolio_id = trim( (string) get_option( 'opsgate_portfolio_id', 'portfolio_default' ) );
        $site_label = self::connected_site_label( $site_config_item, $scope );
        $site_url = self::connected_site_url( $site_config_item, $scope );
        $site_host = (string) ( wp_parse_url( $site_url, PHP_URL_HOST ) ?: '' );
        $score_grade = isset( $score_summary['grade'] ) ? strtolower( trim( (string) $score_summary['grade'] ) ) : '';
        $score_value = isset( $score_summary['score'] ) ? (string) $score_summary['score'] : '—';
        $score_grade_label = '' !== $score_grade ? ucfirst( $score_grade ) : 'Unrated';
        $score_tone = 'neutral';
        $score_summary_copy = 'Current posture pending.';
        if ( in_array( $score_grade, array( 'green', 'healthy' ), true ) ) {
            $score_tone = 'good';
            $score_summary_copy = 'Healthy posture';
        } elseif ( in_array( $score_grade, array( 'yellow', 'amber' ), true ) ) {
            $score_tone = 'warn';
            $score_summary_copy = 'Needs attention';
        } elseif ( in_array( $score_grade, array( 'red', 'critical' ), true ) ) {
            $score_tone = 'bad';
            $score_summary_copy = 'Action required';
        }

        $portfolio_display = 'portfolio_default' === $portfolio_id
            ? 'Default Portfolio'
            : ucwords( str_replace( array( '_', '-' ), ' ', $portfolio_id ) );
        $current_plan = isset( $package['plan_key'] ) ? (string) $package['plan_key'] : self::get_current_plan();
        $portfolio_unlocked = self::entitlement_capability_enabled( 'portfolio.board' );
        $package_display_name = isset( $package['display_name'] ) ? (string) $package['display_name'] : ucfirst( $current_plan );
        $package_outcome = isset( $package['buyer_outcome'] ) ? (string) $package['buyer_outcome'] : 'Portfolio context is shown from current account and site records.';
        $package_status_label = $package_display_name;
        $latest_run_value = isset( $job['finished_at_utc'] ) ? (string) $job['finished_at_utc'] : '';
        if ( '' === $latest_run_value && isset( $job['completed_at_utc'] ) ) {
            $latest_run_value = (string) $job['completed_at_utc'];
        }
        $latest_run_when = '' !== $latest_run_value ? self::canonical_report_datetime_label( $latest_run_value ) : 'No completed run yet';
        $latest_run_reference = isset( $job['job_id'] ) ? self::canonical_activity_reference_copy( 'Run', (string) $job['job_id'] ) : 'Run not recorded yet';
        $board_lifecycle = isset( $local_board_row['primary_lifecycle_state'] ) ? str_replace( '_', ' ', (string) $local_board_row['primary_lifecycle_state'] ) : '';
        $board_freshness = isset( $local_board_row['freshness']['freshness_class'] ) ? str_replace( '_', ' ', (string) $local_board_row['freshness']['freshness_class'] ) : '';
        $board_trust     = isset( $local_board_row['latest_trust']['signature_state'] ) ? strtoupper( (string) $local_board_row['latest_trust']['signature_state'] ) : '';
        $board_lifecycle_label = '' !== trim( $board_lifecycle ) ? ucfirst( trim( $board_lifecycle ) ) : 'Pending';
        $board_freshness_label = '' !== trim( $board_freshness ) ? ucfirst( trim( $board_freshness ) ) : 'Pending';
        $board_trust_label     = '' !== trim( $board_trust ) ? $board_trust : 'Visible';
        $last_seen_iso = isset( $local_board_row['freshness']['last_completed_run_at_utc'] ) ? trim( (string) $local_board_row['freshness']['last_completed_run_at_utc'] ) : '';
        $last_seen_relative = 'Never';
        $last_seen_is_amber = false;
        if ( '' !== $last_seen_iso ) {
            try {
                $last_seen_dt = new DateTimeImmutable( $last_seen_iso, new DateTimeZone( 'UTC' ) );
                $now_dt       = new DateTimeImmutable( 'now', new DateTimeZone( 'UTC' ) );
                $diff_secs    = max( 0, $now_dt->getTimestamp() - $last_seen_dt->getTimestamp() );
                $diff_days    = (int) floor( $diff_secs / 86400 );
                if ( $diff_days === 0 ) {
                    $diff_hours = (int) floor( $diff_secs / 3600 );
                    $last_seen_relative = $diff_hours <= 0 ? 'Just now' : $diff_hours . 'h ago';
                } elseif ( $diff_days < 7 ) {
                    $last_seen_relative = $diff_days . 'd ago';
                } elseif ( $diff_days < 30 ) {
                    $diff_weeks = (int) floor( $diff_days / 7 );
                    $last_seen_relative = $diff_weeks . 'w ago';
                } else {
                    $diff_months = (int) floor( $diff_days / 30 );
                    $last_seen_relative = $diff_months . 'mo ago';
                }
                $last_seen_is_amber = $diff_days >= 14;
            } catch ( \Exception $e ) {
                $last_seen_relative = $latest_run_when;
            }
        }
        $current_live_items = array_values( array_filter( array_map( 'strval', self::package_capability_items( 'live_now' ) ) ) );
        $current_locked_items = array_values( array_filter( array_map( 'strval', self::package_capability_items( 'visible_locked' ) ) ) );
        $portfolio_plan_rank_map = array(
            'free'    => 0,
            'starter' => 1,
            'pro'     => 2,
            'agency'  => 3,
        );
        $current_plan_rank = isset( $portfolio_plan_rank_map[ $current_plan ] ) ? $portfolio_plan_rank_map[ $current_plan ] : -1;
        $next_package = array();
        foreach ( self::package_comparison_entries() as $comparison_entry ) {
            if ( ! is_array( $comparison_entry ) ) {
                continue;
            }
            $comparison_plan_key = isset( $comparison_entry['plan_key'] ) ? (string) $comparison_entry['plan_key'] : '';
            $comparison_rank = isset( $portfolio_plan_rank_map[ $comparison_plan_key ] ) ? $portfolio_plan_rank_map[ $comparison_plan_key ] : -1;
            if ( $comparison_rank <= $current_plan_rank ) {
                continue;
            }
            if ( empty( $next_package ) ) {
                $next_package = $comparison_entry;
                continue;
            }
            $next_plan_key = isset( $next_package['plan_key'] ) ? (string) $next_package['plan_key'] : '';
            $next_rank = isset( $portfolio_plan_rank_map[ $next_plan_key ] ) ? $portfolio_plan_rank_map[ $next_plan_key ] : 99;
            if ( $comparison_rank < $next_rank ) {
                $next_package = $comparison_entry;
            }
        }
        $next_package_label = isset( $next_package['display_name'] ) ? (string) $next_package['display_name'] : '';
        $current_scope_title = $portfolio_unlocked ? 'Portfolio-aware operations' : 'Site-level operations';
        $current_scope_copy = $portfolio_unlocked
            ? 'This site is already participating in broader portfolio operations while the plugin remains the current site operating surface.'
            : 'This site is operating from the site surface today, with portfolio placement visible and broader board/account operations unlocked at a higher tier.';
        $operational_now_copy = 'Current posture is still being recorded for this site.';
        if ( 'good' === $score_tone ) {
            $operational_now_copy = $portfolio_unlocked
                ? 'Healthy posture is recorded and ready for portfolio attention from the current package.'
                : 'Healthy posture is recorded, with portfolio placement visible from the current site surface.';
        } elseif ( 'warn' === $score_tone ) {
            $operational_now_copy = $portfolio_unlocked
                ? 'This site needs follow-up before it is treated as healthy across portfolio operations.'
                : 'This site needs follow-up before it is treated as healthy in broader portfolio context.';
        } elseif ( 'bad' === $score_tone ) {
            $operational_now_copy = $portfolio_unlocked
                ? 'Critical posture is recorded and needs portfolio attention now.'
                : 'Critical posture is recorded and needs attention before broader portfolio operations treat this site as healthy.';
        }
        $scope_now_value = $portfolio_unlocked ? 'Portfolio board active' : 'Portfolio placement recorded';
        $scope_now_copy = $portfolio_unlocked
            ? 'Board participation and broader portfolio visibility are already unlocked on this package.'
            : 'This site is connected to portfolio identity now, but broader board operations remain a higher-tier capability.';
        $included_now_value = $package_display_name;
        $included_now_copy = $package_outcome;
        $next_move_value = $portfolio_unlocked
            ? 'Agency active'
            : ( '' !== $next_package_label ? 'Upgrade to ' . $next_package_label : 'Current commercial ceiling' );
        $next_move_copy = $portfolio_unlocked
            ? 'Agency keeps this site in the plugin for site truth while broader account and portfolio operations expand above it.'
            : ( isset( $package['upgrade_reason'] ) && '' !== trim( (string) $package['upgrade_reason'] )
                ? (string) $package['upgrade_reason']
                : 'The next package expands broader portfolio and account-level operations.' );
        $live_preview = array_slice( $current_live_items, 0, 3 );
        $locked_preview = array_slice( $current_locked_items, 0, 3 );

        echo '<div class="opsgate-card opsgate-clients-dashboard">';
        echo '<div class="opsgate-clients-header">';
        echo '<div class="opsgate-clients-header-copy">';
        echo '<h2 class="opsgate-clients-title">Portfolio</h2>';
        echo '<p class="opsgate-clients-subtitle">Current site profile, portfolio placement, and what this package expands next.</p>';
        echo '</div>';
        echo '</div>';

        if ( '' === $account_id || '' === $site_id ) {
            echo '<div class="opsgate-clients-empty">';
            echo '<strong>Connect this site to start tracking its security posture.</strong>';
            echo '<p>Complete the pairing in Settings to unlock plugin vulnerability scans, scheduled triage, and client-ready security reports for this site.</p>';
            echo '</div>';
            echo '</div>';
            return;
        }

        echo '<section class="opsgate-clients-hero opsgate-clients-hero-tone-' . esc_attr( $score_tone ) . '">';
        echo '<div class="opsgate-clients-hero-main">';
        echo '<span class="opsgate-clients-eyebrow">Current portfolio profile</span>';
        echo '<div class="opsgate-clients-hero-site">' . esc_html( '' !== $site_label ? $site_label : $site_host ) . '</div>';
        echo '<div class="opsgate-clients-hero-meta">';
        echo '<span class="opsgate-clients-hero-meta-item">' . esc_html( $portfolio_display ) . '</span>';
        if ( '' !== $site_host ) {
            echo '<span class="opsgate-clients-hero-meta-item">' . esc_html( $site_host ) . '</span>';
        }
        echo '</div>';
        echo '<div class="opsgate-clients-hero-posture">';
        echo '<div class="opsgate-clients-hero-score">' . esc_html( $score_value ) . '</div>';
        echo '<div class="opsgate-clients-hero-state">';
        echo '<div class="opsgate-clients-hero-state-title">' . esc_html( $score_grade_label . ' posture' ) . '</div>';
        echo '<p class="opsgate-clients-hero-copy">' . esc_html( $operational_now_copy ) . '</p>';
        echo '<div class="opsgate-clients-summary-pills">';
        echo '<span class="opsgate-clients-pill opsgate-clients-pill-' . esc_attr( $score_tone ) . '">' . esc_html( $score_grade_label ) . '</span>';
        echo '<span class="opsgate-clients-pill opsgate-clients-pill-soft">' . esc_html( $score_summary_copy ) . '</span>';
        echo '<span class="opsgate-clients-pill opsgate-clients-pill-soft">' . esc_html( $portfolio_unlocked ? 'Portfolio-aware' : 'Site scope' ) . '</span>';
        echo '</div>';
        echo '</div>';
        echo '</div>';
        echo '</div>';
        echo '<aside class="opsgate-clients-hero-side">';
        echo '<span class="opsgate-clients-eyebrow">Package meaning now</span>';
        echo '<div class="opsgate-clients-summary-value">' . esc_html( $package_display_name ) . '</div>';
        echo '<p class="opsgate-clients-summary-copy">' . esc_html( $current_scope_copy ) . '</p>';
        echo '<div class="opsgate-clients-hero-side-divider"></div>';
        echo '<span class="opsgate-clients-detail-label">Next relevant move</span>';
        echo '<span class="opsgate-clients-detail-value">' . esc_html( $next_move_value ) . '</span>';
        echo '<p class="opsgate-clients-summary-copy">' . esc_html( $next_move_copy ) . '</p>';
        echo '</aside>';
        echo '</section>';

        echo '<div class="opsgate-clients-confidence-strip">';
        $last_seen_class = $last_seen_is_amber ? 'opsgate-clients-lastseen-amber' : 'opsgate-clients-lastseen';
        echo '<div class="opsgate-clients-confidence-item"><span class="opsgate-clients-status-label">Last seen</span><span class="opsgate-clients-status-value ' . esc_attr( $last_seen_class ) . '">' . esc_html( $last_seen_relative ) . ( $last_seen_is_amber ? ' ⚠' : '' ) . '</span></div>';
        echo '<div class="opsgate-clients-confidence-item"><span class="opsgate-clients-status-label">Latest recorded truth</span><span class="opsgate-clients-status-value">' . esc_html( $latest_run_when ) . '</span></div>';
        echo '<div class="opsgate-clients-confidence-item"><span class="opsgate-clients-status-label">Trust state</span><span class="opsgate-clients-status-value">' . esc_html( $board_trust_label ) . '</span></div>';
        echo '<div class="opsgate-clients-confidence-item"><span class="opsgate-clients-status-label">Freshness</span><span class="opsgate-clients-status-value">' . esc_html( $board_freshness_label ) . '</span></div>';
        echo '<div class="opsgate-clients-confidence-item"><span class="opsgate-clients-status-label">Portfolio truth</span><span class="opsgate-clients-status-value">' . esc_html( $board_lifecycle_label ) . '</span></div>';
        echo '<div class="opsgate-clients-confidence-item"><span class="opsgate-clients-status-label">Current package</span><span class="opsgate-clients-status-value">' . esc_html( $package_status_label ) . '</span></div>';
        echo '</div>';

        echo '<div class="opsgate-clients-surfaces">';
        echo '<section class="opsgate-clients-surface opsgate-clients-surface-main">';
        echo '<div class="opsgate-clients-surface-header"><h3 class="opsgate-clients-surface-title">Current site profile</h3><span class="opsgate-clients-surface-link">Portfolio placement</span></div>';
        echo '<p class="opsgate-clients-surface-copy">Canonical identity and portfolio assignment for this connected site.</p>';
        echo '<div class="opsgate-clients-identity-grid">';
        echo '<div class="opsgate-clients-identity-card"><span class="opsgate-clients-detail-label">Site Label</span><span class="opsgate-clients-detail-value">' . esc_html( '' !== $site_label ? $site_label : '—' ) . '</span></div>';
        echo '<div class="opsgate-clients-identity-card"><span class="opsgate-clients-detail-label">Primary URL</span><span class="opsgate-clients-detail-value"><a href="' . esc_url( $site_url ) . '" target="_blank" rel="noopener noreferrer">' . esc_html( $site_url ) . '</a></span></div>';
        echo '<div class="opsgate-clients-identity-card"><span class="opsgate-clients-detail-label">Host</span><span class="opsgate-clients-detail-value">' . esc_html( '' !== $site_host ? $site_host : '—' ) . '</span></div>';
        echo '<div class="opsgate-clients-identity-card"><span class="opsgate-clients-detail-label">Portfolio</span><span class="opsgate-clients-detail-value">' . esc_html( $portfolio_display ) . '</span></div>';
        echo '</div>';
        echo '</section>';

        echo '<section class="opsgate-clients-surface opsgate-clients-surface-secondary">';
        echo '<div class="opsgate-clients-surface-header"><h3 class="opsgate-clients-surface-title">' . esc_html( $portfolio_unlocked ? 'Portfolio operations' : 'Current scope and next move' ) . '</h3><span class="opsgate-clients-surface-link">' . esc_html( $portfolio_unlocked ? 'Agency active' : 'Upgrade path' ) . '</span></div>';
        echo '<p class="opsgate-clients-surface-copy">' . esc_html( $portfolio_unlocked ? 'This package already unlocks broader portfolio operations while keeping site truth visible from the plugin.' : 'This package keeps the site in portfolio context today and shows what expands next.' ) . '</p>';
        echo '<div class="opsgate-clients-ops-grid">';
        echo '<div class="opsgate-clients-reference-item">';
        echo '<span class="opsgate-clients-detail-label">Current scope now</span>';
        echo '<span class="opsgate-clients-detail-value">' . esc_html( $scope_now_value ) . '</span>';
        echo '<p class="opsgate-clients-summary-copy">' . esc_html( $scope_now_copy ) . '</p>';
        echo '</div>';
        echo '<div class="opsgate-clients-reference-item">';
        echo '<span class="opsgate-clients-detail-label">Unlocked now</span>';
        echo '<span class="opsgate-clients-detail-value">' . esc_html( $included_now_value ) . '</span>';
        echo '<p class="opsgate-clients-summary-copy">' . esc_html( $included_now_copy ) . '</p>';
        if ( ! empty( $live_preview ) ) {
            echo '<ul class="opsgate-clients-list">';
            foreach ( $live_preview as $live_item ) {
                echo '<li>' . esc_html( $live_item ) . '</li>';
            }
            echo '</ul>';
        }
        echo '</div>';
        echo '<div class="opsgate-clients-reference-item">';
        echo '<span class="opsgate-clients-detail-label">' . esc_html( $portfolio_unlocked ? 'Broader portfolio value' : 'Next relevant move' ) . '</span>';
        echo '<span class="opsgate-clients-detail-value">' . esc_html( $next_move_value ) . '</span>';
        echo '<p class="opsgate-clients-summary-copy">' . esc_html( $next_move_copy ) . '</p>';
        $locked_preview_filtered = array_values( array_filter( $locked_preview, static function ( $item ) {
            return false === stripos( (string) $item, 'unavailable until implemented' );
        } ) );
        if ( ! empty( $locked_preview_filtered ) ) {
            echo '<ul class="opsgate-clients-list">';
            foreach ( $locked_preview_filtered as $locked_item ) {
                echo '<li>' . esc_html( $locked_item ) . '</li>';
            }
            echo '</ul>';
        }
        echo '</div>';
        echo '</div>';
        echo '</section>';
        echo '</div>';

        // B1 — Executive Brief card (Starter+, only when summary_text is not null).
        $is_starter_plus = in_array( $current_plan, array( 'starter', 'pro', 'agency' ), true );
        if ( $is_starter_plus && '' !== $account_id && '' !== $site_id ) {
            $ai_resp = self::mcp_get_json(
                '/v1/sites/' . rawurlencode( $site_id ) . '/ai-summary/latest',
                array( 'account_id' => $account_id )
            );
            $ai_data = isset( $ai_resp['ok'] ) && $ai_resp['ok'] && isset( $ai_resp['data'] ) && is_array( $ai_resp['data'] ) ? $ai_resp['data'] : null;
            $ai_summary_text = is_array( $ai_data ) && isset( $ai_data['summary_text'] ) && null !== $ai_data['summary_text'] ? (string) $ai_data['summary_text'] : '';
            if ( '' !== $ai_summary_text ) {
                $ai_action_items = is_array( $ai_data ) && isset( $ai_data['action_items'] ) && is_array( $ai_data['action_items'] ) ? $ai_data['action_items'] : array();
                echo '<div class="opsgate-card" style="margin-top:16px;">';
                echo '<div class="opsgate-clients-surface-header"><h3 class="opsgate-clients-surface-title">Executive Brief</h3><span class="opsgate-clients-surface-link">AI-generated</span></div>';
                echo '<p class="opsgate-clients-surface-copy" style="margin:8px 0 12px 0;">' . esc_html( $ai_summary_text ) . '</p>';
                if ( ! empty( $ai_action_items ) ) {
                    echo '<ul style="margin:0 0 0 18px;padding:0;">';
                    foreach ( $ai_action_items as $item ) {
                        $item_text = is_string( $item ) ? $item : ( is_array( $item ) ? (string) ( $item['text'] ?? $item['action'] ?? '' ) : '' );
                        if ( '' !== $item_text ) {
                            echo '<li style="margin-bottom:4px;">' . esc_html( $item_text ) . '</li>';
                        }
                    }
                    echo '</ul>';
                }
                echo '<p style="font-size:11px;color:#888;margin:12px 0 0 0;">AI interpretation — not a security audit or legal attestation. Based on recorded triage evidence.</p>';
                echo '</div>';
            }
        }

        // B3 — Site Health panel (Starter+, PHP error batch summary).
        if ( $is_starter_plus && '' !== $site_id ) {
            $err_resp = self::mcp_get_json(
                '/v1/sites/' . rawurlencode( $site_id ) . '/error-batches',
                array( 'account_id' => $account_id, 'days' => '7' )
            );
            $err_items = isset( $err_resp['ok'] ) && $err_resp['ok'] && isset( $err_resp['data']['items'] ) && is_array( $err_resp['data']['items'] ) ? $err_resp['data']['items'] : array();
            $err_count = count( $err_items );
            echo '<div class="opsgate-card" style="margin-top:16px;">';
            echo '<div class="opsgate-clients-surface-header"><h3 class="opsgate-clients-surface-title">Site Health — PHP Errors</h3><span class="opsgate-clients-surface-link">Last 7 days</span></div>';
            if ( 0 === $err_count ) {
                echo '<p class="opsgate-clients-surface-copy" style="margin:8px 0 0 0;">No PHP errors captured in the last 7 days.</p>';
            } else {
                echo '<p class="opsgate-clients-surface-copy" style="margin:8px 0 8px 0;">' . esc_html( $err_count ) . ' error class' . ( 1 === $err_count ? '' : 'es' ) . ' captured in the last 7 days.</p>';
                echo '<div class="opsgate-clients-identity-grid">';
                foreach ( array_slice( $err_items, 0, 5 ) as $err ) {
                    if ( ! is_array( $err ) ) {
                        continue;
                    }
                    $err_class = isset( $err['error_class'] ) ? (string) $err['error_class'] : 'Unknown';
                    $err_count_val = isset( $err['occurrence_count'] ) ? (int) $err['occurrence_count'] : 1;
                    $err_file = isset( $err['file_path'] ) ? (string) $err['file_path'] : '';
                    $err_file_short = '' !== $err_file ? basename( $err_file ) : '';
                    echo '<div class="opsgate-clients-identity-card">';
                    echo '<span class="opsgate-clients-detail-label">' . esc_html( $err_class ) . '</span>';
                    echo '<span class="opsgate-clients-detail-value">' . esc_html( $err_count_val . 'x' . ( '' !== $err_file_short ? ' — ' . $err_file_short : '' ) ) . '</span>';
                    echo '</div>';
                }
                echo '</div>';
                if ( $err_count > 5 ) {
                    echo '<p style="font-size:11px;color:#888;margin:8px 0 0 0;">Showing 5 of ' . esc_html( (string) $err_count ) . ' error classes.</p>';
                }
            }
            echo '</div>';
        }

        // SSL expiry monitoring panel (Starter+) — UI Pass 7: fixed to read from
        // score_summary.components.ssl.details (was: external_signal which does not exist).
        // Domain expiry removed — no artifact currently produces it.
        if ( $is_starter_plus && '' !== $site_id ) {
            $latest_artifacts      = isset( $latest['artifacts'] ) && is_array( $latest['artifacts'] ) ? $latest['artifacts'] : array();
            $score_summary_body    = isset( $latest_artifacts['score_summary']['body'] ) && is_array( $latest_artifacts['score_summary']['body'] )
                ? $latest_artifacts['score_summary']['body'] : array();
            $ss_components         = isset( $score_summary_body['components'] ) && is_array( $score_summary_body['components'] )
                ? $score_summary_body['components'] : array();
            $ssl_component         = isset( $ss_components['ssl'] ) && is_array( $ss_components['ssl'] ) ? $ss_components['ssl'] : array();
            $ssl_details           = isset( $ssl_component['details'] ) && is_array( $ssl_component['details'] ) ? $ssl_component['details'] : array();
            $ssl_days              = isset( $ssl_details['days_to_expiry'] ) && null !== $ssl_details['days_to_expiry']
                ? (int) $ssl_details['days_to_expiry'] : null;
            $ssl_ok_raw            = isset( $ssl_details['ok'] ) ? $ssl_details['ok'] : null;
            if ( null !== $ssl_days || null !== $ssl_ok_raw ) {
                $ssl_tone  = null !== $ssl_days && $ssl_days <= 0  ? 'bad'
                    : ( null !== $ssl_days && $ssl_days <= 14 ? 'bad'
                    : ( null !== $ssl_days && $ssl_days <= 30 ? 'warn' : 'good' ) );
                echo '<div class="opsgate-card" style="margin-top:16px;">';
                echo '<div class="opsgate-clients-surface-header"><h3 class="opsgate-clients-surface-title">SSL Certificate</h3><span class="opsgate-clients-surface-link">Expiry monitoring</span></div>';
                echo '<div class="opsgate-clients-identity-grid">';
                if ( null !== $ssl_days ) {
                    $ssl_label = $ssl_days <= 0 ? 'Expired' : $ssl_days . ' days remaining';
                    echo '<div class="opsgate-clients-identity-card">';
                    echo '<span class="opsgate-clients-detail-label">Days to expiry</span>';
                    echo '<span class="opsgate-clients-detail-value opsgate-tone-' . esc_attr( $ssl_tone ) . '">' . esc_html( $ssl_label ) . '</span>';
                    echo '</div>';
                }
                if ( null !== $ssl_ok_raw ) {
                    $ssl_valid_label = $ssl_ok_raw ? 'Valid' : 'Invalid';
                    $ssl_valid_tone  = $ssl_ok_raw ? 'good' : 'bad';
                    echo '<div class="opsgate-clients-identity-card">';
                    echo '<span class="opsgate-clients-detail-label">SSL status</span>';
                    echo '<span class="opsgate-clients-detail-value opsgate-tone-' . esc_attr( $ssl_valid_tone ) . '">' . esc_html( $ssl_valid_label ) . '</span>';
                    echo '</div>';
                }
                echo '</div>';
                echo '<p style="font-size:11px;color:#888;margin:8px 0 0 0;">Based on latest recorded triage. Re-run triage to refresh.</p>';
                echo '</div>';
            }
        }

        // Part D — Site Quality: broken link/image check (Pro+).
        $is_pro_plus = in_array( $current_plan, array( 'pro', 'agency' ), true );
        if ( $is_pro_plus && '' !== $site_id && '' !== $account_id ) {
            $lc_resp = self::mcp_get_json(
                '/v1/sites/' . rawurlencode( $site_id ) . '/link-checks',
                array( 'account_id' => $account_id, 'days' => '7', 'limit' => '20' )
            );
            $lc_ok       = isset( $lc_resp['ok'] ) ? (bool) $lc_resp['ok'] : ( isset( $lc_resp['total'] ) );
            $lc_checks   = isset( $lc_resp['checks'] ) && is_array( $lc_resp['checks'] ) ? $lc_resp['checks'] : array();
            $lc_total    = isset( $lc_resp['total'] ) ? (int) $lc_resp['total'] : count( $lc_checks );
            $lc_broken   = isset( $lc_resp['broken_count'] ) ? (int) $lc_resp['broken_count'] : 0;
            echo '<div class="opsgate-card" style="margin-top:16px;">';
            echo '<div class="opsgate-clients-surface-header"><h3 class="opsgate-clients-surface-title">Site Quality — Broken Links</h3><span class="opsgate-clients-surface-link">Last 7 days</span></div>';
            if ( 0 === $lc_total ) {
                echo '<p class="opsgate-clients-surface-copy" style="margin:8px 0 0 0;">No link check results in the last 7 days. A weekly automated check will appear here after the next scheduled run.</p>';
            } else {
                $lc_tone = $lc_broken > 0 ? 'bad' : 'good';
                echo '<p class="opsgate-clients-surface-copy" style="margin:8px 0 8px 0;">';
                echo esc_html( $lc_total . ' URL' . ( 1 === $lc_total ? '' : 's' ) . ' checked — ' . $lc_broken . ' broken.' );
                echo '</p>';
                $lc_broken_items = array_values( array_filter( $lc_checks, static function ( $c ) {
                    return ! empty( $c['is_broken'] );
                } ) );
                if ( ! empty( $lc_broken_items ) ) {
                    echo '<div class="opsgate-clients-identity-grid">';
                    foreach ( array_slice( $lc_broken_items, 0, 10 ) as $lc_item ) {
                        $lc_url    = isset( $lc_item['url'] ) ? (string) $lc_item['url'] : '';
                        $lc_status = isset( $lc_item['status_code'] ) ? (string) $lc_item['status_code'] : 'ERR';
                        $lc_type   = isset( $lc_item['resource_type'] ) ? (string) $lc_item['resource_type'] : 'link';
                        $lc_src    = isset( $lc_item['source_page'] ) ? (string) $lc_item['source_page'] : '';
                        $lc_short  = '' !== $lc_url ? ( strlen( $lc_url ) > 60 ? '…' . substr( $lc_url, -57 ) : $lc_url ) : '—';
                        echo '<div class="opsgate-clients-identity-card">';
                        echo '<span class="opsgate-clients-detail-label">' . esc_html( strtoupper( $lc_type ) . ' — ' . $lc_status ) . '</span>';
                        echo '<span class="opsgate-clients-detail-value"><a href="' . esc_url( $lc_url ) . '" target="_blank" rel="noopener noreferrer">' . esc_html( $lc_short ) . '</a></span>';
                        if ( '' !== $lc_src ) {
                            echo '<span style="font-size:10px;color:#888;">From: ' . esc_html( wp_parse_url( $lc_src, PHP_URL_PATH ) ?: $lc_src ) . '</span>';
                        }
                        echo '</div>';
                    }
                    echo '</div>';
                    if ( count( $lc_broken_items ) > 10 ) {
                        echo '<p style="font-size:11px;color:#888;margin:8px 0 0 0;">Showing 10 of ' . esc_html( (string) count( $lc_broken_items ) ) . ' broken URLs.</p>';
                    }
                }
            }
            echo '</div>';
        }

        // Part C — Free tier CTA: public check result with conversion prompt (Free plan only).
        if ( 'free' === $current_plan && '' !== $site_id ) {
            $pub_resp = self::mcp_get_json(
                '/v1/sites/' . rawurlencode( $site_id ) . '/public-check',
                array( 'account_id' => $account_id )
            );
            // UI Pass 7: fields match GET /v1/sites/{id}/public-check response.
            $pub_data         = isset( $pub_resp['ok'] ) && $pub_resp['ok'] && isset( $pub_resp['data'] ) && is_array( $pub_resp['data'] ) ? $pub_resp['data'] : array();
            $pub_reachable    = isset( $pub_data['reachable'] ) && null !== $pub_data['reachable'] ? (bool) $pub_data['reachable'] : null;
            $pub_ssl_valid    = isset( $pub_data['ssl_valid'] ) && null !== $pub_data['ssl_valid'] ? (bool) $pub_data['ssl_valid'] : null;
            $pub_ssl_days     = isset( $pub_data['ssl_days_to_expiry'] ) && null !== $pub_data['ssl_days_to_expiry'] ? (int) $pub_data['ssl_days_to_expiry'] : null;
            $pub_score        = isset( $pub_data['score'] ) && null !== $pub_data['score'] ? (string) $pub_data['score'] : null;
            $pub_grade        = isset( $pub_data['grade'] ) ? strtolower( trim( (string) $pub_data['grade'] ) ) : '';
            $pub_checked_at   = isset( $pub_data['checked_at'] ) ? trim( (string) $pub_data['checked_at'] ) : '';
            $pub_checked_label = '' !== $pub_checked_at ? self::canonical_report_datetime_label( $pub_checked_at ) : '';
            echo '<div class="opsgate-card" style="margin-top:16px;border-left:3px solid #0073aa;">';
            echo '<div class="opsgate-clients-surface-header"><h3 class="opsgate-clients-surface-title">Public Check Results</h3>';
            if ( '' !== $pub_checked_label ) {
                echo '<span class="opsgate-clients-surface-link">Last checked: ' . esc_html( $pub_checked_label ) . '</span>';
            } else {
                echo '<span class="opsgate-clients-surface-link">Free tier</span>';
            }
            echo '</div>';
            echo '<p class="opsgate-clients-surface-copy" style="margin:8px 0 8px 0;">The latest public reachability and SSL result for this site, based on the most recent recorded triage.</p>';
            if ( ! empty( $pub_data ) ) {
                echo '<div class="opsgate-clients-identity-grid">';
                if ( null !== $pub_reachable ) {
                    echo '<div class="opsgate-clients-identity-card">';
                    echo '<span class="opsgate-clients-detail-label">Reachability</span>';
                    echo '<span class="opsgate-clients-detail-value opsgate-tone-' . esc_attr( $pub_reachable ? 'good' : 'bad' ) . '">' . esc_html( $pub_reachable ? 'Online' : 'Unreachable' ) . '</span>';
                    echo '</div>';
                }
                if ( null !== $pub_ssl_valid ) {
                    echo '<div class="opsgate-clients-identity-card">';
                    echo '<span class="opsgate-clients-detail-label">SSL</span>';
                    echo '<span class="opsgate-clients-detail-value opsgate-tone-' . esc_attr( $pub_ssl_valid ? 'good' : 'bad' ) . '">' . esc_html( $pub_ssl_valid ? 'Valid' : 'Invalid / Expired' ) . '</span>';
                    echo '</div>';
                }
                if ( null !== $pub_ssl_days ) {
                    $pub_ssl_days_label = $pub_ssl_days <= 0 ? 'Expired' : $pub_ssl_days . ' days remaining';
                    $pub_ssl_days_tone  = $pub_ssl_days <= 0 ? 'bad' : ( $pub_ssl_days <= 14 ? 'bad' : ( $pub_ssl_days <= 30 ? 'warn' : 'good' ) );
                    echo '<div class="opsgate-clients-identity-card">';
                    echo '<span class="opsgate-clients-detail-label">SSL expiry</span>';
                    echo '<span class="opsgate-clients-detail-value opsgate-tone-' . esc_attr( $pub_ssl_days_tone ) . '">' . esc_html( $pub_ssl_days_label ) . '</span>';
                    echo '</div>';
                }
                if ( null !== $pub_score ) {
                    $pub_score_tone = in_array( $pub_grade, array( 'green', 'healthy' ), true ) ? 'good'
                        : ( in_array( $pub_grade, array( 'yellow', 'amber' ), true ) ? 'warn'
                        : ( in_array( $pub_grade, array( 'red', 'critical' ), true ) ? 'bad' : 'neutral' ) );
                    echo '<div class="opsgate-clients-identity-card">';
                    echo '<span class="opsgate-clients-detail-label">Security score</span>';
                    echo '<span class="opsgate-clients-detail-value opsgate-tone-' . esc_attr( $pub_score_tone ) . '">' . esc_html( $pub_score . ( '' !== $pub_grade ? ' — ' . ucfirst( $pub_grade ) : '' ) ) . '</span>';
                    echo '</div>';
                }
                echo '</div>';
            } else {
                echo '<p class="opsgate-clients-surface-copy" style="color:#888;margin:8px 0 0 0;">Public check results will appear here once a triage has run for this site.</p>';
            }
            echo '<div class="opsgate-alert-panel" style="margin-top:12px;">';
            echo '<p><strong>Unlock full triage, alerts, and reports.</strong> Upgrade to Starter to access plugin vulnerability scans, scheduled monitoring, PHP error tracking, and client-ready security reports.</p>';
            echo '<p><a href="https://opsgate.io/pricing" target="_blank" rel="noopener noreferrer">View Starter plan &rarr;</a></p>';
            echo '</div>';
            echo '</div>';
        }

        echo '<div class="opsgate-alert-panel" style="margin-top:16px;">';
        echo '<p><strong>Connect another site:</strong> Install the OpsGate plugin on any WordPress site, then pair it from Settings on that site. Each connected site joins this portfolio automatically and will appear in your OpsGate account alongside this one.</p>';
        echo '</div>';

        echo '</div>';
    }

    /**
     * Read raw/binary content from OpsGate MCP API (thin client proxy).
     *
     * @param string $path Path starting with /v1/...
     * @return array{ok:bool,http:int,body?:string,content_type?:string,content_disposition?:string,error?:string}
     */
    private static function mcp_get_raw( string $path ): array {
        $base = self::mcp_base_url();
        if ( ! is_string( $base ) || '' === trim( $base ) ) {
            return array( 'ok' => false, 'http' => 0, 'error' => 'MCP base URL not configured.' );
        }

        $url = rtrim( $base, '/' ) . $path;

        $headers = array( 'Accept' => '*/*' );
        if ( function_exists( 'opsgate_get_api_token' ) ) {
            $token = opsgate_get_api_token();
            if ( is_string( $token ) && '' !== trim( $token ) ) {
                $headers['X-Token'] = trim( $token );
            }
        }

        $resp = wp_remote_get(
            $url,
            array(
                'timeout'     => 20,
                'redirection' => 2,
                'headers'     => $headers,
            )
        );

        if ( is_wp_error( $resp ) ) {
            return array( 'ok' => false, 'http' => 0, 'error' => $resp->get_error_message() );
        }

        $http = (int) wp_remote_retrieve_response_code( $resp );
        $body = (string) wp_remote_retrieve_body( $resp );
        $content_type = (string) wp_remote_retrieve_header( $resp, 'content-type' );
        $content_disposition = (string) wp_remote_retrieve_header( $resp, 'content-disposition' );

        if ( $http < 200 || $http >= 300 ) {
            $error = '' !== $body ? $body : 'Binary request failed.';
            $decoded = json_decode( $body, true );
            if ( is_array( $decoded ) && isset( $decoded['detail'] ) && is_string( $decoded['detail'] ) && '' !== trim( $decoded['detail'] ) ) {
                $error = trim( $decoded['detail'] );
            }
            return array(
                'ok'    => false,
                'http'  => $http,
                'error' => $error,
            );
        }

        return array(
            'ok'                  => true,
            'http'                => $http,
            'body'                => $body,
            'content_type'        => ( '' !== $content_type ) ? $content_type : 'application/octet-stream',
            'content_disposition' => ( '' !== $content_disposition ) ? $content_disposition : 'attachment',
        );
    }

    /**
     * Week 10–12: Return the current export-record state for live Reports polling.
     * Reports must poll the same truth source they render from: export history.
     */
    public static function handle_export_record_status(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error(
                array(
                    'message' => 'Forbidden',
                ),
                403
            );
        }

        $export_job_id = isset( $_GET['export_job_id'] ) ? sanitize_text_field( wp_unslash( $_GET['export_job_id'] ) ) : '';
        $export_job_id = trim( $export_job_id );

        if ( '' === $export_job_id ) {
            wp_send_json_error(
                array(
                    'message' => 'Missing export job ID.',
                ),
                400
            );
        }

        $history = self::canonical_exports_history( 50 );
        if ( empty( $history['ok'] ) || empty( $history['items'] ) || ! is_array( $history['items'] ) ) {
            wp_send_json_error(
                array(
                    'message' => 'Could not load export history.',
                ),
                502
            );
        }

        $matched = null;
        foreach ( $history['items'] as $item ) {
            if ( ! is_array( $item ) ) {
                continue;
            }

            $candidate_export_job_id = isset( $item['export_job_id'] ) ? trim( (string) $item['export_job_id'] ) : '';
            if ( $candidate_export_job_id === $export_job_id ) {
                $matched = $item;
                break;
            }
        }

        if ( ! is_array( $matched ) ) {
            wp_send_json_error(
                array(
                    'message' => 'Export record not found.',
                ),
                404
            );
        }

        $state = isset( $matched['state'] ) ? strtoupper( trim( (string) $matched['state'] ) ) : '';
        $kind  = isset( $matched['kind'] ) ? trim( (string) $matched['kind'] ) : '';

        wp_send_json_success(
            array(
                'export_job_id' => $export_job_id,
                'state'         => $state,
                'kind'          => $kind,
                'terminal'      => in_array( $state, array( 'COMPLETED', 'FAILED' ), true ),
            )
        );
    }

    /**
     * Resolve the latest known export record state for the selected scope.
     *
     * @return array{ok:bool,state:string,kind:string,terminal:bool,error:string}
     */
    private static function export_record_state_summary( string $export_job_id ): array {
        $export_job_id = trim( $export_job_id );
        if ( '' === $export_job_id ) {
            return array(
                'ok'       => false,
                'state'    => '',
                'kind'     => '',
                'terminal' => false,
                'error'    => 'missing_export_job_id',
            );
        }

        $history = self::canonical_exports_history( 50 );
        if ( empty( $history['ok'] ) || empty( $history['items'] ) || ! is_array( $history['items'] ) ) {
            return array(
                'ok'       => false,
                'state'    => '',
                'kind'     => '',
                'terminal' => false,
                'error'    => 'export_history_unavailable',
            );
        }

        foreach ( $history['items'] as $item ) {
            if ( ! is_array( $item ) ) {
                continue;
            }

            $candidate_export_job_id = isset( $item['export_job_id'] ) ? trim( (string) $item['export_job_id'] ) : '';
            if ( $candidate_export_job_id !== $export_job_id ) {
                continue;
            }

            $state = isset( $item['state'] ) ? strtoupper( trim( (string) $item['state'] ) ) : '';
            $kind  = isset( $item['kind'] ) ? trim( (string) $item['kind'] ) : '';
            return array(
                'ok'       => true,
                'state'    => $state,
                'kind'     => $kind,
                'terminal' => in_array( $state, array( 'COMPLETED', 'FAILED' ), true ),
                'error'    => '',
            );
        }

        return array(
            'ok'       => false,
            'state'    => '',
            'kind'     => '',
            'terminal' => false,
            'error'    => 'export_record_not_found',
        );
    }

    /**
     * @return array<string,mixed>
     */
    private static function triage_live_status_snapshot(): array {
        $scope = self::get_mcp_scope_snapshot();
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id    = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';
        if ( '' === $account_id || '' === $site_id ) {
            return array(
                'ok'      => false,
                'message' => 'Missing canonical site scope.',
                'error'   => 'missing_scope',
            );
        }

        $runtime_refs = self::scope_runtime_refs_for_scope( $scope );
        $last_triage_job_id = trim( (string) ( $runtime_refs['last_triage_job_id'] ?? '' ) );
        $last_export_job_id = trim( (string) ( $runtime_refs['last_export_job_id'] ?? '' ) );
        $last_export_source_job_id = trim( (string) ( $runtime_refs['last_export_source_job_id'] ?? '' ) );
        $selected_site = self::current_selected_site_summary();
        $connection_status = isset( $selected_site['connection_status'] ) ? trim( (string) $selected_site['connection_status'] ) : 'external_only';
        $connection_mode   = isset( $selected_site['connection_mode'] ) ? trim( (string) $selected_site['connection_mode'] ) : 'public_scan';
        $connected_truth_available = 'connected' === strtolower( $connection_status ) && 'wp_connector' === strtolower( $connection_mode );

        $current_run_state = '';
        $current_run_copy = '';
        $started_label = 'No active run recorded';

        if ( '' !== $last_triage_job_id ) {
            $current_run = self::mcp_get_json( '/v1/jobs/' . rawurlencode( $last_triage_job_id ) );
            $current_run_job = is_array( $current_run ) && isset( $current_run['data'] ) && is_array( $current_run['data'] ) ? $current_run['data'] : array();
            if ( ! empty( $current_run_job ) && self::job_matches_scope( $current_run_job, $scope ) ) {
                $current_run_state = isset( $current_run_job['state'] ) ? strtoupper( trim( (string) $current_run_job['state'] ) ) : '';
                $started_value = isset( $current_run_job['started_at_utc'] ) ? trim( (string) $current_run_job['started_at_utc'] ) : '';
                if ( '' === $started_value ) {
                    $started_value = isset( $current_run_job['created_at_utc'] ) ? trim( (string) $current_run_job['created_at_utc'] ) : '';
                }
                if ( '' !== $started_value ) {
                    $started_label = self::canonical_report_datetime_label( $started_value );
                }
            }
        }
        $current_run_payload = isset( $current_run_job['payload_json'] ) && is_array( $current_run_job['payload_json'] ) ? $current_run_job['payload_json'] : array();
        $progress_payload = isset( $current_run_payload['progress'] ) && is_array( $current_run_payload['progress'] ) ? $current_run_payload['progress'] : array();
        $progress_stage_key = isset( $progress_payload['stage_key'] ) ? strtolower( trim( (string) $progress_payload['stage_key'] ) ) : '';
        $progress_stage_label = isset( $progress_payload['stage_label'] ) ? trim( (string) $progress_payload['stage_label'] ) : '';
        $progress_stage_copy = isset( $progress_payload['stage_copy'] ) ? trim( (string) $progress_payload['stage_copy'] ) : '';
        $progress_completed_keys = array();
        if ( isset( $progress_payload['completed_keys'] ) && is_array( $progress_payload['completed_keys'] ) ) {
            foreach ( $progress_payload['completed_keys'] as $progress_completed_key ) {
                $progress_completed_key = strtolower( trim( (string) $progress_completed_key ) );
                if ( '' === $progress_completed_key || in_array( $progress_completed_key, $progress_completed_keys, true ) ) {
                    continue;
                }
                $progress_completed_keys[] = $progress_completed_key;
            }
        }
        $progress_truth_available = '' !== $progress_stage_key || ! empty( $progress_completed_keys );

        $live_bundle = '' !== $last_triage_job_id ? self::triage_bundle_for_job_id( $last_triage_job_id ) : array(
            'ok'        => false,
            'job'       => array(),
            'artifacts' => array(),
            'error'     => 'missing_job_id',
        );
        $live_artifacts = ! empty( $live_bundle['ok'] ) && isset( $live_bundle['artifacts'] ) && is_array( $live_bundle['artifacts'] )
            ? $live_bundle['artifacts']
            : array();
        $live_inventory_ready = isset( $live_artifacts['inventory_snapshot']['body'] ) && is_array( $live_artifacts['inventory_snapshot']['body'] );
        $live_updates_ready = isset( $live_artifacts['update_posture']['body'] ) && is_array( $live_artifacts['update_posture']['body'] );
        $live_vulnerabilities_ready = isset( $live_artifacts['vulnerability_posture']['body'] ) && is_array( $live_artifacts['vulnerability_posture']['body'] );
        $live_reachability_ready = isset( $live_artifacts['reachability_posture']['body'] ) && is_array( $live_artifacts['reachability_posture']['body'] );
        $live_performance_ready = isset( $live_artifacts['performance_snapshot']['body'] ) && is_array( $live_artifacts['performance_snapshot']['body'] );
        $live_evidence_ready = ! empty( $live_artifacts );

        if ( 'QUEUED' === $current_run_state ) {
            $current_run_copy = 'Queued behind the API and waiting for worker execution.';
        } elseif ( 'RUNNING' === $current_run_state ) {
            $current_run_copy = 'Evidence is being recorded for this site now.';
        } elseif ( 'COMPLETED' === $current_run_state ) {
            $current_run_copy = 'The latest scan completed and results are ready to review.';
        } elseif ( 'FAILED' === $current_run_state ) {
            $current_run_copy = 'The latest run ended with issues and should be reviewed before sharing outputs.';
        }

        $export_state_upper = '';
        $export_copy = '';
        if ( '' !== $last_export_job_id ) {
            $export_summary = self::export_record_state_summary( $last_export_job_id );
            if ( ! empty( $export_summary['ok'] ) ) {
                $export_state_upper = isset( $export_summary['state'] ) ? strtoupper( (string) $export_summary['state'] ) : '';
            }
        }
        if ( '' !== $last_triage_job_id && '' !== $last_export_source_job_id && $last_export_source_job_id !== $last_triage_job_id ) {
            $last_export_job_id = '';
            $last_export_source_job_id = '';
            $export_state_upper = '';
        }

        if ( 'QUEUED' === $export_state_upper ) {
            $export_copy = 'Report packaging is queued for the latest recorded run.';
        } elseif ( 'RUNNING' === $export_state_upper ) {
            $export_copy = 'Rendered outputs are being packaged from the latest completed run.';
        } elseif ( 'COMPLETED' === $export_state_upper ) {
            $export_copy = 'Rendered outputs are ready in Reports.';
        } elseif ( 'FAILED' === $export_state_upper ) {
            $export_copy = 'The latest packaging attempt did not finish cleanly.';
        }
        $live_reports_ready = 'COMPLETED' === $export_state_upper || ( 'COMPLETED' === $current_run_state && '' === $export_state_upper );
        $live_complete_ready = 'COMPLETED' === $current_run_state && ! in_array( $export_state_upper, array( 'QUEUED', 'RUNNING', 'FAILED' ), true );

        $run_visual_key = 'pending';
        if ( 'FAILED' === $current_run_state || 'FAILED' === $export_state_upper ) {
            $run_visual_key = 'failed';
        } elseif ( 'QUEUED' === $current_run_state ) {
            $run_visual_key = 'queued';
        } elseif ( 'RUNNING' === $current_run_state || in_array( $export_state_upper, array( 'QUEUED', 'RUNNING' ), true ) ) {
            $run_visual_key = 'in_progress';
        } elseif ( 'COMPLETED' === $current_run_state || 'COMPLETED' === $export_state_upper ) {
            $run_visual_key = 'completed';
        }

        $progress_tone = 'info';
        if ( 'in_progress' === $run_visual_key || 'queued' === $run_visual_key ) {
            $progress_tone = 'warn';
        } elseif ( 'failed' === $run_visual_key ) {
            $progress_tone = 'bad';
        }

        $progress_title = 'Latest scan is ready to review';
        $progress_copy  = '' !== $current_run_copy ? $current_run_copy : 'Review the latest scan results and evidence.';
        if ( 'queued' === $run_visual_key ) {
            $progress_title = 'Security scan is queued';
        } elseif ( 'in_progress' === $run_visual_key ) {
            $progress_title = in_array( $export_state_upper, array( 'QUEUED', 'RUNNING' ), true ) ? 'Report packaging is still running' : 'OpsGate is gathering evidence now';
            $progress_copy  = in_array( $export_state_upper, array( 'QUEUED', 'RUNNING' ), true ) ? $export_copy : $current_run_copy;
        } elseif ( 'failed' === $run_visual_key ) {
            $progress_title = 'The latest run needs follow-up';
            $progress_copy  = '' !== $export_copy ? $export_copy : $current_run_copy;
        }

        $phase_items = array(
            array(
                'step' => 1,
                'key' => 'queued',
                'label' => 'Queued',
                'copy' => 'Accepted behind the API and waiting on worker execution.',
                'ready' => in_array( $current_run_state, array( 'QUEUED', 'RUNNING', 'FAILED', 'COMPLETED' ), true ) || '' !== $export_state_upper,
                'blocked' => false,
            ),
            array(
                'step' => 2,
                'key' => 'inventory',
                'label' => 'Inventory',
                'copy' => $connected_truth_available ? 'Authenticated WordPress inventory and footprint capture.' : 'Connected-only evidence stays blocked until connector trust is active.',
                'ready' => $connected_truth_available && $live_inventory_ready,
                'blocked' => ! $connected_truth_available,
            ),
            array(
                'step' => 3,
                'key' => 'updates',
                'label' => 'Updates',
                'copy' => $connected_truth_available ? 'Version drift and package currency review.' : 'Connected-only evidence stays blocked until connector trust is active.',
                'ready' => $connected_truth_available && $live_updates_ready,
                'blocked' => ! $connected_truth_available,
            ),
            array(
                'step' => 4,
                'key' => 'vulnerabilities',
                'label' => 'Vulnerabilities',
                'copy' => $connected_truth_available ? 'Live plugin advisory coverage and installed-version evaluation.' : 'Connected-only evidence stays blocked until connector trust is active.',
                'ready' => $connected_truth_available && $live_vulnerabilities_ready,
                'blocked' => ! $connected_truth_available,
            ),
            array(
                'step' => 5,
                'key' => 'reachability',
                'label' => 'Reachability',
                'copy' => 'Public HTTP and transport posture checks.',
                'ready' => $live_reachability_ready,
                'blocked' => false,
            ),
            array(
                'step' => 6,
                'key' => 'performance',
                'label' => 'Performance',
                'copy' => 'Recorded latency and response timing snapshot.',
                'ready' => $live_performance_ready,
                'blocked' => false,
            ),
            array(
                'step' => 7,
                'key' => 'reports',
                'label' => 'Report packaging',
                'copy' => 'Rendered outputs linked to the current run.',
                'ready' => $live_reports_ready,
                'blocked' => false,
            ),
            array(
                'step' => 8,
                'key' => 'complete',
                'label' => 'Complete',
                'copy' => 'Run and package are ready for review or sharing.',
                'ready' => $live_complete_ready,
                'blocked' => false,
            ),
        );

        $phase_current_key = '';
        if ( $progress_truth_available && 'completed' !== $run_visual_key ) {
            foreach ( $phase_items as $index => $phase_item ) {
                $phase_key = (string) ( $phase_item['key'] ?? '' );
                if ( ! empty( $phase_item['blocked'] ) ) {
                    continue;
                }
                if ( 'reports' === $phase_key || 'complete' === $phase_key ) {
                    continue;
                }
                $phase_items[ $index ]['ready'] = in_array( $phase_key, $progress_completed_keys, true );
            }
            if ( '' !== $progress_stage_key ) {
                $phase_current_key = $progress_stage_key;
            }
        }

        if ( '' === $phase_current_key ) {
            if ( 'queued' === $run_visual_key ) {
                $phase_current_key = 'queued';
            } elseif ( 'in_progress' === $run_visual_key ) {
                $phase_current_key = in_array( $export_state_upper, array( 'QUEUED', 'RUNNING' ), true ) ? 'reports' : 'inventory';
                foreach ( $phase_items as $phase_item ) {
                    if ( ! empty( $phase_item['blocked'] ) ) {
                        continue;
                    }
                    if ( empty( $phase_item['ready'] ) ) {
                        $phase_current_key = (string) $phase_item['key'];
                        break;
                    }
                }
            } elseif ( 'failed' === $run_visual_key ) {
                $phase_current_key = in_array( $export_state_upper, array( 'FAILED' ), true ) ? 'reports' : 'queued';
                foreach ( $phase_items as $phase_item ) {
                    if ( ! empty( $phase_item['blocked'] ) ) {
                        continue;
                    }
                    if ( empty( $phase_item['ready'] ) ) {
                        $phase_current_key = (string) $phase_item['key'];
                        break;
                    }
                }
            }
        }

        $phase_state_labels = array(
            'pending'  => 'Waiting',
            'current'  => 'Active now',
            'complete' => 'Complete',
            'failed'   => 'Needs review',
            'blocked'  => 'Blocked',
        );

        $phase_active_count = 0;
        $phase_complete_count = 0;
        $progress_phase_label = 'Waiting';
        $progress_phase_copy = 'Waiting for the next truthful run state.';

        foreach ( $phase_items as $index => $phase_item ) {
            $phase_items[ $index ]['state'] = 'pending';
            if ( ! empty( $phase_item['blocked'] ) ) {
                $phase_items[ $index ]['state'] = 'blocked';
                $phase_items[ $index ]['state_label'] = $phase_state_labels['blocked'];
                continue;
            }

            ++$phase_active_count;
            if ( 'completed' === $run_visual_key ) {
                $phase_items[ $index ]['state'] = 'complete';
                $phase_items[ $index ]['state_label'] = $phase_state_labels['complete'];
                ++$phase_complete_count;
                continue;
            }

            if ( (string) $phase_item['key'] === $phase_current_key ) {
                $phase_items[ $index ]['state'] = 'failed' === $run_visual_key ? 'failed' : 'current';
                $phase_items[ $index ]['state_label'] = $phase_state_labels[ $phase_items[ $index ]['state'] ];
                $progress_phase_label = (string) $phase_item['label'];
                $progress_phase_copy = (string) $phase_item['copy'];
                continue;
            }

            if ( ! empty( $phase_item['ready'] ) ) {
                $phase_items[ $index ]['state'] = 'complete';
                $phase_items[ $index ]['state_label'] = $phase_state_labels['complete'];
                ++$phase_complete_count;
            } else {
                $phase_items[ $index ]['state_label'] = $phase_state_labels['pending'];
            }
        }

        if ( 'completed' === $run_visual_key ) {
            $progress_phase_label = 'Complete';
            $progress_phase_copy = 'Scan results and rendered outputs are ready for review.';
        } elseif ( 'failed' === $run_visual_key && '' === $phase_current_key ) {
            $progress_phase_label = 'Needs review';
            $progress_phase_copy = 'The latest run did not finish cleanly and should be reviewed before acting or sharing.';
        } elseif ( 'failed' === $run_visual_key && '' !== $phase_current_key ) {
            foreach ( $phase_items as $phase_item ) {
                if ( (string) $phase_item['key'] === $phase_current_key ) {
                    $progress_phase_label = (string) $phase_item['label'];
                    $progress_phase_copy = 'The scan stopped before this phase finished. Review the latest results before rerunning.';
                    break;
                }
            }
        } elseif ( '' !== $progress_stage_label || '' !== $progress_stage_copy ) {
            if ( '' !== $progress_stage_label ) {
                $progress_phase_label = $progress_stage_label;
            }
            if ( '' !== $progress_stage_copy ) {
                $progress_phase_copy = $progress_stage_copy;
            }
        }

        $progress_percent = 0;
        if ( $phase_active_count > 0 ) {
            if ( $progress_truth_available && 'completed' !== $run_visual_key ) {
                $fraction = (float) $phase_complete_count / (float) $phase_active_count;
                if ( '' !== $phase_current_key && 'failed' !== $run_visual_key ) {
                    $fraction = min( 0.96, $fraction + ( 0.5 / (float) $phase_active_count ) );
                } elseif ( 'queued' === $run_visual_key ) {
                    $fraction = max( $fraction, 0.08 );
                } elseif ( 'failed' === $run_visual_key ) {
                    $fraction = min( 0.92, $fraction + 0.05 );
                }
            } else {
                $fraction = (float) $phase_complete_count / (float) $phase_active_count;
                if ( 'queued' === $run_visual_key ) {
                    $fraction = max( $fraction, 0.08 );
                } elseif ( 'in_progress' === $run_visual_key ) {
                    $fraction = min( 0.96, $fraction + ( in_array( $export_state_upper, array( 'QUEUED', 'RUNNING' ), true ) ? 0.16 : 0.08 ) );
                } elseif ( 'failed' === $run_visual_key ) {
                    $fraction = min( 0.92, $fraction + 0.05 );
                } elseif ( 'completed' === $run_visual_key ) {
                    $fraction = 1;
                }
            }
            $progress_percent = (int) round( 100 * $fraction );
        }

        $lifecycle_profile = $connected_truth_available
            ? array(
                array( 'key' => 'queued', 'label' => 'Queued' ),
                array( 'key' => 'collecting_wordpress_evidence', 'label' => 'Collecting WordPress evidence' ),
                array( 'key' => 'checking_vulnerabilities', 'label' => 'Checking vulnerabilities' ),
                array( 'key' => 'checking_uptime_performance', 'label' => 'Checking uptime/performance' ),
                array( 'key' => 'finalizing', 'label' => 'Finalizing' ),
                array( 'key' => 'complete', 'label' => 'Complete' ),
            )
            : array(
                array( 'key' => 'queued', 'label' => 'Queued' ),
                array( 'key' => 'checking_public_site', 'label' => 'Checking public site' ),
                array( 'key' => 'finalizing', 'label' => 'Finalizing' ),
                array( 'key' => 'complete', 'label' => 'Complete' ),
            );
        $lifecycle_map = $connected_truth_available
            ? array(
                'queued' => 'queued',
                'inventory' => 'collecting_wordpress_evidence',
                'updates' => 'collecting_wordpress_evidence',
                'vulnerabilities' => 'checking_vulnerabilities',
                'reachability' => 'checking_uptime_performance',
                'performance' => 'checking_uptime_performance',
                'reports' => 'finalizing',
                'complete' => 'complete',
            )
            : array(
                'queued' => 'queued',
                'inventory' => 'checking_public_site',
                'updates' => 'checking_public_site',
                'vulnerabilities' => 'checking_public_site',
                'reachability' => 'checking_public_site',
                'performance' => 'finalizing',
                'reports' => 'finalizing',
                'complete' => 'complete',
            );
        $lifecycle_current_key = isset( $lifecycle_map[ $phase_current_key ] ) ? (string) $lifecycle_map[ $phase_current_key ] : '';
        if ( '' === $lifecycle_current_key ) {
            if ( 'queued' === $run_visual_key ) {
                $lifecycle_current_key = 'queued';
            } elseif ( 'completed' === $run_visual_key ) {
                $lifecycle_current_key = 'complete';
            } elseif ( 'in_progress' === $run_visual_key ) {
                $lifecycle_current_key = $connected_truth_available ? 'collecting_wordpress_evidence' : 'checking_public_site';
            } elseif ( 'failed' === $run_visual_key ) {
                $lifecycle_current_key = $connected_truth_available ? 'checking_uptime_performance' : 'finalizing';
            }
        }
        $normalized_phase_items = array();
        $normalized_current_index = 0;
        foreach ( $lifecycle_profile as $profile_index => $profile_item ) {
            if ( (string) $profile_item['key'] === $lifecycle_current_key ) {
                $normalized_current_index = $profile_index;
                break;
            }
        }
        foreach ( $lifecycle_profile as $profile_index => $profile_item ) {
            $normalized_state = 'pending';
            if ( 'completed' === $run_visual_key ) {
                $normalized_state = 'complete';
            } elseif ( 'failed' === $run_visual_key && $profile_index === $normalized_current_index ) {
                $normalized_state = 'failed';
            } elseif ( $profile_index < $normalized_current_index ) {
                $normalized_state = 'complete';
            } elseif ( $profile_index === $normalized_current_index ) {
                $normalized_state = 'current';
            }
            $normalized_phase_items[] = array(
                'key' => (string) $profile_item['key'],
                'state' => $normalized_state,
                'state_label' => 'complete' === $normalized_state ? 'Complete' : ( 'current' === $normalized_state ? 'Active now' : ( 'failed' === $normalized_state ? 'Needs review' : 'Waiting' ) ),
            );
        }
        if ( isset( $lifecycle_profile[ $normalized_current_index ]['label'] ) ) {
            $progress_phase_label = (string) $lifecycle_profile[ $normalized_current_index ]['label'];
        }
        if ( $connected_truth_available && 'Collecting WordPress evidence' === $progress_phase_label && '' === $progress_phase_copy ) {
            $progress_phase_copy = 'Collecting authenticated WordPress evidence for this site.';
        }

        $live_states = array_values( array_unique( array_filter( array( $current_run_state, $export_state_upper ) ) ) );

        return array(
            'ok' => true,
            'job_id' => $last_triage_job_id,
            'export_job_id' => $last_export_job_id,
            'export_source_job_id' => $last_export_source_job_id,
            'run_state' => $current_run_state,
            'export_state' => $export_state_upper,
            'live_states' => $live_states,
            'run_visual_key' => $run_visual_key,
            'progress_tone' => $progress_tone,
            'progress_title' => $progress_title,
            'progress_copy' => $progress_copy,
            'progress_percent' => $progress_percent,
            'progress_phase_label' => $progress_phase_label,
            'progress_phase_copy' => $progress_phase_copy,
            'progress_meter_label' => sprintf( '%d%% of the current scan is complete', $progress_percent ),
            'elapsed_label' => 'Last activity ' . $started_label,
            'evidence_label' => in_array( $run_visual_key, array( 'queued', 'in_progress' ), true )
                ? ( $live_evidence_ready ? 'Scan data is accumulating' : 'Scan in progress' )
                : ( $live_evidence_ready ? 'Results ready' : 'Results not yet available' ),
            'phase_items' => $normalized_phase_items,
            'should_refresh' => in_array( $current_run_state, array( 'COMPLETED', 'FAILED' ), true ) || in_array( $export_state_upper, array( 'COMPLETED', 'FAILED' ), true ),
            'terminal' => ! array_filter(
                $live_states,
                static function ( string $state_value ): bool {
                    return ! in_array( strtoupper( $state_value ), array( 'COMPLETED', 'FAILED' ), true );
                }
            ),
        );
    }

    public static function handle_triage_live_status(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error(
                array(
                    'message' => 'Forbidden',
                ),
                403
            );
        }

        $payload = self::triage_live_status_snapshot();
        if ( empty( $payload['ok'] ) ) {
            wp_send_json_error(
                array(
                    'message' => isset( $payload['message'] ) ? (string) $payload['message'] : 'Could not load triage status.',
                    'error' => isset( $payload['error'] ) ? (string) $payload['error'] : 'triage_status_unavailable',
                ),
                502
            );
        }

        wp_send_json_success( $payload );
    }

    /**
     * Download canonical report/export artifacts through WordPress.
     *
     * Browser -> WP admin-post -> MCP authority -> streamed response
     *
     * This keeps WordPress thin and avoids exposing internal Docker hostnames
     * like mcp/opsgate-mcp to the browser.
     */
    public static function handle_download_export(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_download_export' );

        $kind = isset( $_GET['kind'] ) ? sanitize_text_field( wp_unslash( $_GET['kind'] ) ) : '';
        $export_job_id = isset( $_GET['export_job_id'] ) ? sanitize_text_field( wp_unslash( $_GET['export_job_id'] ) ) : '';
        $mode = isset( $_GET['mode'] ) ? sanitize_text_field( wp_unslash( $_GET['mode'] ) ) : 'download';

        $kind = trim( $kind );
        $export_job_id = trim( $export_job_id );
        $mode = 'view' === strtolower( trim( $mode ) ) ? 'view' : 'download';

        if ( '' === $kind || '' === $export_job_id ) {
            wp_die( 'Missing download parameters.', 400 );
        }

        $path = '';
        if ( 'report_html' === $kind ) {
            $path = '/v1/exports/report-html/' . rawurlencode( $export_job_id );
        } elseif ( 'report_pdf' === $kind ) {
            $path = '/v1/exports/report-pdf/' . rawurlencode( $export_job_id );
        } elseif ( 'report_xlsx' === $kind ) {
            $path = '/v1/exports/report-xlsx/' . rawurlencode( $export_job_id );
        } elseif ( 'csv' === $kind || 'export_csv' === $kind || 'triage_csv' === $kind ) {
            $path = '/v1/exports/csv/' . rawurlencode( $export_job_id );
        } elseif ( 'triage_json' === $kind || 'export_triage_json' === $kind ) {
            $path = '/v1/exports/triage-json/' . rawurlencode( $export_job_id );
        } elseif ( 'triage_xml' === $kind || 'export_triage_xml' === $kind ) {
            $path = '/v1/exports/triage-xml/' . rawurlencode( $export_job_id );
        } else {
            wp_die( 'Unsupported download type.', 400 );
        }

        $resp = self::mcp_get_raw( $path );
        if ( empty( $resp['ok'] ) ) {
            $message = isset( $resp['error'] ) ? (string) $resp['error'] : 'Download failed.';
            wp_die( esc_html( $message ), (int) ( $resp['http'] ?? 500 ) );
        }

        $content_type = isset( $resp['content_type'] ) ? (string) $resp['content_type'] : 'application/octet-stream';
        $content_disposition = isset( $resp['content_disposition'] ) ? (string) $resp['content_disposition'] : '';
        $body = isset( $resp['body'] ) ? (string) $resp['body'] : '';

        if ( 'report_pdf' === $kind ) {
            // Serve the canonical stored PDF artifact from the worker directly.
            // The MCP API already returns the worker-generated styled PDF bytes.
            // Override the filename to a human-readable name; do not re-render via TCPDF.
            $content_type = 'application/pdf';
            $content_disposition = 'attachment; filename="opsgate-security-report-' . date( 'Y-m-d' ) . '.pdf"';
        }

        if ( 'report_xlsx' === $kind && 'download' === $mode ) {
            $rebuilt_xlsx = self::render_client_xlsx_from_bytes( $body );
            if ( '' !== $rebuilt_xlsx ) {
                $content_type        = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
                $content_disposition = 'attachment; filename="opsgate-security-report-' . date( 'Y-m-d' ) . '.xlsx"';
                $body                = $rebuilt_xlsx;
            }
        }

        if ( ( 'csv' === $kind || 'export_csv' === $kind || 'triage_csv' === $kind ) && 'download' === $mode ) {
            $rebuilt_csv = self::render_client_csv_from_bytes( $body );
            if ( '' !== $rebuilt_csv ) {
                $content_type        = 'text/csv; charset=utf-8';
                $content_disposition = 'attachment; filename="opsgate-security-report-' . date( 'Y-m-d' ) . '.csv"';
                $body                = $rebuilt_csv;
            }
        }

        if ( headers_sent() ) {
            wp_die( 'Download headers already sent.', 500 );
        }

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

        nocache_headers();
        if ( 'view' === $mode && ! self::canonical_report_supports_inline_view( $kind ) ) {
            wp_die( 'This export downloads directly. Inline view is not supported for this format.', 400 );
        }

        if ( 'view' === $mode && ( 'csv' === $kind || 'export_csv' === $kind || 'triage_csv' === $kind ) ) {
            $csv_lines = preg_split( '/\r\n|\r|\n/', $body );
            $csv_rows  = array();
            if ( is_array( $csv_lines ) ) {
                foreach ( $csv_lines as $csv_line ) {
                    if ( '' === trim( (string) $csv_line ) ) {
                        continue;
                    }
                    $parsed = str_getcsv( (string) $csv_line );
                    if ( is_array( $parsed ) && ! empty( $parsed ) ) {
                        $csv_rows[] = $parsed;
                    }
                }
            }
            $raw_header = ! empty( $csv_rows ) ? array_shift( $csv_rows ) : array( 'Section', 'Finding', 'Status', 'Severity', 'Recommendation', 'Evidence Summary', 'Report Date' );
            $csv_header_map = array(
                'section'          => 'Section',
                'finding'          => 'Finding',
                'status'           => 'Status',
                'severity'         => 'Severity',
                'recommendation'   => 'Recommendation',
                'evidence'         => 'Evidence Summary',
                'evidence_summary' => 'Evidence Summary',
                'run_id'           => 'Run Reference',
                'job_id'           => 'Run Reference',
                'export_job_id'    => 'Run Reference',
                'report_date'      => 'Report Date',
                'date'             => 'Report Date',
                'site'             => 'Site',
                'site_name'        => 'Site',
                'value'            => 'Value',
                'detail'           => 'Detail',
            );
            $csv_header = array_map( static function ( $col ) use ( $csv_header_map ) {
                $key = strtolower( trim( (string) $col ) );
                $key = preg_replace( '/[^a-z0-9_]/', '_', $key ) ?? $key;
                return $csv_header_map[ $key ] ?? ucwords( str_replace( '_', ' ', $key ) );
            }, $raw_header );
            header( 'Content-Type: text/html; charset=utf-8' );
            $inline_filename = 'opsgate-' . sanitize_file_name( $kind . '-' . $export_job_id ) . '.html';
            header( 'Content-Disposition: inline; filename="' . $inline_filename . '"' );
            echo '<!doctype html><html><head><meta charset="utf-8"><title>OpsGate Security Report</title><style>*{box-sizing:border-box;}body{margin:0;padding:32px;font:15px/1.6 "Segoe UI","Helvetica Neue",Arial,sans-serif;background:#eef4fb;color:#12304a;}main{max-width:1180px;margin:0 auto;}h1{margin:0 0 4px;font-size:28px;font-weight:900;color:#0d2940;}h1+p{color:#4b6478;font-size:14px;margin:0 0 20px;}table{width:100%;border-collapse:collapse;background:#fff;border-radius:14px;overflow:hidden;box-shadow:0 8px 24px rgba(16,39,67,.08);}th,td{text-align:left;padding:11px 14px;border-bottom:1px solid #e3ebf3;vertical-align:top;}th{background:#eef6ff;color:#0d2940;font-size:11px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;}tr:last-child td{border-bottom:none;}tr:nth-child(even) td{background:#f8fbff;}</style></head><body><main><h1>OpsGate Security Report</h1><p>Site findings, status, severity, and recommendations — ready to share with your client.</p><table><thead><tr>';
            foreach ( $csv_header as $csv_header_cell ) {
                echo '<th>' . esc_html( (string) $csv_header_cell ) . '</th>';
            }
            echo '</tr></thead><tbody>';
            foreach ( $csv_rows as $csv_row ) {
                echo '<tr>';
                foreach ( $csv_header as $csv_index => $unused_header ) {
                    $csv_cell = isset( $csv_row[ $csv_index ] ) ? (string) $csv_row[ $csv_index ] : '';
                    echo '<td>' . esc_html( $csv_cell ) . '</td>';
                }
                echo '</tr>';
            }
            echo '</tbody></table></main></body></html>';
            exit;
        }

        if ( 'view' === $mode && 'report_xlsx' === $kind ) {
            $preview_html = self::xlsx_preview_document( $body, 'OpsGate Client Security Report' );
            if ( '' === $preview_html ) {
                wp_die( 'This workbook could not be rendered for inline preview.', 500 );
            }
            header( 'Content-Type: text/html; charset=utf-8' );
            $inline_filename = 'opsgate-' . sanitize_file_name( $kind . '-' . $export_job_id ) . '.html';
            header( 'Content-Disposition: inline; filename="' . $inline_filename . '"' );
            echo $preview_html;
            exit;
        }

        if ( 'view' === $mode && 'report_html' === $kind ) {
            $client_html = self::render_client_html_view( $body );
            header( 'Content-Type: text/html; charset=utf-8' );
            $inline_filename = 'opsgate-' . sanitize_file_name( $kind . '-' . $export_job_id ) . '.html';
            header( 'Content-Disposition: inline; filename="' . $inline_filename . '"' );
            echo $client_html;
            exit;
        }

        header( 'Content-Type: ' . $content_type );
        if ( 'view' === $mode ) {
            $inline_filename = 'opsgate-' . sanitize_file_name( $kind . '-' . $export_job_id );
            if ( 'report_html' === $kind ) {
                $inline_filename .= '.html';
            } elseif ( 'report_pdf' === $kind ) {
                $inline_filename .= '.pdf';
            } elseif ( 'report_xlsx' === $kind ) {
                $inline_filename .= '.xlsx';
            } else {
                $inline_filename .= '.csv';
            }
            header( 'Content-Disposition: inline; filename="' . $inline_filename . '"' );
        } elseif ( '' !== $content_disposition ) {
            header( 'Content-Disposition: ' . $content_disposition );
        } else {
            header( 'Content-Disposition: attachment; filename="opsgate-download"' );
        }
        header( 'Content-Length: ' . strlen( $body ) );

        echo $body;
        exit;
    }


    /**
     * Post JSON to OpsGate MCP API (thin client).
     *
     * @param string $path Path starting with /v1/...
     * @param array  $body JSON body
     * @return array{ok:bool,http:int,data?:array,error?:string}
     */
    private static function mcp_post_json( string $path, array $body ): array {
        $base = self::mcp_base_url();
        if ( ! is_string( $base ) || '' === trim( $base ) ) {
            return array( 'ok' => false, 'http' => 0, 'error' => 'MCP base URL not configured.' );
        }

        $url = rtrim( $base, '/' ) . $path;

        $headers = array(
            'Accept'       => 'application/json',
            'Content-Type' => 'application/json',
        );

        if ( function_exists( 'opsgate_get_api_token' ) ) {
            $token = opsgate_get_api_token();
            if ( is_string( $token ) && '' !== trim( $token ) ) {
                $headers['X-Token'] = trim( $token );
            }
        }

        $resp = wp_remote_post(
            $url,
            array(
                'timeout'     => 15,
                'redirection' => 2,
                'headers'     => $headers,
                'body'        => wp_json_encode( $body ),
            )
        );

        if ( is_wp_error( $resp ) ) {
            return array( 'ok' => false, 'http' => 0, 'error' => $resp->get_error_message() );
        }

        $http = (int) wp_remote_retrieve_response_code( $resp );
        $raw  = (string) wp_remote_retrieve_body( $resp );

        $data = json_decode( $raw, true );
        if ( ! is_array( $data ) ) {
            return array( 'ok' => false, 'http' => $http, 'error' => 'Invalid JSON from MCP.' );
        }

        if ( $http < 200 || $http >= 300 ) {
            $detail = self::mcp_error_message_from_payload( $data, 'Request failed.' );
            return array( 'ok' => false, 'http' => $http, 'error' => $detail, 'data' => $data );
        }

        return array( 'ok' => true, 'http' => $http, 'data' => $data );
    }

    /**
     * Patch JSON to OpsGate MCP API (thin client).
     *
     * @param string $path Path starting with /v1/...
     * @param array  $body JSON body
     * @return array{ok:bool,http:int,data?:array,error?:string}
     */
    private static function mcp_patch_json( string $path, array $body ): array {
        $base = self::mcp_base_url();
        if ( ! is_string( $base ) || '' === trim( $base ) ) {
            return array( 'ok' => false, 'http' => 0, 'error' => 'MCP base URL not configured.' );
        }

        $url = rtrim( $base, '/' ) . $path;

        $headers = array(
            'Accept'       => 'application/json',
            'Content-Type' => 'application/json',
        );

        if ( function_exists( 'opsgate_get_api_token' ) ) {
            $token = opsgate_get_api_token();
            if ( is_string( $token ) && '' !== trim( $token ) ) {
                $headers['X-Token'] = trim( $token );
            }
        }

        $resp = wp_remote_request(
            $url,
            array(
                'method'      => 'PATCH',
                'timeout'     => 15,
                'redirection' => 2,
                'headers'     => $headers,
                'body'        => wp_json_encode( $body ),
            )
        );

        if ( is_wp_error( $resp ) ) {
            return array( 'ok' => false, 'http' => 0, 'error' => $resp->get_error_message() );
        }

        $http = (int) wp_remote_retrieve_response_code( $resp );
        $raw  = (string) wp_remote_retrieve_body( $resp );

        $data = json_decode( $raw, true );
        if ( ! is_array( $data ) ) {
            return array( 'ok' => false, 'http' => $http, 'error' => 'Invalid JSON from MCP.' );
        }

        if ( $http < 200 || $http >= 300 ) {
            $detail = self::mcp_error_message_from_payload( $data, 'Request failed.' );
            return array( 'ok' => false, 'http' => $http, 'error' => $detail, 'data' => $data );
        }

        return array( 'ok' => true, 'http' => $http, 'data' => $data );
    }

    /**
     * @param array<string,mixed> $body
     */
    private static function mcp_delete_json( string $path, array $body = array() ): array {
        $base = self::mcp_base_url();
        if ( ! is_string( $base ) || '' === trim( $base ) ) {
            return array( 'ok' => false, 'http' => 0, 'error' => 'MCP base URL not configured.' );
        }

        $url = rtrim( $base, '/' ) . $path;

        $headers = array(
            'Accept'       => 'application/json',
            'Content-Type' => 'application/json',
        );

        if ( function_exists( 'opsgate_get_api_token' ) ) {
            $token = opsgate_get_api_token();
            if ( is_string( $token ) && '' !== trim( $token ) ) {
                $headers['X-Token'] = trim( $token );
            }
        }

        $request_args = array(
            'method'      => 'DELETE',
            'timeout'     => 15,
            'redirection' => 2,
            'headers'     => $headers,
        );
        if ( ! empty( $body ) ) {
            $request_args['body'] = wp_json_encode( $body );
        }

        $resp = wp_remote_request( $url, $request_args );

        if ( is_wp_error( $resp ) ) {
            return array( 'ok' => false, 'http' => 0, 'error' => $resp->get_error_message() );
        }

        $http = (int) wp_remote_retrieve_response_code( $resp );
        $raw  = (string) wp_remote_retrieve_body( $resp );
        if ( '' === trim( $raw ) ) {
            return $http >= 200 && $http < 300
                ? array( 'ok' => true, 'http' => $http, 'data' => array() )
                : array( 'ok' => false, 'http' => $http, 'error' => 'Request failed.' );
        }

        $data = json_decode( $raw, true );
        if ( ! is_array( $data ) ) {
            return array( 'ok' => false, 'http' => $http, 'error' => 'Invalid JSON from MCP.' );
        }

        if ( $http < 200 || $http >= 300 ) {
            $detail = self::mcp_error_message_from_payload( $data, 'Request failed.' );
            return array( 'ok' => false, 'http' => $http, 'error' => $detail, 'data' => $data );
        }

        return array( 'ok' => true, 'http' => $http, 'data' => $data );
    }

    /**
     * Canonical portfolio triage payload basis used for manual and scheduled dispatch.
     *
     * @return array<string,mixed>
     */
    private static function canonical_portfolio_triage_payload_basis(): array {
        $identity = self::get_identity_snapshot();
        $scope = self::get_mcp_scope_snapshot();
        $site_config = self::canonical_site_config();
        $site_config_item = ! empty( $site_config['ok'] ) && isset( $site_config['item'] ) && is_array( $site_config['item'] ) ? $site_config['item'] : array();
        $site_url = self::connected_site_url( $site_config_item, $scope );
        $site_host = (string) ( wp_parse_url( $site_url, PHP_URL_HOST ) ?: '' );

        if ( '' === $site_host ) {
            $parsed_host = wp_parse_url( $site_url, PHP_URL_HOST );
            $site_host   = is_string( $parsed_host ) ? trim( $parsed_host ) : '';
        }

        $portfolio_id = trim( (string) get_option( 'opsgate_portfolio_id', '' ) );
        if ( '' === $portfolio_id ) {
            $portfolio_id = 'portfolio_default';
        }

        $payload = array(
            'portfolio_id'       => $portfolio_id,
            'domain'             => $site_host,
            'site_url'           => $site_url,
            'site_host'          => $site_host,
        );

        return $payload;
    }

    /**
     * Read the canonical portfolio triage schedule for this connected site.
     *
     * @return array{ok:bool,schedule:array<string,mixed>,error:string}
     */
    private static function canonical_portfolio_triage_schedule(): array {
        $scope = self::get_mcp_scope_snapshot();
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id    = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';

        if ( '' === $account_id || '' === $site_id ) {
            return array(
                'ok'       => false,
                'schedule' => array(),
                'error'    => 'Connect this site in Settings before configuring schedules.',
            );
        }

        $resp = self::mcp_get_json(
            '/v1/run-schedules/portfolio-triage',
            array(
                'account_id' => $account_id,
                'site_id'    => $site_id,
            )
        );

        if ( empty( $resp['ok'] ) ) {
            return array(
                'ok'       => false,
                'schedule' => array(),
                'error'    => isset( $resp['error'] ) ? (string) $resp['error'] : 'Could not load the saved schedule.',
            );
        }

        $data = isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array();
        $schedule = isset( $data['schedule'] ) && is_array( $data['schedule'] ) ? $data['schedule'] : array();

        return array(
            'ok'       => true,
            'schedule' => $schedule,
            'error'    => '',
        );
    }

    /**
     * Convert canonical schedule truth into the legacy row shape expected by the current Settings UI.
     *
     * @param array{ok:bool,schedule:array<string,mixed>,error:string} $state
     * @return array<string,array<string,mixed>>
     */
    private static function canonical_schedule_rows_for_ui( array $state ): array {
        $schedule = isset( $state['schedule'] ) && is_array( $state['schedule'] ) ? $state['schedule'] : array();
        $product = isset( $schedule['product'] ) && is_array( $schedule['product'] ) ? $schedule['product'] : array();

        $is_enabled = ! empty( $schedule['is_enabled'] );
        $cadence    = isset( $schedule['cadence'] ) ? (string) $schedule['cadence'] : 'disabled';
        $time_hm    = isset( $schedule['time_hm_utc'] ) ? (string) $schedule['time_hm_utc'] : '02:00';
        $ui_mode    = isset( $product['ui_mode'] ) ? (string) $product['ui_mode'] : '';
        $has_saved_schedule = ! empty( $product['has_saved_schedule'] );
        $allowed_cadences = isset( $product['allowed_cadences'] ) && is_array( $product['allowed_cadences'] ) ? array_values( $product['allowed_cadences'] ) : array();

        return array(
            'portfolio_triage' => array(
                'mode'                 => '' !== $ui_mode ? $ui_mode : ( $is_enabled ? $cadence : 'off' ),
                'time'                 => $time_hm,
                'timezone'             => isset( $schedule['timezone'] ) ? (string) $schedule['timezone'] : 'UTC',
                'dow'                  => isset( $schedule['day_of_week'] ) ? $schedule['day_of_week'] : null,
                'dom'                  => isset( $schedule['day_of_month'] ) ? $schedule['day_of_month'] : null,
                'schedule_id'          => isset( $schedule['schedule_id'] ) ? (string) $schedule['schedule_id'] : '',
                'last_dispatched_at'   => isset( $schedule['last_dispatched_at_utc'] ) ? (string) $schedule['last_dispatched_at_utc'] : '',
                'last_dispatch_job_id' => isset( $schedule['last_dispatch_job_id'] ) ? (string) $schedule['last_dispatch_job_id'] : '',
                'due_at_utc'           => isset( $schedule['due_at_utc'] ) ? (string) $schedule['due_at_utc'] : '',
                'state'                => isset( $schedule['state'] ) ? (string) $schedule['state'] : '',
                'state_reason'         => isset( $schedule['state_reason'] ) ? (string) $schedule['state_reason'] : '',
                'schedule_eligible'    => array_key_exists( 'schedule_eligible', $schedule ) ? (bool) $schedule['schedule_eligible'] : null,
                'last_evaluated_at'    => isset( $schedule['last_evaluated_at_utc'] ) ? (string) $schedule['last_evaluated_at_utc'] : '',
                'updated_at_utc'       => isset( $schedule['updated_at_utc'] ) ? (string) $schedule['updated_at_utc'] : '',
                'suspended_at_utc'     => isset( $schedule['suspended_at_utc'] ) ? (string) $schedule['suspended_at_utc'] : '',
                'product_state'        => isset( $product['operator_state'] ) ? (string) $product['operator_state'] : '',
                'product_title'        => isset( $product['operator_title'] ) ? (string) $product['operator_title'] : '',
                'product_summary'      => isset( $product['operator_summary'] ) ? (string) $product['operator_summary'] : '',
                'saved_cadence'        => isset( $product['saved_cadence'] ) ? (string) $product['saved_cadence'] : '',
                'has_saved_schedule'   => $has_saved_schedule,
                'allowed_cadences'     => $allowed_cadences,
            ),
        );
    }

    /**
     * Human-friendly schedule state label for canonical schedule truth.
     *
     * @param array<string,mixed> $schedule_settings
     */
    private static function schedule_state_label( array $schedule_settings ): string {
        $product_title = isset( $schedule_settings['product_title'] ) ? trim( (string) $schedule_settings['product_title'] ) : '';
        if ( '' !== $product_title ) {
            return $product_title;
        }

        $state = isset( $schedule_settings['state'] ) ? strtolower( trim( (string) $schedule_settings['state'] ) ) : '';

        if ( '' === $state ) {
            return ! empty( $schedule_settings['mode'] ) && 'off' !== (string) $schedule_settings['mode'] ? 'Enabled' : 'Disabled';
        }

        if ( 'eligible' === $state ) {
            return 'Eligible';
        }

        if ( 'scheduled' === $state ) {
            return 'Scheduled';
        }

        if ( 'suspended' === $state ) {
            return 'Suspended';
        }

        if ( 'ineligible' === $state ) {
            return 'Unavailable';
        }

        return ucwords( str_replace( '_', ' ', $state ) );
    }

    /**
     * Customer-safe schedule state explanation from canonical API truth.
     *
     * @param array<string,mixed> $schedule_settings
     */
    private static function schedule_state_summary_copy( array $schedule_settings ): string {
        $product_summary = isset( $schedule_settings['product_summary'] ) ? trim( (string) $schedule_settings['product_summary'] ) : '';
        if ( '' !== $product_summary ) {
            // Normalise legacy "triage" language from API product_summary values.
            if ( false !== strpos( $product_summary, 'triage plan is armed' ) ) {
                return 'No recurring scan is scheduled yet.';
            }
            return $product_summary;
        }

        $state_reason = isset( $schedule_settings['state_reason'] ) ? trim( (string) $schedule_settings['state_reason'] ) : '';
        $due_at_utc = isset( $schedule_settings['due_at_utc'] ) ? trim( (string) $schedule_settings['due_at_utc'] ) : '';
        $last_evaluated_at = isset( $schedule_settings['last_evaluated_at'] ) ? trim( (string) $schedule_settings['last_evaluated_at'] ) : '';

        if ( 'schedule_suspended_due_to_plan_change' === $state_reason ) {
            return 'Scheduling is suspended until the current plan allows it again.';
        }

        if ( 'scheduling_not_available' === $state_reason || 'not_in_plan' === $state_reason ) {
            return 'Scheduling is not available for the current entitlement state.';
        }

        if ( 'limit_reached' === $state_reason ) {
            return 'Scheduling is paused because the current schedule limit has been reached.';
        }

        if ( '' !== $due_at_utc ) {
            return 'Next due run: ' . self::schedule_datetime_label( $due_at_utc, $schedule_settings ) . '.';
        }

        if ( '' !== $last_evaluated_at ) {
            return 'Last evaluated by OpsGate schedule processing: ' . self::schedule_datetime_label( $last_evaluated_at, $schedule_settings ) . '.';
        }

        return 'Schedule state is read directly from OpsGate and saved scheduling records.';
    }
    

    /**
     * Generate and persist a link proof (Day-8.3).
     *
     * Proof design:
     * - HMAC-SHA256 over a stable message using the stored site token as key
     * - Only the HMAC is stored (no token stored in proof)
     *
     * @return array{linked_at:string,proof:string}
     */
    private static function generate_and_store_link_proof() {
        $identity  = self::get_identity_snapshot();
        $linked_at = gmdate( 'c' );

        $proof = self::compute_link_proof( $linked_at, $identity );

        update_option( 'opsgate_site_linked_at', $linked_at, true );
        update_option( 'opsgate_site_link_proof', $proof, true );

        return array(
            'linked_at' => $linked_at,
            'proof'     => $proof,
        );
    }

    /**
     * Clear link proof (keeps site_id and site_token intact).
     *
     * @return void
     */
    private static function clear_link_proof() {
        update_option( 'opsgate_site_linked_at', '', true );
        update_option( 'opsgate_site_link_proof', '', true );
    }

    /**
     * Compute link proof for given timestamp and identity snapshot.
     *
     * @param string $linked_at ISO8601 timestamp in UTC (gmdate('c')).
     * @param array  $identity Identity snapshot.
     * @return string Hex-encoded HMAC-SHA256 proof.
     */
    private static function compute_link_proof( $linked_at, $identity ) {
        $linked_at = is_string( $linked_at ) ? trim( $linked_at ) : '';
        if ( '' === $linked_at ) {
            $linked_at = gmdate( 'c' );
        }

        $site_id  = isset( $identity['site_id'] ) ? (string) $identity['site_id'] : '';
        $site_url = isset( $identity['site_url'] ) ? (string) $identity['site_url'] : '';
        $email    = isset( $identity['identity_email'] ) ? (string) $identity['identity_email'] : '';
        $token    = isset( $identity['site_token'] ) ? (string) $identity['site_token'] : '';

        $site_id  = trim( $site_id );
        $site_url = trim( $site_url );
        $email    = trim( $email );
        $token    = trim( $token );

        // Message is stable and deterministic.
        $message = implode(
            '|',
            array(
                'opsgate_link_v1',
                $site_id,
                strtolower( $email ),
                $site_url,
                $linked_at,
            )
        );

        // HMAC key = site_token (never logged).
        if ( '' === $token ) {
            // If token is unexpectedly missing, fail closed to an empty proof.
            return '';
        }

        return hash_hmac( 'sha256', $message, $token );
    }

    /**
     * Verify an existing proof against current identity snapshot (Day-8.4).
     *
     * @param string $linked_at Linked timestamp.
     * @param string $proof Stored proof.
     * @return bool
     */
    private static function verify_link_proof( $linked_at, $proof ) {
        $linked_at = is_string( $linked_at ) ? trim( $linked_at ) : '';
        $proof     = is_string( $proof ) ? trim( $proof ) : '';

        if ( '' === $linked_at || '' === $proof ) {
            return false;
        }

        $identity = self::get_identity_snapshot();
        $expected = self::compute_link_proof( $linked_at, $identity );

        $expected = is_string( $expected ) ? $expected : '';
        $proof    = strtolower( $proof );
        $expected = strtolower( $expected );

        if ( '' === $expected ) {
            return false;
        }

        return hash_equals( $expected, $proof );
    }

    /**
     * Day-8.2: single visibility line for MCP payload (safe, no secrets).
     *
     * Requirements:
     * - Must log exactly one line per trigger when WP_DEBUG_LOG is enabled.
     * - Must be prefixed exactly: "OPSGATE MCP PAYLOAD: "
     * - Must include ONLY: site_id, site_label, email, linked, service
     * - Must NOT log tokens, headers, URLs, or any secret material.
     *
     * @param array  $payload MCP payload array (site/identity sections expected).
     * @param string $service Service key (e.g. wordpress_security_audit).
     * @return void
     */
    private static function log_mcp_payload_visibility_line( $payload, $service ) {
        if ( ! defined( 'WP_DEBUG_LOG' ) || true !== WP_DEBUG_LOG ) {
            return;
        }

        $service = is_string( $service ) ? trim( $service ) : '';
        if ( '' === $service ) {
            $service = 'unknown';
        }

        $site     = ( isset( $payload['site'] ) && is_array( $payload['site'] ) ) ? $payload['site'] : array();
        $identity = ( isset( $payload['identity'] ) && is_array( $payload['identity'] ) ) ? $payload['identity'] : array();

        $line = array(
            'site_id'    => isset( $site['id'] ) ? (string) $site['id'] : '',
            'site_label' => isset( $site['label'] ) ? (string) $site['label'] : '',
            'email'      => isset( $identity['email'] ) ? (string) $identity['email'] : '',
            'linked'     => self::is_site_linked() ? '1' : '0',
            'service'    => $service,
        );

        error_log( 'OPSGATE MCP PAYLOAD: ' . wp_json_encode( $line, JSON_UNESCAPED_SLASHES ) );
    }

    // =========================================================================
    // Day-9: Licensing Engine (Phase 1) - CONSTANTS
    // =========================================================================

    /**
     * Option name for storing the license JSON string.
     */
    private const OPSGATE_LICENSE_OPTION = 'opsgate_license_json';

    /**
     * License load status constants.
     */
    private const LICENSE_LOAD_OK      = 'ok';
    private const LICENSE_LOAD_MISSING = 'missing';
    private const LICENSE_LOAD_INVALID = 'invalid';

    /**
     * License validation status constants.
     */
    private const LICENSE_STATUS_VALID    = 'valid';
    private const LICENSE_STATUS_EXPIRED  = 'expired';
    private const LICENSE_STATUS_INVALID  = 'invalid';
    private const LICENSE_STATUS_UNBOUND  = 'unbound';
    private const LICENSE_STATUS_MISSING  = 'missing';

    // =========================================================================
    // Day-9: Licensing Engine (Phase 1) - LICENSE LOADER (Step 9.2)
    // =========================================================================

    /**
     * Loads the stored license JSON from WordPress options and parses it safely.
     *
     * Step 9.2: License Loader implementation.
     * Strict, Sonar-clean, no enforcement, backward safe.
     *
     * @return array{
     *   status: string,
     *   raw: string,
     *   data: array<string,mixed>,
     *   error: string
     * }
     */
    public static function load_license(): array {
        $raw = get_option( self::OPSGATE_LICENSE_OPTION, '' );

        if ( ! is_string( $raw ) ) {
            return [
                'status' => self::LICENSE_LOAD_INVALID,
                'raw'    => '',
                'data'   => [],
                'error'  => 'license_option_not_string',
            ];
        }

        $raw = trim( $raw );

        if ( '' === $raw ) {
            return [
                'status' => self::LICENSE_LOAD_MISSING,
                'raw'    => '',
                'data'   => [],
                'error'  => '',
            ];
        }

        $decoded = json_decode( $raw, true );

        if ( ! is_array( $decoded ) ) {
            return [
                'status' => self::LICENSE_LOAD_INVALID,
                'raw'    => $raw,
                'data'   => [],
                'error'  => 'license_json_decode_failed',
            ];
        }

        // Must be an associative array-like structure.
        // (Do not validate fields here — that is Step 9.3.)
        return [
            'status' => self::LICENSE_LOAD_OK,
            'raw'    => $raw,
            'data'   => $decoded,
            'error'  => '',
        ];
    }

    // =========================================================================
    // Day-9: Licensing Engine (Phase 1) - UTILITY METHODS
    // =========================================================================

    /**
     * Get current OpsGate billing plan for display and mapping.
     *
     * IMPORTANT:
     * - This does NOT enforce behavior. It is used for UI and safe sanitation only.
     * - Package/channel truth is reread from the canonical API entitlement snapshot.
     *
    * @return string 'free'|'starter'|'pro'|'agency'
     */
    private static function get_current_plan() {
        $snapshot = self::get_entitlement_plan_snapshot();
        return self::entitlement_plan_key_from_snapshot( is_array( $snapshot ) ? $snapshot : array() );
    }

    private static function requested_onboarding_plan_from_post( bool $allow_free = true ): string {
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $raw = isset( $_POST['opsgate_requested_plan'] ) ? sanitize_text_field( wp_unslash( $_POST['opsgate_requested_plan'] ) ) : '';
        $plan = self::normalize_plan( $raw );

        if ( ! $allow_free && 'free' === $plan ) {
            return '';
        }
        if ( in_array( $plan, array( 'free', 'starter', 'pro', 'agency' ), true ) ) {
            return $plan;
        }

        return '';
    }

    private static function onboarding_path_from_post(): string {
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $path = isset( $_POST['opsgate_onboarding_path'] ) ? sanitize_key( wp_unslash( $_POST['opsgate_onboarding_path'] ) ) : '';
        return in_array( $path, array( 'free_public', 'connect_paid' ), true ) ? $path : '';
    }

    private static function entitlement_plan_key_from_snapshot( array $snapshot ): string {
        $plan = isset( $snapshot['plan'] ) ? $snapshot['plan'] : 'unknown';
        if ( is_array( $plan ) ) {
            $plan = isset( $plan['key'] ) ? $plan['key'] : 'unknown';
        }
        $plan = strtolower( trim( (string) $plan ) );
        return '' !== $plan ? $plan : 'unknown';
    }


    /**
     * Day-12: Normalize plan values to allowed set.
     *
     * @param mixed $raw
     * @return string
     */
    private static function normalize_plan( $raw ) {
        $plan = is_string( $raw ) ? strtolower( trim( $raw ) ) : 'unknown';

        $allowed = array( 'free', 'starter', 'pro', 'agency', 'missing', 'unknown' );
        if ( ! in_array( $plan, $allowed, true ) ) {
            $plan = 'unknown';
        }

        return $plan;
    }

    /**
     * Day-12: Entitlement snapshot (single source of truth for plan).
     *
    * @return array
     */
    private static function get_entitlement_plan_snapshot() {
        // Operator test-plan override: takes priority over API when explicitly set.
        // Written via the Operator billing settings panel (hidden from customers).
        // Allows testing Free/Starter/Pro/Agency journeys on any account.
        $operator_override = function_exists( 'get_option' ) ? self::normalize_plan( trim( (string) get_option( 'opsgate_plan_operator_override', '' ) ) ) : '';
        if ( in_array( $operator_override, array( 'free', 'starter', 'pro', 'agency' ), true ) ) {
            return array(
                'plan'    => $operator_override,
                'source'  => 'operator_override',
                'authority' => array(),
                'package' => array(),
                'hybrid'  => array(),
                'limits'  => array(),
                'eligibility' => array(),
                'capabilities_enabled' => array(),
                'capabilities_locked' => array(),
            );
        }

        if ( function_exists( 'opsgate_get_api_entitlement_snapshot' ) ) {
            $snapshot = opsgate_get_api_entitlement_snapshot();
            if ( is_array( $snapshot ) && isset( $snapshot['plan'] ) && is_array( $snapshot['plan'] ) ) {
                $plan_key = isset( $snapshot['plan']['key'] ) ? (string) $snapshot['plan']['key'] : '';
                $source   = isset( $snapshot['plan']['source'] ) ? (string) $snapshot['plan']['source'] : 'api';
                if ( '' !== trim( $plan_key ) ) {
                    return array(
                        'plan'    => self::normalize_plan( $plan_key ),
                        'source'  => $source,
                        'authority' => isset( $snapshot['authority'] ) && is_array( $snapshot['authority'] ) ? $snapshot['authority'] : array(),
                        'package' => isset( $snapshot['package'] ) && is_array( $snapshot['package'] ) ? $snapshot['package'] : array(),
                        'hybrid'  => isset( $snapshot['hybrid'] ) && is_array( $snapshot['hybrid'] ) ? $snapshot['hybrid'] : array(),
                        'limits'  => isset( $snapshot['limits'] ) && is_array( $snapshot['limits'] ) ? $snapshot['limits'] : array(),
                        'eligibility' => isset( $snapshot['eligibility'] ) && is_array( $snapshot['eligibility'] ) ? $snapshot['eligibility'] : array(),
                        'capabilities_enabled' => isset( $snapshot['capabilities_enabled'] ) && is_array( $snapshot['capabilities_enabled'] ) ? $snapshot['capabilities_enabled'] : array(),
                        'capabilities_locked' => isset( $snapshot['capabilities_locked'] ) && is_array( $snapshot['capabilities_locked'] ) ? $snapshot['capabilities_locked'] : array(),
                    );
                }
            }
        }

        // Fall back to the locally stored plan set during bootstrap or pairing.
        $stored_plan = self::normalize_plan( trim( (string) get_option( 'opsgate_plan', '' ) ) );
        if ( in_array( $stored_plan, array( 'free', 'starter', 'pro', 'agency' ), true ) ) {
            return array(
                'plan'    => $stored_plan,
                'source'  => 'stored',
                'authority' => array(),
                'package' => array(),
                'hybrid'  => array(),
                'limits'  => array(),
                'eligibility' => array(),
                'capabilities_enabled' => array(),
                'capabilities_locked' => array(),
            );
        }

        return array(
            'plan'    => 'unknown',
            'source'  => 'api_unavailable',
            'authority' => array(),
            'package' => array(),
            'hybrid'  => array(),
            'limits'  => array(),
            'eligibility' => array(),
            'capabilities_enabled' => array(),
            'capabilities_locked' => array(),
        );
    }

    private static function entitlement_capability_enabled( string $capability_key ): bool {
        $snapshot = self::get_entitlement_plan_snapshot();
        $enabled = isset( $snapshot['capabilities_enabled'] ) && is_array( $snapshot['capabilities_enabled'] )
            ? $snapshot['capabilities_enabled']
            : array();

        return in_array( trim( $capability_key ), array_map( 'strval', $enabled ), true );
    }

    /**
     * Day-12: Get allowed schedule modes for current package from the API snapshot.
     *
     * @return array
     */
    private static function get_allowed_schedule_modes_for_current_plan() {
        if ( function_exists( 'opsgate_get_api_entitlement_snapshot' ) ) {
            $snapshot = opsgate_get_api_entitlement_snapshot();
            if ( is_array( $snapshot ) ) {
                $eligibility = isset( $snapshot['eligibility'] ) && is_array( $snapshot['eligibility'] ) ? $snapshot['eligibility'] : array();
                $scheduling = isset( $eligibility['scheduling'] ) && is_array( $eligibility['scheduling'] ) ? $eligibility['scheduling'] : array();
                $allowed = isset( $scheduling['allowed_cadences'] ) && is_array( $scheduling['allowed_cadences'] ) ? $scheduling['allowed_cadences'] : array();
                $normalized = array( 'off' );
                foreach ( $allowed as $cadence ) {
                    $cadence = strtolower( trim( (string) $cadence ) );
                    if ( '' !== $cadence && ! in_array( $cadence, $normalized, true ) ) {
                        $normalized[] = $cadence;
                    }
                }
                return $normalized;
            }
        }
        return array( 'off' );
    }

    /**
     * Day 19.4 (Step B): Human label for evaluation frequency.
     *
     * @param string $key Frequency key (hourly|twicedaily|daily).
     * @return string
     */
    private static function scheduling_frequency_label( $key ) {
        $key = is_string( $key ) ? $key : '';
        $map = array(
            'api_owned'  => 'Managed by OpsGate',
            'hourly'     => 'Hourly',
            'twicedaily' => 'Twice daily',
            'daily'      => 'Daily',
        );

        return isset( $map[ $key ] ) ? $map[ $key ] : 'Hourly';
    }

    /**
     * Day 19.4 (Step B): Present a friendly service label without relying on internal plumbing.
     *
     * @param string $service_key
     * @return string
     */
    private static function schedule_service_label( $service_key ) {
        $service_key = is_string( $service_key ) ? $service_key : '';
        if ( 'portfolio_triage' === $service_key ) {
            return 'Security Scan';
        }
        $service_key = str_replace( array( '-', '_' ), ' ', $service_key );
        $service_key = trim( $service_key );

        if ( '' === $service_key ) {
            return 'Service';
        }

        return ucwords( $service_key );
    }

    /**
     * Day 19.4 (Step B): Build a deterministic "Configured" summary string from
     * canonical schedule truth, including the saved timezone when available.
     *
     * @param array $schedule_settings
     * @param array $days
     * @return string
     */
    private static function schedule_configured_text_utc( $schedule_settings, $days ) {
        if ( ! is_array( $schedule_settings ) ) {
            return 'Not configured';
        }

        $mode = isset( $schedule_settings['mode'] ) ? (string) $schedule_settings['mode'] : 'off';
        $time = isset( $schedule_settings['time'] ) ? (string) $schedule_settings['time'] : '02:00';
        $timezone = isset( $schedule_settings['timezone'] ) ? trim( (string) $schedule_settings['timezone'] ) : self::ui_display_timezone_name();
        $dow  = isset( $schedule_settings['dow'] ) ? $schedule_settings['dow'] : null;
        $dom  = isset( $schedule_settings['dom'] ) ? $schedule_settings['dom'] : null;

        if ( 'off' === $mode ) {
            return 'Off';
        }

        // Normalize time to HH:MM
        if ( ! preg_match( '/^\d{2}:\d{2}$/', $time ) ) {
            $time = '02:00';
        }
        if ( '' === $timezone ) {
            $timezone = self::ui_display_timezone_name();
        }

        if ( 'daily' === $mode ) {
            return 'Daily at ' . $time . ' ' . $timezone;
        }

        if ( 'weekly' === $mode ) {
            $dow_i = is_numeric( $dow ) ? (int) $dow : -1;
            $day_label = ( isset( $days[ $dow_i ] ) ) ? (string) $days[ $dow_i ] : '—';
            return 'Weekly on ' . $day_label . ' at ' . $time . ' ' . $timezone;
        }

        if ( 'monthly' === $mode ) {
            $dom_i = is_numeric( $dom ) ? (int) $dom : 0;
            if ( $dom_i < 1 || $dom_i > 31 ) {
                $dom_i = 1;
            }
            return 'Monthly on day ' . $dom_i . ' at ' . $time . ' ' . $timezone;
        }

        return 'Configured';
    }

    /**
     * Day 19.4 (Step B): Best-effort next due run time (UTC). Falls back safely to "Configured" text.
     *
     * @param array $schedule_settings
     * @param array $days
     * @return string
     */
    private static function schedule_next_due_text_best_effort_utc( $schedule_settings, $days ) {
        if ( ! is_array( $schedule_settings ) ) {
            return 'Not available';
        }

        $due_at_utc = isset( $schedule_settings['due_at_utc'] ) ? trim( (string) $schedule_settings['due_at_utc'] ) : '';
        if ( '' !== $due_at_utc ) {
            return 'Next due: ' . self::schedule_datetime_label( $due_at_utc, is_array( $schedule_settings ) ? $schedule_settings : array() );
        }

        $mode = isset( $schedule_settings['mode'] ) ? (string) $schedule_settings['mode'] : 'off';
        if ( 'off' === $mode ) {
            return 'Off';
        }
        return 'Due time will appear after OpsGate schedule processing evaluates this schedule.';
    }


    public static function handle_change_entitlement_plan() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden' );
        }

        if (
            ! isset( $_POST['opsgate_change_entitlement_plan_nonce'] ) ||
            ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['opsgate_change_entitlement_plan_nonce'] ) ), 'opsgate_change_entitlement_plan' )
        ) {
            wp_die( 'Invalid request. Please try again.' );
        }

        $plan = self::normalize_plan( isset( $_POST['plan'] ) ? sanitize_text_field( wp_unslash( $_POST['plan'] ) ) : '' );
        if ( ! in_array( $plan, array( 'free', 'starter', 'pro', 'agency' ), true ) ) {
            wp_safe_redirect( self::admin_tab_url( 'billing', array( 'opsgate_notice' => 'entitlement_update_invalid' ) ) );
            exit;
        }

        $scope = self::get_mcp_scope_snapshot();
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';

        if ( '' === $account_id || '' === $site_id ) {
            $notice_args = array( 'opsgate_notice' => 'entitlement_scope_missing' );
            if ( isset( $scope['error'] ) && '' !== trim( (string) $scope['error'] ) ) {
                $notice_args['opsgate_notice_detail'] = sanitize_key( (string) $scope['error'] );
            }
            wp_safe_redirect( self::admin_tab_url( 'billing', $notice_args ) );
            exit;
        }

        $resp = self::mcp_post_json(
            '/v1/entitlements/update',
            array(
                'account_id' => $account_id,
                'site_id'    => $site_id,
                'plan'       => $plan,
                'source'     => 'admin',
            )
        );

        if ( empty( $resp['ok'] ) ) {
            $notice = 'entitlement_update_failed';
            $error = isset( $resp['error'] ) ? (string) $resp['error'] : '';
            if ( 'entitlement_plan_invalid' === $error || 'plan_not_active' === $error ) {
                $notice = 'entitlement_update_invalid';
            }
            wp_safe_redirect(
                self::admin_tab_url(
                    'billing',
                    array(
                        'opsgate_notice'        => $notice,
                        'opsgate_notice_detail' => sanitize_key( $error ),
                    )
                )
            );
            exit;
        }

        wp_safe_redirect(
            self::admin_tab_url(
                'billing',
                array(
                    'opsgate_notice' => 'entitlement_updated',
                    'plan'           => $plan,
                )
            )
        );
        exit;
    }

    /**
     * Enqueue admin styles.
     *
     * @return void
     */
    public static function enqueue_admin_styles( $hook_suffix = '' ) {
        if ( ! self::is_opsgate_admin_page( $hook_suffix ) ) {
            return;
        }

        $admin_css_path = dirname( __FILE__ ) . '/../assets/admin.css';
        $admin_css_ver  = file_exists( $admin_css_path ) ? (string) filemtime( $admin_css_path ) : null;
        wp_enqueue_style( 'opsgate-admin', self::browser_safe_plugins_url( '../assets/admin.css' ), array(), $admin_css_ver );

        $admin_js_path = dirname( __FILE__ ) . '/../assets/admin-live.js';
        $admin_js_ver  = file_exists( $admin_js_path ) ? (string) filemtime( $admin_js_path ) : null;
        wp_enqueue_script( 'opsgate-admin-runtime', self::browser_safe_plugins_url( '../assets/admin-live.js' ), array(), $admin_js_ver, true );

        wp_register_script( 'opsgate-admin-inline', '', array( 'opsgate-admin-runtime' ), null, true );
        wp_enqueue_script( 'opsgate-admin-inline' );

        $inline_js = <<<JS
    (function () {
        function opsgateBoot() {
        var useStableRuntime = !!window.OpsGateStableUI;
        function currentAdminTab() {
            try {
                var url = new URL(window.location.href);
                return url.searchParams.get('tab') || 'overview';
            } catch (error) {
                return 'overview';
            }
        }

        function currentStateKey() {
            return 'opsgate:ui-state:' + currentAdminTab() + ':' + window.location.pathname;
        }

        function saveUiState(extra) {
            try {
                var payload = {
                    scrollY: window.scrollY || window.pageYOffset || 0,
                    details: Array.prototype.slice.call(document.querySelectorAll('details[id]')).filter(function (node) {
                        return node.open;
                    }).map(function (node) {
                        return node.id;
                    }),
                    triageDetail: ''
                };

                var activeTriageDetail = document.querySelector('.opsgate-triage-inline-detail[open][data-opsgate-triage-detail-key]');
                if (activeTriageDetail) {
                    payload.triageDetail = activeTriageDetail.getAttribute('data-opsgate-triage-detail-key') || '';
                }

                if (extra && typeof extra === 'object') {
                    Object.keys(extra).forEach(function (key) {
                        payload[key] = extra[key];
                    });
                }

                window.sessionStorage.setItem(currentStateKey(), JSON.stringify(payload));
            } catch (error) {
                // Preserve graceful behavior if sessionStorage is unavailable.
            }
        }

        function restoreUiState() {
            try {
                var raw = window.sessionStorage.getItem(currentStateKey());
                if (!raw) {
                    return;
                }
                var payload = JSON.parse(raw);
                if (!payload || typeof payload !== 'object') {
                    return;
                }

                if (Array.isArray(payload.details)) {
                    payload.details.forEach(function (id) {
                        var detail = document.getElementById(String(id));
                        if (detail && detail.tagName === 'DETAILS') {
                            detail.open = true;
                        }
                    });
                }

                if (payload.triageDetail) {
                    var triageDetail = document.querySelector('[data-opsgate-triage-detail-key="' + String(payload.triageDetail) + '"]');
                    if (triageDetail) {
                        triageDetail.open = true;
                    }
                }

                if (typeof payload.scrollY === 'number') {
                    window.requestAnimationFrame(function () {
                        window.scrollTo(0, payload.scrollY);
                    });
                }
            } catch (error) {
                // Ignore restore errors and keep the page usable.
            }
        }

        function initUiStatePreservation() {
            restoreUiState();

            document.addEventListener('click', function (event) {
                var link = event.target.closest('a[href]');
                if (!link || link.hasAttribute('data-opsgate-no-preserve')) {
                    return;
                }
                try {
                    var url = new URL(link.href, window.location.origin);
                    if (url.origin !== window.location.origin || url.pathname !== window.location.pathname) {
                        return;
                    }
                } catch (error) {
                    return;
                }
                saveUiState();
            });

            document.addEventListener('submit', function (event) {
                var form = event.target;
                if (!form || 'FORM' !== form.tagName) {
                    return;
                }
                saveUiState();
            });

            window.addEventListener('beforeunload', function () {
                saveUiState();
            });
        }

        initUiStatePreservation();

        function parseStates(panel) {
            if (!panel) {
                return [];
            }
            return String(panel.getAttribute('data-opsgate-live-states') || '')
                .split(',')
                .map(function (value) { return value.trim().toUpperCase(); })
                .filter(Boolean);
        }

        function shouldPoll(states) {
            if (!states.length) {
                return false;
            }
            return states.some(function (state) {
                return ['COMPLETED', 'FAILED'].indexOf(state) === -1;
            });
        }

        function normalizedDataValue(panel, name) {
            if (!panel) {
                return '';
            }
            var value = panel.getAttribute(name);
            return String(value || '').trim();
        }

        function shouldPollTriagePanel(panel) {
            var states = parseStates(panel);
            if (shouldPoll(states)) {
                return true;
            }

            var currentJobId = normalizedDataValue(panel, 'data-opsgate-current-job-id');
            var renderedRunId = normalizedDataValue(panel, 'data-opsgate-rendered-run-id');
            if (currentJobId && (!renderedRunId || currentJobId !== renderedRunId)) {
                return true;
            }

            var currentExportJobId = normalizedDataValue(panel, 'data-opsgate-current-export-job-id');
            var currentExportSourceJobId = normalizedDataValue(panel, 'data-opsgate-current-export-source-job-id');
            var renderedExportJobId = normalizedDataValue(panel, 'data-opsgate-rendered-export-job-id');
            if (
                currentExportJobId &&
                currentJobId &&
                currentExportSourceJobId === currentJobId &&
                (!renderedExportJobId || currentExportJobId !== renderedExportJobId)
            ) {
                return true;
            }

            return false;
        }

        function triagePanelNeedsRenderedRefresh(panel, payload) {
            if (!panel) {
                return false;
            }
            if (payload && payload.should_refresh) {
                return true;
            }
            var currentJobId = normalizedDataValue(panel, 'data-opsgate-current-job-id');
            var currentExportJobId = normalizedDataValue(panel, 'data-opsgate-current-export-job-id');
            var currentExportSourceJobId = normalizedDataValue(panel, 'data-opsgate-current-export-source-job-id');
            var renderedExportJobId = normalizedDataValue(panel, 'data-opsgate-rendered-export-job-id');
            return !!(
                currentJobId &&
                currentExportJobId &&
                currentExportSourceJobId &&
                currentExportSourceJobId === currentJobId &&
                currentExportJobId !== renderedExportJobId
            );
        }

        function shouldPollReportsPanel(panel) {
            if (!panel) {
                return false;
            }

            var rawStates = String(panel.getAttribute('data-opsgate-live-states') || '');
            var states = rawStates.split(',').map(function (value) {
                return value.trim().toUpperCase();
            }).filter(Boolean);
            if (shouldPoll(states)) {
                return true;
            }

            var currentSourceJobId = normalizedDataValue(panel, 'data-opsgate-current-source-job-id');
            var renderedSourceJobId = normalizedDataValue(panel, 'data-opsgate-rendered-source-job-id');
            if (currentSourceJobId && (!renderedSourceJobId || currentSourceJobId !== renderedSourceJobId)) {
                return true;
            }

            var currentExportJobId = normalizedDataValue(panel, 'data-opsgate-current-export-job-id');
            var renderedExportJobId = normalizedDataValue(panel, 'data-opsgate-rendered-export-job-id');
            if (currentExportJobId && (!renderedExportJobId || currentExportJobId !== renderedExportJobId)) {
                return true;
            }

            return false;
        }

        function reportsPanelNeedsRenderedRefresh(panel, payload) {
            var state = String(payload && payload.state ? payload.state : '').toUpperCase();
            return ['COMPLETED', 'FAILED'].indexOf(state) !== -1;
        }

        function setRunButtonsBusy(panel, isBusy, label) {
            Array.prototype.slice.call(panel.querySelectorAll('[data-opsgate-run-button]')).forEach(function (button) {
                var idleLabel = button.getAttribute('data-opsgate-run-idle-label') || 'Run Security Scan';
                var busyLabel = button.getAttribute('data-opsgate-run-busy-label') || 'Run in progress';
                button.disabled = !!isBusy;
                button.textContent = isBusy ? (label || busyLabel) : idleLabel;
            });
        }

        function setRuntimeNote(panel, message, tone) {
            if (!panel) {
                return;
            }
            var note = panel.querySelector('[data-opsgate-triage-runtime-note]');
            if (!note) {
                return;
            }
            note.textContent = String(message || '');
            note.hidden = !message;
            ['info', 'success', 'warn', 'error'].forEach(function (value) {
                note.classList.remove('is-' + value);
            });
            if (tone) {
                note.classList.add('is-' + tone);
            }
        }

        function updateTriagePanel(panel, payload) {
            var deck = panel.querySelector('[data-opsgate-triage-command-deck]');
            var runPill = panel.querySelector('[data-opsgate-triage-run-pill]');
            var commandStatusCopy = panel.querySelector('[data-opsgate-triage-command-status-copy]');
            var title = panel.querySelector('[data-opsgate-triage-progress-title]');
            var copy = panel.querySelector('[data-opsgate-triage-progress-copy]');
            var meter = panel.querySelector('[data-opsgate-triage-progress-meter]');
            var fill = panel.querySelector('[data-opsgate-triage-progress-fill]');
            var phase = panel.querySelector('[data-opsgate-triage-progress-phase]');
            var elapsed = panel.querySelector('[data-opsgate-triage-progress-elapsed]');
            var evidence = panel.querySelector('[data-opsgate-triage-progress-evidence]');
            var asideTitle = panel.querySelector('[data-opsgate-triage-aside-title]');
            var asideCopy = panel.querySelector('[data-opsgate-triage-aside-copy]');
            var states = Array.isArray(payload.live_states) ? payload.live_states : [];
            var terminal = !shouldPoll(states);

            panel.setAttribute('data-opsgate-live-states', states.join(','));
            if (payload.job_id) {
                panel.setAttribute('data-opsgate-current-job-id', String(payload.job_id));
            }
            if (Object.prototype.hasOwnProperty.call(payload, 'export_job_id')) {
                panel.setAttribute('data-opsgate-current-export-job-id', String(payload.export_job_id || ''));
            }
            if (Object.prototype.hasOwnProperty.call(payload, 'export_source_job_id')) {
                panel.setAttribute('data-opsgate-current-export-source-job-id', String(payload.export_source_job_id || ''));
            }

            if (deck) {
                ['good', 'info', 'warn', 'bad'].forEach(function (tone) {
                    deck.classList.remove('opsgate-triage-command-deck-' + tone);
                });
                deck.classList.add('opsgate-triage-command-deck-' + String(payload.progress_tone || 'info'));
            }

            if (runPill) {
                runPill.textContent = String(payload.run_visual_key || 'pending').replace(/_/g, ' ');
                runPill.textContent = runPill.textContent.charAt(0).toUpperCase() + runPill.textContent.slice(1);
                runPill.className = 'opsgate-triage-pill opsgate-triage-pill-' + String(payload.progress_tone || 'info');
            }
            if (title) {
                title.textContent = String(payload.progress_title || 'Latest run status');
            }
            if (commandStatusCopy) {
                commandStatusCopy.textContent = String(payload.progress_copy || '');
            }
            if (copy) {
                copy.textContent = String(payload.progress_copy || '');
            }
            if (meter) {
                meter.setAttribute('aria-valuenow', String(payload.progress_percent || 0));
                meter.setAttribute('aria-label', String(payload.progress_meter_label || 'Run progress'));
            }
            if (fill) {
                fill.style.width = String(payload.progress_percent || 0) + '%';
            }
            if (phase) {
                phase.textContent = String(payload.progress_phase_label || 'Waiting');
            }
            if (elapsed) {
                elapsed.textContent = String(payload.elapsed_label || '');
            }
            if (evidence) {
                evidence.textContent = String(payload.evidence_label || '');
            }
            if (asideTitle) {
                asideTitle.textContent = String(payload.progress_phase_label || 'Waiting');
            }
            if (asideCopy) {
                asideCopy.textContent = String(payload.progress_phase_copy || '');
            }

            if (terminal || payload.should_refresh) {
                clearTransientStatuses(document);
            }

            if (Array.isArray(payload.phase_items)) {
                payload.phase_items.forEach(function (item) {
                    var phaseCard = panel.querySelector('[data-opsgate-triage-phase-key="' + String(item.key || '') + '"]');
                    if (!phaseCard) {
                        return;
                    }
                    ['pending', 'current', 'complete', 'failed', 'blocked'].forEach(function (state) {
                        phaseCard.classList.remove('is-' + state);
                    });
                    phaseCard.classList.add('is-' + String(item.state || 'pending'));
                    var phaseStatus = phaseCard.querySelector('[data-opsgate-triage-phase-status]');
                    if (phaseStatus) {
                        phaseStatus.textContent = String(item.state_label || 'Waiting');
                    }
                });
            }

            setRunButtonsBusy(panel, shouldPollTriagePanel(panel), 'Run in progress');

            var refreshButton = panel.querySelector('[data-opsgate-triage-refresh-button]');
            if (refreshButton) {
                if (payload.should_refresh && !shouldPollTriagePanel(panel)) {
                    refreshButton.textContent = 'Load recorded evidence';
                    refreshButton.classList.add('is-ready');
                } else {
                    refreshButton.textContent = refreshButton.getAttribute('data-opsgate-refresh-label') || 'Refresh status';
                    refreshButton.classList.remove('is-ready');
                }
            }
        }

        function initTriageLivePanel(root) {
            root = root || document;
            var panel = root.querySelector('#opsgate-triage-live-panel');
            if (!panel) {
                return;
            }
            if (panel.getAttribute('data-opsgate-live-init') === '1') {
                return;
            }
            panel.setAttribute('data-opsgate-live-init', '1');

            var timer = null;
            var startingRun = false;
            var refreshingPanel = false;

            function stopPolling() {
                if (timer) {
                    window.clearTimeout(timer);
                    timer = null;
                }
            }

            function scheduleRefresh(delay) {
                stopPolling();
                if (!panel || !panel.isConnected || !shouldPollTriagePanel(panel)) {
                    return;
                }
                timer = window.setTimeout(function () {
                    poll();
                }, delay || 1800);
            }

            function poll() {
                if (refreshingPanel || !panel || !panel.isConnected) {
                    return;
                }
                refreshingPanel = true;
                stopPolling();
                refreshTriagePanel(panel)
                    .then(function (nextPanel) {
                        panel = nextPanel || document.getElementById('opsgate-triage-live-panel') || panel;
                    })
                    .catch(function () {
                        if (panel && panel.isConnected && shouldPollTriagePanel(panel)) {
                            scheduleRefresh(2200);
                        }
                    })
                    .finally(function () {
                        refreshingPanel = false;
                    });
            }

            panel._opsgateTriageControl = {
                ensurePolling: function () {
                    scheduleRefresh(1800);
                },
                poll: poll,
                stopPolling: stopPolling
            };

            function startRun(form) {
                if (startingRun) {
                    return;
                }
                var actionUrl = normalizeOpsGateUrl(panel.getAttribute('data-opsgate-run-url') || '');
                if (!actionUrl) {
                    return;
                }
                var nonce = '';
                var nonceField = form.querySelector('input[name="_wpnonce"]');
                if (nonceField) {
                    nonce = nonceField.value || '';
                }
                startingRun = true;
                setRuntimeNote(panel, 'Starting security scan…', 'info');
                setRunButtonsBusy(panel, true, 'Starting run…');

                var body = new URLSearchParams();
                body.set('action', 'opsgate_run_portfolio_triage_live');
                body.set('nonce', nonce);

                fetch(actionUrl, {
                    method: 'POST',
                    credentials: 'same-origin',
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
                    },
                    body: body.toString()
                })
                .then(function (response) { return response.json(); })
                .then(function (payload) {
                    if (!payload || !payload.success || !payload.data) {
                        var message = payload && payload.data && payload.data.message ? payload.data.message : 'Could not start Security Scan.';
                        throw new Error(message);
                    }
                    updateTriagePanel(panel, payload.data);
                    setRuntimeNote(panel, payload.data.message || 'Security Scan started. Live run state is now updating in place.', 'success');
                    stopPolling();
                    refreshTriagePanel(panel)
                        .then(function (nextPanel) {
                            panel = nextPanel || document.getElementById('opsgate-triage-live-panel') || panel;
                        })
                        .catch(function () {
                            // Keep the live controller moving even if the first queued render refresh fails.
                        })
                        .finally(function () {
                            scheduleRefresh(350);
                        });
                })
                .catch(function (error) {
                    setRuntimeNote(panel, error && error.message ? error.message : 'Could not start Security Scan.', 'error');
                    setRunButtonsBusy(panel, false);
                })
                .finally(function () {
                    startingRun = false;
                });
            }

            Array.prototype.slice.call(panel.querySelectorAll('[data-opsgate-triage-run-form]')).forEach(function (form) {
                if (form.getAttribute('data-opsgate-triage-launch-form') === '1') {
                    return;
                }
                form.addEventListener('submit', function (event) {
                    event.preventDefault();
                    startRun(form);
                });
            });

            Array.prototype.slice.call(panel.querySelectorAll('[data-opsgate-triage-detail-link], a[href*="opsgate_detail="]')).forEach(function (link) {
                link.addEventListener('click', function (event) {
                    var detailKey = link.getAttribute('data-opsgate-triage-detail-link') || '';
                    if (!detailKey) {
                        try {
                            var href = new URL(link.href, window.location.origin);
                            detailKey = href.searchParams.get('opsgate_detail') || '';
                        } catch (error) {
                            detailKey = '';
                        }
                    }
                    if (!detailKey) {
                        return;
                    }
                    var detail = panel.querySelector('[data-opsgate-triage-detail-key="' + detailKey + '"]');
                    if (!detail) {
                        return;
                    }
                    event.preventDefault();
                    detail.open = true;
                    var body = detail.querySelector('.opsgate-triage-inline-detail-body');
                    if (body) {
                        body.hidden = false;
                    }
                    if (window.history && window.history.replaceState) {
                        var nextUrl = new URL(window.location.href);
                        nextUrl.searchParams.set('opsgate_detail', detailKey);
                        nextUrl.hash = 'opsgate-detail-' + detailKey;
                        window.history.replaceState({}, '', nextUrl.toString());
                    }
                    saveUiState({ triageDetail: detailKey });
                    detail.scrollIntoView({ block: 'nearest' });
                });
            });

            Array.prototype.slice.call(panel.querySelectorAll('[data-opsgate-triage-refresh-button]')).forEach(function (button) {
                button.addEventListener('click', function (event) {
                    event.preventDefault();
                    loadWorkspace(scrubWorkspaceUrl(window.location.href), { replace: true, preserveScroll: true });
                });
            });

            var detailModules = Array.prototype.slice.call(panel.querySelectorAll('.opsgate-triage-inline-detail'));
            detailModules.forEach(function (detail) {
                detail.addEventListener('toggle', function () {
                    if (!detail.open) {
                        return;
                    }
                    detailModules.forEach(function (other) {
                        if (other !== detail) {
                            other.open = false;
                        }
                    });
                });
            });

            if (shouldPollTriagePanel(panel)) {
                scheduleRefresh(700);
            }
        }

        function initTriageReferenceAccordion(root) {
            root = root || document;
            var modules = Array.prototype.slice.call(root.querySelectorAll('.opsgate-triage-reference-details'));
            if (!modules.length) {
                return;
            }

            modules.forEach(function (module) {
                if (module.getAttribute('data-opsgate-accordion-init') === '1') {
                    return;
                }
                module.setAttribute('data-opsgate-accordion-init', '1');
                module.addEventListener('toggle', function () {
                    if (!module.open) {
                        return;
                    }
                    modules.forEach(function (other) {
                        if (other !== module) {
                            other.removeAttribute('open');
                        }
                    });
                });
            });
        }

        var workspaceLoading = false;
        var workspaceLoadPromise = null;
        var pendingWorkspaceRequest = null;
        var inlineStatusTimers = {};
        var transientWorkspaceQueryKeys = [
            'opsgate_notice',
            'opsgate_notice_detail',
            'opsgate_validation_notice',
            'opsgate_validation_notice_detail',
            'opsgate_alerts_notice',
            'opsgate_alerts_error',
            'opsgate_alert_destinations_notice',
            'opsgate_alert_destinations_error',
            'opsgate_settings_saved',
            'opsgate_settings_error',
            'opsgate_export_error',
            'opsgate_export_started',
            'opsgate_link_notice',
            'opsgate_link_notice_detail',
            'opsgate_agency_notice',
            'opsgate_license_error'
        ];

        function normalizeOpsGateUrl(rawUrl) {
            try {
                var baseUrl = new URL(window.location.href);
                var url = new URL(rawUrl || window.location.href, baseUrl);
                var path = String(url.pathname || '');
                var isWorkspace = url.searchParams.get('page') === 'opsgate';
                var isWpAdminEndpoint = /\/wp-admin\/(?:admin|admin-ajax|admin-post)\.php$/i.test(path);
                if (!isWorkspace && !isWpAdminEndpoint) {
                    return url.toString();
                }
                if (url.origin === window.location.origin) {
                    return url.toString();
                }
                return new URL(path + url.search + url.hash, window.location.origin).toString();
            } catch (error) {
                return rawUrl || window.location.href;
            }
        }

        function isOpsGateInternalUrl(href) {
            try {
                var url = new URL(normalizeOpsGateUrl(href), window.location.origin);
                return url.origin === window.location.origin && url.searchParams.get('page') === 'opsgate';
            } catch (error) {
                return false;
            }
        }

        function refreshReportsPanel(panel) {
            if (!panel) {
                return Promise.resolve();
            }
            var refreshUrl = normalizeOpsGateUrl(panel.getAttribute('data-opsgate-refresh-url') || window.location.href);
            return fetch(refreshUrl, {
                credentials: 'same-origin',
                cache: 'no-store'
            })
            .then(function (response) { return response.text(); })
            .then(function (html) {
                var parser = new DOMParser();
                var doc = parser.parseFromString(html, 'text/html');
                var next = doc.getElementById('opsgate-reports-live-panel');
                var current = document.getElementById('opsgate-reports-live-panel');
                if (!next || !current) {
                    throw new Error('Could not refresh the report center.');
                }
                current.outerHTML = next.outerHTML;
                initializeWorkspace(document);
                return document.getElementById('opsgate-reports-live-panel');
            });
        }

        function refreshTriagePanel(panel) {
            if (!panel) {
                return Promise.resolve();
            }
            var refreshUrl = normalizeOpsGateUrl(panel.getAttribute('data-opsgate-refresh-url') || window.location.href);
            return fetch(refreshUrl, {
                credentials: 'same-origin',
                cache: 'no-store'
            })
            .then(function (response) { return response.text(); })
            .then(function (html) {
                var parser = new DOMParser();
                var doc = parser.parseFromString(html, 'text/html');
                var next = doc.getElementById('opsgate-triage-live-panel');
                var current = document.getElementById('opsgate-triage-live-panel');
                if (!next || !current) {
                    throw new Error('Could not refresh the triage panel.');
                }
                var helpEl = current.querySelector('.opsgate-p5-help-panel');
                var helpPanelOpen = !!(helpEl && helpEl.hasAttribute('open'));
                var openRefIds = Array.prototype.slice.call(current.querySelectorAll('.opsgate-triage-reference-details[open]')).map(function (d) { return d.getAttribute('data-opsgate-accordion-init') || ''; }).filter(Boolean);
                current.outerHTML = next.outerHTML;
                initializeWorkspace(document);
                var newPanel = document.getElementById('opsgate-triage-live-panel');
                if (newPanel) {
                    if (helpPanelOpen) {
                        var newHelp = newPanel.querySelector('.opsgate-p5-help-panel');
                        if (newHelp) { newHelp.setAttribute('open', ''); }
                    }
                    openRefIds.forEach(function (id) {
                        var el = newPanel.querySelector('.opsgate-triage-reference-details[data-opsgate-accordion-init="' + id + '"]');
                        if (el) { el.setAttribute('open', ''); }
                    });
                }
                return newPanel;
            });
        }

        function showInlineStatus(id, message, kind) {
            var box = document.getElementById(id);
            if (!box) {
                return;
            }
            if (inlineStatusTimers[id]) {
                window.clearTimeout(inlineStatusTimers[id]);
                delete inlineStatusTimers[id];
            }
            box.className = 'opsgate-alert-inline-status is-visible ' + (kind === 'error' ? 'is-error' : 'is-success');
            var text = box.querySelector('p');
            if (text) {
                text.textContent = message;
            }
            if (box.getAttribute('data-opsgate-autohide') !== '0') {
                inlineStatusTimers[id] = window.setTimeout(function () {
                    clearInlineStatus(id);
                }, 5200);
            }
        }

        function clearInlineStatus(id) {
            var box = document.getElementById(id);
            if (!box) {
                return;
            }
            if (inlineStatusTimers[id]) {
                window.clearTimeout(inlineStatusTimers[id]);
                delete inlineStatusTimers[id];
            }
            box.className = 'opsgate-alert-inline-status';
            var text = box.querySelector('p');
            if (text) {
                text.textContent = '';
            }
        }

        function ensureWorkspaceStatusBox() {
            var wrap = document.querySelector('.wrap.opsgate-admin');
            if (!wrap) {
                return null;
            }
            var existing = document.getElementById('opsgate-workspace-status');
            if (existing) {
                return existing;
            }
            var box = document.createElement('div');
            box.id = 'opsgate-workspace-status';
            box.className = 'opsgate-alert-inline-status';
            box.setAttribute('data-opsgate-transient-status', '1');
            box.setAttribute('role', 'status');
            box.setAttribute('aria-live', 'polite');
            var text = document.createElement('p');
            box.appendChild(text);
            var anchor = wrap.querySelector('.opsgate-card, .opsgate-triage-dashboard, .opsgate-alerts-dashboard, .opsgate-reports-dashboard, .opsgate-settings-dashboard, .opsgate-activity-dashboard');
            if (anchor && anchor.parentNode) {
                anchor.parentNode.insertBefore(box, anchor);
            } else {
                wrap.insertBefore(box, wrap.firstChild);
            }
            return box;
        }

        function showWorkspaceStatus(message, kind) {
            var box = ensureWorkspaceStatusBox();
            if (!box) {
                return;
            }
            box.className = 'opsgate-alert-inline-status is-visible ' + (kind === 'error' ? 'is-error' : 'is-success');
            var text = box.querySelector('p');
            if (text) {
                text.textContent = String(message || '');
            }
            window.setTimeout(function () {
                clearInlineStatus('opsgate-workspace-status');
            }, 5200);
        }

        function clearTransientStatuses(root) {
            root = root || document;
            Array.prototype.slice.call(root.querySelectorAll('[data-opsgate-transient-status="1"]')).forEach(function (box) {
                box.classList.remove('is-visible');
            });
        }

        function scrubWorkspaceUrl(rawUrl) {
            try {
                var nextUrl = new URL(normalizeOpsGateUrl(rawUrl || window.location.href), window.location.origin);
                transientWorkspaceQueryKeys.forEach(function (key) {
                    nextUrl.searchParams.delete(key);
                });
                return nextUrl.toString();
            } catch (error) {
                return rawUrl || window.location.href;
            }
        }

        function replaceWorkspaceMarkup(doc, requestUrl, options) {
            options = options || {};
            var next = doc.querySelector('.wrap.opsgate-admin');
            var current = document.querySelector('.wrap.opsgate-admin');
            if (!next || !current) {
                throw new Error('Could not load the latest OpsGate workspace.');
            }
            current.outerHTML = next.outerHTML;

            var historyUrl = options.keepTransientQuery ? (requestUrl || window.location.href) : scrubWorkspaceUrl(requestUrl || window.location.href);
            if (!options.skipHistory && window.history && window.history.replaceState) {
                if (options.replace) {
                    window.history.replaceState({}, '', historyUrl);
                } else if (window.history.pushState) {
                    window.history.pushState({}, '', historyUrl);
                }
            }

            initializeWorkspace(document);

            if (options.preserveScroll) {
                var scrollY = options.scrollY || 0;
                window.requestAnimationFrame(function () {
                    window.scrollTo(0, scrollY);
                });
            } else {
                restoreUiState();
            }
        }

        function initTransientStatuses(root) {
            root = root || document;

            if (window.history && window.history.replaceState) {
                var cleanedUrl = scrubWorkspaceUrl(window.location.href);
                if (cleanedUrl !== window.location.href) {
                    window.history.replaceState({}, '', cleanedUrl);
                }
            }

            Array.prototype.slice.call(root.querySelectorAll('[data-opsgate-transient-status="1"]')).forEach(function (box, index) {
                if (box.getAttribute('data-opsgate-transient-init') === '1') {
                    return;
                }
                box.setAttribute('data-opsgate-transient-init', '1');
                window.setTimeout(function () {
                    clearTransientStatuses(root);
                }, 5200 + (index * 120));
            });
        }

        function loadWorkspace(url, options) {
            options = options || {};
            var normalizedUrl = normalizeOpsGateUrl(url);
            if (workspaceLoading) {
                pendingWorkspaceRequest = {
                    url: normalizedUrl,
                    options: options
                };
                return workspaceLoadPromise || Promise.resolve();
            }

            workspaceLoading = true;
            var preserveScroll = !!options.preserveScroll;
            var scrollY = preserveScroll ? (window.scrollY || window.pageYOffset || 0) : 0;
            saveUiState();

            workspaceLoadPromise = fetch(normalizedUrl, {
                credentials: 'same-origin',
                cache: 'no-store'
            })
            .then(function (response) {
                if (!response.ok) {
                    throw new Error('Could not load the latest OpsGate workspace.');
                }
                return response.text();
            })
            .then(function (html) {
                var parser = new DOMParser();
                var doc = parser.parseFromString(html, 'text/html');
                replaceWorkspaceMarkup(doc, normalizedUrl, {
                    replace: !!options.replace,
                    skipHistory: !!options.skipHistory,
                    preserveScroll: preserveScroll,
                    scrollY: scrollY
                });
            })
            .catch(function (error) {
                showWorkspaceStatus(
                    error && error.message ? error.message : 'Could not update this OpsGate view in place. The current page stayed intact.',
                    'error'
                );
                throw error || new Error('workspace_load_failed');
            })
            .then(function (result) {
                workspaceLoading = false;
                if (pendingWorkspaceRequest) {
                    var nextRequest = pendingWorkspaceRequest;
                    pendingWorkspaceRequest = null;
                    return loadWorkspace(nextRequest.url, nextRequest.options).then(function () {
                        return result;
                    });
                }
                workspaceLoadPromise = null;
                return result;
            }, function (error) {
                workspaceLoading = false;
                workspaceLoadPromise = null;
                if (pendingWorkspaceRequest) {
                    pendingWorkspaceRequest = null;
                }
                throw error;
            });

            return workspaceLoadPromise;
        }

        function initWorkspaceForms(root) {
            root = root || document;
            Array.prototype.slice.call(root.querySelectorAll('.wrap.opsgate-admin form[action*="admin-post.php"]')).forEach(function (form) {
                if (form.getAttribute('data-opsgate-workspace-form-init') === '1') {
                    return;
                }
                var actionInput = form.querySelector('input[name="action"]');
                var actionName = actionInput ? String(actionInput.value || '') : '';
                if (!actionName) {
                    return;
                }
                if (
                    actionName === 'opsgate_run_portfolio_triage' ||
                    actionName === 'opsgate_export_triage_csv' ||
                    actionName === 'opsgate_export_report_html' ||
                    actionName === 'opsgate_export_report_pdf' ||
                    actionName === 'opsgate_export_report_xlsx' ||
                    actionName === 'opsgate_notification_rule_create' ||
                    actionName.indexOf('opsgate_notification_destination_') === 0 ||
                    actionName.indexOf('opsgate_download_') === 0
                ) {
                    return;
                }
                if (form.getAttribute('enctype') && String(form.getAttribute('enctype')).toLowerCase().indexOf('multipart/form-data') !== -1) {
                    return;
                }
                form.setAttribute('data-opsgate-workspace-form-init', '1');
                form.addEventListener('submit', function (event) {
                    event.preventDefault();
                    event.stopPropagation();

                    var submitter = event.submitter || form.querySelector('button[type="submit"], input[type="submit"]');
                    var originalLabel = submitter ? (submitter.textContent || submitter.value || '') : '';
                    if (submitter) {
                        submitter.disabled = true;
                        if (submitter.tagName === 'BUTTON') {
                            submitter.textContent = 'Saving…';
                        } else if ('value' in submitter) {
                            submitter.value = 'Saving…';
                        }
                    }

                    saveUiState();
                    var currentScroll = window.scrollY || window.pageYOffset || 0;
                    var body = new URLSearchParams(new FormData(form));

                    fetch(normalizeOpsGateUrl(form.action), {
                        method: 'POST',
                        credentials: 'same-origin',
                        body: body
                    })
                    .then(function (response) {
                        if (!response.ok) {
                            throw new Error('Could not save this OpsGate change in place.');
                        }
                        return response.text().then(function (html) { return { html: html, url: response.url || window.location.href }; });
                    })
                    .then(function (payload) {
                        var parser = new DOMParser();
                        var doc = parser.parseFromString(payload.html, 'text/html');
                        replaceWorkspaceMarkup(doc, payload.url || window.location.href, {
                            replace: true,
                            preserveScroll: true,
                            scrollY: currentScroll
                        });
                    })
                    .catch(function (error) {
                        showWorkspaceStatus(
                            error && error.message ? error.message : 'Could not save this OpsGate change in place. The current page stayed intact.',
                            'error'
                        );
                    })
                    .finally(function () {
                        if (submitter) {
                            submitter.disabled = false;
                            if (submitter.tagName === 'BUTTON') {
                                submitter.textContent = originalLabel || 'Save';
                            } else if ('value' in submitter) {
                                submitter.value = originalLabel || 'Save';
                            }
                        }
                    });
                });
            });
        }

        function initWorkspaceNavigation() {
            if (useStableRuntime) {
                return;
            }
            if (document.body.getAttribute('data-opsgate-workspace-nav-init') === '1') {
                return;
            }
            document.body.setAttribute('data-opsgate-workspace-nav-init', '1');

            document.addEventListener('click', function (event) {
                var link = event.target.closest('a[href]');
                if (!link || link.hasAttribute('data-opsgate-no-ajax')) {
                    return;
                }
                if (!isOpsGateInternalUrl(link.href)) {
                    return;
                }
                event.preventDefault();
                event.stopPropagation();
                loadWorkspace(normalizeOpsGateUrl(link.href), { preserveScroll: false });
            }, true);

            window.addEventListener('popstate', function () {
                if (!isOpsGateInternalUrl(window.location.href)) {
                    return;
                }
                loadWorkspace(window.location.href, { replace: true, skipHistory: true, preserveScroll: false });
            });
        }

        function initTriageLaunchForms(root) {
            root = root || document;
            Array.prototype.slice.call(root.querySelectorAll('[data-opsgate-triage-launch-form]')).forEach(function (form) {
                if (form.getAttribute('data-opsgate-triage-launch-init') === '1') {
                    return;
                }
                form.setAttribute('data-opsgate-triage-launch-init', '1');
                form.addEventListener('submit', function (event) {
                    event.preventDefault();
                    event.stopPropagation();

                    var ajaxUrl = normalizeOpsGateUrl(form.getAttribute('data-opsgate-triage-run-url') || '');
                    var destinationUrl = scrubWorkspaceUrl(normalizeOpsGateUrl(form.getAttribute('data-opsgate-triage-destination-url') || window.location.href));
                    var nonceField = form.querySelector('input[name="_wpnonce"]');
                    var statusId = form.getAttribute('data-opsgate-status-target') || '';
                    var nonce = nonceField ? (nonceField.value || '') : '';
                    var submitter = event.submitter || form.querySelector('button[type="submit"], input[type="submit"]');
                    var originalLabel = submitter ? (submitter.textContent || submitter.value || '') : '';
                    var livePanel = document.getElementById('opsgate-triage-live-panel');

                    function reportLaunchStatus(message, tone) {
                        if (statusId) {
                            showInlineStatus(statusId, message, tone === 'error' ? 'error' : 'success');
                            return;
                        }
                        if (livePanel) {
                            setRuntimeNote(livePanel, message, tone);
                        }
                    }

                    if (!ajaxUrl || !nonce) {
                        reportLaunchStatus('Could not start Security Scan from this surface right now.', 'error');
                        return;
                    }

                    if (submitter) {
                        submitter.disabled = true;
                        if (submitter.tagName === 'BUTTON') {
                            submitter.textContent = 'Starting run…';
                        } else if ('value' in submitter) {
                            submitter.value = 'Starting run…';
                        }
                    }
                    reportLaunchStatus('Starting Security Scan and opening the live run surface…', 'success');

                    var body = new URLSearchParams();
                    body.set('action', 'opsgate_run_portfolio_triage_live');
                    body.set('nonce', nonce);

                    fetch(ajaxUrl, {
                        method: 'POST',
                        credentials: 'same-origin',
                        headers: {
                            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
                        },
                        body: body.toString()
                    })
                    .then(function (response) { return response.json(); })
                    .then(function (payload) {
                        if (!payload || !payload.success || !payload.data) {
                            throw new Error(payload && payload.data && payload.data.message ? payload.data.message : 'Could not start Security Scan.');
                        }
                        var currentWorkspaceUrl = scrubWorkspaceUrl(window.location.href);
                        var sameWorkspace = destinationUrl === currentWorkspaceUrl;
                        var triagePanel = document.getElementById('opsgate-triage-live-panel');

                        if (sameWorkspace && triagePanel) {
                            updateTriagePanel(triagePanel, payload.data);
                            if (triagePanel._opsgateTriageControl) {
                                triagePanel._opsgateTriageControl.ensurePolling();
                                window.setTimeout(function () {
                                    if (triagePanel._opsgateTriageControl) {
                                        triagePanel._opsgateTriageControl.poll();
                                    }
                                }, 350);
                            }
                            setRuntimeNote(triagePanel, payload.data.message || 'Security Scan started. Live run state is updating in place.', 'success');
                            return;
                        }

                        return loadWorkspace(destinationUrl, { preserveScroll: false }).then(function () {
                            var nextTriagePanel = document.getElementById('opsgate-triage-live-panel');
                            if (nextTriagePanel) {
                                updateTriagePanel(nextTriagePanel, payload.data);
                                if (nextTriagePanel._opsgateTriageControl) {
                                    nextTriagePanel._opsgateTriageControl.ensurePolling();
                                    window.setTimeout(function () {
                                        if (nextTriagePanel._opsgateTriageControl) {
                                            nextTriagePanel._opsgateTriageControl.poll();
                                        }
                                    }, 350);
                                }
                                setRuntimeNote(nextTriagePanel, payload.data.message || 'Security Scan started. Live run state is updating in place.', 'success');
                            }
                        });
                    })
                    .catch(function (error) {
                        reportLaunchStatus(error && error.message ? error.message : 'Could not start Security Scan.', 'error');
                    })
                    .finally(function () {
                        if (!submitter) {
                            return;
                        }
                        submitter.disabled = false;
                        if (submitter.tagName === 'BUTTON') {
                            submitter.textContent = originalLabel || 'Run Security Scan';
                        } else if ('value' in submitter) {
                            submitter.value = originalLabel || 'Run Security Scan';
                        }
                    });
                });
            });
        }

        function initReportsPanel(root) {
            root = root || document;
            var panel = root.querySelector('#opsgate-reports-live-panel');
            if (!panel || panel.getAttribute('data-opsgate-reports-init') === '1') {
                return;
            }
            panel.setAttribute('data-opsgate-reports-init', '1');
            var timer = null;
            var refreshingPanel = false;

            function stopPolling() {
                if (timer) {
                    window.clearTimeout(timer);
                    timer = null;
                }
            }

            function scheduleRefresh(delay) {
                stopPolling();
                if (!panel || !panel.isConnected || !shouldPollReportsPanel(panel)) {
                    return;
                }
                timer = window.setTimeout(function () {
                    poll();
                }, delay || 1500);
            }

            function poll() {
                if (refreshingPanel || !panel || !panel.isConnected) {
                    return;
                }
                refreshingPanel = true;
                stopPolling();
                refreshReportsPanel(panel).then(function (nextPanel) {
                    panel = nextPanel || document.getElementById('opsgate-reports-live-panel') || panel;
                    if (!panel || !shouldPollReportsPanel(panel)) {
                        stopPolling();
                    }
                }).catch(function () {
                    if (panel && panel.isConnected && shouldPollReportsPanel(panel)) {
                        scheduleRefresh(2200);
                    }
                }).finally(function () {
                    refreshingPanel = false;
                });
            }

            if (shouldPollReportsPanel(panel)) {
                scheduleRefresh(700);
            }

            Array.prototype.slice.call(panel.querySelectorAll('[data-opsgate-export-form]')).forEach(function (form) {
                if (form.getAttribute('data-opsgate-export-init') === '1') {
                    return;
                }
                form.setAttribute('data-opsgate-export-init', '1');
                form.addEventListener('submit', function (event) {
                    event.preventDefault();
                    event.stopPropagation();

                    var actionInput = form.querySelector('input[name="action"]');
                    var sourceInput = form.querySelector('input[name="source_job_id"]');
                    var exportType = '';
                    if (actionInput) {
                        if (actionInput.value === 'opsgate_export_report_pdf') {
                            exportType = 'pdf';
                        } else if (actionInput.value === 'opsgate_export_report_html') {
                            exportType = 'html';
                        } else if (actionInput.value === 'opsgate_export_report_xlsx') {
                            exportType = 'xlsx';
                        } else if (actionInput.value === 'opsgate_export_triage_csv') {
                            exportType = 'csv';
                        }
                    }
                    if (!exportType || !sourceInput) {
                        return;
                    }

                    var ajaxUrl = normalizeOpsGateUrl(panel.getAttribute('data-opsgate-ajax-url') || '');
                    var nonce = panel.getAttribute('data-opsgate-export-nonce') || '';
                    var submit = form.querySelector('button[type="submit"]');
                    var originalLabel = submit ? submit.textContent : '';
                    if (submit) {
                        submit.disabled = true;
                        submit.textContent = 'Generating…';
                    }

                    var params = new URLSearchParams();
                    params.set('action', 'opsgate_export_start');
                    params.set('nonce', nonce);
                    params.set('export_type', exportType);
                    params.set('source_job_id', sourceInput.value || '');

                    fetch(ajaxUrl, {
                        method: 'POST',
                        credentials: 'same-origin',
                        headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
                        body: params.toString()
                    })
                    .then(function (response) { return response.json(); })
                    .then(function (payload) {
                        if (!payload || !payload.success || !payload.data) {
                            throw new Error(payload && payload.data && payload.data.message ? payload.data.message : 'Could not start the packaged output.');
                        }
                        showInlineStatus('opsgate-reports-status-box', payload.data.message || 'Packaged output started.', 'success');
                        panel.setAttribute('data-opsgate-live-states', 'RUNNING');
                        if (payload.data.export_job_id) {
                            panel.setAttribute('data-opsgate-current-export-job-id', String(payload.data.export_job_id));
                            panel.setAttribute(
                                'data-opsgate-poll-url',
                                normalizeOpsGateUrl(
                                    panel.getAttribute('data-opsgate-ajax-url') || ''
                                ).replace(/admin-ajax\.php(?:\?.*)?$/i, 'admin-ajax.php?action=opsgate_export_record_status&export_job_id=' + encodeURIComponent(String(payload.data.export_job_id)))
                            );
                        }
                        if (payload.data.source_job_id) {
                            panel.setAttribute('data-opsgate-current-source-job-id', String(payload.data.source_job_id));
                        }
                        stopPolling();
                        refreshReportsPanel(panel).then(function (nextPanel) {
                            panel = nextPanel || document.getElementById('opsgate-reports-live-panel') || panel;
                            if (panel && shouldPollReportsPanel(panel)) {
                                scheduleRefresh(700);
                            }
                        }).catch(function () {
                            // Leave the current report center active if the first processing refresh fails.
                            scheduleRefresh(1200);
                        });
                    })
                    .catch(function (error) {
                        showInlineStatus('opsgate-reports-status-box', error && error.message ? error.message : 'Could not start the packaged output.', 'error');
                    })
                    .finally(function () {
                        if (submit) {
                            submit.disabled = false;
                            submit.textContent = originalLabel || 'Generate';
                        }
                    });
                });
            });
        }

        function initReportsViewer() {
            if (document.body.getAttribute('data-opsgate-viewer-init') === '1') {
                return;
            }
            document.body.setAttribute('data-opsgate-viewer-init', '1');
            document.addEventListener('click', function (event) {
                var modal = document.getElementById('opsgate-reports-viewer-modal');
                var frame = document.getElementById('opsgate-reports-viewer-frame');
                var title = document.getElementById('opsgate-reports-viewer-title');
                if (!modal || !frame || !title) {
                    return;
                }
                var trigger = event.target.closest('.opsgate-reports-viewer-trigger');
                if (trigger) {
                    event.preventDefault();
                    title.textContent = (trigger.getAttribute('data-viewer-kind') || 'Client Report') + ' Viewer';
                    frame.setAttribute('src', trigger.getAttribute('data-viewer-url') || 'about:blank');
                    modal.removeAttribute('hidden');
                    return;
                }
                if (event.target.closest('[data-opsgate-viewer-close]')) {
                    event.preventDefault();
                    modal.setAttribute('hidden', 'hidden');
                    frame.setAttribute('src', 'about:blank');
                }
            }, true);

            document.addEventListener('keydown', function (event) {
                var modal = document.getElementById('opsgate-reports-viewer-modal');
                var frame = document.getElementById('opsgate-reports-viewer-frame');
                if (!modal || !frame) {
                    return;
                }
                if (event.key === 'Escape' && !modal.hasAttribute('hidden')) {
                    modal.setAttribute('hidden', 'hidden');
                    frame.setAttribute('src', 'about:blank');
                }
            });
        }

        function refreshAlertsPanelInPlace() {
            if (window.OpsGateStableUI && typeof window.OpsGateStableUI.refreshAlertsPanel === 'function') {
                return window.OpsGateStableUI.refreshAlertsPanel();
            }
            return loadWorkspace(scrubWorkspaceUrl(window.location.href), { replace: true, preserveScroll: true });
        }

        function isLegacyAlertsToggleForm(form) {
            return !!(form && form.closest && form.closest('.opsgate-alerts-legacy-block'));
        }

        function refreshAlertsRuleRowInPlace(ruleId, currentForm) {
            var panel = document.getElementById('opsgate-alerts-live-panel');
            var normalizedRuleId = String(ruleId || '').trim();
            if (!panel || !normalizedRuleId) {
                return refreshAlertsPanelInPlace();
            }
            var currentToggleForms = Array.prototype.slice.call(panel.querySelectorAll('.opsgate-alert-switch-form[data-rule-id]')).filter(function (candidate) {
                return !isLegacyAlertsToggleForm(candidate) && (candidate.getAttribute('data-rule-id') || '') === normalizedRuleId;
            });
            if (!currentToggleForms.length) {
                return refreshAlertsPanelInPlace();
            }
            var refreshUrl = normalizeOpsGateUrl(panel.getAttribute('data-opsgate-refresh-url') || window.location.href);
            return fetch(refreshUrl, {
                credentials: 'same-origin',
                cache: 'no-store'
            }).then(function (response) {
                if (!response.ok) {
                    throw new Error('Could not refresh this alert row.');
                }
                return response.text();
            }).then(function (html) {
                var parser = new DOMParser();
                var doc = parser.parseFromString(html, 'text/html');
                var nextPanel = doc.getElementById('opsgate-alerts-live-panel');
                if (!nextPanel) {
                    throw new Error('Could not refresh this alert row.');
                }
                var nextToggleForms = Array.prototype.slice.call(nextPanel.querySelectorAll('.opsgate-alert-switch-form[data-rule-id]')).filter(function (candidate) {
                    return !isLegacyAlertsToggleForm(candidate) && (candidate.getAttribute('data-rule-id') || '') === normalizedRuleId;
                });
                if (!nextToggleForms.length) {
                    throw new Error('Could not refresh this alert row.');
                }
                currentToggleForms.forEach(function (toggleForm, index) {
                    var currentRow = toggleForm.closest('tr');
                    var nextForm = nextToggleForms[index] || nextToggleForms[0] || null;
                    var nextRow = nextForm ? nextForm.closest('tr') : null;
                    if (!currentRow || !nextRow) {
                        return;
                    }
                    currentRow.outerHTML = nextRow.outerHTML;
                });
                var livePanel = document.getElementById('opsgate-alerts-live-panel');
                if (livePanel) {
                    livePanel.removeAttribute('data-opsgate-alerts-init');
                    initAlertsPanel(livePanel);
                }
                return true;
            });
        }

        function alertToggleFormsForRule(ruleId, root) {
            var normalizedRuleId = String(ruleId || '').trim();
            var scopeRoot = root || document;
            if (!normalizedRuleId || !scopeRoot || !scopeRoot.querySelectorAll) {
                return [];
            }
            return Array.prototype.slice.call(scopeRoot.querySelectorAll('.opsgate-alert-switch-form[data-rule-id]')).filter(function (candidate) {
                return !isLegacyAlertsToggleForm(candidate) && (candidate.getAttribute('data-rule-id') || '') === normalizedRuleId;
            });
        }

        function syncAlertsRuleRowState(form, isEnabled) {
            if (!form) {
                return;
            }
            var switchControl = form.querySelector('[data-opsgate-alert-toggle-button]');
            var label = form.querySelector('[data-opsgate-alert-toggle-label]');
            var row = form.closest('tr');
            var routingChip = form.parentNode ? form.parentNode.querySelector('[data-opsgate-alert-routing-chip]') : null;
            var routingCopy = form.parentNode ? form.parentNode.querySelector('[data-opsgate-alert-routing-copy]') : null;
            var configChip = row ? row.querySelector('[data-opsgate-alert-config-chip]') : null;
            var deliveryChip = row ? row.querySelector('[data-opsgate-alert-delivery-chip]') : null;
            var actionField = form.querySelector('input[name="action"]');
            var nonceField = form.querySelector('input[name="_wpnonce"]');
            var refererField = form.querySelector('input[name="_wp_http_referer"]');

            form.setAttribute('data-next-enabled', isEnabled ? '0' : '1');
            form.setAttribute('data-current-enabled', isEnabled ? '1' : '0');

            if (switchControl) {
                switchControl.setAttribute('aria-checked', isEnabled ? 'true' : 'false');
                switchControl.setAttribute('aria-label', isEnabled ? 'Disable alert' : 'Enable alert');
            }
            if (actionField) {
                actionField.value = isEnabled ? 'opsgate_notification_rule_disable' : 'opsgate_notification_rule_enable';
            }
            if (nonceField) {
                nonceField.value = isEnabled
                    ? (form.getAttribute('data-disable-admin-nonce') || nonceField.value)
                    : (form.getAttribute('data-enable-admin-nonce') || nonceField.value);
            }
            if (refererField && !refererField.value) {
                refererField.value = window.location.href;
            }
            if (label) {
                label.textContent = isEnabled ? 'ON' : 'OFF';
            }
            if (row) {
                row.classList.toggle('is-enabled', isEnabled);
            }
            if (configChip) {
                var configTone = isEnabled
                    ? (form.getAttribute('data-config-enabled-tone') || 'good')
                    : (form.getAttribute('data-config-disabled-tone') || 'info');
                var configLabel = isEnabled
                    ? (form.getAttribute('data-config-enabled-label') || 'Configured')
                    : (form.getAttribute('data-config-disabled-label') || 'Available');
                configChip.className = 'opsgate-alerts-status-chip opsgate-alerts-status-chip-' + configTone;
                configChip.textContent = configLabel;
            }
            if (deliveryChip) {
                var deliveryTone = isEnabled
                    ? (form.getAttribute('data-delivery-enabled-tone') || 'neutral')
                    : (form.getAttribute('data-delivery-disabled-tone') || 'info');
                var deliveryLabel = isEnabled
                    ? (form.getAttribute('data-delivery-enabled-label') || 'No delivery recorded yet')
                    : (form.getAttribute('data-delivery-disabled-label') || 'Rule is off');
                deliveryChip.className = 'opsgate-alerts-status-chip opsgate-alerts-status-chip-' + deliveryTone;
                deliveryChip.textContent = deliveryLabel;
            }
            if (routingChip) {
                var enabledRoutingLabel = form.getAttribute('data-routing-enabled-label') || 'On';
                var enabledRoutingTone = form.getAttribute('data-routing-enabled-tone') || 'good';
                routingChip.className = 'opsgate-alerts-status-chip opsgate-alerts-status-chip-' + (isEnabled ? enabledRoutingTone : 'info');
                routingChip.textContent = isEnabled ? enabledRoutingLabel : 'Off';
            }
            if (routingCopy) {
                var enabledRoutingCopy = form.getAttribute('data-routing-enabled-copy') || 'This alert is enabled.';
                routingCopy.textContent = isEnabled ? enabledRoutingCopy : 'Toggle on to route this alert.';
            }
        }

        function syncAlertsRuleState(ruleId, isEnabled, root) {
            var forms = alertToggleFormsForRule(ruleId, root);
            if (!forms.length) {
                return;
            }
            forms.forEach(function (candidateForm) {
                syncAlertsRuleRowState(candidateForm, isEnabled);
            });
        }

        function setAlertsRuleBusyState(ruleId, isBusy, root) {
            var forms = alertToggleFormsForRule(ruleId, root);
            forms.forEach(function (candidateForm) {
                var candidateSwitch = candidateForm.querySelector('[data-opsgate-alert-toggle-button]');
                if (isBusy) {
                    candidateForm.setAttribute('data-opsgate-toggle-busy', '1');
                    candidateForm.classList.add('is-busy');
                    if (candidateSwitch) {
                        candidateSwitch.classList.add('is-busy');
                        candidateSwitch.disabled = true;
                    }
                    return;
                }
                candidateForm.removeAttribute('data-opsgate-toggle-busy');
                candidateForm.classList.remove('is-busy');
                if (candidateSwitch) {
                    candidateSwitch.classList.remove('is-busy');
                    candidateSwitch.disabled = false;
                }
            });
        }

        function submitAlertsRuleToggle(form, requestedEnabled) {
            if (!form) {
                return Promise.resolve(false);
            }
            var switchControl = form.querySelector('[data-opsgate-alert-toggle-button]');
            if (!switchControl || switchControl.disabled || form.getAttribute('data-opsgate-toggle-busy') === '1') {
                return Promise.resolve(false);
            }
            var panel = document.getElementById('opsgate-alerts-live-panel');
            var ajaxUrl = panel ? normalizeOpsGateUrl(panel.getAttribute('data-opsgate-ajax-url') || '') : '';
            if (!ajaxUrl) {
                ajaxUrl = normalizeOpsGateUrl(form.getAttribute('data-ajax-url') || '');
            }
            var nonce = form.getAttribute('data-ajax-nonce') || '';
            var ruleId = form.getAttribute('data-rule-id') || '';
            var previousEnabled = form.getAttribute('data-current-enabled') === '1';
            var params = new URLSearchParams();
            params.set('action', 'opsgate_notification_rule_toggle');
            params.set('nonce', nonce);
            params.set('rule_id', ruleId);
            params.set('enabled', requestedEnabled ? '1' : '0');

            syncAlertsRuleState(ruleId, requestedEnabled);
            setAlertsRuleBusyState(ruleId, true);

            return fetch(ajaxUrl, {
                method: 'POST',
                credentials: 'same-origin',
                headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
                body: params.toString()
            })
            .then(function (response) { return response.json(); })
            .then(function (payload) {
                if (!payload || !payload.success || !payload.data) {
                    throw new Error(payload && payload.data && payload.data.message ? payload.data.message : 'Could not update the alert setting.');
                }
                var isEnabled = !!payload.data.is_enabled;
                syncAlertsRuleState(ruleId, isEnabled);
                showInlineStatus('opsgate-alerts-rules-status', payload.data.message || 'Alert setting updated.', 'success');
                return refreshAlertsRuleRowInPlace(ruleId, form);
            })
            .catch(function (error) {
                syncAlertsRuleState(ruleId, previousEnabled);
                showInlineStatus('opsgate-alerts-rules-status', error && error.message ? error.message : 'Could not update the alert setting.', 'error');
                return false;
            })
            .finally(function () {
                setAlertsRuleBusyState(ruleId, false);
            });
        }

        window.OpsGateAlertToggle = {
            handleClick: function (button) {
                if (!button || !button.closest) {
                    return false;
                }
                var form = button.closest('.opsgate-alert-switch-form[data-rule-id]');
                if (!form) {
                    return false;
                }
                var nextEnabled = form.getAttribute('data-current-enabled') !== '1';
                submitAlertsRuleToggle(form, nextEnabled);
                return false;
            }
        };

        function initAlertsPanel(root) {
            root = root || document;
            var panel = root && root.id === 'opsgate-alerts-live-panel'
                ? root
                : (root.querySelector ? root.querySelector('#opsgate-alerts-live-panel') : null);
            if (!panel || panel.getAttribute('data-opsgate-alerts-init') === '1') {
                return;
            }
            panel.setAttribute('data-opsgate-alerts-init', '1');
            var ajaxUrl = normalizeOpsGateUrl(panel.getAttribute('data-opsgate-ajax-url') || '');

            var familySelect = panel.querySelector('#opsgate-destination-family');
            var familyValueLabel = panel.querySelector('#opsgate-alerts-destination-value-label');
            var familyValueInput = panel.querySelector('#opsgate-destination-value');
            var familyValueHelp = panel.querySelector('#opsgate-alerts-destination-value-help');
            var familyNote = panel.querySelector('#opsgate-alerts-destination-family-note');

            function syncDestinationFamilyHelp() {
                if (!familySelect) {
                    return;
                }
                var option = familySelect.options[familySelect.selectedIndex];
                if (!option) {
                    return;
                }
                if (familyValueLabel) {
                    familyValueLabel.textContent = option.getAttribute('data-value-label') || 'Destination value';
                }
                if (familyValueInput) {
                    familyValueInput.setAttribute('placeholder', option.getAttribute('data-placeholder') || '');
                }
                if (familyValueHelp) {
                    familyValueHelp.textContent = option.getAttribute('data-help') || '';
                }
                if (familyNote) {
                    var stateLabel = option.getAttribute('data-state-label') || '';
                    var note = option.getAttribute('data-note') || '';
                    familyNote.textContent = [stateLabel, note].filter(Boolean).join(' • ');
                }
            }
            if (familySelect) {
                syncDestinationFamilyHelp();
                familySelect.addEventListener('change', syncDestinationFamilyHelp);
            }

            function destinationStatusTargetId(form) {
                if (!form) {
                    return 'opsgate-alert-destinations-status';
                }
                return form.getAttribute('data-opsgate-status-target') || 'opsgate-alert-destinations-status';
            }

            function destinationFieldErrorMessage(family, key, type, value, isRequired, isUpdate, isSecret) {
                var trimmed = String(value || '').trim();
                    if (!trimmed) {
                        if (!isRequired || (isUpdate && isSecret)) {
                            return '';
                        }
                        if (family === 'email' && key === 'recipient') {
                            return 'Enter a recipient email address before saving this email destination.';
                        }
                        if ((family === 'webhook' || family === 'slack' || family === 'teams' || family === 'discord') && key === 'url') {
                            return 'Enter the webhook URL before saving this destination.';
                        }
                        if (family === 'telegram' && key === 'bot_token') {
                            return 'Enter the Telegram bot token before saving this destination.';
                        }
                        if (family === 'telegram' && key === 'chat_id') {
                            return 'Enter the Telegram chat ID before saving this destination.';
                        }
                        if (family === 'whatsapp' && key === 'recipient') {
                            return 'Enter the WhatsApp recipient before saving this destination.';
                        }
                        if (family === 'sns' && key === 'topic_arn') {
                            return 'Enter the SNS topic ARN before saving this destination.';
                        }
                    return 'Finish the required destination details before saving this route.';
                }

                if (family === 'email' && key === 'recipient') {
                    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(trimmed)) {
                        return 'Enter a valid recipient email address for this destination.';
                    }
                }

                if (key === 'cc') {
                    var ccItems = trimmed.split(/[\r\n,;]+/).map(function (item) { return item.trim(); }).filter(Boolean);
                    for (var i = 0; i < ccItems.length; i += 1) {
                        if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(ccItems[i])) {
                            return 'One or more CC email addresses are invalid. Use valid comma-separated email addresses.';
                        }
                    }
                }

                if ((type === 'url') || ((family === 'webhook' || family === 'slack' || family === 'teams' || family === 'discord') && key === 'url')) {
                    try {
                        var parsedUrl = new URL(trimmed);
                        if (!/^https?:$/.test(parsedUrl.protocol)) {
                            return 'Enter a valid HTTPS webhook URL before saving this destination.';
                        }
                    } catch (error) {
                        return 'Enter a valid HTTPS webhook URL before saving this destination.';
                    }
                }

                return '';
            }

            function validateDestinationForm(form) {
                if (!form) {
                    return '';
                }
                var familyField = form.querySelector('.opsgate-destination-family-select') || form.querySelector('input[name="destination_family"]');
                var family = familyField ? String(familyField.value || '').trim().toLowerCase() : '';
                var actionField = form.querySelector('input[name="action"]');
                var actionName = actionField ? String(actionField.value || '') : '';
                var isUpdate = actionName === 'opsgate_notification_destination_update';
                var fields = form.querySelectorAll('[data-opsgate-destination-field-key]');
                for (var i = 0; i < fields.length; i += 1) {
                    var field = fields[i];
                    var fieldKey = field.getAttribute('data-opsgate-destination-field-key') || '';
                    var fieldType = field.getAttribute('data-opsgate-destination-field-type') || field.getAttribute('type') || 'text';
                    var fieldRequired = field.getAttribute('data-opsgate-destination-field-required') === '1';
                    var fieldSecret = field.getAttribute('data-opsgate-destination-field-secret') === '1';
                    var fieldFamily = field.getAttribute('data-opsgate-destination-family') || '';
                    var familyGroup = field.closest('[data-family-fields]');
                    if (familyGroup && familyGroup.getAttribute('data-family-fields') !== family) {
                        continue;
                    }
                    if (fieldFamily && fieldFamily !== family) {
                        continue;
                    }
                    var fieldError = destinationFieldErrorMessage(family, fieldKey, fieldType, field.value || '', fieldRequired, isUpdate, fieldSecret);
                    if (fieldError) {
                        return fieldError;
                    }
                }
                return '';
            }

            function wireDestinationFormState(form) {
                if (!form || form.getAttribute('data-opsgate-destination-state-init') === '1') {
                    return;
                }
                form.setAttribute('data-opsgate-destination-state-init', '1');
                var statusId = destinationStatusTargetId(form);
                Array.prototype.slice.call(form.querySelectorAll('input, select, textarea')).forEach(function (field) {
                    field.addEventListener('input', function () {
                        clearInlineStatus(statusId);
                    });
                    field.addEventListener('change', function () {
                        clearInlineStatus(statusId);
                    });
                });
            }

            Array.prototype.slice.call(panel.querySelectorAll('.opsgate-alert-switch-form[data-rule-id]')).forEach(function (form) {
                if (isLegacyAlertsToggleForm(form)) {
                    return;
                }
                if (form.getAttribute('data-opsgate-toggle-init') === '1') {
                    return;
                }
                form.setAttribute('data-opsgate-toggle-init', '1');
                form._opsgateSubmitToggleRequest = function (requestedEnabled) {
                    return submitAlertsRuleToggle(form, requestedEnabled);
                };
                var switchControl = form.querySelector('[data-opsgate-alert-toggle-button]');
                if (!switchControl) {
                    return;
                }
                var renderedEnabled = form.getAttribute('data-rendered-enabled');
                var initialEnabled = renderedEnabled === '1';
                syncAlertsRuleRowState(form, initialEnabled);
                if (switchControl) {
                    switchControl.setAttribute('role', 'switch');
                    switchControl.setAttribute('tabindex', '0');
                    switchControl.setAttribute('aria-checked', initialEnabled ? 'true' : 'false');
                    if (switchControl.getAttribute('data-opsgate-alert-control-init') !== '1') {
                        switchControl.setAttribute('data-opsgate-alert-control-init', '1');
                        switchControl.addEventListener('click', function (event) {
                            event.preventDefault();
                            event.stopPropagation();
                            var nextEnabled = form.getAttribute('data-current-enabled') !== '1';
                            form._opsgateSubmitToggleRequest(nextEnabled);
                        });
                        switchControl.addEventListener('keydown', function (event) {
                            if (event.key !== ' ' && event.key !== 'Enter') {
                                return;
                            }
                            event.preventDefault();
                            event.stopPropagation();
                            var nextEnabled = form.getAttribute('data-current-enabled') !== '1';
                            form._opsgateSubmitToggleRequest(nextEnabled);
                        });
                    }
                }
            });

            Array.prototype.slice.call(panel.querySelectorAll('form[action*="admin-post.php"]')).forEach(function (form) {
                if (form.getAttribute('data-opsgate-alert-form-init') === '1') {
                    return;
                }
                var actionInput = form.querySelector('input[name="action"]');
                if (!actionInput) {
                    return;
                }
                var actionName = actionInput.value || '';
                var ajaxKind = '';
                if (actionName === 'opsgate_notification_rule_create') {
                    ajaxKind = 'rule';
                } else if (actionName === 'opsgate_notification_rule_delete') {
                    ajaxKind = 'rule-delete';
                } else if (actionName.indexOf('opsgate_notification_destination_') === 0) {
                    ajaxKind = 'destination';
                }
                if (!ajaxKind) {
                    return;
                }
                form.setAttribute('data-opsgate-alert-form-init', '1');
                if (ajaxKind === 'destination') {
                    wireDestinationFormState(form);
                }
                form.addEventListener('submit', function (event) {
                    event.preventDefault();
                    event.stopPropagation();
                    var statusId = ajaxKind === 'destination' ? destinationStatusTargetId(form) : 'opsgate-alerts-rules-status';
                    if (ajaxKind === 'rule-delete' && !window.confirm('Remove this alert rule from the live routing table?')) {
                        return;
                    }
                    if (ajaxKind === 'destination' && (actionName === 'opsgate_notification_destination_create' || actionName === 'opsgate_notification_destination_update')) {
                        var validationMessage = validateDestinationForm(form);
                        if (validationMessage) {
                            showInlineStatus(statusId, validationMessage, 'error');
                            return;
                        }
                    }
                    var params = new URLSearchParams(new FormData(form));
                    var nonceField = form.querySelector('input[name="_wpnonce"]');
                    var nonceValue = nonceField ? (nonceField.value || '') : '';
                    var ajaxAction = 'opsgate_notification_destination_mutation';
                    if (ajaxKind === 'rule') {
                        ajaxAction = 'opsgate_notification_rule_create';
                    } else if (ajaxKind === 'rule-delete') {
                        ajaxAction = 'opsgate_notification_rule_delete';
                    }
                    var submitter = event.submitter || form.querySelector('button[type="submit"], input[type="submit"]');
                    var originalSubmitText = submitter ? (submitter.textContent || submitter.value || '') : '';
                    if (submitter) {
                        submitter.disabled = true;
                        if (submitter.tagName === 'BUTTON') {
                            submitter.textContent = actionName === 'opsgate_notification_destination_test' ? 'Queueing…' : (ajaxKind === 'rule-delete' ? 'Removing…' : 'Saving…');
                        } else if ('value' in submitter) {
                            submitter.value = actionName === 'opsgate_notification_destination_test' ? 'Queueing…' : (ajaxKind === 'rule-delete' ? 'Removing…' : 'Saving…');
                        }
                    }
                    params.set('action', ajaxAction);
                    params.set('nonce', nonceValue);
                    if (ajaxKind === 'destination') {
                        params.set('mutation_action', actionName);
                    }
                    fetch(ajaxUrl, {
                        method: 'POST',
                        credentials: 'same-origin',
                        headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
                        body: params.toString()
                    })
                    .then(function (response) { return response.json(); })
                    .then(function (payload) {
                        if (!payload || !payload.success || !payload.data) {
                            throw new Error(payload && payload.data && payload.data.message ? payload.data.message : 'Could not update the alert center.');
                        }
                        return refreshAlertsPanelInPlace().then(function () {
                            showInlineStatus(
                                statusId,
                                payload.data.message || 'Alert center updated.',
                                'success'
                            );
                        });
                    })
                    .catch(function (error) {
                        showInlineStatus(
                            statusId,
                            error && error.message ? error.message : 'Could not update the alert center.',
                            'error'
                        );
                    })
                    .finally(function () {
                        if (!submitter) {
                            return;
                        }
                        submitter.disabled = false;
                        if (submitter.tagName === 'BUTTON') {
                            submitter.textContent = originalSubmitText || 'Save';
                        } else if ('value' in submitter) {
                            submitter.value = originalSubmitText || 'Save';
                        }
                    });
                });
            });
        }

        function safeWorkspaceStep(label, callback) {
            try {
                callback();
            } catch (error) {
                if (window.console && typeof window.console.error === 'function') {
                    window.console.error('OpsGate workspace step failed:', label, error);
                }
            }
        }

        function initializeWorkspace(root) {
            safeWorkspaceStep('transient-statuses', function () {
                initTransientStatuses(root);
            });
            if (!useStableRuntime) {
                safeWorkspaceStep('triage-launch-forms', function () {
                    initTriageLaunchForms(root);
                });
                safeWorkspaceStep('triage-live-panel', function () {
                    initTriageLivePanel(root);
                });
            }
            safeWorkspaceStep('triage-reference-accordion', function () {
                initTriageReferenceAccordion(root);
            });
            if (!useStableRuntime) {
                safeWorkspaceStep('reports-panel', function () {
                    initReportsPanel(root);
                });
                safeWorkspaceStep('reports-viewer', function () {
                    initReportsViewer();
                });
            }
            safeWorkspaceStep('alerts-panel', function () {
                initAlertsPanel(root);
            });
            if (!useStableRuntime) {
                safeWorkspaceStep('workspace-forms', function () {
                    initWorkspaceForms(root);
                });
            }
        }

        window.OpsGateWorkspace = {
            loadWorkspace: loadWorkspace,
            initializeWorkspace: initializeWorkspace,
            normalizeUrl: normalizeOpsGateUrl,
            scrubUrl: scrubWorkspaceUrl
        };

        document.documentElement.setAttribute('data-opsgate-js', '1');
        safeWorkspaceStep('workspace-navigation', function () {
            initWorkspaceNavigation();
        });
        initializeWorkspace(document);
        }

        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', opsgateBoot, { once: true });
        } else {
            opsgateBoot();
        }
    }());
    JS;

        wp_add_inline_script( 'opsgate-admin-inline', $inline_js );

        // Theme toggle JS — persists preference via AJAX to WP option.
        $theme_js = <<<JS
(function() {
    var btn = document.getElementById('opsgate-theme-toggle');
    if (!btn) { return; }
    var wrap = document.querySelector('.wrap.opsgate-admin[data-og-theme]');
    if (!wrap) { return; }
    var iconDark  = btn.querySelector('.opsgate-theme-icon-dark');
    var iconLight = btn.querySelector('.opsgate-theme-icon-light');
    var label     = btn.querySelector('.opsgate-theme-toggle-label');
    btn.addEventListener('click', function() {
        var current = wrap.getAttribute('data-og-theme') || 'light';
        var next    = current === 'dark' ? 'light' : 'dark';
        wrap.setAttribute('data-og-theme', next);
        if (iconDark)  { iconDark.style.display  = next === 'dark' ? 'none' : 'block'; }
        if (iconLight) { iconLight.style.display = next === 'dark' ? 'block' : 'none'; }
        if (label)     { label.textContent = next === 'dark' ? 'Light mode' : 'Dark mode'; }
        // Persist via AJAX
        var fd = new FormData();
        fd.append('action', 'opsgate_set_ui_theme');
        fd.append('theme', next);
        fd.append('nonce', (window.opsgateAdminData && window.opsgateAdminData.themeNonce) || '');
        fetch(window.ajaxurl || '/wp-admin/admin-ajax.php', { method: 'POST', credentials: 'same-origin', body: fd });
    });
}());
JS;
        wp_add_inline_script( 'opsgate-admin-inline', $theme_js );
    }


    /**
     * Day-11: Default Agency State (Phase 1).
     *
     * @return array
     */
    private static function default_agency_state() {
        $now = time();

        return array(
            'agency' => array(
                'name'                => '',
                'logo_url'            => '',
                'primary_color'        => '#0073aa',
                'white_label_enabled' => 0,
            ),
            'groups' => array(),
            'meta'   => array(
                'created' => $now,
                'updated' => $now,
            ),
        );
    }

    /**
     * Day-11: Get Agency state, always normalized.
     *
     * @return array
     */
    private static function get_agency_state() {
        $raw = get_option( 'opsgate_agency_state', null );

        if ( ! is_array( $raw ) ) {
            $raw = self::default_agency_state();
            update_option( 'opsgate_agency_state', $raw, false );
            return $raw;
        }

        // Normalize minimally (future-safe).
        if ( ! isset( $raw['agency'] ) || ! is_array( $raw['agency'] ) ) {
            $raw['agency'] = array();
        }
        if ( ! isset( $raw['groups'] ) || ! is_array( $raw['groups'] ) ) {
            $raw['groups'] = array();
        }
        if ( ! isset( $raw['meta'] ) || ! is_array( $raw['meta'] ) ) {
            $raw['meta'] = array();
        }

        $raw['agency'] = array_merge(
            array(
                'name'                => '',
                'logo_url'            => '',
                'primary_color'        => '#0073aa',
                'white_label_enabled' => 0,
            ),
            $raw['agency']
        );

        $raw['meta'] = array_merge(
            array(
                'created' => (int) time(),
                'updated' => (int) time(),
            ),
            $raw['meta']
        );

        return $raw;
    }

    /**
     * Day-11: Persist Agency state with updated timestamp.
     *
     * @param array $state State.
     * @return void
     */
    private static function save_agency_state( $state ) {
        $state                 = is_array( $state ) ? $state : self::default_agency_state();
        $state['meta']         = isset( $state['meta'] ) && is_array( $state['meta'] ) ? $state['meta'] : array();
        $state['meta']['updated'] = time();

        if ( ! isset( $state['meta']['created'] ) ) {
            $state['meta']['created'] = $state['meta']['updated'];
        }

        update_option( 'opsgate_agency_state', $state, false );
    }

    /**
     * Day-11: Render Agency tab (Phase 1).
     *
     * @return void
     */
    public static function render_agency_tab() {
        $state  = self::get_agency_state();
        $agency = $state['agency'];
        $groups = $state['groups'];

        $notice = isset( $_GET['opsgate_agency_notice'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_agency_notice'] ) ) : '';
        ?>
        <div class="opsgate-card" style="margin-top:12px;">
            <h2 style="margin:0 0 10px 0;">
                <span class="dashicons dashicons-admin-multisite"></span>
                Client Portfolio
            </h2>
            <div style="margin:10px 0 12px 0; display:flex; gap:10px; flex-wrap:wrap;">
                <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:0;">
                    <input type="hidden" name="action" value="opsgate_agency_export_state" />
                    <?php wp_nonce_field( 'opsgate_agency_export_state' ); ?>
                    <button type="submit" class="button">Export Portfolio (JSON)</button>
                </form>

                <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:0;">
                    <input type="hidden" name="action" value="opsgate_agency_reset_state" />
                    <?php wp_nonce_field( 'opsgate_agency_reset_state' ); ?>
                    <button type="submit" class="button button-secondary">Reset Portfolio</button>
                </form>
            </div>

            <?php
            $notice_code = isset( $_GET['opsgate_agency_notice'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_agency_notice'] ) ) : '';
            if ( '' !== $notice_code ) {
                $map = array(
                    // Success
                    'agency_saved'        => array( 'success', '✓ Agency settings saved.' ),
                    'group_created'       => array( 'success', '✓ Group created.' ),
                    'group_deleted'       => array( 'success', '✓ Group deleted.' ),
                    'site_added'          => array( 'success', '✓ Site added to group.' ),
                    'site_removed'        => array( 'success', '✓ Site removed from group.' ),
                    'reset_ok'            => array( 'success', '✓ Agency state reset to defaults.' ),
                    'export_failed'       => array( 'error', 'Could not export agency state (JSON encoding failed).' ),


                    // Errors / guardrails
                    'missing_group'       => array( 'error', 'Group not found.' ),
                    'missing_fields'      => array( 'error', 'Missing required fields.' ),
                    'label_required'      => array( 'error', 'Site label is required.' ),
                    'site_id_required'    => array( 'error', 'site_id is required.' ),
                    'site_id_invalid'     => array( 'error', 'site_id is invalid (no spaces allowed).' ),
                    'site_id_too_long'    => array( 'error', 'site_id is too long (max 64 characters).' ),
                    'duplicate_site_id'   => array( 'error', 'This site_id already exists in this group.' ),
                );

                $cls = 'info';
                $msg = 'Notice: ' . $notice_code;

                if ( isset( $map[ $notice_code ] ) ) {
                    $cls = (string) $map[ $notice_code ][0];
                    $msg = (string) $map[ $notice_code ][1];
                }

                $notice_class = 'notice notice-info';
                if ( 'success' === $cls ) {
                    $notice_class = 'notice notice-success';
                } elseif ( 'error' === $cls ) {
                    $notice_class = 'notice notice-error';
                } elseif ( 'warning' === $cls ) {
                    $notice_class = 'notice notice-warning';
                }

                echo '<div class="' . esc_attr( $notice_class ) . ' is-dismissible"><p>' . esc_html( $msg ) . '</p></div>';
            }
            ?>

            <?php
            $updated = isset( $state['meta']['updated'] ) ? (int) $state['meta']['updated'] : 0;
            $updated_txt = $updated ? gmdate( 'Y-m-d\TH:i:s\Z', $updated ) : 'never';
            ?>
            <p style="margin:0 0 8px 0; color:#666;">
                <strong>Portfolio last updated (UTC):</strong> <code><?php echo esc_html( $updated_txt ); ?></code>
            </p>

            <p style="margin:0 0 12px 0; color:#555;">
                Organize client sites in one place so you can track protection evidence and reporting per site.
            </p>

            <div style="display:flex; gap:16px; flex-wrap:wrap;">

                <!-- Agency Settings -->
                <div style="min-width:360px; flex:1; border:1px solid #ddd; border-radius:8px; padding:12px;">
                    <h3 style="margin:0 0 10px 0;">Portfolio Settings</h3>

                    <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:0;">
                        <input type="hidden" name="action" value="opsgate_save_agency_settings" />
                        <?php wp_nonce_field( 'opsgate_save_agency_settings' ); ?>

                        <p style="margin:0 0 8px 0;">
                            <label for="opsgate_agency_name"><strong>Portfolio Name</strong></label><br>
                            <input id="opsgate_agency_name" name="agency_name" type="text" class="regular-text"
                                value="<?php echo esc_attr( (string) ( $agency['name'] ?? '' ) ); ?>" />
                        </p>

			<!--
                        <p style="margin:0 0 8px 0;">
                            <label for="opsgate_agency_logo"><strong>Logo URL</strong> (placeholder)</label><br>
                            <input id="opsgate_agency_logo" name="logo_url" type="text" class="regular-text"
                              value="<?php echo esc_attr( (string) ( $agency['logo_url'] ?? '' ) ); ?>" />
                        </p>
			-->

			<!--
                        <p style="margin:0 0 8px 0;">
                            <label for="opsgate_agency_color"><strong>Primary Color</strong> (hex)</label><br>
                            <input id="opsgate_agency_color" name="primary_color" type="text" class="regular-text"
                                value="<?php echo esc_attr( (string) ( $agency['primary_color'] ?? '#0073aa' ) ); ?>" />
                            <span style="display:inline-block; width:14px; height:14px; margin-left:8px; vertical-align:middle; border:1px solid #ccc; background:<?php echo esc_attr( (string) ( $agency['primary_color'] ?? '#0073aa' ) ); ?>;"></span>
                        </p>
			-->

			<!--
                        <p style="margin:0 0 12px 0;">
                            <label>
                                <input type="checkbox" name="white_label_enabled" value="1" <?php checked( (int) ( $agency['white_label_enabled'] ?? 0 ), 1 ); ?> />
                                <strong>White-label enabled</strong> (placeholder)
                            </label>
                        </p>
			-->

                        <button type="submit" class="button button-primary">Save Portfolio Settings</button>
                    </form>
                </div>

                <!-- Groups -->
                <div style="min-width:420px; flex:2; border:1px solid #ddd; border-radius:8px; padding:12px;">
                    <h3 style="margin:0 0 10px 0;">Client Groups</h3>

                    <!-- Create group -->
                    <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:0 0 12px 0; display:flex; gap:8px; flex-wrap:wrap;">
                        <input type="hidden" name="action" value="opsgate_agency_create_group" />
                        <?php wp_nonce_field( 'opsgate_agency_create_group' ); ?>

                        <input name="group_name" type="text" class="regular-text" placeholder="Create group (e.g., Client A)" />
                        <button type="submit" class="button">Add Group</button>
                    </form>

                    <?php if ( empty( $groups ) ) : ?>
                        <p style="margin:0; color:#666;">No groups yet. Create your first group above.</p>
                    <?php else : ?>
                        <?php foreach ( $groups as $g ) : ?>
                            <?php
                            $group_id   = isset( $g['id'] ) ? (string) $g['id'] : '';
                            $group_name = isset( $g['name'] ) ? (string) $g['name'] : '';
                            $sites      = isset( $g['sites'] ) && is_array( $g['sites'] ) ? $g['sites'] : array();
                            ?>
                            <div style="border:1px solid #e5e5e5; border-radius:8px; padding:10px; margin:0 0 12px 0;">
                                <div style="display:flex; justify-content:space-between; align-items:center; gap:10px; flex-wrap:wrap;">
                                    <?php
                                    $sum = self::agency_group_summary( $sites );
                                    ?>

                                    <!-- Header Row 1: full width, title left, delete right -->
                                    <div style="display:flex; justify-content:space-between; align-items:center; width:100%; margin:0 0 8px 0;">
                                        <div style="min-width:180px;">
                                            <strong><?php echo esc_html( $group_name ); ?></strong>
                                        </div>

                                        <div style="margin-left:auto;">
                                            <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:0;">
                                                <input type="hidden" name="action" value="opsgate_agency_delete_group" />
                                                <input type="hidden" name="group_id" value="<?php echo esc_attr( (string) $group_id ); ?>" />
                                                <?php wp_nonce_field( 'opsgate_agency_delete_group' ); ?>
                                                <button type="submit" class="button button-secondary">Delete Group</button>
                                            </form>
                                        </div>
                                    </div>

                                    <!-- Header Row 2: summary below -->
                                    <div style="margin:0 0 10px 0; color:#555; font-size:13px;">
                                        <strong>Summary:</strong>
                                        <?php echo self::agency_badge( 'Sites: ' . (string) $sum['total'], 'info' ); ?>
                                        <?php echo self::agency_badge( 'Active: ' . (string) $sum['status']['active'], 'ok' ); ?>
                                        <?php echo self::agency_badge( 'Paused: ' . (string) $sum['status']['paused'], 'warn' ); ?>
                                        <?php echo self::agency_badge( 'Unknown: ' . (string) $sum['status']['unknown'], 'info' ); ?>
                                        <?php echo self::agency_badge( 'Prod: ' . (string) $sum['env']['prod'], 'info' ); ?>
                                        <?php echo self::agency_badge( 'Staging: ' . (string) $sum['env']['staging'], 'info' ); ?>
                                    </div>

                                <!-- Add site to group -->
                                <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:10px 0 10px 0; display:flex; gap:8px; flex-wrap:wrap;">
                                    <input type="hidden" name="action" value="opsgate_agency_add_site" />
                                    <input type="hidden" name="group_id" value="<?php echo esc_attr( $group_id ); ?>" />
                                    <?php wp_nonce_field( 'opsgate_agency_add_site' ); ?>

                                    <input name="site_label" type="text" class="regular-text" placeholder="Site label" />
                                    <input name="site_id" type="text" class="regular-text" placeholder="site_id / external id" />
                                    <textarea
                                    name="site_notes"
                                    rows="2"
                                    class="large-text"
                                    placeholder="Notes (optional) — visibility only"
                                    style="max-width:420px; height:32px; resize:vertical; overflow:auto;"
                                ></textarea>
                                    <select name="environment" style="height:32px; line-height:32px; padding:0 8px;">
                                        <option value="prod">prod</option>
                                        <option value="staging">staging</option>
                                    </select>

                                    <select name="status" style="height:32px; line-height:32px; padding:0 8px;">
                                        <option value="active">active</option>
                                        <option value="paused">paused</option>
                                        <option value="unknown">unknown</option>
                                    </select>

                                    <button type="submit" class="button">Add Site</button>
                                </form>

                                <!-- Sites list -->
                                <?php if ( empty( $sites ) ) : ?>
                                    <p style="margin:0; color:#666;">No sites in this group yet.</p>
                                <?php else : ?>
                                    <table class="widefat striped" style="margin:0;">
                                        <thead>
                                            <tr>
                                                <th>Label</th>
                                                <th>Site ID</th>
                                                <th>Env</th>
                                                <th>Status</th>
                                                <th>Notes</th>
                                                <th style="width:120px;">Action</th>
                                            </tr>
                                        </thead>
                                        <tbody>
                                            <?php foreach ( $sites as $s ) : ?>
                                                <?php
                                                $sid   = isset( $s['id'] ) ? (string) $s['id'] : '';
                                                $label = isset( $s['label'] ) ? (string) $s['label'] : '';
                                                $extid = isset( $s['site_id'] ) ? (string) $s['site_id'] : '';
                                                $env   = isset( $s['environment'] ) ? (string) $s['environment'] : 'unknown';
                                                $st    = isset( $s['status'] ) ? (string) $s['status'] : 'unknown';
                                                ?>
                                                <tr>
                                                    <td><?php echo esc_html( $label ); ?></td>
                                                    <td><code><?php echo esc_html( $extid ); ?></code></td>
                                                    <td>
                                                        <?php
                                                        $env_type = ( 'prod' === $env ) ? 'info' : ( ( 'staging' === $env ) ? 'warn' : 'info' );
                                                        echo self::agency_badge( $env, $env_type );
                                                        ?>
                                                    </td>
                                                    <td>
                                                        <?php
                                                        $st_type = ( 'active' === $st ) ? 'ok' : ( ( 'paused' === $st ) ? 'warn' : 'info' );
                                                        echo self::agency_badge( $st, $st_type );
                                                        ?>
                                                    </td>
                                                    <td>
                                                        <?php
                                                        $notes = isset( $s['notes'] ) ? (string) $s['notes'] : '';
                                                        $notes = trim( $notes );
                                                        echo ( '' !== $notes ) ? esc_html( $notes ) : '<span style="color:#777;">—</span>';
                                                        ?>
                                                    </td>
                                                    <td>
                                                        <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:0;">
                                                            <input type="hidden" name="action" value="opsgate_agency_remove_site" />
                                                            <input type="hidden" name="group_id" value="<?php echo esc_attr( $group_id ); ?>" />
                                                            <input type="hidden" name="site_row_id" value="<?php echo esc_attr( $sid ); ?>" />
                                                            <?php wp_nonce_field( 'opsgate_agency_remove_site' ); ?>
                                                            <button type="submit" class="button button-small">Remove</button>
                                                        </form>
                                                    </td>
                                                </tr>
                                            <?php endforeach; ?>
                                        </tbody>
                                    </table>
                                <?php endif; ?>

                            </div>
                        <?php endforeach; ?>
                    <?php endif; ?>
                </div>

                <?php
                // Slice 5 Part E: Portfolio Report Generation (Agency plan — AJAX-driven)
                $portfolio_plan        = self::normalize_plan( self::get_current_plan() );
                $portfolio_api_base    = self::mcp_base_url();
                $portfolio_exec_ctx    = self::current_site_execution_context();
                $portfolio_account_id  = isset( $portfolio_exec_ctx['account_id'] ) ? (string) $portfolio_exec_ctx['account_id'] : '';
                if ( 'agency' === $portfolio_plan && '' !== $portfolio_account_id ) :
                ?>
                <div class="opsgate-card" style="margin-top:12px;">
                    <h2><span class="dashicons dashicons-media-spreadsheet"></span> Portfolio Report</h2>
                    <p class="description" style="margin:0 0 10px 0;">Generate a full-portfolio security summary report across all connected sites. Agency plan only.</p>
                    <button
                        type="button"
                        class="button button-primary opsgate-portfolio-report-btn"
                        data-account-id="<?php echo esc_attr( $portfolio_account_id ); ?>"
                        data-api-base="<?php echo esc_attr( $portfolio_api_base ); ?>"
                        data-nonce="<?php echo esc_attr( wp_create_nonce( 'opsgate_portfolio_report' ) ); ?>">
                        Generate Portfolio Report
                    </button>
                    <span class="opsgate-portfolio-report-status" style="margin-left:10px;font-size:12px;color:#666;"></span>
                    <div id="opsgate-portfolio-report-list" style="margin-top:12px;"></div>
                </div>
                <?php endif; ?>

            </div>
        </div>
        <?php
    }

    /**
     * Day-11: Admin notices for Agency actions.
     *
     * @return void
     */
    public static function maybe_show_agency_admin_notices() {
        if ( ! isset( $_GET['page'] ) || 'opsgate' !== sanitize_text_field( wp_unslash( $_GET['page'] ) ) ) {
            return;
        }

        $code = isset( $_GET['opsgate_agency_notice'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_agency_notice'] ) ) : '';
        if ( '' === $code ) {
            return;
        }

        $map = array(
            'agency_saved'        => array( 'success', '✓ Agency settings saved.' ),
            'group_created'       => array( 'success', '✓ Group created.' ),
            'group_deleted'       => array( 'info',    'Group deleted.' ),
            'site_added'          => array( 'success', '✓ Site added to group.' ),
            'site_removed'        => array( 'info',    'Site removed from group.' ),
            'invalid_request'     => array( 'error',   'Invalid request. Please try again.' ),
            'missing_group'       => array( 'error',   'Group not found.' ),
            'missing_fields'      => array( 'error',   'Missing required fields.' ),
            'invalid_color'       => array( 'warning', 'Primary color must be a valid hex value (e.g., #0073aa).' ),
        );

        if ( ! isset( $map[ $code ] ) ) {
            return;
        }

        $type = $map[ $code ][0];
        $msg  = $map[ $code ][1];

        $class = 'notice notice-info is-dismissible';
        if ( 'success' === $type ) {
            $class = 'notice notice-success is-dismissible';
        } elseif ( 'warning' === $type ) {
            $class = 'notice notice-warning is-dismissible';
        } elseif ( 'error' === $type ) {
            $class = 'notice notice-error is-dismissible';
        }

        echo '<div class="' . esc_attr( $class ) . '"><p>' . esc_html( $msg ) . '</p></div>';
    }

    public static function maybe_show_pricing_admin_notices() {
        if ( ! is_admin() ) {
            return;
        }

        $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
        $tab  = isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : '';

        if ( 'opsgate' !== $page || 'billing' !== $tab ) {
            return;
        }

        $notice = isset( $_GET['opsgate_notice'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_notice'] ) ) : '';
        $detail = isset( $_GET['opsgate_notice_detail'] ) ? sanitize_key( wp_unslash( $_GET['opsgate_notice_detail'] ) ) : '';

        if ( 'entitlement_updated' === $notice ) {
            $plan = isset( $_GET['plan'] ) ? self::normalize_plan( sanitize_text_field( wp_unslash( $_GET['plan'] ) ) ) : 'unknown';
            echo '<div class="notice notice-success is-dismissible"><p><strong>Package updated:</strong> current package set to <code>' . esc_html( ucfirst( $plan ) ) . '</code>.</p></div>';
            return;
        }

        if ( 'entitlement_scope_missing' === $notice ) {
            $message = 'Connect this site before changing the package.';
            if ( 'site_scope_ambiguous' === $detail ) {
                $message = 'Current site scope could not be matched to a single OpsGate site record.';
            } elseif ( 'site_scope_identity_missing' === $detail ) {
                $message = 'Complete the site identity fields and confirm the connection before changing the package.';
            } elseif ( 'site_not_found_for_entitlements' === $detail || 'site_scope_missing' === $detail || 'site_scope_not_found' === $detail ) {
                $message = 'Current site is not connected in OpsGate yet.';
            }
            echo '<div class="notice notice-error is-dismissible"><p>' . esc_html( $message ) . '</p></div>';
            return;
        }

        if ( 'entitlement_update_invalid' === $notice ) {
            echo '<div class="notice notice-error is-dismissible"><p>The requested package is unavailable.</p></div>';
            return;
        }

        if ( 'entitlement_update_failed' === $notice ) {
            $message = 'The package could not be updated right now.';
            if ( 'site_not_found_for_entitlements' === $detail || 'site_scope_not_found' === $detail ) {
                $message = 'Current site is not connected in OpsGate yet.';
            } elseif ( 'site_scope_ambiguous' === $detail ) {
                $message = 'Current site scope could not be matched to a single OpsGate site record.';
            } elseif ( 'site_scope_identity_missing' === $detail ) {
                $message = 'Complete the site identity fields and confirm the connection before changing the package.';
            } elseif ( 'plan_not_active' === $detail ) {
                $message = 'The requested package is unavailable for this site.';
            } elseif ( 'entitlement_update_invalid' === $detail ) {
                $message = 'The entitlement record update was rejected.';
            }
            echo '<div class="notice notice-error is-dismissible"><p>' . esc_html( $message ) . '</p></div>';
            return;
        }
    }

    /**
     * Day-11: Save Agency settings handler.
     *
     * @return void
     */
    public static function handle_save_agency_settings() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden' );
        }

        check_admin_referer( 'opsgate_save_agency_settings' );

        $name   = isset( $_POST['agency_name'] ) ? sanitize_text_field( wp_unslash( $_POST['agency_name'] ) ) : '';
        $logo   = isset( $_POST['logo_url'] ) ? esc_url_raw( wp_unslash( $_POST['logo_url'] ) ) : '';
        $color  = isset( $_POST['primary_color'] ) ? sanitize_text_field( wp_unslash( $_POST['primary_color'] ) ) : '';
        $wl     = isset( $_POST['white_label_enabled'] ) ? 1 : 0;

        $color = trim( $color );
        $color_ok = ( '' === $color ) ? true : ( 1 === preg_match( '/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/', $color ) );

        if ( ! $color_ok ) {
            wp_safe_redirect( admin_url( 'admin.php?page=opsgate&tab=agency&opsgate_agency_notice=invalid_color' ) );
            exit;
        }

        if ( '' === $color ) {
            $color = '#0073aa';
        }

        $state = self::get_agency_state();
        $state['agency']['name']                = $name;
        $state['agency']['logo_url']            = $logo;
        $state['agency']['primary_color']        = $color;
        $state['agency']['white_label_enabled'] = (int) $wl;

        self::save_agency_state( $state );

        wp_safe_redirect( admin_url( 'admin.php?page=opsgate&tab=agency&opsgate_agency_notice=agency_saved' ) );
        exit;
    }

    /**
     * Day-11: Create Group handler.
     *
     * @return void
     */
    public static function handle_agency_create_group() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden' );
        }

        check_admin_referer( 'opsgate_agency_create_group' );

        $name = isset( $_POST['group_name'] ) ? sanitize_text_field( wp_unslash( $_POST['group_name'] ) ) : '';
        if ( '' === $name ) {
            wp_safe_redirect( admin_url( 'admin.php?page=opsgate&tab=agency&opsgate_agency_notice=missing_fields' ) );
            exit;
        }

        $state = self::get_agency_state();
        $state['groups'][] = array(
            'id'    => function_exists( 'wp_generate_uuid4' ) ? wp_generate_uuid4() : (string) ( time() . '-' . wp_rand( 1000, 9999 ) ),
            'name'  => $name,
            'sites' => array(),
        );

        self::save_agency_state( $state );

        wp_safe_redirect( admin_url( 'admin.php?page=opsgate&tab=agency&opsgate_agency_notice=group_created' ) );
        exit;
    }

    /**
     * Day-11: Delete Group handler.
     *
     * @return void
     */
    public static function handle_agency_delete_group() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden' );
        }

        check_admin_referer( 'opsgate_agency_delete_group' );

        $group_id = isset( $_POST['group_id'] ) ? sanitize_text_field( wp_unslash( $_POST['group_id'] ) ) : '';
        if ( '' === $group_id ) {
            wp_safe_redirect( admin_url( 'admin.php?page=opsgate&tab=agency&opsgate_agency_notice=invalid_request' ) );
            exit;
        }

        $state  = self::get_agency_state();
        $groups = isset( $state['groups'] ) && is_array( $state['groups'] ) ? $state['groups'] : array();

        $new = array();
        foreach ( $groups as $g ) {
            if ( isset( $g['id'] ) && (string) $g['id'] === $group_id ) {
                continue;
            }
            $new[] = $g;
        }

        $state['groups'] = $new;
        self::save_agency_state( $state );

        wp_safe_redirect( admin_url( 'admin.php?page=opsgate&tab=agency&opsgate_agency_notice=group_deleted' ) );
        exit;
    }

    /**
     * Day-11: Add Site to Group handler.
     *
     * @return void
     */
    public static function handle_agency_add_site() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden' );
        }

        check_admin_referer( 'opsgate_agency_add_site' );

        $group_id = isset( $_POST['group_id'] ) ? sanitize_text_field( wp_unslash( $_POST['group_id'] ) ) : '';
        $label    = isset( $_POST['site_label'] ) ? sanitize_text_field( wp_unslash( $_POST['site_label'] ) ) : '';
        $site_id  = isset( $_POST['site_id'] ) ? sanitize_text_field( wp_unslash( $_POST['site_id'] ) ) : '';
        $notes = isset( $_POST['site_notes'] ) ? sanitize_textarea_field( wp_unslash( $_POST['site_notes'] ) ) : '';
        $notes = trim( (string) $notes );
        $env      = isset( $_POST['environment'] ) ? sanitize_text_field( wp_unslash( $_POST['environment'] ) ) : 'prod';
        $status   = isset( $_POST['status'] ) ? sanitize_text_field( wp_unslash( $_POST['status'] ) ) : 'unknown';

        // Step 3C: Normalize inputs (trim).
        $label   = trim( (string) $label );
        $site_id = trim( (string) $site_id );

        // Step 3B: Validation guardrails (visibility-only).
        if ( '' === $group_id ) {
            wp_safe_redirect( admin_url( 'admin.php?page=opsgate&tab=agency&opsgate_agency_notice=missing_group' ) );
            exit;
        }

        if ( '' === $label ) {
            wp_safe_redirect( admin_url( 'admin.php?page=opsgate&tab=agency&opsgate_agency_notice=label_required' ) );
            exit;
        }

        if ( '' === $site_id ) {
            wp_safe_redirect( admin_url( 'admin.php?page=opsgate&tab=agency&opsgate_agency_notice=site_id_required' ) );
            exit;
        }

        // No spaces allowed in site_id (keeps IDs consistent).
        if ( preg_match( '/\s/', $site_id ) ) {
            wp_safe_redirect( admin_url( 'admin.php?page=opsgate&tab=agency&opsgate_agency_notice=site_id_invalid' ) );
            exit;
        }

        // Length sanity limits.
        if ( strlen( $site_id ) > 64 ) {
            wp_safe_redirect( admin_url( 'admin.php?page=opsgate&tab=agency&opsgate_agency_notice=site_id_too_long' ) );
            exit;
        }

        if ( strlen( $label ) > 80 ) {
            $label = substr( $label, 0, 80 );
        }

        if ( strlen( $notes ) > 500 ) {
            $notes = substr( $notes, 0, 500 );
        }


        $env    = in_array( $env, array( 'prod', 'staging' ), true ) ? $env : 'prod';
        $status = in_array( $status, array( 'active', 'paused', 'unknown' ), true ) ? $status : 'unknown';

        $state  = self::get_agency_state();
        $groups = isset( $state['groups'] ) && is_array( $state['groups'] ) ? $state['groups'] : array();

        $found = false;
        foreach ( $groups as $i => $g ) {
            if ( ! isset( $g['id'] ) || (string) $g['id'] !== $group_id ) {
                continue;
            }

            $found = true;
            if ( ! isset( $groups[ $i ]['sites'] ) || ! is_array( $groups[ $i ]['sites'] ) ) {
                $groups[ $i ]['sites'] = array();
            }

            // Step 3A: Prevent duplicate site_id within the same group.
            foreach ( $groups[ $i ]['sites'] as $es ) {
                if ( ! is_array( $es ) ) {
                    continue;
                }
                $es_id = isset( $es['site_id'] ) ? (string) $es['site_id'] : '';
                if ( '' !== $es_id && $es_id === $site_id ) {
                    wp_safe_redirect( admin_url( 'admin.php?page=opsgate&tab=agency&opsgate_agency_notice=duplicate_site_id' ) );
                    exit;
                }
            }

            $groups[ $i ]['sites'][] = array(
                'id'          => function_exists( 'wp_generate_uuid4' ) ? wp_generate_uuid4() : (string) ( time() . '-' . wp_rand( 1000, 9999 ) ),
                'label'       => $label,
                'site_id'     => $site_id,
                'environment' => $env,
                'status'      => $status,
                'notes'       => $notes,
            );
            break;
        }

        if ( ! $found ) {
            wp_safe_redirect( admin_url( 'admin.php?page=opsgate&tab=agency&opsgate_agency_notice=missing_group' ) );
            exit;
        }

        $state['groups'] = $groups;
        self::save_agency_state( $state );

        wp_safe_redirect( admin_url( 'admin.php?page=opsgate&tab=agency&opsgate_agency_notice=site_added' ) );
        exit;
    }

    public static function handle_agency_export_state() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden' );
        }

        check_admin_referer( 'opsgate_agency_export_state' );

        $state = self::get_agency_state();

        // Ensure we always export a valid structure.
        if ( ! is_array( $state ) ) {
            $state = array();
        }

        $json = wp_json_encode( $state, JSON_PRETTY_PRINT );

        if ( false === $json ) {
            wp_safe_redirect( admin_url( 'admin.php?page=opsgate&tab=agency&opsgate_agency_notice=export_failed' ) );
            exit;
        }

        $filename = 'opsgate_agency_state_' . gmdate( 'Ymd_His' ) . '.json';

        nocache_headers();
        header( 'Content-Type: application/json; charset=utf-8' );
        header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
        header( 'X-Content-Type-Options: nosniff' );

        echo $json; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
        exit;
    }

    public static function handle_agency_reset_state() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden' );
        }

        check_admin_referer( 'opsgate_agency_reset_state' );

        $default = self::default_agency_state();
        self::save_agency_state( $default );

        wp_safe_redirect( admin_url( 'admin.php?page=opsgate&tab=agency&opsgate_agency_notice=reset_ok' ) );
        exit;
    }


    /**
     * Day-11: Remove Site from Group handler.
     *
     * @return void
     */
    public static function handle_agency_remove_site() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden' );
        }

        check_admin_referer( 'opsgate_agency_remove_site' );

        $group_id    = isset( $_POST['group_id'] ) ? sanitize_text_field( wp_unslash( $_POST['group_id'] ) ) : '';
        $site_row_id = isset( $_POST['site_row_id'] ) ? sanitize_text_field( wp_unslash( $_POST['site_row_id'] ) ) : '';

        if ( '' === $group_id || '' === $site_row_id ) {
            wp_safe_redirect( admin_url( 'admin.php?page=opsgate&tab=agency&opsgate_agency_notice=invalid_request' ) );
            exit;
        }

        $state  = self::get_agency_state();
        $groups = isset( $state['groups'] ) && is_array( $state['groups'] ) ? $state['groups'] : array();

        $found = false;
        foreach ( $groups as $i => $g ) {
            if ( ! isset( $g['id'] ) || (string) $g['id'] !== $group_id ) {
                continue;
            }

            $sites = isset( $g['sites'] ) && is_array( $g['sites'] ) ? $g['sites'] : array();
            $new_sites = array();
            foreach ( $sites as $s ) {
                if ( isset( $s['id'] ) && (string) $s['id'] === $site_row_id ) {
                    $found = true;
                    continue;
                }
                $new_sites[] = $s;
            }

            $groups[ $i ]['sites'] = $new_sites;
            break;
        }

        if ( ! $found ) {
            wp_safe_redirect( admin_url( 'admin.php?page=opsgate&tab=agency&opsgate_agency_notice=invalid_request' ) );
            exit;
        }

        $state['groups'] = $groups;
        self::save_agency_state( $state );

        wp_safe_redirect( admin_url( 'admin.php?page=opsgate&tab=agency&opsgate_agency_notice=site_removed' ) );
        exit;
    }

    /**
     * Day-11 Step 2: Simple badge HTML (visibility only).
     *
     * @param string $label Label.
     * @param string $type  Type: ok|warn|info|err.
     * @return string
     */
    private static function agency_badge( $label, $type ) {
        $type = (string) $type;

        $bg = '#f0f0f1';
        $fg = '#1d2327';
        $bd = '#c3c4c7';

        if ( 'ok' === $type ) {
            $bg = '#edfaef';
            $fg = '#0a5a18';
            $bd = '#7ad08a';
        } elseif ( 'warn' === $type ) {
            $bg = '#fff8e5';
            $fg = '#7a4b00';
            $bd = '#f0c36d';
        } elseif ( 'err' === $type ) {
            $bg = '#fde8e8';
            $fg = '#8a1f1f';
            $bd = '#f2a3a3';
        }

        return '<span style="display:inline-block; padding:2px 8px; border-radius:999px; font-size:12px; border:1px solid ' . esc_attr( $bd ) . '; background:' . esc_attr( $bg ) . '; color:' . esc_attr( $fg ) . ';">' . esc_html( $label ) . '</span>';
    }

    /**
     * Day-11 Step 2: Compute group summary counts (visibility only).
     *
     * @param array $sites Sites array.
     * @return array
     */
    private static function agency_group_summary( $sites ) {
        $sites = is_array( $sites ) ? $sites : array();

        $out = array(
            'total'   => 0,
            'status'  => array( 'active' => 0, 'paused' => 0, 'unknown' => 0 ),
            'env'     => array( 'prod' => 0, 'staging' => 0, 'unknown' => 0 ),
        );

        foreach ( $sites as $s ) {
            if ( ! is_array( $s ) ) {
                continue;
            }

            $st  = isset( $s['status'] ) ? (string) $s['status'] : 'unknown';
            $env = isset( $s['environment'] ) ? (string) $s['environment'] : 'unknown';

            $st  = in_array( $st, array( 'active', 'paused', 'unknown' ), true ) ? $st : 'unknown';
            $env = in_array( $env, array( 'prod', 'staging' ), true ) ? $env : 'unknown';

            $out['total']++;

            $out['status'][ $st ] = (int) $out['status'][ $st ] + 1;
            $out['env'][ $env ]   = (int) $out['env'][ $env ] + 1;
        }

        return $out;
    }


    /**
     * Register the top-level OpsGate menu.
     *
     * @return void
     */
    public static function menu() {
        $menu_hook = add_menu_page(
            'OpsGate',
            'OpsGate',
            'manage_options',
            'opsgate',
            array( __CLASS__, 'render' ),
            'dashicons-shield-alt',
            58
        );

        // Mirror the parent slug as the first submenu item so the WordPress
        // admin sidebar always has a concrete page target for the parent click.
        $overview_hook = add_submenu_page(
            'opsgate',
            'OpsGate Overview',
            'Overview',
            'manage_options',
            'opsgate',
            array( __CLASS__, 'render' )
        );

        self::$admin_page_hooks = array_values(
            array_filter(
                array(
                    is_string( $menu_hook ) ? $menu_hook : '',
                    is_string( $overview_hook ) ? $overview_hook : '',
                    'toplevel_page_opsgate',
                )
            )
        );
    }

    /**
     * Determine whether the current admin request is on the OpsGate dashboard page.
     *
     * @param mixed $hook_suffix
     * @return bool
     */
    private static function is_opsgate_admin_page( $hook_suffix = '' ): bool {
        $hook_suffix = is_string( $hook_suffix ) ? trim( $hook_suffix ) : '';
        if ( '' !== $hook_suffix && in_array( $hook_suffix, self::$admin_page_hooks, true ) ) {
            return true;
        }

        $page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : '';
        return 'opsgate' === $page;
    }

    /**
     * Register telemetry / inbound token settings (Overview tab) + Identity (Day-8).
     *
     * @return void
     */
    public static function settings() {
        register_setting( 'opsgate', 'opsgate_telemetry_enabled' );
        register_setting( 'opsgate', 'opsgate_inbound_token' );

        /**
         * Day-8 Identity options.
         * - Storage only for now (no licensing enforcement yet).
         */
        register_setting( 'opsgate', 'opsgate_identity_email' );
        register_setting( 'opsgate', 'opsgate_site_label' );
        register_setting( 'opsgate', 'opsgate_site_id' );
        register_setting( 'opsgate', 'opsgate_site_token' );

        add_settings_section(
            'opsgate_main',
            'Settings',
            function () {
                echo '<p class="description">Optional: If you use external integrations, paste your connection key here.</p>';
            },
            'opsgate'
        );

        add_settings_field(
            'telemetry',
            'Activity Dashboard',
            function () {
                $v = get_option( 'opsgate_telemetry_enabled', '0' );
                echo '<label class="opsgate-toggle"><input type="checkbox" name="opsgate_telemetry_enabled" value="1" ' .
                    checked( '1', $v, false ) .
                    '> Enable Activity Dashboard</label>';
                 echo '<p class="description">When enabled, OpsGate records a history of actions so you can review what ran and when.</p>';
            },
            'opsgate',
            'opsgate_main'
        );

        add_settings_field(
            'inbound',
            'Inbound Token',
            function () {
                $v = esc_attr( get_option( 'opsgate_inbound_token', '' ) );
                echo '<input type="text" class="regular-text" name="opsgate_inbound_token" value="' . $v . '" placeholder="Paste connection key (optional)">';
                echo '<p class="description">Required for receiving automated updates from external systems.</p>';
            },
            'opsgate',
            'opsgate_main'
        );

        /**
         * Day-8 Identity section (added under Overview -> Configuration form).
         */
        add_settings_section(
            'opsgate_identity',
            'Identity',
            function () {
                echo '<p class="description">Connect this site to your OpsGate account to keep reporting, activity, and access consistent.</p>';
            },
            'opsgate'
        );

        add_settings_field(
            'opsgate_site_id',
            'Site ID',
            function () {
                $site_id = self::get_or_create_site_id();
                echo '<input type="text" class="regular-text" name="opsgate_site_id" value="' . esc_attr( $site_id ) . '" readonly="readonly">';
                echo '<p class="description">Stable identifier for this WordPress site (auto-generated). Used for linking and licensing.</p>';
            },
            'opsgate',
            'opsgate_identity'
        );

        add_settings_field(
            'opsgate_site_label',
            'Site Label',
            function () {
                $default = (string) get_bloginfo( 'name' );
                $v       = get_option( 'opsgate_site_label', $default );
                $v       = is_string( $v ) ? $v : $default;

                echo '<input type="text" class="regular-text" name="opsgate_site_label" value="' . esc_attr( $v ) . '" placeholder="e.g., Client A – Main Site">';
                echo '<p class="description">Human-readable label used in reports and dashboards.</p>';
            },
            'opsgate',
            'opsgate_identity'
        );

        add_settings_field(
            'opsgate_identity_email',
            'Account Email',
            function () {
                $default = (string) get_bloginfo( 'admin_email' );
                $v       = get_option( 'opsgate_identity_email', $default );
                $v       = is_string( $v ) ? $v : $default;

                echo '<input type="email" class="regular-text" name="opsgate_identity_email" value="' . esc_attr( $v ) . '" placeholder="you@agency.com">';
                echo '<p class="description">Used for identity linkage and licensing. This can differ from the WordPress admin email.</p>';
            },
            'opsgate',
            'opsgate_identity'
        );

        add_settings_field(
            'opsgate_site_token',
            'Site Token (reserved)',
            function () {
                $v = get_option( 'opsgate_site_token', '' );
                $v = is_string( $v ) ? $v : '';

                echo '<input type="text" class="regular-text" name="opsgate_site_token" value="' . esc_attr( $v ) . '" placeholder="(used internally)">';
                echo '<p class="description">Reserved for site-linking and license validation. Do not share this value. It is never logged.</p>';
            },
            'opsgate',
            'opsgate_identity'
        );

                /**
         * Day-9 Licensing section (Phase 1): status snapshot (read-only).
         */
        add_settings_section(
            'opsgate_licensing',
            'Licensing',
            function () {
                echo '<p class="description">Phase 1 stores a local license JSON blob and reports validation status. No enforcement yet.</p>';
            },
            'opsgate'
        );
        
        add_settings_field(
            'opsgate_license_json_viewer',
            'License JSON (read-only)',
            function () {
                $raw = get_option( 'opsgate_license_json', '' );
                $raw = is_string( $raw ) ? trim( $raw ) : '';


                if ( '' === $raw ) {
                    echo '<p><em>No license stored.</em></p>';
                    echo '<p class="description">Option: <code>opsgate_license_json</code></p>';
                    return;
                }

                // Pretty-print if valid JSON, otherwise show raw safely.
                $pretty = $raw;
                $decoded = json_decode( $raw, true );

                if ( JSON_ERROR_NONE === json_last_error() && is_array( $decoded ) ) {
                    $pretty = wp_json_encode( $decoded, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );
                }

                echo '<textarea class="large-text code" rows="10" readonly="readonly" style="font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;">' .
                    esc_textarea( $pretty ) .
                '</textarea>';

                echo '<p class="description">Read-only view of <code>opsgate_license_json</code>. Phase 1 is local storage only; no enforcement.</p>';
            },
            'opsgate',
            'opsgate_licensing'
        );

        add_settings_field(
            'opsgate_license_reset',
            'Reset (admin)',
            function () {
                $url = self::get_license_reset_url();

                echo '<a class="button button-secondary" href="' . esc_url( $url ) . '" onclick="return confirm(\'Reset license on this site? This cannot be undone.\');">Reset License</a>';
                echo '<p class="description">Deletes <code>opsgate_license_json</code>. No enforcement; used for local testing and support.</p>';
            },
            'opsgate',
            'opsgate_licensing'
        );

        add_settings_field(
            'opsgate_license_status',
            'License Status',
            function () {
                $snap = self::get_license_validation_snapshot();

                $status = isset( $snap['status'] ) ? (string) $snap['status'] : 'unknown';
                $tier   = isset( $snap['tier'] ) ? (string) $snap['tier'] : 'free';

                $expires_at      = isset( $snap['expires_at'] ) ? (string) $snap['expires_at'] : '';
                $last_checked_at = isset( $snap['last_checked_at'] ) ? (string) $snap['last_checked_at'] : '';
                $reason          = isset( $snap['reason'] ) ? (string) $snap['reason'] : '';

                $status = strtolower( trim( $status ) );
                $tier   = strtolower( trim( $tier ) );

                $type = 'info';
                if ( 'valid' === $status ) {
                    $type = 'ok';
                } elseif ( in_array( $status, array( 'expired', 'unbound' ), true ) ) {
                    $type = 'warn';
                } elseif ( in_array( $status, array( 'invalid', 'missing' ), true ) ) {
                    $type = 'err';
                }

                // Make labels unmissable in UI.
                $label_status = ( '' !== $status ) ? strtoupper( $status ) : 'UNKNOWN';
                $label_tier   = ( '' !== $tier ) ? strtoupper( $tier ) : 'FREE';

                echo '<div style="display:flex; gap:8px; align-items:center; flex-wrap:wrap; margin-bottom:6px;">';
                echo self::badge( 'License', $label_status, $type );
                echo self::badge( 'Tier', $label_tier, ( 'valid' === $status ? 'ok' : 'info' ) );
                echo '</div>';

                // Guidance line (Phase-1, non-enforcing).
                if ( 'valid' === $status ) {
                    echo '<p style="margin:4px 0 0 0;">License is bound and not expired.</p>';
                } elseif ( 'missing' === $status ) {
                    echo '<p style="margin:4px 0 0 0;"><strong>Action:</strong> Paste a license JSON and click <em>Save License</em>.</p>';
                } elseif ( 'invalid' === $status ) {
                    echo '<p style="margin:4px 0 0 0;"><strong>Action:</strong> License JSON is invalid. Re-issue or re-paste the trusted license.</p>';
                } elseif ( 'expired' === $status ) {
                    echo '<p style="margin:4px 0 0 0;"><strong>Action:</strong> License is expired. Renew and paste the updated license JSON.</p>';
                } elseif ( 'unbound' === $status ) {
                    echo '<p style="margin:4px 0 0 0;"><strong>Action:</strong> License does not match this site. Verify <code>site_id</code>.</p>';
                } else {
                    echo '<p style="margin:4px 0 0 0;">License status is unknown. Check stored option format and validator output.</p>';
                }

                if ( '' !== trim( $expires_at ) ) {
                    echo '<p style="margin:6px 0 0 0;"><strong>Expires:</strong> ' . esc_html( $expires_at ) . '</p>';
                } else {
                    echo '<p style="margin:6px 0 0 0;"><strong>Expires:</strong> —</p>';
                }

                echo '<p style="margin:4px 0 0 0;"><strong>Last checked:</strong> ' . esc_html( $last_checked_at ) . '</p>';

                if ( '' !== trim( $reason ) ) {
                    echo '<p style="margin:4px 0 0 0;"><strong>Reason:</strong> ' . esc_html( $reason ) . '</p>';
                }

                echo '<p class="description" style="margin-top:8px;">Stored option: <code>opsgate_license_json</code>. Phase 1 is local-only status reporting (no enforcement).</p>';
            },
            'opsgate',
            'opsgate_licensing'
        );
    
    }

    /**
     * Get or create a stable OpsGate Site ID.
     *
     * @return string
     */
    private static function get_or_create_site_id() {
        $site_id = get_option( 'opsgate_site_id', '' );

        if ( is_string( $site_id ) ) {
            $site_id = trim( $site_id );
        } else {
            $site_id = '';
        }

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

        if ( function_exists( 'wp_generate_uuid4' ) ) {
            $site_id = wp_generate_uuid4();
        } else {
            $site_id = sha1( home_url() . '|' . (string) time() . '|' . (string) wp_rand() );
        }

        update_option( 'opsgate_site_id', $site_id );

        return $site_id;
    }

    /**
     * Render a small badge with color-coded status.
     *
     * @param string $label Badge label.
     * @param string $value Badge value.
     * @param string $type  Status type (ok|warn|err|info).
     *
     * @return string
     */
    private static function badge( $label, $value, $type = 'info' ) {
        $colors = array(
            'ok'   => '#2e7d32',
            'warn' => '#f57c00',
            'err'  => '#d32f2f',
            'info' => '#1976d2',
        );

        $bg = isset( $colors[ $type ] ) ? $colors[ $type ] : $colors['info'];
        $v  = ( '' !== $value ) ? esc_html( $value ) : '—';

        $border_colors = array(
            'ok'   => '#4caf50',
            'warn' => '#ff9800',
            'err'  => '#f44336',
            'info' => '#2196f3',
        );
        $border_color = isset( $border_colors[ $type ] ) ? $border_colors[ $type ] : $border_colors['info'];

        return '<div class="opsgate-badge" style="display:inline-flex;align-items:center;margin:8px 16px 8px 0;padding:12px 20px;border-radius:10px;background:' . esc_attr( $bg ) . ';font-size:14px;line-height:1.5;box-shadow:0 4px 8px rgba(0,0,0,0.12);border-left:5px solid ' . esc_attr( $border_color ) . ';transition:all 0.3s ease;">' .
            '<span style="font-weight:600;color:#ffffff;margin-right:10px;opacity:0.95;">' . esc_html( $label ) . ':</span>' .
            '<span style="font-weight:700;color:#ffffff;">' . $v . '</span>' .
        '</div>';
    }

        /**
     * Day-9.4: Build admin-post URL for resetting the local license JSON.
     *
     * @return string
     */
    private static function get_license_reset_url() {
        $action = 'opsgate_reset_license';
        $url    = admin_url( 'admin-post.php?action=' . rawurlencode( $action ) );

        return wp_nonce_url( $url, $action, '_wpnonce' );
    }

    /**
     * Get allowed schedule modes for a billing plan.
     *
     * Option B (confirmed by user):
     * - Free: off + daily
     * - Starter: off + daily + weekly
     * - Pro: off + daily + weekly + monthly
     *
     * @param string $plan Billing plan.
     * @return array Allowed modes.
     */
    private static function allowed_schedule_modes_for_plan( $plan ) {
        $plan = is_string( $plan ) ? strtolower( trim( $plan ) ) : 'free';

        if ( 'pro' === $plan ) {
            return array( 'off', 'daily', 'weekly', 'monthly' );
        }

        if ( 'agency' === $plan ) {
            return array( 'off', 'daily', 'weekly', 'monthly' );
        }

        if ( 'starter' === $plan ) {
            return array( 'off', 'daily', 'weekly' );
        }

        return array( 'off', 'daily' );
    }

    /**
     * Highest allowed schedule mode for a plan, given a desired mode.
     *
     * If the desired mode isn't allowed, we downgrade to the nearest safe mode.
     * Order of preference: monthly > weekly > daily > off.
     *
     * @param string $plan         Billing plan.
     * @param string $desired_mode Desired mode.
     * @return string Sanitized mode.
     */
    private static function sanitize_schedule_mode_for_plan( $plan, $desired_mode ) {
        $desired_mode = is_string( $desired_mode ) ? strtolower( trim( $desired_mode ) ) : 'off';

        $allowed = self::allowed_schedule_modes_for_plan( $plan );
        if ( in_array( $desired_mode, $allowed, true ) ) {
            return $desired_mode;
        }

        $priority = array( 'monthly', 'weekly', 'daily', 'off' );
        foreach ( $priority as $m ) {
            if ( in_array( $m, $allowed, true ) ) {
                return $m;
            }
        }

        return 'off';
    }

    private static function rollup_badge_meta( string $status, ?string $iso_utc, int $stale_hours ): array {
        $status      = is_string( $status ) ? trim( $status ) : '';
        $iso_utc     = is_string( $iso_utc ) ? trim( $iso_utc ) : '';
        $stale_hours = max( 1, (int) $stale_hours );

        if ( '' === $status || 'never' === $status ) {
            return array( 'class' => 'opsgate-badge--neutral', 'label' => 'Never' );
        }

        if ( 'error' === $status ) {
            return array( 'class' => 'opsgate-badge--bad', 'label' => 'Error' );
        }

        // Treat anything else (including "ok") as time-based if we have a timestamp.
        if ( '' === $iso_utc ) {
            return array( 'class' => 'opsgate-badge--neutral', 'label' => 'Never' );
        }

        $ts = strtotime( $iso_utc );
        if ( false === $ts || $ts <= 0 ) {
            return array( 'class' => 'opsgate-badge--neutral', 'label' => 'Never' );
        }

        $age_seconds   = time() - (int) $ts;
        $stale_seconds = $stale_hours * 3600;

        if ( $age_seconds > $stale_seconds ) {
            return array( 'class' => 'opsgate-badge--warn', 'label' => 'Stale' );
        }

        return array( 'class' => 'opsgate-badge--good', 'label' => 'OK' );
    }

    /**
     * Day-16 Step-1: Placeholder panel for tabs that will be implemented in later days.
     * Customer-first language only. No internal plumbing terms.
     */
    private static function render_placeholder_panel( string $title, string $body ): void {
        echo '<div class="opsgate-card" style="margin-top:12px;">';
        echo '<h2>' . esc_html( $title ) . '</h2>';
        echo '<p class="description">' . esc_html( $body ) . '</p>';
        echo '</div>';
    }

    /**
     * Day-17: Activity Timeline UI (evidence-first).
     */
    private static function render_activity_timeline_panel(): void {
        $enabled = self::activity_timeline_enabled();

        echo '<div class="opsgate-card">';
        echo '<h2><span class="dashicons dashicons-list-view"></span> Activity</h2>';
        echo '<p class="opsgate-value-header">See what ran, when it ran, and the outcome.</p>';
	echo '<p class="description" style="margin:0 0 10px 0;"><strong>Report for:</strong> ' . esc_html( self::evidence_site_label() ) . '</p>';

        if ( ! $enabled ) {
            echo '<div class="notice notice-warning"><p>Activity tracking is currently off. Turn it on to record what ran and when.</p></div>';
            echo '</div>';
            return;
        }

        $items = self::activity_timeline_read();

        if ( empty( $items ) ) {
            echo '<div class="notice notice-info"><p>No activity yet. Run a protection check to start building your timeline.</p></div>';
            echo '</div>';
            return;
        }

        echo '<div style="display:flex; flex-direction:column; gap:10px; margin-top:10px;">';

        foreach ( $items as $it ) {
            $label   = isset( $it['label'] ) ? (string) $it['label'] : '';
            $outcome = isset( $it['outcome'] ) ? (string) $it['outcome'] : 'completed';
            $details = isset( $it['details'] ) ? (string) $it['details'] : '';
            $ts_utc  = isset( $it['ts_utc'] ) ? (string) $it['ts_utc'] : '';

            $when  = self::activity_timeline_format_time( $ts_utc );
            $badge = self::activity_timeline_outcome_badge( $outcome );

            echo '<div style="border:1px solid #ddd; border-radius:10px; padding:10px 12px;">';
            echo '<div style="display:flex; justify-content:space-between; align-items:flex-start; gap:12px;">';
            echo '<div>';
            echo '<div style="font-weight:600; margin-bottom:2px;">' . esc_html( $label ) . '</div>';
            echo '<div style="color:#555;">' . esc_html( $when ) . '</div>';
            echo '</div>';
            echo '<div><span class="opsgate-rollup-badge ' . esc_attr( $badge['class'] ) . '">' . esc_html( $badge['label'] ) . '</span></div>';
            echo '</div>';

            if ( '' !== $details ) {
                echo '<div style="margin-top:6px; color:#333;">' . esc_html( $details ) . '</div>';
            }

            echo '</div>';
        }

        echo '</div>'; // list
        echo '</div>'; // card
    }

    /**
     * Day-17: Reports UI (viewable inside UI, evidence-first).
     */
    private static function render_reports_panel(): void {
        echo '<div class="opsgate-card">';
        echo '<h2><span class="dashicons dashicons-media-document"></span> Reports</h2>';
        echo '<p class="opsgate-value-header">Open your latest reports and share proof of protection.</p>';
        echo '<p class="description" style="margin:0 0 10px 0;"><strong>Report for:</strong> ' . esc_html( self::evidence_site_label() ) . '</p>';

        // Day-18.1: Hardening evidence (proof-first, independent of scan services).
        $hardening_history = get_option( 'opsgate_hardening_history', array() );
        $hardening_last    = ( is_array( $hardening_history ) && ! empty( $hardening_history ) ) ? $hardening_history[0] : null;

        echo '<div class="opsgate-card" style="margin-top:12px;margin-bottom:12px;">';
        echo '<h3><span class="dashicons dashicons-lock"></span> Protection Evidence</h3>';
        echo '<p class="description" style="margin:0 0 10px 0;">Download proof of the last protection update applied by OpsGate.</p>';

        if ( is_array( $hardening_last ) ) {
            $pdf_file  = isset( $hardening_last['pdf_file'] ) ? (string) $hardening_last['pdf_file'] : '';
            $csv_file  = isset( $hardening_last['csv_file'] ) ? (string) $hardening_last['csv_file'] : '';
            $json_file = isset( $hardening_last['json_file'] ) ? (string) $hardening_last['json_file'] : '';
            $xlsx_file = isset( $hardening_last['xlsx_file'] ) ? (string) $hardening_last['xlsx_file'] : '';

            echo '<p style="margin:0 0 8px 0;">'
                . '<strong>Last change:</strong> ' . esc_html( date_i18n( 'Y-m-d H:i:s', (int) ( $hardening_last['ts'] ?? 0 ) ) )
                . ' &nbsp;·&nbsp; <strong>Action:</strong> ' . esc_html( (string) ( $hardening_last['action'] ?? '—' ) )
                . ' &nbsp;·&nbsp; <strong>Status:</strong> ' . esc_html( (string) ( $hardening_last['status'] ?? '—' ) )
                . '</p>';

            echo '<p style="margin:0;">';

            if ( '' !== $pdf_file ) {
                $pdf_url = wp_nonce_url(
                    admin_url( 'admin-post.php?action=opsgate_htaccess_download_pdf&file=' . rawurlencode( $pdf_file ) ),
                    'opsgate_htaccess_download_pdf'
                );
                echo '<a class="button button-small" href="' . esc_url( $pdf_url ) . '">Download PDF</a> ';
            }

            if ( '' !== $csv_file ) {
                $csv_url = wp_nonce_url(
                    admin_url( 'admin-post.php?action=opsgate_htaccess_download_evidence&file=' . rawurlencode( $csv_file ) ),
                    'opsgate_htaccess_download_evidence'
                );
                echo '<a class="button button-small" href="' . esc_url( $csv_url ) . '">Download CSV</a> ';
            }

            if ( '' !== $json_file ) {
                $json_url = wp_nonce_url(
                    admin_url( 'admin-post.php?action=opsgate_htaccess_download_evidence&file=' . rawurlencode( $json_file ) ),
                    'opsgate_htaccess_download_evidence'
                );
                echo '<a class="button button-small" href="' . esc_url( $json_url ) . '">Download JSON</a>';
            }

	    if ( '' !== $xlsx_file ) {
                $xlsx_url = wp_nonce_url(
                     admin_url( 'admin-post.php?action=opsgate_htaccess_download_evidence&file=' . rawurlencode( $xlsx_file ) ),
                     'opsgate_htaccess_download_evidence'
               );
               echo ' <a class="button button-small" href="' . esc_url( $xlsx_url ) . '">Download Excel</a>';
            }

            echo '</p>';
        } else {
            echo '<p style="margin:0;">No protection evidence yet. Apply or revert hardening once to generate proof files.</p>';
        }

        echo '</div>';

	// Day-19.1: Malware evidence (proof-first, customer-readable).
	$malware_last = get_option( 'opsgate_malware_last_result', array() );
	$malware_hist = get_option( 'opsgate_malware_history', array() );

	$malware_last_run = ( is_array( $malware_last ) && isset( $malware_last['last_run_at_utc'] ) ) ? (string) $malware_last['last_run_at_utc'] : '';
	$malware_status   = ( is_array( $malware_last ) && isset( $malware_last['status'] ) ) ? (string) $malware_last['status'] : 'never';
	$malware_files    = (int) ( is_array( $malware_last ) ? ( $malware_last['files_checked'] ?? 0 ) : 0 );
	$malware_hits     = (int) ( is_array( $malware_last ) ? ( $malware_last['suspicious_found'] ?? 0 ) : 0 );

	echo '<div class="opsgate-card" style="margin-top:12px;margin-bottom:12px;">';
	echo '<h3><span class="dashicons dashicons-shield"></span> Malware Check</h3>';
	echo '<p class="description" style="margin:0 0 10px 0;">Download proof of your most recent malware check.</p>';

	if ( '' === $malware_last_run || 'never' === $malware_status ) {
	    echo '<div class="notice notice-info"><p>No malware check has been run yet.</p></div>';
	    echo '</div>';
	} else {
	    $display_run = $malware_last_run;
	    try {
	        $dt = new DateTimeImmutable( $malware_last_run, new DateTimeZone( 'UTC' ) );
	        $display_run = $dt->format( 'M d, Y H:i' ) . ' UTC';
	    } catch ( Exception $e ) {
	        $display_run = $malware_last_run;
	    }

	    echo '<p style="margin:0 0 8px 0;">'
	        . '<strong>Last run:</strong> ' . esc_html( $display_run )
	        . ' &nbsp;·&nbsp; <strong>Status:</strong> ' . esc_html( $malware_status )
	        . ' &nbsp;·&nbsp; <strong>Files checked:</strong> ' . esc_html( (string) $malware_files )
	        . ' &nbsp;·&nbsp; <strong>Findings:</strong> ' . esc_html( (string) $malware_hits )
	        . '</p>';

	    $pdf_url = wp_nonce_url(
	        admin_url( 'admin-post.php?action=opsgate_malware_download_pdf' ),
	        'opsgate_malware_download_pdf'
	    );
	    $json_url = wp_nonce_url(
	        admin_url( 'admin-post.php?action=opsgate_malware_download_json' ),
	        'opsgate_malware_download_json'
	    );
	    $csv_url = wp_nonce_url(
	        admin_url( 'admin-post.php?action=opsgate_malware_download_csv' ),
	        'opsgate_malware_download_csv'
	    );
	    $xlsx_url = wp_nonce_url(
	        admin_url( 'admin-post.php?action=opsgate_malware_download_xlsx' ),
	        'opsgate_malware_download_xlsx'
	    );

	    echo '<p style="margin:0;">';
	    echo '<a class="button button-small" href="' . esc_url( $pdf_url ) . '">Download PDF</a> ';
	    echo '<a class="button button-small" href="' . esc_url( $json_url ) . '">Download JSON</a> ';
	    echo '<a class="button button-small" href="' . esc_url( $csv_url ) . '">Download CSV</a> ';
	    echo '<a class="button button-small" href="' . esc_url( $xlsx_url ) . '">Download Excel</a>';
	    echo '</p>';

	    // Store latest snapshot for export handlers (no filesystem assumptions).
	    update_option(
	        'opsgate_malware_export_snapshot',
	        array(
	            'last'    => is_array( $malware_last ) ? $malware_last : array(),
	            'history' => is_array( $malware_hist ) ? $malware_hist : array(),
	            'ts_utc'  => gmdate( 'Y-m-d\TH:i:s\Z' ),
	        )
	    );

	    echo '</div>';
	}


        // Weeks 17–18: WordPress-local scheduled receipts are retired from the active truth path.
        echo '<div class="opsgate-card" style="margin-top:12px;margin-bottom:12px;">';
        echo '<h3><span class="dashicons dashicons-clock"></span> Scheduled Runs</h3>';
        echo '<p class="description" style="margin:0 0 10px 0;">Recurring schedule truth now lives in the OpsGate API and Postgres. Legacy WordPress-local scheduled receipts are no longer part of the active proof path.</p>';
        echo '<div class="notice notice-info"><p>Use the Settings tab to view and change the managed Security Scan schedule. Reports and exports continue to read stored evidence only.</p></div>';

        echo '</div>';

        if ( ! function_exists( 'opsgate_get_services_settings' ) ) {
            echo '<div class="notice notice-error"><p>Reports are not available right now.</p></div>';
            echo '</div>';
            return;
        }

        $services = opsgate_get_services_settings();
        if ( ! is_array( $services ) || empty( $services ) ) {
            echo '<div class="notice notice-info"><p>No reports yet. Run a security scan to generate your first report.</p></div>';
            echo '</div>';
            return;
        }

        // Build rows for services that have last outputs.
        $rows = array();

        foreach ( $services as $service_key => $service_settings ) {
            if ( ! is_array( $service_settings ) ) {
                continue;
            }

            $last_scan_at = isset( $service_settings['last_scan_at'] ) ? (string) $service_settings['last_scan_at'] : '';
            $last_output  = ( isset( $service_settings['last_output'] ) && is_array( $service_settings['last_output'] ) )
                ? $service_settings['last_output']
                : array();

            $json = isset( $last_output['json'] ) ? (string) $last_output['json'] : '';
            $csv  = isset( $last_output['csv'] ) ? (string) $last_output['csv'] : '';
            $pdf  = isset( $last_output['pdf'] ) ? (string) $last_output['pdf'] : '';

            // Future-ready: display only if present (do not fabricate).
            $xlsx = isset( $last_output['xlsx'] ) ? (string) $last_output['xlsx'] : '';

            $has_any = ( '' !== $json ) || ( '' !== $csv ) || ( '' !== $pdf ) || ( '' !== $xlsx );
            if ( ! $has_any ) {
                continue;
            }

            // Plain-language service name (minimum safe mapping; fall back to key).
            $title = ( 'wordpress_security_audit' === $service_key )
                ? 'Security Scan Report'
                : $service_key;

            $when = '';
            if ( '' !== $last_scan_at ) {
                $ts = strtotime( $last_scan_at );
                if ( $ts ) {
                    $when = wp_date( 'M j, Y g:i A', $ts );
                } else {
                    $when = $last_scan_at;
                }
            }

            $rows[] = array(
                'title' => $title,
                'when'  => $when,
                'json'  => $json,
                'csv'   => $csv,
                'pdf'   => $pdf,
                'xlsx'  => $xlsx,
            );
        }

        if ( empty( $rows ) ) {
            echo '<div class="notice notice-info"><p>No reports yet. Run a security scan to generate your first report.</p></div>';
            echo '</div>';
            return;
        }

        echo '<div class="notice notice-info" style="margin-top:10px;">';
        echo '<p><strong>Sharing:</strong> Open a report and share it with your client as proof of protection.</p>';
        echo '</div>';

        echo '<table class="widefat fixed striped" style="margin-top:10px;">';
        echo '<thead><tr>';
        echo '<th>Report</th>';
        echo '<th>Last run</th>';
        echo '<th>Open</th>';
        echo '<th>Summary</th>';
        echo '</tr></thead><tbody>';

        foreach ( $rows as $r ) {
            $links = array();

            if ( '' !== $r['pdf'] ) {
                $links[] = '<a href="' . esc_url( $r['pdf'] ) . '" target="_blank" rel="noopener">PDF</a>';
            }
            if ( '' !== $r['json'] ) {
                $links[] = '<a href="' . esc_url( $r['json'] ) . '" target="_blank" rel="noopener">JSON</a>';
            }
            if ( '' !== $r['csv'] ) {
                $links[] = '<a href="' . esc_url( $r['csv'] ) . '" target="_blank" rel="noopener">CSV</a>';
            }
            // Future-ready Excel link (only appears if real output exists).
            if ( '' !== $r['xlsx'] ) {
                $links[] = '<a href="' . esc_url( $r['xlsx'] ) . '" target="_blank" rel="noopener">Excel</a>';
            }

            $open = empty( $links ) ? '—' : implode( ' · ', $links );

            echo '<tr>';
            echo '<td><strong>' . esc_html( $r['title'] ) . '</strong></td>';
            echo '<td>' . esc_html( $r['when'] ?: '—' ) . '</td>';
            echo '<td>' . $open . '</td>';
            echo '<td>Evidence Files generated.</td>';
            echo '</tr>';
        }

        echo '</tbody></table>';
        echo '</div>';
    }

    private static function render_security_panel(): void {

        echo '<div class="opsgate-card" style="margin-bottom:12px;">';
        echo '<h2><span class="dashicons dashicons-shield"></span> Security</h2>';
        echo '<p class="description">Run security protections manually when needed. Recurring scheduling is now controlled from managed schedule settings in Settings.</p>';

        // OPSGATE-BEGIN: CDN_CHECK_CARD
        echo '<div class="opsgate-card" style="margin-top:12px;margin-bottom:12px;">';
        echo '<h3><span class="dashicons dashicons-cloud"></span> CDN Posture Check</h3>';
        echo '<p class="opsgate-value-header">Validate whether this site shows configuration signals consistent with a CDN or edge caching layer.</p>';
        echo '<p class="description" style="margin:6px 0 10px 0;">This is a configuration posture check. It does not modify CDN settings and does not perform any external requests by default.</p>';

        // If user clicked "Run", we present a confirmation screen (no checkbox friction).
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $cdn_confirm = isset( $_GET['opsgate_cdn_confirm'] ) ? (string) wp_unslash( $_GET['opsgate_cdn_confirm'] ) : '';
        $cdn_confirm = sanitize_key( $cdn_confirm );

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $cdn_ran = isset( $_GET['cdn_checked'] ) ? (string) wp_unslash( $_GET['cdn_checked'] ) : '';
        $cdn_ran = sanitize_key( $cdn_ran );

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $cdn_file = isset( $_GET['cdn_file'] ) ? (string) wp_unslash( $_GET['cdn_file'] ) : '';
        $cdn_file = basename( $cdn_file );

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $cdn_outcome = isset( $_GET['cdn_outcome'] ) ? (string) wp_unslash( $_GET['cdn_outcome'] ) : '';
        $cdn_outcome = sanitize_key( $cdn_outcome );

        if ( '1' === $cdn_confirm ) {

            echo '<div style="margin:10px 0 0 0;padding:12px;border:1px solid #dcdcde;border-radius:8px;background:#fff;">';
            echo '<h4 style="margin:0 0 8px 0;">Confirm CDN posture check</h4>';
            echo '<p class="description" style="margin:0 0 10px 0;">OpsGate will evaluate local WordPress configuration signals (active plugins and related configuration cues). It will not call external services unless you explicitly enable that capability in a future version.</p>';
            echo '<ul style="margin:0 0 10px 18px;list-style:disc;">';
            echo '<li><strong>What runs:</strong> local configuration inspection (plugins and settings cues).</li>';
            echo '<li><strong>What it produces:</strong> a JSON receipt saved to <code>wp-content/uploads/opsgate/cdn/</code>.</li>';
            echo '<li><strong>What it does not do:</strong> modify CDN settings, change caching behavior, or perform network requests.</li>';
            echo '</ul>';

            $confirm_run = wp_nonce_url(
                admin_url( 'admin-post.php?action=opsgate_cdn_check_run' ),
                'opsgate_cdn_check_run'
            );

            $cancel = admin_url( 'admin.php?page=opsgate&tab=security' );

            echo '<p style="margin:0;">';
            echo '<a class="button button-primary" href="' . esc_url( $confirm_run ) . '">Confirm &amp; Run</a> ';
            echo '<a class="button" href="' . esc_url( $cancel ) . '">Cancel</a>';
            echo '</p>';
            echo '</div>';

        } else {

            $prepare = wp_nonce_url(
                admin_url( 'admin-post.php?action=opsgate_cdn_check_prepare' ),
                'opsgate_cdn_check_prepare'
            );

            echo '<p style="margin:0;">';
            echo '<a class="button button-primary" href="' . esc_url( $prepare ) . '">Run CDN Check</a>';
            echo '</p>';
        }

        // Evidence-first: show recent CDN check receipts (local-only).
        $cdn_recent = self::cdn_receipts_list( 10 );

        echo '<div style="margin-top:12px;">';
        echo '<strong>Recent CDN checks</strong>';
        echo '<p class="description" style="margin:6px 0 10px 0;">Each entry is a saved JSON receipt for audit and client reporting.</p>';

        if ( empty( $cdn_recent ) ) {
            echo '<p style="margin:0;">No CDN checks recorded yet.</p>';
        } else {
            echo '<table class="widefat striped" style="margin:0;max-width:860px;">';
            echo '<thead><tr>';
            echo '<th style="width:220px;">Recorded (UTC)</th>';
            echo '<th style="width:140px;">Outcome</th>';
            echo '<th>Receipt</th>';
            echo '</tr></thead><tbody>';

            foreach ( $cdn_recent as $r ) {
                $file = isset( $r['file'] ) ? (string) $r['file'] : '';
                $when = isset( $r['when'] ) ? (string) $r['when'] : '—';
                $out  = isset( $r['outcome'] ) ? (string) $r['outcome'] : '—';

                $dl = wp_nonce_url(
                    admin_url( 'admin-post.php?action=opsgate_cdn_download_json&file=' . rawurlencode( $file ) ),
                    'opsgate_cdn_download_json'
                );

                echo '<tr>';
                echo '<td><code>' . esc_html( $when ) . '</code></td>';
                echo '<td><code>' . esc_html( $out ) . '</code></td>';
                echo '<td><a href="' . esc_url( $dl ) . '">Download JSON</a></td>';
                echo '</tr>';
            }

            echo '</tbody></table>';
        }

        // If a run just occurred, show a one-line outcome banner (truthful, only after success redirect).
        if ( '1' === $cdn_ran && '' !== $cdn_outcome ) {
            echo '<div class="notice notice-info" style="margin-top:10px;"><p><strong>CDN check recorded.</strong> Outcome: <code>' . esc_html( $cdn_outcome ) . '</code></p></div>';
        }

        echo '</div>';
        echo '</div>';
        // OPSGATE-END: CDN_CHECK_CARD


        // OPSGATE-BEGIN: RECOVERY_REQUEST_CARD
        echo '<div class="opsgate-card" style="margin-bottom:12px;">';
        echo '<h3><span class="dashicons dashicons-sos"></span> Recovery Request</h3>';
        echo '<p class="description">This records a recovery request for audit and tracking purposes and does not initiate any automated recovery or remediation.</p>';

        $recovery_action = esc_url( admin_url( 'admin-post.php' ) );

        echo '<form method="post" action="' . $recovery_action . '" style="margin:0;">';
        echo '<input type="hidden" name="action" value="opsgate_recovery_request_submit" />';
        wp_nonce_field( 'opsgate_recovery_request_submit', 'opsgate_recovery_request_nonce' );

        echo '<div style="display:grid;grid-template-columns:1fr;gap:10px;max-width:720px;">';

        echo '<div>';
        echo '<label for="opsgate_recovery_urgency"><strong>Urgency</strong></label><br />';
        echo '<select name="opsgate_recovery_urgency" id="opsgate_recovery_urgency">';
        echo '<option value="low">Low</option>';
        echo '<option value="normal" selected="selected">Normal</option>';
        echo '<option value="high">High</option>';
        echo '</select>';
        echo '</div>';

        echo '<div>';
        echo '<label for="opsgate_recovery_reason"><strong>Reason</strong></label><br />';
        echo '<textarea name="opsgate_recovery_reason" id="opsgate_recovery_reason" rows="4" class="large-text" placeholder="Describe what you observed (e.g., suspicious redirects, admin lockout, unknown users)."></textarea>';
        echo '</div>';

        echo '<div>';
        echo '<button type="submit" class="button button-primary">Create Recovery Request</button>';
        echo '</div>';

        echo '</div>';
        echo '</form>';
        // Evidence-first: show recent recovery request receipts (local-only).
        $recent = self::recovery_receipts_list( 10 );

        echo '<div style="margin-top:12px;">';
        echo '<strong>Recent recovery requests</strong>';
        echo '<p class="description" style="margin:6px 0 10px 0;">Local receipts saved for audit and follow-up. No recovery actions run automatically.</p>';

        if ( empty( $recent ) ) {
            echo '<p style="margin:0;">No recovery requests recorded yet.</p>';
        } else {
            echo '<table class="widefat striped" style="margin:0;max-width:720px;">';
            echo '<thead><tr>';
            echo '<th style="width:220px;">Recorded (UTC)</th>';
            echo '<th>Receipt</th>';
            echo '</tr></thead><tbody>';

            foreach ( $recent as $r ) {
                $file = isset( $r['file'] ) ? (string) $r['file'] : '';
                $when = isset( $r['when'] ) ? (string) $r['when'] : '—';

                $dl = wp_nonce_url(
                    admin_url( 'admin-post.php?action=opsgate_recovery_download_json&file=' . rawurlencode( $file ) ),
                    'opsgate_recovery_download_json'
                );

                echo '<tr>';
                echo '<td><code>' . esc_html( $when ) . '</code></td>';
                echo '<td><a href="' . esc_url( $dl ) . '">Download JSON</a></td>';
                echo '</tr>';
            }

            echo '</tbody></table>';
        }

        echo '</div>';
        echo '</div>';
        // OPSGATE-END: RECOVERY_REQUEST_CARD

        echo '<div class="opsgate-card" style="margin-bottom:12px;">';
        echo '<h3><span class="dashicons dashicons-shield-alt"></span> Incident Response Playbooks</h3>';
        echo '<p class="description">Manual, on-demand response actions. Each action is explicit, produces evidence, and is designed to be safe to run during an incident workflow.</p>';

        // Read current hardening posture so the operator has immediate context.
        $h_state   = self::htaccess_read_state();
        $h_applied = ( ! empty( $h_state['has_block'] ) );

        $hardening_status_label = $h_applied ? 'Baseline applied' : 'Baseline not applied';

        echo '<div style="margin:10px 0 12px 0;">';
        echo '<span class="badge" style="display:inline-block;padding:4px 10px;border-radius:999px;border:1px solid #e5e7eb;background:#fff;">';
        echo '<strong>Status:</strong> ' . esc_html( $hardening_status_label );
        echo '</span>';
        echo '</div>';

        echo '<div style="display:grid;grid-template-columns:1fr;gap:12px;max-width:860px;">';

        // Playbook A — Create Restore Point (Backup).
        echo '<div style="border:1px solid #e5e7eb;border-radius:8px;padding:12px;background:#fff;">';
        echo '<h4 style="margin:0 0 6px 0;">Create Restore Point</h4>';
        echo '<p class="description" style="margin:0 0 10px 0;">Creates a downloadable snapshot you can use to restore quickly if the incident escalates. Recommended before applying configuration changes during remediation.</p>';

        echo '<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;">';
        echo '<form method="post" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '" style="margin:0;">';
        echo '<input type="hidden" name="action" value="opsgate_run_backup" />';
        wp_nonce_field( 'opsgate_run_backup', 'opsgate_run_backup_nonce' );
        echo '<button type="submit" class="button button-primary">';
        echo '<span class="dashicons dashicons-backup" style="vertical-align:middle;margin-right:6px;"></span>';
        echo 'Create Restore Point';
        echo '</button>';
        echo '</form>';

        echo '<a class="button button-secondary" href="#opsgate-backups">View backup evidence</a>';
        echo '</div>';
        echo '</div>';

        // Playbook B — Re-assert Baseline (Hardening) — operator is routed to the canonical control surface.
        echo '<div style="border:1px solid #e5e7eb;border-radius:8px;padding:12px;background:#fff;">';
        echo '<h4 style="margin:0 0 6px 0;">Confirm Baseline Configuration</h4>';
        echo '<p class="description" style="margin:0 0 10px 0;">Use this when troubleshooting indicates the baseline may have been modified. This action is performed in the Baseline section to ensure one authoritative control surface and consistent evidence outputs.</p>';

        echo '<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;">';
        echo '<a class="button button-primary" href="#opsgate-hardening">';
        echo '<span class="dashicons dashicons-lock" style="vertical-align:middle;margin-right:6px;"></span>';
        echo 'Open Configuration Controls';
        echo '</a>';

        echo '<a class="button button-secondary" href="#opsgate-hardening">View configuration evidence</a>';
        echo '</div>';
        echo '</div>';

        // Playbook C — Rollback Baseline — also routed to canonical Hardening surface (no duplicate forms).
        echo '<div style="border:1px solid #e5e7eb;border-radius:8px;padding:12px;background:#fff;">';
        echo '<h4 style="margin:0 0 6px 0;">Restore Baseline Configuration</h4>';
        echo '<p class="description" style="margin:0 0 10px 0;">Rollback is sometimes required to isolate incompatibilities during incident response. Use the Baseline section to revert the baseline and produce a consistent rollback evidence trail.</p>';

        echo '<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;">';
        echo '<a class="button button-secondary" href="#opsgate-hardening">';
        echo '<span class="dashicons dashicons-undo" style="vertical-align:middle;margin-right:6px;"></span>';
        echo 'Open Baseline Controls';
        echo '</a>';

        echo '<a class="button button-secondary" href="#opsgate-hardening">View rollback evidence</a>';
        echo '</div>';
        echo '</div>';

        echo '</div>'; // grid
        echo '</div>'; // card

    }

    /**
     * Day 19.4 (Step C): List scheduled receipt JSON files (most recent first).
     * Pure listing only. No background work.
     *
     * @param int $limit
     * @return array<int, array<string, string|int>>
     */
    private static function scheduled_receipts_list( $limit = 20 ) {
        $limit = is_numeric( $limit ) ? (int) $limit : 20;
        if ( $limit < 1 ) {
            $limit = 1;
        }
        if ( $limit > 200 ) {
            $limit = 200;
        }

        $uploads = wp_upload_dir();
        $baseurl = isset( $uploads['baseurl'] ) ? (string) $uploads['baseurl'] : '';
        $basedir = isset( $uploads['basedir'] ) ? (string) $uploads['basedir'] : '';

        if ( '' === $baseurl || '' === $basedir ) {
            return array();
        }

        $dir = rtrim( $basedir, '/\\' ) . '/opsgate/scheduled';
        if ( ! is_dir( $dir ) || ! is_readable( $dir ) ) {
            return array();
        }

        $files = glob( $dir . '/scheduled_*.json' );
        if ( false === $files || empty( $files ) ) {
            return array();
        }

        $rows = array();

        foreach ( $files as $abs ) {
            if ( ! is_string( $abs ) || '' === $abs ) {
                continue;
            }

            $basename = basename( $abs );
            if ( ! preg_match( '/^scheduled_(.+)_(\d{8}-\d{6})\.json$/', $basename, $m ) ) {
                continue;
            }

            $service_key = (string) $m[1];
            $stamp       = (string) $m[2];

            $ts = filemtime( $abs );
            $ts = $ts ? (int) $ts : 0;

            $rel = 'opsgate/scheduled/' . $basename;
            $url = rtrim( $baseurl, '/' ) . '/' . $rel;

            $rows[] = array(
                'service_key' => $service_key,
                'service'     => self::service_display_name( $service_key ),
                'stamp'       => $stamp,
                'ts'          => $ts,
                'file'        => $basename,
                'url'         => $url,
            );
        }

        usort(
            $rows,
            static function ( $a, $b ) {
                $ta = isset( $a['ts'] ) ? (int) $a['ts'] : 0;
                $tb = isset( $b['ts'] ) ? (int) $b['ts'] : 0;
                return $tb <=> $ta;
            }
        );

        return array_slice( $rows, 0, $limit );
    }

    /**
     * Day 20.3: List recovery request receipt JSON files (most recent first).
     * Pure listing only. No background work. No network calls.
     *
     * @param int $limit
     * @return array<int, array<string, string|int>>
     */
    private static function recovery_receipts_list( $limit = 20 ) {
        $limit = is_numeric( $limit ) ? (int) $limit : 20;
        if ( $limit < 1 ) {
            $limit = 1;
        }
        if ( $limit > 200 ) {
            $limit = 200;
        }

        $uploads = wp_upload_dir( null, false );
        $baseurl = isset( $uploads['baseurl'] ) ? (string) $uploads['baseurl'] : '';
        $basedir = isset( $uploads['basedir'] ) ? (string) $uploads['basedir'] : '';

        if ( '' === $baseurl || '' === $basedir ) {
            return array();
        }

        $dir = rtrim( $basedir, '/\\' ) . '/opsgate/recovery';
        if ( ! is_dir( $dir ) || ! is_readable( $dir ) ) {
            return array();
        }

        $files = glob( $dir . '/recovery_request_*.json' );
        if ( false === $files || empty( $files ) ) {
            return array();
        }

        // Sort newest first (by mtime).
        usort(
            $files,
            function( $a, $b ) {
                $ta = is_string( $a ) ? (int) ( filemtime( $a ) ?: 0 ) : 0;
                $tb = is_string( $b ) ? (int) ( filemtime( $b ) ?: 0 ) : 0;
                return $tb <=> $ta;
            }
        );

        $rows = array();

        foreach ( $files as $abs ) {
            if ( count( $rows ) >= $limit ) {
                break;
            }
            if ( ! is_string( $abs ) || '' === $abs ) {
                continue;
            }

            $basename = basename( $abs );
            if ( ! preg_match( '/^recovery_request_\d{8}-\d{6}\.json$/', $basename ) ) {
                continue;
            }

            $ts = filemtime( $abs );
            $ts = $ts ? (int) $ts : 0;

            $rel = 'opsgate/recovery/' . $basename;
            $url = rtrim( $baseurl, '/' ) . '/' . $rel;

            $rows[] = array(
                'file'   => $basename,
                'ts'     => $ts,
                'when'   => $ts > 0 ? gmdate( 'Y-m-d H:i:s', $ts ) . ' UTC' : '—',
                'url'    => $url,
            );
        }

        return $rows;
    }

    /**
     * Validate a recovery receipt filename (basename only).
     */
    private static function recovery_validate_receipt_file( string $file ): string {
        $file = trim( $file );
        $file = basename( $file );

        if ( '' === $file ) {
            return '';
        }

        if ( ! preg_match( '/^recovery_request_\d{8}-\d{6}\.json$/', $file ) ) {
            return '';
        }

        return $file;
    }

    /**
     * Load recovery receipt JSON payload (local).
     *
     * @return array<string,mixed>
     */
    private static function recovery_load_receipt_payload( string $file ): array {
        $uploads = wp_upload_dir( null, false );
        $basedir = isset( $uploads['basedir'] ) ? (string) $uploads['basedir'] : '';
        if ( '' === $basedir ) {
            return array();
        }

        $abs = rtrim( $basedir, '/\\' ) . '/opsgate/recovery/' . $file;

        if ( ! file_exists( $abs ) || ! is_readable( $abs ) ) {
            return array();
        }

        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
        $raw = file_get_contents( $abs );
        if ( ! is_string( $raw ) || '' === $raw ) {
            return array();
        }

        $decoded = json_decode( $raw, true );
        return is_array( $decoded ) ? $decoded : array();
    }

    /**
     * Send a local download (small payloads only).
     */
    private static function recovery_send_download( string $filename, string $content_type, string $body ): void {
        nocache_headers();
        header( 'Content-Type: ' . $content_type );
        header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
        header( 'Content-Length: ' . (string) strlen( $body ) );
        echo $body; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
        exit;
    }

    /**
     * Admin-post: Download Recovery Request receipt JSON (validated local file).
     */
    public static function handle_recovery_download_json(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden', 403 );
        }

        check_admin_referer( 'opsgate_recovery_download_json' );

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $file = isset( $_GET['file'] ) ? (string) wp_unslash( $_GET['file'] ) : '';
        $file = self::recovery_validate_receipt_file( $file );
        if ( '' === $file ) {
            wp_die( 'Invalid file', 400 );
        }

        $payload = self::recovery_load_receipt_payload( $file );
        if ( empty( $payload ) ) {
            wp_die( 'Receipt not found', 404 );
        }

        // Re-encode for consistent export.
        $json = wp_json_encode( $payload, JSON_PRETTY_PRINT );
        if ( false === $json ) {
            wp_die( 'Could not generate JSON.', 500 );
        }

        $export = str_replace( '.json', '', $file ) . '.json';
        self::recovery_send_download( $export, 'application/json; charset=utf-8', $json );
    }


    /**
     * Customer-facing service labels (display only).
     */
    private static function service_display_name( string $service_key ): string {
        $map = array(
            'wordpress_security_audit' => 'Security Scan',
        );

        if ( isset( $map[ $service_key ] ) ) {
            return (string) $map[ $service_key ];
        }

        // Safe fallback: turn snake_case into Title Case.
        $label = str_replace( array( '_', '-' ), ' ', $service_key );
        $label = trim( preg_replace( '/\s+/', ' ', $label ) );
        return ucwords( $label );
    }

    private static function normalize_admin_tab_request( string $active_tab ): string {
        $tab_aliases = array(
            'services'  => 'triage',
            'security'  => 'triage',
            'schedules' => 'settings',
            'agency'    => 'clients',
            'portfolio' => 'clients',
            'pricing'   => 'billing',
            'overview'  => 'overview',
            'triage'    => 'triage',
            'reports'   => 'reports',
            'alerts'    => 'alerts',
            'activity'  => 'activity',
            'clients'   => 'clients',
            'billing'   => 'billing',
            'settings'  => 'settings',
        );

        return isset( $tab_aliases[ $active_tab ] ) ? $tab_aliases[ $active_tab ] : 'overview';
    }

    private static function admin_tab_definitions(): array {
        return array(
            'overview' => array(
                'label' => 'Dashboard',
                'icon'  => 'dashicons-dashboard',
            ),
            'triage' => array(
                'label' => 'Scan',
                'icon'  => 'dashicons-clipboard',
            ),
            'reports' => array(
                'label' => 'Reports',
                'icon'  => 'dashicons-media-document',
            ),
            'alerts' => array(
                'label' => 'Alerts',
                'icon'  => 'dashicons-bell',
            ),
            'activity' => array(
                'label' => 'Activity',
                'icon'  => 'dashicons-chart-bar',
            ),
            'clients' => array(
                'label' => 'Portfolio',
                'icon'  => 'dashicons-admin-multisite',
            ),
            'billing' => array(
                'label' => 'Billing',
                'icon'  => 'dashicons-cart',
            ),
            'settings' => array(
                'label' => 'Settings',
                'icon'  => 'dashicons-admin-generic',
            ),
        );
    }

    private static function central_allowed_tabs_for_plan( string $plan ): array {
        $plan = self::normalize_plan( $plan );

        if ( 'agency' === $plan ) {
            // Agency: Portfolio leads, then core tabs, Settings before Billing at the end.
            return array( 'clients', 'overview', 'triage', 'reports', 'alerts', 'activity', 'settings', 'billing' );
        }
        if ( 'pro' === $plan ) {
            // Pro: core tabs, Activity visible, Settings before Billing.
            return array( 'overview', 'triage', 'reports', 'alerts', 'activity', 'settings', 'billing' );
        }
        if ( 'starter' === $plan ) {
            // Starter: Activity kept (add-on 3 — locked), Portfolio context in Dashboard tab (no standalone tab), Settings before Billing.
            return array( 'overview', 'triage', 'reports', 'alerts', 'activity', 'settings', 'billing' );
        }

        // Free: Portfolio context card is in the Dashboard tab, not a standalone tab.
        return array( 'overview', 'billing' );
    }

    private static function remote_companion_section_keys_for_plan( string $plan ): array {
        $plan = self::normalize_plan( $plan );

        if ( 'agency' === $plan || 'pro' === $plan || 'starter' === $plan ) {
            return array( 'connection', 'site_status', 'triage_action', 'report_summary', 'alert_summary', 'activity_summary', 'plan_upgrade', 'support' );
        }

        return array( 'connection', 'site_status', 'public_history', 'plan_upgrade', 'support' );
    }

    /**
     * Resolve the canonical effective site state for the current request.
     *
     * This is the single source of truth for all UI decisions on both the remote
     * companion and the central dashboard. It must be called once per request and
     * its output passed to every surface decision: badge, tabs, actions, evidence
     * copy, Billing, Reports, Alerts, Activity, pairing routing.
     *
     * Resolution rules:
     * - effective_plan: operator override > API plan > stored plan > unknown
     * - plan_source: 'operator_override' | 'api' | 'stored' | 'api_unavailable'
     * - connection_mode: from site summary API read only
     * - connection_status: from site summary API read only
     * - evidence_mode: 'connected' only when wp_connector + connected status
     * - surface_mode: derived from effective_plan + connection state
     *   - 'free_public': free plan, public_scan
     *   - 'paid_unconnected': paid plan, public_scan (pairing required)
     *   - 'paid_connected': paid plan, wp_connector + connected
     *   - 'credential_problem': wp_connector + credential_invalid
     *   - 'disconnected': wp_connector + disconnected/pairing_pending
     * - allowed_tabs: derived from surface_mode + effective_plan (never from plan alone)
     *
     * @return array{
     *   account_id:string,
     *   site_id:string,
     *   site_label:string,
     *   site_url:string,
     *   effective_plan:string,
     *   plan_source:string,
     *   connection_mode:string,
     *   connection_status:string,
     *   evidence_mode:string,
     *   surface_mode:string,
     *   is_connected:bool,
     *   is_operator_override:bool,
     *   is_public_scan:bool,
     *   allowed_tabs:array,
     *   entitlement_snapshot:array,
     *   site_summary:array
     * }
     */
    private static function resolve_effective_site_state(): array {
        // --- 1. Single canonical plan read ---
        $ent_snapshot  = self::get_entitlement_plan_snapshot();
        $effective_plan = self::normalize_plan( isset( $ent_snapshot['plan'] ) ? (string) $ent_snapshot['plan'] : 'unknown' );
        $plan_source    = isset( $ent_snapshot['source'] ) ? (string) $ent_snapshot['source'] : 'api_unavailable';
        $is_operator_override = ( 'operator_override' === $plan_source );

        // --- 2. Single canonical site read ---
        $site_summary     = self::current_selected_site_summary();
        $account_id       = trim( (string) ( self::get_mcp_scope_snapshot()['account_id'] ?? '' ) );
        $site_id          = trim( (string) ( $site_summary['site_id'] ?? self::get_mcp_scope_snapshot()['site_id'] ?? '' ) );
        $site_label       = trim( (string) ( $site_summary['site_label'] ?? '' ) );
        $site_url         = trim( (string) ( $site_summary['site_url'] ?? '' ) );
        $connection_mode   = strtolower( trim( (string) ( $site_summary['connection_mode'] ?? 'public_scan' ) ) );
        $connection_status = strtolower( trim( (string) ( $site_summary['connection_status'] ?? 'external_only' ) ) );

        if ( ! in_array( $connection_mode, array( 'public_scan', 'wp_connector' ), true ) ) {
            $connection_mode = 'public_scan';
        }

        // --- 3. Derive connection truth ---
        $is_public_scan = ( 'wp_connector' !== $connection_mode );
        $is_connected   = ( 'connected' === $connection_status && 'wp_connector' === $connection_mode );

        // evidence_mode: connected only when wire + credential are both valid.
        $evidence_mode = $is_connected ? 'connected' : 'public_only';

        // --- 4. Derive surface_mode ---
        // This is the single variable that decides which UI experience to render.
        // Operator override unlocks higher-tier tabs/actions for testing but does NOT
        // change the connection reality — a public_scan site is still unconnected
        // even under override, so evidence_mode stays honest.
        if ( 'credential_invalid' === $connection_status ) {
            $surface_mode = 'credential_problem';
        } elseif ( in_array( $connection_status, array( 'disconnected', 'pairing_pending' ), true ) ) {
            $surface_mode = 'disconnected';
        } elseif ( $is_connected ) {
            // wp_connector + connected: paid or free with stored connector.
            // Free + connected is a downgrade/mismatch state: connected paid features gated.
            $surface_mode = 'paid_connected';
        } elseif ( $is_public_scan && in_array( $effective_plan, array( 'starter', 'pro', 'agency' ), true ) ) {
            // Paid plan but not connected yet (operator override or real paid + new site).
            $surface_mode = 'paid_unconnected';
        } else {
            // free + public_scan, or unknown + public_scan.
            $surface_mode = 'free_public';
        }

        // --- 5. Derive surface_plan (for tab gating) ---
        // Operator override is the only reason a public_scan site gets paid tabs.
        // Without override: public_scan always caps to free for tab purposes.
        // With override: surface_plan follows the override tier for lifecycle testing.
        // Evidence availability is independent — always driven by connection reality.
        if ( $is_operator_override ) {
            $surface_plan_for_tabs = $effective_plan;
        } elseif ( $is_public_scan ) {
            $surface_plan_for_tabs = 'free';
        } else {
            $surface_plan_for_tabs = $effective_plan;
        }
        $allowed_tabs = self::central_allowed_tabs_for_plan( $surface_plan_for_tabs );

        // Billing is always accessible so users can upgrade regardless of mode.
        if ( ! in_array( 'billing', $allowed_tabs, true ) ) {
            $allowed_tabs[] = 'billing';
        }

        return array(
            'account_id'           => $account_id,
            'site_id'              => $site_id,
            'site_label'           => '' !== $site_label ? $site_label : 'Current site',
            'site_url'             => $site_url,
            'effective_plan'       => $effective_plan,
            'plan_source'          => $plan_source,
            'connection_mode'      => $connection_mode,
            'connection_status'    => $connection_status,
            'evidence_mode'        => $evidence_mode,
            'surface_mode'         => $surface_mode,
            'surface_plan_for_tabs'=> $surface_plan_for_tabs,
            'is_connected'         => $is_connected,
            'is_operator_override' => $is_operator_override,
            'is_public_scan'       => $is_public_scan,
            'allowed_tabs'         => $allowed_tabs,
            'entitlement_snapshot' => $ent_snapshot,
            'site_summary'         => $site_summary,
        );
    }

    private static function current_surface_mode(): array {
        $execution = self::current_site_execution_context();

        return array(
            'plan'             => self::get_current_plan(),
            'remote_companion' => ! self::current_install_is_central_console(),
            'execution'        => $execution,
        );
    }

    private static function current_install_is_central_console(): bool {
        $home_host = (string) ( wp_parse_url( (string) home_url(), PHP_URL_HOST ) ?: '' );
        $console_base = self::remote_companion_console_base_url();
        $console_host = (string) ( wp_parse_url( $console_base, PHP_URL_HOST ) ?: '' );

        if ( '' !== $home_host && '' !== $console_host && strtolower( $home_host ) === strtolower( $console_host ) ) {
            return true;
        }

        $api_host = strtolower( (string) ( wp_parse_url( self::mcp_base_url(), PHP_URL_HOST ) ?: '' ) );
        $home_host = strtolower( $home_host );

        if ( '' === $home_host || '' === $api_host ) {
            return false;
        }

        if ( in_array( $api_host, array( 'mcp', 'api' ), true ) ) {
            return 0 === strpos( $home_host, 'wp.' );
        }

        if ( 0 === strpos( $api_host, 'mcp.' ) ) {
            return 'wp.' . substr( $api_host, 4 ) === $home_host;
        }

        if ( 0 === strpos( $api_host, 'api.' ) ) {
            return 'wp.' . substr( $api_host, 4 ) === $home_host;
        }

        return false;
    }

    private static function render_surface_notice( string $message, string $tone = 'warning' ): void {
        $class = 'notice notice-warning';
        if ( 'error' === $tone ) {
            $class = 'notice notice-error';
        } elseif ( 'success' === $tone ) {
            $class = 'notice notice-success';
        }

        echo '<div class="' . esc_attr( $class ) . '"><p>' . esc_html( $message ) . '</p></div>';
    }

    /**
     * @param array<string,mixed> $requested_scope
     * @return array{title:string,copy:string,target_label:string,site_label:string,site_url:string,setup_url:string,open_url:string,sign_in_url:string,return_url:string,diagnostic_reason:string,diagnostic_account:string,diagnostic_site_id:string,diagnostic_source:string}
     */
    private static function scoped_handoff_view_model( array $requested_scope ): array {
        $reason_code = isset( $requested_scope['reason_code'] ) ? sanitize_key( (string) $requested_scope['reason_code'] ) : 'site_scope_unavailable';
        $site_label = trim( (string) ( $requested_scope['site_label'] ?? '' ) );
        $site_url = trim( (string) ( $requested_scope['site_url'] ?? '' ) );
        $site_id = trim( (string) ( $requested_scope['site_id'] ?? '' ) );
        $account_id = trim( (string) ( $requested_scope['requested_account_id'] ?? '' ) );
        if ( '' === $site_label ) {
            $site_label = '' !== $site_url ? $site_url : 'Requested site';
        }

        $requested_tab = isset( $requested_scope['requested_tab'] ) ? sanitize_text_field( (string) $requested_scope['requested_tab'] ) : 'overview';
        $requested_section = isset( $requested_scope['requested_section'] ) ? sanitize_key( (string) $requested_scope['requested_section'] ) : '';
        $requested_panel = isset( $requested_scope['requested_panel'] ) ? sanitize_key( (string) $requested_scope['requested_panel'] ) : '';
        $target_label = self::scoped_handoff_target_label( $requested_tab, $requested_section, $requested_panel );

        $title = 'OpsGate could not open this requested site yet.';
        $copy = 'OpsGate could not confirm the requested site scope from this link. Start setup for this site or return to the WordPress companion.';
        if ( in_array( $reason_code, array( 'missing_active_account', 'requested_account_not_attached', 'requested_site_not_attached' ), true ) ) {
            $title = 'This site is not attached to the current OpsGate session.';
            $copy = 'To continue, sign in with the OpsGate account that owns this site, switch account, or start setup for this site.';
        }

        $setup_args = array(
            'section' => 'site-configuration',
            'opsgate_source' => 'remote-onboarding',
        );
        if ( 'settings' === self::normalize_admin_tab_request( $requested_tab ) && 'site-configuration' === $requested_section ) {
            $setup_args['panel'] = '' !== $requested_panel ? $requested_panel : 'pairing-material';
        }
        if ( '' !== $site_url ) {
            $setup_args['opsgate_prefill_site_url'] = $site_url;
        }
        if ( '' !== $site_label ) {
            $setup_args['opsgate_prefill_site_label'] = $site_label;
        }
        $setup_args['opsgate_requested_tab'] = $requested_tab;
        if ( '' !== $requested_section ) {
            $setup_args['opsgate_requested_section'] = $requested_section;
        }
        if ( '' !== $requested_panel ) {
            $setup_args['opsgate_requested_panel'] = $requested_panel;
        }
        if ( ! empty( $requested_scope['requested_connection_mode'] ) ) {
            $setup_args['opsgate_requested_connection_mode'] = sanitize_key( (string) $requested_scope['requested_connection_mode'] );
        }
        if ( ! empty( $requested_scope['intended_action'] ) ) {
            $setup_args['opsgate_intended_action'] = sanitize_key( (string) $requested_scope['intended_action'] );
        }
        if ( ! empty( $requested_scope['source_job_id'] ) ) {
            $setup_args['opsgate_source_job_id'] = sanitize_text_field( (string) $requested_scope['source_job_id'] );
        }
        // Carry onboarding session params so the setup URL retriggers the claim/resolve flow.
        if ( ! empty( $requested_scope['onboarding_session_id'] ) ) {
            $setup_args['opsgate_onboarding_session_id'] = sanitize_text_field( (string) $requested_scope['onboarding_session_id'] );
        }
        if ( ! empty( $requested_scope['onboarding_token'] ) ) {
            $setup_args['opsgate_onboarding_token'] = sanitize_text_field( (string) $requested_scope['onboarding_token'] );
        }

        $return_url = isset( $requested_scope['return_url'] ) ? trim( (string) $requested_scope['return_url'] ) : '';
        if ( '' === $return_url && '' !== $site_url ) {
            $return_url = self::remote_companion_return_url( $site_url );
        }
        if ( '' !== $return_url ) {
            $setup_args['opsgate_return_url'] = $return_url;
        }

        $setup_url = self::admin_tab_url( 'settings', $setup_args ) . '#opsgate-site-configuration-section';
        $open_tab = self::normalize_admin_tab_request( $requested_tab );
        $open_url = self::browser_safe_admin_url(
            'admin.php',
            array_filter(
                array_merge(
                    array(
                        'page' => 'opsgate',
                        'tab'  => $open_tab,
                        'opsgate_scope_account' => $account_id,
                        'opsgate_scope_site_id' => $site_id,
                        'opsgate_scope_site_url' => $site_url,
                        'opsgate_scope_site_label' => $site_label,
                        'opsgate_requested_tab' => $requested_tab,
                        'opsgate_requested_section' => $requested_section,
                        'opsgate_requested_panel' => $requested_panel,
                        'opsgate_return_url' => $return_url,
                        'opsgate_requested_connection_mode' => isset( $requested_scope['requested_connection_mode'] ) ? sanitize_key( (string) $requested_scope['requested_connection_mode'] ) : '',
                        'opsgate_intended_action' => isset( $requested_scope['intended_action'] ) ? sanitize_key( (string) $requested_scope['intended_action'] ) : '',
                        'opsgate_source_job_id' => isset( $requested_scope['source_job_id'] ) ? sanitize_text_field( (string) $requested_scope['source_job_id'] ) : '',
                    )
                ),
                static function ( $value ): bool {
                    return null !== $value && '' !== $value;
                }
            )
        );
        // Sign-in URL for unauthenticated visitors — points to the central WP login.
        $console_base = self::remote_companion_console_base_url();
        $sign_in_url = '' !== $console_base
            ? add_query_arg( 'redirect_to', rawurlencode( $open_url ), str_replace( '/wp-admin', '', $console_base ) . '/wp-login.php' )
            : '';
        return array(
            'title' => $title,
            'copy' => $copy,
            'target_label' => $target_label,
            'site_label' => $site_label,
            'site_url' => $site_url,
            'setup_url' => $setup_url,
            'open_url' => $open_url,
            'sign_in_url' => $sign_in_url,
            'return_url' => $return_url,
            'diagnostic_reason' => '' !== $reason_code ? $reason_code : 'site_scope_unavailable',
            'diagnostic_account' => $account_id,
            'diagnostic_site_id' => $site_id,
            'diagnostic_source' => isset( $_GET['opsgate_source'] ) ? sanitize_key( wp_unslash( $_GET['opsgate_source'] ) ) : '',
        );
    }

    private static function scoped_handoff_target_label( string $requested_tab, string $requested_section, string $requested_panel ): string {
        $tab = self::normalize_admin_tab_request( $requested_tab );
        if ( 'settings' === $tab && 'site-configuration' === $requested_section && 'pairing-material' === $requested_panel ) {
            return 'Settings / Site Configuration / Pairing Material';
        }
        if ( 'settings' === $tab && 'site-configuration' === $requested_section ) {
            return 'Settings / Site Configuration';
        }

        $labels = array(
            'overview' => 'Overview',
            'reports' => 'Reports',
            'alerts' => 'Alerts',
            'activity' => 'Activity',
            'billing' => 'Billing / Upgrade',
            'clients' => 'Portfolio',
            'settings' => 'Settings',
        );

        return isset( $labels[ $tab ] ) ? $labels[ $tab ] : 'OpsGate';
    }

    /**
     * @param array<string,mixed> $requested_scope
     * @return void
     */
    private static function render_scoped_handoff_notice( array $requested_scope ): void {
        $view = self::scoped_handoff_view_model( $requested_scope );
        ?>
        <div class="opsgate-card opsgate-pricing-dashboard">
            <h2><span class="dashicons dashicons-admin-site-alt3"></span> Requested Site Handoff</h2>
            <div class="opsgate-alert-panel opsgate-alert-panel-error">
                <p><strong><?php echo esc_html( $view['title'] ); ?></strong></p>
                <p><?php echo esc_html( $view['copy'] ); ?></p>
            </div>
            <div class="opsgate-settings-support-grid" style="margin-top:16px;">
                <article class="opsgate-settings-support-card">
                    <span class="opsgate-overview-eyebrow">Requested destination</span>
                    <p>OpsGate kept the requested destination and did not open another site.</p>
                    <input type="text" class="regular-text" value="<?php echo esc_attr( $view['target_label'] ); ?>" readonly="readonly" />
                </article>
                <article class="opsgate-settings-support-card">
                    <span class="opsgate-overview-eyebrow">Requested site</span>
                    <p>Customer-safe site label from the remote handoff.</p>
                    <input type="text" class="regular-text" value="<?php echo esc_attr( $view['site_label'] ); ?>" readonly="readonly" />
                </article>
                <article class="opsgate-settings-support-card">
                    <span class="opsgate-overview-eyebrow">Requested URL</span>
                    <p>WordPress companion URL from the remote handoff.</p>
                    <input type="text" class="regular-text" value="<?php echo esc_attr( '' !== $view['site_url'] ? $view['site_url'] : 'Not provided on this handoff' ); ?>" readonly="readonly" />
                </article>
            </div>
            <div class="opsgate-settings-inline-form opsgate-settings-connection-actions" style="margin-top:16px;">
                <?php if ( '' !== $view['sign_in_url'] ) : ?>
                    <a class="button button-primary" href="<?php echo esc_url( $view['sign_in_url'] ); ?>" data-opsgate-no-ajax="1">Sign in to OpsGate &rarr;</a>
                <?php endif; ?>
                <?php if ( '' !== $view['site_url'] ) : ?>
                <?php
                // "Open OpsGate" claims the site first (via POST handler) and then redirects to
                // the requested destination tab — prevents landing back on the handoff gate.
                $open_requested_tab = isset( $requested_scope['requested_tab'] ) ? (string) $requested_scope['requested_tab'] : 'overview';
                ?>
                <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="display:inline;">
                    <?php wp_nonce_field( 'opsgate_claim_remote_site', 'opsgate_claim_remote_site_nonce' ); ?>
                    <input type="hidden" name="action" value="opsgate_claim_remote_site" />
                    <input type="hidden" name="opsgate_site_url" value="<?php echo esc_attr( $view['site_url'] ); ?>" />
                    <input type="hidden" name="opsgate_site_label" value="<?php echo esc_attr( $view['site_label'] ); ?>" />
                    <input type="hidden" name="opsgate_scope_account" value="<?php echo esc_attr( $view['diagnostic_account'] ); ?>" />
                    <input type="hidden" name="opsgate_return_url" value="<?php echo esc_attr( $view['return_url'] ); ?>" />
                    <input type="hidden" name="opsgate_requested_tab" value="<?php echo esc_attr( $open_requested_tab ); ?>" />
                    <?php if ( ! empty( $requested_scope['onboarding_session_id'] ) ) : ?>
                    <input type="hidden" name="opsgate_onboarding_session_id" value="<?php echo esc_attr( (string) $requested_scope['onboarding_session_id'] ); ?>" />
                    <?php endif; ?>
                    <?php if ( ! empty( $requested_scope['onboarding_token'] ) ) : ?>
                    <input type="hidden" name="opsgate_onboarding_token" value="<?php echo esc_attr( (string) $requested_scope['onboarding_token'] ); ?>" />
                    <?php endif; ?>
                    <button type="submit" class="button <?php echo '' !== $view['sign_in_url'] ? 'button-secondary' : 'button-primary'; ?>">Open OpsGate &rarr;</button>
                </form>
                <?php else : ?>
                <a class="button <?php echo '' !== $view['sign_in_url'] ? 'button-secondary' : 'button-primary'; ?>" href="<?php echo esc_url( $view['open_url'] ); ?>" data-opsgate-no-ajax="1">Open OpsGate &rarr;</a>
                <?php endif; ?>
                <?php if ( '' !== $view['site_url'] ) : ?>
                <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="display:inline;">
                    <?php wp_nonce_field( 'opsgate_claim_remote_site', 'opsgate_claim_remote_site_nonce' ); ?>
                    <input type="hidden" name="action" value="opsgate_claim_remote_site" />
                    <input type="hidden" name="opsgate_site_url" value="<?php echo esc_attr( $view['site_url'] ); ?>" />
                    <input type="hidden" name="opsgate_site_label" value="<?php echo esc_attr( $view['site_label'] ); ?>" />
                    <input type="hidden" name="opsgate_scope_account" value="<?php echo esc_attr( $view['diagnostic_account'] ); ?>" />
                    <input type="hidden" name="opsgate_return_url" value="<?php echo esc_attr( $view['return_url'] ); ?>" />
                    <input type="hidden" name="opsgate_requested_tab" value="<?php echo esc_attr( isset( $requested_scope['requested_tab'] ) ? (string) $requested_scope['requested_tab'] : 'overview' ); ?>" />
                    <input type="hidden" name="opsgate_requested_section" value="<?php echo esc_attr( isset( $requested_scope['requested_section'] ) ? (string) $requested_scope['requested_section'] : '' ); ?>" />
                    <input type="hidden" name="opsgate_requested_panel" value="<?php echo esc_attr( isset( $requested_scope['requested_panel'] ) ? (string) $requested_scope['requested_panel'] : '' ); ?>" />
                    <input type="hidden" name="opsgate_intended_action" value="<?php echo esc_attr( isset( $requested_scope['intended_action'] ) ? (string) $requested_scope['intended_action'] : '' ); ?>" />
                    <?php if ( ! empty( $requested_scope['onboarding_session_id'] ) ) : ?>
                    <input type="hidden" name="opsgate_onboarding_session_id" value="<?php echo esc_attr( (string) $requested_scope['onboarding_session_id'] ); ?>" />
                    <?php endif; ?>
                    <?php if ( ! empty( $requested_scope['onboarding_token'] ) ) : ?>
                    <input type="hidden" name="opsgate_onboarding_token" value="<?php echo esc_attr( (string) $requested_scope['onboarding_token'] ); ?>" />
                    <?php endif; ?>
                    <button type="submit" class="button button-secondary">Start setup for this site</button>
                </form>
                <?php else : ?>
                <a class="button button-secondary" href="<?php echo esc_url( $view['setup_url'] ); ?>" data-opsgate-no-ajax="1">Start setup for this site</a>
                <?php endif; ?>
                <?php if ( '' !== $view['return_url'] ) : ?>
                    <a class="button button-secondary" href="<?php echo esc_url( $view['return_url'] ); ?>" data-opsgate-no-ajax="1">&larr; Back to <?php echo esc_html( '' !== $view['site_label'] ? $view['site_label'] : 'remote plugin' ); ?></a>
                <?php endif; ?>
            </div>
            <details class="opsgate-advanced-details" style="margin-top:16px;">
                <summary><strong>Support diagnostics</strong></summary>
                <div class="opsgate-settings-support-grid" style="margin-top:12px;">
                    <article class="opsgate-settings-support-card">
                        <span class="opsgate-overview-eyebrow">Reason code</span>
                        <p>Support-safe scoped handoff reason.</p>
                        <input type="text" class="regular-text" value="<?php echo esc_attr( $view['diagnostic_reason'] ); ?>" readonly="readonly" />
                    </article>
                    <article class="opsgate-settings-support-card">
                        <span class="opsgate-overview-eyebrow">Requested account</span>
                        <p>Shown for support only.</p>
                        <input type="text" class="regular-text" value="<?php echo esc_attr( '' !== $view['diagnostic_account'] ? $view['diagnostic_account'] : 'Not provided' ); ?>" readonly="readonly" />
                    </article>
                    <article class="opsgate-settings-support-card">
                        <span class="opsgate-overview-eyebrow">Requested site ID</span>
                        <p>Shown for support only.</p>
                        <input type="text" class="regular-text" value="<?php echo esc_attr( '' !== $view['diagnostic_site_id'] ? $view['diagnostic_site_id'] : 'Not provided' ); ?>" readonly="readonly" />
                    </article>
                    <article class="opsgate-settings-support-card">
                        <span class="opsgate-overview-eyebrow">Handoff source</span>
                        <p>Remote source marker from the incoming link.</p>
                        <input type="text" class="regular-text" value="<?php echo esc_attr( '' !== $view['diagnostic_source'] ? $view['diagnostic_source'] : 'Not provided' ); ?>" readonly="readonly" />
                    </article>
                </div>
            </details>
        </div>
        <?php
    }

    private static function next_upgrade_link_for_plan( string $plan ): string {
        $plan = self::normalize_plan( $plan );
        if ( 'free' === $plan ) {
            return trim( (string) get_option( 'opsgate_stripe_payment_link_starter', '' ) );
        }
        if ( 'starter' === $plan ) {
            return trim( (string) get_option( 'opsgate_stripe_payment_link_pro', '' ) );
        }
        if ( 'pro' === $plan ) {
            return trim( (string) get_option( 'opsgate_stripe_payment_link_agency', '' ) );
        }

        return '';
    }

    private static function remote_companion_bundle_is_public_only( array $job, array $artifacts ): bool {
        $payload = isset( $job['payload_json'] ) && is_array( $job['payload_json'] ) ? $job['payload_json'] : array();
        $score = isset( $artifacts['score_summary']['body'] ) && is_array( $artifacts['score_summary']['body'] ) ? $artifacts['score_summary']['body'] : array();
        $receipt = isset( $artifacts['json_receipt']['body'] ) && is_array( $artifacts['json_receipt']['body'] ) ? $artifacts['json_receipt']['body'] : array();
        $receipt_inputs = isset( $receipt['inputs'] ) && is_array( $receipt['inputs'] ) ? $receipt['inputs'] : array();

        $markers = array(
            ! empty( $score['public_only'] ),
            ! empty( $receipt_inputs['public_only'] ),
            ! empty( $payload['public_only'] ),
            ! empty( $payload['external_only'] ),
            'public_scan' === strtolower( trim( (string) ( $score['connection_mode'] ?? '' ) ) ),
            'public_scan' === strtolower( trim( (string) ( $receipt_inputs['connection_mode'] ?? '' ) ) ),
            'public_scan' === strtolower( trim( (string) ( $payload['connection_mode'] ?? '' ) ) ),
        );

        return in_array( true, $markers, true );
    }

    private static function remote_companion_latest_run_mode( array $job, array $score, array $receipt_inputs, string $fallback_mode ): string {
        $payload = isset( $job['payload_json'] ) && is_array( $job['payload_json'] ) ? $job['payload_json'] : array();
        $candidates = array(
            isset( $payload['connection_mode'] ) ? (string) $payload['connection_mode'] : '',
            isset( $score['connection_mode'] ) ? (string) $score['connection_mode'] : '',
            isset( $receipt_inputs['connection_mode'] ) ? (string) $receipt_inputs['connection_mode'] : '',
            $fallback_mode,
        );

        foreach ( $candidates as $candidate ) {
            $normalized = strtolower( trim( (string) $candidate ) );
            if ( in_array( $normalized, array( 'public_scan', 'wp_connector' ), true ) ) {
                return $normalized;
            }
        }

        return 'public_scan';
    }

    private static function remote_companion_report_formats(): array {
        $formats = array(
            'PDF'  => self::export_kind_allowed_now( 'report_pdf' ),
            'HTML' => self::export_kind_allowed_now( 'report_html' ),
            'CSV'  => self::export_kind_allowed_now( 'csv' ),
            'XLSX' => self::export_kind_allowed_now( 'report_xlsx' ),
        );

        $included = array();
        $locked   = array();
        foreach ( $formats as $label => $is_allowed ) {
            if ( $is_allowed ) {
                $included[] = $label;
            } else {
                $locked[] = $label;
            }
        }

        return array(
            'included' => $included,
            'locked'   => $locked,
            'headline' => ! empty( $included ) ? implode( ' / ', $included ) . ' ready on this plan' : 'Connected reports are not included on this plan',
        );
    }

    private static function remote_companion_alert_family_summary( string $plan ): array {
        $plan = self::normalize_plan( $plan );
        $labels = array(
            'email'    => 'Email',
            'webhook'  => 'Webhook',
            'telegram' => 'Telegram',
            'slack'    => 'Slack',
            'whatsapp' => 'WhatsApp',
            'discord'  => 'Discord',
            'sns'      => 'SNS',
            'teams'    => 'Teams',
        );
        $included_by_plan = array(
            'free'    => array(),
            'starter' => array( 'email', 'webhook', 'telegram' ),
            'pro'     => array( 'email', 'webhook', 'telegram', 'slack', 'whatsapp' ),
            'agency'  => array( 'email', 'webhook', 'telegram', 'slack', 'whatsapp', 'discord', 'sns', 'teams' ),
        );
        $expected_included = isset( $included_by_plan[ $plan ] ) ? $included_by_plan[ $plan ] : array();

        $included = array();
        $locked   = array();
        foreach ( array_keys( $labels ) as $family ) {
            if ( in_array( $family, $expected_included, true ) ) {
                $included[] = $labels[ $family ];
            } else {
                $locked[] = $labels[ $family ];
            }
        }

        return array(
            'included' => $included,
            'locked'   => $locked,
        );
    }

    private static function remote_companion_plan_story( string $plan ): array {
        $plan = self::normalize_plan( $plan );

        if ( 'free' === $plan ) {
            return array(
                'current' => 'Free keeps this site in outside-in mode only: public reachability, SSL/TLS health, public availability, and public performance signals.',
                'next'    => 'Starter unlocks connected WordPress evidence, PDF reports, and Email / Webhook / Telegram alert routing after pairing the plugin.',
            );
        }
        if ( 'starter' === $plan ) {
            return array(
                'current' => 'Starter keeps this site connected with one-site security scanning, PDF reporting, and Email / Webhook / Telegram alert routing.',
                'next'    => 'Pro adds HTML and CSV reports, daily cadence, dedicated uptime, vulnerability routing, and Slack / WhatsApp delivery options.',
            );
        }
        if ( 'pro' === $plan ) {
            return array(
                'current' => 'Pro keeps this site on the hybrid operations path with PDF / HTML / CSV reporting, uptime, vulnerability routing, and broader connected alerting.',
                'next'    => 'Agency adds XLSX reporting, the widest alert family coverage, and multi-site scale while this plugin stays site-scoped.',
            );
        }

        return array(
            'current' => 'Agency keeps this plugin focused on one site while the broader portfolio, client, and multi-site operations stay in the central OpsGate management layer.',
            'next'    => 'Agency is already the highest current tier in this release line.',
        );
    }

    private static function default_remote_api_base_url(): string {
        // No hardcoded fallback. Central URL must be explicitly configured.
        // Callers that receive '' must fail safely rather than routing to a proof/lab site.
        return '';
    }

    private static function remote_companion_client_safe_error( string $error, string $fallback ): string {
        $message = trim( $error );
        if ( '' === $message ) {
            return $fallback;
        }

        $normalized = strtolower( $message );
        if ( false !== strpos( $normalized, 'site_url_invalid' ) || false !== strpos( $normalized, 'invalid url' ) || false !== strpos( $normalized, 'valid url' ) ) {
            return 'Enter a valid public site URL before starting the Free public check.';
        }
        if ( false !== strpos( $normalized, 'contact_email' ) ) {
            return 'OpsGate needs a valid contact email before the Free public check can start.';
        }
        if ( false !== strpos( $normalized, 'not found' ) || false !== strpos( $normalized, '404' ) ) {
            return 'OpsGate could not start the Free public check right now. Open OpsGate or try again in a moment.';
        }
        if ( false !== strpos( $normalized, 'free_account_bootstrap_failed' ) || false !== strpos( $normalized, 'bootstrap the free site' ) || false !== strpos( $normalized, 'canonical site' ) ) {
            return 'OpsGate could not create the Free public site record right now. Try again in a moment or open OpsGate.';
        }
        if ( false !== strpos( $normalized, 'mcp base url not configured' ) ) {
            return 'OpsGate setup is missing its service endpoint. Open OpsGate or review plugin settings before running the first public check.';
        }
        if ( false !== strpos( $normalized, 'rate limit' ) || false !== strpos( $normalized, 'too many requests' ) || false !== strpos( $normalized, '429' ) ) {
            return 'OpsGate rate-limited this public check. Wait a moment, then try again.';
        }
        if ( false !== strpos( $normalized, 'unreachable' ) ) {
            return 'OpsGate could not reach that public URL. Check the site URL and try again.';
        }
        if ( false !== strpos( $normalized, 'timed out' ) || false !== strpos( $normalized, 'could not resolve host' ) || false !== strpos( $normalized, 'curl error' ) ) {
            return 'OpsGate could not reach the service right now. Try again in a moment or open OpsGate for setup.';
        }
        if ( false !== strpos( $normalized, 'dispatch_failed' ) || false !== strpos( $normalized, 'could not queue' ) || false !== strpos( $normalized, 'could not start portfolio triage' ) ) {
            return 'OpsGate could not queue the Free public check right now. Try again in a moment or open OpsGate.';
        }

        return $message;
    }

    private static function remote_companion_pairing_safe_error( string $error, string $fallback ): string {
        $message = trim( $error );
        if ( '' === $message ) {
            return $fallback;
        }

        $normalized = strtolower( $message );
        if ( false !== strpos( $normalized, 'pairing_code_invalid' ) || false !== strpos( $normalized, 'site_pairing_session_not_found' ) ) {
            return 'That pairing code is invalid or expired.';
        }
        if ( false !== strpos( $normalized, 'expired' ) ) {
            return 'That pairing code expired. Create a new pairing code in OpsGate and try again.';
        }
        if ( false !== strpos( $normalized, 'not_pending' ) || false !== strpos( $normalized, 'already' ) ) {
            return 'That pairing code is no longer available. Create a fresh pairing code in OpsGate.';
        }
        if ( false !== strpos( $normalized, 'timed out' ) || false !== strpos( $normalized, 'could not resolve host' ) || false !== strpos( $normalized, 'curl error' ) ) {
            return 'OpsGate could not reach the pairing service right now. Try again in a moment.';
        }

        return $message;
    }

    /**
     * Create a canonical onboarding session on the central API and return the handoff URL.
     * Returns empty string on failure — callers must fall back to the legacy query-param URL.
     *
     * @param string $tab        The central tab being targeted (overview, reports, settings, …).
     * @param array  $scope      Scope array from the calling context (account_id, site_id …).
     * @param array  $site_summary Site summary array (site_url, site_label, …).
     * @param array  $args       Extra args (opsgate_intended_action, etc.) passed through.
     * @return string            central_handoff_url from the API, or '' on failure.
     */
    private static function remote_companion_create_onboarding_session( string $tab, array $scope = array(), array $site_summary = array(), array $args = array() ): string {
        $site_url = isset( $site_summary['site_url'] ) ? trim( (string) $site_summary['site_url'] ) : '';
        $site_label = isset( $site_summary['site_label'] ) ? trim( (string) $site_summary['site_label'] ) : '';
        if ( '' === $site_url ) {
            $site_url = trim( (string) home_url() );
        }
        if ( '' === $site_label ) {
            $site_label = trim( (string) get_bloginfo( 'name' ) );
        }
        if ( '' === $site_url ) {
            return '';
        }

        $intended_action = isset( $args['opsgate_intended_action'] ) ? sanitize_key( (string) $args['opsgate_intended_action'] ) : '';
        $intent_map = array(
            'get_pairing'      => 'get_pairing',
            'open_reports'     => 'reports',
            'open_alerts'      => 'alerts',
            'open_activity'    => 'activity',
            'open_billing'     => 'billing',
            'open_summary'     => 'public_summary',
        );
        $intent = isset( $intent_map[ $intended_action ] ) ? $intent_map[ $intended_action ] : 'setup';

        $destination_map = array(
            'overview'  => 'overview',
            'reports'   => 'reports',
            'alerts'    => 'alerts',
            'activity'  => 'activity',
            'billing'   => 'billing',
            'settings'  => 'settings',
            'clients'   => 'overview',
        );
        $destination = isset( $destination_map[ $tab ] ) ? $destination_map[ $tab ] : 'overview';
        if ( 'get_pairing' === $intent ) {
            $destination = 'pairing-material';
        }

        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : trim( (string) get_option( 'opsgate_account_id', '' ) );

        $origin_admin_url = admin_url( 'admin.php?page=opsgate' );
        $return_url = self::remote_companion_return_url( $site_url );

        $payload = array(
            'site_url'              => $site_url,
            'site_label'            => '' !== $site_label ? $site_label : $site_url,
            'origin_wp_admin_url'   => $origin_admin_url,
            'return_url'            => '' !== $return_url ? $return_url : $origin_admin_url,
            'requested_destination' => $destination,
            'intent'                => $intent,
            'plugin_version'        => defined( 'OPSGATE_PLUGIN_VERSION' ) ? OPSGATE_PLUGIN_VERSION : '',
            'current_mode'          => isset( $site_summary['connection_mode'] ) ? (string) $site_summary['connection_mode'] : '',
            'expires_in_seconds'    => 3600,
        );
        if ( '' !== $account_id ) {
            $payload['account_id'] = $account_id;
        }

        $resp = self::mcp_post_json( '/v1/onboarding/sessions', $payload );
        if ( empty( $resp['ok'] ) || ! isset( $resp['data']['session_token'], $resp['data']['onboarding_session_id'] ) ) {
            return '';
        }

        // Build the handoff URL locally so it always points to the correct web console
        // path (/console/connect) regardless of what OPSGATE_CENTRAL_BASE_URL is set to
        // on the API server. The API-returned central_handoff_url may point to an old
        // WP admin path if the server env var has not been updated.
        $console_base = self::remote_companion_console_base_url();
        if ( '' === $console_base ) {
            // Fall back to whatever the API returned if we cannot derive the console base.
            return isset( $resp['data']['central_handoff_url'] ) ? (string) $resp['data']['central_handoff_url'] : '';
        }

        $params = array(
            'opsgate_onboarding_session_id' => (string) $resp['data']['onboarding_session_id'],
            'opsgate_onboarding_token'      => (string) $resp['data']['session_token'],
            'opsgate_source'                => 'remote-companion',
        );
        if ( '' !== $site_url ) {
            $params['opsgate_scope_site_url'] = $site_url;
        }
        if ( '' !== $site_label ) {
            $params['opsgate_scope_site_label'] = $site_label;
        }

        return add_query_arg( $params, $console_base . '/console/connect' );
    }

    private static function remote_companion_console_base_url(): string {
        $configured = trim( (string) get_option( 'opsgate_console_base_url', '' ) );
        if ( '' !== $configured ) {
            return untrailingslashit( $configured );
        }

        $api_base = self::mcp_base_url();
        $scheme = (string) ( wp_parse_url( $api_base, PHP_URL_SCHEME ) ?: 'https' );
        $host   = (string) ( wp_parse_url( $api_base, PHP_URL_HOST ) ?: '' );
        if ( '' === $host ) {
            return '';
        }

        // Derive the web console host from the API host.
        // api.example.com → app.example.com  (web console lives at app.)
        // mcp.example.com → app.example.com  (legacy prefix — same derivation)
        // Anything else: return empty — cannot safely guess.
        if ( 0 === strpos( $host, 'api.' ) ) {
            $host = 'console.' . substr( $host, 4 );
        } elseif ( 0 === strpos( $host, 'mcp.' ) ) {
            $host = 'console.' . substr( $host, 4 );
        } else {
            return '';
        }

        return $scheme . '://' . $host;
    }

    private static function remote_companion_console_url( string $tab, array $scope = array(), array $site_summary = array(), array $args = array() ): string {
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : trim( (string) get_option( 'opsgate_account_id', '' ) );
        $site_id = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';
        $site_url = isset( $site_summary['site_url'] ) ? trim( (string) $site_summary['site_url'] ) : '';
        $site_label = isset( $site_summary['site_label'] ) ? trim( (string) $site_summary['site_label'] ) : '';
        $return_url = self::remote_companion_return_url( $site_url );

        // When running as the remote companion, create a canonical onboarding session
        // so central can resolve scope from DB truth rather than stale query params.
        if ( ! self::current_install_is_central_console() ) {
            $handoff_url = self::remote_companion_create_onboarding_session( $tab, $scope, $site_summary, $args );
            if ( '' !== $handoff_url ) {
                return $handoff_url;
            }
        }

        // Session creation failed — build a direct link to the web console connect page.
        // The console will handle auth and prompt the user to connect.
        $console_base = self::remote_companion_console_base_url();
        if ( '' === $console_base ) {
            return '';
        }

        $query = array_filter(
            array(
                'opsgate_source'           => 'remote-companion',
                'opsgate_scope_site_url'   => $site_url,
                'opsgate_scope_site_label' => $site_label,
            ),
            static function ( $value ): bool {
                return null !== $value && '' !== $value;
            }
        );

        return add_query_arg( $query, $console_base . '/console/connect' );
    }

    private static function remote_companion_return_url( string $site_url = '' ): string {
        $site_url = trim( $site_url );
        if ( '' === $site_url ) {
            $site_url = trim( (string) home_url() );
        }
        if ( '' === $site_url ) {
            return '';
        }

        return add_query_arg(
            array(
                'page' => 'opsgate',
            ),
            untrailingslashit( $site_url ) . '/wp-admin/admin.php'
        );
    }

    private static function remote_companion_console_target_url( string $target, array $scope = array(), array $site_summary = array(), array $args = array() ): string {
        $target = strtolower( trim( $target ) );
        $site_connection_mode = isset( $site_summary['connection_mode'] ) ? strtolower( trim( (string) $site_summary['connection_mode'] ) ) : 'public_scan';
        if ( ! in_array( $site_connection_mode, array( 'public_scan', 'wp_connector' ), true ) ) {
            $site_connection_mode = 'public_scan';
        }

        if ( 'summary' === $target || 'public_summary' === $target ) {
            return self::remote_companion_console_url(
                'overview',
                $scope,
                $site_summary,
                array_merge(
                    array(
                        'opsgate_requested_connection_mode' => 'public_summary' === $target ? 'public_scan' : $site_connection_mode,
                        'opsgate_intended_action' => 'open_summary',
                    ),
                    $args
                )
            );
        }
        if ( in_array( $target, array( 'reports', 'alerts', 'activity', 'billing', 'clients' ), true ) ) {
            return self::remote_companion_console_url(
                $target,
                $scope,
                $site_summary,
                array_merge(
                    array(
                        'opsgate_requested_connection_mode' => 'billing' === $target ? 'public_scan' : $site_connection_mode,
                        'opsgate_intended_action' => 'open_' . $target,
                    ),
                    $args
                )
            );
        }
        if ( 'site_config' === $target ) {
            $settings_url = self::remote_companion_console_url(
                'settings',
                $scope,
                $site_summary,
                array_merge(
                    array(
                        'section'        => 'site-configuration',
                        'panel'          => 'pairing-material',
                        'opsgate_source' => 'remote-onboarding',
                        'opsgate_requested_section' => 'site-configuration',
                        'opsgate_requested_panel' => 'pairing-material',
                        'opsgate_requested_connection_mode' => 'wp_connector',
                        'opsgate_intended_action' => 'get_pairing',
                    ),
                    $args
                )
            );

            return $settings_url . '#opsgate-site-configuration-section';
        }

        return self::remote_companion_console_url( 'overview', $scope, $site_summary, $args );
    }

    /**
     * @return array{has_explicit_scope:bool,account_id:string,site_id:string,site_url:string,site_label:string,source_job_id:string,requested_tab:string,requested_section:string,requested_panel:string,return_url:string,requested_connection_mode:string,intended_action:string}
     */
    private static function requested_site_scope_from_query(): array {
        if ( function_exists( 'current_user_can' ) && ! current_user_can( 'manage_options' ) ) {
            return array(
                'has_explicit_scope' => false,
                'account_id'         => '',
                'site_id'            => '',
                'site_url'           => '',
                'site_label'         => '',
                'source_job_id'      => '',
                'requested_tab'      => '',
                'requested_section'  => '',
                'requested_panel'    => '',
                'return_url'         => '',
                'requested_connection_mode' => '',
                'intended_action'    => '',
            );
        }

        $page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : '';
        if ( 'opsgate' !== $page ) {
            return array(
                'has_explicit_scope' => false,
                'account_id'         => '',
                'site_id'            => '',
                'site_url'           => '',
                'site_label'         => '',
                'source_job_id'      => '',
                'requested_tab'      => '',
                'requested_section'  => '',
                'requested_panel'    => '',
                'return_url'         => '',
                'requested_connection_mode' => '',
                'intended_action'    => '',
            );
        }

        $site_id = isset( $_GET['opsgate_scope_site_id'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_scope_site_id'] ) ) : '';
        $site_url = isset( $_GET['opsgate_scope_site_url'] ) ? self::normalize_requested_site_scope_url( (string) wp_unslash( $_GET['opsgate_scope_site_url'] ) ) : '';
        $prefill_site_url = isset( $_GET['opsgate_prefill_site_url'] ) ? self::normalize_requested_site_scope_url( (string) wp_unslash( $_GET['opsgate_prefill_site_url'] ) ) : '';
        $prefill_site_label = isset( $_GET['opsgate_prefill_site_label'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_prefill_site_label'] ) ) : '';

        if ( '' === $site_url ) {
            $site_url = $prefill_site_url;
        }

        $site_label = isset( $_GET['opsgate_scope_site_label'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_scope_site_label'] ) ) : '';
        if ( '' === $site_label ) {
            $site_label = $prefill_site_label;
        }

        return array(
            'has_explicit_scope' => '' !== $site_id || '' !== $site_url,
            'account_id'         => isset( $_GET['opsgate_scope_account'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_scope_account'] ) ) : '',
            'site_id'            => $site_id,
            'site_url'           => $site_url,
            'site_label'         => $site_label,
            'source_job_id'      => isset( $_GET['opsgate_source_job_id'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_source_job_id'] ) ) : '',
            'requested_tab'      => isset( $_GET['opsgate_requested_tab'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_requested_tab'] ) ) : ( isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : 'overview' ),
            'requested_section'  => isset( $_GET['opsgate_requested_section'] ) ? sanitize_key( wp_unslash( $_GET['opsgate_requested_section'] ) ) : ( isset( $_GET['section'] ) ? sanitize_key( wp_unslash( $_GET['section'] ) ) : '' ),
            'requested_panel'    => isset( $_GET['opsgate_requested_panel'] ) ? sanitize_key( wp_unslash( $_GET['opsgate_requested_panel'] ) ) : ( isset( $_GET['panel'] ) ? sanitize_key( wp_unslash( $_GET['panel'] ) ) : '' ),
            'return_url'         => isset( $_GET['opsgate_return_url'] ) ? esc_url_raw( wp_unslash( $_GET['opsgate_return_url'] ) ) : '',
            'requested_connection_mode' => isset( $_GET['opsgate_requested_connection_mode'] ) ? sanitize_key( wp_unslash( $_GET['opsgate_requested_connection_mode'] ) ) : '',
            'intended_action'    => isset( $_GET['opsgate_intended_action'] ) ? sanitize_key( wp_unslash( $_GET['opsgate_intended_action'] ) ) : '',
        );
    }

    /**
     * @param array<string,mixed> $requested_scope
     */
    private static function requested_scope_targets_site_setup( array $requested_scope ): bool {
        $requested_tab = self::normalize_admin_tab_request( isset( $requested_scope['requested_tab'] ) ? (string) $requested_scope['requested_tab'] : '' );
        $requested_section = sanitize_key( isset( $requested_scope['requested_section'] ) ? (string) $requested_scope['requested_section'] : '' );
        $requested_panel = sanitize_key( isset( $requested_scope['requested_panel'] ) ? (string) $requested_scope['requested_panel'] : '' );
        $requested_connection_mode = sanitize_key( isset( $requested_scope['requested_connection_mode'] ) ? (string) $requested_scope['requested_connection_mode'] : '' );
        $intended_action = sanitize_key( isset( $requested_scope['intended_action'] ) ? (string) $requested_scope['intended_action'] : '' );
        $reason_code = sanitize_key( isset( $requested_scope['reason_code'] ) ? (string) $requested_scope['reason_code'] : '' );

        if ( 'settings' !== $requested_tab || 'site-configuration' !== $requested_section ) {
            return false;
        }

        if ( in_array( $reason_code, array( 'requested_account_not_attached', 'missing_active_account' ), true ) ) {
            return false;
        }

        if ( in_array( $intended_action, array( 'start_setup', 'get_pairing', 'connect_paid' ), true ) ) {
            return true;
        }

        if ( 'pairing-material' === $requested_panel && 'wp_connector' === $requested_connection_mode ) {
            return true;
        }

        return false;
    }

    private static function normalize_requested_site_scope_url( string $site_url ): string {
        $site_url = trim( $site_url );
        if ( '' === $site_url ) {
            return '';
        }

        $normalized = esc_url_raw( $site_url );
        if ( '' === $normalized ) {
            return '';
        }

        $parts = wp_parse_url( $normalized );
        if ( ! is_array( $parts ) || empty( $parts['host'] ) ) {
            return '';
        }

        $scheme = isset( $parts['scheme'] ) ? strtolower( (string) $parts['scheme'] ) : 'https';
        $host   = strtolower( (string) $parts['host'] );
        $path   = isset( $parts['path'] ) ? (string) $parts['path'] : '';
        $query  = isset( $parts['query'] ) ? (string) $parts['query'] : '';

        $rebuilt = $scheme . '://' . $host;
        if ( '' !== $path ) {
            $rebuilt .= $path;
        }
        if ( '' !== $query ) {
            $rebuilt .= '?' . $query;
        }

        return untrailingslashit( $rebuilt );
    }

    private static function scoped_site_authority_error_message( array $requested_scope, string $fallback = '' ): string {
        $fallback = trim( $fallback );
        if ( '' === $fallback ) {
            $fallback = 'OpsGate could not resolve the requested site scope for this account.';
        }

        $requested_site_id  = isset( $requested_scope['site_id'] ) ? trim( (string) $requested_scope['site_id'] ) : '';
        $requested_site_url = isset( $requested_scope['site_url'] ) ? trim( (string) $requested_scope['site_url'] ) : '';
        $requested_account  = isset( $requested_scope['account_id'] ) ? trim( (string) $requested_scope['account_id'] ) : '';
        $requested_ref      = '' !== $requested_site_id ? 'Site ID ' . $requested_site_id : ( '' !== $requested_site_url ? 'Site URL ' . $requested_site_url : 'the requested site' );

        $message = $fallback;
        if ( '' !== $requested_account ) {
            $message .= ' Requested account ' . $requested_account . '.';
        } else {
            $message .= '';
        }
        if ( '.' !== substr( $message, -1 ) ) {
            $message .= '.';
        }

        return trim( $message . ' Requested scope ' . $requested_ref . ' was not authorized. OpsGate did not fall back to another site.' );
    }

    private static function scoped_site_reason_code( string $error, string $fallback_reason ): string {
        $fallback_reason = sanitize_key( $fallback_reason );
        if ( '' !== $fallback_reason ) {
            return $fallback_reason;
        }

        $error = strtolower( trim( $error ) );
        if ( false !== strpos( $error, 'account' ) ) {
            return 'requested_account_not_attached';
        }
        if ( false !== strpos( $error, 'not authorized' ) || false !== strpos( $error, 'not found' ) ) {
            return 'requested_site_not_attached';
        }

        return 'site_scope_unavailable';
    }

    /**
     * @return array{has_explicit_scope:bool,ok:bool,account_id:string,requested_account_id:string,site_id:string,site_url:string,site_label:string,resolution_kind:string,source_job_id:string,requested_tab:string,requested_section:string,requested_panel:string,return_url:string,requested_connection_mode:string,intended_action:string,error:string,reason_code:string}
     */
    private static function resolve_requested_site_scope_from_query(): array {
        static $cache = null;

        if ( is_array( $cache ) ) {
            return $cache;
        }

        // Canonical onboarding session path: remote plugin stamped a DB session token.
        // Resolve via API instead of trusting stale query params.
        $onboarding_session_id = isset( $_GET['opsgate_onboarding_session_id'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_onboarding_session_id'] ) ) : '';
        $onboarding_token = isset( $_GET['opsgate_onboarding_token'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_onboarding_token'] ) ) : '';
        if ( '' !== $onboarding_session_id && '' !== $onboarding_token ) {
            $stored_account_id = trim( (string) get_option( 'opsgate_account_id', '' ) );
            // If central has no stored account yet, fall back to the requesting account from the URL.
            if ( '' === $stored_account_id ) {
                $stored_account_id = isset( $_GET['opsgate_scope_account'] ) ? trim( sanitize_text_field( wp_unslash( $_GET['opsgate_scope_account'] ) ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
            }
            if ( '' !== $stored_account_id ) {
                $resolve_resp = self::mcp_post_json(
                    '/v1/onboarding/sessions/resolve',
                    array(
                        'account_id'    => $stored_account_id,
                        'session_token' => $onboarding_token,
                    )
                );
                if ( ! empty( $resolve_resp['ok'] ) && isset( $resolve_resp['data']['session'] ) ) {
                    $session = $resolve_resp['data']['session'];
                    $resolved_site_id = isset( $session['resolved_site_id'] ) ? trim( (string) $session['resolved_site_id'] ) : '';
                    $resolved_site = isset( $resolve_resp['data']['site'] ) && is_array( $resolve_resp['data']['site'] ) ? $resolve_resp['data']['site'] : array();
                    $site_url = isset( $resolved_site['site_url'] ) ? trim( (string) $resolved_site['site_url'] ) : trim( (string) $session['requested_site_url'] );
                    $site_label = isset( $resolved_site['site_label'] ) ? trim( (string) $resolved_site['site_label'] ) : trim( (string) $session['requested_site_label'] );
                    // Prefer the explicit return_url (added in migration 0039); fall back to origin_wp_admin_url.
                    $return_url = '' !== trim( (string) ( $session['return_url'] ?? '' ) ) ? trim( (string) $session['return_url'] ) : trim( (string) $session['origin_wp_admin_url'] );
                    $requested_dest = trim( (string) $session['requested_destination'] );
                    $dest_tab_map = array(
                        'overview'        => 'overview',
                        'reports'         => 'reports',
                        'alerts'          => 'alerts',
                        'activity'        => 'activity',
                        'billing'         => 'billing',
                        'settings'        => 'settings',
                        'pairing-material'=> 'settings',
                    );
                    $tab = isset( $dest_tab_map[ $requested_dest ] ) ? $dest_tab_map[ $requested_dest ] : 'overview';
                    $section = 'pairing-material' === $requested_dest ? 'site-configuration' : '';
                    $panel = 'pairing-material' === $requested_dest ? 'pairing-material' : '';
                    if ( '' !== $resolved_site_id ) {
                        self::sync_active_site_scope_options( array(
                            'site_id'    => $resolved_site_id,
                            'site_url'   => $site_url,
                            'site_label' => $site_label,
                        ) );
                    }
                    $cache = array(
                        'has_explicit_scope'        => true,
                        'ok'                        => '' !== $resolved_site_id,
                        'account_id'                => $stored_account_id,
                        'requested_account_id'      => $stored_account_id,
                        'site_id'                   => $resolved_site_id,
                        'site_url'                  => $site_url,
                        'site_label'                => $site_label,
                        'resolution_kind'           => 'onboarding_session',
                        'source_job_id'             => '',
                        'requested_tab'             => $tab,
                        'requested_section'         => $section,
                        'requested_panel'           => $panel,
                        'return_url'                => $return_url,
                        'requested_connection_mode' => '',
                        'intended_action'           => trim( (string) $session['intent'] ),
                        'error'                     => '' === $resolved_site_id ? 'OpsGate could not resolve the site for this onboarding session.' : '',
                        'reason_code'               => '' === $resolved_site_id ? 'site_scope_unavailable' : '',
                        'onboarding_session_id'     => $onboarding_session_id,
                        'onboarding_token'          => $onboarding_token,
                    );
                    return $cache;
                }
                // Resolve failed (API error, expired session, account mismatch, etc.).
                // Build an explicit error scope so the handoff notice "Start setup" link
                // carries the session params and can retry the claim on next load.
                $fb_site_url = isset( $_GET['opsgate_scope_site_url'] ) ? esc_url_raw( wp_unslash( $_GET['opsgate_scope_site_url'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
                $fb_site_label = isset( $_GET['opsgate_scope_site_label'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_scope_site_label'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
                $fb_return_url = isset( $_GET['opsgate_return_url'] ) ? esc_url_raw( wp_unslash( $_GET['opsgate_return_url'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
                $fb_dest = isset( $_GET['opsgate_requested_tab'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_requested_tab'] ) ) : 'settings'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
                $fb_section = isset( $_GET['opsgate_requested_section'] ) ? sanitize_key( wp_unslash( $_GET['opsgate_requested_section'] ) ) : 'site-configuration'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
                $fb_panel = isset( $_GET['opsgate_requested_panel'] ) ? sanitize_key( wp_unslash( $_GET['opsgate_requested_panel'] ) ) : 'pairing-material'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
                $api_error = isset( $resolve_resp['error'] ) ? trim( (string) $resolve_resp['error'] ) : 'OpsGate could not resolve the onboarding session.';
                $reason = in_array( $api_error, array( 'onboarding_session_expired', 'onboarding_session_cancelled' ), true ) ? $api_error : 'site_scope_unavailable';
                // When the resolve failed because the Starter plan site limit was reached,
                // redirect back to the remote plugin immediately — do not strand the user
                // on central showing a stale site. Derive the return URL from the site URL
                // when opsgate_return_url is absent from the handoff URL (current API behaviour).
                $limit_in_obs_error = false !== stripos( $api_error, 'site_limit_reached' )
                    || false !== stripos( $api_error, 'limit_reached' );
                if ( $limit_in_obs_error ) {
                    $obs_return_url = $fb_return_url;
                    if ( '' === $obs_return_url && '' !== $fb_site_url ) {
                        $obs_return_url = self::remote_companion_return_url( $fb_site_url );
                    }
                    if ( '' !== $obs_return_url ) {
                        $limit_label = '' !== $fb_site_label ? $fb_site_label : $fb_site_url;
                        $limit_msg   = 'Your current plan supports 1 connected site. To connect ' . ( '' !== $limit_label ? $limit_label : 'this site' ) . ', upgrade your plan or disconnect the existing site from OpsGate Settings.';
                        wp_safe_redirect( add_query_arg(
                            array(
                                'opsgate_pairing_error' => rawurlencode( $limit_msg ),
                                'opsgate_pairing_open'  => '1',
                            ),
                            $obs_return_url
                        ) );
                        exit;
                    }
                }
                $cache = array(
                    'has_explicit_scope'        => true,
                    'ok'                        => false,
                    'account_id'                => $stored_account_id,
                    'requested_account_id'      => $stored_account_id,
                    'site_id'                   => '',
                    'site_url'                  => $fb_site_url,
                    'site_label'                => $fb_site_label,
                    'resolution_kind'           => 'onboarding_session',
                    'source_job_id'             => '',
                    'requested_tab'             => $fb_dest,
                    'requested_section'         => $fb_section,
                    'requested_panel'           => $fb_panel,
                    'return_url'                => $fb_return_url,
                    'requested_connection_mode' => '',
                    'intended_action'           => 'setup',
                    'error'                     => $api_error,
                    'reason_code'               => $reason,
                    'onboarding_session_id'     => $onboarding_session_id,
                    'onboarding_token'          => $onboarding_token,
                );
                return $cache;
            }
            // No stored account yet — build a minimal explicit scope so the handoff notice
            // prompts the user to sign in, with the session params preserved for retry.
            $fb_site_url2 = isset( $_GET['opsgate_scope_site_url'] ) ? esc_url_raw( wp_unslash( $_GET['opsgate_scope_site_url'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
            $fb_site_label2 = isset( $_GET['opsgate_scope_site_label'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_scope_site_label'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
            $fb_return_url2 = isset( $_GET['opsgate_return_url'] ) ? esc_url_raw( wp_unslash( $_GET['opsgate_return_url'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
            $cache = array(
                'has_explicit_scope'        => true,
                'ok'                        => false,
                'account_id'                => '',
                'requested_account_id'      => '',
                'site_id'                   => '',
                'site_url'                  => $fb_site_url2,
                'site_label'                => $fb_site_label2,
                'resolution_kind'           => 'onboarding_session',
                'source_job_id'             => '',
                'requested_tab'             => 'settings',
                'requested_section'         => 'site-configuration',
                'requested_panel'           => 'pairing-material',
                'return_url'                => $fb_return_url2,
                'requested_connection_mode' => '',
                'intended_action'           => 'setup',
                'error'                     => 'OpsGate has no active account — sign in first.',
                'reason_code'               => 'missing_active_account',
                'onboarding_session_id'     => $onboarding_session_id,
                'onboarding_token'          => $onboarding_token,
            );
            return $cache;
        }

        $requested_scope = self::requested_site_scope_from_query();
        $requested_tab = isset( $requested_scope['requested_tab'] ) ? trim( (string) $requested_scope['requested_tab'] ) : 'overview';
        $requested_section = isset( $requested_scope['requested_section'] ) ? trim( (string) $requested_scope['requested_section'] ) : '';
        $requested_panel = isset( $requested_scope['requested_panel'] ) ? trim( (string) $requested_scope['requested_panel'] ) : '';
        $return_url = isset( $requested_scope['return_url'] ) ? trim( (string) $requested_scope['return_url'] ) : '';
        $requested_connection_mode = isset( $requested_scope['requested_connection_mode'] ) ? trim( (string) $requested_scope['requested_connection_mode'] ) : '';
        $intended_action = isset( $requested_scope['intended_action'] ) ? trim( (string) $requested_scope['intended_action'] ) : '';
        if ( empty( $requested_scope['has_explicit_scope'] ) ) {
            $cache = array(
                'has_explicit_scope' => false,
                'ok'                 => true,
                'account_id'         => '',
                'requested_account_id' => '',
                'site_id'            => '',
                'site_url'           => '',
                'site_label'         => '',
                'resolution_kind'    => '',
                'source_job_id'      => '',
                'requested_tab'      => $requested_tab,
                'requested_section'  => $requested_section,
                'requested_panel'    => $requested_panel,
                'return_url'         => $return_url,
                'requested_connection_mode' => $requested_connection_mode,
                'intended_action'    => $intended_action,
                'error'              => '',
                'reason_code'        => '',
            );
            return $cache;
        }

        $stored_account_id = trim( (string) get_option( 'opsgate_account_id', '' ) );
        if ( '' === $stored_account_id ) {
            $cache = array(
                'has_explicit_scope' => true,
                'ok'                 => false,
                'account_id'         => '',
                'requested_account_id' => trim( (string) $requested_scope['account_id'] ),
                'site_id'            => trim( (string) $requested_scope['site_id'] ),
                'site_url'           => trim( (string) $requested_scope['site_url'] ),
                'site_label'         => trim( (string) $requested_scope['site_label'] ),
                'resolution_kind'    => '',
                'source_job_id'      => (string) $requested_scope['source_job_id'],
                'requested_tab'      => $requested_tab,
                'requested_section'  => $requested_section,
                'requested_panel'    => $requested_panel,
                'return_url'         => $return_url,
                'requested_connection_mode' => $requested_connection_mode,
                'intended_action'    => $intended_action,
                'error'              => self::scoped_site_authority_error_message( $requested_scope, 'OpsGate has no active account scope for this request' ),
                'reason_code'        => 'missing_active_account',
            );
            return $cache;
        }

        $requested_account_id = trim( (string) $requested_scope['account_id'] );
        if ( '' !== $requested_account_id && $requested_account_id !== $stored_account_id ) {
            $cache = array(
                'has_explicit_scope' => true,
                'ok'                 => false,
                'account_id'         => $stored_account_id,
                'requested_account_id' => $requested_account_id,
                'site_id'            => trim( (string) $requested_scope['site_id'] ),
                'site_url'           => trim( (string) $requested_scope['site_url'] ),
                'site_label'         => trim( (string) $requested_scope['site_label'] ),
                'resolution_kind'    => '',
                'source_job_id'      => (string) $requested_scope['source_job_id'],
                'requested_tab'      => $requested_tab,
                'requested_section'  => $requested_section,
                'requested_panel'    => $requested_panel,
                'return_url'         => $return_url,
                'requested_connection_mode' => $requested_connection_mode,
                'intended_action'    => $intended_action,
                'error'              => self::scoped_site_authority_error_message( $requested_scope, 'OpsGate rejected the requested account scope for this request' ),
                'reason_code'        => 'requested_account_not_attached',
            );
            return $cache;
        }

        $resolve_body = array(
            'account_id' => $stored_account_id,
            'site_id'    => '' !== trim( (string) $requested_scope['site_id'] ) ? trim( (string) $requested_scope['site_id'] ) : null,
            'site_url'   => '' !== trim( (string) $requested_scope['site_url'] ) ? trim( (string) $requested_scope['site_url'] ) : null,
            'site_label' => '' !== trim( (string) $requested_scope['site_label'] ) ? trim( (string) $requested_scope['site_label'] ) : null,
        );

        $resp = self::mcp_post_json( '/v1/sites/resolve', $resolve_body );
        if ( empty( $resp['ok'] ) ) {
            $cache = array(
                'has_explicit_scope' => true,
                'ok'                 => false,
                'account_id'         => $stored_account_id,
                'requested_account_id' => $requested_account_id,
                'site_id'            => trim( (string) $requested_scope['site_id'] ),
                'site_url'           => trim( (string) $requested_scope['site_url'] ),
                'site_label'         => trim( (string) $requested_scope['site_label'] ),
                'resolution_kind'    => '',
                'source_job_id'      => (string) $requested_scope['source_job_id'],
                'requested_tab'      => $requested_tab,
                'requested_section'  => $requested_section,
                'requested_panel'    => $requested_panel,
                'return_url'         => $return_url,
                'requested_connection_mode' => $requested_connection_mode,
                'intended_action'    => $intended_action,
                'error'              => self::scoped_site_authority_error_message(
                    $requested_scope,
                    isset( $resp['error'] ) ? (string) $resp['error'] : 'OpsGate could not resolve the requested site scope for this account'
                ),
                'reason_code'        => self::scoped_site_reason_code(
                    isset( $resp['error'] ) ? (string) $resp['error'] : '',
                    isset( $resp['error'] ) && false !== strpos( strtolower( (string) $resp['error'] ), 'account' ) ? 'requested_account_not_attached' : 'requested_site_not_attached'
                ),
            );
            return $cache;
        }

        $resolved_scope = isset( $resp['data'] ) && is_array( $resp['data'] ) ? $resp['data'] : array();
        $resolved_site_id = isset( $resolved_scope['site_id'] ) ? trim( (string) $resolved_scope['site_id'] ) : '';
        if ( '' === $resolved_site_id ) {
            $cache = array(
                'has_explicit_scope' => true,
                'ok'                 => false,
                'account_id'         => $stored_account_id,
                'requested_account_id' => $requested_account_id,
                'site_id'            => trim( (string) $requested_scope['site_id'] ),
                'site_url'           => trim( (string) $requested_scope['site_url'] ),
                'site_label'         => trim( (string) $requested_scope['site_label'] ),
                'resolution_kind'    => '',
                'source_job_id'      => (string) $requested_scope['source_job_id'],
                'requested_tab'      => $requested_tab,
                'requested_section'  => $requested_section,
                'requested_panel'    => $requested_panel,
                'return_url'         => $return_url,
                'requested_connection_mode' => $requested_connection_mode,
                'intended_action'    => $intended_action,
                'error'              => self::scoped_site_authority_error_message( $requested_scope, 'OpsGate resolved the request without a canonical site identifier' ),
                'reason_code'        => 'site_scope_unavailable',
            );
            return $cache;
        }

        self::sync_active_site_scope_options( $resolved_scope );

        $runtime_scope = array(
            'account_id' => $stored_account_id,
            'site_id'    => $resolved_site_id,
        );
        $source_job_id = trim( (string) $requested_scope['source_job_id'] );
        if ( '' !== $source_job_id ) {
            self::update_scope_runtime_refs(
                $runtime_scope,
                array(
                    'last_triage_job_id' => $source_job_id,
                )
            );
        } else {
            self::sync_scope_runtime_refs_for_scope( $runtime_scope );
        }

        $cache = array(
            'has_explicit_scope' => true,
            'ok'                 => true,
            'account_id'         => $stored_account_id,
            'requested_account_id' => $requested_account_id,
            'site_id'            => $resolved_site_id,
            'site_url'           => isset( $resolved_scope['site_url'] ) ? trim( (string) $resolved_scope['site_url'] ) : '',
            'site_label'         => isset( $resolved_scope['site_label'] ) ? trim( (string) $resolved_scope['site_label'] ) : '',
            'resolution_kind'    => isset( $resolved_scope['resolution_kind'] ) ? trim( (string) $resolved_scope['resolution_kind'] ) : '',
            'source_job_id'      => $source_job_id,
            'requested_tab'      => $requested_tab,
            'requested_section'  => $requested_section,
            'requested_panel'    => $requested_panel,
            'return_url'         => $return_url,
            'requested_connection_mode' => $requested_connection_mode,
            'intended_action'    => $intended_action,
            'error'              => '',
            'reason_code'        => '',
        );

        return $cache;
    }

    private static function current_request_scope_query_args(): array {
        $resolved_scope = self::resolve_requested_site_scope_from_query();
        if ( empty( $resolved_scope['has_explicit_scope'] ) || empty( $resolved_scope['ok'] ) ) {
            return array();
        }

        return array_filter(
            array(
                'opsgate_scope_account'    => $resolved_scope['account_id'],
                'opsgate_scope_site_id'    => $resolved_scope['site_id'],
                'opsgate_scope_site_url'   => $resolved_scope['site_url'],
                'opsgate_scope_site_label' => $resolved_scope['site_label'],
                'opsgate_requested_tab'    => $resolved_scope['requested_tab'],
                'opsgate_requested_section' => $resolved_scope['requested_section'],
                'opsgate_requested_panel'  => $resolved_scope['requested_panel'],
                'opsgate_return_url'       => $resolved_scope['return_url'],
                'opsgate_requested_connection_mode' => $resolved_scope['requested_connection_mode'],
                'opsgate_intended_action'  => $resolved_scope['intended_action'],
            ),
            static function ( $value ): bool {
                return null !== $value && '' !== $value;
            }
        );
    }

    private static function raw_requested_handoff_query_args(): array {
        $requested_scope = self::requested_site_scope_from_query();
        if ( empty( $requested_scope['has_explicit_scope'] ) ) {
            return array();
        }

        return array_filter(
            array(
                'opsgate_scope_account'    => $requested_scope['account_id'],
                'opsgate_scope_site_id'    => $requested_scope['site_id'],
                'opsgate_scope_site_url'   => $requested_scope['site_url'],
                'opsgate_scope_site_label' => $requested_scope['site_label'],
                'opsgate_source_job_id'    => $requested_scope['source_job_id'],
                'opsgate_requested_tab'    => $requested_scope['requested_tab'],
                'opsgate_requested_section' => $requested_scope['requested_section'],
                'opsgate_requested_panel'  => $requested_scope['requested_panel'],
                'opsgate_return_url'       => $requested_scope['return_url'],
                'opsgate_requested_connection_mode' => $requested_scope['requested_connection_mode'],
                'opsgate_intended_action'  => $requested_scope['intended_action'],
            ),
            static function ( $value ): bool {
                return null !== $value && '' !== $value;
            }
        );
    }

    private static function maybe_sync_requested_site_scope_from_query(): void {
        self::resolve_requested_site_scope_from_query();
    }

    /**
     * @param array<string,mixed> $contract
     * @return array{scope_label:string,site_label:string,site_url:string,mode_label:string,connection_copy:string}
     */
    private static function remote_companion_scope_summary( array $contract ): array {
        $site_label = trim( (string) ( $contract['site_label'] ?? '' ) );
        if ( '' === $site_label ) {
            $site_label = 'Current site';
        }

        $site_url = trim( (string) ( $contract['site_url'] ?? '' ) );
        $connection_state = strtolower( trim( (string) ( $contract['connection_state'] ?? 'external_only' ) ) );
        $connection_mode = strtolower( trim( (string) ( $contract['connection_mode'] ?? 'public_scan' ) ) );
        $mode_label = self::canonical_connection_mode_label( $connection_mode );
        $connection_copy = self::canonical_connection_status_copy( $connection_state, $connection_mode, true );
        $scope_label = 'Site scope pending';

        if ( 'connected' === $connection_state && 'wp_connector' === $connection_mode ) {
            $scope_label = 'Connected site scope';
        } elseif ( 'pairing_pending' === $connection_state ) {
            $scope_label = 'Pairing required scope';
        } elseif ( in_array( $connection_state, array( 'credential_invalid', 'disconnected' ), true ) ) {
            $scope_label = 'Reconnect site scope';
        } elseif ( 'public_scan' === $connection_mode || 'external_only' === $connection_state ) {
            $scope_label = 'Public site scope';
        }

        return array(
            'scope_label' => $scope_label,
            'site_label' => $site_label,
            'site_url' => $site_url,
            'mode_label' => $mode_label,
            'connection_copy' => $connection_copy,
        );
    }

    private static function remote_companion_breakdown_items( array $artifacts, array $score, bool $public_only ): array {
        $components = isset( $score['components'] ) && is_array( $score['components'] ) ? $score['components'] : array();
        $inventory = isset( $artifacts['inventory_snapshot']['body'] ) && is_array( $artifacts['inventory_snapshot']['body'] ) ? $artifacts['inventory_snapshot']['body'] : array();
        $updates = isset( $artifacts['update_posture']['body'] ) && is_array( $artifacts['update_posture']['body'] ) ? $artifacts['update_posture']['body'] : array();
        $vulnerabilities = isset( $artifacts['vulnerability_posture']['body'] ) && is_array( $artifacts['vulnerability_posture']['body'] ) ? $artifacts['vulnerability_posture']['body'] : array();
        $reachability = isset( $artifacts['reachability_posture']['body'] ) && is_array( $artifacts['reachability_posture']['body'] ) ? $artifacts['reachability_posture']['body'] : array();
        $performance = isset( $artifacts['performance_snapshot']['body'] ) && is_array( $artifacts['performance_snapshot']['body'] ) ? $artifacts['performance_snapshot']['body'] : array();
        $availability = isset( $artifacts['availability_snapshot']['body'] ) && is_array( $artifacts['availability_snapshot']['body'] ) ? $artifacts['availability_snapshot']['body'] : array();
        $validation = isset( $artifacts['configuration_validation']['body'] ) && is_array( $artifacts['configuration_validation']['body'] ) ? $artifacts['configuration_validation']['body'] : array();
        $logs = isset( $artifacts['operational_log_intelligence']['body'] ) && is_array( $artifacts['operational_log_intelligence']['body'] ) ? $artifacts['operational_log_intelligence']['body'] : array();
        $uptime = isset( $artifacts['uptime_window']['body'] ) && is_array( $artifacts['uptime_window']['body'] ) ? $artifacts['uptime_window']['body'] : array();

        if ( $public_only ) {
            $reachability_details = isset( $components['reachability']['details'] ) && is_array( $components['reachability']['details'] ) ? $components['reachability']['details'] : array();
            $ssl_details = isset( $components['ssl']['details'] ) && is_array( $components['ssl']['details'] ) ? $components['ssl']['details'] : array();
            $availability_details = isset( $components['availability']['details'] ) && is_array( $components['availability']['details'] ) ? $components['availability']['details'] : array();
            $performance_details = isset( $components['performance']['details'] ) && is_array( $components['performance']['details'] ) ? $components['performance']['details'] : array();

            return array(
                array(
                    'label' => 'Public Reachability',
                    'value' => 'reachable' === strtolower( (string) ( $reachability_details['posture'] ?? '' ) ) ? 'Reachable' : 'Checking',
                    'copy'  => 'Latest public HTTP reachability and transport check.',
                    'meta'  => isset( $reachability_details['duration_ms'] ) ? 'HTTP ' . (string) ( $reachability_details['http_status'] ?? '—' ) . ' in ' . (string) $reachability_details['duration_ms'] . ' ms' : 'Public reachability state is recorded with the latest check.',
                    'tone'  => 'reachable' === strtolower( (string) ( $reachability_details['posture'] ?? '' ) ) ? 'good' : 'neutral',
                ),
                array(
                    'label' => 'SSL / Transport',
                    'value' => ! empty( $ssl_details['handshake'] ) ? 'Healthy' : 'Review',
                    'copy'  => 'SSL and transport health from the latest public check.',
                    'meta'  => isset( $ssl_details['days_to_expiry'] ) ? (string) $ssl_details['days_to_expiry'] . ' days to certificate expiry' : 'Certificate expiry details were not recorded.',
                    'tone'  => ! empty( $ssl_details['handshake'] ) ? 'good' : 'warn',
                ),
                array(
                    'label' => 'Public Availability',
                    'value' => 'available' === strtolower( (string) ( $availability_details['posture'] ?? '' ) ) ? 'Available' : 'Checking',
                    'copy'  => 'Bounded public availability probes from the latest check.',
                    'meta'  => isset( $availability_details['successful_attempts'] ) ? (string) $availability_details['successful_attempts'] . ' of ' . (string) ( $availability_details['attempt_count'] ?? 0 ) . ' attempts succeeded' : 'Availability attempt detail was not recorded.',
                    'tone'  => 'available' === strtolower( (string) ( $availability_details['posture'] ?? '' ) ) ? 'good' : 'warn',
                ),
                array(
                    'label' => 'Public Performance',
                    'value' => 'good' === strtolower( (string) ( $performance_details['posture'] ?? '' ) ) ? 'Within target' : 'Review',
                    'copy'  => 'Public response timing from the latest probe.',
                    'meta'  => isset( $performance_details['first_byte_ms'] ) ? 'First byte ' . (string) $performance_details['first_byte_ms'] . ' ms · Total ' . (string) ( $performance_details['total_duration_ms'] ?? '—' ) . ' ms' : 'Performance timings were not recorded.',
                    'tone'  => 'good' === strtolower( (string) ( $performance_details['posture'] ?? '' ) ) ? 'good' : 'warn',
                ),
            );
        }

        $plugin_count = isset( $inventory['plugins']['count'] ) ? (int) $inventory['plugins']['count'] : 0;
        $theme_count = isset( $inventory['themes']['count'] ) ? (int) $inventory['themes']['count'] : 0;
        $runtime = isset( $inventory['runtime'] ) && is_array( $inventory['runtime'] ) ? $inventory['runtime'] : array();
        $update_summary = isset( $updates['summary'] ) && is_array( $updates['summary'] ) ? $updates['summary'] : array();
        $vulnerability_summary = isset( $vulnerabilities['summary'] ) && is_array( $vulnerability_summary = $vulnerabilities['summary'] ) ? $vulnerability_summary : array();
        $uptime_summary = isset( $uptime['summary'] ) && is_array( $uptime['summary'] ) ? $uptime['summary'] : array();
        $performance_summary = isset( $performance['summary'] ) && is_array( $performance['summary'] ) ? $performance['summary'] : array();
        $validation_summary = isset( $validation['summary'] ) && is_array( $validation['summary'] ) ? $validation['summary'] : array();
        $log_summary = isset( $logs['summary'] ) && is_array( $logs['summary'] ) ? $logs['summary'] : array();
        $outdated_total = isset( $update_summary['outdated_total'] ) ? (int) $update_summary['outdated_total'] : 0;
        $match_count = isset( $vulnerability_summary['match_count'] ) ? (int) $vulnerability_summary['match_count'] : 0;
        $finding_count = isset( $validation_summary['finding_count'] ) ? (int) $validation_summary['finding_count'] : 0;
        $log_signal_count = isset( $log_summary['signal_count'] ) ? (int) $log_summary['signal_count'] : 0;
        $uptime_percent = isset( $uptime_summary['uptime_percent'] ) ? (float) $uptime_summary['uptime_percent'] : 0.0;

        return array(
            array(
                'label' => 'Inventory',
                'value' => $plugin_count . ' plugins · ' . $theme_count . ' theme' . ( 1 === $theme_count ? '' : 's' ),
                'copy'  => 'Connected WordPress inventory and runtime snapshot from this site.',
                'meta'  => 'WordPress ' . (string) ( $inventory['wordpress']['core_version'] ?? '—' ) . ' · PHP ' . (string) ( $runtime['php_version'] ?? '—' ),
                'tone'  => $plugin_count > 0 || $theme_count > 0 ? 'good' : 'neutral',
            ),
            array(
                'label' => 'Updates',
                'value' => 0 === $outdated_total ? 'Current' : (string) $outdated_total . ' pending',
                'copy'  => 0 === $outdated_total ? 'No update drift was recorded in the latest run.' : 'Version drift was recorded in the latest connected run.',
                'meta'  => 'Core ' . ( ! empty( $update_summary['core_outdated'] ) ? 'outdated' : 'current' ) . ' · Plugins ' . (string) ( $update_summary['plugin_outdated_count'] ?? 0 ) . ' · Themes ' . (string) ( $update_summary['theme_outdated_count'] ?? 0 ),
                'tone'  => 0 === $outdated_total ? 'good' : 'warn',
            ),
            array(
                'label' => 'Vulnerabilities',
                'value' => 0 === $match_count ? 'No matches' : (string) $match_count . ' match' . ( 1 === $match_count ? '' : 'es' ),
                'copy'  => 0 === $match_count ? 'No known package matches were recorded for this run.' : 'Known package exposure was recorded in the latest connected run.',
                'meta'  => 'Checked plugins ' . (string) ( $vulnerability_summary['checked_plugin_count'] ?? 0 ) . ' · Critical ' . (string) ( $vulnerability_summary['critical_count'] ?? 0 ),
                'tone'  => 0 === $match_count ? 'good' : 'bad',
            ),
            array(
                'label' => 'Uptime / Reachability',
                'value' => $uptime_percent > 0 ? number_format_i18n( $uptime_percent, 0 ) . '% uptime' : ucfirst( strtolower( (string) ( $reachability['posture'] ?? 'pending' ) ) ),
                'copy'  => 'Public availability, recent uptime observations, and reachability are recorded together here.',
                'meta'  => ucfirst( strtolower( (string) ( $reachability['posture'] ?? 'Pending' ) ) ) . ' · ' . (string) ( $uptime_summary['history_label'] ?? 'Uptime history building' ),
                'tone'  => ! empty( $uptime_summary['failure_count'] ) ? 'warn' : 'good',
            ),
            array(
                'label' => 'Performance',
                'value' => isset( $performance_summary['total_duration_ms'] ) ? (string) $performance_summary['total_duration_ms'] . ' ms' : 'Pending',
                'copy'  => 'Response timing and first-byte performance from the latest site check.',
                'meta'  => 'HTTP ' . (string) ( $performance_summary['status_code'] ?? '—' ) . ' · First byte ' . (string) ( $performance_summary['first_byte_ms'] ?? '—' ) . ' ms',
                'tone'  => 'good' === strtolower( (string) ( $performance['posture'] ?? '' ) ) ? 'good' : 'warn',
            ),
            array(
                'label' => 'Validation / Logs',
                'value' => 0 === $finding_count && 0 === $log_signal_count ? 'Clean' : (string) ( $finding_count + $log_signal_count ) . ' item' . ( 1 === ( $finding_count + $log_signal_count ) ? '' : 's' ),
                'copy'  => 'Host validation and runtime log visibility stay compact here and open fully in OpsGate.',
                'meta'  => 'Validation findings ' . $finding_count . ' · Log signals ' . $log_signal_count,
                'tone'  => 0 === $finding_count && 0 === $log_signal_count ? 'neutral' : 'warn',
            ),
        );
    }

    /**
     * Build the backend-authoritative remote companion contract from canonical API readback.
     *
     * @return array<string,mixed>
     */
    private static function remote_companion_state_contract(): array {
        // Single canonical state read — same resolver used by central surface.
        $eff = self::resolve_effective_site_state();
        $plan = $eff['effective_plan'];
        $identity = self::get_identity_snapshot();
        $scope = self::get_mcp_scope_snapshot();
        $site_summary = $eff['site_summary'];
        $bundle = self::canonical_latest_triage_bundle();
        $job = isset( $bundle['job'] ) && is_array( $bundle['job'] ) ? $bundle['job'] : array();
        $artifacts = isset( $bundle['artifacts'] ) && is_array( $bundle['artifacts'] ) ? $bundle['artifacts'] : array();
        $score = isset( $artifacts['score_summary']['body'] ) && is_array( $artifacts['score_summary']['body'] ) ? $artifacts['score_summary']['body'] : array();
        $receipt = isset( $artifacts['json_receipt']['body'] ) && is_array( $artifacts['json_receipt']['body'] ) ? $artifacts['json_receipt']['body'] : array();
        $receipt_inputs = isset( $receipt['inputs'] ) && is_array( $receipt['inputs'] ) ? $receipt['inputs'] : array();
        $events = self::notification_events_list( 6 );
        $event_items = ! empty( $events['ok'] ) && isset( $events['items'] ) && is_array( $events['items'] ) ? self::live_items_only( $events['items'] ) : array();
        $alert_rollup = self::notification_delivery_rollup( $event_items );
        $activity_items = self::canonical_activity_feed( 4 );
        $reports_history = self::canonical_exports_history( 6 );
        $report_items = isset( $reports_history['items'] ) && is_array( $reports_history['items'] ) ? self::live_items_only( $reports_history['items'] ) : array();
        $triage_snapshot = self::triage_live_status_snapshot();
        $report_formats = self::remote_companion_report_formats();
        $package = self::current_package_entry();

        // Identity from effective state — consistent with central surface.
        $account_id = '' !== $eff['account_id'] ? $eff['account_id'] : ( isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '' );
        $site_id    = '' !== $eff['site_id']    ? $eff['site_id']    : ( isset( $scope['site_id']    ) ? trim( (string) $scope['site_id']    ) : '' );
        $site_label = $eff['site_label'];
        $site_url   = '' !== $eff['site_url'] ? $eff['site_url'] : ( isset( $site_summary['site_url'] ) ? trim( (string) $site_summary['site_url'] ) : trim( (string) ( $identity['site_url'] ?? '' ) ) );
        $install_is_central_console = self::current_install_is_central_console();
        $selected_scope_targets_local = self::scope_targets_local_wordpress( $site_url );
        $connector_credential_present = '' !== self::connector_site_credential();

        if ( ! $install_is_central_console && $selected_scope_targets_local && $connector_credential_present ) {
            $register = self::register_local_connector();
            if ( ! empty( $register['ok'] ) && isset( $register['data']['site'] ) && is_array( $register['data']['site'] ) ) {
                $registered_site = $register['data']['site'];
                if ( ! empty( $registered_site['account_id'] ) ) {
                    $account_id = trim( (string) $registered_site['account_id'] );
                    update_option( 'opsgate_account_id', $account_id, false );
                }
                if ( ! empty( $registered_site['site_id'] ) ) {
                    $site_id = trim( (string) $registered_site['site_id'] );
                    update_option( 'opsgate_site_id', $site_id, false );
                }
                if ( ! empty( $registered_site['site_label'] ) ) {
                    update_option( 'opsgate_site_label', trim( (string) $registered_site['site_label'] ), false );
                }
                if ( ! empty( $registered_site['site_url'] ) ) {
                    update_option( 'opsgate_site_url', trim( (string) $registered_site['site_url'] ), false );
                }
                self::sync_active_site_scope_options( $registered_site );
                $site_summary = array_merge( $site_summary, $registered_site );
                $site_label = isset( $site_summary['site_label'] ) ? trim( (string) $site_summary['site_label'] ) : $site_label;
                $site_url = isset( $site_summary['site_url'] ) ? trim( (string) $site_summary['site_url'] ) : $site_url;
            } elseif (
                empty( $register['ok'] )
                && isset( $register['error'] )
                && in_array( trim( (string) $register['error'] ), array( 'site_credential_invalid', 'Unauthorized' ), true )
            ) {
                // Central revoked the credential — clear local caches so the remote companion
                // shows clean onboarding state on the CURRENT request, not just the next one.
                // $eff was already captured from the stale cache above; reset it now so the
                // render path uses cleared state rather than the pre-revoke connected snapshot.
                self::clear_connector_site_credential();
                delete_option( 'opsgate_connector_connection_summary' );
                $connector_credential_present = false;
                $site_summary = array(
                    'site_label'        => $site_label,
                    'site_url'          => $site_url,
                    'connection_status' => 'external_only',
                    'connection_mode'   => 'public_scan',
                );
                $eff        = self::resolve_effective_site_state();
                $account_id = '' !== $eff['account_id'] ? $eff['account_id'] : '';
                $site_id    = '' !== $eff['site_id']    ? $eff['site_id']    : '';
            }
        }

        if ( ! $install_is_central_console && ! $selected_scope_targets_local ) {
            $account_id = '';
            $site_id = '';
            $site_label = trim( (string) ( $identity['site_label'] ?? '' ) );
            $site_url = trim( (string) ( $identity['site_url'] ?? '' ) );
            $site_summary = array(
                'site_label' => $site_label,
                'site_url' => $site_url,
                'connection_status' => 'external_only',
                'connection_mode' => 'public_scan',
            );
            $job = array();
            $artifacts = array();
            $score = array();
            $receipt = array();
            $receipt_inputs = array();
            $report_items = array();
            $activity_items = array();
            $event_items = array();
            $alert_rollup = array();
            $triage_snapshot = array();
        }
        if ( '' === $site_label ) {
            $site_label = 'Current site';
        }
        if ( '' === $site_url ) {
            $site_url = trim( (string) home_url() );
        }

        // Connection state from effective state resolver (same source as central surface).
        $connection_state = $eff['connection_status'];
        $connection_mode  = $eff['connection_mode'];
        $latest_run_mode = self::remote_companion_latest_run_mode( $job, $score, $receipt_inputs, $connection_mode );
        $latest_truth_is_public_only = self::remote_companion_bundle_is_public_only( $job, $artifacts ) || 'public_scan' === $latest_run_mode;
        $scope_ready = '' !== $account_id && '' !== $site_id;
        $is_connected = $eff['is_connected'];
        $matrix_case = self::remote_companion_matrix_case( $plan, $connection_state, $connection_mode, $scope_ready, $latest_truth_is_public_only );
        $variant = isset( $matrix_case['render_variant'] ) ? (string) $matrix_case['render_variant'] : 'onboarding_required';
        $onboarding_state = isset( $matrix_case['onboarding_state'] ) ? (string) $matrix_case['onboarding_state'] : 'ready';
        // If plan is still unknown but the site is in a free/public-only state, treat as free.
        if ( 'unknown' === $plan && in_array( $variant, array( 'free_public_companion', 'onboarding_required' ), true ) ) {
            $plan = 'free';
            update_option( 'opsgate_plan', 'free', false );
        }

        if ( 'free' === $plan && ! $latest_truth_is_public_only && ! $is_connected ) {
            $job = array();
            $artifacts = array();
            $score = array();
        }

        $public_only = ! empty( $matrix_case['public_only'] );
        $connected_site_awaiting_fresh_truth = $is_connected && ! $public_only && $latest_truth_is_public_only;
        $artifact_breakdown_allowed = ! empty( $artifacts ) && ! $connected_site_awaiting_fresh_truth;
        $breakdown_items = $artifact_breakdown_allowed ? self::remote_companion_breakdown_items( $artifacts, $score, $public_only ) : self::remote_companion_placeholder_breakdown_items(
            $variant,
            $plan,
            $connection_state,
            $connected_site_awaiting_fresh_truth
        );

        $report_actions = array();
        $job_id = isset( $job['job_id'] ) ? trim( (string) $job['job_id'] ) : '';
        $latest_outputs_by_kind = array(
            'PDF'  => '' !== $job_id ? self::canonical_latest_completed_export_for_source_kind( $job_id, 'report_pdf' ) : array(),
            'HTML' => '' !== $job_id ? self::canonical_latest_completed_export_for_source_kind( $job_id, 'report_html' ) : array(),
            'CSV'  => '' !== $job_id ? self::canonical_latest_completed_export_for_source_kind( $job_id, 'csv' ) : array(),
            'XLSX' => '' !== $job_id ? self::canonical_latest_completed_export_for_source_kind( $job_id, 'report_xlsx' ) : array(),
        );
        foreach ( $latest_outputs_by_kind as $output_label => $output_item ) {
            $output_kind = 'PDF' === $output_label ? 'report_pdf' : ( 'HTML' === $output_label ? 'report_html' : ( 'CSV' === $output_label ? 'csv' : 'report_xlsx' ) );
            $output_job_id = isset( $output_item['export_job_id'] ) ? trim( (string) $output_item['export_job_id'] ) : '';
            if ( ! in_array( $output_label, $report_formats['included'], true ) || '' === $output_job_id ) {
                continue;
            }
            $report_actions[] = array(
                'label' => in_array( $output_label, array( 'CSV', 'XLSX' ), true ) ? 'Download ' . $output_label : 'Open ' . $output_label,
                'url'   => wp_nonce_url(
                    admin_url(
                        'admin-post.php?action=opsgate_download_export&kind=' . rawurlencode( $output_kind ) . '&export_job_id=' . rawurlencode( $output_job_id ) . '&mode=' . rawurlencode( in_array( $output_kind, array( 'report_pdf', 'report_html' ), true ) ? 'view' : 'download' )
                    ),
                    'opsgate_download_export'
                ),
            );
        }

        $console_overview_url = self::remote_companion_console_target_url(
            'summary',
            $scope,
            $site_summary,
            '' !== $job_id ? array( 'opsgate_source_job_id' => $job_id ) : array()
        );
        $console_reports_url = self::remote_companion_console_target_url(
            'reports',
            $scope,
            $site_summary,
            '' !== $job_id ? array( 'source_job_id' => $job_id, 'opsgate_source_job_id' => $job_id ) : array()
        );
        $console_alerts_url = self::remote_companion_console_target_url( 'alerts', $scope, $site_summary );
        $console_activity_url = self::remote_companion_console_target_url( 'activity', $scope, $site_summary );
        $console_billing_url = self::remote_companion_console_target_url( 'billing', $scope, $site_summary );
        $console_clients_url = self::remote_companion_console_target_url( 'clients', $scope, $site_summary );
        $console_site_config_url = self::remote_companion_console_target_url( 'site_config', $scope, $site_summary );

        $allowed_actions = array();
        foreach ( isset( $matrix_case['allowed_actions'] ) && is_array( $matrix_case['allowed_actions'] ) ? $matrix_case['allowed_actions'] : array() as $action_key ) {
            $action_key = (string) $action_key;
            if ( 'run_public_check' === $action_key ) {
                $allowed_actions[] = array( 'key' => $action_key, 'label' => 'onboarding_required' === $variant ? 'Run Free Public Check' : 'Run Public Check', 'kind' => 'submit' );
            } elseif ( 'run_site_triage' === $action_key ) {
                $allowed_actions[] = array( 'key' => $action_key, 'label' => 'Run Security Scan', 'kind' => 'submit' );
            } elseif ( 'connect_with_code' === $action_key ) {
                $allowed_actions[] = array( 'key' => $action_key, 'label' => 'Connect with Pairing Code', 'kind' => 'modal' );
            } elseif ( 'connect_this_site' === $action_key ) {
                $allowed_actions[] = array( 'key' => $action_key, 'label' => 'Connect this site', 'kind' => 'link', 'url' => self::admin_tab_url( 'settings' ) );
            } elseif ( in_array( $action_key, array( 'reconnect_this_site', 'repair_connection' ), true ) ) {
                $allowed_actions[] = array( 'key' => $action_key, 'label' => 'Reconnect this site', 'kind' => 'link', 'url' => self::admin_tab_url( 'settings' ) );
            } else {
                $allowed_actions[] = array( 'key' => $action_key, 'label' => 'onboarding_required' === $variant ? 'Open OpsGate' : 'Open in OpsGate', 'kind' => 'link', 'url' => $console_overview_url );
            }
        }

        $latest_run = array(
            'id'           => $job_id,
            'status'       => isset( $job['state'] ) ? strtoupper( trim( (string) $job['state'] ) ) : '',
            'mode'         => $latest_run_mode,
            'score'        => isset( $score['score'] ) ? (string) $score['score'] : '',
            'risk_color'   => isset( $score['grade'] ) ? strtolower( trim( (string) $score['grade'] ) ) : '',
            'stage'        => ! empty( $triage_snapshot['progress_phase_label'] ) ? (string) $triage_snapshot['progress_phase_label'] : '',
            'started_at'   => isset( $job['started_at_utc'] ) ? (string) $job['started_at_utc'] : '',
            'completed_at' => isset( $job['finished_at_utc'] ) ? (string) $job['finished_at_utc'] : '',
            'updated_at'   => isset( $job['updated_at_utc'] ) ? (string) $job['updated_at_utc'] : '',
        );

        $credential_status = 'not_applicable';
        if ( 'connected_companion' === $variant ) {
            $credential_status = 'valid';
        } elseif ( 'credential_invalid' === $variant ) {
            $credential_status = 'invalid';
        } elseif ( 'disconnected' === $variant ) {
            $credential_status = 'pairing_pending' === $connection_state ? 'pairing_pending' : 'disconnected';
        }

        return array(
            'account_id'         => $account_id,
            'site_id'            => $site_id,
            'site_label'         => $site_label,
            'site_url'           => $site_url,
            'plan'               => $plan,
            'tier'               => $plan,
            'connection_state'   => $connection_state,
            'connection_mode'    => $connection_mode,
            'is_connected'       => $is_connected,
            'credential_status'  => isset( $matrix_case['credential_status'] ) ? (string) $matrix_case['credential_status'] : $credential_status,
            'onboarding_state'   => $onboarding_state,
            'latest_run'         => $latest_run,
            'score_breakdown'    => $breakdown_items,
            'allowed_actions'    => $allowed_actions,
            'report_actions'     => $report_actions,
            'alert_summary'      => array(
                'headline'  => isset( $alert_rollup['latest_status'] ) ? (string) $alert_rollup['latest_status'] : 'No alerts yet',
                'count'     => count( $event_items ),
                'reason'    => self::remote_companion_unavailable_reason( $variant, 'alerts' ),
                'cta_label' => 'Manage alerts',
            ),
            'activity_summary'   => array(
                'headline' => ! empty( $activity_items ) ? 'Latest site activity' : 'No recent activity yet',
                'count'    => count( $activity_items ),
                'items'    => array_slice( $activity_items, 0, 2 ),
            ),
            'central_links'      => array(
                'overview' => $console_overview_url,
                'reports'  => $console_reports_url,
                'alerts'   => $console_alerts_url,
                'activity' => $console_activity_url,
                'billing'  => $console_billing_url,
                'portfolio'=> $console_clients_url,
                'site_config' => $console_site_config_url,
            ),
            'support_diagnostics' => array(
                'connection_copy'           => self::canonical_connection_status_copy( $connection_state, $connection_mode, true ),
                'connector_version'         => isset( $site_summary['connector_version'] ) ? (string) $site_summary['connector_version'] : '',
                'last_connection_error'     => isset( $site_summary['last_connection_error'] ) ? (string) $site_summary['last_connection_error'] : '',
                'package_name'              => isset( $package['display_name'] ) ? (string) $package['display_name'] : ucfirst( $plan ),
                'report_formats'            => $report_formats,
                'report_history_count'      => count( $report_items ),
                'refresh_url'               => self::admin_tab_url( 'overview' ),
                'support_export_url'        => admin_url( 'admin-post.php?action=opsgate_export_logs' ),
                'connector_pairing_token'   => self::connector_pairing_token(),
                'connector_credential_set'  => '' !== self::connector_site_credential(),
            ),
            'render_variant'      => $variant,
            'progress'            => ! empty( $triage_snapshot['ok'] ) ? $triage_snapshot : array(),
            'primary_action_label'=> isset( $allowed_actions[0]['label'] ) ? (string) $allowed_actions[0]['label'] : '',
            'breakdown_title'     => isset( $matrix_case['breakdown_title'] ) ? (string) $matrix_case['breakdown_title'] : ( $public_only ? 'Public check breakdown' : 'Connected evidence breakdown' ),
            'breakdown_copy'      => isset( $matrix_case['breakdown_copy'] ) ? (string) $matrix_case['breakdown_copy'] : ( $public_only ? 'This score uses public evidence only.' : 'Connected evidence is active for this WordPress site.' ),
        );
    }

    /**
     * @return array<int,array<string,string>>
     */
    private static function remote_companion_placeholder_breakdown_items( string $variant, string $plan, string $connection_state, bool $awaiting_connected_run = false ): array {
        if ( 'free_public_companion' === $variant ) {
            return array(
                array( 'label' => 'Public Reachability', 'value' => 'Awaiting run', 'copy' => 'Latest public reachability state.', 'meta' => 'awaiting next public check', 'tone' => 'neutral' ),
                array( 'label' => 'SSL / Transport', 'value' => 'Awaiting run', 'copy' => 'Latest SSL and transport health.', 'meta' => 'awaiting next public check', 'tone' => 'neutral' ),
                array( 'label' => 'Public Availability', 'value' => 'Awaiting run', 'copy' => 'Public availability probes.', 'meta' => 'awaiting next public check', 'tone' => 'neutral' ),
                array( 'label' => 'Public Performance', 'value' => 'Awaiting run', 'copy' => 'Public timing snapshot.', 'meta' => 'awaiting next public check', 'tone' => 'neutral' ),
            );
        }

        $reason = self::remote_companion_unavailable_reason( $variant, 'connected_evidence', $plan, $connection_state, $awaiting_connected_run );
        $items = array(
            'Inventory',
            'Updates',
            'Vulnerabilities',
            'Uptime / Reachability',
            'Performance',
            'Validation / Logs',
        );
        if ( in_array( $plan, array( 'pro', 'agency' ), true ) ) {
            $items[] = 'Remediation eligibility';
        }

        $payload = array();
        foreach ( $items as $label ) {
            $payload[] = array(
                'label' => $label,
                'value' => 'Unavailable',
                'copy'  => 'Connected evidence summary for ' . $label . '.',
                'meta'  => $reason,
                'tone'  => 'neutral',
            );
        }

        return $payload;
    }

    private static function remote_companion_unavailable_reason( string $variant, string $surface, string $plan = '', string $connection_state = '', bool $awaiting_connected_run = false ): string {
        if ( 'credential_invalid' === $variant ) {
            return 'credential invalid';
        }
        if ( 'disconnected' === $variant ) {
            return 'pairing_pending' === $connection_state ? 'awaiting next connected run' : 'disconnected';
        }
        if ( 'onboarding_required' === $variant ) {
            return 'connect this site first';
        }
        if ( 'free_public_companion' === $variant && 'connected_evidence' === $surface ) {
            return 'not included on plan';
        }
        if ( 'free_public_companion' === $variant && 'alerts' === $surface ) {
            return 'not included on plan';
        }
        if ( $awaiting_connected_run ) {
            return 'awaiting next connected run';
        }

        return 'no evidence from latest run';
    }

    /**
     * @param array<string,mixed> $contract
     * @return array{title:string,headline:string,copy:string,button_label:string,button_url:string,button_kind:string}
     */
    private static function remote_companion_report_summary( array $contract ): array {
        $variant = self::remote_companion_variant_for_contract( $contract );
        $status = strtoupper( trim( (string) ( $contract['latest_run']['status'] ?? '' ) ) );
        $job_id = trim( (string) ( $contract['latest_run']['id'] ?? '' ) );
        $report_actions = isset( $contract['report_actions'] ) && is_array( $contract['report_actions'] ) ? $contract['report_actions'] : array();
        $overview_link = isset( $contract['central_links']['overview'] ) ? (string) $contract['central_links']['overview'] : '';
        $reports_link = isset( $contract['central_links']['reports'] ) ? (string) $contract['central_links']['reports'] : '';
        $completed = 'COMPLETED' === $status && '' !== $job_id;
        $running = in_array( $status, array( 'QUEUED', 'RUNNING' ), true );

        if ( 'free_public_companion' === $variant ) {
            if ( $completed ) {
                return array(
                    'title'       => 'Public summary',
                    'headline'    => 'Latest public check completed.',
                    'copy'        => 'Connected PDF, HTML, CSV, and XLSX reports unlock after connecting a paid plan.',
                    'button_label'=> 'View public summary →',
                    'button_url'  => $overview_link,
                    'button_kind' => 'link',
                );
            }

            return array(
                'title'       => 'Public summary',
                'headline'    => 'Run a public check to create your first summary.',
                'copy'        => 'Connected PDF, HTML, CSV, and XLSX reports unlock after connecting a paid plan.',
                'button_label'=> 'Run Free Public Check',
                'button_url'  => '',
                'button_kind' => 'submit',
            );
        }

        if ( ! empty( $report_actions ) ) {
            return array(
                'title'       => 'View reports',
                'headline'    => 'Reports ready',
                'copy'        => 'Open the latest completed report outputs for this site.',
                'button_label'=> 'Reports →',
                'button_url'  => $reports_link,
                'button_kind' => 'link',
            );
        }

        if ( $running ) {
            return array(
                'title'       => 'View reports',
                'headline'    => 'Reports pending',
                'copy'        => 'Reports will be available after this scan completes.',
                'button_label'=> 'Reports →',
                'button_url'  => $reports_link,
                'button_kind' => 'link',
            );
        }

        if ( $completed ) {
            return array(
                'title'       => 'View reports',
                'headline'    => 'Ready to generate',
                'copy'        => 'Open central reports for this site and generate outputs from the latest completed scan.',
                'button_label'=> 'Reports →',
                'button_url'  => $reports_link,
                'button_kind' => 'link',
            );
        }

        return array(
            'title'       => 'View reports',
            'headline'    => 'Run Site Triage to create the first report set.',
            'copy'        => 'Report outputs are created from the latest completed scan in OpsGate.',
            'button_label'=> 'Run Site Triage',
            'button_url'  => '',
            'button_kind' => 'none',
        );
    }

    /**
     * @param array<string,mixed> $contract
     * @return array{headline:string,copy:string,button_label:string,button_url:string}
     */
    private static function remote_companion_alert_summary_view( array $contract ): array {
        $variant = self::remote_companion_variant_for_contract( $contract );
        $alert_summary = isset( $contract['alert_summary'] ) && is_array( $contract['alert_summary'] ) ? $contract['alert_summary'] : array();
        $alerts_link = isset( $contract['central_links']['alerts'] ) ? (string) $contract['central_links']['alerts'] : '';
        $billing_link = isset( $contract['central_links']['billing'] ) ? (string) $contract['central_links']['billing'] : '';
        $count = isset( $alert_summary['count'] ) ? (int) $alert_summary['count'] : 0;
        $latest_status = trim( (string) ( $alert_summary['headline'] ?? '' ) );

        if ( 'free_public_companion' === $variant ) {
            return array(
                'headline'    => 'Alerts available on connected plans',
                'copy'        => 'Upgrade to unlock alert routing and delivery history for this site.',
                'button_label'=> 'Upgrade now',
                'button_url'  => $billing_link,
            );
        }

        if ( $count > 0 && '' !== $latest_status ) {
            return array(
                'headline'    => 'Latest alert activity',
                'copy'        => 'Latest status: ' . $latest_status . '. View the matching rule and delivery history in OpsGate.',
                'button_label'=> 'Alerts →',
                'button_url'  => $alerts_link,
            );
        }

        return array(
            'headline'    => 'Add alert triggers',
            'copy'        => 'Configure rules and destinations in OpsGate so this site can notify you when risk changes.',
            'button_label'=> 'Alerts →',
            'button_url'  => $alerts_link,
        );
    }

    /**
     * @param array<string,mixed> $contract
     * @return array{headline:string,copy:string}
     */
    private static function remote_companion_activity_summary_view( array $contract ): array {
        $activity_summary = isset( $contract['activity_summary'] ) && is_array( $contract['activity_summary'] ) ? $contract['activity_summary'] : array();
        $items = isset( $activity_summary['items'] ) && is_array( $activity_summary['items'] ) ? $activity_summary['items'] : array();
        if ( empty( $items ) ) {
            return array(
                'headline' => 'No activity yet',
                'copy'     => 'Run a check to create the first activity event.',
            );
        }

        return array(
            'headline' => 'Latest site activity',
            'copy'     => 'Only the latest 1-2 events stay here. Full history opens in OpsGate.',
        );
    }

    private static function remote_companion_variant_for_contract( array $contract ): string {
        return isset( $contract['render_variant'] ) ? (string) $contract['render_variant'] : 'onboarding_required';
    }

    /**
     * Pure tier/mode classifier for the remote companion state matrix.
     *
     * @return array<string,mixed>
     */
    private static function remote_companion_matrix_case( string $plan, string $connection_state, string $connection_mode, bool $scope_ready, bool $latest_truth_is_public_only ): array {
        $plan = self::normalize_plan( $plan );
        $connection_state = strtolower( trim( $connection_state ) );
        $connection_mode = strtolower( trim( $connection_mode ) );
        $variant = 'onboarding_required';
        $onboarding_state = 'ready';

        $is_paid_plan = in_array( $plan, array( 'starter', 'pro', 'agency' ), true );

        if ( ! $scope_ready ) {
            $variant = 'onboarding_required';
            $onboarding_state = 'onboarding_required';
        } elseif ( 'credential_invalid' === $connection_state ) {
            $variant = 'credential_invalid';
        } elseif ( 'disconnected' === $connection_state || 'pairing_pending' === $connection_state ) {
            $variant = 'disconnected';
        } elseif ( 'connected' === $connection_state && 'wp_connector' === $connection_mode && $is_paid_plan ) {
            // Connected + paid plan = full connected companion. Plan is the commercial gate;
            // connection_mode is the technical channel. Both must be true.
            $variant = 'connected_companion';
        } elseif ( 'free' === $plan ) {
            // Free plan always gates connected features, regardless of connection_mode or credential.
            // A previously-connected site that was downgraded must show public-only state.
            $variant = 'free_public_companion';
        } elseif ( $is_paid_plan && 'public_scan' === $connection_mode ) {
            // Paid plan but site not yet connected/paired.
            // Show disconnected so pairing CTA is prominent.
            $variant = 'disconnected';
        } elseif ( 'public_scan' === $connection_mode || $latest_truth_is_public_only ) {
            $variant = 'free_public_companion';
        } else {
            $variant = 'onboarding_required';
            $onboarding_state = 'onboarding_required';
        }

        $allowed_actions = array();
        if ( 'onboarding_required' === $variant ) {
            $allowed_actions = array( 'run_public_check', 'connect_with_code', 'open_opsgate' );
        } elseif ( 'free_public_companion' === $variant ) {
            $allowed_actions = array( 'run_public_check', 'connect_this_site', 'open_opsgate' );
        } elseif ( 'connected_companion' === $variant ) {
            $allowed_actions = array( 'run_site_triage', 'open_opsgate' );
        } elseif ( 'credential_invalid' === $variant ) {
            $allowed_actions = array( 'reconnect_this_site', 'open_opsgate' );
        } else {
            $allowed_actions = array( 'repair_connection', 'open_opsgate' );
        }

        return array(
            'render_variant' => $variant,
            'onboarding_state' => $onboarding_state,
            'public_only' => 'free_public_companion' === $variant,
            'credential_status' => 'connected_companion' === $variant ? 'valid' : ( 'credential_invalid' === $variant ? 'invalid' : ( 'disconnected' === $variant ? ( 'pairing_pending' === $connection_state ? 'pairing_pending' : 'disconnected' ) : 'not_applicable' ) ),
            'allowed_actions' => $allowed_actions,
            'breakdown_title' => 'free_public_companion' === $variant ? 'Public check breakdown' : 'Connected evidence breakdown',
            'breakdown_copy' => 'free_public_companion' === $variant ? 'This score uses public evidence only.' : 'Connected evidence is active for this WordPress site.',
        );
    }

    /**
     * @param array<string,mixed> $contract
     * @return array<string,mixed>
     */
    private static function remote_companion_progress_view( array $contract ): array {
        $progress = isset( $contract['progress'] ) && is_array( $contract['progress'] ) ? $contract['progress'] : array();
        $variant = self::remote_companion_variant_for_contract( $contract );
        $public_only = 'free_public_companion' === $variant;
        $profile = $public_only
            ? array(
                array( 'key' => 'queued', 'label' => 'Queued' ),
                array( 'key' => 'checking_public_site', 'label' => 'Checking public site' ),
                array( 'key' => 'finalizing', 'label' => 'Finalizing' ),
                array( 'key' => 'complete', 'label' => 'Complete' ),
            )
            : array(
                array( 'key' => 'queued', 'label' => 'Queued' ),
                array( 'key' => 'collecting_wordpress_evidence', 'label' => 'Collecting WordPress evidence' ),
                array( 'key' => 'checking_vulnerabilities', 'label' => 'Checking vulnerabilities' ),
                array( 'key' => 'checking_uptime_performance', 'label' => 'Checking uptime/performance' ),
                array( 'key' => 'finalizing', 'label' => 'Finalizing' ),
                array( 'key' => 'complete', 'label' => 'Complete' ),
            );

        $phase_map = $public_only
            ? array(
                'queued' => 'queued',
                'inventory' => 'checking_public_site',
                'updates' => 'checking_public_site',
                'vulnerabilities' => 'checking_public_site',
                'reachability' => 'checking_public_site',
                'performance' => 'finalizing',
                'reports' => 'finalizing',
                'complete' => 'complete',
            )
            : array(
                'queued' => 'queued',
                'inventory' => 'collecting_wordpress_evidence',
                'updates' => 'collecting_wordpress_evidence',
                'vulnerabilities' => 'checking_vulnerabilities',
                'reachability' => 'checking_uptime_performance',
                'performance' => 'checking_uptime_performance',
                'reports' => 'finalizing',
                'complete' => 'complete',
            );

        $current = '';
        $raw_label = isset( $progress['progress_phase_label'] ) ? trim( (string) $progress['progress_phase_label'] ) : '';
        if ( '' !== $raw_label ) {
            foreach ( $profile as $profile_item ) {
                if ( strtolower( (string) $profile_item['label'] ) === strtolower( $raw_label ) ) {
                    $current = (string) $profile_item['key'];
                    break;
                }
            }
        }
        if ( '' === $current ) {
            $legacy_items = isset( $progress['phase_items'] ) && is_array( $progress['phase_items'] ) ? $progress['phase_items'] : array();
            foreach ( $legacy_items as $legacy_item ) {
                if ( ! is_array( $legacy_item ) ) {
                    continue;
                }
                $legacy_key = isset( $legacy_item['key'] ) ? trim( (string) $legacy_item['key'] ) : '';
                $legacy_state = isset( $legacy_item['state'] ) ? trim( (string) $legacy_item['state'] ) : '';
                if ( 'current' !== $legacy_state && 'failed' !== $legacy_state ) {
                    continue;
                }
                if ( isset( $phase_map[ $legacy_key ] ) ) {
                    $current = (string) $phase_map[ $legacy_key ];
                    break;
                }
            }
        }
        if ( '' === $current && ! empty( $progress['run_visual_key'] ) && 'completed' === $progress['run_visual_key'] ) {
            $current = 'complete';
        }
        if ( '' === $current ) {
            $current = 'queued';
        }

        $cards = array();
        $current_index = 0;
        foreach ( $profile as $index => $profile_item ) {
            if ( (string) $profile_item['key'] === $current ) {
                $current_index = $index;
                break;
            }
        }

        foreach ( $profile as $index => $profile_item ) {
            $state = 'pending';
            if ( ! empty( $progress['run_visual_key'] ) && 'completed' === $progress['run_visual_key'] ) {
                $state = 'complete';
            } elseif ( ! empty( $progress['run_visual_key'] ) && 'failed' === $progress['run_visual_key'] && $index === $current_index ) {
                $state = 'failed';
            } elseif ( $index < $current_index ) {
                $state = 'complete';
            } elseif ( $index === $current_index ) {
                $state = 'current';
            }
            $cards[] = array(
                'key' => (string) $profile_item['key'],
                'label' => (string) $profile_item['label'],
                'state' => $state,
                'state_label' => 'complete' === $state ? 'Complete' : ( 'current' === $state ? 'Active now' : ( 'failed' === $state ? 'Needs review' : 'Waiting' ) ),
            );
        }

        return array(
            'title' => isset( $progress['progress_title'] ) ? (string) $progress['progress_title'] : 'Latest check',
            'copy' => isset( $progress['progress_copy'] ) ? (string) $progress['progress_copy'] : '',
            'phase_label' => isset( $profile[ $current_index ]['label'] ) ? (string) $profile[ $current_index ]['label'] : 'Queued',
            'phase_copy' => isset( $progress['progress_phase_copy'] ) ? (string) $progress['progress_phase_copy'] : '',
            'percent' => isset( $progress['progress_percent'] ) ? (int) $progress['progress_percent'] : 0,
            'elapsed_label' => isset( $progress['elapsed_label'] ) ? (string) $progress['elapsed_label'] : 'No active run recorded',
            'evidence_label' => isset( $progress['evidence_label'] ) ? (string) $progress['evidence_label'] : 'Results not yet available',
            'cards' => $cards,
            'payload' => $progress,
        );
    }

    private static function render_remote_pairing_modal( string $api_base_url_value, string $site_config_link, string $pairing_error_notice, bool $pairing_modal_open ): void {
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $auto_pair_token = isset( $_GET['opsgate_pairing_token'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_pairing_token'] ) ) : '';
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $auto_pair_mode = isset( $_GET['opsgate_auto_pair'] ) && '1' === (string) wp_unslash( $_GET['opsgate_auto_pair'] );
        if ( $auto_pair_mode && '' !== $auto_pair_token ) {
            $pairing_modal_open = true;
        }
        ?>
        <div class="opsgate-remote-pairing-modal" id="opsgate-remote-pairing-modal" <?php echo $pairing_modal_open ? '' : 'hidden'; ?> <?php echo ( $auto_pair_mode && '' !== $auto_pair_token ) ? 'data-opsgate-auto-pair="1"' : ''; ?>>
            <div class="opsgate-remote-pairing-backdrop" data-opsgate-pairing-close></div>
            <div class="opsgate-remote-pairing-dialog" role="dialog" aria-modal="true" aria-labelledby="opsgate-remote-pairing-title">
                <div class="opsgate-remote-pairing-header">
                    <div>
                        <span class="opsgate-remote-eyebrow">Pairing</span>
                        <h4 id="opsgate-remote-pairing-title">Connect with Pairing Code</h4>
                    </div>
                    <button type="button" class="button-link opsgate-remote-pairing-close" data-opsgate-pairing-close aria-label="Close pairing">&times;</button>
                </div>
                <div class="opsgate-remote-pairing-body">
                    <?php if ( $auto_pair_mode && '' !== $auto_pair_token ) : ?>
                        <p>Your connection code was generated. Completing the connection now&hellip;</p>
                    <?php else : ?>
                        <p>Paste the pairing code from OpsGate. This flow connects the current WordPress site without exposing raw account, site, credential, or token IDs.</p>
                    <?php endif; ?>
                    <?php if ( '' !== $pairing_error_notice ) : ?>
                        <div class="notice notice-error inline"><p><?php echo esc_html( $pairing_error_notice ); ?></p></div>
                    <?php endif; ?>
                    <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="opsgate-remote-pairing-form" data-opsgate-pairing-submit-form <?php echo ( $auto_pair_mode && '' !== $auto_pair_token ) ? 'data-opsgate-auto-pair-form="1"' : ''; ?>>
                        <?php wp_nonce_field( 'opsgate_complete_pairing', 'opsgate_complete_pairing_nonce' ); ?>
                        <input type="hidden" name="action" value="opsgate_complete_pairing" />
                        <input type="hidden" name="opsgate_api_base_url" value="<?php echo esc_attr( $api_base_url_value ); ?>" />
                        <div class="opsgate-remote-onboarding-grid" <?php echo ( $auto_pair_mode && '' !== $auto_pair_token ) ? 'hidden' : ''; ?>>
                            <div>
                                <label for="opsgate_remote_pairing_code"><strong>Pairing code</strong></label>
                                <input id="opsgate_remote_pairing_code" type="text" class="regular-text" name="opsgate_pairing_code" value="<?php echo esc_attr( $auto_pair_token ); ?>" autocomplete="off" />
                            </div>
                        </div>
                        <div class="opsgate-remote-card-actions" <?php echo ( $auto_pair_mode && '' !== $auto_pair_token ) ? 'hidden' : ''; ?>>
                            <button type="submit" class="button button-primary" data-opsgate-pairing-submit-btn data-opsgate-idle-label="Complete Pairing" data-opsgate-busy-label="Connecting…">Complete Pairing</button>
                            <?php if ( '' !== $site_config_link ) : ?>
                                <a class="button button-secondary" href="<?php echo esc_url( $site_config_link ); ?>" target="_blank" rel="noopener noreferrer" data-opsgate-no-ajax="1">Get Pairing in OpsGate</a>
                            <?php endif; ?>
                            <button type="button" class="button button-secondary" data-opsgate-pairing-close>Cancel</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
        <?php
    }

    /**
     * @param array<string,mixed> $contract
     * @return void
     */
    private static function render_remote_companion_shell( array $contract ): void {
        $variant = self::remote_companion_variant_for_contract( $contract );
        $site_label = isset( $contract['site_label'] ) ? (string) $contract['site_label'] : 'Current site';
        $site_url = isset( $contract['site_url'] ) ? (string) $contract['site_url'] : '';
        $plan = isset( $contract['plan'] ) ? (string) $contract['plan'] : 'unknown';
        $support = isset( $contract['support_diagnostics'] ) && is_array( $contract['support_diagnostics'] ) ? $contract['support_diagnostics'] : array();
        $api_base_url_value = trim( (string) get_option( 'opsgate_api_base_url', '' ) );
        $progress_view = self::remote_companion_progress_view( $contract );
        $progress_payload = isset( $progress_view['payload'] ) && is_array( $progress_view['payload'] ) ? $progress_view['payload'] : array();
        $run_button_label = isset( $contract['primary_action_label'] ) ? (string) $contract['primary_action_label'] : '';
        $triage_states = isset( $progress_payload['live_states'] ) && is_array( $progress_payload['live_states'] ) ? $progress_payload['live_states'] : array();
        $triage_run_busy = ! empty( array_intersect( $triage_states, array( 'QUEUED', 'RUNNING' ) ) );
        $triage_run_disabled = ! in_array( $variant, array( 'free_public_companion', 'connected_companion' ), true ) || $triage_run_busy;
        $triage_run_button_label = $triage_run_busy ? 'Run in progress' : $run_button_label;
        $job_id = isset( $contract['latest_run']['id'] ) ? (string) $contract['latest_run']['id'] : '';
        $score_value = isset( $contract['latest_run']['score'] ) && '' !== (string) $contract['latest_run']['score'] ? (string) $contract['latest_run']['score'] : '—';
        $completed_at = isset( $contract['latest_run']['completed_at'] ) ? (string) $contract['latest_run']['completed_at'] : '';
        $completed_label = '' !== $completed_at ? self::canonical_report_datetime_label( $completed_at ) : 'No completed check recorded yet';
        $grade = isset( $contract['latest_run']['risk_color'] ) ? strtolower( (string) $contract['latest_run']['risk_color'] ) : '';
        $score_tone = in_array( $grade, array( 'green', 'healthy' ), true ) ? 'good' : ( in_array( $grade, array( 'red', 'critical' ), true ) ? 'bad' : 'warn' );
        $refresh_url = self::admin_tab_url( 'overview' );
        $poll_url = self::browser_safe_admin_url( 'admin-ajax.php', array( 'action' => 'opsgate_triage_live_status' ) );
        $run_url = self::browser_safe_admin_url( 'admin-ajax.php', array( 'action' => 'opsgate_run_portfolio_triage_live' ) );
        $allowed_actions = isset( $contract['allowed_actions'] ) && is_array( $contract['allowed_actions'] ) ? $contract['allowed_actions'] : array();
        $primary_link = isset( $allowed_actions[1]['url'] ) ? (string) $allowed_actions[1]['url'] : '';
        $primary_link_label = isset( $allowed_actions[1]['label'] ) ? (string) $allowed_actions[1]['label'] : '';
        $open_link = isset( $contract['central_links']['overview'] ) ? (string) $contract['central_links']['overview'] : '';
        $billing_link = isset( $contract['central_links']['billing'] ) ? (string) $contract['central_links']['billing'] : '';
        $site_config_link = isset( $contract['central_links']['site_config'] ) ? (string) $contract['central_links']['site_config'] : '';
        $breakdown_items = isset( $contract['score_breakdown'] ) && is_array( $contract['score_breakdown'] ) ? $contract['score_breakdown'] : array();
        $report_actions = isset( $contract['report_actions'] ) && is_array( $contract['report_actions'] ) ? $contract['report_actions'] : array();
        $activity_items = isset( $contract['activity_summary']['items'] ) && is_array( $contract['activity_summary']['items'] ) ? $contract['activity_summary']['items'] : array();
        $alert_summary = isset( $contract['alert_summary'] ) && is_array( $contract['alert_summary'] ) ? $contract['alert_summary'] : array();
        $report_summary = self::remote_companion_report_summary( $contract );
        $alert_summary_view = self::remote_companion_alert_summary_view( $contract );
        $activity_summary_view = self::remote_companion_activity_summary_view( $contract );
        $package_name = isset( $support['package_name'] ) ? (string) $support['package_name'] : ucfirst( $plan );
        $hero_secondary_label = $primary_link_label;
        $hero_secondary_url = $primary_link;
        $hero_secondary_external = false;
        $hero_tertiary_label = '';
        $hero_tertiary_url = '';
        $hero_tertiary_external = false;
        $surface_error_notice = isset( $_GET['opsgate_settings_error'] ) ? sanitize_text_field( rawurldecode( (string) wp_unslash( $_GET['opsgate_settings_error'] ) ) ) : '';
        $pairing_error_notice = isset( $_GET['opsgate_pairing_error'] ) ? sanitize_text_field( rawurldecode( (string) wp_unslash( $_GET['opsgate_pairing_error'] ) ) ) : '';
        $pairing_modal_open = isset( $_GET['opsgate_pairing_open'] ) && '1' === (string) wp_unslash( $_GET['opsgate_pairing_open'] );
        $scope_summary = self::remote_companion_scope_summary( $contract );
        $remote_connection_state = isset( $contract['connection_state'] ) ? strtolower( trim( (string) $contract['connection_state'] ) ) : 'external_only';
        $remote_connection_mode  = isset( $contract['connection_mode'] ) ? strtolower( trim( (string) $contract['connection_mode'] ) ) : 'public_scan';
        // "paid_unconnected": paid plan + public_scan site that has never been paired.
        // Detected when disconnected variant is used but connection_state is external_only (no prior pairing).
        $is_paid_unconnected = 'disconnected' === $variant
            && 'external_only' === $remote_connection_state
            && in_array( $plan, array( 'starter', 'pro', 'agency' ), true );

        if ( 'connected_companion' === $variant ) {
            $hero_secondary_label = 'View in OpsGate';
            $hero_secondary_url = $open_link;
            $hero_secondary_external = true;
        } elseif ( 'credential_invalid' === $variant ) {
            $hero_secondary_label = 'Reconnect this site';
            $hero_secondary_url = self::admin_tab_url( 'settings' );
            $hero_secondary_external = false;
        } elseif ( 'disconnected' === $variant ) {
            $hero_secondary_label = '' !== $site_config_link ? 'Get Pairing in OpsGate' : 'Open OpsGate';
            $hero_secondary_url = '' !== $site_config_link ? $site_config_link : $open_link;
            $hero_secondary_external = true;
        } elseif ( 'free_public_companion' === $variant && '' !== $job_id ) {
            $hero_secondary_label = 'View public summary →';
            $hero_secondary_url = $open_link;
            $hero_secondary_external = true;
        } elseif ( 'free_public_companion' === $variant && '' !== $billing_link ) {
            $hero_secondary_label = 'Upgrade now';
            $hero_secondary_url = $billing_link;
            $hero_secondary_external = true;
        }
        ?>
        <?php $og_theme = ( get_option( 'opsgate_ui_theme', 'light' ) === 'dark' ) ? 'dark' : 'light'; ?>
        <div class="wrap opsgate-admin opsgate-admin-remote-companion opsgate-admin-tab-overview" data-og-theme="<?php echo esc_attr( $og_theme ); ?>">
            <h1 class="wp-heading-inline">
                <span class="opsgate-remote-logo-mark">
                    <svg class="opsgate-remote-logo-shield" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
                        <defs><linearGradient id="og-logo-grad" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="#6366f1"/><stop offset="100%" stop-color="#a855f7"/></linearGradient></defs>
                        <rect width="40" height="40" rx="8" fill="url(#og-logo-grad)"/>
                        <path d="M20 6L8 11v9c0 7.18 5.14 13.9 12 15.57C27.86 33.9 32 27.18 32 20V11L20 6z" fill="white" opacity="0.95"/>
                    </svg>
                    <span class="opsgate-remote-logo-text">OpsGate</span>
                </span>
            </h1>
            <hr class="wp-header-end">
            <?php if ( '' !== $surface_error_notice ) : ?>
                <?php self::render_surface_notice( $surface_error_notice, 'error' ); ?>
            <?php endif; ?>
            <div class="opsgate-remote-companion-shell opsgate-remote-companion-shell-v2 opsgate-remote-companion-state-<?php echo esc_attr( $variant ); ?>">
                <?php if ( 'onboarding_required' === $variant ) : ?>
                    <section class="opsgate-remote-section opsgate-remote-onboarding">
                        <div class="opsgate-remote-onboarding-header">
                            <div class="opsgate-remote-onboarding-brand">
                                <span class="opsgate-remote-eyebrow">Security &amp; operations — free to start</span>
                                <h3>Know exactly what is exposed on <?php echo esc_html( '' !== $site_url ? $site_url : 'this site' ); ?></h3>
                                <p>OpsGate scans plugins, checks for known CVEs, and delivers independently verified security reports — so you can show clients what was found, what was fixed, and why it matters.</p>
                            </div>
                        </div>
                        <div class="opsgate-remote-onboarding-paths">
                            <div class="opsgate-remote-onboarding-path opsgate-remote-onboarding-path-new">
                                <span class="opsgate-remote-eyebrow">Step 1 of 2 — No account needed</span>
                                <h4>Get a free security assessment of <?php echo esc_html( '' !== $site_url ? $site_url : 'this site' ); ?></h4>
                                <p>Run an instant SSL, reachability, and performance scan. Results are ready in seconds — no account required.</p>
                                <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="opsgate-remote-onboarding-form">
                                    <?php wp_nonce_field( 'opsgate_run_free_public_onboarding', 'opsgate_run_free_public_onboarding_nonce' ); ?>
                                    <input type="hidden" name="action" value="opsgate_run_free_public_onboarding" />
                                    <input type="hidden" name="opsgate_site_label" value="<?php echo esc_attr( $site_label ); ?>" />
                                    <input type="hidden" name="opsgate_api_base_url" value="<?php echo esc_attr( $api_base_url_value ); ?>" />
                                    <input type="hidden" name="opsgate_identity_email" value="<?php echo esc_attr( trim( (string) get_option( 'opsgate_identity_email', (string) get_bloginfo( 'admin_email' ) ) ) ); ?>" />
                                    <div class="opsgate-remote-onboarding-url-row">
                                        <label for="opsgate_remote_public_site_url">Detected site URL</label>
                                        <input id="opsgate_remote_public_site_url" type="url" class="regular-text" name="opsgate_site_url" value="<?php echo esc_attr( $site_url ); ?>" placeholder="https://yoursite.com" />
                                        <p class="description">Uses public evidence only — no WordPress connection required.</p>
                                    </div>
                                    <div class="opsgate-remote-card-actions">
                                        <button type="submit" class="button button-primary">Run Free Security Assessment</button>
                                    </div>
                                </form>
                            </div>
                            <div class="opsgate-remote-onboarding-path opsgate-remote-onboarding-path-existing">
                                <span class="opsgate-remote-eyebrow">Step 2 of 2 — Already have an account</span>
                                <h4>Connect this site to unlock full plugin &amp; CVE coverage</h4>
                                <p>Pair this site to run scheduled security scans, capture plugin vulnerability findings, generate client-ready security reports, and receive real-time alerts.</p>
                                <div class="opsgate-remote-card-actions">
                                    <button type="button" class="button button-primary" data-opsgate-pairing-open>Connect with Pairing Code</button>
                                    <?php if ( '' !== $site_config_link ) : ?>
                                        <a class="button button-secondary" href="<?php echo esc_url( $site_config_link ); ?>" target="_blank" rel="noopener noreferrer" data-opsgate-no-ajax="1">Get pairing code in OpsGate</a>
                                    <?php elseif ( '' !== $open_link ) : ?>
                                        <a class="button button-secondary" href="<?php echo esc_url( $open_link ); ?>" target="_blank" rel="noopener noreferrer" data-opsgate-no-ajax="1">Open OpsGate</a>
                                    <?php endif; ?>
                                </div>
                            </div>
                        </div>
                        <?php self::render_remote_pairing_modal( $api_base_url_value, $site_config_link, $pairing_error_notice, $pairing_modal_open ); ?>
                    </section>
                    <?php return; ?>
                <?php endif; ?>

                <?php if ( in_array( $variant, array( 'credential_invalid', 'disconnected' ), true ) ) : ?>
                    <div class="opsgate-remote-repair-banner opsgate-remote-repair-banner-<?php echo esc_attr( $variant ); ?>">
                        <div class="opsgate-remote-repair-banner-content">
                            <?php if ( 'credential_invalid' === $variant ) : ?>
                                <strong>Connection needs attention</strong>
                                <p>The connector credential for this site is invalid or has been revoked. Connected scanning is paused until reconnected.</p>
                            <?php elseif ( $is_paid_unconnected ) : ?>
                                <strong><?php echo esc_html( ucfirst( $plan ) ); ?> plan active — connect this site to unlock connected scanning</strong>
                                <p>This site is not yet connected to OpsGate. Pair it to unlock WordPress inventory, scheduled scans, reports, and alerts on your <?php echo esc_html( ucfirst( $plan ) ); ?> plan.</p>
                            <?php else : ?>
                                <strong>Site is disconnected</strong>
                                <p>This site is not connected to OpsGate. Public checks may still run, but WordPress inventory and connected scanning are not active.</p>
                            <?php endif; ?>
                        </div>
                        <?php if ( '' !== $hero_secondary_url && '' !== $hero_secondary_label ) : ?>
                            <a class="button button-primary" href="<?php echo esc_url( $hero_secondary_url ); ?>"<?php echo $hero_secondary_external ? ' target="_blank" rel="noopener noreferrer" data-opsgate-no-ajax="1"' : ''; ?>><?php echo esc_html( $hero_secondary_label ); ?></a>
                        <?php endif; ?>
                    </div>
                <?php endif; ?>
                <?php if ( in_array( $variant, array( 'credential_invalid', 'disconnected' ), true ) ) : ?>
                    <?php self::render_remote_pairing_modal( $api_base_url_value, $site_config_link, $pairing_error_notice, $pairing_modal_open ); ?>
                <?php endif; ?>
                <section class="opsgate-remote-hero-band opsgate-remote-hero-band-v2">
                    <div class="opsgate-remote-hero-band-main">
                        <div class="opsgate-remote-hero-band-head">
                            <div class="opsgate-remote-hero-band-identity">
                                <h2><?php echo esc_html( $site_label ); ?></h2>
                                <p class="opsgate-remote-hero-url"><?php echo esc_html( $site_url ); ?></p>
                            </div>
                            <div class="opsgate-remote-hero-pills">
                                <span class="opsgate-tier-badge opsgate-tier-badge-<?php echo esc_attr( $plan ); ?>"><?php echo esc_html( $package_name ); ?></span>
                                <span class="opsgate-remote-pill"><?php echo esc_html( self::canonical_connection_mode_label( (string) ( $contract['connection_mode'] ?? 'public_scan' ) ) ); ?></span>
                                <span class="opsgate-remote-pill"><?php echo esc_html( self::canonical_connection_status_label( (string) ( $contract['connection_state'] ?? 'external_only' ) ) ); ?></span>
                            </div>
                        </div>
                        <div class="opsgate-remote-topline-grid">
                            <article class="opsgate-remote-topline-card opsgate-remote-topline-score is-<?php echo esc_attr( $score_tone ); ?>">
                                <span class="opsgate-remote-stat-label">Current score</span>
                                <strong><?php echo esc_html( $score_value ); ?></strong>
                                <p><?php echo esc_html( '' !== $job_id ? 'Latest check recorded' : 'Awaiting first check' ); ?></p>
                            </article>
                            <article class="opsgate-remote-topline-card">
                                <span class="opsgate-remote-stat-label">Last checked</span>
                                <strong class="opsgate-remote-topline-timestamp"><?php echo esc_html( $completed_label ); ?></strong>
                                <p><?php echo esc_html( (string) ( $contract['breakdown_copy'] ?? '' ) ); ?></p>
                            </article>
                        </div>
                        <div id="opsgate-triage-live-panel" class="opsgate-remote-live-panel opsgate-remote-live-panel-hero" data-opsgate-live-states="<?php echo esc_attr( implode( ',', $triage_states ) ); ?>" data-opsgate-refresh-url="<?php echo esc_url( $refresh_url ); ?>" data-opsgate-poll-url="<?php echo esc_url( $poll_url ); ?>" data-opsgate-run-url="<?php echo esc_url( $run_url ); ?>" data-opsgate-current-job-id="<?php echo esc_attr( isset( $progress_payload['job_id'] ) ? (string) $progress_payload['job_id'] : '' ); ?>" data-opsgate-current-export-job-id="<?php echo esc_attr( isset( $progress_payload['export_job_id'] ) ? (string) $progress_payload['export_job_id'] : '' ); ?>" data-opsgate-current-export-source-job-id="<?php echo esc_attr( isset( $progress_payload['export_source_job_id'] ) ? (string) $progress_payload['export_source_job_id'] : '' ); ?>" data-opsgate-rendered-run-id="<?php echo esc_attr( isset( $progress_payload['job_id'] ) ? (string) $progress_payload['job_id'] : '' ); ?>" data-opsgate-rendered-export-job-id="<?php echo esc_attr( isset( $progress_payload['export_job_id'] ) ? (string) $progress_payload['export_job_id'] : '' ); ?>" data-opsgate-reload-workspace-on-settle="1">
                            <span class="opsgate-triage-command-runtime-note" data-opsgate-triage-runtime-note hidden="hidden"></span>
                            <div class="opsgate-remote-progress-grid">
                                <div class="opsgate-remote-progress-main">
                                    <h3 data-opsgate-triage-progress-title="1"><?php echo esc_html( (string) $progress_view['title'] ); ?></h3>
                                    <p class="opsgate-remote-progress-copy" data-opsgate-triage-progress-copy="1"><?php echo esc_html( (string) $progress_view['copy'] ); ?></p>
                                    <div class="opsgate-remote-progress-meter" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="<?php echo esc_attr( (string) $progress_view['percent'] ); ?>" aria-label="Run progress" data-opsgate-triage-progress-meter="1">
                                        <span class="opsgate-remote-progress-fill" style="width:<?php echo esc_attr( (string) $progress_view['percent'] ); ?>%;" data-opsgate-triage-progress-fill="1"></span>
                                    </div>
                                    <div class="opsgate-remote-progress-meta">
                                        <span data-opsgate-triage-progress-phase="1"><?php echo esc_html( (string) $progress_view['phase_label'] ); ?></span>
                                        <span data-opsgate-triage-progress-elapsed="1"><?php echo esc_html( (string) $progress_view['elapsed_label'] ); ?></span>
                                        <span data-opsgate-triage-progress-evidence="1"><?php echo esc_html( (string) $progress_view['evidence_label'] ); ?></span>
                                    </div>
                                    <div class="opsgate-remote-phase-grid">
                                        <?php foreach ( $progress_view['cards'] as $card ) : ?>
                                            <article class="opsgate-remote-phase-card is-<?php echo esc_attr( (string) $card['state'] ); ?>" data-opsgate-triage-phase-key="<?php echo esc_attr( (string) $card['key'] ); ?>">
                                                <span class="opsgate-remote-phase-title"><?php echo esc_html( (string) $card['label'] ); ?></span>
                                                <span class="opsgate-remote-phase-status" data-opsgate-triage-phase-status="1"><?php echo esc_html( (string) $card['state_label'] ); ?></span>
                                            </article>
                                        <?php endforeach; ?>
                                    </div>
                                </div>
                                <aside class="opsgate-remote-progress-side">
                                    <span class="opsgate-remote-eyebrow">Current phase</span>
                                    <strong data-opsgate-triage-aside-title="1"><?php echo esc_html( (string) $progress_view['phase_label'] ); ?></strong>
                                    <p data-opsgate-triage-aside-copy="1"><?php echo esc_html( (string) $progress_view['phase_copy'] ); ?></p>
                                </aside>
                            </div>
                        </div>
                    </div>
                    <aside class="opsgate-remote-hero-band-actions">
                        <?php if ( in_array( $variant, array( 'free_public_companion', 'connected_companion' ), true ) ) : ?>
                            <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="opsgate-triage-command-bar-form" data-opsgate-triage-run-form data-opsgate-triage-launch-form="1" data-opsgate-triage-run-url="<?php echo esc_url( $run_url ); ?>" data-opsgate-triage-destination-url="<?php echo esc_url( $refresh_url ); ?>">
                                <?php wp_nonce_field( 'opsgate_run_portfolio_triage' ); ?>
                                <input type="hidden" name="action" value="opsgate_run_portfolio_triage" />
                                <button type="submit" class="button button-primary button-hero-primary" data-opsgate-run-button data-opsgate-run-idle-label="<?php echo esc_attr( $run_button_label ); ?>" data-opsgate-run-busy-label="Run in progress" <?php disabled( $triage_run_disabled ); ?>><?php echo esc_html( $triage_run_button_label ); ?></button>
                            </form>
                        <?php endif; ?>
                        <?php if ( ! in_array( $variant, array( 'credential_invalid', 'disconnected' ), true ) && '' !== $hero_secondary_url && '' !== $hero_secondary_label ) : ?>
                            <a class="button button-secondary" href="<?php echo esc_url( $hero_secondary_url ); ?>"<?php echo $hero_secondary_external ? ' target="_blank" rel="noopener noreferrer" data-opsgate-no-ajax="1"' : ''; ?>><?php echo esc_html( $hero_secondary_label ); ?></a>
                        <?php endif; ?>
                        <?php if ( in_array( $variant, array( 'free_public_companion', 'credential_invalid', 'disconnected' ), true ) ) : ?>
                            <button type="button" class="button button-secondary" data-opsgate-pairing-open>Connect with Pairing Code</button>
                        <?php endif; ?>
                        <?php if ( 'connected_companion' === $variant ) : ?>
                            <a class="button" href="<?php echo esc_url( $refresh_url ); ?>">Refresh</a>
                        <?php endif; ?>
                    </aside>
                </section>

                <section class="opsgate-remote-section">
                    <div class="opsgate-remote-section-head">
                        <div>
                            <span class="opsgate-remote-eyebrow">Score breakdown</span>
                            <h3><?php echo esc_html( (string) ( $contract['breakdown_title'] ?? 'Score breakdown' ) ); ?></h3>
                            <p><?php echo esc_html( (string) ( $contract['breakdown_copy'] ?? '' ) ); ?></p>
                        </div>
                    </div>
                    <div class="opsgate-remote-breakdown-grid">
                        <?php foreach ( $breakdown_items as $breakdown_item ) : ?>
                            <article class="opsgate-remote-breakdown-card is-<?php echo esc_attr( (string) ( $breakdown_item['tone'] ?? 'neutral' ) ); ?>">
                                <span class="opsgate-remote-stat-label"><?php echo esc_html( (string) ( $breakdown_item['label'] ?? '' ) ); ?></span>
                                <strong><?php echo esc_html( (string) ( $breakdown_item['value'] ?? '' ) ); ?></strong>
                                <p><?php echo esc_html( (string) ( $breakdown_item['copy'] ?? '' ) ); ?></p>
                                <span class="opsgate-remote-breakdown-meta"><?php echo esc_html( (string) ( $breakdown_item['meta'] ?? '' ) ); ?></span>
                            </article>
                        <?php endforeach; ?>
                    </div>
                </section>

                <div class="opsgate-remote-main-layout">
                    <div class="opsgate-remote-primary-column">
                        <section class="opsgate-remote-section">
                            <div class="opsgate-remote-section-head">
                                <div>
                                    <span class="opsgate-remote-eyebrow">Reports</span>
                                    <h3><?php echo esc_html( (string) $report_summary['title'] ); ?></h3>
                                    <p><?php echo esc_html( (string) $report_summary['copy'] ); ?></p>
                                </div>
                            </div>
                            <div class="opsgate-remote-action-card-grid">
                                <article class="opsgate-remote-action-card">
                                    <span class="opsgate-remote-stat-label"><?php echo esc_html( 'free_public_companion' === $variant ? 'Public summary' : 'Reports' ); ?></span>
                                    <strong><?php echo esc_html( (string) $report_summary['headline'] ); ?></strong>
                                    <div class="opsgate-remote-card-actions">
                                        <?php if ( 'submit' === $report_summary['button_kind'] ) : ?>
                                            <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="opsgate-triage-command-bar-form" data-opsgate-triage-run-form data-opsgate-triage-launch-form="1" data-opsgate-triage-run-url="<?php echo esc_url( $run_url ); ?>" data-opsgate-triage-destination-url="<?php echo esc_url( $refresh_url ); ?>">
                                                <?php wp_nonce_field( 'opsgate_run_portfolio_triage' ); ?>
                                                <input type="hidden" name="action" value="opsgate_run_portfolio_triage" />
                                                <button type="submit" class="button button-secondary" data-opsgate-run-button data-opsgate-run-idle-label="Run Free Public Check" data-opsgate-run-busy-label="Run in progress">Run Free Public Check</button>
                                            </form>
                                        <?php elseif ( 'link' === $report_summary['button_kind'] && '' !== $report_summary['button_url'] ) : ?>
                                            <a class="button button-secondary" href="<?php echo esc_url( (string) $report_summary['button_url'] ); ?>" target="_blank" rel="noopener noreferrer" data-opsgate-no-ajax="1"><?php echo esc_html( (string) $report_summary['button_label'] ); ?></a>
                                        <?php endif; ?>
                                    </div>
                                </article>
                            </div>
                        </section>

                        <section class="opsgate-remote-section is-demoted">
                            <div class="opsgate-remote-section-head">
                                <div>
                                    <span class="opsgate-remote-eyebrow">Get help</span>
                                    <h3>Support diagnostics</h3>
                                    <p>Download a support package to share with the OpsGate team if you need assistance.</p>
                                </div>
                            </div>
                            <details class="opsgate-remote-support-details">
                                <summary>Open support diagnostics</summary>
                                <div class="opsgate-remote-card-actions" style="margin-top:14px;">
                                    <a class="button button-secondary" href="<?php echo esc_url( wp_nonce_url( (string) $support['support_export_url'], 'opsgate_export_logs' ) ); ?>">Download support package</a>
                                </div>
                            </details>
                        </section>
                    </div>

                    <div class="opsgate-remote-secondary-column">
                        <section class="opsgate-remote-section opsgate-remote-scope-card">
                            <div class="opsgate-remote-section-head">
                                <div>
                                    <span class="opsgate-remote-eyebrow">Site scope</span>
                                    <h3><?php echo esc_html( (string) $scope_summary['scope_label'] ); ?></h3>
                                </div>
                            </div>
                            <div class="opsgate-remote-meta-list">
                                <span><?php echo esc_html( 'Site: ' . (string) $scope_summary['site_label'] ); ?></span>
                                <span><?php echo esc_html( 'URL: ' . (string) $scope_summary['site_url'] ); ?></span>
                                <span><?php echo esc_html( 'Mode: ' . (string) $scope_summary['mode_label'] ); ?></span>
                            </div>
                        </section>

                        <section class="opsgate-remote-section">
                            <div class="opsgate-remote-section-head">
                                <div>
                                    <span class="opsgate-remote-eyebrow">Alerts</span>
                                    <h3><?php echo esc_html( (string) $alert_summary_view['headline'] ); ?></h3>
                                    <p><?php echo esc_html( (string) $alert_summary_view['copy'] ); ?></p>
                                </div>
                            </div>
                            <?php if ( '' !== $alert_summary_view['button_url'] ) : ?>
                                <div class="opsgate-remote-card-actions">
                                    <a class="button button-secondary" href="<?php echo esc_url( (string) $alert_summary_view['button_url'] ); ?>" target="_blank" rel="noopener noreferrer" data-opsgate-no-ajax="1"><?php echo esc_html( (string) $alert_summary_view['button_label'] ); ?></a>
                                </div>
                            <?php endif; ?>
                        </section>

                        <section class="opsgate-remote-section">
                            <div class="opsgate-remote-section-head">
                                <div>
                                    <span class="opsgate-remote-eyebrow">Activity</span>
                                    <?php if ( 'free_public_companion' === $variant ) : ?>
                                    <h3>Activity available on connected plans</h3>
                                    <p>Upgrade to unlock full site activity history for this site.</p>
                                    <?php else : ?>
                                    <h3><?php echo esc_html( (string) $activity_summary_view['headline'] ); ?></h3>
                                    <p><?php echo esc_html( (string) $activity_summary_view['copy'] ); ?></p>
                                    <?php endif; ?>
                                </div>
                            </div>
                            <?php if ( 'free_public_companion' !== $variant ) : ?>
                            <div class="opsgate-remote-activity-list compact">
                                <?php if ( empty( $activity_items ) ) : ?>
                                    <article class="opsgate-remote-activity-card is-empty">
                                        <strong>No activity yet</strong>
                                        <p>Run a check to create the first activity event.</p>
                                    </article>
                                <?php else : ?>
                                    <?php foreach ( $activity_items as $activity_item ) : ?>
                                        <article class="opsgate-remote-activity-card">
                                            <div class="opsgate-remote-activity-top">
                                                <strong><?php echo esc_html( isset( $activity_item['label'] ) ? (string) $activity_item['label'] : 'Activity' ); ?></strong>
                                                <span class="opsgate-remote-chip"><?php echo esc_html( isset( $activity_item['status'] ) ? (string) $activity_item['status'] : 'Recorded' ); ?></span>
                                            </div>
                                            <p><?php echo esc_html( isset( $activity_item['details'] ) ? (string) $activity_item['details'] : '' ); ?></p>
                                            <?php if ( ! empty( $activity_item['when'] ) ) : ?>
                                                <div class="opsgate-remote-meta-list">
                                                    <span><?php echo esc_html( (string) $activity_item['when'] ); ?></span>
                                                </div>
                                            <?php endif; ?>
                                        </article>
                                    <?php endforeach; ?>
                                <?php endif; ?>
                            </div>
                            <?php if ( ! empty( $contract['central_links']['activity'] ) ) : ?>
                                <div class="opsgate-remote-card-actions">
                                    <a class="button button-secondary" href="<?php echo esc_url( (string) $contract['central_links']['activity'] ); ?>" target="_blank" rel="noopener noreferrer" data-opsgate-no-ajax="1">Activity →</a>
                                </div>
                            <?php endif; ?>
                            <?php else : ?>
                            <?php if ( ! empty( $contract['central_links']['billing'] ) ) : ?>
                                <div class="opsgate-remote-card-actions">
                                    <a class="button button-secondary" href="<?php echo esc_url( (string) $contract['central_links']['billing'] ); ?>" target="_blank" rel="noopener noreferrer" data-opsgate-no-ajax="1">Upgrade now</a>
                                </div>
                            <?php endif; ?>
                            <?php endif; ?>
                        </section>
                    </div>
                </div>
            </div>
            <?php if ( 'free_public_companion' === $variant ) : ?>
                <?php self::render_remote_pairing_modal( $api_base_url_value, $site_config_link, $pairing_error_notice, $pairing_modal_open ); ?>
            <?php endif; ?>
        </div>
        <?php
    }

    /**
     * @param array<string,mixed> $contract
     * @return void
     */
    private static function render_onboarding_required( array $contract ): void {
        self::render_remote_companion_shell( $contract );
    }

    /**
     * @param array<string,mixed> $contract
     * @return void
     */
    private static function render_free_public_companion( array $contract ): void {
        self::render_remote_companion_shell( $contract );
    }

    /**
     * @param array<string,mixed> $contract
     * @return void
     */
    private static function render_connected_companion( array $contract ): void {
        self::render_remote_companion_shell( $contract );
    }

    /**
     * @param array<string,mixed> $contract
     * @return void
     */
    private static function render_credential_invalid( array $contract ): void {
        self::render_remote_companion_shell( $contract );
    }

    /**
     * @param array<string,mixed> $contract
     * @return void
     */
    private static function render_disconnected( array $contract ): void {
        self::render_remote_companion_shell( $contract );
    }

    private static function render_remote_companion_page( string $active_tab, string $plan ): void {
        $contract = self::remote_companion_state_contract();
        $variant = self::remote_companion_variant_for_contract( $contract );
        if ( 'onboarding_required' === $variant ) {
            self::render_onboarding_required( $contract );
            return;
        }
        if ( 'free_public_companion' === $variant ) {
            self::render_free_public_companion( $contract );
            return;
        }
        if ( 'connected_companion' === $variant ) {
            self::render_connected_companion( $contract );
            return;
        }
        if ( 'credential_invalid' === $variant ) {
            self::render_credential_invalid( $contract );
            return;
        }
        self::render_disconnected( $contract );
        return;

        $plan = self::normalize_plan( $plan );
        $identity = self::get_identity_snapshot();
        $site_summary = self::current_selected_site_summary();
        $scope = self::get_mcp_scope_snapshot();
        $bundle = self::canonical_latest_triage_bundle();
        $job = isset( $bundle['job'] ) && is_array( $bundle['job'] ) ? $bundle['job'] : array();
        $artifacts = isset( $bundle['artifacts'] ) && is_array( $bundle['artifacts'] ) ? $bundle['artifacts'] : array();
        $score = isset( $artifacts['score_summary']['body'] ) && is_array( $artifacts['score_summary']['body'] ) ? $artifacts['score_summary']['body'] : array();
        $receipt = isset( $artifacts['json_receipt']['body'] ) && is_array( $artifacts['json_receipt']['body'] ) ? $artifacts['json_receipt']['body'] : array();
        $receipt_inputs = isset( $receipt['inputs'] ) && is_array( $receipt['inputs'] ) ? $receipt['inputs'] : array();
        $reports_history = self::canonical_exports_history( 6 );
        $report_items = isset( $reports_history['items'] ) && is_array( $reports_history['items'] ) ? self::live_items_only( $reports_history['items'] ) : array();
        $rules = self::notification_rules_list();
        $rule_items = isset( $rules['items'] ) && is_array( $rules['items'] ) ? self::live_items_only( $rules['items'] ) : array();
        $package = self::current_package_entry();
        $sections = self::remote_companion_section_keys_for_plan( $plan );
        $activity_items = self::canonical_activity_feed( 4 );
        $events = self::notification_events_list( 6 );
        $event_items = ! empty( $events['ok'] ) && isset( $events['items'] ) && is_array( $events['items'] ) ? self::live_items_only( $events['items'] ) : array();
        $alert_rollup = self::notification_delivery_rollup( $event_items );
        $connection_status = isset( $site_summary['connection_status'] ) ? strtolower( trim( (string) $site_summary['connection_status'] ) ) : '';
        if ( isset( $receipt_inputs['connection_status'] ) && '' !== trim( (string) $receipt_inputs['connection_status'] ) ) {
            $connection_status = strtolower( trim( (string) $receipt_inputs['connection_status'] ) );
        }
        $connection_mode = isset( $site_summary['connection_mode'] ) ? strtolower( trim( (string) $site_summary['connection_mode'] ) ) : '';
        if ( isset( $receipt_inputs['connection_mode'] ) && '' !== trim( (string) $receipt_inputs['connection_mode'] ) ) {
            $connection_mode = strtolower( trim( (string) $receipt_inputs['connection_mode'] ) );
        }
        $connection_copy = self::canonical_connection_status_copy( $connection_status, $connection_mode, true );
        $site_label = isset( $site_summary['site_label'] ) ? trim( (string) $site_summary['site_label'] ) : '';
        if ( '' === $site_label ) {
            $site_label = isset( $identity['site_label'] ) ? trim( (string) $identity['site_label'] ) : 'Current site';
        }
        $site_url = isset( $site_summary['site_url'] ) ? trim( (string) $site_summary['site_url'] ) : '';
        if ( '' === $site_url ) {
            $site_url = isset( $identity['site_url'] ) ? trim( (string) $identity['site_url'] ) : trim( (string) home_url() );
        }
        $site_id = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';
        $account_id_value = trim( (string) get_option( 'opsgate_account_id', '' ) );
        $api_base_url_value = trim( (string) get_option( 'opsgate_api_base_url', '' ) );
        $identity_email_value = trim( (string) get_option( 'opsgate_identity_email', (string) ( $identity['identity_email'] ?? '' ) ) );
        $connector_pairing_token_value = self::connector_pairing_token();
        $connector_credential_present = '' !== self::connector_site_credential();
        $setup_onboarding_path = 'free';
        if ( in_array( $plan, array( 'starter', 'pro', 'agency' ), true ) || 'connected' === $connection_status || 'wp_connector' === $connection_mode ) {
            $setup_onboarding_path = 'connect';
        }
        $scope_ready = '' !== $account_id_value && '' !== $site_id && '' !== $site_url;
        $setup_needed = ! $scope_ready;
        $public_only = in_array( $plan, array( 'free', 'missing', 'unknown' ), true ) || 'public_scan' === $connection_mode || ! empty( $score['public_only'] );
        $latest_truth_is_public_only = self::remote_companion_bundle_is_public_only( $job, $artifacts );
        if ( 'free' === $plan && ! $latest_truth_is_public_only ) {
            $job = array();
            $artifacts = array();
            $score = array();
            $receipt = array();
            $receipt_inputs = array();
        }

        $score_value = isset( $score['score'] ) ? (string) $score['score'] : '—';
        $grade_value = isset( $score['grade'] ) && '' !== trim( (string) $score['grade'] ) ? ucfirst( (string) $score['grade'] ) : 'Pending';
        $run_finished = isset( $job['finished_at_utc'] ) && '' !== (string) $job['finished_at_utc'] ? self::canonical_report_datetime_label( (string) $job['finished_at_utc'] ) : 'No completed result recorded yet';
        $run_button_label = $public_only ? 'Run Public Check' : 'Run Security Scan';
        $report_formats = self::remote_companion_report_formats();
        $alert_families = self::remote_companion_alert_family_summary( $plan );
        $enabled_rules = 0;
        foreach ( $rule_items as $rule_item ) {
            if ( is_array( $rule_item ) && ! empty( $rule_item['is_enabled'] ) ) {
                ++$enabled_rules;
            }
        }
        $upgrade_link = self::next_upgrade_link_for_plan( $plan );
        $package_name = isset( $package['display_name'] ) ? trim( (string) $package['display_name'] ) : '';
        if ( '' === $package_name || 'Unknown' === $package_name ) {
            $package_name = in_array( $plan, array( 'free', 'starter', 'pro', 'agency' ), true ) ? ucfirst( $plan ) : 'Setup needed';
        }
        $package_outcome = isset( $package['buyer_outcome'] ) ? trim( (string) $package['buyer_outcome'] ) : '';
        if ( '' === $package_outcome ) {
            $package_outcome = $setup_needed
                ? 'Finish this site connection to resolve its plan, canonical site record, and live run path.'
                : 'OpsGate keeps site evidence, reports, alerts, and visibility tied to canonical API truth.';
        }
        $plan_story = in_array( $plan, array( 'free', 'starter', 'pro', 'agency' ), true )
            ? self::remote_companion_plan_story( $plan )
            : array(
                'current' => 'This installation still needs an OpsGate account and canonical site scope before the plan can be reflected here.',
                'next'    => 'Connect this site first. After scope is resolved, the companion will reflect the active tier and unlock path honestly.',
            );
        $support_export_url = admin_url( 'admin-post.php?action=opsgate_export_logs' );
        $refresh_url = self::admin_tab_url( $active_tab );
        $triage_status_poll_url = self::browser_safe_admin_url(
            'admin-ajax.php',
            array(
                'action' => 'opsgate_triage_live_status',
            )
        );
        $triage_run_ajax_url = self::browser_safe_admin_url(
            'admin-ajax.php',
            array(
                'action' => 'opsgate_run_portfolio_triage_live',
            )
        );
        $triage_live_snapshot = self::triage_live_status_snapshot();
        $triage_payload = ! empty( $triage_live_snapshot['ok'] ) ? $triage_live_snapshot : array(
            'ok' => false,
            'job_id' => '',
            'export_job_id' => '',
            'export_source_job_id' => '',
            'live_states' => array(),
            'progress_title' => 'Run status unavailable',
            'progress_copy' => $setup_needed ? 'Connect this site to an OpsGate account before starting a public check or connected scan.' : 'Refresh this companion after selecting a site scope.',
            'progress_percent' => 0,
            'progress_phase_label' => 'Waiting',
            'progress_phase_copy' => $setup_needed ? 'The run button stays disabled until account scope and the canonical site record are saved from this companion.' : 'Run progress will appear here when the canonical path is available.',
            'progress_meter_label' => '0% of the current truthful run path is complete',
            'elapsed_label' => 'No active run recorded',
            'evidence_label' => 'Evidence state not recorded',
            'phase_items' => array(
                array( 'key' => 'queued', 'state' => 'pending', 'state_label' => 'Waiting' ),
                array( 'key' => 'inventory', 'state' => 'pending', 'state_label' => 'Waiting' ),
                array( 'key' => 'updates', 'state' => 'pending', 'state_label' => 'Waiting' ),
                array( 'key' => 'vulnerabilities', 'state' => 'pending', 'state_label' => 'Waiting' ),
                array( 'key' => 'reachability', 'state' => 'pending', 'state_label' => 'Waiting' ),
                array( 'key' => 'performance', 'state' => 'pending', 'state_label' => 'Waiting' ),
                array( 'key' => 'reports', 'state' => 'pending', 'state_label' => 'Waiting' ),
                array( 'key' => 'complete', 'state' => 'pending', 'state_label' => 'Waiting' ),
            ),
        );
        $triage_run_command_states = isset( $triage_payload['live_states'] ) && is_array( $triage_payload['live_states'] ) ? $triage_payload['live_states'] : array();
        $triage_rendered_run_id = isset( $triage_payload['job_id'] ) ? (string) $triage_payload['job_id'] : '';
        $triage_rendered_export_job_id = isset( $triage_payload['export_job_id'] ) ? (string) $triage_payload['export_job_id'] : '';
        $triage_current_export_source_job_id = isset( $triage_payload['export_source_job_id'] ) ? (string) $triage_payload['export_source_job_id'] : '';
        $triage_run_command_busy = ! empty( array_intersect( $triage_run_command_states, array( 'QUEUED', 'RUNNING' ) ) );
        $triage_run_disabled = $triage_run_command_busy || $setup_needed;
        $triage_run_button_label = $triage_run_command_busy ? 'Run in progress' : $run_button_label;
        $triage_runtime_reference = isset( $job['job_id'] ) ? self::canonical_activity_reference_copy( 'Run reference', (string) $job['job_id'] ) : 'No run reference recorded yet';
        $triage_disabled_copy = $setup_needed
            ? 'Connect this installation to an OpsGate account and save the site scope before starting a truthful run from this companion.'
            : '';
        $public_value_copy = 'This public check shows what OpsGate can verify from outside your site. Connect the plugin on a paid plan to unlock internal WordPress evidence such as plugins, themes, updates, runtime details, vulnerability routing, uptime automation, alerts, reports, and remediation guidance.';
        $public_includes = array(
            'Public reachability and transport checks',
            'SSL and transport health',
            'Public availability signal',
            'Public performance snapshot',
        );
        $public_excludes = array(
            'No plugin or theme inventory',
            'No authenticated runtime or PHP truth',
            'No connected vulnerability routing',
            'No connected alert automation or remediation',
        );
        $latest_result_copy = $public_only
            ? ( ! empty( $job ) ? 'Latest public-only evidence recorded from outside the site.' : 'Run a public check to record an outside-in view of this site.' )
            : ( ! empty( $job ) ? 'Latest connected evidence recorded from the paired WordPress site.' : 'Run a security scan to record the latest connected evidence for this site.' );
        $mode_badge_label = $public_only ? 'Public-only mode' : 'Connected mode';
        $mode_source_label = $public_only ? 'Source: public-only evidence' : 'Source: connected WordPress evidence';
        $latest_source_copy = $public_only
            ? 'Free stays honest: this score never implies authenticated WordPress truth.'
            : 'Connected results stay site-scoped and read from canonical OpsGate run truth.';
        $latest_outputs_by_kind = array(
            'PDF'  => ! empty( $job['job_id'] ) ? self::canonical_latest_completed_export_for_source_kind( (string) $job['job_id'], 'report_pdf' ) : array(),
            'HTML' => ! empty( $job['job_id'] ) ? self::canonical_latest_completed_export_for_source_kind( (string) $job['job_id'], 'report_html' ) : array(),
            'CSV'  => ! empty( $job['job_id'] ) ? self::canonical_latest_completed_export_for_source_kind( (string) $job['job_id'], 'csv' ) : array(),
            'XLSX' => ! empty( $job['job_id'] ) ? self::canonical_latest_completed_export_for_source_kind( (string) $job['job_id'], 'report_xlsx' ) : array(),
        );
        $job_id = isset( $job['job_id'] ) ? trim( (string) $job['job_id'] ) : '';
        $breakdown_items = self::remote_companion_breakdown_items( $artifacts, $score, $public_only );
        $console_overview_url = self::remote_companion_console_url(
            'overview',
            $scope,
            $site_summary,
            '' !== $job_id ? array( 'opsgate_source_job_id' => $job_id ) : array()
        );
        $console_reports_url = self::remote_companion_console_url(
            'reports',
            $scope,
            $site_summary,
            '' !== $job_id ? array(
                'source_job_id'         => $job_id,
                'opsgate_source_job_id' => $job_id,
            ) : array()
        );
        $console_alerts_url = self::remote_companion_console_url( 'alerts', $scope, $site_summary );
        $console_activity_url = self::remote_companion_console_url( 'activity', $scope, $site_summary );
        $console_clients_url = self::remote_companion_console_url( 'clients', $scope, $site_summary );
        $grade_slug = strtolower( trim( (string) $grade_value ) );
        $hero_status_tone = in_array( $grade_slug, array( 'green', 'healthy' ), true ) ? 'good' : ( in_array( $grade_slug, array( 'red', 'critical' ), true ) ? 'bad' : 'warn' );
        $triage_phase_cards = array(
            'queued' => array( 'label' => 'Queued', 'state' => 'pending', 'status' => 'Waiting' ),
            'inventory' => array( 'label' => $public_only ? 'Checking public site' : 'Checking connected site', 'state' => 'pending', 'status' => 'Waiting' ),
            'vulnerabilities' => array( 'label' => 'Finalizing', 'state' => 'pending', 'status' => 'Waiting' ),
            'complete' => array( 'label' => 'Complete', 'state' => 'pending', 'status' => 'Waiting' ),
        );
        $triage_phase_items = isset( $triage_payload['phase_items'] ) && is_array( $triage_payload['phase_items'] ) ? $triage_payload['phase_items'] : array();
        foreach ( $triage_phase_items as $triage_phase_item ) {
            if ( ! is_array( $triage_phase_item ) ) {
                continue;
            }
            $triage_phase_key = isset( $triage_phase_item['key'] ) ? (string) $triage_phase_item['key'] : '';
            if ( '' === $triage_phase_key || ! isset( $triage_phase_cards[ $triage_phase_key ] ) ) {
                continue;
            }
            $triage_phase_cards[ $triage_phase_key ]['state'] = isset( $triage_phase_item['state'] ) ? (string) $triage_phase_item['state'] : 'pending';
            $triage_phase_cards[ $triage_phase_key ]['status'] = isset( $triage_phase_item['state_label'] ) ? (string) $triage_phase_item['state_label'] : 'Waiting';
        }
        $report_actions = array();
        foreach ( $latest_outputs_by_kind as $output_label => $output_item ) {
            $output_kind = 'PDF' === $output_label ? 'report_pdf' : ( 'HTML' === $output_label ? 'report_html' : ( 'CSV' === $output_label ? 'csv' : 'report_xlsx' ) );
            $output_allowed = in_array( $output_label, $report_formats['included'], true );
            $output_job_id = isset( $output_item['export_job_id'] ) ? trim( (string) $output_item['export_job_id'] ) : '';
            if ( ! $output_allowed || '' === $output_job_id ) {
                continue;
            }
            $action_mode = in_array( $output_kind, array( 'report_pdf', 'report_html' ), true ) ? 'view' : 'download';
            $action_label = in_array( $output_label, array( 'CSV', 'XLSX' ), true ) ? 'Download ' . $output_label : 'Open ' . $output_label;
            $report_actions[] = array(
                'label' => $action_label,
                'url'   => wp_nonce_url(
                    admin_url(
                        'admin-post.php?action=opsgate_download_export&kind=' . rawurlencode( $output_kind ) . '&export_job_id=' . rawurlencode( $output_job_id ) . '&mode=' . rawurlencode( $action_mode )
                    ),
                    'opsgate_download_export'
                ),
            );
        }
        $activity_preview = array_slice( $activity_items, 0, 2 );
        $plan_primary_label = 'View plan details';
        $plan_primary_url = $console_clients_url;
        if ( 'free' === $plan ) {
            $plan_primary_label = 'Connect this site';
            $plan_primary_url = self::admin_tab_url( 'settings' );
        } elseif ( 'starter' === $plan ) {
            $plan_primary_label = 'Upgrade to Pro';
            $plan_primary_url = '' !== $upgrade_link ? $upgrade_link : $console_clients_url;
        } elseif ( 'pro' === $plan ) {
            $plan_primary_label = 'View Agency options';
            $plan_primary_url = '' !== $upgrade_link ? $upgrade_link : $console_clients_url;
        } elseif ( 'agency' === $plan ) {
            $plan_primary_label = 'Open portfolio';
            $plan_primary_url = $console_clients_url;
        }
        $plan_primary_is_external = 0 === strpos( $plan_primary_url, 'http' );
        $og_theme = ( get_option( 'opsgate_ui_theme', 'light' ) === 'dark' ) ? 'dark' : 'light';
        ?>
        <div class="wrap opsgate-admin opsgate-admin-remote-companion opsgate-admin-tab-<?php echo esc_attr( $active_tab ); ?>" data-og-theme="<?php echo esc_attr( $og_theme ); ?>">
            <h1 class="wp-heading-inline">
                <span class="dashicons dashicons-shield-alt" style="color:#0073aa;vertical-align:middle;margin-right:10px;font-size:32px;"></span>
                OpsGate
            </h1>
            <hr class="wp-header-end">
            <?php if ( isset( $_GET['opsgate_settings_saved'] ) && '1' === (string) $_GET['opsgate_settings_saved'] ) : // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?>
                <?php self::render_surface_notice( 'Site connection saved. OpsGate can now resolve the canonical site scope for this companion.', 'success' ); ?>
            <?php endif; ?>
            <?php if ( isset( $_GET['opsgate_settings_error'] ) && '' !== (string) $_GET['opsgate_settings_error'] ) : // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?>
                <?php self::render_surface_notice( sanitize_text_field( rawurldecode( (string) wp_unslash( $_GET['opsgate_settings_error'] ) ) ), 'error' ); ?>
            <?php endif; ?>
            <div class="opsgate-remote-companion-shell">
                <section class="opsgate-remote-hero-band">
                    <div class="opsgate-remote-hero-band-main">
                        <span class="opsgate-remote-eyebrow">One site. One score. One primary action.</span>
                        <div class="opsgate-remote-hero-band-head">
                            <div>
                                <h2><?php echo esc_html( $site_label ); ?></h2>
                                <p><?php echo esc_html( $site_url ); ?></p>
                            </div>
                            <div class="opsgate-remote-hero-pills">
                                <span class="opsgate-remote-pill is-plan"><?php echo esc_html( $package_name ); ?></span>
                                <span class="opsgate-remote-pill"><?php echo esc_html( self::canonical_connection_mode_label( $connection_mode ?: 'public_scan' ) ); ?></span>
                                <span class="opsgate-remote-pill"><?php echo esc_html( self::canonical_connection_status_label( $connection_status ?: 'external_only' ) ); ?></span>
                            </div>
                        </div>
                        <div class="opsgate-remote-topline-grid">
                            <article class="opsgate-remote-topline-card is-<?php echo esc_attr( $hero_status_tone ); ?>">
                                <span class="opsgate-remote-stat-label">Current score</span>
                                <strong><?php echo esc_html( $score_value ); ?></strong>
                                <p><?php echo esc_html( $grade_value . ' · ' . $latest_result_copy ); ?></p>
                            </article>
                            <article class="opsgate-remote-topline-card">
                                <span class="opsgate-remote-stat-label">Latest check</span>
                                <strong><?php echo esc_html( $run_finished ); ?></strong>
                                <p><?php echo esc_html( $mode_source_label ); ?></p>
                            </article>
                            <article class="opsgate-remote-topline-card">
                                <span class="opsgate-remote-stat-label">Site scope</span>
                                <strong><?php echo esc_html( '' !== $site_id ? $site_id : 'Pending site ID' ); ?></strong>
                                <p><?php echo esc_html( $connection_copy ); ?></p>
                            </article>
                        </div>
                    </div>
                    <aside class="opsgate-remote-hero-band-actions">
                        <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="opsgate-triage-command-bar-form" data-opsgate-triage-run-form data-opsgate-triage-launch-form="1" data-opsgate-triage-run-url="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>" data-opsgate-triage-destination-url="<?php echo esc_url( $refresh_url ); ?>">
                            <?php wp_nonce_field( 'opsgate_run_portfolio_triage' ); ?>
                            <input type="hidden" name="action" value="opsgate_run_portfolio_triage" />
                            <button type="submit" class="button button-primary button-hero-primary" data-opsgate-run-button data-opsgate-run-idle-label="<?php echo esc_attr( $run_button_label ); ?>" data-opsgate-run-busy-label="Run in progress" <?php disabled( $triage_run_disabled ); ?>><?php echo esc_html( $triage_run_button_label ); ?></button>
                        </form>
                        <a class="button button-secondary" href="<?php echo esc_url( $refresh_url ); ?>">Refresh</a>
                        <?php if ( '' !== $console_overview_url ) : ?>
                        <a class="button button-secondary" href="<?php echo esc_url( $console_overview_url ); ?>" target="_blank" rel="noopener noreferrer" data-opsgate-no-ajax="1">View in OpsGate &rarr;</a>
                        <?php endif; ?>
                        <p class="opsgate-remote-hero-support-copy"><?php echo esc_html( $latest_source_copy ); ?></p>
                        <?php if ( $public_only ) : ?>
                            <p class="opsgate-remote-hero-support-copy"><?php echo esc_html( $public_value_copy ); ?></p>
                        <?php endif; ?>
                    </aside>
                </section>

                <div class="opsgate-remote-main-layout">
                    <div class="opsgate-remote-primary-column">
                        <?php if ( $setup_needed ) : ?>
                            <section id="opsgate-remote-setup" class="opsgate-remote-section">
                                <div class="opsgate-remote-section-head">
                                    <div>
                                        <span class="opsgate-remote-eyebrow">Site connection</span>
                                        <h3>Set up this site</h3>
                                        <p>Choose Free public checks or connect this site for paid connected evidence. You should not need to invent internal IDs to complete setup.</p>
                                    </div>
                                </div>
                                <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
                                    <?php wp_nonce_field( 'opsgate_save_configuration', 'opsgate_save_configuration_nonce' ); ?>
                                    <input type="hidden" name="action" value="opsgate_save_configuration" />
                                    <div class="opsgate-settings-form-grid opsgate-settings-identity-grid">
                                        <div>
                                            <label><strong>Choose a setup path</strong></label>
                                            <div class="opsgate-remote-chip-row">
                                                <label class="opsgate-remote-chip">
                                                    <input type="radio" name="opsgate_onboarding_path" value="free_public" <?php checked( 'free' === $setup_onboarding_path ); ?> />
                                                    <span>Run a Free public check</span>
                                                </label>
                                                <label class="opsgate-remote-chip">
                                                    <input type="radio" name="opsgate_onboarding_path" value="connect_paid" <?php checked( 'connect' === $setup_onboarding_path ); ?> />
                                                    <span>Connect this WordPress site to OpsGate</span>
                                                </label>
                                            </div>
                                        </div>
                                        <div>
                                            <label for="opsgate_remote_requested_plan"><strong>Connected plan</strong></label>
                                            <select id="opsgate_remote_requested_plan" name="opsgate_requested_plan">
                                                <option value="">Use existing paid plan</option>
                                                <option value="starter">Starter</option>
                                                <option value="pro">Pro</option>
                                                <option value="agency">Agency</option>
                                            </select>
                                        </div>
                                        <input type="hidden" name="opsgate_account_id" value="<?php echo esc_attr( $account_id_value ); ?>" />
                                        <input type="hidden" name="opsgate_api_base_url" value="<?php echo esc_attr( $api_base_url_value ); ?>" />
                                        <div>
                                            <label for="opsgate_remote_inbound_token"><strong>OpsGate connection key</strong></label>
                                            <input id="opsgate_remote_inbound_token" type="password" class="regular-text" name="opsgate_inbound_token" value="" placeholder="Paste the approved connection key from OpsGate onboarding." />
                                        </div>
                                        <div>
                                            <label for="opsgate_remote_identity_email"><strong>Contact email</strong></label>
                                            <input id="opsgate_remote_identity_email" type="email" class="regular-text" name="opsgate_identity_email" value="<?php echo esc_attr( $identity_email_value ); ?>" />
                                        </div>
                                        <div>
                                            <label for="opsgate_remote_site_label"><strong>Site label</strong></label>
                                            <input id="opsgate_remote_site_label" type="text" class="regular-text" name="opsgate_site_label" value="<?php echo esc_attr( $site_label ); ?>" />
                                        </div>
                                        <div>
                                            <label for="opsgate_remote_site_url"><strong>Site URL</strong></label>
                                            <input id="opsgate_remote_site_url" type="url" class="regular-text" name="opsgate_site_url" value="<?php echo esc_attr( $site_url ); ?>" />
                                        </div>
                                    </div>
                                    <p class="opsgate-remote-support-note">Free saves this scope as external-only so the first public check can run truthfully. Paid connected setup saves the same canonical site scope and then completes pairing for connected evidence.</p>
                                    <?php submit_button( 'Save site connection', 'secondary', 'submit', false ); ?>
                                </form>
                            </section>
                        <?php endif; ?>

                        <section class="opsgate-remote-section">
                            <div class="opsgate-remote-section-head">
                                <div>
                                    <span class="opsgate-remote-eyebrow">Score breakdown</span>
                                    <h3><?php echo esc_html( $public_only ? 'Public check breakdown' : 'Connected evidence breakdown' ); ?></h3>
                                    <p><?php echo esc_html( $public_only ? 'This public check stays outside-in on Free. Connected WordPress evidence appears only after pairing on a paid plan.' : 'This site companion keeps the latest connected evidence readable at a glance and hands deeper review to OpsGate.' ); ?></p>
                                </div>
                            </div>
                            <div class="opsgate-remote-breakdown-grid">
                                <?php foreach ( $breakdown_items as $breakdown_item ) : ?>
                                    <article class="opsgate-remote-breakdown-card is-<?php echo esc_attr( (string) ( $breakdown_item['tone'] ?? 'neutral' ) ); ?>">
                                        <span class="opsgate-remote-stat-label"><?php echo esc_html( (string) ( $breakdown_item['label'] ?? 'Recorded evidence' ) ); ?></span>
                                        <strong><?php echo esc_html( (string) ( $breakdown_item['value'] ?? 'Pending' ) ); ?></strong>
                                        <p><?php echo esc_html( (string) ( $breakdown_item['copy'] ?? '' ) ); ?></p>
                                        <span class="opsgate-remote-breakdown-meta"><?php echo esc_html( (string) ( $breakdown_item['meta'] ?? '' ) ); ?></span>
                                    </article>
                                <?php endforeach; ?>
                            </div>
                        </section>

                        <section class="opsgate-remote-section">
                            <div class="opsgate-remote-section-head">
                                <div>
                                    <span class="opsgate-remote-eyebrow">Run progress</span>
                                    <h3 data-opsgate-triage-progress-title="1"><?php echo esc_html( $triage_payload['progress_title'] ?? 'Latest check' ); ?></h3>
                                    <p><?php echo esc_html( '' !== $triage_disabled_copy ? $triage_disabled_copy : ( $triage_payload['progress_copy'] ?? 'Run progress will update here during the latest check.' ) ); ?></p>
                                </div>
                            </div>
                            <div id="opsgate-triage-live-panel" class="opsgate-remote-live-panel" data-opsgate-live-states="<?php echo esc_attr( implode( ',', $triage_run_command_states ) ); ?>" data-opsgate-refresh-url="<?php echo esc_url( $refresh_url ); ?>" data-opsgate-poll-url="<?php echo esc_url( $triage_status_poll_url ); ?>" data-opsgate-run-url="<?php echo esc_url( $triage_run_ajax_url ); ?>" data-opsgate-current-job-id="<?php echo esc_attr( $triage_rendered_run_id ); ?>" data-opsgate-current-export-job-id="<?php echo esc_attr( $triage_rendered_export_job_id ); ?>" data-opsgate-current-export-source-job-id="<?php echo esc_attr( $triage_current_export_source_job_id ); ?>" data-opsgate-rendered-run-id="<?php echo esc_attr( $triage_rendered_run_id ); ?>" data-opsgate-rendered-export-job-id="<?php echo esc_attr( $triage_rendered_export_job_id ); ?>" data-opsgate-reload-workspace-on-settle="1">
                                <span class="opsgate-triage-command-runtime-note" data-opsgate-triage-runtime-note hidden="hidden"></span>
                                <div class="opsgate-remote-progress-grid">
                                    <div class="opsgate-remote-progress-main">
                                        <p class="opsgate-remote-progress-copy" data-opsgate-triage-progress-copy="1"><?php echo esc_html( '' !== $triage_disabled_copy ? $triage_disabled_copy : ( $triage_payload['progress_copy'] ?? 'Live progress will appear here.' ) ); ?></p>
                                        <div class="opsgate-remote-progress-meter" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="<?php echo esc_attr( (string) ( $triage_payload['progress_percent'] ?? 0 ) ); ?>" aria-label="<?php echo esc_attr( $triage_payload['progress_meter_label'] ?? 'Run progress' ); ?>" data-opsgate-triage-progress-meter="1">
                                            <span class="opsgate-remote-progress-fill" style="width:<?php echo esc_attr( (string) ( $triage_payload['progress_percent'] ?? 0 ) ); ?>%;" data-opsgate-triage-progress-fill="1"></span>
                                        </div>
                                        <div class="opsgate-remote-progress-meta">
                                            <span data-opsgate-triage-progress-phase="1"><?php echo esc_html( $triage_payload['progress_phase_label'] ?? 'Waiting' ); ?></span>
                                            <span data-opsgate-triage-progress-elapsed="1"><?php echo esc_html( $triage_payload['elapsed_label'] ?? 'No active run recorded' ); ?></span>
                                            <span data-opsgate-triage-progress-evidence="1"><?php echo esc_html( $triage_payload['evidence_label'] ?? 'Evidence state not recorded' ); ?></span>
                                        </div>
                                        <div class="opsgate-remote-phase-grid">
                                            <?php foreach ( $triage_phase_cards as $triage_phase_key => $triage_phase_card ) : ?>
                                                <article class="opsgate-remote-phase-card is-<?php echo esc_attr( $triage_phase_card['state'] ); ?>" data-opsgate-triage-phase-key="<?php echo esc_attr( $triage_phase_key ); ?>">
                                                    <span class="opsgate-remote-phase-title"><?php echo esc_html( $triage_phase_card['label'] ); ?></span>
                                                    <span class="opsgate-remote-phase-status" data-opsgate-triage-phase-status="1"><?php echo esc_html( $triage_phase_card['status'] ); ?></span>
                                                </article>
                                            <?php endforeach; ?>
                                        </div>
                                    </div>
                                    <aside class="opsgate-remote-progress-side">
                                        <span class="opsgate-remote-eyebrow">Current phase</span>
                                        <strong data-opsgate-triage-aside-title="1"><?php echo esc_html( $triage_payload['progress_phase_label'] ?? 'Waiting' ); ?></strong>
                                        <p data-opsgate-triage-aside-copy="1"><?php echo esc_html( $triage_payload['progress_phase_copy'] ?? 'Run progress will update here as the canonical job changes state.' ); ?></p>
                                        <span class="opsgate-remote-breakdown-meta"><?php echo esc_html( $triage_runtime_reference ); ?></span>
                                    </aside>
                                </div>
                            </div>
                        </section>

                        <section id="opsgate-remote-reports" class="opsgate-remote-section">
                            <div class="opsgate-remote-section-head">
                                <div>
                                    <span class="opsgate-remote-eyebrow">Reports</span>
                                    <h3><?php echo esc_html( $public_only ? 'Public summary' : 'Reports for this site' ); ?></h3>
                                    <p><?php echo esc_html( $public_only ? 'Free can explain the latest public-only results here. Connected reports unlock after you pair the plugin on a paid plan.' : ( ! empty( $report_actions ) ? 'Latest reports for this site are ready to open or download.' : 'The latest connected run is recorded. Open Reports in OpsGate to generate or refresh report outputs.' ) ); ?></p>
                                </div>
                            </div>
                            <div class="opsgate-remote-chip-row">
                                <?php foreach ( $report_formats['included'] as $included_format ) : ?>
                                    <span class="opsgate-remote-chip is-good"><?php echo esc_html( $included_format ); ?></span>
                                <?php endforeach; ?>
                                <?php foreach ( $report_formats['locked'] as $locked_format ) : ?>
                                    <span class="opsgate-remote-chip"><?php echo esc_html( $locked_format . ' locked' ); ?></span>
                                <?php endforeach; ?>
                            </div>
                            <div class="opsgate-remote-action-card-grid">
                                <article class="opsgate-remote-action-card">
                                    <span class="opsgate-remote-stat-label"><?php echo esc_html( $public_only ? 'Public summary' : 'Latest report outputs' ); ?></span>
                                    <strong><?php echo esc_html( $public_only ? ( ! empty( $job ) ? 'Latest public check recorded' : 'Run a public check first' ) : ( ! empty( $report_actions ) ? 'Ready to open' : 'Generate reports in OpsGate' ) ); ?></strong>
                                    <p><?php echo esc_html( $public_only ? $public_value_copy : 'Open the latest site-scoped outputs directly here or continue in OpsGate for full report management.' ); ?></p>
                                    <div class="opsgate-remote-card-actions">
                                        <?php foreach ( $report_actions as $report_action ) : ?>
                                            <a class="button button-secondary" href="<?php echo esc_url( $report_action['url'] ); ?>"><?php echo esc_html( $report_action['label'] ); ?></a>
                                        <?php endforeach; ?>
                                        <?php if ( '' !== ( $public_only ? $console_overview_url : $console_reports_url ) ) : ?>
                                        <a class="button button-secondary" href="<?php echo esc_url( $public_only ? $console_overview_url : $console_reports_url ); ?>" target="_blank" rel="noopener noreferrer" data-opsgate-no-ajax="1"><?php echo esc_html( $public_only ? 'View report in OpsGate →' : 'Reports →' ); ?></a>
                                        <?php endif; ?>
                                    </div>
                                </article>
                            </div>
                        </section>
                    </div>

                    <div class="opsgate-remote-secondary-column">
                        <section id="opsgate-remote-alerts" class="opsgate-remote-section">
                            <div class="opsgate-remote-section-head">
                                <div>
                                    <span class="opsgate-remote-eyebrow">Alerts</span>
                                    <h3><?php echo esc_html( $alert_rollup['latest_status'] ?? 'No alerts yet' ); ?></h3>
                                    <p><?php echo esc_html( ! empty( $alert_families['included'] ) ? 'Included on ' . ucfirst( $plan ) . ': ' . implode( ', ', $alert_families['included'] ) . '.' : 'Alerts unlock after you connect this site on a paid plan.' ); ?></p>
                                </div>
                            </div>
                            <div class="opsgate-remote-card-actions">
                                <?php if ( '' !== $console_alerts_url ) : ?>
                                <a class="button button-secondary" href="<?php echo esc_url( $console_alerts_url ); ?>" target="_blank" rel="noopener noreferrer" data-opsgate-no-ajax="1">Alerts &rarr;</a>
                                <?php endif; ?>
                            </div>
                        </section>

                        <section id="opsgate-remote-activity" class="opsgate-remote-section">
                            <div class="opsgate-remote-section-head">
                                <div>
                                    <span class="opsgate-remote-eyebrow">Activity</span>
                                    <h3>Latest site activity</h3>
                                    <p>Only the latest site events stay here. Full history opens in OpsGate.</p>
                                </div>
                            </div>
                            <div class="opsgate-remote-activity-list compact">
                                <?php if ( empty( $activity_preview ) ) : ?>
                                    <article class="opsgate-remote-activity-card is-empty">
                                        <strong>No recent site activity is recorded yet.</strong>
                                        <p>Run a public check or connected site triage to populate this companion timeline.</p>
                                    </article>
                                <?php else : ?>
                                    <?php foreach ( $activity_preview as $activity_item ) : ?>
                                        <article class="opsgate-remote-activity-card">
                                            <div class="opsgate-remote-activity-top">
                                                <strong><?php echo esc_html( isset( $activity_item['label'] ) ? (string) $activity_item['label'] : 'Activity' ); ?></strong>
                                                <span class="opsgate-remote-chip"><?php echo esc_html( isset( $activity_item['status'] ) ? (string) $activity_item['status'] : 'Recorded' ); ?></span>
                                            </div>
                                            <p><?php echo esc_html( isset( $activity_item['details'] ) ? (string) $activity_item['details'] : 'Site activity recorded.' ); ?></p>
                                            <div class="opsgate-remote-meta-list">
                                                <span><?php echo esc_html( isset( $activity_item['when'] ) ? (string) $activity_item['when'] : '—' ); ?></span>
                                            </div>
                                        </article>
                                    <?php endforeach; ?>
                                <?php endif; ?>
                            </div>
                            <div class="opsgate-remote-card-actions">
                                <?php if ( '' !== $console_activity_url ) : ?>
                                <a class="button button-secondary" href="<?php echo esc_url( $console_activity_url ); ?>" target="_blank" rel="noopener noreferrer" data-opsgate-no-ajax="1">Activity &rarr;</a>
                                <?php endif; ?>
                            </div>
                        </section>

                        <section id="opsgate-remote-plan" class="opsgate-remote-section">
                            <div class="opsgate-remote-section-head">
                                <div>
                                    <span class="opsgate-remote-eyebrow">Plan</span>
                                    <h3><?php echo esc_html( $package_name ); ?></h3>
                                    <p><?php echo esc_html( $plan_story['current'] ); ?></p>
                                </div>
                            </div>
                            <div class="opsgate-remote-plan-summary">
                                <p><?php echo esc_html( $plan_story['next'] ); ?></p>
                                <div class="opsgate-remote-card-actions">
                                    <a class="button button-primary" href="<?php echo esc_url( $plan_primary_url ); ?>"<?php echo $plan_primary_is_external ? ' target="_blank" rel="noopener noreferrer" data-opsgate-no-ajax="1"' : ''; ?>><?php echo esc_html( $plan_primary_label ); ?></a>
                                </div>
                            </div>
                        </section>

                        <section id="opsgate-remote-support" class="opsgate-remote-section is-demoted">
                            <div class="opsgate-remote-section-head">
                                <div>
                                    <span class="opsgate-remote-eyebrow">Support / Diagnostics</span>
                                    <h3>Support diagnostics</h3>
                                    <p>Support diagnostics stay visually demoted, support-only, and never become canonical product truth for this site.</p>
                                </div>
                            </div>
                            <div class="opsgate-remote-card-actions">
                                <a id="opsgate-support-export-button" class="button button-secondary" href="<?php echo esc_url( wp_nonce_url( $support_export_url, 'opsgate_export_logs' ) ); ?>">Download Support Export</a>
                                <a class="button button-secondary" href="<?php echo esc_url( $console_overview_url ); ?>" target="_blank" rel="noopener noreferrer" data-opsgate-no-ajax="1">Open in OpsGate</a>
                            </div>
                            <p id="opsgate-support-export-status" class="description opsgate-remote-support-note">Support export stays non-canonical and support-only.</p>
                            <details class="opsgate-remote-support-details">
                                <summary>Show support diagnostics</summary>
                                <div class="opsgate-remote-support-grid">
                                    <div>
                                        <span class="opsgate-remote-stat-label">Site URL</span>
                                        <strong><?php echo esc_html( $site_url ); ?></strong>
                                    </div>
                                    <div>
                                        <span class="opsgate-remote-stat-label">Site ID</span>
                                        <strong><?php echo esc_html( '' !== $site_id ? $site_id : 'Pending' ); ?></strong>
                                    </div>
                                    <div>
                                        <span class="opsgate-remote-stat-label">Connection mode</span>
                                        <strong><?php echo esc_html( self::canonical_connection_mode_label( $connection_mode ?: 'public_scan' ) ); ?></strong>
                                    </div>
                                    <div>
                                        <span class="opsgate-remote-stat-label">Connector version</span>
                                        <strong><?php echo esc_html( '' !== (string) ( $site_summary['connector_version'] ?? '' ) ? (string) $site_summary['connector_version'] : 'Not recorded' ); ?></strong>
                                    </div>
                                    <?php if ( ! $public_only ) : ?>
                                        <div>
                                            <span class="opsgate-remote-stat-label">Pairing token</span>
                                            <strong><?php echo esc_html( '' !== $connector_pairing_token_value ? $connector_pairing_token_value : 'Not issued yet' ); ?></strong>
                                        </div>
                                        <div>
                                            <span class="opsgate-remote-stat-label">Connector credential</span>
                                            <strong><?php echo esc_html( $connector_credential_present ? 'Stored securely' : 'Not stored' ); ?></strong>
                                        </div>
                                    <?php endif; ?>
                                </div>
                                <?php if ( ! $public_only ) : ?>
                                    <div class="opsgate-remote-card-actions" style="margin-top:16px;">
                                        <?php
                                        $pairing_form_obs_id = isset( $_GET['opsgate_onboarding_session_id'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_onboarding_session_id'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
                                        $pairing_form_obs_token = isset( $_GET['opsgate_onboarding_token'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_onboarding_token'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
                                        ?>
                                        <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:0;">
                                            <?php wp_nonce_field( 'opsgate_create_pairing_session', 'opsgate_create_pairing_session_nonce' ); ?>
                                            <input type="hidden" name="action" value="opsgate_create_pairing_session" />
                                            <?php if ( '' !== $pairing_form_obs_id ) : ?>
                                                <input type="hidden" name="opsgate_onboarding_session_id" value="<?php echo esc_attr( $pairing_form_obs_id ); ?>" />
                                                <input type="hidden" name="opsgate_onboarding_token" value="<?php echo esc_attr( $pairing_form_obs_token ); ?>" />
                                            <?php endif; ?>
                                            <button type="submit" class="button button-secondary">Create Pairing Material</button>
                                        </form>
                                        <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:0;">
                                            <?php wp_nonce_field( 'opsgate_complete_pairing', 'opsgate_complete_pairing_nonce' ); ?>
                                            <input type="hidden" name="action" value="opsgate_complete_pairing" />
                                            <input type="hidden" name="opsgate_pairing_token" value="<?php echo esc_attr( $connector_pairing_token_value ); ?>" />
                                            <button type="submit" class="button" <?php disabled( '' === $connector_pairing_token_value ); ?>>Complete Pairing</button>
                                        </form>
                                        <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:0;">
                                            <?php wp_nonce_field( 'opsgate_rotate_connector_credential', 'opsgate_rotate_connector_credential_nonce' ); ?>
                                            <input type="hidden" name="action" value="opsgate_rotate_connector_credential" />
                                            <button type="submit" class="button" <?php disabled( ! $connector_credential_present ); ?>>Rotate Credential</button>
                                        </form>
                                        <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:0;">
                                            <?php wp_nonce_field( 'opsgate_revoke_connector_credential', 'opsgate_revoke_connector_credential_nonce' ); ?>
                                            <input type="hidden" name="action" value="opsgate_revoke_connector_credential" />
                                            <button type="submit" class="button" <?php disabled( ! $connector_credential_present ); ?>>Revoke Credential</button>
                                        </form>
                                    </div>
                                    <p class="opsgate-remote-support-note">Paid connected mode completes the connector handshake from this WordPress host using site-scoped pairing material and then stores the connector credential locally.</p>
                                <?php endif; ?>
                                <?php if ( ! empty( $site_summary['last_connection_error'] ) ) : ?>
                                    <p class="opsgate-remote-support-warning"><?php echo esc_html( (string) $site_summary['last_connection_error'] ); ?></p>
                                <?php endif; ?>
                            </details>
                        </section>
                    </div>
                </div>
            </div>
        </div>
        <?php
        return;
        ?>
        <div class="wrap opsgate-admin opsgate-admin-remote-companion opsgate-admin-tab-<?php echo esc_attr( $active_tab ); ?>">
            <h1 class="wp-heading-inline">
                <span class="dashicons dashicons-shield-alt" style="color:#0073aa;vertical-align:middle;margin-right:10px;font-size:32px;"></span>
                OpsGate
            </h1>
            <hr class="wp-header-end">
            <?php if ( isset( $_GET['opsgate_settings_saved'] ) && '1' === (string) $_GET['opsgate_settings_saved'] ) : // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?>
                <?php self::render_surface_notice( 'Site connection saved. OpsGate can now resolve the canonical site scope for this companion.', 'success' ); ?>
            <?php endif; ?>
            <?php if ( isset( $_GET['opsgate_settings_error'] ) && '' !== (string) $_GET['opsgate_settings_error'] ) : // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?>
                <?php self::render_surface_notice( sanitize_text_field( rawurldecode( (string) wp_unslash( $_GET['opsgate_settings_error'] ) ) ), 'error' ); ?>
            <?php endif; ?>

            <div class="opsgate-remote-companion-shell">
                <section class="opsgate-remote-hero">
                    <div class="opsgate-remote-hero-main">
                        <span class="opsgate-remote-eyebrow">Compact site companion</span>
                        <div class="opsgate-remote-hero-heading">
                            <div>
                                <h2><?php echo esc_html( $site_label ); ?></h2>
                                <p><?php echo esc_html( $package_outcome ); ?></p>
                            </div>
                            <div class="opsgate-remote-hero-pills">
                                <span class="opsgate-remote-pill is-plan"><?php echo esc_html( $package_name ); ?></span>
                                <span class="opsgate-remote-pill"><?php echo esc_html( $mode_badge_label ); ?></span>
                                <span class="opsgate-remote-pill"><?php echo esc_html( self::canonical_connection_status_label( $connection_status ?: 'external_only' ) ); ?></span>
                            </div>
                        </div>
                        <div class="opsgate-remote-hero-grid">
                            <article class="opsgate-remote-stat-card">
                                <span class="opsgate-remote-stat-label">Connection / Mode</span>
                                <strong><?php echo esc_html( self::canonical_connection_mode_label( $connection_mode ?: 'public_scan' ) ); ?></strong>
                                <p><?php echo esc_html( $connection_copy ); ?></p>
                            </article>
                            <article class="opsgate-remote-stat-card">
                                <span class="opsgate-remote-stat-label">Latest Result</span>
                                <strong><?php echo esc_html( $score_value . ' / ' . $grade_value ); ?></strong>
                                <p><?php echo esc_html( $latest_result_copy ); ?></p>
                            </article>
                            <article class="opsgate-remote-stat-card">
                                <span class="opsgate-remote-stat-label">Latest Timestamp</span>
                                <strong><?php echo esc_html( $run_finished ); ?></strong>
                                <p><?php echo esc_html( $mode_source_label ); ?></p>
                            </article>
                            <article class="opsgate-remote-stat-card">
                                <span class="opsgate-remote-stat-label">Reports on this plan</span>
                                <strong><?php echo esc_html( ! empty( $report_formats['included'] ) ? implode( ' / ', $report_formats['included'] ) : 'Locked' ); ?></strong>
                                <p><?php echo esc_html( ! empty( $report_formats['included'] ) ? 'Reports ready on this plan.' : 'Connected reporting unlocks on paid connected tiers.' ); ?></p>
                            </article>
                        </div>
                    </div>
                    <aside class="opsgate-remote-hero-side">
                        <div class="opsgate-remote-side-card">
                            <span class="opsgate-remote-eyebrow">Site scope</span>
                            <strong><?php echo esc_html( $site_url ); ?></strong>
                            <p><?php echo esc_html( '' !== $site_id ? 'Site ID ' . $site_id : 'Canonical site ID will appear after scope resolution.' ); ?></p>
                            <p><?php echo esc_html( $latest_source_copy ); ?></p>
                        </div>
                        <?php if ( $public_only ) : ?>
                            <div class="opsgate-remote-side-card is-soft">
                                <span class="opsgate-remote-eyebrow">What Free shows honestly</span>
                                <p><?php echo esc_html( $public_value_copy ); ?></p>
                            </div>
                        <?php else : ?>
                            <div class="opsgate-remote-side-card is-soft">
                                <span class="opsgate-remote-eyebrow">Connected evidence path</span>
                                <p>Connected runs can include inventory, update drift, plugin advisory coverage, runtime details, report packaging, alert routing, and activity history for this site.</p>
                            </div>
                        <?php endif; ?>
                    </aside>
                </section>

                <section class="opsgate-remote-summary-grid">
                    <?php if ( in_array( 'connection', $sections, true ) ) : ?>
                        <article class="opsgate-remote-summary-card">
                            <span class="opsgate-remote-eyebrow">Connection / Mode</span>
                            <h3><?php echo esc_html( self::canonical_connection_status_label( $connection_status ?: 'external_only' ) ); ?></h3>
                            <p><?php echo esc_html( $connection_copy ); ?></p>
                            <div class="opsgate-remote-card-actions">
                                <a class="button button-secondary" href="<?php echo esc_url( $setup_needed ? '#opsgate-remote-setup' : '#opsgate-remote-run' ); ?>"><?php echo esc_html( $setup_needed ? 'Connect this site' : ( $public_only ? 'Open public check' : 'Open live triage' ) ); ?></a>
                                <?php if ( $public_only && '' !== $upgrade_link ) : ?>
                                    <a class="button" href="<?php echo esc_url( $upgrade_link ); ?>" target="_blank" rel="noopener noreferrer">Upgrade to unlock connected evidence</a>
                                <?php else : ?>
                                    <a class="button" href="#opsgate-remote-plan">View plan details</a>
                                <?php endif; ?>
                            </div>
                        </article>
                    <?php endif; ?>

                    <?php if ( in_array( 'site_status', $sections, true ) ) : ?>
                        <article class="opsgate-remote-summary-card">
                            <span class="opsgate-remote-eyebrow">Site Status / Latest Result</span>
                            <h3><?php echo esc_html( $score_value . ' / ' . $grade_value ); ?></h3>
                            <p><?php echo esc_html( $latest_result_copy ); ?></p>
                            <div class="opsgate-remote-meta-list">
                                <span><?php echo esc_html( $run_finished ); ?></span>
                                <span><?php echo esc_html( $mode_source_label ); ?></span>
                                <span><?php echo esc_html( $triage_runtime_reference ); ?></span>
                            </div>
                        </article>
                    <?php endif; ?>

                    <?php if ( in_array( 'report_summary', $sections, true ) || in_array( 'public_history', $sections, true ) ) : ?>
                        <article class="opsgate-remote-summary-card">
                            <span class="opsgate-remote-eyebrow">Reports</span>
                            <h3><?php echo esc_html( $report_formats['headline'] ); ?></h3>
                            <p><?php echo esc_html( $public_only ? 'Free keeps reports limited to public-only results and does not include connected exports.' : 'Use the latest site-scoped run to review or share the report formats unlocked on this plan.' ); ?></p>
                            <div class="opsgate-remote-card-actions">
                                <a class="button button-secondary" href="#opsgate-remote-reports">Open report summary</a>
                                <?php if ( $public_only && '' !== $upgrade_link ) : ?>
                                    <a class="button" href="<?php echo esc_url( $upgrade_link ); ?>" target="_blank" rel="noopener noreferrer">Upgrade for connected reports</a>
                                <?php endif; ?>
                            </div>
                        </article>
                    <?php endif; ?>

                    <?php if ( in_array( 'alert_summary', $sections, true ) ) : ?>
                        <article class="opsgate-remote-summary-card">
                            <span class="opsgate-remote-eyebrow">Alerts</span>
                            <h3><?php echo esc_html( $alert_rollup['headline'] ?? 'No alert activity recorded' ); ?></h3>
                            <p><?php echo esc_html( ! empty( $alert_families['included'] ) ? implode( ' / ', $alert_families['included'] ) . ' included on this plan.' : 'No connected alert automation is included on this plan.' ); ?></p>
                            <div class="opsgate-remote-card-actions">
                                <a class="button button-secondary" href="#opsgate-remote-alerts">Open alert summary</a>
                                <a class="button" href="#opsgate-remote-plan"><?php echo esc_html( ! empty( $alert_families['locked'] ) ? 'See what unlocks next' : 'Review plan coverage' ); ?></a>
                            </div>
                        </article>
                    <?php endif; ?>

                    <?php if ( in_array( 'activity_summary', $sections, true ) ) : ?>
                        <article class="opsgate-remote-summary-card">
                            <span class="opsgate-remote-eyebrow">Activity</span>
                            <h3><?php echo esc_html( sprintf( '%d recent item%s', count( $activity_items ), 1 === count( $activity_items ) ? '' : 's' ) ); ?></h3>
                            <p>Recent site-scoped run, report, and delivery activity stays visible here without turning this plugin into an account-wide console.</p>
                            <div class="opsgate-remote-card-actions">
                                <a class="button button-secondary" href="#opsgate-remote-activity">Open activity</a>
                                <a class="button" href="#opsgate-remote-support">Open support diagnostics</a>
                            </div>
                        </article>
                    <?php endif; ?>
                </section>

                <section id="opsgate-remote-run" class="opsgate-remote-section">
                    <div class="opsgate-remote-section-head">
                        <div>
                            <span class="opsgate-remote-eyebrow"><?php echo esc_html( $public_only ? 'Primary action' : 'Connected triage action' ); ?></span>
                            <h3><?php echo esc_html( $run_button_label ); ?></h3>
                            <p><?php echo esc_html( $public_only ? 'Queue a fresh public-only check and watch the status change in place until the latest score, timestamp, and summary are refreshed.' : 'Queue a fresh connected site scan and watch the latest score, timestamp, and summary refresh without manually reloading this page.' ); ?></p>
                        </div>
                    </div>

                    <?php if ( $public_only ) : ?>
                        <div class="opsgate-remote-explainer-grid">
                            <article class="opsgate-remote-explainer-card">
                                <span class="opsgate-remote-explainer-title">What OpsGate can see from outside</span>
                                <ul>
                                    <?php foreach ( $public_includes as $public_include ) : ?>
                                        <li><?php echo esc_html( $public_include ); ?></li>
                                    <?php endforeach; ?>
                                </ul>
                            </article>
                            <article class="opsgate-remote-explainer-card is-locked">
                                <span class="opsgate-remote-explainer-title">What Free does not claim</span>
                                <ul>
                                    <?php foreach ( $public_excludes as $public_exclude ) : ?>
                                        <li><?php echo esc_html( $public_exclude ); ?></li>
                                    <?php endforeach; ?>
                                </ul>
                            </article>
                        </div>
                    <?php endif; ?>
                    <?php if ( $setup_needed ) : ?>
                        <div id="opsgate-remote-setup" class="opsgate-remote-summary-card">
                            <span class="opsgate-remote-eyebrow">Connection setup</span>
                            <h3>Connect this installation before running</h3>
                            <p><?php echo esc_html( $triage_disabled_copy ); ?></p>
                            <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="opsgate-settings-form opsgate-settings-form-spacing">
                                <?php wp_nonce_field( 'opsgate_save_configuration', 'opsgate_save_configuration_nonce' ); ?>
                                <input type="hidden" name="action" value="opsgate_save_configuration" />
                                <div class="opsgate-settings-form-grid opsgate-settings-identity-grid">
                                    <div>
                                        <label><strong>Choose a setup path</strong></label>
                                        <div class="opsgate-remote-chip-row">
                                            <label class="opsgate-remote-chip">
                                                <input type="radio" name="opsgate_onboarding_path" value="free_public" <?php checked( 'free' === $setup_onboarding_path ); ?> />
                                                <span>Run a Free public check</span>
                                            </label>
                                            <label class="opsgate-remote-chip">
                                                <input type="radio" name="opsgate_onboarding_path" value="connect_paid" <?php checked( 'connect' === $setup_onboarding_path ); ?> />
                                                <span>Connect this WordPress site to OpsGate</span>
                                            </label>
                                        </div>
                                    </div>
                                    <div>
                                        <label for="opsgate_remote_requested_plan"><strong>Connected plan</strong></label>
                                        <select id="opsgate_remote_requested_plan" name="opsgate_requested_plan">
                                            <option value="">Use existing paid plan</option>
                                            <option value="starter">Starter</option>
                                            <option value="pro">Pro</option>
                                            <option value="agency">Agency</option>
                                        </select>
                                        <p class="description">Used only for the paid connect path when this site is being onboarded before an entitlement snapshot already exists.</p>
                                    </div>
                                    <input type="hidden" name="opsgate_account_id" value="<?php echo esc_attr( $account_id_value ); ?>" />
                                    <input type="hidden" name="opsgate_api_base_url" value="<?php echo esc_attr( $api_base_url_value ); ?>" />
                                    <div>
                                        <label for="opsgate_remote_inbound_token"><strong>OpsGate connection key</strong></label>
                                        <input id="opsgate_remote_inbound_token" type="password" class="regular-text" name="opsgate_inbound_token" value="" placeholder="Paste the approved connection key from OpsGate onboarding." />
                                    </div>
                                    <div>
                                        <label for="opsgate_remote_identity_email"><strong>Contact email</strong></label>
                                        <input id="opsgate_remote_identity_email" type="email" class="regular-text" name="opsgate_identity_email" value="<?php echo esc_attr( $identity_email_value ); ?>" />
                                    </div>
                                    <div>
                                        <label for="opsgate_remote_site_label"><strong>Site label</strong></label>
                                        <input id="opsgate_remote_site_label" type="text" class="regular-text" name="opsgate_site_label" value="<?php echo esc_attr( $site_label ); ?>" />
                                    </div>
                                    <div>
                                        <label for="opsgate_remote_site_url"><strong>Site URL</strong></label>
                                        <input id="opsgate_remote_site_url" type="url" class="regular-text" name="opsgate_site_url" value="<?php echo esc_attr( $site_url ); ?>" />
                                    </div>
                                </div>
                                <p class="opsgate-remote-support-note">Free saves this scope with an explicit external-only entitlement so the first public check can run truthfully. The paid connect path saves the same canonical site scope, records the requested paid plan when needed, and then adds pairing for connected evidence.</p>
                                <?php submit_button( 'Save site connection', 'secondary', 'submit', false ); ?>
                            </form>
                        </div>
                    <?php endif; ?>

                    <div id="opsgate-triage-live-panel" class="opsgate-remote-live-panel" data-opsgate-live-states="<?php echo esc_attr( implode( ',', $triage_run_command_states ) ); ?>" data-opsgate-refresh-url="<?php echo esc_url( $refresh_url ); ?>" data-opsgate-poll-url="<?php echo esc_url( $triage_status_poll_url ); ?>" data-opsgate-run-url="<?php echo esc_url( $triage_run_ajax_url ); ?>" data-opsgate-current-job-id="<?php echo esc_attr( $triage_rendered_run_id ); ?>" data-opsgate-current-export-job-id="<?php echo esc_attr( $triage_rendered_export_job_id ); ?>" data-opsgate-current-export-source-job-id="<?php echo esc_attr( $triage_current_export_source_job_id ); ?>" data-opsgate-rendered-run-id="<?php echo esc_attr( $triage_rendered_run_id ); ?>" data-opsgate-rendered-export-job-id="<?php echo esc_attr( $triage_rendered_export_job_id ); ?>" data-opsgate-reload-workspace-on-settle="1">
                        <div class="opsgate-triage-command-bar opsgate-remote-command-bar">
                            <div class="opsgate-triage-command-bar-copy">
                                <span class="opsgate-triage-eyebrow"><?php echo esc_html( $public_only ? 'Public check progress' : 'Run progress' ); ?></span>
                                <strong data-opsgate-triage-progress-title="1"><?php echo esc_html( $triage_payload['progress_title'] ?? 'Latest run status' ); ?></strong>
                                <span data-opsgate-triage-command-status-copy="1"><?php echo esc_html( '' !== $triage_disabled_copy ? $triage_disabled_copy : ( $triage_payload['progress_copy'] ?? 'Live status will appear here.' ) ); ?></span>
                                <span class="opsgate-triage-command-runtime-note" data-opsgate-triage-runtime-note hidden="hidden"></span>
                            </div>
                            <div class="opsgate-triage-command-bar-actions">
                                <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="opsgate-triage-command-bar-form" data-opsgate-triage-run-form data-opsgate-triage-launch-form="1" data-opsgate-triage-run-url="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>" data-opsgate-triage-destination-url="<?php echo esc_url( $refresh_url ); ?>">
                                    <input type="hidden" name="action" value="opsgate_run_portfolio_triage" />
                                    <?php wp_nonce_field( 'opsgate_run_portfolio_triage' ); ?>
                                    <button type="submit" class="button button-primary opsgate-triage-action-primary opsgate-triage-command-run-button" data-opsgate-run-button data-opsgate-run-idle-label="<?php echo esc_attr( $run_button_label ); ?>" data-opsgate-run-busy-label="Run in progress" <?php disabled( $triage_run_disabled ); ?>><?php echo esc_html( $triage_run_button_label ); ?></button>
                                </form>
                                <a class="button button-secondary opsgate-triage-command-refresh" data-opsgate-triage-refresh-button data-opsgate-refresh-label="Refresh status" href="<?php echo esc_url( $setup_needed ? '#opsgate-remote-setup' : $refresh_url ); ?>"><?php echo esc_html( $setup_needed ? 'Open site connection' : 'Refresh status' ); ?></a>
                            </div>
                        </div>

                        <div class="opsgate-remote-progress-grid">
                            <div class="opsgate-remote-progress-main">
                                <p class="opsgate-remote-progress-copy" data-opsgate-triage-progress-copy="1"><?php echo esc_html( '' !== $triage_disabled_copy ? $triage_disabled_copy : ( $triage_payload['progress_copy'] ?? 'Live progress will appear here.' ) ); ?></p>
                                <div class="opsgate-remote-progress-meter" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="<?php echo esc_attr( (string) ( $triage_payload['progress_percent'] ?? 0 ) ); ?>" aria-label="<?php echo esc_attr( $triage_payload['progress_meter_label'] ?? 'Run progress' ); ?>" data-opsgate-triage-progress-meter="1">
                                    <span class="opsgate-remote-progress-fill" style="width:<?php echo esc_attr( (string) ( $triage_payload['progress_percent'] ?? 0 ) ); ?>%;" data-opsgate-triage-progress-fill="1"></span>
                                </div>
                                <div class="opsgate-remote-progress-meta">
                                    <span data-opsgate-triage-progress-phase="1"><?php echo esc_html( $triage_payload['progress_phase_label'] ?? 'Waiting' ); ?></span>
                                    <span data-opsgate-triage-progress-elapsed="1"><?php echo esc_html( $triage_payload['elapsed_label'] ?? 'No active run recorded' ); ?></span>
                                    <span data-opsgate-triage-progress-evidence="1"><?php echo esc_html( $triage_payload['evidence_label'] ?? 'Evidence state not recorded' ); ?></span>
                                </div>
                                <div class="opsgate-remote-phase-grid">
                                    <?php foreach ( $triage_payload['phase_items'] as $phase_item ) : ?>
                                        <?php
                                        $phase_key = isset( $phase_item['key'] ) ? (string) $phase_item['key'] : 'pending';
                                        $phase_state = isset( $phase_item['state'] ) ? (string) $phase_item['state'] : 'pending';
                                        $phase_label = ucfirst( str_replace( '_', ' ', $phase_key ) );
                                        if ( 'inventory' === $phase_key ) {
                                            $phase_label = $public_only ? 'Checking' : 'Inventory';
                                        } elseif ( 'updates' === $phase_key ) {
                                            $phase_label = $public_only ? 'Public findings' : 'Updates';
                                        } elseif ( 'vulnerabilities' === $phase_key ) {
                                            $phase_label = $public_only ? 'Finalizing' : 'Vulnerabilities';
                                        } elseif ( 'reports' === $phase_key ) {
                                            $phase_label = 'Reports';
                                        } elseif ( 'complete' === $phase_key ) {
                                            $phase_label = 'Complete';
                                        }
                                        ?>
                                        <article class="opsgate-remote-phase-card is-<?php echo esc_attr( $phase_state ); ?>" data-opsgate-triage-phase-key="<?php echo esc_attr( $phase_key ); ?>">
                                            <span class="opsgate-remote-phase-title"><?php echo esc_html( $phase_label ); ?></span>
                                            <span class="opsgate-remote-phase-status" data-opsgate-triage-phase-status="1"><?php echo esc_html( $phase_item['state_label'] ?? 'Waiting' ); ?></span>
                                        </article>
                                    <?php endforeach; ?>
                                </div>
                            </div>
                            <aside class="opsgate-remote-progress-side">
                                <span class="opsgate-remote-eyebrow">Current phase</span>
                                <strong data-opsgate-triage-aside-title="1"><?php echo esc_html( $triage_payload['progress_phase_label'] ?? 'Waiting' ); ?></strong>
                                <p data-opsgate-triage-aside-copy="1"><?php echo esc_html( $triage_payload['progress_phase_copy'] ?? 'Run progress will update here as the canonical job changes state.' ); ?></p>
                            </aside>
                        </div>
                    </div>
                </section>

                <section id="opsgate-remote-reports" class="opsgate-remote-section">
                    <div class="opsgate-remote-section-head">
                        <div>
                            <span class="opsgate-remote-eyebrow">Reports</span>
                            <h3><?php echo esc_html( $report_formats['headline'] ); ?></h3>
                            <p><?php echo esc_html( $public_only ? 'Free can explain the latest public-only posture, but connected report packaging stays locked until a paid connected tier is active.' : 'Reports ready on this plan follow the latest completed site-scoped run and stay tied to canonical run truth.' ); ?></p>
                        </div>
                    </div>
                    <div class="opsgate-remote-chip-row">
                        <?php foreach ( $report_formats['included'] as $included_format ) : ?>
                            <span class="opsgate-remote-chip is-good"><?php echo esc_html( $included_format ); ?></span>
                        <?php endforeach; ?>
                        <?php foreach ( $report_formats['locked'] as $locked_format ) : ?>
                            <span class="opsgate-remote-chip"><?php echo esc_html( $locked_format . ' locked' ); ?></span>
                        <?php endforeach; ?>
                    </div>
                    <div class="opsgate-remote-output-grid">
                        <?php foreach ( $latest_outputs_by_kind as $output_label => $output_item ) : ?>
                            <?php
                            $output_kind = 'PDF' === $output_label ? 'report_pdf' : ( 'HTML' === $output_label ? 'report_html' : ( 'CSV' === $output_label ? 'csv' : 'report_xlsx' ) );
                            $output_allowed = in_array( $output_label, $report_formats['included'], true );
                            $output_job_id = isset( $output_item['export_job_id'] ) ? trim( (string) $output_item['export_job_id'] ) : '';
                            $output_url = '';
                            if ( '' !== $output_job_id ) {
                                $output_url = wp_nonce_url(
                                    admin_url(
                                        'admin-post.php?action=opsgate_download_export&kind=' . rawurlencode( $output_kind ) . '&export_job_id=' . rawurlencode( $output_job_id )
                                    ),
                                    'opsgate_download_export'
                                );
                            }
                            ?>
                            <article class="opsgate-remote-output-card<?php echo $output_allowed ? '' : ' is-locked'; ?>">
                                <span class="opsgate-remote-output-label"><?php echo esc_html( $output_label ); ?></span>
                                <strong><?php echo esc_html( $output_allowed ? ( '' !== $output_job_id ? 'Ready' : 'Available after the next completed run' ) : 'Locked on this plan' ); ?></strong>
                                <p><?php echo esc_html( $output_allowed ? ( '' !== $output_job_id ? 'Latest packaged output is ready for this site.' : 'Run triage to refresh the next output for this site.' ) : 'Upgrade to unlock this connected report format.' ); ?></p>
                                <?php if ( '' !== $output_url ) : ?>
                                    <a class="button button-secondary" href="<?php echo esc_url( $output_url ); ?>"><?php echo esc_html( 'Download ' . $output_label ); ?></a>
                                <?php elseif ( $output_allowed ) : ?>
                                    <a class="button button-secondary" href="#opsgate-remote-run">Run and refresh outputs</a>
                                <?php else : ?>
                                    <a class="button" href="#opsgate-remote-plan">View unlock path</a>
                                <?php endif; ?>
                            </article>
                        <?php endforeach; ?>
                    </div>
                </section>

                <section id="opsgate-remote-alerts" class="opsgate-remote-section">
                    <div class="opsgate-remote-section-head">
                        <div>
                            <span class="opsgate-remote-eyebrow">Alerts</span>
                            <h3><?php echo esc_html( $alert_rollup['headline'] ?? 'No alert activity recorded' ); ?></h3>
                            <p><?php echo esc_html( ! empty( $alert_families['included'] ) ? 'Included families on this plan: ' . implode( ' / ', $alert_families['included'] ) . '.' : 'Free does not include connected alert automation. Upgrade and pair the plugin before expecting site-backed alert delivery.' ); ?></p>
                        </div>
                    </div>
                    <div class="opsgate-remote-chip-row">
                        <?php foreach ( $alert_families['included'] as $included_family ) : ?>
                            <span class="opsgate-remote-chip is-good"><?php echo esc_html( $included_family ); ?></span>
                        <?php endforeach; ?>
                        <?php foreach ( $alert_families['locked'] as $locked_family ) : ?>
                            <span class="opsgate-remote-chip"><?php echo esc_html( $locked_family . ' locked' ); ?></span>
                        <?php endforeach; ?>
                    </div>
                    <div class="opsgate-remote-alert-grid">
                        <article class="opsgate-remote-summary-card">
                            <span class="opsgate-remote-stat-label">Latest delivery state</span>
                            <strong><?php echo esc_html( $alert_rollup['latest_status'] ?? 'No alerts recorded' ); ?></strong>
                            <p><?php echo esc_html( $alert_rollup['latest_summary'] ?? 'No alert events were emitted for this site yet.' ); ?></p>
                            <div class="opsgate-remote-meta-list">
                                <span><?php echo esc_html( $alert_rollup['latest_target'] ?? '—' ); ?></span>
                                <span><?php echo esc_html( $alert_rollup['latest_reference'] ?? 'Event reference unavailable' ); ?></span>
                                <span><?php echo esc_html( $alert_rollup['latest_attempt_reference'] ?? 'No delivery attempts recorded yet' ); ?></span>
                            </div>
                        </article>
                        <article class="opsgate-remote-summary-card">
                            <span class="opsgate-remote-stat-label">Configuration status</span>
                            <strong><?php echo esc_html( sprintf( '%d live rule%s', $enabled_rules, 1 === $enabled_rules ? '' : 's' ) ); ?></strong>
                            <p><?php echo esc_html( ! empty( $alert_families['included'] ) ? 'Included families may still need destination setup before they can deliver live alerts.' : 'No connected alert families are active on this plan.' ); ?></p>
                            <a class="button button-secondary" href="#opsgate-remote-plan"><?php echo esc_html( ! empty( $alert_families['included'] ) ? 'Review plan coverage' : 'See what unlocks next' ); ?></a>
                        </article>
                    </div>
                </section>

                <section id="opsgate-remote-activity" class="opsgate-remote-section">
                    <div class="opsgate-remote-section-head">
                        <div>
                            <span class="opsgate-remote-eyebrow">Activity</span>
                            <h3>Latest site activity</h3>
                            <p>Recent activity stays readable and site-scoped here instead of dropping a raw log feed into WordPress Admin.</p>
                        </div>
                    </div>
                    <div class="opsgate-remote-activity-list">
                        <?php if ( empty( $activity_items ) ) : ?>
                            <article class="opsgate-remote-activity-card is-empty">
                                <strong>No recent site activity is recorded yet.</strong>
                                <p>Run a public check or connected site triage to populate this companion timeline.</p>
                            </article>
                        <?php else : ?>
                            <?php foreach ( $activity_items as $activity_item ) : ?>
                                <article class="opsgate-remote-activity-card">
                                    <div class="opsgate-remote-activity-top">
                                        <strong><?php echo esc_html( isset( $activity_item['label'] ) ? (string) $activity_item['label'] : 'Activity' ); ?></strong>
                                        <span class="opsgate-remote-chip"><?php echo esc_html( isset( $activity_item['status'] ) ? (string) $activity_item['status'] : 'Recorded' ); ?></span>
                                    </div>
                                    <p><?php echo esc_html( isset( $activity_item['details'] ) ? (string) $activity_item['details'] : 'Site activity recorded.' ); ?></p>
                                    <div class="opsgate-remote-meta-list">
                                        <span><?php echo esc_html( isset( $activity_item['when'] ) ? (string) $activity_item['when'] : '—' ); ?></span>
                                        <span><?php echo esc_html( isset( $activity_item['supporting'] ) ? (string) $activity_item['supporting'] : '' ); ?></span>
                                    </div>
                                </article>
                            <?php endforeach; ?>
                        <?php endif; ?>
                    </div>
                </section>

                <section id="opsgate-remote-plan" class="opsgate-remote-section">
                    <div class="opsgate-remote-section-head">
                        <div>
                            <span class="opsgate-remote-eyebrow">Plan / Upgrade</span>
                            <h3><?php echo esc_html( $package_name ); ?></h3>
                            <p><?php echo esc_html( $package_outcome ); ?></p>
                        </div>
                    </div>
                    <div class="opsgate-remote-plan-grid">
                        <article class="opsgate-remote-summary-card">
                            <span class="opsgate-remote-stat-label">Included now</span>
                            <strong><?php echo esc_html( $package_name ); ?></strong>
                            <p><?php echo esc_html( $plan_story['current'] ); ?></p>
                        </article>
                        <article class="opsgate-remote-summary-card">
                            <span class="opsgate-remote-stat-label">Next unlock path</span>
                            <strong><?php echo esc_html( '' !== $upgrade_link ? 'Upgrade available' : 'Plan guidance' ); ?></strong>
                            <p><?php echo esc_html( $plan_story['next'] ); ?></p>
                            <div class="opsgate-remote-card-actions">
                                <?php if ( '' !== $upgrade_link ) : ?>
                                    <a class="button button-primary" href="<?php echo esc_url( $upgrade_link ); ?>" target="_blank" rel="noopener noreferrer"><?php echo esc_html( 'free' === $plan ? 'Upgrade to Starter' : ( 'starter' === $plan ? 'Upgrade to Pro' : ( 'pro' === $plan ? 'Upgrade to Agency' : 'Review plan' ) ) ); ?></a>
                                <?php else : ?>
                                    <a class="button button-secondary" href="#opsgate-remote-support">Review with support</a>
                                <?php endif; ?>
                            </div>
                        </article>
                    </div>
                </section>

                <section id="opsgate-remote-support" class="opsgate-remote-section is-demoted">
                    <div class="opsgate-remote-section-head">
                        <div>
                            <span class="opsgate-remote-eyebrow">Support / Diagnostics</span>
                            <h3>Support diagnostics</h3>
                            <p>Support diagnostics stay visually demoted, support-only, and never become canonical product truth for this site.</p>
                        </div>
                    </div>
                    <div class="opsgate-remote-card-actions">
                        <a id="opsgate-support-export-button" class="button button-secondary" href="<?php echo esc_url( wp_nonce_url( $support_export_url, 'opsgate_export_logs' ) ); ?>">Download Support Export</a>
                        <a class="button" href="#opsgate-remote-run">Back to live status</a>
                    </div>
                    <p id="opsgate-support-export-status" class="description opsgate-remote-support-note">Support export stays non-canonical and support-only.</p>
                    <details class="opsgate-remote-support-details">
                        <summary>Open support diagnostics</summary>
                        <div class="opsgate-remote-support-grid">
                            <div>
                                <span class="opsgate-remote-stat-label">Site URL</span>
                                <strong><?php echo esc_html( $site_url ); ?></strong>
                            </div>
                            <div>
                                <span class="opsgate-remote-stat-label">Site ID</span>
                                <strong><?php echo esc_html( '' !== $site_id ? $site_id : 'Pending' ); ?></strong>
                            </div>
                            <div>
                                <span class="opsgate-remote-stat-label">Connection mode</span>
                                <strong><?php echo esc_html( self::canonical_connection_mode_label( $connection_mode ?: 'public_scan' ) ); ?></strong>
                            </div>
                            <div>
                                <span class="opsgate-remote-stat-label">Connector version</span>
                                <strong><?php echo esc_html( '' !== (string) ( $site_summary['connector_version'] ?? '' ) ? (string) $site_summary['connector_version'] : 'Not recorded' ); ?></strong>
                            </div>
                            <?php if ( ! $public_only ) : ?>
                                <div>
                                    <span class="opsgate-remote-stat-label">Pairing token</span>
                                    <strong><?php echo esc_html( '' !== $connector_pairing_token_value ? $connector_pairing_token_value : 'Not issued yet' ); ?></strong>
                                </div>
                                <div>
                                    <span class="opsgate-remote-stat-label">Connector credential</span>
                                    <strong><?php echo esc_html( $connector_credential_present ? 'Stored securely' : 'Not stored' ); ?></strong>
                                </div>
                            <?php endif; ?>
                        </div>
                        <?php if ( ! $public_only ) : ?>
                            <div class="opsgate-remote-card-actions" style="margin-top:16px;">
                                <?php
                                $pairing_form_obs_id2 = isset( $_GET['opsgate_onboarding_session_id'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_onboarding_session_id'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
                                $pairing_form_obs_token2 = isset( $_GET['opsgate_onboarding_token'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_onboarding_token'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
                                ?>
                                <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:0;">
                                    <?php wp_nonce_field( 'opsgate_create_pairing_session', 'opsgate_create_pairing_session_nonce' ); ?>
                                    <input type="hidden" name="action" value="opsgate_create_pairing_session" />
                                    <?php if ( '' !== $pairing_form_obs_id2 ) : ?>
                                        <input type="hidden" name="opsgate_onboarding_session_id" value="<?php echo esc_attr( $pairing_form_obs_id2 ); ?>" />
                                        <input type="hidden" name="opsgate_onboarding_token" value="<?php echo esc_attr( $pairing_form_obs_token2 ); ?>" />
                                    <?php endif; ?>
                                    <button type="submit" class="button button-secondary">Create Pairing Material</button>
                                </form>
                                <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:0;">
                                    <?php wp_nonce_field( 'opsgate_complete_pairing', 'opsgate_complete_pairing_nonce' ); ?>
                                    <input type="hidden" name="action" value="opsgate_complete_pairing" />
                                    <input type="hidden" name="opsgate_pairing_token" value="<?php echo esc_attr( $connector_pairing_token_value ); ?>" />
                                    <button type="submit" class="button" <?php disabled( '' === $connector_pairing_token_value ); ?>>Complete Pairing</button>
                                </form>
                                <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:0;">
                                    <?php wp_nonce_field( 'opsgate_rotate_connector_credential', 'opsgate_rotate_connector_credential_nonce' ); ?>
                                    <input type="hidden" name="action" value="opsgate_rotate_connector_credential" />
                                    <button type="submit" class="button" <?php disabled( ! $connector_credential_present ); ?>>Rotate Credential</button>
                                </form>
                                <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:0;">
                                    <?php wp_nonce_field( 'opsgate_revoke_connector_credential', 'opsgate_revoke_connector_credential_nonce' ); ?>
                                    <input type="hidden" name="action" value="opsgate_revoke_connector_credential" />
                                    <button type="submit" class="button" <?php disabled( ! $connector_credential_present ); ?>>Revoke Credential</button>
                                </form>
                            </div>
                            <p class="opsgate-remote-support-note">Paid connected mode completes the connector handshake from this WordPress host using site-scoped pairing material and then stores the connector credential locally.</p>
                        <?php endif; ?>
                        <?php if ( ! empty( $site_summary['last_connection_error'] ) ) : ?>
                            <p class="opsgate-remote-support-warning"><?php echo esc_html( (string) $site_summary['last_connection_error'] ); ?></p>
                        <?php endif; ?>
                    </details>
                </div>
            </div>
        </div>
        <?php
    }


    // =========================================================================
    /**
     * Returns true when the setup wizard should intercept the normal render path.
     * Conditions: central console install, account not yet linked OR site not registered,
     * connection not yet fully paired, and user has not dismissed the wizard.
     */
    private static function should_show_setup_wizard( array $eff_state ): bool {
        // Never show on the remote companion plugin.
        if ( ! self::current_install_is_central_console() ) {
            return false;
        }
        // Operator override: developer is testing — skip wizard.
        if ( $eff_state['is_operator_override'] ) {
            return false;
        }
        // User dismissed the wizard explicitly.
        if ( '1' === get_option( 'opsgate_setup_wizard_dismissed', '0' ) ) {
            return false;
        }
        // Already fully connected — wizard is done.
        if ( $eff_state['is_connected'] ) {
            return false;
        }
        return true;
    }

    /**
     * Renders the full-screen setup wizard in place of the normal nav + tab layout.
     * Called by render() when should_show_setup_wizard() returns true.
     */
    private static function render_setup_wizard( array $eff_state ): void {
        $account_id       = trim( (string) get_option( 'opsgate_account_id', '' ) );
        $api_base_url     = trim( (string) get_option( 'opsgate_api_base_url', 'https://api.opsgate.ca' ) );
        $site_id          = $eff_state['site_id'];
        $site_label       = $eff_state['site_label'];
        $site_url         = $eff_state['site_url'];
        $connection_status = $eff_state['connection_status'];
        $effective_plan   = $eff_state['effective_plan'];

        // Derive step completion state.
        $step1_done = '' !== $account_id && '' !== $api_base_url;
        $step2_done = $step1_done && '' !== $site_id && 'Current site' !== $site_label;
        $pairing_summary  = self::pairing_material_scope_summary();
        $pairing_token    = isset( $pairing_summary['pairing_token'] ) ? (string) $pairing_summary['pairing_token'] : '';
        $step3_done = $step2_done && '' !== $pairing_token;
        $step4_done = $step3_done && 'connected' === $connection_status;
        $latest_bundle    = self::canonical_latest_triage_bundle();
        $latest_job       = isset( $latest_bundle['job'] ) && is_array( $latest_bundle['job'] ) ? $latest_bundle['job'] : array();
        $step5_done = $step4_done && in_array( strtolower( (string) ( $latest_job['status'] ?? '' ) ), array( 'completed', 'complete' ), true );

        // Active step: first incomplete.
        $active_step = 1;
        if ( $step1_done && ! $step2_done ) { $active_step = 2; }
        elseif ( $step2_done && ! $step3_done ) { $active_step = 3; }
        elseif ( $step3_done && ! $step4_done ) { $active_step = 4; }
        elseif ( $step4_done && ! $step5_done ) { $active_step = 5; }

        $skip_url    = admin_url( 'admin-post.php?action=opsgate_dismiss_setup_wizard&_wpnonce=' . wp_create_nonce( 'opsgate_dismiss_setup_wizard' ) );
        $settings_url = self::admin_tab_url( 'settings', array( 'section' => 'site-configuration' ) );
        $billing_url  = self::admin_tab_url( 'billing' );

        $plan_display = 'free' === $effective_plan ? 'Free' : ucfirst( $effective_plan );

        // Pairing scope for step 3.
        $pairing_scope_site_id = '' !== $site_id ? $site_id : '';
        $pairing_scope_site_url_for_resolve = '' === $pairing_scope_site_id ? $site_url : '';
        $create_pairing_disabled = '' === $pairing_scope_site_id && '' === $pairing_scope_site_url_for_resolve;
        ?>
        <div class="wrap opsgate-admin opsgate-setup-wizard-wrap">
            <div class="opsgate-setup-wizard">
                <div class="opsgate-setup-wizard-header">
                    <span class="opsgate-setup-wizard-brand">
                        <svg class="opsgate-setup-wizard-shield" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
                            <rect width="40" height="40" rx="8" fill="#0073aa"/>
                            <path d="M20 6L8 11v9c0 7.18 5.14 13.9 12 15.57C27.86 33.9 32 27.18 32 20V11L20 6z" fill="white" opacity="0.95"/>
                        </svg>
                        <span>OpsGate</span>
                    </span>
                    <a href="<?php echo esc_url( $skip_url ); ?>" class="opsgate-setup-wizard-skip">Skip setup &rarr;</a>
                </div>

                <div class="opsgate-setup-wizard-hero">
                    <h1>Get started with OpsGate</h1>
                    <p>Connect your site to start monitoring security. This takes about 2 minutes.</p>
                </div>

                <div class="opsgate-setup-wizard-progress">
                    <?php
                    $steps = array(
                        1 => array( 'label' => 'Link your account',      'done' => $step1_done ),
                        2 => array( 'label' => 'Register this site',      'done' => $step2_done ),
                        3 => array( 'label' => 'Install the connector',   'done' => $step3_done ),
                        4 => array( 'label' => 'Verify connection',       'done' => $step4_done ),
                        5 => array( 'label' => 'Run first scan',          'done' => $step5_done ),
                    );
                    foreach ( $steps as $num => $s ) :
                        $is_active = ( $num === $active_step );
                        $is_done   = $s['done'];
                        $is_locked = ( ! $is_done && ! $is_active );
                        $row_class = $is_done ? 'is-done' : ( $is_active ? 'is-active' : 'is-locked' );
                    ?>
                        <div class="opsgate-setup-step-row <?php echo esc_attr( $row_class ); ?>">
                            <span class="opsgate-setup-step-num">
                                <?php if ( $is_done ) : ?>
                                    <span class="dashicons dashicons-yes-alt"></span>
                                <?php else : ?>
                                    <?php echo esc_html( $num ); ?>
                                <?php endif; ?>
                            </span>
                            <span class="opsgate-setup-step-label"><?php echo esc_html( $s['label'] ); ?></span>
                            <span class="opsgate-setup-step-status">
                                <?php if ( $is_done ) : ?>
                                    Complete
                                <?php elseif ( $is_active ) : ?>
                                    Action needed
                                <?php else : ?>
                                    Waiting
                                <?php endif; ?>
                            </span>
                        </div>
                    <?php endforeach; ?>
                </div>

                <div class="opsgate-setup-wizard-body">

                    <?php if ( $active_step === 1 ) : ?>
                    <div class="opsgate-setup-wizard-step-card">
                        <h2><span class="opsgate-setup-step-badge">1</span> Link your account</h2>
                        <p>Enter your OpsGate account ID and API base URL. You'll find these in your OpsGate account settings.</p>
                        <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="opsgate-setup-wizard-form">
                            <?php wp_nonce_field( 'opsgate_save_configuration', 'opsgate_save_configuration_nonce' ); ?>
                            <input type="hidden" name="action" value="opsgate_save_configuration" />
                            <input type="hidden" name="opsgate_wizard_return" value="1" />
                            <div class="opsgate-setup-wizard-fields">
                                <div>
                                    <label for="opsgate_wizard_api_base_url"><strong>API base URL</strong></label>
                                    <input id="opsgate_wizard_api_base_url" type="url" name="opsgate_api_base_url" class="regular-text" value="<?php echo esc_attr( $api_base_url ); ?>" placeholder="https://api.opsgate.ca" required />
                                </div>
                                <div>
                                    <label for="opsgate_wizard_account_id"><strong>Account ID</strong></label>
                                    <input id="opsgate_wizard_account_id" type="text" name="opsgate_account_id" class="regular-text" value="<?php echo esc_attr( $account_id ); ?>" placeholder="acct_…" required />
                                </div>
                                <div>
                                    <label for="opsgate_wizard_inbound_token"><strong>API token</strong></label>
                                    <input id="opsgate_wizard_inbound_token" type="text" name="opsgate_inbound_token" class="regular-text" value="<?php echo esc_attr( trim( (string) get_option( 'opsgate_inbound_token', '' ) ) ); ?>" placeholder="tok_…" />
                                </div>
                            </div>
                            <div class="opsgate-setup-wizard-actions">
                                <?php submit_button( 'Save and continue', 'primary large', 'submit', false ); ?>
                            </div>
                        </form>
                    </div>

                    <?php elseif ( $active_step === 2 ) : ?>
                    <div class="opsgate-setup-wizard-step-card">
                        <h2><span class="opsgate-setup-step-badge">2</span> Register this site</h2>
                        <p>Tell OpsGate which site this plugin is monitoring. This creates or resolves a site record in your account.</p>
                        <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="opsgate-setup-wizard-form">
                            <?php wp_nonce_field( 'opsgate_save_configuration', 'opsgate_save_configuration_nonce' ); ?>
                            <input type="hidden" name="action" value="opsgate_save_configuration" />
                            <input type="hidden" name="opsgate_account_id" value="<?php echo esc_attr( $account_id ); ?>" />
                            <input type="hidden" name="opsgate_api_base_url" value="<?php echo esc_attr( $api_base_url ); ?>" />
                            <input type="hidden" name="opsgate_inbound_token" value="<?php echo esc_attr( trim( (string) get_option( 'opsgate_inbound_token', '' ) ) ); ?>" />
                            <input type="hidden" name="opsgate_wizard_return" value="1" />
                            <div class="opsgate-setup-wizard-fields">
                                <div>
                                    <label for="opsgate_wizard_site_url"><strong>Site URL</strong></label>
                                    <input id="opsgate_wizard_site_url" type="url" name="opsgate_site_url" class="regular-text" value="<?php echo esc_attr( '' !== $site_url ? $site_url : get_site_url() ); ?>" placeholder="https://yoursite.com" required />
                                </div>
                                <div>
                                    <label for="opsgate_wizard_site_label"><strong>Site label</strong></label>
                                    <input id="opsgate_wizard_site_label" type="text" name="opsgate_site_label" class="regular-text" value="<?php echo esc_attr( '' !== $site_label && 'Current site' !== $site_label ? $site_label : '' ); ?>" placeholder="e.g. Acme — Production" />
                                </div>
                                <div>
                                    <label for="opsgate_wizard_identity_email"><strong>Contact email</strong></label>
                                    <input id="opsgate_wizard_identity_email" type="email" name="opsgate_identity_email" class="regular-text" value="" placeholder="you@example.com" />
                                </div>
                            </div>
                            <div class="opsgate-setup-wizard-actions">
                                <?php submit_button( 'Register site and continue', 'primary large', 'submit', false ); ?>
                            </div>
                        </form>
                    </div>

                    <?php elseif ( $active_step === 3 ) : ?>
                    <div class="opsgate-setup-wizard-step-card">
                        <h2><span class="opsgate-setup-step-badge">3</span> Install the connector</h2>
                        <p>Your site is running public security scans. Install the OpsGate connector plugin on <strong><?php echo esc_html( '' !== $site_label && 'Current site' !== $site_label ? $site_label : $site_url ); ?></strong> to unlock authenticated scanning, evidence recording, and real-time alerts.</p>
                        <div class="opsgate-setup-wizard-connection-status">
                            <span class="opsgate-setup-wizard-status-chip opsgate-setup-wizard-status-chip-warn">Public scan only</span>
                            <span class="opsgate-setup-wizard-status-copy">No connector installed yet &mdash; authenticated scanning is not active.</span>
                        </div>
                        <?php if ( '' !== $pairing_token ) : ?>
                            <div class="opsgate-setup-wizard-token-row">
                                <label><strong>Connection code</strong></label>
                                <p class="description">Copy this code into the OpsGate connector plugin on your target site to complete the connection.</p>
                                <div class="opsgate-setup-wizard-token-copy-row">
                                    <input type="text" class="regular-text" id="opsgate-wizard-pairing-token" value="<?php echo esc_attr( $pairing_token ); ?>" readonly="readonly" />
                                    <button type="button" class="button" onclick="var el=document.getElementById('opsgate-wizard-pairing-token');el.select();document.execCommand('copy');this.textContent='Copied';">Copy</button>
                                </div>
                            </div>
                            <div class="opsgate-setup-wizard-actions" style="margin-top:16px;">
                                <a href="<?php echo esc_url( self::admin_tab_url( 'settings', array( 'tab' => 'settings', 'section' => 'pairing-material' ) ) ); ?>" class="button">Manage in Settings</a>
                                <span class="description" style="margin-left:10px;">Waiting for the connector to complete pairing&hellip;</span>
                            </div>
                        <?php else : ?>
                            <div class="opsgate-setup-wizard-actions" style="margin-top:16px;">
                                <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="display:inline;">
                                    <?php wp_nonce_field( 'opsgate_create_pairing_session', 'opsgate_create_pairing_session_nonce' ); ?>
                                    <input type="hidden" name="action" value="opsgate_create_pairing_session" />
                                    <?php if ( '' !== $pairing_scope_site_url_for_resolve ) : ?>
                                        <input type="hidden" name="opsgate_scope_site_url" value="<?php echo esc_attr( $pairing_scope_site_url_for_resolve ); ?>" />
                                    <?php endif; ?>
                                    <input type="hidden" name="opsgate_wizard_return" value="1" />
                                    <button type="submit" class="button button-primary button-large" <?php disabled( $create_pairing_disabled ); ?>>Create Connection Code</button>
                                </form>
                                <a href="<?php echo esc_url( $skip_url ); ?>" class="button" style="margin-left:8px;">I&rsquo;ll do this later</a>
                            </div>
                            <?php if ( $create_pairing_disabled ) : ?>
                                <p class="description" style="margin-top:8px;">Complete site registration (step 2) before creating a connection code.</p>
                            <?php endif; ?>
                        <?php endif; ?>
                    </div>

                    <?php elseif ( $active_step === 4 ) : ?>
                    <div class="opsgate-setup-wizard-step-card">
                        <h2><span class="opsgate-setup-step-badge">4</span> Verify connection</h2>
                        <p>The connection code has been issued. Install the OpsGate connector plugin on <strong><?php echo esc_html( '' !== $site_label && 'Current site' !== $site_label ? $site_label : $site_url ); ?></strong> and paste the code to complete the handshake.</p>
                        <div class="opsgate-setup-wizard-connection-status">
                            <span class="opsgate-setup-wizard-status-chip opsgate-setup-wizard-status-chip-info">Pairing pending</span>
                            <span class="opsgate-setup-wizard-status-copy">Waiting for the connector plugin to complete the handshake.</span>
                        </div>
                        <?php if ( '' !== $pairing_token ) : ?>
                            <div class="opsgate-setup-wizard-token-row" style="margin-top:16px;">
                                <label><strong>Your connection code</strong></label>
                                <div class="opsgate-setup-wizard-token-copy-row">
                                    <input type="text" class="regular-text" id="opsgate-wizard-pairing-token-4" value="<?php echo esc_attr( $pairing_token ); ?>" readonly="readonly" />
                                    <button type="button" class="button" onclick="var el=document.getElementById('opsgate-wizard-pairing-token-4');el.select();document.execCommand('copy');this.textContent='Copied';">Copy</button>
                                </div>
                            </div>
                        <?php endif; ?>
                        <div class="opsgate-setup-wizard-actions" style="margin-top:16px;">
                            <a href="<?php echo esc_url( self::admin_tab_url( 'settings' ) . '&opsgate_wizard_check=1' ); ?>" class="button button-primary">Check connection status</a>
                            <a href="<?php echo esc_url( $skip_url ); ?>" class="button" style="margin-left:8px;">Skip for now</a>
                        </div>
                    </div>

                    <?php elseif ( $active_step === 5 ) : ?>
                    <div class="opsgate-setup-wizard-step-card">
                        <h2><span class="opsgate-setup-step-badge">5</span> Run your first scan</h2>
                        <p>Your site is connected. Run a security scan to generate your first report and start tracking your security posture.</p>
                        <div class="opsgate-setup-wizard-connection-status">
                            <span class="opsgate-setup-wizard-status-chip opsgate-setup-wizard-status-chip-good">Connected</span>
                            <span class="opsgate-setup-wizard-status-copy">Authenticated scanning is active for <strong><?php echo esc_html( '' !== $site_label && 'Current site' !== $site_label ? $site_label : $site_url ); ?></strong>.</span>
                        </div>
                        <div class="opsgate-setup-wizard-actions" style="margin-top:20px;">
                            <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="display:inline;">
                                <?php wp_nonce_field( 'opsgate_run_triage', 'opsgate_run_triage_nonce' ); ?>
                                <input type="hidden" name="action" value="opsgate_run_triage" />
                                <input type="hidden" name="opsgate_wizard_return" value="done" />
                                <button type="submit" class="button button-primary button-large">Run security scan</button>
                            </form>
                            <a href="<?php echo esc_url( $skip_url ); ?>" class="button" style="margin-left:8px;">Go to Dashboard &rarr;</a>
                        </div>
                    </div>
                    <?php endif; ?>

                </div><!-- .opsgate-setup-wizard-body -->

                <div class="opsgate-setup-wizard-footer">
                    <span class="description">
                        <?php if ( 'free' === $effective_plan ) : ?>
                            You&rsquo;re on the <strong>Free</strong> plan. <a href="<?php echo esc_url( $billing_url ); ?>">Upgrade</a> to unlock authenticated scanning, reports, and alerts.
                        <?php else : ?>
                            You&rsquo;re on the <strong><?php echo esc_html( $plan_display ); ?></strong> plan &mdash; authenticated scanning and reports are included.
                        <?php endif; ?>
                    </span>
                    <a href="<?php echo esc_url( $skip_url ); ?>" class="opsgate-setup-wizard-skip-footer">Skip and go to Dashboard &rarr;</a>
                </div>

            </div><!-- .opsgate-setup-wizard -->
        </div><!-- .wrap -->
        <?php
    }

    /**
     * Main OpsGate admin page with nav tabs.
     *
     * @return void
     */
    public static function render() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden' );
        }

        self::maybe_sync_requested_site_scope_from_query();
        $requested_scope = self::resolve_requested_site_scope_from_query();
        $requested_setup_surface = self::requested_scope_targets_site_setup( $requested_scope );

        $requested_tab = isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : 'overview';
        $active_tab    = self::normalize_admin_tab_request( $requested_tab );
        if ( ! empty( $requested_scope['has_explicit_scope'] ) && empty( $requested_scope['ok'] ) && ! $requested_setup_surface ) {
            ?>
            <div class="wrap opsgate-admin opsgate-admin-tab-<?php echo esc_attr( $active_tab ); ?>">
                <h1 class="wp-heading-inline">
                    <span class="dashicons dashicons-shield-alt" style="color:#0073aa;vertical-align:middle;margin-right:10px;font-size:32px;"></span>
                    OpsGate
                </h1>
                <hr class="wp-header-end">
                <?php self::render_scoped_handoff_notice( $requested_scope ); ?>
            </div>
            <?php
            return;
        }

        // Single canonical state resolution — one read for plan + connection truth.
        // Both the remote companion and central surface consume this resolved state.
        $eff_state     = self::resolve_effective_site_state();
        $surface_mode  = self::current_surface_mode();
        $current_plan  = $eff_state['effective_plan'];

        if ( ! empty( $surface_mode['remote_companion'] ) ) {
            self::render_remote_companion_page( $active_tab, $current_plan );
            return;
        }

        // Setup wizard intercept — fires before nav or any tab renders.
        if ( self::should_show_setup_wizard( $eff_state ) ) {
            self::render_setup_wizard( $eff_state );
            return;
        }

        // Unpack effective state — all tab, badge, action, and evidence decisions come from here.
        $active_site_conn_mode = $eff_state['connection_mode'];
        $is_operator_override  = $eff_state['is_operator_override'];
        $surface_plan          = $eff_state['surface_plan_for_tabs'];
        $allowed_tabs          = $eff_state['allowed_tabs'];
        $blocked_tab  = '';
        if ( $requested_setup_surface && 'settings' === $active_tab ) {
            if ( ! in_array( 'settings', $allowed_tabs, true ) ) {
                $allowed_tabs[] = 'settings';
            }
        } elseif ( ! in_array( $active_tab, $allowed_tabs, true ) ) {
            $blocked_tab = $active_tab;
            $active_tab  = ! empty( $allowed_tabs ) ? (string) $allowed_tabs[0] : 'overview';
        }

        $telemetry_enabled = ( '1' === get_option( 'opsgate_telemetry_enabled', '0' ) );

        $services_settings       = function_exists( 'opsgate_get_services_settings' ) ? opsgate_get_services_settings() : array();
        $canonical_schedule      = self::canonical_portfolio_triage_schedule();
        $schedules_settings      = self::canonical_schedule_rows_for_ui( $canonical_schedule );
        $canonical_schedule_ok   = ! empty( $canonical_schedule['ok'] );
        $canonical_schedule_error = isset( $canonical_schedule['error'] ) ? (string) $canonical_schedule['error'] : '';

        $allowed_plans = array( 'free', 'starter', 'pro', 'agency' );                                                          

        $is_linked      = self::is_site_linked();
        $link_claim     = self::get_link_claim_snapshot();
        $link_badge_val = $is_linked ? 'Connected' : 'Not Connected';
        $link_badge_typ = $is_linked ? 'ok' : 'warn';

        $link_notice = isset( $_GET['opsgate_link_notice'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_link_notice'] ) ) : '';
        $link_notice_detail = isset( $_GET['opsgate_link_notice_detail'] ) ? sanitize_key( wp_unslash( $_GET['opsgate_link_notice_detail'] ) ) : '';

        ?>
        <?php $og_theme = ( get_option( 'opsgate_ui_theme', 'light' ) === 'dark' ) ? 'dark' : 'light'; ?>
        <div class="wrap opsgate-admin opsgate-admin-tab-<?php echo esc_attr( $active_tab ); ?><?php echo 'overview' === $active_tab ? ' opsgate-admin-overview' : ''; ?>" data-og-theme="<?php echo esc_attr( $og_theme ); ?>">
            <h1 class="wp-heading-inline opsgate-central-header-logo">
                <span class="opsgate-remote-logo-mark">
                    <svg class="opsgate-remote-logo-shield" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
                        <defs><linearGradient id="og-logo-grad" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="#6366f1"/><stop offset="100%" stop-color="#a855f7"/></linearGradient></defs>
                        <rect width="40" height="40" rx="8" fill="url(#og-logo-grad)"/>
                        <path d="M20 6L8 11v9c0 7.18 5.14 13.9 12 15.57C27.86 33.9 32 27.18 32 20V11L20 6z" fill="white" opacity="0.95"/>
                    </svg>
                    <span class="opsgate-remote-logo-text">OpsGate</span>
                </span>
            </h1>
            <hr class="wp-header-end">

            <?php if ( '' !== $blocked_tab ) : ?>
                <div class="opsgate-r1-guidance-state opsgate-blocked-tab-notice" style="margin:12px 0 16px;">
                    <?php if ( 'wp_connector' !== strtolower( trim( $ctx_conn_mode ) ) ) : ?>
                    <strong><?php echo esc_html( ucfirst( $blocked_tab ) ); ?> requires a connected site.</strong>
                    Connect this site to OpsGate to unlock connected dashboard surfaces.
                    <a href="<?php echo esc_url( self::admin_tab_url( 'billing' ) ); ?>" style="margin-left:8px;">Connect this site &rarr;</a>
                    <?php else : ?>
                    <strong><?php echo esc_html( ucfirst( $blocked_tab ) ); ?> is not available on your current plan.</strong>
                    OpsGate opened the Dashboard instead.
                    <?php if ( 'free' === self::normalize_plan( $surface_plan ) ) : ?>
                    <a href="<?php echo esc_url( self::admin_tab_url( 'billing' ) ); ?>" style="margin-left:8px;">Upgrade to unlock &rarr;</a>
                    <?php endif; ?>
                    <?php endif; ?>
                </div>
            <?php endif; ?>

            <?php
            // 5.QA.3 — Persistent context strip — reads from effective state (no extra API call).
            $ctx_site_label  = $eff_state['site_label'];
            $ctx_site_url    = $eff_state['site_url'];
            $ctx_site_host   = (string) ( wp_parse_url( $ctx_site_url, PHP_URL_HOST ) ?: '' );
            $ctx_conn_status = $eff_state['connection_status'];
            $ctx_conn_mode   = $eff_state['connection_mode'];
            // Badge: effective plan (operator override or real API plan) — independent of connection mode.
            $ctx_plan_display = ucfirst( $eff_state['effective_plan'] );
            // Mode label: honest connection reality, not billing plan.
            // public_scan → "Public-only" even on paid accounts.
            $ctx_mode_label = $eff_state['is_public_scan']
                ? 'Public-only'
                : ( $eff_state['is_connected'] ? 'Connected' : 'External-only' );
            $ctx_site_display = '' !== $ctx_site_label ? $ctx_site_label : ( '' !== $ctx_site_host ? $ctx_site_host : 'No site selected' );
            ?>
            <div class="opsgate-ctx-strip">
                <span class="opsgate-ctx-strip-product">OpsGate</span>
                <span class="opsgate-ctx-strip-sep">·</span>
                <span class="opsgate-ctx-strip-site"><?php echo esc_html( $ctx_site_display ); ?><?php if ( '' !== $ctx_site_host && $ctx_site_host !== $ctx_site_display ) : ?> <span class="opsgate-ctx-strip-domain">(<?php echo esc_html( $ctx_site_host ); ?>)</span><?php endif; ?></span>
                <span class="opsgate-ctx-strip-sep">·</span>
                <span class="opsgate-ctx-strip-plan opsgate-ctx-strip-plan-<?php echo esc_attr( $eff_state['effective_plan'] ); ?>"><?php echo esc_html( $ctx_plan_display ); ?></span>
                <span class="opsgate-ctx-strip-sep">·</span>
                <span class="opsgate-ctx-strip-mode"><?php echo esc_html( $ctx_mode_label ); ?></span>
            </div>

            <div class="opsgate-nav-tabs-wrap">
            <nav class="nav-tab-wrapper opsgate-nav-tabs" style="border-bottom:none;flex:1 1 auto;">
                <?php
                $all_tab_defs = self::admin_tab_definitions();
                foreach ( $allowed_tabs as $tab_key ) :
                    if ( ! isset( $all_tab_defs[ $tab_key ] ) ) { continue; }
                    $tab_meta = $all_tab_defs[ $tab_key ];
                ?>
                    <a href="<?php echo esc_url( self::admin_tab_url( $tab_key ) ); ?>" class="nav-tab <?php echo $tab_key === $active_tab ? 'nav-tab-active' : ''; ?>">
                        <span class="dashicons <?php echo esc_attr( (string) $tab_meta['icon'] ); ?>"></span> <?php echo esc_html( (string) $tab_meta['label'] ); ?>
                    </a>
                <?php endforeach; ?>
            </nav>
            <button type="button" class="opsgate-theme-toggle" id="opsgate-theme-toggle" aria-label="Toggle dark mode">
                <svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="opsgate-theme-icon-dark" style="display:<?php echo 'dark' === $og_theme ? 'none' : 'block'; ?>">
                    <path d="M8 11a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0-9a1 1 0 0 1 1 1v.5a1 1 0 0 1-2 0V3a1 1 0 0 1 1-1zm0 11a1 1 0 0 1 1 1v.5a1 1 0 0 1-2 0V13a1 1 0 0 1 1-1zm7-5h-.5a1 1 0 0 1 0-2H15a1 1 0 0 1 0 2zm-13 0H1.5a1 1 0 0 1 0-2H2a1 1 0 0 1 0 2zm9.9-5.1-.35.35a1 1 0 0 1-1.4-1.4l.35-.35a1 1 0 0 1 1.4 1.4zm-9.2 9.2-.35.35a1 1 0 0 1-1.4-1.4l.35-.35a1 1 0 0 1 1.4 1.4zm9.2.7.35.35a1 1 0 0 1-1.4 1.4l-.35-.35a1 1 0 0 1 1.4-1.4zm-9.2-9.2.35.35a1 1 0 0 1-1.4 1.4l-.35-.35a1 1 0 0 1 1.4-1.4z"/>
                </svg>
                <svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="opsgate-theme-icon-light" style="display:<?php echo 'dark' === $og_theme ? 'block' : 'none'; ?>">
                    <path d="M6 .278a.77.77 0 0 1 .08.858 7.208 7.208 0 0 0-.878 3.46c0 4.021 3.278 7.277 7.318 7.277q.792-.001 1.533-.16a.787.787 0 0 1 .81.316.733.733 0 0 1-.031.893A8.349 8.349 0 0 1 8.344 16C3.734 16 0 12.286 0 7.71 0 4.266 2.114 1.312 5.124.06A.752.752 0 0 1 6 .278"/>
                </svg>
                <span class="opsgate-theme-toggle-label"><?php echo 'dark' === $og_theme ? 'Light mode' : 'Dark mode'; ?></span>
            </button>
            </div>
            <hr style="border-color:var(--og-border);margin:0 0 16px;">
            <?php if ( 'overview' === $active_tab ) : ?>

                <?php
                $overview_latest = self::canonical_latest_triage_bundle();
                $overview_job = isset( $overview_latest['job'] ) && is_array( $overview_latest['job'] ) ? $overview_latest['job'] : array();
                $overview_artifacts = isset( $overview_latest['artifacts'] ) && is_array( $overview_latest['artifacts'] ) ? $overview_latest['artifacts'] : array();
                $overview_score = isset( $overview_artifacts['score_summary']['body'] ) && is_array( $overview_artifacts['score_summary']['body'] ) ? $overview_artifacts['score_summary']['body'] : array();
                $overview_operator_degradation = self::operator_degradation_meta( $overview_score );
                $overview_history = self::canonical_exports_history( 6 );
                $overview_alerts = self::notification_events_list( 6 );
                $overview_rules = self::notification_rules_list();
                $overview_board = self::canonical_portfolio_board();
                $overview_board_row = self::canonical_local_board_row( $overview_board );
                $overview_package = self::current_package_entry();
                $overview_hybrid = self::hybrid_product_snapshot();
                $overview_schedule = isset( $canonical_schedule['schedule'] ) && is_array( $canonical_schedule['schedule'] ) ? $canonical_schedule['schedule'] : array();
                $overview_scope = self::get_mcp_scope_snapshot();
                $overview_site_config = self::canonical_site_config();
                $overview_site_config_item = ! empty( $overview_site_config['ok'] ) && isset( $overview_site_config['item'] ) && is_array( $overview_site_config['item'] ) ? $overview_site_config['item'] : array();
                $overview_enabled_rules = 0;
                $overview_rule_items = ( ! empty( $overview_rules['ok'] ) && isset( $overview_rules['items'] ) && is_array( $overview_rules['items'] ) ) ? self::live_items_only( $overview_rules['items'] ) : array();

                if ( ! empty( $overview_rule_items ) ) {
                    foreach ( $overview_rule_items as $rule ) {
                        if ( is_array( $rule ) && ! empty( $rule['is_enabled'] ) ) {
                            $overview_enabled_rules++;
                        }
                    }
                }
                $overview_activity = self::canonical_activity_feed( 4 );
                $overview_score_value = isset( $overview_score['score'] ) ? (string) $overview_score['score'] : '—';
                $overview_grade_value = isset( $overview_score['grade'] ) ? (string) $overview_score['grade'] : '—';
                $overview_run_label = isset( $overview_job['finished_at_utc'] ) ? self::human_relative_datetime_label( (string) $overview_job['finished_at_utc'] ) : 'No completed scan yet';
                $overview_finished_ts = isset( $overview_job['finished_at_utc'] ) && '' !== (string) $overview_job['finished_at_utc'] ? strtotime( (string) $overview_job['finished_at_utc'] ) : 0;
                $overview_is_stale = $overview_finished_ts > 0 && ( time() - $overview_finished_ts ) > ( 7 * DAY_IN_SECONDS );
                $overview_schedule_label = ! empty( $overview_schedule['is_enabled'] ) ? ucfirst( (string) $overview_schedule['cadence'] ) : 'Not scheduled';
                $overview_due_label = isset( $overview_schedule['due_at_utc'] ) && '' !== (string) $overview_schedule['due_at_utc'] ? self::schedule_datetime_label( (string) $overview_schedule['due_at_utc'], is_array( $overview_schedule ) ? $overview_schedule : array() ) : 'Not scheduled';
                $overview_site_label = self::connected_site_label( $overview_site_config_item, $overview_scope );
                $overview_portfolio_id = trim( (string) get_option( 'opsgate_portfolio_id', 'portfolio_default' ) );
                $overview_update_posture = isset( $overview_artifacts['update_posture']['body'] ) && is_array( $overview_artifacts['update_posture']['body'] ) ? $overview_artifacts['update_posture']['body'] : array();
                $overview_vulnerability_posture = isset( $overview_artifacts['vulnerability_posture']['body'] ) && is_array( $overview_artifacts['vulnerability_posture']['body'] ) ? $overview_artifacts['vulnerability_posture']['body'] : array();
                $overview_reachability_posture = isset( $overview_artifacts['reachability_posture']['body'] ) && is_array( $overview_artifacts['reachability_posture']['body'] ) ? $overview_artifacts['reachability_posture']['body'] : array();
                $overview_availability_snapshot = isset( $overview_artifacts['availability_snapshot']['body'] ) && is_array( $overview_artifacts['availability_snapshot']['body'] ) ? $overview_artifacts['availability_snapshot']['body'] : array();
                $overview_export_items = isset( $overview_history['items'] ) && is_array( $overview_history['items'] ) ? $overview_history['items'] : array();
                $overview_live_export_items = self::live_items_only( $overview_export_items );
                $overview_history_reports_count = count( $overview_live_export_items );
                $overview_account_id = isset( $overview_scope['account_id'] ) ? trim( (string) $overview_scope['account_id'] ) : '';
                $overview_site_id = isset( $overview_scope['site_id'] ) ? trim( (string) $overview_scope['site_id'] ) : '';
                $overview_is_connected = '' !== $overview_account_id && '' !== $overview_site_id;
                $overview_scope_url = self::connected_site_url( $overview_site_config_item, $overview_scope );
                $overview_site_host = (string) ( wp_parse_url( $overview_scope_url, PHP_URL_HOST ) ?: '' );
                $overview_job_id = isset( $overview_job['job_id'] ) ? trim( (string) $overview_job['job_id'] ) : '';
                $overview_trigger_label = self::canonical_run_trigger_label( isset( $overview_job['trigger'] ) ? (string) $overview_job['trigger'] : '' );
                $overview_run_alerts = self::notification_events_for_source_id( $overview_job_id, 6 );
                $overview_run_alert_items = ! empty( $overview_run_alerts['ok'] ) && isset( $overview_run_alerts['items'] ) && is_array( $overview_run_alerts['items'] ) ? $overview_run_alerts['items'] : array();
                $overview_alert_rollup = self::notification_delivery_rollup( $overview_run_alert_items );
                $overview_reports_url = '' !== $overview_job_id ? self::admin_tab_url( 'reports', array( 'source_job_id' => $overview_job_id ) ) : self::admin_tab_url( 'reports' );
                $overview_alerts_url = self::admin_tab_url( 'alerts' );
                $overview_activity_url = self::admin_tab_url( 'activity' );
                $overview_scope_meta = 'portfolio_default' === $overview_portfolio_id ? 'Default portfolio scope' : $overview_portfolio_id;
                $overview_grade_slug = strtolower( trim( (string) $overview_grade_value ) );
                $overview_grade_label = '' !== $overview_grade_slug && '—' !== $overview_grade_value ? ucfirst( $overview_grade_slug ) : 'Unrated';
                $overview_grade_summary = 'Scan pending';
                $overview_grade_tone = 'neutral';

                if ( in_array( $overview_grade_slug, array( 'green', 'healthy' ), true ) ) {
                    $overview_grade_summary = 'Healthy';
                    $overview_grade_tone = 'good';
                } elseif ( in_array( $overview_grade_slug, array( 'yellow', 'amber' ), true ) ) {
                    $overview_grade_summary = 'Needs attention';
                    $overview_grade_tone = 'warn';
                } elseif ( in_array( $overview_grade_slug, array( 'red', 'critical' ), true ) ) {
                    $overview_grade_summary = 'Action required';
                    $overview_grade_tone = 'bad';
                }

                $overview_update_summary = isset( $overview_update_posture['summary'] ) && is_array( $overview_update_posture['summary'] ) ? $overview_update_posture['summary'] : array();
                $overview_update_total = isset( $overview_update_summary['outdated_total'] ) ? (int) $overview_update_summary['outdated_total'] : null;
                $overview_updates_note = 'No update data yet.';
                if ( null !== $overview_update_total ) {
                    $overview_updates_note = 0 === $overview_update_total
                        ? 'No outdated components detected.'
                        : sprintf( '%d outdated component%s recorded.', $overview_update_total, 1 === $overview_update_total ? '' : 's' );
                }

                $overview_vulnerability_summary = isset( $overview_vulnerability_posture['summary'] ) && is_array( $overview_vulnerability_posture['summary'] ) ? $overview_vulnerability_posture['summary'] : array();
                $overview_vulnerability_total = isset( $overview_vulnerability_summary['match_count'] ) ? (int) $overview_vulnerability_summary['match_count'] : null;
                $overview_vulnerability_note = 'No vulnerability data yet.';
                if ( null !== $overview_vulnerability_total ) {
                    $overview_vulnerability_note = 0 === $overview_vulnerability_total
                        ? 'No vulnerabilities found.'
                        : sprintf( '%d %s found.', $overview_vulnerability_total, 1 === $overview_vulnerability_total ? 'vulnerability' : 'vulnerabilities' );
                }

                $overview_reachability_slug = strtolower( trim( (string) ( $overview_reachability_posture['posture'] ?? '' ) ) );
                $overview_reachability_label = 'Reachability pending';
                $overview_reachability_note = '' !== $overview_site_host ? $overview_site_host . ' is the current monitored host.' : 'No reachability data yet.';
                if ( 'reachable' === $overview_reachability_slug ) {
                    $overview_reachability_label = 'Reachable';
                    $overview_reachability_note = '' !== $overview_site_host ? $overview_site_host . ' responded successfully.' : 'Latest reachability check responded successfully.';
                } elseif ( 'unreachable' === $overview_reachability_slug ) {
                    $overview_reachability_label = 'Unreachable';
                    $overview_reachability_note = '' !== $overview_site_host ? $overview_site_host . ' did not respond successfully.' : 'Latest reachability check needs attention.';
                } elseif ( '' !== $overview_reachability_slug ) {
                    $overview_reachability_label = ucwords( str_replace( array( '_', '-' ), ' ', $overview_reachability_slug ) );
                }

                $overview_reports_count = 0;
                if ( '' !== $overview_job_id ) {
                    foreach ( $overview_live_export_items as $overview_export_item ) {
                        if ( ! is_array( $overview_export_item ) ) {
                            continue;
                        }
                        $overview_export_kind = isset( $overview_export_item['kind'] ) ? (string) $overview_export_item['kind'] : '';
                        $overview_export_source_job_id = isset( $overview_export_item['source_job_id'] ) ? trim( (string) $overview_export_item['source_job_id'] ) : '';
                        $overview_export_state = isset( $overview_export_item['state'] ) ? strtoupper( (string) $overview_export_item['state'] ) : '';
                        if (
                            $overview_export_source_job_id === $overview_job_id
                            && 'COMPLETED' === $overview_export_state
                            && in_array( $overview_export_kind, array( 'report_html', 'report_pdf', 'csv', 'export_csv', 'triage_csv', 'report_xlsx' ), true )
                        ) {
                            ++$overview_reports_count;
                        }
                    }
                }
                $overview_reports_label = 'No packaged outputs yet';
                $overview_package_name = isset( $overview_package['display_name'] ) ? (string) $overview_package['display_name'] : ucfirst( $eff_state['effective_plan'] );
                if ( '' !== $overview_job_id && $overview_reports_count > 0 ) {
                    $overview_reports_label = 'Latest run outputs ready';
                    $overview_reports_note = sprintf( '%d latest-run output%s are ready on %s.', $overview_reports_count, 1 === $overview_reports_count ? '' : 's', $overview_package_name );
                } elseif ( '' !== $overview_job_id ) {
                    $overview_reports_label = 'Latest run outputs pending';
                    $overview_reports_note = 'The latest run is recorded. Open Reports to generate or review packaged outputs for that run.';
                } elseif ( $overview_history_reports_count > 0 ) {
                    $overview_reports_label = 'Historical outputs available';
                    $overview_reports_note = 'Prior packaged outputs remain available in Reports.';
                } else {
                    $overview_reports_note = sprintf( '%s posture is recorded. Generate a report to package it for %s.', $overview_grade_summary, $overview_package_name );
                }
                $overview_package_outcome = isset( $overview_package['buyer_outcome'] ) ? (string) $overview_package['buyer_outcome'] : 'Current package truth is available from the OpsGate API.';
                $overview_hybrid_copy = isset( $overview_hybrid['framing'] ) ? (string) $overview_hybrid['framing'] : 'OpsGate is one product with site-level operations in the plugin and account-level value across the broader portfolio surface.';
                $overview_system_state = $overview_grade_summary;
                if ( ! $overview_is_connected ) {
                    $overview_system_state = 'Connection needed';
                } elseif ( 'Scan pending' === $overview_grade_summary ) {
                    $overview_system_state = 'Pending';
                } elseif ( 'Healthy' === $overview_grade_summary ) {
                    $overview_system_state = 'Operational';
                }
                $overview_schedule_strip = ! empty( $overview_schedule['is_enabled'] )
                    ? $overview_schedule_label . ' - ' . ( isset( $overview_schedule['due_at_utc'] ) && '' !== (string) $overview_schedule['due_at_utc'] ? 'Next due ' . $overview_due_label : 'Active' )
                    : 'Not scheduled';
                $overview_latest_export = ! empty( $overview_live_export_items ) && is_array( $overview_live_export_items[0] ) ? $overview_live_export_items[0] : array();
                $overview_trust_badge = ! empty( $overview_latest_export ) ? self::canonical_report_trust_badge( $overview_latest_export ) : array( 'tone' => 'neutral', 'label' => 'Trust recorded when outputs exist' );
                $overview_governance_badges = ! empty( $overview_latest_export ) ? self::canonical_report_governance_badges( $overview_latest_export ) : array();
                $overview_package_live = self::package_capability_items( 'live_now' );
                $overview_package_locked = self::package_capability_items( 'visible_locked' );
                $overview_update_detail_items = self::posture_detail_items( 'updates', $overview_update_posture, array( 'vulnerability_posture' => $overview_vulnerability_posture ) );
                $overview_vulnerability_detail_items = self::posture_detail_items( 'vulnerabilities', $overview_vulnerability_posture );
                $overview_reason_items = self::posture_reason_items( $overview_score, $overview_update_posture, $overview_vulnerability_posture, $overview_reachability_posture, $overview_availability_snapshot );
                $overview_next_action_label = 'Run Security Scan';
                $overview_next_action_url = self::admin_tab_url( 'triage' );
                $overview_next_action_copy = 'Refresh the current site posture and generate fresh evidence-backed outputs.';
                if ( ! $overview_is_connected ) {
                    $overview_next_action_label = 'Finish Connection';
                    $overview_next_action_url = self::admin_tab_url( 'settings' );
                    $overview_next_action_copy = 'Complete site identity and confirm the connection before relying on reporting or schedules.';
                } elseif ( 'Scan pending' === $overview_grade_summary ) {
                    $overview_next_action_label = 'Run First Scan';
                    $overview_next_action_url = self::admin_tab_url( 'triage' );
                    $overview_next_action_copy = 'Start the first recorded scan so OpsGate can capture posture, evidence, and packaged outputs.';
                } elseif ( 0 === $overview_reports_count ) {
                    $overview_next_action_label = 'Open Reports';
                    $overview_next_action_url = self::admin_tab_url( 'reports' );
                    $overview_next_action_copy = 'Generate customer-facing outputs from the latest run and confirm their trust state.';
                } elseif ( 'Action required' === $overview_grade_summary || 'Needs attention' === $overview_grade_summary ) {
                    $overview_next_action_label = 'Review Reports';
                    $overview_next_action_url = $overview_reports_url;
                    $overview_next_action_copy = 'Use the latest outputs to review trust state, findings, and evidence-backed next steps.';
                }

                $overview_reason_map = array();
                foreach ( $overview_reason_items as $overview_reason_item ) {
                    if ( ! is_array( $overview_reason_item ) || empty( $overview_reason_item['label'] ) ) {
                        continue;
                    }
                    $overview_reason_map[ strtolower( trim( (string) $overview_reason_item['label'] ) ) ] = $overview_reason_item;
                }

                $overview_update_counts = self::update_posture_counts( $overview_update_posture );
                $overview_availability_summary = isset( $overview_availability_snapshot['summary'] ) && is_array( $overview_availability_snapshot['summary'] ) ? $overview_availability_snapshot['summary'] : array();
                $overview_availability_attempts = isset( $overview_availability_summary['attempt_count'] ) ? (int) $overview_availability_summary['attempt_count'] : 0;
                $overview_availability_failures = isset( $overview_availability_summary['failed_attempts'] ) ? (int) $overview_availability_summary['failed_attempts'] : 0;
                $overview_outputs_strip = 'Not generated';
                $overview_outputs_chip = 'Outputs pending';
                if ( '' !== $overview_job_id && $overview_reports_count > 0 ) {
                    $overview_outputs_strip = sprintf( '%d ready', $overview_reports_count );
                    $overview_outputs_chip = 'Outputs ready';
                } elseif ( '' !== $overview_job_id ) {
                    $overview_outputs_strip = 'Pending';
                    $overview_outputs_chip = 'Outputs pending';
                } elseif ( $overview_history_reports_count > 0 ) {
                    $overview_outputs_strip = 'Historical';
                    $overview_outputs_chip = 'Historical outputs';
                } else {
                    $overview_outputs_chip = 'No outputs yet';
                }

                $overview_hero_reasons = array();
                if ( in_array( $overview_reachability_slug, array( 'unreachable', 'degraded' ), true ) ) {
                    $overview_hero_reasons[] = 'reachability is ' . strtolower( $overview_reachability_label );
                }
                if ( ! empty( $overview_vulnerability_total ) ) {
                    $overview_hero_reasons[] = sprintf( '%d %s found', (int) $overview_vulnerability_total, 1 === (int) $overview_vulnerability_total ? 'vulnerability' : 'vulnerabilities' );
                }
                if ( ! empty( $overview_update_counts['outdated_total'] ) ) {
                    $overview_hero_reasons[] = sprintf( '%d %s need attention', (int) $overview_update_counts['outdated_total'], 1 === (int) $overview_update_counts['outdated_total'] ? 'update' : 'updates' );
                }
                if ( $overview_availability_attempts > 0 && $overview_availability_failures > 0 ) {
                    $overview_hero_reasons[] = sprintf( '%d of %d availability %s failed', $overview_availability_failures, $overview_availability_attempts, 1 === $overview_availability_attempts ? 'probe' : 'probes' );
                }

                $overview_hero_reason = ! empty( $overview_hero_reasons )
                    ? ucfirst( implode( ', ', array_slice( $overview_hero_reasons, 0, 2 ) ) ) . '.'
                    : 'All checks are stable — no immediate action needed.';

                $overview_status_items = array(
                    array(
                        'label' => 'Score',
                        'value' => $overview_score_value . ' / ' . $overview_grade_label,
                    ),
                    array(
                        'label' => 'Scope',
                        'value' => '' !== $overview_site_label ? $overview_site_label : 'Connected site',
                    ),
                    array(
                        'label' => 'Next due',
                        'value' => ! empty( $overview_schedule['is_enabled'] ) ? $overview_due_label : 'Not scheduled',
                    ),
                    array(
                        'label' => 'Trigger',
                        'value' => $overview_trigger_label,
                    ),
                    array(
                        'label' => 'Alerts',
                        'value' => ! empty( $overview_alert_rollup['headline'] ) ? (string) $overview_alert_rollup['headline'] : sprintf( '%d enabled', $overview_enabled_rules ),
                    ),
                    array(
                        'label' => 'Outputs',
                        'value' => $overview_outputs_strip,
                    ),
                    array(
                        'label' => 'Last run',
                        'value' => $overview_run_label,
                    ),
                );

                $overview_state_items = array();
                foreach ( array( 'updates', 'reachability', 'availability', 'vulnerabilities' ) as $overview_driver_key ) {
                    if ( isset( $overview_reason_map[ $overview_driver_key ] ) ) {
                        $overview_state_items[] = $overview_reason_map[ $overview_driver_key ];
                    }
                }

                if ( isset( $overview_reason_map['performance'] ) ) {
                    $overview_state_items[] = $overview_reason_map['performance'];
                }
                $overview_state_grid_class = 'opsgate-overview-state-grid' . ( count( $overview_state_items ) > 4 ? ' opsgate-overview-state-grid-extended' : '' );

                $overview_context_badges = array();
                if ( ! empty( $overview_trust_badge['label'] ) ) {
                    $overview_context_badges[] = array(
                        'tone'  => isset( $overview_trust_badge['tone'] ) ? (string) $overview_trust_badge['tone'] : 'neutral',
                        'label' => (string) $overview_trust_badge['label'],
                    );
                }
                foreach ( $overview_governance_badges as $overview_governance_badge ) {
                    if ( is_array( $overview_governance_badge ) && ! empty( $overview_governance_badge['label'] ) ) {
                        $overview_context_badges[] = $overview_governance_badge;
                    }
                }

                $overview_plan_key = $eff_state['effective_plan'];
                // Evidence availability depends on connection_mode only, not billing tier.
                // $eff_state['is_public_scan'] is the single source of truth for this decision.
                // Operator override does not change evidence availability — that is connection reality.
                $overview_public_only = $eff_state['is_public_scan'];
                if ( $overview_public_only ) {
                    $overview_public_breakdown = self::remote_companion_breakdown_items( $overview_artifacts, $overview_score, true );
                    $overview_grade_label = 'Public check';
                    $overview_grade_summary = 'Public scan only';
                    // Use real posture color when a score exists; fall back to info (blue) only when unscored.
                    $overview_public_score_slug = strtolower( trim( $overview_grade_value ) );
                    if ( in_array( $overview_public_score_slug, array( 'green', 'healthy' ), true ) ) {
                        $overview_grade_tone = 'good';
                    } elseif ( in_array( $overview_public_score_slug, array( 'yellow', 'amber' ), true ) ) {
                        $overview_grade_tone = 'warn';
                    } elseif ( in_array( $overview_public_score_slug, array( 'red', 'critical' ), true ) ) {
                        $overview_grade_tone = 'bad';
                    } else {
                        $overview_grade_tone = 'info';
                    }
                    if ( $is_operator_override && 'free' !== $eff_state['effective_plan'] ) {
                        // Operator override: site is not yet connected but a paid tier is being tested.
                        $overview_hero_reason = 'This site is not yet connected. ' . ucfirst( $eff_state['effective_plan'] ) . ' plan is active for testing. Connect this site via Settings / Site Configuration / Pairing Material to unlock WordPress evidence.';
                        $overview_next_action_label = 'Connect this site →';
                        $overview_next_action_url = self::admin_tab_url( 'settings', array( 'section' => 'site-configuration', 'panel' => 'pairing-material' ) );
                        $overview_next_action_copy = 'Pair this site to unlock connected WordPress inventory, updates, vulnerabilities, alerts, and remediation on the ' . ucfirst( $eff_state['effective_plan'] ) . ' plan.';
                    } else {
                        $overview_hero_reason = 'This site uses public evidence only. Connected WordPress inventory, updates, vulnerabilities, alerts, and remediation stay unavailable on Free.';
                        $overview_next_action_label = 'Upgrade for connected evidence';
                        $overview_next_action_url = self::admin_tab_url( 'billing' );
                        $overview_next_action_copy = 'Connect this site on a paid plan to unlock WordPress inventory, updates, vulnerabilities, alerts, and remediation guidance.';
                    }
                    $overview_scope_meta = 'Public-only site scope';
                    $overview_package_outcome = 'Free keeps this site on public checks only without connected WordPress evidence.';
                    $overview_hybrid_copy = 'Latest public check truth is shown here. Connected reports, alert routing, and remediation stay unavailable until this site is connected on a paid plan.';
                    $overview_reports_label = '' !== $overview_job_id ? 'Public summary ready' : 'No public summary yet';
                    $overview_reports_note = '' !== $overview_job_id
                        ? 'Latest public check completed for this site.'
                        : 'Run a public check in the remote WordPress plugin to create the first public summary.';
                    $overview_outputs_strip = '' !== $overview_job_id ? 'Public summary' : 'Not recorded';
                    $overview_outputs_chip = '' !== $overview_job_id ? 'Public-only' : 'No public summary yet';
                    $overview_status_items = array(
                        array(
                            'label' => 'Score',
                            'value' => $overview_score_value . ' / Public-only',
                        ),
                        array(
                            'label' => 'Scope',
                            'value' => '' !== $overview_site_label ? $overview_site_label : 'Selected site',
                        ),
                        array(
                            'label' => 'Mode',
                            'value' => 'Public check',
                        ),
                        array(
                            'label' => 'Evidence',
                            'value' => 'Public-only',
                        ),
                        array(
                            'label' => 'Alerts',
                            'value' => 'Connected plans only',
                        ),
                        array(
                            'label' => 'Outputs',
                            'value' => $overview_outputs_strip,
                        ),
                        array(
                            'label' => 'Last run',
                            'value' => $overview_run_label,
                        ),
                    );
                    $overview_state_items = array();
                    foreach ( $overview_public_breakdown as $overview_public_item ) {
                        if ( ! is_array( $overview_public_item ) ) {
                            continue;
                        }
                        $facts = array();
                        if ( ! empty( $overview_public_item['meta'] ) ) {
                            $facts[] = (string) $overview_public_item['meta'];
                        }
                        $overview_state_items[] = array(
                            'label' => isset( $overview_public_item['label'] ) ? (string) $overview_public_item['label'] : 'Public evidence',
                            'name'  => isset( $overview_public_item['value'] ) ? (string) $overview_public_item['value'] : 'Recorded',
                            'meta'  => isset( $overview_public_item['copy'] ) ? (string) $overview_public_item['copy'] : 'Public evidence recorded for this site.',
                            'facts' => $facts,
                        );
                    }
                    $overview_state_grid_class = 'opsgate-overview-state-grid' . ( count( $overview_state_items ) > 4 ? ' opsgate-overview-state-grid-extended' : '' );
                    $overview_context_badges = array(
                        array(
                            'tone'  => 'info',
                            'label' => 'Public-only evidence',
                        ),
                        array(
                            'tone'  => 'neutral',
                            'label' => 'External only',
                        ),
                    );
                }
                ?>


                <?php
                // Phase 5 — Dashboard premium hero data
                $p5_run_delta = isset( $overview_artifacts['run_delta']['body'] ) && is_array( $overview_artifacts['run_delta']['body'] ) ? $overview_artifacts['run_delta']['body'] : array();
                $p5_previous_score = isset( $p5_run_delta['previous_score'] ) ? (int) $p5_run_delta['previous_score'] : null;
                $p5_current_score_int = is_numeric( $overview_score_value ) ? (int) $overview_score_value : null;
                $p5_score_display = is_numeric( $overview_score_value ) ? $overview_score_value . '/100' : $overview_score_value;
                $p5_trend_direction = 'flat';
                $p5_trend_delta = 0;
                if ( null !== $p5_previous_score && null !== $p5_current_score_int ) {
                    $p5_trend_delta = $p5_current_score_int - $p5_previous_score;
                    if ( $p5_trend_delta > 0 ) {
                        $p5_trend_direction = 'up';
                    } elseif ( $p5_trend_delta < 0 ) {
                        $p5_trend_direction = 'down';
                    }
                }
                $p5_trend_icon = 'flat' === $p5_trend_direction ? '–' : ( 'up' === $p5_trend_direction ? '↑' : '↓' );
                $p5_trend_label = 'flat' !== $p5_trend_direction ? sprintf( '%s%d from last run', 'up' === $p5_trend_direction ? '+' : '', $p5_trend_delta ) : 'No change from last run';
                // P1-A — Gauge arc calculation (circumference of r=72: 2πr ≈ 452.39, ring sized to 180px)
                $p5_gauge_circumference = 452.39;
                $p5_gauge_pct = ( null !== $p5_current_score_int && $p5_current_score_int >= 0 && $p5_current_score_int <= 100 ) ? $p5_current_score_int / 100 : 0;
                $p5_gauge_offset = $p5_gauge_circumference * ( 1 - $p5_gauge_pct );
                // Phase 5 — dimension chips (5 compact chips from posture data)
                $p5_performance_snapshot = isset( $overview_artifacts['performance_snapshot']['body'] ) && is_array( $overview_artifacts['performance_snapshot']['body'] ) ? $overview_artifacts['performance_snapshot']['body'] : array();
                $p5_perf_score = isset( $p5_performance_snapshot['score'] ) ? (int) $p5_performance_snapshot['score'] : null;
                $p5_perf_tone = ( null !== $p5_perf_score ) ? ( $p5_perf_score >= 80 ? 'good' : ( $p5_perf_score >= 50 ? 'warn' : 'bad' ) ) : 'neutral';
                $p5_ssl_tone = 'reachable' === $overview_reachability_slug ? 'good' : ( '' === $overview_reachability_slug ? 'neutral' : 'bad' );
                $p5_avail_tone = ( $overview_availability_attempts > 0 && $overview_availability_failures === 0 ) ? 'good' : ( $overview_availability_failures > 0 ? 'warn' : 'neutral' );
                $p5_vuln_tone = ( null !== $overview_vulnerability_total && 0 === $overview_vulnerability_total ) ? 'good' : ( null !== $overview_vulnerability_total && $overview_vulnerability_total > 0 ? 'bad' : 'neutral' );
                $p5_update_tone = ( null !== $overview_update_total && 0 === $overview_update_total ) ? 'good' : ( null !== $overview_update_total && $overview_update_total > 0 ? 'warn' : 'neutral' );
                $p5_chips = array(
                    array( 'label' => 'Reachability', 'tone' => $p5_ssl_tone, 'value' => 'reachable' === $overview_reachability_slug ? 'OK' : ( '' === $overview_reachability_slug ? 'Not measured' : 'Issue' ) ),
                    array( 'label' => 'Availability', 'tone' => $p5_avail_tone, 'value' => $overview_availability_attempts > 0 ? sprintf( '%d/%d', $overview_availability_attempts - $overview_availability_failures, $overview_availability_attempts ) : 'Not measured' ),
                    array( 'label' => 'Performance', 'tone' => $p5_perf_tone, 'value' => null !== $p5_perf_score ? $p5_perf_score . '/100' : 'Not measured' ),
                    array( 'label' => 'Vulnerabilities', 'tone' => $p5_vuln_tone, 'value' => null !== $overview_vulnerability_total ? (string) $overview_vulnerability_total : 'Not measured' ),
                    array( 'label' => 'Updates', 'tone' => $p5_update_tone, 'value' => null !== $overview_update_total ? (string) $overview_update_total . ' pending' : 'Not measured' ),
                );
                // Phase 5 — mini activity feed (3 items) from overview_activity
                $p5_mini_feed_items = array_slice( array_filter( (array) $overview_activity, 'is_array' ), 0, 3 );
                $p5_activity_family_fn = static function( array $item ): string {
                    $lk = strtolower( (string) ( $item['label'] ?? '' ) );
                    if ( false !== strpos( $lk, 'report' ) ) { return 'report'; }
                    if ( false !== strpos( $lk, 'alert' ) || false !== strpos( $lk, 'deliver' ) ) { return 'alert'; }
                    if ( false !== strpos( $lk, 'triage' ) || false !== strpos( $lk, 'scan' ) ) { return 'scan'; }
                    if ( false !== strpos( $lk, 'connect' ) || false !== strpos( $lk, 'pair' ) ) { return 'connection'; }
                    return 'system';
                };
                $p5_family_icon_fn = static function( string $family ): string {
                    $map = array(
                        'report'     => 'R',
                        'alert'      => 'A',
                        'scan'       => 'S',
                        'triage'     => 'S',
                        'connection' => 'C',
                        'delivery'   => 'D',
                        'system'     => '·',
                    );
                    return isset( $map[ $family ] ) ? $map[ $family ] : '·';
                };
                $p5_last_checked_human = '' !== $overview_run_label ? $overview_run_label : 'Not run yet';
                ?>

                <div class="opsgate-card opsgate-overview-dashboard">

                    <!-- Phase 5: Premium Dashboard Hero -->
                    <div class="opsgate-p5-dashboard-hero">
                        <div class="opsgate-p5-gauge-wrap<?php echo $overview_is_stale ? ' opsgate-score-stale' : ''; ?>">
                            <svg class="opsgate-p5-gauge-svg" viewBox="0 0 180 180" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
                                <circle class="opsgate-p5-gauge-track" cx="90" cy="90" r="72"/>
                                <circle
                                    class="opsgate-p5-gauge-arc<?php echo $overview_is_stale ? ' tone-warn' : ' tone-' . esc_attr( $overview_grade_tone ); ?>"
                                    cx="90" cy="90" r="72"
                                    stroke-dasharray="<?php echo esc_attr( number_format( $p5_gauge_circumference, 2, '.', '' ) ); ?>"
                                    stroke-dashoffset="<?php echo esc_attr( number_format( $p5_gauge_offset, 2, '.', '' ) ); ?>"
                                />
                            </svg>
                            <div class="opsgate-p5-gauge-center">
                                <span class="opsgate-p5-gauge-score tone-<?php echo esc_attr( $overview_grade_tone ); ?>"><?php echo esc_html( $overview_score_value ); ?></span>
                                <?php if ( is_numeric( $overview_score_value ) ) : ?><span class="opsgate-p5-gauge-out-of">/100</span><?php endif; ?>
                                <span class="opsgate-p5-gauge-label"><?php echo esc_html( $overview_grade_label ); ?></span>
                            </div>
                        </div>
                        <div class="opsgate-p5-dashboard-hero-main">
                            <div class="opsgate-p5-dashboard-hero-meta">
                                <span class="opsgate-p5-last-checked<?php echo $overview_is_stale ? ' opsgate-score-stale-label' : ''; ?>"><?php echo $overview_is_stale ? esc_html( 'Scan overdue — last checked ' . $p5_last_checked_human ) : esc_html( 'Last checked: ' . $p5_last_checked_human ); ?></span>
                                <?php if ( null !== $p5_previous_score ) : ?>
                                <span class="opsgate-p5-trend trend-<?php echo esc_attr( $p5_trend_direction ); ?>"><?php echo esc_html( $p5_trend_icon . ' ' . $p5_trend_label ); ?></span>
                                <?php endif; ?>
                            </div>
                            <h3 class="opsgate-p5-dashboard-hero-title"><?php echo esc_html( 'Security status: ' . $overview_grade_label . ' — ' . ( '' !== $overview_site_label ? $overview_site_label : 'Connected site' ) ); ?></h3>
                            <p class="opsgate-p5-dashboard-hero-subtitle"><?php echo esc_html( $overview_hero_reason ); ?></p>
                            <div class="opsgate-p5-action-strip">
                                <?php if ( $overview_public_only ) : ?>
                                <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
                                    <input type="hidden" name="action" value="opsgate_run_free_public_onboarding"/>
                                    <?php wp_nonce_field( 'opsgate_run_free_public_onboarding', 'opsgate_run_free_public_onboarding_nonce' ); ?>
                                    <button type="submit" class="button button-primary">Run Public Check</button>
                                </form>
                                <a class="button button-secondary" href="<?php echo esc_url( self::admin_tab_url( 'billing' ) ); ?>">Upgrade for Reports</a>
                                <a class="button button-secondary" href="<?php echo esc_url( self::admin_tab_url( 'billing' ) ); ?>">View Billing</a>
                                <?php elseif ( ! $overview_is_connected ) : ?>
                                <a class="button button-primary" href="<?php echo esc_url( self::admin_tab_url( 'settings' ) ); ?>">Finish Connection</a>
                                <?php else : ?>
                                <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" data-opsgate-triage-launch-form="1" data-opsgate-triage-run-url="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>" data-opsgate-triage-destination-url="<?php echo esc_url( self::admin_tab_url( 'triage' ) ); ?>" data-opsgate-status-target="opsgate-p5-hero-status">
                                    <input type="hidden" name="action" value="opsgate_run_portfolio_triage"/>
                                    <?php wp_nonce_field( 'opsgate_run_portfolio_triage' ); ?>
                                    <button type="submit" class="button button-primary">Run New Scan</button>
                                </form>
                                <div class="opsgate-p5-action-links">
                                    <a href="<?php echo esc_url( self::admin_tab_url( 'reports', '' !== $overview_job_id ? array( 'source_job_id' => $overview_job_id ) : array() ) ); ?>">Open Reports</a>
                                    <span class="opsgate-p5-action-sep">·</span>
                                    <a href="<?php echo esc_url( $overview_alerts_url ); ?>">Configure Alerts</a>
                                </div>
                                <?php endif; ?>
                            </div>
                            <div id="opsgate-p5-hero-status" class="opsgate-alert-inline-status" role="status" aria-live="polite"><p></p></div>
                            <?php if ( $overview_public_only && '' === $overview_job_id ) : ?>
                            <div class="opsgate-r1-guidance-state" style="margin-top:16px;">
                                <strong>No public check yet.</strong> Use the remote WordPress plugin to run your first public check, or click <em>Run Public Check</em> above. OpsGate will check what is publicly visible from outside this site and show the results here.
                            </div>
                            <?php endif; ?>
                            <div class="opsgate-p5-chip-row">
                                <?php foreach ( $p5_chips as $p5_chip ) : ?>
                                <span class="opsgate-p5-dim-chip tone-<?php echo esc_attr( $p5_chip['tone'] ); ?>">
                                    <span class="opsgate-p5-dim-dot"></span>
                                    <?php echo esc_html( $p5_chip['label'] . ' ' . $p5_chip['value'] ); ?>
                                </span>
                                <?php endforeach; ?>
                            </div>
                        </div>
                    </div>

                    <?php if ( ! empty( $p5_mini_feed_items ) ) : ?>
                    <div class="opsgate-p5-mini-feed">
                        <div class="opsgate-p5-mini-feed-head">
                            <span class="opsgate-p5-mini-feed-title">Recent Activity</span>
                            <?php if ( ! $overview_public_only ) : ?>
                            <a class="opsgate-p5-mini-feed-viewall" href="<?php echo esc_url( $overview_activity_url ); ?>">View all →</a>
                            <?php endif; ?>
                        </div>
                        <?php foreach ( $p5_mini_feed_items as $p5_mini_item ) : ?>
                        <?php $p5_mf = $p5_activity_family_fn( $p5_mini_item ); ?>
                        <div class="opsgate-p5-mini-feed-item">
                            <div class="opsgate-p5-mini-feed-icon family-<?php echo esc_attr( $p5_mf ); ?>" aria-hidden="true"><?php echo esc_html( $p5_family_icon_fn( $p5_mf ) ); ?></div>
                            <div class="opsgate-p5-mini-feed-body">
                                <div class="opsgate-p5-mini-feed-label"><?php echo esc_html( (string) ( $p5_mini_item['label'] ?? 'Activity event' ) ); ?></div>
                                <div class="opsgate-p5-mini-feed-when"><?php echo esc_html( (string) ( $p5_mini_item['when'] ?? '' ) ); ?></div>
                            </div>
                        </div>
                        <?php endforeach; ?>
                    </div>
                    <?php endif; ?>

                    <?php if ( ! empty( $overview_state_items ) ) : ?>
                    <section class="opsgate-p5-evidence-section">
                        <div class="opsgate-p5-section-head">
                            <span class="opsgate-p5-section-heading"><?php echo esc_html( $overview_public_only ? 'Public evidence for this site' : ( 'Scan pending' === $overview_grade_summary ? 'Evidence recorded for this site' : 'What makes this site ' . $overview_grade_label ) ); ?></span>
                            <a class="opsgate-p5-section-link" href="<?php echo esc_url( $overview_public_only ? self::admin_tab_url( 'billing' ) : self::admin_tab_url( 'triage' ) ); ?>"><?php echo esc_html( $overview_public_only ? 'Upgrade for full evidence' : 'Open Triage' ); ?> &rarr;</a>
                        </div>
                        <p class="opsgate-p5-meta-text" style="margin-bottom:12px;"><?php echo esc_html( $overview_public_only ? 'Public checks showing what is visible from outside the site.' : 'Checks showing where the current condition comes from.' ); ?></p>
                        <div class="<?php echo esc_attr( $overview_state_grid_class ); ?>">
                            <?php foreach ( $overview_state_items as $overview_driver_item ) : ?>
                                <?php
                                $overview_driver_label = isset( $overview_driver_item['label'] ) ? strtolower( trim( (string) $overview_driver_item['label'] ) ) : 'neutral';
                                $overview_driver_facts = isset( $overview_driver_item['facts'] ) && is_array( $overview_driver_item['facts'] ) ? array_slice( array_values( array_filter( $overview_driver_item['facts'] ) ), 0, 3 ) : array();
                                ?>
                                <article class="opsgate-overview-metric-card opsgate-overview-state-card opsgate-overview-state-card-<?php echo esc_attr( $overview_driver_label ); ?>">
                                    <span class="opsgate-overview-eyebrow"><?php echo esc_html( (string) ( $overview_driver_item['label'] ?? 'Recorded state' ) ); ?></span>
                                    <div class="opsgate-overview-state-heading"><?php echo esc_html( (string) ( $overview_driver_item['name'] ?? 'State recorded' ) ); ?></div>
                                    <?php if ( ! empty( $overview_driver_item['meta'] ) ) : ?>
                                        <p class="opsgate-overview-state-summary"><?php echo esc_html( (string) $overview_driver_item['meta'] ); ?></p>
                                    <?php endif; ?>
                                    <?php if ( ! empty( $overview_driver_facts ) ) : ?>
                                        <ul class="opsgate-overview-state-facts">
                                            <?php foreach ( $overview_driver_facts as $overview_driver_fact ) : ?>
                                                <li><?php echo esc_html( (string) $overview_driver_fact ); ?></li>
                                            <?php endforeach; ?>
                                        </ul>
                                    <?php endif; ?>
                                </article>
                            <?php endforeach; ?>
                        </div>
                    </section>
                    <?php endif; ?>
                </div>

            <?php elseif ( 'triage' === $active_tab ) : ?>
                <div class="opsgate-card">
                    <h2><span class="dashicons dashicons-clipboard"></span> Security Scan</h2>
                    <p class="description" style="margin:0 0 16px 0;font-size:15px;line-height:1.6;font-weight:500;color:#1d2327;">
                        Run a security scan, monitor live progress, and review results from the latest recorded run.
                    </p>

                    <?php
                    $triage_scope = self::get_mcp_scope_snapshot();
                    $account_id = isset( $triage_scope['account_id'] ) ? trim( (string) $triage_scope['account_id'] ) : '';
                    $site_id    = isset( $triage_scope['site_id'] ) ? trim( (string) $triage_scope['site_id'] ) : '';
                    $triage_scope_error = isset( $triage_scope['error'] ) ? trim( (string) $triage_scope['error'] ) : '';
                    $triage_is_connected = '' !== $account_id && '' !== $site_id && '' === $triage_scope_error;
                    $triage_selected_site = self::current_selected_site_summary();
                    $triage_connection_status = isset( $triage_selected_site['connection_status'] ) ? trim( (string) $triage_selected_site['connection_status'] ) : 'external_only';
                    $triage_connection_mode = isset( $triage_selected_site['connection_mode'] ) ? trim( (string) $triage_selected_site['connection_mode'] ) : 'public_scan';
                    $triage_current_plan = $eff_state['surface_plan_for_tabs'];
                    $triage_public_only_plan = 'free' === $triage_current_plan;
                    $triage_selected_is_local = self::scope_targets_local_wordpress( isset( $triage_selected_site['site_url'] ) ? (string) $triage_selected_site['site_url'] : '' );
                    $triage_connection_label = self::canonical_connection_status_label( $triage_connection_status );
                    $triage_connection_mode_label = self::canonical_connection_mode_label( $triage_connection_mode );
                    $triage_connection_copy = self::canonical_connection_status_copy( $triage_connection_status, $triage_connection_mode, $triage_selected_is_local );
                    if ( $triage_public_only_plan ) {
                        $triage_connection_label = 'External/public-only';
                        $triage_connection_mode_label = 'Public scan';
                        $triage_connection_copy = 'Free runs external public checks only. Authenticated WordPress inventory, runtime, updates, vulnerabilities, and connector credential truth stay unavailable until a paid connected tier is active.';
                    }
                    $triage_runtime_refs = self::scope_runtime_refs_for_scope( $triage_scope );
                    $last_triage_job_id = trim( (string) ( $triage_runtime_refs['last_triage_job_id'] ?? '' ) );
                    $last_export_job_id = trim( (string) ( $triage_runtime_refs['last_export_job_id'] ?? '' ) );
                    $last_export_source_job_id = trim( (string) ( $triage_runtime_refs['last_export_source_job_id'] ?? '' ) );

                    $current_run = null;
                    $current_run_state = '';
                    $current_run_copy = '';

                    if ( '' !== $last_triage_job_id ) {
                        $current_run = self::mcp_get_json( '/v1/jobs/' . rawurlencode( $last_triage_job_id ) );
                        $current_run_job = is_array( $current_run ) && isset( $current_run['data'] ) && is_array( $current_run['data'] ) ? $current_run['data'] : array();
                        if ( ! empty( $current_run_job ) && ! self::job_matches_scope( $current_run_job, $triage_scope ) ) {
                            $current_run = null;
                            $last_triage_job_id = '';
                        }

                        $state_value = '';

                        if ( is_array( $current_run ) ) {
                            if ( isset( $current_run['data'] ) && is_array( $current_run['data'] ) && ! empty( $current_run['data']['state'] ) ) {
                                $state_value = (string) $current_run['data']['state'];
                            } elseif ( ! empty( $current_run['state'] ) ) {
                                $state_value = (string) $current_run['state'];
                            }
                        }

                            if ( '' !== $state_value ) {
                            $current_run_state = strtoupper( $state_value );

                            if ( 'QUEUED' === $current_run_state ) {
                                $current_run_copy = 'Queued — your run will begin shortly.';
                            } elseif ( 'RUNNING' === $current_run_state ) {
                                $current_run_copy = 'Running — gathering evidence now.';
                            } elseif ( 'COMPLETED' === $current_run_state ) {
                                $current_run_copy = 'Scan complete. Review the results and outputs.';
                            } elseif ( 'FAILED' === $current_run_state ) {
                                $current_run_copy = 'This run ended with issues. Review run details and evidence.';
                            } else {
                                $current_run_copy = 'Status: ' . $current_run_state;
                            }
                        }
                    }

                    $export_state = '';
                    $export_state_upper = '';
                    $export_copy = '';

                    if ( '' !== $last_export_job_id ) {
                        $export_meta = self::export_record_state_summary( $last_export_job_id );
                        if ( ! empty( $export_meta['ok'] ) ) {
                            $export_state = isset( $export_meta['state'] ) ? (string) $export_meta['state'] : '';
                            $export_state_upper = strtoupper( $export_state );
                        }

                        if ( 'QUEUED' === $export_state_upper ) {
                            $export_copy = 'Latest run outputs are queued for packaging.';
                        } elseif ( 'RUNNING' === $export_state_upper ) {
                            $export_copy = 'Latest run outputs are being prepared now.';
                        } elseif ( 'COMPLETED' === $export_state_upper ) {
                            $export_copy = 'Latest run outputs are ready in Reports.';
                        } elseif ( 'FAILED' === $export_state_upper ) {
                            $export_copy = 'Latest run outputs did not finish packaging. Refresh status or open Reports.';
                        } elseif ( '' !== $export_state_upper ) {
                            $export_copy = 'Status: ' . $export_state_upper;
                        }
                    }

                    $should_auto_refresh = in_array( $current_run_state, array( 'QUEUED', 'RUNNING' ), true ) || in_array( $export_state_upper, array( 'QUEUED', 'RUNNING' ), true );
                    $triage_live_snapshot = self::triage_live_status_snapshot();
                    $triage_live_snapshot_ok = ! empty( $triage_live_snapshot['ok'] );
                    $refresh_url = add_query_arg( array( 'tab' => 'triage' ), admin_url( 'admin.php?page=opsgate' ) );
                    $latest = self::canonical_latest_triage_bundle();
                    $operator_degradation_state = self::operator_degradation_status();
                    $operator_degradation_scenarios = isset( $operator_degradation_state['catalog'] ) && is_array( $operator_degradation_state['catalog'] ) ? $operator_degradation_state['catalog'] : self::operator_degradation_scenarios();
                    $operator_degradation_active_item = isset( $operator_degradation_state['active_item'] ) && is_array( $operator_degradation_state['active_item'] ) ? $operator_degradation_state['active_item'] : array();
                    $operator_degradation_recent_items = isset( $operator_degradation_state['recent_items'] ) && is_array( $operator_degradation_state['recent_items'] ) ? $operator_degradation_state['recent_items'] : array();
                    $operator_degradation_status = isset( $operator_degradation_state['status'] ) ? strtolower( trim( (string) $operator_degradation_state['status'] ) ) : 'inactive';
                    $operator_degradation_message = isset( $operator_degradation_state['status_message'] ) ? (string) $operator_degradation_state['status_message'] : 'No active degradation.';
                    $selected_proof_run_id = isset( $_GET['proof_run_id'] ) ? sanitize_text_field( wp_unslash( $_GET['proof_run_id'] ) ) : '';
                    $selected_proof_run = array();
                    if ( '' !== $selected_proof_run_id ) {
                        $selected_proof_lookup = self::proof_run_get( $selected_proof_run_id );
                        if ( ! empty( $selected_proof_lookup['ok'] ) && ! empty( $selected_proof_lookup['item'] ) ) {
                            $selected_proof_run = $selected_proof_lookup['item'];
                        }
                    }
                    $selected_proof_job_id = ! empty( $selected_proof_run ) ? self::proof_run_linked_job_id( $selected_proof_run ) : '';
                    $selected_proof_bundle = '' !== $selected_proof_job_id ? self::triage_bundle_for_job_id( $selected_proof_job_id ) : array( 'ok' => false, 'job' => array(), 'artifacts' => array(), 'error' => 'missing_job_id' );
                    $triage_notice = isset( $_GET['opsgate_notice'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_notice'] ) ) : '';
                    $triage_notice_detail = isset( $_GET['opsgate_notice_detail'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_notice_detail'] ) ) : '';


                    ?>

                    <?php if ( ! $triage_is_connected ) : ?>
                        <p><?php echo esc_html( '' !== $triage_scope_error ? 'Select or create a canonical site in Settings before viewing site-scoped triage truth.' : 'Select or create a canonical site in Settings before viewing site-scoped triage truth.' ); ?></p>
                    <?php else : ?>

                        <?php
                        if ( 'proof_run_failed' === $triage_notice ) {
                            $proof_error_message = 'The legacy proof receipt could not be opened right now.';
                            if ( 'proof_site_scope_missing' === $triage_notice_detail || 'proof_site_id_required' === $triage_notice_detail ) {
                                $proof_error_message = 'Connect this site in Settings before opening legacy Level 1 proof receipts.';
                            } elseif ( 'proof_posture_scenario_retired' === $triage_notice_detail ) {
                                $proof_error_message = 'Legacy Level 1 posture proof creation is retired. Use the operator degradation harness instead.';
                            } elseif ( 'proof_scenario_not_supported' === $triage_notice_detail ) {
                                $proof_error_message = 'That legacy proof scenario is no longer available from Triage.';
                            }
                            echo '<div class="opsgate-alert-inline-status is-visible is-error" data-opsgate-transient-status="1" style="margin:0 0 16px 0;"><p>' . esc_html( $proof_error_message ) . '</p></div>';
                        } elseif ( 'operator_degradation_failed' === $triage_notice ) {
                            $operator_error_message = 'The operator degradation request could not be recorded right now.';
                            if ( 'operator_harness_scope_missing' === $triage_notice_detail ) {
                                $operator_error_message = 'Connect this site in Settings before using the operator degradation harness.';
                            } elseif ( 'operator_harness_not_enabled' === $triage_notice_detail ) {
                                $operator_error_message = 'The operator degradation harness is not enabled for this site.';
                            } elseif ( false !== strpos( $triage_notice_detail, 'site_' ) || false !== strpos( $triage_notice_detail, 'operator_harness_site_' ) ) {
                                $operator_error_message = 'The operator degradation request could not be linked to the current site scope.';
                            } elseif ( 'operator_degradation_scenario_invalid' === $triage_notice_detail ) {
                                $operator_error_message = 'The requested operator degradation scenario is unavailable.';
                            }
                            echo '<div class="opsgate-alert-inline-status is-visible is-error" data-opsgate-transient-status="1" style="margin:0 0 16px 0;"><p>' . esc_html( $operator_error_message ) . '</p></div>';
                        } elseif ( 'operator_degradation_applied' === $triage_notice ) {
                            $operator_success_message = 'Operator degradation updated. Run Security Scan to record the current live degraded state.';
                            if ( 'no_change' === $triage_notice_detail ) {
                                $operator_success_message = 'The selected operator degradation was already active. Run Security Scan to refresh current live truth if needed.';
                            }
                            echo '<div class="opsgate-alert-inline-status is-visible is-success" data-opsgate-transient-status="1" style="margin:0 0 16px 0;"><p>' . esc_html( $operator_success_message ) . '</p></div>';
                        } elseif ( 'operator_degradation_cleared' === $triage_notice ) {
                            $operator_clear_message = 'Degradation cleared. Run Security Scan to restore the current live state.';
                            if ( 'no_active_degradation' === $triage_notice_detail ) {
                                $operator_clear_message = 'No active degradation was set. Run Security Scan if you want to refresh live truth now.';
                            }
                            echo '<div class="opsgate-alert-inline-status is-visible is-success" data-opsgate-transient-status="1" style="margin:0 0 16px 0;"><p>' . esc_html( $operator_clear_message ) . '</p></div>';
                        }
                        $validation_notice = isset( $_GET['opsgate_validation_notice'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_validation_notice'] ) ) : '';
                        $validation_notice_detail = isset( $_GET['opsgate_validation_notice_detail'] ) ? sanitize_text_field( rawurldecode( (string) wp_unslash( $_GET['opsgate_validation_notice_detail'] ) ) ) : '';
                        if ( 'queued' === $validation_notice ) {
                            echo '<div class="opsgate-alert-inline-status is-visible is-success" data-opsgate-transient-status="1" style="margin:0 0 16px 0;"><p>' . esc_html( '' !== $validation_notice_detail ? $validation_notice_detail : 'Validation remediation was queued through canonical OpsGate execution.' ) . '</p></div>';
                        } elseif ( 'error' === $validation_notice ) {
                            echo '<div class="opsgate-alert-inline-status is-visible is-error" data-opsgate-transient-status="1" style="margin:0 0 16px 0;"><p>' . esc_html( '' !== $validation_notice_detail ? $validation_notice_detail : 'Validation remediation could not be queued right now.' ) . '</p></div>';
                        }

                        $operator_status_label = 'No active degradation';
                        $operator_status_tone = 'neutral';
                        if ( 'warning_active' === $operator_degradation_status ) {
                            $operator_status_label = 'Warning active';
                            $operator_status_tone = 'warn';
                        } elseif ( 'critical_active' === $operator_degradation_status ) {
                            $operator_status_label = 'Critical active';
                            $operator_status_tone = 'bad';
                        } elseif ( 'cleared_awaiting_rerun' === $operator_degradation_status ) {
                            $operator_status_label = 'Cleared awaiting rerun';
                            $operator_status_tone = 'info';
                        } elseif ( 'unavailable' === $operator_degradation_status ) {
                            $operator_status_label = 'Harness unavailable';
                            $operator_status_tone = 'neutral';
                        }
                        ?>
                        <?php if ( ! empty( $selected_proof_run ) ) : ?>
                            <?php
                            $selected_proof_actual = isset( $selected_proof_run['actual_result'] ) && is_array( $selected_proof_run['actual_result'] ) ? $selected_proof_run['actual_result'] : array();
                            $selected_proof_score = isset( $selected_proof_actual['score'] ) ? (int) $selected_proof_actual['score'] : null;
                            $selected_proof_grade = isset( $selected_proof_actual['grade'] ) ? ucfirst( (string) $selected_proof_actual['grade'] ) : 'Recorded';
                            $selected_proof_posture = isset( $selected_proof_actual['primary_posture_state'] ) ? ucfirst( str_replace( '_', ' ', (string) $selected_proof_actual['primary_posture_state'] ) ) : 'Recorded';
                            $selected_proof_completed = isset( $selected_proof_run['completed_at_utc'] ) && '' !== (string) $selected_proof_run['completed_at_utc'] ? self::canonical_report_datetime_label( (string) $selected_proof_run['completed_at_utc'] ) : ( isset( $selected_proof_run['started_at_utc'] ) ? self::canonical_report_datetime_label( (string) $selected_proof_run['started_at_utc'] ) : '—' );
                            $selected_proof_bundle_job = isset( $selected_proof_bundle['job'] ) && is_array( $selected_proof_bundle['job'] ) ? $selected_proof_bundle['job'] : array();
                            $selected_proof_artifacts = isset( $selected_proof_bundle['artifacts'] ) && is_array( $selected_proof_bundle['artifacts'] ) ? $selected_proof_bundle['artifacts'] : array();
                            $selected_proof_score_summary = isset( $selected_proof_artifacts['score_summary']['body'] ) && is_array( $selected_proof_artifacts['score_summary']['body'] ) ? $selected_proof_artifacts['score_summary']['body'] : array();
                            $selected_proof_update_posture = isset( $selected_proof_artifacts['update_posture']['body'] ) && is_array( $selected_proof_artifacts['update_posture']['body'] ) ? $selected_proof_artifacts['update_posture']['body'] : array();
                            $selected_proof_vulnerability_posture = isset( $selected_proof_artifacts['vulnerability_posture']['body'] ) && is_array( $selected_proof_artifacts['vulnerability_posture']['body'] ) ? $selected_proof_artifacts['vulnerability_posture']['body'] : array();
                            $selected_proof_reachability_posture = isset( $selected_proof_artifacts['reachability_posture']['body'] ) && is_array( $selected_proof_artifacts['reachability_posture']['body'] ) ? $selected_proof_artifacts['reachability_posture']['body'] : array();
                            $selected_proof_availability_snapshot = isset( $selected_proof_artifacts['availability_snapshot']['body'] ) && is_array( $selected_proof_artifacts['availability_snapshot']['body'] ) ? $selected_proof_artifacts['availability_snapshot']['body'] : array();
                            $selected_proof_update_items = self::posture_detail_items( 'updates', $selected_proof_update_posture, array( 'vulnerability_posture' => $selected_proof_vulnerability_posture ) );
                            $selected_proof_vulnerability_items = self::posture_detail_items( 'vulnerabilities', $selected_proof_vulnerability_posture );
                            $selected_proof_update_counts = self::update_posture_counts( $selected_proof_update_posture );
                            $selected_proof_vulnerability_summary = isset( $selected_proof_vulnerability_posture['summary'] ) && is_array( $selected_proof_vulnerability_posture['summary'] ) ? $selected_proof_vulnerability_posture['summary'] : array();
                            $selected_proof_reachability_summary = isset( $selected_proof_reachability_posture['summary'] ) && is_array( $selected_proof_reachability_posture['summary'] ) ? $selected_proof_reachability_posture['summary'] : array();
                            $selected_proof_reason_items = self::posture_reason_items(
                                $selected_proof_score_summary,
                                $selected_proof_update_posture,
                                $selected_proof_vulnerability_posture,
                                $selected_proof_reachability_posture,
                                $selected_proof_availability_snapshot
                            );
                            ?>
                            <details class="opsgate-r1-help-panel opsgate-triage-legacy-receipt" style="margin:0 0 18px 0;">
                                <summary>Legacy proof receipt <span style="font-weight:400;font-size:12px;color:var(--og-text-3);">— operator/demo context, not canonical product truth</span></summary>
                                <div class="opsgate-r1-help-panel-body">
                            <section class="opsgate-triage-surface">
                                <div class="opsgate-triage-surface-header">
                                    <h3 class="opsgate-triage-surface-title">Legacy Level 1 Proof Receipt</h3>
                                    <span class="opsgate-triage-surface-link">Legacy proof/demo context</span>
                                </div>

                                <div class="opsgate-pricing-summary-grid">
                                    <article class="opsgate-pricing-summary-card">
                                        <span class="opsgate-overview-eyebrow">Scenario</span>
                                        <div class="opsgate-pricing-hero-side-title"><?php echo esc_html( self::proof_run_scenario_label( $selected_proof_run ) ); ?></div>
                                        <p><?php echo esc_html( self::proof_run_summary_copy( $selected_proof_run ) ); ?></p>
                                    </article>
                                    <article class="opsgate-pricing-summary-card">
                                        <span class="opsgate-overview-eyebrow">Recorded posture</span>
                                        <div class="opsgate-pricing-hero-side-title"><?php echo esc_html( null !== $selected_proof_score ? (string) $selected_proof_score . ' / ' . $selected_proof_grade : $selected_proof_grade ); ?></div>
                                        <p><?php echo esc_html( $selected_proof_posture . ' recorded for operator validation.' ); ?></p>
                                    </article>
                                    <article class="opsgate-pricing-summary-card">
                                        <span class="opsgate-overview-eyebrow">Completed</span>
                                        <div class="opsgate-pricing-hero-side-title"><?php echo esc_html( $selected_proof_completed ); ?></div>
                                        <p>Latest/current tabs continue to follow Security Scan live evidence. This legacy receipt stays separate.</p>
                                    </article>
                                </div>

                                <?php if ( ! empty( $selected_proof_bundle['ok'] ) ) : ?>
                                    <div class="opsgate-pricing-summary-grid" style="margin-top:16px;">
                                        <article class="opsgate-pricing-summary-card">
                                            <span class="opsgate-overview-eyebrow">Updates behind this result</span>
                                            <div class="opsgate-pricing-hero-side-title"><?php echo esc_html( (string) (int) $selected_proof_update_counts['outdated_total'] ); ?></div>
                                            <p><?php echo esc_html( ! empty( $selected_proof_update_items ) ? implode( ' | ', array_map( static function ( $item ) { return (string) ( $item['name'] ?? 'Item' ); }, array_slice( $selected_proof_update_items, 0, 3 ) ) ) : 'No update pressure was recorded for this scenario.' ); ?></p>
                                        </article>
                                        <article class="opsgate-pricing-summary-card">
                                            <span class="opsgate-overview-eyebrow">Vulnerabilities behind this result</span>
                                            <div class="opsgate-pricing-hero-side-title"><?php echo esc_html( (string) (int) ( $selected_proof_vulnerability_summary['match_count'] ?? 0 ) ); ?></div>
                                            <p><?php echo esc_html( ! empty( $selected_proof_vulnerability_items ) ? implode( ' | ', array_map( static function ( $item ) { return (string) ( $item['name'] ?? 'Component' ); }, array_slice( $selected_proof_vulnerability_items, 0, 3 ) ) ) : 'No vulnerability matches were recorded for this scenario.' ); ?></p>
                                        </article>
                                        <article class="opsgate-pricing-summary-card">
                                            <span class="opsgate-overview-eyebrow">Reachability behind this result</span>
                                            <div class="opsgate-pricing-hero-side-title"><?php echo esc_html( ucfirst( (string) ( $selected_proof_reachability_posture['posture'] ?? 'pending' ) ) ); ?></div>
                                            <p><?php echo esc_html( isset( $selected_proof_reachability_summary['failure_class'] ) && '' !== (string) $selected_proof_reachability_summary['failure_class'] ? 'Failure class: ' . (string) $selected_proof_reachability_summary['failure_class'] : 'HTTP ' . (string) ( $selected_proof_reachability_summary['http_status'] ?? '—' ) . ' · Duration ' . (string) ( $selected_proof_reachability_summary['duration_ms'] ?? '—' ) . ' ms' ); ?></p>
                                        </article>
                                    </div>

                                    <div class="opsgate-proof-reason-grid" style="margin-top:16px;">
                                        <article class="opsgate-settings-module">
                                            <div class="opsgate-settings-module-head">
                                                <div>
                                                    <strong>Why this proof is <?php echo esc_html( $selected_proof_grade ); ?></strong>
                                                    <p class="description">Explanation drawn from the recorded score inputs and artifact summaries for this proof/demo receipt.</p>
                                                </div>
                                            </div>
                                            <div class="opsgate-posture-detail-body opsgate-posture-detail-body-static">
                                                <?php self::render_posture_detail_items_list( $selected_proof_reason_items, 'Reason detail is unavailable for this validation receipt.' ); ?>
                                            </div>
                                        </article>

                                        <article class="opsgate-settings-module">
                                            <div class="opsgate-settings-module-head">
                                                <div>
                                                    <strong>Update detail</strong>
                                                    <p class="description">Recorded artifact items linked to this validation receipt.</p>
                                                </div>
                                            </div>
                                            <div class="opsgate-posture-detail-body opsgate-posture-detail-body-static">
                                                <?php self::render_posture_detail_items_list( $selected_proof_update_items, 'No update items were recorded for this validation receipt.' ); ?>
                                            </div>
                                        </article>

                                        <article class="opsgate-settings-module">
                                            <div class="opsgate-settings-module-head">
                                                <div>
                                                    <strong>Vulnerability detail</strong>
                                                    <p class="description">Recorded artifact items linked to this validation receipt.</p>
                                                </div>
                                            </div>
                                            <div class="opsgate-posture-detail-body opsgate-posture-detail-body-static">
                                                <?php self::render_posture_detail_items_list( $selected_proof_vulnerability_items, 'No vulnerability matches were recorded for this validation receipt.' ); ?>
                                            </div>
                                        </article>
                                    </div>
                                <?php endif; ?>
                            </section>
                                </div><!-- /.opsgate-r1-help-panel-body -->
                            </details>
                        <?php endif; ?>

                        <?php
                        $triage_live_states = array();
                        if ( ! empty( $current_run_state ) ) {
                            $triage_live_states[] = strtoupper( (string) $current_run_state );
                        }
                        if ( ! empty( $export_state_upper ) ) {
                            $triage_live_states[] = strtoupper( (string) $export_state_upper );
                        }
                        $triage_live_states = array_values( array_unique( array_filter( $triage_live_states ) ) );
                        $triage_status_poll_url = add_query_arg(
                            array(
                                'action' => 'opsgate_triage_live_status',
                            ),
                            admin_url( 'admin-ajax.php' )
                        );
                        $triage_run_ajax_url = add_query_arg(
                            array(
                                'action' => 'opsgate_run_portfolio_triage_live',
                            ),
                            admin_url( 'admin-ajax.php' )
                        );
                        $triage_run_command_state = $current_run_state;
                        $triage_run_command_copy = '' !== $current_run_copy ? $current_run_copy : $triage_connection_copy;
                        $triage_run_command_states = $triage_live_states;
                        if ( $triage_live_snapshot_ok ) {
                            $triage_run_command_state = strtoupper( trim( (string) ( $triage_live_snapshot['run_state'] ?? $triage_run_command_state ) ) );
                            $triage_run_command_copy = trim( (string) ( $triage_live_snapshot['progress_copy'] ?? $triage_run_command_copy ) );
                            if ( isset( $triage_live_snapshot['live_states'] ) && is_array( $triage_live_snapshot['live_states'] ) ) {
                                $triage_run_command_states = array_values(
                                    array_unique(
                                        array_filter(
                                            array_map(
                                                static function ( $value ): string {
                                                    return strtoupper( trim( (string) $value ) );
                                                },
                                                $triage_live_snapshot['live_states']
                                            )
                                        )
                                    )
                                );
                            }
                        }
                        if ( '' === $triage_run_command_copy ) {
                            $triage_run_command_copy = $triage_connection_copy;
                        }
                        $triage_current_export_job_id = ( '' !== $last_export_job_id && '' !== $last_export_source_job_id && '' !== $last_triage_job_id && $last_export_source_job_id === $last_triage_job_id )
                            ? $last_export_job_id
                            : '';
                        $triage_current_export_source_job_id = '' !== $triage_current_export_job_id ? $last_export_source_job_id : '';
                        $triage_rendered_run_id = ! empty( $latest['ok'] ) && isset( $latest['job']['job_id'] )
                            ? trim( (string) $latest['job']['job_id'] )
                            : '';
                        if (
                            '' !== $last_triage_job_id
                            && (
                                in_array( $triage_run_command_state, array( 'QUEUED', 'RUNNING', 'FAILED' ), true )
                                || ! empty( array_intersect( $triage_run_command_states, array( 'QUEUED', 'RUNNING', 'FAILED' ) ) )
                            )
                        ) {
                            $triage_rendered_run_id = $last_triage_job_id;
                        }
                        $triage_rendered_export_job_id = ( '' !== $triage_current_export_source_job_id && $triage_current_export_source_job_id === $triage_rendered_run_id )
                            ? $triage_current_export_job_id
                            : '';
                        $triage_run_command_busy = in_array( $triage_run_command_state, array( 'QUEUED', 'RUNNING' ), true )
                            || ! empty( array_intersect( $triage_run_command_states, array( 'QUEUED', 'RUNNING' ) ) );
                        $triage_run_idle_label = $triage_public_only_plan ? 'Run Public Check' : 'Run Security Scan';
                        $triage_run_button_label = $triage_run_command_busy ? 'Run in progress' : $triage_run_idle_label;
                        ?>
                        <div id="opsgate-triage-live-panel" data-opsgate-live-states="<?php echo esc_attr( implode( ',', $triage_run_command_states ) ); ?>" data-opsgate-refresh-url="<?php echo esc_url( $refresh_url ); ?>" data-opsgate-poll-url="<?php echo esc_url( $triage_status_poll_url ); ?>" data-opsgate-run-url="<?php echo esc_url( $triage_run_ajax_url ); ?>" data-opsgate-current-job-id="<?php echo esc_attr( $last_triage_job_id ); ?>" data-opsgate-current-export-job-id="<?php echo esc_attr( $triage_current_export_job_id ); ?>" data-opsgate-current-export-source-job-id="<?php echo esc_attr( $triage_current_export_source_job_id ); ?>" data-opsgate-rendered-run-id="<?php echo esc_attr( $triage_rendered_run_id ); ?>" data-opsgate-rendered-export-job-id="<?php echo esc_attr( $triage_rendered_export_job_id ); ?>">
                            <!-- This panel updates automatically when a run is in progress. --> 
                            <div class="opsgate-triage-command-bar">
                                <div class="opsgate-triage-command-bar-copy">
                                    <span class="opsgate-triage-eyebrow">Security scan controls</span>
                                    <strong>Launch and monitor a security scan from the top of the page.</strong>
                                    <span data-opsgate-triage-command-status-copy="1"><?php echo esc_html( $triage_run_command_copy ); ?></span>
                                    <span class="opsgate-triage-command-runtime-note" data-opsgate-triage-runtime-note hidden="hidden"></span>
                                </div>
                                <div class="opsgate-triage-command-bar-actions">
                                    <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="opsgate-triage-command-bar-form" data-opsgate-triage-run-form data-opsgate-triage-launch-form="1" data-opsgate-triage-run-url="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>" data-opsgate-triage-destination-url="<?php echo esc_url( self::admin_tab_url( 'triage' ) ); ?>">
                                        <input type="hidden" name="action" value="opsgate_run_portfolio_triage" />
                                        <?php wp_nonce_field( 'opsgate_run_portfolio_triage' ); ?>
                                        <button type="submit" class="button button-primary opsgate-triage-action-primary opsgate-triage-command-run-button" data-opsgate-run-button data-opsgate-run-idle-label="<?php echo esc_attr( $triage_run_idle_label ); ?>" data-opsgate-run-busy-label="Run in progress" <?php disabled( $triage_run_command_busy ); ?>><?php echo esc_html( $triage_run_button_label ); ?></button>
                                    </form>
                                    <a class="button button-secondary opsgate-triage-command-refresh" data-opsgate-triage-refresh-button data-opsgate-refresh-label="Refresh status" href="<?php echo esc_url( $refresh_url ); ?>">Refresh status</a>
                                </div>
                            </div>

                        <?php if ( empty( $latest['ok'] ) ) : ?>
                            <div class="opsgate-card opsgate-triage-empty-state" style="margin:0 0 16px 0;">
                                <h3>No completed scan is available yet.</h3>
                                <p><?php echo esc_html( $latest['error'] ?? 'Refresh status or start a new security scan for this site.' ); ?></p>
                                <div class="opsgate-triage-rail-actions">
                                    <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="opsgate-overview-action-form" data-opsgate-triage-run-form data-opsgate-triage-launch-form="1" data-opsgate-triage-run-url="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>" data-opsgate-triage-destination-url="<?php echo esc_url( self::admin_tab_url( 'triage' ) ); ?>">
                                        <input type="hidden" name="action" value="opsgate_run_portfolio_triage" />
                                        <?php wp_nonce_field( 'opsgate_run_portfolio_triage' ); ?>
                                        <button type="submit" class="button button-primary opsgate-overview-action-primary" data-opsgate-run-button data-opsgate-run-idle-label="<?php echo esc_attr( $triage_run_idle_label ); ?>" data-opsgate-run-busy-label="Run in progress"><?php echo esc_html( $triage_run_idle_label ); ?></button>
                                    </form>
                                    <a class="button button-secondary opsgate-triage-action-link" href="<?php echo esc_url( $refresh_url ); ?>">Refresh run status</a>
                                </div>
                            </div>
                        <?php else : ?>
                            <?php
                            $job    = isset( $latest['job'] ) && is_array( $latest['job'] ) ? $latest['job'] : array();
                            $arts   = isset( $latest['artifacts'] ) && is_array( $latest['artifacts'] ) ? $latest['artifacts'] : array();
                            $sum    = isset( $arts['score_summary']['body'] ) && is_array( $arts['score_summary']['body'] ) ? $arts['score_summary']['body'] : array();
                            $inventory = isset( $arts['inventory_snapshot']['body'] ) && is_array( $arts['inventory_snapshot']['body'] ) ? $arts['inventory_snapshot']['body'] : array();
                            $update_posture = isset( $arts['update_posture']['body'] ) && is_array( $arts['update_posture']['body'] ) ? $arts['update_posture']['body'] : array();
                            $vulnerability_posture = isset( $arts['vulnerability_posture']['body'] ) && is_array( $arts['vulnerability_posture']['body'] ) ? $arts['vulnerability_posture']['body'] : array();
                            $reachability_posture = isset( $arts['reachability_posture']['body'] ) && is_array( $arts['reachability_posture']['body'] ) ? $arts['reachability_posture']['body'] : array();
                            $availability_snapshot = isset( $arts['availability_snapshot']['body'] ) && is_array( $arts['availability_snapshot']['body'] ) ? $arts['availability_snapshot']['body'] : array();
                            $performance_snapshot = isset( $arts['performance_snapshot']['body'] ) && is_array( $arts['performance_snapshot']['body'] ) ? $arts['performance_snapshot']['body'] : array();
                            $configuration_validation = isset( $arts['configuration_validation']['body'] ) && is_array( $arts['configuration_validation']['body'] ) ? $arts['configuration_validation']['body'] : array();
                            $operational_log_intelligence = isset( $arts['operational_log_intelligence']['body'] ) && is_array( $arts['operational_log_intelligence']['body'] ) ? $arts['operational_log_intelligence']['body'] : array();
                            $uptime_window_artifact = isset( $arts['uptime_window']['body'] ) && is_array( $arts['uptime_window']['body'] ) ? $arts['uptime_window']['body'] : array();
                            $safe_update_smoke_check = isset( $arts['safe_update_smoke_check']['body'] ) && is_array( $arts['safe_update_smoke_check']['body'] ) ? $arts['safe_update_smoke_check']['body'] : array();
                            $hardening_guidance = isset( $arts['hardening_guidance']['body'] ) && is_array( $arts['hardening_guidance']['body'] ) ? $arts['hardening_guidance']['body'] : array();
                            $uptime_window_bundle = self::canonical_uptime_window();
                            $uptime_window = ! empty( $uptime_window_bundle['ok'] ) && ! empty( $uptime_window_bundle['summary'] ) ? array(
                                'summary' => isset( $uptime_window_bundle['summary'] ) && is_array( $uptime_window_bundle['summary'] ) ? $uptime_window_bundle['summary'] : array(),
                                'observations' => isset( $uptime_window_bundle['observations'] ) && is_array( $uptime_window_bundle['observations'] ) ? $uptime_window_bundle['observations'] : array(),
                            ) : $uptime_window_artifact;

                            $job_id = isset( $job['job_id'] ) ? (string) $job['job_id'] : '';
                            $state  = isset( $job['state'] ) ? strtoupper( (string) $job['state'] ) : 'UNKNOWN';
                            $score  = isset( $sum['score'] ) ? (int) $sum['score'] : null;
                            $grade  = isset( $sum['grade'] ) ? (string) $sum['grade'] : '';
                            $started = isset( $job['started_at_utc'] ) ? (string) $job['started_at_utc'] : '';
                            $inventory_generated = isset( $inventory['generated_at_utc'] ) ? (string) $inventory['generated_at_utc'] : '';
                            $inventory_core = isset( $inventory['wordpress']['core_version'] ) ? (string) $inventory['wordpress']['core_version'] : '';
                            $inventory_core_update = isset( $inventory['wordpress']['core_update_version'] ) ? (string) $inventory['wordpress']['core_update_version'] : '';
                            $inventory_php = isset( $inventory['runtime']['php_version'] ) ? (string) $inventory['runtime']['php_version'] : '';
                            $inventory_plugin_count = isset( $inventory['plugins']['count'] ) ? (int) $inventory['plugins']['count'] : null;
                            $inventory_theme_count = isset( $inventory['themes']['count'] ) ? (int) $inventory['themes']['count'] : null;
                            $update_summary = isset( $update_posture['summary'] ) && is_array( $update_posture['summary'] ) ? $update_posture['summary'] : array();
                            $update_counts = self::update_posture_counts( $update_posture );
                            $vulnerability_summary = isset( $vulnerability_posture['summary'] ) && is_array( $vulnerability_posture['summary'] ) ? $vulnerability_posture['summary'] : array();
                            $update_outdated_total = (int) $update_counts['outdated_total'];
                            $update_plugin_outdated = (int) $update_counts['plugin_outdated_count'];
                            $update_theme_outdated = (int) $update_counts['theme_outdated_count'];
                            $update_core_outdated = ! empty( $update_counts['core_outdated'] );
                            $update_posture_label = isset( $update_posture['posture'] ) ? (string) $update_posture['posture'] : '';
                            $vulnerability_match_count = isset( $vulnerability_summary['match_count'] ) ? (int) $vulnerability_summary['match_count'] : null;
                            $vulnerability_evidence_state = isset( $vulnerability_summary['evidence_state'] ) ? (string) $vulnerability_summary['evidence_state'] : '';
                            $vulnerability_coverage_scope = isset( $vulnerability_summary['coverage_scope'] ) ? (string) $vulnerability_summary['coverage_scope'] : '';
                            $vulnerability_checked_plugin_count = isset( $vulnerability_summary['checked_plugin_count'] ) ? (int) $vulnerability_summary['checked_plugin_count'] : null;
                            $vulnerability_unresolved_plugin_count = isset( $vulnerability_summary['unresolved_plugin_count'] ) ? (int) $vulnerability_summary['unresolved_plugin_count'] : null;
                            $vulnerability_posture_label = isset( $vulnerability_posture['posture'] ) ? (string) $vulnerability_posture['posture'] : '';
                            $vulnerability_source_provider = isset( $vulnerability_posture['source_provider'] ) ? (string) $vulnerability_posture['source_provider'] : '';
                            $vulnerability_source_mode = isset( $vulnerability_posture['source_mode'] ) ? (string) $vulnerability_posture['source_mode'] : '';
                            $vulnerability_source_updated_at = isset( $vulnerability_posture['source_updated_at_utc'] ) ? (string) $vulnerability_posture['source_updated_at_utc'] : '';
                            $reachability_summary = isset( $reachability_posture['summary'] ) && is_array( $reachability_posture['summary'] ) ? $reachability_posture['summary'] : array();
                            $reachability_label = isset( $reachability_posture['posture'] ) ? (string) $reachability_posture['posture'] : '';
                            $reachability_http_status = isset( $reachability_summary['http_status'] ) ? (string) $reachability_summary['http_status'] : '';
                            $reachability_duration_ms = isset( $reachability_summary['duration_ms'] ) ? (string) $reachability_summary['duration_ms'] : '';
                            $reachability_tls_ok = isset( $reachability_summary['tls_ok'] ) ? (bool) $reachability_summary['tls_ok'] : null;
                            $reachability_transport_ok = isset( $reachability_summary['transport_ok'] ) ? (bool) $reachability_summary['transport_ok'] : null;
                            $availability_summary = isset( $availability_snapshot['summary'] ) && is_array( $availability_snapshot['summary'] ) ? $availability_snapshot['summary'] : array();
                            $availability_label = isset( $availability_snapshot['posture'] ) ? (string) $availability_snapshot['posture'] : '';
                            $availability_attempt_count = isset( $availability_summary['attempt_count'] ) ? (int) $availability_summary['attempt_count'] : null;
                            $availability_success_count = isset( $availability_summary['successful_attempts'] ) ? (int) $availability_summary['successful_attempts'] : null;
                            $availability_failure_count = isset( $availability_summary['failed_attempts'] ) ? (int) $availability_summary['failed_attempts'] : null;
                            $performance_summary = isset( $performance_snapshot['summary'] ) && is_array( $performance_snapshot['summary'] ) ? $performance_snapshot['summary'] : array();
                            $performance_label = isset( $performance_snapshot['posture'] ) ? (string) $performance_snapshot['posture'] : '';
                            $performance_status_code = isset( $performance_summary['status_code'] ) ? (string) $performance_summary['status_code'] : '';
                            $performance_total_duration = isset( $performance_summary['total_duration_ms'] ) ? (string) $performance_summary['total_duration_ms'] : '';
                            $performance_first_byte = isset( $performance_summary['first_byte_ms'] ) ? (string) $performance_summary['first_byte_ms'] : '';
                            $configuration_validation_summary = isset( $configuration_validation['summary'] ) && is_array( $configuration_validation['summary'] ) ? $configuration_validation['summary'] : array();
                            $configuration_validation_families = isset( $configuration_validation['families'] ) && is_array( $configuration_validation['families'] ) ? $configuration_validation['families'] : array();
                            $configuration_validation_htaccess = isset( $configuration_validation_families['htaccess'] ) && is_array( $configuration_validation_families['htaccess'] ) ? $configuration_validation_families['htaccess'] : array();
                            $configuration_validation_folder = isset( $configuration_validation_families['folder_structure'] ) && is_array( $configuration_validation_families['folder_structure'] ) ? $configuration_validation_families['folder_structure'] : array();
                            $configuration_validation_posture = isset( $configuration_validation['posture'] ) ? (string) $configuration_validation['posture'] : '';
                            $configuration_validation_findings = isset( $configuration_validation_summary['finding_count'] ) ? (int) $configuration_validation_summary['finding_count'] : 0;
                            $configuration_validation_critical = isset( $configuration_validation_summary['critical_count'] ) ? (int) $configuration_validation_summary['critical_count'] : 0;
                            $configuration_validation_warning = isset( $configuration_validation_summary['warning_count'] ) ? (int) $configuration_validation_summary['warning_count'] : 0;
                            $configuration_validation_review_state = isset( $configuration_validation_summary['review_state'] ) ? strtolower( trim( (string) $configuration_validation_summary['review_state'] ) ) : '';
                            $configuration_validation_htaccess_ran = array_key_exists( 'ran', $configuration_validation_htaccess ) ? (bool) $configuration_validation_htaccess['ran'] : ! empty( $configuration_validation_htaccess );
                            $configuration_validation_folder_ran = array_key_exists( 'ran', $configuration_validation_folder ) ? (bool) $configuration_validation_folder['ran'] : ! empty( $configuration_validation_folder );
                            $operational_log_summary = isset( $operational_log_intelligence['summary'] ) && is_array( $operational_log_intelligence['summary'] ) ? $operational_log_intelligence['summary'] : array();
                            $operational_log_sources = isset( $operational_log_intelligence['sources'] ) && is_array( $operational_log_intelligence['sources'] ) ? $operational_log_intelligence['sources'] : array();
                            $operational_log_posture = isset( $operational_log_intelligence['posture'] ) ? (string) $operational_log_intelligence['posture'] : '';
                            $operational_log_signal_count = isset( $operational_log_summary['signal_count'] ) ? (int) $operational_log_summary['signal_count'] : 0;
                            $operational_log_critical = isset( $operational_log_summary['critical_count'] ) ? (int) $operational_log_summary['critical_count'] : 0;
                            $operational_log_warning = isset( $operational_log_summary['warning_count'] ) ? (int) $operational_log_summary['warning_count'] : 0;
                            $operational_log_available_source_count = isset( $operational_log_summary['available_source_count'] ) ? (int) $operational_log_summary['available_source_count'] : 0;
                            $operational_log_unavailable_source_count = isset( $operational_log_summary['unavailable_source_count'] ) ? (int) $operational_log_summary['unavailable_source_count'] : 0;
                            $operational_log_source_state = isset( $operational_log_summary['source_state'] ) ? strtolower( trim( (string) $operational_log_summary['source_state'] ) ) : '';
                            $uptime_summary = isset( $uptime_window['summary'] ) && is_array( $uptime_window['summary'] ) ? $uptime_window['summary'] : array();
                            $uptime_posture = isset( $uptime_summary['posture'] ) ? (string) $uptime_summary['posture'] : ( isset( $uptime_window['posture'] ) ? (string) $uptime_window['posture'] : '' );
                            $uptime_percent = isset( $uptime_summary['uptime_percent'] ) ? (string) $uptime_summary['uptime_percent'] : '';
                            $uptime_observation_count = isset( $uptime_summary['observation_count'] ) ? (int) $uptime_summary['observation_count'] : 0;
                            $uptime_failure_count = isset( $uptime_summary['failure_count'] ) ? (int) $uptime_summary['failure_count'] : 0;
                            $uptime_history_state = isset( $uptime_summary['history_state'] ) ? (string) $uptime_summary['history_state'] : '';
                            $uptime_history_label = isset( $uptime_summary['history_label'] ) ? (string) $uptime_summary['history_label'] : '';
                            $uptime_history_copy = isset( $uptime_summary['history_copy'] ) ? (string) $uptime_summary['history_copy'] : '';
                            $safe_update_summary = isset( $safe_update_smoke_check['summary'] ) && is_array( $safe_update_smoke_check['summary'] ) ? $safe_update_smoke_check['summary'] : array();
                            $safe_update_label = isset( $safe_update_smoke_check['posture'] ) ? (string) $safe_update_smoke_check['posture'] : '';
                            $safe_update_caution_checks = isset( $safe_update_summary['caution_checks'] ) ? (int) $safe_update_summary['caution_checks'] : null;
                            $safe_update_blocking_checks = isset( $safe_update_summary['blocking_checks'] ) ? (int) $safe_update_summary['blocking_checks'] : null;
                            $hardening_summary = isset( $hardening_guidance['summary'] ) && is_array( $hardening_guidance['summary'] ) ? $hardening_guidance['summary'] : array();
                            $hardening_items = isset( $hardening_guidance['items'] ) && is_array( $hardening_guidance['items'] ) ? $hardening_guidance['items'] : array();
                            $hardening_guidance_state = isset( $hardening_summary['guidance_state'] ) ? strtolower( trim( (string) $hardening_summary['guidance_state'] ) ) : '';
                            $hardening_guidance_title = isset( $hardening_summary['guidance_title'] ) ? (string) $hardening_summary['guidance_title'] : 'Recorded hardening guidance';
                            $hardening_guidance_copy = isset( $hardening_summary['guidance_copy'] ) ? (string) $hardening_summary['guidance_copy'] : 'OpsGate did not record hardening guidance for this run.';
                            $hardening_guidance_count = isset( $hardening_summary['item_count'] ) ? (int) $hardening_summary['item_count'] : count( $hardening_items );
                            $export_busy = in_array( $export_state_upper, array( 'QUEUED', 'RUNNING' ), true );
                            $triage_site_config = self::canonical_site_config();
                            $triage_site_config_item = ! empty( $triage_site_config['ok'] ) && isset( $triage_site_config['item'] ) && is_array( $triage_site_config['item'] ) ? $triage_site_config['item'] : array();
                            $triage_site_label = self::connected_site_label( $triage_site_config_item, $triage_scope );
                            $triage_scope_url = self::connected_site_url( $triage_site_config_item, $triage_scope );
                            $triage_site_host = (string) ( wp_parse_url( $triage_scope_url, PHP_URL_HOST ) ?: '' );
                            $triage_grade_slug = strtolower( trim( $grade ) );
                            $triage_grade_label = '' !== $triage_grade_slug ? ucfirst( $triage_grade_slug ) : 'Unrated';
                            $triage_grade_summary = 'Posture pending';
                            $triage_grade_tone = 'neutral';
                            if ( in_array( $triage_grade_slug, array( 'green', 'healthy' ), true ) ) {
                                $triage_grade_summary = 'Healthy';
                                $triage_grade_tone = 'good';
                            } elseif ( in_array( $triage_grade_slug, array( 'yellow', 'amber' ), true ) ) {
                                $triage_grade_summary = 'Needs attention';
                                $triage_grade_tone = 'warn';
                            } elseif ( in_array( $triage_grade_slug, array( 'red', 'critical' ), true ) ) {
                                $triage_grade_summary = 'Action required';
                                $triage_grade_tone = 'bad';
                            }

                            $triage_state_label = 'Unknown';
                            if ( 'COMPLETED' === $state ) {
                                $triage_state_label = 'Completed';
                            } elseif ( 'RUNNING' === $state ) {
                                $triage_state_label = 'Running';
                            } elseif ( 'QUEUED' === $state ) {
                                $triage_state_label = 'Queued';
                            } elseif ( 'FAILED' === $state ) {
                                $triage_state_label = 'Failed';
                            }

                            $triage_state_note = '' !== $current_run_copy ? $current_run_copy : ( 'COMPLETED' === $state ? 'Recorded artifacts are available for review.' : 'Review the latest recorded run and evidence.' );
                            $triage_started_label = '' !== $started ? self::canonical_report_datetime_label( $started ) : '—';
                            $triage_captured_label = '' !== $inventory_generated ? self::canonical_report_datetime_label( $inventory_generated ) : '—';
                            $triage_run_reference = '' !== $job_id ? self::canonical_activity_reference_copy( 'Run reference', $job_id ) : 'Run reference unavailable';
                            $triage_trigger_label = self::canonical_run_trigger_label( isset( $latest_job['trigger'] ) ? (string) $latest_job['trigger'] : '' );
                            $triage_scope_label = '' !== $triage_site_label ? $triage_site_label : 'Connected site';
                            $triage_scope_meta = '' !== $triage_site_host ? $triage_site_host : 'Connected WordPress site';
                            $triage_evidence_count = is_array( $arts ) ? count( array_filter( $arts ) ) : 0;
                            $triage_evidence_state = 'Results ready';
                            if ( '' !== $vulnerability_evidence_state && 'complete' !== $vulnerability_evidence_state ) {
                                $triage_evidence_state = 'Results ' . str_replace( '_', ' ', strtolower( $vulnerability_evidence_state ) );
                            } elseif ( $export_busy ) {
                                $triage_evidence_state = 'Outputs in progress';
                            } elseif ( 0 === $triage_evidence_count ) {
                                $triage_evidence_state = 'Results pending';
                            }
                            $triage_update_detail_items = self::posture_detail_items( 'updates', $update_posture, array( 'vulnerability_posture' => $vulnerability_posture ) );
                            $triage_vulnerability_detail_items = self::posture_detail_items( 'vulnerabilities', $vulnerability_posture );
                            $triage_severity_weight = array( 'critical' => 0, 'high' => 1, 'medium' => 2, 'low' => 3, 'warning' => 2 );
                            usort( $triage_vulnerability_detail_items, static function ( array $a, array $b ) use ( $triage_severity_weight ): int {
                                $wa = $triage_severity_weight[ strtolower( trim( (string) ( $a['label'] ?? '' ) ) ) ] ?? 99;
                                $wb = $triage_severity_weight[ strtolower( trim( (string) ( $b['label'] ?? '' ) ) ) ] ?? 99;
                                return $wa <=> $wb;
                            } );
                            $triage_validation_detail_items = self::posture_detail_items(
                                'validation',
                                $configuration_validation,
                                array(
                                    'account_id'    => $account_id,
                                    'site_id'       => $site_id,
                                    'source_job_id' => $job_id,
                                )
                            );
                            $triage_uptime_detail_items = self::posture_detail_items( 'uptime', $uptime_window );
                            $triage_log_detail_items = self::posture_detail_items( 'logs', $operational_log_intelligence );
                            $triage_hardening_detail_items = self::posture_detail_items( 'hardening', $hardening_guidance );
                            $triage_reason_items = self::posture_reason_items( $sum, $update_posture, $vulnerability_posture, $reachability_posture, $availability_snapshot );
                            $triage_operator_degradation = self::operator_degradation_meta( $sum );
                            $triage_alert_events = self::notification_events_for_source_id( $job_id, 12 );
                            $triage_alert_items = ! empty( $triage_alert_events['ok'] ) && isset( $triage_alert_events['items'] ) && is_array( $triage_alert_events['items'] ) ? $triage_alert_events['items'] : array();
                            $triage_alert_rollup = self::notification_delivery_rollup( $triage_alert_items );
                            $triage_checked_items = array(
                                sprintf( 'Core %s', '' !== $inventory_core ? $inventory_core : 'unknown' ),
                                sprintf( 'Updates %s', (string) $update_outdated_total ),
                                sprintf( 'Vulnerabilities %s', null !== $vulnerability_match_count ? (string) $vulnerability_match_count : '—' ),
                                sprintf( 'Evidence %d', (int) $triage_evidence_count ),
                            );
                            $triage_reports_url = self::admin_tab_url( 'reports', array( 'source_job_id' => $job_id ) );
                            $triage_next_step_label = 'Open Reports';
                            $triage_next_step_url = $triage_reports_url;
                            $triage_next_step_copy = 'Use the packaged output hub to review trust state and share the latest evidence-backed reports.';
                            if ( in_array( $state, array( 'QUEUED', 'RUNNING' ), true ) ) {
                                $triage_next_step_label = 'Refresh run status';
                                $triage_next_step_url = $refresh_url;
                                $triage_next_step_copy = 'This triage run is still active. Refresh to pick up recorded evidence and packaged outputs as they land.';
                            } elseif ( 0 === $triage_evidence_count ) {
                                $triage_next_step_label = 'Run Security Scan';
                                $triage_next_step_url = self::admin_tab_url( 'triage' );
                                $triage_next_step_copy = 'Start a recorded scan so OpsGate can capture security results and packaged outputs for this site.';
                            } elseif ( $export_busy ) {
                                $triage_next_step_label = 'Open Reports';
                                $triage_next_step_copy = 'The run is complete and packaged outputs are being prepared. Reports will show each output as it becomes ready.';
                            }
                            $reachability_label_normalized = strtolower( trim( $reachability_label ) );
                            $availability_label_normalized = strtolower( trim( $availability_label ) );
                            $performance_label_normalized = strtolower( trim( $performance_label ) );
                            $safe_update_label_normalized = strtolower( trim( $safe_update_label ) );
                            $reachability_is_bad = in_array( $reachability_label_normalized, array( 'unreachable', 'failed', 'error' ), true );
                            $availability_is_bad = in_array( $availability_label_normalized, array( 'unavailable', 'failed', 'down' ), true ) || ( null !== $availability_failure_count && $availability_failure_count > 0 );
                            $performance_is_bad = in_array( $performance_label_normalized, array( 'poor', 'failed', 'degraded', 'slow' ), true );
                            $safe_update_needs_attention = ( null !== $safe_update_blocking_checks && $safe_update_blocking_checks > 0 ) || ( null !== $safe_update_caution_checks && $safe_update_caution_checks > 0 );
                            $triage_operational_clauses = array();
                            if ( $reachability_is_bad ) {
                                $triage_operational_clauses[] = 'Reachability is failing';
                            }
                            if ( null !== $vulnerability_match_count && $vulnerability_match_count > 0 ) {
                                $triage_operational_clauses[] = sprintf( '%d %s found', $vulnerability_match_count, 1 === $vulnerability_match_count ? 'vulnerability' : 'vulnerabilities' );
                            }
                            if ( $update_outdated_total > 0 ) {
                                $triage_operational_clauses[] = sprintf( '%d update item(s) need attention', $update_outdated_total );
                            }
                            if ( $availability_is_bad && null !== $availability_failure_count && null !== $availability_attempt_count ) {
                                $triage_operational_clauses[] = sprintf( '%d of %d availability probe(s) failed', $availability_failure_count, $availability_attempt_count );
                            }
                            if ( $performance_is_bad ) {
                                $triage_operational_clauses[] = 'Performance is degraded';
                            }
                            if ( $configuration_validation_findings > 0 ) {
                                $triage_operational_clauses[] = sprintf( '%d configuration validation finding(s) require review', $configuration_validation_findings );
                            }
                            if ( $uptime_observation_count > 0 && $uptime_failure_count > 0 ) {
                                $triage_operational_clauses[] = sprintf( '%d uptime observation(s) failed in the recent window', $uptime_failure_count );
                            }
                            if ( $operational_log_signal_count > 0 ) {
                                $triage_operational_clauses[] = sprintf( '%d normalized log signal(s) were recorded', $operational_log_signal_count );
                            }
                            $triage_current_title = sprintf( 'Security status: %s — %s', $triage_grade_label, $triage_scope_label );
                            if ( 'FAILED' === $state ) {
                                $triage_current_title = sprintf( 'Run issue recorded for %s', $triage_scope_label );
                            } elseif ( in_array( $state, array( 'QUEUED', 'RUNNING' ), true ) ) {
                                $triage_current_title = sprintf( 'Assessment in progress for %s', $triage_scope_label );
                            } elseif ( 0 === $triage_evidence_count ) {
                                $triage_current_title = sprintf( 'Assessment pending for %s', $triage_scope_label );
                            }
                            $triage_current_copy = '' !== $current_run_copy ? $current_run_copy : 'Run a live assessment for this site.';
                            if ( 'COMPLETED' === $state ) {
                                if ( ! empty( $triage_operational_clauses ) ) {
                                    $triage_current_copy = implode( '. ', array_slice( $triage_operational_clauses, 0, 3 ) ) . '.';
                                } else {
                                    $triage_current_copy = 'Latest evidence shows stable updates, vulnerability coverage, reachability, availability, and performance.';
                                }
                            }
                            $triage_explanation_badge = ! empty( $triage_operator_degradation ) ? (string) $triage_operator_degradation['label'] : 'Scan complete';
                            $triage_explanation_title = sprintf( 'What makes this site %s', $triage_grade_label );
                            $triage_explanation_copy = ! empty( $triage_operational_clauses )
                                ? implode( ' · ', array_slice( $triage_operational_clauses, 0, 3 ) )
                                : 'No active pressure is recorded in the latest run.';
                            $triage_assessment_tags = ! empty( $triage_operational_clauses )
                                ? array_slice( $triage_operational_clauses, 0, 3 )
                                : array( $triage_state_label, $triage_evidence_state );
                            $triage_current_freshness = 'Last run ' . $triage_started_label;
                            $triage_current_side_title = $triage_next_step_label;
                            $triage_current_side_copy = $triage_next_step_copy;
                            $triage_current_side_meta = $triage_state_label . ' · ' . $triage_evidence_state;
                            $triage_live_progress_active = in_array( $state, array( 'QUEUED', 'RUNNING' ), true ) || $export_busy;
                            $triage_live_progress_tone = $triage_live_progress_active ? 'warn' : 'info';
                            if ( 'FAILED' === $state ) {
                                $triage_live_progress_tone = 'bad';
                            }
                            $triage_live_progress_label = $triage_live_progress_active ? 'Run in progress' : 'Latest run status';
                            $triage_live_progress_title = 'Latest scan is ready to review';
                            if ( 'QUEUED' === $state ) {
                                $triage_live_progress_title = 'Security scan is queued';
                            } elseif ( 'RUNNING' === $state ) {
                                $triage_live_progress_title = 'OpsGate is gathering evidence now';
                            } elseif ( $export_busy ) {
                                $triage_live_progress_title = 'Report packaging is still running';
                            } elseif ( 'FAILED' === $state ) {
                                $triage_live_progress_title = 'The latest run needs follow-up';
                            } elseif ( 0 === $triage_evidence_count ) {
                                $triage_live_progress_title = 'No recorded evidence is available yet';
                            }
                            $triage_live_latest_action = 'No recent action has been recorded yet.';
                            if ( 'QUEUED' === $state ) {
                                $triage_live_latest_action = 'The run is waiting for worker execution behind the API.';
                            } elseif ( 'RUNNING' === $state ) {
                                $triage_live_latest_action = 'Evidence is being recorded for this site now.';
                            } elseif ( $export_busy ) {
                                $triage_live_latest_action = 'Rendered outputs are being prepared from the finished run.';
                            } elseif ( 'FAILED' === $state ) {
                                $triage_live_latest_action = 'The latest run failed and should be reviewed before sharing outputs.';
                            } elseif ( 'COMPLETED' === $state ) {
                                $triage_live_latest_action = 'Evidence and latest posture have been recorded for review.';
                            }
                            $triage_live_progress_copy_parts = array_filter(
                                array(
                                    $current_run_copy,
                                    $export_copy,
                                )
                            );
                            if ( empty( $triage_live_progress_copy_parts ) ) {
                                $triage_live_progress_copy_parts[] = $triage_live_latest_action;
                            }
                            $triage_live_progress_copy = implode( ' ', $triage_live_progress_copy_parts );
                            $triage_live_status_items = array(
                                array(
                                    'label' => 'Run state',
                                    'value' => $triage_state_label,
                                ),
                                array(
                                    'label' => 'Reports',
                                    'value' => $export_busy ? ( '' !== $export_copy ? $export_copy : 'Packaging in progress.' ) : ( 'COMPLETED' === $state ? 'Ready now or available to generate.' : 'Pending latest run.' ),
                                ),
                                array(
                                    'label' => 'Latest action',
                                    'value' => $triage_live_latest_action,
                                ),
                                array(
                                    'label' => 'Next step',
                                    'value' => $triage_next_step_label . ' — ' . $triage_next_step_copy,
                                ),
                            );
                            $triage_connected_truth_available = 'connected' === $triage_connection_status && 'wp_connector' === $triage_connection_mode;
                            $triage_connected_only_copy = 'Authenticated WordPress evidence is not ready yet.';
                            $triage_connected_only_value = 'Connected data unavailable';
                            if ( 'external_only' === $triage_connection_status ) {
                                $triage_connected_only_copy  = 'External-only monitoring is honest public monitoring. Inventory, updates, and vulnerability evidence unlock after the connector is paired.';
                                $triage_connected_only_value = 'External-only mode';
                            } elseif ( 'pairing_pending' === $triage_connection_status ) {
                                $triage_connected_only_copy  = 'Connected evidence will appear after pairing is completed from this WordPress site.';
                                $triage_connected_only_value = 'Pairing pending';
                            } elseif ( 'credential_invalid' === $triage_connection_status ) {
                                $triage_connected_only_copy  = 'Connected evidence is blocked until the site credential is rotated or reconnected from Settings.';
                                $triage_connected_only_value = 'Credential invalid';
                            } elseif ( 'disconnected' === $triage_connection_status ) {
                                $triage_connected_only_copy  = 'Connected evidence is paused because the connector trust path is disconnected.';
                                $triage_connected_only_value = 'Disconnected';
                            }
                            $triage_inventory_copy = implode(
                                ' · ',
                                array(
                                    '' !== $inventory_php ? 'PHP ' . $inventory_php : 'PHP snapshot pending',
                                    null !== $inventory_plugin_count ? 'Plugins ' . (string) $inventory_plugin_count : 'Plugins not recorded yet',
                                    null !== $inventory_theme_count ? 'Themes ' . (string) $inventory_theme_count : 'Themes not recorded yet',
                                )
                            );
                            $triage_inventory_meta = '—' !== $triage_captured_label ? 'Captured ' . $triage_captured_label : 'Capture time not recorded for this run';
                            if ( $triage_connected_truth_available && ( null === $inventory_plugin_count || null === $inventory_theme_count || '' === $inventory_php ) ) {
                                $triage_inventory_meta .= ' · Inventory is partial for this run';
                            }
                            $triage_update_copy = $update_outdated_total > 0
                                ? sprintf( '%d outdated component(s) are contributing to current posture.', $update_outdated_total )
                                : ( $triage_connected_truth_available ? 'Installed core, plugins, and themes were checked with no update pressure recorded.' : 'Connected-only update truth is not available yet.' );
                            $triage_update_meta = $update_outdated_total > 0
                                ? 'Plugins ' . (string) $update_plugin_outdated . ' · Themes ' . (string) $update_theme_outdated . ' · Core ' . ( $update_core_outdated ? 'outdated' : 'current' )
                                : 'No changes require action';
                            $triage_vulnerability_match_total = null !== $vulnerability_match_count ? (int) $vulnerability_match_count : 0;
                            $triage_vulnerability_checked_total = null !== $vulnerability_checked_plugin_count ? (int) $vulnerability_checked_plugin_count : 0;
                            $triage_vulnerability_clean_total = isset( $vulnerability_summary['clean_plugin_count'] ) ? (int) $vulnerability_summary['clean_plugin_count'] : max( 0, $triage_vulnerability_checked_total - $triage_vulnerability_match_total );
                            $triage_vulnerability_unresolved_total = null !== $vulnerability_unresolved_plugin_count ? (int) $vulnerability_unresolved_plugin_count : 0;
                            $triage_vulnerability_coverage_limited = 'evidence_limited' === strtolower( trim( $vulnerability_posture_label ) )
                                || ( '' !== trim( $vulnerability_evidence_state ) && 'complete' !== strtolower( trim( $vulnerability_evidence_state ) ) );
                            $triage_vulnerability_has_coverage = $triage_vulnerability_checked_total > 0 || $triage_vulnerability_unresolved_total > 0;
                            $triage_vulnerability_live_source_recorded = '' !== trim( $vulnerability_source_provider ) || '' !== trim( $vulnerability_source_mode );
                            $triage_vulnerability_value = $triage_vulnerability_match_total > 0
                                ? sprintf( '%d %s', $triage_vulnerability_match_total, 1 === $triage_vulnerability_match_total ? 'vulnerability' : 'vulnerabilities' )
                                : ( $triage_vulnerability_has_coverage ? sprintf( '%d plugin(s) checked', $triage_vulnerability_checked_total ) : 'Pending' );
                            $triage_vulnerability_copy = $triage_vulnerability_match_total > 0
                                ? 'Live plugin advisory coverage matched installed components in this recorded inventory and needs review.'
                                : (
                                    $triage_vulnerability_unresolved_total > 0 || $triage_vulnerability_coverage_limited
                                        ? 'Live advisory coverage ran, but unresolved plugins or limited evidence still require manual review.'
                                        : ( $triage_vulnerability_has_coverage ? 'Live plugin advisory coverage completed for the recorded plugin inventory.' : 'Live advisory coverage is not recorded for this run yet.' )
                                );
                            $triage_vulnerability_meta = $triage_vulnerability_has_coverage
                                ? 'Checked ' . (string) $triage_vulnerability_checked_total . ' · Clean ' . (string) $triage_vulnerability_clean_total . ' · Unresolved ' . (string) $triage_vulnerability_unresolved_total
                                : 'Live plugin coverage was not recorded for this run';
                            if ( $triage_vulnerability_live_source_recorded ) {
                                $triage_vulnerability_meta .= ' · Source ' . ( '' !== trim( $vulnerability_source_provider ) ? $vulnerability_source_provider : ucfirst( str_replace( '_', ' ', trim( $vulnerability_source_mode ) ) ) );
                            }
                            if ( '' !== trim( $vulnerability_evidence_state ) ) {
                                $triage_vulnerability_meta .= ' · Evidence ' . ucfirst( str_replace( '_', ' ', strtolower( $vulnerability_evidence_state ) ) );
                            }
                            $triage_vulnerability_signals = array_filter(
                                array(
                                    $triage_vulnerability_live_source_recorded ? 'Advisory data recorded' : 'Source lineage pending',
                                    'Checked ' . (string) $triage_vulnerability_checked_total,
                                    'Clean ' . (string) $triage_vulnerability_clean_total,
                                    'Unresolved ' . (string) $triage_vulnerability_unresolved_total,
                                    '' !== trim( $vulnerability_evidence_state ) ? 'Evidence ' . ucfirst( str_replace( '_', ' ', strtolower( $vulnerability_evidence_state ) ) ) : '',
                                )
                            );
                            $triage_reachability_copy = '' !== $reachability_http_status ? 'HTTP ' . $reachability_http_status : 'HTTP status not recorded for this run';
                            $triage_reachability_meta = '' !== $reachability_duration_ms ? 'Duration ' . $reachability_duration_ms . ' ms' : 'Duration not recorded for this run';
                            $triage_availability_copy = ( null !== $availability_attempt_count || null !== $availability_success_count )
                                ? 'Attempts ' . ( null !== $availability_attempt_count ? (string) $availability_attempt_count : 'pending' ) . ' · Success ' . ( null !== $availability_success_count ? (string) $availability_success_count : 'pending' )
                                : 'No availability sample was recorded for this run';
                            $triage_availability_meta = null !== $availability_failure_count ? 'Failed ' . (string) $availability_failure_count : 'Failure count was not recorded';
                            $triage_performance_value = '' !== $performance_total_duration ? $performance_total_duration . ' ms' : 'Not recorded';
                            $triage_performance_copy = ( '' !== $performance_status_code || '' !== $performance_first_byte )
                                ? 'Status ' . ( '' !== $performance_status_code ? $performance_status_code : 'pending' ) . ' · First byte ' . ( '' !== $performance_first_byte ? $performance_first_byte . ' ms' : 'not recorded' )
                                : 'No performance snapshot was captured';
                            $triage_performance_meta = '' !== $performance_total_duration ? 'Recorded performance snapshot' : 'Not recorded for this run';
                            $triage_validation_recorded = ! empty( $configuration_validation ) || ! empty( $triage_validation_detail_items );
                            $triage_validation_htaccess_recorded = ! empty( $configuration_validation_htaccess );
                            $triage_validation_folder_recorded = ! empty( $configuration_validation_folder );
                            $triage_validation_completeness = '' !== $configuration_validation_review_state
                                ? $configuration_validation_review_state
                                : ( ! $triage_validation_recorded
                                    ? 'unavailable'
                                    : ( $triage_validation_htaccess_recorded && $triage_validation_folder_recorded ? 'complete' : 'partial' ) );
                            $triage_validation_htaccess_posture = strtolower( trim( (string) ( $configuration_validation_htaccess['posture'] ?? '' ) ) );
                            $triage_validation_folder_posture = strtolower( trim( (string) ( $configuration_validation_folder['posture'] ?? '' ) ) );
                            $triage_validation_value = ! $triage_validation_recorded ? 'Unavailable' : ( $configuration_validation_findings > 0 ? (string) $configuration_validation_findings : 'Passed' );
                            $triage_validation_copy = ! $triage_validation_recorded
                                ? 'No .htaccess or folder-structure validation artifact was recorded for this run.'
                                : ( $configuration_validation_findings > 0
                                    ? 'Configuration validation found actionable .htaccess or folder-structure issues.'
                                    : ( 'partial' === $triage_validation_completeness
                                        ? 'Configuration validation ran, but one or more review families could not be read completely during this run.'
                                        : 'Configuration validation ran and recorded no risky .htaccess or folder-structure patterns.' ) );
                            $triage_validation_meta = 'Critical ' . (string) $configuration_validation_critical . ' · Warning ' . (string) $configuration_validation_warning . ( $triage_validation_recorded ? ' · Review ' . $triage_validation_completeness : ' · Review not recorded' );
                            $triage_validation_signals = array_filter(
                                array(
                                    $triage_validation_recorded ? 'Review ' . ucfirst( $triage_validation_completeness ) : 'Artifact unavailable',
                                    $triage_validation_htaccess_recorded ? '.htaccess ' . ( $configuration_validation_htaccess_ran ? ( 'passed' === $triage_validation_htaccess_posture ? 'checked' : 'needs review' ) : 'unavailable' ) : '.htaccess not recorded',
                                    $triage_validation_folder_recorded ? 'Folders ' . ( $configuration_validation_folder_ran ? ( 'passed' === $triage_validation_folder_posture ? 'checked' : 'need review' ) : 'unavailable' ) : 'Folders not recorded',
                                )
                            );
                            $triage_uptime_window_recorded = ! empty( $uptime_window ) || $uptime_observation_count > 0 || $uptime_failure_count > 0;
                            $triage_uptime_value = '' !== $uptime_history_label
                                ? $uptime_history_label
                                : ( '' !== $uptime_percent ? $uptime_percent . '%' : ( $uptime_observation_count > 0 ? ucfirst( str_replace( '_', ' ', (string) $uptime_posture ) ) : 'Building history' ) );
                            $triage_uptime_copy = '' !== $uptime_history_copy
                                ? $uptime_history_copy
                                : ( $uptime_failure_count > 0
                                    ? 'The recorded uptime window includes recent failures and should not be treated as stable.'
                                    : ( $uptime_observation_count > 0
                                        ? 'A historical uptime window was recorded and remained stable in the latest observations.'
                                        : ( $triage_uptime_window_recorded
                                            ? 'Uptime history is enabled, but this site has not accumulated enough observations to produce a meaningful recent window yet.'
                                            : 'No historical uptime window was recorded for this run yet.' ) ) );
                            $triage_uptime_meta = 'Observations ' . (string) $uptime_observation_count . ' · Failures ' . (string) $uptime_failure_count . ( '' !== $uptime_percent ? ' · Uptime ' . $uptime_percent . '%' : '' );
                            $triage_uptime_signals = array_filter(
                                array(
                                    '' !== $uptime_history_label ? $uptime_history_label : '',
                                    'Observations ' . (string) $uptime_observation_count,
                                    'Failures ' . (string) $uptime_failure_count,
                                )
                            );
                            $operational_log_source_count = isset( $operational_log_summary['source_count'] ) ? (int) $operational_log_summary['source_count'] : count( $operational_log_sources );
                            $operational_log_source_families = array();
                            foreach ( $operational_log_sources as $operational_log_source ) {
                                if ( ! is_array( $operational_log_source ) ) {
                                    continue;
                                }
                                $operational_log_source_family = trim( (string) ( $operational_log_source['source_family'] ?? '' ) );
                                if ( '' === $operational_log_source_family ) {
                                    continue;
                                }
                                if ( 'wordpress_debug' === $operational_log_source_family ) {
                                    $operational_log_source_families[ $operational_log_source_family ] = 'WordPress debug';
                                } elseif ( 'woocommerce_log' === $operational_log_source_family ) {
                                    $operational_log_source_families[ $operational_log_source_family ] = 'WooCommerce';
                                } else {
                                    $operational_log_source_families[ $operational_log_source_family ] = ucwords( str_replace( '_', ' ', $operational_log_source_family ) );
                                }
                            }
                            $triage_log_recorded = ! empty( $operational_log_intelligence ) || ! empty( $triage_log_detail_items ) || $operational_log_source_count > 0;
                            $triage_log_value = ! $triage_log_recorded
                                ? 'Unavailable'
                                : ( $operational_log_signal_count > 0
                                    ? (string) $operational_log_signal_count
                                    : ( 'unavailable' === $operational_log_source_state ? 'Unavailable' : 'No signals' ) );
                            $triage_log_copy = ! $triage_log_recorded
                                ? 'WordPress or WooCommerce runtime log intelligence was not recorded for this run.'
                                : ( 'unavailable' === $operational_log_source_state || 0 === $operational_log_available_source_count
                                    ? 'OpsGate checked WordPress and WooCommerce log families, but no readable log source was found for this scan.'
                                    : ( $operational_log_signal_count > 0
                                        ? 'Runtime logs were available and normalized into actionable WordPress or WooCommerce signals.'
                                        : 'Runtime logs were available for normalization and no persistent WordPress or WooCommerce signals were found.' ) );
                            $triage_log_meta = 'Critical ' . (string) $operational_log_critical . ' · Warning ' . (string) $operational_log_warning . ( $triage_log_recorded ? ' · Readable ' . (string) $operational_log_available_source_count . ' · Unavailable ' . (string) $operational_log_unavailable_source_count : ' · Normalization unavailable' );
                            if ( ! empty( $operational_log_source_families ) ) {
                                $triage_log_meta .= ' · ' . implode( ', ', array_values( $operational_log_source_families ) );
                            }
                            $triage_log_signals = array_filter(
                                array(
                                    $triage_log_recorded ? 'Log analysis complete' : 'Log analysis unavailable',
                                    'Readable ' . (string) $operational_log_available_source_count,
                                    'Unavailable ' . (string) $operational_log_unavailable_source_count,
                                    'Signals ' . (string) $operational_log_signal_count,
                                    ! empty( $operational_log_source_families ) ? implode( ', ', array_values( $operational_log_source_families ) ) : '',
                                )
                            );
                            $triage_safe_update_value = '' !== $safe_update_label ? ucfirst( strtolower( $safe_update_label ) ) : 'No record';
                            $triage_safe_update_copy = ( null !== $safe_update_caution_checks || null !== $safe_update_blocking_checks )
                                ? 'Caution ' . ( null !== $safe_update_caution_checks ? (string) $safe_update_caution_checks : '0' ) . ' · Blocking ' . ( null !== $safe_update_blocking_checks ? (string) $safe_update_blocking_checks : '0' )
                                : 'No smoke-check record captured';
                            $triage_safe_update_meta = '' !== $safe_update_label ? 'Operator preflight evidence' : 'Not recorded for this run';
                            $triage_driver_cards = array();
                            if ( $reachability_is_bad ) {
                                $triage_driver_cards[] = array(
                                    'tone'  => 'bad',
                                    'label' => 'Reachability',
                                    'title' => '' !== $reachability_label ? ucfirst( strtolower( $reachability_label ) ) : 'Reachability failure',
                                    'copy'  => 'Live reachability did not complete.',
                                    'facts' => array( $triage_reachability_copy, $triage_reachability_meta ),
                                );
                            }
                            if ( null !== $vulnerability_match_count && $vulnerability_match_count > 0 ) {
                                $triage_driver_cards[] = array(
                                    'tone'  => 'bad',
                                    'label' => 'Vulnerabilities',
                                    'title' => sprintf( '%d %s found', $vulnerability_match_count, 1 === $vulnerability_match_count ? 'vulnerability' : 'vulnerabilities' ),
                                    'copy'  => 'Active vulnerabilities are affecting this site\'s score.',
                                    'facts' => array(
                                        'Critical findings: ' . (string) (int) ( $vulnerability_summary['critical_count'] ?? 0 ),
                                        'High findings: ' . (string) (int) ( $vulnerability_summary['high_count'] ?? 0 ),
                                    ),
                                );
                            } elseif ( $triage_vulnerability_unresolved_total > 0 || $triage_vulnerability_coverage_limited ) {
                                $triage_driver_cards[] = array(
                                    'tone'  => 'warn',
                                    'label' => 'Plugin advisory coverage',
                                    'title' => $triage_vulnerability_unresolved_total > 0 ? 'Manual review is still required' : 'Coverage needs review',
                                    'copy'  => 'OpsGate checked live plugin advisory coverage, but this run still has unresolved or limited coverage truth.',
                                    'facts' => array(
                                        'Checked plugins: ' . (string) $triage_vulnerability_checked_total,
                                        'Unresolved plugins: ' . (string) $triage_vulnerability_unresolved_total,
                                        '' !== trim( $vulnerability_evidence_state ) ? 'Evidence state: ' . ucfirst( str_replace( '_', ' ', strtolower( $vulnerability_evidence_state ) ) ) : '',
                                    ),
                                );
                            }
                            if ( $update_outdated_total > 0 ) {
                                $triage_driver_cards[] = array(
                                    'tone'  => 'warn',
                                    'label' => 'Updates',
                                    'title' => sprintf( '%d item(s) need attention', $update_outdated_total ),
                                    'copy'  => 'Version drift is adding pressure.',
                                    'facts' => array(
                                        'Plugins: ' . (string) $update_plugin_outdated,
                                        'Themes: ' . (string) $update_theme_outdated,
                                        'Core: ' . ( $update_core_outdated ? 'outdated' : 'current' ),
                                    ),
                                );
                            }
                            if ( $availability_is_bad ) {
                                $triage_driver_cards[] = array(
                                    'tone'  => 'warn',
                                    'label' => 'Availability',
                                    'title' => '' !== $availability_label ? ucfirst( strtolower( $availability_label ) ) : 'Availability issue',
                                    'copy'  => 'Probe results show instability.',
                                    'facts' => array(
                                        'Attempts: ' . ( null !== $availability_attempt_count ? (string) $availability_attempt_count : 'pending' ),
                                        'Failed: ' . ( null !== $availability_failure_count ? (string) $availability_failure_count : 'pending' ),
                                    ),
                                );
                            }
                            if ( $performance_is_bad ) {
                                $triage_driver_cards[] = array(
                                    'tone'  => 'warn',
                                    'label' => 'Performance',
                                    'title' => '' !== $performance_label ? ucfirst( strtolower( $performance_label ) ) : 'Performance issue',
                                    'copy'  => 'Recorded latency is degraded.',
                                    'facts' => array(
                                        '' !== $performance_total_duration ? 'Duration: ' . $performance_total_duration . ' ms' : 'Duration not recorded',
                                        '' !== $performance_first_byte ? 'First byte: ' . $performance_first_byte . ' ms' : 'First byte not recorded',
                                    ),
                                );
                            }
                            if ( $safe_update_needs_attention ) {
                                $triage_driver_cards[] = array(
                                    'tone'  => 'warn',
                                    'label' => 'Safe-update smoke check',
                                    'title' => '' !== $safe_update_label ? ucfirst( strtolower( $safe_update_label ) ) : 'Follow-up needed',
                                    'copy'  => 'Smoke-check follow-up is required.',
                                    'facts' => array(
                                        'Caution checks: ' . ( null !== $safe_update_caution_checks ? (string) $safe_update_caution_checks : '0' ),
                                        'Blocking checks: ' . ( null !== $safe_update_blocking_checks ? (string) $safe_update_blocking_checks : '0' ),
                                    ),
                                );
                            }
                            if ( $hardening_guidance_count > 0 ) {
                                $triage_driver_cards[] = array(
                                    'tone'  => in_array( $hardening_guidance_state, array( 'action_required', 'review_required' ), true ) ? ( 'action_required' === $hardening_guidance_state ? 'bad' : 'warn' ) : 'good',
                                    'label' => 'Hardening guidance',
                                    'title' => $hardening_guidance_title,
                                    'copy'  => $hardening_guidance_copy,
                                    'facts' => array(
                                        'Guidance items: ' . (string) $hardening_guidance_count,
                                        'Critical: ' . (string) (int) ( $hardening_summary['critical_count'] ?? 0 ),
                                        'Warning: ' . (string) (int) ( $hardening_summary['warning_count'] ?? 0 ),
                                    ),
                                );
                            }
                            if ( empty( $triage_driver_cards ) ) {
                                $triage_driver_cards[] = array(
                                    'tone'  => 'good',
                                    'label' => 'Recorded drivers',
                                    'title' => 'No immediate pressure recorded',
                                    'copy'  => 'The latest run did not record active pressure.',
                                    'facts' => array(
                                        'Evidence state: ' . $triage_evidence_state,
                                        'Scope: ' . $triage_scope_label,
                                    ),
                                );
                            }
                            $triage_driver_cards = array_slice( $triage_driver_cards, 0, 4 );
                            $triage_detail_focus = isset( $_GET['opsgate_detail'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_detail'] ) ) : '';
                            $triage_reason_detail_open = 'rationale' === $triage_detail_focus;
                            $triage_updates_detail_open = 'updates' === $triage_detail_focus;
                            $triage_vulnerabilities_detail_open = 'vulnerabilities' === $triage_detail_focus;
                            $triage_reason_detail_summary = ! empty( $triage_reason_items )
                                ? sprintf( '%d factor(s)', count( $triage_reason_items ) )
                                : 'No factors';
                            $triage_updates_detail_summary = $update_outdated_total > 0
                                ? sprintf( '%d item(s)', $update_outdated_total )
                                : 'No items';
                            $triage_vulnerabilities_detail_summary = ( null !== $vulnerability_match_count && $vulnerability_match_count > 0 )
                                ? sprintf( '%d %s', $vulnerability_match_count, 1 === $vulnerability_match_count ? 'vulnerability' : 'vulnerabilities' )
                                : 'No vulnerabilities';
                            $triage_dataset_value = $triage_vulnerability_live_source_recorded ? 'Live plugin advisory lineage recorded' : 'Live source lineage not recorded';
                            $triage_dataset_meta = $triage_vulnerability_live_source_recorded
                                ? trim(
                                    implode(
                                        ' · ',
                                        array_filter(
                                            array(
                                                '' !== $vulnerability_source_provider ? 'Provider ' . $vulnerability_source_provider : '',
                                                '' !== $vulnerability_source_mode ? 'Lookup ' . ucfirst( str_replace( '_', ' ', $vulnerability_source_mode ) ) : '',
                                                '' !== $vulnerability_source_updated_at ? 'Updated ' . self::format_event_datetime( $vulnerability_source_updated_at ) : '',
                                            )
                                        )
                                    )
                                )
                                : 'This run did not record live advisory source metadata.';
                            $triage_support_label = 'Support evidence package';

                            $inventory_download = '';
                            if ( ! empty( $inventory ) ) {
                                $inventory_download = wp_nonce_url(
                                    add_query_arg(
                                        array(
                                            'action' => 'opsgate_download_triage_artifact',
                                            'job_id' => $job_id,
                                            'kind'   => 'inventory_snapshot',
                                        ),
                                        admin_url( 'admin-post.php' )
                                    ),
                                    'opsgate_download_triage_artifact'
                                );
                            }

                            $update_download = '';
                            if ( ! empty( $update_posture ) ) {
                                $update_download = wp_nonce_url(
                                    add_query_arg(
                                        array(
                                            'action' => 'opsgate_download_triage_artifact',
                                            'job_id' => $job_id,
                                            'kind'   => 'update_posture',
                                        ),
                                        admin_url( 'admin-post.php' )
                                    ),
                                    'opsgate_download_triage_artifact'
                                );
                            }

                            $vulnerability_download = '';
                            if ( ! empty( $vulnerability_posture ) ) {
                                $vulnerability_download = wp_nonce_url(
                                    add_query_arg(
                                        array(
                                            'action' => 'opsgate_download_triage_artifact',
                                            'job_id' => $job_id,
                                            'kind'   => 'vulnerability_posture',
                                        ),
                                        admin_url( 'admin-post.php' )
                                    ),
                                    'opsgate_download_triage_artifact'
                                );
                            }

                            $reachability_download = '';
                            if ( ! empty( $reachability_posture ) ) {
                                $reachability_download = wp_nonce_url(
                                    add_query_arg(
                                        array(
                                            'action' => 'opsgate_download_triage_artifact',
                                            'job_id' => $job_id,
                                            'kind'   => 'reachability_posture',
                                        ),
                                        admin_url( 'admin-post.php' )
                                    ),
                                    'opsgate_download_triage_artifact'
                                );
                            }

                            $availability_download = '';
                            if ( ! empty( $availability_snapshot ) ) {
                                $availability_download = wp_nonce_url(
                                    add_query_arg(
                                        array(
                                            'action' => 'opsgate_download_triage_artifact',
                                            'job_id' => $job_id,
                                            'kind'   => 'availability_snapshot',
                                        ),
                                        admin_url( 'admin-post.php' )
                                    ),
                                    'opsgate_download_triage_artifact'
                                );
                            }

                            $performance_download = '';
                            if ( ! empty( $performance_snapshot ) ) {
                                $performance_download = wp_nonce_url(
                                    add_query_arg(
                                        array(
                                            'action' => 'opsgate_download_triage_artifact',
                                            'job_id' => $job_id,
                                            'kind'   => 'performance_snapshot',
                                        ),
                                        admin_url( 'admin-post.php' )
                                    ),
                                    'opsgate_download_triage_artifact'
                                );
                            }

                            $configuration_validation_download = '';
                            if ( ! empty( $configuration_validation ) ) {
                                $configuration_validation_download = wp_nonce_url(
                                    add_query_arg(
                                        array(
                                            'action' => 'opsgate_download_triage_artifact',
                                            'job_id' => $job_id,
                                            'kind'   => 'configuration_validation',
                                        ),
                                        admin_url( 'admin-post.php' )
                                    ),
                                    'opsgate_download_triage_artifact'
                                );
                            }

                            $uptime_window_download = '';
                            if ( ! empty( $uptime_window_artifact ) ) {
                                $uptime_window_download = wp_nonce_url(
                                    add_query_arg(
                                        array(
                                            'action' => 'opsgate_download_triage_artifact',
                                            'job_id' => $job_id,
                                            'kind'   => 'uptime_window',
                                        ),
                                        admin_url( 'admin-post.php' )
                                    ),
                                    'opsgate_download_triage_artifact'
                                );
                            }

                            $operational_log_download = '';
                            if ( ! empty( $operational_log_intelligence ) ) {
                                $operational_log_download = wp_nonce_url(
                                    add_query_arg(
                                        array(
                                            'action' => 'opsgate_download_triage_artifact',
                                            'job_id' => $job_id,
                                            'kind'   => 'operational_log_intelligence',
                                        ),
                                        admin_url( 'admin-post.php' )
                                    ),
                                    'opsgate_download_triage_artifact'
                                );
                            }

                            $safe_update_download = '';
                            if ( ! empty( $safe_update_smoke_check ) ) {
                                $safe_update_download = wp_nonce_url(
                                    add_query_arg(
                                        array(
                                            'action' => 'opsgate_download_triage_artifact',
                                            'job_id' => $job_id,
                                            'kind'   => 'safe_update_smoke_check',
                                        ),
                                        admin_url( 'admin-post.php' )
                                    ),
                                    'opsgate_download_triage_artifact'
                                );
                            }

                            $hardening_guidance_download = '';
                            if ( ! empty( $hardening_guidance ) ) {
                                $hardening_guidance_download = wp_nonce_url(
                                    add_query_arg(
                                        array(
                                            'action' => 'opsgate_download_triage_artifact',
                                            'job_id' => $job_id,
                                            'kind'   => 'hardening_guidance',
                                        ),
                                        admin_url( 'admin-post.php' )
                                    ),
                                    'opsgate_download_triage_artifact'
                                );
                            }

                            $triage_download_actions = array();
                            if ( '' !== $inventory_download ) {
                                $triage_download_actions[] = array( 'label' => 'Inventory JSON', 'url' => $inventory_download );
                            }
                            if ( '' !== $update_download ) {
                                $triage_download_actions[] = array( 'label' => 'Update JSON', 'url' => $update_download );
                            }
                            if ( '' !== $vulnerability_download ) {
                                $triage_download_actions[] = array( 'label' => 'Vulnerability JSON', 'url' => $vulnerability_download );
                            }
                            if ( '' !== $reachability_download ) {
                                $triage_download_actions[] = array( 'label' => 'Reachability JSON', 'url' => $reachability_download );
                            }
                            if ( '' !== $availability_download ) {
                                $triage_download_actions[] = array( 'label' => 'Availability JSON', 'url' => $availability_download );
                            }
                            if ( '' !== $performance_download ) {
                                $triage_download_actions[] = array( 'label' => 'Performance JSON', 'url' => $performance_download );
                            }
                            if ( '' !== $configuration_validation_download ) {
                                $triage_download_actions[] = array( 'label' => 'Validation JSON', 'url' => $configuration_validation_download );
                            }
                            if ( '' !== $uptime_window_download ) {
                                $triage_download_actions[] = array( 'label' => 'Uptime JSON', 'url' => $uptime_window_download );
                            }
                            if ( '' !== $operational_log_download ) {
                                $triage_download_actions[] = array( 'label' => 'Log Intelligence JSON', 'url' => $operational_log_download );
                            }
                            if ( '' !== $safe_update_download ) {
                                $triage_download_actions[] = array( 'label' => 'Safe-Update JSON', 'url' => $safe_update_download );
                            }
                            if ( '' !== $hardening_guidance_download ) {
                                $triage_download_actions[] = array( 'label' => 'Hardening Guidance JSON', 'url' => $hardening_guidance_download );
                            }
                            $triage_artifact_count = count( $triage_download_actions );
                            $triage_artifact_value = $triage_artifact_count > 0 ? sprintf( '%d files', $triage_artifact_count ) : 'Not recorded';
                            $triage_artifact_meta = $triage_artifact_count > 0 ? 'JSON evidence remains available.' : 'No support artifact summary is available yet.';
                            $triage_hero_reason = ! empty( $triage_operational_clauses )
                                ? implode( ', ', array_slice( $triage_operational_clauses, 0, 2 ) ) . '.'
                                : 'No active operational pressure is recorded.';
                            $triage_hero_freshness = 'Last run ' . $triage_started_label;
                            $triage_hero_chips = array(
                                array(
                                    'class' => 'opsgate-triage-pill-' . $triage_grade_tone,
                                    'label' => $triage_grade_label,
                                ),
                                array(
                                    'class' => 'opsgate-triage-pill-soft-' . $triage_grade_tone,
                                    'label' => $triage_grade_summary,
                                ),
                            );
                            $triage_assessment_intro = 'Recorded checks show where the current pressure is coming from.';
                            $triage_assessment_cards = array(
                                array(
                                    'label'   => 'Overall',
                                    'tone'    => $triage_grade_tone,
                                    'title'   => $triage_grade_summary,
                                    'summary' => $triage_hero_reason,
                                    'facts'   => array(
                                        'Score ' . ( null !== $score ? (string) $score : '—' ),
                                        'Run ' . $triage_state_label,
                                        'Evidence ' . $triage_evidence_state,
                                    ),
                                ),
                                array(
                                    'label'   => 'Updates',
                                    'tone'    => $update_outdated_total > 0 ? 'warn' : 'neutral',
                                    'title'   => sprintf( '%d item(s)', $update_outdated_total ),
                                    'summary' => $update_outdated_total > 0 ? 'Version drift needs review.' : 'No update pressure recorded.',
                                    'facts'   => array(
                                        'Plugins ' . (string) $update_plugin_outdated,
                                        'Themes ' . (string) $update_theme_outdated,
                                        'Core ' . ( $update_core_outdated ? 'outdated' : 'current' ),
                                    ),
                                ),
                                array(
                                    'label'   => 'Vulnerabilities',
                                    'tone'    => ( null !== $vulnerability_match_count && $vulnerability_match_count > 0 ) ? 'bad' : 'neutral',
                                    'title'   => null !== $vulnerability_match_count ? sprintf( '%d %s', $vulnerability_match_count, 1 === (int) $vulnerability_match_count ? 'vulnerability' : 'vulnerabilities' ) : 'No vulnerabilities',
                                    'summary' => ( null !== $vulnerability_match_count && $vulnerability_match_count > 0 ) ? 'Recorded advisories are affecting posture.' : 'No advisory pressure was recorded.',
                                    'facts'   => array(
                                        'Critical ' . (string) (int) ( $vulnerability_summary['critical_count'] ?? 0 ),
                                        'High ' . (string) (int) ( $vulnerability_summary['high_count'] ?? 0 ),
                                        $triage_vulnerability_meta,
                                    ),
                                ),
                                array(
                                    'label'   => 'Reachability',
                                    'tone'    => $reachability_is_bad ? 'bad' : 'neutral',
                                    'title'   => '' !== $reachability_label ? ucfirst( strtolower( $reachability_label ) ) : 'Not recorded',
                                    'summary' => $reachability_is_bad ? 'Live check failed.' : 'Live check completed.',
                                    'facts'   => array(
                                        '' !== $reachability_http_status ? 'HTTP ' . $reachability_http_status : 'HTTP not recorded',
                                        '' !== $reachability_duration_ms ? 'Duration ' . $reachability_duration_ms . ' ms' : 'Duration not recorded',
                                        null !== $reachability_transport_ok ? 'Transport ' . ( $reachability_transport_ok ? 'ok' : 'failed' ) : 'Transport not recorded',
                                    ),
                                ),
                                array(
                                    'label'   => 'Availability',
                                    'tone'    => $availability_is_bad ? 'warn' : 'neutral',
                                    'title'   => '' !== $availability_label ? ucfirst( strtolower( $availability_label ) ) : 'Not recorded',
                                    'summary' => $availability_is_bad ? 'Probe results are unstable.' : 'Probe window is stable.',
                                    'facts'   => array(
                                        'Attempts ' . ( null !== $availability_attempt_count ? (string) $availability_attempt_count : 'pending' ),
                                        'Success ' . ( null !== $availability_success_count ? (string) $availability_success_count : 'pending' ),
                                        'Failed ' . ( null !== $availability_failure_count ? (string) $availability_failure_count : 'pending' ),
                                    ),
                                ),
                            );
                            $triage_capability_cards = array(
                                array(
                                    'label'   => 'Plugin advisory coverage',
                                    'tone'    => $triage_connected_truth_available ? ( $triage_vulnerability_match_total > 0 ? 'bad' : ( $triage_vulnerability_unresolved_total > 0 || $triage_vulnerability_coverage_limited ? 'warn' : ( $triage_vulnerability_has_coverage ? 'good' : 'neutral' ) ) ) : 'neutral',
                                    'title'   => $triage_connected_truth_available ? $triage_vulnerability_value : $triage_connected_only_value,
                                    'summary' => $triage_connected_truth_available ? $triage_vulnerability_copy : $triage_connected_only_copy,
                                    'signals' => $triage_connected_truth_available ? $triage_vulnerability_signals : array(),
                                    'facts'   => array(
                                        $triage_connected_truth_available ? $triage_vulnerability_meta : $triage_connection_copy,
                                        $triage_connected_truth_available && '' !== $vulnerability_source_mode ? 'Lookup path: ' . ucfirst( str_replace( '_', ' ', $vulnerability_source_mode ) ) : '',
                                        $triage_connected_truth_available && '' !== $vulnerability_source_updated_at ? 'Source updated ' . self::format_event_datetime( $vulnerability_source_updated_at ) : '',
                                    ),
                                    'href'    => $triage_connected_truth_available ? self::detail_surface_url( 'triage', 'vulnerabilities' ) . '#opsgate-evidence-detail' : '',
                                    'detail_key' => $triage_connected_truth_available ? 'vulnerabilities' : '',
                                    'link'    => $triage_connected_truth_available ? 'Open advisory review' : '',
                                ),
                                array(
                                    'label'   => 'Configuration validation',
                                    'tone'    => $triage_connected_truth_available ? ( $configuration_validation_findings > 0 ? 'warn' : 'good' ) : 'neutral',
                                    'title'   => $triage_connected_truth_available ? $triage_validation_value : $triage_connected_only_value,
                                    'summary' => $triage_connected_truth_available ? $triage_validation_copy : $triage_connected_only_copy,
                                    'signals' => $triage_connected_truth_available ? $triage_validation_signals : array(),
                                    'facts'   => array(
                                        $triage_connected_truth_available ? $triage_validation_meta : $triage_connection_copy,
                                    ),
                                    'href'    => $triage_connected_truth_available ? self::detail_surface_url( 'triage', 'validation' ) . '#opsgate-evidence-detail' : '',
                                    'detail_key' => $triage_connected_truth_available ? 'validation' : '',
                                    'link'    => $triage_connected_truth_available ? 'Open validation review' : '',
                                ),
                                array(
                                    'label'   => 'Uptime over time',
                                    'tone'    => $uptime_failure_count > 0 ? 'warn' : ( $uptime_observation_count > 0 ? 'good' : 'neutral' ),
                                    'title'   => $triage_uptime_value,
                                    'summary' => $triage_uptime_copy,
                                    'signals' => $triage_uptime_signals,
                                    'facts'   => array(
                                        $triage_uptime_meta,
                                    ),
                                    'href'    => self::detail_surface_url( 'triage', 'uptime' ) . '#opsgate-evidence-detail',
                                    'detail_key' => 'uptime',
                                    'link'    => 'Open uptime history',
                                ),
                                array(
                                    'label'   => 'Operational log intelligence',
                                    'tone'    => $triage_connected_truth_available ? ( $operational_log_signal_count > 0 ? 'warn' : 'good' ) : 'neutral',
                                    'title'   => $triage_connected_truth_available ? $triage_log_value : $triage_connected_only_value,
                                    'summary' => $triage_connected_truth_available ? $triage_log_copy : $triage_connected_only_copy,
                                    'signals' => $triage_connected_truth_available ? $triage_log_signals : array(),
                                    'facts'   => array(
                                        $triage_connected_truth_available ? $triage_log_meta : $triage_connection_copy,
                                    ),
                                    'href'    => $triage_connected_truth_available ? self::detail_surface_url( 'triage', 'logs' ) . '#opsgate-evidence-detail' : '',
                                    'detail_key' => $triage_connected_truth_available ? 'logs' : '',
                                    'link'    => $triage_connected_truth_available ? 'Open log signals' : '',
                                ),
                            );
                            $triage_assessment_support_cards = array(
                                array(
                                    'label'   => 'Performance',
                                    'tone'    => $performance_is_bad ? 'warn' : 'neutral',
                                    'title'   => $triage_performance_value,
                                    'summary' => $performance_is_bad ? 'Latency is outside target.' : 'Latency stayed within target.',
                                    'facts'   => array(
                                        '' !== $performance_status_code ? 'Status ' . $performance_status_code : 'Status not recorded',
                                        '' !== $performance_total_duration ? 'Duration ' . $performance_total_duration . ' ms' : 'Duration not recorded',
                                        '' !== $performance_first_byte ? 'First byte ' . $performance_first_byte . ' ms' : 'First byte not recorded',
                                    ),
                                ),
                                array(
                                    'label'   => 'Smoke check',
                                    'tone'    => $safe_update_needs_attention ? 'warn' : 'muted',
                                    'title'   => $triage_safe_update_value,
                                    'summary' => '' !== $safe_update_label ? 'Recorded preflight state.' : 'No smoke-check record captured.',
                                    'facts'   => array(
                                        null !== $safe_update_caution_checks ? 'Caution ' . (string) $safe_update_caution_checks : 'Caution not recorded',
                                        null !== $safe_update_blocking_checks ? 'Blocking ' . (string) $safe_update_blocking_checks : 'Blocking not recorded',
                                    ),
                                ),
                            );
                            $triage_detail_focus = isset( $_GET['opsgate_detail'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_detail'] ) ) : '';
                            $triage_detail_focus = in_array( $triage_detail_focus, array( 'rationale', 'updates', 'vulnerabilities', 'validation', 'uptime', 'logs', 'hardening' ), true ) ? $triage_detail_focus : '';
                            $triage_detail_tabs = array(
                                'rationale'      => array(
                                    'label'   => 'Rationale',
                                    'count'   => count( $triage_reason_items ),
                                    'title'   => 'Recorded rationale',
                                    'summary' => 'Why the score landed here',
                                    'items'   => $triage_reason_items,
                                    'empty'   => 'Reason detail is unavailable for this live run.',
                                ),
                                'updates'        => array(
                                    'label'   => 'Updates',
                                    'count'   => $update_outdated_total,
                                    'title'   => 'Update items',
                                    'summary' => 'Recorded version drift detail',
                                    'items'   => $triage_update_detail_items,
                                    'empty'   => 'No update items are listed for this run.',
                                ),
                                'vulnerabilities' => array(
                                    'label'   => 'Advisories',
                                    'count'   => max( $triage_vulnerability_match_total + $triage_vulnerability_unresolved_total, count( $triage_vulnerability_detail_items ) ),
                                    'title'   => $triage_vulnerability_match_total > 0 ? 'Vulnerable installed plugins' : 'Plugin advisory coverage',
                                    'summary' => $triage_vulnerability_match_total > 0
                                        ? 'Affected installed versions, severity, and review path'
                                        : 'Checked plugin coverage, unresolved items, and manual review',
                                    'items'   => $triage_vulnerability_detail_items,
                                    'empty'   => 'No vulnerable installed plugins or unresolved advisory lookups are listed for this run.',
                                ),
                                'validation' => array(
                                    'label'   => 'Validation',
                                    'count'   => max( $configuration_validation_findings, count( $triage_validation_detail_items ) ),
                                    'title'   => 'Configuration findings',
                                    'summary' => 'Recorded .htaccess and folder-structure review',
                                    'items'   => $triage_validation_detail_items,
                                    'empty'   => 'No configuration findings are listed for this run.',
                                ),
                                'uptime' => array(
                                    'label'   => 'Uptime',
                                    'count'   => max( $uptime_observation_count, count( $triage_uptime_detail_items ) ),
                                    'title'   => 'Recent uptime observations',
                                    'summary' => 'Recorded uptime-over-time window',
                                    'items'   => $triage_uptime_detail_items,
                                    'empty'   => 'No uptime observations are listed for this window.',
                                ),
                                'logs' => array(
                                    'label'   => 'Logs',
                                    'count'   => max( $operational_log_signal_count, count( $triage_log_detail_items ) ),
                                    'title'   => 'Operational log signals',
                                    'summary' => 'Normalized WordPress and WooCommerce log intelligence',
                                    'items'   => $triage_log_detail_items,
                                    'empty'   => 'No normalized log signals are listed for this run.',
                                ),
                                'hardening' => array(
                                    'label'   => 'Hardening',
                                    'count'   => max( $hardening_guidance_count, count( $triage_hardening_detail_items ) ),
                                    'title'   => 'Hardening and remediation guidance',
                                    'summary' => 'Recorded next-step guidance grounded in this run',
                                    'items'   => $triage_hardening_detail_items,
                                    'empty'   => 'No hardening guidance is recorded for this run.',
                                ),
                            );
                            $triage_why_updates = 0 === $update_outdated_total
                                ? 'No pending updates were recorded — the installed WordPress core, plugins, and themes are up to date as of this run.'
                                : sprintf( '%d outdated component(s) were recorded: %s%s%s. Applying available updates removes the version-drift pressure contributing to this score.',
                                    $update_outdated_total,
                                    $update_core_outdated ? 'core' : '',
                                    ( $update_core_outdated && ( $update_plugin_outdated > 0 || $update_theme_outdated > 0 ) ) ? ', ' : '',
                                    implode( ', ', array_filter( array(
                                        $update_plugin_outdated > 0 ? $update_plugin_outdated . ' plugin(s)' : '',
                                        $update_theme_outdated > 0 ? $update_theme_outdated . ' theme(s)' : '',
                                    ) ) )
                                );
                            $triage_why_vulnerabilities = null === $vulnerability_match_count
                                ? 'OpsGate has not recorded a completed vulnerability advisory check for this run yet.'
                                : ( 0 === (int) $vulnerability_match_count
                                    ? sprintf( 'No active CVE matches were recorded — OpsGate checked %s plugin(s) against live advisory data and found no affected installed versions.',
                                        null !== $vulnerability_checked_plugin_count ? (string) $vulnerability_checked_plugin_count : 'the tracked'
                                    )
                                    : sprintf( '%d %s found against the installed plugin set. Each matched plugin has a known CVE in its installed version — update to the fixed version shown to close the exposure.',
                                        (int) $vulnerability_match_count,
                                        1 === (int) $vulnerability_match_count ? 'vulnerability' : 'vulnerabilities'
                                    )
                                );
                            $triage_detail_tabs['rationale']['why_note'] = 'This score reflects what OpsGate recorded during this scan — each factor below contributed to the result. Review the individual dimensions to understand the findings and what action, if any, is required.';
                            $triage_detail_tabs['updates']['why_note'] = $triage_why_updates;
                            $triage_detail_tabs['vulnerabilities']['why_note'] = $triage_why_vulnerabilities;
                            $triage_selected_detail = '' !== $triage_detail_focus && isset( $triage_detail_tabs[ $triage_detail_focus ] ) ? $triage_detail_tabs[ $triage_detail_focus ] : null;
                            $triage_alert_meta_items = array_filter(
                                array(
                                    (string) $triage_alert_rollup['headline'],
                                    (string) $triage_alert_rollup['latest_summary'],
                                    (string) $triage_alert_rollup['latest_time'],
                                )
                            );
                            $triage_board_state = self::canonical_portfolio_board();
                            $triage_board_row = self::canonical_local_board_row( $triage_board_state );

                            $triage_started_timestamp = '' !== $started ? strtotime( $started ) : false;
                            $triage_elapsed_label     = 'Freshness unavailable';
                            if ( false !== $triage_started_timestamp ) {
                                $triage_elapsed_human = human_time_diff( $triage_started_timestamp, current_time( 'timestamp' ) );
                                $triage_elapsed_label = in_array( $state, array( 'QUEUED', 'RUNNING' ), true ) || $export_busy
                                    ? sprintf( 'Running for %s', $triage_elapsed_human )
                                    : sprintf( 'Recorded %s ago', $triage_elapsed_human );
                            }

                            $triage_action_cards = array();
                            $triage_action_signatures = array();
                            $triage_add_action_card = static function ( array $card ) use ( &$triage_action_cards, &$triage_action_signatures ) {
                                $signature = strtolower(
                                    trim( (string) ( $card['title'] ?? '' ) ) . '|' .
                                    trim( (string) ( $card['label'] ?? '' ) ) . '|' .
                                    trim( (string) ( $card['url'] ?? '' ) )
                                );
                                if ( '' === $signature || isset( $triage_action_signatures[ $signature ] ) ) {
                                    return;
                                }
                                $triage_action_signatures[ $signature ] = true;
                                $triage_action_cards[] = $card;
                            };
                            if ( in_array( $triage_connection_status, array( 'credential_invalid', 'disconnected' ), true ) ) {
                                $triage_add_action_card( array(
                                    'eyebrow' => 'Connection recovery',
                                    'title'   => 'Restore the connector trust path before the next connected run',
                                    'copy'    => 'Authenticated inventory, updates, and vulnerability evidence are paused. Reconnect or rotate the site credential from canonical Settings.',
                                    'url'     => self::admin_tab_url( 'settings' ),
                                    'label'   => 'Reconnect Site',
                                ) );
                            } elseif ( 'pairing_pending' === $triage_connection_status ) {
                                $triage_add_action_card( array(
                                    'eyebrow' => 'Connection recovery',
                                    'title'   => 'Finish pairing so connected evidence can start flowing',
                                    'copy'    => 'This site is waiting for the connector handshake. Complete pairing in Settings before expecting authenticated inventory or vulnerability truth.',
                                    'url'     => self::admin_tab_url( 'settings' ),
                                    'label'   => 'Finish Pairing',
                                ) );
                            } elseif ( 'external_only' === $triage_connection_status ) {
                                $triage_add_action_card( array(
                                    'eyebrow' => 'Connection upgrade',
                                    'title'   => 'Connect this site for authenticated WordPress assessment',
                                    'copy'    => 'External-only mode is limited to public checks. Pair the connector when you need inventory, update drift, and vulnerability evidence.',
                                    'url'     => self::admin_tab_url( 'settings' ),
                                    'label'   => 'Open Settings',
                                ) );
                            } elseif ( $export_busy ) {
                                $triage_add_action_card( array(
                                    'eyebrow' => 'Run progress',
                                    'title'   => 'Stay with this run while the report package finishes',
                                    'copy'    => 'The assessment is recorded and rendered outputs are still packaging. Refresh status or jump to Reports to watch the package land.',
                                    'url'     => $refresh_url,
                                    'label'   => 'Refresh run status',
                                ) );
                            } elseif ( 'RUNNING' === $state ) {
                                $triage_add_action_card( array(
                                    'eyebrow' => 'Run progress',
                                    'title'   => 'Stay with the live run while evidence is still arriving',
                                    'copy'    => 'The progress rail updates in place while OpsGate records evidence behind the API. Keep this workspace open until the recorded run settles.',
                                    'url'     => $refresh_url,
                                    'label'   => 'Refresh run status',
                                ) );
                            } elseif ( 'QUEUED' === $state ) {
                                $triage_add_action_card( array(
                                    'eyebrow' => 'Run progress',
                                    'title'   => 'Keep this workspace open while worker execution begins',
                                    'copy'    => 'The run has been accepted behind the API and is waiting to start. Refresh when you want the latest truthful run state.',
                                    'url'     => $refresh_url,
                                    'label'   => 'Refresh run status',
                                ) );
                            } elseif ( 'FAILED' === $state || 'FAILED' === $export_state_upper ) {
                                $triage_add_action_card( array(
                                    'eyebrow' => 'Run follow-up',
                                    'title'   => 'Review the failed run before sharing or acting',
                                    'copy'    => 'Open Reports and the support package to understand what failed, then rerun triage after the issue is resolved.',
                                    'url'     => $triage_reports_url,
                                    'label'   => 'Open Reports',
                                ) );
                            } elseif ( 'COMPLETED' === $state && ! $export_busy ) {
                                $triage_add_action_card( array(
                                    'eyebrow' => 'Run complete',
                                    'title'   => 'Generate a report for this scan',
                                    'copy'    => 'This scan is complete and ready. Open Reports to generate and download PDF, HTML, CSV, or Excel outputs for this site.',
                                    'url'     => $triage_reports_url,
                                    'label'   => 'Generate Report',
                                ) );
                            }
                            if ( $hardening_guidance_count > 0 && ! empty( $hardening_items[0] ) && is_array( $hardening_items[0] ) ) {
                                $hardening_action_title = isset( $hardening_items[0]['title'] ) ? (string) $hardening_items[0]['title'] : 'Review recorded hardening guidance';
                                $hardening_action_copy = isset( $hardening_items[0]['recommended_action'] ) ? (string) $hardening_items[0]['recommended_action'] : $hardening_guidance_copy;
                                $triage_add_action_card( array(
                                    'eyebrow' => 'Hardening guidance',
                                    'title'   => $hardening_action_title,
                                    'copy'    => $hardening_action_copy,
                                    'url'     => self::detail_surface_url( 'triage', 'hardening' ) . '#opsgate-evidence-detail',
                                    'label'   => 'Open Guidance',
                                ) );
                            }
                            if ( null !== $vulnerability_match_count && $vulnerability_match_count > 0 ) {
                                $triage_add_action_card( array(
                                    'eyebrow' => 'Critical follow-up',
                                    'title'   => 'Review vulnerable installed plugins and set response order',
                                    'copy'    => 'Use the recorded matches to identify which components need immediate update, replacement, or containment before the next customer update.',
                                    'url'     => self::detail_surface_url( 'triage', 'vulnerabilities' ) . '#opsgate-evidence-detail',
                                    'label'   => 'Review Vulnerabilities',
                                ) );
                                $triage_add_action_card( array(
                                    'eyebrow' => 'Communication',
                                    'title'   => 'Open the report package once you confirm what is affected',
                                    'copy'    => 'Use Reports for the customer-safe package after you confirm scope, timing, and the next operator decision.',
                                    'url'     => $triage_reports_url,
                                    'label'   => 'Open Reports',
                                ) );
                            }
                            if ( $reachability_is_bad || $availability_is_bad ) {
                                $triage_add_action_card( array(
                                    'eyebrow' => 'Service follow-up',
                                    'title'   => 'Review public uptime evidence before customer-facing reporting',
                                    'copy'    => 'Reachability or availability pressure is affecting posture. Use the recorded evidence to confirm whether the issue is ongoing or already resolved.',
                                    'url'     => self::detail_surface_url( 'triage', 'uptime' ) . '#opsgate-evidence-detail',
                                    'label'   => 'Review Uptime',
                                ) );
                            }
                            if ( $update_outdated_total > 0 || $safe_update_needs_attention ) {
                                $triage_add_action_card( array(
                                    'eyebrow' => 'Warning follow-up',
                                    'title'   => 'Review change pressure before the next maintenance decision',
                                    'copy'    => 'Use the recorded update and smoke-check evidence to decide what to patch first and what can wait for a scheduled change window.',
                                    'url'     => self::detail_surface_url( 'triage', 'updates' ) . '#opsgate-evidence-detail',
                                    'label'   => 'Review Updates',
                                ) );
                            }
                            if ( $configuration_validation_findings > 0 ) {
                                $triage_add_action_card( array(
                                    'eyebrow' => 'Configuration follow-up',
                                    'title'   => 'Review the recorded validation findings before you treat the host as stable',
                                    'copy'    => 'The latest connected review recorded .htaccess or folder-structure findings that should be checked before the next customer update.',
                                    'url'     => self::detail_surface_url( 'triage', 'validation' ) . '#opsgate-evidence-detail',
                                    'label'   => 'Review Validation',
                                ) );
                            }
                            if ( $operational_log_signal_count > 0 ) {
                                $triage_add_action_card( array(
                                    'eyebrow' => 'Operational follow-up',
                                    'title'   => 'Review the normalized runtime signals before they compound into customer-facing failure',
                                    'copy'    => 'OpsGate recorded recurring runtime patterns from WordPress or WooCommerce logs. Use the normalized signal list to focus remediation.',
                                    'url'     => self::detail_surface_url( 'triage', 'logs' ) . '#opsgate-evidence-detail',
                                    'label'   => 'Review Log Signals',
                                ) );
                            }
                            if ( $performance_is_bad ) {
                                $triage_add_action_card( array(
                                    'eyebrow' => 'Experience follow-up',
                                    'title'   => 'Review the performance snapshot before sharing this run',
                                    'copy'    => 'The current posture includes degraded latency. Confirm whether the slowdown was transient or part of a broader site issue.',
                                    'url'     => self::detail_surface_url( 'triage', 'performance' ) . '#opsgate-evidence-detail',
                                    'label'   => 'Review Performance',
                                ) );
                            }
                            if ( empty( $triage_action_cards ) ) {
                                $triage_add_action_card( array(
                                    'eyebrow' => 'Next step',
                                    'title'   => 'Review the latest report package before you share or schedule follow-up',
                                    'copy'    => 'This run is recorded cleanly. Use Reports for the customer-ready package, then rerun triage only when conditions materially change.',
                                    'url'     => $triage_reports_url,
                                    'label'   => 'View Reports',
                                ) );
                            }
                            if ( ! in_array( $triage_connection_status, array( 'external_only', 'pairing_pending', 'credential_invalid', 'disconnected' ), true ) ) {
                                $triage_add_action_card( array(
                                    'eyebrow' => 'Report review',
                                    'title'   => 'Use Reports for the share-ready package and deeper support files',
                                    'copy'    => 'The report center keeps customer-ready outputs first while leaving support evidence available when you need to verify or export more detail.',
                                    'url'     => $triage_reports_url,
                                    'label'   => 'Open Reports',
                                ) );
                            }
                            if ( ! in_array( $triage_connection_status, array( 'credential_invalid', 'disconnected' ), true ) ) {
                                $triage_add_action_card( array(
                                    'eyebrow' => 'Fresh evidence',
                                    'title'   => 'Run Security Scan again only when site conditions materially change',
                                    'copy'    => 'A fresh run is the honest way to refresh posture, evidence, and packaged outputs after a fix, a new issue, or a scheduled change window.',
                                    'url'     => self::admin_tab_url( 'triage' ),
                                    'label'   => 'Stay on Triage',
                                ) );
                            }
                            $triage_action_cards = array_slice( $triage_action_cards, 0, 4 );
                            $triage_primary_action = $triage_action_cards[0];
                            $triage_secondary_actions = array_slice( $triage_action_cards, 1 );
                            $triage_secondary_actions = array_slice( array_values( array_unique( $triage_secondary_actions, SORT_REGULAR ) ), 0, 3 );

                            $triage_run_visual_key = 'pending';
                            if ( 'QUEUED' === $state ) {
                                $triage_run_visual_key = 'queued';
                            } elseif ( 'RUNNING' === $state || $export_busy ) {
                                $triage_run_visual_key = 'in_progress';
                            } elseif ( 'FAILED' === $state || 'FAILED' === $export_state_upper ) {
                                $triage_run_visual_key = 'failed';
                            } elseif ( 'COMPLETED' === $state ) {
                                $triage_run_visual_key = 'completed';
                            }

                            $triage_run_visual_label = 'Waiting';
                            if ( 'queued' === $triage_run_visual_key ) {
                                $triage_run_visual_label = 'Queued';
                            } elseif ( 'in_progress' === $triage_run_visual_key ) {
                                $triage_run_visual_label = 'In progress';
                            } elseif ( 'failed' === $triage_run_visual_key ) {
                                $triage_run_visual_label = 'Needs review';
                            } elseif ( 'completed' === $triage_run_visual_key ) {
                                $triage_run_visual_label = 'Completed';
                            }

                            $triage_command_copy = $triage_live_progress_copy;
                            if ( ! $triage_connected_truth_available ) {
                                $triage_command_copy .= ' ' . $triage_connected_only_copy;
                            }

                            $triage_inventory_ready = $triage_connected_truth_available && ! empty( $inventory );
                            $triage_updates_ready = $triage_connected_truth_available && ! empty( $update_posture );
                            $triage_vulnerabilities_ready = $triage_connected_truth_available && ! empty( $vulnerability_posture );
                            $triage_reachability_ready = '' !== $reachability_label || '' !== $reachability_http_status || '' !== $reachability_duration_ms;
                            $triage_performance_ready = '' !== $performance_label || '' !== $performance_status_code || '' !== $performance_total_duration || '' !== $performance_first_byte;
                            $triage_reports_ready = 'COMPLETED' === $export_state_upper || ( 'COMPLETED' === $state && ! $export_busy );
                            $triage_complete_ready = 'COMPLETED' === $state && ! $export_busy && 'FAILED' !== $export_state_upper;

                            $triage_phase_items = array(
                                array(
                                    'step'    => 1,
                                    'key'     => 'queued',
                                    'label'   => 'Queued',
                                    'copy'    => 'Accepted behind the API and waiting on worker execution.',
                                    'ready'   => in_array( $state, array( 'QUEUED', 'RUNNING', 'FAILED', 'COMPLETED' ), true ) || $export_busy || 0 !== $triage_evidence_count,
                                    'blocked' => false,
                                ),
                                array(
                                    'step'    => 2,
                                    'key'     => 'inventory',
                                    'label'   => 'Inventory',
                                    'copy'    => $triage_connected_truth_available ? 'Authenticated WordPress inventory and footprint capture.' : $triage_connected_only_copy,
                                    'ready'   => $triage_inventory_ready,
                                    'blocked' => ! $triage_connected_truth_available,
                                ),
                                array(
                                    'step'    => 3,
                                    'key'     => 'updates',
                                    'label'   => 'Updates',
                                    'copy'    => $triage_connected_truth_available ? 'Version drift and package currency review.' : $triage_connected_only_copy,
                                    'ready'   => $triage_updates_ready,
                                    'blocked' => ! $triage_connected_truth_available,
                                ),
                                array(
                                    'step'    => 4,
                                    'key'     => 'vulnerabilities',
                                    'label'   => 'Vulnerabilities',
                                    'copy'    => $triage_connected_truth_available ? 'Recorded advisory and package exposure analysis.' : $triage_connected_only_copy,
                                    'ready'   => $triage_vulnerabilities_ready,
                                    'blocked' => ! $triage_connected_truth_available,
                                ),
                                array(
                                    'step'    => 5,
                                    'key'     => 'reachability',
                                    'label'   => 'Reachability',
                                    'copy'    => 'Public HTTP and transport posture checks.',
                                    'ready'   => $triage_reachability_ready,
                                    'blocked' => false,
                                ),
                                array(
                                    'step'    => 6,
                                    'key'     => 'performance',
                                    'label'   => 'Performance',
                                    'copy'    => 'Recorded latency and response timing snapshot.',
                                    'ready'   => $triage_performance_ready,
                                    'blocked' => false,
                                ),
                                array(
                                    'step'    => 7,
                                    'key'     => 'reports',
                                    'label'   => 'Report packaging',
                                    'copy'    => 'Rendered outputs linked to the current run.',
                                    'ready'   => $triage_reports_ready,
                                    'blocked' => false,
                                ),
                                array(
                                    'step'    => 8,
                                    'key'     => 'complete',
                                    'label'   => 'Complete',
                                    'copy'    => 'Run and package are ready for review or sharing.',
                                    'ready'   => $triage_complete_ready,
                                    'blocked' => false,
                                ),
                            );

                            $triage_phase_current_key = '';
                            if ( 'queued' === $triage_run_visual_key ) {
                                $triage_phase_current_key = 'queued';
                            } elseif ( 'in_progress' === $triage_run_visual_key ) {
                                if ( $export_busy ) {
                                    $triage_phase_current_key = 'reports';
                                } else {
                                    foreach ( $triage_phase_items as $triage_phase_item ) {
                                        if ( ! empty( $triage_phase_item['blocked'] ) ) {
                                            continue;
                                        }
                                        if ( empty( $triage_phase_item['ready'] ) ) {
                                            $triage_phase_current_key = (string) $triage_phase_item['key'];
                                            break;
                                        }
                                    }
                                    if ( '' === $triage_phase_current_key ) {
                                        $triage_phase_current_key = 'complete';
                                    }
                                }
                            } elseif ( 'failed' === $triage_run_visual_key ) {
                                if ( 'FAILED' === $export_state_upper ) {
                                    $triage_phase_current_key = 'reports';
                                } else {
                                    foreach ( $triage_phase_items as $triage_phase_item ) {
                                        if ( ! empty( $triage_phase_item['blocked'] ) ) {
                                            continue;
                                        }
                                        if ( empty( $triage_phase_item['ready'] ) ) {
                                            $triage_phase_current_key = (string) $triage_phase_item['key'];
                                            break;
                                        }
                                    }
                                    if ( '' === $triage_phase_current_key ) {
                                        $triage_phase_current_key = 'queued';
                                    }
                                }
                            }

                            $triage_phase_active_count   = 0;
                            $triage_phase_complete_count = 0;
                            $triage_progress_phase_copy  = 'Waiting for the next truthful run state.';
                            $triage_progress_phase_label = 'Waiting';
                            foreach ( $triage_phase_items as $triage_phase_index => $triage_phase_item ) {
                                $triage_phase_items[ $triage_phase_index ]['state'] = 'pending';
                                if ( ! empty( $triage_phase_item['blocked'] ) ) {
                                    $triage_phase_items[ $triage_phase_index ]['state'] = 'blocked';
                                    continue;
                                }
                                ++$triage_phase_active_count;
                                if ( 'completed' === $triage_run_visual_key ) {
                                    $triage_phase_items[ $triage_phase_index ]['state'] = 'complete';
                                    ++$triage_phase_complete_count;
                                    continue;
                                }
                                if ( (string) $triage_phase_item['key'] === $triage_phase_current_key ) {
                                    $triage_phase_items[ $triage_phase_index ]['state'] = 'failed' === $triage_run_visual_key ? 'failed' : 'current';
                                    $triage_progress_phase_label = (string) $triage_phase_item['label'];
                                    $triage_progress_phase_copy  = (string) $triage_phase_item['copy'];
                                    continue;
                                }
                                if ( ! empty( $triage_phase_item['ready'] ) ) {
                                    $triage_phase_items[ $triage_phase_index ]['state'] = 'complete';
                                    ++$triage_phase_complete_count;
                                }
                            }
                            if ( 'completed' === $triage_run_visual_key ) {
                                $triage_progress_phase_label = 'Complete';
                                $triage_progress_phase_copy  = 'Scan results and rendered outputs are ready for review.';
                            } elseif ( 'failed' === $triage_run_visual_key && '' === $triage_phase_current_key ) {
                                $triage_progress_phase_label = 'Needs review';
                                $triage_progress_phase_copy  = 'The latest run did not finish cleanly and should be reviewed before acting or sharing.';
                            } elseif ( 'failed' === $triage_run_visual_key && '' !== $triage_phase_current_key ) {
                                foreach ( $triage_phase_items as $triage_phase_item ) {
                                    if ( (string) $triage_phase_item['key'] === $triage_phase_current_key ) {
                                        $triage_progress_phase_label = (string) $triage_phase_item['label'];
                                        $triage_progress_phase_copy  = 'The scan stopped before this phase finished. Review the latest results before rerunning.';
                                        break;
                                    }
                                }
                            }
                            $triage_progress_percent = 0;
                            if ( $triage_phase_active_count > 0 ) {
                                $triage_progress_fraction = (float) $triage_phase_complete_count / (float) $triage_phase_active_count;
                                if ( 'queued' === $triage_run_visual_key ) {
                                    $triage_progress_fraction = max( $triage_progress_fraction, 0.08 );
                                } elseif ( 'in_progress' === $triage_run_visual_key ) {
                                    $triage_progress_fraction = min( 0.96, $triage_progress_fraction + ( $export_busy ? 0.16 : 0.08 ) );
                                } elseif ( 'failed' === $triage_run_visual_key ) {
                                    $triage_progress_fraction = min( 0.92, $triage_progress_fraction + 0.05 );
                                } elseif ( 'completed' === $triage_run_visual_key ) {
                                    $triage_progress_fraction = 1;
                                }
                                $triage_progress_percent = (int) round( 100 * $triage_progress_fraction );
                            }

                            $triage_progress_meter_label = sprintf( '%d%% of the current truthful run path is complete', $triage_progress_percent );
                            if ( ! $triage_connected_truth_available ) {
                                $triage_progress_meter_label .= '. Connected-only phases are blocked.';
                            }

                            $triage_live_snapshot_run_state = $triage_live_snapshot_ok ? strtoupper( trim( (string) ( $triage_live_snapshot['run_state'] ?? '' ) ) ) : '';
                            $triage_live_snapshot_export_state = $triage_live_snapshot_ok ? strtoupper( trim( (string) ( $triage_live_snapshot['export_state'] ?? '' ) ) ) : '';
                            $triage_live_snapshot_states = $triage_live_snapshot_ok && isset( $triage_live_snapshot['live_states'] ) && is_array( $triage_live_snapshot['live_states'] )
                                ? array_values(
                                    array_filter(
                                        array_map(
                                            static function ( $value ): string {
                                                return strtoupper( trim( (string) $value ) );
                                            },
                                            $triage_live_snapshot['live_states']
                                        )
                                    )
                                )
                                : array();
                            $triage_live_snapshot_active = ! empty(
                                array_filter(
                                    $triage_live_snapshot_states,
                                    static function ( string $state_value ): bool {
                                        return ! in_array( $state_value, array( 'COMPLETED', 'FAILED' ), true );
                                    }
                                )
                            );

                            if ( $triage_live_snapshot_ok && ( $triage_live_snapshot_active || in_array( $triage_live_snapshot_run_state, array( 'FAILED' ), true ) ) ) {
                                $triage_run_visual_key = isset( $triage_live_snapshot['run_visual_key'] ) ? (string) $triage_live_snapshot['run_visual_key'] : $triage_run_visual_key;
                                if ( 'queued' === $triage_run_visual_key ) {
                                    $triage_run_visual_label = 'Queued';
                                } elseif ( 'in_progress' === $triage_run_visual_key ) {
                                    $triage_run_visual_label = 'In progress';
                                } elseif ( 'failed' === $triage_run_visual_key ) {
                                    $triage_run_visual_label = 'Needs review';
                                } elseif ( 'completed' === $triage_run_visual_key ) {
                                    $triage_run_visual_label = 'Completed';
                                } else {
                                    $triage_run_visual_label = 'Waiting';
                                }

                                $triage_live_progress_tone = isset( $triage_live_snapshot['progress_tone'] ) ? (string) $triage_live_snapshot['progress_tone'] : $triage_live_progress_tone;
                                $triage_live_progress_title = isset( $triage_live_snapshot['progress_title'] ) ? (string) $triage_live_snapshot['progress_title'] : $triage_live_progress_title;
                                $triage_command_copy = isset( $triage_live_snapshot['progress_copy'] ) ? (string) $triage_live_snapshot['progress_copy'] : $triage_command_copy;
                                if ( $triage_live_snapshot_active && ! empty( $latest['ok'] ) ) {
                                    $triage_command_copy .= ' The previous completed run remains available below until this live run settles.';
                                }
                                $triage_progress_percent = isset( $triage_live_snapshot['progress_percent'] ) ? (int) $triage_live_snapshot['progress_percent'] : $triage_progress_percent;
                                $triage_progress_phase_label = isset( $triage_live_snapshot['progress_phase_label'] ) ? (string) $triage_live_snapshot['progress_phase_label'] : $triage_progress_phase_label;
                                $triage_progress_phase_copy = isset( $triage_live_snapshot['progress_phase_copy'] ) ? (string) $triage_live_snapshot['progress_phase_copy'] : $triage_progress_phase_copy;
                                $triage_progress_meter_label = isset( $triage_live_snapshot['progress_meter_label'] ) ? (string) $triage_live_snapshot['progress_meter_label'] : $triage_progress_meter_label;
                                $triage_elapsed_label = isset( $triage_live_snapshot['elapsed_label'] ) ? (string) $triage_live_snapshot['elapsed_label'] : $triage_elapsed_label;
                                $triage_evidence_state = isset( $triage_live_snapshot['evidence_label'] ) ? (string) $triage_live_snapshot['evidence_label'] : $triage_evidence_state;

                                if ( isset( $triage_live_snapshot['phase_items'] ) && is_array( $triage_live_snapshot['phase_items'] ) ) {
                                    $triage_phase_states = array();
                                    foreach ( $triage_live_snapshot['phase_items'] as $triage_live_phase_item ) {
                                        if ( ! is_array( $triage_live_phase_item ) ) {
                                            continue;
                                        }
                                        $triage_live_phase_key = isset( $triage_live_phase_item['key'] ) ? (string) $triage_live_phase_item['key'] : '';
                                        if ( '' === $triage_live_phase_key ) {
                                            continue;
                                        }
                                        $triage_phase_states[ $triage_live_phase_key ] = array(
                                            'state' => isset( $triage_live_phase_item['state'] ) ? (string) $triage_live_phase_item['state'] : 'pending',
                                            'state_label' => isset( $triage_live_phase_item['state_label'] ) ? (string) $triage_live_phase_item['state_label'] : 'Waiting',
                                        );
                                    }
                                    foreach ( $triage_phase_items as $triage_phase_index => $triage_phase_item ) {
                                        $triage_phase_key = isset( $triage_phase_item['key'] ) ? (string) $triage_phase_item['key'] : '';
                                        if ( '' === $triage_phase_key || ! isset( $triage_phase_states[ $triage_phase_key ] ) ) {
                                            continue;
                                        }
                                        $triage_phase_items[ $triage_phase_index ]['state'] = $triage_phase_states[ $triage_phase_key ]['state'];
                                        $triage_phase_items[ $triage_phase_index ]['state_label'] = $triage_phase_states[ $triage_phase_key ]['state_label'];
                                    }
                                }
                            }

                            $triage_posture_meta_items = array_filter(
                                array(
                                    $triage_grade_summary,
                                    $triage_current_freshness,
                                    $triage_evidence_state,
                                )
                            );
                            $triage_live_unsettled = in_array( $triage_run_visual_key, array( 'queued', 'in_progress', 'failed' ), true );
                            $triage_display_grade_summary = $triage_grade_summary;
                            $triage_display_grade_tone = $triage_grade_tone;
                            $triage_posture_panel_tone = $triage_grade_tone;
                            $triage_posture_score_display = null !== $score ? (string) $score : '—';
                            $triage_display_current_title = $triage_current_title;
                            $triage_display_current_copy = $triage_current_copy;
                            $triage_display_posture_meta_items = $triage_posture_meta_items;
                            $triage_display_assessment_tags = $triage_assessment_tags;

                            if ( $triage_live_unsettled ) {
                                if ( 'failed' === $triage_run_visual_key ) {
                                    $triage_display_grade_summary = 'Needs review';
                                    $triage_display_grade_tone = 'bad';
                                    $triage_posture_panel_tone = 'bad';
                                    $triage_posture_score_display = '!';
                                    $triage_display_current_title = sprintf( 'The live run needs review for %s', $triage_scope_label );
                                    $triage_display_current_copy = 'This scan did not settle cleanly, so OpsGate is not replacing the previous scan results yet. Review the failed run detail before sharing or acting.';
                                } else {
                                    $triage_display_grade_summary = 'Scan in progress';
                                    $triage_display_grade_tone = 'neutral';
                                    $triage_posture_panel_tone = 'warn';
                                    $triage_posture_score_display = '…';
                                    $triage_display_current_title = sprintf( 'Security scan in progress for %s', $triage_scope_label );
                                    $triage_display_current_copy = 'OpsGate is still running this scan. The previous completed results stay below for reference until the scan settles.';
                                }

                                $triage_display_posture_meta_items = array_filter(
                                    array(
                                        $triage_run_visual_label,
                                        $triage_elapsed_label,
                                        $triage_evidence_state,
                                    )
                                );
                                $triage_display_assessment_tags = array(
                                    $triage_run_visual_label,
                                    $triage_evidence_state,
                                    'Previous completed assessment remains below',
                                );
                            }

                            $triage_context_items = array(
                                array(
                                    'label' => 'Site scope',
                                    'value' => $triage_scope_label,
                                    'meta'  => $triage_scope_meta,
                                ),
                                array(
                                    'label' => 'Connection path',
                                    'value' => $triage_connection_label . ' / ' . $triage_connection_mode_label,
                                    'meta'  => $triage_connection_copy,
                                ),
                                array(
                                    'label' => 'Run freshness',
                                    'value' => $triage_current_freshness,
                                    'meta'  => $triage_elapsed_label,
                                ),
                                array(
                                    'label' => 'Report',
                                    'value' => $export_busy ? 'Packaging in progress' : ( 'COMPLETED' === $state ? 'Ready for review' : 'Waiting for next completed run' ),
                                    'meta'  => $export_busy ? $export_copy : $triage_run_reference,
                                ),
                            );

                            $triage_priority_driver_cards = array_slice( $triage_driver_cards, 0, 3 );
                            if ( empty( $triage_priority_driver_cards ) ) {
                                $triage_priority_driver_cards[] = array(
                                    'tone'  => 'good',
                                    'label' => 'Recorded drivers',
                                    'title' => 'No immediate pressure recorded',
                                    'copy'  => 'The latest canonical run did not record active pressure on this site.',
                                    'facts' => array(
                                        'Freshness: ' . $triage_current_freshness,
                                        'Evidence state: ' . $triage_evidence_state,
                                        'Scope: ' . $triage_scope_label,
                                    ),
                                );
                            }

                            $triage_evidence_dimensions = array(
                                array(
                                    'label' => 'Inventory',
                                    'value' => $triage_connected_truth_available ? ( '' !== $inventory_core ? 'Core ' . $inventory_core : 'Inventory recorded' ) : $triage_connected_only_value,
                                    'copy'  => $triage_connected_truth_available ? $triage_inventory_copy : $triage_connected_only_copy,
                                    'meta'  => $triage_connected_truth_available ? $triage_inventory_meta : $triage_connection_copy,
                                    'tone'  => $triage_connected_truth_available ? 'foundation' : 'blocked',
                                    'href'  => '',
                                    'link'  => '',
                                ),
                                array(
                                    'label' => 'Updates',
                                    'value' => $triage_connected_truth_available ? (string) $update_outdated_total : $triage_connected_only_value,
                                    'copy'  => $triage_connected_truth_available ? ( $update_outdated_total > 0 ? 'Version drift is contributing to current posture.' : 'No update pressure was recorded in this run.' ) : $triage_connected_only_copy,
                                    'meta'  => $triage_connected_truth_available ? $triage_update_meta : $triage_connection_copy,
                                    'tone'  => $triage_connected_truth_available ? ( $update_outdated_total > 0 ? 'warn' : 'neutral' ) : 'blocked',
                                    'href'  => $triage_connected_truth_available ? self::detail_surface_url( 'triage', 'updates' ) . '#opsgate-evidence-detail' : '',
                                    'detail_key' => $triage_connected_truth_available ? 'updates' : '',
                                    'link'  => $triage_connected_truth_available ? 'Open update evidence' : '',
                                ),
                                array(
                                    'label' => 'Vulnerabilities',
                                    'value' => $triage_connected_truth_available ? $triage_vulnerability_value : $triage_connected_only_value,
                                    'copy'  => $triage_connected_truth_available ? $triage_vulnerability_copy : $triage_connected_only_copy,
                                    'meta'  => $triage_connected_truth_available ? $triage_vulnerability_meta : $triage_connection_copy,
                                    'tone'  => $triage_connected_truth_available ? ( $triage_vulnerability_match_total > 0 ? 'bad' : ( $triage_vulnerability_unresolved_total > 0 || $triage_vulnerability_coverage_limited ? 'warn' : 'neutral' ) ) : 'blocked',
                                    'href'  => $triage_connected_truth_available ? self::detail_surface_url( 'triage', 'vulnerabilities' ) . '#opsgate-evidence-detail' : '',
                                    'detail_key' => $triage_connected_truth_available ? 'vulnerabilities' : '',
                                    'link'  => $triage_connected_truth_available ? 'Open vulnerability evidence' : '',
                                ),
                                array(
                                    'label' => 'Reachability',
                                    'value' => '' !== $reachability_label ? ucfirst( strtolower( $reachability_label ) ) : 'Not recorded',
                                    'copy'  => $reachability_is_bad ? 'Live reachability failed during the recorded run.' : 'Live reachability completed during the recorded run.',
                                    'meta'  => $triage_reachability_copy . ' · ' . $triage_reachability_meta,
                                    'tone'  => $reachability_is_bad ? 'bad' : 'neutral',
                                    'href'  => '',
                                    'link'  => '',
                                ),
                                array(
                                    'label' => 'Availability',
                                    'value' => '' !== $availability_label ? ucfirst( strtolower( $availability_label ) ) : 'Not recorded',
                                    'copy'  => $availability_is_bad ? 'Availability probes showed instability.' : 'Availability probes remained stable in the recorded window.',
                                    'meta'  => $triage_availability_copy . ' · ' . $triage_availability_meta,
                                    'tone'  => $availability_is_bad ? 'warn' : 'neutral',
                                    'href'  => '',
                                    'link'  => '',
                                ),
                                array(
                                    'label' => 'Uptime over time',
                                    'value' => $triage_uptime_value,
                                    'copy'  => $triage_uptime_copy,
                                    'meta'  => $triage_uptime_meta,
                                    'tone'  => $uptime_failure_count > 0 ? 'warn' : 'neutral',
                                    'href'  => self::detail_surface_url( 'triage', 'uptime' ) . '#opsgate-evidence-detail',
                                    'detail_key' => 'uptime',
                                    'link'  => 'Open uptime history',
                                ),
                                array(
                                    'label' => 'Performance',
                                    'value' => $triage_performance_value,
                                    'copy'  => $performance_is_bad ? 'Latency is outside target for this run.' : 'Performance stayed within the expected range for this run.',
                                    'meta'  => $triage_performance_copy,
                                    'tone'  => $performance_is_bad ? 'warn' : 'neutral',
                                    'href'  => '',
                                    'link'  => '',
                                ),
                                array(
                                    'label' => 'Validation',
                                    'value' => $triage_connected_truth_available ? $triage_validation_value : $triage_connected_only_value,
                                    'copy'  => $triage_connected_truth_available ? $triage_validation_copy : $triage_connected_only_copy,
                                    'meta'  => $triage_connected_truth_available ? $triage_validation_meta : $triage_connection_copy,
                                    'tone'  => $triage_connected_truth_available ? ( $configuration_validation_findings > 0 ? 'warn' : 'neutral' ) : 'blocked',
                                    'href'  => $triage_connected_truth_available ? self::detail_surface_url( 'triage', 'validation' ) . '#opsgate-evidence-detail' : '',
                                    'detail_key' => $triage_connected_truth_available ? 'validation' : '',
                                    'link'  => $triage_connected_truth_available ? 'Open validation findings' : '',
                                ),
                                array(
                                    'label' => 'Log intelligence',
                                    'value' => $triage_connected_truth_available ? $triage_log_value : $triage_connected_only_value,
                                    'copy'  => $triage_connected_truth_available ? $triage_log_copy : $triage_connected_only_copy,
                                    'meta'  => $triage_connected_truth_available ? $triage_log_meta : $triage_connection_copy,
                                    'tone'  => $triage_connected_truth_available ? ( $operational_log_signal_count > 0 ? 'warn' : 'neutral' ) : 'blocked',
                                    'href'  => $triage_connected_truth_available ? self::detail_surface_url( 'triage', 'logs' ) . '#opsgate-evidence-detail' : '',
                                    'detail_key' => $triage_connected_truth_available ? 'logs' : '',
                                    'link'  => $triage_connected_truth_available ? 'Open log signals' : '',
                                ),
                                array(
                                    'label' => 'Smoke check',
                                    'value' => $triage_safe_update_value,
                                    'copy'  => $safe_update_needs_attention ? 'Preflight checks are asking for follow-up.' : 'No smoke-check pressure was recorded.',
                                    'meta'  => $triage_safe_update_copy,
                                    'tone'  => $safe_update_needs_attention ? 'warn' : 'neutral',
                                    'href'  => '',
                                    'link'  => '',
                                ),
                                array(
                                    'label' => 'Hardening guidance',
                                    'value' => $hardening_guidance_title,
                                    'copy'  => $hardening_guidance_copy,
                                    'meta'  => isset( $hardening_summary['support_boundary_copy'] ) ? (string) $hardening_summary['support_boundary_copy'] : 'OpsGate records guidance and evidence, but it does not silently apply risky changes.',
                                    'tone'  => ( $hardening_guidance_count > 0 && in_array( $hardening_guidance_state, array( 'action_required', 'review_required' ), true ) ) ? ( 'action_required' === $hardening_guidance_state ? 'bad' : 'warn' ) : ( $hardening_guidance_count > 0 ? 'good' : 'neutral' ),
                                    'href'  => $hardening_guidance_count > 0 ? self::detail_surface_url( 'triage', 'hardening' ) . '#opsgate-evidence-detail' : '',
                                    'detail_key' => $hardening_guidance_count > 0 ? 'hardening' : '',
                                    'link'  => $hardening_guidance_count > 0 ? 'Open hardening guidance' : '',
                                ),
                            );

                            $triage_evidence_groups = array(
                                array(
                                    'title'   => 'Connected foundation',
                                    'summary' => $triage_connected_truth_available ? 'Authenticated inventory plus public footprint define the current baseline for this site.' : 'Public assessment is available, but connected WordPress truth is blocked until the connector trust path is ready.',
                                    'items'   => array(
                                        $triage_evidence_dimensions[0],
                                        $triage_evidence_dimensions[3],
                                        $triage_evidence_dimensions[4],
                                        $triage_evidence_dimensions[5],
                                    ),
                                ),
                                array(
                                    'title'   => 'Change pressure',
                                    'summary' => 'Version drift, advisory exposure, host validation, smoke checks, and recorded hardening guidance show whether operational change pressure is building.',
                                    'items'   => array(
                                        $triage_evidence_dimensions[1],
                                        $triage_evidence_dimensions[2],
                                        $triage_evidence_dimensions[7],
                                        $triage_evidence_dimensions[9],
                                        $triage_evidence_dimensions[10],
                                    ),
                                ),
                                array(
                                    'title'   => 'Operational continuity',
                                    'summary' => 'Recent uptime history, runtime signal normalization, and public performance show whether current issues are transient or persistent.',
                                    'items'   => array(
                                        $triage_evidence_dimensions[6],
                                        $triage_evidence_dimensions[8],
                                    ),
                                ),
                            );

                            $triage_command_context_note = $triage_run_reference . ' · Trigger ' . $triage_trigger_label;

                            $triage_reference_modules = array(
                                array(
                                    'title'   => 'Security score',
                                    'summary' => 'How OpsGate calculates and displays the site security score.',
                                    'items'   => array(
                                        'The score reflects findings from the most recent completed scan for this site.',
                                        'Each category — vulnerabilities, updates, reachability, availability, and configuration — contributes to the overall score.',
                                        'The driver cards highlight the highest-priority issues first so you can focus your review where it matters most.',
                                        'A green score means no significant issues were found in the latest scan, not that the site is permanently secure.',
                                        'The scan date shown below the score tells you how fresh the results are before you act or share them with a client.',
                                    ),
                                ),
                                array(
                                    'title'   => 'Scan progress',
                                    'summary' => 'What the progress bar and phase steps mean while a scan is running.',
                                    'items'   => array(
                                        'Queued means the scan has been submitted and is waiting to start.',
                                        'Each phase — Inventory, Updates, Vulnerabilities, Reachability, Performance, and Report — only advances when that check is actually complete.',
                                        'If report generation is still running, the scan stays active until the client-ready package is finished.',
                                        'A failed phase means the scan stopped before that check completed. Review the details before sharing results with a client.',
                                    ),
                                ),
                                array(
                                    'title'   => 'Scans and reports',
                                    'summary' => 'The difference between a scan and a downloadable report.',
                                    'items'   => array(
                                        'A scan collects the findings. A report packages those findings into a shareable format for your client.',
                                        'Reports are generated from scan data — PDF, HTML, CSV, and Excel formats are available from the Reports tab.',
                                        'Generating a report does not change the scan results. The underlying findings remain on record.',
                                    ),
                                ),
                                array(
                                    'title'   => 'Vulnerability checks',
                                    'summary' => 'How to interpret plugin vulnerability results.',
                                    'items'   => array(
                                        'OpsGate checks each installed plugin version against a live vulnerability database.',
                                        'Unresolved items mean a plugin could not be fully matched — this is flagged for manual review rather than assumed safe.',
                                        'Zero vulnerabilities means all checked plugins were reviewed and no known issues were found for the installed versions.',
                                        'When vulnerabilities are found, review the severity, the affected version, and whether an update is available to resolve the issue.',
                                    ),
                                ),
                                array(
                                    'title'   => 'Configuration, uptime, and logs',
                                    'summary' => 'What the operational checks cover beyond vulnerabilities.',
                                    'items'   => array(
                                        'Configuration validation checks .htaccess rules and folder structure for security issues.',
                                        'Uptime over time shows whether OpsGate has observed any availability failures in the recent monitoring window.',
                                        'Log analysis surfaces patterns from WordPress and WooCommerce logs when they are accessible — it highlights issues rather than dumping raw log data.',
                                        'When these checks are all clear, the site showed no hidden operational issues behind the headline score.',
                                    ),
                                ),
                                array(
                                    'title'   => 'Remediation guidance',
                                    'summary' => 'How to act on issues found during the scan.',
                                    'items'   => array(
                                        'Each guidance item explains what was found, why it matters, and what action is recommended.',
                                        'OpsGate does not mark an issue as resolved until a follow-up scan confirms the fix is in place.',
                                        'Sensitive WordPress or hosting changes are flagged for review first — OpsGate does not apply them automatically.',
                                        'Use the Reports tab to package and share remediation findings with your client after completing your review.',
                                    ),
                                ),
                                array(
                                    'title'   => 'Connection modes',
                                    'summary' => 'What OpsGate can check depending on how the site is connected.',
                                    'items'   => array(
                                        'External-only mode runs public checks — reachability, availability, and performance — without needing a connector.',
                                        'Connected mode adds authenticated checks — installed plugins, theme versions, update status, and vulnerability matching.',
                                        'If a phase shows as blocked, it means that check requires a connected site. Complete the connector setup in Settings to unlock it.',
                                    ),
                                ),
                                array(
                                    'title'   => 'Alerts and notifications',
                                    'summary' => 'When OpsGate sends alerts and what triggers them.',
                                    'items'   => array(
                                        'Alerts are scoped to this site and tied to scan results.',
                                        'Vulnerability alerts fire when a new vulnerable plugin is found or when a vulnerability state changes.',
                                        'Healthy scans with no changes do not generate repeat alerts.',
                                        'Configure alert destinations in the Alerts tab. Delivery history is visible there without affecting the scan results shown here.',
                                    ),
                                ),
                            );
                            ?>
                            <div class="opsgate-card opsgate-triage-dashboard">
                                <section class="opsgate-triage-command-deck opsgate-triage-command-deck-<?php echo esc_attr( $triage_live_progress_tone ); ?>" data-opsgate-triage-command-deck="1">
                                    <div class="opsgate-triage-command-main" data-opsgate-triage-command-main="1">
                                        <div class="opsgate-triage-command-head">
                                            <span class="opsgate-triage-eyebrow">Live security scan</span>
                                            <div class="opsgate-triage-pill-row">
                                                <span class="opsgate-triage-pill opsgate-triage-pill-<?php echo esc_attr( $triage_live_progress_tone ); ?>" data-opsgate-triage-run-pill="1"><?php echo esc_html( $triage_run_visual_label ); ?></span>
                                                <span class="opsgate-triage-pill opsgate-triage-pill-soft-<?php echo esc_attr( $triage_display_grade_tone ); ?>"><?php echo esc_html( $triage_display_grade_summary ); ?></span>
                                                <span class="opsgate-triage-pill opsgate-triage-pill-soft-neutral"><?php echo esc_html( $triage_connection_label ); ?></span>
                                            </div>
                                        </div>

                                        <div class="opsgate-triage-progress-shell">
                                            <div class="opsgate-triage-progress-main">
                                                <h2 class="opsgate-triage-command-title" data-opsgate-triage-progress-title="1"><?php echo esc_html( $triage_live_progress_title ); ?></h2>
                                                <p class="opsgate-triage-command-copy" data-opsgate-triage-progress-copy="1"><?php echo esc_html( $triage_command_copy ); ?></p>
                                                <div class="opsgate-triage-progress-meter" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="<?php echo esc_attr( (string) $triage_progress_percent ); ?>" aria-label="<?php echo esc_attr( $triage_progress_meter_label ); ?>" data-opsgate-triage-progress-meter="1">
                                                    <span class="opsgate-triage-progress-meter-fill" data-opsgate-triage-progress-fill="1" style="width: <?php echo esc_attr( (string) $triage_progress_percent ); ?>%;"></span>
                                                </div>
                                                <div class="opsgate-triage-progress-summary">
                                                    <strong data-opsgate-triage-progress-phase="1"><?php echo esc_html( $triage_progress_phase_label ); ?></strong>
                                                    <span data-opsgate-triage-progress-elapsed="1"><?php echo esc_html( $triage_elapsed_label ); ?></span>
                                                    <span data-opsgate-triage-progress-evidence="1"><?php echo esc_html( $triage_evidence_state ); ?></span>
                                                </div>
                                            </div>
                                            <aside class="opsgate-triage-progress-aside">
                                                <span class="opsgate-triage-eyebrow">Current phase</span>
                                                <div class="opsgate-triage-progress-aside-title" data-opsgate-triage-aside-title="1"><?php echo esc_html( $triage_progress_phase_label ); ?></div>
                                                <p class="opsgate-triage-progress-aside-copy" data-opsgate-triage-aside-copy="1"><?php echo esc_html( $triage_progress_phase_copy ); ?></p>
                                                <?php if ( ! $triage_connected_truth_available ) : ?>
                                                    <div class="opsgate-triage-progress-block-note"><?php echo esc_html( $triage_connected_only_copy ); ?></div>
                                                <?php endif; ?>
                                            </aside>
                                        </div>

                                        <?php
                                        $triage_phase_accent_map = array(
                                            'queued'          => 'queue',
                                            'inventory'       => 'inventory',
                                            'updates'         => 'updates',
                                            'vulnerabilities' => 'vulnerabilities',
                                            'reachability'    => 'reachability',
                                            'performance'     => 'performance',
                                            'reports'         => 'reports',
                                            'complete'        => 'complete',
                                        );
                                        $triage_phase_state_labels = array(
                                            'pending'  => 'Waiting',
                                            'current'  => 'Active now',
                                            'complete' => 'Complete',
                                            'failed'   => 'Needs review',
                                            'blocked'  => 'Blocked',
                                        );
                                        ?>
                                        <ol class="opsgate-triage-phase-track" aria-label="Run progress phases">
                                            <?php foreach ( $triage_phase_items as $triage_phase_item ) : ?>
                                                <?php
                                                $triage_phase_key = (string) ( $triage_phase_item['key'] ?? '' );
                                                $triage_phase_state = (string) ( $triage_phase_item['state'] ?? 'pending' );
                                                $triage_phase_accent = isset( $triage_phase_accent_map[ $triage_phase_key ] ) ? $triage_phase_accent_map[ $triage_phase_key ] : 'queue';
                                                $triage_phase_state_label = isset( $triage_phase_state_labels[ $triage_phase_state ] ) ? $triage_phase_state_labels[ $triage_phase_state ] : 'Waiting';
                                                ?>
                                                <li class="opsgate-triage-phase-chip opsgate-triage-phase-chip-accent-<?php echo esc_attr( $triage_phase_accent ); ?> is-<?php echo esc_attr( $triage_phase_state ); ?>" data-opsgate-triage-phase-key="<?php echo esc_attr( $triage_phase_key ); ?>">
                                                    <span class="opsgate-triage-phase-chip-step"><?php echo esc_html( (string) ( $triage_phase_item['step'] ?? '' ) ); ?></span>
                                                    <div class="opsgate-triage-phase-chip-copy">
                                                        <div class="opsgate-triage-phase-chip-head">
                                                            <strong><?php echo esc_html( (string) $triage_phase_item['label'] ); ?></strong>
                                                            <span class="opsgate-triage-phase-chip-status" data-opsgate-triage-phase-status="1"><?php echo esc_html( $triage_phase_state_label ); ?></span>
                                                        </div>
                                                        <span><?php echo esc_html( (string) $triage_phase_item['copy'] ); ?></span>
                                                    </div>
                                                </li>
                                            <?php endforeach; ?>
                                        </ol>
                                    </div>

                                    <aside class="opsgate-triage-command-side">
                                        <article class="opsgate-triage-posture-panel opsgate-triage-posture-panel-<?php echo esc_attr( $triage_posture_panel_tone ); ?>">
                                            <span class="opsgate-triage-eyebrow">Current status</span>
                                            <div class="opsgate-triage-posture-top">
                                                <div class="opsgate-triage-posture-score"><?php echo esc_html( $triage_posture_score_display ); ?></div>
                                                <div class="opsgate-triage-posture-copy">
                                                    <h3 class="opsgate-triage-posture-title"><?php echo esc_html( $triage_display_current_title ); ?></h3>
                                                    <p class="opsgate-triage-posture-note"><?php echo esc_html( $triage_display_current_copy ); ?></p>
                                                </div>
                                            </div>
                                            <div class="opsgate-triage-posture-meta-row">
                                                <?php foreach ( $triage_display_posture_meta_items as $triage_posture_meta_item ) : ?>
                                                    <span class="opsgate-triage-posture-meta-chip"><?php echo esc_html( (string) $triage_posture_meta_item ); ?></span>
                                                <?php endforeach; ?>
                                            </div>
                                            <ul class="opsgate-triage-posture-list">
                                                <?php foreach ( array_slice( $triage_display_assessment_tags, 0, 3 ) as $triage_assessment_tag ) : ?>
                                                    <li><?php echo esc_html( (string) $triage_assessment_tag ); ?></li>
                                                <?php endforeach; ?>
                                            </ul>
                                        </article>

                                        <section class="opsgate-triage-surface opsgate-triage-action-surface">
                                            <div class="opsgate-triage-surface-header">
                                                <h3 class="opsgate-triage-surface-title">What to do next</h3>
                                                <span class="opsgate-triage-surface-link">Decision surface</span>
                                            </div>
                                            <article class="opsgate-triage-action-spotlight">
                                                <span class="opsgate-triage-eyebrow"><?php echo esc_html( (string) $triage_primary_action['eyebrow'] ); ?></span>
                                                <div class="opsgate-triage-action-spotlight-title"><?php echo esc_html( (string) $triage_primary_action['title'] ); ?></div>
                                                <p class="opsgate-triage-action-spotlight-copy"><?php echo esc_html( (string) $triage_primary_action['copy'] ); ?></p>
                                                <div class="opsgate-triage-action-spotlight-actions">
                                                    <a class="button button-primary opsgate-triage-action-primary" href="<?php echo esc_url( (string) $triage_primary_action['url'] ); ?>"><?php echo esc_html( (string) $triage_primary_action['label'] ); ?></a>
                                                    <a class="button button-secondary opsgate-triage-action-link" href="<?php echo esc_url( $refresh_url ); ?>">Refresh run status</a>
                                                </div>
                                            </article>
                                        </section>
                                    </aside>

                                    <?php if ( ! empty( $triage_secondary_actions ) ) : ?>
                                    <div class="opsgate-triage-action-grid-fullwidth">
                                        <?php foreach ( $triage_secondary_actions as $triage_secondary_action ) : ?>
                                            <article class="opsgate-triage-action-grid-card">
                                                <span class="opsgate-triage-eyebrow"><?php echo esc_html( (string) $triage_secondary_action['eyebrow'] ); ?></span>
                                                <div class="opsgate-triage-action-list-title"><?php echo esc_html( (string) $triage_secondary_action['title'] ); ?></div>
                                                <p class="opsgate-triage-action-list-copy"><?php echo esc_html( (string) $triage_secondary_action['copy'] ); ?></p>
                                                <a class="button button-secondary opsgate-triage-download-button" href="<?php echo esc_url( (string) $triage_secondary_action['url'] ); ?>"><?php echo esc_html( (string) $triage_secondary_action['label'] ); ?></a>
                                            </article>
                                        <?php endforeach; ?>
                                    </div>
                                    <?php endif; ?>

                                    <div class="opsgate-triage-command-context-row">
                                        <?php foreach ( $triage_context_items as $triage_context_item ) : ?>
                                            <article class="opsgate-triage-command-context-item">
                                                <span class="opsgate-triage-command-meta-label"><?php echo esc_html( (string) $triage_context_item['label'] ); ?></span>
                                                <strong><?php echo esc_html( (string) $triage_context_item['value'] ); ?></strong>
                                                <span class="opsgate-triage-command-context-meta"><?php echo esc_html( (string) $triage_context_item['meta'] ); ?></span>
                                            </article>
                                        <?php endforeach; ?>
                                    </div>
                                    <p class="opsgate-triage-command-context-note"><?php echo esc_html( $triage_command_context_note ); ?></p>
                                </section>

                                <div class="opsgate-triage-workspace">
                                    <section class="opsgate-triage-surface opsgate-triage-assessment-workspace">
                                        <div class="opsgate-triage-surface-header">
                                            <h3 class="opsgate-triage-surface-title">Site Findings</h3>
                                            <span class="opsgate-triage-surface-link">Why the site looks like this</span>
                                        </div>
                                        <p class="opsgate-triage-section-intro"><?php echo esc_html( $triage_explanation_copy ); ?></p>

                                        <div class="opsgate-triage-driver-grid opsgate-triage-driver-grid-priority">
                                            <?php foreach ( $triage_priority_driver_cards as $triage_driver_card ) : ?>
                                                <?php
                                                $triage_driver_class = 'opsgate-triage-driver-card';
                                                if ( in_array( (string) $triage_driver_card['tone'], array( 'good', 'warn', 'bad' ), true ) ) {
                                                    $triage_driver_class .= ' is-' . (string) $triage_driver_card['tone'];
                                                }
                                                if ( in_array( (string) $triage_driver_card['tone'], array( 'warn', 'bad' ), true ) ) {
                                                    $triage_driver_class .= ' is-priority';
                                                }
                                                ?>
                                                <article class="<?php echo esc_attr( $triage_driver_class ); ?>">
                                                    <span class="opsgate-triage-eyebrow"><?php echo esc_html( (string) $triage_driver_card['label'] ); ?></span>
                                                    <div class="opsgate-triage-driver-title"><?php echo esc_html( (string) $triage_driver_card['title'] ); ?></div>
                                                    <p class="opsgate-triage-driver-copy"><?php echo esc_html( (string) $triage_driver_card['copy'] ); ?></p>
                                                    <ul class="opsgate-triage-driver-facts">
                                                        <?php foreach ( array_slice( (array) $triage_driver_card['facts'], 0, 3 ) as $triage_driver_fact ) : ?>
                                                            <li><?php echo esc_html( (string) $triage_driver_fact ); ?></li>
                                                        <?php endforeach; ?>
                                                    </ul>
                                                </article>
                                            <?php endforeach; ?>
                                        </div>

                                        <div class="opsgate-triage-assessment-grid opsgate-triage-capability-grid">
                                            <?php foreach ( $triage_capability_cards as $triage_capability_card ) : ?>
                                                <?php
                                                $triage_capability_card_class = 'opsgate-triage-assessment-card';
                                                if ( ! empty( $triage_capability_card['tone'] ) && in_array( (string) $triage_capability_card['tone'], array( 'good', 'warn', 'bad' ), true ) ) {
                                                    $triage_capability_card_class .= ' is-' . (string) $triage_capability_card['tone'];
                                                }
                                                ?>
                                                <article class="<?php echo esc_attr( $triage_capability_card_class ); ?>">
                                                    <span class="opsgate-triage-eyebrow"><?php echo esc_html( (string) $triage_capability_card['label'] ); ?></span>
                                                    <div class="opsgate-triage-assessment-card-title"><?php echo esc_html( (string) $triage_capability_card['title'] ); ?></div>
                                                    <?php if ( ! empty( $triage_capability_card['signals'] ) ) : ?>
                                                        <div class="opsgate-triage-proof-badge-row">
                                                            <?php foreach ( array_slice( array_values( array_filter( array_map( 'strval', (array) $triage_capability_card['signals'] ) ) ), 0, 4 ) as $triage_capability_signal ) : ?>
                                                                <span class="opsgate-triage-proof-badge"><?php echo esc_html( $triage_capability_signal ); ?></span>
                                                            <?php endforeach; ?>
                                                        </div>
                                                    <?php endif; ?>
                                                    <p class="opsgate-triage-assessment-card-summary"><?php echo esc_html( (string) $triage_capability_card['summary'] ); ?></p>
                                                    <?php if ( ! empty( $triage_capability_card['facts'] ) ) : ?>
                                                        <ul class="opsgate-triage-card-facts">
                                                            <?php foreach ( array_slice( array_values( array_filter( array_map( 'strval', (array) $triage_capability_card['facts'] ) ) ), 0, 4 ) as $triage_capability_fact ) : ?>
                                                                <li><?php echo esc_html( $triage_capability_fact ); ?></li>
                                                            <?php endforeach; ?>
                                                        </ul>
                                                    <?php endif; ?>
                                                    <?php if ( ! empty( $triage_capability_card['href'] ) && ! empty( $triage_capability_card['link'] ) ) : ?>
                                                        <a class="opsgate-triage-inline-link opsgate-triage-capability-link" href="<?php echo esc_url( (string) $triage_capability_card['href'] ); ?>"<?php echo ! empty( $triage_capability_card['detail_key'] ) ? ' data-opsgate-triage-detail-link="' . esc_attr( (string) $triage_capability_card['detail_key'] ) . '"' : ''; ?>><?php echo esc_html( (string) $triage_capability_card['link'] ); ?></a>
                                                    <?php endif; ?>
                                                </article>
                                            <?php endforeach; ?>
                                        </div>

                                        <details class="opsgate-r1-help-panel opsgate-triage-evidence-help">
                                            <summary>Evidence dimensions — what each category means</summary>
                                            <div class="opsgate-r1-help-panel-body">
                                                <dl class="opsgate-r1-help-dl">
                                                    <dt>Vulnerabilities</dt><dd>Live plugin advisory matches against the recorded installed inventory. A match means a known CVE or advisory applies to a currently installed plugin version.</dd>
                                                    <dt>Updates</dt><dd>Version drift between installed and available versions of WordPress core, plugins, and themes. Outdated components increase exposure surface.</dd>
                                                    <dt>Reachability</dt><dd>Whether the public site responded to an external HTTP probe. Checks TLS, transport, and HTTP status from outside the server.</dd>
                                                    <dt>Availability</dt><dd>Multi-probe availability sampling across the triage window. Failures mean the site did not respond on one or more timed observations.</dd>
                                                    <dt>Performance</dt><dd>Response timing captured from the public probe — total duration and time-to-first-byte. Slow values indicate frontend or server-side bottlenecks.</dd>
                                                    <dt>Configuration</dt><dd>.htaccess and folder-structure patterns checked against known risky configurations. Findings here do not always mean the site is exploited, but they reduce defensive depth.</dd>
                                                    <dt>Logs / WooCommerce</dt><dd>Normalized signal extraction from WordPress debug logs and WooCommerce logs. Signals are warnings or errors that appeared in recent runtime log output.</dd>
                                                    <dt>Uptime</dt><dd>Historical uptime observations accumulated across prior monitoring windows. Shows trend and failure rate, not just the current moment.</dd>
                                                    <dt>Passed / Foundation</dt><dd>Dimensions that ran and recorded no active finding. Green means the evidence was captured and no pressure was found. Foundation means the check anchors the scoring model but does not drive a finding on its own.</dd>
                                                </dl>
                                                <p style="margin-top:10px;font-size:12px;color:var(--og-text-3);">Filter buttons above let you isolate specific evidence categories. Use the full FAQ at the bottom of this page for deeper interpretation guidance.</p>
                                            </div>
                                        </details>

                                        <div class="opsgate-triage-filter-strip" id="opsgate-triage-filter-strip" role="toolbar" aria-label="Filter triage dimensions">
                                            <button type="button" class="opsgate-triage-filter-btn is-active" data-og-triage-filter="all">All</button>
                                            <button type="button" class="opsgate-triage-filter-btn" data-og-triage-filter="needs_action">Needs action</button>
                                            <button type="button" class="opsgate-triage-filter-btn" data-og-triage-filter="vulnerabilities">Vulnerabilities</button>
                                            <button type="button" class="opsgate-triage-filter-btn" data-og-triage-filter="updates">Updates</button>
                                            <button type="button" class="opsgate-triage-filter-btn" data-og-triage-filter="uptime">Uptime &amp; Performance</button>
                                            <button type="button" class="opsgate-triage-filter-btn" data-og-triage-filter="configuration">Configuration</button>
                                            <button type="button" class="opsgate-triage-filter-btn" data-og-triage-filter="logs">Logs &amp; WooCommerce</button>
                                            <button type="button" class="opsgate-triage-filter-btn" data-og-triage-filter="passed">Passed</button>
                                        </div>
                                        <div id="opsgate-triage-filter-empty" class="opsgate-r1-empty-state" style="display:none;" role="status">
                                            <div class="opsgate-r1-empty-state-title">No dimensions match this filter</div>
                                            <p class="opsgate-r1-empty-state-body">The latest run did not record evidence in this category. Run a new triage or choose a different filter.</p>
                                        </div>

                                        <details class="opsgate-r1-scan-evidence-details">
                                            <summary class="opsgate-r1-scan-evidence-summary">Full evidence assessment <span class="opsgate-r1-scan-evidence-count">(<?php echo esc_html( (string) $triage_evidence_count ); ?> dimensions recorded)</span> &#9658;</summary>
                                        <section class="opsgate-triage-evidence-workbench">
                                            <div class="opsgate-triage-surface-header opsgate-triage-surface-header-secondary">
                                                <h3 class="opsgate-triage-surface-title">Evidence assessment</h3>
                                                <span class="opsgate-triage-surface-link">Recorded dimensions and drilldown</span>
                                            </div>

                                            <div class="opsgate-triage-evidence-group-stack">
                                                <?php foreach ( $triage_evidence_groups as $triage_evidence_group ) : ?>
                                                    <section class="opsgate-triage-evidence-group">
                                                        <div class="opsgate-triage-evidence-group-head">
                                                            <div>
                                                                <span class="opsgate-triage-eyebrow"><?php echo esc_html( (string) $triage_evidence_group['title'] ); ?></span>
                                                                <div class="opsgate-triage-evidence-group-title"><?php echo esc_html( (string) $triage_evidence_group['summary'] ); ?></div>
                                                            </div>
                                                        </div>
                                                        <div class="opsgate-triage-evidence-ledger">
                                                            <?php foreach ( (array) $triage_evidence_group['items'] as $triage_evidence_dimension ) : ?>
                                                                <?php
                                                                $triage_dimension_class = 'opsgate-triage-dimension-row';
                                                                if ( in_array( (string) $triage_evidence_dimension['tone'], array( 'warn', 'bad', 'blocked' ), true ) ) {
                                                                    $triage_dimension_class .= ' is-' . (string) $triage_evidence_dimension['tone'];
                                                                } elseif ( 'foundation' === (string) $triage_evidence_dimension['tone'] ) {
                                                                    $triage_dimension_class .= ' is-foundation';
                                                                }
                                                                ?>
                                                                <article class="<?php echo esc_attr( $triage_dimension_class ); ?>" data-og-triage-tone="<?php echo esc_attr( (string) $triage_evidence_dimension['tone'] ); ?>">
                                                                    <div class="opsgate-triage-dimension-main">
                                                                        <span class="opsgate-severity-dot tone-<?php echo esc_attr( (string) $triage_evidence_dimension['tone'] ); ?>" aria-hidden="true"></span>
                                                                        <span class="opsgate-triage-eyebrow"><?php echo esc_html( (string) $triage_evidence_dimension['label'] ); ?></span>
                                                                        <div class="opsgate-triage-dimension-title-row">
                                                                            <div class="opsgate-triage-dimension-value"><?php echo esc_html( (string) $triage_evidence_dimension['value'] ); ?></div>
                                                                            <?php if ( ! empty( $triage_evidence_dimension['link'] ) && ! empty( $triage_evidence_dimension['href'] ) ) : ?>
                                                                                <a class="opsgate-triage-inline-link" href="<?php echo esc_url( (string) $triage_evidence_dimension['href'] ); ?>"<?php echo ! empty( $triage_evidence_dimension['detail_key'] ) ? ' data-opsgate-triage-detail-link="' . esc_attr( (string) $triage_evidence_dimension['detail_key'] ) . '"' : ''; ?>><?php echo esc_html( (string) $triage_evidence_dimension['link'] ); ?></a>
                                                                            <?php endif; ?>
                                                                        </div>
                                                                        <p class="opsgate-triage-dimension-copy"><?php echo esc_html( (string) $triage_evidence_dimension['copy'] ); ?></p>
                                                                    </div>
                                                                    <div class="opsgate-triage-dimension-meta"><?php echo esc_html( (string) $triage_evidence_dimension['meta'] ); ?></div>
                                                                </article>
                                                            <?php endforeach; ?>
                                                        </div>
                                                    </section>
                                                <?php endforeach; ?>
                                            </div>

                                            <div id="opsgate-evidence-detail" class="opsgate-triage-detail-region">
                                                <div class="opsgate-triage-inline-detail-stack">
                                                    <?php foreach ( $triage_detail_tabs as $triage_detail_key => $triage_detail_tab ) : ?>
                                                        <details id="opsgate-detail-<?php echo esc_attr( $triage_detail_key ); ?>" class="opsgate-triage-inline-detail"<?php echo $triage_detail_key === $triage_detail_focus ? ' open="open"' : ''; ?> data-opsgate-triage-detail-key="<?php echo esc_attr( $triage_detail_key ); ?>">
                                                            <summary>
                                                                <div class="opsgate-triage-inline-detail-head">
                                                                    <span class="opsgate-triage-eyebrow"><?php echo esc_html( $triage_detail_tab['label'] ); ?></span>
                                                                    <span class="opsgate-triage-inline-detail-title"><?php echo esc_html( $triage_detail_tab['title'] ); ?></span>
                                                                    <span class="opsgate-triage-inline-detail-kicker"><?php echo esc_html( $triage_detail_tab['summary'] ); ?></span>
                                                                </div>
                                                                <span class="opsgate-triage-inline-detail-chip"><?php echo esc_html( (string) $triage_detail_tab['count'] ); ?></span>
                                                            </summary>
                                                            <div class="opsgate-triage-inline-detail-body">
                                                                <?php if ( ! empty( $triage_detail_tab['why_note'] ) ) : ?>
                                                                    <p class="opsgate-triage-why-note"><?php echo esc_html( (string) $triage_detail_tab['why_note'] ); ?></p>
                                                                <?php endif; ?>
                                                                <?php self::render_triage_detail_items_list( $triage_detail_tab['items'], (string) $triage_detail_tab['empty'] ); ?>
                                                            </div>
                                                        </details>
                                                    <?php endforeach; ?>
                                                </div>
                                            </div>
                                        </section>
                                        </details><!-- /opsgate-r1-scan-evidence-details -->
                                    </section>
                                </div>

                                <?php
                                // Phase 5: WooCommerce 3-state signal card — only render when operational_log_intelligence artifact present
                                $p5_woo_sources = array_filter( $operational_log_sources, static function( $src ) {
                                    return is_array( $src ) && isset( $src['source_family'] ) && 'woocommerce_log' === $src['source_family'];
                                } );
                                $p5_woo_source = ! empty( $p5_woo_sources ) ? reset( $p5_woo_sources ) : null;
                                $p5_woo_has_artifact = ! empty( $operational_log_intelligence );
                                $p5_woo_present = null !== $p5_woo_source;
                                $p5_woo_available = $p5_woo_present && isset( $p5_woo_source['available'] ) ? (bool) $p5_woo_source['available'] : ( $p5_woo_present && $operational_log_available_source_count > 0 );
                                $p5_woo_signals = array_filter( isset( $operational_log_intelligence['signals'] ) && is_array( $operational_log_intelligence['signals'] ) ? $operational_log_intelligence['signals'] : array(), static function( $sig ) {
                                    return is_array( $sig ) && isset( $sig['source_family'] ) && 'woocommerce_log' === $sig['source_family'];
                                } );
                                if ( $p5_woo_has_artifact && $p5_woo_present ) :
                                    if ( ! $p5_woo_present ) :
                                        $p5_woo_state = 'absent';
                                        $p5_woo_title = 'WooCommerce not detected';
                                        $p5_woo_copy = 'No WooCommerce log source was found in the connected site\'s runtime log families for this run.';
                                        $p5_woo_notice = 'WooCommerce log intelligence was not recorded — either the site does not use WooCommerce, or logging is disabled.';
                                    elseif ( ! $p5_woo_available ) :
                                        $p5_woo_state = 'unavailable';
                                        $p5_woo_title = 'WooCommerce logs unavailable';
                                        $p5_woo_copy = 'A WooCommerce log source was detected but was not readable for this run.';
                                        $p5_woo_notice = 'Enable WooCommerce logging on the connected site to allow normalized signal capture in the next run.';
                                    elseif ( empty( $p5_woo_signals ) ) :
                                        $p5_woo_state = 'clean';
                                        $p5_woo_title = 'WooCommerce logs reviewed — no signals';
                                        $p5_woo_copy = 'WooCommerce runtime logs were available and normalized. No recurring signal pattern was recorded in this run.';
                                        $p5_woo_notice = '';
                                    else :
                                        $p5_woo_state = 'signals';
                                        $p5_woo_title = count( $p5_woo_signals ) . ' WooCommerce signal' . ( count( $p5_woo_signals ) !== 1 ? 's' : '' ) . ' recorded';
                                        $p5_woo_copy = 'Normalized WooCommerce runtime log signals from this run are listed below. Review each pattern before the next customer update.';
                                        $p5_woo_notice = '';
                                    endif;
                                    ?>
                                <section class="opsgate-p5-woo-card">
                                    <div class="opsgate-p5-woo-card-head">
                                        <span class="opsgate-p5-section-heading">WooCommerce Log Intelligence</span>
                                        <span class="opsgate-p5-woo-state-badge state-<?php echo esc_attr( $p5_woo_state ); ?>"><?php echo esc_html( ucfirst( str_replace( '_', ' ', $p5_woo_state ) ) ); ?></span>
                                    </div>
                                    <p class="opsgate-p5-body-text"><?php echo esc_html( $p5_woo_title ); ?></p>
                                    <p class="opsgate-p5-meta-text"><?php echo esc_html( $p5_woo_copy ); ?></p>
                                    <?php if ( '' !== $p5_woo_notice ) : ?>
                                    <div class="opsgate-p5-woo-notice"><?php echo esc_html( $p5_woo_notice ); ?></div>
                                    <?php endif; ?>
                                    <?php if ( ! empty( $p5_woo_signals ) ) : ?>
                                    <ul class="opsgate-p5-woo-signal-list">
                                        <?php foreach ( $p5_woo_signals as $p5_woo_sig ) : ?>
                                        <li>
                                            <strong><?php echo esc_html( (string) ( $p5_woo_sig['label'] ?? $p5_woo_sig['pattern'] ?? 'Signal' ) ); ?></strong>
                                            <?php if ( ! empty( $p5_woo_sig['meta'] ) ) : ?>
                                            <span class="opsgate-p5-meta-text"><?php echo esc_html( (string) $p5_woo_sig['meta'] ); ?></span>
                                            <?php endif; ?>
                                        </li>
                                        <?php endforeach; ?>
                                    </ul>
                                    <?php endif; ?>
                                </section>
                                <?php endif; ?>

                                <details class="opsgate-p5-help-panel">
                                    <summary>Help &amp; Glossary — Security Scan FAQ</summary>
                                    <div class="opsgate-p5-help-panel-body">
                                    <section class="opsgate-triage-surface opsgate-triage-reference-surface">
                                        <div class="opsgate-triage-surface-header">
                                            <h3 class="opsgate-triage-surface-title">Security Scan FAQ</h3>
                                            <span class="opsgate-triage-surface-link">Interpretation guide</span>
                                        </div>
                                        <p class="opsgate-triage-section-intro">Use this reference when you need to interpret scan results, understand what each check covers, or explain findings to a client.</p>
                                        <div class="opsgate-triage-reference-stack">
                                            <?php foreach ( $triage_reference_modules as $triage_reference_index => $triage_reference_module ) : ?>
                                                <details class="opsgate-triage-reference-details">
                                                    <summary>
                                                        <div>
                                                            <span class="opsgate-triage-eyebrow"><?php echo esc_html( (string) $triage_reference_module['title'] ); ?></span>
                                                            <div class="opsgate-triage-reference-title"><?php echo esc_html( (string) $triage_reference_module['summary'] ); ?></div>
                                                        </div>
                                                    </summary>
                                                    <ul class="opsgate-triage-reference-list">
                                                        <?php foreach ( (array) $triage_reference_module['items'] as $triage_reference_item ) : ?>
                                                            <li><?php echo esc_html( (string) $triage_reference_item ); ?></li>
                                                        <?php endforeach; ?>
                                                    </ul>
                                                </details>
                                            <?php endforeach; ?>
                                        </div>
                                    </section>
                                    </div>
                                </details><!-- /opsgate-p5-help-panel -->

                                <details id="opsgate-triage-support-package" class="opsgate-triage-support-strip">
                                    <summary class="opsgate-triage-support-strip-summary">
                                        <div class="opsgate-triage-section-head">
                                            <h3 class="opsgate-triage-section-title">Support evidence package</h3>
                                            <span class="opsgate-triage-section-kicker"><?php echo esc_html( $triage_support_label ); ?></span>
                                        </div>
                                        <p class="opsgate-triage-section-intro">Support files remain available for export, verification, and deeper review without competing with the main customer-facing assessment above.</p>
                                    </summary>
                                    <div class="opsgate-triage-support-strip-body">
                                    <div class="opsgate-triage-support-strip-grid">
                                        <article class="opsgate-triage-support-strip-card">
                                            <span class="opsgate-triage-eyebrow">Source lineage</span>
                                            <div class="opsgate-triage-support-strip-value"><?php echo esc_html( $triage_dataset_value ); ?></div>
                                            <p class="opsgate-triage-support-strip-copy"><?php echo esc_html( $triage_dataset_meta ); ?></p>
                                        </article>
                                        <article class="opsgate-triage-support-strip-card">
                                            <span class="opsgate-triage-eyebrow">Evidence state</span>
                                            <div class="opsgate-triage-support-strip-value"><?php echo esc_html( $triage_evidence_state ); ?></div>
                                            <p class="opsgate-triage-support-strip-copy"><?php echo esc_html( 'Artifacts ' . (string) $triage_evidence_count ); ?></p>
                                        </article>
                                        <article class="opsgate-triage-support-strip-card">
                                            <span class="opsgate-triage-eyebrow">Support files</span>
                                            <div class="opsgate-triage-support-strip-value"><?php echo esc_html( $triage_artifact_value ); ?></div>
                                            <p class="opsgate-triage-support-strip-copy"><?php echo esc_html( $triage_artifact_meta ); ?></p>
                                            <?php if ( ! empty( $triage_download_actions ) ) : ?>
                                                <details class="opsgate-triage-advanced-artifacts">
                                                    <summary>Open support package</summary>
                                                    <div class="opsgate-triage-download-grid">
                                                        <?php foreach ( $triage_download_actions as $triage_download_action ) : ?>
                                                            <a class="button button-secondary opsgate-triage-download-button" href="<?php echo esc_url( $triage_download_action['url'] ); ?>"><?php echo esc_html( $triage_download_action['label'] ); ?></a>
                                                        <?php endforeach; ?>
                                                    </div>
                                                </details>
                                            <?php endif; ?>
                                        </article>
                                    </div>
                                    </div>
                                </details>
                            </div>
                        <?php endif; ?>

                            </div>
                            <?php
                            $triage_job_id = isset( $_GET['triage_job_id'] ) ? sanitize_text_field( wp_unslash( $_GET['triage_job_id'] ) ) : '';
                            ?>
                    <?php endif; ?>
                </div>

            <?php elseif ( 'clients' === $active_tab ) : ?>
                <?php self::render_clients_dashboard_panel(); ?>
                    
                <?php elseif ( 'reports' === $active_tab ) : ?>
                <?php
                $history = self::canonical_exports_history( 20 );
                $selected_source_job_id = isset( $_GET['source_job_id'] ) ? sanitize_text_field( wp_unslash( $_GET['source_job_id'] ) ) : '';
                $selected_source_job_id = trim( $selected_source_job_id );

                $history_ok = ! empty( $history['ok'] );
                $history_items = ( isset( $history['items'] ) && is_array( $history['items'] ) ) ? $history['items'] : array();

                $report_items = array();
                foreach ( $history_items as $item ) {
                    if ( ! is_array( $item ) ) {
                        continue;
                    }

                    $kind = isset( $item['kind'] ) ? (string) $item['kind'] : '';
                    if ( ! in_array( $kind, array( 'report_html', 'report_pdf', 'csv', 'export_csv', 'triage_csv', 'report_xlsx' ), true ) ) {
                        continue;
                    }

                    $report_items[] = $item;
                }

                usort(
                    $report_items,
                    static function ( $a, $b ) {
                        $a_time = self::report_item_sort_timestamp( is_array( $a ) ? $a : array() );
                        $b_time = self::report_item_sort_timestamp( is_array( $b ) ? $b : array() );

                        if ( $a_time === $b_time ) {
                            return 0;
                        }

                        return ( $a_time > $b_time ) ? -1 : 1;
                    }
                );

                $live_report_items = self::live_items_only( $report_items );
                $latest_item = ! empty( $live_report_items ) ? $live_report_items[0] : null;
                $reports_default_ready_context = false;

                $selected_report_items = array();
                if ( '' !== $selected_source_job_id ) {
                    foreach ( $live_report_items as $item ) {
                        if ( ! is_array( $item ) ) {
                            continue;
                        }

                        $item_source_job_id = isset( $item['source_job_id'] ) ? trim( (string) $item['source_job_id'] ) : '';
                        if ( '' !== $item_source_job_id && $item_source_job_id === $selected_source_job_id ) {
                            $selected_report_items[] = $item;
                        }
                    }
                }

                $history_focus_source_job_id = $selected_source_job_id;
                $selected_triage_bundle = array(
                    'ok'        => false,
                    'job'       => array(),
                    'artifacts' => array(),
                    'error'     => '',
                );
                if ( '' !== $selected_source_job_id ) {
                    $selected_triage_bundle = self::triage_bundle_for_job_id( $selected_source_job_id );
                    $selected_triage_job = ! empty( $selected_triage_bundle['job'] ) && is_array( $selected_triage_bundle['job'] ) ? $selected_triage_bundle['job'] : array();
                    $reports_scope_for_selection = self::current_mcp_scope_snapshot();
                    if ( ! empty( $selected_triage_job ) && ! self::job_matches_scope( $selected_triage_job, $reports_scope_for_selection ) ) {
                        $selected_source_job_id = '';
                        $selected_triage_bundle = array(
                            'ok'        => false,
                            'job'       => array(),
                            'artifacts' => array(),
                            'error'     => 'site_scope_mismatch',
                        );
                    }
                }

                $latest_triage_bundle = self::canonical_latest_triage_bundle();
                $latest_triage_job = ! empty( $latest_triage_bundle['job'] ) && is_array( $latest_triage_bundle['job'] ) ? $latest_triage_bundle['job'] : array();
                $latest_triage_artifacts = ! empty( $latest_triage_bundle['artifacts'] ) && is_array( $latest_triage_bundle['artifacts'] ) ? $latest_triage_bundle['artifacts'] : array();
                $latest_triage_score_summary = isset( $latest_triage_artifacts['score_summary']['body'] ) && is_array( $latest_triage_artifacts['score_summary']['body'] )
                    ? $latest_triage_artifacts['score_summary']['body']
                    : array();
                $latest_triage_job_id = isset( $latest_triage_job['job_id'] ) ? trim( (string) $latest_triage_job['job_id'] ) : '';
                $latest_triage_state = isset( $latest_triage_job['state'] ) ? strtoupper( trim( (string) $latest_triage_job['state'] ) ) : '';
                $latest_triage_finished = isset( $latest_triage_job['finished_at_utc'] ) ? trim( (string) $latest_triage_job['finished_at_utc'] ) : '';
                $latest_triage_started = isset( $latest_triage_job['started_at_utc'] ) ? trim( (string) $latest_triage_job['started_at_utc'] ) : '';
                $latest_triage_when = '' !== $latest_triage_finished ? $latest_triage_finished : $latest_triage_started;
                $latest_triage_score = isset( $latest_triage_score_summary['score'] ) ? (int) $latest_triage_score_summary['score'] : null;
                $latest_triage_grade = isset( $latest_triage_score_summary['grade'] ) ? strtolower( trim( (string) $latest_triage_score_summary['grade'] ) ) : '';
                $latest_triage_grade_label = '' !== $latest_triage_grade ? ucfirst( $latest_triage_grade ) : 'Unrated';
                $latest_triage_grade_summary = 'Posture pending';
                $latest_triage_grade_tone = 'neutral';
                if ( in_array( $latest_triage_grade, array( 'green', 'healthy' ), true ) ) {
                    $latest_triage_grade_summary = 'Healthy';
                    $latest_triage_grade_tone = 'good';
                } elseif ( in_array( $latest_triage_grade, array( 'yellow', 'amber' ), true ) ) {
                    $latest_triage_grade_summary = 'Needs attention';
                    $latest_triage_grade_tone = 'warn';
                } elseif ( in_array( $latest_triage_grade, array( 'red', 'critical' ), true ) ) {
                    $latest_triage_grade_summary = 'Action required';
                    $latest_triage_grade_tone = 'bad';
                }

                $latest_run_report_items = array();
                if ( '' !== $latest_triage_job_id ) {
                    foreach ( $live_report_items as $item ) {
                        if ( ! is_array( $item ) ) {
                            continue;
                        }

                        $item_source_job_id = isset( $item['source_job_id'] ) ? trim( (string) $item['source_job_id'] ) : '';
                        if ( '' !== $item_source_job_id && $item_source_job_id === $latest_triage_job_id ) {
                            $latest_run_report_items[] = $item;
                        }
                    }
                }

                if ( '' === $selected_source_job_id && empty( $latest_run_report_items ) && is_array( $latest_item ) ) {
                    $default_ready_source_job_id = isset( $latest_item['source_job_id'] ) ? trim( (string) $latest_item['source_job_id'] ) : '';
                    if ( '' !== $default_ready_source_job_id && $default_ready_source_job_id !== $latest_triage_job_id ) {
                        $default_triage_bundle = self::triage_bundle_for_job_id( $default_ready_source_job_id );
                        $default_triage_job = ! empty( $default_triage_bundle['job'] ) && is_array( $default_triage_bundle['job'] ) ? $default_triage_bundle['job'] : array();
                        $reports_scope_for_default = self::current_mcp_scope_snapshot();
                        if ( ! empty( $default_triage_job ) && self::job_matches_scope( $default_triage_job, $reports_scope_for_default ) ) {
                            $selected_source_job_id = $default_ready_source_job_id;
                            $selected_triage_bundle = $default_triage_bundle;
                            $history_focus_source_job_id = $default_ready_source_job_id;
                            $reports_default_ready_context = true;
                            foreach ( $live_report_items as $item ) {
                                if ( ! is_array( $item ) ) {
                                    continue;
                                }
                                $item_source_job_id = isset( $item['source_job_id'] ) ? trim( (string) $item['source_job_id'] ) : '';
                                if ( $item_source_job_id === $default_ready_source_job_id ) {
                                    $selected_report_items[] = $item;
                                }
                            }
                        }
                    }
                }

                $selected_triage_job = ! empty( $selected_triage_bundle['job'] ) && is_array( $selected_triage_bundle['job'] ) ? $selected_triage_bundle['job'] : array();
                $selected_triage_job_id = isset( $selected_triage_job['job_id'] ) ? trim( (string) $selected_triage_job['job_id'] ) : '';
                $selected_triage_provenance = strtolower( trim( (string) ( $selected_triage_job['provenance_kind'] ?? 'live' ) ) );
                $selected_live_context = ! empty( $selected_triage_bundle['ok'] ) && '' !== $selected_triage_job_id && 'proof' !== $selected_triage_provenance;
                if ( ! $selected_live_context ) {
                    $history_focus_source_job_id = '';
                }

                $reports_context_triage_bundle = $selected_live_context ? $selected_triage_bundle : $latest_triage_bundle;
                $reports_context_triage_job = ! empty( $reports_context_triage_bundle['job'] ) && is_array( $reports_context_triage_bundle['job'] ) ? $reports_context_triage_bundle['job'] : array();
                $reports_context_triage_artifacts = ! empty( $reports_context_triage_bundle['artifacts'] ) && is_array( $reports_context_triage_bundle['artifacts'] ) ? $reports_context_triage_bundle['artifacts'] : array();
                $reports_context_score_summary = isset( $reports_context_triage_artifacts['score_summary']['body'] ) && is_array( $reports_context_triage_artifacts['score_summary']['body'] )
                    ? $reports_context_triage_artifacts['score_summary']['body']
                    : array();
                $reports_context_source_job_id = isset( $reports_context_triage_job['job_id'] ) ? trim( (string) $reports_context_triage_job['job_id'] ) : '';
                $reports_context_state = isset( $reports_context_triage_job['state'] ) ? strtoupper( trim( (string) $reports_context_triage_job['state'] ) ) : '';
                $reports_context_finished = isset( $reports_context_triage_job['finished_at_utc'] ) ? trim( (string) $reports_context_triage_job['finished_at_utc'] ) : '';
                $reports_context_started = isset( $reports_context_triage_job['started_at_utc'] ) ? trim( (string) $reports_context_triage_job['started_at_utc'] ) : '';
                $reports_context_when = '' !== $reports_context_finished ? $reports_context_finished : $reports_context_started;
                $reports_context_score = isset( $reports_context_score_summary['score'] ) ? (int) $reports_context_score_summary['score'] : null;
                $reports_context_grade = isset( $reports_context_score_summary['grade'] ) ? strtolower( trim( (string) $reports_context_score_summary['grade'] ) ) : '';
                $reports_context_grade_label = '' !== $reports_context_grade ? ucfirst( $reports_context_grade ) : 'Unrated';
                $reports_context_grade_summary = 'Posture pending';
                $reports_context_grade_tone = 'neutral';
                if ( in_array( $reports_context_grade, array( 'green', 'healthy' ), true ) ) {
                    $reports_context_grade_summary = 'Healthy';
                    $reports_context_grade_tone = 'good';
                } elseif ( in_array( $reports_context_grade, array( 'yellow', 'amber' ), true ) ) {
                    $reports_context_grade_summary = 'Needs attention';
                    $reports_context_grade_tone = 'warn';
                } elseif ( in_array( $reports_context_grade, array( 'red', 'critical' ), true ) ) {
                    $reports_context_grade_summary = 'Action required';
                    $reports_context_grade_tone = 'bad';
                }

                $reports_update_posture = isset( $reports_context_triage_artifacts['update_posture']['body'] ) && is_array( $reports_context_triage_artifacts['update_posture']['body'] )
                    ? $reports_context_triage_artifacts['update_posture']['body']
                    : array();
                $reports_vulnerability_posture = isset( $reports_context_triage_artifacts['vulnerability_posture']['body'] ) && is_array( $reports_context_triage_artifacts['vulnerability_posture']['body'] )
                    ? $reports_context_triage_artifacts['vulnerability_posture']['body']
                    : array();
                $reports_hardening_guidance = isset( $reports_context_triage_artifacts['hardening_guidance']['body'] ) && is_array( $reports_context_triage_artifacts['hardening_guidance']['body'] )
                    ? $reports_context_triage_artifacts['hardening_guidance']['body']
                    : array();
                $reports_reachability_posture = isset( $reports_context_triage_artifacts['reachability_posture']['body'] ) && is_array( $reports_context_triage_artifacts['reachability_posture']['body'] )
                    ? $reports_context_triage_artifacts['reachability_posture']['body']
                    : array();
                $reports_availability_snapshot = isset( $reports_context_triage_artifacts['availability_snapshot']['body'] ) && is_array( $reports_context_triage_artifacts['availability_snapshot']['body'] )
                    ? $reports_context_triage_artifacts['availability_snapshot']['body']
                    : array();
                $reports_reason_items = self::posture_reason_items(
                    $reports_context_score_summary,
                    $reports_update_posture,
                    $reports_vulnerability_posture,
                    $reports_reachability_posture,
                    $reports_availability_snapshot
                );
                $reports_operator_degradation = self::operator_degradation_meta( $reports_context_score_summary );
                $reports_update_detail_items = self::posture_detail_items( 'updates', $reports_update_posture, array( 'vulnerability_posture' => $reports_vulnerability_posture ) );
                $reports_vulnerability_detail_items = self::posture_detail_items( 'vulnerabilities', $reports_vulnerability_posture );
                $reports_hardening_detail_items = self::posture_detail_items( 'hardening', $reports_hardening_guidance );

                $context_report_items = $selected_live_context ? $selected_report_items : $latest_run_report_items;
                $latest_item = ! empty( $context_report_items ) ? $context_report_items[0] : null;
                if ( null === $latest_item && ! $selected_live_context && ! empty( $live_report_items ) ) {
                    $latest_item = $live_report_items[0];
                }

                $available_output_labels = array();
                $missing_output_labels = array();

                $available_outputs_copy = ! empty( $available_output_labels ) ? implode( ', ', $available_output_labels ) : 'none yet';
                $missing_outputs_copy = ! empty( $missing_output_labels ) ? implode( ', ', $missing_output_labels ) : '';
                $reports_intro_copy = 'This surface shows latest-run output state first. Older packaged history stays available below.';
                $reports_selected_site = self::current_selected_site_summary();
                $reports_connection_status = isset( $reports_selected_site['connection_status'] ) ? trim( (string) $reports_selected_site['connection_status'] ) : 'external_only';
                $reports_connection_mode = isset( $reports_selected_site['connection_mode'] ) ? trim( (string) $reports_selected_site['connection_mode'] ) : 'public_scan';
                $reports_connection_label = self::canonical_connection_status_label( $reports_connection_status );
                $reports_connection_copy = self::canonical_connection_status_copy(
                    $reports_connection_status,
                    $reports_connection_mode,
                    self::scope_targets_local_wordpress( isset( $reports_selected_site['site_url'] ) ? (string) $reports_selected_site['site_url'] : '' )
                );
                if ( $reports_default_ready_context && '' !== $reports_context_source_job_id ) {
                    $reports_intro_copy = 'This surface is focused on the latest report-ready run because the newest recorded run does not have packaged outputs yet.';
                } elseif ( $selected_live_context && '' !== $reports_context_source_job_id && $reports_context_source_job_id !== $latest_triage_job_id ) {
                    $reports_intro_copy = 'This surface is focused on the selected live run. Latest-run output state remains available when you clear the selected run.';
                }
                $reports_package = self::current_package_entry();
                $reports_evidence_story = self::package_evidence_governance();
                $reports_proof_runs = self::proof_runs_list( 6 );
                $reports_proof_items = ! empty( $reports_proof_runs['ok'] ) && isset( $reports_proof_runs['items'] ) && is_array( $reports_proof_runs['items'] ) ? $reports_proof_runs['items'] : array();
                $reports_latest_proof = array();
                foreach ( $reports_proof_items as $reports_proof_item ) {
                    if ( is_array( $reports_proof_item ) && isset( $reports_proof_item['scenario_family'] ) && in_array( (string) $reports_proof_item['scenario_family'], array( 'trust_signature', 'export_report_failure' ), true ) ) {
                        $reports_latest_proof = $reports_proof_item;
                        break;
                    }
                }

                if ( '' !== $reports_context_source_job_id && empty( $context_report_items ) ) {
                    $reports_intro_copy = 'This scan is complete, but no report has been generated yet. Previous reports are available below.';
                } elseif ( '' === $latest_triage_job_id && ! empty( $live_report_items ) ) {
                    $reports_intro_copy = 'No completed latest run is recorded right now. Historical packaged outputs stay available below.';
                }

                ?>
                    <?php if ( ! $history_ok ) : ?>
                        <div class="notice notice-error" style="margin:12px 0 0 0;">
                            <p>Reports are temporarily unavailable because report history could not be loaded.</p>
                        </div>
                    <?php elseif ( empty( $report_items ) && '' === $latest_triage_job_id ) : ?>
                        <div class="opsgate-reports-empty-guidance">
                            <h3 class="opsgate-reports-empty-guidance-title">Run your first security scan to generate a report</h3>
                            <p class="opsgate-reports-empty-guidance-copy">Once you run a Security Scan, OpsGate produces evidence-backed HTML, PDF, CSV, and Excel security reports you can share directly with clients. Start your first scan now.</p>
                            <div class="opsgate-reports-empty-guidance-actions">
                                <a class="button button-primary" href="<?php echo esc_url( self::admin_tab_url( 'triage' ) ); ?>">Run First Security Scan</a>
                            </div>
                        </div>
                    <?php else : ?>
                        
                        <?php
                        $reports_context_phrase = $selected_live_context ? 'selected run' : 'latest run';
                        $latest_kind = is_array( $latest_item ) && isset( $latest_item['kind'] ) ? (string) $latest_item['kind'] : '';
                        $latest_job_id = is_array( $latest_item ) && isset( $latest_item['export_job_id'] ) ? (string) $latest_item['export_job_id'] : '';
                        $latest_source_job_id = '' !== $reports_context_source_job_id ? $reports_context_source_job_id : ( is_array( $latest_item ) && isset( $latest_item['source_job_id'] ) ? (string) $latest_item['source_job_id'] : '' );
                        $latest_state = '' !== $reports_context_state ? $reports_context_state : ( is_array( $latest_item ) && isset( $latest_item['state'] ) ? strtoupper( (string) $latest_item['state'] ) : '' );
                        $latest_created = '' !== $reports_context_when ? $reports_context_when : ( is_array( $latest_item ) && isset( $latest_item['created_at_utc'] ) ? (string) $latest_item['created_at_utc'] : '' );
                        $reports_context_source_job_id = $latest_source_job_id;
                        $reports_refresh_url = self::admin_tab_url(
                            'reports',
                            array_filter(
                                array(
                                    'source_job_id' => ( $selected_live_context || $reports_default_ready_context ) ? $reports_context_source_job_id : '',
                                )
                            )
                        );
                        $reports_scope = self::current_mcp_scope_snapshot();
                        $reports_alert_events = self::notification_events_for_source_id( $reports_context_source_job_id, 12 );
                        $reports_alert_items = ! empty( $reports_alert_events['ok'] ) && isset( $reports_alert_events['items'] ) && is_array( $reports_alert_events['items'] ) ? $reports_alert_events['items'] : array();
                        $reports_alert_rollup = self::notification_delivery_rollup( $reports_alert_items );
                        $reports_triage_url = self::admin_tab_url( 'triage' );
                        $reports_status_poll_url = '';
                        $reports_current_export_job_id = '';
                        $reports_runtime_refs = self::scope_runtime_refs_for_scope( $reports_scope );
                        $reports_runtime_export_job_id = trim( (string) ( $reports_runtime_refs['last_export_job_id'] ?? '' ) );
                        $reports_runtime_export_source_job_id = trim( (string) ( $reports_runtime_refs['last_export_source_job_id'] ?? '' ) );
                        foreach ( $context_report_items as $context_item ) {
                            if ( ! is_array( $context_item ) ) {
                                continue;
                            }

                            $context_item_state = isset( $context_item['state'] ) ? strtoupper( (string) $context_item['state'] ) : '';
                            if ( in_array( $context_item_state, array( 'QUEUED', 'RUNNING' ), true ) ) {
                                $latest_job_id = isset( $context_item['export_job_id'] ) ? (string) $context_item['export_job_id'] : $latest_job_id;
                                $reports_current_export_job_id = $latest_job_id;
                                break;
                            }
                        }
                        if ( '' === $reports_current_export_job_id && '' !== $reports_runtime_export_job_id ) {
                            if ( '' === $reports_runtime_export_source_job_id || '' === $reports_context_source_job_id || $reports_runtime_export_source_job_id === $reports_context_source_job_id ) {
                                $reports_current_export_job_id = $reports_runtime_export_job_id;
                            }
                        }
                        if ( '' === $reports_current_export_job_id ) {
                            $reports_current_export_job_id = $latest_job_id;
                        }
                        if ( '' !== $reports_current_export_job_id ) {
                            $reports_status_poll_url = add_query_arg(
                                array(
                                    'action'        => 'opsgate_export_record_status',
                                    'export_job_id' => $reports_current_export_job_id,
                                ),
                                admin_url( 'admin-ajax.php' )
                            );
                        }

                        $reports_current_source_job_id = '' !== $selected_source_job_id ? $reports_context_source_job_id : $latest_triage_job_id;
                        if ( '' === $reports_current_source_job_id ) {
                            $reports_current_source_job_id = $reports_context_source_job_id;
                        }
                        $reports_current_export_poll_id = '';
                        if ( '' !== $reports_current_source_job_id && $reports_current_source_job_id === $reports_context_source_job_id ) {
                            $reports_current_export_poll_id = $reports_current_export_job_id;
                        } elseif ( '' !== $reports_current_source_job_id && '' !== $reports_runtime_export_source_job_id && $reports_runtime_export_source_job_id === $reports_current_source_job_id ) {
                            $reports_current_export_poll_id = $reports_runtime_export_job_id;
                        }

                        $reports_live_states = array();
                        foreach ( $context_report_items as $context_item ) {
                            if ( ! is_array( $context_item ) ) {
                                continue;
                            }

                            $candidate_state = isset( $context_item['state'] ) ? strtoupper( (string) $context_item['state'] ) : '';
                            if ( '' !== $candidate_state ) {
                                $reports_live_states[] = $candidate_state;
                            }
                        }
                        $reports_live_states = array_values( array_unique( array_filter( $reports_live_states ) ) );

                        $reports_site_config = self::canonical_site_config();
                        $reports_site_config_item = ! empty( $reports_site_config['ok'] ) && isset( $reports_site_config['item'] ) && is_array( $reports_site_config['item'] ) ? $reports_site_config['item'] : array();
                        $reports_selected_site = self::current_selected_site_summary();
                        $reports_site_label = self::connected_site_label( $reports_site_config_item, $reports_scope );
                        $reports_scope_label = '' !== $reports_site_label ? $reports_site_label : 'Connected site';
                        $reports_connection_status = isset( $reports_selected_site['connection_status'] ) ? trim( (string) $reports_selected_site['connection_status'] ) : 'external_only';
                        $reports_connection_mode = isset( $reports_selected_site['connection_mode'] ) ? trim( (string) $reports_selected_site['connection_mode'] ) : 'public_scan';
                        $reports_connection_label = self::canonical_connection_status_label( $reports_connection_status );
                        $reports_connection_copy = self::canonical_connection_status_copy(
                            $reports_connection_status,
                            $reports_connection_mode,
                            self::scope_targets_local_wordpress( isset( $reports_selected_site['site_url'] ) ? (string) $reports_selected_site['site_url'] : '' )
                        );
                        $reports_run_label = '' !== $latest_created ? self::canonical_report_datetime_label( $latest_created ) : 'No run outputs yet';
                        $reports_latest_state_label = 'Pending';
                        $reports_latest_state_tone = 'info';
                        if ( 'COMPLETED' === $latest_state ) {
                            $reports_latest_state_label = 'Completed';
                            $reports_latest_state_tone = 'good';
                        } elseif ( 'RUNNING' === $latest_state ) {
                            $reports_latest_state_label = 'Running';
                            $reports_latest_state_tone = 'warn';
                        } elseif ( 'QUEUED' === $latest_state ) {
                            $reports_latest_state_label = 'Queued';
                            $reports_latest_state_tone = 'warn';
                        } elseif ( 'FAILED' === $latest_state ) {
                            $reports_latest_state_label = 'Failed';
                            $reports_latest_state_tone = 'bad';
                        }

                        $latest_outputs = array(
                            'pdf'  => array(
                                'label' => 'PDF',
                                'kind'  => 'report_pdf',
                                'item'  => null,
                            ),
                            'html' => array(
                                'label' => 'HTML',
                                'kind'  => 'report_html',
                                'item'  => null,
                            ),
                            'csv'  => array(
                                'label' => 'CSV',
                                'kind'  => 'csv',
                                'item'  => null,
                            ),
                            'xlsx' => array(
                                'label' => 'Excel',
                                'kind'  => 'report_xlsx',
                                'item'  => null,
                            ),
                            'json' => array(
                                'label' => 'JSON',
                                'kind'  => 'triage_json',
                                'item'  => null,
                            ),
                            'xml'  => array(
                                'label' => 'XML',
                                'kind'  => 'triage_xml',
                                'item'  => null,
                            ),
                        );

                        foreach ( $context_report_items as $item ) {
                            if ( ! is_array( $item ) ) {
                                continue;
                            }

                            $kind = isset( $item['kind'] ) ? (string) $item['kind'] : '';

                            if ( 'report_pdf' === $kind && null === $latest_outputs['pdf']['item'] ) {
                                $latest_outputs['pdf']['item'] = $item;
                            } elseif ( 'report_html' === $kind && null === $latest_outputs['html']['item'] ) {
                                $latest_outputs['html']['item'] = $item;
                            } elseif ( in_array( $kind, array( 'csv', 'export_csv', 'triage_csv' ), true ) && null === $latest_outputs['csv']['item'] ) {
                                $latest_outputs['csv']['item'] = $item;
                            } elseif ( 'report_xlsx' === $kind && null === $latest_outputs['xlsx']['item'] ) {
                                $latest_outputs['xlsx']['item'] = $item;
                            } elseif ( in_array( $kind, array( 'triage_json', 'export_triage_json' ), true ) && null === $latest_outputs['json']['item'] ) {
                                $latest_outputs['json']['item'] = $item;
                            } elseif ( in_array( $kind, array( 'triage_xml', 'export_triage_xml' ), true ) && null === $latest_outputs['xml']['item'] ) {
                                $latest_outputs['xml']['item'] = $item;
                            }
                        }

                        $generated_output_labels = array();
                        $processing_output_labels = array();
                        $locked_output_labels = array();
                        $not_generated_output_labels = array();
                        foreach ( $latest_outputs as $latest_output_meta ) {
                            $latest_output_item = isset( $latest_output_meta['item'] ) && is_array( $latest_output_meta['item'] ) ? $latest_output_meta['item'] : null;
                            $latest_output_kind = isset( $latest_output_meta['kind'] ) ? (string) $latest_output_meta['kind'] : '';
                            $latest_output_allowed = self::export_kind_allowed_now( $latest_output_kind );
                            $latest_output_state = is_array( $latest_output_item ) && isset( $latest_output_item['state'] ) ? strtoupper( (string) $latest_output_item['state'] ) : '';
                            if ( null !== $latest_output_item && 'COMPLETED' === $latest_output_state ) {
                                $available_output_labels[] = $latest_output_meta['label'];
                                $generated_output_labels[] = $latest_output_meta['label'];
                            } elseif ( in_array( $latest_output_state, array( 'QUEUED', 'RUNNING' ), true ) ) {
                                $processing_output_labels[] = $latest_output_meta['label'];
                            } elseif ( ! $latest_output_allowed ) {
                                $locked_output_labels[] = $latest_output_meta['label'];
                            } else {
                                $not_generated_output_labels[] = $latest_output_meta['label'];
                            }
                        }

                        $available_outputs_copy = ! empty( $available_output_labels ) ? implode( ', ', $available_output_labels ) : 'none yet';
                        $missing_outputs_copy = ! empty( $not_generated_output_labels ) ? implode( ', ', $not_generated_output_labels ) : '';
                        $reports_output_state_copy = ! empty( $generated_output_labels ) ? implode( ', ', $generated_output_labels ) . ' ready' : 'No report generated yet';
                        if ( ! empty( $processing_output_labels ) ) {
                            $reports_output_state_copy .= '; ' . implode( ', ', $processing_output_labels ) . ' processing';
                        }
                        if ( ! empty( $not_generated_output_labels ) ) {
                            $reports_output_state_copy .= '; ' . implode( ', ', $not_generated_output_labels ) . ' not generated';
                        }
                        if ( ! empty( $locked_output_labels ) ) {
                            $reports_output_state_copy .= '; ' . implode( ', ', $locked_output_labels ) . ' locked on this package';
                        }
                        $reports_verified_count = 0;
                        $reports_review_count = 0;
                        $reports_locked_count = 0;
                        foreach ( $latest_outputs as $reports_output_meta ) {
                            $reports_output_item = isset( $reports_output_meta['item'] ) && is_array( $reports_output_meta['item'] ) ? $reports_output_meta['item'] : null;
                            $reports_output_kind = isset( $reports_output_meta['kind'] ) ? (string) $reports_output_meta['kind'] : '';
                            if ( ! self::export_kind_allowed_now( $reports_output_kind ) ) {
                                ++$reports_locked_count;
                            }
                            if ( is_array( $reports_output_item ) ) {
                                $reports_output_badge = self::canonical_report_trust_badge( $reports_output_item );
                                if ( 'Verified export' === ( $reports_output_badge['label'] ?? '' ) ) {
                                    ++$reports_verified_count;
                                } elseif ( 'Needs trust review' === ( $reports_output_badge['label'] ?? '' ) ) {
                                    ++$reports_review_count;
                                }
                            }
                        }
                        $reports_verification_item = self::best_report_verification_item( $context_report_items );
                        $reports_verification_status = ! empty( $reports_verification_item ) ? self::canonical_report_trust_badge( $reports_verification_item ) : array( 'tone' => 'neutral', 'label' => 'Not yet generated' );
                        $reports_verification_timestamp = ! empty( $reports_verification_item['verified_at_utc'] )
                            ? self::report_datetime_label( (string) $reports_verification_item['verified_at_utc'] )
                            : ( ! empty( $reports_verification_item['created_at_utc'] ) ? self::report_datetime_label( (string) $reports_verification_item['created_at_utc'] ) : 'No verification record for this run yet' );
                        $reports_verification_reference = ! empty( $reports_verification_item['export_job_id'] ) ? self::canonical_activity_reference_copy( 'Package reference', (string) $reports_verification_item['export_job_id'] ) : 'Package reference unavailable';
                        $reports_verification_retention = ! empty( $reports_verification_item['retention_policy_key'] ) ? (string) $reports_verification_item['retention_policy_key'] : 'Current policy visible when packaged outputs exist';
                        $reports_verification_reason = 'No report generated yet.';
                        if ( ! empty( $reports_verification_item ) ) {
                            $reports_verification_signature_state = strtolower( trim( (string) ( $reports_verification_item['signature_state'] ?? '' ) ) );
                            $reports_verification_status_key = strtolower( trim( (string) ( $reports_verification_item['verification_state'] ?? ( $reports_verification_item['verification_status'] ?? '' ) ) ) );
                            if ( in_array( $reports_verification_signature_state, array( 'verified', 'signed' ), true ) || 'verified' === $reports_verification_status_key ) {
                                $reports_verification_reason = 'Manifest reference and verification data are available for this packaged output.';
                            } elseif ( 'failed' === $reports_verification_signature_state || 'failed' === $reports_verification_status_key ) {
                                $reports_verification_reason = 'This packaged output recorded a verification failure and needs operator review.';
                            } else {
                                $reports_verification_reason = 'This packaged output is recorded, but verification has not completed yet.';
                            }
                        } elseif ( ! empty( $processing_output_labels ) ) {
                            $reports_verification_reason = 'Packaged outputs are still processing for this run.';
                        } elseif ( ! empty( $live_report_items ) ) {
                            $reports_verification_reason = 'No packaged output is recorded for this run yet. Historical packages remain available below.';
                        }

                        $reports_ready_count = count( $generated_output_labels );
                        $reports_processing_count = count( $processing_output_labels );
                        $reports_not_generated_count = count( $not_generated_output_labels );
                        $reports_current_tone = 'neutral';
                        if ( $reports_ready_count > 0 ) {
                            $reports_current_tone = 'good';
                        } elseif ( 'FAILED' === $latest_state ) {
                            $reports_current_tone = 'bad';
                        } elseif ( $reports_processing_count > 0 || $reports_not_generated_count > 0 ) {
                            $reports_current_tone = 'warn';
                        }

                        if ( $reports_ready_count > 0 ) {
                            $reports_current_headline = implode( ', ', $generated_output_labels ) . ' ready for this ' . $reports_context_phrase;
                        } elseif ( $reports_processing_count > 0 ) {
                            $reports_current_headline = 'Reports are still processing for this ' . $reports_context_phrase;
                        } elseif ( $reports_not_generated_count > 0 ) {
                            $reports_current_headline = 'Generate a report for this ' . $reports_context_phrase;
                        } else {
                            $reports_current_headline = 'Report readiness is pending for this ' . $reports_context_phrase;
                        }

                        $reports_current_summary_parts = array();
                        if ( $reports_ready_count > 0 ) {
                            $reports_current_summary_parts[] = implode( ', ', $generated_output_labels ) . ' can be reviewed now';
                        }
                        if ( $reports_processing_count > 0 ) {
                            $reports_current_summary_parts[] = implode( ', ', $processing_output_labels ) . ' still processing';
                        }
                        if ( $reports_not_generated_count > 0 ) {
                            $reports_current_summary_parts[] = implode( ', ', $not_generated_output_labels ) . ' can be generated from this run';
                        }
                        if ( $reports_locked_count > 0 ) {
                            $reports_current_summary_parts[] = sprintf( '%d format%s require a plan upgrade', $reports_locked_count, 1 === $reports_locked_count ? '' : 's' );
                        }
                        $reports_current_summary = ! empty( $reports_current_summary_parts )
                            ? implode( '. ', $reports_current_summary_parts ) . '.'
                            : $reports_output_state_copy . '.';

                        $reports_signature_label = 'Signature pending';
                        $reports_signature_copy = 'A signed packaged output will surface here when this run records verification data.';
                        if ( ! empty( $reports_verification_item ) ) {
                            $reports_signature_label = 'Signature recorded';
                            $reports_signature_copy = self::canonical_report_trust_copy( $reports_verification_item );
                            if ( 'Needs trust review' === ( $reports_verification_status['label'] ?? '' ) ) {
                                $reports_signature_label = 'Signature review needed';
                            } elseif ( 'Verified export' === ( $reports_verification_status['label'] ?? '' ) ) {
                                $reports_signature_label = 'Signature verified';
                            } elseif ( 'Signed export' === ( $reports_verification_status['label'] ?? '' ) ) {
                                $reports_signature_label = 'Signed package recorded';
                            }
                        } elseif ( ! empty( $processing_output_labels ) ) {
                            $reports_signature_copy = 'Signed package evidence will appear when the current export finishes processing.';
                        }

                        $reports_package_fit_copy = $reports_locked_count > 0
                            ? sprintf( '%d format%s not yet available on %s.', $reports_locked_count, 1 === $reports_locked_count ? '' : 's', isset( $reports_package['display_name'] ) ? (string) $reports_package['display_name'] : ucfirst( $eff_state['effective_plan'] ) )
                            : 'All report formats on your current plan are available.';
                        $reports_lifecycle_copy = ! empty( $reports_evidence_story['summary'] )
                            ? (string) $reports_evidence_story['summary']
                            : 'Report history is available for all completed scans.';
                        $reports_view_kind = isset( $_GET['view_kind'] ) ? sanitize_text_field( wp_unslash( $_GET['view_kind'] ) ) : '';
                        $reports_view_job_id = isset( $_GET['view_export_job_id'] ) ? sanitize_text_field( wp_unslash( $_GET['view_export_job_id'] ) ) : '';
                        $reports_show_json_package = 'json_package' === $reports_view_kind;
                        $reports_update_counts = self::update_posture_counts( $reports_update_posture );
                        $reports_vulnerability_summary = isset( $reports_vulnerability_posture['summary'] ) && is_array( $reports_vulnerability_posture['summary'] ) ? $reports_vulnerability_posture['summary'] : array();
                        $reports_vulnerability_match_count = isset( $reports_vulnerability_summary['match_count'] ) ? (int) $reports_vulnerability_summary['match_count'] : 0;
                        $reports_hardening_summary = isset( $reports_hardening_guidance['summary'] ) && is_array( $reports_hardening_guidance['summary'] ) ? $reports_hardening_guidance['summary'] : array();
                        $reports_hardening_title = isset( $reports_hardening_summary['guidance_title'] ) ? (string) $reports_hardening_summary['guidance_title'] : 'Hardening guidance not recorded';
                        $reports_hardening_copy = isset( $reports_hardening_summary['guidance_copy'] ) ? (string) $reports_hardening_summary['guidance_copy'] : 'No hardening guidance is recorded for this run.';
                        $reports_hardening_count = isset( $reports_hardening_summary['item_count'] ) ? (int) $reports_hardening_summary['item_count'] : count( $reports_hardening_detail_items );
                        $reports_summary_cards = array(
                            array(
                                'eyebrow' => 'Security score',
                                'value'   => ( null !== $reports_context_score ? (string) $reports_context_score : '—' ) . ' / ' . $reports_context_grade_label,
                                'copy'    => $reports_context_grade_summary,
                            ),
                            array(
                                'eyebrow' => 'Report status',
                                'value'   => $reports_output_state_copy,
                                'copy'    => $reports_current_summary,
                            ),
                            array(
                                'eyebrow' => 'Updates',
                                'value'   => ( (int) ( $reports_update_counts['outdated_total'] ?? 0 ) ) === 1 ? '1 update needed' : sprintf( '%d updates', (int) ( $reports_update_counts['outdated_total'] ?? 0 ) ),
                                'copy'    => ( (int) ( $reports_update_counts['outdated_total'] ?? 0 ) ) > 0 ? 'Updates are affecting this site\'s score.' : 'No updates needed.',
                            ),
                            array(
                                'eyebrow' => 'Vulnerabilities',
                                'value'   => $reports_vulnerability_match_count === 1 ? '1 vulnerability found' : sprintf( '%d vulnerabilities found', $reports_vulnerability_match_count ),
                                'copy'    => $reports_vulnerability_match_count > 0 ? 'Vulnerabilities are affecting this site\'s score.' : 'No vulnerabilities found in this scan.',
                            ),
                            array(
                                'eyebrow' => 'Remediation items',
                                'value'   => $reports_hardening_count > 0 ? sprintf( '%d remediation item%s', $reports_hardening_count, 1 === $reports_hardening_count ? '' : 's' ) : 'No open items',
                                'copy'    => $reports_hardening_copy,
                            ),
                        );
                        $reports_summary_meaning_title = 'The latest packaged view is customer-ready';
                        $reports_summary_meaning_copy = 'Use the rendered report first, then open the support package only when you need deeper verification detail.';
                        if ( 'external_only' === $reports_connection_status ) {
                            $reports_summary_meaning_title = 'This site is still external-only';
                            $reports_summary_meaning_copy = 'Reports stay honest to public-check evidence until the connector is paired for authenticated WordPress truth.';
                        } elseif ( in_array( $reports_connection_status, array( 'pairing_pending', 'credential_invalid', 'disconnected' ), true ) ) {
                            $reports_summary_meaning_title = 'Connected reporting needs connection follow-up';
                            $reports_summary_meaning_copy = 'The report surface stays truthful, but authenticated connected evidence will remain limited until the connector state is restored.';
                        } elseif ( $reports_vulnerability_match_count > 0 || (int) ( $reports_update_counts['outdated_total'] ?? 0 ) > 0 ) {
                            $reports_summary_meaning_title = 'This report highlights remediation work';
                            $reports_summary_meaning_copy = 'Use the summary to explain the findings, then review the vulnerability details.';
                        }
                        $reports_action_cards = array();
                        if ( in_array( $reports_context_state, array( 'QUEUED', 'RUNNING' ), true ) || $reports_processing_count > 0 ) {
                            $reports_action_cards[] = array(
                                'eyebrow' => 'Live progress',
                                'title'   => 'Refresh while outputs are still processing',
                                'copy'    => 'The current run or export is still active. Refresh this page to pick up the next rendered report state.',
                                'url'     => $reports_refresh_url,
                                'label'   => 'Refresh report center',
                            );
                        }
                        if ( 'external_only' === $reports_connection_status ) {
                            $reports_action_cards[] = array(
                                'eyebrow' => 'Connection path',
                                'title'   => 'Connect the site for fuller report depth',
                                'copy'    => 'External-only reporting is honest public evidence. Pair the connector in Settings to add authenticated inventory, updates, and vulnerabilities.',
                                'url'     => self::admin_tab_url( 'settings' ),
                                'label'   => 'Open Settings',
                            );
                        } elseif ( in_array( $reports_connection_status, array( 'pairing_pending', 'credential_invalid', 'disconnected' ), true ) ) {
                            $reports_action_cards[] = array(
                                'eyebrow' => 'Connection path',
                                'title'   => 'Restore the connector trust path',
                                'copy'    => 'Connected report detail depends on canonical connector truth. Complete pairing or reconnect before relying on authenticated site data.',
                                'url'     => self::admin_tab_url( 'settings' ),
                                'label'   => 'Restore Connection',
                            );
                        }
                        if ( $reports_vulnerability_match_count > 0 ) {
                            $reports_action_cards[] = array(
                                'eyebrow' => 'Critical follow-up',
                                'title'   => 'Review vulnerabilities from the report',
                                'copy'    => 'Start with the summary, then open Scan for the exact vulnerability details for this site.',
                                'url'     => self::admin_tab_url( 'triage', array( 'opsgate_detail' => 'vulnerabilities' ) ),
                                'label'   => 'Open Vulnerabilities',
                            );
                        } elseif ( (int) ( $reports_update_counts['outdated_total'] ?? 0 ) > 0 ) {
                            $reports_action_cards[] = array(
                                'eyebrow' => 'Warning follow-up',
                                'title'   => 'Review update drift behind this report',
                                'copy'    => 'Use the update evidence to explain why posture changed and what should be patched first.',
                                'url'     => self::admin_tab_url( 'triage', array( 'opsgate_detail' => 'updates' ) ),
                                'label'   => 'Open Updates',
                            );
                        }
                        if ( $reports_hardening_count > 0 ) {
                            $reports_action_cards[] = array(
                                'eyebrow' => 'Hardening guidance',
                                'title'   => $reports_hardening_title,
                                'copy'    => $reports_hardening_copy,
                                'url'     => self::admin_tab_url( 'triage', array( 'opsgate_detail' => 'hardening' ) ),
                                'label'   => 'Open Guidance',
                            );
                        }
                        if ( empty( $reports_action_cards ) ) {
                            $reports_action_cards[] = array(
                                'eyebrow' => 'Next step',
                                'title'   => 'View the latest rendered report',
                                'copy'    => 'The default report surface is the customer-friendly view. Keep the technical package for support and export workflows only.',
                                'url'     => $reports_refresh_url,
                                'label'   => 'Stay on Reports',
                            );
                        }
                        $reports_action_cards = array_slice( $reports_action_cards, 0, 3 );
                        $reports_primary_action = $reports_action_cards[0];
                        $reports_glossary_cards = self::canonical_customer_explanation_cards();

                        $reports_advanced_artifact_job_id = $reports_context_source_job_id;
                        $reports_advanced_artifacts = array();
                        if ( '' !== $reports_advanced_artifact_job_id ) {
                            $reports_artifact_kinds = array(
                                'Inventory JSON'      => 'inventory_snapshot',
                                'Update JSON'         => 'update_posture',
                                'Vulnerability JSON'  => 'vulnerability_posture',
                                'Reachability JSON'   => 'reachability_posture',
                                'Availability JSON'   => 'availability_snapshot',
                                'Performance JSON'    => 'performance_snapshot',
                                'Validation JSON'     => 'configuration_validation',
                                'Uptime JSON'         => 'uptime_window',
                                'Log Intelligence JSON' => 'operational_log_intelligence',
                                'Safe-Update JSON'    => 'safe_update_smoke_check',
                                'Hardening Guidance JSON' => 'hardening_guidance',
                            );

                            foreach ( $reports_artifact_kinds as $reports_artifact_label => $reports_artifact_kind ) {
                                $reports_advanced_artifacts[] = array(
                                    'label' => $reports_artifact_label,
                                    'url'   => wp_nonce_url(
                                        add_query_arg(
                                            array(
                                                'action' => 'opsgate_download_triage_artifact',
                                                'job_id' => $reports_advanced_artifact_job_id,
                                                'kind'   => $reports_artifact_kind,
                                            ),
                                            admin_url( 'admin-post.php' )
                                        ),
                                        'opsgate_download_triage_artifact'
                                    ),
                                );
                            }
                        }

                        $reports_history_groups = array();
                        foreach ( $report_items as $item ) {
                            if ( ! is_array( $item ) ) {
                                continue;
                            }

                            $group_source_job_id = isset( $item['source_job_id'] ) ? trim( (string) $item['source_job_id'] ) : '';
                            if ( '' === $group_source_job_id ) {
                                $group_source_job_id = isset( $item['export_job_id'] ) ? trim( (string) $item['export_job_id'] ) : '';
                            }

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

                            if ( '' !== $reports_context_source_job_id && $group_source_job_id === $reports_context_source_job_id ) {
                                continue;
                            }

                            if ( ! isset( $reports_history_groups[ $group_source_job_id ] ) ) {
                                $reports_history_groups[ $group_source_job_id ] = array(
                                    'source_job_id' => $group_source_job_id,
                                    'created_at_utc' => isset( $item['created_at_utc'] ) ? (string) $item['created_at_utc'] : '',
                                    'latest_state' => isset( $item['state'] ) ? strtoupper( (string) $item['state'] ) : '',
                                    'items' => array(),
                                );
                            }

                            $reports_history_groups[ $group_source_job_id ]['items'][] = $item;
                        }

                        foreach ( $reports_history_groups as $reports_history_group_key => $reports_history_group ) {
                            $reports_history_items = isset( $reports_history_group['items'] ) && is_array( $reports_history_group['items'] ) ? $reports_history_group['items'] : array();
                            usort(
                                $reports_history_items,
                                static function ( $a, $b ) {
                                    $a_time = self::report_item_sort_timestamp( is_array( $a ) ? $a : array() );
                                    $b_time = self::report_item_sort_timestamp( is_array( $b ) ? $b : array() );

                                    if ( $a_time === $b_time ) {
                                        return 0;
                                    }

                                    return ( $a_time > $b_time ) ? -1 : 1;
                                }
                            );
                            $reports_history_groups[ $reports_history_group_key ]['items'] = $reports_history_items;
                            if ( ! empty( $reports_history_items ) ) {
                                $reports_history_groups[ $reports_history_group_key ]['created_at_utc'] = isset( $reports_history_items[0]['created_at_utc'] ) ? (string) $reports_history_items[0]['created_at_utc'] : '';
                                $reports_history_groups[ $reports_history_group_key ]['latest_state'] = isset( $reports_history_items[0]['state'] ) ? strtoupper( (string) $reports_history_items[0]['state'] ) : '';
                            }
                        }

                        uasort(
                            $reports_history_groups,
                            static function ( $a, $b ) {
                                $a_time = isset( $a['created_at_utc'] ) ? self::report_item_sort_timestamp( array( 'created_at_utc' => (string) $a['created_at_utc'] ) ) : 0;
                                $b_time = isset( $b['created_at_utc'] ) ? self::report_item_sort_timestamp( array( 'created_at_utc' => (string) $b['created_at_utc'] ) ) : 0;

                                if ( $a_time === $b_time ) {
                                    return 0;
                                }

                                return ( $a_time > $b_time ) ? -1 : 1;
                            }
                        );
                        ?>
                        <div
                            id="opsgate-reports-live-panel"
                            data-opsgate-live-states="<?php echo esc_attr( implode( ',', $reports_live_states ) ); ?>"
                            data-opsgate-poll-url="<?php echo esc_url( $reports_status_poll_url ); ?>"
                            data-opsgate-refresh-url="<?php echo esc_url( $reports_refresh_url ); ?>"
                            data-opsgate-ajax-url="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"
                            data-opsgate-export-nonce="<?php echo esc_attr( wp_create_nonce( 'opsgate_export_start_ajax' ) ); ?>"
                            data-opsgate-current-source-job-id="<?php echo esc_attr( $reports_current_source_job_id ); ?>"
                            data-opsgate-current-export-job-id="<?php echo esc_attr( $reports_current_export_poll_id ); ?>"
                            data-opsgate-rendered-source-job-id="<?php echo esc_attr( $reports_context_source_job_id ); ?>"
                            data-opsgate-rendered-export-job-id="<?php echo esc_attr( $latest_job_id ); ?>"
                        >
                            <div class="opsgate-card opsgate-reports-dashboard">
                        <div class="opsgate-reports-header">
                            <div class="opsgate-reports-header-copy">
                                <h2 class="opsgate-reports-title">Reports</h2>
                                <p class="opsgate-reports-subtitle"><?php echo esc_html( $reports_intro_copy ); ?></p>
                                <p class="opsgate-alerts-history-copy"><?php echo esc_html( $reports_connection_label . ' · ' . $reports_connection_copy ); ?></p>
                            </div>
                                    <div class="opsgate-reports-actions">
                                        <a class="button button-secondary opsgate-reports-action-link" href="<?php echo esc_url( $reports_refresh_url ); ?>">Refresh report center</a>
                                        <a class="button button-secondary opsgate-reports-action-link" href="<?php echo esc_url( $reports_triage_url ); ?>">Return to Triage</a>
                                    </div>
                                </div>
                                <div id="opsgate-reports-status-box" class="opsgate-alert-inline-status" role="status" aria-live="polite"><p></p></div>

                                <?php if ( $reports_ready_count > 0 ) : ?>
                                <div class="opsgate-reports-ready-band">
                                    <div class="opsgate-reports-ready-copy">
                                        <p class="opsgate-reports-ready-title"><?php echo esc_html( implode( ', ', $generated_output_labels ) ); ?> ready for <?php echo esc_html( $reports_context_phrase ); ?></p>
                                        <p class="opsgate-reports-ready-meta"><?php echo esc_html( $reports_scope_label ); ?> · <?php echo esc_html( $reports_run_label ); ?></p>
                                    </div>
                                    <div>
                                        <?php foreach ( $latest_outputs as $ready_output_meta ) : ?>
                                            <?php
                                            $ready_item = isset( $ready_output_meta['item'] ) && is_array( $ready_output_meta['item'] ) ? $ready_output_meta['item'] : null;
                                            if ( null === $ready_item || 'COMPLETED' !== strtoupper( (string) ( $ready_item['state'] ?? '' ) ) ) {
                                                continue;
                                            }
                                            $ready_url = '' !== trim( (string) ( $ready_item['download_url'] ?? '' ) ) ? (string) $ready_item['download_url'] : '';
                                            if ( '' === $ready_url ) {
                                                continue;
                                            }
                                            ?>
                                            <a class="button button-secondary" href="<?php echo esc_url( $ready_url ); ?>" target="_blank" rel="noopener">
                                                <?php echo esc_html( $ready_output_meta['label'] ); ?>
                                            </a>
                                        <?php endforeach; ?>
                                        <?php
                                        // Phase 4: Send to client — Starter+ only, requires at least one ready output
                                        $delivery_plan = $eff_state['effective_plan'];
                                        $delivery_allowed = in_array( $delivery_plan, array( 'starter', 'pro', 'agency' ), true );
                                        $delivery_api_base = self::mcp_base_url();
                                        $delivery_exec_ctx = self::current_site_execution_context();
                                        $delivery_site_id  = isset( $delivery_exec_ctx['site_id'] ) ? (string) $delivery_exec_ctx['site_id'] : '';
                                        $delivery_job_id   = $reports_context_source_job_id ?? '';
                                        if ( $delivery_allowed && '' !== $delivery_site_id && '' !== $delivery_job_id ) :
                                        ?>
                                        <button
                                            type="button"
                                            class="button button-primary opsgate-send-to-client-btn"
                                            data-delivery-site-id="<?php echo esc_attr( $delivery_site_id ); ?>"
                                            data-delivery-job-id="<?php echo esc_attr( $delivery_job_id ); ?>"
                                            data-delivery-nonce="<?php echo esc_attr( wp_create_nonce( 'opsgate_report_deliver' ) ); ?>"
                                            data-delivery-ajax-url="<?php echo esc_attr( admin_url( 'admin-ajax.php' ) ); ?>"
                                            style="margin-left:8px;"
                                        >
                                            Send to client &rarr;
                                        </button>
                                        <div id="opsgate-deliver-modal" class="opsgate-deliver-modal" role="dialog" aria-modal="true" aria-labelledby="opsgate-deliver-modal-title" hidden>
                                            <div class="opsgate-deliver-modal-inner">
                                                <h3 id="opsgate-deliver-modal-title" class="opsgate-deliver-modal-title">Send report to client</h3>
                                                <p class="opsgate-deliver-modal-copy">Enter the recipient email address. OpsGate will queue the report for delivery from reports@opsgate.ca.</p>
                                                <label class="opsgate-deliver-modal-label" for="opsgate-deliver-email">Recipient email</label>
                                                <input id="opsgate-deliver-email" class="opsgate-deliver-modal-input" type="email" placeholder="client@example.com" autocomplete="email" />
                                                <div id="opsgate-deliver-status" class="opsgate-deliver-modal-status" role="status" aria-live="polite"></div>
                                                <div class="opsgate-deliver-modal-actions">
                                                    <button type="button" id="opsgate-deliver-submit" class="button button-primary">Send report</button>
                                                    <button type="button" id="opsgate-deliver-cancel" class="button button-secondary">Cancel</button>
                                                </div>
                                            </div>
                                        </div>
                                        <?php endif; ?>
                                    </div>
                                </div>
                                <?php endif; ?>

                                <section class="opsgate-reports-current-band opsgate-reports-current-band-tone-<?php echo esc_attr( $reports_current_tone ); ?>">
                                    <div class="opsgate-reports-current-main">
                                        <span class="opsgate-reports-eyebrow">Current report state</span>
                                        <div class="opsgate-reports-output-top">
                                            <h3 class="opsgate-reports-current-title"><?php echo esc_html( $reports_current_headline ); ?></h3>
                                            <span class="opsgate-reports-output-state opsgate-reports-output-state-<?php echo esc_attr( $reports_current_tone ); ?>">
                                                <?php
                                                if ( $reports_ready_count > 0 ) {
                                                    echo esc_html( 'Ready now' );
                                                } elseif ( $reports_processing_count > 0 ) {
                                                    echo esc_html( 'Processing' );
                                                } elseif ( $reports_not_generated_count > 0 ) {
                                                    echo esc_html( 'Generate now' );
                                                } else {
                                                    echo esc_html( 'Pending' );
                                                }
                                                ?>
                                            </span>
                                        </div>
                                        <p class="opsgate-reports-current-copy"><?php echo esc_html( $reports_current_summary ); ?></p>
                                        <div class="opsgate-reports-rail-pill-row">
                                            <?php if ( $reports_ready_count > 0 ) : ?>
                                                <span class="opsgate-reports-rail-pill opsgate-reports-rail-pill-soft-good"><?php echo esc_html( sprintf( '%d ready now', $reports_ready_count ) ); ?></span>
                                            <?php endif; ?>
                                            <?php if ( $reports_processing_count > 0 ) : ?>
                                                <span class="opsgate-reports-rail-pill opsgate-reports-rail-pill-soft-warn"><?php echo esc_html( sprintf( '%d processing', $reports_processing_count ) ); ?></span>
                                            <?php endif; ?>
                                            <?php if ( $reports_not_generated_count > 0 ) : ?>
                                                <span class="opsgate-reports-rail-pill opsgate-reports-rail-pill-soft-info"><?php echo esc_html( sprintf( '%d available to generate', $reports_not_generated_count ) ); ?></span>
                                            <?php endif; ?>
                                            <?php if ( $reports_locked_count > 0 ) : ?>
                                                <span class="opsgate-reports-rail-pill opsgate-reports-rail-pill-soft-warn"><?php echo esc_html( sprintf( '%d format%s require upgrade', $reports_locked_count, 1 === $reports_locked_count ? '' : 's' ) ); ?></span>
                                            <?php endif; ?>
                                        </div>
                                    </div>
                                    <aside class="opsgate-reports-current-side">
                                        <span class="opsgate-reports-eyebrow"><?php echo esc_html( $selected_live_context ? 'Selected run' : 'Latest run' ); ?></span>
                                        <div class="opsgate-reports-current-side-title"><?php echo esc_html( $reports_run_label ); ?></div>
                                        <p class="opsgate-reports-current-side-copy"><?php echo esc_html( $reports_scope_label ); ?></p>
                                        <p class="opsgate-reports-current-side-copy"><?php echo esc_html( 'Scan status: ' . $reports_latest_state_label ); ?></p>
                                    </aside>
                                </section>

                                <div class="opsgate-reports-trust-band">
                                    <article class="opsgate-reports-trust-panel opsgate-reports-trust-panel-tone-<?php echo esc_attr( empty( $reports_verification_item ) ? 'neutral' : ( $reports_verification_status['tone'] ?? 'neutral' ) ); ?>">
                                        <span class="opsgate-reports-eyebrow">Report verification</span>
                                        <div class="opsgate-reports-trust-panel-value"><?php echo esc_html( $reports_verification_status['label'] ?? 'Verification pending' ); ?></div>
                                        <p class="opsgate-reports-trust-panel-copy"><?php echo esc_html( $reports_verification_reason ); ?></p>
                                    </article>
                                    <article class="opsgate-reports-trust-panel opsgate-reports-trust-panel-tone-<?php echo esc_attr( in_array( $reports_verification_status['tone'] ?? 'neutral', array( 'good', 'bad' ), true ) ? ( $reports_verification_status['tone'] ?? 'good' ) : 'neutral' ); ?>">
                                        <span class="opsgate-reports-eyebrow">Export signature</span>
                                        <div class="opsgate-reports-trust-panel-value"><?php echo esc_html( $reports_signature_label ); ?></div>
                                        <p class="opsgate-reports-trust-panel-copy"><?php echo esc_html( $reports_signature_copy ); ?></p>
                                    </article>
                                    <article class="opsgate-reports-trust-panel opsgate-reports-trust-panel-tone-<?php echo esc_attr( $reports_locked_count > 0 ? 'warn' : 'info' ); ?>">
                                        <span class="opsgate-reports-eyebrow">Plan &amp; formats</span>
                                        <div class="opsgate-reports-trust-panel-value"><?php echo esc_html( isset( $reports_package['display_name'] ) ? (string) $reports_package['display_name'] : ucfirst( $eff_state['effective_plan'] ) ); ?></div>
                                        <p class="opsgate-reports-trust-panel-copy"><?php echo esc_html( $reports_package_fit_copy ); ?></p>
                                        <p class="opsgate-reports-trust-panel-meta"><?php echo esc_html( $reports_lifecycle_copy ); ?></p>
                                    </article>
                                </div>

                                <details class="opsgate-r1-support-demotion" style="margin-bottom:12px;">
                                    <summary class="opsgate-r1-support-demotion-summary">Report details</summary>
                                    <div class="opsgate-reports-status-strip">
                                        <div class="opsgate-reports-status-item opsgate-reports-status-item-tone-info"><span class="opsgate-reports-status-label"><?php echo esc_html( $selected_live_context ? 'Selected scan' : 'Latest scan' ); ?></span><span class="opsgate-reports-status-value"><?php echo esc_html( $reports_run_label ); ?></span></div>
                                        <div class="opsgate-reports-status-item opsgate-reports-status-item-tone-info"><span class="opsgate-reports-status-label">Site</span><span class="opsgate-reports-status-value"><?php echo esc_html( $reports_scope_label ); ?></span></div>
                                        <div class="opsgate-reports-status-item opsgate-reports-status-item-tone-<?php echo esc_attr( $reports_latest_state_tone ); ?>"><span class="opsgate-reports-status-label">Scan status</span><span class="opsgate-reports-status-value"><?php echo esc_html( $reports_latest_state_label ); ?></span></div>
                                        <div class="opsgate-reports-status-item opsgate-reports-status-item-tone-<?php echo esc_attr( 'neutral' === $reports_current_tone ? 'info' : $reports_current_tone ); ?>"><span class="opsgate-reports-status-label">Report status</span><span class="opsgate-reports-status-value"><?php echo esc_html( $reports_output_state_copy ); ?></span></div>
                                        <div class="opsgate-reports-status-item opsgate-reports-status-item-tone-<?php echo esc_attr( 'neutral' === ( $reports_verification_status['tone'] ?? 'warn' ) ? 'info' : ( $reports_verification_status['tone'] ?? 'warn' ) ); ?>"><span class="opsgate-reports-status-label">Verification</span><span class="opsgate-reports-status-value"><?php echo esc_html( $reports_verification_status['label'] ?? 'Not yet generated' ); ?></span></div>
                                        <div class="opsgate-reports-status-item opsgate-reports-status-item-tone-info"><span class="opsgate-reports-status-label">Scan reference</span><span class="opsgate-reports-status-value"><?php echo '' !== $reports_context_source_job_id ? esc_html( strlen( $reports_context_source_job_id ) > 18 ? substr( $reports_context_source_job_id, 0, 6 ) . '…' . substr( $reports_context_source_job_id, -8 ) : $reports_context_source_job_id ) : esc_html( 'Unavailable' ); ?></span></div>
                                    </div>
                                </details>


                                <section class="opsgate-reports-surface opsgate-reports-story-surface">
                                    <div class="opsgate-reports-surface-header">
                                        <h3 class="opsgate-reports-surface-title">Scan summary</h3>
                                        <span class="opsgate-reports-surface-link">Report overview</span>
                                    </div>
                                    <div class="opsgate-reports-story-grid">
                                        <?php foreach ( $reports_summary_cards as $reports_summary_card ) : ?>
                                            <article class="opsgate-reports-story-card">
                                                <span class="opsgate-reports-eyebrow"><?php echo esc_html( (string) $reports_summary_card['eyebrow'] ); ?></span>
                                                <div class="opsgate-reports-story-value"><?php echo esc_html( (string) $reports_summary_card['value'] ); ?></div>
                                                <p class="opsgate-reports-story-copy"><?php echo esc_html( (string) $reports_summary_card['copy'] ); ?></p>
                                            </article>
                                        <?php endforeach; ?>
                                    </div>
                                    <div class="opsgate-reports-story-note-grid">
                                        <article class="opsgate-reports-story-note">
                                            <span class="opsgate-reports-eyebrow">Executive summary</span>
                                            <div class="opsgate-reports-story-note-title"><?php echo esc_html( $reports_current_headline ); ?></div>
                                            <p class="opsgate-reports-story-note-copy"><?php echo esc_html( $reports_current_summary ); ?></p>
                                        </article>
                                        <article class="opsgate-reports-story-note">
                                            <span class="opsgate-reports-eyebrow">What this means</span>
                                            <div class="opsgate-reports-story-note-title"><?php echo esc_html( $reports_summary_meaning_title ); ?></div>
                                            <p class="opsgate-reports-story-note-copy"><?php echo esc_html( $reports_summary_meaning_copy ); ?></p>
                                        </article>
                                        <article class="opsgate-reports-story-note">
                                            <span class="opsgate-reports-eyebrow">Next step</span>
                                            <div class="opsgate-reports-story-note-title"><?php echo esc_html( $reports_primary_action['title'] ); ?></div>
                                            <p class="opsgate-reports-story-note-copy"><?php echo esc_html( $reports_primary_action['copy'] ); ?></p>
                                            <a class="button button-secondary opsgate-reports-output-button" href="<?php echo esc_url( $reports_primary_action['url'] ); ?>"><?php echo esc_html( $reports_primary_action['label'] ); ?></a>
                                        </article>
                                    </div>
                                </section>

                                <?php if ( $reports_ready_count === 0 && $reports_not_generated_count > 0 && '' !== $reports_context_source_job_id ) : ?>
                                <div class="opsgate-reports-generate-cta">
                                    <div class="opsgate-reports-generate-cta-copy">
                                        <strong>No report generated yet</strong>
                                        <p>A scan is recorded for this site. Generate your first report to package and share the results.</p>
                                    </div>
                                    <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="opsgate-reports-inline-form" data-opsgate-export-form="1">
                                        <input type="hidden" name="action" value="opsgate_export_report_pdf">
                                        <input type="hidden" name="source_job_id" value="<?php echo esc_attr( $reports_context_source_job_id ); ?>">
                                        <?php wp_nonce_field( 'opsgate_export_report_pdf' ); ?>
                                        <button type="submit" class="button button-primary">Generate report &rarr;</button>
                                    </form>
                                </div>
                                <?php endif; ?>

                                <div class="opsgate-reports-filter-bar" id="opsgate-reports-filter-bar" role="toolbar" aria-label="Filter outputs">
                                    <button type="button" class="opsgate-reports-filter-btn is-active" data-og-report-filter="all">All</button>
                                    <button type="button" class="opsgate-reports-filter-btn" data-og-report-filter="ready">Ready</button>
                                    <button type="button" class="opsgate-reports-filter-btn" data-og-report-filter="pending">Pending</button>
                                    <button type="button" class="opsgate-reports-filter-btn" data-og-report-filter="failed">Failed</button>
                                    <span class="opsgate-reports-filter-divider" aria-hidden="true"></span>
                                    <button type="button" class="opsgate-reports-filter-btn" data-og-report-filter="pdf">PDF</button>
                                    <button type="button" class="opsgate-reports-filter-btn" data-og-report-filter="html">HTML</button>
                                    <button type="button" class="opsgate-reports-filter-btn" data-og-report-filter="csv">CSV</button>
                                    <button type="button" class="opsgate-reports-filter-btn" data-og-report-filter="xlsx">Excel</button>
                                </div>
                                <div id="opsgate-reports-filter-empty" class="opsgate-r1-empty-state" style="display:none;" role="status">No outputs match this filter.</div>

                                <div class="opsgate-reports-columns">
                                    <section class="opsgate-reports-surface opsgate-reports-surface-main">
                                        <div class="opsgate-reports-surface-header">
                                            <h3 class="opsgate-reports-surface-title">Client-ready outputs</h3>
                                            <span class="opsgate-reports-surface-link"><?php echo esc_html( $reports_output_state_copy ); ?></span>
                                        </div>

                                        <div class="opsgate-reports-output-grid" id="opsgate-reports-output-grid">
                                            <?php foreach ( $latest_outputs as $latest_output_key => $latest_output_meta ) : ?>
                                                <?php
                                                $latest_output_label = isset( $latest_output_meta['label'] ) ? (string) $latest_output_meta['label'] : 'Output';
                                                $latest_output_item = isset( $latest_output_meta['item'] ) && is_array( $latest_output_meta['item'] ) ? $latest_output_meta['item'] : null;
                                                $latest_output_kind = '';
                                                $latest_output_job_id = '';
                                                $latest_output_state = '';
                                                $latest_output_status_label = 'Not generated';
                                                $latest_output_status_tone = 'pending';
                                                $latest_output_created = 'Generate this packaged output for the recorded run.';
                                                $latest_output_download = '';
                                                $latest_output_view_url = '';
                                                $latest_output_generate_action = '';
                                                $latest_output_generate_nonce = '';
                                                $latest_output_generate_label = 'Generate';

                                                if ( is_array( $latest_output_item ) ) {
                                                    $latest_output_kind = isset( $latest_output_item['kind'] ) ? (string) $latest_output_item['kind'] : '';
                                                    $latest_output_job_id = isset( $latest_output_item['export_job_id'] ) ? (string) $latest_output_item['export_job_id'] : '';
                                                    $latest_output_state = isset( $latest_output_item['state'] ) ? strtoupper( (string) $latest_output_item['state'] ) : '';
                                                    if ( 'COMPLETED' === $latest_output_state ) {
                                                        $latest_output_status_label = 'Ready';
                                                    } elseif ( 'RUNNING' === $latest_output_state ) {
                                                        $latest_output_status_label = 'Processing';
                                                    } elseif ( 'QUEUED' === $latest_output_state ) {
                                                        $latest_output_status_label = 'Pending';
                                                    } elseif ( 'FAILED' === $latest_output_state ) {
                                                        $latest_output_status_label = 'Failed';
                                                    }
                                                    if ( 'COMPLETED' === $latest_output_state ) {
                                                        $latest_output_status_tone = 'good';
                                                    } elseif ( in_array( $latest_output_state, array( 'QUEUED', 'RUNNING' ), true ) ) {
                                                        $latest_output_status_tone = 'warn';
                                                    } elseif ( 'FAILED' === $latest_output_state ) {
                                                        $latest_output_status_tone = 'bad';
                                                    }
                                                    if ( 'COMPLETED' === $latest_output_state ) {
                                                        $latest_output_created = isset( $latest_output_item['created_at_utc'] ) ? self::report_datetime_label( (string) $latest_output_item['created_at_utc'] ) : 'Ready';
                                                    } elseif ( 'FAILED' === $latest_output_state ) {
                                                        $latest_output_created = 'The latest generation attempt failed. Start a new export from this run.';
                                                    } else {
                                                        $latest_output_created = 'Packaged output is still being prepared for this run.';
                                                    }
                                                    if ( 'COMPLETED' === $latest_output_state ) {
                                                        $latest_output_download = self::canonical_report_download_url( $latest_output_kind, $latest_output_job_id );
                                                        $latest_output_view_url = self::canonical_report_download_url( $latest_output_kind, $latest_output_job_id, 'view' );
                                                    }
                                                }

                                                if ( 'pdf' === $latest_output_key ) {
                                                    $latest_output_generate_action = 'opsgate_export_report_pdf';
                                                    $latest_output_generate_nonce = 'opsgate_export_report_pdf';
                                                } elseif ( 'html' === $latest_output_key ) {
                                                    $latest_output_generate_action = 'opsgate_export_report_html';
                                                    $latest_output_generate_nonce = 'opsgate_export_report_html';
                                                } elseif ( 'csv' === $latest_output_key ) {
                                                    $latest_output_generate_action = 'opsgate_export_triage_csv';
                                                    $latest_output_generate_nonce = 'opsgate_export_triage_csv';
                                                } elseif ( 'xlsx' === $latest_output_key ) {
                                                    $latest_output_generate_action = 'opsgate_export_report_xlsx';
                                                    $latest_output_generate_nonce = 'opsgate_export_report_xlsx';
                                                } elseif ( 'json' === $latest_output_key ) {
                                                    $latest_output_generate_action = 'opsgate_export_triage_json';
                                                    $latest_output_generate_nonce = 'opsgate_export_triage_json';
                                                } elseif ( 'xml' === $latest_output_key ) {
                                                    $latest_output_generate_action = 'opsgate_export_triage_xml';
                                                    $latest_output_generate_nonce = 'opsgate_export_triage_xml';
                                                }

                                                if ( 'FAILED' === $latest_output_state ) {
                                                    $latest_output_generate_label = 'Generate again';
                                                }
                                                $latest_output_kind_for_policy = '' !== $latest_output_kind ? $latest_output_kind : ( 'csv' === $latest_output_key ? 'csv' : (string) $latest_output_meta['kind'] );
                                                $latest_output_is_allowed = self::export_kind_allowed_now( $latest_output_kind_for_policy );
                                                $latest_output_package_status_label = $latest_output_is_allowed ? 'Available on your plan' : 'Requires plan upgrade';
                                                $latest_output_package_status_tone = $latest_output_is_allowed ? 'info' : 'warn';
                                                $latest_output_trust_copy = is_array( $latest_output_item )
                                                    ? self::canonical_report_trust_copy( $latest_output_item )
                                                    : 'Verification will appear after a packaged output is recorded.';
                                                $latest_output_trust_badge = is_array( $latest_output_item ) ? self::canonical_report_trust_badge( $latest_output_item ) : array(
                                                    'tone' => $latest_output_is_allowed ? 'neutral' : 'warn',
                                                    'label' => 'Not yet generated',
                                                );
                                                $latest_output_detail_copy = '';
                                                if ( is_array( $latest_output_item ) && 'COMPLETED' === $latest_output_state ) {
                                                    $latest_output_created = 'Report is ready.';
                                                    $latest_output_detail_copy = $latest_output_trust_copy;
                                                } elseif ( is_array( $latest_output_item ) && 'FAILED' === $latest_output_state ) {
                                                    $latest_output_created = 'The latest output generation failed for this run.';
                                                    $latest_output_detail_copy = $latest_output_trust_copy;
                                                } elseif ( is_array( $latest_output_item ) && in_array( $latest_output_state, array( 'QUEUED', 'RUNNING' ), true ) ) {
                                                    $latest_output_created = 'Current run output is still processing.';
                                                } elseif ( $latest_output_is_allowed ) {
                                                    $latest_output_created = 'Current run output has not been generated yet.';
                                                } else {
                                                    $latest_output_created = self::export_kind_unavailable_copy( $latest_output_kind_for_policy );
                                                    $latest_output_detail_copy = self::export_kind_unavailable_copy( $latest_output_kind_for_policy );
                                                }
                                                ?>
                                                <article
                                                    class="opsgate-reports-output-card"
                                                    data-og-report-format="<?php echo esc_attr( $latest_output_key ); ?>"
                                                    data-og-report-state="<?php echo esc_attr( strtolower( $latest_output_status_label ) ); ?>"
                                                >
                                                    <div class="opsgate-reports-output-top">
                                                        <span class="opsgate-reports-output-label"><?php echo esc_html( $latest_output_label ); ?></span>
                                                        <span class="opsgate-reports-output-state opsgate-reports-output-state-<?php echo esc_attr( $latest_output_status_tone ); ?>"><?php echo esc_html( $latest_output_status_label ); ?></span>
                                                    </div>
                                                    <div class="opsgate-reports-output-badge-row">
                                                        <span class="opsgate-reports-rail-pill opsgate-reports-rail-pill-soft-<?php echo esc_attr( $latest_output_package_status_tone ); ?>"><?php echo esc_html( $latest_output_package_status_label ); ?></span>
                                                        <span class="opsgate-reports-rail-pill opsgate-reports-rail-pill-soft-<?php echo esc_attr( $latest_output_trust_badge['tone'] ?? 'neutral' ); ?>"><?php echo esc_html( $latest_output_trust_badge['label'] ?? 'Trust state pending' ); ?></span>
                                                    </div>
                                                    <p class="opsgate-reports-output-meta"><?php echo esc_html( $latest_output_created ); ?></p>
                                                    <?php if ( '' !== $latest_output_detail_copy ) : ?>
                                                        <p class="opsgate-reports-output-meta"><?php echo esc_html( $latest_output_detail_copy ); ?></p>
                                                    <?php endif; ?>
                                                    <div class="opsgate-reports-output-actions">
                                                        <?php if ( '' !== $latest_output_view_url ) : ?>
                                                            <button type="button" class="button button-secondary opsgate-reports-output-button opsgate-reports-viewer-trigger" data-viewer-kind="<?php echo esc_attr( $latest_output_label ); ?>" data-viewer-url="<?php echo esc_url( $latest_output_view_url ); ?>"><?php echo esc_html( self::canonical_report_view_action_label( $latest_output_kind_for_policy ) ); ?></button>
                                                        <?php else : ?>
                                                            <span class="opsgate-reports-output-empty"><?php echo esc_html( self::canonical_report_view_unavailable_copy( $latest_output_kind_for_policy, $latest_output_state ) ); ?></span>
                                                        <?php endif; ?>
                                                        <?php if ( 'COMPLETED' === $latest_output_state && '' !== $latest_output_download ) : ?>
                                                            <a class="button button-secondary opsgate-reports-output-button" href="<?php echo esc_url( $latest_output_download ); ?>">Download</a>
                                                        <?php elseif ( '' !== $reports_context_source_job_id && '' !== $latest_output_generate_action && ! in_array( $latest_output_state, array( 'QUEUED', 'RUNNING' ), true ) && $latest_output_is_allowed ) : ?>
                                                            <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="opsgate-reports-inline-form" data-opsgate-export-form="1">
                                                                <input type="hidden" name="action" value="<?php echo esc_attr( $latest_output_generate_action ); ?>">
                                                                <input type="hidden" name="source_job_id" value="<?php echo esc_attr( $reports_context_source_job_id ); ?>">
                                                                <?php wp_nonce_field( $latest_output_generate_nonce ); ?>
                                                                <button type="submit" class="button button-secondary opsgate-reports-output-button"><?php echo esc_html( $latest_output_generate_label ); ?></button>
                                                            </form>
                                                        <?php elseif ( ! $latest_output_is_allowed ) : ?>
                                                            <span class="opsgate-reports-output-empty"><?php echo esc_html( self::export_kind_unavailable_copy( $latest_output_kind_for_policy ) ); ?></span>
                                                        <?php else : ?>
                                                            <span class="opsgate-reports-output-empty">Download when ready</span>
                                                        <?php endif; ?>
                                                    </div>
                                                </article>
                                            <?php endforeach; ?>
                                        </div>
                                    </section>

                                    <aside class="opsgate-reports-surface opsgate-reports-surface-rail">
                                        <div class="opsgate-reports-surface-header">
                                            <h3 class="opsgate-reports-surface-title">Output Hub</h3>
                                            <span class="opsgate-reports-surface-link">Latest vs history</span>
                                        </div>

                                        <div class="opsgate-reports-rail-card opsgate-reports-rail-card-tone-<?php echo esc_attr( $reports_context_grade_tone ); ?>">
                                            <span class="opsgate-reports-eyebrow"><?php echo esc_html( $selected_live_context ? 'Selected scan' : 'Latest scan' ); ?></span>
                                            <div class="opsgate-reports-rail-value"><?php echo esc_html( null !== $reports_context_score ? (string) $reports_context_score : '—' ); ?></div>
                                            <div class="opsgate-reports-rail-pill-row">
                                                <span class="opsgate-reports-rail-pill opsgate-reports-rail-pill-<?php echo esc_attr( $reports_context_grade_tone ); ?>"><?php echo esc_html( $reports_context_grade_label ); ?></span>
                                                <span class="opsgate-reports-rail-pill opsgate-reports-rail-pill-soft-<?php echo esc_attr( $reports_context_grade_tone ); ?>"><?php echo esc_html( $reports_context_grade_summary ); ?></span>
                                                <?php if ( ! empty( $reports_operator_degradation ) ) : ?>
                                                    <span class="opsgate-reports-rail-pill opsgate-reports-rail-pill-soft-<?php echo esc_attr( (string) $reports_operator_degradation['tone'] ); ?>"><?php echo esc_html( (string) $reports_operator_degradation['label'] ); ?></span>
                                                <?php endif; ?>
                                            </div>
                                            <?php if ( '' !== $latest_job_id ) : ?>
                                                <p class="opsgate-reports-rail-meta"><?php echo esc_html( self::canonical_activity_reference_copy( 'Export reference', $latest_job_id ) ); ?></p>
                                            <?php endif; ?>
                                            <?php if ( '' !== $reports_context_source_job_id ) : ?>
                                                <p class="opsgate-reports-rail-meta"><?php echo esc_html( self::canonical_activity_reference_copy( 'Run reference', $reports_context_source_job_id ) ); ?></p>
                                            <?php endif; ?>
                                        </div>

                                        <div class="opsgate-reports-rail-card opsgate-reports-rail-card-tone-<?php echo esc_attr( (string) $reports_alert_rollup['tone'] ); ?>">
                                            <span class="opsgate-reports-eyebrow">Alert delivery</span>
                                            <div class="opsgate-reports-rail-value"><?php echo esc_html( (string) $reports_alert_rollup['latest_status'] ); ?></div>
                                            <div class="opsgate-reports-rail-pill-row">
                                                <span class="opsgate-reports-rail-pill opsgate-reports-rail-pill-soft-<?php echo esc_attr( (string) $reports_alert_rollup['tone'] ); ?>"><?php echo esc_html( (string) $reports_alert_rollup['headline'] ); ?></span>
                                            </div>
                                            <p class="opsgate-reports-rail-meta"><?php echo esc_html( (string) $reports_alert_rollup['latest_summary'] ); ?></p>
                                            <p class="opsgate-reports-rail-meta"><?php echo esc_html( (string) $reports_alert_rollup['latest_reference'] ); ?></p>
                                            <p class="opsgate-reports-rail-meta"><?php echo esc_html( (string) $reports_alert_rollup['latest_attempt_reference'] ); ?></p>
                                            <?php if ( ! empty( $reports_alert_rollup['latest_time'] ) ) : ?>
                                                <p class="opsgate-reports-rail-meta"><?php echo esc_html( (string) $reports_alert_rollup['latest_time'] ); ?></p>
                                            <?php endif; ?>
                                        </div>

                                    </aside>
                                </div>

                                <?php
                                // B2 — Compliance Alignment section (Pro+/Agency, only when compliance_posture artifact exists for this job).
                                $reports_is_pro_plus = in_array( $current_plan, array( 'pro', 'agency' ), true );
                                if ( $reports_is_pro_plus && '' !== $reports_context_source_job_id ) {
                                    $scope_cp = self::get_mcp_scope_snapshot();
                                    $cp_account_id = isset( $scope_cp['account_id'] ) ? trim( (string) $scope_cp['account_id'] ) : '';
                                    $cp_site_id = isset( $scope_cp['site_id'] ) ? trim( (string) $scope_cp['site_id'] ) : '';
                                    if ( '' !== $cp_account_id && '' !== $cp_site_id ) {
                                        $cp_resp = self::mcp_get_json(
                                            '/v1/sites/' . rawurlencode( $cp_site_id ) . '/compliance-posture/' . rawurlencode( $reports_context_source_job_id ),
                                            array( 'account_id' => $cp_account_id )
                                        );
                                        $cp_data = isset( $cp_resp['ok'] ) && $cp_resp['ok'] && isset( $cp_resp['data'] ) && is_array( $cp_resp['data'] ) ? $cp_resp['data'] : null;
                                        $cp_posture = is_array( $cp_data ) && isset( $cp_data['posture'] ) && is_array( $cp_data['posture'] ) ? $cp_data['posture'] : null;
                                        if ( null !== $cp_posture ) {
                                            $owasp_controls = isset( $cp_posture['owasp_controls'] ) && is_array( $cp_posture['owasp_controls'] ) ? $cp_posture['owasp_controls'] : array();
                                            $pci_controls = isset( $cp_posture['pci_controls'] ) && is_array( $cp_posture['pci_controls'] ) ? $cp_posture['pci_controls'] : array();
                                            $lang_note = isset( $cp_posture['language_note'] ) ? (string) $cp_posture['language_note'] : '';
                                            $overall_owasp = isset( $cp_posture['overall_owasp_status'] ) ? (string) $cp_posture['overall_owasp_status'] : '';
                                            ?>
                                            <section class="opsgate-reports-surface" style="margin-top:24px;">
                                                <div class="opsgate-reports-surface-header">
                                                    <h3 class="opsgate-reports-surface-title">Compliance Alignment</h3>
                                                    <span class="opsgate-reports-surface-link"><?php echo esc_html( '' !== $overall_owasp ? 'Overall: ' . ucfirst( $overall_owasp ) : 'OWASP · PCI-DSS' ); ?></span>
                                                </div>
                                                <?php if ( ! empty( $owasp_controls ) ) : ?>
                                                    <h4 style="margin:12px 0 8px 0;font-size:13px;font-weight:600;">OWASP WordPress Security Checklist</h4>
                                                    <div class="opsgate-clients-identity-grid">
                                                        <?php foreach ( $owasp_controls as $cp_ctrl ) : ?>
                                                            <?php
                                                            $cp_ctrl_id = isset( $cp_ctrl['control_id'] ) ? (string) $cp_ctrl['control_id'] : '';
                                                            $cp_ctrl_name = isset( $cp_ctrl['name'] ) ? (string) $cp_ctrl['name'] : $cp_ctrl_id;
                                                            $cp_ctrl_status = isset( $cp_ctrl['status'] ) ? strtolower( (string) $cp_ctrl['status'] ) : 'not_applicable';
                                                            $cp_ctrl_tone = 'pass' === $cp_ctrl_status ? 'good' : ( 'fail' === $cp_ctrl_status ? 'bad' : ( 'partial' === $cp_ctrl_status ? 'warn' : 'neutral' ) );
                                                            $cp_ctrl_label = 'pass' === $cp_ctrl_status ? 'Pass' : ( 'fail' === $cp_ctrl_status ? 'Fail' : ( 'partial' === $cp_ctrl_status ? 'Partial' : 'N/A' ) );
                                                            ?>
                                                            <div class="opsgate-clients-identity-card">
                                                                <span class="opsgate-clients-detail-label"><?php echo esc_html( $cp_ctrl_name ); ?></span>
                                                                <span class="opsgate-clients-detail-value opsgate-tone-<?php echo esc_attr( $cp_ctrl_tone ); ?>"><?php echo esc_html( $cp_ctrl_label ); ?></span>
                                                            </div>
                                                        <?php endforeach; ?>
                                                    </div>
                                                <?php endif; ?>
                                                <?php if ( ! empty( $pci_controls ) && 'agency' === $current_plan ) : ?>
                                                    <h4 style="margin:16px 0 8px 0;font-size:13px;font-weight:600;">PCI-DSS 4.0</h4>
                                                    <div class="opsgate-clients-identity-grid">
                                                        <?php foreach ( $pci_controls as $cp_ctrl ) : ?>
                                                            <?php
                                                            $cp_ctrl_id = isset( $cp_ctrl['control_id'] ) ? (string) $cp_ctrl['control_id'] : '';
                                                            $cp_ctrl_name = isset( $cp_ctrl['name'] ) ? (string) $cp_ctrl['name'] : $cp_ctrl_id;
                                                            $cp_ctrl_status = isset( $cp_ctrl['status'] ) ? strtolower( (string) $cp_ctrl['status'] ) : 'not_applicable';
                                                            $cp_ctrl_tone = 'pass' === $cp_ctrl_status ? 'good' : ( 'fail' === $cp_ctrl_status ? 'bad' : ( 'partial' === $cp_ctrl_status ? 'warn' : 'neutral' ) );
                                                            $cp_ctrl_label = 'pass' === $cp_ctrl_status ? 'Pass' : ( 'fail' === $cp_ctrl_status ? 'Fail' : ( 'partial' === $cp_ctrl_status ? 'Partial' : 'N/A' ) );
                                                            ?>
                                                            <div class="opsgate-clients-identity-card">
                                                                <span class="opsgate-clients-detail-label"><?php echo esc_html( $cp_ctrl_name ); ?></span>
                                                                <span class="opsgate-clients-detail-value opsgate-tone-<?php echo esc_attr( $cp_ctrl_tone ); ?>"><?php echo esc_html( $cp_ctrl_label ); ?></span>
                                                            </div>
                                                        <?php endforeach; ?>
                                                    </div>
                                                <?php endif; ?>
                                                <?php if ( '' !== $lang_note ) : ?>
                                                    <p style="font-size:11px;color:#888;margin:12px 0 0 0;"><?php echo esc_html( $lang_note ); ?></p>
                                                <?php endif; ?>
                                            </section>
                                            <?php
                                        }
                                    }
                                }
                                ?>

                                <section class="opsgate-reports-surface opsgate-reports-history-surface">
                                    <div class="opsgate-reports-surface-header">
                                        <h3 class="opsgate-reports-surface-title">Report History</h3>
                                        <span class="opsgate-reports-surface-link">Prior run outputs</span>
                                    </div>

                                    <div class="opsgate-reports-history-list">
                                        <?php if ( empty( $reports_history_groups ) ) : ?>
                                            <article class="opsgate-reports-history-card opsgate-reports-history-card-empty">
                                                <p class="opsgate-reports-history-empty">No prior report history is available beyond the current latest run outputs.</p>
                                            </article>
                                        <?php else : ?>
                                            <?php foreach ( $reports_history_groups as $reports_history_group ) : ?>
                                                <?php
                                                $reports_history_group_source_job_id = isset( $reports_history_group['source_job_id'] ) ? (string) $reports_history_group['source_job_id'] : '';
                                                $reports_history_group_created = isset( $reports_history_group['created_at_utc'] ) ? (string) $reports_history_group['created_at_utc'] : '';
                                                $reports_history_group_items = isset( $reports_history_group['items'] ) && is_array( $reports_history_group['items'] ) ? $reports_history_group['items'] : array();
                                                $reports_history_group_outputs = array();
                                                $reports_history_group_actions = array();
                                                $reports_history_group_state_tone = 'pending';
                                                $reports_history_group_state_label = 'Pending';
                                                $reports_history_group_has_completed = false;
                                                $reports_history_group_has_running = false;
                                                $reports_history_group_has_queued = false;
                                                $reports_history_group_has_failed = false;

                                                foreach ( $reports_history_group_items as $reports_history_item ) {
                                                    if ( ! is_array( $reports_history_item ) ) {
                                                        continue;
                                                    }

                                                    $reports_history_item_kind = isset( $reports_history_item['kind'] ) ? (string) $reports_history_item['kind'] : '';
                                                    $reports_history_item_state = isset( $reports_history_item['state'] ) ? strtoupper( (string) $reports_history_item['state'] ) : '';
                                                    $reports_history_item_export_job_id = isset( $reports_history_item['export_job_id'] ) ? (string) $reports_history_item['export_job_id'] : '';
                                                    if ( 'COMPLETED' === $reports_history_item_state && '' !== $reports_history_item_export_job_id ) {
                                                        $reports_history_group_has_completed = true;
                                                        if ( 'report_pdf' === $reports_history_item_kind ) {
                                                            $reports_history_group_outputs['PDF'] = true;
                                                            $reports_history_group_actions['PDF'] = array(
                                                                'kind' => $reports_history_item_kind,
                                                                'view' => self::canonical_report_download_url( $reports_history_item_kind, $reports_history_item_export_job_id, 'view' ),
                                                                'download' => self::canonical_report_download_url( $reports_history_item_kind, $reports_history_item_export_job_id ),
                                                            );
                                                        } elseif ( 'report_html' === $reports_history_item_kind ) {
                                                            $reports_history_group_outputs['HTML'] = true;
                                                            $reports_history_group_actions['HTML'] = array(
                                                                'kind' => $reports_history_item_kind,
                                                                'view' => self::canonical_report_download_url( $reports_history_item_kind, $reports_history_item_export_job_id, 'view' ),
                                                                'download' => self::canonical_report_download_url( $reports_history_item_kind, $reports_history_item_export_job_id ),
                                                            );
                                                        } elseif ( in_array( $reports_history_item_kind, array( 'csv', 'export_csv', 'triage_csv' ), true ) ) {
                                                            $reports_history_group_outputs['CSV'] = true;
                                                            $reports_history_group_actions['CSV'] = array(
                                                                'kind' => $reports_history_item_kind,
                                                                'view' => self::canonical_report_download_url( $reports_history_item_kind, $reports_history_item_export_job_id, 'view' ),
                                                                'download' => self::canonical_report_download_url( $reports_history_item_kind, $reports_history_item_export_job_id ),
                                                            );
                                                        } elseif ( 'report_xlsx' === $reports_history_item_kind ) {
                                                            $reports_history_group_outputs['Excel'] = true;
                                                            $reports_history_group_actions['Excel'] = array(
                                                                'kind' => $reports_history_item_kind,
                                                                'view' => self::canonical_report_download_url( $reports_history_item_kind, $reports_history_item_export_job_id, 'view' ),
                                                                'download' => self::canonical_report_download_url( $reports_history_item_kind, $reports_history_item_export_job_id ),
                                                            );
                                                        }
                                                    } elseif ( 'RUNNING' === $reports_history_item_state ) {
                                                        $reports_history_group_has_running = true;
                                                    } elseif ( 'QUEUED' === $reports_history_item_state ) {
                                                        $reports_history_group_has_queued = true;
                                                    } elseif ( 'FAILED' === $reports_history_item_state ) {
                                                        $reports_history_group_has_failed = true;
                                                    }
                                                }

                                                if ( $reports_history_group_has_completed ) {
                                                    $reports_history_group_state_tone = 'good';
                                                    $reports_history_group_state_label = 'Ready';
                                                } elseif ( $reports_history_group_has_running ) {
                                                    $reports_history_group_state_tone = 'warn';
                                                    $reports_history_group_state_label = 'Processing';
                                                } elseif ( $reports_history_group_has_queued ) {
                                                    $reports_history_group_state_tone = 'pending';
                                                    $reports_history_group_state_label = 'Pending';
                                                } elseif ( $reports_history_group_has_failed ) {
                                                    $reports_history_group_state_tone = 'bad';
                                                    $reports_history_group_state_label = 'Failed';
                                                }
                                                $reports_history_group_latest_item = ! empty( $reports_history_group_items ) && is_array( $reports_history_group_items[0] ) ? $reports_history_group_items[0] : array();
                                                $reports_history_group_is_proof = self::item_is_proof( $reports_history_group_latest_item );
                                                $reports_history_group_provenance = self::item_provenance_note_copy( $reports_history_group_latest_item );

                                                ?>
                                                <article class="opsgate-reports-history-card<?php echo $reports_history_group_source_job_id === $history_focus_source_job_id ? ' opsgate-reports-history-card-active' : ''; ?>">
                                                    <div class="opsgate-reports-history-main">
                                                        <div class="opsgate-reports-history-top">
                                                            <h4 class="opsgate-reports-history-title"><?php echo esc_html( '' !== $reports_history_group_created ? self::human_relative_datetime_label( $reports_history_group_created ) : 'Previous scan' ); ?></h4>
                                                        </div>
                                                        <p class="opsgate-reports-history-meta"><?php echo esc_html( '' !== $reports_history_group_created ? self::human_relative_datetime_label( $reports_history_group_created ) : 'Date unavailable' ); ?></p>
                                                        <p class="opsgate-reports-history-copy"><?php echo esc_html( ! empty( $reports_history_group_outputs ) ? 'Available outputs: ' . implode( ', ', array_keys( $reports_history_group_outputs ) ) : ( 'Failed' === $reports_history_group_state_label ? 'No completed outputs are available for this run.' : 'Outputs are still processing for this run.' ) ); ?></p>
                                                        <?php if ( ! empty( $reports_history_group_outputs ) ) : ?>
                                                            <div class="opsgate-reports-history-format-row">
                                                                <?php foreach ( array_keys( $reports_history_group_outputs ) as $reports_history_output_label ) : ?>
                                                                    <?php
                                                                    $reports_history_output_tone = 'neutral';
                                                                    if ( 'Excel' === $reports_history_output_label ) {
                                                                        $reports_history_output_tone = 'good';
                                                                    } elseif ( 'HTML' === $reports_history_output_label ) {
                                                                        $reports_history_output_tone = 'info';
                                                                    } elseif ( 'CSV' === $reports_history_output_label ) {
                                                                        $reports_history_output_tone = 'warn';
                                                                    } elseif ( 'PDF' === $reports_history_output_label ) {
                                                                        $reports_history_output_tone = 'bad';
                                                                    }
                                                                    ?>
                                                                    <span class="opsgate-reports-rail-pill opsgate-reports-rail-pill-soft-<?php echo esc_attr( $reports_history_output_tone ); ?>"><?php echo esc_html( $reports_history_output_label ); ?></span>
                                                                <?php endforeach; ?>
                                                            </div>
                                                        <?php endif; ?>
                                                        <?php if ( ! empty( $reports_history_group_latest_item ) ) : ?>
                                                            <p class="opsgate-reports-history-copy"><?php echo esc_html( self::canonical_report_trust_copy( $reports_history_group_latest_item ) ); ?></p>
                                                            <p class="opsgate-reports-history-copy"><?php echo esc_html( self::canonical_report_governance_copy( $reports_history_group_latest_item ) ); ?></p>
                                                            <?php if ( '' !== $reports_history_group_provenance ) : ?>
                                                                <p class="opsgate-reports-history-copy"><?php echo esc_html( $reports_history_group_provenance ); ?></p>
                                                            <?php endif; ?>
                                                        <?php endif; ?>
                                                    </div>
                                                    <div class="opsgate-reports-history-actions">
                                                        <?php if ( ! empty( $reports_history_group_actions ) ) : ?>
                                                            <div class="opsgate-reports-history-actions-head">
                                                                <span class="opsgate-reports-history-state opsgate-reports-history-state-<?php echo esc_attr( $reports_history_group_state_tone ); ?>"><?php echo esc_html( $reports_history_group_state_label ); ?></span>
                                                                <details class="opsgate-reports-history-action-details">
                                                            <summary>View outputs</summary>
                                                                    <div class="opsgate-reports-history-action-grid">
                                                                        <?php foreach ( $reports_history_group_actions as $reports_history_action_label => $reports_history_action ) : ?>
                                                                            <div class="opsgate-reports-history-action-group">
                                                                                <span class="opsgate-reports-eyebrow"><?php echo esc_html( $reports_history_action_label ); ?></span>
                                                                                <div class="opsgate-reports-history-action-links">
                                                                                    <?php if ( ! empty( $reports_history_action['view'] ) ) : ?>
                                                                                        <button type="button" class="button button-secondary opsgate-reports-output-button opsgate-reports-viewer-trigger" data-viewer-kind="Historical <?php echo esc_attr( $reports_history_action_label ); ?>" data-viewer-url="<?php echo esc_url( $reports_history_action['view'] ); ?>"><?php echo esc_html( self::canonical_report_view_action_label( isset( $reports_history_action['kind'] ) ? (string) $reports_history_action['kind'] : '' ) ); ?></button>
                                                                                    <?php endif; ?>
                                                                                    <?php if ( ! empty( $reports_history_action['download'] ) ) : ?>
                                                                                        <a class="button button-secondary opsgate-reports-output-button" href="<?php echo esc_url( $reports_history_action['download'] ); ?>">Download</a>
                                                                                    <?php endif; ?>
                                                                                </div>
                                                                            </div>
                                                                        <?php endforeach; ?>
                                                                    </div>
                                                                </details>
                                                            </div>
                                                        <?php elseif ( 'Failed' === $reports_history_group_state_label ) : ?>
                                                            <span class="opsgate-reports-output-empty">Failed</span>
                                                        <?php else : ?>
                                                            <span class="opsgate-reports-output-empty">Pending</span>
                                                        <?php endif; ?>
                                                    </div>
                                                </article>
                                            <?php endforeach; ?>
                                        <?php endif; ?>
                                    </div>
                                </section>

                                <?php
                                // Phase 5: Surface Phase 4 report delivery truth (authority.report_deliveries)
                                $p5_del_job_id = $reports_context_source_job_id ?? '';
                                $p5_del_allowed = isset( $delivery_allowed ) ? (bool) $delivery_allowed : false;
                                if ( $p5_del_allowed && '' !== $p5_del_job_id ) :
                                    $p5_delivery_resp = self::canonical_report_deliveries( $p5_del_job_id );
                                    $p5_delivery_items = isset( $p5_delivery_resp['items'] ) && is_array( $p5_delivery_resp['items'] ) ? $p5_delivery_resp['items'] : array();
                                    $p5_delivery_sender_map = array(
                                        'report'          => 'reports@opsgate.ca',
                                        'report_delivery' => 'reports@opsgate.ca',
                                        'alert'           => 'alerts@opsgate.ca',
                                        'vulnerability'   => 'security@opsgate.ca',
                                        'security'        => 'security@opsgate.ca',
                                    );
                                    ?>
                                <section class="opsgate-p5-delivery-section">
                                    <div class="opsgate-reports-surface-header">
                                        <h3 class="opsgate-p5-section-heading">Report Delivery History</h3>
                                        <span class="opsgate-p5-meta-text">Mail sent via mail.opsgate.ca · Self-hosted Postfix + OpenDKIM</span>
                                    </div>
                                    <?php if ( empty( $p5_delivery_items ) ) : ?>
                                    <p class="opsgate-p5-body-text" style="margin:8px 0;">No deliveries recorded for this run yet. Use &ldquo;Send to client&rdquo; above to queue the first delivery.</p>
                                    <?php else : ?>
                                    <?php foreach ( $p5_delivery_items as $p5_del ) :
                                        if ( ! is_array( $p5_del ) ) { continue; }
                                        $p5_del_status          = strtolower( trim( (string) ( $p5_del['status'] ?? 'queued' ) ) );
                                        $p5_del_recipient       = (string) ( $p5_del['recipient_email'] ?? '' );
                                        $p5_del_type            = strtolower( trim( (string) ( $p5_del['delivery_type'] ?? 'report' ) ) );
                                        $p5_del_sender          = (string) ( $p5_del['sender_address'] ?? '' );
                                        if ( '' === $p5_del_sender ) {
                                            $p5_del_sender = isset( $p5_delivery_sender_map[ $p5_del_type ] ) ? $p5_delivery_sender_map[ $p5_del_type ] : 'reports@opsgate.ca';
                                        }
                                        $p5_del_provider_msg_id = (string) ( $p5_del['provider_message_id'] ?? '' );
                                        $p5_del_queued_at       = (string) ( $p5_del['queued_at'] ?? '' );
                                        $p5_del_sent_at         = (string) ( $p5_del['sent_at'] ?? '' );
                                        $p5_del_failure_reason  = (string) ( $p5_del['failure_reason'] ?? '' );
                                        $p5_del_when            = '' !== $p5_del_sent_at ? self::canonical_report_datetime_label( $p5_del_sent_at ) : ( '' !== $p5_del_queued_at ? self::canonical_report_datetime_label( $p5_del_queued_at ) : '—' );
                                    ?>
                                    <div class="opsgate-p5-delivery-row">
                                        <span class="opsgate-p5-delivery-status-badge status-<?php echo esc_attr( $p5_del_status ); ?>"><?php echo esc_html( ucfirst( $p5_del_status ) ); ?></span>
                                        <div class="opsgate-p5-delivery-detail">
                                            <span class="opsgate-p5-body-text"><?php echo esc_html( $p5_del_recipient ); ?></span>
                                            <span class="opsgate-p5-delivery-sender">From: <?php echo esc_html( $p5_del_sender ); ?></span>
                                            <span class="opsgate-p5-meta-text"><?php echo esc_html( $p5_del_when ); ?></span>
                                            <?php if ( '' !== $p5_del_provider_msg_id ) : ?>
                                            <span class="opsgate-p5-delivery-auth-badge" title="Provider message ID: <?php echo esc_attr( $p5_del_provider_msg_id ); ?>">DKIM/SPF authenticated · <?php echo esc_html( $p5_del_provider_msg_id ); ?></span>
                                            <?php endif; ?>
                                            <?php if ( '' !== $p5_del_failure_reason ) : ?>
                                            <span class="opsgate-p5-meta-text" style="color:var(--og-red,#c0392b);"><?php echo esc_html( $p5_del_failure_reason ); ?></span>
                                            <?php endif; ?>
                                        </div>
                                    </div>
                                    <?php endforeach; ?>
                                    <?php endif; ?>
                                </section>
                                <?php endif; ?>

                                <?php
                                // Slice 5 Part C: 1-click WP admin login (Starter+, connected sites only)
                                $admin_session_site_id = '' !== $delivery_site_id ? $delivery_site_id : '';
                                $admin_session_allowed = $delivery_allowed && '' !== $admin_session_site_id;
                                if ( $admin_session_allowed ) :
                                ?>
                                <section class="opsgate-p5-delivery-section" style="margin-top:12px;">
                                    <div class="opsgate-reports-surface-header">
                                        <h3 class="opsgate-p5-section-heading">1-Click WP Admin</h3>
                                        <span class="opsgate-p5-meta-text">Opens a temporary session — token expires in 60 seconds, one-time use only.</span>
                                    </div>
                                    <button
                                        type="button"
                                        class="button opsgate-admin-session-btn"
                                        data-site-id="<?php echo esc_attr( $admin_session_site_id ); ?>"
                                        data-api-base="<?php echo esc_attr( $delivery_api_base ); ?>"
                                        data-wp-rest-base="<?php echo esc_attr( rest_url( 'opsgate/v1' ) ); ?>"
                                        data-nonce="<?php echo esc_attr( wp_create_nonce( 'opsgate_admin_session' ) ); ?>">
                                        Open WP Admin &rarr;
                                    </button>
                                    <span class="opsgate-admin-session-status" style="margin-left:10px;font-size:12px;color:#666;"></span>
                                </section>
                                <?php endif; ?>

                                <?php
                                // Slice 5 Part B: Shareable report link (Starter+)
                                $share_allowed = $delivery_allowed;
                                if ( $share_allowed && '' !== $delivery_site_id && '' !== $delivery_job_id ) :
                                ?>
                                <section class="opsgate-p5-delivery-section" style="margin-top:12px;">
                                    <div class="opsgate-reports-surface-header">
                                        <h3 class="opsgate-p5-section-heading">Shareable Report Link</h3>
                                        <span class="opsgate-p5-meta-text">Links expire after 60 days by default. Revoke anytime.</span>
                                    </div>
                                    <div id="opsgate-share-link-container-<?php echo esc_attr( $delivery_job_id ); ?>">
                                        <button
                                            type="button"
                                            class="button opsgate-create-share-link-btn"
                                            data-site-id="<?php echo esc_attr( $delivery_site_id ); ?>"
                                            data-job-id="<?php echo esc_attr( $delivery_job_id ); ?>"
                                            data-api-base="<?php echo esc_attr( $delivery_api_base ); ?>"
                                            data-nonce="<?php echo esc_attr( wp_create_nonce( 'opsgate_share_link' ) ); ?>">
                                            Generate Shareable Link
                                        </button>
                                        <span class="opsgate-share-link-result" style="margin-left:10px;display:none;">
                                            <input type="text" class="opsgate-share-link-url" readonly style="width:360px;font-size:12px;" value="" />
                                            <button type="button" class="button button-small opsgate-copy-share-link-btn">Copy</button>
                                            <button type="button" class="button button-small opsgate-revoke-share-link-btn" style="margin-left:6px;">Revoke</button>
                                        </span>
                                    </div>
                                </section>
                                <?php endif; ?>

                                <details class="opsgate-p5-help-panel">
                                    <summary>Help &amp; Glossary — How to read reports</summary>
                                <section class="opsgate-reports-surface opsgate-reports-glossary-surface">
                                    <div class="opsgate-reports-surface-header">
                                        <h3 class="opsgate-reports-surface-title">How to read reports</h3>
                                        <span class="opsgate-reports-surface-link">Glossary and FAQ</span>
                                    </div>
                                    <div class="opsgate-reports-glossary-grid">
                                        <?php foreach ( $reports_glossary_cards as $reports_glossary_card ) : ?>
                                            <article class="opsgate-reports-glossary-card">
                                                <div class="opsgate-reports-glossary-title"><?php echo esc_html( (string) $reports_glossary_card['title'] ); ?></div>
                                                <p class="opsgate-reports-glossary-copy"><?php echo esc_html( (string) $reports_glossary_card['copy'] ); ?></p>
                                            </article>
                                        <?php endforeach; ?>
                                    </div>
                                </section>
                                </details><!-- /opsgate-p5-help-panel -->

                                <section class="opsgate-reports-surface opsgate-reports-technical-strip">
                                    <details id="opsgate-reports-support-package" class="opsgate-reports-technical-details"<?php echo $reports_show_json_package ? ' open="open"' : ''; ?>>
                                        <summary>
                                            <div>
                                                <span class="opsgate-reports-eyebrow">Support evidence</span>
                                                <h3 class="opsgate-reports-surface-title">Support evidence package</h3>
                                            </div>
                                            <span class="opsgate-reports-surface-link">JSON, datasets, and export support</span>
                                        </summary>
                                        <div class="opsgate-reports-technical-strip-layout">
                                            <div class="opsgate-reports-technical-grid">
                                                <article class="opsgate-reports-technical-stat">
                                                    <span class="opsgate-reports-eyebrow">Package state</span>
                                                    <div class="opsgate-reports-technical-value"><?php echo esc_html( '' !== $reports_advanced_artifact_job_id ? 'Ready' : 'Pending' ); ?></div>
                                                </article>
                                                <article class="opsgate-reports-technical-stat">
                                                    <span class="opsgate-reports-eyebrow">Run Ref</span>
                                                    <div class="opsgate-reports-technical-value"><?php echo esc_html( '' !== $reports_context_source_job_id ? self::canonical_activity_reference_copy( 'Run reference', $reports_context_source_job_id ) : 'Run reference unavailable' ); ?></div>
                                                </article>
                                                <article class="opsgate-reports-technical-stat">
                                                    <span class="opsgate-reports-eyebrow">Artifacts</span>
                                                    <div class="opsgate-reports-technical-value"><?php echo esc_html( (string) count( $reports_advanced_artifacts ) ); ?></div>
                                                </article>
                                            </div>
                                            <div class="opsgate-reports-technical-actions">
                                                <p class="opsgate-reports-technical-copy"><?php echo esc_html( '' !== $reports_advanced_artifact_job_id ? 'Inspect the recorded JSON artifacts only when you need the support evidence package.' : 'Support JSON becomes available when a run reference is recorded.' ); ?></p>
                                                <a class="button button-secondary opsgate-reports-output-button" href="<?php echo esc_url( self::admin_tab_url( 'reports', array_filter( array( 'source_job_id' => $reports_context_source_job_id, 'view_kind' => 'json_package' ) ) ) ); ?>">Open support package</a>
                                            </div>
                                        </div>
                                        <?php if ( $reports_show_json_package ) : ?>
                                            <?php if ( ! empty( $reports_advanced_artifacts ) ) : ?>
                                                <div class="opsgate-reports-artifact-list">
                                                    <?php foreach ( $reports_advanced_artifacts as $reports_advanced_artifact ) : ?>
                                                        <?php $reports_artifact_view_url = add_query_arg( 'mode', 'view', $reports_advanced_artifact['url'] ); ?>
                                                        <div class="opsgate-reports-artifact-row">
                                                            <div class="opsgate-reports-artifact-copy">
                                                                <span class="opsgate-reports-eyebrow">Artifact</span>
                                                                <div class="opsgate-reports-artifact-title"><?php echo esc_html( $reports_advanced_artifact['label'] ); ?></div>
                                                            </div>
                                                            <div class="opsgate-reports-artifact-actions">
                                                                <button type="button" class="button button-secondary opsgate-reports-output-button opsgate-reports-viewer-trigger" data-viewer-kind="<?php echo esc_attr( $reports_advanced_artifact['label'] ); ?>" data-viewer-url="<?php echo esc_url( $reports_artifact_view_url ); ?>">View</button>
                                                                <a class="button button-secondary opsgate-reports-output-button" href="<?php echo esc_url( $reports_advanced_artifact['url'] ); ?>">Download</a>
                                                            </div>
                                                        </div>
                                                    <?php endforeach; ?>
                                                </div>
                                            <?php else : ?>
                                                <p class="opsgate-reports-technical-copy">No support artifacts are available for this run yet.</p>
                                            <?php endif; ?>
                                        <?php endif; ?>
                                    </details>
                                </section>
                            </div>
                            <div class="opsgate-reports-modal" id="opsgate-reports-viewer-modal" hidden>
                                <div class="opsgate-reports-modal-backdrop" data-opsgate-viewer-close></div>
                                <div class="opsgate-reports-modal-dialog" role="dialog" aria-modal="true" aria-labelledby="opsgate-reports-viewer-title">
                                    <div class="opsgate-reports-modal-header">
                                        <h4 id="opsgate-reports-viewer-title" class="opsgate-reports-modal-title">Report Viewer</h4>
                                        <button type="button" class="button-link opsgate-reports-modal-close" data-opsgate-viewer-close aria-label="Close viewer">&times;</button>
                                    </div>
                                    <div class="opsgate-reports-modal-body">
                                        <iframe class="opsgate-reports-modal-frame" id="opsgate-reports-viewer-frame" src="about:blank" title="Report viewer"></iframe>
                                    </div>
                                </div>
                            </div>
                        </div>
                    <?php endif; ?>
                    <?php elseif ( 'alerts' === $active_tab ) : ?>
                    <?php
                    $alerts_rules  = self::notification_rules_list();
                    $alerts_events = self::notification_events_list( 20 );

                    $alerts_rules_ok    = ! empty( $alerts_rules['ok'] );
                    $alerts_rules_items = ( isset( $alerts_rules['items'] ) && is_array( $alerts_rules['items'] ) ) ? $alerts_rules['items'] : array();
                    $alerts_rules_error = isset( $alerts_rules['error'] ) ? (string) $alerts_rules['error'] : '';
                    $alerts_live_rules_items = self::notification_rule_sort_for_alerts(
                        self::notification_rule_dedupe_for_alerts(
                            self::live_items_only( $alerts_rules_items )
                        )
                    );

                    $alerts_destinations = self::notification_destinations_list();
                    $alerts_destinations_ok = ! empty( $alerts_destinations['ok'] );
                    $alerts_destinations_items = ( isset( $alerts_destinations['items'] ) && is_array( $alerts_destinations['items'] ) ) ? $alerts_destinations['items'] : array();
                    $alerts_destinations_error = isset( $alerts_destinations['error'] ) ? (string) $alerts_destinations['error'] : '';

                    $alerts_events_ok    = ! empty( $alerts_events['ok'] );
                    $alerts_events_items = ( isset( $alerts_events['items'] ) && is_array( $alerts_events['items'] ) ) ? $alerts_events['items'] : array();
                    $alerts_events_error = isset( $alerts_events['error'] ) ? (string) $alerts_events['error'] : '';
                    $alerts_live_events_items = self::live_items_only( $alerts_events_items );

                    $alerts_notice = isset( $_GET['opsgate_alerts_notice'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_alerts_notice'] ) ) : '';
                    $alerts_error  = isset( $_GET['opsgate_alerts_error'] ) ? sanitize_text_field( rawurldecode( (string) wp_unslash( $_GET['opsgate_alerts_error'] ) ) ) : '';
                    $alerts_destinations_notice = isset( $_GET['opsgate_alert_destinations_notice'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_alert_destinations_notice'] ) ) : '';
                    $alerts_destinations_error_notice = isset( $_GET['opsgate_alert_destinations_error'] ) ? sanitize_text_field( rawurldecode( (string) wp_unslash( $_GET['opsgate_alert_destinations_error'] ) ) ) : '';
                    $alerts_toggle_nonce = wp_create_nonce( 'opsgate_notification_rule_toggle_ajax' );
                    $alerts_refresh_url = self::admin_tab_url( 'alerts' );
                    $alerts_scope = self::current_mcp_scope_snapshot();
                    $alerts_site_config = self::canonical_site_config();
                    $alerts_site_config_item = ! empty( $alerts_site_config['ok'] ) && isset( $alerts_site_config['item'] ) && is_array( $alerts_site_config['item'] ) ? $alerts_site_config['item'] : array();
                    $alerts_selected_site = self::current_selected_site_summary();
                    $alerts_site_label = self::connected_site_label( $alerts_site_config_item, $alerts_scope );
                    $alerts_scope_label = '' !== $alerts_site_label ? $alerts_site_label : 'Connected site';
                    $alerts_connection_status = isset( $alerts_selected_site['connection_status'] ) ? trim( (string) $alerts_selected_site['connection_status'] ) : 'external_only';
                    $alerts_connection_mode = isset( $alerts_selected_site['connection_mode'] ) ? trim( (string) $alerts_selected_site['connection_mode'] ) : 'public_scan';
                    $alerts_connection_label = self::canonical_connection_status_label( $alerts_connection_status );
                    $alerts_connection_copy = self::canonical_connection_status_copy(
                        $alerts_connection_status,
                        $alerts_connection_mode,
                        self::scope_targets_local_wordpress( isset( $alerts_selected_site['site_url'] ) ? (string) $alerts_selected_site['site_url'] : '' )
                    );
                    $alerts_scope_meta = isset( $alerts_scope['site_id'] ) ? trim( (string) $alerts_scope['site_id'] ) : '';
                    $alerts_active_rules = 0;
                    $alerts_channels = array();
                    foreach ( $alerts_live_rules_items as $rule ) {
                        if ( ! is_array( $rule ) ) {
                            continue;
                        }
                        if ( ! empty( $rule['is_enabled'] ) ) {
                            ++$alerts_active_rules;
                            $rule_channel = isset( $rule['channel'] ) ? self::notification_channel_label( (string) $rule['channel'] ) : '';
                            if ( '' !== trim( $rule_channel ) && '—' !== $rule_channel ) {
                                $alerts_channels[ $rule_channel ] = true;
                            }
                        }
                    }
                    $alerts_channels_copy = ! empty( $alerts_channels ) ? implode( ', ', array_keys( $alerts_channels ) ) : 'None configured';
                    $alerts_latest_event = ! empty( $alerts_live_events_items ) && is_array( $alerts_live_events_items[0] ) ? $alerts_live_events_items[0] : array();
                    $alerts_latest_event_status = isset( $alerts_latest_event['status'] ) ? strtolower( trim( (string) $alerts_latest_event['status'] ) ) : '';
                    $alerts_latest_event_label = '' !== $alerts_latest_event_status ? self::notification_status_label( $alerts_latest_event_status ) : 'No recent delivery';
                    $alerts_latest_event_tone = 'neutral';
                    $alerts_proof_runs = self::proof_runs_list( 6 );
                    $alerts_proof_items = ! empty( $alerts_proof_runs['ok'] ) && isset( $alerts_proof_runs['items'] ) && is_array( $alerts_proof_runs['items'] ) ? $alerts_proof_runs['items'] : array();
                    $alerts_channel_families = self::package_channel_families();
                    $alerts_channel_groups = self::package_channel_family_groups();
                    $alerts_webhook_allowance = self::webhook_destination_allowance();
                    $alerts_package_scope_allowance = self::package_scope_allowance();
                    $alerts_latest_proof = array();
                    foreach ( $alerts_proof_items as $alerts_proof_item ) {
                        if ( is_array( $alerts_proof_item ) && isset( $alerts_proof_item['scenario_family'] ) && in_array( (string) $alerts_proof_item['scenario_family'], array( 'alert_delivery_failure', 'trigger_origin' ), true ) ) {
                            $alerts_latest_proof = $alerts_proof_item;
                            break;
                        }
                    }
                    $alerts_latest_proof_event = array();
                    foreach ( $alerts_events_items as $alerts_event_item ) {
                        if ( ! is_array( $alerts_event_item ) || ! self::item_is_proof( $alerts_event_item ) ) {
                            continue;
                        }
                        if ( 'alert_delivery_failure' === (string) ( $alerts_event_item['proof_scenario_family'] ?? '' ) ) {
                            $alerts_latest_proof_event = $alerts_event_item;
                            break;
                        }
                    }
                    if ( in_array( $alerts_latest_event_status, array( 'delivered', 'completed' ), true ) ) {
                        $alerts_latest_event_tone = 'good';
                    } elseif ( in_array( $alerts_latest_event_status, array( 'ready', 'queued', 'pending', 'running', 'in_progress' ), true ) ) {
                        $alerts_latest_event_tone = 'warn';
                    } elseif ( in_array( $alerts_latest_event_status, array( 'failed', 'rejected', 'timeout', 'error' ), true ) ) {
                        $alerts_latest_event_tone = 'bad';
                    }
                    $alerts_latest_timestamp = isset( $alerts_latest_event['triggered_at_utc'] ) ? self::notification_datetime_label( (string) $alerts_latest_event['triggered_at_utc'] ) : 'No recent delivery';
                    $alerts_latest_event_name = isset( $alerts_latest_event['event_type'] ) ? self::canonical_notification_event_label( (string) $alerts_latest_event['event_type'] ) : 'No recent alert';
                    $alerts_live_channel_labels = array_map(
                        'strtolower',
                        wp_list_pluck( $alerts_channel_groups['live_now'] ?? array(), 'label' )
                    );
                    $alerts_rule_delivery_by_rule = array();
                    $alerts_rule_delivery_by_signature = array();
                    $alerts_event_by_destination = array();
                    $alerts_rule_name_by_id = array();
                    $alerts_rule_event_options = self::notification_rule_event_options();
                    foreach ( $alerts_rules_items as $alerts_rule_item ) {
                        if ( ! is_array( $alerts_rule_item ) ) {
                            continue;
                        }
                        $alerts_rule_item_id = isset( $alerts_rule_item['rule_id'] ) ? trim( (string) $alerts_rule_item['rule_id'] ) : '';
                        if ( '' !== $alerts_rule_item_id && ! isset( $alerts_rule_name_by_id[ $alerts_rule_item_id ] ) ) {
                            $alerts_rule_name_by_id[ $alerts_rule_item_id ] = self::notification_rule_display_name( $alerts_rule_item );
                        }
                    }
                    $alerts_event_by_id = array();
                    foreach ( $alerts_live_events_items as $alerts_event_item ) {
                        if ( ! is_array( $alerts_event_item ) ) {
                            continue;
                        }
                        $alerts_event_id = isset( $alerts_event_item['event_id'] ) ? trim( (string) $alerts_event_item['event_id'] ) : '';
                        $alerts_event_rule_id = isset( $alerts_event_item['rule_id'] ) ? trim( (string) $alerts_event_item['rule_id'] ) : '';
                        $alerts_event_destination_id = isset( $alerts_event_item['destination_id'] ) ? trim( (string) $alerts_event_item['destination_id'] ) : '';
                        $alerts_event_signature = strtolower(
                            trim( (string) ( $alerts_event_item['event_type'] ?? '' ) ) . '|' .
                            trim( (string) ( $alerts_event_item['channel'] ?? '' ) ) . '|' .
                            trim( (string) ( $alerts_event_item['target'] ?? '' ) )
                        );
                        if ( '' !== $alerts_event_id && ! isset( $alerts_event_by_id[ $alerts_event_id ] ) ) {
                            $alerts_event_by_id[ $alerts_event_id ] = $alerts_event_item;
                        }
                        if ( '' !== $alerts_event_rule_id && ! isset( $alerts_rule_delivery_by_rule[ $alerts_event_rule_id ] ) ) {
                            $alerts_rule_delivery_by_rule[ $alerts_event_rule_id ] = $alerts_event_item;
                        }
                        if ( '' !== $alerts_event_destination_id && ! isset( $alerts_event_by_destination[ $alerts_event_destination_id ] ) ) {
                            $alerts_event_by_destination[ $alerts_event_destination_id ] = $alerts_event_item;
                        }
                        if ( '' !== $alerts_event_signature && ! isset( $alerts_rule_delivery_by_signature[ $alerts_event_signature ] ) ) {
                            $alerts_rule_delivery_by_signature[ $alerts_event_signature ] = $alerts_event_item;
                        }
                    }
                    $alerts_vulnerability_event_types = array(
                        'vulnerability.plugin_first_detected',
                        'vulnerability.plugin_state_changed',
                        'update.available_with_security_fix',
                    );
                    $alerts_live_rules_items = self::notification_rule_sort_for_alerts(
                        self::notification_rule_dedupe_for_alerts(
                            self::live_items_only( is_array( $alerts_rules_items ) ? $alerts_rules_items : array() )
                        )
                    );
                    $alerts_support_rules_items = array_values(
                        array_filter(
                            is_array( $alerts_rules_items ) ? $alerts_rules_items : array(),
                            static function ( $item ) {
                                return is_array( $item ) && self::item_is_proof( $item );
                            }
                        )
                    );
                    $alerts_customer_events_items = self::live_items_only( is_array( $alerts_events_items ) ? $alerts_events_items : array() );
                    $alerts_recent_customer_events_items = array_slice( $alerts_customer_events_items, 0, 4 );
                    $alerts_vulnerability_rules_items = array_values(
                        array_filter(
                            $alerts_live_rules_items,
                            static function ( $item ) use ( $alerts_vulnerability_event_types ) {
                                return is_array( $item ) && in_array( (string) ( $item['event_type'] ?? '' ), $alerts_vulnerability_event_types, true );
                            }
                        )
                    );
                    $alerts_vulnerability_events_items = array_values(
                        array_filter(
                            $alerts_customer_events_items,
                            static function ( $item ) use ( $alerts_vulnerability_event_types ) {
                                return is_array( $item ) && in_array( (string) ( $item['event_type'] ?? '' ), $alerts_vulnerability_event_types, true );
                            }
                        )
                    );
                    $alerts_recent_vulnerability_event = ! empty( $alerts_vulnerability_events_items ) && is_array( $alerts_vulnerability_events_items[0] )
                        ? $alerts_vulnerability_events_items[0]
                        : array();
                    $alerts_support_events_items = array_values(
                        array_filter(
                            is_array( $alerts_events_items ) ? $alerts_events_items : array(),
                            static function ( $item ) {
                                return is_array( $item ) && self::item_is_proof( $item );
                            }
                        )
                    );
                    $alerts_latest_delivery_event = ! empty( $alerts_customer_events_items ) && is_array( $alerts_customer_events_items[0] )
                        ? $alerts_customer_events_items[0]
                        : $alerts_latest_event;
                    $alerts_latest_event_status = isset( $alerts_latest_delivery_event['status'] ) ? strtolower( trim( (string) $alerts_latest_delivery_event['status'] ) ) : $alerts_latest_event_status;
                    $alerts_latest_event_label = '' !== $alerts_latest_event_status ? self::notification_status_label( $alerts_latest_event_status ) : 'No recent delivery';
                    $alerts_latest_event_tone = 'neutral';
                    if ( in_array( $alerts_latest_event_status, array( 'delivered', 'completed' ), true ) ) {
                        $alerts_latest_event_tone = 'good';
                    } elseif ( in_array( $alerts_latest_event_status, array( 'ready', 'queued', 'pending', 'running', 'in_progress' ), true ) ) {
                        $alerts_latest_event_tone = 'warn';
                    } elseif ( in_array( $alerts_latest_event_status, array( 'failed', 'rejected', 'timeout', 'error' ), true ) ) {
                        $alerts_latest_event_tone = 'bad';
                    }
                    $alerts_latest_timestamp = isset( $alerts_latest_delivery_event['triggered_at_utc'] ) ? self::notification_datetime_label( (string) $alerts_latest_delivery_event['triggered_at_utc'] ) : 'No recent delivery';
                    $alerts_latest_event_name = isset( $alerts_latest_delivery_event['event_type'] ) ? self::canonical_notification_event_label( (string) $alerts_latest_delivery_event['event_type'] ) : 'No recent alert';
                    $alerts_latest_event_summary = ! empty( $alerts_latest_delivery_event ) ? self::notification_event_display_summary( $alerts_latest_delivery_event ) : 'No recent delivery has been recorded for this site.';
                    $alerts_vulnerability_story_title = 'No vulnerability-driven alert has fired for this site';
                    $alerts_vulnerability_story_copy = 'Healthy runs with zero vulnerable installed plugins do not emit vulnerability alerts, and unchanged reruns do not repeat the same vulnerability event. This rail becomes active when OpsGate first detects a vulnerable installed plugin or records a vulnerability state change.';
                    $alerts_vulnerability_story_tone = 'info';
                    if ( ! empty( $alerts_recent_vulnerability_event ) ) {
                        $alerts_vulnerability_story_title = self::notification_event_display_title( $alerts_recent_vulnerability_event );
                        $alerts_vulnerability_story_copy = self::notification_event_display_summary( $alerts_recent_vulnerability_event );
                        $alerts_vulnerability_story_tone = 'bad';
                    } elseif ( empty( $alerts_vulnerability_rules_items ) ) {
                        $alerts_vulnerability_story_title = 'Vulnerability alerts are not set up yet.';
                        $alerts_vulnerability_story_copy = 'Create an alert rule to get notified when a vulnerability is found on this site.';
                        $alerts_vulnerability_story_tone = 'warn';
                    } elseif ( 'connected' !== $alerts_connection_status ) {
                        $alerts_vulnerability_story_title = 'Connected vulnerability events are waiting on trust';
                        $alerts_vulnerability_story_copy = 'Vulnerability routing stays configured, but this connection state cannot promise fresh connected plugin findings until the selected site is fully reconnected.';
                        $alerts_vulnerability_story_tone = 'warn';
                    }
                    $alerts_history_intro_copy = ! empty( $alerts_vulnerability_rules_items )
                        ? 'Customer-facing delivery history appears here. Vulnerability-driven events join the same rail when OpsGate first detects a vulnerable installed plugin or records a plugin vulnerability state change. Unchanged healthy reruns do not add duplicate vulnerability events.'
                        : 'Customer-facing delivery history appears here. Delivery checks and routed alert events remain separate from support validation receipts.';
                    $alerts_destinations_total = is_array( $alerts_destinations_items ) ? count( $alerts_destinations_items ) : 0;
                    $alerts_default_destinations_total = 0;
                    $alerts_active_destinations_total = 0;
                    foreach ( is_array( $alerts_destinations_items ) ? $alerts_destinations_items : array() as $alerts_destination_summary_item ) {
                        if ( ! is_array( $alerts_destination_summary_item ) ) {
                            continue;
                        }
                        if ( ! empty( $alerts_destination_summary_item['is_default'] ) ) {
                            ++$alerts_default_destinations_total;
                        }
                        if ( 'active' === strtolower( trim( (string) ( $alerts_destination_summary_item['state'] ?? '' ) ) ) ) {
                            ++$alerts_active_destinations_total;
                        }
                    }
                    $alerts_email_destinations_items = array_values(
                        array_filter(
                            is_array( $alerts_destinations_items ) ? $alerts_destinations_items : array(),
                            static function ( $item ) {
                                return is_array( $item ) && 'email' === strtolower( trim( (string) ( $item['family'] ?? '' ) ) );
                            }
                        )
                    );
                    $alerts_email_delivery_quality_title = 'No external email destination is configured yet';
                    $alerts_email_delivery_quality_copy = 'Email routing is optional until a live destination is added. Other delivery families keep their own readback and proof path.';
                    $alerts_email_delivery_quality_tone = 'info';
                    $alerts_recent_email_event = array();
                    foreach ( $alerts_customer_events_items as $alerts_email_event_item ) {
                        if ( ! is_array( $alerts_email_event_item ) ) {
                            continue;
                        }
                        $alerts_email_event_family = strtolower( trim( (string) ( $alerts_email_event_item['destination_family'] ?? $alerts_email_event_item['channel'] ?? '' ) ) );
                        if ( 'email' !== $alerts_email_event_family ) {
                            continue;
                        }
                        $alerts_recent_email_event = $alerts_email_event_item;
                        break;
                    }
                    if ( ! empty( $alerts_email_destinations_items ) ) {
                        $alerts_email_delivery_quality_title = 'Email routing is configured';
                        $alerts_email_delivery_quality_copy = 'OpsGate has a live outbound email route for this site. Recent delivery history becomes the source of truth for send success, while inbox placement quality can still vary by sender reputation and mailbox filtering.';
                        $alerts_email_delivery_quality_tone = 'warn';
                    }
                    if ( ! empty( $alerts_recent_email_event ) ) {
                        $alerts_recent_email_status = strtolower( trim( (string) ( $alerts_recent_email_event['status'] ?? '' ) ) );
                        if ( in_array( $alerts_recent_email_status, array( 'delivered', 'completed' ), true ) ) {
                            $alerts_email_delivery_quality_title = 'Outbound email is working';
                            $alerts_email_delivery_quality_copy = 'OpsGate has recorded successful outbound email delivery for this site. Deliverability hardening still matters because mailbox providers may place the message outside the primary inbox.';
                            $alerts_email_delivery_quality_tone = 'warn';
                        } elseif ( in_array( $alerts_recent_email_status, array( 'failed', 'rejected', 'timeout', 'error' ), true ) ) {
                            $alerts_email_delivery_quality_title = 'Email delivery needs review';
                            $alerts_email_delivery_quality_copy = 'A recent outbound email attempt did not complete cleanly. Review the recorded event and destination history before treating this route as dependable.';
                            $alerts_email_delivery_quality_tone = 'bad';
                        } else {
                            $alerts_email_delivery_quality_title = 'Email delivery is in progress';
                            $alerts_email_delivery_quality_copy = 'OpsGate has a recorded outbound email event for this site and is waiting for the final delivery outcome.';
                            $alerts_email_delivery_quality_tone = 'info';
                        }
                    }
                    $alerts_destinations_summary_copy = sprintf( '%d active', $alerts_active_destinations_total );
                    if ( ! empty( $alerts_email_destinations_items ) ) {
                        $alerts_destinations_summary_copy .= ' • ' . $alerts_email_delivery_quality_title;
                    }
                    $alerts_webhook_destinations_total = count(
                        array_filter(
                            is_array( $alerts_destinations_items ) ? $alerts_destinations_items : array(),
                            static function ( $item ) {
                                return is_array( $item ) && 'webhook' === strtolower( trim( (string) ( $item['family'] ?? '' ) ) );
                            }
                        )
                    );
                    $alerts_full_family_creation_enabled = self::alerts_full_family_creation_enabled();
                    $alerts_rule_destination_focus_id = isset( $_GET['opsgate_alert_rule_destination'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_alert_rule_destination'] ) ) : '';
                    $alerts_rule_destination_focus_label = '';
                    if ( '' !== $alerts_rule_destination_focus_id ) {
                        foreach ( $alerts_destinations_items as $alerts_destination_focus_item ) {
                            if ( ! is_array( $alerts_destination_focus_item ) ) {
                                continue;
                            }
                            if ( $alerts_rule_destination_focus_id === trim( (string) ( $alerts_destination_focus_item['destination_id'] ?? '' ) ) ) {
                                $alerts_rule_destination_focus_label = trim( (string) ( $alerts_destination_focus_item['label'] ?? '' ) );
                                break;
                            }
                        }
                    }
                    $alerts_webhook_limit = isset( $alerts_webhook_allowance['limit'] ) ? (int) $alerts_webhook_allowance['limit'] : 0;
                    $alerts_webhook_remaining = max( 0, $alerts_webhook_limit - $alerts_webhook_destinations_total );
                    $alerts_destination_family_meta = array();
                    foreach ( self::alerts_canonical_families() as $alerts_family_key ) {
                        $alerts_destination_family_meta[ $alerts_family_key ] = self::notification_destination_family_meta( $alerts_family_key );
                    }
                    $alerts_destination_family_options = array();
                    foreach ( self::alerts_canonical_families() as $alerts_destination_family_option ) {
                        $alerts_family_availability = self::alert_availability_for_channel( $alerts_destination_family_option );
                        $alerts_family_has_live_destination = false;
                        foreach ( $alerts_destinations_items as $alerts_family_destination_item ) {
                            if ( ! is_array( $alerts_family_destination_item ) ) {
                                continue;
                            }
                            if ( strtolower( trim( (string) ( $alerts_family_destination_item['family'] ?? '' ) ) ) !== $alerts_destination_family_option ) {
                                continue;
                            }
                            if ( self::notification_destination_is_live( $alerts_family_destination_item ) ) {
                                $alerts_family_has_live_destination = true;
                                break;
                            }
                        }
                        $alerts_family_is_available = 'email' === $alerts_destination_family_option
                            ? ( empty( $alerts_family_availability ) ? true : ! empty( $alerts_family_availability['is_available'] ) )
                            : ( ! empty( $alerts_family_availability['is_available'] ) || $alerts_family_has_live_destination );

                        $alerts_family_note = '';
                        $alerts_family_disabled = false;
                        $alerts_family_state_label = $alerts_family_is_available ? 'Live' : 'Not available';
                        $alerts_family_visibility = $alerts_family_is_available ? 'live' : 'locked';

                        if ( 'webhook' === $alerts_destination_family_option ) {
                            if ( $alerts_webhook_limit <= 0 ) {
                                $alerts_family_disabled = true;
                                $alerts_family_note = 'Not included on this package';
                                $alerts_family_state_label = 'Not included';
                                $alerts_family_visibility = 'locked';
                            } elseif ( $alerts_webhook_destinations_total >= $alerts_webhook_limit ) {
                                $alerts_family_disabled = true;
                                $alerts_family_note = 'Webhook allowance used';
                                $alerts_family_state_label = 'Allowance used';
                                $alerts_family_visibility = 'limited';
                            } else {
                                $alerts_family_note = sprintf( '%d remaining', $alerts_webhook_remaining );
                                $alerts_family_state_label = $alerts_family_is_available ? 'Live' : 'Pending live delivery';
                                $alerts_family_visibility = $alerts_family_is_available ? 'live' : 'pending';
                            }
                        } elseif ( $alerts_family_is_available ) {
                            $alerts_family_note = 'Live on this package';
                            $alerts_family_state_label = 'Live';
                            $alerts_family_visibility = 'live';
                        } elseif ( $alerts_full_family_creation_enabled ) {
                            $alerts_family_note = 'Available on your plan';
                            $alerts_family_state_label = 'Pending live delivery';
                            $alerts_family_visibility = 'pending';
                        } else {
                            $alerts_family_disabled = true;
                            $alerts_tier_hint = '';
                            if ( in_array( $alerts_destination_family_option, array( 'slack', 'whatsapp' ), true ) ) {
                                $alerts_tier_hint = 'Pro or higher';
                            } elseif ( in_array( $alerts_destination_family_option, array( 'discord', 'teams', 'sns' ), true ) ) {
                                $alerts_tier_hint = 'Agency';
                            }
                            $alerts_family_note = '' !== $alerts_tier_hint ? 'Requires ' . $alerts_tier_hint . ' plan' : 'Requires package upgrade';
                            $alerts_family_state_label = 'Upgrade required';
                            $alerts_family_visibility = 'locked';
                        }

                        $alerts_family_meta = isset( $alerts_destination_family_meta[ $alerts_destination_family_option ] ) && is_array( $alerts_destination_family_meta[ $alerts_destination_family_option ] )
                            ? $alerts_destination_family_meta[ $alerts_destination_family_option ]
                            : self::notification_destination_family_meta( $alerts_destination_family_option );
                        $alerts_family_label = self::notification_channel_label( $alerts_destination_family_option );
                        if ( '' === $alerts_family_label || '—' === $alerts_family_label ) {
                            $alerts_family_label = strtoupper( $alerts_destination_family_option );
                        }
                        $alerts_family_guidance = 'Create a destination for this live delivery family on the selected site.';
                        if ( 'email' === $alerts_destination_family_option ) {
                            $alerts_family_guidance = 'Email uses OpsGate\'s verified sender path. Use one primary recipient and optional CC recipients for this destination.';
                        } elseif ( 'webhook' === $alerts_destination_family_option ) {
                            $alerts_family_guidance = ! empty( $alerts_webhook_allowance['is_available'] ) && $alerts_webhook_limit > 0
                                ? sprintf(
                                    'Webhook slots used: %d of %d%s',
                                    $alerts_webhook_destinations_total,
                                    $alerts_webhook_limit,
                                    $alerts_webhook_remaining > 0 ? ' • ' . $alerts_webhook_remaining . ' remaining' : ' • limit reached'
                                )
                                : 'Webhook destinations are not included in the current package.';
                        } elseif ( in_array( $alerts_destination_family_option, array( 'slack', 'teams', 'discord' ), true ) ) {
                            $alerts_family_guidance = 'This destination sends to one configured webhook endpoint and keeps channel context in canonical OpsGate readback.';
                        } elseif ( 'telegram' === $alerts_destination_family_option ) {
                            $alerts_family_guidance = 'Telegram requires a bot token and chat ID for the destination that should receive this alert.';
                        } elseif ( 'whatsapp' === $alerts_destination_family_option ) {
                            $alerts_family_guidance = 'WhatsApp stores the recipient now and keeps provider credentials separate from customer-facing readback.';
                        } elseif ( 'sns' === $alerts_destination_family_option ) {
                            $alerts_family_guidance = 'SNS stores a topic ARN for this route and keeps region/provider details in canonical OpsGate configuration.';
                        }

                        $alerts_destination_family_options[] = array(
                            'value'        => $alerts_destination_family_option,
                            'label'        => $alerts_family_label,
                            'note'         => $alerts_family_note,
                            'state_label'  => $alerts_family_state_label,
                            'visibility'   => $alerts_family_visibility,
                            'disabled'     => $alerts_family_disabled,
                            'value_label'  => (string) ( $alerts_family_meta['value_label'] ?? 'Destination value' ),
                            'placeholder'  => (string) ( $alerts_family_meta['placeholder'] ?? '' ),
                            'help'         => (string) ( $alerts_family_meta['help'] ?? '' ),
                            'guidance'     => $alerts_family_guidance,
                        );
                    }
                    $alerts_destination_create_available = ! empty(
                        array_filter(
                            $alerts_destination_family_options,
                            static function ( $item ) {
                                return is_array( $item ) && empty( $item['disabled'] );
                            }
                        )
                    );
                    $alerts_webhook_allowance_detail = ! empty( $alerts_webhook_allowance['is_available'] ) && $alerts_webhook_limit > 0
                        ? sprintf(
                            'Webhook slots used: %d of %d%s',
                            $alerts_webhook_destinations_total,
                            $alerts_webhook_limit,
                            $alerts_webhook_remaining > 0 ? ' • ' . $alerts_webhook_remaining . ' remaining' : ' • limit reached'
                        )
                        : 'Webhook destinations are not included in the current package.';
                    $alerts_live_rules_total = count(
                        array_filter(
                            $alerts_live_rules_items,
                            static function ( $rule ) {
                                return is_array( $rule ) && ! empty( $rule['is_enabled'] );
                            }
                        )
                    );
                    $alerts_live_family_labels = ! empty( $alerts_channel_groups['live_now'] ) ? implode( ', ', wp_list_pluck( $alerts_channel_groups['live_now'], 'label' ) ) : 'No channels configured';
                    $alerts_locked_family_labels = ! empty( $alerts_channel_groups['visible_locked'] ) ? implode( ', ', wp_list_pluck( $alerts_channel_groups['visible_locked'], 'label' ) ) : 'No additional live channels locked';
                    $alerts_planned_family_labels = ! empty( $alerts_channel_groups['planned_direction'] ) ? implode( ', ', wp_list_pluck( $alerts_channel_groups['planned_direction'], 'label' ) ) : 'No planned families exposed here';
                    $alerts_create_destination_open = 'destination_error' === $alerts_destinations_notice || empty( $alerts_destinations_items );
                    $alerts_create_rule_open = 'rule_error' === $alerts_notice || empty( $alerts_live_rules_items ) || '' !== $alerts_rule_destination_focus_id;
                    $alerts_rule_submit_label = '' !== $alerts_rule_destination_focus_id ? 'Link alert rule' : 'Create or link alert rule';
                    $alerts_rule_form_hint = '' !== $alerts_rule_destination_focus_id
                        ? 'Existing matching rules are reused before a new route is created for this destination.'
                        : 'Matching alert rules are reused so this surface does not create duplicate routing.';
                    $alerts_settings_url = self::admin_tab_url( 'settings' );
                    $alerts_destinations_url = self::admin_tab_url( 'alerts' ) . '#opsgate-alerts-destinations';
                    $alerts_create_destination_url = self::admin_tab_url( 'alerts' ) . '#opsgate-alerts-create-destination';
                    $alerts_rules_url = self::admin_tab_url( 'alerts' ) . '#opsgate-alerts-rules';
                    $alerts_create_rule_url = self::admin_tab_url( 'alerts' ) . '#opsgate-alerts-create-rule';
                    $alerts_history_url = self::admin_tab_url( 'alerts' ) . '#opsgate-alerts-history';
                    $alerts_next_action_title = 'Review selected-site alert routing';
                    $alerts_next_action_copy = 'Use this surface to confirm configured destinations, linked rules, and recent customer-facing delivery history for the selected site.';
                    $alerts_next_action_primary_label = 'Refresh status';
                    $alerts_next_action_primary_url = $alerts_refresh_url;
                    $alerts_next_action_secondary_label = 'Open destinations';
                    $alerts_next_action_secondary_url = $alerts_destinations_url;
                    if ( 'external_only' === $alerts_connection_status ) {
                        $alerts_next_action_title = 'Connect this site before configuring live alerts';
                        $alerts_next_action_copy = 'External-only sites can keep public monitoring, but connected alert routing and destination management are unavailable until pairing is completed on a paid connected tier.';
                        $alerts_next_action_primary_label = 'Open Settings';
                        $alerts_next_action_primary_url = $alerts_settings_url;
                        $alerts_next_action_secondary_label = 'Review connection state';
                        $alerts_next_action_secondary_url = $alerts_settings_url . '#opsgate-site-connection';
                    } elseif ( 'pairing_pending' === $alerts_connection_status ) {
                        $alerts_next_action_title = 'Finish pairing to activate alert routing';
                        $alerts_next_action_copy = 'The canonical site scope exists, but live connector-backed delivery should not be treated as active until pairing completes and the connector credential is issued.';
                        $alerts_next_action_primary_label = 'Open Settings';
                        $alerts_next_action_primary_url = $alerts_settings_url . '#opsgate-site-connection';
                        $alerts_next_action_secondary_label = 'Refresh status';
                        $alerts_next_action_secondary_url = $alerts_refresh_url;
                    } elseif ( in_array( $alerts_connection_status, array( 'credential_invalid', 'disconnected' ), true ) ) {
                        $alerts_next_action_title = 'Reconnect the selected site before trusting delivery';
                        $alerts_next_action_copy = 'Routing records remain visible, but this connection state cannot promise current connected delivery truth until the connector is repaired from the selected site settings.';
                        $alerts_next_action_primary_label = 'Reconnect in Settings';
                        $alerts_next_action_primary_url = $alerts_settings_url . '#opsgate-site-connection';
                        $alerts_next_action_secondary_label = 'Review history';
                        $alerts_next_action_secondary_url = $alerts_history_url;
                    } elseif ( empty( $alerts_destinations_items ) ) {
                        $alerts_next_action_title = 'Create your first alert destination';
                        $alerts_next_action_copy = 'No alert destinations configured yet. Add a destination, then create a rule to start receiving alerts.';
                        $alerts_next_action_primary_label = 'Create destination';
                        $alerts_next_action_primary_url = $alerts_create_destination_url;
                        $alerts_next_action_secondary_label = 'Review destinations';
                        $alerts_next_action_secondary_url = $alerts_destinations_url;
                    } elseif ( $alerts_live_rules_total <= 0 ) {
                        $alerts_next_action_title = 'Link live routing for the selected site';
                        $alerts_next_action_copy = 'Destinations are ready, but no live rules are enabled yet. Link a rule to a destination so triage and report events can route customer-facing alerts for this site.';
                        $alerts_next_action_primary_label = 'Create or link rule';
                        $alerts_next_action_primary_url = $alerts_create_rule_url;
                        $alerts_next_action_secondary_label = 'Review destinations';
                        $alerts_next_action_secondary_url = $alerts_destinations_url;
                    } elseif ( empty( $alerts_recent_customer_events_items ) ) {
                        $alerts_next_action_title = 'Run a delivery check for this selected site';
                        $alerts_next_action_copy = 'Routing is configured, but no customer-facing delivery history has been recorded yet. Trigger a destination test to capture the first live delivery event for this site.';
                        $alerts_next_action_primary_label = 'Review destinations';
                        $alerts_next_action_primary_url = $alerts_destinations_url;
                        $alerts_next_action_secondary_label = 'Review rules';
                        $alerts_next_action_secondary_url = $alerts_rules_url;
                    } else {
                        $alerts_next_action_title = 'Review recent delivery history';
                        $alerts_next_action_copy = 'Live alert routing is recorded for this selected site. Use recent customer-facing history first, then open the secondary support area only when you need validation detail.';
                        $alerts_next_action_primary_label = 'Review history';
                        $alerts_next_action_primary_url = $alerts_history_url;
                        $alerts_next_action_secondary_label = 'Review rules';
                        $alerts_next_action_secondary_url = $alerts_rules_url;
                    }
                    ?>
                    <div
                        id="opsgate-alerts-live-panel"
                        class="opsgate-card opsgate-alerts-dashboard"
                        data-opsgate-refresh-url="<?php echo esc_url( $alerts_refresh_url ); ?>"
                        data-opsgate-ajax-url="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"
                    >
                        <?php if ( $alerts_destinations_total === 0 && '' === $alerts_destinations_error ) : ?>
                        <div class="opsgate-alerts-empty-state">
                            <div class="opsgate-alerts-empty-state-inner">
                                <h2 class="opsgate-alerts-empty-state-title">No alert destinations configured yet</h2>
                                <p class="opsgate-alerts-empty-state-copy">Add a destination to receive security alerts by email, Slack, or webhook. Alerts fire automatically when OpsGate detects a vulnerability or scan result change on this site.</p>
                                <button type="button" class="button button-primary button-large" data-og-overview-action="destinations">Add your first destination &rarr;</button>
                            </div>
                        </div>
                        <?php else : ?>
                        <div class="opsgate-alerts-header">
                            <div class="opsgate-alerts-header-copy">
                                <h2 class="opsgate-alerts-title">Alerts</h2>
                                <p class="opsgate-alerts-subtitle">Configure alert destinations, review delivery history, and track vulnerability notifications for this site.</p>
                                <p class="opsgate-alerts-history-copy"><?php echo esc_html( $alerts_connection_label . ' · ' . $alerts_connection_copy ); ?></p>
                            </div>
                            <div class="opsgate-alerts-actions">
                                <button type="button" class="button button-secondary" data-opsgate-refresh-panel="opsgate-alerts-live-panel">Refresh alert center</button>
                            </div>
                        </div>

                        <div class="opsgate-sub-nav" id="opsgate-alerts-subnav" role="tablist">
                            <a href="#" class="opsgate-sub-nav-item is-active" data-og-sub-target="alerts-overview" role="tab" aria-selected="true">Overview</a>
                            <a href="#" class="opsgate-sub-nav-item" data-og-sub-target="alerts-destinations" role="tab" aria-selected="false">Destinations</a>
                            <a href="#" class="opsgate-sub-nav-item" data-og-sub-target="alerts-rules" role="tab" aria-selected="false">Rules</a>
                            <a href="#" class="opsgate-sub-nav-item" data-og-sub-target="alerts-history" role="tab" aria-selected="false">History</a>
                        </div>

                        <div class="opsgate-sub-panel is-active" id="opsgate-alerts-sub-overview" role="tabpanel">

                        <div class="opsgate-alerts-summary-grid opsgate-alerts-summary-grid-hero">
                            <article class="opsgate-alerts-summary-card opsgate-alerts-summary-card-primary opsgate-alerts-summary-card-<?php echo esc_attr( $alerts_latest_event_tone ); ?>">
                                <span class="opsgate-alerts-eyebrow">Alert delivery health</span>
                                <div class="opsgate-alerts-summary-value opsgate-alerts-summary-value-<?php echo esc_attr( $alerts_latest_event_tone ); ?>"><?php echo esc_html( $alerts_latest_event_label ); ?></div>
                                <p class="opsgate-alerts-summary-copy"><?php echo esc_html( $alerts_latest_event_name . ' • ' . $alerts_latest_timestamp ); ?></p>
                                <p class="opsgate-alerts-summary-copy"><?php echo esc_html( $alerts_latest_event_summary ); ?></p>
                            </article>
                            <article class="opsgate-alerts-summary-card opsgate-alerts-summary-card-action">
                                <span class="opsgate-alerts-eyebrow">What to do next</span>
                                <div class="opsgate-alerts-summary-value"><?php echo esc_html( $alerts_next_action_title ); ?></div>
                                <p class="opsgate-alerts-summary-copy"><?php echo esc_html( $alerts_next_action_copy ); ?></p>
                                <div class="opsgate-alerts-summary-actions">
                                    <?php
                                    $alerts_panel_hash_map = array(
                                        '#opsgate-alerts-history'     => 'history',
                                        '#opsgate-alerts-rules'        => 'rules',
                                        '#opsgate-alerts-destinations' => 'destinations',
                                        '#opsgate-alerts-overview'     => 'overview',
                                    );
                                    $alerts_primary_panel_action = '';
                                    foreach ( $alerts_panel_hash_map as $hash => $panel ) {
                                        if ( false !== strpos( $alerts_next_action_primary_url, $hash ) ) {
                                            $alerts_primary_panel_action = $panel;
                                            break;
                                        }
                                    }
                                    $alerts_secondary_panel_action = '';
                                    foreach ( $alerts_panel_hash_map as $hash => $panel ) {
                                        if ( false !== strpos( $alerts_next_action_secondary_url, $hash ) ) {
                                            $alerts_secondary_panel_action = $panel;
                                            break;
                                        }
                                    }
                                    if ( '' !== $alerts_primary_panel_action ) :
                                        ?>
                                        <button type="button" class="button button-secondary" data-og-overview-action="<?php echo esc_attr( $alerts_primary_panel_action ); ?>"><?php echo esc_html( $alerts_next_action_primary_label ); ?></button>
                                    <?php else : ?>
                                        <a class="button button-secondary" href="<?php echo esc_url( $alerts_next_action_primary_url ); ?>"><?php echo esc_html( $alerts_next_action_primary_label ); ?></a>
                                    <?php endif; ?>
                                    <?php if ( '' !== trim( $alerts_next_action_secondary_label ) ) : ?>
                                        <?php if ( '' !== $alerts_secondary_panel_action ) : ?>
                                            <button type="button" class="button-link" data-og-overview-action="<?php echo esc_attr( $alerts_secondary_panel_action ); ?>"><?php echo esc_html( $alerts_next_action_secondary_label ); ?></button>
                                        <?php else : ?>
                                            <a class="button-link" href="<?php echo esc_url( $alerts_next_action_secondary_url ); ?>"><?php echo esc_html( $alerts_next_action_secondary_label ); ?></a>
                                        <?php endif; ?>
                                    <?php endif; ?>
                                </div>
                            </article>
                            <article class="opsgate-alerts-summary-card<?php echo in_array( $alerts_vulnerability_story_tone, array( 'good', 'warn', 'bad' ), true ) ? ' opsgate-alerts-summary-card-' . esc_attr( $alerts_vulnerability_story_tone ) : ''; ?>">
                                <span class="opsgate-alerts-eyebrow">Vulnerability-driven events</span>
                                <div class="opsgate-alerts-summary-value<?php echo in_array( $alerts_vulnerability_story_tone, array( 'good', 'warn', 'bad' ), true ) ? ' opsgate-alerts-summary-value-' . esc_attr( $alerts_vulnerability_story_tone ) : ''; ?>"><?php echo esc_html( $alerts_vulnerability_story_title ); ?></div>
                                <p class="opsgate-alerts-summary-copy"><?php echo esc_html( $alerts_vulnerability_story_copy ); ?></p>
                            </article>
                            <article class="opsgate-alerts-summary-card">
                                <span class="opsgate-alerts-eyebrow">Configured destinations</span>
                                <div class="opsgate-alerts-summary-value"><?php echo esc_html( sprintf( '%d destination%s', $alerts_destinations_total, 1 === $alerts_destinations_total ? '' : 's' ) ); ?></div>
                                <p class="opsgate-alerts-summary-copy"><?php echo esc_html( $alerts_destinations_summary_copy ); ?></p>
                            </article>
                            <article class="opsgate-alerts-summary-card">
                                <span class="opsgate-alerts-eyebrow">Active alerts</span>
                                <div class="opsgate-alerts-summary-value"><?php echo esc_html( sprintf( '%d rule%s active', $alerts_live_rules_total, 1 === $alerts_live_rules_total ? '' : 's' ) ); ?></div>
                                <p class="opsgate-alerts-summary-copy"><?php echo esc_html( $alerts_live_family_labels ); ?></p>
                            </article>
                        </div>

                        <details class="opsgate-r1-support-demotion" style="margin-top:8px;">
                            <summary class="opsgate-r1-support-demotion-summary">Delivery summary</summary>
                            <div class="opsgate-alerts-status-strip opsgate-alerts-status-strip-refined">
                                <div class="opsgate-alerts-status-item"><span class="opsgate-alerts-status-label">Active rules</span><span class="opsgate-alerts-status-value"><?php echo esc_html( (string) $alerts_live_rules_total ); ?></span></div>
                                <div class="opsgate-alerts-status-item"><span class="opsgate-alerts-status-label">Alert channels</span><span class="opsgate-alerts-status-value"><?php echo esc_html( $alerts_channels_copy ); ?></span></div>
                                <div class="opsgate-alerts-status-item"><span class="opsgate-alerts-status-label">Latest delivery</span><span class="opsgate-alerts-status-value"><?php echo esc_html( $alerts_latest_event_label ); ?></span></div>
                                <div class="opsgate-alerts-status-item"><span class="opsgate-alerts-status-label">Latest event</span><span class="opsgate-alerts-status-value"><?php echo esc_html( $alerts_latest_timestamp ); ?></span></div>
                                <div class="opsgate-alerts-status-item"><span class="opsgate-alerts-status-label">Scope</span><span class="opsgate-alerts-status-value"><?php echo esc_html( $alerts_scope_label ); ?></span></div>
                            </div>
                        </details>

                        </div><!-- /#opsgate-alerts-sub-overview -->

                        <div class="opsgate-sub-panel" id="opsgate-alerts-sub-destinations" role="tabpanel">

                        <section id="opsgate-alerts-destinations" class="opsgate-alerts-surface opsgate-alerts-destinations-surface">
                            <div class="opsgate-alerts-surface-header">
                                <div class="opsgate-alerts-surface-copy">
                                    <h3 class="opsgate-alerts-surface-title">Configured destinations</h3>
                                    <p class="opsgate-alerts-history-copy">Where alerts are going, which routes are active, and what recent delivery activity proves.</p>
                                </div>
                            </div>
                            <div
                                id="opsgate-alert-destinations-status"
                                class="opsgate-alert-inline-status<?php echo in_array( $alerts_destinations_notice, array( 'destination_created', 'destination_updated', 'destination_removed', 'destination_tested', 'destination_error' ), true ) ? ' is-visible ' . ( 'destination_error' === $alerts_destinations_notice ? 'is-error' : 'is-success' ) : ''; ?>"
                                data-opsgate-transient-status="1"
                                role="status"
                                aria-live="polite"
                            >
                                <p>
                                    <?php
                                    if ( 'destination_created' === $alerts_destinations_notice ) {
                                        echo esc_html( 'Alert destination created.' );
                                    } elseif ( 'destination_updated' === $alerts_destinations_notice ) {
                                        echo esc_html( 'Alert destination updated.' );
                                    } elseif ( 'destination_removed' === $alerts_destinations_notice ) {
                                        echo esc_html( 'Alert destination removed.' );
                                    } elseif ( 'destination_tested' === $alerts_destinations_notice ) {
                                        echo esc_html( 'Alert destination test queued.' );
                                    } elseif ( 'destination_error' === $alerts_destinations_notice ) {
                                        echo esc_html( '' !== $alerts_destinations_error_notice ? $alerts_destinations_error_notice : 'Could not update the alert destination.' );
                                    }
                                    ?>
                                </p>
                            </div>
                            <div class="opsgate-alerts-summary-grid opsgate-alerts-summary-grid-compact">
                                <article class="opsgate-alerts-summary-card">
                                    <span class="opsgate-alerts-eyebrow">Destination coverage</span>
                                    <div class="opsgate-alerts-summary-value"><?php echo esc_html( sprintf( '%d destination%s', $alerts_destinations_total, 1 === $alerts_destinations_total ? '' : 's' ) ); ?></div>
                                    <p class="opsgate-alerts-summary-copy"><?php echo esc_html( sprintf( '%d active • %d default', $alerts_active_destinations_total, $alerts_default_destinations_total ) ); ?></p>
                                </article>
                                <article class="opsgate-alerts-summary-card">
                                    <span class="opsgate-alerts-eyebrow">Plan details</span>
                                    <div class="opsgate-alerts-summary-value"><?php echo esc_html( self::package_scope_allowance_label_for_entry( $alerts_package_scope_allowance ) ); ?></div>
                                    <p class="opsgate-alerts-summary-copy"><?php echo esc_html( self::package_scope_allowance_summary_for_entry( $alerts_package_scope_allowance ) ); ?></p>
                                </article>
                                <article class="opsgate-alerts-summary-card<?php echo in_array( $alerts_email_delivery_quality_tone, array( 'good', 'warn', 'bad' ), true ) ? ' opsgate-alerts-summary-card-' . esc_attr( $alerts_email_delivery_quality_tone ) : ''; ?>">
                                    <span class="opsgate-alerts-eyebrow">Email delivery quality</span>
                                    <div class="opsgate-alerts-summary-value"><?php echo esc_html( $alerts_email_delivery_quality_title ); ?></div>
                                    <p class="opsgate-alerts-summary-copy"><?php echo esc_html( $alerts_email_delivery_quality_copy ); ?></p>
                                </article>
                            </div>

                            <details id="opsgate-alerts-create-destination" class="opsgate-alerts-create-details"<?php echo $alerts_create_destination_open ? ' open="open"' : ''; ?>>
                                <summary>Create destination</summary>
                                <div class="opsgate-alerts-create-panel">
                                    <?php if ( empty( $alerts_destination_family_options ) ) : ?>
                                        <div class="opsgate-alert-panel">
                                            <p>No live destination families are available on the current package yet.</p>
                                        </div>
                                    <?php else : ?>
                                        <?php
                                        $alerts_destination_default_family = $alerts_destination_family_options[0];
                                        $alerts_destination_default_family_key = (string) ( $alerts_destination_default_family['value'] ?? 'email' );
                                        $alerts_destination_default_help = (string) ( $alerts_destination_default_family['help'] ?? '' );
                                        $alerts_destination_default_state = (string) ( $alerts_destination_default_family['state_label'] ?? '' );
                                        $alerts_destination_default_note = (string) ( $alerts_destination_default_family['note'] ?? '' );
                                        $alerts_destination_default_guidance = (string) ( $alerts_destination_default_family['guidance'] ?? '' );
                                        ?>
                                        <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" data-opsgate-destination-form="create">
                                            <input type="hidden" name="action" value="opsgate_notification_destination_create" />
                                            <?php wp_nonce_field( 'opsgate_notification_destination_create' ); ?>
                                            <div class="opsgate-alerts-form-grid">
                                                <label class="opsgate-alerts-form-field">
                                                    <span>Family</span>
                                                    <select name="destination_family" class="regular-text opsgate-destination-family-select">
                                                        <?php foreach ( $alerts_destination_family_options as $alerts_destination_family_option ) : ?>
                                                            <?php if ( ! is_array( $alerts_destination_family_option ) ) { continue; } ?>
                                                            <option
                                                                value="<?php echo esc_attr( (string) ( $alerts_destination_family_option['value'] ?? '' ) ); ?>"
                                                                data-state-label="<?php echo esc_attr( (string) ( $alerts_destination_family_option['state_label'] ?? '' ) ); ?>"
                                                                data-note="<?php echo esc_attr( (string) ( $alerts_destination_family_option['note'] ?? '' ) ); ?>"
                                                                data-value-label="<?php echo esc_attr( (string) ( $alerts_destination_family_option['value_label'] ?? 'Destination value' ) ); ?>"
                                                                data-placeholder="<?php echo esc_attr( (string) ( $alerts_destination_family_option['placeholder'] ?? '' ) ); ?>"
                                                                data-help="<?php echo esc_attr( (string) ( $alerts_destination_family_option['help'] ?? '' ) ); ?>"
                                                                data-guidance="<?php echo esc_attr( (string) ( $alerts_destination_family_option['guidance'] ?? '' ) ); ?>"
                                                                <?php disabled( ! empty( $alerts_destination_family_option['disabled'] ) ); ?>
                                                            >
                                                                <?php
                                                                $alerts_destination_family_option_label = (string) ( $alerts_destination_family_option['label'] ?? 'Family' );
                                                                $alerts_destination_family_option_note  = trim( (string) ( $alerts_destination_family_option['note'] ?? '' ) );
                                                                echo esc_html( '' !== $alerts_destination_family_option_note ? $alerts_destination_family_option_label . ' — ' . $alerts_destination_family_option_note : $alerts_destination_family_option_label );
                                                                ?>
                                                            </option>
                                                        <?php endforeach; ?>
                                                    </select>
                                                    <small class="opsgate-alerts-destination-family-note"><?php echo esc_html( trim( $alerts_destination_default_state . ( '' !== $alerts_destination_default_note ? ' • ' . $alerts_destination_default_note : '' ) ) ); ?></small>
                                                </label>
                                                <label class="opsgate-alerts-form-field">
                                                    <span>Label</span>
                                                    <input name="destination_label" type="text" class="regular-text" placeholder="Primary email, primary webhook, escalation channel" />
                                                </label>
                                                <div class="opsgate-alerts-form-field opsgate-alerts-form-field-wide">
                                                    <?php foreach ( self::alerts_canonical_families() as $alerts_destination_form_family ) : ?>
                                                        <?php $alerts_destination_form_fields = self::notification_destination_family_fields( $alerts_destination_form_family ); ?>
                                                        <?php if ( empty( $alerts_destination_form_fields ) ) { continue; } ?>
                                                        <div data-family-fields="<?php echo esc_attr( $alerts_destination_form_family ); ?>"<?php echo $alerts_destination_form_family === $alerts_destination_default_family_key ? '' : ' hidden="hidden"'; ?>>
                                                            <div class="opsgate-alerts-form-grid">
                                                                <?php foreach ( $alerts_destination_form_fields as $alerts_destination_form_field ) : ?>
                                                                    <?php
                                                                    if ( ! is_array( $alerts_destination_form_field ) || empty( $alerts_destination_form_field['key'] ) ) {
                                                                        continue;
                                                                    }
                                                                    $alerts_destination_form_field_key = (string) $alerts_destination_form_field['key'];
                                                                    $alerts_destination_form_field_type = (string) ( $alerts_destination_form_field['type'] ?? 'text' );
                                                                    $alerts_destination_form_field_help = (string) ( $alerts_destination_form_field['help'] ?? '' );
                                                                    ?>
                                                                    <label class="opsgate-alerts-form-field<?php echo ! empty( $alerts_destination_form_field['required'] ) ? ' opsgate-alerts-form-field-required' : ''; ?>">
                                                                        <span><?php echo esc_html( (string) ( $alerts_destination_form_field['label'] ?? 'Destination value' ) ); ?></span>
                                                                        <input
                                                                            name="destination_config[<?php echo esc_attr( $alerts_destination_form_field_key ); ?>]"
                                                                            type="<?php echo esc_attr( in_array( $alerts_destination_form_field_type, array( 'email', 'url', 'password' ), true ) ? $alerts_destination_form_field_type : 'text' ); ?>"
                                                                            class="regular-text"
                                                                            placeholder="<?php echo esc_attr( (string) ( $alerts_destination_form_field['placeholder'] ?? '' ) ); ?>"
                                                                            data-opsgate-destination-field-key="<?php echo esc_attr( $alerts_destination_form_field_key ); ?>"
                                                                            data-opsgate-destination-field-type="<?php echo esc_attr( $alerts_destination_form_field_type ); ?>"
                                                                            data-opsgate-destination-field-required="<?php echo ! empty( $alerts_destination_form_field['required'] ) ? '1' : '0'; ?>"
                                                                            data-opsgate-destination-field-secret="<?php echo ! empty( $alerts_destination_form_field['secret'] ) ? '1' : '0'; ?>"
                                                                        />
                                                                        <?php if ( '' !== $alerts_destination_form_field_help ) : ?>
                                                                            <small><?php echo esc_html( $alerts_destination_form_field_help ); ?></small>
                                                                        <?php endif; ?>
                                                                    </label>
                                                                <?php endforeach; ?>
                                                            </div>
                                                            <?php
                                                            $alerts_create_form_setup_steps = self::notification_destination_family_setup_steps( $alerts_destination_form_family );
                                                            if ( ! empty( $alerts_create_form_setup_steps ) ) :
                                                                $alerts_create_form_setup_heading = (string) ( $alerts_create_form_setup_steps['heading'] ?? '' );
                                                                $alerts_create_form_setup_list    = isset( $alerts_create_form_setup_steps['steps'] ) && is_array( $alerts_create_form_setup_steps['steps'] ) ? $alerts_create_form_setup_steps['steps'] : array();
                                                            ?>
                                                            <details class="opsgate-alerts-setup-steps">
                                                                <summary><?php echo esc_html( '' !== $alerts_create_form_setup_heading ? $alerts_create_form_setup_heading : 'Provider setup steps' ); ?></summary>
                                                                <ol class="opsgate-alerts-setup-list">
                                                                    <?php foreach ( $alerts_create_form_setup_list as $alerts_create_form_setup_step ) : ?>
                                                                        <li><?php echo esc_html( (string) $alerts_create_form_setup_step ); ?></li>
                                                                    <?php endforeach; ?>
                                                                </ol>
                                                            </details>
                                                            <?php endif; ?>
                                                        </div>
                                                    <?php endforeach; ?>
                                                    <small class="opsgate-alerts-detail-meta"><?php echo esc_html( $alerts_destination_default_help ); ?></small>
                                                </div>
                                            </div>
                                            <div class="opsgate-alerts-create-footer">
                                                <div class="opsgate-alerts-create-guidance">
                                                    <label class="opsgate-alerts-checkbox">
                                                        <input type="checkbox" name="destination_is_default" value="1" />
                                                        Set as active default for this family
                                                    </label>
                                                    <span class="opsgate-alerts-detail-meta opsgate-alerts-destination-family-guidance"><?php echo esc_html( $alerts_destination_default_guidance ); ?></span>
                                                </div>
                                                <button type="submit" class="button button-secondary" <?php disabled( ! $alerts_destination_create_available ); ?>>Create destination</button>
                                            </div>
                                        </form>
                                        <script>
                                        (function() {
                                            var forms = document.querySelectorAll('[data-opsgate-destination-form="create"]');
                                            forms.forEach(function(form) {
                                                var select = form.querySelector('.opsgate-destination-family-select');
                                                var note = form.querySelector('.opsgate-alerts-destination-family-note');
                                                var help = form.querySelector('.opsgate-alerts-form-field-wide .opsgate-alerts-detail-meta');
                                                var guidance = form.querySelector('.opsgate-alerts-destination-family-guidance');
                                                var groups = form.querySelectorAll('[data-family-fields]');
                                                if (!select) {
                                                    return;
                                                }
                                                var sync = function() {
                                                    var selected = select.value || '';
                                                    groups.forEach(function(group) {
                                                        var isActiveFamily = group.getAttribute('data-family-fields') === selected;
                                                        group.hidden = !isActiveFamily;
                                                        Array.prototype.slice.call(group.querySelectorAll('input, select, textarea')).forEach(function(field) {
                                                            field.disabled = !isActiveFamily;
                                                        });
                                                    });
                                                    if (note) {
                                                        var option = select.options[select.selectedIndex];
                                                        var state = option ? (option.getAttribute('data-state-label') || '') : '';
                                                        var detail = option ? (option.getAttribute('data-note') || '') : '';
                                                        note.textContent = [state, detail].filter(Boolean).join(' • ');
                                                    }
                                                    if (help) {
                                                        var selectedHelp = select.options[select.selectedIndex] ? (select.options[select.selectedIndex].getAttribute('data-help') || '') : '';
                                                        help.textContent = selectedHelp;
                                                    }
                                                    if (guidance) {
                                                        var selectedGuidance = select.options[select.selectedIndex] ? (select.options[select.selectedIndex].getAttribute('data-guidance') || '') : '';
                                                        guidance.textContent = selectedGuidance;
                                                    }
                                                };
                                                select.addEventListener('change', sync);
                                                sync();
                                            });
                                        })();
                                        </script>
                                    <?php endif; ?>
                                </div>
                            </details>

                            <?php if ( ! $alerts_destinations_ok ) : ?>
                                <div class="opsgate-alert-panel opsgate-alert-panel-error">
                                    <p><?php echo esc_html( '' !== $alerts_destinations_error ? $alerts_destinations_error : 'Could not load alert destinations.' ); ?></p>
                                </div>
                            <?php elseif ( empty( $alerts_destinations_items ) ) : ?>
                                <div class="opsgate-alert-panel">
                                    <p>No canonical alert destinations are configured for this site yet.</p>
                                </div>
                            <?php else : ?>
                                <div class="opsgate-alerts-destinations-list">
                                    <?php foreach ( $alerts_destinations_items as $alerts_destination_item ) : ?>
                                        <?php
                                        if ( ! is_array( $alerts_destination_item ) ) {
                                            continue;
                                        }
                                        $alerts_destination_id = isset( $alerts_destination_item['destination_id'] ) ? trim( (string) $alerts_destination_item['destination_id'] ) : '';
                                        $alerts_destination_family = isset( $alerts_destination_item['family'] ) ? strtolower( trim( (string) $alerts_destination_item['family'] ) ) : '';
                                        $alerts_destination_label = isset( $alerts_destination_item['label'] ) ? trim( (string) $alerts_destination_item['label'] ) : 'Untitled destination';
                                        $alerts_destination_state = isset( $alerts_destination_item['state'] ) ? strtolower( trim( (string) $alerts_destination_item['state'] ) ) : '';
                                        $alerts_destination_state_label = self::notification_status_label( $alerts_destination_state );
                                        $alerts_destination_state_tone = 'active' === $alerts_destination_state ? 'good' : 'warn';
                                        $alerts_destination_is_default = ! empty( $alerts_destination_item['is_default'] );
                                        $alerts_destination_is_active = 'active' === $alerts_destination_state;
                                        $alerts_destination_target = self::notification_target_display(
                                            isset( $alerts_destination_item['resolved_target'] ) ? (string) $alerts_destination_item['resolved_target'] : '',
                                            $alerts_destination_family
                                        );
                                        $alerts_destination_delivery_reason = isset( $alerts_destination_item['delivery_state_reason'] ) ? trim( (string) $alerts_destination_item['delivery_state_reason'] ) : '';
                                        $alerts_destination_rule_names = array();
                                        $alerts_destination_rule_ids = isset( $alerts_destination_item['linked_rule_ids'] ) && is_array( $alerts_destination_item['linked_rule_ids'] ) ? $alerts_destination_item['linked_rule_ids'] : array();
                                        $alerts_destination_linked_event_types = array();
                                        $alerts_destination_linked_enabled_count = 0;
                                        foreach ( $alerts_destination_rule_ids as $alerts_destination_rule_id ) {
                                            $alerts_destination_rule_id = trim( (string) $alerts_destination_rule_id );
                                            if ( '' === $alerts_destination_rule_id ) {
                                                continue;
                                            }
                                            $alerts_destination_rule_names[] = isset( $alerts_rule_name_by_id[ $alerts_destination_rule_id ] ) ? (string) $alerts_rule_name_by_id[ $alerts_destination_rule_id ] : $alerts_destination_rule_id;
                                        }
                                        foreach ( $alerts_live_rules_items as $alerts_destination_rule_item ) {
                                            if ( ! is_array( $alerts_destination_rule_item ) || ! self::notification_rule_targets_destination( $alerts_destination_rule_item, $alerts_destination_item ) ) {
                                                continue;
                                            }
                                            $alerts_destination_matched_rule_id = isset( $alerts_destination_rule_item['rule_id'] ) ? trim( (string) $alerts_destination_rule_item['rule_id'] ) : '';
                                            if ( '' !== $alerts_destination_matched_rule_id ) {
                                                $alerts_destination_rule_ids[] = $alerts_destination_matched_rule_id;
                                            }
                                            $alerts_destination_rule_names[] = self::notification_rule_display_name( $alerts_destination_rule_item );
                                            $alerts_destination_linked_event_type = isset( $alerts_destination_rule_item['event_type'] ) ? trim( (string) $alerts_destination_rule_item['event_type'] ) : '';
                                            if ( '' !== $alerts_destination_linked_event_type ) {
                                                $alerts_destination_linked_event_types[] = $alerts_destination_linked_event_type;
                                            }
                                            if ( ! empty( $alerts_destination_rule_item['is_enabled'] ) ) {
                                                ++$alerts_destination_linked_enabled_count;
                                            }
                                        }
                                        $alerts_destination_rule_names = array_values( array_unique( array_filter( $alerts_destination_rule_names ) ) );
                                        $alerts_destination_linked_event_types = array_values( array_unique( array_filter( $alerts_destination_linked_event_types ) ) );
                                        $alerts_destination_rule_preview = array_slice( $alerts_destination_rule_names, 0, 3 );
                                        $alerts_destination_rule_preview_copy = ! empty( $alerts_destination_rule_preview ) ? implode( ' • ', $alerts_destination_rule_preview ) : '';
                                        if ( count( $alerts_destination_rule_names ) > count( $alerts_destination_rule_preview ) ) {
                                            $alerts_destination_rule_preview_copy .= ' • +' . ( count( $alerts_destination_rule_names ) - count( $alerts_destination_rule_preview ) ) . ' more';
                                        }
                                        $alerts_destination_available_rule_labels = array();
                                        foreach ( $alerts_rule_event_options as $alerts_destination_rule_event_key => $alerts_destination_rule_event_label ) {
                                            if ( ! in_array( $alerts_destination_rule_event_key, $alerts_destination_linked_event_types, true ) ) {
                                                $alerts_destination_available_rule_labels[] = $alerts_destination_rule_event_label;
                                            }
                                        }
                                        $alerts_destination_available_rule_preview = array_slice( $alerts_destination_available_rule_labels, 0, 3 );
                                        $alerts_destination_available_rule_copy = ! empty( $alerts_destination_available_rule_preview ) ? implode( ' • ', $alerts_destination_available_rule_preview ) : 'All alert types on this surface already route here.';
                                        if ( count( $alerts_destination_available_rule_labels ) > count( $alerts_destination_available_rule_preview ) ) {
                                            $alerts_destination_available_rule_copy .= ' • +' . ( count( $alerts_destination_available_rule_labels ) - count( $alerts_destination_available_rule_preview ) ) . ' more';
                                        }
                                        $alerts_destination_last_test_event_id = isset( $alerts_destination_item['last_test_event_id'] ) ? trim( (string) $alerts_destination_item['last_test_event_id'] ) : '';
                                        $alerts_destination_last_test_event = ( '' !== $alerts_destination_last_test_event_id && isset( $alerts_event_by_id[ $alerts_destination_last_test_event_id ] ) && is_array( $alerts_event_by_id[ $alerts_destination_last_test_event_id ] ) ) ? $alerts_event_by_id[ $alerts_destination_last_test_event_id ] : array();
                                        $alerts_destination_last_activity_event = ( '' !== $alerts_destination_id && isset( $alerts_event_by_destination[ $alerts_destination_id ] ) && is_array( $alerts_event_by_destination[ $alerts_destination_id ] ) ) ? $alerts_event_by_destination[ $alerts_destination_id ] : $alerts_destination_last_test_event;
                                        $alerts_destination_last_activity_event_id = isset( $alerts_destination_last_activity_event['event_id'] ) ? trim( (string) $alerts_destination_last_activity_event['event_id'] ) : $alerts_destination_last_test_event_id;
                                        $alerts_destination_last_activity_status = isset( $alerts_destination_last_activity_event['status'] ) ? strtolower( trim( (string) $alerts_destination_last_activity_event['status'] ) ) : '';
                                        $alerts_destination_last_activity_label = '' !== $alerts_destination_last_activity_status ? self::notification_status_label( $alerts_destination_last_activity_status ) : ( '' !== $alerts_destination_last_activity_event_id ? 'Recorded' : 'No activity yet' );
                                        $alerts_destination_last_activity_tone = 'neutral';
                                        if ( in_array( $alerts_destination_last_activity_status, array( 'delivered', 'completed' ), true ) ) {
                                            $alerts_destination_last_activity_tone = 'good';
                                        } elseif ( in_array( $alerts_destination_last_activity_status, array( 'ready', 'queued', 'pending', 'running', 'in_progress', 'suppressed' ), true ) ) {
                                            $alerts_destination_last_activity_tone = 'warn';
                                        } elseif ( in_array( $alerts_destination_last_activity_status, array( 'failed', 'rejected', 'timeout', 'error' ), true ) ) {
                                            $alerts_destination_last_activity_tone = 'bad';
                                        }
                                        if ( 'email' === $alerts_destination_family ) {
                                            if ( in_array( $alerts_destination_last_activity_status, array( 'delivered', 'completed' ), true ) ) {
                                                $alerts_destination_delivery_reason = 'Outbound email is working for this destination. Mailbox placement can still vary while sender trust and inbox placement continue to improve.';
                                            } elseif ( in_array( $alerts_destination_last_activity_status, array( 'failed', 'rejected', 'timeout', 'error' ), true ) ) {
                                                $alerts_destination_delivery_reason = 'Recent outbound email for this destination did not complete cleanly. Review recorded attempts before treating this route as dependable.';
                                            } elseif ( '' === $alerts_destination_delivery_reason && $alerts_destination_is_active ) {
                                                $alerts_destination_delivery_reason = 'This destination is configured for outbound email. Recent delivery history will confirm send success and inbox placement quality separately.';
                                            }
                                        }
                                        $alerts_destination_last_activity_issue = ! empty( $alerts_destination_last_activity_event ) ? self::canonical_notification_issue_copy( (string) ( $alerts_destination_last_activity_event['error_code'] ?? '' ), (string) ( $alerts_destination_last_activity_event['error_message'] ?? '' ) ) : '';
                                        $alerts_destination_last_activity_event_type = isset( $alerts_destination_last_activity_event['event_type'] ) ? trim( (string) $alerts_destination_last_activity_event['event_type'] ) : '';
                                        $alerts_destination_last_activity_source_type = isset( $alerts_destination_last_activity_event['source_type'] ) ? trim( (string) $alerts_destination_last_activity_event['source_type'] ) : '';
                                        $alerts_destination_last_activity_source_id = isset( $alerts_destination_last_activity_event['source_id'] ) ? trim( (string) $alerts_destination_last_activity_event['source_id'] ) : '';
                                        $alerts_destination_last_activity_reference = '';
                                        if ( in_array( $alerts_destination_last_activity_source_type, array( 'run', 'triage', 'job' ), true ) && '' !== $alerts_destination_last_activity_source_id ) {
                                            $alerts_destination_last_activity_reference = self::canonical_activity_reference_copy( 'Run reference', $alerts_destination_last_activity_source_id );
                                        } elseif ( '' !== $alerts_destination_last_activity_event_id ) {
                                            $alerts_destination_last_activity_reference = self::canonical_activity_reference_copy( 'Event reference', $alerts_destination_last_activity_event_id );
                                        }
                                        $alerts_destination_routing_state_label = 'Incomplete routing';
                                        $alerts_destination_routing_state_tone = 'warn';
                                        $alerts_destination_routing_state_copy = 'No alert rules are linked to this destination yet.';
                                        if ( ! $alerts_destination_is_active ) {
                                            $alerts_destination_routing_state_label = 'Disabled';
                                            $alerts_destination_routing_state_tone = 'warn';
                                            $alerts_destination_routing_state_copy = 'This destination is off and will not receive live routing.';
                                        } elseif ( empty( $alerts_destination_rule_names ) ) {
                                            $alerts_destination_routing_state_label = 'Incomplete routing';
                                            $alerts_destination_routing_state_tone = 'warn';
                                            $alerts_destination_routing_state_copy = 'Create or link at least one alert rule before treating this destination as live.';
                                        } elseif ( $alerts_destination_linked_enabled_count <= 0 ) {
                                            $alerts_destination_routing_state_label = 'On but not routed';
                                            $alerts_destination_routing_state_tone = 'warn';
                                            $alerts_destination_routing_state_copy = 'Linked rules exist, but they are currently off.';
                                        } elseif ( '' === $alerts_destination_last_activity_event_id ) {
                                            $alerts_destination_routing_state_label = 'Pending live delivery';
                                            $alerts_destination_routing_state_tone = 'info';
                                            $alerts_destination_routing_state_copy = 'Linked and active, waiting for the first recorded delivery.';
                                        } elseif ( in_array( $alerts_destination_last_activity_status, array( 'delivered', 'completed' ), true ) ) {
                                            $alerts_destination_routing_state_label = 'Linked';
                                            $alerts_destination_routing_state_tone = 'good';
                                            $alerts_destination_routing_state_copy = 'Linked rules are active and this destination has recorded delivery.';
                                        } else {
                                            $alerts_destination_routing_state_label = 'Pending live delivery';
                                            $alerts_destination_routing_state_tone = 'info';
                                            $alerts_destination_routing_state_copy = 'Routing is configured, but delivery still needs a clean recorded result.';
                                        }
                                        $alerts_destination_toggle_action = 'active' === $alerts_destination_state ? 'opsgate_notification_destination_disable' : 'opsgate_notification_destination_enable';
                                        $alerts_destination_toggle_nonce = 'active' === $alerts_destination_state ? 'opsgate_notification_destination_disable' : 'opsgate_notification_destination_enable';
                                        $alerts_destination_toggle_label = 'active' === $alerts_destination_state ? 'Disable' : 'Enable';
                                        $alerts_destination_value_for_edit = self::notification_destination_value_from_item( $alerts_destination_item );
                                        $alerts_destination_family_fields = self::notification_destination_family_fields( $alerts_destination_family );
                                        $alerts_destination_config_summary_lines = self::notification_destination_config_summary_lines( $alerts_destination_item );
                                        $alerts_destination_manage_routing_url = self::admin_tab_url(
                                            'alerts',
                                            array(
                                                'opsgate_alert_rule_destination' => $alerts_destination_id,
                                            )
                                        ) . '#opsgate-alerts-create-rule';
                                        ?>
                                        <article class="opsgate-alerts-destination-card">
                                            <div class="opsgate-alerts-destination-top">
                                                <div class="opsgate-alerts-destination-heading">
                                                    <div class="opsgate-alerts-history-meta">
                                                        <span class="opsgate-alerts-pill"><?php echo esc_html( self::notification_channel_label( $alerts_destination_family ) ); ?></span>
                                                    </div>
                                                    <h4 class="opsgate-alerts-history-title"><?php echo esc_html( $alerts_destination_label ); ?></h4>
                                                    <?php if ( '' !== $alerts_destination_id ) : ?>
                                                        <p class="opsgate-alerts-detail-meta"><?php echo esc_html( 'Ref ' . $alerts_destination_id ); ?></p>
                                                    <?php endif; ?>
                                                </div>
                                                <div class="opsgate-alerts-destination-statuses">
                                                    <span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( $alerts_destination_state_tone ); ?>"><?php echo esc_html( $alerts_destination_state_label ); ?></span>
                                                    <span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( $alerts_destination_is_default ? 'good' : 'info' ); ?>"><?php echo esc_html( $alerts_destination_is_default ? 'Default' : 'Not default' ); ?></span>
                                                    <span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( $alerts_destination_routing_state_tone ); ?>"><?php echo esc_html( $alerts_destination_routing_state_label ); ?></span>
                                                </div>
                                            </div>
                                            <div class="opsgate-alerts-destination-grid">
                                                <div class="opsgate-alerts-rule-detail">
                                                    <span class="opsgate-alerts-detail-label">Destination</span>
                                                    <div class="opsgate-alerts-detail-value"><?php echo esc_html( $alerts_destination_target ); ?></div>
                                                    <?php foreach ( $alerts_destination_config_summary_lines as $alerts_destination_config_summary_line ) : ?>
                                                        <p class="opsgate-alerts-detail-meta"><?php echo esc_html( (string) $alerts_destination_config_summary_line ); ?></p>
                                                    <?php endforeach; ?>
                                                </div>
                                                <div class="opsgate-alerts-rule-detail">
                                                    <span class="opsgate-alerts-detail-label">Linked rules</span>
                                                    <?php if ( ! empty( $alerts_destination_rule_names ) ) : ?>
                                                        <div class="opsgate-alerts-detail-value"><?php echo esc_html( $alerts_destination_rule_preview_copy ); ?></div>
                                                        <p class="opsgate-alerts-detail-meta"><?php echo esc_html( sprintf( '%d linked rule%s • %d enabled', count( $alerts_destination_rule_names ), 1 === count( $alerts_destination_rule_names ) ? '' : 's', $alerts_destination_linked_enabled_count ) ); ?></p>
                                                    <?php else : ?>
                                                        <div class="opsgate-alerts-detail-value">No linked rules</div>
                                                    <?php endif; ?>
                                                    <p class="opsgate-alerts-detail-meta"><?php echo esc_html( 'Available rules to link: ' . $alerts_destination_available_rule_copy ); ?></p>
                                                    <p class="opsgate-alerts-detail-meta"><?php echo esc_html( $alerts_destination_routing_state_copy ); ?></p>
                                                </div>
                                                <div class="opsgate-alerts-rule-detail">
                                                    <span class="opsgate-alerts-detail-label">Recent delivery</span>
                                                    <?php if ( '' !== $alerts_destination_last_activity_event_type ) : ?>
                                                        <div class="opsgate-alerts-detail-value"><?php echo esc_html( self::canonical_notification_event_label( $alerts_destination_last_activity_event_type ) ); ?></div>
                                                    <?php else : ?>
                                                        <div class="opsgate-alerts-detail-value"><?php echo esc_html( $alerts_destination_last_activity_label ); ?></div>
                                                    <?php endif; ?>
                                                    <?php if ( '' !== $alerts_destination_last_activity_reference ) : ?>
                                                        <p class="opsgate-alerts-detail-meta"><?php echo esc_html( $alerts_destination_last_activity_reference ); ?></p>
                                                    <?php endif; ?>
                                                    <?php if ( ! empty( $alerts_destination_last_activity_event['triggered_at_utc'] ) ) : ?>
                                                        <p class="opsgate-alerts-detail-meta"><?php echo esc_html( self::notification_datetime_label( (string) $alerts_destination_last_activity_event['triggered_at_utc'] ) ); ?></p>
                                                    <?php endif; ?>
                                                </div>
                                            </div>
                                            <?php if ( '—' !== $alerts_destination_last_activity_issue && '' !== $alerts_destination_last_activity_issue ) : ?>
                                                <p class="opsgate-alerts-history-issue"><?php echo esc_html( $alerts_destination_last_activity_issue ); ?></p>
                                            <?php elseif ( '' !== $alerts_destination_delivery_reason ) : ?>
                                                <p class="opsgate-alerts-detail-meta"><?php echo esc_html( $alerts_destination_delivery_reason ); ?></p>
                                            <?php endif; ?>
                                            <?php
                                            $alerts_destination_setup_steps = self::notification_destination_family_setup_steps( $alerts_destination_family );
                                            if ( ! empty( $alerts_destination_setup_steps ) ) :
                                                $alerts_destination_setup_heading = (string) ( $alerts_destination_setup_steps['heading'] ?? '' );
                                                $alerts_destination_setup_list    = isset( $alerts_destination_setup_steps['steps'] ) && is_array( $alerts_destination_setup_steps['steps'] ) ? $alerts_destination_setup_steps['steps'] : array();
                                            ?>
                                            <details class="opsgate-alerts-setup-steps">
                                                <summary><?php echo esc_html( '' !== $alerts_destination_setup_heading ? $alerts_destination_setup_heading : 'Provider setup steps' ); ?></summary>
                                                <ol class="opsgate-alerts-setup-list">
                                                    <?php foreach ( $alerts_destination_setup_list as $alerts_destination_setup_step ) : ?>
                                                        <li><?php echo esc_html( (string) $alerts_destination_setup_step ); ?></li>
                                                    <?php endforeach; ?>
                                                </ol>
                                            </details>
                                            <?php endif; ?>
                                            <div class="opsgate-alerts-destination-actions">
                                                <?php if ( '' !== $alerts_destination_id ) : ?>
                                                    <div class="opsgate-alerts-destination-action-buttons">
                                                        <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
                                                            <input type="hidden" name="action" value="<?php echo esc_attr( $alerts_destination_toggle_action ); ?>" />
                                                            <?php wp_nonce_field( $alerts_destination_toggle_nonce ); ?>
                                                            <input type="hidden" name="destination_id" value="<?php echo esc_attr( $alerts_destination_id ); ?>" />
                                                            <button type="submit" class="button button-small"><?php echo esc_html( $alerts_destination_toggle_label ); ?></button>
                                                        </form>
                                                        <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
                                                            <input type="hidden" name="action" value="opsgate_notification_destination_test" />
                                                            <?php wp_nonce_field( 'opsgate_notification_destination_test' ); ?>
                                                            <input type="hidden" name="destination_id" value="<?php echo esc_attr( $alerts_destination_id ); ?>" />
                                                            <button type="submit" class="button button-small button-secondary">Test delivery</button>
                                                        </form>
                                                    </div>
                                                    <div class="opsgate-alerts-destination-secondary-actions">
                                                        <a class="button button-small button-secondary" href="<?php echo esc_url( $alerts_destination_manage_routing_url ); ?>">Manage routing</a>
                                                        <details class="opsgate-alerts-inline-details">
                                                            <summary>Edit destination</summary>
                                                            <div class="opsgate-alerts-create-panel">
                                                                <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" data-opsgate-destination-form="edit">
                                                                    <input type="hidden" name="action" value="opsgate_notification_destination_update" />
                                                                    <?php wp_nonce_field( 'opsgate_notification_destination_update' ); ?>
                                                                    <input type="hidden" name="destination_id" value="<?php echo esc_attr( $alerts_destination_id ); ?>" />
                                                                    <input type="hidden" name="destination_family" value="<?php echo esc_attr( $alerts_destination_family ); ?>" />
                                                                    <div class="opsgate-alerts-form-grid">
                                                                        <label class="opsgate-alerts-form-field">
                                                                            <span>Label</span>
                                                                            <input name="destination_label" type="text" class="regular-text" value="<?php echo esc_attr( $alerts_destination_label ); ?>" />
                                                                        </label>
                                                                        <div class="opsgate-alerts-form-field opsgate-alerts-form-field-wide">
                                                                            <div class="opsgate-alerts-form-grid">
                                                                                <?php foreach ( $alerts_destination_family_fields as $alerts_destination_form_field ) : ?>
                                                                                    <?php
                                                                                    if ( ! is_array( $alerts_destination_form_field ) || empty( $alerts_destination_form_field['key'] ) ) {
                                                                                        continue;
                                                                                    }
                                                                                    $alerts_destination_form_field_key = (string) $alerts_destination_form_field['key'];
                                                                                    $alerts_destination_form_field_type = (string) ( $alerts_destination_form_field['type'] ?? 'text' );
                                                                                    $alerts_destination_form_field_value = self::notification_destination_item_config_value( $alerts_destination_item, $alerts_destination_form_field_key );
                                                                                    $alerts_destination_form_field_help = (string) ( $alerts_destination_form_field['help'] ?? '' );
                                                                                    $alerts_destination_form_field_placeholder = (string) ( $alerts_destination_form_field['placeholder'] ?? '' );
                                                                                    if ( ! empty( $alerts_destination_form_field['secret'] ) ) {
                                                                                        $alerts_destination_form_field_placeholder = 'Leave blank to keep the saved secret.';
                                                                                    }
                                                                                    ?>
                                                                                    <label class="opsgate-alerts-form-field">
                                                                                        <span><?php echo esc_html( (string) ( $alerts_destination_form_field['label'] ?? 'Destination value' ) ); ?></span>
                                                                                        <input
                                                                                            name="destination_config[<?php echo esc_attr( $alerts_destination_form_field_key ); ?>]"
                                                                                            type="<?php echo esc_attr( in_array( $alerts_destination_form_field_type, array( 'email', 'url', 'password' ), true ) ? $alerts_destination_form_field_type : 'text' ); ?>"
                                                                                            class="regular-text"
                                                                                            value="<?php echo esc_attr( ! empty( $alerts_destination_form_field['secret'] ) ? '' : $alerts_destination_form_field_value ); ?>"
                                                                                            placeholder="<?php echo esc_attr( $alerts_destination_form_field_placeholder ); ?>"
                                                                                            data-opsgate-destination-family="<?php echo esc_attr( $alerts_destination_family ); ?>"
                                                                                            data-opsgate-destination-field-key="<?php echo esc_attr( $alerts_destination_form_field_key ); ?>"
                                                                                            data-opsgate-destination-field-type="<?php echo esc_attr( $alerts_destination_form_field_type ); ?>"
                                                                                            data-opsgate-destination-field-required="<?php echo ! empty( $alerts_destination_form_field['required'] ) ? '1' : '0'; ?>"
                                                                                            data-opsgate-destination-field-secret="<?php echo ! empty( $alerts_destination_form_field['secret'] ) ? '1' : '0'; ?>"
                                                                                        />
                                                                                        <?php if ( '' !== $alerts_destination_form_field_help ) : ?>
                                                                                            <small><?php echo esc_html( $alerts_destination_form_field_help ); ?></small>
                                                                                        <?php endif; ?>
                                                                                    </label>
                                                                                <?php endforeach; ?>
                                                                                <?php if ( empty( $alerts_destination_family_fields ) ) : ?>
                                                                                    <label class="opsgate-alerts-form-field">
                                                                                        <span>Destination value</span>
                                                                                        <input name="destination_value" type="text" class="regular-text" value="<?php echo esc_attr( $alerts_destination_value_for_edit ); ?>" />
                                                                                    </label>
                                                                                <?php endif; ?>
                                                                            </div>
                                                                        </div>
                                                                    </div>
                                                                    <div class="opsgate-alerts-create-footer">
                                                                        <label class="opsgate-alerts-checkbox">
                                                                            <input type="checkbox" name="destination_is_default" value="1" <?php checked( $alerts_destination_is_default ); ?> />
                                                                            Default destination
                                                                        </label>
                                                                        <button type="submit" class="button button-small">Update</button>
                                                                    </div>
                                                                </form>
                                                            </div>
                                                        </details>
                                                        <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" onsubmit="return window.confirm('Remove this destination from Alerts?');">
                                                            <input type="hidden" name="action" value="opsgate_notification_destination_delete" />
                                                            <?php wp_nonce_field( 'opsgate_notification_destination_delete' ); ?>
                                                            <input type="hidden" name="destination_id" value="<?php echo esc_attr( $alerts_destination_id ); ?>" />
                                                            <button type="submit" class="button button-small opsgate-alerts-button-quiet-danger">Remove</button>
                                                        </form>
                                                    </div>
                                                <?php else : ?>
                                                    <span class="opsgate-alerts-detail-meta">Unavailable</span>
                                                <?php endif; ?>
                                            </div>
                                        </article>
                                    <?php endforeach; ?>
                                </div>
                            <?php endif; ?>
                        </section>

                        </div><!-- /#opsgate-alerts-sub-destinations -->

                        <div class="opsgate-sub-panel" id="opsgate-alerts-sub-rules" role="tabpanel">

                            <section id="opsgate-alerts-rules" class="opsgate-alerts-surface opsgate-alerts-surface-main">
                                <div class="opsgate-alerts-surface-header">
                                    <div class="opsgate-alerts-surface-copy">
                                        <h3 class="opsgate-alerts-surface-title">Alert Rules</h3>
                                        <p class="opsgate-alerts-history-copy">Live routing coverage and active rule state for this site.</p>
                                    </div>
                                    <span class="opsgate-alerts-surface-link">Live routing</span>
                                </div>
                                    <div
                                        id="opsgate-alerts-rules-status"
                                        class="opsgate-alert-inline-status<?php echo in_array( $alerts_notice, array( 'rule_created', 'rule_updated', 'rule_error' ), true ) ? ' is-visible ' . ( 'rule_error' === $alerts_notice ? 'is-error' : 'is-success' ) : ''; ?>"
                                        data-opsgate-transient-status="1"
                                        role="status"
                                        aria-live="polite"
                                    >
                                    <p>
                                        <?php
                                        if ( 'rule_created' === $alerts_notice ) {
                                            echo esc_html( 'Alert rule created.' );
                                        } elseif ( 'rule_updated' === $alerts_notice ) {
                                            echo esc_html( 'Alert rule updated.' );
                                        } elseif ( 'rule_error' === $alerts_notice ) {
                                            echo esc_html( '' !== $alerts_error ? $alerts_error : 'Could not update the alert setting.' );
                                        }
                                        ?>
                                    </p>
                                </div>

                                <details id="opsgate-alerts-create-rule" class="opsgate-alerts-create-details"<?php echo $alerts_create_rule_open ? ' open="open"' : ''; ?>>
                                    <summary>Create rule</summary>
                                    <div class="opsgate-alerts-create-panel">
                                        <?php if ( '' !== $alerts_rule_destination_focus_label ) : ?>
                                            <p class="opsgate-alerts-detail-meta">Routing new rules to <?php echo esc_html( $alerts_rule_destination_focus_label ); ?>.</p>
                                        <?php endif; ?>
                                        <p class="opsgate-alerts-detail-meta"><?php echo esc_html( $alerts_rule_form_hint ); ?></p>
                                        <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" data-opsgate-rule-form="create">
                                            <input type="hidden" name="action" value="opsgate_notification_rule_create" />
                                            <?php wp_nonce_field( 'opsgate_notification_rule_create' ); ?>
                                            <div class="opsgate-alerts-form-grid">
                                                <label class="opsgate-alerts-form-field" for="opsgate-rule-event-type">
                                                    <span>Alert type</span>
                                                    <select id="opsgate-rule-event-type" name="rule_event_type" class="regular-text">
                                                        <?php foreach ( $alerts_rule_event_options as $alerts_rule_event_key => $alerts_rule_event_label ) : ?>
                                                            <option value="<?php echo esc_attr( $alerts_rule_event_key ); ?>"><?php echo esc_html( $alerts_rule_event_label ); ?></option>
                                                        <?php endforeach; ?>
                                                    </select>
                                                </label>
                                                <label class="opsgate-alerts-form-field" for="opsgate-rule-destination-id">
                                                    <span>Destination</span>
                                                    <select id="opsgate-rule-destination-id" name="rule_destination_id" class="regular-text">
                                                        <?php foreach ( $alerts_destinations_items as $alerts_rule_destination_option ) : ?>
                                                            <?php if ( ! is_array( $alerts_rule_destination_option ) ) { continue; } ?>
                                                            <?php
                                                            $alerts_rule_destination_option_id = isset( $alerts_rule_destination_option['destination_id'] ) ? trim( (string) $alerts_rule_destination_option['destination_id'] ) : '';
                                                            if ( '' === $alerts_rule_destination_option_id ) { continue; }
                                                            $alerts_rule_destination_option_family = isset( $alerts_rule_destination_option['family'] ) ? strtolower( trim( (string) $alerts_rule_destination_option['family'] ) ) : '';
                                                            $alerts_rule_destination_option_label = isset( $alerts_rule_destination_option['label'] ) ? trim( (string) $alerts_rule_destination_option['label'] ) : 'Destination';
                                                            $alerts_rule_destination_option_target = self::notification_target_display( isset( $alerts_rule_destination_option['resolved_target'] ) ? (string) $alerts_rule_destination_option['resolved_target'] : '', $alerts_rule_destination_option_family );
                                                            ?>
                                                            <option value="<?php echo esc_attr( $alerts_rule_destination_option_id ); ?>" <?php selected( $alerts_rule_destination_focus_id, $alerts_rule_destination_option_id ); ?>><?php echo esc_html( self::notification_channel_label( $alerts_rule_destination_option_family ) . ' — ' . $alerts_rule_destination_option_label . ' — ' . $alerts_rule_destination_option_target ); ?></option>
                                                        <?php endforeach; ?>
                                                    </select>
                                                </label>
                                                <label class="opsgate-alerts-form-field opsgate-alerts-form-field-wide" for="opsgate-rule-name">
                                                    <span>Rule label</span>
                                                    <input id="opsgate-rule-name" name="rule_name" type="text" class="regular-text" placeholder="Healthy email alert, critical webhook alert" />
                                                </label>
                                            </div>
                                            <div class="opsgate-alerts-create-footer">
                                                <label class="opsgate-alerts-checkbox">
                                                    <input type="checkbox" name="rule_is_enabled" value="1" checked="checked" />
                                                    Enable immediately if the current package allows it
                                                </label>
                                                <button type="submit" class="button button-secondary" <?php disabled( empty( $alerts_destinations_items ) ); ?>><?php echo esc_html( $alerts_rule_submit_label ); ?></button>
                                            </div>
                                        </form>
                                    </div>
                                </details>

                                <?php if ( ! $alerts_rules_ok ) : ?>
                                    <div class="opsgate-alert-panel opsgate-alert-panel-error">
                                        <p><?php echo esc_html( '' !== $alerts_rules_error ? $alerts_rules_error : 'Could not load alerts.' ); ?></p>
                                    </div>
                                <?php elseif ( empty( $alerts_live_rules_items ) ) : ?>
                                    <div class="opsgate-alert-panel">
                                        <p>No live customer-facing alerts are configured for this site yet.</p>
                                    </div>
                                <?php else : ?>
                                    <div class="opsgate-alerts-rules-table-wrap">
                                        <table class="opsgate-alerts-rules-table">
                                            <thead>
                                                <tr>
                                                    <th>Rule</th>
                                                    <th>Event</th>
                                                    <th>Channel</th>
                                                    <th>Destination</th>
                                                    <th>Package</th>
                                                    <th>Configuration state</th>
                                                    <th>Delivery state</th>
                                                    <th>Control</th>
                                                </tr>
                                            </thead>
                                            <tbody>
                                                <?php $alerts_rules_current_group = ''; ?>
                                                <?php foreach ( $alerts_live_rules_items as $rule ) : ?>
                                                    <?php
                                                    if ( ! is_array( $rule ) ) {
                                                        continue;
                                                    }
                                                    $alerts_rule_category = self::notification_rule_category_key( $rule );
                                                    $rule_id       = isset( $rule['rule_id'] ) ? trim( (string) $rule['rule_id'] ) : '';
                                                    $name          = self::notification_rule_display_name( $rule );
                                                    $description   = self::notification_rule_display_description( $rule );
                                                    $event_type    = isset( $rule['event_type'] ) ? (string) $rule['event_type'] : '';
                                                    $channel       = isset( $rule['channel'] ) ? (string) $rule['channel'] : '';
                                                    $target        = isset( $rule['target'] ) ? trim( (string) $rule['target'] ) : '';
                                                    $schedule_mode = isset( $rule['schedule_mode'] ) ? (string) $rule['schedule_mode'] : '';
                                                    $is_enabled    = ! empty( $rule['is_enabled'] );
                                                    $toggle_action = $is_enabled ? 'opsgate_notification_rule_disable' : 'opsgate_notification_rule_enable';
                                                    $toggle_nonce  = $is_enabled ? 'opsgate_notification_rule_disable' : 'opsgate_notification_rule_enable';
                                                    $toggle_target = $is_enabled ? '0' : '1';
                                                    $target_copy   = self::notification_target_display( $target, $channel );
                                                    $channel_label = self::notification_channel_label( $channel );
                                                    $channel_is_live = self::notification_rule_channel_is_live( $rule, $alerts_destinations_items, $alerts_live_channel_labels );
                                                    $channel_is_editable = $channel_is_live;
                                                    $package_state_label = $channel_is_live ? 'Available on current package' : 'Locked on current package';
                                                    $configuration_state_label = $channel_is_live ? ( $is_enabled ? 'Configured' : 'Available' ) : 'Locked';
                                                    $configuration_state_tone = $channel_is_live ? ( $is_enabled ? 'good' : 'info' ) : 'warn';
                                                    $alerts_rule_config_enabled_label = $channel_is_live ? 'Configured' : 'Locked';
                                                    $alerts_rule_config_enabled_tone = $channel_is_live ? 'good' : 'warn';
                                                    $alerts_rule_config_disabled_label = $channel_is_live ? 'Available' : 'Locked';
                                                    $alerts_rule_config_disabled_tone = $channel_is_live ? 'info' : 'warn';
                                                    $alerts_rule_matching_destinations = array();
                                                    foreach ( $alerts_destinations_items as $alerts_rule_destination_item ) {
                                                        if ( ! is_array( $alerts_rule_destination_item ) || ! self::notification_rule_targets_destination( $rule, $alerts_rule_destination_item ) ) {
                                                            continue;
                                                        }
                                                        $alerts_rule_matching_destinations[] = $alerts_rule_destination_item;
                                                    }
                                                    $alerts_rule_active_destinations = array_values(
                                                        array_filter(
                                                            $alerts_rule_matching_destinations,
                                                            static function ( $alerts_rule_destination_item ) {
                                                                return is_array( $alerts_rule_destination_item ) && 'active' === strtolower( trim( (string) ( $alerts_rule_destination_item['state'] ?? '' ) ) );
                                                            }
                                                        )
                                                    );
                                                    $alerts_rule_routing_label = 'Off';
                                                    $alerts_rule_routing_copy = 'Toggle on to route this alert.';
                                                    $alerts_rule_routing_tone = 'info';
                                                    if ( $is_enabled && ! empty( $alerts_rule_active_destinations ) ) {
                                                        $alerts_rule_routing_label = 'On and routed';
                                                        $alerts_rule_routing_tone = 'good';
                                                        $alerts_rule_routing_targets = array();
                                                        foreach ( $alerts_rule_active_destinations as $alerts_rule_active_destination_item ) {
                                                            $alerts_rule_routing_targets[] = isset( $alerts_rule_active_destination_item['label'] ) && '' !== trim( (string) $alerts_rule_active_destination_item['label'] )
                                                                ? trim( (string) $alerts_rule_active_destination_item['label'] )
                                                                : self::notification_target_display( (string) ( $alerts_rule_active_destination_item['resolved_target'] ?? '' ), (string) ( $alerts_rule_active_destination_item['family'] ?? '' ) );
                                                        }
                                                        $alerts_rule_routing_targets = array_values( array_unique( array_filter( $alerts_rule_routing_targets ) ) );
                                                        $alerts_rule_routing_copy = ! empty( $alerts_rule_routing_targets )
                                                            ? 'Routed to ' . implode( ' • ', array_slice( $alerts_rule_routing_targets, 0, 2 ) ) . ( count( $alerts_rule_routing_targets ) > 2 ? ' • +' . ( count( $alerts_rule_routing_targets ) - 2 ) . ' more' : '' )
                                                            : 'Routed to an active destination.';
                                                    } elseif ( $is_enabled ) {
                                                        $alerts_rule_routing_label = 'On but not routed';
                                                        $alerts_rule_routing_tone = 'warn';
                                                        $alerts_rule_routing_copy = empty( $alerts_rule_matching_destinations )
                                                            ? 'No active destination is linked to this rule yet.'
                                                            : 'A matching destination exists, but it is not active.';
                                                    }
                                                    $delivery_lookup_key = '' !== $rule_id ? $rule_id : '';
                                                    $delivery_signature = strtolower( $event_type . '|' . $channel . '|' . $target );
                                                    $latest_rule_event = array();
                                                    if ( '' !== $delivery_lookup_key && isset( $alerts_rule_delivery_by_rule[ $delivery_lookup_key ] ) && is_array( $alerts_rule_delivery_by_rule[ $delivery_lookup_key ] ) ) {
                                                        $latest_rule_event = $alerts_rule_delivery_by_rule[ $delivery_lookup_key ];
                                                    } elseif ( isset( $alerts_rule_delivery_by_signature[ $delivery_signature ] ) && is_array( $alerts_rule_delivery_by_signature[ $delivery_signature ] ) ) {
                                                        $latest_rule_event = $alerts_rule_delivery_by_signature[ $delivery_signature ];
                                                    }
                                                    $delivery_state_label = 'No delivery recorded yet';
                                                    $delivery_state_tone = 'neutral';
                                                    if ( ! empty( $latest_rule_event ) ) {
                                                        $delivery_state_key = strtolower( trim( (string) ( $latest_rule_event['status'] ?? '' ) ) );
                                                        $delivery_state_label = self::notification_status_label( $delivery_state_key );
                                                        if ( in_array( $delivery_state_key, array( 'delivered', 'completed' ), true ) ) {
                                                            $delivery_state_tone = 'good';
                                                        } elseif ( in_array( $delivery_state_key, array( 'ready', 'queued', 'pending', 'running', 'in_progress' ), true ) ) {
                                                            $delivery_state_tone = 'warn';
                                                        } elseif ( in_array( $delivery_state_key, array( 'failed', 'rejected', 'timeout', 'error' ), true ) ) {
                                                            $delivery_state_tone = 'bad';
                                                        }
                                                    }
                                                    $alerts_rule_delivery_enabled_label = $delivery_state_label;
                                                    $alerts_rule_delivery_enabled_tone = $delivery_state_tone;
                                                    if ( ! $is_enabled ) {
                                                        $delivery_state_label = 'Rule is off';
                                                        $delivery_state_tone = 'info';
                                                    }
                                                    $alerts_rule_delivery_disabled_label = 'Rule is off';
                                                    $alerts_rule_delivery_disabled_tone = 'info';
                                                    ?>
                                                    <?php if ( $alerts_rule_category !== $alerts_rules_current_group ) : ?>
                                                        <?php $alerts_rules_current_group = $alerts_rule_category; ?>
                                                        <tr class="opsgate-alerts-rules-group-row">
                                                            <td colspan="8">
                                                                <span class="opsgate-alerts-rules-group-label"><?php echo esc_html( self::notification_rule_category_label( $alerts_rule_category ) ); ?></span>
                                                            </td>
                                                        </tr>
                                                    <?php endif; ?>
                                                    <tr class="<?php echo $is_enabled ? 'is-enabled' : ''; ?>" data-opsgate-alert-rule-row="1">
                                                        <td>
                                                            <strong><?php echo esc_html( '' !== $name ? $name : 'Untitled alert' ); ?></strong>
                                                            <?php if ( '' !== $description ) : ?>
                                                                <div class="opsgate-alerts-table-copy"><?php echo esc_html( $description ); ?></div>
                                                            <?php endif; ?>
                                                        </td>
                                                        <td><?php echo esc_html( self::canonical_notification_event_label( $event_type ) ); ?><div class="opsgate-alerts-table-copy"><?php echo esc_html( self::notification_schedule_label( $schedule_mode ) ); ?></div></td>
                                                        <td><?php echo esc_html( $channel_label ); ?></td>
                                                        <td><?php echo esc_html( $target_copy ); ?></td>
                                                        <td><span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( $channel_is_live ? 'good' : 'warn' ); ?>"><?php echo esc_html( $package_state_label ); ?></span></td>
                                                        <td><span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( $configuration_state_tone ); ?>" data-opsgate-alert-config-chip="1"><?php echo esc_html( $configuration_state_label ); ?></span></td>
                                                        <td><span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( $delivery_state_tone ); ?>" data-opsgate-alert-delivery-chip="1"><?php echo esc_html( $delivery_state_label ); ?></span></td>
                                                        <td>
                                                            <?php if ( '' !== $rule_id && $channel_is_editable ) : ?>
                                                                <form
                                                                    method="post"
                                                                    action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>"
                                                                    class="opsgate-alert-switch-form"
                                                                    data-rule-id="<?php echo esc_attr( $rule_id ); ?>"
                                                                    data-rendered-enabled="<?php echo esc_attr( $is_enabled ? '1' : '0' ); ?>"
                                                                    data-current-enabled="<?php echo esc_attr( $is_enabled ? '1' : '0' ); ?>"
                                                                    data-next-enabled="<?php echo esc_attr( $toggle_target ); ?>"
                                                                    data-ajax-url="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"
                                                                    data-ajax-nonce="<?php echo esc_attr( $alerts_toggle_nonce ); ?>"
                                                                    data-enable-admin-nonce="<?php echo esc_attr( wp_create_nonce( 'opsgate_notification_rule_enable' ) ); ?>"
                                                                    data-disable-admin-nonce="<?php echo esc_attr( wp_create_nonce( 'opsgate_notification_rule_disable' ) ); ?>"
                                                                    data-routing-enabled-label="<?php echo esc_attr( ! empty( $alerts_rule_active_destinations ) ? 'On and routed' : 'On but not routed' ); ?>"
                                                                    data-routing-enabled-copy="<?php echo esc_attr( ! empty( $alerts_rule_active_destinations ) ? $alerts_rule_routing_copy : ( ! empty( $alerts_rule_matching_destinations ) ? 'A matching destination exists, but it is not active.' : 'No active destination is linked to this rule yet.' ) ); ?>"
                                                                    data-routing-enabled-tone="<?php echo esc_attr( ! empty( $alerts_rule_active_destinations ) ? 'good' : 'warn' ); ?>"
                                                                    data-config-enabled-label="<?php echo esc_attr( $alerts_rule_config_enabled_label ); ?>"
                                                                    data-config-enabled-tone="<?php echo esc_attr( $alerts_rule_config_enabled_tone ); ?>"
                                                                    data-config-disabled-label="<?php echo esc_attr( $alerts_rule_config_disabled_label ); ?>"
                                                                    data-config-disabled-tone="<?php echo esc_attr( $alerts_rule_config_disabled_tone ); ?>"
                                                                    data-delivery-enabled-label="<?php echo esc_attr( $alerts_rule_delivery_enabled_label ); ?>"
                                                                    data-delivery-enabled-tone="<?php echo esc_attr( $alerts_rule_delivery_enabled_tone ); ?>"
                                                                    data-delivery-disabled-label="<?php echo esc_attr( $alerts_rule_delivery_disabled_label ); ?>"
                                                                    data-delivery-disabled-tone="<?php echo esc_attr( $alerts_rule_delivery_disabled_tone ); ?>"
                                                                >
                                                                    <?php wp_nonce_field( $toggle_nonce ); ?>
                                                                    <input type="hidden" name="action" value="<?php echo esc_attr( $toggle_action ); ?>" />
                                                                    <input type="hidden" name="rule_id" value="<?php echo esc_attr( $rule_id ); ?>" />
                                                                    <button type="button" class="opsgate-alert-switch" data-opsgate-alert-toggle-button="1" aria-label="<?php echo esc_attr( $is_enabled ? 'Disable alert' : 'Enable alert' ); ?>">
                                                                        <span class="opsgate-alert-switch-track">
                                                                            <span class="opsgate-alert-switch-slider" aria-hidden="true"></span>
                                                                        </span>
                                                                        <span class="opsgate-alert-switch-label" data-opsgate-alert-toggle-label="1"><?php echo esc_html( $is_enabled ? 'ON' : 'OFF' ); ?></span>
                                                                    </button>
                                                                </form>
                                                                <div class="opsgate-alerts-rule-routing-copy">
                                                                    <span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( $alerts_rule_routing_tone ); ?>" data-opsgate-alert-routing-chip="1"><?php echo esc_html( $alerts_rule_routing_label ); ?></span>
                                                                    <span class="opsgate-alerts-table-copy" data-opsgate-alert-routing-copy="1"><?php echo esc_html( $alerts_rule_routing_copy ); ?></span>
                                                                </div>
                                                                <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="opsgate-alerts-rule-remove-form">
                                                                    <input type="hidden" name="action" value="opsgate_notification_rule_delete" />
                                                                    <input type="hidden" name="rule_id" value="<?php echo esc_attr( $rule_id ); ?>" />
                                                                    <?php wp_nonce_field( 'opsgate_notification_rule_delete' ); ?>
                                                                    <button type="submit" class="button button-link-delete button-small opsgate-alerts-rule-remove-button">Remove rule</button>
                                                                </form>
                                                            <?php else : ?>
                                                                <span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-warn">Locked</span>
                                                            <?php endif; ?>
                                                        </td>
                                                    </tr>
                                                <?php endforeach; ?>
                                            </tbody>
                                        </table>
                                    </div>
                                <?php endif; ?>
                            </section>

                        </div><!-- /#opsgate-alerts-sub-rules -->

                        <div class="opsgate-sub-panel" id="opsgate-alerts-sub-history" role="tabpanel">

                            <aside id="opsgate-alerts-history" class="opsgate-alerts-surface opsgate-alerts-surface-rail">
                                <div class="opsgate-alerts-surface-header">
                                    <div class="opsgate-alerts-surface-copy">
                                        <h3 class="opsgate-alerts-surface-title">Recent Alert History</h3>
                                        <p class="opsgate-alerts-history-copy"><?php echo esc_html( $alerts_history_intro_copy ); ?></p>
                                    </div>
                                    <span class="opsgate-alerts-surface-link">Recent delivery history</span>
                                </div>

                                <?php if ( ! $alerts_events_ok ) : ?>
                                    <div class="opsgate-alert-panel opsgate-alert-panel-error">
                                        <p><?php echo esc_html( '' !== $alerts_events_error ? $alerts_events_error : 'Could not load alert history.' ); ?></p>
                                    </div>
                                <?php elseif ( empty( $alerts_recent_customer_events_items ) ) : ?>
                                    <div class="opsgate-alert-panel">
                                        <p><?php echo esc_html( ! empty( $alerts_live_rules_items ) ? ( ! empty( $alerts_vulnerability_rules_items ) ? 'Alert rules are configured for this site, but no customer-facing delivery has been recorded yet. Healthy runs with zero vulnerable installed plugins will not emit vulnerability alerts.' : 'Alert rules are configured for this site, but no live customer delivery activity has been recorded yet.' ) : 'No live alert activity has been recorded for this site yet.' ); ?></p>
                                    </div>
                                <?php else : ?>
                                    <div class="opsgate-alerts-history-list opsgate-alerts-history-list-compact">
                                        <?php foreach ( $alerts_recent_customer_events_items as $event ) : ?>
                                            <?php
                                            if ( ! is_array( $event ) ) {
                                                continue;
                                            }
                                            $event_type       = isset( $event['event_type'] ) ? (string) $event['event_type'] : '';
                                            $channel          = isset( $event['channel'] ) ? (string) $event['channel'] : '';
                                            $target           = isset( $event['target'] ) ? trim( (string) $event['target'] ) : '';
                                            $status           = isset( $event['status'] ) ? (string) $event['status'] : '';
                                            $title            = self::notification_event_display_title( $event );
                                            $summary          = self::notification_event_display_summary( $event );
                                            $triggered_at_utc = isset( $event['triggered_at_utc'] ) ? (string) $event['triggered_at_utc'] : '';
                                            $last_attempt     = isset( $event['last_attempt_at_utc'] ) ? (string) $event['last_attempt_at_utc'] : '';
                                            $finalized        = isset( $event['finalized_at_utc'] ) ? (string) $event['finalized_at_utc'] : '';
                                            $issue_copy       = self::canonical_notification_issue_copy( (string) ( $event['error_code'] ?? '' ), (string) ( $event['error_message'] ?? '' ) );
                                            $status_label     = self::notification_status_label( $status );
                                            $event_source_type = isset( $event['source_type'] ) ? trim( (string) $event['source_type'] ) : '';
                                            $event_source_id   = isset( $event['source_id'] ) ? trim( (string) $event['source_id'] ) : '';
                                            $event_attempt_count = isset( $event['attempt_count'] ) ? (int) $event['attempt_count'] : 0;
                                            $event_reference_copy = isset( $event['event_id'] ) ? self::canonical_activity_reference_copy( 'Event reference', (string) $event['event_id'] ) : '';
                                            $event_source_reference = in_array( $event_source_type, array( 'run', 'triage', 'job' ), true ) && '' !== $event_source_id
                                                ? self::canonical_activity_reference_copy( 'Run reference', $event_source_id )
                                                : '';
                                            $status_tone      = 'neutral';
                                            $status_key       = strtolower( trim( $status ) );
                                            if ( in_array( $status_key, array( 'delivered', 'completed' ), true ) ) {
                                                $status_tone = 'good';
                                            } elseif ( in_array( $status_key, array( 'ready', 'queued', 'pending', 'running', 'in_progress' ), true ) ) {
                                                $status_tone = 'warn';
                                            } elseif ( in_array( $status_key, array( 'failed', 'rejected', 'timeout', 'error' ), true ) ) {
                                                $status_tone = 'bad';
                                            }
                                            $target_copy = self::notification_target_compact_display( $target, $channel );
                                            $alerts_history_timing = array();
                                            if ( $event_attempt_count > 0 ) {
                                                $alerts_history_timing[] = sprintf( '%d attempt%s', $event_attempt_count, 1 === $event_attempt_count ? '' : 's' );
                                            }
                                            if ( '' !== $last_attempt ) {
                                                $alerts_history_timing[] = 'Last attempt ' . self::notification_datetime_label( $last_attempt );
                                            }
                                            if ( '' !== $finalized ) {
                                                $alerts_history_timing[] = 'Finalized ' . self::notification_datetime_label( $finalized );
                                            }
                                            $triggered_parts = self::notification_datetime_parts( $triggered_at_utc );
                                            $event_is_vulnerability = in_array( $event_type, $alerts_vulnerability_event_types, true );
                                            $event_is_delivery_check = 'alert.test' === $event_type;
                                            ?>
                                            <article class="opsgate-alerts-history-card">
                                                <div class="opsgate-alerts-history-top">
                                                    <div class="opsgate-alerts-history-heading">
                                                        <h4 class="opsgate-alerts-history-title"><?php echo esc_html( '' !== $title ? $title : self::canonical_notification_event_label( $event_type ) ); ?></h4>
                                                        <p class="opsgate-alerts-history-copy"><?php echo esc_html( '' !== $summary ? $summary : 'No summary recorded.' ); ?></p>
                                                    </div>
                                                    <span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( $status_tone ); ?>"><?php echo esc_html( $status_label ); ?></span>
                                                </div>
                                                <div class="opsgate-alerts-history-meta">
                                                    <?php if ( $event_is_vulnerability ) : ?>
                                                        <span class="opsgate-alerts-pill opsgate-alerts-pill-event-vulnerability">Vulnerability finding</span>
                                                    <?php elseif ( $event_is_delivery_check ) : ?>
                                                        <span class="opsgate-alerts-pill opsgate-alerts-pill-event-delivery">Delivery check</span>
                                                    <?php endif; ?>
                                                    <span class="opsgate-alerts-pill opsgate-alerts-pill-channel"><?php echo esc_html( self::notification_channel_label( $channel ) ); ?></span>
                                                    <span class="opsgate-alerts-pill opsgate-alerts-pill-target"><?php echo esc_html( $target_copy ); ?></span>
                                                    <span class="opsgate-alerts-pill opsgate-alerts-pill-time"><?php echo esc_html( $triggered_parts['date'] . ( '' !== $triggered_parts['time'] ? ' • ' . $triggered_parts['time'] : '' ) ); ?></span>
                                                </div>
                                                <div class="opsgate-alerts-history-reference-row">
                                                    <?php if ( '' !== $event_source_reference ) : ?>
                                                        <span class="opsgate-alerts-history-reference"><?php echo esc_html( $event_source_reference ); ?></span>
                                                    <?php endif; ?>
                                                    <?php if ( '' !== $event_reference_copy ) : ?>
                                                        <span class="opsgate-alerts-history-reference"><?php echo esc_html( $event_reference_copy ); ?></span>
                                                    <?php endif; ?>
                                                </div>
                                                <?php if ( ! empty( $alerts_history_timing ) ) : ?>
                                                    <p class="opsgate-alerts-history-timing"><?php echo esc_html( implode( ' • ', $alerts_history_timing ) ); ?></p>
                                                <?php endif; ?>
                                                <?php if ( '—' !== $issue_copy ) : ?>
                                                    <p class="opsgate-alerts-history-issue"><?php echo esc_html( $issue_copy ); ?></p>
                                                <?php endif; ?>
                                            </article>
                                        <?php endforeach; ?>
                                    </div>
                                <?php endif; ?>
                            </aside>
                        </div><!-- /#opsgate-alerts-sub-history -->

                        <?php if ( ! empty( $alerts_support_rules_items ) || ! empty( $alerts_support_events_items ) || ! empty( $alerts_latest_proof_event ) ) : ?>
                            <details class="opsgate-alerts-support-details">
                                <summary>Operator proof & support detail</summary>
                                <div class="opsgate-alerts-support-stack">
                                    <?php if ( ! empty( $alerts_latest_proof_event ) ) : ?>
                                        <div class="opsgate-alerts-summary-grid opsgate-alerts-summary-grid-compact">
                                            <article class="opsgate-alerts-summary-card">
                                                <span class="opsgate-alerts-eyebrow">Latest validation receipt</span>
                                                <div class="opsgate-alerts-summary-value"><?php echo esc_html( self::notification_event_display_title( $alerts_latest_proof_event ) ); ?></div>
                                                <p class="opsgate-alerts-summary-copy"><?php echo esc_html( self::notification_event_display_summary( $alerts_latest_proof_event ) ); ?></p>
                                            </article>
                                            <article class="opsgate-alerts-summary-card">
                                                <span class="opsgate-alerts-eyebrow">Proof destination</span>
                                                <div class="opsgate-alerts-summary-value"><?php echo esc_html( self::notification_target_display( (string) ( $alerts_latest_proof_event['target'] ?? '' ), (string) ( $alerts_latest_proof_event['channel'] ?? '' ) ) ); ?></div>
                                                <p class="opsgate-alerts-summary-copy">Recorded as operator proof so it cannot be mistaken for a live customer destination.</p>
                                            </article>
                                        </div>
                                    <?php endif; ?>

                                    <?php if ( ! empty( $alerts_support_rules_items ) ) : ?>
                                        <section class="opsgate-alerts-surface">
                                            <div class="opsgate-alerts-surface-header">
                                                <div class="opsgate-alerts-surface-copy">
                                                    <h3 class="opsgate-alerts-surface-title">Validation rules</h3>
                                                    <p class="opsgate-alerts-history-copy">Recorded proof and validation rows kept separate from live customer routing.</p>
                                                </div>
                                                <span class="opsgate-alerts-surface-link">Support only</span>
                                            </div>
                                            <div class="opsgate-alerts-rules-table-wrap">
                                                <table class="opsgate-alerts-rules-table opsgate-alerts-rules-table-secondary">
                                                    <thead>
                                                        <tr>
                                                            <th>Rule</th>
                                                            <th>Event</th>
                                                            <th>Destination</th>
                                                            <th>Configuration state</th>
                                                            <th>Delivery state</th>
                                                        </tr>
                                                    </thead>
                                                    <tbody>
                                                        <?php foreach ( $alerts_support_rules_items as $rule ) : ?>
                                                            <?php
                                                            if ( ! is_array( $rule ) ) {
                                                                continue;
                                                            }
                                                            $rule_id       = isset( $rule['rule_id'] ) ? trim( (string) $rule['rule_id'] ) : '';
                                                            $name          = self::notification_rule_display_name( $rule );
                                                            $description   = self::notification_rule_display_description( $rule );
                                                            $event_type    = isset( $rule['event_type'] ) ? (string) $rule['event_type'] : '';
                                                            $channel       = isset( $rule['channel'] ) ? (string) $rule['channel'] : '';
                                                            $target        = isset( $rule['target'] ) ? trim( (string) $rule['target'] ) : '';
                                                            $delivery_lookup_key = '' !== $rule_id ? $rule_id : '';
                                                            $delivery_signature = strtolower( $event_type . '|' . $channel . '|' . $target );
                                                            $latest_rule_event = array();
                                                            if ( '' !== $delivery_lookup_key && isset( $alerts_rule_delivery_by_rule[ $delivery_lookup_key ] ) && is_array( $alerts_rule_delivery_by_rule[ $delivery_lookup_key ] ) ) {
                                                                $latest_rule_event = $alerts_rule_delivery_by_rule[ $delivery_lookup_key ];
                                                            } elseif ( isset( $alerts_rule_delivery_by_signature[ $delivery_signature ] ) && is_array( $alerts_rule_delivery_by_signature[ $delivery_signature ] ) ) {
                                                                $latest_rule_event = $alerts_rule_delivery_by_signature[ $delivery_signature ];
                                                            }
                                                            $delivery_state_label = 'Recorded';
                                                            $delivery_state_tone = 'neutral';
                                                            if ( ! empty( $latest_rule_event ) ) {
                                                                $delivery_state_key = strtolower( trim( (string) ( $latest_rule_event['status'] ?? '' ) ) );
                                                                $delivery_state_label = self::notification_status_label( $delivery_state_key );
                                                                if ( in_array( $delivery_state_key, array( 'delivered', 'completed' ), true ) ) {
                                                                    $delivery_state_tone = 'good';
                                                                } elseif ( in_array( $delivery_state_key, array( 'ready', 'queued', 'pending', 'running', 'in_progress' ), true ) ) {
                                                                    $delivery_state_tone = 'warn';
                                                                } elseif ( in_array( $delivery_state_key, array( 'failed', 'rejected', 'timeout', 'error' ), true ) ) {
                                                                    $delivery_state_tone = 'bad';
                                                                }
                                                            }
                                                            ?>
                                                            <tr>
                                                                <td>
                                                                    <strong><?php echo esc_html( $name ); ?></strong>
                                                                    <?php if ( '' !== $description ) : ?>
                                                                        <div class="opsgate-alerts-table-copy"><?php echo esc_html( $description ); ?></div>
                                                                    <?php endif; ?>
                                                                </td>
                                                                <td><?php echo esc_html( self::canonical_notification_event_label( $event_type ) ); ?></td>
                                                                <td><?php echo esc_html( self::notification_target_display( $target, $channel ) ); ?></td>
                                                                <td><span class="opsgate-alerts-status-chip">Validation receipt</span></td>
                                                                <td><span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( $delivery_state_tone ); ?>"><?php echo esc_html( $delivery_state_label ); ?></span></td>
                                                            </tr>
                                                        <?php endforeach; ?>
                                                    </tbody>
                                                </table>
                                            </div>
                                        </section>
                                    <?php endif; ?>

                                    <?php if ( ! empty( $alerts_support_events_items ) ) : ?>
                                        <section class="opsgate-alerts-surface">
                                            <div class="opsgate-alerts-surface-header">
                                                <div class="opsgate-alerts-surface-copy">
                                                    <h3 class="opsgate-alerts-surface-title">Validation history</h3>
                                                    <p class="opsgate-alerts-history-copy">Recorded proof events and support receipts kept outside the live customer-facing history rail.</p>
                                                </div>
                                                <span class="opsgate-alerts-surface-link">Support receipts</span>
                                            </div>
                                            <div class="opsgate-alerts-history-list opsgate-alerts-history-list-compact">
                                                <?php foreach ( array_slice( $alerts_support_events_items, 0, 3 ) as $event ) : ?>
                                                    <?php
                                                    if ( ! is_array( $event ) ) {
                                                        continue;
                                                    }
                                                    $event_type       = isset( $event['event_type'] ) ? (string) $event['event_type'] : '';
                                                    $channel          = isset( $event['channel'] ) ? (string) $event['channel'] : '';
                                                    $target           = isset( $event['target'] ) ? trim( (string) $event['target'] ) : '';
                                                    $status           = isset( $event['status'] ) ? (string) $event['status'] : '';
                                                    $title            = self::notification_event_display_title( $event );
                                                    $summary          = self::notification_event_display_summary( $event );
                                                    $triggered_at_utc = isset( $event['triggered_at_utc'] ) ? (string) $event['triggered_at_utc'] : '';
                                                    $issue_copy       = self::canonical_notification_issue_copy( (string) ( $event['error_code'] ?? '' ), (string) ( $event['error_message'] ?? '' ) );
                                                    $status_label     = self::notification_status_label( $status );
                                                    $status_tone      = 'neutral';
                                                    $status_key       = strtolower( trim( $status ) );
                                                    if ( in_array( $status_key, array( 'delivered', 'completed' ), true ) ) {
                                                        $status_tone = 'good';
                                                    } elseif ( in_array( $status_key, array( 'ready', 'queued', 'pending', 'running', 'in_progress' ), true ) ) {
                                                        $status_tone = 'warn';
                                                    } elseif ( in_array( $status_key, array( 'failed', 'rejected', 'timeout', 'error' ), true ) ) {
                                                        $status_tone = 'bad';
                                                    }
                                                    ?>
                                                    <article class="opsgate-alerts-history-card">
                                                        <div class="opsgate-alerts-history-top">
                                                            <div class="opsgate-alerts-history-heading">
                                                                <h4 class="opsgate-alerts-history-title"><?php echo esc_html( $title ); ?></h4>
                                                                <p class="opsgate-alerts-history-copy"><?php echo esc_html( $summary ); ?></p>
                                                            </div>
                                                            <span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( $status_tone ); ?>"><?php echo esc_html( $status_label ); ?></span>
                                                        </div>
                                                        <div class="opsgate-alerts-history-meta">
                                                            <span class="opsgate-alerts-pill"><?php echo esc_html( self::notification_channel_label( $channel ) ); ?></span>
                                                            <span class="opsgate-alerts-pill"><?php echo esc_html( self::notification_target_display( $target, $channel ) ); ?></span>
                                                            <?php if ( '' !== $triggered_at_utc ) : ?>
                                                                <span class="opsgate-alerts-pill"><?php echo esc_html( self::notification_datetime_label( $triggered_at_utc ) ); ?></span>
                                                            <?php endif; ?>
                                                        </div>
                                                        <?php if ( '—' !== $issue_copy ) : ?>
                                                            <p class="opsgate-alerts-history-issue"><?php echo esc_html( $issue_copy ); ?></p>
                                                        <?php endif; ?>
                                                    </article>
                                                <?php endforeach; ?>
                                            </div>
                                        </section>
                                    <?php endif; ?>
                                </div>
                            </details>
                        <?php endif; ?>

                        <div class="opsgate-alerts-status-strip opsgate-alerts-legacy-block">
                            <div class="opsgate-alerts-status-item"><span class="opsgate-alerts-status-label">Active rules</span><span class="opsgate-alerts-status-value"><?php echo esc_html( (string) $alerts_active_rules ); ?></span></div>
                            <div class="opsgate-alerts-status-item"><span class="opsgate-alerts-status-label">Alert configuration</span><span class="opsgate-alerts-status-value"><?php echo esc_html( $alerts_channels_copy ); ?></span></div>
                            <div class="opsgate-alerts-status-item"><span class="opsgate-alerts-status-label">Alert delivery</span><span class="opsgate-alerts-status-value"><?php echo esc_html( $alerts_latest_event_label ); ?></span></div>
                            <div class="opsgate-alerts-status-item"><span class="opsgate-alerts-status-label">Latest event</span><span class="opsgate-alerts-status-value"><?php echo esc_html( $alerts_latest_timestamp ); ?></span></div>
                            <div class="opsgate-alerts-status-item"><span class="opsgate-alerts-status-label">Scope</span><span class="opsgate-alerts-status-value"><?php echo esc_html( $alerts_scope_label ); ?></span></div>
                        </div>

                        <div class="opsgate-alerts-channel-family-grid opsgate-alerts-legacy-block">
                            <article class="opsgate-alerts-channel-family-card">
                                <span class="opsgate-alerts-detail-label">Live now</span>
                                <div class="opsgate-alerts-detail-value"><?php echo esc_html( ! empty( $alerts_channel_groups['live_now'] ) ? implode( ', ', wp_list_pluck( $alerts_channel_groups['live_now'], 'label' ) ) : 'None on this package' ); ?></div>
                                <p class="opsgate-alerts-history-copy">Channels this package can configure and deliver from the current plugin surface.</p>
                            </article>
                            <article class="opsgate-alerts-channel-family-card">
                                <span class="opsgate-alerts-detail-label">Upgrade unlocks</span>
                                <div class="opsgate-alerts-detail-value"><?php echo esc_html( ! empty( $alerts_channel_groups['visible_locked'] ) ? implode( ', ', wp_list_pluck( $alerts_channel_groups['visible_locked'], 'label' ) ) : 'No additional live channels locked' ); ?></div>
                                <p class="opsgate-alerts-history-copy">Visible package differences for communication and escalation from this surface.</p>
                            </article>
                            <article class="opsgate-alerts-channel-family-card">
                                <span class="opsgate-alerts-detail-label">Planned direction</span>
                                <div class="opsgate-alerts-detail-value"><?php echo esc_html( ! empty( $alerts_channel_groups['planned_direction'] ) ? implode( ', ', wp_list_pluck( $alerts_channel_groups['planned_direction'], 'label' ) ) : 'No planned families exposed here' ); ?></div>
                                <p class="opsgate-alerts-history-copy">Future communication-family direction remains visible without being presented as live today.</p>
                            </article>
                        </div>

                        <div class="opsgate-settings-module opsgate-alerts-legacy-block" style="margin-bottom:18px;">
                            <div class="opsgate-settings-module-head">
                                <div>
                                    <strong>Alert Destinations</strong>
                                    <p class="description">Canonical destination records for this connected site. WordPress reads and writes these through the OpsGate API only.</p>
                                </div>
                                <a class="button button-secondary" href="<?php echo esc_url( $alerts_refresh_url ); ?>">Refresh destinations</a>
                            </div>
                            <div
                                id="opsgate-alert-destinations-status-legacy"
                                class="opsgate-alert-inline-status<?php echo in_array( $alerts_destinations_notice, array( 'destination_created', 'destination_updated', 'destination_tested', 'destination_error' ), true ) ? ' is-visible ' . ( 'destination_error' === $alerts_destinations_notice ? 'is-error' : 'is-success' ) : ''; ?>"
                                role="status"
                                aria-live="polite"
                            >
                                <p>
                                    <?php
                                    if ( 'destination_created' === $alerts_destinations_notice ) {
                                        echo esc_html( 'Alert destination created.' );
                                    } elseif ( 'destination_updated' === $alerts_destinations_notice ) {
                                        echo esc_html( 'Alert destination updated.' );
                                    } elseif ( 'destination_tested' === $alerts_destinations_notice ) {
                                        echo esc_html( 'Alert destination test queued.' );
                                    } elseif ( 'destination_error' === $alerts_destinations_notice ) {
                                        echo esc_html( '' !== $alerts_destinations_error_notice ? $alerts_destinations_error_notice : 'Could not update the alert destination.' );
                                    }
                                    ?>
                                </p>
                            </div>

                            <div class="opsgate-pricing-summary-grid" style="margin-bottom:16px;">
                                <article class="opsgate-pricing-summary-card">
                                    <span class="opsgate-overview-eyebrow">Webhook allowance</span>
                                    <div class="opsgate-pricing-hero-side-title"><?php echo esc_html( (string) ( $alerts_webhook_allowance['label'] ?? 'No webhook destinations' ) ); ?></div>
                                    <p><?php echo esc_html( (string) ( $alerts_webhook_allowance['summary'] ?? 'Webhook delivery is read from canonical package truth.' ) ); ?></p>
                                </article>
                                <article class="opsgate-pricing-summary-card">
                                    <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
                                        <input type="hidden" name="action" value="opsgate_notification_destination_create" />
                                        <?php wp_nonce_field( 'opsgate_notification_destination_create' ); ?>
                                        <span class="opsgate-overview-eyebrow">Create destination</span>
                                        <div style="margin:10px 0;">
                                            <label for="opsgate-destination-family"><strong>Family</strong></label>
                                            <select id="opsgate-destination-family" name="destination_family" class="regular-text" style="width:100%; margin-top:4px;">
                                                <?php foreach ( array( 'email', 'webhook', 'slack', 'teams', 'whatsapp', 'telegram', 'discord', 'sns' ) as $alerts_destination_family_option ) : ?>
                                                    <option value="<?php echo esc_attr( $alerts_destination_family_option ); ?>"><?php echo esc_html( self::notification_channel_label( $alerts_destination_family_option ) ); ?></option>
                                                <?php endforeach; ?>
                                            </select>
                                        </div>
                                        <div style="margin:10px 0;">
                                            <label for="opsgate-destination-label"><strong>Label</strong></label>
                                            <input id="opsgate-destination-label" name="destination_label" type="text" class="regular-text" style="width:100%; margin-top:4px;" placeholder="Primary email, primary webhook, escalation channel" />
                                        </div>
                                        <div style="margin:10px 0;">
                                            <label for="opsgate-destination-value"><strong>Destination value</strong></label>
                                            <input id="opsgate-destination-value" name="destination_value" type="text" class="regular-text" style="width:100%; margin-top:4px;" placeholder="Recipient, URL, chat id, or topic ARN" />
                                            <p class="description" style="margin-top:4px;">Email uses recipient. Webhook, Slack, Teams, and Discord use URL. Telegram uses chat id. SNS uses topic ARN.</p>
                                        </div>
                                        <p style="margin:10px 0;">
                                            <label>
                                                <input type="checkbox" name="destination_is_default" value="1" />
                                                Set as active default for this family
                                            </label>
                                        </p>
                                        <p style="margin:0;">
                                            <button type="submit" class="button button-secondary">Create destination</button>
                                        </p>
                                    </form>
                                </article>
                            </div>

                            <?php if ( ! $alerts_destinations_ok ) : ?>
                                <div class="opsgate-alert-panel opsgate-alert-panel-error">
                                    <p><?php echo esc_html( '' !== $alerts_destinations_error ? $alerts_destinations_error : 'Could not load alert destinations.' ); ?></p>
                                </div>
                            <?php elseif ( empty( $alerts_destinations_items ) ) : ?>
                                <div class="opsgate-alert-panel">
                                    <p>No canonical alert destinations are configured for this site yet.</p>
                                </div>
                            <?php else : ?>
                                <div class="opsgate-alerts-rules-table-wrap">
                                    <table class="opsgate-alerts-rules-table">
                                        <thead>
                                            <tr>
                                                <th>Family</th>
                                                <th>Label</th>
                                                <th>State</th>
                                                <th>Default</th>
                                                <th>Destination</th>
                                                <th>Rule linkage</th>
                                                <th>Last activity</th>
                                                <th>Control</th>
                                            </tr>
                                        </thead>
                                        <tbody>
                                            <?php foreach ( $alerts_destinations_items as $alerts_destination_item ) : ?>
                                                <?php
                                                if ( ! is_array( $alerts_destination_item ) ) {
                                                    continue;
                                                }
                                                $alerts_destination_id = isset( $alerts_destination_item['destination_id'] ) ? trim( (string) $alerts_destination_item['destination_id'] ) : '';
                                                $alerts_destination_family = isset( $alerts_destination_item['family'] ) ? strtolower( trim( (string) $alerts_destination_item['family'] ) ) : '';
                                                $alerts_destination_label = isset( $alerts_destination_item['label'] ) ? trim( (string) $alerts_destination_item['label'] ) : 'Untitled destination';
                                                $alerts_destination_state = isset( $alerts_destination_item['state'] ) ? strtolower( trim( (string) $alerts_destination_item['state'] ) ) : '';
                                                $alerts_destination_state_label = self::notification_status_label( $alerts_destination_state );
                                                $alerts_destination_state_tone = 'active' === $alerts_destination_state ? 'good' : 'warn';
                                                $alerts_destination_is_default = ! empty( $alerts_destination_item['is_default'] );
                                                $alerts_destination_target = self::notification_target_display(
                                                    isset( $alerts_destination_item['resolved_target'] ) ? (string) $alerts_destination_item['resolved_target'] : '',
                                                    $alerts_destination_family
                                                );
                                                $alerts_destination_delivery_state = isset( $alerts_destination_item['delivery_state'] ) ? strtolower( trim( (string) $alerts_destination_item['delivery_state'] ) ) : '';
                                                $alerts_destination_delivery_reason = isset( $alerts_destination_item['delivery_state_reason'] ) ? trim( (string) $alerts_destination_item['delivery_state_reason'] ) : '';
                                                $alerts_destination_delivery_label = '' !== $alerts_destination_delivery_state ? self::notification_status_label( $alerts_destination_delivery_state ) : 'Unknown';
                                                $alerts_destination_delivery_tone = 'neutral';
                                                if ( 'live' === $alerts_destination_delivery_state ) {
                                                    $alerts_destination_delivery_tone = 'good';
                                                } elseif ( 'configured_only' === $alerts_destination_delivery_state ) {
                                                    $alerts_destination_delivery_tone = 'warn';
                                                }
                                                $alerts_destination_rule_names = array();
                                                $alerts_destination_rule_ids = isset( $alerts_destination_item['linked_rule_ids'] ) && is_array( $alerts_destination_item['linked_rule_ids'] ) ? $alerts_destination_item['linked_rule_ids'] : array();
                                                foreach ( $alerts_destination_rule_ids as $alerts_destination_rule_id ) {
                                                    $alerts_destination_rule_id = trim( (string) $alerts_destination_rule_id );
                                                    if ( '' === $alerts_destination_rule_id ) {
                                                        continue;
                                                    }
                                                    $alerts_destination_rule_names[] = isset( $alerts_rule_name_by_id[ $alerts_destination_rule_id ] ) ? (string) $alerts_rule_name_by_id[ $alerts_destination_rule_id ] : $alerts_destination_rule_id;
                                                }
                                                $alerts_destination_rule_names = array_values( array_unique( array_filter( $alerts_destination_rule_names ) ) );
                                                $alerts_destination_last_test_event_id = isset( $alerts_destination_item['last_test_event_id'] ) ? trim( (string) $alerts_destination_item['last_test_event_id'] ) : '';
                                                $alerts_destination_last_test_event = ( '' !== $alerts_destination_last_test_event_id && isset( $alerts_event_by_id[ $alerts_destination_last_test_event_id ] ) && is_array( $alerts_event_by_id[ $alerts_destination_last_test_event_id ] ) ) ? $alerts_event_by_id[ $alerts_destination_last_test_event_id ] : array();
                                                $alerts_destination_last_activity_event = ( '' !== $alerts_destination_id && isset( $alerts_event_by_destination[ $alerts_destination_id ] ) && is_array( $alerts_event_by_destination[ $alerts_destination_id ] ) ) ? $alerts_event_by_destination[ $alerts_destination_id ] : $alerts_destination_last_test_event;
                                                $alerts_destination_last_activity_event_id = isset( $alerts_destination_last_activity_event['event_id'] ) ? trim( (string) $alerts_destination_last_activity_event['event_id'] ) : $alerts_destination_last_test_event_id;
                                                $alerts_destination_last_activity_status = isset( $alerts_destination_last_activity_event['status'] ) ? strtolower( trim( (string) $alerts_destination_last_activity_event['status'] ) ) : '';
                                                $alerts_destination_last_activity_label = '' !== $alerts_destination_last_activity_status ? self::notification_status_label( $alerts_destination_last_activity_status ) : ( '' !== $alerts_destination_last_activity_event_id ? 'Recorded' : 'No activity yet' );
                                                $alerts_destination_last_activity_tone = 'neutral';
                                                if ( in_array( $alerts_destination_last_activity_status, array( 'delivered', 'completed' ), true ) ) {
                                                    $alerts_destination_last_activity_tone = 'good';
                                                } elseif ( in_array( $alerts_destination_last_activity_status, array( 'ready', 'queued', 'pending', 'running', 'in_progress', 'suppressed' ), true ) ) {
                                                    $alerts_destination_last_activity_tone = 'warn';
                                                } elseif ( in_array( $alerts_destination_last_activity_status, array( 'failed', 'rejected', 'timeout', 'error' ), true ) ) {
                                                    $alerts_destination_last_activity_tone = 'bad';
                                                }
                                                $alerts_destination_last_activity_issue = ! empty( $alerts_destination_last_activity_event ) ? self::canonical_notification_issue_copy( (string) ( $alerts_destination_last_activity_event['error_code'] ?? '' ), (string) ( $alerts_destination_last_activity_event['error_message'] ?? '' ) ) : '';
                                                $alerts_destination_last_activity_event_type = isset( $alerts_destination_last_activity_event['event_type'] ) ? trim( (string) $alerts_destination_last_activity_event['event_type'] ) : '';
                                                $alerts_destination_last_activity_source_type = isset( $alerts_destination_last_activity_event['source_type'] ) ? trim( (string) $alerts_destination_last_activity_event['source_type'] ) : '';
                                                $alerts_destination_last_activity_source_id = isset( $alerts_destination_last_activity_event['source_id'] ) ? trim( (string) $alerts_destination_last_activity_event['source_id'] ) : '';
                                                $alerts_destination_last_activity_reference = '';
                                                if ( in_array( $alerts_destination_last_activity_source_type, array( 'run', 'triage', 'job' ), true ) && '' !== $alerts_destination_last_activity_source_id ) {
                                                    $alerts_destination_last_activity_reference = self::canonical_activity_reference_copy( 'Run reference', $alerts_destination_last_activity_source_id );
                                                } elseif ( '' !== $alerts_destination_last_activity_event_id ) {
                                                    $alerts_destination_last_activity_reference = self::canonical_activity_reference_copy( 'Event reference', $alerts_destination_last_activity_event_id );
                                                }
                                                $alerts_destination_toggle_action = 'active' === $alerts_destination_state ? 'opsgate_notification_destination_disable' : 'opsgate_notification_destination_enable';
                                                $alerts_destination_toggle_nonce = 'active' === $alerts_destination_state ? 'opsgate_notification_destination_disable' : 'opsgate_notification_destination_enable';
                                                $alerts_destination_toggle_label = 'active' === $alerts_destination_state ? 'Disable' : 'Enable';
                                                $alerts_destination_value_for_edit = self::notification_destination_value_from_item( $alerts_destination_item );
                                                ?>
                                                <tr>
                                                    <td>
                                                        <strong><?php echo esc_html( self::notification_channel_label( $alerts_destination_family ) ); ?></strong>
                                                        <div class="opsgate-alerts-table-copy">
                                                            <span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( $alerts_destination_delivery_tone ); ?>">
                                                                <?php echo esc_html( $alerts_destination_delivery_label ); ?>
                                                            </span>
                                                        </div>
                                                        <?php if ( '' !== $alerts_destination_delivery_reason ) : ?>
                                                            <div class="opsgate-alerts-table-copy"><?php echo esc_html( $alerts_destination_delivery_reason ); ?></div>
                                                        <?php endif; ?>
                                                    </td>
                                                    <td>
                                                        <strong><?php echo esc_html( $alerts_destination_label ); ?></strong>
                                                        <?php if ( '' !== $alerts_destination_id ) : ?>
                                                            <div class="opsgate-alerts-table-copy"><?php echo esc_html( 'Ref ' . $alerts_destination_id ); ?></div>
                                                        <?php endif; ?>
                                                    </td>
                                                    <td>
                                                        <span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( $alerts_destination_state_tone ); ?>">
                                                            <?php echo esc_html( $alerts_destination_state_label ); ?>
                                                        </span>
                                                    </td>
                                                    <td>
                                                        <span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( $alerts_destination_is_default ? 'good' : 'neutral' ); ?>">
                                                            <?php echo esc_html( $alerts_destination_is_default ? 'Yes' : 'No' ); ?>
                                                        </span>
                                                    </td>
                                                    <td>
                                                        <?php echo esc_html( $alerts_destination_target ); ?>
                                                        <?php if ( ! empty( $alerts_destination_item['config'] ) && is_array( $alerts_destination_item['config'] ) && isset( $alerts_destination_item['config']['subject_prefix'] ) && '' !== trim( (string) $alerts_destination_item['config']['subject_prefix'] ) ) : ?>
                                                            <div class="opsgate-alerts-table-copy"><?php echo esc_html( 'Subject prefix: ' . (string) $alerts_destination_item['config']['subject_prefix'] ); ?></div>
                                                        <?php endif; ?>
                                                    </td>
                                                    <td>
                                                        <?php if ( ! empty( $alerts_destination_rule_names ) ) : ?>
                                                            <strong><?php echo esc_html( implode( ', ', $alerts_destination_rule_names ) ); ?></strong>
                                                            <div class="opsgate-alerts-table-copy"><?php echo esc_html( sprintf( '%d linked rule%s', count( $alerts_destination_rule_names ), 1 === count( $alerts_destination_rule_names ) ? '' : 's' ) ); ?></div>
                                                        <?php else : ?>
                                                            <span class="opsgate-alerts-table-copy">No linked rules</span>
                                                        <?php endif; ?>
                                                    </td>
                                                    <td>
                                                        <span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( $alerts_destination_last_activity_tone ); ?>">
                                                            <?php echo esc_html( $alerts_destination_last_activity_label ); ?>
                                                        </span>
                                                        <?php if ( '' !== $alerts_destination_last_activity_event_type ) : ?>
                                                            <div class="opsgate-alerts-table-copy"><?php echo esc_html( self::canonical_notification_event_label( $alerts_destination_last_activity_event_type ) ); ?></div>
                                                        <?php endif; ?>
                                                        <?php if ( '' !== $alerts_destination_last_activity_reference ) : ?>
                                                            <div class="opsgate-alerts-table-copy"><?php echo esc_html( $alerts_destination_last_activity_reference ); ?></div>
                                                        <?php endif; ?>
                                                        <?php if ( ! empty( $alerts_destination_last_activity_event ) && ! empty( $alerts_destination_last_activity_event['triggered_at_utc'] ) ) : ?>
                                                            <div class="opsgate-alerts-table-copy"><?php echo esc_html( self::notification_datetime_label( (string) $alerts_destination_last_activity_event['triggered_at_utc'] ) ); ?></div>
                                                        <?php endif; ?>
                                                        <?php if ( ! empty( $alerts_destination_last_activity_event ) && ! empty( $alerts_destination_last_activity_event['attempt_count'] ) ) : ?>
                                                            <div class="opsgate-alerts-table-copy"><?php echo esc_html( sprintf( '%d attempt%s recorded', (int) $alerts_destination_last_activity_event['attempt_count'], 1 === (int) $alerts_destination_last_activity_event['attempt_count'] ? '' : 's' ) ); ?></div>
                                                        <?php endif; ?>
                                                        <?php if ( '—' !== $alerts_destination_last_activity_issue && '' !== $alerts_destination_last_activity_issue ) : ?>
                                                            <div class="opsgate-alerts-table-copy"><?php echo esc_html( $alerts_destination_last_activity_issue ); ?></div>
                                                        <?php endif; ?>
                                                    </td>
                                                    <td>
                                                        <?php if ( '' !== $alerts_destination_id ) : ?>
                                                            <div style="display:flex; gap:6px; flex-wrap:wrap;">
                                                                <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:0;">
                                                                    <input type="hidden" name="action" value="<?php echo esc_attr( $alerts_destination_toggle_action ); ?>" />
                                                                    <?php wp_nonce_field( $alerts_destination_toggle_nonce ); ?>
                                                                    <input type="hidden" name="destination_id" value="<?php echo esc_attr( $alerts_destination_id ); ?>" />
                                                                    <button type="submit" class="button button-small"><?php echo esc_html( $alerts_destination_toggle_label ); ?></button>
                                                                </form>
                                                                <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:0;">
                                                                    <input type="hidden" name="action" value="opsgate_notification_destination_test" />
                                                                    <?php wp_nonce_field( 'opsgate_notification_destination_test' ); ?>
                                                                    <input type="hidden" name="destination_id" value="<?php echo esc_attr( $alerts_destination_id ); ?>" />
                                                                    <button type="submit" class="button button-small button-secondary">Test delivery</button>
                                                                </form>
                                                            </div>
                                                            <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:8px 0 0 0;">
                                                                <input type="hidden" name="action" value="opsgate_notification_destination_update" />
                                                                <?php wp_nonce_field( 'opsgate_notification_destination_update' ); ?>
                                                                <input type="hidden" name="destination_id" value="<?php echo esc_attr( $alerts_destination_id ); ?>" />
                                                                <input type="hidden" name="destination_family" value="<?php echo esc_attr( $alerts_destination_family ); ?>" />
                                                                <label style="display:block; margin-bottom:6px;">
                                                                    <span class="screen-reader-text">Destination label</span>
                                                                    <input name="destination_label" type="text" class="regular-text" value="<?php echo esc_attr( $alerts_destination_label ); ?>" />
                                                                </label>
                                                                <label style="display:block; margin-bottom:6px;">
                                                                    <span class="screen-reader-text">Destination value</span>
                                                                    <input name="destination_value" type="text" class="regular-text" value="<?php echo esc_attr( $alerts_destination_value_for_edit ); ?>" />
                                                                </label>
                                                                <label style="display:block; margin-bottom:6px;">
                                                                    <input type="checkbox" name="destination_is_default" value="1" <?php checked( $alerts_destination_is_default ); ?> />
                                                                    Default destination
                                                                </label>
                                                                <button type="submit" class="button button-small">Update</button>
                                                            </form>
                                                        <?php else : ?>
                                                            <span class="opsgate-alerts-table-copy">Unavailable</span>
                                                        <?php endif; ?>
                                                    </td>
                                                </tr>
                                            <?php endforeach; ?>
                                        </tbody>
                                    </table>
                                </div>
                            <?php endif; ?>
                        </div>

                        <?php if ( ! empty( $alerts_latest_proof_event ) ) : ?>
                            <div class="opsgate-settings-module opsgate-alerts-legacy-block" style="margin-bottom:18px;">
                                <div class="opsgate-settings-module-head">
                                    <div>
                                        <strong>Operator validation receipt</strong>
                                        <p class="description">This row is recorded from a deterministic operator validation scenario. It does not represent a live customer-facing delivery failure.</p>
                                    </div>
                                    <span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-neutral">Proof receipt</span>
                                </div>
                                <div class="opsgate-pricing-summary-grid">
                                    <article class="opsgate-pricing-summary-card">
                                        <span class="opsgate-overview-eyebrow">Receipt</span>
                                        <div class="opsgate-pricing-hero-side-title"><?php echo esc_html( self::notification_event_display_title( $alerts_latest_proof_event ) ); ?></div>
                                        <p><?php echo esc_html( self::notification_event_display_summary( $alerts_latest_proof_event ) ); ?></p>
                                    </article>
                                    <article class="opsgate-pricing-summary-card">
                                        <span class="opsgate-overview-eyebrow">Destination</span>
                                        <div class="opsgate-pricing-hero-side-title"><?php echo esc_html( self::notification_target_display( (string) ( $alerts_latest_proof_event['target'] ?? '' ), (string) ( $alerts_latest_proof_event['channel'] ?? '' ) ) ); ?></div>
                                        <p>OpsGate records this target as the operator proof delivery endpoint so it cannot be mistaken for a live customer destination.</p>
                                    </article>
                                    <article class="opsgate-pricing-summary-card">
                                        <span class="opsgate-overview-eyebrow">Why it failed</span>
                                        <div class="opsgate-pricing-hero-side-title"><?php echo esc_html( self::notification_status_label( (string) ( $alerts_latest_proof_event['status'] ?? '' ) ) ); ?></div>
                                        <p><?php echo esc_html( self::canonical_notification_issue_copy( (string) ( $alerts_latest_proof_event['error_code'] ?? '' ), (string) ( $alerts_latest_proof_event['error_message'] ?? '' ) ) ); ?></p>
                                    </article>
                                </div>
                            </div>
                        <?php endif; ?>

                        <div class="opsgate-alerts-columns opsgate-alerts-legacy-block">
                            <section class="opsgate-alerts-surface opsgate-alerts-surface-main">
                                <div class="opsgate-alerts-surface-header">
                                    <h3 class="opsgate-alerts-surface-title">Alert Rules</h3>
                                    <span class="opsgate-alerts-surface-link">Live toggles</span>
                                </div>
                                    <div
                                        id="opsgate-alerts-rules-status-legacy"
                                        class="opsgate-alert-inline-status<?php echo in_array( $alerts_notice, array( 'rule_created', 'rule_updated', 'rule_error' ), true ) ? ' is-visible ' . ( 'rule_error' === $alerts_notice ? 'is-error' : 'is-success' ) : ''; ?>"
                                        data-opsgate-transient-status="1"
                                        role="status"
                                        aria-live="polite"
                                    >
                                    <p>
                                        <?php
                                        if ( 'rule_created' === $alerts_notice ) {
                                            echo esc_html( 'Alert rule created.' );
                                        } elseif ( 'rule_updated' === $alerts_notice ) {
                                            echo esc_html( 'Alert rule updated.' );
                                        } elseif ( 'rule_error' === $alerts_notice ) {
                                            echo esc_html( '' !== $alerts_error ? $alerts_error : 'Could not update the alert setting.' );
                                        }
                                        ?>
                                    </p>
                                </div>

                                <div class="opsgate-pricing-summary-grid" style="margin-bottom:16px;">
                                    <article class="opsgate-pricing-summary-card">
                                        <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" data-opsgate-rule-form="create">
                                            <input type="hidden" name="action" value="opsgate_notification_rule_create" />
                                            <?php wp_nonce_field( 'opsgate_notification_rule_create' ); ?>
                                            <span class="opsgate-overview-eyebrow">Create alert rule</span>
                                            <p class="opsgate-alerts-detail-meta" style="margin:8px 0 0;"><?php echo esc_html( $alerts_rule_form_hint ); ?></p>
                                            <div style="margin:10px 0;">
                                                <label for="opsgate-rule-event-type"><strong>Alert type</strong></label>
                                                <select id="opsgate-rule-event-type" name="rule_event_type" class="regular-text" style="width:100%; margin-top:4px;">
                                                    <?php foreach ( $alerts_rule_event_options as $alerts_rule_event_key => $alerts_rule_event_label ) : ?>
                                                        <option value="<?php echo esc_attr( $alerts_rule_event_key ); ?>"><?php echo esc_html( $alerts_rule_event_label ); ?></option>
                                                    <?php endforeach; ?>
                                                </select>
                                            </div>
                                            <div style="margin:10px 0;">
                                                <label for="opsgate-rule-destination-id"><strong>Destination</strong></label>
                                                <select id="opsgate-rule-destination-id" name="rule_destination_id" class="regular-text" style="width:100%; margin-top:4px;">
                                                    <?php foreach ( $alerts_destinations_items as $alerts_rule_destination_option ) : ?>
                                                        <?php if ( ! is_array( $alerts_rule_destination_option ) ) { continue; } ?>
                                                        <?php
                                                        $alerts_rule_destination_option_id = isset( $alerts_rule_destination_option['destination_id'] ) ? trim( (string) $alerts_rule_destination_option['destination_id'] ) : '';
                                                        if ( '' === $alerts_rule_destination_option_id ) { continue; }
                                                        $alerts_rule_destination_option_family = isset( $alerts_rule_destination_option['family'] ) ? strtolower( trim( (string) $alerts_rule_destination_option['family'] ) ) : '';
                                                        $alerts_rule_destination_option_label = isset( $alerts_rule_destination_option['label'] ) ? trim( (string) $alerts_rule_destination_option['label'] ) : 'Destination';
                                                        $alerts_rule_destination_option_target = self::notification_target_display( isset( $alerts_rule_destination_option['resolved_target'] ) ? (string) $alerts_rule_destination_option['resolved_target'] : '', $alerts_rule_destination_option_family );
                                                        ?>
                                                        <option value="<?php echo esc_attr( $alerts_rule_destination_option_id ); ?>"><?php echo esc_html( self::notification_channel_label( $alerts_rule_destination_option_family ) . ' — ' . $alerts_rule_destination_option_label . ' — ' . $alerts_rule_destination_option_target ); ?></option>
                                                    <?php endforeach; ?>
                                                </select>
                                            </div>
                                            <div style="margin:10px 0;">
                                                <label for="opsgate-rule-name"><strong>Rule label</strong></label>
                                                <input id="opsgate-rule-name" name="rule_name" type="text" class="regular-text" style="width:100%; margin-top:4px;" placeholder="Healthy email alert, critical webhook alert" />
                                            </div>
                                            <p style="margin:10px 0;">
                                                <label>
                                                    <input type="checkbox" name="rule_is_enabled" value="1" checked="checked" />
                                                    Enable immediately if the current package allows it
                                                </label>
                                            </p>
                                            <p style="margin:0;">
                                                <button type="submit" class="button button-secondary" <?php disabled( empty( $alerts_destinations_items ) ); ?>><?php echo esc_html( $alerts_rule_submit_label ); ?></button>
                                            </p>
                                        </form>
                                    </article>
                                </div>

                                <?php if ( ! $alerts_rules_ok ) : ?>
                                    <div class="opsgate-alert-panel opsgate-alert-panel-error">
                                        <p><?php echo esc_html( '' !== $alerts_rules_error ? $alerts_rules_error : 'Could not load alerts.' ); ?></p>
                                    </div>
                                <?php elseif ( empty( $alerts_rules_items ) ) : ?>
                                    <div class="opsgate-alert-panel">
                                        <p>No alerts are configured for this site yet.</p>
                                    </div>
                                <?php else : ?>
                                    <div class="opsgate-alerts-rules-table-wrap">
                                        <table class="opsgate-alerts-rules-table">
                                            <thead>
                                                <tr>
                                                    <th>Rule</th>
                                                    <th>Event</th>
                                                    <th>Channel</th>
                                                    <th>Destination</th>
                                                    <th>Package</th>
                                                    <th>Configuration state</th>
                                                    <th>Delivery state</th>
                                                    <th>Control</th>
                                                </tr>
                                            </thead>
                                            <tbody>
                                                <?php foreach ( $alerts_rules_items as $rule ) : ?>
                                                    <?php
                                                    if ( ! is_array( $rule ) ) {
                                                        continue;
                                                    }

                                                    $rule_id       = isset( $rule['rule_id'] ) ? trim( (string) $rule['rule_id'] ) : '';
                                                    $name          = self::notification_rule_display_name( $rule );
                                                    $description   = self::notification_rule_display_description( $rule );
                                                    $event_type    = isset( $rule['event_type'] ) ? (string) $rule['event_type'] : '';
                                                    $channel       = isset( $rule['channel'] ) ? (string) $rule['channel'] : '';
                                                    $target        = isset( $rule['target'] ) ? trim( (string) $rule['target'] ) : '';
                                                    $schedule_mode = isset( $rule['schedule_mode'] ) ? (string) $rule['schedule_mode'] : '';
                                                    $is_enabled    = ! empty( $rule['is_enabled'] );
                                                    $rule_is_proof = self::item_is_proof( $rule );
                                                    $rule_provenance_note = self::item_provenance_note_copy( $rule );
                                                    $toggle_action = $is_enabled ? 'opsgate_notification_rule_disable' : 'opsgate_notification_rule_enable';
                                                    $toggle_nonce  = $is_enabled ? 'opsgate_notification_rule_disable' : 'opsgate_notification_rule_enable';
                                                    $toggle_target = $is_enabled ? '0' : '1';
                                                    $target_copy   = self::notification_target_display( $target, $channel );
                                                    $channel_label = self::notification_channel_label( $channel );
                                                    $channel_is_live = self::notification_rule_channel_is_live( $rule, $alerts_destinations_items, $alerts_live_channel_labels );
                                                    $channel_is_editable = $channel_is_live && ! $rule_is_proof;
                                                    $package_state_label = $rule_is_proof ? 'Operator proof' : ( $channel_is_live ? 'Available on current package' : 'Locked on current package' );
                                                    $configuration_state_label = $rule_is_proof ? 'Validation receipt' : ( $channel_is_live ? ( $is_enabled ? 'Configured' : 'Available' ) : 'Locked' );
                                                    $configuration_state_tone = $rule_is_proof ? 'neutral' : ( $channel_is_live ? ( $is_enabled ? 'good' : 'info' ) : 'warn' );
                                                    $delivery_lookup_key = '' !== $rule_id ? $rule_id : '';
                                                    $delivery_signature = strtolower( $event_type . '|' . $channel . '|' . $target );
                                                    $latest_rule_event = array();
                                                    if ( '' !== $delivery_lookup_key && isset( $alerts_rule_delivery_by_rule[ $delivery_lookup_key ] ) && is_array( $alerts_rule_delivery_by_rule[ $delivery_lookup_key ] ) ) {
                                                        $latest_rule_event = $alerts_rule_delivery_by_rule[ $delivery_lookup_key ];
                                                    } elseif ( isset( $alerts_rule_delivery_by_signature[ $delivery_signature ] ) && is_array( $alerts_rule_delivery_by_signature[ $delivery_signature ] ) ) {
                                                        $latest_rule_event = $alerts_rule_delivery_by_signature[ $delivery_signature ];
                                                    }
                                                    $delivery_state_label = 'No delivery recorded yet';
                                                    $delivery_state_tone = 'neutral';
                                                    if ( ! empty( $latest_rule_event ) ) {
                                                        $delivery_state_key = strtolower( trim( (string) ( $latest_rule_event['status'] ?? '' ) ) );
                                                        $delivery_state_label = self::notification_status_label( $delivery_state_key );
                                                        if ( in_array( $delivery_state_key, array( 'delivered', 'completed' ), true ) ) {
                                                            $delivery_state_tone = 'good';
                                                        } elseif ( in_array( $delivery_state_key, array( 'ready', 'queued', 'pending', 'running', 'in_progress' ), true ) ) {
                                                            $delivery_state_tone = 'warn';
                                                        } elseif ( in_array( $delivery_state_key, array( 'failed', 'rejected', 'timeout', 'error' ), true ) ) {
                                                            $delivery_state_tone = 'bad';
                                                        }
                                                    } elseif ( ! $is_enabled ) {
                                                        $delivery_state_label = 'Rule is off';
                                                    }
                                                    ?>
                                                    <tr class="<?php echo $is_enabled ? 'is-enabled' : ''; ?>">
                                                        <td>
                                                            <strong><?php echo esc_html( '' !== $name ? $name : 'Untitled alert' ); ?></strong>
                                                            <div class="opsgate-alerts-table-copy"><?php echo esc_html( '' !== $description ? $description : 'Alert delivery for this site.' ); ?></div>
                                                            <?php if ( '' !== $rule_provenance_note ) : ?>
                                                                <div class="opsgate-alerts-table-copy"><?php echo esc_html( $rule_provenance_note ); ?></div>
                                                            <?php endif; ?>
                                                        </td>
                                                        <td><?php echo esc_html( self::canonical_notification_event_label( $event_type ) ); ?><div class="opsgate-alerts-table-copy"><?php echo esc_html( self::notification_schedule_label( $schedule_mode ) ); ?></div></td>
                                                        <td><?php echo esc_html( $channel_label ); ?></td>
                                                        <td><?php echo esc_html( $target_copy ); ?></td>
                                                        <td><span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( $channel_is_live ? 'good' : 'warn' ); ?>"><?php echo esc_html( $package_state_label ); ?></span></td>
                                                        <td>
                                                            <span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( $configuration_state_tone ); ?>">
                                                                <?php echo esc_html( $configuration_state_label ); ?>
                                                            </span>
                                                        </td>
                                                        <td>
                                                            <span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( $delivery_state_tone ); ?>">
                                                                <?php echo esc_html( $delivery_state_label ); ?>
                                                            </span>
                                                        </td>
                                                        <td>
                                                            <?php if ( '' !== $rule_id && $channel_is_editable ) : ?>
                                                                <form
                                                                    method="post"
                                                                    action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>"
                                                                    class="opsgate-alert-switch-form-legacy"
                                                                    data-rule-id="<?php echo esc_attr( $rule_id ); ?>"
                                                                    data-rendered-enabled="<?php echo esc_attr( $is_enabled ? '1' : '0' ); ?>"
                                                                    data-current-enabled="<?php echo esc_attr( $is_enabled ? '1' : '0' ); ?>"
                                                                    data-next-enabled="<?php echo esc_attr( $toggle_target ); ?>"
                                                                    data-ajax-url="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"
                                                                    data-ajax-nonce="<?php echo esc_attr( $alerts_toggle_nonce ); ?>"
                                                                    data-enable-admin-nonce="<?php echo esc_attr( wp_create_nonce( 'opsgate_notification_rule_enable' ) ); ?>"
                                                                    data-disable-admin-nonce="<?php echo esc_attr( wp_create_nonce( 'opsgate_notification_rule_disable' ) ); ?>"
                                                                >
                                                                    <?php wp_nonce_field( $toggle_nonce ); ?>
                                                                    <input type="hidden" name="action" value="<?php echo esc_attr( $toggle_action ); ?>" />
                                                                    <input type="hidden" name="rule_id" value="<?php echo esc_attr( $rule_id ); ?>" />
                                                                    <button type="button" class="opsgate-alert-switch" data-opsgate-alert-toggle-button-legacy="1" aria-label="<?php echo esc_attr( $is_enabled ? 'Disable alert' : 'Enable alert' ); ?>">
                                                                        <span class="opsgate-alert-switch-track">
                                                                            <span class="opsgate-alert-switch-slider" aria-hidden="true"></span>
                                                                        </span>
                                                                        <span class="opsgate-alert-switch-label" data-opsgate-alert-toggle-label-legacy="1"><?php echo esc_html( $is_enabled ? 'ON' : 'OFF' ); ?></span>
                                                                    </button>
                                                                </form>
                                                            <?php else : ?>
                                                                <span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( $rule_is_proof ? 'neutral' : 'warn' ); ?>"><?php echo esc_html( $rule_is_proof ? 'Recorded' : 'Locked' ); ?></span>
                                                            <?php endif; ?>
                                                        </td>
                                                    </tr>
                                                <?php endforeach; ?>
                                            </tbody>
                                        </table>
                                    </div>
                                <?php endif; ?>
                            </section>

                            <aside class="opsgate-alerts-surface opsgate-alerts-surface-rail">
                                <div class="opsgate-alerts-surface-header">
                                    <h3 class="opsgate-alerts-surface-title">Recent Alert History</h3>
                                    <span class="opsgate-alerts-surface-link">Recent delivery history</span>
                                </div>

                                <?php if ( ! $alerts_events_ok ) : ?>
                                    <div class="opsgate-alert-panel opsgate-alert-panel-error">
                                        <p><?php echo esc_html( '' !== $alerts_events_error ? $alerts_events_error : 'Could not load alert history.' ); ?></p>
                                    </div>
                                <?php elseif ( empty( $alerts_events_items ) ) : ?>
                                    <div class="opsgate-alert-panel">
                                        <p><?php echo esc_html( ! empty( $alerts_rules_items ) ? 'Alert rules are configured for this site, but no delivery activity has been recorded yet.' : 'No alert activity has been recorded for this site yet.' ); ?></p>
                                    </div>
                                <?php else : ?>
                                    <div class="opsgate-alerts-history-list opsgate-alerts-history-list-compact">
                                        <?php foreach ( $alerts_events_items as $event ) : ?>
                                            <?php
                                            if ( ! is_array( $event ) ) {
                                                continue;
                                            }
                                            $event_type       = isset( $event['event_type'] ) ? (string) $event['event_type'] : '';
                                            $channel          = isset( $event['channel'] ) ? (string) $event['channel'] : '';
                                            $target           = isset( $event['target'] ) ? trim( (string) $event['target'] ) : '';
                                            $status           = isset( $event['status'] ) ? (string) $event['status'] : '';
                                            $title            = self::notification_event_display_title( $event );
                                            $summary          = self::notification_event_display_summary( $event );
                                            $triggered_at_utc = isset( $event['triggered_at_utc'] ) ? (string) $event['triggered_at_utc'] : '';
                                            $last_attempt     = isset( $event['last_attempt_at_utc'] ) ? (string) $event['last_attempt_at_utc'] : '';
                                            $finalized        = isset( $event['finalized_at_utc'] ) ? (string) $event['finalized_at_utc'] : '';
                                            $error_code       = isset( $event['error_code'] ) ? (string) $event['error_code'] : '';
                                            $error_message    = isset( $event['error_message'] ) ? (string) $event['error_message'] : '';
                                            $triggered_parts  = self::notification_datetime_parts( $triggered_at_utc );
                                            $last_parts       = self::notification_datetime_parts( $last_attempt );
                                            $finalized_parts  = self::notification_datetime_parts( $finalized );
                                            $issue_copy       = self::canonical_notification_issue_copy( $error_code, $error_message );
                                            $event_provenance_note = self::item_provenance_note_copy( $event );
                                            $status_label     = self::notification_status_label( $status );
                                            $event_source_type = isset( $event['source_type'] ) ? trim( (string) $event['source_type'] ) : '';
                                            $event_source_id   = isset( $event['source_id'] ) ? trim( (string) $event['source_id'] ) : '';
                                            $event_attempt_count = isset( $event['attempt_count'] ) ? (int) $event['attempt_count'] : 0;
                                            $event_reference_copy = isset( $event['event_id'] ) ? self::canonical_activity_reference_copy( 'Event reference', (string) $event['event_id'] ) : '';
                                            $event_source_reference = in_array( $event_source_type, array( 'run', 'triage', 'job' ), true ) && '' !== $event_source_id
                                                ? self::canonical_activity_reference_copy( 'Run reference', $event_source_id )
                                                : '';
                                            $status_tone      = 'neutral';
                                            $status_key       = strtolower( trim( $status ) );
                                            if ( in_array( $status_key, array( 'delivered', 'completed' ), true ) ) {
                                                $status_tone = 'good';
                                            } elseif ( in_array( $status_key, array( 'ready', 'queued', 'pending', 'running', 'in_progress' ), true ) ) {
                                                $status_tone = 'warn';
                                            } elseif ( in_array( $status_key, array( 'failed', 'rejected', 'timeout', 'error' ), true ) ) {
                                                $status_tone = 'bad';
                                            }
                                            $target_copy = self::notification_target_compact_display( $target, $channel );
                                            ?>
                                            <article class="opsgate-alerts-history-card">
                                                <div class="opsgate-alerts-history-top">
                                                    <div class="opsgate-alerts-history-heading">
                                                        <h4 class="opsgate-alerts-history-title"><?php echo esc_html( '' !== $title ? $title : self::canonical_notification_event_label( $event_type ) ); ?></h4>
                                                        <p class="opsgate-alerts-history-copy"><?php echo esc_html( '' !== $summary ? $summary : 'No summary recorded.' ); ?></p>
                                                    </div>
                                                    <span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( $status_tone ); ?>"><?php echo esc_html( $status_label ); ?></span>
                                                </div>
                                                <div class="opsgate-alerts-history-meta">
                                                    <span class="opsgate-alerts-pill opsgate-alerts-pill-channel"><?php echo esc_html( self::notification_channel_label( $channel ) ); ?></span>
                                                    <span class="opsgate-alerts-pill opsgate-alerts-pill-target"><?php echo esc_html( $target_copy ); ?></span>
                                                    <span class="opsgate-alerts-pill opsgate-alerts-pill-time"><?php echo esc_html( $triggered_parts['date'] . ( '' !== $triggered_parts['time'] ? ' · ' . $triggered_parts['time'] : '' ) ); ?></span>
                                                </div>
                                                <?php if ( '' !== $event_source_reference ) : ?>
                                                    <p class="opsgate-alerts-history-copy"><?php echo esc_html( $event_source_reference ); ?></p>
                                                <?php endif; ?>
                                                <?php if ( '' !== $event_reference_copy ) : ?>
                                                    <p class="opsgate-alerts-history-copy"><?php echo esc_html( $event_reference_copy ); ?></p>
                                                <?php endif; ?>
                                                <?php if ( $event_attempt_count > 0 ) : ?>
                                                    <p class="opsgate-alerts-history-copy"><?php echo esc_html( sprintf( '%d delivery attempt%s recorded.', $event_attempt_count, 1 === $event_attempt_count ? '' : 's' ) ); ?></p>
                                                <?php endif; ?>
                                                <?php if ( '' !== $last_attempt ) : ?>
                                                    <p class="opsgate-alerts-history-copy"><?php echo esc_html( 'Last attempt ' . self::notification_datetime_label( $last_attempt ) ); ?></p>
                                                <?php endif; ?>
                                                <?php if ( '' !== $finalized ) : ?>
                                                    <p class="opsgate-alerts-history-copy"><?php echo esc_html( 'Finalized ' . self::notification_datetime_label( $finalized ) ); ?></p>
                                                <?php endif; ?>
                                                <?php if ( '' !== $event_provenance_note ) : ?>
                                                    <p class="opsgate-alerts-history-copy"><?php echo esc_html( $event_provenance_note ); ?></p>
                                                <?php endif; ?>
                                                <?php if ( '—' !== $issue_copy ) : ?>
                                                    <p class="opsgate-alerts-history-issue"><?php echo esc_html( $issue_copy ); ?></p>
                                                <?php endif; ?>
                                            </article>
                                        <?php endforeach; ?>
                                    </div>
                                <?php endif; ?>
                            </aside>
                        </div>
                        <?php endif; ?>
                    </div>
                    <?php elseif ( 'activity' === $active_tab ) : ?>
                    <?php
                    $activity_items = self::canonical_activity_feed( 12 );
                    $activity_scope = self::get_mcp_scope_snapshot();
                    $activity_site_config = self::canonical_site_config();
                    $activity_site_config_item = ! empty( $activity_site_config['ok'] ) && isset( $activity_site_config['item'] ) && is_array( $activity_site_config['item'] ) ? $activity_site_config['item'] : array();
                    $activity_selected_site = self::current_selected_site_summary();
                    $activity_refresh_url = self::admin_tab_url( 'activity' );
                    $activity_site_label = self::connected_site_label( $activity_site_config_item, $activity_scope );
                    $activity_scope_label = '' !== $activity_site_label ? $activity_site_label : 'Connected site';
                    $activity_connection_status = isset( $activity_selected_site['connection_status'] ) ? trim( (string) $activity_selected_site['connection_status'] ) : 'external_only';
                    $activity_connection_mode = isset( $activity_selected_site['connection_mode'] ) ? trim( (string) $activity_selected_site['connection_mode'] ) : 'public_scan';
                    $activity_connection_label = self::canonical_connection_status_label( $activity_connection_status );
                    $activity_connection_copy = self::canonical_connection_status_copy(
                        $activity_connection_status,
                        $activity_connection_mode,
                        self::scope_targets_local_wordpress( isset( $activity_selected_site['site_url'] ) ? (string) $activity_selected_site['site_url'] : '' )
                    );
                    $activity_latest_item = ! empty( $activity_items ) && is_array( $activity_items[0] ) ? $activity_items[0] : array();
                    $activity_latest_when = isset( $activity_latest_item['when'] ) ? (string) $activity_latest_item['when'] : 'No recent activity';
                    $activity_latest_label = isset( $activity_latest_item['label'] ) ? (string) $activity_latest_item['label'] : 'No recent activity';
                    $activity_latest_status = isset( $activity_latest_item['status'] ) ? (string) $activity_latest_item['status'] : '';
                    $activity_recorded_count = 0;
                    $activity_alert_count = 0;
                    $activity_validation_count = 0;
                    $activity_report_count = 0;
                    $activity_scan_count = 0;
                    foreach ( $activity_items as $activity_item ) {
                        if ( ! is_array( $activity_item ) ) {
                            continue;
                        }
                        $activity_status_key = strtolower( trim( (string) ( $activity_item['status'] ?? '' ) ) );
                        if ( in_array( $activity_status_key, array( 'recorded', 'delivered', 'ready' ), true ) ) {
                            ++$activity_recorded_count;
                        }
                        $activity_label_key = strtolower( trim( (string) ( $activity_item['label'] ?? '' ) ) );
                        if ( false !== strpos( $activity_label_key, 'alert' ) ) {
                            ++$activity_alert_count;
                        }
                        if ( false !== strpos( $activity_label_key, 'validation' ) ) {
                            ++$activity_validation_count;
                        }
                        if ( false !== strpos( $activity_label_key, 'report' ) ) {
                            ++$activity_report_count;
                        }
                        if ( false !== strpos( $activity_label_key, 'scan' ) || false !== strpos( $activity_label_key, 'security scan' ) || false !== strpos( $activity_label_key, 'triage' ) ) {
                            ++$activity_scan_count;
                        }
                    }
                    $activity_event_family = static function ( array $activity_item ): string {
                        $label_key = strtolower( trim( (string) ( $activity_item['label'] ?? '' ) ) );
                        $details_key = strtolower( trim( (string) ( $activity_item['details'] ?? '' ) ) );
                        $full_key = $label_key . ' ' . $details_key;
                        if ( false !== strpos( $label_key, 'validation receipt' ) ) {
                            return 'proof';
                        }
                        if ( false !== strpos( $label_key, 'report package' ) ) {
                            return 'report';
                        }
                        if ( false !== strpos( $full_key, 'deliver' ) || false !== strpos( $full_key, 'sent to client' ) ) {
                            return 'delivery';
                        }
                        if ( false !== strpos( $label_key, 'alert' ) ) {
                            return 'alert';
                        }
                        if ( false !== strpos( $label_key, 'triage' ) ) {
                            return 'triage';
                        }
                        if ( false !== strpos( $full_key, 'connect' ) || false !== strpos( $full_key, 'pair' ) ) {
                            return 'connection';
                        }
                        return 'timeline';
                    };
                    $activity_family_tone = static function ( array $activity_item, string $badge_class, string $family ): string {
                        $label_key = strtolower( trim( (string) ( $activity_item['label'] ?? '' ) ) . ' ' . trim( (string) ( $activity_item['details'] ?? '' ) ) );
                        if ( false !== strpos( $label_key, 'critical' ) || false !== strpos( $label_key, 'red posture' ) ) {
                            return 'bad';
                        }
                        if ( false !== strpos( $label_key, 'warning' ) || false !== strpos( $label_key, 'yellow posture' ) ) {
                            return 'warn';
                        }
                        if ( false !== strpos( $label_key, 'healthy' ) || false !== strpos( $label_key, 'green posture' ) ) {
                            return 'good';
                        }
                        if ( 'proof' === $family ) {
                            return 'proof';
                        }
                        if ( 'report' === $family ) {
                            return 'info';
                        }
                        if ( 'danger' === $badge_class ) {
                            return 'bad';
                        }
                        if ( 'warning' === $badge_class ) {
                            return 'warn';
                        }
                        if ( 'success' === $badge_class ) {
                            return 'good';
                        }
                        return 'info';
                    };
                    $activity_family_label = static function ( string $family ): string {
                        $map = array(
                            'report'     => 'Report ready',
                            'triage'     => 'Security Scan',
                            'alert'      => 'Alert delivery',
                            'delivery'   => 'Report delivery',
                            'connection' => 'Connection',
                            'proof'      => 'Configuration checks',
                            'timeline'   => 'Activity event',
                        );
                        return $map[ $family ] ?? 'Activity event';
                    };
                    // Phase 5: event icon map — letter abbreviations, no emoji
                    $activity_family_icon = static function ( string $family ): string {
                        $map = array(
                            'report'     => 'R',
                            'triage'     => 'T',
                            'alert'      => 'A',
                            'delivery'   => 'D',
                            'connection' => 'C',
                            'proof'      => 'V',
                            'timeline'   => 'S',
                        );
                        return $map[ $family ] ?? '·';
                    };
                    $activity_featured_item = array();
                    $activity_primary_items = array();
                    $activity_proof_items = array();
                    foreach ( $activity_items as $activity_item ) {
                        if ( ! is_array( $activity_item ) ) {
                            continue;
                        }
                        $family = $activity_event_family( $activity_item );
                        $activity_item['_family'] = $family;
                        if ( empty( $activity_featured_item ) && 'proof' !== $family ) {
                            $activity_featured_item = $activity_item;
                            continue;
                        }
                        if ( 'proof' === $family ) {
                            $activity_proof_items[] = $activity_item;
                            continue;
                        }
                        $activity_primary_items[] = $activity_item;
                    }
                    if ( empty( $activity_featured_item ) && ! empty( $activity_items ) && is_array( $activity_items[0] ) ) {
                        $activity_featured_item = $activity_items[0];
                    }
                    $activity_focus_label = ! empty( $activity_featured_item ) && isset( $activity_featured_item['label'] )
                        ? (string) $activity_featured_item['label']
                        : $activity_latest_label;
                    ?>
                    <div class="opsgate-card opsgate-activity-dashboard">
                        <div class="opsgate-activity-header">
                            <div class="opsgate-activity-header-copy">
                                <h2 class="opsgate-activity-title">Activity</h2>
                                <p class="opsgate-activity-subtitle">Operational timeline, recent deliveries, and activity history for this site.</p>
                                <p class="opsgate-alerts-history-copy"><?php echo esc_html( $activity_connection_label . ' · ' . $activity_connection_copy ); ?></p>
                            </div>
                            <div class="opsgate-activity-actions">
                                <a class="button button-secondary opsgate-activity-action-link" href="<?php echo esc_url( $activity_refresh_url ); ?>">Refresh activity</a>
                            </div>
                        </div>

                        <div class="opsgate-activity-status-strip">
                            <div class="opsgate-activity-status-item"><span class="opsgate-activity-status-label">Scans</span><span class="opsgate-activity-status-value"><?php echo esc_html( (string) $activity_scan_count ); ?></span></div>
                            <div class="opsgate-activity-status-item"><span class="opsgate-activity-status-label">Reports</span><span class="opsgate-activity-status-value"><?php echo esc_html( (string) $activity_report_count ); ?></span></div>
                            <div class="opsgate-activity-status-item"><span class="opsgate-activity-status-label">Alerts</span><span class="opsgate-activity-status-value"><?php echo esc_html( (string) $activity_alert_count ); ?></span></div>
                            <div class="opsgate-activity-status-item"><span class="opsgate-activity-status-label">Last event</span><span class="opsgate-activity-status-value"><?php echo esc_html( $activity_latest_when ); ?></span></div>
                        </div>

                        <div class="opsgate-filter-bar" id="opsgate-activity-filter-bar" role="toolbar" aria-label="Filter activity">
                            <button type="button" class="opsgate-filter-btn is-active" data-og-filter="all">All</button>
                            <button type="button" class="opsgate-filter-btn" data-og-filter="triage">Scans</button>
                            <button type="button" class="opsgate-filter-btn" data-og-filter="alert">Alerts</button>
                            <button type="button" class="opsgate-filter-btn" data-og-filter="report">Reports</button>
                            <button type="button" class="opsgate-filter-btn" data-og-filter="delivery">Delivery</button>
                            <button type="button" class="opsgate-filter-btn" data-og-filter="uptime">Uptime</button>
                            <button type="button" class="opsgate-filter-btn" data-og-filter="vulnerability">Vulnerabilities</button>
                            <button type="button" class="opsgate-filter-btn" data-og-filter="remediation">Remediation</button>
                            <button type="button" class="opsgate-filter-btn" data-og-filter="configuration">Configuration</button>
                            <button type="button" class="opsgate-filter-btn" data-og-filter="proof">Connection</button>
                            <button type="button" class="opsgate-filter-btn" data-og-filter="system">System</button>
                        </div>

                        <div class="opsgate-activity-summary-grid">
                            <article class="opsgate-activity-summary-card">
                                <span class="opsgate-activity-status-label">Reports generated</span>
                                <div class="opsgate-activity-status-value"><?php echo esc_html( (string) $activity_report_count ); ?></div>
                            </article>
                            <article class="opsgate-activity-summary-card">
                                <span class="opsgate-activity-status-label">Configuration checks</span>
                                <div class="opsgate-activity-status-value"><?php echo esc_html( (string) $activity_validation_count ); ?></div>
                            </article>
                        </div>

                        <?php if ( empty( $activity_items ) ) : ?>
                            <div class="opsgate-activity-empty">
                                <strong>No activity has been recorded yet.</strong>
                                <p>Run a portfolio triage or generate a report to begin this feed.</p>
                            </div>
                        <?php else : ?>
                            <?php
                            $featured_badge = self::canonical_activity_status_badge( isset( $activity_featured_item['status'] ) ? (string) $activity_featured_item['status'] : '' );
                            $featured_family = $activity_event_family( $activity_featured_item );
                            $featured_tone = $activity_family_tone( $activity_featured_item, (string) $featured_badge['class'], $featured_family );
                            ?>
                            <article class="opsgate-activity-featured opsgate-activity-featured-family-<?php echo esc_attr( $featured_family ); ?> opsgate-activity-featured-tone-<?php echo esc_attr( $featured_tone ); ?>">
                                <div class="opsgate-activity-featured-top">
                                    <div class="opsgate-activity-featured-meta">
                                        <span class="opsgate-activity-eyebrow">Latest significant event</span>
                                        <h3 class="opsgate-activity-featured-title"><?php echo esc_html( isset( $activity_featured_item['label'] ) ? (string) $activity_featured_item['label'] : 'Activity event' ); ?></h3>
                                        <p class="opsgate-activity-featured-copy"><?php echo esc_html( isset( $activity_featured_item['details'] ) ? (string) $activity_featured_item['details'] : '—' ); ?></p>
                                    </div>
                                    <div class="opsgate-activity-featured-side">
                                        <span class="opsgate-activity-family-chip opsgate-activity-family-chip-<?php echo esc_attr( $featured_family ); ?>"><?php echo esc_html( $activity_family_label( $featured_family ) ); ?></span>
                                        <span class="opsgate-activity-item-stamp opsgate-activity-item-stamp-<?php echo esc_attr( $featured_badge['class'] ); ?>"><?php echo esc_html( $featured_badge['label'] ); ?></span>
                                    </div>
                                </div>
                                <div class="opsgate-activity-featured-bottom">
                                    <span class="opsgate-activity-featured-when"><?php echo esc_html( isset( $activity_featured_item['when'] ) ? (string) $activity_featured_item['when'] : '—' ); ?></span>
                                    <?php if ( ! empty( $activity_featured_item['supporting'] ) ) : ?>
                                        <span class="opsgate-activity-featured-supporting"><?php echo esc_html( (string) $activity_featured_item['supporting'] ); ?></span>
                                    <?php endif; ?>
                                </div>
                            </article>

                            <?php if ( count( $activity_items ) <= 5 ) : ?>
                            <div class="opsgate-activity-schedule-nudge">
                                <p>Set up a scan schedule to build your activity timeline.&nbsp;<a href="<?php echo esc_url( self::admin_tab_url( 'settings' ) . '&section=schedule' ); ?>">Go to Settings &rarr;</a></p>
                            </div>
                            <?php endif; ?>

                            <div class="opsgate-activity-feed" id="opsgate-activity-feed-list">
                                <?php
                                $activity_last_day_key = '';
                                foreach ( $activity_primary_items as $activity_item ) :
                                    $activity_badge = self::canonical_activity_status_badge( isset( $activity_item['status'] ) ? (string) $activity_item['status'] : '' );
                                    $activity_family = $activity_event_family( $activity_item );
                                    $activity_tone = $activity_family_tone( $activity_item, (string) $activity_badge['class'], $activity_family );
                                    $activity_when_raw = isset( $activity_item['when'] ) ? (string) $activity_item['when'] : '';
                                    $activity_day_key = '';
                                    if ( '' !== $activity_when_raw ) {
                                        $activity_day_key = preg_replace( '/\s+\d+:\d+.*$/', '', $activity_when_raw );
                                        if ( '' === $activity_day_key ) {
                                            $activity_day_key = $activity_when_raw;
                                        }
                                    }
                                    if ( '' !== $activity_day_key && $activity_day_key !== $activity_last_day_key ) :
                                        $activity_last_day_key = $activity_day_key;
                                    ?>
                                    <div class="opsgate-activity-day-group">
                                        <span class="opsgate-activity-day-label"><?php echo esc_html( $activity_day_key ); ?></span>
                                    </div>
                                    <?php endif; ?>
                                    <article class="opsgate-activity-item opsgate-activity-item-family-<?php echo esc_attr( $activity_family ); ?> opsgate-activity-item-tone-<?php echo esc_attr( $activity_tone ); ?>" data-og-family="<?php echo esc_attr( $activity_family ); ?>">
                                        <div class="opsgate-p5-event-icon family-<?php echo esc_attr( $activity_family ); ?>" aria-hidden="true"><?php echo esc_html( $activity_family_icon( $activity_family ) ); ?></div>
                                        <div class="opsgate-activity-item-head">
                                            <div class="opsgate-activity-item-meta">
                                                <span class="opsgate-activity-family-chip opsgate-activity-family-chip-<?php echo esc_attr( $activity_family ); ?>"><?php echo esc_html( $activity_family_label( $activity_family ) ); ?></span>
                                                <h3 class="opsgate-activity-item-label"><?php echo esc_html( isset( $activity_item['label'] ) ? (string) $activity_item['label'] : 'Activity event' ); ?></h3>
                                                <div class="opsgate-activity-item-when"><?php echo esc_html( isset( $activity_item['when'] ) ? (string) $activity_item['when'] : '—' ); ?></div>
                                            </div>
                                            <span class="opsgate-activity-item-stamp opsgate-activity-item-stamp-<?php echo esc_attr( $activity_badge['class'] ); ?>"><?php echo esc_html( $activity_badge['label'] ); ?></span>
                                        </div>
                                        <p class="opsgate-activity-item-details"><?php echo esc_html( isset( $activity_item['details'] ) ? (string) $activity_item['details'] : '—' ); ?></p>
                                        <?php if ( ! empty( $activity_item['supporting'] ) ) : ?>
                                            <div class="opsgate-activity-item-supporting"><?php echo esc_html( (string) $activity_item['supporting'] ); ?></div>
                                        <?php endif; ?>
                                        <?php
                                        $p5_detail_url = '';
                                        if ( 'triage' === $activity_family ) {
                                            $p5_detail_url = self::admin_tab_url( 'triage' );
                                        } elseif ( 'report' === $activity_family ) {
                                            $p5_detail_url = self::admin_tab_url( 'reports' );
                                        } elseif ( 'alert' === $activity_family || 'delivery' === $activity_family ) {
                                            $p5_detail_url = self::admin_tab_url( 'alerts' );
                                        } elseif ( 'connection' === $activity_family || 'proof' === $activity_family ) {
                                            $p5_detail_url = self::admin_tab_url( 'settings' );
                                        }
                                        if ( '' !== $p5_detail_url ) :
                                        ?>
                                        <a class="opsgate-p5-detail-link" href="<?php echo esc_url( $p5_detail_url ); ?>"><?php echo esc_html( 'triage' === $activity_family ? 'View triage' : ( 'report' === $activity_family ? 'View report' : ( in_array( $activity_family, array( 'alert', 'delivery' ), true ) ? 'View alert' : 'View event details' ) ) ); ?> →</a>
                                        <?php endif; ?>
                                    </article>
                                <?php endforeach; ?>
                            </div>

                            <div class="opsgate-activity-filter-empty" id="opsgate-activity-filter-empty" style="display:none;">
                                <p>No activity events match this filter. Select a different category or <button type="button" class="opsgate-filter-btn-inline" onclick="document.querySelector('#opsgate-activity-filter-bar [data-og-filter=all]').click()">view all events</button>.</p>
                            </div>

                            <?php if ( ! empty( $activity_proof_items ) ) : ?>
                                <section class="opsgate-activity-proof-block">
                                    <div class="opsgate-activity-surface-head">
                                        <h3 class="opsgate-activity-surface-title">Configuration checks</h3>
                                        <span class="opsgate-activity-surface-note">Recorded support proof</span>
                                    </div>
                                    <div class="opsgate-activity-feed opsgate-activity-feed-proof">
                                        <?php foreach ( $activity_proof_items as $activity_item ) : ?>
                                            <?php
                                            $activity_badge = self::canonical_activity_status_badge( isset( $activity_item['status'] ) ? (string) $activity_item['status'] : '' );
                                            $activity_family = 'proof';
                                            $activity_tone = $activity_family_tone( $activity_item, (string) $activity_badge['class'], $activity_family );
                                            ?>
                                            <article class="opsgate-activity-item opsgate-activity-item-proof opsgate-activity-item-tone-<?php echo esc_attr( $activity_tone ); ?>">
                                                <div class="opsgate-activity-item-head">
                                                    <div class="opsgate-activity-item-meta">
                                                        <span class="opsgate-activity-family-chip opsgate-activity-family-chip-proof">Configuration checks</span>
                                                        <h3 class="opsgate-activity-item-label"><?php echo esc_html( isset( $activity_item['label'] ) ? (string) $activity_item['label'] : 'Activity event' ); ?></h3>
                                                        <div class="opsgate-activity-item-when"><?php echo esc_html( isset( $activity_item['when'] ) ? (string) $activity_item['when'] : '—' ); ?></div>
                                                    </div>
                                                    <span class="opsgate-activity-item-stamp opsgate-activity-item-stamp-<?php echo esc_attr( $activity_badge['class'] ); ?>"><?php echo esc_html( $activity_badge['label'] ); ?></span>
                                                </div>
                                                <p class="opsgate-activity-item-details"><?php echo esc_html( isset( $activity_item['details'] ) ? (string) $activity_item['details'] : '—' ); ?></p>
                                                <?php if ( ! empty( $activity_item['supporting'] ) ) : ?>
                                                    <div class="opsgate-activity-item-supporting"><?php echo esc_html( (string) $activity_item['supporting'] ); ?></div>
                                                <?php endif; ?>
                                            </article>
                                        <?php endforeach; ?>
                                    </div>
                                </section>
                            <?php endif; ?>
                        <?php endif; ?>
                    </div>

                        <?php elseif ( 'security' === $active_tab ) : ?>
                    <?php self::render_security_panel(); ?>

                            <?php
                            if ( isset( $_GET['opsgate_audit_status'] ) ) :
                                $status  = sanitize_text_field( wp_unslash( $_GET['opsgate_audit_status'] ) );
                                $message = isset( $_GET['opsgate_audit_message'] )
                                    ? rawurldecode( (string) wp_unslash( $_GET['opsgate_audit_message'] ) )
                                    : '';
                                $class = ( 'success' === $status ) ? 'notice-success' : 'notice-error';
                                ?>
                                <div class="notice <?php echo esc_attr( $class ); ?> is-dismissible">
                                    <p><?php echo esc_html( $message ); ?></p>
                                </div>
                            <?php endif; ?>

                <?php if ( isset( $_GET['opsgate_malware_run'] ) ) : ?>
                    <?php
		    $m = sanitize_text_field( wp_unslash( $_GET['opsgate_malware_run'] ) );

                      if ( 'success' === $m ) :
                          ?>
                          <div class="notice notice-success is-dismissible">
                              <p><strong>&#10003;</strong> Quick Malware Check completed. Results were saved to your evidence history.</p>
                          </div>
                      <?php elseif ( 'warning' === $m ) : ?>
                          <div class="notice notice-warning is-dismissible">
                              <p><strong>!</strong> Attention: suspicious indicators were found. Review the evidence and investigate.</p>
                          </div>
                      <?php elseif ( 'info' === $m ) : ?>
                          <div class="notice notice-info is-dismissible">
                              <p>Quick Malware Check is not enabled yet. No scan was performed.</p>
                          </div>
                      <?php else : ?>
                          <div class="notice notice-error is-dismissible">
                              <p>Malware check could not be completed due to a runtime problem. Please try again.</p>
                          </div>
                      <?php endif; ?>


		<?php endif; ?>

		<?php
		$malware = get_option(
		    'opsgate_malware_last_result',
		    array(
		        'status'           => 'never',
		        'last_run_at_utc'   => '',
		        'files_checked'     => 0,
		        'suspicious_found'  => 0,
		        'notes'            => '',
		    )
		);

		$malware_status = is_array( $malware ) && isset( $malware['status'] ) ? (string) $malware['status'] : 'never';
		$malware_last   = is_array( $malware ) && isset( $malware['last_run_at_utc'] ) ? (string) $malware['last_run_at_utc'] : '';
		$malware_files  = (int) ( is_array( $malware ) ? ( $malware['files_checked'] ?? 0 ) : 0 );
		$malware_hits   = (int) ( is_array( $malware ) ? ( $malware['suspicious_found'] ?? 0 ) : 0 );

		$malware_badge_type = 'info';
		$malware_badge_text = 'Not yet';

		if ( 'ok' === $malware_status ) {
		    $malware_badge_type = 'ok';
		    $malware_badge_text = 'No issues found';
		} elseif ( 'attention' === $malware_status ) {
		    $malware_badge_type = 'warn';
		    $malware_badge_text = 'Review recommended';
		} elseif ( 'error' === $malware_status ) {
		    $malware_badge_type = 'err';
		    $malware_badge_text = 'Could not run';
		}
		?>

		<div class="opsgate-card" style="margin-top:12px;">
		    <h2><span class="dashicons dashicons-shield"></span> Malware Check</h2>
		    <p class="description">Checks your site for common indicators of compromise and suspicious code patterns. Results are saved to your evidence history.</p>

		    <div class="opsgate-badges-container" style="margin-top:10px;">
		        <?php
		        echo self::badge( 'Status', $malware_badge_text, $malware_badge_type );
		        $malware_last_display = 'Not yet';
			if ( '' !== $malware_last ) {
			    try {
			        $dt = new DateTimeImmutable( $malware_last, new DateTimeZone( 'UTC' ) );
			        $malware_last_display = $dt->format( 'M d, Y H:i' ) . ' UTC';
			    } catch ( Exception $e ) {
			        $malware_last_display = $malware_last; // Safe fallback.
			    }
			}
			echo self::badge( 'Last Run (UTC)', $malware_last_display, '' !== $malware_last ? 'ok' : 'info' );
		        echo self::badge( 'Files Checked', (string) $malware_files, 'info' );
		        echo self::badge( 'Findings', (string) $malware_hits, ( $malware_hits > 0 ) ? 'warn' : 'ok' );
		        ?>
		    </div>

		    <div style="margin-top:12px;">
		        <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:0;">
		            <input type="hidden" name="action" value="opsgate_run_malware_check" />
		            <?php wp_nonce_field( 'opsgate_run_malware_check', 'opsgate_malware_nonce' ); ?>
		            <button type="submit" class="button button-primary">Run Malware Check</button>
		        </form>
		    </div>
		</div>

                <div class="opsgate-card">
                    <h2><span class="dashicons dashicons-admin-tools"></span> Protections</h2>
                    <p class="description">Enable/disable services and set their subscription plans.</p>

                    <?php if ( empty( $services_settings ) ) : ?>
                        <div class="notice notice-info">
                            <p>No services are configured yet.</p>
                        </div>
                    <?php else : ?>
                        <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="opsgate-services-form">
                            <?php wp_nonce_field( 'opsgate_save_service_settings', 'opsgate_service_nonce' ); ?>
                            <input type="hidden" name="action" value="opsgate_save_service_settings" />

                            <div class="table-responsive">
                                <table class="wp-list-table widefat fixed striped table-view-list">
                                    <thead>
                                    <tr>
                                        <th scope="col" class="column-service">Service</th>
                                        <th scope="col" class="column-status">Status</th>
                                        <th scope="col" class-="column-plan">Plan</th>
                                        <th scope="col" class="column-last-audit">Last Scan</th>
                                    </tr>
                                    </thead>
                                    <tbody>
                                    <?php foreach ( $services_settings as $service_key => $service_settings ) : ?>
                                        <?php
                                        $enabled      = ! empty( $service_settings['enabled'] );
                                        $plan         = isset( $service_settings['plan'] ) ? $service_settings['plan'] : 'free';
                                        $last_scan_at = isset( $service_settings['last_scan_at'] ) ? $service_settings['last_scan_at'] : null;
                                        $last_output  = ( isset( $service_settings['last_output'] ) && is_array( $service_settings['last_output'] ) )
                                            ? $service_settings['last_output']
                                            : array( 'json' => null, 'csv' => null, 'pdf' => null );
                                        ?>
                                        <tr>
                                            <td class="column-service">
                                                <strong><?php echo esc_html( self::service_display_name( (string) $service_key ) ); ?></strong>
                                            </td>
                                            <td class="column-status">
                                                <label class="opsgate-toggle">
                                                    <input type="checkbox"
                                                           name="opsgate_services[<?php echo esc_attr( $service_key ); ?>][enabled]"
                                                           value="1"
                                                        <?php checked( $enabled, true ); ?> />
                                                    <span class="toggle-slider"></span>
                                                    <span class="toggle-label toggle-label-disabled">Disabled</span>
                                                    <span class="toggle-label toggle-label-enabled">Enabled</span>
                                                </label>
                                            </td>
                                            <td class="column-plan">
                                                <select name="opsgate_services[<?php echo esc_attr( $service_key ); ?>][plan]" class="opsgate-plan-select">
                                                    <?php foreach ( $allowed_plans as $plan_key ) : ?>
                                                        <option value="<?php echo esc_attr( $plan_key ); ?>"
                                                            <?php selected( $plan, $plan_key ); ?>
                                                                class="plan-<?php echo esc_attr( $plan_key ); ?>">
                                                            <?php echo esc_html( ucfirst( $plan_key ) ); ?>
                                                        </option>
                                                    <?php endforeach; ?>
                                                </select>
                                            </td>
                                            <td class="column-last-audit">
                                                <?php if ( $last_scan_at ) : ?>
                                                    <div class="last-scan-time">
                                                        <span class="dashicons dashicons-clock"></span>
                                                        <?php echo esc_html( $last_scan_at ); ?>
                                                    </div>
                                                    <div class="output-files">
                                                        <?php if ( ! empty( $last_output['json'] ) ) : ?>
                                                            <span class="file-badge json">JSON</span>
                                                        <?php endif; ?>
                                                        <?php if ( ! empty( $last_output['csv'] ) ) : ?>
                                                            <span class="file-badge csv">CSV</span>
                                                        <?php endif; ?>
                                                        <?php if ( ! empty( $last_output['pdf'] ) ) : ?>
                                                            <span class="file-badge pdf">PDF</span>
                                                        <?php endif; ?>
                                                    </div>
                                                <?php else : ?>
                                                    <span class="description">No scan recorded</span>
                                                <?php endif; ?>
                                            </td>
                                        </tr>
                                    <?php endforeach; ?>
                                    </tbody>
                                </table>
                            </div>

                            <div class="submit-box">
                                <?php submit_button( 'Save Service Settings', 'primary large', 'submit', false ); ?>
                            </div>
                        </form>
                    <?php endif; ?>
                </div>

                <?php if ( isset( $services_settings['wordpress_security_audit'] ) ) : ?>
                    <?php
                    $token_available = ( function_exists( 'opsgate_get_api_token' ) && opsgate_get_api_token() );

                    $get_running = ( isset( $_GET['opsgate_audit_running'] ) && '1' === sanitize_text_field( wp_unslash( $_GET['opsgate_audit_running'] ) ) );
                    $run_token   = isset( $_GET['opsgate_run_token'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_run_token'] ) ) : '';

                    $run_token_valid = false;
                    if ( $get_running && '' !== $run_token ) {
                        $run_token_valid = ( '1' === get_transient( 'opsgate_audit_run_token_' . $run_token ) );
                    }

                    $is_running = ( $token_available && $get_running && '' !== $run_token && $run_token_valid );
                    ?>
                    <div class="opsgate-card opsgate-audit-card">
                        <h2><span class="dashicons dashicons-update"></span> Run Security Check</h2>
                        <p>Run a security check for this site using your current configuration.</p>

                        <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="opsgate-audit-form">
                            <?php wp_nonce_field( 'opsgate_run_audit_prepare', 'opsgate_run_audit_prepare_nonce' ); ?>
                            <input type="hidden" name="action" value="opsgate_run_audit_prepare" />
                            <input type="hidden" name="service" value="wordpress_security_audit" />

                            <button type="submit"
                                    class="button button-secondary button-large opsgate-audit-button opsgate-audit-btn"
                                <?php echo ( $token_available && ! $is_running ) ? '' : 'disabled="disabled"'; ?>>
                                <span class="dashicons dashicons-play"></span>
                                <?php
                                echo $is_running ? esc_html__( 'Running…', 'opsgate' ) : esc_html__( 'Run Security Scan', 'opsgate' );
                                ?>
                            </button>

                            <?php if ( ! $token_available ) : ?>
                                <div class="notice notice-warning inline" style="margin-top: 15px;">
                                    <p><strong>Connection required:</strong> Complete setup in Settings to run security checks.</p>
                                </div>
                            <?php else : ?>
                                <p class="description" style="margin:8px 0 0 0;">Runs a full security scan and updates your latest report.</p>
                            <?php endif; ?>
                        </form>

                        <?php if ( $is_running ) : ?>
                            <?php
                            $exec_url = wp_nonce_url(
                                add_query_arg(
                                    array(
                                        'action'            => 'opsgate_run_audit_execute',
                                        'service' => 'wordpress_security_audit',
                                        'opsgate_run_token' => $run_token,
                                    ),
                                    admin_url( 'admin-post.php' )
                                ),
                                'opsgate_run_audit_execute'
                            );
                            ?>
                            <meta http-equiv="refresh" content="1;url=<?php echo esc_url( $exec_url ); ?>">
                        <?php endif; ?>
                    </div>
                <?php endif; ?>
                  <?php
                  // Day-18.1: .htaccess Hardening (Wordfence baseline)
                  $h_state   = self::htaccess_read_state();
                  $h_enabled = ( ! empty( $h_state['has_block'] ) );

                  $hardening_notice = isset( $_GET['opsgate_hardening'] )
                      ? sanitize_text_field( wp_unslash( $_GET['opsgate_hardening'] ) )
                      : '';

                  $hardening_history = get_option( 'opsgate_hardening_history', array() );
                  $hardening_last    = ( is_array( $hardening_history ) && ! empty( $hardening_history ) ) ? $hardening_history[0] : null;

                  $hardening_status_label = $h_enabled ? 'Applied' : 'Not Applied';
                  $hardening_status_type  = $h_enabled ? 'notice-success' : 'notice-warning';
                  ?>

                  <?php if ( 'applied' === $hardening_notice ) : ?>
                      <div class="notice notice-success is-dismissible"><p>Protection applied successfully.</p></div>
                  <?php elseif ( 'reverted' === $hardening_notice ) : ?>
                      <div class="notice notice-success is-dismissible"><p>Protection reverted successfully.</p></div>
                  <?php elseif ( 'error' === $hardening_notice ) : ?>
                      <div class="notice notice-error is-dismissible"><p>Protection could not be updated. Please review permissions and try again.</p></div>
                  <?php endif; ?>

                  <div class="opsgate-card" id="opsgate-hardening">
                      <h2><span class="dashicons dashicons-lock"></span> Hardening</h2>
                      <p class="opsgate-value-header">Reduce common file-based attacks by applying safe protections to your site.</p>

                      <div class="notice <?php echo esc_attr( $hardening_status_type ); ?>" style="margin-top:10px;">
                          <p><strong>Status:</strong> <?php echo esc_html( $hardening_status_label ); ?></p>
                      </div>

                      <p class="description" style="margin:10px 0 0 0;">
                          OpsGate applies a reversible protection block to <code>.htaccess</code>. You can apply or revert at any time.
                      </p>

                      <div style="display:flex;gap:10px;flex-wrap:wrap;margin-top:12px;">
                          <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:0;">
                              <?php wp_nonce_field( 'opsgate_htaccess_apply', 'opsgate_htaccess_apply_nonce' ); ?>
                              <input type="hidden" name="action" value="opsgate_htaccess_apply" />
                              <button type="submit" class="button button-primary button-large" <?php echo $h_enabled ? 'disabled="disabled"' : ''; ?>>
                                  <span class="dashicons dashicons-yes"></span>
                                  Apply Hardening
                              </button>
                          </form>

                          <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:0;">
                              <?php wp_nonce_field( 'opsgate_htaccess_revert', 'opsgate_htaccess_revert_nonce' ); ?>
                              <input type="hidden" name="action" value="opsgate_htaccess_revert" />
                              <button type="submit" class="button button-secondary button-large" <?php echo $h_enabled ? '' : 'disabled="disabled"'; ?>>
                                  <span class="dashicons dashicons-undo"></span>
                                  Revert Hardening
                              </button>
                          </form>
                      </div>

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

                      <h3 style="margin-top:0;">Evidence</h3>

                      <?php if ( is_array( $hardening_last ) ) : ?>
                          <p style="margin:6px 0 0 0;">
                              <strong>Last change:</strong>
                              <?php echo esc_html( date_i18n( 'Y-m-d H:i:s', (int) ( $hardening_last['ts'] ?? 0 ) ) ); ?>
                              &nbsp;·&nbsp;
                              <strong>Action:</strong> <?php echo esc_html( (string) ( $hardening_last['action'] ?? '—' ) ); ?>
                              &nbsp;·&nbsp;
                              <strong>Result:</strong> <?php echo esc_html( (string) ( $hardening_last['status'] ?? '—' ) ); ?>
                          </p>

                          <p style="margin:10px 0 0 0;">
                              <?php
                              $pdf_file = isset( $hardening_last['pdf_file'] ) ? (string) $hardening_last['pdf_file'] : '';
                              $csv_file = isset( $hardening_last['csv_file'] ) ? (string) $hardening_last['csv_file'] : '';
                              $json_file = isset( $hardening_last['json_file'] ) ? (string) $hardening_last['json_file'] : '';

                              if ( '' !== $pdf_file ) {
                                  $pdf_url = wp_nonce_url(
                                      admin_url( 'admin-post.php?action=opsgate_htaccess_download_pdf&file=' . rawurlencode( $pdf_file ) ),
                                      'opsgate_htaccess_download_pdf'
                                  );
                                  echo '<a class="button button-small" href="' . esc_url( $pdf_url ) . '">Download PDF</a> ';
                              }

                              if ( '' !== $csv_file ) {
                                  $csv_url = wp_nonce_url(
                                      admin_url( 'admin-post.php?action=opsgate_htaccess_download_evidence&file=' . rawurlencode( $csv_file ) ),
                                      'opsgate_htaccess_download_evidence'
                                  );
                                  echo '<a class="button button-small" href="' . esc_url( $csv_url ) . '">Download CSV</a> ';
                              }

                              if ( '' !== $json_file ) {
                                  $json_url = wp_nonce_url(
                                      admin_url( 'admin-post.php?action=opsgate_htaccess_download_evidence&file=' . rawurlencode( $json_file ) ),
                                      'opsgate_htaccess_download_evidence'
                                  );
                                  echo '<a class="button button-small" href="' . esc_url( $json_url ) . '">Download JSON</a>';
                              }
			      // Excel (XLSX) — only show if we have a real file.
			      $xlsx_file = isset( $hardening_last['xlsx_file'] ) ? (string) $hardening_last['xlsx_file'] : '';

			      if ( '' !== $xlsx_file ) {
				  $xlsx_url = wp_nonce_url(
				      admin_url( 'admin-post.php?action=opsgate_htaccess_download_evidence&file=' . rawurlencode( $xlsx_file ) ),
				      'opsgate_htaccess_download_evidence'
				 );

				 echo ' <a class="button button-small" href="' . esc_url( $xlsx_url ) . '">Download Excel</a>';
			      }
                              ?>
                          </p>

                          <p class="description" style="margin-top:8px;">
                              These files are your proof: what was changed, when it was changed, and the before/after state.
                          </p>
                      <?php else : ?>
                          <p style="margin:6px 0 0 0;">No hardening evidence yet. Apply or revert once to generate your first proof files.</p>
                      <?php endif; ?>
                  </div>

		<?php
                $backup_history = get_option( 'opsgate_backup_history', array() );
                $last_backup    = ! empty( $backup_history ) ? $backup_history[0] : null;
                ?>

                <div class="opsgate-card" id="opsgate-backups">
                    <h2><span class="dashicons dashicons-database"></span> Backups</h2>
                    <p class="opsgate-value-header">Create a restore point you can download if something breaks.</p>

                    <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
                        <?php wp_nonce_field( 'opsgate_run_backup', 'opsgate_run_backup_nonce' ); ?>
                        <input type="hidden" name="action" value="opsgate_run_backup" />
                        <button type="submit" class="button button-primary button-large">
                            <span class="dashicons dashicons-backup"></span>
                            Run Backup
                        </button>
                    </form>

                    <hr />

                    <h3 style="margin-top:12px;">Evidence</h3>

                    <?php if ( $last_backup ) : ?>
                        <p><strong>Last backup:</strong> <?php echo esc_html( date_i18n( 'Y-m-d H:i:s', intval( $last_backup['ts'] ) ) ); ?></p>
                        <p><strong>Status:</strong> <?php echo esc_html( $last_backup['status'] ); ?></p>
                        <?php if ( ! empty( $last_backup['summary'] ) ) : ?>
                            <p><strong>Summary:</strong> <?php echo esc_html( $last_backup['summary'] ); ?></p>
                        <?php endif; ?>
                    <?php else : ?>
                        <p><strong>Last backup:</strong> None yet</p>
                    <?php endif; ?>

                    <?php if ( ! empty( $backup_history ) ) : ?>
                        <h3 style="margin-top:12px;">Backup history</h3>
                        <table class="widefat striped">
                            <thead>
                            <tr>
                                <th>Time</th>
                                <th>Status</th>
                                <th>Size</th>
                                <th>Download</th>
                            </tr>
                            </thead>
                            <tbody>
                            <?php foreach ( $backup_history as $row ) : ?>
                                <tr>
                                    <td><?php echo esc_html( date_i18n( 'Y-m-d H:i:s', intval( $row['ts'] ) ) ); ?></td>
                                    <td><?php echo esc_html( $row['status'] ); ?></td>
                                    <td><?php echo esc_html( ! empty( $row['size_h'] ) ? $row['size_h'] : '—' ); ?></td>
                                    <td>
                                        <?php if ( ! empty( $row['file'] ) ) : ?>
                                            <?php
                                            $dl_url = wp_nonce_url(
                                                admin_url( 'admin-post.php?action=opsgate_download_backup&file=' . rawurlencode( $row['file'] ) ),
                                                'opsgate_download_backup'
                                            );
                                            ?>
                                            <a class="button button-small" href="<?php echo esc_url( $dl_url ); ?>">Download</a>
                                        <?php else : ?>
                                            —
                                        <?php endif; ?>
                                    </td>
                                </tr>
                            <?php endforeach; ?>
                            </tbody>
                        </table>
                    <?php endif; ?>
                </div>


                <?php elseif ( 'settings' === $active_tab ) : ?>
                <?php
                // Settings reads plan from effective state — no separate entitlement call.
                $ent_plan               = $eff_state['entitlement_snapshot'];
                $current_plan           = $eff_state['effective_plan'];
                $current_package        = self::current_package_entry();
                $allowed_modes_for_ui   = self::get_allowed_schedule_modes_for_current_plan();
                $current_package_name   = self::current_package_display_name();
                $settings_package_copy  = isset( $current_package['operational_value'] ) ? (string) $current_package['operational_value'] : 'Schedule options are based on your ' . ucfirst( self::normalize_plan( $current_plan ) ) . ' plan.';
                $days                   = array(
                    0 => 'Sunday',
                    1 => 'Monday',
                    2 => 'Tuesday',
                    3 => 'Wednesday',
                    4 => 'Thursday',
                    5 => 'Friday',
                    6 => 'Saturday',
                );
                $portfolio_schedule_row   = isset( $schedules_settings['portfolio_triage'] ) && is_array( $schedules_settings['portfolio_triage'] ) ? $schedules_settings['portfolio_triage'] : array();
                $schedule_product_state   = isset( $portfolio_schedule_row['product_state'] ) ? (string) $portfolio_schedule_row['product_state'] : '';
                $schedule_controls_locked = in_array( $schedule_product_state, array( 'locked_by_package', 'saved_but_locked' ), true );
                $scheduling_enabled       = ! $schedule_controls_locked && ! empty( $portfolio_schedule_row['mode'] ) && 'off' !== $portfolio_schedule_row['mode'];
                $schedule_controls_available = count( $allowed_modes_for_ui ) > 1;
                $schedule_can_write       = $schedule_controls_available && ! $schedule_controls_locked && ! empty( $schedules_settings );
                $automation_enabled_label = $scheduling_enabled ? 'Enabled' : 'Disabled';
                $allowed_label            = implode( ', ', array_map( 'ucfirst', $allowed_modes_for_ui ) );
                $selected_mode            = isset( $portfolio_schedule_row['mode'] ) ? (string) $portfolio_schedule_row['mode'] : 'off';
                $selected_time            = isset( $portfolio_schedule_row['time'] ) ? (string) $portfolio_schedule_row['time'] : '02:00';
                $selected_dow             = isset( $portfolio_schedule_row['dow'] ) ? (string) $portfolio_schedule_row['dow'] : '';
                $selected_dom             = isset( $portfolio_schedule_row['dom'] ) ? (string) $portfolio_schedule_row['dom'] : '';
                $schedule_mode_story      = self::schedule_mode_story( $allowed_modes_for_ui, $selected_mode, $scheduling_enabled );
                $schedule_state_label     = self::schedule_state_label( $portfolio_schedule_row );
                $schedule_state_summary   = self::schedule_state_summary_copy( $portfolio_schedule_row );
                $saved_history_copy       = $schedule_state_summary;
                if ( ! empty( $portfolio_schedule_row['has_saved_schedule'] ) && in_array( $schedule_product_state, array( 'locked_by_package', 'saved_but_locked' ), true ) ) {
                    $saved_history_copy = 'Saved daily schedule exists, but it is not active on this package.';
                }
                $managed_by_label         = 'Managed by OpsGate';
                $saved_schedule_label     = self::schedule_configured_text_utc( $portfolio_schedule_row, $days );
                $saved_schedule_updated_value = isset( $portfolio_schedule_row['updated_at_utc'] ) ? trim( (string) $portfolio_schedule_row['updated_at_utc'] ) : '';
                $saved_schedule_updated_label = '' !== $saved_schedule_updated_value ? self::canonical_report_datetime_label( $saved_schedule_updated_value ) : 'No saved schedule timestamp yet';
                $saved_schedule_readback_copy = '' !== $saved_schedule_updated_value
                    ? 'Saved in OpsGate at ' . $saved_schedule_updated_label . '.'
                    : 'Schedule history is synced from your OpsGate account after refresh.';
                $next_due_value           = isset( $portfolio_schedule_row['due_at_utc'] ) ? trim( (string) $portfolio_schedule_row['due_at_utc'] ) : '';
                $last_evaluated_value     = isset( $portfolio_schedule_row['last_evaluated_at'] ) ? trim( (string) $portfolio_schedule_row['last_evaluated_at'] ) : '';
                $next_due_label           = 'Next run will appear when this schedule is enabled.';
                $next_due_note            = 'Next run will appear when this schedule is enabled.';
                if ( '' !== $next_due_value ) {
                    $next_due_label = self::schedule_datetime_label( $next_due_value, $portfolio_schedule_row );
                    $next_due_note  = 'Next due run from the current managed schedule.';
                } elseif ( $scheduling_enabled && '' !== $last_evaluated_value ) {
                    $next_due_label = 'Schedule is active';
                    $next_due_note  = 'Last evaluated by OpsGate schedule processing: ' . self::schedule_datetime_label( $last_evaluated_value, $portfolio_schedule_row ) . '.';
                } elseif ( $scheduling_enabled ) {
                    $next_due_label = 'Schedule is active';
                    $next_due_note  = 'OpsGate is evaluating the current schedule window.';
                }
                $schedule_read_write_state = $schedule_can_write ? 'Editable' : 'Read-only';
                if ( ! $schedule_controls_available ) {
                    $schedule_read_write_state = 'Locked';
                } elseif ( $schedule_controls_locked ) {
                    $schedule_read_write_state = 'Locked';
                }
                $schedule_lock_reason = '';
                if ( ! $schedule_controls_available ) {
                    $schedule_lock_reason = 'Recurring automation is not available on the current package.';
                } elseif ( $schedule_controls_locked ) {
                    $schedule_lock_reason = 'Saved schedule history is visible, but this package does not keep it active.';
                }
                $site_identity            = self::get_identity_snapshot();
                $settings_site_config     = self::canonical_site_config();
                $settings_site_config_item = ! empty( $settings_site_config['ok'] ) && isset( $settings_site_config['item'] ) && is_array( $settings_site_config['item'] ) ? $settings_site_config['item'] : array();
                $settings_selected_site   = self::current_selected_site_summary();
                $settings_account_id_value = trim( (string) get_option( 'opsgate_account_id', '' ) );
                $settings_api_base_url_value = trim( (string) get_option( 'opsgate_api_base_url', '' ) );
                $settings_api_token_value = trim( (string) get_option( 'opsgate_inbound_token', '' ) );
                $site_url_value           = isset( $settings_selected_site['site_url'] ) ? (string) $settings_selected_site['site_url'] : '';
                $site_label_value         = isset( $settings_selected_site['site_label'] ) ? (string) $settings_selected_site['site_label'] : '';
                $identity_email_value     = isset( $settings_selected_site['contact_email'] ) ? (string) $settings_selected_site['contact_email'] : '';
                $settings_primary_email   = isset( $settings_site_config_item['primary_email_destination'] ) && is_array( $settings_site_config_item['primary_email_destination'] ) ? $settings_site_config_item['primary_email_destination'] : array();
                $settings_primary_webhook = isset( $settings_site_config_item['primary_webhook_destination'] ) && is_array( $settings_site_config_item['primary_webhook_destination'] ) ? $settings_site_config_item['primary_webhook_destination'] : array();
                $settings_family_context_copy = self::alerts_full_family_creation_enabled()
                    ? 'Broader alert-family routing is available in Alerts.'
                    : 'Email and webhook routing for this site is managed in Alerts.';
                $telemetry_enabled_cfg    = ( '1' === get_option( 'opsgate_telemetry_enabled', '0' ) );
                $telemetry_enabled_label  = $telemetry_enabled_cfg ? 'Enabled' : 'Disabled';
                $activity_dashboard_copy  = $telemetry_enabled_cfg
                    ? 'Local activity log records what ran, what reports were generated, and what alerts were delivered.'
                    : 'Local activity logging is turned off for this installation.';
                $connection_status_value  = isset( $settings_selected_site['connection_status'] ) ? (string) $settings_selected_site['connection_status'] : 'external_only';
                $connection_mode_value    = isset( $settings_selected_site['connection_mode'] ) ? (string) $settings_selected_site['connection_mode'] : 'public_scan';
                $connector_credential_present = '' !== self::connector_site_credential();
                $connector_installation_id_value = self::connector_installation_id();
                $connection_scope_label   = ucfirst( str_replace( '_', ' ', $connection_status_value ) );
                $connection_scope_copy    = 'Canonical site connection truth is being read from the OpsGate API.';
                if ( 'external_only' === $connection_status_value ) {
                    $connection_scope_copy = 'This site is external-only. OpsGate runs public checks only until a connector is paired.';
                } elseif ( 'pairing_pending' === $connection_status_value ) {
                    $connection_scope_copy = 'Pairing material issued. Complete the handshake from the remote plugin to activate the connector.';
                } elseif ( 'connected' === $connection_status_value ) {
                    $connection_scope_copy = 'Site verified and linked to OpsGate. Connected triage is active through the WordPress connector.';
                } elseif ( 'credential_invalid' === $connection_status_value ) {
                    $connection_scope_copy = 'The last connector handshake failed credential validation. Rotate or reconnect the site credential.';
                } elseif ( 'disconnected' === $connection_status_value ) {
                    $connection_scope_copy = 'The connector credential was revoked or the site was intentionally disconnected.';
                }
                $connection_proof_label   = $connector_credential_present ? 'Credential present' : 'No active credential';
                $connection_proof_copy    = $connector_credential_present
                    ? 'A site-scoped connector credential is stored locally for this installation.'
                    : 'No active connector credential is stored on this installation.';
                $settings_inbound_token_value = trim( (string) get_option( 'opsgate_inbound_token', '' ) );
                $settings_site_token_value    = trim( (string) get_option( 'opsgate_site_token', '' ) );
                $settings_site_id_value       = trim( (string) get_option( 'opsgate_site_id', '' ) );
                $settings_portfolio_id_value  = trim( (string) get_option( 'opsgate_portfolio_id', 'portfolio_default' ) );
                $settings_inbound_token_copy  = '' !== $settings_inbound_token_value ? 'Used by approved inbound automation requests.' : 'No inbound automation key is stored for this site yet.';
                $settings_site_token_copy     = '' !== $settings_site_token_value ? 'Legacy local token retained for support only. It is not the live connector credential.' : 'No legacy local token is stored for this installation.';
                $settings_site_id_copy        = '' !== $settings_site_id_value ? 'Local installation identity used only when this WordPress host itself is the selected site.' : 'No local installation site ID is stored yet.';
                $settings_portfolio_id_copy   = '' !== $settings_portfolio_id_value ? 'Internal portfolio assignment identifier.' : 'No portfolio assignment is stored yet.';
                $support_export_ready         = class_exists( 'ZipArchive' );
                $settings_selected_is_local   = self::scope_targets_local_wordpress( $site_url_value );
                $settings_requested_section = isset( $_GET['section'] ) ? sanitize_key( wp_unslash( $_GET['section'] ) ) : '';
                $settings_requested_panel = isset( $_GET['panel'] ) ? sanitize_key( wp_unslash( $_GET['panel'] ) ) : '';
                // When arriving via an onboarding session, the resolved scope carries the requested
                // section and panel — promote them if GET params are absent.
                if ( '' === $settings_requested_section && isset( $requested_scope['requested_section'] ) && '' !== (string) $requested_scope['requested_section'] ) {
                    $settings_requested_section = sanitize_key( (string) $requested_scope['requested_section'] );
                }
                if ( '' === $settings_requested_panel && isset( $requested_scope['requested_panel'] ) && '' !== (string) $requested_scope['requested_panel'] ) {
                    $settings_requested_panel = sanitize_key( (string) $requested_scope['requested_panel'] );
                }
                $settings_focus_site_configuration = 'site-configuration' === $settings_requested_section;
                $settings_focus_pairing_material = $settings_focus_site_configuration && in_array( $settings_requested_panel, array( 'pairing-material', 'pairing_material' ), true );
                $settings_requested_source = isset( $_GET['opsgate_source'] ) ? sanitize_key( wp_unslash( $_GET['opsgate_source'] ) ) : '';
                $settings_requested_site_id = isset( $_GET['opsgate_scope_site_id'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_scope_site_id'] ) ) : '';
                $settings_requested_site_url = isset( $_GET['opsgate_prefill_site_url'] ) ? esc_url_raw( wp_unslash( $_GET['opsgate_prefill_site_url'] ) ) : ( isset( $_GET['opsgate_scope_site_url'] ) ? esc_url_raw( wp_unslash( $_GET['opsgate_scope_site_url'] ) ) : '' );
                $settings_requested_site_label = isset( $_GET['opsgate_prefill_site_label'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_prefill_site_label'] ) ) : ( isset( $_GET['opsgate_scope_site_label'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_scope_site_label'] ) ) : '' );
                $settings_onboarding_session_url   = isset( $requested_scope['site_url'] ) ? trim( (string) $requested_scope['site_url'] ) : '';
                $settings_onboarding_session_label = isset( $requested_scope['site_label'] ) ? trim( (string) $requested_scope['site_label'] ) : '';
                $settings_onboarding_session_id_val     = isset( $requested_scope['onboarding_session_id'] ) ? trim( (string) $requested_scope['onboarding_session_id'] ) : '';
                $settings_onboarding_token_val          = isset( $requested_scope['onboarding_token'] ) ? trim( (string) $requested_scope['onboarding_token'] ) : '';
                $settings_onboarding_intended_action    = isset( $requested_scope['intended_action'] ) ? trim( (string) $requested_scope['intended_action'] ) : '';

                $settings_remote_onboarding_prefill = $settings_focus_site_configuration
                    && 'remote-onboarding' === $settings_requested_source
                    && '' === $settings_requested_site_id
                    && '' !== $settings_requested_site_url;
                // Also prefill from a resolved onboarding session when the API-issued handoff URL
                // carries session credentials instead of plain query-param scope values.
                if ( ! $settings_remote_onboarding_prefill
                    && $settings_focus_site_configuration
                    && 'onboarding_session' === ( isset( $requested_scope['resolution_kind'] ) ? (string) $requested_scope['resolution_kind'] : '' )
                    && '' !== $settings_onboarding_session_url
                ) {
                    $settings_remote_onboarding_prefill = true;
                    $settings_requested_site_url   = $settings_onboarding_session_url;
                    $settings_requested_site_label = $settings_onboarding_session_label;
                }
                if ( $settings_remote_onboarding_prefill ) {
                    $site_url_value = $settings_requested_site_url;
                    if ( '' !== $settings_requested_site_label ) {
                        $site_label_value = $settings_requested_site_label;
                    }
                    $settings_selected_is_local = self::scope_targets_local_wordpress( $site_url_value );
                }
                if ( ! $settings_selected_is_local ) {
                    $connection_proof_label = 'Remote scope';
                    $connection_proof_copy  = 'This selected canonical site is remote. Pairing and credential storage must happen from the plugin installed on that WordPress host.';
                }
                $pairing_material_summary = self::pairing_material_scope_summary();
                $connector_pairing_token_value = isset( $pairing_material_summary['pairing_token'] ) ? (string) $pairing_material_summary['pairing_token'] : '';
                ?>

                <nav class="opsgate-settings-subnav" role="tablist" aria-label="Settings sections">
                    <button type="button" class="opsgate-settings-subnav-btn is-active" data-og-settings-tab="schedule" role="tab" aria-selected="true">Schedule</button>
                    <button type="button" class="opsgate-settings-subnav-btn" data-og-settings-tab="site" role="tab" aria-selected="false">Site<?php if ( 'agency' === self::normalize_plan( $current_plan ) ) { echo ' &amp; Branding'; } ?></button>
                    <?php if ( $settings_show_manage_connector ) : ?>
                    <button type="button" class="opsgate-settings-subnav-btn" data-og-settings-tab="connector" role="tab" aria-selected="false">Connector</button>
                    <?php endif; ?>
                </nav>

                <div class="opsgate-settings-zone-a-heading">Site configuration &amp; schedule</div>

                <div class="opsgate-card opsgate-settings-dashboard" data-og-settings-panel="schedule">
                    <h2><span class="dashicons dashicons-calendar"></span> Schedule Configuration</h2>
                    <p class="description">Configure recurring security scans for this site.</p>

                    <?php if ( isset( $_GET['opsgate_notice'] ) && 'schedule_saved' === (string) $_GET['opsgate_notice'] ) : // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?>
                        <div class="opsgate-alert-inline-status is-visible is-success" data-opsgate-transient-status="1" style="margin-top:12px;">
                            <p><?php echo esc_html( 'Managed schedule saved in OpsGate. ' . $saved_schedule_label . '. ' . ( '' !== $next_due_value ? 'Next due ' . $next_due_label . '.' : $saved_schedule_readback_copy ) ); ?></p>
                        </div>
                    <?php elseif ( isset( $_GET['opsgate_notice'] ) && 'schedule_save_failed' === (string) $_GET['opsgate_notice'] ) : // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?>
                        <div class="opsgate-alert-inline-status is-visible is-error" data-opsgate-transient-status="1" style="margin-top:12px;">
                            <?php $schedule_save_error = isset( $_GET['opsgate_notice_detail'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_notice_detail'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?>
                            <p><?php echo esc_html( '' !== $schedule_save_error ? 'Managed schedule could not be saved right now: ' . $schedule_save_error : 'Managed schedule could not be saved right now.' ); ?></p>
                        </div>
                    <?php endif; ?>

                    <div class="opsgate-settings-schedule-hero">
                        <article class="opsgate-settings-module opsgate-settings-module-primary">
                            <span class="opsgate-overview-eyebrow">Current schedule</span>
                            <div class="opsgate-pricing-hero-side-title" id="opsgate-current-schedule-label"><?php echo esc_html( $saved_schedule_label ); ?></div>
                            <p id="opsgate-schedule-hero-copy"><?php echo esc_html( $schedule_state_label ); ?></p>
                            <div class="opsgate-overview-pill-row">
                                <span class="opsgate-overview-pill opsgate-overview-pill-soft-info"><?php echo esc_html( $current_package_name ); ?></span>
                                <span id="opsgate-schedule-automation-pill" class="opsgate-overview-pill opsgate-overview-pill-soft-<?php echo esc_attr( $scheduling_enabled ? 'good' : 'warn' ); ?>"><?php echo esc_html( $automation_enabled_label ); ?></span>
                                <span class="opsgate-overview-pill opsgate-overview-pill-soft-<?php echo esc_attr( ! $schedule_controls_available ? 'warn' : ( $schedule_can_write ? 'good' : 'info' ) ); ?>"><?php echo esc_html( $schedule_read_write_state ); ?></span>
                            </div>
                        </article>
                        <aside class="opsgate-settings-module opsgate-settings-module-side">
                            <div class="opsgate-settings-inline-stat">
                                <span class="opsgate-overview-eyebrow">Next due</span>
                                <div class="opsgate-pricing-hero-side-title"><?php echo esc_html( $next_due_label ); ?></div>
                                <p><?php echo esc_html( $next_due_note ); ?></p>
                            </div>
                            <div class="opsgate-settings-inline-stat">
                                <span class="opsgate-overview-eyebrow">Last saved (Eastern)</span>
                                <div class="opsgate-pricing-hero-side-title"><?php echo esc_html( $saved_schedule_updated_label ); ?></div>
                                <p><?php echo esc_html( $saved_schedule_readback_copy ); ?></p>
                            </div>
                        </aside>
                    </div>

                    <div class="opsgate-settings-mode-grid">
                        <?php foreach ( $schedule_mode_story as $schedule_mode_card ) : ?>
                            <?php if ( ! is_array( $schedule_mode_card ) ) { continue; } ?>
                            <?php
                            $schedule_mode_state = isset( $schedule_mode_card['state'] ) ? (string) $schedule_mode_card['state'] : '';
                            $schedule_mode_tone = 'info';
                            if ( 'current_mode' === $schedule_mode_state ) {
                                $schedule_mode_tone = 'good';
                            } elseif ( 'visible_locked' === $schedule_mode_state || 'locked' === $schedule_mode_state ) {
                                $schedule_mode_tone = 'warn';
                            }
                            ?>
                            <article class="opsgate-settings-mode-card opsgate-settings-mode-card-<?php echo esc_attr( $schedule_mode_tone ); ?>">
                                <div class="opsgate-settings-mode-card-head">
                                    <span class="opsgate-overview-eyebrow"><?php echo esc_html( $schedule_mode_card['label'] ?? 'Schedule mode' ); ?></span>
                                    <span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( $schedule_mode_tone ); ?>"><?php echo esc_html( self::package_visibility_state_label( $schedule_mode_state ) ); ?></span>
                                </div>
                                <div class="opsgate-settings-mode-card-title"><?php echo esc_html( $schedule_mode_card['label'] ?? 'Schedule mode' ); ?></div>
                                <p><?php echo esc_html( $schedule_mode_card['summary'] ?? '' ); ?></p>
                            </article>
                        <?php endforeach; ?>
                    </div>

                    <?php if ( ! $canonical_schedule_ok && '' !== $canonical_schedule_error ) : ?>
                        <div class="opsgate-alert-panel opsgate-alert-panel-error" style="margin-bottom:18px;">
                            <p><?php echo esc_html( $canonical_schedule_error ); ?></p>
                        </div>
                    <?php endif; ?>

                    <?php if ( empty( $schedules_settings ) ) : ?>
                        <div class="opsgate-alert-panel">
                            <p>No recurring scan is scheduled yet. Choose a schedule mode to enable recurring checks.</p>
                        </div>
                    <?php endif; ?>

                    <div class="opsgate-settings-compact-strip">
                        <article class="opsgate-settings-compact-tile">
                            <span class="opsgate-overview-eyebrow">Package</span>
                            <div class="opsgate-settings-value-compact"><?php echo esc_html( $current_package_name ); ?></div>
                            <p><?php echo esc_html( $settings_package_copy ); ?></p>
                        </article>
                        <article class="opsgate-settings-compact-tile">
                            <span class="opsgate-overview-eyebrow">Saved schedule history</span>
                            <div class="opsgate-settings-value-compact"><?php echo esc_html( $saved_history_copy ); ?></div>
                            <p>Previous schedule history is available in your OpsGate account.</p>
                        </article>
                        <article class="opsgate-settings-compact-tile">
                            <span class="opsgate-overview-eyebrow">Managed by</span>
                            <div class="opsgate-settings-value-compact"><?php echo esc_html( $managed_by_label ); ?></div>
                            <p>Schedule settings are synced with your OpsGate account.</p>
                        </article>
                        <article class="opsgate-settings-compact-tile">
                            <span class="opsgate-overview-eyebrow">Schedule access</span>
                            <div class="opsgate-settings-value-compact"><?php echo esc_html( $schedule_read_write_state ); ?></div>
                            <p><?php echo esc_html( '' !== $schedule_lock_reason ? $schedule_lock_reason : 'Current package rules allow schedule changes from this surface.' ); ?></p>
                        </article>
                    </div>

                    <?php if ( $schedule_controls_available ) : ?>
                        <form id="opsgate-schedule-form" method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="opsgate-settings-form opsgate-settings-form-spacing" data-opsgate-settings-form="schedule" data-editable="<?php echo esc_attr( $schedule_can_write ? '1' : '0' ); ?>">
                            <?php wp_nonce_field( 'opsgate_save_schedule_settings', 'opsgate_schedule_nonce' ); ?>
                            <input type="hidden" name="action" value="opsgate_save_schedule_settings" />
                            <div class="opsgate-settings-module">
                                <div class="opsgate-settings-module-head">
                                    <div>
                                        <strong>Managed schedule control</strong>
                                        <p class="description">Allowed modes on the current package: <?php echo esc_html( '' !== $allowed_label ? $allowed_label : 'Off' ); ?></p>
                                    </div>
                                    <span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( $schedule_can_write ? 'good' : 'info' ); ?>"><?php echo esc_html( $schedule_can_write ? 'Editable' : 'Read-only' ); ?></span>
                                </div>
                                <div class="opsgate-settings-toggle-block opsgate-settings-toggle-block-top">
                                    <span class="opsgate-overview-eyebrow">Automated checks</span>
                                    <div class="opsgate-settings-value" id="opsgate-schedule-automation-state"><?php echo esc_html( $automation_enabled_label ); ?></div>
                                    <label class="opsgate-switch" style="margin-top:10px;">
                                        <span class="description" style="margin:0;">Off</span>
                                        <span class="opsgate-switch-track">
                                            <input id="opsgate-scheduling-enabled" type="checkbox" name="opsgate_scheduling_enabled" value="1" <?php checked( true, $scheduling_enabled ); ?> <?php disabled( ! $schedule_can_write ); ?> />
                                            <span class="opsgate-slider"></span>
                                        </span>
                                        <span class="description" style="margin:0;">On</span>
                                    </label>
                                </div>
                                <div class="opsgate-settings-form-grid">
                                    <div>
                                        <label for="opsgate_schedule_mode"><strong>Schedule mode</strong></label>
                                        <select id="opsgate_schedule_mode" name="opsgate_schedules[portfolio_triage][mode]" class="regular-text" <?php disabled( ! $schedule_can_write ); ?>>
                                            <?php foreach ( array( 'off' => 'Off', 'daily' => 'Daily', 'weekly' => 'Weekly', 'monthly' => 'Monthly' ) as $mode_key => $mode_label ) : ?>
                                                <?php if ( 'off' !== $mode_key && ! in_array( $mode_key, $allowed_modes_for_ui, true ) ) { continue; } ?>
                                                <option value="<?php echo esc_attr( $mode_key ); ?>" <?php selected( $selected_mode, $mode_key ); ?>><?php echo esc_html( $mode_label ); ?></option>
                                            <?php endforeach; ?>
                                        </select>
                                    </div>
                                    <div>
                                        <label for="opsgate_schedule_time"><strong>Run time</strong></label>
                                        <input id="opsgate_schedule_time" type="time" class="regular-text" name="opsgate_schedules[portfolio_triage][time]" value="<?php echo esc_attr( $selected_time ); ?>" pattern="\d{2}:\d{2}" <?php disabled( ! $schedule_can_write ); ?> />
                                    </div>
                                    <div>
                                        <label for="opsgate_schedule_dow"><strong>Day of week</strong></label>
                                        <select id="opsgate_schedule_dow" name="opsgate_schedules[portfolio_triage][dow]" class="regular-text" <?php disabled( ! $schedule_can_write || 'weekly' !== $selected_mode ); ?>>
                                            <option value="">—</option>
                                            <?php foreach ( $days as $day_index => $day_label ) : ?>
                                                <option value="<?php echo esc_attr( $day_index ); ?>" <?php selected( $selected_dow, (string) $day_index ); ?>><?php echo esc_html( $day_label ); ?></option>
                                            <?php endforeach; ?>
                                        </select>
                                    </div>
                                    <div>
                                        <label for="opsgate_schedule_dom"><strong>Day of month</strong></label>
                                        <input id="opsgate_schedule_dom" type="number" class="regular-text" name="opsgate_schedules[portfolio_triage][dom]" value="<?php echo esc_attr( $selected_dom ); ?>" min="1" max="31" placeholder="—" <?php disabled( ! $schedule_can_write || 'monthly' !== $selected_mode ); ?> />
                                    </div>
                                </div>
                                <div class="opsgate-settings-inline-form opsgate-settings-inline-form-schedule">
                                    <p id="opsgate-schedule-save-note" class="opsgate-settings-inline-note"><?php echo esc_html( '' !== $schedule_lock_reason ? $schedule_lock_reason : 'Changes are saved to your OpsGate account.' ); ?></p>
                                    <div class="submit-box opsgate-settings-submit-box">
                                    <?php
                                    $save_schedule_attrs = array( 'id' => 'opsgate-save-schedule' );
                                    if ( ! $schedule_can_write ) {
                                        $save_schedule_attrs['disabled'] = 'disabled';
                                    }
                                    submit_button( 'Save schedule', 'primary large', 'submit', false, $save_schedule_attrs );
                                    if ( ! $schedule_can_write ) :
                                    ?>
                                        <span class="opsgate-p5-disabled-hint"><?php echo esc_html( '' !== $schedule_lock_reason ? $schedule_lock_reason : 'Set a schedule mode above to enable save.' ); ?></span>
                                    <?php endif; ?>
                                    </div>
                                </div>
                            </div>
                        </form>
                    <?php else : ?>
                        <div class="opsgate-settings-module">
                            <div class="opsgate-settings-module-head">
                                <div>
                                    <strong>Managed schedule control</strong>
                                    <p class="description"><?php echo esc_html( $schedule_lock_reason ); ?></p>
                                </div>
                                <span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-warn">Locked</span>
                            </div>
                            <div class="opsgate-settings-form-grid">
                                <div>
                                    <span class="opsgate-overview-eyebrow">Current schedule mode</span>
                                    <div class="opsgate-pricing-hero-side-title"><?php echo esc_html( ucfirst( $selected_mode ) ); ?></div>
                                </div>
                                <div>
                                    <span class="opsgate-overview-eyebrow">Saved schedule history</span>
                                    <div class="opsgate-pricing-hero-side-title"><?php echo esc_html( $saved_history_copy ); ?></div>
                                </div>
                                <div>
                                    <span class="opsgate-overview-eyebrow">Managed by</span>
                                    <div class="opsgate-pricing-hero-side-title">Managed by OpsGate</div>
                                </div>
                                <div>
                                    <span class="opsgate-overview-eyebrow">Next due</span>
                                    <div class="opsgate-pricing-hero-side-title"><?php echo esc_html( $next_due_label ); ?></div>
                                </div>
                            </div>
                        </div>
                    <?php endif; ?>
                </div>

                <div id="opsgate-site-configuration-section" class="opsgate-card opsgate-pricing-dashboard" data-og-settings-panel="site">
                    <h2><span class="dashicons dashicons-admin-settings"></span> Site Configuration</h2>
                    <?php if ( $settings_focus_site_configuration ) : ?>
                        <div class="opsgate-alert-inline-status is-visible is-info" data-opsgate-transient-status="1" style="margin-top:12px;">
                            <p><?php echo esc_html( $settings_remote_onboarding_prefill ? 'Your WordPress site was detected. Save to register it with OpsGate, then create a connection code.' : 'Confirm the site details below and save to register this site with OpsGate.' ); ?></p>
                        </div>
                    <?php endif; ?>
                    <?php if ( isset( $_GET['opsgate_settings_saved'] ) && '1' === (string) $_GET['opsgate_settings_saved'] ) : // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?>
                        <div class="opsgate-alert-inline-status is-visible is-success" data-opsgate-transient-status="1" style="margin-top:12px;">
                            <p>Site configuration saved.</p>
                        </div>
                    <?php endif; ?>
                    <?php if ( isset( $_GET['opsgate_settings_error'] ) && '' !== (string) $_GET['opsgate_settings_error'] ) : // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?>
                        <div class="opsgate-alert-inline-status is-visible is-error" data-opsgate-transient-status="1" style="margin-top:12px;">
                            <p><?php echo esc_html( sanitize_text_field( rawurldecode( (string) wp_unslash( $_GET['opsgate_settings_error'] ) ) ) ); ?></p>
                        </div>
                    <?php endif; ?>

                    <form id="opsgate-site-config-form" method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="opsgate-settings-form opsgate-settings-form-spacing" data-opsgate-settings-form="site-config">
                        <?php wp_nonce_field( 'opsgate_save_configuration', 'opsgate_save_configuration_nonce' ); ?>
                        <input type="hidden" name="action" value="opsgate_save_configuration" />
                        <?php if ( '' !== $settings_onboarding_session_id_val ) : ?>
                        <input type="hidden" name="opsgate_onboarding_session_id" value="<?php echo esc_attr( $settings_onboarding_session_id_val ); ?>" />
                        <input type="hidden" name="opsgate_onboarding_token" value="<?php echo esc_attr( $settings_onboarding_token_val ); ?>" />
                        <input type="hidden" name="opsgate_intended_action" value="<?php echo esc_attr( $settings_onboarding_intended_action ); ?>" />
                        <input type="hidden" name="opsgate_requested_section" value="site-configuration" />
                        <input type="hidden" name="opsgate_requested_panel" value="pairing-material" />
                        <?php endif; ?>

                        <div class="opsgate-settings-site-grid">
                            <article class="opsgate-settings-module opsgate-settings-activity-card">
                                <div class="opsgate-settings-module-head">
                                    <div>
                                        <span class="opsgate-overview-eyebrow">Activity dashboard</span>
                                        <div class="opsgate-settings-value" id="opsgate-activity-dashboard-state"><?php echo esc_html( $telemetry_enabled_label ); ?></div>
                                        <p id="opsgate-activity-dashboard-copy"><?php echo esc_html( $activity_dashboard_copy ); ?></p>
                                    </div>
                                    <span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( $telemetry_enabled_cfg ? 'good' : 'neutral' ); ?>" id="opsgate-activity-dashboard-chip"><?php echo esc_html( $telemetry_enabled_label ); ?></span>
                                </div>
                                <label class="opsgate-switch" style="margin-top:10px;">
                                    <span class="description" style="margin:0;">Off</span>
                                    <span class="opsgate-switch-track">
                                        <input id="opsgate-telemetry-enabled" type="checkbox" name="opsgate_telemetry_enabled" value="1" <?php checked( $telemetry_enabled_cfg ); ?> />
                                        <span class="opsgate-slider"></span>
                                    </span>
                                    <span class="description" style="margin:0;">On</span>
                                </label>
                                <p class="opsgate-settings-inline-note">Display setting only — does not affect your OpsGate account data.</p>
                            </article>
                            <article class="opsgate-settings-module opsgate-settings-identity-card">
                                <div class="opsgate-settings-module-head">
                                    <div>
                                        <strong>Active site</strong>
                                        <p class="description">Choose the customer site OpsGate should operate on. Saving resolves or creates one OpsGate site record and reuses it when the same site is selected again.</p>
                                    </div>
                                    <span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( ! empty( $settings_site_config['ok'] ) ? 'good' : ( $settings_remote_onboarding_prefill ? 'info' : 'neutral' ) ); ?>"><?php echo esc_html( ! empty( $settings_site_config['ok'] ) ? 'Site configured' : ( $settings_remote_onboarding_prefill ? 'Ready to save' : 'Not yet saved' ) ); ?></span>
                                </div>
                                <input type="hidden" name="opsgate_account_id" value="<?php echo esc_attr( $settings_account_id_value ); ?>" />
                                <input type="hidden" name="opsgate_inbound_token" value="<?php echo esc_attr( $settings_api_token_value ); ?>" />
                                <div class="opsgate-settings-form-grid opsgate-settings-identity-grid">
                                    <div>
                                        <label for="opsgate_identity_email"><strong>Contact email</strong></label>
                                        <input id="opsgate_identity_email" type="email" class="regular-text" name="opsgate_identity_email" value="<?php echo esc_attr( $identity_email_value ); ?>" />
                                    </div>
                                    <div>
                                        <label for="opsgate_site_label"><strong>Site label</strong></label>
                                        <input id="opsgate_site_label" type="text" class="regular-text" name="opsgate_site_label" value="<?php echo esc_attr( $site_label_value ); ?>" />
                                    </div>
                                    <div>
                                        <label for="opsgate_site_url"><strong>Site URL</strong></label>
                                        <input id="opsgate_site_url" type="url" class="regular-text" name="opsgate_site_url" value="<?php echo esc_attr( $site_url_value ); ?>" />
                                    </div>
                                    <?php if ( '' !== $settings_account_id_value ) : ?>
                                    <div class="opsgate-settings-support-ref">
                                        <details>
                                            <summary><span class="description">Support &amp; diagnostic reference</span></summary>
                                            <p class="description" style="margin-top:6px;">Connection scope — share only with OpsGate support.</p>
                                            <input type="text" class="regular-text" value="<?php echo esc_attr( '' !== $settings_account_id_value ? 'acct_' . substr( md5( $settings_account_id_value ), 0, 8 ) . '…' : '' ); ?>" readonly="readonly" style="font-family:monospace;font-size:12px;color:#6b7280;" />
                                        </details>
                                    </div>
                                    <?php endif; ?>
                                </div>
                                <div class="opsgate-settings-context-grid">
                                    <article class="opsgate-settings-context-card">
                                        <span class="opsgate-overview-eyebrow">OpsGate site record</span>
                                        <div class="opsgate-settings-value-compact"><?php echo esc_html( $settings_remote_onboarding_prefill && '' !== $site_label_value ? $site_label_value : ( ! empty( $settings_selected_site['site_label'] ) ? (string) $settings_selected_site['site_label'] : 'Not resolved yet' ) ); ?></div>
                                        <p><?php echo esc_html( $settings_remote_onboarding_prefill ? 'This remote onboarding handoff prefilled the site details. Save Site Configuration to resolve or create the canonical site record.' : ( ! empty( $settings_selected_site['site_id'] ) ? 'Site verified and linked to OpsGate.' : 'Save a site URL to resolve or create its canonical site record.' ) ); ?></p>
                                    </article>
                                    <article class="opsgate-settings-context-card">
                                        <span class="opsgate-overview-eyebrow">Primary email route</span>
                                        <div class="opsgate-settings-value-compact"><?php echo esc_html( ! empty( $settings_primary_email['resolved_target'] ) ? (string) $settings_primary_email['resolved_target'] : 'Not configured' ); ?></div>
                                        <p><?php echo esc_html( ! empty( $settings_primary_email['label'] ) ? (string) $settings_primary_email['label'] : 'Create or update it in Alerts.' ); ?></p>
                                    </article>
                                    <article class="opsgate-settings-context-card opsgate-settings-context-card-webhook">
                                        <span class="opsgate-overview-eyebrow">Primary webhook route</span>
                                        <div class="opsgate-settings-value-compact opsgate-settings-value-break"><?php echo esc_html( ! empty( $settings_primary_webhook['resolved_target'] ) ? (string) $settings_primary_webhook['resolved_target'] : 'Not configured' ); ?></div>
                                        <p><?php echo esc_html( ! empty( $settings_primary_webhook['label'] ) ? (string) $settings_primary_webhook['label'] : 'Create or update it in Alerts.' ); ?></p>
                                    </article>
                                    <article class="opsgate-settings-context-card">
                                        <span class="opsgate-overview-eyebrow">Plan limits</span>
                                        <div class="opsgate-settings-value-compact"><?php echo esc_html( self::package_scope_allowance_label() ); ?></div>
                                        <p><?php echo esc_html( trim( self::package_scope_allowance_summary() . ' ' . $settings_family_context_copy ) ); ?></p>
                                    </article>
                                </div>
                            </article>
                        </div>

                        <input type="hidden" name="opsgate_api_base_url" value="<?php echo esc_attr( $settings_api_base_url_value ); ?>" />
                        <div class="submit-box opsgate-settings-submit-box" style="margin-top:16px;">
                            <p id="opsgate-site-config-save-note" class="opsgate-settings-inline-note opsgate-settings-inline-note-submit">Changes are saved to your OpsGate account and this site's local settings.</p>
                            <?php submit_button( 'Save Site Configuration', 'primary large', 'submit', false, array( 'id' => 'opsgate-save-site-config' ) ); ?>
                        </div>
                    </form>

                    <?php
                    // Slice 5 Part A: Agency Branding (Agency plan only)
                    if ( 'agency' === self::normalize_plan( $current_plan ) ) :
                        $branding_account_id = isset( $eff_state['account_id'] ) ? (string) $eff_state['account_id'] : '';
                        $branding_api_base   = self::mcp_base_url();
                        if ( isset( $_GET['opsgate_branding_saved'] ) && '1' === (string) $_GET['opsgate_branding_saved'] ) : // phpcs:ignore WordPress.Security.NonceVerification.Recommended
                    ?>
                        <div class="opsgate-alert-inline-status is-visible is-success" data-opsgate-transient-status="1" style="margin-top:12px;">
                            <p>Agency branding saved.</p>
                        </div>
                    <?php endif; ?>
                    <div class="opsgate-card" style="margin-top:12px;">
                        <h3><span class="dashicons dashicons-art"></span> Agency Branding</h3>
                        <p class="description" style="margin:0 0 10px 0;">Customize how your firm appears in generated reports and shared links. Agency plan only.</p>
                        <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="opsgate-settings-form">
                            <?php wp_nonce_field( 'opsgate_save_agency_branding', 'opsgate_save_agency_branding_nonce' ); ?>
                            <input type="hidden" name="action" value="opsgate_save_agency_branding" />
                            <input type="hidden" name="opsgate_branding_account_id" value="<?php echo esc_attr( $branding_account_id ); ?>" />
                            <input type="hidden" name="opsgate_branding_api_base" value="<?php echo esc_attr( $branding_api_base ); ?>" />
                            <table class="form-table" style="margin-top:0;">
                                <tr>
                                    <th><label for="opsgate_branding_firm_name">Firm name</label></th>
                                    <td><input id="opsgate_branding_firm_name" type="text" name="opsgate_branding_firm_name" class="regular-text"
                                        value="<?php echo esc_attr( (string) get_option( 'opsgate_branding_firm_name', trim( (string) get_option( 'opsgate_firm_name', '' ) ) ) ); ?>"
                                        placeholder="e.g. Acme Web Agency" /></td>
                                </tr>
                                <tr>
                                    <th><label for="opsgate_branding_logo_url">Logo URL</label></th>
                                    <td><input id="opsgate_branding_logo_url" type="url" name="opsgate_branding_logo_url" class="regular-text"
                                        value="<?php echo esc_attr( (string) get_option( 'opsgate_branding_logo_url', '' ) ); ?>"
                                        placeholder="https://example.com/logo.png" />
                                    <p class="description">HTTPS URL to your firm logo. Used in report headers.</p></td>
                                </tr>
                                <tr>
                                    <th><label for="opsgate_branding_primary_hex">Brand color</label></th>
                                    <td><input id="opsgate_branding_primary_hex" type="text" name="opsgate_branding_primary_hex" class="small-text"
                                        value="<?php echo esc_attr( (string) get_option( 'opsgate_branding_primary_hex', '' ) ); ?>"
                                        placeholder="#1a4080" maxlength="7" />
                                    <p class="description">Hex color code (e.g. #1a4080). Optional.</p></td>
                                </tr>
                                <tr>
                                    <th><label for="opsgate_branding_tagline">Tagline</label></th>
                                    <td><input id="opsgate_branding_tagline" type="text" name="opsgate_branding_tagline" class="regular-text"
                                        value="<?php echo esc_attr( (string) get_option( 'opsgate_branding_tagline', '' ) ); ?>"
                                        placeholder="Your WordPress security partner" /></td>
                                </tr>
                                <tr>
                                    <th><label for="opsgate_branding_contact_email">Contact email</label></th>
                                    <td><input id="opsgate_branding_contact_email" type="email" name="opsgate_branding_contact_email" class="regular-text"
                                        value="<?php echo esc_attr( (string) get_option( 'opsgate_branding_contact_email', '' ) ); ?>"
                                        placeholder="hello@youragency.com" /></td>
                                </tr>
                            </table>
                            <div class="submit-box" style="margin-top:8px;">
                                <?php submit_button( 'Save Agency Branding', 'secondary', 'submit', false ); ?>
                            </div>
                        </form>
                    </div>
                    <?php endif; // agency plan ?>
                </div>

                <?php
                $settings_plugin_update = self::plugin_update_status();
                $settings_plugin_installed_version = isset( $settings_plugin_update['installed_version'] ) ? (string) $settings_plugin_update['installed_version'] : 'Not recorded';
                $settings_plugin_available_version = isset( $settings_plugin_update['available_version'] ) ? trim( (string) $settings_plugin_update['available_version'] ) : '';
                $settings_plugin_update_available = ! empty( $settings_plugin_update['update_available'] );
                $settings_plugin_auto_update_enabled = ! empty( $settings_plugin_update['auto_update_enabled'] );
                $settings_plugin_checked_at = isset( $settings_plugin_update['checked_at_utc'] ) ? trim( (string) $settings_plugin_update['checked_at_utc'] ) : '';
                $settings_plugin_update_copy = $settings_plugin_update_available
                    ? sprintf( 'Version %s is available through the WordPress-native update lane.', $settings_plugin_available_version )
                    : 'This installation is currently aligned with the latest published OpsGate plugin release.';
                $settings_plugin_update_meta = $settings_plugin_auto_update_enabled
                    ? 'WordPress auto-update is enabled for this plugin.'
                    : 'WordPress auto-update is currently disabled for this plugin.';
                if ( '' !== $settings_plugin_checked_at ) {
                    $settings_plugin_update_meta .= ' Last checked ' . self::canonical_report_datetime_label( $settings_plugin_checked_at ) . '.';
                }
                ?>

                <?php
                // Manage Connector block — shown in Settings only when site is connected, disconnected, or credential_invalid.
                // external_only state: wizard handles the full connect flow; this block is suppressed.
                $settings_show_manage_connector = in_array( $connection_status_value, array( 'connected', 'disconnected', 'pairing_pending', 'credential_invalid' ), true );
                if ( $settings_show_manage_connector ) :
                    $site_has_active_credential = in_array( $connection_status_value, array( 'connected', 'credential_invalid' ), true );
                    $conn_tone = 'connected' === $connection_status_value ? 'good' : ( 'credential_invalid' === $connection_status_value ? 'error' : 'warn' );
                ?>
                <div class="opsgate-card opsgate-pricing-dashboard opsgate-manage-connector-card" style="margin-top:12px;" data-og-settings-panel="connector">
                    <h2><span class="dashicons dashicons-admin-network"></span> Manage Connector</h2>
                    <div class="opsgate-manage-connector-status-row">
                        <span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-<?php echo esc_attr( $conn_tone ); ?>"><?php echo esc_html( self::canonical_connection_status_label( $connection_status_value ) ); ?></span>
                        <span class="description"><?php echo esc_html( self::canonical_connection_status_copy( $connection_status_value, $connection_mode_value, $settings_selected_is_local ) ); ?></span>
                    </div>
                    <div class="opsgate-settings-inline-form" style="margin-top:14px;gap:10px;">
                        <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:0;">
                            <?php wp_nonce_field( 'opsgate_rotate_connector_credential', 'opsgate_rotate_connector_credential_nonce' ); ?>
                            <input type="hidden" name="action" value="opsgate_rotate_connector_credential" />
                            <button type="submit" class="button" <?php disabled( ! $site_has_active_credential ); ?>>Rotate Credential</button>
                        </form>
                        <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:0;">
                            <?php wp_nonce_field( 'opsgate_revoke_connector_credential', 'opsgate_revoke_connector_credential_nonce' ); ?>
                            <input type="hidden" name="action" value="opsgate_revoke_connector_credential" />
                            <button type="submit" class="button" <?php disabled( ! $site_has_active_credential ); ?>>Revoke Credential</button>
                        </form>
                    </div>
                    <?php if ( '1' !== get_option( 'opsgate_setup_wizard_dismissed', '0' ) || 'disconnected' === $connection_status_value ) : ?>
                        <p class="description" style="margin-top:10px;">Need to reconnect? <a href="<?php echo esc_url( admin_url( 'admin.php?page=opsgate' ) ); ?>">Open setup wizard &rarr;</a></p>
                    <?php endif; ?>
                </div>
                <?php endif; ?>

                    <div class="opsgate-settings-zone-b">
                        <button type="button" class="opsgate-settings-zone-b-toggle" aria-expanded="false" aria-controls="opsgate-settings-zone-b-body">
                            Advanced &amp; diagnostics <span class="dashicons dashicons-arrow-down-alt2"></span>
                        </button>
                        <div class="opsgate-settings-zone-b-body" id="opsgate-settings-zone-b-body">

                    <div class="opsgate-card opsgate-pricing-dashboard" style="margin-top:12px;">
                        <h2><span class="dashicons dashicons-update"></span> Plugin maintenance</h2>
                        <p class="opsgate-settings-support-intro">Plugin updates follow the normal WordPress package-maintenance lane. They do not change OpsGate plan or entitlement authority.</p>
                        <div class="opsgate-settings-support-grid">
                            <article class="opsgate-settings-support-card">
                                <span class="opsgate-overview-eyebrow">Installed version</span>
                                <p><?php echo esc_html( $settings_plugin_update_copy ); ?></p>
                                <input type="text" class="regular-text" value="<?php echo esc_attr( $settings_plugin_installed_version ); ?>" readonly="readonly" />
                            </article>
                            <article class="opsgate-settings-support-card">
                                <span class="opsgate-overview-eyebrow">Available release</span>
                                <p><?php echo esc_html( $settings_plugin_update_meta ); ?></p>
                                <input type="text" class="regular-text" value="<?php echo esc_attr( '' !== $settings_plugin_available_version ? $settings_plugin_available_version : 'Up to date' ); ?>" readonly="readonly" />
                            </article>
                            <article class="opsgate-settings-support-card">
                                <span class="opsgate-overview-eyebrow">Update source</span>
                                <p>Release metadata is served by the OpsGate API for the WordPress-native update checker.</p>
                                <input type="text" class="regular-text" value="<?php echo esc_attr( (string) ( $settings_plugin_update['metadata_url'] ?? '' ) ); ?>" readonly="readonly" />
                            </article>
                        </div>
                    </div>
                    <div class="opsgate-card opsgate-pricing-dashboard" style="margin-top:12px;">
                        <h2><span class="dashicons dashicons-admin-tools"></span> Support-only connection values</h2>
                        <p class="opsgate-settings-support-intro">These values stay available for support and audit. They are not daily operating controls.</p>
                        <div class="opsgate-settings-support-grid">
                            <article class="opsgate-settings-support-card">
                                <span class="opsgate-overview-eyebrow">Inbound automation key</span>
                                <p><?php echo esc_html( $settings_inbound_token_copy ); ?></p>
                                <input type="text" class="regular-text" value="<?php echo esc_attr( $settings_inbound_token_value ); ?>" readonly="readonly" />
                            </article>
                            <article class="opsgate-settings-support-card">
                                <span class="opsgate-overview-eyebrow">Local support token</span>
                                <p><?php echo esc_html( $settings_site_token_copy ); ?></p>
                                <input type="text" class="regular-text" value="<?php echo esc_attr( $settings_site_token_value ); ?>" readonly="readonly" />
                            </article>
                            <article class="opsgate-settings-support-card">
                                <span class="opsgate-overview-eyebrow">Local install site reference</span>
                                <p><?php echo esc_html( $settings_site_id_copy ); ?></p>
                                <input type="text" class="regular-text" value="<?php echo esc_attr( $settings_site_id_value ); ?>" readonly="readonly" />
                            </article>
                            <article class="opsgate-settings-support-card">
                                <span class="opsgate-overview-eyebrow">Current selected site ID</span>
                                <p>Canonical site scope currently driving triage, reports, and alerts.</p>
                                <input type="text" class="regular-text" value="<?php echo esc_attr( (string) ( $settings_selected_site['site_id'] ?? '' ) ); ?>" readonly="readonly" />
                            </article>
                            <article class="opsgate-settings-support-card">
                                <span class="opsgate-overview-eyebrow">Portfolio ID</span>
                                <p><?php echo esc_html( $settings_portfolio_id_copy ); ?></p>
                                <input type="text" class="regular-text" value="<?php echo esc_attr( $settings_portfolio_id_value ); ?>" readonly="readonly" />
                            </article>
                        </div>
                    </div>
                    <div class="opsgate-card opsgate-pricing-dashboard" style="margin-top:12px;">
                        <h2><span class="dashicons dashicons-download"></span> Support Export</h2>
                        <p class="opsgate-settings-support-intro">Used for support investigation only. Includes the plugin log and current system snapshot. Not part of the customer report/export package.</p>
                        <?php if ( isset( $_GET['opsgate_support_export'] ) && 'failed' === (string) $_GET['opsgate_support_export'] ) : // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?>
                            <?php $support_export_detail = isset( $_GET['opsgate_support_export_detail'] ) ? sanitize_key( wp_unslash( $_GET['opsgate_support_export_detail'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?>
                            <?php
                            $support_export_message = 'Support export could not be prepared right now.';
                            if ( 'zip_unavailable' === $support_export_detail ) {
                                $support_export_message = 'ZIP support is not available on this WordPress host right now.';
                            } elseif ( 'export_dir_unavailable' === $support_export_detail ) {
                                $support_export_message = 'OpsGate could not prepare the support export directory.';
                            } elseif ( 'snapshot_write_failed' === $support_export_detail ) {
                                $support_export_message = 'OpsGate could not write the support snapshot for export.';
                            } elseif ( 'log_write_failed' === $support_export_detail ) {
                                $support_export_message = 'OpsGate could not prepare the support log file for export.';
                            } elseif ( 'zip_create_failed' === $support_export_detail ) {
                                $support_export_message = 'OpsGate could not build the support ZIP file right now.';
                            }
                            ?>
                            <div class="opsgate-alert-inline-status is-visible is-error" style="margin-top:12px;">
                                <p><?php echo esc_html( $support_export_message ); ?></p>
                            </div>
                        <?php endif; ?>
                        <?php $export_url = admin_url( 'admin-post.php?action=opsgate_export_logs' ); ?>
                        <div class="opsgate-settings-support-export">
                            <?php if ( $support_export_ready ) : ?>
                                <a id="opsgate-support-export-button" href="<?php echo esc_url( $export_url ); ?>" class="button button-secondary button-large">
                                    <span class="dashicons dashicons-download" style="vertical-align:middle;margin-right:5px;"></span>
                                    Download support package
                                </a>
                            <?php else : ?>
                                <button type="button" class="button button-secondary button-large" disabled="disabled">
                                    <span class="dashicons dashicons-dismiss" style="vertical-align:middle;margin-right:5px;"></span>
                                    Export unavailable
                                </button>
                                <span class="opsgate-p5-disabled-hint">Export requires PHP ZIP extension support on this host.</span>
                            <?php endif; ?>
                        </div>
                        <p id="opsgate-support-export-status" class="opsgate-settings-inline-note"><?php echo esc_html( $support_export_ready ? 'Exports plugin log and current system snapshot as a support ZIP.' : 'Support export is currently unavailable because ZIP support is missing on this host.' ); ?></p>
                    </div>

                    <?php if ( current_user_can( 'manage_options' ) ) : ?>
                    <div class="opsgate-card opsgate-pricing-dashboard" style="margin-top:12px;border:2px solid var(--og-amber,#f59e0b);">
                        <h2 style="color:var(--og-amber,#f59e0b);">&#9881; Operator: Test Site Soft Reset</h2>
                        <p class="opsgate-settings-support-intro" style="color:var(--og-text-2,#60768b);">
                            <strong>OPERATOR ONLY &mdash; not customer-facing.</strong>
                            Soft reset returns the currently selected site to an unpaired, external-only state for release testing.
                            This revokes the active site credential, expires open pairing sessions, resets connection status to
                            <code>external_only</code> / <code>public_scan</code>, clears the local operator tier override, and
                            clears local credential/connection caches so the remote plugin re-reads clean canonical state.
                            Historical runs, reports, and alerts are preserved. The site canonical row is preserved.
                        </p>
                        <?php
                        $reset_scope_label = isset( $settings_selected_site['site_label'] ) ? trim( (string) $settings_selected_site['site_label'] ) : '';
                        $reset_scope_id    = isset( $settings_selected_site['site_id'] ) ? trim( (string) $settings_selected_site['site_id'] ) : '';
                        $reset_conn_status = isset( $settings_selected_site['connection_status'] ) ? trim( (string) $settings_selected_site['connection_status'] ) : 'external_only';
                        $reset_conn_mode   = isset( $settings_selected_site['connection_mode'] ) ? trim( (string) $settings_selected_site['connection_mode'] ) : 'public_scan';
                        ?>
                        <?php if ( isset( $_GET['opsgate_operator_reset_result'] ) && 'soft_reset_complete' === sanitize_key( wp_unslash( $_GET['opsgate_operator_reset_result'] ) ) ) : // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?>
                        <div class="opsgate-alert-inline-status is-visible is-ok" style="margin-bottom:12px;padding:10px 14px;border-radius:6px;background:var(--og-green-bg,#f0fdf4);border:1px solid var(--og-green,#22c55e);">
                            <strong>Soft Reset complete.</strong> Site returned to external-only / public_scan state. Credential revoked. Pairing sessions expired. Operator override cleared. Reinstall or refresh the remote plugin to confirm clean onboarding state.
                        </div>
                        <?php endif; ?>
                        <div class="opsgate-settings-support-grid" style="margin-bottom:12px;">
                            <article class="opsgate-settings-support-card">
                                <span class="opsgate-overview-eyebrow">Selected site</span>
                                <p>Site that will be reset.</p>
                                <input type="text" class="regular-text" value="<?php echo esc_attr( '' !== $reset_scope_label ? $reset_scope_label : '(none selected)' ); ?>" readonly="readonly" />
                            </article>
                            <article class="opsgate-settings-support-card">
                                <span class="opsgate-overview-eyebrow">Current connection status</span>
                                <p>Will be reset to <code>external_only</code>.</p>
                                <input type="text" class="regular-text" value="<?php echo esc_attr( $reset_conn_status ); ?>" readonly="readonly" />
                            </article>
                            <article class="opsgate-settings-support-card">
                                <span class="opsgate-overview-eyebrow">Current connection mode</span>
                                <p>Will be reset to <code>public_scan</code>.</p>
                                <input type="text" class="regular-text" value="<?php echo esc_attr( $reset_conn_mode ); ?>" readonly="readonly" />
                            </article>
                        </div>
                        <?php $soft_reset_disabled = '' === $reset_scope_id; ?>
                        <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="display:flex;align-items:center;gap:10px;flex-wrap:wrap;"
                              onsubmit="return confirm('Soft Reset: revoke credential, expire pairing sessions, and return this site to external-only / public_scan state?\n\nSite: <?php echo esc_js( $reset_scope_label ); ?>\n\nHistorical runs and reports are preserved.');">
                            <?php wp_nonce_field( 'opsgate_operator_soft_reset', 'opsgate_operator_soft_reset_nonce' ); ?>
                            <input type="hidden" name="action" value="opsgate_operator_soft_reset" />
                            <input type="hidden" name="opsgate_reset_reason" value="operator_soft_reset_release_testing" />
                            <button type="submit" class="button" style="border-color:var(--og-amber,#f59e0b);color:var(--og-amber,#f59e0b);" <?php disabled( $soft_reset_disabled ); ?>>
                                Run Soft Reset for <?php echo esc_html( '' !== $reset_scope_label ? $reset_scope_label : 'selected site' ); ?>
                            </button>
                            <?php if ( $soft_reset_disabled ) : ?>
                                <span class="opsgate-p5-disabled-hint">Select a canonical site first.</span>
                            <?php endif; ?>
                        </form>
                        <p class="opsgate-settings-inline-note" style="margin-top:8px;font-size:11px;color:var(--og-text-2,#60768b);">
                            After reset: refresh the remote plugin — it should show Free/public-only or paid-unconnected state. Then re-run the full lifecycle to prove clean onboarding.
                        </p>
                    </div>
                    <?php endif; ?>

                    <?php if ( current_user_can( 'manage_options' ) ) : ?>
                    <?php
                    // Part E — Provider activation readiness checklist (operator-facing, manage_options only).
                    // All email (notifications + reports) routes through opsgate-mail (self-hosted Postfix+DKIM).
                    // No external email provider (Resend decommissioned). No external API key required for email.
                    $telegram_token_set   = '' !== trim( (string) get_option( 'opsgate_telegram_bot_token', '' ) );
                    $twilio_sid_set       = '' !== trim( (string) get_option( 'opsgate_twilio_account_sid', '' ) );
                    $aws_key_set          = '' !== trim( (string) get_option( 'opsgate_aws_access_key_id', '' ) );
                    $provider_rows = array(
                        array( 'label' => 'Email (all — self-hosted SMTP)', 'family' => 'email', 'configured' => true, 'note' => 'opsgate-mail container (Postfix + OpenDKIM). Notifications: alerts@opsgate.ca. Reports: reports@opsgate.ca. DKIM verified. No external provider.' ),
                        array( 'label' => 'Webhook (HTTP)', 'family' => 'webhook', 'configured' => true, 'note' => 'No credentials needed — ready when a destination URL is added.' ),
                        array( 'label' => 'Telegram', 'family' => 'telegram', 'configured' => $telegram_token_set, 'note' => $telegram_token_set ? 'Bot token set — provider active.' : 'Set opsgate_telegram_bot_token in DB or plugin options.' ),
                        array( 'label' => 'Slack (Incoming Webhook)', 'family' => 'slack', 'configured' => true, 'note' => 'Webhook URL provided per notification rule — no global credential needed.' ),
                        array( 'label' => 'Discord (Incoming Webhook)', 'family' => 'discord', 'configured' => true, 'note' => 'Webhook URL provided per notification rule — no global credential needed.' ),
                        array( 'label' => 'Microsoft Teams', 'family' => 'teams', 'configured' => true, 'note' => 'Incoming webhook URL provided per notification rule — no global credential needed.' ),
                        array( 'label' => 'WhatsApp (Twilio)', 'family' => 'whatsapp', 'configured' => $twilio_sid_set, 'note' => $twilio_sid_set ? 'Twilio credentials set — provider active.' : 'Set opsgate_twilio_account_sid and opsgate_twilio_auth_token.' ),
                        array( 'label' => 'AWS SNS', 'family' => 'sns', 'configured' => $aws_key_set, 'note' => $aws_key_set ? 'AWS credentials set — provider active.' : 'Set opsgate_aws_access_key_id and opsgate_aws_secret_access_key.' ),
                    );
                    $all_ready = ! in_array( false, array_column( $provider_rows, 'configured' ), true );
                    ?>
                    <div class="opsgate-card opsgate-pricing-dashboard" style="margin-top:12px;border:2px solid var(--og-amber,#f59e0b);">
                        <h2 style="color:var(--og-amber,#f59e0b);">&#9881; Operator: Provider Activation Readiness</h2>
                        <p class="opsgate-settings-support-intro" style="color:var(--og-text-2,#60768b);">
                            <strong>OPERATOR ONLY &mdash; not customer-facing.</strong>
                            Status of each notification delivery provider. Providers shown as <strong>Ready</strong> will activate as soon as a matching notification rule and destination are configured by the account.
                        </p>
                        <?php if ( $all_ready ) : ?>
                        <div class="opsgate-alert-inline-status is-visible is-ok" style="margin-bottom:12px;padding:10px 14px;border-radius:6px;background:var(--og-green-bg,#f0fdf4);border:1px solid var(--og-green,#22c55e);">
                            <strong>All providers configured.</strong> Every notification family is ready to deliver.
                        </div>
                        <?php endif; ?>
                        <table style="width:100%;border-collapse:collapse;font-size:13px;">
                            <thead>
                                <tr style="border-bottom:1px solid var(--og-border,#e5e7eb);">
                                    <th style="padding:6px 8px;text-align:left;font-weight:600;">Provider</th>
                                    <th style="padding:6px 8px;text-align:left;font-weight:600;">Status</th>
                                    <th style="padding:6px 8px;text-align:left;font-weight:600;">Note</th>
                                </tr>
                            </thead>
                            <tbody>
                            <?php foreach ( $provider_rows as $pr ) : ?>
                                <tr style="border-bottom:1px solid var(--og-border,#e5e7eb);">
                                    <td style="padding:6px 8px;"><?php echo esc_html( $pr['label'] ); ?></td>
                                    <td style="padding:6px 8px;">
                                        <?php if ( $pr['configured'] ) : ?>
                                        <span style="color:var(--og-green,#22c55e);font-weight:600;">&#10003; Ready</span>
                                        <?php else : ?>
                                        <span style="color:var(--og-amber,#f59e0b);font-weight:600;">&#9888; Not configured</span>
                                        <?php endif; ?>
                                    </td>
                                    <td style="padding:6px 8px;color:var(--og-text-2,#60768b);"><?php echo esc_html( $pr['note'] ); ?></td>
                                </tr>
                            <?php endforeach; ?>
                            </tbody>
                        </table>
                        <p class="opsgate-settings-inline-note" style="margin-top:8px;font-size:11px;color:var(--og-text-2,#60768b);">
                            Credentials are stored as WP options or environment variables on the worker container. Reload this page after updating environment configuration.
                        </p>
                    </div>

                    <?php /* AI Activation status panel (operator-facing, manage_options only). */ ?>
                    <div class="opsgate-card opsgate-pricing-dashboard" style="margin-top:12px;border:2px solid var(--og-border,#e5e7eb);">
                        <h2>&#129504; Operator: AI Activation Status</h2>
                        <p class="opsgate-settings-support-intro" style="color:var(--og-text-2,#60768b);">
                            <strong>OPERATOR ONLY &mdash; not customer-facing.</strong>
                            AI features (Executive Brief, CVE context enrichment) are controlled by environment variables on the worker container. Status is read-only — set variables in <code>config/mcp.env</code> and restart the worker.
                        </p>
                        <table style="width:100%;border-collapse:collapse;font-size:13px;">
                            <thead>
                                <tr style="border-bottom:1px solid var(--og-border,#e5e7eb);">
                                    <th style="padding:6px 8px;text-align:left;font-weight:600;">Variable</th>
                                    <th style="padding:6px 8px;text-align:left;font-weight:600;">Required action</th>
                                </tr>
                            </thead>
                            <tbody>
                                <tr style="border-bottom:1px solid var(--og-border,#e5e7eb);">
                                    <td style="padding:6px 8px;font-family:monospace;">OPSGATE_AI_ENABLED</td>
                                    <td style="padding:6px 8px;color:var(--og-text-2,#60768b);">Set to <code>true</code> in <code>config/mcp.env</code> to enable AI calls. When false (default): placeholder rows written, no API calls, no AI content shown to buyers.</td>
                                </tr>
                                <tr style="border-bottom:1px solid var(--og-border,#e5e7eb);">
                                    <td style="padding:6px 8px;font-family:monospace;">ANTHROPIC_API_KEY / ANTHROPIC_API_KEY_FILE</td>
                                    <td style="padding:6px 8px;color:var(--og-text-2,#60768b);">Write raw key to <code>config/secrets/anthropic_api_key</code> (referenced by <code>ANTHROPIC_API_KEY_FILE</code>) or set <code>ANTHROPIC_API_KEY</code> directly. File path is preferred — secret never committed to repo.</td>
                                </tr>
                                <tr>
                                    <td style="padding:6px 8px;font-family:monospace;">STRIPE_WEBHOOK_SECRET / STRIPE_WEBHOOK_SECRET_FILE</td>
                                    <td style="padding:6px 8px;color:var(--og-text-2,#60768b);">Write Stripe webhook signing secret to <code>config/secrets/stripe_webhook_secret</code> or set env var directly. Required before Stripe webhook endpoint will accept events.</td>
                                </tr>
                            </tbody>
                        </table>
                    </div>
                    <?php endif; ?>

                        </div><!-- /.opsgate-settings-zone-b-body -->
                    </div><!-- /.opsgate-settings-zone-b -->

                <script>
                (function () {
                    var settingsRoot = document.querySelector('.opsgate-admin-tab-settings');
                    if (!settingsRoot) {
                        return;
                    }

                    var requestedSection = '';
                    try {
                        requestedSection = new URLSearchParams(window.location.search).get('section') || '';
                    } catch (error) {
                        requestedSection = '';
                    }
                    if (requestedSection === 'site-configuration') {
                        var siteConfigSection = document.getElementById('opsgate-site-configuration-section');
                        if (siteConfigSection && typeof siteConfigSection.scrollIntoView === 'function') {
                            siteConfigSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
                        }
                    }
                    if (requestedSection === 'site-configuration') {
                        var requestedPanel = '';
                        try {
                            requestedPanel = new URLSearchParams(window.location.search).get('panel') || '';
                        } catch (error) {
                            requestedPanel = '';
                        }
                        if (requestedPanel === 'pairing-material' || requestedPanel === 'pairing_material') {
                            var supportDetail = document.getElementById('opsgate-settings-support-detail');
                            if (supportDetail) {
                                supportDetail.open = true;
                            }
                            var pairingPanel = document.getElementById('opsgate-pairing-material-panel');
                            if (pairingPanel && typeof pairingPanel.scrollIntoView === 'function') {
                                pairingPanel.scrollIntoView({ behavior: 'smooth', block: 'start' });
                            }
                        }
                    }

                    function captureFormState(form) {
                        var state = {};
                        if (!form) {
                            return JSON.stringify(state);
                        }
                        var fields = form.querySelectorAll('input[name], select[name], textarea[name]');
                        fields.forEach(function (field) {
                            if (field.type === 'submit') {
                                return;
                            }
                            if (field.type === 'checkbox') {
                                state[field.name] = field.checked ? '1' : '0';
                                return;
                            }
                            state[field.name] = field.value;
                        });
                        return JSON.stringify(state);
                    }

                    function resetFormToRenderedState(form) {
                        if (!form) {
                            return;
                        }
                        form.querySelectorAll('input[name], select[name], textarea[name]').forEach(function (field) {
                            if (field.type === 'submit') {
                                return;
                            }
                            if (field.tagName === 'SELECT') {
                                Array.prototype.slice.call(field.options || []).forEach(function (option) {
                                    option.selected = !!option.defaultSelected;
                                });
                                return;
                            }
                            if (field.type === 'checkbox' || field.type === 'radio') {
                                field.checked = !!field.defaultChecked;
                                return;
                            }
                            field.value = field.defaultValue;
                        });
                    }

                    function syncScheduleModeFields(form) {
                        var modeField = form.querySelector('[name="opsgate_schedules[portfolio_triage][mode]"]');
                        var dowField = form.querySelector('[name="opsgate_schedules[portfolio_triage][dow]"]');
                        var domField = form.querySelector('[name="opsgate_schedules[portfolio_triage][dom]"]');
                        var toggleField = form.querySelector('[name="opsgate_scheduling_enabled"]');
                        if (!modeField) {
                            return;
                        }
                        var mode = modeField.value || 'off';
                        if (toggleField && mode === 'off') {
                            toggleField.checked = false;
                        }
                        if (dowField) {
                            dowField.disabled = mode !== 'weekly' || form.dataset.editable !== '1';
                            if (mode !== 'weekly') {
                                dowField.value = '';
                            }
                        }
                        if (domField) {
                            domField.disabled = mode !== 'monthly' || form.dataset.editable !== '1';
                            if (mode !== 'monthly') {
                                domField.value = '';
                            }
                        }
                    }

                    function scheduleFormIsValid(form) {
                        var modeField = form.querySelector('[name="opsgate_schedules[portfolio_triage][mode]"]');
                        var timeField = form.querySelector('[name="opsgate_schedules[portfolio_triage][time]"]');
                        var dowField = form.querySelector('[name="opsgate_schedules[portfolio_triage][dow]"]');
                        var domField = form.querySelector('[name="opsgate_schedules[portfolio_triage][dom]"]');
                        var mode = modeField ? (modeField.value || 'off') : 'off';
                        var time = timeField ? (timeField.value || '') : '';

                        if (mode !== 'off' && !/^\d{2}:\d{2}$/.test(time)) {
                            return false;
                        }
                        if (mode === 'weekly' && dowField && !dowField.value) {
                            return false;
                        }
                        if (mode === 'monthly' && domField) {
                            var dom = parseInt(domField.value || '', 10);
                            if (!dom || dom < 1 || dom > 31) {
                                return false;
                            }
                        }
                        return true;
                    }

                    function firstEnabledScheduleMode(modeField) {
                        if (!modeField || !modeField.options) {
                            return 'daily';
                        }
                        for (var i = 0; i < modeField.options.length; i += 1) {
                            var candidate = modeField.options[i];
                            if (candidate && candidate.value && candidate.value !== 'off' && !candidate.disabled) {
                                return candidate.value;
                            }
                        }
                        return 'daily';
                    }

                    function scheduleModeLabel(mode) {
                        if (mode === 'daily') {
                            return 'Daily';
                        }
                        if (mode === 'weekly') {
                            return 'Weekly';
                        }
                        if (mode === 'monthly') {
                            return 'Monthly';
                        }
                        return 'Automation off';
                    }

                    function scheduleCurrentLabel(form, enabled) {
                        var modeField = form.querySelector('[name="opsgate_schedules[portfolio_triage][mode]"]');
                        var timeField = form.querySelector('[name="opsgate_schedules[portfolio_triage][time]"]');
                        var dowField = form.querySelector('[name="opsgate_schedules[portfolio_triage][dow]"]');
                        var domField = form.querySelector('[name="opsgate_schedules[portfolio_triage][dom]"]');
                        var mode = modeField ? (modeField.value || 'off') : 'off';
                        var time = timeField ? (timeField.value || '') : '';
                        if (!enabled || mode === 'off') {
                            return 'Automation off';
                        }
                        if (mode === 'weekly' && dowField && dowField.options[dowField.selectedIndex]) {
                            return 'Weekly on ' + dowField.options[dowField.selectedIndex].text + (time ? ' at ' + time : '');
                        }
                        if (mode === 'monthly') {
                            return 'Monthly on day ' + ((domField && domField.value) ? domField.value : '—') + (time ? ' at ' + time : '');
                        }
                        return scheduleModeLabel(mode) + (time ? ' at ' + time : '');
                    }

                    function wireDirtyForm(form, submitButton, options) {
                        if (!form || !submitButton) {
                            return;
                        }
                        if (options && typeof options.beforeState === 'function') {
                            options.beforeState(form);
                        }
                        var initialState = captureFormState(form);
                        function update() {
                            if (options && typeof options.beforeState === 'function') {
                                options.beforeState(form);
                            }
                            var dirty = captureFormState(form) !== initialState;
                            var valid = !options || typeof options.validate !== 'function' ? true : options.validate(form);
                            var editable = form.dataset.editable !== '0';
                            submitButton.disabled = !editable || !dirty || !valid;
                            submitButton.classList.toggle('is-dirty', editable && dirty && valid);
                            form.classList.toggle('is-dirty', editable && dirty);
                            if (options && typeof options.syncUi === 'function') {
                                options.syncUi(form, dirty, valid, editable);
                            }
                        }
                        form.querySelectorAll('input, select, textarea').forEach(function (field) {
                            field.addEventListener('input', update);
                            field.addEventListener('change', update);
                        });
                        update();
                    }

                    var scheduleForm = document.getElementById('opsgate-schedule-form');
                    var scheduleButton = document.getElementById('opsgate-save-schedule');
                    resetFormToRenderedState(scheduleForm);
                    if (scheduleForm) {
                        var scheduleModeField = scheduleForm.querySelector('[name="opsgate_schedules[portfolio_triage][mode]"]');
                        var scheduleToggleField = document.getElementById('opsgate-scheduling-enabled');
                        if (scheduleModeField && scheduleToggleField) {
                            scheduleModeField.addEventListener('change', function () {
                                if ((scheduleModeField.value || 'off') === 'off') {
                                    scheduleToggleField.checked = false;
                                } else {
                                    scheduleModeField.dataset.lastLiveMode = scheduleModeField.value;
                                }
                            });
                            scheduleToggleField.addEventListener('change', function () {
                                if (scheduleToggleField.checked && (scheduleModeField.value || 'off') === 'off') {
                                    scheduleModeField.value = scheduleModeField.dataset.lastLiveMode || firstEnabledScheduleMode(scheduleModeField);
                                }
                            });
                        }
                    }
                    wireDirtyForm(scheduleForm, scheduleButton, {
                        beforeState: syncScheduleModeFields,
                        validate: scheduleFormIsValid,
                        syncUi: function (form, dirty, valid, editable) {
                            var currentScheduleLabel = document.getElementById('opsgate-current-schedule-label');
                            var scheduleState = document.getElementById('opsgate-schedule-automation-state');
                            var schedulePill = document.getElementById('opsgate-schedule-automation-pill');
                            var scheduleHeroCopy = document.getElementById('opsgate-schedule-hero-copy');
                            var scheduleMode = form.querySelector('[name="opsgate_schedules[portfolio_triage][mode]"]');
                            var scheduleToggle = document.getElementById('opsgate-scheduling-enabled');
                            var scheduleNote = document.getElementById('opsgate-schedule-save-note');
                            var enabled = !!(scheduleToggle && scheduleToggle.checked && scheduleMode && scheduleMode.value !== 'off');
                            var modeLabel = scheduleMode && scheduleMode.value ? scheduleMode.value : 'off';
                            if (scheduleState) {
                                scheduleState.textContent = enabled ? 'Enabled' : 'Disabled';
                            }
                            if (currentScheduleLabel) {
                                currentScheduleLabel.textContent = scheduleCurrentLabel(form, enabled);
                            }
                            if (schedulePill) {
                                schedulePill.textContent = enabled ? 'Enabled' : 'Disabled';
                                schedulePill.classList.toggle('opsgate-overview-pill-soft-good', enabled);
                                schedulePill.classList.toggle('opsgate-overview-pill-soft-warn', !enabled);
                            }
                            if (scheduleHeroCopy) {
                                if (!editable) {
                                    scheduleHeroCopy.textContent = 'Schedule changes are locked for the current package or site state.';
                                } else if (dirty && valid) {
                                    scheduleHeroCopy.textContent = enabled
                                        ? 'Pending change: automated checks will run on the selected cadence after you save.'
                                        : 'Pending change: automated checks will stay off after you save.';
                                } else if (dirty && !valid) {
                                    scheduleHeroCopy.textContent = 'Finish the required schedule details before saving this change.';
                                } else {
                                    scheduleHeroCopy.textContent = enabled
                                        ? 'Managed schedule is currently enabled for this site.'
                                        : 'Managed schedule is currently disabled for this site.';
                                }
                            }
                            if (scheduleNote) {
                                if (!editable) {
                                    scheduleNote.textContent = 'Schedule controls are read-only on the current package or site state.';
                                } else if (dirty && !valid) {
                                    scheduleNote.textContent = modeLabel === 'weekly'
                                        ? 'Choose a day of week before saving the updated schedule.'
                                        : (modeLabel === 'monthly'
                                            ? 'Choose a day of month between 1 and 31 before saving the updated schedule.'
                                            : 'Enter a valid run time before saving the updated schedule.');
                                } else if (dirty) {
                                    scheduleNote.textContent = enabled
                                        ? 'Unsaved change: save to update your OpsGate schedule and next due calculation.'
                                        : 'Unsaved change: save to turn automation off in your OpsGate account.';
                                } else {
                                    scheduleNote.textContent = enabled
                                        ? 'Changes are saved to your OpsGate account.'
                                        : 'Automation is off. Save to store the updated schedule in your OpsGate account.';
                                }
                            }
                        }
                    });

                    var siteConfigForm = document.getElementById('opsgate-site-config-form');
                    var siteConfigButton = document.getElementById('opsgate-save-site-config');
                    resetFormToRenderedState(siteConfigForm);
                    wireDirtyForm(siteConfigForm, siteConfigButton, {
                        validate: function (form) {
                            return typeof form.checkValidity === 'function' ? form.checkValidity() : true;
                        },
                        syncUi: function (form, dirty, valid, editable) {
                            var activityCheckbox = document.getElementById('opsgate-telemetry-enabled');
                            var activityState = document.getElementById('opsgate-activity-dashboard-state');
                            var activityChip = document.getElementById('opsgate-activity-dashboard-chip');
                            var activityCopy = document.getElementById('opsgate-activity-dashboard-copy');
                            var siteConfigNote = document.getElementById('opsgate-site-config-save-note');
                            var enabled = !!(activityCheckbox && activityCheckbox.checked);
                            if (activityState) {
                                activityState.textContent = enabled ? 'Enabled' : 'Disabled';
                            }
                            if (activityChip) {
                                activityChip.textContent = enabled ? 'Enabled' : 'Disabled';
                                activityChip.classList.toggle('opsgate-alerts-status-chip-good', enabled);
                                activityChip.classList.toggle('opsgate-alerts-status-chip-neutral', !enabled);
                            }
                            if (activityCopy) {
                                activityCopy.textContent = enabled
                                    ? 'Local activity log records what ran, what reports were generated, and what alerts were delivered.'
                                    : 'Local activity logging is turned off for this installation.';
                            }
                            if (siteConfigNote) {
                                if (!editable) {
                                    siteConfigNote.textContent = 'This settings surface is currently read-only.';
                                } else if (dirty && !valid) {
                                    siteConfigNote.textContent = 'Complete the required site identity fields before saving.';
                                } else if (dirty) {
                                    siteConfigNote.textContent = enabled
                                        ? 'Unsaved change: save to store the updated local activity preference and site configuration.'
                                        : 'Unsaved change: save to turn local activity off and store the updated site configuration.';
                                } else {
                                    siteConfigNote.textContent = 'Changes are saved to your OpsGate account and this site\'s local settings.';
                                }
                            }
                        }
                    });

                    var supportExportButton = document.getElementById('opsgate-support-export-button');
                    var supportExportStatus = document.getElementById('opsgate-support-export-status');
                    if (supportExportButton && supportExportStatus) {
                        supportExportButton.addEventListener('click', function () {
                            supportExportStatus.textContent = 'Preparing support export… your ZIP download will start if the export is available.';
                        });
                    }

                    // Settings sub-tab switching
                    (function () {
                        var navBtns = document.querySelectorAll('.opsgate-settings-subnav-btn');
                        var panels  = document.querySelectorAll('[data-og-settings-panel]');
                        if (!navBtns.length || !panels.length) { return; }

                        function activateTab(tabKey) {
                            navBtns.forEach(function (btn) {
                                var active = btn.getAttribute('data-og-settings-tab') === tabKey;
                                btn.classList.toggle('is-active', active);
                                btn.setAttribute('aria-selected', active ? 'true' : 'false');
                            });
                            panels.forEach(function (panel) {
                                panel.style.display = panel.getAttribute('data-og-settings-panel') === tabKey ? '' : 'none';
                            });
                        }

                        // Default: show schedule, hide others
                        var defaultTab = 'schedule';
                        // If URL has section=site-configuration, open the site tab
                        try {
                            var urlSection = new URLSearchParams(window.location.search).get('section') || '';
                            if (urlSection === 'site-configuration') { defaultTab = 'site'; }
                        } catch (e) {}

                        activateTab(defaultTab);

                        navBtns.forEach(function (btn) {
                            btn.addEventListener('click', function () {
                                activateTab(btn.getAttribute('data-og-settings-tab'));
                            });
                        });
                    }());
                }());
                </script>


            <?php elseif ( 'billing' === $active_tab ) : ?>
                <?php
                // Billing reads from effective state — no separate entitlement call.
                $ent_plan            = $eff_state['entitlement_snapshot'];
                $current_plan        = $eff_state['effective_plan'];
                $plan_src            = $eff_state['plan_source'];
                $package_snapshot    = self::current_package_snapshot();
                $current_package     = self::current_package_entry();
                $comparison_entries  = self::package_comparison_entries();
                // When operator override is active, the API package is suppressed and comparison_entries
                // is empty. Build a minimal static comparison so tier cards still render for journey testing.
                // This is intentional: operator/release testing requires seeing all four tiers.
                if ( empty( $comparison_entries ) && 'operator_override' === $plan_src ) {
                    $comparison_entries = array(
                        array( 'plan_key' => 'free',    'display_name' => 'Free',    'scope_allowances' => array( 'summary_label' => '1 account · 1 site' ),        'target_buyer' => 'Site owner who wants an instant security baseline before committing', 'buyer_outcome' => 'Instant public security scan — see your SSL, reachability, and performance score in seconds, free forever', 'live_now' => array( 'Free public security assessment — no account required.', 'SSL, reachability, and performance scan with independently verified score.', 'Upgrade path remains clear when plugin vulnerability checks or client reports are needed.' ), 'visible_locked' => array( 'Plugin vulnerability checks', 'Scheduled automated scans', 'Client-ready PDF, HTML, CSV, and Excel security reports' ), 'visible_direction' => array( 'Portfolio and multi-site operations become available at higher tiers.', 'Connected alert routing, scheduled vulnerability scanning, and downloadable reports require Starter or above.' ), 'pricing' => array( 'display' => '$0' ), 'upgrade_reason' => 'Upgrade to Starter to connect this site, run plugin vulnerability scans, and generate your first client-ready security report.' ),
                        array( 'plan_key' => 'starter', 'display_name' => 'Starter', 'scope_allowances' => array( 'summary_label' => '1 account · 1 site · 1 email · 1 webhook · 1 Telegram' ), 'target_buyer' => 'Solo operator or consultant managing one client site', 'buyer_outcome' => 'Prove your site\'s security to one client — plugin CVE scans, a PDF report they can read, and email alerts when something changes', 'live_now' => array( 'Connected WordPress security scan with plugin CVE checks.', 'PDF security report ready to share with clients.', 'Email alert when vulnerabilities or updates are detected.', 'Webhook notification for one configured destination.' ), 'visible_locked' => array( 'Daily automated scans', 'HTML and CSV report outputs', 'XLSX report output' ), 'visible_direction' => array( 'Pro expands to five sites, daily schedules, and broader alert channels for growing teams.' ), 'pricing' => array( 'display' => '$19/month' ), 'upgrade_reason' => 'Upgrade to Pro for multi-site security operations, daily automated scans, and broader report formats.' ),
                        array( 'plan_key' => 'pro',     'display_name' => 'Pro',     'scope_allowances' => array( 'summary_label' => '1 account · 5 sites · 5 email · 5 webhook · 5 Telegram · 5 Slack · 5 WhatsApp' ), 'target_buyer' => 'Freelancer or small agency managing up to five client sites', 'buyer_outcome' => 'Security operations across five sites — scheduled CVE scans, PDF and HTML reports per client, and real-time alerts across Slack, email, and webhook', 'live_now' => array( 'Security triage across up to five connected sites.', 'Scheduled daily scans — no manual trigger needed.', 'HTML, PDF, and CSV security reports per site.', 'Slack, email, webhook, Telegram, and WhatsApp alerts.' ), 'visible_locked' => array( 'XLSX report output', 'Agency portfolio board', 'Discord, SNS, and Teams alert channels' ), 'visible_direction' => array( 'Agency unlocks portfolio-scale operations and broader alert routing for larger client rosters.' ), 'pricing' => array( 'display' => '$59/month up to 5 sites' ), 'upgrade_reason' => 'Upgrade to Agency for portfolio-wide security operations, XLSX reports, and a broader set of alert channels.' ),
                        array( 'plan_key' => 'agency',  'display_name' => 'Agency',  'scope_allowances' => array( 'summary_label' => '1 account · 25 sites · agency-scale alert destinations' ), 'target_buyer' => 'Agency or managed-service provider running up to 25 client WordPress sites', 'buyer_outcome' => 'Portfolio-scale security operations — CVE scans, XLSX and HTML reports, and real-time alerts across every major channel for up to 25 sites', 'live_now' => array( 'Security triage across up to 25 connected client sites.', 'Scheduled portfolio scans with automated alerting.', 'HTML, PDF, CSV, and XLSX security reports.', 'Email, webhook, Slack, Teams, WhatsApp, Discord, Telegram, and SNS alerts.' ), 'visible_locked' => array( 'Dedicated web console portfolio controls (coming)' ), 'visible_direction' => array( 'Dedicated portfolio console and deeper agency controls are part of the active product roadmap.' ), 'pricing' => array( 'display' => '$149/month up to 25 sites' ), 'upgrade_reason' => '' ),
                    );
                }
                $channel_families    = self::package_channel_families();
                $channel_groups      = self::package_channel_family_groups();
                $evidence_story      = self::package_evidence_governance();
                $hybrid_story        = self::hybrid_product_snapshot();
                $stripe_mode         = get_option( 'opsgate_stripe_mode', 'test' );
                $publishable_key     = get_option( 'opsgate_stripe_publishable_key', '' );
                $payment_link_start  = get_option( 'opsgate_stripe_payment_link_starter', '' );
                $payment_link_pro    = get_option( 'opsgate_stripe_payment_link_pro', '' );
                $payment_link_agency = get_option( 'opsgate_stripe_payment_link_agency', '' );
                $plan_eff           = $current_plan;
                $current_target_buyer = isset( $current_package['target_buyer'] ) ? (string) $current_package['target_buyer'] : 'Current plan truth is read from the OpsGate API.';
                $current_buyer_outcome = isset( $current_package['buyer_outcome'] ) ? (string) $current_package['buyer_outcome'] : 'Plan details are loaded from the OpsGate API.';
                $current_operational_value = isset( $current_package['operational_value'] ) ? (string) $current_package['operational_value'] : 'Operational value is read from the current package rules.';
                $current_upgrade_reason = isset( $current_package['upgrade_reason'] ) ? (string) $current_package['upgrade_reason'] : 'Upgrade path is shown when higher-tier value is relevant.';
                $current_pricing_display = isset( $current_package['pricing']['display'] ) ? (string) $current_package['pricing']['display'] : '';
                $hybrid_framing = isset( $hybrid_story['framing'] ) ? (string) $hybrid_story['framing'] : 'OpsGate is one product with site-level operations in the plugin and account-level value across the broader portfolio surface.';
                $billing_package_label = 'Current plan';
                $billing_plan_rank_map = array(
                    'free'    => 0,
                    'starter' => 1,
                    'pro'     => 2,
                    'agency'  => 3,
                );
                $current_plan_rank = isset( $billing_plan_rank_map[ $current_plan ] ) ? $billing_plan_rank_map[ $current_plan ] : -1;
                $current_display_name = isset( $current_package['display_name'] ) ? (string) $current_package['display_name'] : ucfirst( $plan_eff );
                $current_live_items = array_map(
                    static function ( $item ) {
                        return trim( str_ireplace( 'canonical schedule control', 'managed schedule control', (string) $item ) );
                    },
                    self::package_capability_items( 'live_now' )
                );
                $current_locked_items = array_values( array_filter( array_map( 'strval', self::package_capability_items( 'visible_locked' ) ) ) );
                $billing_family_labels = static function ( array $items ): array {
                    $labels = array();
                    foreach ( $items as $item ) {
                        if ( is_array( $item ) && ! empty( $item['label'] ) ) {
                            $labels[] = (string) $item['label'];
                        }
                    }
                    return array_values( array_unique( $labels ) );
                };
                $channel_live_labels = $billing_family_labels( isset( $channel_groups['live_now'] ) && is_array( $channel_groups['live_now'] ) ? $channel_groups['live_now'] : array() );
                $channel_not_live_labels = $billing_family_labels(
                    array_merge(
                        isset( $channel_groups['visible_locked'] ) && is_array( $channel_groups['visible_locked'] ) ? $channel_groups['visible_locked'] : array(),
                        isset( $channel_groups['integration_ready'] ) && is_array( $channel_groups['integration_ready'] ) ? $channel_groups['integration_ready'] : array()
                    )
                );
                $channel_planned_labels = $billing_family_labels( isset( $channel_groups['planned_direction'] ) && is_array( $channel_groups['planned_direction'] ) ? $channel_groups['planned_direction'] : array() );
                $billing_confidence_copy = isset( $evidence_story['summary'] ) && '' !== trim( (string) $evidence_story['summary'] )
                    ? (string) $evidence_story['summary']
                    : 'Evidence governance and retention remain visible across packaged exports.';
                $billing_confidence_title = isset( $evidence_story['headline'] ) && '' !== trim( (string) $evidence_story['headline'] )
                    ? (string) $evidence_story['headline']
                    : 'Purchase confidence';
                $billing_surface_model_copy = 'Site operations stay in the plugin. Portfolio and account operations expand in the web console as tiers increase.';
                $billing_pricing_display = static function ( array $package_entry ): array {
                    $pricing = isset( $package_entry['pricing'] ) && is_array( $package_entry['pricing'] ) ? $package_entry['pricing'] : array();
                    return array(
                        'price'     => isset( $pricing['display'] ) ? (string) $pricing['display'] : '',
                        'footprint' => self::package_scope_allowance_label_for_entry( $package_entry ),
                    );
                };
                $current_pricing_parts = $billing_pricing_display( is_array( $current_package ) ? $current_package : array() );
                $billing_next_tier = array();
                foreach ( $comparison_entries as $comparison_entry ) {
                    if ( ! is_array( $comparison_entry ) ) {
                        continue;
                    }
                    $comparison_plan_key = isset( $comparison_entry['plan_key'] ) ? (string) $comparison_entry['plan_key'] : '';
                    $comparison_rank = isset( $billing_plan_rank_map[ $comparison_plan_key ] ) ? $billing_plan_rank_map[ $comparison_plan_key ] : -1;
                    if ( $comparison_rank <= $current_plan_rank ) {
                        continue;
                    }
                    if ( empty( $billing_next_tier ) ) {
                        $billing_next_tier = $comparison_entry;
                        continue;
                    }
                    $billing_next_rank = isset( $billing_plan_rank_map[ (string) ( $billing_next_tier['plan_key'] ?? '' ) ] ) ? $billing_plan_rank_map[ (string) $billing_next_tier['plan_key'] ] : 99;
                    if ( $comparison_rank < $billing_next_rank ) {
                        $billing_next_tier = $comparison_entry;
                    }
                }
                $billing_next_tier_label = isset( $billing_next_tier['display_name'] ) ? (string) $billing_next_tier['display_name'] : '';
                // $billing_next_move_title and $billing_next_move_copy are finalised after $p5_billing_sites_cap is known (below).
                ?>

                <?php
                // Billing usage data — fetch from entitlement snapshot API directly so limits are always
                // real regardless of operator_override (which suppresses the WP-side package snapshot).
                $p5_bill_acct_id   = isset( $eff_state['account_id'] ) ? trim( (string) $eff_state['account_id'] ) : '';
                $p5_bill_site_id   = isset( $eff_state['site_id'] ) ? trim( (string) $eff_state['site_id'] ) : '';
                $p5_bill_ent_resp  = ( '' !== $p5_bill_acct_id && '' !== $p5_bill_site_id )
                    ? self::mcp_get_json( '/v1/entitlements/snapshot/' . rawurlencode( $p5_bill_acct_id ) . '/' . rawurlencode( $p5_bill_site_id ) )
                    : array( 'ok' => false );
                $p5_bill_limits    = ( ! empty( $p5_bill_ent_resp['ok'] ) && isset( $p5_bill_ent_resp['data']['limits'] ) && is_array( $p5_bill_ent_resp['data']['limits'] ) )
                    ? $p5_bill_ent_resp['data']['limits']
                    : array();
                $p5_bill_usage_raw = ( ! empty( $p5_bill_ent_resp['ok'] ) && isset( $p5_bill_ent_resp['data']['usage'] ) && is_array( $p5_bill_ent_resp['data']['usage'] ) )
                    ? $p5_bill_ent_resp['data']['usage']
                    : array();

                // Extract caps from canonical limits object.
                $p5_billing_sites_cap      = isset( $p5_bill_limits['limits.sites.max'] ) ? (int) $p5_bill_limits['limits.sites.max'] : 0;
                $p5_billing_emails_cap     = isset( $p5_bill_limits['limits.alerts.email_destinations.max'] ) ? (int) $p5_bill_limits['limits.alerts.email_destinations.max'] : 0;
                $p5_billing_webhooks_cap   = isset( $p5_bill_limits['limits.alerts.webhook_destinations.max'] ) ? (int) $p5_bill_limits['limits.alerts.webhook_destinations.max'] : 0;
                $p5_billing_schedules_cap  = isset( $p5_bill_limits['limits.schedules.active.max'] ) ? (int) $p5_bill_limits['limits.schedules.active.max'] : 0;
                $p5_billing_uptime_cap     = isset( $p5_bill_limits['uptime.targets_per_site'] ) ? (int) $p5_bill_limits['uptime.targets_per_site'] : 0;
                $p5_billing_portfolio_cap  = isset( $p5_bill_limits['limits.portfolio.rows.max'] ) ? (int) $p5_bill_limits['limits.portfolio.rows.max'] : 0;

                // Finalise next-move card content — requires $p5_billing_sites_cap from above.
                if ( '' !== $billing_next_tier_label ) {
                    $billing_next_move_title = 'Upgrade to ' . $billing_next_tier_label;
                    $billing_next_move_copy  = $current_upgrade_reason;
                    $billing_next_move_is_agency_growth = false;
                } else {
                    $billing_sites_remaining = $p5_billing_sites_cap > 0 ? max( 0, $p5_billing_sites_cap - 1 ) : 0;
                    $billing_next_move_title = $p5_billing_sites_cap > 0
                        ? (string) $billing_sites_remaining . ' site slot' . ( 1 === $billing_sites_remaining ? '' : 's' ) . ' remaining'
                        : 'Agency plan active';
                    $billing_next_move_copy  = $p5_billing_sites_cap > 0
                        ? 'You\'re on Agency. Add more sites to your portfolio to fill your available capacity.'
                        : 'You are on the highest commercial tier.';
                    $billing_next_move_is_agency_growth = true;
                }

                // Extract actual usage from canonical usage object.
                $p5_billing_schedules_used = isset( $p5_bill_usage_raw['limits.schedules.active.max']['used'] ) ? (int) $p5_bill_usage_raw['limits.schedules.active.max']['used'] : -1;

                // Notification destinations — count by family (API uses 'family', not 'destination_family').
                $p5_billing_dest_resp  = self::mcp_get_json( '/v1/notification-destinations' );
                $p5_billing_dest_items = ! empty( $p5_billing_dest_resp['ok'] ) && isset( $p5_billing_dest_resp['data']['items'] ) && is_array( $p5_billing_dest_resp['data']['items'] )
                    ? $p5_billing_dest_resp['data']['items']
                    : ( isset( $p5_billing_dest_resp['items'] ) && is_array( $p5_billing_dest_resp['items'] ) ? $p5_billing_dest_resp['items'] : array() );
                $p5_billing_email_count   = 0;
                $p5_billing_webhook_count = 0;
                foreach ( $p5_billing_dest_items as $p5_bd ) {
                    if ( ! is_array( $p5_bd ) ) {
                        continue;
                    }
                    // API returns 'family'; some versions also have 'destination_family' — accept both.
                    $p5_bd_family = '';
                    if ( isset( $p5_bd['family'] ) && '' !== (string) $p5_bd['family'] ) {
                        $p5_bd_family = strtolower( trim( (string) $p5_bd['family'] ) );
                    } elseif ( isset( $p5_bd['destination_family'] ) && '' !== (string) $p5_bd['destination_family'] ) {
                        $p5_bd_family = strtolower( trim( (string) $p5_bd['destination_family'] ) );
                    }
                    if ( 'email' === $p5_bd_family ) {
                        ++$p5_billing_email_count;
                    } elseif ( 'webhook' === $p5_bd_family ) {
                        ++$p5_billing_webhook_count;
                    }
                }

                // Uptime monitors count.
                $p5_billing_uptime_resp   = self::mcp_get_json( '/v1/sites/uptime-monitors' );
                $p5_billing_uptime_items  = ! empty( $p5_billing_uptime_resp['ok'] ) && isset( $p5_billing_uptime_resp['data']['items'] ) && is_array( $p5_billing_uptime_resp['data']['items'] )
                    ? $p5_billing_uptime_resp['data']['items']
                    : ( isset( $p5_billing_uptime_resp['items'] ) && is_array( $p5_billing_uptime_resp['items'] ) ? $p5_billing_uptime_resp['items'] : array() );
                $p5_billing_uptime_count  = count( $p5_billing_uptime_items );

                // Hero copy — human wording for paid plans.
                $billing_plan_hero_copy = $current_buyer_outcome;
                if ( '' === $billing_plan_hero_copy || 'Plan details are loaded from the OpsGate API.' === $billing_plan_hero_copy ) {
                    $billing_plan_hero_copy = 'Your ' . $current_display_name . ' plan is active. Usage and included capabilities are shown below.';
                }

                $billing_allowance_label = self::package_scope_allowance_label();
                if ( '' === $billing_allowance_label || 'Plan details loading' === $billing_allowance_label ) {
                    $billing_allowance_label = ucfirst( $current_plan ) . ' plan active';
                }
                $billing_allowance_summary = self::package_scope_allowance_summary();
                if ( '' === $billing_allowance_summary || false !== strpos( $billing_allowance_summary, 'canonical package truth' ) ) {
                    $billing_allowance_summary = 'Plan limits are read from the OpsGate API.';
                }
                $billing_confidence_label = ( 'Purchase confidence' === $billing_confidence_title ) ? 'Audit-ready exports included' : $billing_confidence_title;
                ?>

                <div class="opsgate-card opsgate-billing-layout">
                    <h2><span class="dashicons dashicons-tickets-alt"></span> Billing</h2>

                    <?php /* ── 1. Current plan hero ── */ ?>
                    <div class="opsgate-billing-plan-hero">
                        <div class="opsgate-billing-plan-hero-main">
                            <span class="opsgate-overview-eyebrow"><?php echo esc_html( $billing_package_label ); ?></span>
                            <div class="opsgate-billing-hero-title-row">
                                <h3 class="opsgate-billing-plan-name"><?php echo esc_html( $current_display_name ); ?></h3>
                                <?php if ( '' !== (string) $current_pricing_parts['price'] ) : ?>
                                    <span class="opsgate-pricing-badge opsgate-pricing-badge-hero"><?php echo esc_html( (string) $current_pricing_parts['price'] ); ?></span>
                                <?php endif; ?>
                            </div>
                            <?php
                            $billing_hero_footprint = (string) $current_pricing_parts['footprint'];
                            if ( '' !== $billing_hero_footprint && 'Plan details loading' !== $billing_hero_footprint ) :
                            ?>
                                <p class="opsgate-billing-hero-footprint"><?php echo esc_html( $billing_hero_footprint ); ?></p>
                            <?php endif; ?>
                            <p class="opsgate-billing-plan-copy"><?php echo esc_html( $billing_plan_hero_copy ); ?></p>
                        </div>
                        <div class="opsgate-billing-plan-hero-side">
                            <div class="opsgate-billing-next-move-card">
                                <span class="opsgate-overview-eyebrow">Next relevant move</span>
                                <div class="opsgate-billing-next-move-title"><?php echo esc_html( $billing_next_move_title ); ?></div>
                                <p class="opsgate-billing-next-move-copy"><?php echo esc_html( $billing_next_move_copy ); ?></p>
                                <?php if ( ! empty( $billing_next_move_is_agency_growth ) ) : ?>
                                <a class="opsgate-billing-next-move-cta" href="<?php echo esc_url( admin_url( 'admin.php?page=opsgate&tab=portfolio' ) ); ?>">Go to Portfolio &rarr;</a>
                                <?php endif; ?>
                            </div>
                        </div>
                    </div>

                    <?php /* ── 2. Plan Usage — caps from /v1/entitlements/snapshot, usage from live API ── */ ?>
                    <div class="opsgate-billing-usage-section">
                        <h4 class="opsgate-billing-usage-heading">Plan Usage</h4>
                        <div class="opsgate-billing-usage-grid">

                            <?php /* Sites — cap from limits.sites.max; used = connected sites on this account */ ?>
                            <?php if ( $p5_billing_sites_cap > 0 ) : ?>
                            <div class="opsgate-billing-usage-card">
                                <span class="opsgate-billing-usage-label">Connected sites</span>
                                <span class="opsgate-billing-usage-value">1 / <?php echo esc_html( (string) $p5_billing_sites_cap ); ?></span>
                                <div class="opsgate-billing-usage-bar-track">
                                    <div class="opsgate-billing-usage-bar-fill" style="width:<?php echo esc_attr( (string) min( 100, (int) round( 1 / $p5_billing_sites_cap * 100 ) ) ); ?>%"></div>
                                </div>
                            </div>
                            <?php else : ?>
                            <div class="opsgate-billing-usage-card">
                                <span class="opsgate-billing-usage-label">Connected sites</span>
                                <span class="opsgate-billing-usage-unavailable">Usage is being refreshed.</span>
                            </div>
                            <?php endif; ?>

                            <?php /* Email destinations — cap from limits.alerts.email_destinations.max; used from /v1/notification-destinations */ ?>
                            <?php if ( $p5_billing_emails_cap > 0 ) : ?>
                            <div class="opsgate-billing-usage-card">
                                <span class="opsgate-billing-usage-label">Email destinations</span>
                                <span class="opsgate-billing-usage-value"><?php echo esc_html( $p5_billing_email_count . ' / ' . (string) $p5_billing_emails_cap ); ?></span>
                                <div class="opsgate-billing-usage-bar-track">
                                    <div class="opsgate-billing-usage-bar-fill" style="width:<?php echo esc_attr( (string) min( 100, $p5_billing_emails_cap > 0 ? (int) round( $p5_billing_email_count / $p5_billing_emails_cap * 100 ) : 0 ) ); ?>%"></div>
                                </div>
                            </div>
                            <?php else : ?>
                            <div class="opsgate-billing-usage-card">
                                <span class="opsgate-billing-usage-label">Email destinations</span>
                                <span class="opsgate-billing-usage-unavailable">Not included on this plan.</span>
                            </div>
                            <?php endif; ?>

                            <?php /* Webhook destinations — cap from limits.alerts.webhook_destinations.max */ ?>
                            <?php if ( $p5_billing_webhooks_cap > 0 ) : ?>
                            <div class="opsgate-billing-usage-card">
                                <span class="opsgate-billing-usage-label">Webhook destinations</span>
                                <span class="opsgate-billing-usage-value"><?php echo esc_html( $p5_billing_webhook_count . ' / ' . (string) $p5_billing_webhooks_cap ); ?></span>
                                <div class="opsgate-billing-usage-bar-track">
                                    <div class="opsgate-billing-usage-bar-fill" style="width:<?php echo esc_attr( (string) min( 100, $p5_billing_webhooks_cap > 0 ? (int) round( $p5_billing_webhook_count / $p5_billing_webhooks_cap * 100 ) : 0 ) ); ?>%"></div>
                                </div>
                            </div>
                            <?php else : ?>
                            <div class="opsgate-billing-usage-card">
                                <span class="opsgate-billing-usage-label">Webhook destinations</span>
                                <span class="opsgate-billing-usage-unavailable">Not included on this plan.</span>
                            </div>
                            <?php endif; ?>

                            <?php /* Active schedules — cap from limits.schedules.active.max; used from usage object */ ?>
                            <?php if ( $p5_billing_schedules_cap > 0 ) : ?>
                            <div class="opsgate-billing-usage-card">
                                <span class="opsgate-billing-usage-label">Active schedules</span>
                                <?php if ( $p5_billing_schedules_used >= 0 ) : ?>
                                <span class="opsgate-billing-usage-value"><?php echo esc_html( $p5_billing_schedules_used . ' / ' . (string) $p5_billing_schedules_cap ); ?></span>
                                <div class="opsgate-billing-usage-bar-track">
                                    <div class="opsgate-billing-usage-bar-fill" style="width:<?php echo esc_attr( (string) min( 100, $p5_billing_schedules_cap > 0 ? (int) round( $p5_billing_schedules_used / $p5_billing_schedules_cap * 100 ) : 0 ) ); ?>%"></div>
                                </div>
                                <?php else : ?>
                                <span class="opsgate-billing-usage-value">— / <?php echo esc_html( (string) $p5_billing_schedules_cap ); ?></span>
                                <span class="opsgate-billing-usage-unavailable">Usage is being refreshed.</span>
                                <?php endif; ?>
                            </div>
                            <?php else : ?>
                            <div class="opsgate-billing-usage-card">
                                <span class="opsgate-billing-usage-label">Active schedules</span>
                                <span class="opsgate-billing-usage-unavailable">Not included on this plan.</span>
                            </div>
                            <?php endif; ?>

                            <?php /* Uptime monitors — cap from uptime.targets_per_site; used from /v1/sites/uptime-monitors */ ?>
                            <?php if ( $p5_billing_uptime_cap > 0 ) : ?>
                            <div class="opsgate-billing-usage-card">
                                <span class="opsgate-billing-usage-label">Uptime monitors</span>
                                <span class="opsgate-billing-usage-value"><?php echo esc_html( $p5_billing_uptime_count . ' / ' . (string) $p5_billing_uptime_cap ); ?></span>
                                <div class="opsgate-billing-usage-bar-track">
                                    <div class="opsgate-billing-usage-bar-fill" style="width:<?php echo esc_attr( (string) min( 100, $p5_billing_uptime_cap > 0 ? (int) round( $p5_billing_uptime_count / $p5_billing_uptime_cap * 100 ) : 0 ) ); ?>%"></div>
                                </div>
                            </div>
                            <?php else : ?>
                            <div class="opsgate-billing-usage-card">
                                <span class="opsgate-billing-usage-label">Uptime monitors</span>
                                <span class="opsgate-billing-usage-unavailable">Not included on this plan.</span>
                            </div>
                            <?php endif; ?>

                            <?php /* Portfolio sites — cap from limits.portfolio.rows.max */ ?>
                            <?php if ( $p5_billing_portfolio_cap > 0 ) : ?>
                            <div class="opsgate-billing-usage-card">
                                <span class="opsgate-billing-usage-label">Portfolio capacity</span>
                                <span class="opsgate-billing-usage-value">Up to <?php echo esc_html( (string) $p5_billing_portfolio_cap ); ?> sites</span>
                            </div>
                            <?php endif; ?>

                        </div>
                    </div>


                    <div class="opsgate-pricing-form">

                        <div class="opsgate-billing-section-head">
                            <div>
                                <h3 class="title">Choose the right package</h3>
                                <p class="description">
                                    Compare live capabilities, locked expansion, and the next relevant tier move across Free, Starter, Pro, and Agency.
                                </p>
                            </div>
                        </div>

                        <div class="opsgate-pricing-grid opsgate-billing-comparison-grid">
                            <?php foreach ( $comparison_entries as $comparison_entry ) : ?>
                                <?php
                                if ( ! is_array( $comparison_entry ) ) {
                                    continue;
                                }
                                $comparison_plan_key = isset( $comparison_entry['plan_key'] ) ? (string) $comparison_entry['plan_key'] : '';
                                $comparison_rank = isset( $billing_plan_rank_map[ $comparison_plan_key ] ) ? $billing_plan_rank_map[ $comparison_plan_key ] : -1;
                                $comparison_display = isset( $comparison_entry['display_name'] ) ? (string) $comparison_entry['display_name'] : ucfirst( $comparison_plan_key );
                                $comparison_pricing_parts = $billing_pricing_display( $comparison_entry );
                                $comparison_target = isset( $comparison_entry['target_buyer'] ) ? (string) $comparison_entry['target_buyer'] : '';
                                $comparison_outcome = isset( $comparison_entry['buyer_outcome'] ) ? (string) $comparison_entry['buyer_outcome'] : '';
                                $comparison_value = isset( $comparison_entry['operational_value'] ) ? (string) $comparison_entry['operational_value'] : '';
                                $comparison_upgrade = isset( $comparison_entry['upgrade_reason'] ) ? (string) $comparison_entry['upgrade_reason'] : '';
                                $comparison_live = isset( $comparison_entry['live_now'] ) && is_array( $comparison_entry['live_now'] ) ? $comparison_entry['live_now'] : array();
                                $comparison_locked = isset( $comparison_entry['visible_locked'] ) && is_array( $comparison_entry['visible_locked'] ) ? $comparison_entry['visible_locked'] : array();
                                $comparison_direction = isset( $comparison_entry['visible_direction'] ) && is_array( $comparison_entry['visible_direction'] ) ? $comparison_entry['visible_direction'] : array();
                                ?>
                                <div class="opsgate-pricing-card opsgate-billing-tier-card<?php echo $comparison_plan_key === $current_plan ? ' is-current' : ''; ?>">
                                    <div class="opsgate-billing-tier-head">
                                        <h4><?php echo esc_html( $comparison_display ); ?></h4>
                                        <?php if ( $comparison_plan_key === $current_plan ) : ?>
                                            <span class="opsgate-pricing-badge">Current</span>
                                        <?php endif; ?>
                                    </div>
                                    <?php if ( '' !== (string) $comparison_pricing_parts['price'] ) : ?>
                                        <div class="opsgate-billing-tier-price"><?php echo esc_html( (string) $comparison_pricing_parts['price'] ); ?></div>
                                    <?php endif; ?>
                                    <?php if ( '' !== (string) $comparison_pricing_parts['footprint'] ) : ?>
                                        <div class="opsgate-billing-tier-footprint"><?php echo esc_html( (string) $comparison_pricing_parts['footprint'] ); ?></div>
                                    <?php endif; ?>
                                    <p class="opsgate-billing-tier-summary"><?php echo esc_html( '' !== $comparison_outcome ? $comparison_outcome : $comparison_target ); ?></p>
                                    <?php if ( '' !== $comparison_value ) : ?>
                                        <p class="opsgate-billing-tier-note"><?php echo esc_html( $comparison_value ); ?></p>
                                    <?php endif; ?>

                                    <div class="opsgate-billing-tier-groups">
                                        <?php if ( ! empty( $comparison_live ) ) : ?>
                                            <div class="opsgate-billing-tier-group">
                                                <span class="opsgate-overview-eyebrow">Live now</span>
                                                <ul>
                                                    <?php foreach ( array_slice( $comparison_live, 0, 4 ) as $comparison_live_item ) : ?>
                                                        <li><?php echo esc_html( (string) $comparison_live_item ); ?></li>
                                                    <?php endforeach; ?>
                                                </ul>
                                            </div>
                                        <?php endif; ?>
                                        <?php if ( ! empty( $comparison_locked ) ) : ?>
                                            <div class="opsgate-billing-tier-group">
                                                <span class="opsgate-overview-eyebrow">Locked until upgrade</span>
                                                <ul>
                                                    <?php foreach ( array_slice( $comparison_locked, 0, 3 ) as $comparison_locked_item ) : ?>
                                                        <li><?php echo esc_html( (string) $comparison_locked_item ); ?></li>
                                                    <?php endforeach; ?>
                                                </ul>
                                            </div>
                                        <?php endif; ?>
                                        <?php if ( ! empty( $comparison_direction ) ) : ?>
                                            <div class="opsgate-billing-tier-group">
                                                <span class="opsgate-overview-eyebrow">Planned direction</span>
                                                <ul>
                                                    <?php foreach ( array_slice( $comparison_direction, 0, 2 ) as $comparison_direction_item ) : ?>
                                                        <li><?php echo esc_html( (string) $comparison_direction_item ); ?></li>
                                                    <?php endforeach; ?>
                                                </ul>
                                            </div>
                                        <?php endif; ?>
                                    </div>

                                    <div class="opsgate-billing-tier-footer">
                                        <?php if ( $comparison_plan_key === $current_plan ) : ?>
                                            <span class="opsgate-alerts-status-chip opsgate-alerts-status-chip-good">Current plan</span>
                                        <?php elseif ( $comparison_rank > $current_plan_rank ) : ?>
                                            <!-- Phase 5: Only show upgrade (not downgrade). Use Stripe link if configured. -->
                                            <?php
                                            $p5_tier_stripe_link = '';
                                            if ( 'starter' === $comparison_plan_key ) {
                                                $p5_tier_stripe_link = trim( (string) get_option( 'opsgate_stripe_payment_link_starter', '' ) );
                                            } elseif ( 'pro' === $comparison_plan_key ) {
                                                $p5_tier_stripe_link = trim( (string) get_option( 'opsgate_stripe_payment_link_pro', '' ) );
                                            } elseif ( 'agency' === $comparison_plan_key ) {
                                                $p5_tier_stripe_link = trim( (string) get_option( 'opsgate_stripe_payment_link_agency', '' ) );
                                            }
                                            ?>
                                            <div class="opsgate-billing-tier-upgrade-note"><?php echo esc_html( $comparison_upgrade ); ?></div>
                                            <?php
                                            // If tier-specific link is empty, fall back to the Pro Stripe link.
                                            if ( '' === $p5_tier_stripe_link ) {
                                                $p5_tier_stripe_link = trim( (string) get_option( 'opsgate_stripe_payment_link_pro', '' ) );
                                            }
                                            ?>
                                            <?php if ( '' !== $p5_tier_stripe_link ) : ?>
                                                <a href="<?php echo esc_url( $p5_tier_stripe_link ); ?>" target="_blank" rel="noopener noreferrer" class="button button-primary opsgate-p5-upgrade-btn">
                                                    <?php echo esc_html( 'Upgrade to ' . $comparison_display . ' →' ); ?>
                                                </a>
                                            <?php else : ?>
                                                <span class="opsgate-p5-meta-text">Upgrade link not configured — contact support@opsgate.ca</span>
                                            <?php endif; ?>
                                        <?php else : ?>
                                            <span class="opsgate-p5-meta-text">Current plan is higher than this tier</span>
                                        <?php endif; ?>
                                        <?php if ( current_user_can( 'manage_options' ) && $comparison_plan_key !== $current_plan ) : ?>
                                        <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin-top:8px;">
                                            <?php wp_nonce_field( 'opsgate_set_plan_override', 'opsgate_plan_override_nonce' ); ?>
                                            <input type="hidden" name="action" value="opsgate_set_plan_override" />
                                            <input type="hidden" name="opsgate_plan_override" value="<?php echo esc_attr( $comparison_plan_key ); ?>" />
                                            <?php submit_button( 'Test as ' . $comparison_display, 'secondary small', 'submit', false, array( 'style' => 'margin:0;font-size:11px;', 'title' => 'Operator only: simulate this tier for journey testing' ) ); ?>
                                        </form>
                                        <?php endif; ?>
                                    </div>
                                </div>
                            <?php endforeach; ?>
                        </div>

                        <div class="opsgate-alert-panel" style="margin-top:16px;">
                            <p><strong>Upgrade processing?</strong> After completing checkout, refresh this page to load your updated plan status. If your plan does not update within a few minutes, contact us at support@opsgate.ca.</p>
                        </div>

                        <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="opsgate-billing-payment-form">
                            <?php wp_nonce_field( 'opsgate_save_pricing_settings', 'opsgate_pricing_nonce' ); ?>
                            <input type="hidden" name="action" value="opsgate_save_pricing_settings" />

                        <details class="opsgate-advanced-details opsgate-billing-operator-details opsgate-operator-only" style="margin-top:24px;">
                            <summary><strong>Operator billing settings</strong></summary>
                            <div class="opsgate-billing-operator-body">
                                <div class="opsgate-billing-payment-strip">
                                    <article class="opsgate-pricing-summary-card opsgate-billing-payment-mode-card">
                                        <span class="opsgate-overview-eyebrow">Stripe mode</span>
                                        <div class="opsgate-pricing-hero-side-title"><?php echo esc_html( strtoupper( (string) $stripe_mode ) ); ?></div>
                                        <p>Payments are processed securely through Stripe when payment links are configured.</p>
                                    </article>
                                </div>
                                <div class="opsgate-billing-payment-grid">
                                    <div class="opsgate-billing-payment-field">
                                        <label for="opsgate_stripe_publishable_key"><strong>Stripe Publishable Key</strong> <span class="description">(optional)</span></label>
                                        <input
                                            type="text"
                                            class="regular-text"
                                            id="opsgate_stripe_publishable_key"
                                            name="opsgate_stripe_publishable_key"
                                            value="<?php echo esc_attr( is_string( $publishable_key ) ? $publishable_key : '' ); ?>"
                                            placeholder="pk_test_..."
                                        />
                                        <p class="description">Public Stripe key for billing surfaces that need it.</p>
                                    </div>
                                    <div class="opsgate-billing-payment-field">
                                        <label for="opsgate_stripe_payment_link_starter"><strong>Starter upgrade link</strong></label>
                                        <input
                                            type="url"
                                            class="regular-text"
                                            id="opsgate_stripe_payment_link_starter"
                                            name="opsgate_stripe_payment_link_starter"
                                            value="<?php echo esc_attr( is_string( $payment_link_start ) ? $payment_link_start : '' ); ?>"
                                            placeholder="https://buy.stripe.com/test_..."
                                        />
                                        <p class="description">Stripe payment link for the Starter tier.</p>
                                    </div>
                                    <div class="opsgate-billing-payment-field">
                                        <label for="opsgate_stripe_payment_link_pro"><strong>Pro upgrade link</strong></label>
                                        <input
                                            type="url"
                                            class="regular-text"
                                            id="opsgate_stripe_payment_link_pro"
                                            name="opsgate_stripe_payment_link_pro"
                                            value="<?php echo esc_attr( is_string( $payment_link_pro ) ? $payment_link_pro : '' ); ?>"
                                            placeholder="https://buy.stripe.com/test_..."
                                        />
                                        <p class="description">Stripe payment link for the Pro tier.</p>
                                    </div>
                                    <div class="opsgate-billing-payment-field">
                                        <label for="opsgate_stripe_payment_link_agency"><strong>Agency upgrade link</strong></label>
                                        <input
                                            type="url"
                                            class="regular-text"
                                            id="opsgate_stripe_payment_link_agency"
                                            name="opsgate_stripe_payment_link_agency"
                                            value="<?php echo esc_attr( is_string( $payment_link_agency ) ? $payment_link_agency : '' ); ?>"
                                            placeholder="https://buy.stripe.com/test_..."
                                        />
                                        <p class="description">Stripe payment link for the portfolio/account tier.</p>
                                    </div>
                                </div>
                                <div class="submit-box opsgate-billing-payment-save">
                                    <?php submit_button( 'Save Pricing & Stripe Settings', 'primary large', 'submit', false ); ?>
                                </div>
                                <?php
                                $plan_override_current = self::normalize_plan( trim( (string) get_option( 'opsgate_plan_operator_override', '' ) ) );
                                $plan_override_active = in_array( $plan_override_current, array( 'free', 'starter', 'pro', 'agency' ), true );
                                ?>
                                <div class="opsgate-billing-payment-field" style="margin-top:24px;border-top:1px solid var(--og-border,#ddd);padding-top:20px;">
                                    <h4 style="margin:0 0 4px;">Tier test override <span class="opsgate-overview-eyebrow" style="margin-left:8px;vertical-align:middle;">OPERATOR ONLY</span></h4>
                                    <p class="description" style="margin-bottom:12px;">Override the plan shown across all surfaces for journey testing. Does not affect real API entitlement or billing. Both remote plugin and central dashboard reflect this tier immediately after save. Clear to restore live API truth.</p>
                                    <?php if ( $plan_override_active ) : ?>
                                    <div class="opsgate-alert-panel opsgate-alert-panel-warn" style="margin-bottom:12px;">
                                        <strong>&#9679; Override active: <?php echo esc_html( ucfirst( $plan_override_current ) ); ?></strong> — API plan suppressed. Clear to restore live billing truth.
                                    </div>
                                    <?php endif; ?>
                                    <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="opsgate-operator-tier-override-form" style="margin-top:8px;">
                                        <?php wp_nonce_field( 'opsgate_set_plan_override', 'opsgate_plan_override_nonce' ); ?>
                                        <input type="hidden" name="action" value="opsgate_set_plan_override" />
                                        <div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap;">
                                            <select id="opsgate_plan_override_select" name="opsgate_plan_override" class="regular-text" style="min-width:220px;">
                                                <option value=""<?php selected( ! $plan_override_active ); ?>>— Use API plan (no override) —</option>
                                                <option value="free"<?php selected( $plan_override_current, 'free' ); ?>>Free (public-only)</option>
                                                <option value="starter"<?php selected( $plan_override_current, 'starter' ); ?>>Starter</option>
                                                <option value="pro"<?php selected( $plan_override_current, 'pro' ); ?>>Pro</option>
                                                <option value="agency"<?php selected( $plan_override_current, 'agency' ); ?>>Agency</option>
                                            </select>
                                            <?php submit_button( 'Apply tier override', 'secondary', 'submit', false, array( 'style' => 'margin:0;' ) ); ?>
                                            <?php if ( $plan_override_active ) : ?>
                                            <a href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin-post.php?action=opsgate_clear_plan_override' ), 'opsgate_clear_plan_override', 'opsgate_clear_plan_override_nonce' ) ); ?>" class="button button-secondary">Clear override (restore API plan)</a>
                                            <?php endif; ?>
                                        </div>
                                        <p class="description" style="margin-top:6px;">Select a tier and click Apply. Both remote plugin and central dashboard update immediately. Select "Use API plan" and Apply to clear, or use the Clear button.</p>
                                    </form>
                                </div>
                            </div>
                        </details>
                        </form>

                        <div class="opsgate-billing-section-head opsgate-billing-section-head-secondary opsgate-billing-section-head-context">
                            <div>
                                <h3 class="title">Capability &amp; trust context</h3>
                                <p class="description">Secondary family-routing and evidence confidence context for this package.</p>
                            </div>
                        </div>
                        <div class="opsgate-alerts-channel-family-grid opsgate-billing-capability-grid">
                            <article class="opsgate-alerts-channel-family-card">
                                <span class="opsgate-alerts-detail-label">Live now</span>
                                <div class="opsgate-alerts-detail-value"><?php echo esc_html( ! empty( $channel_live_labels ) ? implode( ', ', $channel_live_labels ) : 'No live families on this package' ); ?></div>
                                <p class="opsgate-alerts-history-copy">Configured and deliverable now on the current package.</p>
                            </article>
                            <article class="opsgate-alerts-channel-family-card">
                                <span class="opsgate-alerts-detail-label">Not live in this tier</span>
                                <div class="opsgate-alerts-detail-value"><?php echo esc_html( ! empty( $channel_not_live_labels ) ? implode( ', ', $channel_not_live_labels ) : 'No additional live family unlocks at this tier' ); ?></div>
                                <p class="opsgate-alerts-history-copy">Families modeled in the product but not live on this current tier.</p>
                            </article>
                            <article class="opsgate-alerts-channel-family-card">
                                <span class="opsgate-alerts-detail-label">Planned direction</span>
                                <div class="opsgate-alerts-detail-value"><?php echo esc_html( ! empty( $channel_planned_labels ) ? implode( ', ', $channel_planned_labels ) : 'No planned families exposed' ); ?></div>
                                <p class="opsgate-alerts-history-copy">Commercial direction remains visible without being presented as live support today.</p>
                            </article>
                            <article class="opsgate-alerts-channel-family-card opsgate-billing-confidence-card">
                                <span class="opsgate-alerts-detail-label"><?php echo esc_html( $billing_confidence_title ); ?></span>
                                <div class="opsgate-alerts-detail-value">Trust stays visible</div>
                                <p class="opsgate-alerts-history-copy"><?php echo esc_html( $billing_confidence_copy ); ?></p>
                            </article>
                        </div>
                    </div>
                </div>
            <?php endif; ?>
        </div>
        <?php
    }

    /**
     * Handle saving of Services tab settings.
     *
     * @return void
     */
    public static function handle_service_settings_save() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden' );
        }

        check_admin_referer( 'opsgate_save_service_settings', 'opsgate_service_nonce' );

        if ( ! function_exists( 'opsgate_get_services_settings' ) || ! function_exists( 'opsgate_update_services_settings' ) ) {
            wp_die( 'Service settings helpers are missing.' );
        }

        $current = opsgate_get_services_settings();

        $posted = ( isset( $_POST['opsgate_services'] ) && is_array( $_POST['opsgate_services'] ) )
            ? wp_unslash( $_POST['opsgate_services'] )
            : array();

        $allowed_plans = array( 'free', 'starter', 'pro' );

        foreach ( $current as $service_key => &$service_settings ) {
            $posted_service = ( isset( $posted[ $service_key ] ) && is_array( $posted[ $service_key ] ) )
                ? $posted[ $service_key ]
                : array();

            $enabled = isset( $posted_service['enabled'] );
            $plan    = isset( $posted_service['plan'] ) ? sanitize_text_field( $posted_service['plan'] ) : ( isset( $service_settings['plan'] ) ? $service_settings['plan'] : 'free' );

            if ( ! in_array( $plan, $allowed_plans, true ) ) {
                $plan = isset( $service_settings['plan'] ) ? $service_settings['plan'] : 'free';
            }

	    // Day 19.4 (Step A): Persist evaluation frequency (built-in schedules only).
	    $old_frequency = get_option( 'opsgate_scheduling_frequency', 'hourly' );

	    $posted_frequency = isset( $_POST['opsgate_scheduling_frequency'] )
    		? sanitize_text_field( wp_unslash( $_POST['opsgate_scheduling_frequency'] ) )
	    	: 'hourly';

	    $allowed_frequencies = array( 'hourly', 'twicedaily', 'daily' );
	    if ( ! in_array( $posted_frequency, $allowed_frequencies, true ) ) {
    		$posted_frequency = 'hourly';
	    }

	    update_option( 'opsgate_scheduling_frequency', $posted_frequency, false );

	    // If enabled and the frequency changed, reschedule the cron tick to match the new frequency.
	    if ( '1' === $enabled_posted && $old_frequency !== $posted_frequency ) {
    		wp_unschedule_hook( self::SCHEDULE_CRON_HOOK );

	        self::activity_timeline_add(
        	    'Schedule evaluation frequency updated',
                    'completed',
                    'OpsGate will now check your schedule settings ' . $posted_frequency . ' (previously: ' . $old_frequency . ').'
    		);
	    }


            $service_settings['enabled'] = $enabled;
            $service_settings['plan']    = $plan;
        }
        unset( $service_settings );

        opsgate_update_services_settings( $current );

        $redirect_url = add_query_arg(
            array(
                'page'             => 'opsgate',
                'tab'              => 'security',
                'settings-updated' => '1',
            ),
            admin_url( 'admin.php' )
        );

        wp_safe_redirect( $redirect_url );
        exit;
    }

    /**
     * Handle saving of Schedules tab settings.
     *
     * Step E: soft gating + safe sanitation only.
     *
     * @return void
     */
    public static function handle_schedule_settings_save() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden' );
        }

        check_admin_referer( 'opsgate_save_schedule_settings', 'opsgate_schedule_nonce' );

        $scope = self::get_mcp_scope_snapshot();
        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id    = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';

        if ( '' === $account_id || '' === $site_id ) {
            wp_safe_redirect(
                add_query_arg(
                    array(
                        'page'           => 'opsgate',
                        'tab'            => 'settings',
                        'opsgate_notice' => 'schedule_save_failed',
                    ),
                    admin_url( 'admin.php' )
                )
            );
            exit;
        }

        $posted = ( isset( $_POST['opsgate_schedules'] ) && is_array( $_POST['opsgate_schedules'] ) )
            ? wp_unslash( $_POST['opsgate_schedules'] )
            : array();

        $schedule_posted = ( isset( $posted['portfolio_triage'] ) && is_array( $posted['portfolio_triage'] ) )
            ? $posted['portfolio_triage']
            : array();

        $mode_raw               = isset( $schedule_posted['mode'] ) ? sanitize_text_field( $schedule_posted['mode'] ) : 'off';
        $mode                   = in_array( $mode_raw, array( 'off', 'daily', 'weekly', 'monthly' ), true ) ? $mode_raw : 'off';

        $time = isset( $schedule_posted['time'] ) ? sanitize_text_field( $schedule_posted['time'] ) : '02:00';
        if ( ! preg_match( '/^\d{2}:\d{2}$/', $time ) ) {
            $time = '02:00';
        }

        $dow = null;
        if ( isset( $schedule_posted['dow'] ) && '' !== $schedule_posted['dow'] ) {
            $dow_val = (int) $schedule_posted['dow'];
            if ( $dow_val >= 0 && $dow_val <= 6 ) {
                $dow = $dow_val;
            }
        }

        $dom = null;
        if ( isset( $schedule_posted['dom'] ) && '' !== $schedule_posted['dom'] ) {
            $dom_val = (int) $schedule_posted['dom'];
            if ( $dom_val >= 1 && $dom_val <= 31 ) {
                $dom = $dom_val;
            }
        }

        $payload_basis = self::canonical_portfolio_triage_payload_basis();
        $enabled       = isset( $_POST['opsgate_scheduling_enabled'] ) && 'off' !== $mode;
        $timezone      = wp_timezone_string();
        if ( '' === trim( (string) $timezone ) ) {
            $timezone = 'UTC';
        }

        $resp = self::mcp_post_json(
            '/v1/run-schedules/portfolio-triage',
            array(
                'account_id'  => $account_id,
                'site_id'     => $site_id,
                'job_type'    => 'portfolio_triage',
                'is_enabled'  => $enabled,
                'cadence'     => $enabled ? $mode : 'disabled',
                'time_hm_utc' => $time,
                'timezone'    => $timezone,
                'day_of_week' => $dow,
                'day_of_month'=> $dom,
                'payload_json'=> $payload_basis,
            )
        );

        $args = array(
            'page'             => 'opsgate',
            'tab'              => 'settings',
            'opsgate_notice'   => ! empty( $resp['ok'] ) ? 'schedule_saved' : 'schedule_save_failed',
        );

        if ( empty( $resp['ok'] ) && isset( $resp['error'] ) && '' !== trim( (string) $resp['error'] ) ) {
            $args['opsgate_notice_detail'] = sanitize_text_field( (string) $resp['error'] );
        }

        if ( ! empty( $resp['ok'] ) ) {
            $args['settings-updated'] = '1';
        }

        if ( ! empty( $resp['ok'] ) ) {
            self::activity_timeline_add(
                'Managed schedule updated',
                'completed',
                sprintf(
                    'Security Scan schedule is now %s (%s at %s).',
                    $enabled ? 'enabled' : 'disabled',
                    ( 'off' === $mode ) ? 'disabled' : $mode,
                    $time . ' ' . $timezone
                )
            );
        }

        wp_safe_redirect( add_query_arg( $args, admin_url( 'admin.php' ) ) );
        exit;
    }

    /**
     * Handle saving of Pricing & Billing settings (Day-7).
     *
     * @return void
     */
    public static function handle_pricing_settings_save() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden' );
        }

        check_admin_referer( 'opsgate_save_pricing_settings', 'opsgate_pricing_nonce' );

        $stripe_mode = 'test';

        $publishable_key = '';
        if ( isset( $_POST['opsgate_stripe_publishable_key'] ) ) {
            $publishable_key = sanitize_text_field( wp_unslash( $_POST['opsgate_stripe_publishable_key'] ) );
        }

        $payment_link_starter = '';
        if ( isset( $_POST['opsgate_stripe_payment_link_starter'] ) ) {
            $payment_link_starter = esc_url_raw( wp_unslash( $_POST['opsgate_stripe_payment_link_starter'] ) );
        }

        $payment_link_pro = '';
        if ( isset( $_POST['opsgate_stripe_payment_link_pro'] ) ) {
            $payment_link_pro = esc_url_raw( wp_unslash( $_POST['opsgate_stripe_payment_link_pro'] ) );
        }

        $payment_link_agency = '';
        if ( isset( $_POST['opsgate_stripe_payment_link_agency'] ) ) {
            $payment_link_agency = esc_url_raw( wp_unslash( $_POST['opsgate_stripe_payment_link_agency'] ) );
        }

        update_option( 'opsgate_stripe_mode', $stripe_mode );
        update_option( 'opsgate_stripe_publishable_key', $publishable_key );
        update_option( 'opsgate_stripe_payment_link_starter', $payment_link_starter );
        update_option( 'opsgate_stripe_payment_link_pro', $payment_link_pro );
        update_option( 'opsgate_stripe_payment_link_agency', $payment_link_agency );

        $redirect_url = add_query_arg(
            array(
                'page'             => 'opsgate',
                'tab'              => 'billing',
                'settings-updated' => '1',
            ),
            admin_url( 'admin.php' )
        );

        wp_safe_redirect( $redirect_url );
        exit;
    }

    /**
     * Apply current billing plan as default service plan across all services.
     *
     * - Updates only opsgate_services[*][plan]
     * - Does NOT change enabled flags
     * - Does NOT touch last scan fields
     *
     * @return void
     */
    public static function handle_apply_plan_defaults() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden' );
        }

        if (
            ! isset( $_GET['opsgate_apply_plan_defaults_nonce'] ) ||
            ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['opsgate_apply_plan_defaults_nonce'] ) ), 'opsgate_apply_plan_defaults' )
        ) {
            wp_die( 'Invalid request. Please try again.' );
        }

        if ( ! function_exists( 'opsgate_get_services_settings' ) || ! function_exists( 'opsgate_update_services_settings' ) ) {
            wp_die( 'Service settings helpers are missing.' );
        }

        $billing_plan = self::get_current_plan();
        $services     = opsgate_get_services_settings();

        foreach ( $services as $service_key => &$svc ) {
            if ( ! is_array( $svc ) ) {
                $svc = array();
            }

            $enabled = isset( $svc['enabled'] ) ? (bool) $svc['enabled'] : false;

            $svc['enabled'] = $enabled;
            $svc['plan']    = $billing_plan;
        }
        unset( $svc );

        opsgate_update_services_settings( $services );

        $redirect_url = add_query_arg(
            array(
                'page'             => 'opsgate',
                'tab'              => 'billing',
                'settings-updated' => '1',
            ),
            admin_url( 'admin.php' )
        );

        wp_safe_redirect( $redirect_url );
        exit;
    }

    /**
     * Day-8.3: Generate link proof and store it.
     *
     * @return void
     */
    public static function handle_generate_link_proof() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden' );
        }

        if (
            ! isset( $_POST['opsgate_generate_link_proof_nonce'] ) ||
            ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['opsgate_generate_link_proof_nonce'] ) ), 'opsgate_generate_link_proof' )
        ) {
            wp_die( 'Invalid request. Please try again.' );
        }

        $redirect_url = self::admin_tab_url(
            'settings',
            array(
                'opsgate_settings_error' => rawurlencode( 'Legacy local link proof is retired. Use canonical pairing and connector credential controls instead.' ),
            )
        );

        wp_safe_redirect( $redirect_url );
        exit;
    }

    /**
     * Day-8.3: Clear link proof.
     *
     * @return void
     */
    public static function handle_clear_link_proof() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden' );
        }

        if (
            ! isset( $_POST['opsgate_clear_link_proof_nonce'] ) ||
            ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['opsgate_clear_link_proof_nonce'] ) ), 'opsgate_clear_link_proof' )
        ) {
            wp_die( 'Invalid request. Please try again.' );
        }

        $redirect_url = self::admin_tab_url(
            'settings',
            array(
                'opsgate_settings_error' => rawurlencode( 'Legacy local link proof is retired. There is no active proof record to clear.' ),
            )
        );

        wp_safe_redirect( $redirect_url );
        exit;
    }

    /**
     * Export plugin logs and a snapshot of current badge data as ZIP.
     *
     * @return void
     */
    public static function export_logs() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Forbidden' );
        }

        $export_failure = static function ( string $detail ): void {
            wp_safe_redirect(
                self::admin_tab_url(
                    'settings',
                    array(
                        'opsgate_support_export'        => 'failed',
                        'opsgate_support_export_detail' => sanitize_key( $detail ),
                    )
                )
            );
            exit;
        };

        if ( ! class_exists( 'ZipArchive' ) ) {
            $export_failure( 'zip_unavailable' );
        }

        $upload = wp_upload_dir();
        $dir    = trailingslashit( $upload['basedir'] ) . 'opsgate';

        if ( ! file_exists( $dir ) && ! wp_mkdir_p( $dir ) ) {
            $export_failure( 'export_dir_unavailable' );
        }

        $snapshot = array(
            'telemetry_enabled'  => get_option( 'opsgate_telemetry_enabled', '0' ),
            'identity'           => array(
                'site_id'    => get_option( 'opsgate_site_id', '' ),
                'site_label' => get_option( 'opsgate_site_label', '' ),
                'email'      => get_option( 'opsgate_identity_email', '' ),
                'linked'     => self::is_site_linked() ? '1' : '0',
                'linked_at'  => get_option( 'opsgate_site_linked_at', '' ),
                'proof'      => get_option( 'opsgate_site_link_proof', '' ),
            ),
        );

        $snapshot_write = file_put_contents( $dir . '/snapshot.json', wp_json_encode( $snapshot, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) );
        if ( false === $snapshot_write ) {
            $export_failure( 'snapshot_write_failed' );
        }

        $log = $dir . '/opsgate.log';
        if ( ! file_exists( $log ) ) {
            $log_write = file_put_contents( $log, '' );
            if ( false === $log_write ) {
                $export_failure( 'log_write_failed' );
            }
        }

        $zip = $dir . '/opsgate_export_' . date( 'Ymd_His' ) . '.zip';
        if ( file_exists( $zip ) ) {
            unlink( $zip );
        }

        $zip_obj = new ZipArchive();
        if ( true === $zip_obj->open( $zip, ZIPARCHIVE::CREATE ) ) {
            $zip_obj->addFile( $log, 'opsgate.log' );
            $zip_obj->addFile( $dir . '/snapshot.json', 'snapshot.json' );
            $zip_obj->close();

            header( 'Content-Type: application/zip' );
            header( 'Content-Disposition: attachment; filename="' . basename( $zip ) . '"' );
            header( 'Content-Length: ' . filesize( $zip ) );
            readfile( $zip );
            exit;
        }

        $export_failure( 'zip_create_failed' );
    }

    /**
     * Step 1 (Day-7 polish): prepare audit run (no JS).
     *
     * Redirects back to Services tab with:
     * - opsgate_audit_running=1
     * - opsgate_run_token=<one-time transient token>
     *
     * @return void
     */
    public static function handle_run_audit_prepare() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( esc_html__( 'You are not allowed to perform this action.', 'opsgate' ) );
        }

        if (
            ! isset( $_POST['opsgate_run_audit_prepare_nonce'] )
            || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['opsgate_run_audit_prepare_nonce'] ) ), 'opsgate_run_audit_prepare' )
        ) {
            wp_die( esc_html__( 'Invalid request. Please try again.', 'opsgate' ) );
        }

        $service = isset( $_POST['service'] ) ? sanitize_text_field( wp_unslash( $_POST['service'] ) ) : '';
        if ( 'wordpress_security_audit' !== $service ) {
            self::redirect_with_audit_status( 'error', __( 'Unsupported service.', 'opsgate' ) );
        }

        if ( ! function_exists( 'opsgate_get_api_token' ) || ! opsgate_get_api_token() ) {
            self::redirect_with_audit_status(
                'error',
                __( 'OpsGate MCP token is not configured. Set it on the Overview tab.', 'opsgate' )
            );
        }

        $run_token = wp_generate_password( 20, false, false );
        set_transient( 'opsgate_audit_run_token_' . $run_token, '1', 2 * MINUTE_IN_SECONDS );
	self::activity_timeline_add(
            'Security scan started',
            'in_progress',
            'Preparing your scan now.'
        );


        $redirect_url = add_query_arg(
            array(
                'page'                  => 'opsgate',
                'tab'                   => 'security',
                'opsgate_audit_running' => '1',
                'opsgate_run_token'     => $run_token,
            ),
            admin_url( 'admin.php' )
        );

        wp_safe_redirect( $redirect_url );
        exit;
    }

    /**
     * Step 1 (Day-7 polish): execute audit run (no JS).
     *
     * Triggered by HTML meta refresh from Services tab.
     *
     * @return void
     */
    public static function handle_run_audit_execute() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( esc_html__( 'You are not allowed to perform this action.', 'opsgate' ) );
        }

        if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'opsgate_run_audit_execute' ) ) {
            wp_die( esc_html__( 'Invalid request. Please try again.', 'opsgate' ) );
        }

        $service   = isset( $_GET['service'] ) ? sanitize_text_field( wp_unslash( $_GET['service'] ) ) : '';
        $run_token = isset( $_GET['opsgate_run_token'] ) ? sanitize_text_field( wp_unslash( $_GET['opsgate_run_token'] ) ) : '';

        if ( 'wordpress_security_audit' !== $service ) {
            self::redirect_with_audit_status( 'error', __( 'Unsupported service.', 'opsgate' ) );
        }

        if ( '' === $run_token || '1' !== get_transient( 'opsgate_audit_run_token_' . $run_token ) ) {
            self::redirect_with_audit_status(
                'error',
                __( 'Invalid or expired audit run token. Please try again.', 'opsgate' )
            );
        }

        delete_transient( 'opsgate_audit_run_token_' . $run_token );

        $result = self::run_audit_now_internal( $service );
	$ok = ( isset( $result['status'] ) && 'success' === (string) $result['status'] );

        self::activity_timeline_add(
            $ok ? 'Security scan completed' : 'Security scan needs attention',
            $ok ? 'completed' : 'attention',
            $ok ? 'Your scan finished. Your reports are ready in the Reports tab.' : 'Your scan could not complete. Please try again.'
        );


        self::redirect_with_audit_status( $result['status'], $result['message'] );
    }

    /**
     * Handle the "Run audit now" action for wordpress_security_audit.
     *
     * Backward compatible endpoint (direct POST).
     *
     * @return void
     */
    public static function handle_run_audit_now() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( esc_html__( 'You are not allowed to perform this action.', 'opsgate' ) );
        }

        if (
            ! isset( $_POST['opsgate_run_audit_now_nonce'] )
            || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['opsgate_run_audit_now_nonce'] ) ), 'opsgate_run_audit_now' )
        ) {
            wp_die( esc_html__( 'Invalid request. Please try again.', 'opsgate' ) );
        }

        $service = isset( $_POST['service'] ) ? sanitize_text_field( wp_unslash( $_POST['service'] ) ) : '';

        $result = self::run_audit_now_internal( $service );
	$ok = ( isset( $result['status'] ) && 'success' === (string) $result['status'] );

        self::activity_timeline_add(
            $ok ? 'Security scan completed' : 'Security scan needs attention',
            $ok ? 'completed' : 'attention',
            $ok ? 'Your scan finished. Review your results in the Reports tab.' : 'Your scan could not complete. Please try again.'
        );


        self::redirect_with_audit_status( $result['status'], $result['message'] );
    }

    /**
     * Fire-and-forget proof event dispatch through the OpsGate API.
     * WordPress never calls n8n or another executor directly.
     */
    private static function post_api_proof_event( $event, $meta = array() ) {

        // PRIME LAW: WordPress must never call the executor directly.
        // This function now dispatches a job request to the OpsGate API only.

        if ( ! function_exists( 'opsgate_get_api_base_url' ) || ! function_exists( 'opsgate_get_api_token' ) ) {
            error_log( 'OPSGATE: API helpers missing; job dispatch skipped.' );
            return;
        }

        $api_base = rtrim( (string) opsgate_get_api_base_url(), '/' );
        $token    = opsgate_get_api_token();

        if ( ! $api_base || ! $token ) {
            error_log( 'OPSGATE: API base URL or token missing; job dispatch skipped.' );
            return;
        }

        $payload = array(
            'event'      => (string) $event,
            'meta'       => is_array( $meta ) ? $meta : array(),
            'site_id'    => (string) get_option( 'opsgate_site_id', '' ),
            'site_label' => (string) get_option( 'opsgate_site_label', '' ),
            'actor'      => 'wp-admin',
            'ts_utc'     => gmdate( 'c' ),
        );

        $args = array(
            'timeout' => 5,
            'headers' => array(
                'Content-Type'  => 'application/json',
                'Authorization' => 'Bearer ' . $token,
            ),
            'body'    => wp_json_encode( $payload ),
        );

        // Fire-and-forget to API only (executor remains invisible to WP).
        wp_remote_post( $api_base . '/jobs', $args );
    }

    /**
     * Internal audit runner (single source of truth).
     *
     * IMPORTANT: Preserves existing MCP behavior and payload, but now includes:
     * - Day-8.2 safe MCP payload visibility single log line (no secrets)
     * - Day-8.3/8.4 link status indicator (boolean only; proof not sent)
     *
     * @param string $service Service key.
     * @return array{status:string,message:string} Result for notices.
     */
    private static function run_audit_now_internal( $service ) {
        if ( 'wordpress_security_audit' !== $service ) {
            return array(
                'status'  => 'error',
                'message' => __( 'Unsupported service.', 'opsgate' ),
            );
        }

        // Ensure defaults exist before building payload (Day-8 safety).
        self::bootstrap_defaults();

        if ( ! function_exists( 'opsgate_get_services_settings' ) || ! function_exists( 'opsgate_update_services_settings' ) ) {
            return array(
                'status'  => 'error',
                'message' => __( 'Service settings helpers are missing.', 'opsgate' ),
            );
        }

        if ( ! function_exists( 'opsgate_get_api_token' ) ) {
            return array(
                'status'  => 'error',
                'message' => __( 'OpsGate MCP token resolver is not available.', 'opsgate' ),
            );
        }

        $token = opsgate_get_api_token();
        if ( ! $token ) {
            return array(
                'status'  => 'error',
                'message' => __( 'OpsGate MCP token is not configured. Set it on the Overview tab.', 'opsgate' ),
            );
        }

        $services = opsgate_get_services_settings();
        $svc      = ( isset( $services['wordpress_security_audit'] ) && is_array( $services['wordpress_security_audit'] ) )
            ? $services['wordpress_security_audit']
            : array();

        $plan = ! empty( $svc['plan'] ) ? $svc['plan'] : 'free';

        // Day-8.2: identity snapshot (safe + consistent).
        $identity = self::get_identity_snapshot();

        $payload = array(
            'site'        => array(
                'id'        => $identity['site_id'],
                'label'     => $identity['site_label'],
                'url'       => $identity['site_url'],
                'host'      => $identity['site_host'],
                'container' => function_exists( 'gethostname' ) ? (string) gethostname() : '',
            ),
            'identity'    => array(
                'email' => $identity['identity_email'],
                'label' => $identity['site_label'],
            ),
            'preferences' => array(
                'scan_type' => 'full_audit',
                'depth'     => 'normal',
            ),
            'service'     => 'wordpress_security_audit',
            'plan'        => $plan,
            'meta'        => array(
                'plugin_version' => defined( 'OPSGATE_VERSION' ) ? OPSGATE_VERSION : '0.0.0-local',
                'initiator'      => 'wordpress_plugin',
                'site_linked'    => self::is_site_linked() ? true : false,
            ),
        );

        $base_url = self::mcp_base_url();
        if ( '' === $base_url ) {
            $base_url = 'http://host.docker.internal:8000';
        }
        $url      = rtrim( (string) $base_url, '/' ) . '/tools/run_audit';

        // Day-8.2: single safe visibility line (no secrets, one line per trigger).
        self::log_mcp_payload_visibility_line( $payload, 'wordpress_security_audit' );

        $args = array(
            'method'      => 'POST',
            'headers'     => array(
                'X-Token'      => $token,
                'Content-Type' => 'application/json',
                'Accept'       => 'application/json',
            ),
            'body'        => wp_json_encode( $payload ),
            'timeout'     => 30,
            'data_format' => 'body',
        );

        $response = wp_remote_post( $url, $args );

        if ( is_wp_error( $response ) ) {
            return array(
                'status'  => 'error',
                'message' => sprintf(
                    __( 'Audit request failed: %s', 'opsgate' ),
                    $response->get_error_message()
                ),
            );
        }

        $status_code = wp_remote_retrieve_response_code( $response );
        $body        = wp_remote_retrieve_body( $response );

        if ( $status_code < 200 || $status_code >= 300 ) {
            $msg = sprintf(
                __( 'Audit failed (HTTP %1$d): %2$s', 'opsgate' ),
                (int) $status_code,
                is_string( $body ) ? wp_strip_all_tags( $body ) : ''
            );

            return array(
                'status'  => 'error',
                'message' => $msg,
            );
        }

        $data = json_decode( (string) $body, true );
        if ( ! is_array( $data ) ) {
            return array(
                'status'  => 'error',
                'message' => __( 'Audit response could not be parsed.', 'opsgate' ),
            );
        }

        $scan_id      = isset( $data['scan_id'] ) ? (string) $data['scan_id'] : null;
        $generated_at = isset( $data['generated_at'] ) ? (string) $data['generated_at'] : null;
        $output       = ( isset( $data['output'] ) && is_array( $data['output'] ) ) ? $data['output'] : array();

        if ( ! $scan_id || ! $generated_at ) {
            return array(
                'status'  => 'error',
                'message' => __( 'Audit response is missing required fields.', 'opsgate' ),
            );
        }

        $services = opsgate_get_services_settings();

        if ( ! isset( $services['wordpress_security_audit'] ) || ! is_array( $services['wordpress_security_audit'] ) ) {
            $services['wordpress_security_audit'] = array();
        }

        $services['wordpress_security_audit']['last_scan_id'] = $scan_id;
        $services['wordpress_security_audit']['last_scan_at'] = $generated_at;
        $services['wordpress_security_audit']['last_output']  = array(
            'json' => isset( $output['json'] ) ? (string) $output['json'] : null,
            'csv'  => isset( $output['csv'] ) ? (string) $output['csv'] : null,
            'pdf'  => isset( $output['pdf'] ) ? (string) $output['pdf'] : null,
        );

        opsgate_update_services_settings( $services );

		$success_msg = __( 'Security scan completed. Reports are ready in the Reports tab.', 'opsgate' );

        return array(
            'status'  => 'success',
            'message' => $success_msg,
        );
    }

    /**
     * Redirect back to the OpsGate Services tab with a status notice.
     *
     * @param string $status  'success' or 'error'.
     * @param string $message Message to display.
     *
     * @return void
     */
    private static function redirect_with_audit_status( $status, $message ) {
        $status = ( 'success' === $status ) ? 'success' : 'error';

        $fallback = add_query_arg(
            array(
                'page' => 'opsgate',
                'tab'  => 'security',
            ),
            admin_url( 'admin.php' )
        );

        $referer = wp_get_referer();
        $target  = $fallback;

        if ( is_string( $referer ) && '' !== $referer ) {
            $referer_path = (string) wp_parse_url( $referer, PHP_URL_PATH );

            $is_admin_php = is_string( $referer_path ) && ( false !== strpos( $referer_path, '/wp-admin/admin.php' ) );

            if ( $is_admin_php ) {
                $page  = '';
                $query = (string) wp_parse_url( $referer, PHP_URL_QUERY );
                if ( '' !== $query ) {
                    parse_str( $query, $qs );
                    $page = isset( $qs['page'] ) ? sanitize_text_field( (string) $qs['page'] ) : '';
                }

                if ( 'opsgate' === $page ) {
                    $target = $referer;
                }
            }
        }

        $target = remove_query_arg(
            array(
                'opsgate_audit_status',
                'opsgate_audit_message',
                'opsgate_audit_running',
                'opsgate_run_token',
                '_wpnonce',
                'action',
                'service',
            ),
            $target
        );

        $url = add_query_arg(
            array(
                'opsgate_audit_status'  => $status,
                'opsgate_audit_message' => rawurlencode( (string) $message ),
            ),
            $target
        );

        wp_safe_redirect( $url );
        exit;
    }

    // ==========================================
    // DAY 10 — MONTHLY PLAN SYSTEM (FOUNDATION)
    // Visibility-only: state storage + rollup snapshot
    // ==========================================

    private const MONTHLY_STATE_OPTION = 'opsgate_monthly_plan_state';

    /**
     * Day 19.4: Scheduling Orchestration (WP-Cron spine).
     *
     * One hook drives all scheduled service runs. We keep this internal and minimal:
     * - No UI waiting
     * - No heavy work in the request/cron callback
     * - Each eligible service run writes evidence + activity via existing runners
     */
    private const SCHEDULE_CRON_HOOK = 'opsgate_scheduled_tick';

    /**
     * Register cron hook handler.
     * Called from self::init().
     */
    private static function register_cron_handlers(): void {
        add_action( self::SCHEDULE_CRON_HOOK, array( __CLASS__, 'cron_tick' ) );
    }

    /**
     * Ensure the scheduled tick is in the correct state based on explicit settings.
     * Deterministic: when enabled, clears then schedules once using the chosen recurrence.
     */
    private static function ensure_cron_tick_state( string $enabled, string $frequency ): void {
        // PRIME LAW: Scheduling is API-owned and must not rely on WP-Cron.
        // Local cron provisioning is disabled. This function is now a no-op.

        return;
   }

   /**
    * Day 19.4 (Option B): Provision the cron tick only when scheduling is explicitly enabled.
    *
    * Uses a built-in schedule ("hourly") to avoid custom intervals and WP.org surprises.
    * Idempotent: safe to call multiple times.
    */
    private static function maybe_provision_cron_tick(): void {
        // PRIME LAW: Scheduling is API-owned and must not rely on WP-Cron.
        return;
    }

    /**
     * Day 19.4 (Option B): Remove the cron tick when scheduling is disabled.
     * Idempotent and args-safe.
     */
    private static function maybe_clear_cron_tick(): void {
        // PRIME LAW: Scheduling is API-owned and must not rely on WP-Cron.
        return;
     }

    /**
     * Cron tick: evaluates schedule settings and triggers lightweight runs.
     *
     * IMPORTANT:
     * - This must stay safe even if called multiple times.
     * - We do not assume wp-cron frequency; we evaluate "due" by time window.
     */
    public static function cron_tick(): void {
        // PRIME LAW: Scheduling authority is now fully API/Postgres-owned.
        // Any legacy WP-Cron invocation must remain a safe no-op.
        return;
    }

    /**
     * Determine if a schedule is due "now" (UTC) with a small execution window.
     *
     * We treat a schedule as due if current time is within the same minute as the configured HH:MM.
     * This keeps behavior deterministic and avoids double-runs when wp-cron is delayed.
     */
    private static function is_schedule_due_utc(
        DateTimeImmutable $now_utc,
        string $mode,
        string $time_hm,
        $dow,
        $dom,
        string $service_key
    ): bool {
        if ( ! preg_match( '/^\d{2}:\d{2}$/', $time_hm ) ) {
            return false;
        }

        $now_hm = $now_utc->format( 'H:i' );
        if ( $now_hm !== $time_hm ) {
            return false;
        }

        if ( 'daily' === $mode ) {
            return self::cron_gate_once_per_day( $now_utc, $service_key, $time_hm );
        }

        if ( 'weekly' === $mode ) {
            if ( null === $dow || '' === $dow ) {
                return false;
            }
            $dow_i = (int) $dow;
            if ( $dow_i < 0 || $dow_i > 6 ) {
                return false;
            }
            $today_dow = (int) $now_utc->format( 'w' ); // 0=Sun..6=Sat
            if ( $today_dow !== $dow_i ) {
                return false;
            }
            return self::cron_gate_once_per_week( $now_utc, $service_key, $time_hm, $dow_i );
        }

        if ( 'monthly' === $mode ) {
            if ( null === $dom || '' === $dom ) {
                return false;
            }
            $dom_i = (int) $dom;
            if ( $dom_i < 1 || $dom_i > 31 ) {
                return false;
            }
            $today_dom = (int) $now_utc->format( 'j' ); // 1..31
            if ( $today_dom !== $dom_i ) {
                return false;
            }
            return self::cron_gate_once_per_month( $now_utc, $service_key, $time_hm, $dom_i );
        }

        return false;
    }

    /**
     * Prevent duplicate executions if wp-cron fires multiple times in the same due minute.
     */
    private static function cron_gate_once_per_day( DateTimeImmutable $now_utc, string $service_key, string $time_hm ): bool {
        $k = 'opsgate_cron_gate_day_' . md5( $service_key . '|' . $time_hm );
        $today = $now_utc->format( 'Y-m-d' );
        $last = get_option( $k, '' );
        if ( $last === $today ) {
            return false;
        }
        update_option( $k, $today );
        return true;
    }

    private static function cron_gate_once_per_week( DateTimeImmutable $now_utc, string $service_key, string $time_hm, int $dow ): bool {
        $k = 'opsgate_cron_gate_week_' . md5( $service_key . '|' . $time_hm . '|' . (string) $dow );
        $iso_week = $now_utc->format( 'o-\WW' ); // e.g. 2026-W01
        $last = get_option( $k, '' );
        if ( $last === $iso_week ) {
            return false;
        }
        update_option( $k, $iso_week );
        return true;
    }

    private static function cron_gate_once_per_month( DateTimeImmutable $now_utc, string $service_key, string $time_hm, int $dom ): bool {
        $k = 'opsgate_cron_gate_month_' . md5( $service_key . '|' . $time_hm . '|' . (string) $dom );
        $ym = $now_utc->format( 'Y-m' );
        $last = get_option( $k, '' );
        if ( $last === $ym ) {
            return false;
        }
        update_option( $k, $ym );
        return true;
    }

    /**
     * PRIME LAW: WordPress must not execute scheduled jobs.
     * This method only dispatches a "job due" notice to the OpsGate API.
     *
     * @param string            $service_key Service key.
     * @param string            $mode        Schedule mode (daily|weekly|monthly|off).
     * @param DateTimeImmutable $now_utc     Current UTC time.
     * @return void
     */
    private static function trigger_scheduled_service_run( string $service_key, string $mode, DateTimeImmutable $now_utc ): void {
        // PRIME LAW: WordPress must not compute or dispatch recurring jobs locally.
        return;
    }

    private static function monthly_state_default(): array {
        return array(
            // Weekly execution rollup
            'weekly' => array(
                'last_run_at_utc' => null,   // string ISO8601 UTC
                'status'          => 'never',// never|ok|error
                'created'         => 0,
                'updated'         => 0,
                'notes'           => '',     // short human note
            ),

            // Monthly consolidation rollup
            'monthly' => array(
                'last_consolidated_at_utc' => null, // string ISO8601 UTC
                'status'                   => 'never',// never|ok|error
                'weeks_included'           => 0,
                'created'                  => 0,
                'updated'                  => 0,
                'notes'                    => '',
            ),

            // Latest generated artifacts (paths/ids only; no enforcement)
            'artifacts' => array(
                'last_weekly_report'  => null, // string (relative path or filename)
                 'last_monthly_report' => null, // string (relative path or filename)
            ),
        );
    }

    private static function monthly_state_read(): array {
        $raw = get_option(self::MONTHLY_STATE_OPTION, '');
        if (!is_string($raw) || $raw === '') {
            return self::monthly_state_default();
        }

        $decoded = json_decode($raw, true);
        if (!is_array($decoded)) {
            return self::monthly_state_default();
        }

        // Merge with defaults to guarantee keys exist
        $default = self::monthly_state_default();
        $merged  = array_replace_recursive($default, $decoded);

        // Hard normalize counters to integers and safe strings
        $merged['weekly']['created']  = max(0, (int) ($merged['weekly']['created'] ?? 0));
        $merged['weekly']['updated']  = max(0, (int) ($merged['weekly']['updated'] ?? 0));
        $merged['monthly']['weeks_included'] = max(0, (int) ($merged['monthly']['weeks_included'] ?? 0));
        $merged['monthly']['created'] = max(0, (int) ($merged['monthly']['created'] ?? 0));
        $merged['monthly']['updated'] = max(0, (int) ($merged['monthly']['updated'] ?? 0));

        $merged['weekly']['status']  = self::monthly_state_sanitize_status($merged['weekly']['status'] ?? 'never');
        $merged['monthly']['status'] = self::monthly_state_sanitize_status($merged['monthly']['status'] ?? 'never');

        $merged['weekly']['notes']  = self::monthly_state_sanitize_note($merged['weekly']['notes'] ?? '');
        $merged['monthly']['notes'] = self::monthly_state_sanitize_note($merged['monthly']['notes'] ?? '');

        $merged['artifacts']['last_weekly_report']  = self::monthly_state_sanitize_pathish($merged['artifacts']['last_weekly_report'] ?? null);
        $merged['artifacts']['last_monthly_report'] = self::monthly_state_sanitize_pathish($merged['artifacts']['last_monthly_report'] ?? null);

        $merged['weekly']['last_run_at_utc'] = self::monthly_state_sanitize_iso8601_utc($merged['weekly']['last_run_at_utc'] ?? null);
        $merged['monthly']['last_consolidated_at_utc'] = self::monthly_state_sanitize_iso8601_utc($merged['monthly']['last_consolidated_at_utc'] ?? null);

        return $merged;
    }

    private static function monthly_state_write(array $state): bool {
        // Always normalize via read-merge rules by encoding then re-decoding through read path logic.
        $json = wp_json_encode($state);

        if (!is_string($json)) {
            return false;
        }

        // Cap to keep option safe
        if (strlen($json) > 4096) {
            return false;
        }

        return update_option(self::MONTHLY_STATE_OPTION, $json, false);
    }

    private static function monthly_state_sanitize_status(string $status): string {
        $status = strtolower(trim($status));
        $allowed = array('never', 'ok', 'error');
        return in_array($status, $allowed, true) ? $status : 'never';
    }

    private static function monthly_state_sanitize_note(string $note): string {
        $note = is_string($note) ? trim($note) : '';
        if (strlen($note) > 180) {
            $note = substr($note, 0, 180);
        }
        return $note;
    }

    private static function monthly_state_sanitize_pathish($value): ?string {
        if ($value === null) {
            return null;
        }
        if (!is_string($value)) {
            return null;
        }
        $value = trim($value);
        if ($value === '' || strlen($value) > 220) {
            return null;
        }
        // no traversal, no absolute windows paths
        if (strpos($value, '..') !== false) {
            return null;
        }
        return $value;
    }

    private static function monthly_state_sanitize_iso8601_utc($value): ?string {
        if (!is_string($value)) {
            return null;
        }
        $value = trim($value);
        if ($value === '' || strlen($value) > 40) {
            return null;
        }

        // Accept only “...Z” UTC strings to keep it deterministic
        if (substr($value, -1) !== 'Z') {
            return null;
        }

        return $value;
    }

    public static function get_monthly_plan_snapshot(): array {
        // Single snapshot method used by UI (and later, workflow writers)
        return self::monthly_state_read();
    }

}

if ( ! function_exists( 'opsgate_get_api_entitlement_snapshot' ) ) {

    /**
     * Read-only entitlement snapshot from the OpsGate API.
     *
     * PRIME LAW:
     * - Plan truth lives in the API.
     * - WordPress requests package changes through the API and reads the resulting truth back.
     *
     * @return array<string, mixed>
     */
    function opsgate_get_api_entitlement_snapshot(): array {
        static $cache = array();

        $base = class_exists( 'OpsGate_Admin' ) && method_exists( 'OpsGate_Admin', 'mcp_base_url_public' )
            ? OpsGate_Admin::mcp_base_url_public()
            : ( defined( 'OPSGATE_MCP_BASE_URL' ) ? (string) OPSGATE_MCP_BASE_URL : trim( (string) get_option( 'opsgate_api_base_url', 'https://api.opsgate.ca' ) ) );
        $base = is_string( $base ) ? trim( $base ) : '';
        $base = rtrim( $base, '/' );

        $scope = class_exists( 'OpsGate_Admin' ) && method_exists( 'OpsGate_Admin', 'current_mcp_scope_snapshot' )
            ? OpsGate_Admin::current_mcp_scope_snapshot()
            : array(
                'account_id' => get_option( 'opsgate_account_id', '' ),
                'site_id'    => get_option( 'opsgate_site_id', '' ),
            );

        $account_id = isset( $scope['account_id'] ) ? trim( (string) $scope['account_id'] ) : '';
        $site_id    = isset( $scope['site_id'] ) ? trim( (string) $scope['site_id'] ) : '';
        $cache_key  = implode( ':', array( $base, $account_id, $site_id ) );

        if ( isset( $cache[ $cache_key ] ) && is_array( $cache[ $cache_key ] ) ) {
            return $cache[ $cache_key ];
        }

        if ( '' === $base || '' === $account_id || '' === $site_id ) {
            $cache[ $cache_key ] = array(
                'plan'   => 'unknown',
                'source' => 'missing_required_identity',
            );
            return $cache[ $cache_key ];
        }

        $url = $base . '/v1/entitlements/snapshot/' . rawurlencode( $account_id ) . '/' . rawurlencode( $site_id );
        $headers = array(
            'Accept' => 'application/json',
        );
        if ( function_exists( 'opsgate_get_api_token' ) ) {
            $token = opsgate_get_api_token();
            if ( is_string( $token ) && '' !== trim( $token ) ) {
                $headers['X-Token'] = trim( $token );
            }
        }

        $res = wp_remote_get(
            $url,
            array(
                'timeout'     => 8,
                'redirection' => 2,
                'headers'     => $headers,
            )
        );

        if ( is_wp_error( $res ) ) {
            $cache[ $cache_key ] = array(
                'plan'   => 'unknown',
                'source' => 'api_error',
                'error'  => $res->get_error_message(),
            );
            return $cache[ $cache_key ];
        }

        $code = (int) wp_remote_retrieve_response_code( $res );
        $body = (string) wp_remote_retrieve_body( $res );

        if ( $code < 200 || $code >= 300 ) {
            $cache[ $cache_key ] = array(
                'plan'   => 'unknown',
                'source' => 'api_http_' . (string) $code,
            );
            return $cache[ $cache_key ];
        }

        $data = json_decode( $body, true );
        if ( ! is_array( $data ) ) {
            $cache[ $cache_key ] = array(
                'plan'   => 'unknown',
                'source' => 'api_bad_json',
            );
            return $cache[ $cache_key ];
        }

        $cache[ $cache_key ] = $data;
        return $cache[ $cache_key ];
    }
}
