<?php
/**
 * Content Miner admin dashboard.
 *
 * @var array<string,mixed>       $scan
 * @var string[]                  $locations
 * @var array<string,mixed>|false $idea_result
 * @var array<string,mixed>       $memory_summary
 * @var array<string,mixed>       $ingestion_state
 * @var array<int,array<string,mixed>> $recent_changes
 * @var array<string,string>      $family_labels
 * @var array<string,string>      $readiness_issue_labels
 * @var array<string,string>      $scoring_reason_labels
 * @var int                       $source_total
 * @var int                       $source_total_available
 * @var array<string,mixed>       $license_state
 * @var array<string,mixed>       $free_tier_state
 * @var array<string,mixed>       $search_console
 * @var array<string,mixed>       $analytics
 * @var array<string,mixed>       $openai
 * @var array<string,mixed>       $cloud_connector
 * @var array<string,mixed>       $analysis_state
 * @var bool                      $analysis_handoff_pending
 * @var array<string,mixed>       $analysis_page
 * @var array<string,mixed>       $ledger_page
 * @var array<int,array<string,mixed>> $page_decisions
 * @var array<string,array<string,mixed>> $pair_decisions
 * @var array<int,array<string,mixed>> $outcomes
 * @var array<string,mixed>       $digest_settings
 * @var int                       $verdict_request_count
 * @var array<string,mixed>       $verification_state
 * @var bool                      $pro_enabled
 * @var bool                      $google_enabled
 * @var bool                      $semantic_enabled
 * @var bool                      $outcomes_enabled
 * @var bool                      $digest_enabled
 * @var bool                      $verification_enabled
 * @var bool                      $ai_explain_enabled
 * @var Content_Miner_Prompt_Builder $prompt_builder
 * @var Closure                   $report_prompt_page_loader
 * @var int                       $report_prompt_search_evidence_count
 * @var Content_Miner_Consultation_CTA $consultation
 * @var array<string,string>      $ai_explanation
 */

// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- This included view receives render-local variables from Content_Miner_Admin::render_page(); it does not define globals.
// phpcs:disable WordPress.Security.NonceVerification.Recommended -- Dashboard query parameters only filter read-only results; they do not mutate state.

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

$notice = isset( $_GET['cm_notice'] ) ? sanitize_key( wp_unslash( $_GET['cm_notice'] ) ) : '';
$notice_messages = array(
	'scan-started'    => __( 'Full-library analysis started. Processing will continue in safe background batches.', 'content-miner' ),
	'analysis-batch-processed' => __( 'The next full-library analysis batch was processed.', 'content-miner' ),
	'idea-checked'    => __( 'Idea checked against the current WordPress inventory.', 'content-miner' ),
	'idea-required'   => __( 'Enter a title, question, or brief before checking an idea.', 'content-miner' ),
	'settings-saved'  => __( 'Service locations saved. Run a new scan to refresh localization candidates.', 'content-miner' ),
	'memory-started'  => __( 'Content synchronization started. Processing will continue in safe background batches.', 'content-miner' ),
	'memory-before-analysis' => __( 'Content memory changed, so synchronization started first. Run full-library analysis after synchronization completes.', 'content-miner' ),
	'analysis-waiting-for-sync' => __( 'Content synchronization started. Full-library analysis is queued and will begin automatically when synchronization completes.', 'content-miner' ),
	'batch-processed' => __( 'The next content-memory batch was processed.', 'content-miner' ),
	'google-credentials-saved' => __( 'Google OAuth credentials were encrypted and saved. Connect Google next.', 'content-miner' ),
	'google-connected' => __( 'Google connected with read-only Search Console and Analytics access. Choose the properties available to this site.', 'content-miner' ),
	'google-property-saved' => __( 'Search Console property saved. Sync performance evidence when ready.', 'content-miner' ),
	'google-synced' => __( 'A Search Console batch was synchronized. Background batches will continue; refresh the full analysis after completion.', 'content-miner' ),
	'google-error' => __( 'The Search Console connection needs attention. Review the connection details below.', 'content-miner' ),
	'analytics-properties-refreshed' => __( 'The available Google Analytics properties were refreshed.', 'content-miner' ),
	'analytics-property-saved' => __( 'Google Analytics property saved. Sync engagement evidence when ready.', 'content-miner' ),
	'analytics-synced' => __( 'A Google Analytics batch was synchronized. Refresh the full analysis after completion.', 'content-miner' ),
	'openai-saved' => __( 'The OpenAI API key was validated, encrypted, and saved. Use Sync content to build vectors for the existing library before running full analysis.', 'content-miner' ),
	'openai-disconnected' => __( 'OpenAI semantic analysis was disconnected. Content Miner remains in Basic mode.', 'content-miner' ),
	'openai-error' => __( 'The OpenAI connection could not be validated. Review the message in Connections.', 'content-miner' ),
	'decision-saved' => __( 'The editorial decision and current evidence snapshot were saved.', 'content-miner' ),
	'decision-error' => __( 'The editorial decision could not be saved.', 'content-miner' ),
	'digest-saved' => __( 'Monthly digest settings saved.', 'content-miner' ),
	'digest-error' => __( 'Enter a valid email address before enabling the monthly digest.', 'content-miner' ),
	'collisions-explained' => __( 'Eligible semantic collision explanations were processed. Existing evidence was preserved when a response was unavailable.', 'content-miner' ),
	'verification-started' => __( 'Rendered-page verification started. Only the site’s own published URLs are fetched in batches of 25.', 'content-miner' ),
	'verification-processed' => __( 'The next rendered-page verification batch was processed.', 'content-miner' ),
	'ai-explained' => __( 'The plain-language AI explanation is ready below.', 'content-miner' ),
	'ai-explain-error' => __( 'The AI explanation was unavailable. Copy the same prompt and use it with your preferred AI instead.', 'content-miner' ),
	'consultation-saved' => __( 'Consultation link settings saved.', 'content-miner' ),
	'consultation-error' => __( 'The consultation settings need attention. Agency links require a valid booking URL.', 'content-miner' ),
	'cloud-connected' => __( 'This WordPress site is connected to Content Miner cloud.', 'content-miner' ),
	'cloud-uploaded' => __( 'The current WordPress report summary was uploaded to Content Miner cloud.', 'content-miner' ),
	'cloud-error' => __( 'The Content Miner cloud connection needs attention. Review the message in Connections.', 'content-miner' ),
	'scoring-override-saved' => __( 'Scoring choice saved. Site-level scores are current; refresh the full analysis to rebuild recommendation and collision totals.', 'content-miner' ),
	'scoring-override-error' => __( 'The scoring choice could not be saved for that page.', 'content-miner' ),
	'scoring-override-sync-required' => __( 'Scoring choices are unavailable while a full synchronization or full-library analysis is unfinished. Let it finish, or restart synchronization if it stopped.', 'content-miner' ),
	'free-activation-saved' => __( 'Your three free analyses are active. If email delivery is unavailable, Content Miner will retry in the background.', 'content-miner' ),
	'free-activation-invalid' => __( 'Enter a valid email address to activate your three free analyses.', 'content-miner' ),
	'free-activation-required' => __( 'Activate your three free analyses before starting a full-library analysis.', 'content-miner' ),
	'free-limit-reached' => __( 'Your three free analyses are complete. Your reports are still yours. License this site to keep analyzing.', 'content-miner' ),
);

$summary = isset( $scan['summary'] ) ? $scan['summary'] : array();
$all_items = isset( $analysis_page['items'] ) && is_array( $analysis_page['items'] ) ? $analysis_page['items'] : array();
$pairs   = isset( $scan['pairs'] ) ? $scan['pairs'] : array();
$inventory_per_page = 25;
$items                 = $all_items;
$inventory_total       = isset( $analysis_page['total'] ) ? (int) $analysis_page['total'] : 0;
$inventory_total_pages = max( 1, (int) ceil( $inventory_total / $inventory_per_page ) );
$inventory_page        = min( $inventory_page, $inventory_total_pages );
$inventory_offset      = ( $inventory_page - 1 ) * $inventory_per_page;
$inventory_first       = $inventory_total > 0 ? $inventory_offset + 1 : 0;
$inventory_last        = min( $inventory_offset + count( $items ), $inventory_total );
$inventory_default_visible = 12;
$inventory_loaded_count = count( $items );
$inventory_can_expand = $inventory_loaded_count > $inventory_default_visible;
$inventory_base_url    = add_query_arg(
	array_filter(
		array(
			'page'      => Content_Miner_Admin::PAGE_SLUG,
			'cm_search' => $inventory_search,
		)
	),
	admin_url( 'admin.php' )
);
$collision_page        = isset( $_GET['cm_collision_page'] ) ? max( 1, absint( $_GET['cm_collision_page'] ) ) : 1;
$collision_per_page    = 10;
$collision_total       = count( $pairs );
$collision_total_pages = max( 1, (int) ceil( $collision_total / $collision_per_page ) );
$collision_page        = min( $collision_page, $collision_total_pages );
$collision_offset      = ( $collision_page - 1 ) * $collision_per_page;
$visible_pairs         = array_slice( $pairs, $collision_offset, $collision_per_page );
$collision_first       = $collision_total > 0 ? $collision_offset + 1 : 0;
$collision_last        = min( $collision_offset + count( $visible_pairs ), $collision_total );
$collision_base_url    = add_query_arg(
	array_filter(
		array(
			'page'              => Content_Miner_Admin::PAGE_SLUG,
			'cm_search'         => $inventory_search,
			'cm_inventory_page' => $inventory_page > 1 ? $inventory_page : 0,
		)
	),
	admin_url( 'admin.php' )
);
$memory_indexed       = (int) $memory_summary['indexed'];
$scored_count         = (int) $memory_summary['scored'];
$excluded_count       = (int) $memory_summary['excluded'];
$memory_upgrade_needed = $memory_indexed > 0 && (int) $memory_summary['schema'] !== Content_Miner_Memory::MEMORY_SCHEMA;
$coverage             = $source_total > 0 ? min( 100, round( ( $memory_indexed / $source_total ) * 100 ) ) : 0;
$job_active           = in_array( $ingestion_state['status'], array( 'queued', 'running' ), true );
$job_visible          = 'idle' !== $ingestion_state['status'];
$full_rebuild_incomplete = 'full' === ( $ingestion_state['mode'] ?? '' ) && in_array( $ingestion_state['status'], array( 'queued', 'running', 'failed' ), true );
$memory_population_current = $memory_indexed === $scored_count + $excluded_count;
$scored_aggregates_current = ! $memory_upgrade_needed && ! $full_rebuild_incomplete && $memory_population_current;
$job_progress   = $ingestion_state['total'] > 0 ? min( 100, round( ( $ingestion_state['processed'] / $ingestion_state['total'] ) * 100 ) ) : 0;
$snapshot_progress = ! empty( $ingestion_state['snapshot_total'] )
	? min( 100, round( ( ( (int) $ingestion_state['snapshot_fetched'] + (int) $ingestion_state['snapshot_fallback'] ) / (int) $ingestion_state['snapshot_total'] ) * 100 ) )
	: 0;
if ( 'rendering' === ( isset( $ingestion_state['stage'] ) ? $ingestion_state['stage'] : '' ) ) {
	$job_progress = $snapshot_progress;
}
$job_progress   = 'complete' === $ingestion_state['status'] ? 100 : $job_progress;
$analysis_active = in_array( $analysis_state['status'], array( 'queued', 'running' ), true );
$analysis_progress = $analysis_state['total'] > 0 ? min( 100, round( ( $analysis_state['processed'] / $analysis_state['total'] ) * 100 ) ) : 0;
$scan_population_current = isset( $scan['item_count'], $scan['summary']['scored'], $scan['summary']['excluded'] )
	&& (int) $scan['item_count'] === $memory_indexed
	&& (int) $scan['summary']['scored'] === $scored_count
	&& (int) $scan['summary']['excluded'] === $excluded_count;
$site_report_current = $scored_aggregates_current && $scan_population_current && ! in_array( $analysis_state['status'], array( 'queued', 'running', 'failed' ), true );
if ( ! $site_report_current ) {
	$pairs                 = array();
	$visible_pairs         = array();
	$collision_total       = 0;
	$collision_total_pages = 1;
	$collision_first       = 0;
	$collision_last        = 0;
}
$openai_error = get_transient( 'content_miner_openai_error_' . get_current_user_id() );
if ( false !== $openai_error ) {
	delete_transient( 'content_miner_openai_error_' . get_current_user_id() );
}
$family_counts = $scored_aggregates_current ? $memory_summary['families'] : array();
arsort( $family_counts );
$readiness_count = $scored_aggregates_current ? (int) $memory_summary['readiness_count'] : 0;
$readiness_scores = array();
foreach ( array( 'seo', 'aeo', 'geo', 'aio' ) as $readiness_lens ) {
	$readiness_scores[ $readiness_lens ] = $readiness_count > 0 ? (int) round( $memory_summary['readiness_sums'][ $readiness_lens ] / $readiness_count ) : 0;
}
$readiness_issues = $memory_summary['readiness_issues'];
arsort( $readiness_issues );
$readiness_tooltips = array(
	'seo' => __( 'Search-engine optimization: how ready this page is to be discovered and understood in search results.', 'content-miner' ),
	'aeo' => __( 'Answer-engine optimization: how ready this page is to be quoted by AI answer tools.', 'content-miner' ),
	'geo' => __( 'Generative-engine optimization: how clearly this page presents useful, supportable information for generative AI systems.', 'content-miner' ),
	'aio' => __( 'AI optimization: how ready this page is for AI tools to extract, understand, and use its information.', 'content-miner' ),
);
$verification_active = in_array( $verification_state['status'], array( 'queued', 'running' ), true );
$pipeline_state_label = function ( $status ) {
	$labels = array(
		'idle' => __( 'Not started', 'content-miner' ),
		'disabled' => __( 'Unavailable', 'content-miner' ),
		'queued' => __( 'Queued', 'content-miner' ),
		'running' => __( 'Running', 'content-miner' ),
		'waiting' => __( 'Waiting', 'content-miner' ),
		'complete' => __( 'Complete', 'content-miner' ),
		'failed' => __( 'Stopped', 'content-miner' ),
	);
	return isset( $labels[ $status ] ) ? $labels[ $status ] : ucfirst( (string) $status );
};
$sync_pipeline_status = isset( $ingestion_state['status'] ) ? sanitize_key( $ingestion_state['status'] ) : 'idle';
$verification_pipeline_status = isset( $verification_state['status'] ) ? sanitize_key( $verification_state['status'] ) : 'idle';
$analysis_pipeline_status = $analysis_handoff_pending && ! $analysis_active
	? 'waiting'
	: ( isset( $analysis_state['status'] ) ? sanitize_key( $analysis_state['status'] ) : 'idle' );
$verification_processed = (int) ( isset( $verification_state['fetched'] ) ? $verification_state['fetched'] : 0 )
	+ (int) ( isset( $verification_state['fallback'] ) ? $verification_state['fallback'] : 0 );
$verification_total = (int) ( isset( $verification_state['total'] ) ? $verification_state['total'] : 0 );
$verification_progress = $verification_total > 0 ? min( 100, round( ( $verification_processed / $verification_total ) * 100 ) ) : 0;
$verification_progress = 'complete' === $verification_pipeline_status ? 100 : $verification_progress;
$analysis_pipeline_progress = 'complete' === $analysis_pipeline_status ? 100 : $analysis_progress;
$pipeline_active = $job_active || $verification_active || $analysis_active;
$cron_disabled = defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON;
$pipeline_next_cron = array(
	'sync' => wp_next_scheduled( Content_Miner_Ingestion::CRON_HOOK ),
	'verification' => wp_next_scheduled( Content_Miner_Rendered_Verification::CRON_HOOK ),
	'analysis' => wp_next_scheduled( Content_Miner_Analysis_Job::CRON_HOOK ),
);
$pipeline_locks = array(
	'sync' => get_option( Content_Miner_Ingestion::LOCK_KEY, array() ),
	'verification' => get_option( Content_Miner_Rendered_Verification::LOCK_KEY, array() ),
	'analysis' => get_option( Content_Miner_Analysis_Job::LOCK_KEY, array() ),
);
$pipeline_runner_labels = array(
	'foreground' => __( 'foreground: this open report page is processing batches', 'content-miner' ),
	'background' => __( 'background: WP-Cron processed the last batch', 'content-miner' ),
	'manual' => __( 'manual: an operator clicked a batch button', 'content-miner' ),
);
$pipeline_last_runner = '';
foreach ( array( $analysis_state, $verification_state, $ingestion_state ) as $pipeline_state_candidate ) {
	if ( ! empty( $pipeline_state_candidate['last_batch_at'] ) ) {
		$pipeline_last_runner = isset( $pipeline_state_candidate['last_runner'] ) ? sanitize_key( $pipeline_state_candidate['last_runner'] ) : '';
		break;
	}
}
$pipeline_mode_text = $pipeline_active
	? __( 'Foreground batches run while this report page stays open; WP-Cron is also scheduled for background progress.', 'content-miner' )
	: __( 'No pipeline stage is currently running.', 'content-miner' );
$pipeline_last_runner_text = isset( $pipeline_runner_labels[ $pipeline_last_runner ] ) ? $pipeline_runner_labels[ $pipeline_last_runner ] : __( 'no batch has completed yet for the visible job state', 'content-miner' );
$pipeline_starved = false;
foreach ( array( $ingestion_state, $verification_state, $analysis_state ) as $pipeline_state_candidate ) {
	if ( in_array( isset( $pipeline_state_candidate['status'] ) ? $pipeline_state_candidate['status'] : '', array( 'queued', 'running' ), true ) ) {
		$updated = ! empty( $pipeline_state_candidate['updated_at'] ) ? strtotime( (string) $pipeline_state_candidate['updated_at'] ) : false;
		if ( false !== $updated && time() - $updated > 2 * MINUTE_IN_SECONDS ) {
			$pipeline_starved = true;
		}
	}
}
$pipeline_format_time = function ( $timestamp ) {
	if ( empty( $timestamp ) ) {
		return __( 'none', 'content-miner' );
	}
	$time = is_numeric( $timestamp ) ? (int) $timestamp : strtotime( (string) $timestamp );
	if ( false === $time || $time <= 0 ) {
		return __( 'none', 'content-miner' );
	}
	return gmdate( 'M j, H:i:s', $time ) . ' UTC';
};
$pipeline_lock_text = function ( $lock ) use ( $pipeline_format_time ) {
	if ( ! is_array( $lock ) || empty( $lock['locked_at'] ) ) {
		return __( 'unlocked', 'content-miner' );
	}
	return sprintf(
		/* translators: %s: UTC lock timestamp. */
		__( 'locked since %s', 'content-miner' ),
		$pipeline_format_time( (int) $lock['locked_at'] )
	);
};
$pipeline_stage_metrics = function ( array $state ) use ( $pipeline_format_time ) {
	$rate = isset( $state['last_batch_pages_per_minute'] ) ? (float) $state['last_batch_pages_per_minute'] : 0.0;
	$records = isset( $state['last_batch_records'] ) ? (int) $state['last_batch_records'] : 0;
	$duration = isset( $state['last_batch_duration_ms'] ) ? (int) $state['last_batch_duration_ms'] : 0;
	return sprintf(
		/* translators: 1: last batch time, 2: processed records, 3: duration in milliseconds, 4: measured pages per minute. */
		__( 'last batch %1$s · %2$s records · %3$s ms · %4$s pages/min', 'content-miner' ),
		$pipeline_format_time( isset( $state['last_batch_at'] ) ? $state['last_batch_at'] : '' ),
		number_format_i18n( $records ),
		number_format_i18n( $duration ),
		number_format_i18n( $rate, 1 )
	);
};
$pipeline_stages = array(
	array(
		'key' => 'sync',
		'label' => __( 'Content synchronization', 'content-miner' ),
		'status' => $sync_pipeline_status,
		'progress' => $job_progress,
		'detail' => 'complete' === $sync_pipeline_status
			? sprintf( /* translators: %s: synchronized record count. */ __( '%s records examined.', 'content-miner' ), number_format_i18n( $ingestion_state['processed'] ) )
			: sprintf( /* translators: 1: synchronized records, 2: total records. */ __( '%1$s of %2$s records examined.', 'content-miner' ), number_format_i18n( $ingestion_state['processed'] ), number_format_i18n( $ingestion_state['total'] ) ),
		'metrics' => $pipeline_stage_metrics( $ingestion_state ),
	),
	array(
		'key' => 'verification',
		'label' => __( 'Rendered verification', 'content-miner' ),
		'status' => $verification_pipeline_status,
		'progress' => $verification_progress,
		'detail' => sprintf(
			/* translators: 1: rendered pages, 2: stored fallbacks, 3: pages remaining. */
			__( '%1$s rendered · %2$s fallback · %3$s remaining.', 'content-miner' ),
			number_format_i18n( isset( $verification_state['fetched'] ) ? $verification_state['fetched'] : 0 ),
			number_format_i18n( isset( $verification_state['fallback'] ) ? $verification_state['fallback'] : 0 ),
			number_format_i18n( isset( $verification_state['remaining'] ) ? $verification_state['remaining'] : 0 )
		),
		'metrics' => $pipeline_stage_metrics( $verification_state ),
	),
	array(
		'key' => 'analysis',
		'label' => __( 'Full-library analysis', 'content-miner' ),
		'status' => $analysis_pipeline_status,
		'progress' => $analysis_pipeline_progress,
		'detail' => 'waiting' === $analysis_pipeline_status
			? __( 'Waiting for synchronization; analysis will start automatically.', 'content-miner' )
			: sprintf( /* translators: 1: analyzed records, 2: total records. */ __( '%1$s of %2$s records analyzed.', 'content-miner' ), number_format_i18n( $analysis_state['processed'] ), number_format_i18n( $analysis_state['total'] ) ),
		'metrics' => $pipeline_stage_metrics( $analysis_state ),
	),
);
$input_source_counts = isset( $memory_summary['input_sources'] ) && is_array( $memory_summary['input_sources'] ) ? $memory_summary['input_sources'] : array();
$ledger_total_pages = max( 1, (int) ceil( (int) $ledger_page['total'] / 25 ) );
$decision_labels = array(
	'keep' => __( 'Keep', 'content-miner' ),
	'refresh' => __( 'Refresh', 'content-miner' ),
	'consolidate' => __( 'Consolidate', 'content-miner' ),
	'differentiate' => __( 'Differentiate', 'content-miner' ),
	'localize' => __( 'Localize', 'content-miner' ),
	'dismiss' => __( 'Dismiss', 'content-miner' ),
);
$content_links = function ( $post_id ) {
	return array(
		'view' => Content_Miner_Repository::get_post_view_url( (int) $post_id ),
		'edit' => get_edit_post_link( (int) $post_id, 'raw' ),
	);
};
$aggregate_metrics = function ( $json ) {
	$data = json_decode( (string) $json, true );
	$totals = array( 'clicks' => 0, 'impressions' => 0, 'sessions' => 0, 'engagement_rate' => 0.0 );
	$engagement_count = 0;
	foreach ( is_array( $data ) && isset( $data['pages'] ) ? $data['pages'] : array() as $page ) {
		$search = isset( $page['search_console'] ) ? $page['search_console'] : array();
		$analytics_page = isset( $page['analytics'] ) ? $page['analytics'] : array();
		$totals['clicks'] += (int) ( isset( $search['clicks'] ) ? $search['clicks'] : 0 );
		$totals['impressions'] += (int) ( isset( $search['impressions'] ) ? $search['impressions'] : 0 );
		$totals['sessions'] += (int) ( isset( $analytics_page['sessions'] ) ? $analytics_page['sessions'] : 0 );
		if ( isset( $analytics_page['engagement_rate'] ) ) {
			$totals['engagement_rate'] += (float) $analytics_page['engagement_rate'];
			++$engagement_count;
		}
	}
	$totals['engagement_rate'] = $engagement_count ? $totals['engagement_rate'] / $engagement_count : 0.0;
	return $totals;
};
$prompt_page = function ( $post_id, $title = '', $url = '', array $recommendation = array() ) {
	$prompt_memory = get_post_meta( (int) $post_id, Content_Miner_Memory::META_KEY, true );
	$prompt_memory = is_array( $prompt_memory ) ? $prompt_memory : array();
	$prompt_analysis = isset( $prompt_memory['analysis'] ) && is_array( $prompt_memory['analysis'] ) ? $prompt_memory['analysis'] : array();
	$prompt_verification = isset( $prompt_memory['verification'] ) && is_array( $prompt_memory['verification'] ) ? $prompt_memory['verification'] : array();
	return array(
		'id'             => (int) $post_id,
		'title'          => '' !== (string) $title ? (string) $title : get_the_title( (int) $post_id ),
		'url'            => '' !== (string) $url ? (string) $url : Content_Miner_Repository::get_post_view_url( (int) $post_id ),
		'recommendation' => $recommendation,
		'input_source'   => isset( $prompt_analysis['content_source'] ) ? $prompt_analysis['content_source'] : ( isset( $prompt_memory['analysis_content_source'] ) ? $prompt_memory['analysis_content_source'] : 'stored_fallback' ),
		'fallback_reason_code' => isset( $prompt_verification['fallback_reason_code'] ) ? $prompt_verification['fallback_reason_code'] : '',
		'search_console' => (array) get_post_meta( (int) $post_id, '_content_miner_search_console', true ),
		'analytics'      => (array) get_post_meta( (int) $post_id, '_content_miner_google_analytics', true ),
	);
};
$report_issues = array();
foreach ( $readiness_issues as $issue_code => $issue_count ) {
	$report_issues[ isset( $readiness_issue_labels[ $issue_code ] ) ? $readiness_issue_labels[ $issue_code ] : $issue_code ] = $issue_count;
}
$report_prompt_pages = $site_report_current ? $report_prompt_page_loader( $search_console ) : array();
$report_prompt_search_sync_needed = $site_report_current
	&& ! empty( $search_console['connected'] )
	&& ! empty( $search_console['property'] )
	&& 0 === (int) $report_prompt_search_evidence_count;
$report_prompt_context = array(
	'source_total'     => $source_total,
	'memory_indexed'   => $memory_indexed,
	'summary'          => $summary,
	'scored_count'     => $scored_count,
	'excluded_count'   => $excluded_count,
	'input_sources'    => $input_source_counts,
	'readiness_scores' => $readiness_scores,
	'top_issues'       => $report_issues,
	'search_console'   => $search_console,
	'analytics'        => $analytics,
	'prompt_pages'     => $report_prompt_pages,
);
$consultation_settings = $consultation->get_settings( isset( $license_state['plan'] ) ? $license_state['plan'] : 'free' );
$report_cta = $consultation->get_cta( $license_state, 'report', get_bloginfo( 'name' ) );
$render_prompt_tools = function ( $target, $prompt, $analysis_context, $button_label = '', $unavailable_message = '', $workflow_download = false ) use ( $ai_explain_enabled, $openai, $ai_explanation, $inventory_page, $collision_page, $inventory_search ) {
	$target       = sanitize_key( $target );
	$prompt_id    = 'cm-prompt-' . $target;
	$item_context = in_array( $analysis_context, array( 'inventory-page', 'collision-pair', 'decision-row' ), true );
	$report_onramp_context = in_array( $analysis_context, array( 'overview', 'readiness' ), true );
	$unavailable_message = trim( (string) $unavailable_message );
	?>
	<div class="cm-ai-tools <?php echo $item_context ? 'cm-ai-tools--item' : 'cm-ai-tools--panel'; ?>" id="cm-ai-<?php echo esc_attr( $target ); ?>">
		<div class="cm-ai-tools__header">
			<?php if ( ! $item_context ) : ?>
			<div class="cm-ai-tools__intro">
				<span class="cm-ai-tools__label"><?php esc_html_e( 'Hand to AI', 'content-miner' ); ?></span>
				<?php if ( $report_onramp_context ) : ?>
					<p class="cm-ai-tools__onramp"><?php esc_html_e( "Don't know what all this means? You don't have to. Copy this prompt into ChatGPT, Claude, or whatever AI you already use — it explains this report and gives you a 30-day action plan.", 'content-miner' ); ?></p>
				<?php endif; ?>
			</div>
			<?php endif; ?>
			<div class="cm-ai-tools__actions">
			<?php if ( '' !== $unavailable_message ) : ?>
				<button class="button button-small" type="button" disabled><?php echo esc_html( $button_label ?: __( 'Copy AI prompt', 'content-miner' ) ); ?></button>
				<?php if ( $ai_explain_enabled && ! empty( $openai['configured'] ) ) : ?>
					<button class="button button-small" type="button" disabled><?php esc_html_e( 'Explain with AI', 'content-miner' ); ?></button>
				<?php endif; ?>
				<span class="cm-ai-tools__status"><?php echo esc_html( $unavailable_message ); ?></span>
			<?php else : ?>
				<button class="button button-small cm-copy-prompt" type="button" data-prompt-target="<?php echo esc_attr( $prompt_id ); ?>"><?php echo esc_html( $button_label ?: __( 'Copy AI prompt', 'content-miner' ) ); ?></button>
				<?php if ( $workflow_download ) : ?>
				<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="cm-ai-explain-form">
					<input type="hidden" name="action" value="content_miner_download_review_workflow">
					<?php wp_nonce_field( 'content_miner_download_review_workflow' ); ?>
					<button class="button button-small" type="submit"><?php esc_html_e( 'Download review workflow', 'content-miner' ); ?></button>
				</form>
				<?php endif; ?>
				<?php if ( $ai_explain_enabled && ! empty( $openai['configured'] ) ) : ?>
				<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="cm-ai-explain-form">
					<input type="hidden" name="action" value="content_miner_explain_prompt">
					<input type="hidden" name="prompt_target" value="<?php echo esc_attr( $target ); ?>">
					<input type="hidden" name="cm_inventory_page" value="<?php echo esc_attr( $inventory_page ); ?>">
					<input type="hidden" name="cm_collision_page" value="<?php echo esc_attr( $collision_page ); ?>">
					<input type="hidden" name="cm_search" value="<?php echo esc_attr( $inventory_search ); ?>">
					<textarea name="prompt" hidden><?php echo esc_textarea( $prompt ); ?></textarea>
					<?php wp_nonce_field( 'content_miner_explain_prompt' ); ?>
					<button class="button button-small cm-explain-prompt" type="submit"><?php esc_html_e( 'Explain with AI', 'content-miner' ); ?></button>
				</form>
				<?php endif; ?>
				<span class="cm-copy-confirmation" role="status" aria-live="polite"></span>
			<?php endif; ?>
			</div>
		</div>
		<?php if ( '' === $unavailable_message ) : ?>
		<textarea id="<?php echo esc_attr( $prompt_id ); ?>" class="cm-ai-prompt-source" readonly hidden><?php echo esc_textarea( $prompt ); ?></textarea>
		<details class="cm-ai-prompt-preview">
			<summary><?php esc_html_e( 'Preview prompt', 'content-miner' ); ?></summary>
			<pre><?php echo esc_html( $prompt ); ?></pre>
		</details>
		<?php if ( isset( $ai_explanation['target'] ) && $target === $ai_explanation['target'] ) : ?>
			<div class="cm-ai-result <?php echo ! empty( $ai_explanation['error'] ) ? 'cm-ai-result--error' : ''; ?>">
				<strong><?php echo ! empty( $ai_explanation['error'] ) ? esc_html__( 'AI explanation unavailable', 'content-miner' ) : esc_html__( 'Plain-language AI explanation', 'content-miner' ); ?></strong>
				<div class="cm-ai-result__body"><?php echo ! empty( $ai_explanation['error'] ) ? esc_html( $ai_explanation['error'] ) : Content_Miner_AI_Response_Renderer::render( $ai_explanation['result'] ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Renderer escapes Markdown and applies a strict wp_kses allowlist. ?></div>
			</div>
			<?php endif; ?>
		<?php endif; ?>
		</div>
		<?php
	};
?>

<div class="wrap cm-wrap">
	<header class="cm-masthead">
		<div>
			<p class="cm-kicker"><?php esc_html_e( 'Editorial evidence, inside WordPress', 'content-miner' ); ?></p>
			<h1 class="cm-brand">
				<img src="<?php echo esc_url( CONTENT_MINER_URL . 'assets/brand/logo-horizontal-dark.svg' ); ?>" alt="<?php esc_attr_e( 'Content Miner', 'content-miner' ); ?>">
			</h1>
			<p class="cm-deck"><?php esc_html_e( 'Decide what to keep, refresh, combine, create, or localize before your content competes with itself.', 'content-miner' ); ?></p>
		</div>
		<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="cm-scan-form cm-memory-form">
			<input type="hidden" name="action" value="content_miner_start_ingestion">
			<?php wp_nonce_field( 'content_miner_start_ingestion' ); ?>
			<button class="button button-primary cm-primary" type="submit" <?php disabled( empty( $free_tier_state['can_sync'] ) ); ?>>
				<?php echo $memory_upgrade_needed ? esc_html__( 'Upgrade content memory', 'content-miner' ) : ( 0 === $memory_indexed ? esc_html__( 'Build content memory', 'content-miner' ) : esc_html__( 'Sync content', 'content-miner' ) ); ?>
			</button>
			<?php if ( ! empty( $memory_summary['last_synced_at'] ) ) : ?>
				<span><?php /* translators: %s: UTC date and time of the latest content-memory sync. */ echo esc_html( sprintf( __( 'Memory updated: %s UTC', 'content-miner' ), gmdate( 'M j, Y H:i', strtotime( $memory_summary['last_synced_at'] ) ) ) ); ?></span>
			<?php endif; ?>
		</form>
	</header>

	<div class="cm-seam" aria-hidden="true">
		<span class="cm-seam__keep"></span><span class="cm-seam__refresh"></span><span class="cm-seam__localize"></span><span class="cm-seam__review"></span>
	</div>

	<?php if ( $notice && isset( $notice_messages[ $notice ] ) ) : ?>
		<div class="cm-notice <?php echo in_array( $notice, array( 'idea-required', 'google-error', 'scoring-override-error', 'scoring-override-sync-required', 'free-activation-invalid', 'free-activation-required', 'free-limit-reached' ), true ) ? 'cm-notice--warning' : ''; ?>" role="status">
			<?php echo esc_html( $notice_messages[ $notice ] ); ?>
		</div>
	<?php endif; ?>

	<?php if ( ! empty( $license_state['limit_reached'] ) ) : ?>
		<div class="cm-notice cm-notice--warning" role="status">
			<?php
			/* translators: 1: licensed page limit, 2: total eligible WordPress records. */
			echo esc_html( sprintf( __( 'Your current plan analyzes up to %1$s pages. Content Miner found %2$s eligible records and preserved existing data beyond the licensed window.', 'content-miner' ), number_format_i18n( $license_state['page_limit'] ), number_format_i18n( $license_state['available_pages'] ) ) );
			?>
			<a href="<?php echo esc_url( $license_state['upgrade_url'] ); ?>"><?php esc_html_e( 'Review upgrade options', 'content-miner' ); ?></a>
		</div>
	<?php endif; ?>

	<?php if ( ! empty( $license_state['configured'] ) && empty( $license_state['is_pro'] ) ) : ?>
		<div class="cm-notice" role="status">
			<?php esc_html_e( 'Content Miner is running in Free mode because no active paid license is available. Existing memory, evidence, vectors, settings, and decisions remain stored.', 'content-miner' ); ?>
			<a href="<?php echo esc_url( $license_state['upgrade_url'] ); ?>"><?php esc_html_e( 'Manage or upgrade the license', 'content-miner' ); ?></a>
		</div>
	<?php endif; ?>

	<?php if ( empty( $free_tier_state['is_pro'] ) ) : ?>
		<section id="free-analyses" class="cm-free-tier" aria-labelledby="cm-free-tier-title">
			<div>
				<p class="cm-eyebrow"><?php esc_html_e( 'Free analyses', 'content-miner' ); ?></p>
				<h2 id="cm-free-tier-title">
					<?php
					/* translators: 1: completed free analyses, 2: lifetime free-analysis limit. */
					echo esc_html( sprintf( __( '%1$d of %2$d free analyses used', 'content-miner' ), (int) $free_tier_state['used'], (int) $free_tier_state['limit'] ) );
					?>
				</h2>
				<?php if ( ! empty( $free_tier_state['exhausted'] ) ) : ?>
					<p><?php esc_html_e( 'Your three free analyses are complete. Your reports are still yours. License this site to keep analyzing.', 'content-miner' ); ?></p>
					<a class="button cm-secondary" href="<?php echo esc_url( $free_tier_state['upgrade_url'] ); ?>"><?php esc_html_e( 'License this site', 'content-miner' ); ?></a>
				<?php elseif ( ! empty( $free_tier_state['activated'] ) ) : ?>
					<p><?php esc_html_e( 'Your free analyses are active. Content synchronization and page updates do not consume an analysis.', 'content-miner' ); ?></p>
					<?php if ( 'pending' === $free_tier_state['subscription_status'] ) : ?>
						<small><?php esc_html_e( 'Email signup delivery is pending and will retry in the background. Analysis remains available.', 'content-miner' ); ?></small>
					<?php endif; ?>
				<?php else : ?>
					<p><?php esc_html_e( 'Activate your 3 free analyses.', 'content-miner' ); ?></p>
					<p><?php esc_html_e( 'Enter your email to activate three free full-library analyses. You’ll receive Content Miner product updates and tips. Every email includes an unsubscribe link.', 'content-miner' ); ?> <a href="<?php echo esc_url( Content_Miner_Free_Scan_Limit::PRIVACY_URL ); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Read the privacy policy.', 'content-miner' ); ?></a></p>
					<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="cm-free-tier__form">
						<input type="hidden" name="action" value="content_miner_activate_free_analyses">
						<?php wp_nonce_field( 'content_miner_activate_free_analyses' ); ?>
						<label for="cm-free-activation-email"><?php esc_html_e( 'Email address', 'content-miner' ); ?></label>
						<input id="cm-free-activation-email" name="activation_email" type="email" autocomplete="email" required>
						<button class="button button-primary cm-primary" type="submit"><?php esc_html_e( 'Activate 3 free analyses', 'content-miner' ); ?></button>
					</form>
				<?php endif; ?>
			</div>
		</section>
	<?php endif; ?>

	<nav class="cm-nav" aria-label="<?php esc_attr_e( 'Content Miner sections', 'content-miner' ); ?>" role="tablist" data-cm-section-nav>
		<a id="cm-tab-overview" href="#overview" role="tab" aria-controls="overview"><?php esc_html_e( 'Overview', 'content-miner' ); ?></a>
		<a id="cm-tab-readiness" href="#readiness" role="tab" aria-controls="readiness"><?php esc_html_e( 'Search & AI', 'content-miner' ); ?></a>
		<a id="cm-tab-inventory" href="#inventory" role="tab" aria-controls="inventory"><?php esc_html_e( 'Inventory', 'content-miner' ); ?></a>
		<a id="cm-tab-collisions" href="#collisions" role="tab" aria-controls="collisions"><?php esc_html_e( 'Collisions', 'content-miner' ); ?></a>
		<a id="cm-tab-decisions" href="#decisions" role="tab" aria-controls="decisions"><?php esc_html_e( 'Decisions', 'content-miner' ); ?></a>
		<a id="cm-tab-idea-checker" href="#idea-checker" role="tab" aria-controls="idea-checker"><?php esc_html_e( 'Check an idea', 'content-miner' ); ?></a>
		<?php if ( $pro_enabled && ( $cloud_connector || $google_enabled || $semantic_enabled ) ) : ?><a id="cm-tab-connections" href="#connections" role="tab" aria-controls="connections"><?php esc_html_e( 'Connections', 'content-miner' ); ?></a><?php endif; ?>
		<a id="cm-tab-settings" href="#settings" role="tab" aria-controls="settings"><?php esc_html_e( 'Settings', 'content-miner' ); ?></a>
		<a id="cm-tab-help" href="#help" role="tab" aria-controls="help"><?php esc_html_e( 'Help', 'content-miner' ); ?></a>
	</nav>

	<div class="cm-report-utilities">
		<details class="cm-ai-disclosure">
			<summary><?php esc_html_e( 'About AI prompts', 'content-miner' ); ?></summary>
			<p class="cm-ai-privacy"><?php esc_html_e( 'Prompts can include page titles, URLs or URL paths, readiness scores, identified gaps, and per-page Search Console clicks, impressions, and visitor metrics when connected. They never include full page bodies. Pasting or sending a prompt shares that evidence with the AI provider you choose.', 'content-miner' ); ?><?php if ( $ai_explain_enabled && ! empty( $openai['configured'] ) ) : ?> <?php esc_html_e( 'Explain with AI sends it to your configured provider and may incur provider charges.', 'content-miner' ); ?><?php endif; ?></p>
		</details>
		<?php if ( $report_cta ) : ?>
			<div class="cm-consultation-cta" data-cta-context="report" data-cta-source="<?php echo esc_attr( $report_cta['source'] ); ?>">
				<a href="<?php echo esc_url( $report_cta['url'] ); ?>" target="_blank" rel="noopener noreferrer"><?php echo esc_html( $report_cta['label'] ); ?></a>
				<button type="button" class="cm-consultation-dismiss" aria-label="<?php esc_attr_e( 'Dismiss consultation link', 'content-miner' ); ?>">×</button>
			</div>
		<?php endif; ?>
	</div>

		<section id="overview" class="cm-overview cm-section" role="tabpanel" aria-labelledby="cm-tab-overview" data-cm-section>
		<?php
		if ( $site_report_current ) {
			$render_prompt_tools( 'overview', $prompt_builder->build_whole_report( $report_prompt_context ), 'overview', __( 'Copy whole-report AI prompt', 'content-miner' ), '', true );
		} else {
			$render_prompt_tools( 'overview', '', 'overview', __( 'Copy whole-report AI prompt', 'content-miner' ), __( 'Your prompt will be ready when the first analysis completes.', 'content-miner' ) );
		}
		?>
		<div class="cm-section-heading">
			<div>
				<p class="cm-eyebrow"><?php esc_html_e( 'Content inventory', 'content-miner' ); ?></p>
				<h2><?php esc_html_e( 'Content Overview', 'content-miner' ); ?></h2>
			</div>
				<div class="cm-section-action"><p><?php esc_html_e( 'A persistent memory of what exists, how it is organized, and what changed since the last synchronization.', 'content-miner' ); ?></p></div>
		</div>
		<section class="cm-pipeline-progress" data-cm-pipeline-active="<?php echo $pipeline_active ? '1' : '0'; ?>" aria-labelledby="cm-pipeline-title">
			<div class="cm-pipeline-progress__heading">
				<div>
					<p class="cm-eyebrow"><?php esc_html_e( 'Run status', 'content-miner' ); ?></p>
					<h3 id="cm-pipeline-title"><?php esc_html_e( 'Analysis pipeline', 'content-miner' ); ?></h3>
				</div>
				<p><?php echo esc_html( $pipeline_mode_text ); ?></p>
			</div>
			<?php if ( $cron_disabled || $pipeline_starved ) : ?>
				<div class="cm-notice cm-notice--warning cm-pipeline-warning" role="status">
					<?php
					echo esc_html(
						$cron_disabled
							? __( 'WP-Cron is disabled. Keep this report page open so foreground batches can finish the work.', 'content-miner' )
							: __( 'WP-Cron appears delayed. Keep this report page open; foreground batches will continue while it is visible.', 'content-miner' )
					);
					?>
				</div>
			<?php endif; ?>
			<div class="cm-pipeline-progress__stages">
				<?php foreach ( $pipeline_stages as $pipeline_stage ) : ?>
					<article class="cm-pipeline-stage cm-pipeline-stage--<?php echo esc_attr( $pipeline_stage['status'] ); ?>" data-cm-pipeline-stage="<?php echo esc_attr( $pipeline_stage['key'] ); ?>">
						<div class="cm-pipeline-stage__title">
							<h4><?php echo esc_html( $pipeline_stage['label'] ); ?></h4>
							<strong><?php echo esc_html( $pipeline_state_label( $pipeline_stage['status'] ) ); ?></strong>
						</div>
						<div class="cm-pipeline-stage__meter" role="progressbar" aria-label="<?php echo esc_attr( $pipeline_stage['label'] ); ?>" aria-valuemin="0" aria-valuemax="100" aria-valuenow="<?php echo esc_attr( $pipeline_stage['progress'] ); ?>"><span style="width: <?php echo esc_attr( $pipeline_stage['progress'] ); ?>%"></span></div>
						<p><?php echo esc_html( $pipeline_stage['detail'] ); ?></p>
						<small><?php echo esc_html( $pipeline_stage['metrics'] ); ?></small>
						<?php if ( 'failed' === $pipeline_stage['status'] ) : ?>
							<p class="cm-error-detail"><?php echo esc_html( 'sync' === $pipeline_stage['key'] ? $ingestion_state['last_error'] : ( 'verification' === $pipeline_stage['key'] ? $verification_state['last_error'] : $analysis_state['last_error'] ) ); ?></p>
						<?php endif; ?>
					</article>
				<?php endforeach; ?>
			</div>
			<details class="cm-pipeline-diagnostics">
				<summary><?php esc_html_e( 'Operator diagnostics', 'content-miner' ); ?></summary>
				<dl>
					<dt><?php esc_html_e( 'Current mode', 'content-miner' ); ?></dt><dd><?php echo esc_html( $pipeline_last_runner_text ); ?></dd>
					<dt><?php esc_html_e( 'WP-Cron', 'content-miner' ); ?></dt><dd><?php echo esc_html( $cron_disabled ? __( 'disabled', 'content-miner' ) : __( 'enabled', 'content-miner' ) ); ?></dd>
					<dt><?php esc_html_e( 'Next sync cron', 'content-miner' ); ?></dt><dd><?php echo esc_html( $pipeline_format_time( $pipeline_next_cron['sync'] ) ); ?></dd>
					<dt><?php esc_html_e( 'Next rendered cron', 'content-miner' ); ?></dt><dd><?php echo esc_html( $pipeline_format_time( $pipeline_next_cron['verification'] ) ); ?></dd>
					<dt><?php esc_html_e( 'Next analysis cron', 'content-miner' ); ?></dt><dd><?php echo esc_html( $pipeline_format_time( $pipeline_next_cron['analysis'] ) ); ?></dd>
					<dt><?php esc_html_e( 'Sync lock', 'content-miner' ); ?></dt><dd><?php echo esc_html( $pipeline_lock_text( $pipeline_locks['sync'] ) ); ?></dd>
					<dt><?php esc_html_e( 'Rendered lock', 'content-miner' ); ?></dt><dd><?php echo esc_html( $pipeline_lock_text( $pipeline_locks['verification'] ) ); ?></dd>
					<dt><?php esc_html_e( 'Analysis lock', 'content-miner' ); ?></dt><dd><?php echo esc_html( $pipeline_lock_text( $pipeline_locks['analysis'] ) ); ?></dd>
				</dl>
			</details>
			<?php if ( $job_active || $analysis_active || ( $verification_active && $verification_enabled ) ) : ?>
				<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="cm-pipeline-progress__action">
					<?php if ( $job_active ) : ?>
						<input type="hidden" name="action" value="content_miner_process_batch"><?php wp_nonce_field( 'content_miner_process_batch' ); ?>
						<button class="button cm-secondary" type="submit"><?php esc_html_e( 'Process next synchronization batch', 'content-miner' ); ?></button>
					<?php elseif ( $analysis_active ) : ?>
						<input type="hidden" name="action" value="content_miner_process_analysis"><?php wp_nonce_field( 'content_miner_process_analysis' ); ?>
						<button class="button cm-secondary" type="submit"><?php esc_html_e( 'Process next analysis batch', 'content-miner' ); ?></button>
					<?php else : ?>
						<input type="hidden" name="action" value="content_miner_process_verification"><?php wp_nonce_field( 'content_miner_process_verification' ); ?>
						<button class="button cm-secondary" type="submit"><?php esc_html_e( 'Process next rendered batch', 'content-miner' ); ?></button>
					<?php endif; ?>
				</form>
			<?php endif; ?>
		</section>
		<?php if ( $report_prompt_search_sync_needed ) : ?>
			<?php // Intentionally non-persistent: collapsing this notice is only visual, and it clears only when current per-page search evidence exists. ?>
			<details class="cm-notice cm-notice--warning cm-report-search-sync-notice" open>
				<summary><?php esc_html_e( 'Per-page search data needs one sync after this update.', 'content-miner' ); ?></summary>
				<p><?php esc_html_e( 'Run a Search Console sync to include clicks and impressions for each page in your AI prompt.', 'content-miner' ); ?></p>
				<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="cm-connection-sync">
					<input type="hidden" name="action" value="content_miner_sync_google">
					<?php wp_nonce_field( 'content_miner_sync_google' ); ?>
					<button class="button button-primary cm-primary" type="submit"><?php echo 'running' === $search_console['sync_status'] ? esc_html__( 'Process next search batch', 'content-miner' ) : esc_html__( 'Sync Search Console', 'content-miner' ); ?></button>
				</form>
			</details>
		<?php endif; ?>
		<?php if ( $job_visible ) : ?>
			<div class="cm-manifest-progress <?php echo 'failed' === $ingestion_state['status'] ? 'cm-manifest-progress--failed' : ''; ?>">
				<div class="cm-manifest-progress__copy">
					<p class="cm-eyebrow">
						<?php
						if ( 'failed' === $ingestion_state['status'] ) {
							esc_html_e( 'Synchronization stopped', 'content-miner' );
						} elseif ( 'complete' === $ingestion_state['status'] ) {
							esc_html_e( 'Last synchronization complete', 'content-miner' );
						} elseif ( 'rendering' === ( isset( $ingestion_state['stage'] ) ? $ingestion_state['stage'] : '' ) ) {
							esc_html_e( 'Collecting rendered inputs', 'content-miner' );
						} else {
							esc_html_e( 'Synchronization in progress', 'content-miner' );
						}
						?>
					</p>
					<strong>
						<?php
						if ( 'rendering' === ( isset( $ingestion_state['stage'] ) ? $ingestion_state['stage'] : '' ) ) {
							/* translators: 1: rendered pages ready, 2: stored fallbacks, 3: pages remaining. */
							echo esc_html( sprintf( __( '%1$s rendered ready · %2$s fallback · %3$s remaining', 'content-miner' ), number_format_i18n( $ingestion_state['snapshot_fetched'] ), number_format_i18n( $ingestion_state['snapshot_fallback'] ), number_format_i18n( $ingestion_state['snapshot_remaining'] ) ) );
						} elseif ( 'complete' === $ingestion_state['status'] ) {
							echo esc_html( number_format_i18n( $ingestion_state['processed'] ) . ' records examined' );
						} else {
							echo esc_html( number_format_i18n( $ingestion_state['processed'] ) . ' of ' . number_format_i18n( $ingestion_state['total'] ) . ' records examined' );
						}
						?>
					</strong>
					<?php if ( 'rendering' === ( isset( $ingestion_state['stage'] ) ? $ingestion_state['stage'] : '' ) ) : ?>
						<span><?php /* translators: 1: request duration, 2: parse duration, 3: queue duration. */ echo esc_html( sprintf( __( 'request %1$s ms · parse %2$s ms · queue %3$s ms', 'content-miner' ), number_format_i18n( $ingestion_state['snapshot_request_duration_ms'] ), number_format_i18n( $ingestion_state['snapshot_parse_duration_ms'] ), number_format_i18n( $ingestion_state['snapshot_queue_duration_ms'] ) ) ); ?></span>
					<?php else : ?>
						<span><?php echo esc_html( number_format_i18n( $ingestion_state['changed'] ) . ' changed · ' . number_format_i18n( $ingestion_state['skipped'] ) . ' unchanged' ); ?></span>
					<?php endif; ?>
					<?php if ( ! empty( $ingestion_state['last_error'] ) ) : ?><span class="cm-error-detail"><?php echo esc_html( $ingestion_state['last_error'] ); ?></span><?php endif; ?>
				</div>
				<div class="cm-manifest-progress__meter" aria-label="<?php /* translators: %d: ingestion progress percentage. */ echo esc_attr( sprintf( __( '%d percent complete', 'content-miner' ), $job_progress ) ); ?>"><span style="width: <?php echo esc_attr( $job_progress ); ?>%"></span></div>
				<?php if ( $job_active ) : ?>
					<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
						<input type="hidden" name="action" value="content_miner_process_batch">
						<?php wp_nonce_field( 'content_miner_process_batch' ); ?>
						<button class="button cm-secondary" type="submit"><?php esc_html_e( 'Process next batch now', 'content-miner' ); ?></button>
					</form>
				<?php endif; ?>
			</div>
		<?php endif; ?>

			<div class="cm-overview-metrics">
			<?php /* translators: %s: total number of eligible WordPress content records before the plan limit. */ ?>
			<article><span><?php echo esc_html( number_format_i18n( $source_total ) ); ?></span><p><?php esc_html_e( 'Source records', 'content-miner' ); ?></p><small><?php echo esc_html( $source_total_available > $source_total ? sprintf( __( '%s eligible · plan limit applied', 'content-miner' ), number_format_i18n( $source_total_available ) ) : __( 'Currently in WordPress', 'content-miner' ) ); ?></small></article>
			<article><span><?php echo esc_html( number_format_i18n( $memory_indexed ) ); ?></span><p><?php esc_html_e( 'Remembered', 'content-miner' ); ?></p><small><?php echo esc_html( $coverage . '% coverage' ); ?></small></article>
			<article><span><?php echo $scored_aggregates_current ? esc_html( number_format_i18n( $memory_summary['exact_duplicate_groups'] ) ) : '&mdash;'; ?></span><p><?php esc_html_e( 'Exact-copy groups', 'content-miner' ); ?></p><small><?php echo $scored_aggregates_current ? esc_html( sprintf( /* translators: %s: scored pages in exact-copy groups. */ __( '%s scored pages affected', 'content-miner' ), number_format_i18n( $memory_summary['exact_duplicate_pages'] ) ) ) : esc_html__( 'Rebuilding scored-page totals', 'content-miner' ); ?></small></article>
			<article><span><?php echo $scored_aggregates_current ? esc_html( number_format_i18n( count( $family_counts ) ) ) : '&mdash;'; ?></span><p><?php esc_html_e( 'Scored content families', 'content-miner' ); ?></p><small><?php echo esc_html( $scored_aggregates_current ? __( 'Compared by structural purpose', 'content-miner' ) : __( 'Rebuilding scored-page totals', 'content-miner' ) ); ?></small></article>
			</div>
			<p class="cm-denominator-note"><?php esc_html_e( 'Content memory is built from WordPress database records, which can include entries a public crawl does not see.', 'content-miner' ); ?></p>

			<?php if ( $memory_indexed > 0 && $scored_aggregates_current ) : ?>
			<p class="cm-scoring-reconciliation">
				<?php
				/* translators: 1: inventoried pages, 2: pages excluded from scoring, 3: scored pages. */
				echo esc_html( sprintf( __( '%1$s pages inventoried, %2$s excluded from site scoring, %3$s scored.', 'content-miner' ), number_format_i18n( $memory_indexed ), number_format_i18n( $excluded_count ), number_format_i18n( $scored_count ) ) );
				?>
			</p>
		<?php elseif ( $memory_upgrade_needed ) : ?>
			<p class="cm-scoring-reconciliation"><?php esc_html_e( 'Upgrade content memory to calculate scored and excluded page totals.', 'content-miner' ); ?></p>
		<?php elseif ( $job_active && 'full' === ( $ingestion_state['mode'] ?? '' ) ) : ?>
			<p class="cm-scoring-reconciliation"><?php /* translators: %s: pages processed during the current synchronization. */ echo esc_html( sprintf( __( 'Scored and excluded page totals are rebuilding. %s pages processed so far.', 'content-miner' ), number_format_i18n( $ingestion_state['processed'] ) ) ); ?></p>
		<?php elseif ( 'failed' === $ingestion_state['status'] && 'full' === ( $ingestion_state['mode'] ?? '' ) ) : ?>
			<p class="cm-scoring-reconciliation"><?php esc_html_e( 'Scored and excluded page totals are unavailable because synchronization stopped before the rebuild finished. Start synchronization again to retry it.', 'content-miner' ); ?></p>
		<?php endif; ?>
		<?php if ( $memory_indexed > 0 ) : ?>
			<p class="cm-scoring-reconciliation">
				<?php
				/* translators: 1: rendered inputs, 2: stored fallbacks, 3: non-public stored inputs. */
				echo esc_html( sprintf( __( 'Input evidence: %1$s rendered, %2$s stored fallback, %3$s stored non-public.', 'content-miner' ), number_format_i18n( isset( $input_source_counts['rendered'] ) ? $input_source_counts['rendered'] : 0 ), number_format_i18n( isset( $input_source_counts['stored_fallback'] ) ? $input_source_counts['stored_fallback'] : 0 ), number_format_i18n( isset( $input_source_counts['stored_nonpublic'] ) ? $input_source_counts['stored_nonpublic'] : 0 ) ) );
				?>
			</p>
		<?php endif; ?>

		<div class="cm-overview-grid">
			<div class="cm-family-manifest cm-panel">
				<div class="cm-panel-heading"><div><p class="cm-eyebrow"><?php esc_html_e( 'Scored composition', 'content-miner' ); ?></p><h3><?php esc_html_e( 'Content families', 'content-miner' ); ?></h3></div><span><?php echo esc_html( $scored_aggregates_current ? number_format_i18n( $scored_count ) . ' scored' : __( 'Rebuilding', 'content-miner' ) ); ?></span></div>
				<?php if ( $family_counts ) : ?>
					<ul>
					<?php foreach ( $family_counts as $family => $count ) : ?>
						<li><span><?php echo esc_html( isset( $family_labels[ $family ] ) ? $family_labels[ $family ] : $family ); ?></span><strong><?php echo esc_html( number_format_i18n( $count ) ); ?></strong><i style="width: <?php echo esc_attr( $scored_count > 0 ? max( 2, round( ( $count / $scored_count ) * 100 ) ) : 0 ); ?>%"></i></li>
					<?php endforeach; ?>
					</ul>
				<?php else : ?>
					<?php if ( $scored_aggregates_current && $memory_indexed > 0 && 0 === $scored_count ) : ?>
						<p class="cm-inline-empty"><?php esc_html_e( 'All inventoried pages are excluded from site scoring. Use “Include in site scoring” in the inventory to restore a page.', 'content-miner' ); ?></p>
					<?php else : ?>
						<p class="cm-inline-empty"><?php echo esc_html( $scored_aggregates_current ? __( 'Build content memory to classify the site.', 'content-miner' ) : __( 'Scored composition will appear when synchronization finishes.', 'content-miner' ) ); ?></p>
					<?php endif; ?>
				<?php endif; ?>
			</div>
				<div class="cm-recent-memory cm-panel">
				<div class="cm-panel-heading"><div><p class="cm-eyebrow"><?php esc_html_e( 'Observed history', 'content-miner' ); ?></p><h3><?php esc_html_e( 'Recent memory', 'content-miner' ); ?></h3></div></div>
				<?php if ( $recent_changes ) : ?>
					<ol>
					<?php foreach ( array_slice( $recent_changes, 0, 8 ) as $change ) : ?>
						<?php $change_links = $content_links( $change['post_id'] ); ?>
						<li><span class="cm-change-mark cm-change-mark--<?php echo esc_attr( $change['change_type'] ); ?>"></span><div><?php if ( $change_links['view'] ) : ?><a href="<?php echo esc_url( $change_links['view'] ); ?>" target="_blank" rel="noopener noreferrer"><?php echo esc_html( $change['title'] ); ?></a><?php else : ?><span><?php echo esc_html( $change['title'] ); ?></span><?php endif; ?><?php if ( $change_links['edit'] ) : ?><a class="cm-edit-link" href="<?php echo esc_url( $change_links['edit'] ); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Edit', 'content-miner' ); ?></a><?php endif; ?><small><?php echo esc_html( ucfirst( $change['change_type'] ) . ' · ' . ( isset( $family_labels[ $change['family'] ] ) ? $family_labels[ $change['family'] ] : $change['family'] ) ); ?></small></div></li>
					<?php endforeach; ?>
					</ol>
				<?php else : ?>
					<p class="cm-inline-empty"><?php esc_html_e( 'New and changed pages will appear here after synchronization.', 'content-miner' ); ?></p>
				<?php endif; ?>
			</div>
		</div>
	</section>

		<section id="readiness" class="cm-readiness cm-section" role="tabpanel" aria-labelledby="cm-tab-readiness" data-cm-section>
		<div class="cm-section-heading">
			<div>
				<p class="cm-eyebrow"><?php esc_html_e( 'Visibility readiness', 'content-miner' ); ?></p>
				<h2><?php esc_html_e( 'Search & AI signals', 'content-miner' ); ?></h2>
			</div>
				<div class="cm-section-action"><p><?php esc_html_e( 'Four evidence tracks show whether content can be discovered, understood, answered, and cited. These are readiness checks—not ranking or citation guarantees.', 'content-miner' ); ?></p></div>
		</div>
		<?php if ( $site_report_current ) { $render_prompt_tools( 'readiness', $prompt_builder->build_whole_report( $report_prompt_context, __( 'Search and AI readiness', 'content-miner' ) ), 'readiness' ); } ?>

		<?php if ( $readiness_count > 0 ) : ?>
			<div class="cm-assay" aria-label="<?php esc_attr_e( 'Average readiness scores', 'content-miner' ); ?>">
			<?php
			$lens_copy = array(
				'seo' => array( __( 'SEO', 'content-miner' ), __( 'Discovery', 'content-miner' ) ),
				'aeo' => array( __( 'AEO', 'content-miner' ), __( 'Answers', 'content-miner' ) ),
				'geo' => array( __( 'GEO', 'content-miner' ), __( 'Evidence', 'content-miner' ) ),
				'aio' => array( __( 'AIO', 'content-miner' ), __( 'AI readiness', 'content-miner' ) ),
			);
			foreach ( $lens_copy as $lens => $copy ) :
				$score = $readiness_scores[ $lens ];
			?>
				<article class="cm-assay__track cm-assay__track--<?php echo esc_attr( $lens ); ?>" title="<?php echo esc_attr( $readiness_tooltips[ $lens ] ); ?>">
					<div><span><?php echo esc_html( $copy[0] ); ?></span><small><?php echo esc_html( $copy[1] ); ?></small></div>
					<strong><?php echo esc_html( $score ); ?></strong>
					<i><b style="height: <?php echo esc_attr( $score ); ?>%"></b></i>
				</article>
			<?php endforeach; ?>
			</div>

			<div class="cm-readiness-grid">
				<div class="cm-panel cm-readiness-bands">
					<div class="cm-panel-heading"><div><p class="cm-eyebrow"><?php esc_html_e( 'Distribution', 'content-miner' ); ?></p><h3><?php esc_html_e( 'Readiness scores', 'content-miner' ); ?></h3></div><span><?php echo esc_html( number_format_i18n( $readiness_count ) . ' pages' ); ?></span></div>
					<ul>
						<li><span><?php esc_html_e( 'Strong', 'content-miner' ); ?></span><strong><?php echo esc_html( number_format_i18n( $memory_summary['readiness_bands']['strong'] ?? 0 ) ); ?></strong></li>
						<li><span><?php esc_html_e( 'Needs improvement', 'content-miner' ); ?></span><strong><?php echo esc_html( number_format_i18n( $memory_summary['readiness_bands']['improve'] ?? 0 ) ); ?></strong></li>
						<li><span><?php esc_html_e( 'Weak', 'content-miner' ); ?></span><strong><?php echo esc_html( number_format_i18n( $memory_summary['readiness_bands']['weak'] ?? 0 ) ); ?></strong></li>
					</ul>
				</div>

				<div class="cm-panel cm-readiness-issues">
					<div class="cm-panel-heading"><div><p class="cm-eyebrow"><?php esc_html_e( 'Recurring evidence', 'content-miner' ); ?></p><h3><?php esc_html_e( 'Most common gaps', 'content-miner' ); ?></h3></div></div>
					<?php if ( $readiness_issues ) : ?><ol>
					<?php foreach ( array_slice( $readiness_issues, 0, 6, true ) as $issue_code => $issue_count ) : ?>
						<li><strong><?php echo esc_html( number_format_i18n( $issue_count ) ); ?></strong><span><?php echo esc_html( $readiness_issue_labels[ $issue_code ] ?? $issue_code ); ?></span></li>
					<?php endforeach; ?>
					</ol><?php else : ?><p class="cm-inline-empty"><?php esc_html_e( 'No recurring gaps were detected.', 'content-miner' ); ?></p><?php endif; ?>
				</div>
			</div>
		<?php else : ?>
			<div class="cm-panel cm-readiness-empty">
				<?php if ( $scored_aggregates_current && $memory_indexed > 0 && 0 === $scored_count ) : ?>
					<h3><?php esc_html_e( 'No pages are included in site scoring.', 'content-miner' ); ?></h3>
					<p><?php esc_html_e( 'Review excluded pages in the inventory and use “Include in site scoring” on any page that should count.', 'content-miner' ); ?></p>
				<?php else : ?>
					<h3><?php esc_html_e( 'Synchronize to build readiness scores.', 'content-miner' ); ?></h3>
					<p><?php esc_html_e( 'The next full memory build will evaluate every scored page without sending content to an external service.', 'content-miner' ); ?></p>
				<?php endif; ?>
			</div>
		<?php endif; ?>
	</section>

	<?php if ( empty( $scan ) && 0 === $memory_indexed ) : ?>
		<section class="cm-empty cm-panel">
			<p class="cm-eyebrow"><?php esc_html_e( 'No inventory yet', 'content-miner' ); ?></p>
			<h2><?php esc_html_e( 'Start with what you already own.', 'content-miner' ); ?></h2>
			<p><?php esc_html_e( 'The first scan reads posts, pages, drafts, and public custom post types. It never deletes, redirects, rewrites, or publishes anything.', 'content-miner' ); ?></p>
		</section>
	<?php elseif ( ! empty( $scan ) && $site_report_current ) : ?>
		<section class="cm-summary" aria-label="<?php esc_attr_e( 'Latest scan summary', 'content-miner' ); ?>">
			<div class="cm-summary__lead">
				<span><?php echo esc_html( (string) $scan['item_count'] ); ?></span>
				<?php if ( isset( $summary['scored'], $summary['excluded'] ) ) : ?>
					<p><?php /* translators: 1: excluded pages, 2: scored pages. */ echo esc_html( sprintf( __( 'pages inventoried · %1$s excluded · %2$s scored', 'content-miner' ), number_format_i18n( $summary['excluded'] ), number_format_i18n( $summary['scored'] ) ) ); ?></p>
				<?php else : ?>
					<p><?php esc_html_e( 'pieces analyzed', 'content-miner' ); ?></p>
				<?php endif; ?>
			</div>
			<div><span><?php echo esc_html( (string) ( $summary['keep'] ?? 0 ) ); ?></span><p><?php esc_html_e( 'Keep', 'content-miner' ); ?></p></div>
			<div><span><?php echo esc_html( (string) ( $summary['refresh'] ?? 0 ) ); ?></span><p><?php esc_html_e( 'Refresh', 'content-miner' ); ?></p></div>
			<div><span><?php echo esc_html( (string) ( $summary['localize'] ?? 0 ) ); ?></span><p><?php esc_html_e( 'Localize', 'content-miner' ); ?></p></div>
			<div><span><?php echo esc_html( (string) ( $summary['overlap_pairs'] ?? 0 ) ); ?></span><p><?php esc_html_e( 'Collisions', 'content-miner' ); ?></p></div>
		</section>
	<?php endif; ?>

	<section id="inventory" class="cm-section" role="tabpanel" aria-labelledby="cm-tab-inventory" data-cm-section>
		<div class="cm-section-heading">
			<div>
				<p class="cm-eyebrow"><?php esc_html_e( 'Current library', 'content-miner' ); ?></p>
				<h2><?php esc_html_e( 'Inventory decisions', 'content-miner' ); ?></h2>
			</div>
			<div class="cm-section-action">
					<p><?php esc_html_e( 'This resumable audit analyzes the complete content memory in batches of 100, shows 12 pages by default, and keeps each screen to 25 pages.', 'content-miner' ); ?></p>
				<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
					<input type="hidden" name="action" value="<?php echo esc_attr( $analysis_active ? 'content_miner_process_analysis' : 'content_miner_run_scan' ); ?>">
					<?php wp_nonce_field( $analysis_active ? 'content_miner_process_analysis' : 'content_miner_run_scan' ); ?>
					<button class="button cm-secondary" type="submit" <?php disabled( ! $analysis_active && empty( $free_tier_state['can_start_analysis'] ) ); ?>><?php echo $analysis_active ? esc_html__( 'Process next analysis batch', 'content-miner' ) : ( empty( $scan ) ? esc_html__( 'Analyze full library', 'content-miner' ) : esc_html__( 'Refresh full analysis', 'content-miner' ) ); ?></button>
					<?php if ( $analysis_active ) : ?><span><?php /* translators: 1: analyzed pages, 2: total pages, 3: completion percentage. */ echo esc_html( sprintf( __( '%1$s of %2$s analyzed (%3$s%%)', 'content-miner' ), number_format_i18n( $analysis_state['processed'] ), number_format_i18n( $analysis_state['total'] ), number_format_i18n( $analysis_progress ) ) ); ?></span><?php endif; ?>
				</form>
				<?php if ( $verification_enabled ) : ?>
					<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
						<input type="hidden" name="action" value="<?php echo esc_attr( $verification_active ? 'content_miner_process_verification' : 'content_miner_start_verification' ); ?>"><?php wp_nonce_field( $verification_active ? 'content_miner_process_verification' : 'content_miner_start_verification' ); ?>
						<button class="button cm-secondary" type="submit"><?php echo $verification_active ? esc_html__( 'Process next rendered batch', 'content-miner' ) : esc_html__( 'Refresh rendered inputs', 'content-miner' ); ?></button>
						<span><?php /* translators: 1: rendered pages, 2: stored fallbacks, 3: pages remaining. */ echo esc_html( sprintf( __( '%1$s rendered · %2$s fallback · %3$s remaining. Public pages only.', 'content-miner' ), number_format_i18n( $verification_state['fetched'] ), number_format_i18n( $verification_state['fallback'] ), number_format_i18n( $verification_state['remaining'] ) ) ); ?></span>
						<span><?php esc_html_e( 'Rendered inputs feed readiness and similarity. Any page using stored fallback is marked explicitly.', 'content-miner' ); ?></span>
					</form>
				<?php endif; ?>
				<?php if ( ! empty( $analysis_state['last_error'] ) ) : ?><div class="cm-connection-warning"><?php echo esc_html( $analysis_state['last_error'] ); ?></div><?php endif; ?>
			</div>
		</div>
		<?php if ( $site_report_current ) { $render_prompt_tools( 'inventory', $prompt_builder->build_whole_report( $report_prompt_context, __( 'inventory decisions', 'content-miner' ) ), 'inventory' ); } ?>

		<?php if ( $inventory_total > 0 || '' !== $inventory_search ) : ?>
			<div class="cm-library-index">
				<form class="cm-inventory-search" method="get" action="<?php echo esc_url( admin_url( 'admin.php' ) ); ?>">
					<input type="hidden" name="page" value="<?php echo esc_attr( Content_Miner_Admin::PAGE_SLUG ); ?>">
					<label for="cm-inventory-search"><?php esc_html_e( 'Find an audited page', 'content-miner' ); ?></label>
					<div class="cm-inventory-search__field">
						<span class="dashicons dashicons-search" aria-hidden="true"></span>
						<input id="cm-inventory-search" name="cm_search" type="search" value="<?php echo esc_attr( $inventory_search ); ?>" placeholder="<?php esc_attr_e( 'Search title, type, status, or decision', 'content-miner' ); ?>">
						<button class="button cm-secondary" type="submit"><?php esc_html_e( 'Search', 'content-miner' ); ?></button>
						<?php if ( '' !== $inventory_search ) : ?><a class="cm-search-clear" href="<?php echo esc_url( add_query_arg( 'page', Content_Miner_Admin::PAGE_SLUG, admin_url( 'admin.php' ) ) . '#inventory' ); ?>"><?php esc_html_e( 'Clear', 'content-miner' ); ?></a><?php endif; ?>
					</div>
				</form>
				<div class="cm-library-index__status" aria-live="polite">
					<strong><?php /* translators: 1: first visible row, 2: last visible row, 3: total rows. */ echo esc_html( sprintf( __( '%1$s–%2$s of %3$s', 'content-miner' ), number_format_i18n( $inventory_first ), number_format_i18n( $inventory_last ), number_format_i18n( $inventory_total ) ) ); ?></strong>
					<span><?php echo '' !== $inventory_search ? esc_html__( 'matching audited pages', 'content-miner' ) : esc_html__( 'audited pages', 'content-miner' ); ?></span>
				</div>
			</div>

			<?php if ( ! empty( $items ) ) : ?>
			<div class="cm-table-shell">
				<table class="cm-table">
					<thead><tr><th><?php esc_html_e( 'Content', 'content-miner' ); ?></th><th><?php esc_html_e( 'Decision', 'content-miner' ); ?></th><th><?php esc_html_e( 'Evidence', 'content-miner' ); ?></th><th><?php esc_html_e( 'Search & AI', 'content-miner' ); ?></th><th><?php esc_html_e( 'Verification', 'content-miner' ); ?></th><th><?php esc_html_e( 'Signals', 'content-miner' ); ?></th></tr></thead>
						<tbody data-cm-inventory-list>
						<?php foreach ( $items as $item_index => $item ) : ?>
						<?php
						$recorded_decision = isset( $page_decisions[ (int) $item['id'] ] ) ? $page_decisions[ (int) $item['id'] ] : null;
						$item_links = array( 'view' => isset( $item['view_url'] ) ? $item['view_url'] : Content_Miner_Repository::get_post_view_url( $item['id'] ), 'edit' => isset( $item['edit_url'] ) ? $item['edit_url'] : get_edit_post_link( (int) $item['id'], 'raw' ) );
						$item_anchor = ltrim( Content_Miner_Admin::decision_anchor( $item['id'] ), '#' );
						$item_scoring = isset( $item['scoring'] ) && is_array( $item['scoring'] ) ? $item['scoring'] : array();
						$item_excluded = ! empty( $item_scoring['excluded'] );
						$item_override = isset( $item_scoring['override'] ) && 'include' === $item_scoring['override'];
						$item_reason_codes = isset( $item_scoring['automatic_reasons'] ) && is_array( $item_scoring['automatic_reasons'] ) ? $item_scoring['automatic_reasons'] : array();
						$item_reason_text = array_map( function ( $code ) use ( $scoring_reason_labels ) { return isset( $scoring_reason_labels[ $code ] ) ? $scoring_reason_labels[ $code ] : $code; }, $item_reason_codes );
						?>
						<?php $item_prompt_recommendation = $recorded_decision ? array( 'action' => $decision_labels[ $recorded_decision['decision'] ], 'reason' => $recorded_decision['note'] ?: __( 'This is the operator’s recorded editorial decision.', 'content-miner' ) ) : $item['recommendation']; $item_prompt_data = $prompt_page( $item['id'], $item['title'], $item_links['view'], $item_prompt_recommendation ); $item_prompt = $prompt_builder->build_single_page( $item_prompt_data ); ?>
							<tr id="<?php echo esc_attr( $item_anchor ); ?>"<?php if ( $item_index >= $inventory_default_visible ) : ?> class="cm-inventory-row--deferred" hidden<?php endif; ?>>
							<td data-label="<?php esc_attr_e( 'Content', 'content-miner' ); ?>">
								<?php if ( $item_links['view'] ) : ?><a href="<?php echo esc_url( $item_links['view'] ); ?>" class="cm-title" target="_blank" rel="noopener noreferrer"><?php echo esc_html( $item['title'] ?: __( '(Untitled)', 'content-miner' ) ); ?></a><?php else : ?><span class="cm-title"><?php echo esc_html( $item['title'] ?: __( '(Untitled)', 'content-miner' ) ); ?></span><?php endif; ?>
								<?php if ( $item_links['edit'] ) : ?><a class="cm-edit-link" href="<?php echo esc_url( $item_links['edit'] ); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Edit', 'content-miner' ); ?></a><?php endif; ?>
								<span class="cm-meta"><?php echo esc_html( $item['post_type'] . ' · ' . $item['status'] ); ?></span>
							</td>
							<td data-label="<?php esc_attr_e( 'Decision', 'content-miner' ); ?>">
								<?php $display_decision = $recorded_decision ? $decision_labels[ $recorded_decision['decision'] ] : $item['recommendation']['action']; ?>
								<?php $display_decision_class = sanitize_html_class( strtolower( str_replace( ' ', '-', $display_decision ) ) ); ?>
								<span class="cm-badge cm-badge--<?php echo esc_attr( $display_decision_class ); ?>"><?php echo esc_html( $display_decision ); ?></span>
								<span class="cm-confidence"><?php echo $recorded_decision ? esc_html__( 'Recorded decision', 'content-miner' ) : esc_html( $item['recommendation']['confidence'] ? $item['recommendation']['confidence'] . ' confidence' : __( 'Analysis pending', 'content-miner' ) ); ?></span>
							</td>
							<td data-label="<?php esc_attr_e( 'Evidence', 'content-miner' ); ?>">
								<p><?php echo esc_html( $recorded_decision && $recorded_decision['note'] ? $recorded_decision['note'] : $item['recommendation']['reason'] ); ?></p>
								<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="cm-decision-form">
									<input type="hidden" name="action" value="content_miner_record_decision"><input type="hidden" name="post_id" value="<?php echo esc_attr( $item['id'] ); ?>"><input type="hidden" name="cm_inventory_page" value="<?php echo esc_attr( $inventory_page ); ?>"><input type="hidden" name="cm_collision_page" value="<?php echo esc_attr( $collision_page ); ?>"><input type="hidden" name="cm_search" value="<?php echo esc_attr( $inventory_search ); ?>">
									<?php wp_nonce_field( 'content_miner_record_decision' ); ?>
									<input name="note" type="text" maxlength="500" placeholder="<?php esc_attr_e( 'Optional decision note', 'content-miner' ); ?>">
									<div class="cm-decision-buttons"><?php foreach ( $decision_labels as $decision_key => $decision_label ) : ?><button class="button button-small" type="submit" name="decision" value="<?php echo esc_attr( $decision_key ); ?>"><?php echo esc_html( $decision_label ); ?></button><?php endforeach; ?></div>
								</form>
								<?php $render_prompt_tools( 'page-' . $item['id'], $item_prompt, 'inventory-page' ); ?>
							</td>
							<td data-label="<?php esc_attr_e( 'Search & AI', 'content-miner' ); ?>">
							<?php if ( $item_excluded ) : ?>
								<span class="cm-signal cm-signal--alert"><?php esc_html_e( 'NOT SCORED — excluded from site scoring', 'content-miner' ); ?></span>
								<?php if ( $item_reason_text ) : ?><small class="cm-readiness-note"><?php /* translators: %s: automatic exclusion reasons. */ echo esc_html( sprintf( __( 'Detected automatically: %s', 'content-miner' ), implode( ' · ', $item_reason_text ) ) ); ?></small><?php endif; ?>
								<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="cm-scoring-form">
									<input type="hidden" name="action" value="content_miner_set_scoring_override"><input type="hidden" name="post_id" value="<?php echo esc_attr( $item['id'] ); ?>"><input type="hidden" name="scoring_mode" value="include"><input type="hidden" name="cm_inventory_page" value="<?php echo esc_attr( $inventory_page ); ?>"><input type="hidden" name="cm_search" value="<?php echo esc_attr( $inventory_search ); ?>">
									<?php wp_nonce_field( 'content_miner_set_scoring_override' ); ?>
									<button class="button button-small" type="submit"><?php esc_html_e( 'Include in site scoring', 'content-miner' ); ?></button>
								</form>
							<?php elseif ( $item_override ) : ?>
								<span class="cm-signal cm-signal--verified"><?php esc_html_e( 'Included by operator', 'content-miner' ); ?></span>
								<small class="cm-readiness-note">
									<?php
									if ( $item_reason_text ) {
										/* translators: %s: automatic exclusion reasons that remain overridden. */
										echo esc_html( sprintf( __( 'Automatic detection would exclude this page: %s', 'content-miner' ), implode( ' · ', $item_reason_text ) ) );
									} else {
										esc_html_e( 'No automatic exclusion is currently detected.', 'content-miner' );
									}
									?>
								</small>
								<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="cm-scoring-form">
									<input type="hidden" name="action" value="content_miner_set_scoring_override"><input type="hidden" name="post_id" value="<?php echo esc_attr( $item['id'] ); ?>"><input type="hidden" name="scoring_mode" value="automatic"><input type="hidden" name="cm_inventory_page" value="<?php echo esc_attr( $inventory_page ); ?>"><input type="hidden" name="cm_search" value="<?php echo esc_attr( $inventory_search ); ?>">
									<?php wp_nonce_field( 'content_miner_set_scoring_override' ); ?>
									<button class="button button-small" type="submit"><?php esc_html_e( 'Use automatic exclusion', 'content-miner' ); ?></button>
								</form>
							<?php endif; ?>
							<?php if ( ! empty( $item['readiness']['scores'] ) ) : ?>
								<div class="cm-mini-assay">
								<?php foreach ( $item['readiness']['scores'] as $lens => $score ) : ?><span class="cm-mini-assay__<?php echo esc_attr( $lens ); ?>" title="<?php echo esc_attr( isset( $readiness_tooltips[ $lens ] ) ? $readiness_tooltips[ $lens ] : '' ); ?>"><b><?php echo esc_html( strtoupper( $lens ) ); ?></b><?php echo esc_html( $score ); ?></span><?php endforeach; ?>
								</div>
								<?php if ( $item_excluded ) : ?><small class="cm-readiness-note"><?php esc_html_e( 'Individual page evidence; not included in site totals.', 'content-miner' ); ?></small><?php endif; ?>
								<?php if ( ! empty( $item['readiness']['issues'] ) ) : ?><small class="cm-readiness-note"><?php echo esc_html( implode( ' · ', array_map( function ( $code ) use ( $readiness_issue_labels ) { return isset( $readiness_issue_labels[ $code ] ) ? $readiness_issue_labels[ $code ] : $code; }, array_slice( $item['readiness']['issues'], 0, 2 ) ) ) ); ?></small><?php endif; ?>
								<?php if ( isset( $item['readiness']['not_measured']['author_context'] ) && 'not_measured' === $item['readiness']['not_measured']['author_context'] ) : ?><small class="cm-readiness-note"><?php esc_html_e( 'Author context: not measured.', 'content-miner' ); ?></small><?php endif; ?>
								<?php if ( isset( $item['readiness']['not_measured']['no-question'] ) ) : ?><small class="cm-readiness-note"><?php /* translators: %s: not-measured reason. */ echo esc_html( sprintf( __( 'Question check: not measured (%s).', 'content-miner' ), $item['readiness']['not_measured']['no-question'] ) ); ?></small><?php endif; ?>
								<?php if ( isset( $item['readiness']['not_measured']['no-faq-depth'] ) ) : ?><small class="cm-readiness-note"><?php /* translators: %s: not-measured reason. */ echo esc_html( sprintf( __( 'FAQ depth check: not measured (%s).', 'content-miner' ), $item['readiness']['not_measured']['no-faq-depth'] ) ); ?></small><?php endif; ?>
								<?php $item_signals = isset( $item['signals'] ) && is_array( $item['signals'] ) ? $item['signals'] : array(); ?>
								<?php if ( ! empty( $item_signals['author_source'] ) ) : ?><small class="cm-readiness-note"><?php /* translators: %s: source of detected author evidence. */ echo esc_html( sprintf( __( 'Author source: %s', 'content-miner' ), $item_signals['author_source'] ) ); ?></small><?php endif; ?>
								<?php if ( ! empty( $item_signals['published_source'] ) ) : ?><small class="cm-readiness-note"><?php /* translators: %s: source of detected publication-date evidence. */ echo esc_html( sprintf( __( 'Published source: %s', 'content-miner' ), $item_signals['published_source'] ) ); ?></small><?php endif; ?>
								<?php if ( ! empty( $item_signals['modified_source'] ) ) : ?><small class="cm-readiness-note"><?php /* translators: %s: source of detected modified-date evidence. */ echo esc_html( sprintf( __( 'Modified source: %s', 'content-miner' ), $item_signals['modified_source'] ) ); ?></small><?php endif; ?>
								<?php $item_readiness_evidence = isset( $item['readiness']['evidence'] ) && is_array( $item['readiness']['evidence'] ) ? $item['readiness']['evidence'] : array(); ?>
								<?php if ( ! empty( $item_readiness_evidence['direct_answer_span'] ) ) : ?><small class="cm-readiness-note"><?php /* translators: %s: measured direct-answer opening span. */ echo esc_html( sprintf( __( 'Direct-answer span: %s', 'content-miner' ), $item_readiness_evidence['direct_answer_span'] ) ); ?></small><?php endif; ?>
							<?php elseif ( ! $item_excluded ) : ?><span class="cm-meta"><?php esc_html_e( 'Refresh the full analysis.', 'content-miner' ); ?></span><?php endif; ?>
							</td>
							<td data-label="<?php esc_attr_e( 'Verification', 'content-miner' ); ?>">
							<?php if ( ! empty( $item['verification'] ) ) : ?>
								<?php
								$item_input_source = isset( $item['analysis_content_source'] ) ? $item['analysis_content_source'] : 'stored_fallback';
								$rendered_used = 'rendered' === $item_input_source;
								$verification_alert = 'stored_fallback' === $item_input_source;
								$verification_label = $rendered_used ? __( 'Rendered', 'content-miner' ) : ( $verification_alert ? __( 'Stored fallback', 'content-miner' ) : __( 'Stored non-public', 'content-miner' ) );
								?>
								<span class="cm-signal <?php echo esc_attr( $verification_alert ? 'cm-signal--alert' : 'cm-signal--verified' ); ?>"><?php echo esc_html( $verification_label ); ?></span>
								<small><?php echo esc_html( Content_Miner_Rendered_Verification::format_result( $item['verification'] ) ); ?></small>
							<?php else : ?>
								<span class="cm-meta"><?php esc_html_e( 'Not checked', 'content-miner' ); ?></span>
							<?php endif; ?>
							</td>
							<td data-label="<?php esc_attr_e( 'Signals', 'content-miner' ); ?>"><span class="cm-signal"><?php echo esc_html( number_format_i18n( $item['word_count'] ) . ' words' ); ?></span><?php if ( null !== $item['age_days'] ) : ?><span class="cm-signal"><?php echo esc_html( number_format_i18n( $item['age_days'] ) . ' days since update' ); ?></span><?php endif; ?><?php if ( ! empty( $item['content_sources'] ) ) : ?><span class="cm-signal cm-signal--verified"><?php echo esc_html( implode( ' + ', $item['content_sources'] ) ); ?></span><?php endif; ?><?php if ( ! empty( $item['extraction_warnings'] ) ) : ?><span class="cm-signal cm-signal--alert"><?php echo esc_html( $item['extraction_warnings'][0] ); ?></span><?php endif; ?><span class="cm-signal <?php echo 'Content only' !== ( $item['data_confidence'] ?? 'Content only' ) ? 'cm-signal--verified' : ''; ?>"><?php echo esc_html( $item['data_confidence'] ?? 'Content only' ); ?></span><?php if ( $item['overlap_count'] ) : ?><span class="cm-signal cm-signal--alert"><?php /* translators: %d: number of content collisions. */ echo esc_html( sprintf( _n( '%d collision', '%d collisions', $item['overlap_count'], 'content-miner' ), $item['overlap_count'] ) ); ?></span><?php endif; ?></td>
						</tr>
					<?php endforeach; ?>
					</tbody>
					</table>
				</div>
				<?php if ( $inventory_can_expand ) : ?>
					<div class="cm-inventory-expand">
						<button class="button cm-secondary" type="button" data-cm-inventory-expand aria-expanded="false">
							<?php
							if ( $inventory_total === $inventory_loaded_count ) {
								/* translators: %s: total audited pages available in this report. */
								echo esc_html( sprintf( __( 'Show all %s pages', 'content-miner' ), number_format_i18n( $inventory_loaded_count ) ) );
							} else {
								/* translators: 1: pages loaded on this report screen, 2: total audited pages. */
								echo esc_html( sprintf( __( 'Show all %1$s pages on this screen (%2$s total)', 'content-miner' ), number_format_i18n( $inventory_loaded_count ), number_format_i18n( $inventory_total ) ) );
							}
							?>
						</button>
					</div>
				<?php endif; ?>
			<?php else : ?>
				<div class="cm-inventory-empty">
					<strong><?php esc_html_e( 'No audited pages match this search.', 'content-miner' ); ?></strong>
					<span><?php esc_html_e( 'Try a shorter title, a post type such as “page,” or a decision such as “Refresh.”', 'content-miner' ); ?></span>
				</div>
			<?php endif; ?>

			<?php if ( $inventory_total_pages > 1 ) : ?>
				<nav class="cm-pagination" aria-label="<?php esc_attr_e( 'Inventory pages', 'content-miner' ); ?>">
					<?php
					$pagination = paginate_links(
						array(
							'base'      => str_replace( '999999999', '%#%', esc_url( add_query_arg( 'cm_inventory_page', 999999999, $inventory_base_url ) ) ) . '#inventory',
							'format'    => '',
							'current'   => $inventory_page,
							'total'     => $inventory_total_pages,
							'mid_size'  => 2,
							'end_size'  => 1,
							'prev_text' => __( 'Previous', 'content-miner' ),
							'next_text' => __( 'Next', 'content-miner' ),
							'type'      => 'list',
						)
					);
					echo wp_kses_post( $pagination );
					?>
				</nav>
			<?php endif; ?>
		<?php else : ?>
			<p class="cm-inline-empty"><?php esc_html_e( 'Build content memory, then analyze the full library to populate page decisions.', 'content-miner' ); ?></p>
		<?php endif; ?>
	</section>

	<section id="collisions" class="cm-section" role="tabpanel" aria-labelledby="cm-tab-collisions" data-cm-section>
		<div class="cm-section-heading">
			<div><p class="cm-eyebrow"><?php esc_html_e( 'Possible competition', 'content-miner' ); ?></p><h2><?php esc_html_e( 'Content collisions', 'content-miner' ); ?></h2></div>
			<div class="cm-section-action">
				<p><?php esc_html_e( 'Similarity is a reason to investigate, not proof of search cannibalization.', 'content-miner' ); ?></p>
				<?php if ( $site_report_current && $verdict_request_count > 0 && $openai['configured'] ) : ?>
					<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
						<input type="hidden" name="action" value="content_miner_explain_collisions"><?php wp_nonce_field( 'content_miner_explain_collisions' ); ?>
						<button class="button cm-secondary" type="submit"><?php /* translators: %d: number of semantic collisions to explain. */ echo esc_html( sprintf( _n( 'Explain %d semantic collision', 'Explain %d semantic collisions', $verdict_request_count, 'content-miner' ), $verdict_request_count ) ); ?></button>
						<span><?php esc_html_e( 'This sends both truncated page texts to OpenAI. Maximum 50 pairs per run.', 'content-miner' ); ?></span>
					</form>
				<?php endif; ?>
				<?php if ( $collision_total > 0 ) : ?>
					<div class="cm-library-index__status" aria-live="polite">
						<strong><?php /* translators: 1: first visible collision, 2: last visible collision, 3: total collisions. */ echo esc_html( sprintf( __( '%1$s–%2$s of %3$s', 'content-miner' ), number_format_i18n( $collision_first ), number_format_i18n( $collision_last ), number_format_i18n( $collision_total ) ) ); ?></strong>
						<span><?php esc_html_e( 'possible collisions', 'content-miner' ); ?></span>
					</div>
				<?php endif; ?>
			</div>
		</div>
		<?php if ( $site_report_current ) { $render_prompt_tools( 'collisions', $prompt_builder->build_whole_report( $report_prompt_context, __( 'content collisions', 'content-miner' ) ), 'collisions' ); } ?>
		<?php if ( ! $site_report_current ) : ?>
			<p class="cm-inline-empty"><?php esc_html_e( 'Collision totals are unavailable until the full-library analysis finishes successfully.', 'content-miner' ); ?></p>
		<?php elseif ( ! empty( $pairs ) ) : ?>
			<div class="cm-pair-grid">
				<?php foreach ( $visible_pairs as $pair ) : ?>
					<?php $pair = Content_Miner_Collision_Recommendation::resolve( $pair ); ?>
					<?php $pair_decision_key = min( (int) $pair['left_id'], (int) $pair['right_id'] ) . ':' . max( (int) $pair['left_id'], (int) $pair['right_id'] ); $recorded_pair_decision = isset( $pair_decisions[ $pair_decision_key ] ) ? $pair_decisions[ $pair_decision_key ] : null; $left_links = $content_links( $pair['left_id'] ); $right_links = $content_links( $pair['right_id'] ); $pair_anchor = ltrim( Content_Miner_Admin::decision_anchor( $pair['left_id'], $pair['right_id'] ), '#' ); $verdict_action = Content_Miner_Collision_Recommendation::verdict_action( $pair ); ?>
					<?php $left_prompt_page = $prompt_page( $pair['left_id'], $pair['left_title'], $left_links['view'] ); $right_prompt_page = $prompt_page( $pair['right_id'], $pair['right_title'], $right_links['view'] ); $pair_prompt = $prompt_builder->build_collision_pair( $pair, $left_prompt_page, $right_prompt_page ); ?>
				<article class="cm-pair-card" id="<?php echo esc_attr( $pair_anchor ); ?>">
				<div class="cm-pair-card__score"><span><?php echo esc_html( number_format_i18n( $pair['score'] * 100 ) ); ?>%</span><?php /* translators: %d: lexical overlap percentage. */ echo esc_html( isset( $pair['evidence'] ) ? $pair['evidence'] : ( 1.0 === (float) $pair['score'] ? __( 'exact copy', 'content-miner' ) : sprintf( __( 'lexical overlap %d%%', 'content-miner' ), round( $pair['score'] * 100 ) ) ) ); ?></div>
					<div class="cm-pair-card__titles"><?php if ( $left_links['view'] ) : ?><a href="<?php echo esc_url( $left_links['view'] ); ?>" target="_blank" rel="noopener noreferrer"><?php echo esc_html( $pair['left_title'] ); ?></a><?php else : ?><strong><?php echo esc_html( $pair['left_title'] ); ?></strong><?php endif; ?><?php if ( $left_links['edit'] ) : ?><a class="cm-edit-link" href="<?php echo esc_url( $left_links['edit'] ); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Edit', 'content-miner' ); ?></a><?php endif; ?><span><?php esc_html_e( 'compared with', 'content-miner' ); ?></span><?php if ( $right_links['view'] ) : ?><a href="<?php echo esc_url( $right_links['view'] ); ?>" target="_blank" rel="noopener noreferrer"><?php echo esc_html( $pair['right_title'] ); ?></a><?php else : ?><strong><?php echo esc_html( $pair['right_title'] ); ?></strong><?php endif; ?><?php if ( $right_links['edit'] ) : ?><a class="cm-edit-link" href="<?php echo esc_url( $right_links['edit'] ); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Edit', 'content-miner' ); ?></a><?php endif; ?></div>
					<div class="cm-pair-card__decision">
						<span class="cm-badge cm-badge--<?php echo esc_attr( strtolower( $pair['action'] ) ); ?>"><?php echo esc_html( $pair['action'] ); ?></span><p><?php echo esc_html( $pair['reason'] ); ?></p>
						<?php if ( '' !== $verdict_action && ! empty( $pair['llm_verdict']['rationale'] ) ) : ?><p><strong><?php esc_html_e( 'AI explanation:', 'content-miner' ); ?></strong> <?php echo esc_html( $pair['action'] . ' — ' . $pair['llm_verdict']['rationale'] ); ?></p><?php endif; ?>
						<?php if ( $recorded_pair_decision ) : ?><p><strong><?php esc_html_e( 'Recorded decision:', 'content-miner' ); ?></strong> <?php echo esc_html( $decision_labels[ $recorded_pair_decision['decision'] ] ); ?><?php if ( $recorded_pair_decision['note'] ) : ?> — <?php echo esc_html( $recorded_pair_decision['note'] ); ?><?php endif; ?></p><?php endif; ?>
						<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="cm-decision-form">
							<input type="hidden" name="action" value="content_miner_record_decision"><input type="hidden" name="post_id" value="<?php echo esc_attr( $pair['left_id'] ); ?>"><input type="hidden" name="pair_post_id" value="<?php echo esc_attr( $pair['right_id'] ); ?>"><input type="hidden" name="cm_inventory_page" value="<?php echo esc_attr( $inventory_page ); ?>"><input type="hidden" name="cm_collision_page" value="<?php echo esc_attr( $collision_page ); ?>"><input type="hidden" name="cm_search" value="<?php echo esc_attr( $inventory_search ); ?>">
							<?php wp_nonce_field( 'content_miner_record_decision' ); ?><input name="note" type="text" maxlength="500" placeholder="<?php esc_attr_e( 'Optional decision note', 'content-miner' ); ?>">
								<div class="cm-decision-buttons"><?php foreach ( $decision_labels as $decision_key => $decision_label ) : ?><button class="button button-small" type="submit" name="decision" value="<?php echo esc_attr( $decision_key ); ?>"><?php echo esc_html( $decision_label ); ?></button><?php endforeach; ?></div>
							</form>
							<?php $render_prompt_tools( 'pair-' . min( (int) $pair['left_id'], (int) $pair['right_id'] ) . '-' . max( (int) $pair['left_id'], (int) $pair['right_id'] ), $pair_prompt, 'collision-pair' ); ?>
					</div>
				</article>
			<?php endforeach; ?>
			</div>
			<?php if ( $collision_total_pages > 1 ) : ?>
				<nav class="cm-pagination" aria-label="<?php esc_attr_e( 'Content collision pages', 'content-miner' ); ?>">
					<?php
					$collision_pagination = paginate_links(
						array(
							'base'      => str_replace( '999999999', '%#%', esc_url( add_query_arg( 'cm_collision_page', 999999999, $collision_base_url ) ) ) . '#collisions',
							'format'    => '',
							'current'   => $collision_page,
							'total'     => $collision_total_pages,
							'mid_size'  => 2,
							'end_size'  => 1,
							'prev_text' => __( 'Previous', 'content-miner' ),
							'next_text' => __( 'Next', 'content-miner' ),
							'type'      => 'list',
						)
					);
					echo wp_kses_post( $collision_pagination );
					?>
				</nav>
			<?php endif; ?>
		<?php else : ?>
			<p class="cm-inline-empty"><?php esc_html_e( 'No meaningful collisions found in the latest scan.', 'content-miner' ); ?></p>
		<?php endif; ?>
	</section>

	<section id="decisions" class="cm-section" role="tabpanel" aria-labelledby="cm-tab-decisions" data-cm-section>
		<div class="cm-section-heading"><div><p class="cm-eyebrow"><?php esc_html_e( 'Operator record', 'content-miner' ); ?></p><h2><?php esc_html_e( 'Decisions', 'content-miner' ); ?></h2></div><div class="cm-section-action"><p><?php esc_html_e( 'Recorded decisions replace recommendations in the inventory and collision views. Recommendations remain advisory until an operator records a choice.', 'content-miner' ); ?></p></div></div>
		<?php if ( $site_report_current ) { $render_prompt_tools( 'decisions', $prompt_builder->build_whole_report( $report_prompt_context, __( 'recorded editorial decisions', 'content-miner' ) ), 'decisions' ); } ?>
		<?php if ( ! empty( $ledger_page['items'] ) ) : ?>
			<div class="cm-table-shell"><table class="cm-table"><thead><tr><th><?php esc_html_e( 'Content', 'content-miner' ); ?></th><th><?php esc_html_e( 'Decision', 'content-miner' ); ?></th><th><?php esc_html_e( 'Who / when', 'content-miner' ); ?></th><th><?php esc_html_e( 'Note', 'content-miner' ); ?></th></tr></thead><tbody>
			<?php foreach ( $ledger_page['items'] as $ledger_item ) : ?>
				<?php
				$ledger_user  = get_userdata( (int) $ledger_item['user_id'] );
				$ledger_title = get_the_title( (int) $ledger_item['post_id'] );
				if ( ! $ledger_title ) {
					/* translators: %d: WordPress post ID. */
					$ledger_title = sprintf( __( 'Post %d', 'content-miner' ), $ledger_item['post_id'] );
				}
				$ledger_prompt_data = $prompt_page( $ledger_item['post_id'], $ledger_title, Content_Miner_Repository::get_post_view_url( (int) $ledger_item['post_id'] ), array( 'action' => $decision_labels[ $ledger_item['decision'] ], 'reason' => $ledger_item['note'] ?: __( 'This is the operator’s recorded editorial decision.', 'content-miner' ) ) );
				$ledger_prompt      = $prompt_builder->build_single_page( $ledger_prompt_data );
				?>
				<tr><td><?php echo esc_html( $ledger_title ); ?><?php if ( $ledger_item['pair_post_id'] ) : ?><span class="cm-meta"><?php /* translators: %d: paired WordPress post ID. */ echo esc_html( sprintf( __( 'Pair with post %d', 'content-miner' ), $ledger_item['pair_post_id'] ) ); ?></span><?php endif; ?></td><td><span class="cm-badge cm-badge--<?php echo esc_attr( $ledger_item['decision'] ); ?>"><?php echo esc_html( $decision_labels[ $ledger_item['decision'] ] ); ?></span></td><td><?php echo esc_html( $ledger_user ? $ledger_user->display_name : __( 'Unknown user', 'content-miner' ) ); ?><span class="cm-meta"><?php echo esc_html( $ledger_item['decided_at'] . ' UTC' ); ?></span></td><td><?php echo esc_html( $ledger_item['note'] ?: __( 'No note recorded.', 'content-miner' ) ); ?><?php $render_prompt_tools( 'decision-' . $ledger_item['id'], $ledger_prompt, 'decision-row' ); ?></td></tr>
			<?php endforeach; ?>
			</tbody></table></div>
			<?php if ( $ledger_total_pages > 1 ) : ?><nav class="cm-pagination" aria-label="<?php esc_attr_e( 'Decision ledger pages', 'content-miner' ); ?>"><?php echo wp_kses_post( paginate_links( array( 'base' => str_replace( '999999999', '%#%', esc_url( add_query_arg( array( 'page' => Content_Miner_Admin::PAGE_SLUG, 'cm_ledger_page' => 999999999 ), admin_url( 'admin.php' ) ) ) ) . '#decisions', 'current' => $ledger_page['page'], 'total' => $ledger_total_pages, 'type' => 'list' ) ) ); ?></nav><?php endif; ?>
		<?php else : ?><p class="cm-inline-empty"><?php esc_html_e( 'No editorial decisions have been recorded yet.', 'content-miner' ); ?></p><?php endif; ?>

		<?php if ( $outcomes_enabled ) : ?><div class="cm-panel cm-outcomes-panel"><div class="cm-panel-heading"><div><p class="cm-eyebrow"><?php esc_html_e( '90-day evidence', 'content-miner' ); ?></p><h3><?php esc_html_e( 'Outcomes', 'content-miner' ); ?></h3></div></div><p><?php esc_html_e( 'Correlation, not causation — other factors also change rankings and traffic.', 'content-miner' ); ?></p>
		<?php if ( ! empty( $outcomes ) ) : ?>
			<div class="cm-outcome-grid"><?php foreach ( $outcomes as $outcome ) : ?><?php $before_metrics = $aggregate_metrics( $outcome['metrics_before'] ); $after_metrics = $aggregate_metrics( $outcome['metrics_after'] ); ?><article><strong><?php /* translators: %d: WordPress post ID. */ echo esc_html( get_the_title( (int) $outcome['post_id'] ) ?: sprintf( __( 'Post %d', 'content-miner' ), $outcome['post_id'] ) ); ?></strong><span><?php echo esc_html( $decision_labels[ $outcome['decision'] ] ); ?></span><ul><?php foreach ( array( 'clicks', 'impressions', 'sessions', 'engagement_rate' ) as $metric_key ) : ?><?php $delta = $after_metrics[ $metric_key ] - $before_metrics[ $metric_key ]; $percent = 0.0 !== (float) $before_metrics[ $metric_key ] ? ( $delta / $before_metrics[ $metric_key ] ) * 100 : null; ?><li><?php echo esc_html( ucwords( str_replace( '_', ' ', $metric_key ) ) . ': ' . number_format_i18n( $before_metrics[ $metric_key ], 'engagement_rate' === $metric_key ? 2 : 0 ) . ' → ' . number_format_i18n( $after_metrics[ $metric_key ], 'engagement_rate' === $metric_key ? 2 : 0 ) . ' (' . ( $delta >= 0 ? '+' : '' ) . number_format_i18n( $delta, 'engagement_rate' === $metric_key ? 2 : 0 ) . ( null !== $percent ? ', ' . ( $percent >= 0 ? '+' : '' ) . number_format_i18n( $percent, 1 ) . '%' : '' ) . ')' ); ?></li><?php endforeach; ?></ul></article><?php endforeach; ?></div>
		<?php else : ?><p><?php esc_html_e( 'No completed before/after evidence snapshots yet.', 'content-miner' ); ?></p><?php endif; ?>
		</div><?php endif; ?>
	</section>

		<section id="idea-checker" class="cm-section cm-idea-section" role="tabpanel" aria-labelledby="cm-tab-idea-checker" data-cm-section>
			<div class="cm-section-heading">
				<div><p class="cm-eyebrow"><?php esc_html_e( 'Before you commission it', 'content-miner' ); ?></p><h2><?php esc_html_e( 'Check a content idea', 'content-miner' ); ?></h2></div>
				<div class="cm-section-action"><p><?php esc_html_e( 'Describe the proposed piece. Add a market when you want to test whether an existing article should be localized.', 'content-miner' ); ?></p></div>
		</div>
		<?php if ( $site_report_current ) { $render_prompt_tools( 'idea-checker', $prompt_builder->build_whole_report( $report_prompt_context, __( 'content idea evaluation', 'content-miner' ) ), 'idea-checker' ); } ?>
		<div class="cm-idea-layout">
			<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="cm-form cm-panel">
				<input type="hidden" name="action" value="content_miner_check_idea">
				<?php wp_nonce_field( 'content_miner_check_idea' ); ?>
				<label for="cm-idea"><?php esc_html_e( 'Title, question, or short brief', 'content-miner' ); ?></label>
				<textarea id="cm-idea" name="idea" rows="5" required placeholder="<?php esc_attr_e( 'Example: What should a homeowner know before replacing a roof?', 'content-miner' ); ?>"></textarea>
				<label for="cm-location"><?php esc_html_e( 'Target market (optional)', 'content-miner' ); ?></label>
				<input id="cm-location" name="location" type="text" placeholder="<?php esc_attr_e( 'Example: Philadelphia, PA', 'content-miner' ); ?>">
				<button class="button button-primary cm-primary" type="submit"><?php esc_html_e( 'Check this idea', 'content-miner' ); ?></button>
			</form>

			<div class="cm-result cm-panel" aria-live="polite">
			<?php if ( $idea_result ) : ?>
				<p class="cm-eyebrow"><?php esc_html_e( 'Recommended decision', 'content-miner' ); ?></p>
				<div class="cm-result__decision"><span class="cm-decision-word"><?php echo esc_html( $idea_result['decision']['action'] ); ?></span><span><?php echo esc_html( $idea_result['decision']['confidence'] . ' confidence' ); ?></span></div>
				<p><?php echo esc_html( $idea_result['decision']['reason'] ); ?></p>
				<?php if ( ! empty( $idea_result['matches'] ) ) : ?>
					<h3><?php esc_html_e( 'Closest existing content', 'content-miner' ); ?></h3>
					<ul class="cm-match-list">
					<?php foreach ( $idea_result['matches'] as $match ) : ?>
						<?php $match_links = $content_links( $match['id'] ); ?>
						<li><div><?php if ( $match_links['view'] ) : ?><a href="<?php echo esc_url( $match_links['view'] ); ?>" target="_blank" rel="noopener noreferrer"><?php echo esc_html( $match['title'] ); ?></a><?php else : ?><strong><?php echo esc_html( $match['title'] ); ?></strong><?php endif; ?><?php if ( $match_links['edit'] ) : ?><a class="cm-edit-link" href="<?php echo esc_url( $match_links['edit'] ); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Edit', 'content-miner' ); ?></a><?php endif; ?></div><span><?php echo esc_html( number_format_i18n( $match['score'] * 100 ) . '% match' ); ?></span></li>
					<?php endforeach; ?>
					</ul>
				<?php endif; ?>
			<?php else : ?>
				<p class="cm-eyebrow"><?php esc_html_e( 'Decision preview', 'content-miner' ); ?></p>
				<h3><?php esc_html_e( 'Your evidence will appear here.', 'content-miner' ); ?></h3>
				<p><?php esc_html_e( 'Content Miner will recommend Create, Update, Differentiate, or Localize and show the closest pages already in WordPress.', 'content-miner' ); ?></p>
			<?php endif; ?>
			</div>
		</div>
	</section>

	<?php if ( $pro_enabled && ( $cloud_connector || $google_enabled || $semantic_enabled ) ) : ?><section id="connections" class="cm-section cm-connections" role="tabpanel" aria-labelledby="cm-tab-connections" data-cm-section>
		<div class="cm-section-heading">
			<div><p class="cm-eyebrow"><?php esc_html_e( 'Evidence and cloud memory', 'content-miner' ); ?></p><h2><?php esc_html_e( 'Data connections', 'content-miner' ); ?></h2></div>
			<p><?php esc_html_e( 'Connect cloud reporting and read-only evidence sources. Content Miner never changes the connected account or publishes site changes.', 'content-miner' ); ?></p>
		</div>

		<div class="cm-connection-grid">
			<?php if ( $cloud_connector ) : ?>
			<article class="cm-connection-card cm-panel">
				<div class="cm-connection-card__head">
					<div><p class="cm-eyebrow"><?php esc_html_e( 'Cloud bridge', 'content-miner' ); ?></p><h3><?php esc_html_e( 'Content Miner cloud', 'content-miner' ); ?></h3></div>
					<span class="cm-connection-state <?php echo ! empty( $cloud_connector['connected'] ) ? 'cm-connection-state--connected' : ''; ?>"><?php echo ! empty( $cloud_connector['connected'] ) ? esc_html__( 'Connected', 'content-miner' ) : esc_html__( 'Not connected', 'content-miner' ); ?></span>
				</div>
				<p><?php esc_html_e( 'Uploads completed WordPress analysis summaries to your Content Miner cloud account for history, comparison, monitoring, and large-library reporting.', 'content-miner' ); ?></p>
				<?php if ( ! empty( $cloud_connector['connected'] ) ) : ?>
					<div class="cm-connection-metrics">
						<div><strong><?php echo esc_html( $cloud_connector['site_hostname'] ); ?></strong><span><?php esc_html_e( 'cloud site', 'content-miner' ); ?></span></div>
						<div><strong><?php echo esc_html( $cloud_connector['token_prefix'] ); ?></strong><span><?php esc_html_e( 'token prefix', 'content-miner' ); ?></span></div>
						<div><strong><?php echo esc_html( number_format_i18n( (int) $cloud_connector['last_upload_count'] ) ); ?></strong><span><?php esc_html_e( 'last upload pages', 'content-miner' ); ?></span></div>
					</div>
					<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="cm-connection-sync">
						<input type="hidden" name="action" value="content_miner_cloud_upload">
						<?php wp_nonce_field( 'content_miner_cloud_upload' ); ?>
						<button class="button button-primary cm-primary" type="submit" <?php disabled( ! $site_report_current ); ?>><?php esc_html_e( 'Upload current report to cloud', 'content-miner' ); ?></button>
						<?php if ( ! $site_report_current ) : ?><span><?php esc_html_e( 'Run a current full-library analysis first.', 'content-miner' ); ?></span><?php endif; ?>
						<?php if ( ! empty( $cloud_connector['last_uploaded_at'] ) ) : ?><span><?php /* translators: %s: UTC date and time of the latest cloud upload. */ echo esc_html( sprintf( __( 'Last upload: %s UTC', 'content-miner' ), gmdate( 'M j, Y H:i', strtotime( $cloud_connector['last_uploaded_at'] ) ) ) ); ?></span><?php endif; ?>
					</form>
				<?php else : ?>
					<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="cm-form cm-connection-form">
						<input type="hidden" name="action" value="content_miner_cloud_connect">
						<?php wp_nonce_field( 'content_miner_cloud_connect' ); ?>
						<label for="cm-cloud-endpoint"><?php esc_html_e( 'Cloud endpoint', 'content-miner' ); ?></label>
						<input id="cm-cloud-endpoint" name="cloud_endpoint" type="url" value="<?php echo esc_attr( $cloud_connector['endpoint'] ); ?>" required>
						<label for="cm-cloud-api-token"><?php esc_html_e( 'Content Miner API token', 'content-miner' ); ?></label>
						<input id="cm-cloud-api-token" name="cloud_api_token" type="password" autocomplete="new-password" required placeholder="cm_...">
						<p class="description"><?php esc_html_e( 'Create a Content Miner API token in the cloud portal, paste it once, and this plugin will store a site-scoped connector token for future uploads.', 'content-miner' ); ?></p>
						<button class="button button-primary cm-primary" type="submit"><?php esc_html_e( 'Connect to cloud', 'content-miner' ); ?></button>
					</form>
				<?php endif; ?>
				<?php if ( ! empty( $cloud_connector['last_error'] ) ) : ?><div class="cm-connection-warning"><?php echo esc_html( $cloud_connector['last_error'] ); ?></div><?php endif; ?>
			</article>
			<?php endif; ?>

			<?php if ( $google_enabled ) : ?>
			<article class="cm-connection-card cm-panel">
				<div class="cm-connection-card__head">
					<div><p class="cm-eyebrow"><?php esc_html_e( 'Available now', 'content-miner' ); ?></p><h3><?php esc_html_e( 'Google Search Console', 'content-miner' ); ?></h3></div>
					<span class="cm-connection-state <?php echo $search_console['connected'] ? 'cm-connection-state--connected' : ''; ?>"><?php echo $search_console['connected'] ? esc_html__( 'Connected', 'content-miner' ) : esc_html__( 'Not connected', 'content-miner' ); ?></span>
				</div>
				<p><?php esc_html_e( 'Imports clicks, impressions, CTR, and average position for the latest 28 complete days using Google’s read-only scope.', 'content-miner' ); ?></p>

				<?php if ( ! $search_console['vault_available'] ) : ?>
					<div class="cm-connection-warning"><?php esc_html_e( 'This server does not provide the authenticated encryption required to store OAuth credentials safely.', 'content-miner' ); ?></div>
				<?php elseif ( ! $search_console['configured'] ) : ?>
					<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="cm-form cm-connection-form">
						<input type="hidden" name="action" value="content_miner_save_google_credentials">
						<?php wp_nonce_field( 'content_miner_save_google_credentials' ); ?>
						<label for="cm-google-client-id"><?php esc_html_e( 'OAuth client ID', 'content-miner' ); ?></label>
						<input id="cm-google-client-id" name="client_id" type="text" autocomplete="off" required placeholder="123456789.apps.googleusercontent.com">
						<label for="cm-google-client-secret"><?php esc_html_e( 'OAuth client secret', 'content-miner' ); ?></label>
						<input id="cm-google-client-secret" name="client_secret" type="password" autocomplete="new-password" required>
						<label for="cm-google-redirect-uri"><?php esc_html_e( 'Authorized redirect URI', 'content-miner' ); ?></label>
						<input id="cm-google-redirect-uri" type="text" readonly value="<?php echo esc_attr( $search_console['redirect_uri'] ); ?>">
						<p class="description"><?php esc_html_e( 'Create a Google Cloud Web application client and add this exact redirect URI. The secret is encrypted before storage and is never displayed again.', 'content-miner' ); ?></p>
						<button class="button cm-secondary" type="submit"><?php esc_html_e( 'Save Google credentials', 'content-miner' ); ?></button>
					</form>
				<?php elseif ( ! $search_console['connected'] ) : ?>
					<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
						<input type="hidden" name="action" value="content_miner_connect_google">
						<?php wp_nonce_field( 'content_miner_connect_google' ); ?>
						<button class="button button-primary cm-primary" type="submit"><?php esc_html_e( 'Connect Google', 'content-miner' ); ?></button>
					</form>
				<?php else : ?>
					<div class="cm-connection-metrics">
						<div><strong><?php echo esc_html( number_format_i18n( $search_console['matched_pages'] ) ); ?></strong><span><?php esc_html_e( 'matched pages', 'content-miner' ); ?></span></div>
						<div><strong><?php echo esc_html( number_format_i18n( $search_console['clicks'] ) ); ?></strong><span><?php esc_html_e( 'clicks', 'content-miner' ); ?></span></div>
						<div><strong><?php echo esc_html( number_format_i18n( $search_console['impressions'] ) ); ?></strong><span><?php esc_html_e( 'impressions', 'content-miner' ); ?></span></div>
					</div>
					<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="cm-form cm-connection-form">
						<input type="hidden" name="action" value="content_miner_save_google_property">
						<?php wp_nonce_field( 'content_miner_save_google_property' ); ?>
						<label for="cm-google-property"><?php esc_html_e( 'Search Console property', 'content-miner' ); ?></label>
						<select id="cm-google-property" name="property" required>
							<option value=""><?php esc_html_e( 'Choose a property', 'content-miner' ); ?></option>
							<?php foreach ( $search_console['sites'] as $site ) : ?><option value="<?php echo esc_attr( $site['url'] ); ?>" <?php selected( $search_console['property'], $site['url'] ); ?>><?php echo esc_html( $site['url'] ); ?></option><?php endforeach; ?>
						</select>
						<button class="button cm-secondary" type="submit"><?php esc_html_e( 'Save property', 'content-miner' ); ?></button>
					</form>
					<?php if ( $search_console['property'] ) : ?>
						<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="cm-connection-sync">
							<input type="hidden" name="action" value="content_miner_sync_google">
							<?php wp_nonce_field( 'content_miner_sync_google' ); ?>
							<button class="button button-primary cm-primary" type="submit"><?php echo 'running' === $search_console['sync_status'] ? esc_html__( 'Process next search batch', 'content-miner' ) : esc_html__( 'Sync Search Console', 'content-miner' ); ?></button>
							<?php if ( $search_console['last_sync_at'] ) : ?><span><?php /* translators: %s: UTC date and time of the latest Search Console sync. */ echo esc_html( sprintf( __( 'Last sync: %s UTC', 'content-miner' ), gmdate( 'M j, Y H:i', strtotime( $search_console['last_sync_at'] ) ) ) ); ?></span><?php endif; ?>
							<?php if ( 'running' === $search_console['sync_status'] ) : ?><span><?php /* translators: %s: number of Search Console rows processed. */ echo esc_html( sprintf( __( '%s rows processed', 'content-miner' ), number_format_i18n( $search_console['rows_received'] ) ) ); ?></span><?php endif; ?>
						</form>
					<?php endif; ?>
				<?php endif; ?>
				<?php if ( $search_console['property'] && 'complete' === $search_console['sync_status'] && $search_console['last_sync_at'] && 0 === (int) $search_console['matched_pages'] ) : ?><div class="cm-connection-warning"><?php esc_html_e( 'Connected, but this property returned no matching pages. Check that you picked the Search Console property that covers this site.', 'content-miner' ); ?></div><?php endif; ?>
				<?php if ( $search_console['last_error'] ) : ?><div class="cm-connection-warning"><?php echo esc_html( $search_console['last_error'] ); ?></div><?php endif; ?>
			</article>
			<article class="cm-connection-card cm-panel">
				<div class="cm-connection-card__head"><div><p class="cm-eyebrow"><?php esc_html_e( 'Available now', 'content-miner' ); ?></p><h3><?php esc_html_e( 'Google Analytics 4', 'content-miner' ); ?></h3></div><span class="cm-connection-state <?php echo $analytics['connected'] ? 'cm-connection-state--connected' : ''; ?>"><?php echo $analytics['connected'] ? esc_html__( 'Connected', 'content-miner' ) : esc_html__( 'Not connected', 'content-miner' ); ?></span></div>
				<p><?php esc_html_e( 'Imports landing-page sessions, active users, engagement rate, and key events for the latest 28 complete days using Google’s read-only Analytics scope.', 'content-miner' ); ?></p>
				<?php if ( ! $search_console['configured'] ) : ?>
					<div class="cm-connection-warning"><?php esc_html_e( 'Save the shared Google OAuth credentials above first.', 'content-miner' ); ?></div>
				<?php elseif ( ! $analytics['connected'] ) : ?>
					<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
						<input type="hidden" name="action" value="content_miner_connect_google">
						<?php wp_nonce_field( 'content_miner_connect_google' ); ?>
						<button class="button button-primary cm-primary" type="submit"><?php esc_html_e( 'Connect Google', 'content-miner' ); ?></button>
					</form>
				<?php else : ?>
					<div class="cm-connection-metrics">
						<div><strong><?php echo esc_html( number_format_i18n( $analytics['matched_pages'] ) ); ?></strong><span><?php esc_html_e( 'matched pages', 'content-miner' ); ?></span></div>
						<div><strong><?php echo esc_html( number_format_i18n( $analytics['sessions'] ) ); ?></strong><span><?php esc_html_e( 'sessions', 'content-miner' ); ?></span></div>
						<div><strong><?php echo esc_html( number_format_i18n( $analytics['key_events'], 2 ) ); ?></strong><span><?php esc_html_e( 'key events', 'content-miner' ); ?></span></div>
					</div>
					<?php if ( empty( $analytics['properties'] ) ) : ?>
						<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
							<input type="hidden" name="action" value="content_miner_refresh_analytics_properties">
							<?php wp_nonce_field( 'content_miner_refresh_analytics_properties' ); ?>
							<button class="button cm-secondary" type="submit"><?php esc_html_e( 'Load Analytics properties', 'content-miner' ); ?></button>
						</form>
					<?php else : ?>
						<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="cm-form cm-connection-form">
							<input type="hidden" name="action" value="content_miner_save_analytics_property">
							<?php wp_nonce_field( 'content_miner_save_analytics_property' ); ?>
							<label for="cm-analytics-property"><?php esc_html_e( 'Google Analytics property', 'content-miner' ); ?></label>
							<select id="cm-analytics-property" name="property" required>
								<option value=""><?php esc_html_e( 'Choose a property', 'content-miner' ); ?></option>
								<?php foreach ( $analytics['properties'] as $property ) : ?><option value="<?php echo esc_attr( $property['id'] ); ?>" <?php selected( $analytics['property'], $property['id'] ); ?>><?php echo esc_html( $property['name'] . ( $property['account'] ? ' — ' . $property['account'] : '' ) ); ?></option><?php endforeach; ?>
							</select>
							<button class="button cm-secondary" type="submit"><?php esc_html_e( 'Save Analytics property', 'content-miner' ); ?></button>
						</form>
					<?php endif; ?>
					<?php if ( $analytics['property'] ) : ?>
						<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="cm-connection-sync">
							<input type="hidden" name="action" value="content_miner_sync_analytics">
							<?php wp_nonce_field( 'content_miner_sync_analytics' ); ?>
							<button class="button button-primary cm-primary" type="submit"><?php echo 'running' === $analytics['sync_status'] ? esc_html__( 'Process next Analytics batch', 'content-miner' ) : esc_html__( 'Sync Google Analytics', 'content-miner' ); ?></button>
							<?php if ( $analytics['last_sync_at'] ) : ?><span><?php /* translators: %s: UTC date and time of the latest Analytics sync. */ echo esc_html( sprintf( __( 'Last sync: %s UTC', 'content-miner' ), gmdate( 'M j, Y H:i', strtotime( $analytics['last_sync_at'] ) ) ) ); ?></span><?php endif; ?>
						</form>
					<?php endif; ?>
				<?php endif; ?>
				<?php if ( $analytics['property'] && 'complete' === $analytics['sync_status'] && $analytics['last_sync_at'] && 0 === (int) $analytics['matched_pages'] ) : ?><div class="cm-connection-warning"><?php esc_html_e( 'Connected, but this property returned no matching pages. Check that you picked the property that collects this site’s traffic.', 'content-miner' ); ?></div><?php endif; ?>
				<?php if ( $analytics['last_error'] ) : ?><div class="cm-connection-warning"><?php echo esc_html( $analytics['last_error'] ); ?></div><?php endif; ?>
			</article>
			<?php endif; ?>

			<?php if ( $semantic_enabled ) : ?>
			<article class="cm-connection-card cm-panel">
				<div class="cm-connection-card__head"><div><p class="cm-eyebrow"><?php esc_html_e( 'AI Analysis (optional)', 'content-miner' ); ?></p><h3><?php esc_html_e( 'Semantic collision detection', 'content-miner' ); ?></h3></div><span class="cm-connection-state <?php echo $openai['configured'] ? 'cm-connection-state--connected' : ''; ?>"><?php echo $openai['configured'] ? esc_html__( 'Connected', 'content-miner' ) : esc_html__( 'Basic mode', 'content-miner' ); ?></span></div>
				<p><?php esc_html_e( 'When you configure an API key, Content Miner sends page titles and text to OpenAI’s embeddings API to find same-intent overlap written with different words. Without a key, no page content is sent to OpenAI and local word-overlap analysis remains unchanged.', 'content-miner' ); ?></p>
				<?php if ( ! $openai['vault_available'] ) : ?>
					<div class="cm-connection-warning"><?php esc_html_e( 'This server does not provide the authenticated encryption required to store an API key safely.', 'content-miner' ); ?></div>
				<?php else : ?>
					<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="cm-form cm-connection-form">
						<input type="hidden" name="action" value="content_miner_save_openai_key">
						<?php wp_nonce_field( 'content_miner_save_openai_key' ); ?>
						<label for="cm-openai-api-key"><?php esc_html_e( 'OpenAI API key', 'content-miner' ); ?></label>
						<input id="cm-openai-api-key" name="openai_api_key" type="password" autocomplete="new-password" placeholder="<?php echo $openai['configured'] ? esc_attr__( 'Enter a replacement key or leave blank to disconnect', 'content-miner' ) : esc_attr__( 'sk-…', 'content-miner' ); ?>">
						<label for="cm-openai-chat-model"><?php esc_html_e( 'Collision explanation model', 'content-miner' ); ?></label><input id="cm-openai-chat-model" name="openai_chat_model" type="text" value="<?php echo esc_attr( $openai['chat_model'] ); ?>">
						<p class="description"><?php /* translators: 1: OpenAI embedding model, 2: vector dimensions. */ echo esc_html( sprintf( __( 'Keys are encrypted before storage. A save performs one small validation request using %1$s at %2$d dimensions. Then use Sync content to embed the existing library. OpenAI API usage may incur charges on your OpenAI account.', 'content-miner' ), $openai['model'], $openai['dimensions'] ) ); ?></p>
						<button class="button cm-secondary" type="submit"><?php echo $openai['configured'] ? esc_html__( 'Update or disconnect', 'content-miner' ) : esc_html__( 'Validate and save key', 'content-miner' ); ?></button>
					</form>
				<?php endif; ?>
				<?php if ( $openai_error ) : ?><div class="cm-connection-warning"><?php echo esc_html( $openai_error ); ?></div><?php endif; ?>
			</article>
			<?php endif; ?>
		</div>
	</section><?php endif; ?>

	<section id="settings" class="cm-section" role="tabpanel" aria-labelledby="cm-tab-settings" data-cm-section>
		<div class="cm-section-heading">
			<div><p class="cm-eyebrow"><?php esc_html_e( 'Localization guardrails', 'content-miner' ); ?></p><h2><?php esc_html_e( 'Service markets', 'content-miner' ); ?></h2></div>
			<p><?php esc_html_e( 'Markets make localization recommendations possible. They do not automatically create location pages.', 'content-miner' ); ?></p>
		</div>
		<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="cm-form cm-settings-form cm-panel">
			<input type="hidden" name="action" value="content_miner_save_settings">
			<?php wp_nonce_field( 'content_miner_save_settings' ); ?>
			<label for="cm-locations"><?php esc_html_e( 'Cities, regions, or countries', 'content-miner' ); ?></label>
			<textarea id="cm-locations" name="locations" rows="4" placeholder="<?php esc_attr_e( "Philadelphia, PA\nCamden, NJ\nWilmington, DE", 'content-miner' ); ?>"><?php echo esc_textarea( implode( "\n", $locations ) ); ?></textarea>
			<p class="description"><?php esc_html_e( 'Enter one market per line. Content Miner only suggests localization when a substantial evergreen piece does not already mention a configured market.', 'content-miner' ); ?></p>
			<button class="button cm-secondary" type="submit"><?php esc_html_e( 'Save markets', 'content-miner' ); ?></button>
		</form>
		<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="cm-form cm-settings-form cm-panel">
			<input type="hidden" name="action" value="content_miner_save_consultation"><?php wp_nonce_field( 'content_miner_save_consultation' ); ?>
			<h3><?php esc_html_e( 'Human consultation link', 'content-miner' ); ?></h3>
			<label><input type="checkbox" name="consultation_enabled" value="1" <?php checked( ! empty( $consultation_settings['enabled'] ) ); ?>> <?php esc_html_e( 'Show a dismissible consultation link with AI prompts', 'content-miner' ); ?></label>
			<?php if ( 'agency' === ( $license_state['plan'] ?? 'free' ) ) : ?>
				<label for="cm-consultation-url"><?php esc_html_e( 'Agency booking URL', 'content-miner' ); ?></label>
				<input id="cm-consultation-url" name="consultation_url" type="url" value="<?php echo esc_attr( $consultation_settings['custom_url'] ); ?>" placeholder="https://agency.example/book/">
				<label for="cm-consultation-label"><?php esc_html_e( 'Agency link label', 'content-miner' ); ?></label>
				<input id="cm-consultation-label" name="consultation_label" type="text" maxlength="180" value="<?php echo esc_attr( $consultation_settings['label'] ); ?>" placeholder="<?php esc_attr_e( 'Want help reviewing this? Book time with our team.', 'content-miner' ); ?>">
				<p class="description"><?php esc_html_e( 'Agency consultation links are off by default and never fall back to Corriston Consulting. Add your own URL and label before enabling.', 'content-miner' ); ?></p>
			<?php else : ?>
				<p class="description"><?php esc_html_e( 'When enabled, the link offers a free 20-minute review with Corriston Consulting and includes only the site name and analysis type in the booking URL.', 'content-miner' ); ?></p>
			<?php endif; ?>
			<button class="button cm-secondary" type="submit"><?php esc_html_e( 'Save consultation settings', 'content-miner' ); ?></button>
		</form>
		<?php if ( $digest_enabled ) : ?><form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="cm-form cm-settings-form cm-panel">
			<input type="hidden" name="action" value="content_miner_save_digest"><?php wp_nonce_field( 'content_miner_save_digest' ); ?>
			<h3><?php esc_html_e( 'Monthly evidence digest', 'content-miner' ); ?></h3>
			<label><input type="checkbox" name="digest_enabled" value="1" <?php checked( ! empty( $digest_settings['enabled'] ) ); ?>> <?php esc_html_e( 'Email a monthly evidence digest', 'content-miner' ); ?></label>
			<label for="cm-digest-email"><?php esc_html_e( 'Digest recipient', 'content-miner' ); ?></label><input id="cm-digest-email" name="digest_email" type="email" value="<?php echo esc_attr( $digest_settings['email'] ); ?>">
			<p class="description"><?php esc_html_e( 'Off by default. The digest uses WordPress mail and includes coverage, new collisions, decisions, completed outcomes, recurring readiness issues, and an unsubscribe reminder.', 'content-miner' ); ?></p>
			<button class="button cm-secondary" type="submit"><?php esc_html_e( 'Save digest settings', 'content-miner' ); ?></button>
		</form><?php endif; ?>
	</section>

	<section id="help" class="cm-help cm-section" role="tabpanel" aria-labelledby="cm-tab-help" data-cm-section>
		<div class="cm-section-heading">
			<div><p class="cm-eyebrow"><?php esc_html_e( 'Operator field guide', 'content-miner' ); ?></p><h2><?php esc_html_e( 'Help and first-run instructions', 'content-miner' ); ?></h2></div>
			<p><?php esc_html_e( 'Use this route for the first staging test, then return here when a score, recommendation, or background job needs explanation.', 'content-miner' ); ?></p>
		</div>

		<div class="cm-help-layout">
			<aside class="cm-help-route cm-panel">
				<div class="cm-panel-heading"><div><p class="cm-eyebrow"><?php esc_html_e( 'First dispatch', 'content-miner' ); ?></p><h3><?php esc_html_e( 'Run the site safely', 'content-miner' ); ?></h3></div><span><?php echo esc_html( 'v' . CONTENT_MINER_VERSION ); ?></span></div>
				<ol>
					<li><strong><?php esc_html_e( 'Install on staging', 'content-miner' ); ?></strong><span><?php esc_html_e( 'Use a recent backup or clone. Activate the plugin with an administrator account.', 'content-miner' ); ?></span></li>
					<li><strong><?php esc_html_e( 'Confirm the license', 'content-miner' ); ?></strong><span><?php esc_html_e( 'Free and Pro analyze up to 500 pages. Enter or change a paid license under Content Miner → Account to unlock Search Console, Analytics, keyword gaps, cloud history, semantic analysis, and monitoring. Agency and Enterprise are for larger or multi-site libraries.', 'content-miner' ); ?></span></li>
					<li><strong><?php esc_html_e( 'Build content memory', 'content-miner' ); ?></strong><span><?php esc_html_e( 'The first build fetches public rendered pages, then analyzes WordPress records in batches of 100. Failed public fetches use an explicit stored fallback.', 'content-miner' ); ?></span></li>
					<li><strong><?php esc_html_e( 'Watch the checkpoint', 'content-miner' ); ?></strong><span><?php esc_html_e( 'Keep the report page open during first sync. Foreground batches run from this screen, WP-Cron can continue in the background, and the diagnostics panel shows the measured pages-per-minute rate. Large-library rendered fetches can take several hours depending on site response time and timeout fallback.', 'content-miner' ); ?></span></li>
					<li><strong><?php esc_html_e( 'Analyze the full library', 'content-miner' ); ?></strong><span><?php esc_html_e( 'Review every remembered page for decisions, collisions, and page-level readiness evidence in resumable batches of 100.', 'content-miner' ); ?></span></li>
					<li><strong><?php esc_html_e( 'Hand findings to AI', 'content-miner' ); ?></strong><span><?php esc_html_e( 'Copy AI prompt works in Free with any assistant. Explain with AI is a paid feature and uses the OpenAI key configured by the site administrator.', 'content-miner' ); ?></span></li>
					<li><strong><?php esc_html_e( 'Validate before acting', 'content-miner' ); ?></strong><span><?php esc_html_e( 'Compare recommendations with traffic, conversions, rankings, backlinks, legal requirements, and business purpose.', 'content-miner' ); ?></span></li>
				</ol>
			</aside>

			<div class="cm-help-reference">
				<div class="cm-help-lenses">
					<article class="cm-help-lens cm-help-lens--seo"><strong><?php esc_html_e( 'SEO', 'content-miner' ); ?></strong><span><?php esc_html_e( 'Discovery', 'content-miner' ); ?></span><p><?php esc_html_e( 'Indexability, search metadata, depth, headings, internal links, images, and freshness.', 'content-miner' ); ?></p></article>
					<article class="cm-help-lens cm-help-lens--aeo"><strong><?php esc_html_e( 'AEO', 'content-miner' ); ?></strong><span><?php esc_html_e( 'Answers', 'content-miner' ); ?></span><p><?php esc_html_e( 'Question-led structure, direct answers, useful sections, lists, tables, and answer depth.', 'content-miner' ); ?></p></article>
					<article class="cm-help-lens cm-help-lens--geo"><strong><?php esc_html_e( 'GEO', 'content-miner' ); ?></strong><span><?php esc_html_e( 'Evidence', 'content-miner' ); ?></span><p><?php esc_html_e( 'Authorship, sources, dates, entity clarity, factual specificity, and substantial coverage.', 'content-miner' ); ?></p></article>
					<article class="cm-help-lens cm-help-lens--aio"><strong><?php esc_html_e( 'AIO', 'content-miner' ); ?></strong><span><?php esc_html_e( 'AI readiness', 'content-miner' ); ?></span><p><?php esc_html_e( 'Search eligibility, extractable answers, structure, supported schema, links, and evidence.', 'content-miner' ); ?></p></article>
				</div>

				<div class="cm-help-details cm-panel">
					<div class="cm-panel-heading"><div><p class="cm-eyebrow"><?php esc_html_e( 'Reference desk', 'content-miner' ); ?></p><h3><?php esc_html_e( 'Questions and troubleshooting', 'content-miner' ); ?></h3></div></div>
					<details open>
						<summary><?php esc_html_e( 'What does Content Miner change?', 'content-miner' ); ?></summary>
						<p><?php esc_html_e( 'It stores fingerprints, scores, issue codes, job state, and summaries. It does not delete, redirect, rewrite, localize, or publish editorial content.', 'content-miner' ); ?></p>
					</details>
					<details>
						<summary><?php esc_html_e( 'What do Keep, Refresh, Consolidate, Differentiate, Localize, and Review mean?', 'content-miner' ); ?></summary>
						<p><?php esc_html_e( 'Keep means no structural concern was found. Refresh flags age or weakness. Consolidate identifies strong overlap. Differentiate means clarify audience or intent. Localize suggests a genuinely useful market version. Review means the available evidence is not enough for an automatic editorial decision.', 'content-miner' ); ?></p>
					</details>
					<details>
						<summary><?php esc_html_e( 'Why did many pages receive low readiness scores?', 'content-miner' ); ?></summary>
						<p><?php esc_html_e( 'Open the recurring gaps and page-level evidence. Common causes include missing descriptions, thin copy, weak headings, no internal links, no visible answers, absent sources, or structured data that is only generated on the public page.', 'content-miner' ); ?></p>
					</details>
					<details>
						<summary><?php esc_html_e( 'Which pages are excluded from site scoring by default?', 'content-miner' ); ?></summary>
						<p><?php esc_html_e( 'Privacy policies, Terms of Service or Conditions, Cookie policies, data-collection and GDPR or CCPA pages, legal notices or disclaimers, and unedited WordPress starter content are excluded only when an exact title, slug, or page-template hint supports that decision. Ambiguous pages stay scored. Excluded pages remain visible in Inventory, do not affect site scores, collisions, or common gaps, and can be restored with “Include in site scoring”.', 'content-miner' ); ?></p>
					</details>
					<details>
						<summary><?php esc_html_e( 'What if synchronization stops moving?', 'content-miner' ); ?></summary>
						<p><?php esc_html_e( 'Reload the dashboard, then use “Process next batch now.” Quiet staging sites may not trigger WordPress Cron frequently. A failed job displays its latest error without changing the source content.', 'content-miner' ); ?></p>
					</details>
					<details>
						<summary><?php esc_html_e( 'When should I use Sync content?', 'content-miner' ); ?></summary>
						<p><?php esc_html_e( 'Use it after imports or before an editorial review. Normal WordPress saves enter the incremental queue automatically. A memory-version upgrade triggers a safe full reconciliation.', 'content-miner' ); ?></p>
					</details>
					<details>
						<summary><?php esc_html_e( 'How do licenses and plan limits work?', 'content-miner' ); ?></summary>
						<p><?php esc_html_e( 'Free includes the local inventory, content memory, word-overlap collisions, readiness scores, idea checks, localization candidates, the decision ledger, and Copy AI prompt for up to 500 pages. Enter or change a license under Content Miner → Account. Pro keeps the 500-page ceiling and adds Google evidence, keyword gaps, cloud report history, semantic analysis, Explain with AI, outcomes, the monthly digest, and rendered verification. Agency and Enterprise are the higher-limit paths. If a paid license expires, paid controls are gated and the Free limit applies, but stored memory, vectors, evidence, settings, and decisions are retained for reactivation.', 'content-miner' ); ?></p>
					</details>
					<details>
						<summary><?php esc_html_e( 'How do I connect Google?', 'content-miner' ); ?></summary>
						<p><?php esc_html_e( 'Open Connections, create a Google Cloud Web application OAuth client with the displayed callback URL, and save its client ID and secret. Choose Connect Google, then select and sync whichever read-only properties you use. Google Analytics 4 works independently and does not require a Search Console property to be selected or synchronized.', 'content-miner' ); ?></p>
					</details>
					<details>
						<summary><?php esc_html_e( 'Does Content Miner send page content to OpenAI?', 'content-miner' ); ?></summary>
						<p><?php esc_html_e( 'Copy AI prompt is available in Free and only copies a provider-neutral prompt to the clipboard; the operator chooses whether and where to paste it. Paid Explain with AI and semantic analysis require a site-owned OpenAI API key in Connections. With that key, Content Miner sends page titles and text for embeddings or the operator-requested explanation. Without a key or that action, Basic mode remains active and no page content is sent to OpenAI.', 'content-miner' ); ?></p>
					</details>
					<details>
						<summary><?php esc_html_e( 'What are rendered verification, outcomes, and the digest?', 'content-miner' ); ?></summary>
						<p><?php esc_html_e( 'Rendered verification is a paid, administrator-started check of this site’s own published pages in batches of 25. Outcomes compare recorded decisions with imported evidence after 90 days and show correlation, not causation. The optional monthly digest uses WordPress mail to summarize coverage, collisions, decisions, completed outcomes, and recurring readiness issues.', 'content-miner' ); ?></p>
					</details>
					<details>
						<summary><?php esc_html_e( 'How does the consultation link work?', 'content-miner' ); ?></summary>
						<p><?php esc_html_e( 'The dismissible consultation link can be enabled or disabled in Service markets. Free and Pro use the Corriston Consulting booking route. Agency is white-label: it is off by default, requires the agency’s own booking URL and label, and never falls back to Corriston Consulting.', 'content-miner' ); ?></p>
					</details>
					<details>
						<summary><?php esc_html_e( 'Do the scores guarantee rankings or AI citations?', 'content-miner' ); ?></summary>
						<p><?php esc_html_e( 'No. Scores describe observable readiness evidence. Crawling, indexing, rankings, rich results, AI inclusion, and citations are never guaranteed.', 'content-miner' ); ?></p>
					</details>
				</div>
			</div>
		</div>

		<div class="cm-pilot-check">
			<strong><?php esc_html_e( 'Before the first site review', 'content-miner' ); ?></strong>
			<ul><li><?php esc_html_e( 'Use staging', 'content-miner' ); ?></li><li><?php esc_html_e( 'Confirm a current backup', 'content-miner' ); ?></li><li><?php esc_html_e( 'Allow up to 30 minutes', 'content-miner' ); ?></li><li><?php esc_html_e( 'Export or record baseline metrics', 'content-miner' ); ?></li><li><?php esc_html_e( 'Do not act on recommendations without review', 'content-miner' ); ?></li></ul>
		</div>
	</section>

	<footer class="cm-footer">
		<div class="cm-footer__safeguard">
			<strong><?php esc_html_e( 'Advisory by design.', 'content-miner' ); ?></strong>
			<span><?php esc_html_e( 'Content Miner never deletes, redirects, rewrites, or publishes content.', 'content-miner' ); ?></span>
		</div>
		<a class="cm-footer__credit" href="https://www.corristonconsulting.com/products/content-miner" target="_blank" rel="noopener noreferrer">
			<?php esc_html_e( 'Content Miner by Corriston Consulting', 'content-miner' ); ?> <span aria-hidden="true">↗</span>
		</a>
	</footer>
</div>
<?php // phpcs:enable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound ?>
<?php // phpcs:enable WordPress.Security.NonceVerification.Recommended ?>
