<?php
/**
 * Admin UI: full-bleed product pages (Zen Plugins admin design system).
 *
 * @package 404Zen
 */

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

class LGBF_Admin {

	const CAPABILITY = 'manage_options';

	/**
	 * Task rows that can be hidden from the issues card.
	 *
	 * @var string[]
	 */
	public static $dismissible_tasks = array( 'digest', 'schedule', 'newsletter', 'review', 'firstfix' );

	/**
	 * Hooks.
	 */
	public static function init() {
		add_action( 'admin_menu', array( __CLASS__, 'register_menu' ) );
		add_action( 'admin_init', array( __CLASS__, 'maybe_activation_redirect' ) );
		add_action( 'admin_init', array( __CLASS__, 'maybe_legacy_pricing_redirect' ) );
		add_action( 'admin_init', array( __CLASS__, 'register_settings' ) );
		add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueue_assets' ) );
		add_action( 'admin_post_lgbf_scan_now', array( __CLASS__, 'handle_scan_now' ) );
		add_action( 'load-toplevel_page_lgbf-404zen', array( __CLASS__, 'handle_bulk_actions' ) );
		add_filter( 'set-screen-option', array( __CLASS__, 'save_screen_option' ), 10, 3 );
	}

	/**
	 * Right after single-plugin activation, send the user to the dashboard.
	 */
	public static function maybe_legacy_pricing_redirect() {
		if ( isset( $_GET['page'] ) && '404zen-pricing' === $_GET['page'] && current_user_can( self::CAPABILITY ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			wp_safe_redirect( admin_url( 'admin.php?page=lgbf-404zen-upgrade' ) );
			exit;
		}
	}

	public static function maybe_activation_redirect() {
		if ( ! get_transient( 'lgbf_activation_redirect' ) ) {
			return;
		}
		delete_transient( 'lgbf_activation_redirect' );

		if ( ! current_user_can( self::CAPABILITY ) ) {
			return;
		}
		if ( isset( $_GET['activate-multi'] ) || is_network_admin() || wp_doing_ajax() ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			return;
		}

		wp_safe_redirect( admin_url( 'admin.php?page=lgbf-404zen' ) );
		exit;
	}

	/**
	 * Registers the admin menu.
	 */
	public static function register_menu() {
		$counts = LGBF_Links_Store::get_counts();
		$badge  = $counts['problems'] > 0
			? ' <span class="awaiting-mod count-' . (int) $counts['problems'] . '"><span class="pending-count">' . number_format_i18n( $counts['problems'] ) . '</span></span>'
			: '';

		$dashboard_hook = add_menu_page(
			__( '404Zen — Link Health', '404zen-broken-link-fixer' ),
			__( '404Zen', '404zen-broken-link-fixer' ) . $badge,
			self::CAPABILITY,
			'lgbf-404zen',
			array( __CLASS__, 'render_dashboard' ),
			'dashicons-editor-unlink',
			80
		);

		add_submenu_page(
			'lgbf-404zen',
			__( 'Dashboard', '404zen-broken-link-fixer' ),
			__( 'Dashboard', '404zen-broken-link-fixer' ),
			self::CAPABILITY,
			'lgbf-404zen',
			array( __CLASS__, 'render_dashboard' )
		);

		$settings_hook = add_submenu_page(
			'lgbf-404zen',
			__( '404Zen Settings', '404zen-broken-link-fixer' ),
			__( 'Settings', '404zen-broken-link-fixer' ),
			self::CAPABILITY,
			'lgbf-404zen-settings',
			array( __CLASS__, 'render_settings' )
		);

		$pricing_hook = add_submenu_page(
			'lgbf-404zen',
			__( '404Zen Pro', '404zen-broken-link-fixer' ),
			__( 'Upgrade', '404zen-broken-link-fixer' ),
			self::CAPABILITY,
			'lgbf-404zen-upgrade',
			array( __CLASS__, 'render_pricing' )
		);

		$contact_hook = add_submenu_page( 'lgbf-404zen', __( 'Contact', '404zen-broken-link-fixer' ), __( 'Contact', '404zen-broken-link-fixer' ), self::CAPABILITY, '404zen-support', array( __CLASS__, 'render_contact' ) );
		add_action( "load-{$contact_hook}", array( __CLASS__, 'prepare_zen_page' ) );

		add_action( "load-{$dashboard_hook}", array( __CLASS__, 'add_screen_options' ) );
		foreach ( array( $dashboard_hook, $settings_hook, $pricing_hook ) as $hook ) {
			add_action( "load-{$hook}", array( __CLASS__, 'prepare_zen_page' ) );
		}
	}

	/**
	 * Full-bleed treatment: our pages own their canvas. Third-party admin
	 * notices are removed on 404Zen screens only (404Zen itself never
	 * adds admin-wide notices anywhere).
	 */
	public static function prepare_zen_page() {
		remove_all_actions( 'admin_notices' );
		remove_all_actions( 'all_admin_notices' );
		add_filter(
			'admin_body_class',
			static function ( $classes ) {
				return $classes . ' lgbf-zen';
			}
		);
	}

	/**
	 * Screen options (rows per page).
	 */
	public static function add_screen_options() {
		add_screen_option(
			'per_page',
			array(
				'label'   => __( 'Links per page', '404zen-broken-link-fixer' ),
				'default' => 25,
				'option'  => 'lgbf_links_per_page',
			)
		);
	}

	/**
	 * Persists the per-page screen option.
	 *
	 * @param mixed  $status Default.
	 * @param string $option Option name.
	 * @param mixed  $value  Submitted value.
	 * @return mixed
	 */
	public static function save_screen_option( $status, $option, $value ) {
		if ( 'lgbf_links_per_page' === $option ) {
			return max( 1, min( 200, absint( $value ) ) );
		}

		return $status;
	}

	/**
	 * Registers the settings option.
	 */
	public static function register_settings() {
		register_setting(
			'lgbf_settings_group',
			LGBF_Settings::OPTION_KEY,
			array(
				'type'              => 'array',
				'sanitize_callback' => array( 'LGBF_Settings', 'sanitize' ),
				'default'           => LGBF_Settings::defaults(),
			)
		);
	}

	/**
	 * Enqueues admin assets on 404Zen pages only.
	 *
	 * @param string $hook_suffix Current admin page.
	 */
	public static function enqueue_assets( $hook_suffix ) {
		if ( false === strpos( (string) $hook_suffix, 'lgbf-404zen' ) ) {
			return;
		}

		wp_enqueue_style( 'zen-admin', LGBF_PLUGIN_URL . 'assets/css/zen-admin.css', array(), LGBF_VERSION );
		wp_enqueue_style( 'lgbf-admin', LGBF_PLUGIN_URL . 'assets/css/admin.css', array( 'zen-admin' ), LGBF_VERSION );
		wp_enqueue_script( 'lgbf-admin', LGBF_PLUGIN_URL . 'assets/js/admin.js', array( 'jquery' ), LGBF_VERSION, true );

		wp_localize_script(
			'lgbf-admin',
			'lgbfAdmin',
			array(
				'ajaxUrl' => admin_url( 'admin-ajax.php' ),
				'nonce'   => wp_create_nonce( 'lgbf_admin_nonce' ),
				'i18n'    => array(
					'confirmUnlink' => __( 'Remove this link but keep its text?', '404zen-broken-link-fixer' ),
					'dismissed'     => __( 'Link dismissed — it will be ignored in future scans.', '404zen-broken-link-fixer' ),
					'undo'          => __( 'Undo', '404zen-broken-link-fixer' ),
					'working'       => __( 'Working…', '404zen-broken-link-fixer' ),
					'error'         => __( 'Something went wrong. Please try again.', '404zen-broken-link-fixer' ),
				),
			)
		);
	}

	/**
	 * "Scan now" button handler.
	 */
	public static function handle_scan_now() {
		if ( ! current_user_can( self::CAPABILITY ) ) {
			wp_die( esc_html__( 'You are not allowed to do that.', '404zen-broken-link-fixer' ) );
		}
		check_admin_referer( 'lgbf_scan_now' );

		LGBF_Scanner::request_immediate_scan();
		spawn_cron();

		wp_safe_redirect( add_query_arg( 'lgbf_notice', 'scan_started', admin_url( 'admin.php?page=lgbf-404zen' ) ) );
		exit;
	}

	/**
	 * Processes list-table bulk actions before the page renders.
	 */
	public static function handle_bulk_actions() {
		if ( ! current_user_can( self::CAPABILITY ) ) {
			return;
		}

		$action = '';
		foreach ( array( 'action', 'action2' ) as $key ) {
			if ( isset( $_REQUEST[ $key ] ) && '-1' !== $_REQUEST[ $key ] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
				$action = sanitize_key( wp_unslash( $_REQUEST[ $key ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
				break;
			}
		}

		if ( ! $action || ! in_array( $action, array( 'recheck', 'dismiss', 'unlink' ), true ) ) {
			return;
		}

		check_admin_referer( 'bulk-lgbf_links' );

		$ids = isset( $_REQUEST['link_ids'] ) ? array_map( 'absint', (array) $_REQUEST['link_ids'] ) : array();
		$ids = array_slice( array_filter( $ids ), 0, 100 );
		if ( empty( $ids ) ) {
			return;
		}

		$done = 0;
		foreach ( $ids as $id ) {
			switch ( $action ) {
				case 'recheck':
					$result = LGBF_Fixer::recheck( $id );
					break;
				case 'dismiss':
					$result = LGBF_Fixer::dismiss( $id );
					break;
				case 'unlink':
					$result = LGBF_Fixer::unlink( $id );
					break;
				default:
					$result = null;
			}
			if ( true === $result || is_array( $result ) ) {
				$done++;
			}
		}

		wp_safe_redirect(
			add_query_arg(
				array(
					'page'        => 'lgbf-404zen',
					'lgbf_notice' => 'bulk_done',
					'lgbf_count'  => $done,
				),
				admin_url( 'admin.php' )
			)
		);
		exit;
	}

	/**
	 * The Zen Plugins top bar (lockup, tabs, docs, Go Pro).
	 *
	 * @param string $active dashboard|settings.
	 */
	private static function render_topbar( $active ) {
		$docs_base = apply_filters( 'lgbf_docs_base', 'https://404zen.com/docs/' );
		?>
		<header class="zen-topbar">
			<div class="zen-lockup">
				<svg width="26" height="26" viewBox="0 0 48 48" aria-hidden="true"><defs><linearGradient id="lgbf-lockup-grad" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#FB923C"/><stop offset="1" stop-color="#EA580C"/></linearGradient></defs><circle cx="24" cy="24" r="19" fill="none" stroke="url(#lgbf-lockup-grad)" stroke-width="3" stroke-linecap="round" stroke-dasharray="98.2 21.2" transform="rotate(120 24 24)"/><path d="M24 14.5 L32 17.5 V24 C32 29 28.8 33 24 35 C19.2 33 16 29 16 24 V17.5 Z" fill="none" stroke="#1B1620" stroke-width="2.8" stroke-linejoin="round"/></svg>
				<span>404Zen</span>
			</div>
			<nav class="zen-tabs" aria-label="<?php esc_attr_e( '404Zen sections', '404zen-broken-link-fixer' ); ?>">
				<a class="zen-tab<?php echo 'dashboard' === $active ? ' is-active' : ''; ?>" <?php echo 'dashboard' === $active ? 'aria-current="page"' : ''; ?> href="<?php echo esc_url( admin_url( 'admin.php?page=lgbf-404zen' ) ); ?>"><?php esc_html_e( 'Dashboard', '404zen-broken-link-fixer' ); ?></a>
				<a class="zen-tab<?php echo 'settings' === $active ? ' is-active' : ''; ?>" <?php echo 'settings' === $active ? 'aria-current="page"' : ''; ?> href="<?php echo esc_url( admin_url( 'admin.php?page=lgbf-404zen-settings' ) ); ?>"><?php esc_html_e( 'Settings', '404zen-broken-link-fixer' ); ?></a>
			</nav>
			<div class="zen-topbar-actions">
				<a class="zen-doclink" href="<?php echo esc_url( $docs_base ); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Documentation', '404zen-broken-link-fixer' ); ?></a>
				<?php if ( ! lgbf_can_use_premium() ) : ?>
					<a class="zen-btn zen-btn--primary zen-btn--pro" href="<?php echo esc_url( self::upgrade_url() ); ?>" aria-label="<?php esc_attr_e( 'Go Pro — stop losing traffic to dead links', '404zen-broken-link-fixer' ); ?>"><span class="zen-pro-main"><?php esc_html_e( 'Go Pro', '404zen-broken-link-fixer' ); ?></span><span class="zen-pro-sub"><?php esc_html_e( 'Stop losing traffic to dead links', '404zen-broken-link-fixer' ); ?></span></a>
				<?php endif; ?>
			</div>
		</header>
		<?php
	}

	/**
	 * Renders the dashboard page.
	 */
	public static function render_dashboard() {
		if ( ! current_user_can( self::CAPABILITY ) ) {
			return;
		}

		$counts    = LGBF_Links_Store::get_counts();
		$breakdown = LGBF_Links_Store::get_issue_breakdown();
		$state     = LGBF_Scanner::get_state();
		$last      = (int) get_option( 'lgbf_last_cycle_completed', 0 );
		$grade     = LGBF_Grade::compute( $counts, $last, LGBF_Scanner::frequency_seconds( LGBF_Settings::get( 'scan_frequency' ) ), time() );
		$tone      = LGBF_Grade::tone( $grade );

		$table = new LGBF_List_Table();
		$table->prepare_items();

		$notice = isset( $_GET['lgbf_notice'] ) ? sanitize_key( wp_unslash( $_GET['lgbf_notice'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		?>
		<div class="zen-admin zen-shell lgbf-wrap">
			<?php self::render_topbar( 'dashboard' ); ?>
			<h1 class="zen-sr-only"><?php esc_html_e( '404Zen dashboard', '404zen-broken-link-fixer' ); ?></h1>
			<hr class="wp-header-end" style="display:none" />

			<div class="zen-layout">
				<main class="zen-main">
					<?php if ( 'scan_started' === $notice ) : ?>
						<div class="notice notice-success lgbf-own"><p><?php esc_html_e( 'Scan queued. 404Zen checks links in small background batches, so results appear gradually.', '404zen-broken-link-fixer' ); ?></p></div>
					<?php elseif ( 'bulk_done' === $notice ) : ?>
						<div class="notice notice-success lgbf-own"><p>
							<?php
							$count = isset( $_GET['lgbf_count'] ) ? absint( $_GET['lgbf_count'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
							/* translators: %d: number of links processed. */
							echo esc_html( sprintf( __( '%d links processed.', '404zen-broken-link-fixer' ), $count ) );
							?>
						</p></div>
					<?php endif; ?>

					<?php if ( ! get_option( 'lgbf_last_cycle_completed' ) && ! LGBF_Optin::has_optin() && ! in_array( 'newsletter', self::hidden_tasks(), true ) ) : ?>
					<section class="zen-card lgbf-optin-card lgbf-optin-inline" aria-label="<?php esc_attr_e( 'Email updates', '404zen-broken-link-fixer' ); ?>">
						<h2><?php esc_html_e( 'Your first scan is running.', '404zen-broken-link-fixer' ); ?></h2>
						<p class="zen-card-sub"><?php esc_html_e( 'Want the results emailed + our link-health guide? Everything works exactly the same either way.', '404zen-broken-link-fixer' ); ?></p>
						<div class="lgbf-optin-form lgbf-optin-form--row">
							<input type="email" class="lgbf-optin-email regular-text" value="<?php echo esc_attr( get_option( 'admin_email' ) ); ?>" aria-label="<?php esc_attr_e( 'Email address', '404zen-broken-link-fixer' ); ?>" />
							<button type="button" class="zen-btn zen-btn--primary lgbf-optin-submit"><?php esc_html_e( 'Send me updates', '404zen-broken-link-fixer' ); ?></button>
							<button type="button" class="zen-btn zen-btn--ghost zen-hide-task" data-task="newsletter"><?php esc_html_e( 'No thanks', '404zen-broken-link-fixer' ); ?></button>
						</div>
						<p class="lgbf-optin-note"><?php esc_html_e( 'No spam, unsubscribe anytime.', '404zen-broken-link-fixer' ); ?></p>
					</section>
					<?php endif; ?>

					<?php self::render_grade_card( $grade, $tone, $counts, $state, $last ); ?>
					<?php self::render_issues_card( $breakdown, $counts ); ?>

					<section class="zen-card zen-table-card" aria-label="<?php esc_attr_e( 'Scan results', '404zen-broken-link-fixer' ); ?>">
						<form method="get">
							<input type="hidden" name="page" value="lgbf-404zen" />
							<?php
							$table->views();
							$table->search_box( __( 'Search URLs', '404zen-broken-link-fixer' ), 'lgbf-search' );
							$table->display();
							?>
						</form>
					</section>
					<p class="zen-footer-ask"><?php esc_html_e( 'Enjoying 404Zen? We\'re a small team and this plugin is free — a ★★★★★ review keeps it that way →', '404zen-broken-link-fixer' ); ?> <a href="https://wordpress.org/support/plugin/404zen-broken-link-fixer/reviews/#new-post" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Review on WordPress.org', '404zen-broken-link-fixer' ); ?></a></p>
				</main>

				<aside class="zen-side">
					<?php self::render_checklist_card( $counts ); ?>
					<?php self::render_zen_family_card(); ?>
					<?php self::render_optin_card(); ?>
					<?php self::render_tips_card(); ?>
				</aside>
			</div>
		</div>
		<?php
	}

	/**
	 * The Link Health grade card.
	 *
	 * @param string $grade  Letter or 'pending'.
	 * @param string $tone   good|warn|bad|pending.
	 * @param array  $counts Status counts.
	 * @param array  $state  Scan state.
	 * @param int    $last   Last cycle timestamp.
	 */
	private static function render_grade_card( $grade, $tone, $counts, $state, $last ) {
		$problems = $counts['broken'] + $counts['timeout'];
		$letter   = 'pending' === $grade ? '…' : $grade;

		if ( 'pending' === $grade ) {
			$headline = __( 'First scan in progress', '404zen-broken-link-fixer' );
			$sub      = __( '404Zen is checking your links in the background. Your grade appears here shortly.', '404zen-broken-link-fixer' );
		} elseif ( 'good' === $tone ) {
			$headline = __( 'Your links are in great shape', '404zen-broken-link-fixer' );
			$sub      = __( 'Keep it up — 404Zen rechecks everything on schedule and will flag anything that breaks.', '404zen-broken-link-fixer' );
		} elseif ( 'warn' === $tone ) {
			$headline = __( 'A few links need attention', '404zen-broken-link-fixer' );
			$sub      = __( 'Fix or dismiss the issues below to bring your grade back up.', '404zen-broken-link-fixer' );
		} else {
			$headline = __( 'Broken links are hurting this site', '404zen-broken-link-fixer' );
			$sub      = __( 'Visitors and search engines are hitting dead ends. The list below shows exactly where.', '404zen-broken-link-fixer' );
		}

		if ( 'idle' !== $state['phase'] ) {
			$scanned_chip = __( 'Scan running now', '404zen-broken-link-fixer' );
		} elseif ( $last ) {
			/* translators: %s: human-readable time difference. */
			$scanned_chip = sprintf( __( 'Scanned %s ago', '404zen-broken-link-fixer' ), human_time_diff( $last, time() ) );
		} else {
			$scanned_chip = __( 'First scan queued', '404zen-broken-link-fixer' );
		}
		$first_fix = get_option( 'lgbf_first_fix_at' ) && ! in_array( 'firstfix', self::hidden_tasks(), true );

		// One-time review ask when the grade improves (dismiss persists like other one-shots).
		$improvement = null;
		if ( 'pending' !== $grade ) {
			$order = array_flip( LGBF_Grade::LETTERS );
			$prev  = get_option( 'lgbf_last_grade', '' );
			if ( $prev && $prev !== $grade && isset( $order[ $prev ], $order[ $grade ] ) && $order[ $grade ] < $order[ $prev ] ) {
				update_option( 'lgbf_grade_improvement', array( 'from' => $prev, 'to' => $grade ), false );
			}
			if ( $prev !== $grade ) {
				update_option( 'lgbf_last_grade', $grade, false );
			}
			$stored = get_option( 'lgbf_grade_improvement' );
			if ( is_array( $stored ) && isset( $stored['to'] ) && $stored['to'] === $grade && ! in_array( 'review', self::hidden_tasks(), true ) ) {
				$improvement = $stored;
			}
		}
		?>
		<section class="zen-card zen-grade zen-grade--<?php echo esc_attr( $tone ); ?>" aria-label="<?php esc_attr_e( 'Link health grade', '404zen-broken-link-fixer' ); ?>">
			<div class="zen-grade-panel"><div class="zen-grade-letter" role="img" aria-label="<?php echo esc_attr( sprintf( /* translators: %s: letter grade. */ __( 'Link health grade: %s', '404zen-broken-link-fixer' ), $letter ) ); ?>"><?php echo esc_html( $letter ); ?></div></div>
			<div class="zen-grade-body">
				<h2><?php echo esc_html( $headline ); ?></h2>
				<p><?php echo esc_html( $sub ); ?></p>
				<div class="zen-stats">
					<div class="zen-stat <?php echo $problems ? 'zen-stat--bad' : 'zen-stat--ok'; ?>"><span class="zen-stat-n"><?php echo esc_html( number_format_i18n( $problems ) ); ?></span><span class="zen-stat-l"><?php esc_html_e( 'broken links', '404zen-broken-link-fixer' ); ?></span></div>
					<div class="zen-stat <?php echo $counts['redirect'] ? 'zen-stat--warn' : 'zen-stat--ok'; ?>"><span class="zen-stat-n"><?php echo esc_html( number_format_i18n( $counts['redirect'] ) ); ?></span><span class="zen-stat-l"><?php esc_html_e( 'redirect chains', '404zen-broken-link-fixer' ); ?></span></div>
					<div class="zen-stat zen-stat--ok"><span class="zen-stat-n"><?php echo esc_html( number_format_i18n( $counts['ok'] ) ); ?></span><span class="zen-stat-l"><?php esc_html_e( 'healthy', '404zen-broken-link-fixer' ); ?></span></div>
					<div class="zen-stat"><span class="zen-stat-n">⏱</span><span class="zen-stat-l"><?php echo esc_html( $scanned_chip ); ?></span></div>
				</div>
				<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="display:inline-block">
					<input type="hidden" name="action" value="lgbf_scan_now" />
					<?php wp_nonce_field( 'lgbf_scan_now' ); ?>
					<button type="submit" class="zen-btn zen-btn--dark"><?php esc_html_e( 'Scan now', '404zen-broken-link-fixer' ); ?></button>
				</form>
				<a class="zen-grade-doclink" href="<?php echo esc_url( apply_filters( 'lgbf_docs_base', 'https://404zen.com/docs/' ) . 'link-health-grade/' ); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'What does my grade mean?', '404zen-broken-link-fixer' ); ?></a>
				<?php if ( $first_fix && ! $improvement ) : ?>
					<p class="zen-review-ask">
						<?php esc_html_e( 'That link\'s fixed — for your visitors and for Google. We\'re a tiny team and 404Zen is free; if it just saved you time, a ★★★★★ review genuinely keeps it alive →', '404zen-broken-link-fixer' ); ?>
						<a href="https://wordpress.org/support/plugin/404zen-broken-link-fixer/reviews/#new-post" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Review on WordPress.org', '404zen-broken-link-fixer' ); ?></a>
						<button type="button" class="zen-hide-task" data-task="firstfix" aria-label="<?php esc_attr_e( 'Dismiss', '404zen-broken-link-fixer' ); ?>">&times;</button>
					</p>
				<?php endif; ?>
				<?php if ( $improvement ) : ?>
					<p class="zen-review-ask">
						<?php echo esc_html( sprintf( /* translators: 1: old grade, 2: new grade. */ __( 'Your grade just went from %1$s to %2$s 🎉 We put a lot of love into this free plugin — if it\'s earned it,', '404zen-broken-link-fixer' ), $improvement['from'], $improvement['to'] ) ); ?>
						<a href="https://wordpress.org/support/plugin/404zen-broken-link-fixer/reviews/#new-post" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'a 5-star review means the world → ★', '404zen-broken-link-fixer' ); ?></a>
						<button type="button" class="zen-hide-task" data-task="review" aria-label="<?php esc_attr_e( 'Dismiss', '404zen-broken-link-fixer' ); ?>">&times;</button>
					</p>
				<?php endif; ?>
				<?php
				/**
				 * Fires next to the dashboard primary actions (used by Pro for the CSV export button).
				 */
				do_action( 'lgbf_dashboard_actions' );
				?>
			</div>
		</section>
		<?php
	}

	/**
	 * The issues card: severity rows + setup task rows.
	 *
	 * @param array $breakdown Rows from LGBF_Links_Store::get_issue_breakdown().
	 * @param array $counts    Status counts.
	 */
	private static function render_issues_card( $breakdown, $counts ) {
		$base = admin_url( 'admin.php?page=lgbf-404zen' );

		$groups = array(
			array(
				'count' => isset( $breakdown['broken']['link'] ) ? $breakdown['broken']['link'] : 0,
				'label' => __( 'Broken links', '404zen-broken-link-fixer' ),
				'sev'   => 'red',
				'view'  => add_query_arg( array( 'link_status' => 'broken', 'link_type' => 'link' ), $base ),
			),
			array(
				'count' => isset( $breakdown['broken']['image'] ) ? $breakdown['broken']['image'] : 0,
				'label' => __( 'Broken images', '404zen-broken-link-fixer' ),
				'sev'   => 'red',
				'view'  => add_query_arg( array( 'link_status' => 'broken', 'link_type' => 'image' ), $base ),
			),
			array(
				'count' => $counts['timeout'],
				'label' => __( 'Timeouts', '404zen-broken-link-fixer' ),
				'sev'   => 'red',
				'view'  => add_query_arg( 'link_status', 'timeout', $base ),
			),
			array(
				'count' => $counts['redirect'],
				'label' => __( 'Redirect chains', '404zen-broken-link-fixer' ),
				'sev'   => 'amber',
				'view'  => add_query_arg( 'link_status', 'redirect', $base ),
			),
		);

		$hidden = self::hidden_tasks();
		$tasks  = array();
		if ( false && ! LGBF_Settings::get( 'digest_enabled' ) && ! in_array( 'digest', $hidden, true ) ) { // folded into the checklist card
			$tasks[] = array(
				'key'   => 'digest',
				'label' => __( 'Enable the weekly email digest so problems reach your inbox', '404zen-broken-link-fixer' ),
				'url'   => admin_url( 'admin.php?page=lgbf-404zen-settings' ),
				'cta'   => __( 'Enable', '404zen-broken-link-fixer' ),
			);
		}
		if ( false && ! lgbf_can_use_premium() && ! in_array( 'schedule', $hidden, true ) ) { // folded into the checklist card
			$tasks[] = array(
				'key'   => 'schedule',
				'label' => __( 'Set a custom scan schedule — hourly to weekly (Pro)', '404zen-broken-link-fixer' ),
				'url'   => self::upgrade_url(),
				'cta'   => __( 'Go Pro', '404zen-broken-link-fixer' ),
			);
		}

		$has_issues = false;
		foreach ( $groups as $group ) {
			if ( $group['count'] > 0 ) {
				$has_issues = true;
				break;
			}
		}
		?>
		<section class="zen-card" aria-label="<?php esc_attr_e( 'Issues', '404zen-broken-link-fixer' ); ?>">
			<h2><?php esc_html_e( 'Issues', '404zen-broken-link-fixer' ); ?></h2>
			<p class="zen-card-sub"><?php esc_html_e( 'What 404Zen found, grouped by severity.', '404zen-broken-link-fixer' ); ?></p>
			<div class="zen-issues">
				<?php if ( ! $has_issues ) : ?>
					<div class="zen-issue">
						<span class="zen-sev zen-sev--done"><?php esc_html_e( 'Clear', '404zen-broken-link-fixer' ); ?></span>
						<span class="zen-issue-label"><?php esc_html_e( 'No issues found — your links look healthy.', '404zen-broken-link-fixer' ); ?></span>
					</div>
				<?php endif; ?>

				<?php foreach ( $groups as $group ) : ?>
					<?php if ( $group['count'] < 1 ) { continue; } ?>
					<div class="zen-issue">
						<span class="zen-sev zen-sev--<?php echo esc_attr( $group['sev'] ); ?>"><?php echo 'red' === $group['sev'] ? esc_html__( 'Broken', '404zen-broken-link-fixer' ) : esc_html__( 'Warning', '404zen-broken-link-fixer' ); ?></span>
						<span class="zen-issue-label"><?php echo esc_html( $group['label'] ); ?></span>
						<span class="zen-count"><?php echo esc_html( number_format_i18n( $group['count'] ) ); ?></span>
						<span class="zen-issue-actions"><a href="<?php echo esc_url( $group['view'] ); ?>"><?php esc_html_e( 'View', '404zen-broken-link-fixer' ); ?></a></span>
					</div>
				<?php endforeach; ?>

				<?php foreach ( $tasks as $task ) : ?>
					<div class="zen-issue" data-task="<?php echo esc_attr( $task['key'] ); ?>">
						<span class="zen-sev zen-sev--task"><?php esc_html_e( 'Setup', '404zen-broken-link-fixer' ); ?></span>
						<span class="zen-issue-label"><?php echo esc_html( $task['label'] ); ?></span>
						<span class="zen-issue-actions">
							<a href="<?php echo esc_url( $task['url'] ); ?>"><?php echo esc_html( $task['cta'] ); ?></a>
							<button type="button" class="zen-hide-task" data-task="<?php echo esc_attr( $task['key'] ); ?>" aria-label="<?php esc_attr_e( 'Hide this suggestion', '404zen-broken-link-fixer' ); ?>">&times;</button>
						</span>
					</div>
				<?php endforeach; ?>
			</div>
		</section>
		<?php
	}

	/**
	 * Link health checklist — every row is a true, auto-verified state.
	 * Dismissed rows leave the denominator: progress is never held hostage.
	 *
	 * @param array $counts Status counts.
	 */
	private static function render_checklist_card( $counts ) {
		$hidden   = self::hidden_tasks();
		$problems = $counts['broken'] + $counts['timeout'];
		$scanned  = (bool) get_option( 'lgbf_last_cycle_completed' );
		$is_https = 'https' === wp_parse_url( home_url(), PHP_URL_SCHEME );
		$base     = admin_url( 'admin.php?page=lgbf-404zen' );

		$items = array(
			array( 'done' => $scanned, 'label' => __( 'First scan completed', '404zen-broken-link-fixer' ), 'sev' => 'task' ),
			array( 'done' => $scanned && 0 === $problems, 'label' => __( 'Fix all broken links', '404zen-broken-link-fixer' ), 'sev' => 'red', 'count' => $problems, 'url' => add_query_arg( 'link_status', 'broken', $base ), 'cta' => __( 'View', '404zen-broken-link-fixer' ) ),
			array( 'done' => $scanned && 0 === $counts['redirect'], 'label' => __( 'Resolve redirect chains', '404zen-broken-link-fixer' ), 'sev' => 'amber', 'count' => $counts['redirect'], 'url' => add_query_arg( 'link_status', 'redirect', $base ), 'cta' => __( 'View', '404zen-broken-link-fixer' ) ),
			array( 'done' => (bool) LGBF_Settings::get( 'digest_enabled' ), 'label' => __( 'Enable the weekly digest', '404zen-broken-link-fixer' ), 'sev' => 'task', 'url' => admin_url( 'admin.php?page=lgbf-404zen-settings' ), 'cta' => __( 'Enable', '404zen-broken-link-fixer' ) ),
			array( 'done' => $is_https, 'label' => $is_https ? __( 'Your site is served over HTTPS', '404zen-broken-link-fixer' ) : __( 'Serve your site over HTTPS', '404zen-broken-link-fixer' ), 'sev' => 'red', 'key' => 'https' ),
			array( 'done' => lgbf_can_use_premium(), 'label' => __( 'Set a scan schedule (Pro)', '404zen-broken-link-fixer' ), 'sev' => 'task', 'key' => 'schedule', 'url' => self::upgrade_url(), 'cta' => __( 'Go Pro', '404zen-broken-link-fixer' ), 'dismiss' => true ),
			array( 'done' => LGBF_Optin::has_optin(), 'label' => __( 'Subscribe to link-health updates', '404zen-broken-link-fixer' ), 'sev' => 'task', 'key' => 'newsletter', 'url' => '#', 'cta' => '', 'dismiss' => true ),
		);

		$rows = array();
		foreach ( $items as $item ) {
			if ( ! empty( $item['key'] ) && ! empty( $item['dismiss'] ) && in_array( $item['key'], $hidden, true ) ) {
				continue; // dismissed → out of the denominator entirely.
			}
			$rows[] = $item;
		}
		$total = count( $rows );
		$done  = count( array_filter( $rows, static function ( $r ) { return $r['done']; } ) );
		$pct   = $total ? round( 100 * $done / $total ) : 100;
		?>
		<section class="zen-card" aria-label="<?php esc_attr_e( 'Link health checklist', '404zen-broken-link-fixer' ); ?>">
			<h2><?php esc_html_e( 'Link health checklist', '404zen-broken-link-fixer' ); ?></h2>
			<p class="zen-card-sub"><?php echo esc_html( sprintf( /* translators: 1: done, 2: total. */ __( '%1$d of %2$d complete', '404zen-broken-link-fixer' ), $done, $total ) ); ?></p>
			<div class="zen-progress" role="progressbar" aria-valuenow="<?php echo (int) $pct; ?>" aria-valuemin="0" aria-valuemax="100"><span style="width:<?php echo (int) $pct; ?>%"></span></div>
			<div class="zen-issues">
				<?php foreach ( $rows as $item ) : ?>
					<div class="zen-issue">
						<span class="zen-sev <?php echo $item['done'] ? 'zen-sev--done' : 'zen-sev--' . esc_attr( $item['sev'] ); ?>"><?php echo $item['done'] ? '✓' : '&nbsp;·&nbsp;'; ?></span>
						<span class="zen-issue-label"><?php echo esc_html( $item['label'] ); ?></span>
						<?php if ( ! $item['done'] && isset( $item['count'] ) && $item['count'] > 0 ) : ?><span class="zen-count"><?php echo esc_html( number_format_i18n( $item['count'] ) ); ?></span><?php endif; ?>
						<span class="zen-issue-actions">
							<?php if ( ! $item['done'] && ! empty( $item['url'] ) && ! empty( $item['cta'] ) ) : ?><a href="<?php echo esc_url( $item['url'] ); ?>"><?php echo esc_html( $item['cta'] ); ?></a><?php endif; ?>
							<?php if ( ! $item['done'] && ! empty( $item['dismiss'] ) && ! empty( $item['key'] ) ) : ?><button type="button" class="zen-hide-task" data-task="<?php echo esc_attr( $item['key'] ); ?>" aria-label="<?php esc_attr_e( 'Hide this task', '404zen-broken-link-fixer' ); ?>">&times;</button><?php endif; ?>
						</span>
					</div>
					<?php if ( ! $item['done'] && 'https' === ( $item['key'] ?? '' ) ) : ?>
						<div class="zen-promo" style="padding:10px 0 14px 34px">
							<img src="<?php echo esc_url( LGBF_PLUGIN_URL . 'assets/img/sslzen-icon.png' ); ?>" width="36" height="36" alt="" style="border-radius:8px" onerror="this.style.display='none'" />
							<p><?php esc_html_e( 'Free SSL certificates + automatic HTTPS', '404zen-broken-link-fixer' ); ?></p>
							<?php $s = self::sslzen_state_link(); ?>
							<a class="zen-btn zen-btn--primary" href="<?php echo esc_url( $s ); ?>"><?php esc_html_e( 'Protect your site — free', '404zen-broken-link-fixer' ); ?></a>
						</div>
					<?php endif; ?>
				<?php endforeach; ?>
			</div>
		</section>
		<?php
	}

	/**
	 * Install/activate/plugins URL for SSL Zen depending on its state.
	 *
	 * @return string
	 */
	private static function sslzen_state_link() {
		if ( ! function_exists( 'is_plugin_active' ) ) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; }
		$file = 'ssl-zen/ssl_zen.php';
		if ( is_plugin_active( $file ) ) { return admin_url( 'plugins.php' ); }
		if ( file_exists( WP_PLUGIN_DIR . '/' . $file ) ) { return wp_nonce_url( self_admin_url( 'plugins.php?action=activate&plugin=' . $file ), 'activate-plugin_' . $file ); }
		return wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=ssl-zen' ), 'install-plugin_ssl-zen' );
	}

	/**
	 * Post-value opt-in card: shown once, only after the first completed
	 * scan, dismissible, and nothing leaves the site without the click.
	 */
	private static function render_optin_card() {
		if ( ! get_option( 'lgbf_last_cycle_completed' ) || LGBF_Optin::has_optin() || in_array( 'newsletter', self::hidden_tasks(), true ) ) {
			return;
		}
		?>
		<section class="zen-card lgbf-optin-card" aria-label="<?php esc_attr_e( 'Email updates', '404zen-broken-link-fixer' ); ?>">
			<button type="button" class="zen-hide-task lgbf-optin-close" data-task="newsletter" aria-label="<?php esc_attr_e( 'Dismiss', '404zen-broken-link-fixer' ); ?>">&times;</button>
			<h2><?php esc_html_e( 'Get update alerts & link-health tips', '404zen-broken-link-fixer' ); ?></h2>
			<p class="zen-card-sub"><?php esc_html_e( 'Occasional, useful emails from the 404Zen team.', '404zen-broken-link-fixer' ); ?></p>
			<div class="lgbf-optin-form">
				<input type="email" class="lgbf-optin-email regular-text" value="<?php echo esc_attr( get_option( 'admin_email' ) ); ?>" aria-label="<?php esc_attr_e( 'Email address', '404zen-broken-link-fixer' ); ?>" />
				<button type="button" class="zen-btn zen-btn--primary lgbf-optin-submit"><?php esc_html_e( 'Subscribe', '404zen-broken-link-fixer' ); ?></button>
			</div>
			<p class="lgbf-optin-note"><?php esc_html_e( 'No spam, unsubscribe anytime.', '404zen-broken-link-fixer' ); ?></p>
		</section>
		<?php
	}

	/**
	 * "More from Zen Plugins" sidebar card (quiet cross-promo, no notices).
	 */
	private static function render_zen_family_card() {
		if ( ! function_exists( 'is_plugin_active' ) ) {
			require_once ABSPATH . 'wp-admin/includes/plugin.php';
		}

		$sslzen_file = 'ssl-zen/ssl_zen.php';
		if ( is_plugin_active( $sslzen_file ) ) {
			$state = '<span class="is-active-state">' . esc_html__( 'Active', '404zen-broken-link-fixer' ) . '</span>';
		} elseif ( file_exists( WP_PLUGIN_DIR . '/' . $sslzen_file ) ) {
			$activate_url = wp_nonce_url( self_admin_url( 'plugins.php?action=activate&plugin=' . $sslzen_file ), 'activate-plugin_' . $sslzen_file );
			$state        = '<a href="' . esc_url( $activate_url ) . '">' . esc_html__( 'Activate', '404zen-broken-link-fixer' ) . '</a>';
		} else {
			$install_url = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=ssl-zen' ), 'install-plugin_ssl-zen' );
			$state       = '<a href="' . esc_url( $install_url ) . '">' . esc_html__( 'Install', '404zen-broken-link-fixer' ) . '</a>';
		}
		?>
		<section class="zen-card" aria-label="<?php esc_attr_e( 'More from Zen Plugins', '404zen-broken-link-fixer' ); ?>">
			<h2><?php esc_html_e( 'More from Zen Plugins', '404zen-broken-link-fixer' ); ?></h2>
			<div class="zen-promo">
				<div class="zen-promo-head">
					<span class="zen-promo-ico"><img src="<?php echo esc_url( LGBF_PLUGIN_URL . 'assets/img/sslzen-icon.png' ); ?>" width="40" height="40" alt="" onerror="this.parentNode.style.display='none'" /></span>
					<span class="zen-promo-id">
						<h3><?php esc_html_e( 'SSL Zen', '404zen-broken-link-fixer' ); ?></h3>
						<span class="zen-proof"><span class="zen-stars" aria-hidden="true">★★★★★</span><span class="zen-proof-num">4.9</span><span aria-hidden="true">·</span><span><?php esc_html_e( '1M+ downloads', '404zen-broken-link-fixer' ); ?></span><span class="zen-sr-only"><?php esc_html_e( 'rated 4.9 out of 5', '404zen-broken-link-fixer' ); ?></span></span>
					</span>
				</div>
				<p class="zen-promo-line"><?php esc_html_e( 'Free SSL certificates + HTTPS enforcement.', '404zen-broken-link-fixer' ); ?></p>
				<?php if ( false !== strpos( $state, 'is-active-state' ) ) : ?>
					<span class="zen-sev zen-sev--done"><?php esc_html_e( 'Active on this site', '404zen-broken-link-fixer' ); ?></span>
				<?php else : ?>
					<?php $promo_url = preg_match( '/href="([^"]+)"/', $state, $pm ) ? $pm[1] : 'https://wordpress.org/plugins/ssl-zen/'; ?>
					<a class="zen-btn zen-btn--primary" href="<?php echo esc_url( $promo_url ); ?>"><?php esc_html_e( 'Protect your site — free', '404zen-broken-link-fixer' ); ?></a>
				<?php endif; ?>
			</div>
			<div class="zen-plugin-row zen-plugin-row--ghost">
				<span class="zen-plugin-ico" aria-hidden="true">
					<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#059669" stroke-width="1.8" stroke-linecap="round"><path d="M12 5v14M5 12h14"/></svg>
				</span>
				<span style="flex:1;min-width:0">
					<h3><?php esc_html_e( 'More tools coming', '404zen-broken-link-fixer' ); ?></h3>
					<p><?php esc_html_e( 'Focused plugins. Zero bloat.', '404zen-broken-link-fixer' ); ?></p>
				</span>
			</div>
		</section>
		<?php
	}

	/**
	 * Tips sidebar card — short educational reads.
	 */
	private static function render_tips_card() {
		$docs_base = apply_filters( 'lgbf_docs_base', 'https://404zen.com/docs/' );
		$tips      = array(
			'#seo'            => __( 'Why broken links hurt SEO', '404zen-broken-link-fixer' ),
			'#redirects'      => __( 'How redirects leak link equity', '404zen-broken-link-fixer' ),
			'#grade'          => __( 'Reading your Link Health grade', '404zen-broken-link-fixer' ),
			'#shared-hosting' => __( 'Tuning scans for shared hosting', '404zen-broken-link-fixer' ),
		);
		?>
		<section class="zen-card" aria-label="<?php esc_attr_e( 'Tips and guides', '404zen-broken-link-fixer' ); ?>">
			<h2><?php esc_html_e( 'Tips & guides', '404zen-broken-link-fixer' ); ?></h2>
			<ul class="zen-tips">
				<?php foreach ( $tips as $anchor => $label ) : ?>
					<li><a href="<?php echo esc_url( $docs_base . $anchor ); ?>" target="_blank" rel="noopener noreferrer"><?php echo esc_html( $label ); ?></a></li>
				<?php endforeach; ?>
			</ul>
		</section>
		<?php
	}

	/**
	 * Renders the settings page inside the same shell.
	 */
	public static function render_settings() {
		if ( ! current_user_can( self::CAPABILITY ) ) {
			return;
		}

		$settings   = LGBF_Settings::all();
		$post_types = get_post_types( array( 'public' => true ), 'objects' );
		unset( $post_types['attachment'] );
		?>
		<div class="zen-admin zen-shell lgbf-wrap">
			<?php self::render_topbar( 'settings' ); ?>
			<h1 class="zen-sr-only"><?php esc_html_e( '404Zen settings', '404zen-broken-link-fixer' ); ?></h1>

			<div class="zen-layout" style="grid-template-columns:1fr;max-width:920px">
				<main class="zen-main">
					<form method="post" action="options.php">
						<?php settings_fields( 'lgbf_settings_group' ); ?>

						<section class="zen-card">
							<h2><?php esc_html_e( 'Scanning', '404zen-broken-link-fixer' ); ?></h2>
							<table class="form-table" role="presentation">
								<tr>
									<th scope="row"><label for="lgbf-frequency"><?php esc_html_e( 'Scan frequency', '404zen-broken-link-fixer' ); ?></label></th>
									<td>
										<select id="lgbf-frequency" name="<?php echo esc_attr( LGBF_Settings::OPTION_KEY ); ?>[scan_frequency]">
											<option value="hourly" <?php selected( $settings['scan_frequency'], 'hourly' ); ?>><?php esc_html_e( 'Hourly', '404zen-broken-link-fixer' ); ?></option>
											<option value="twicedaily" <?php selected( $settings['scan_frequency'], 'twicedaily' ); ?>><?php esc_html_e( 'Twice daily', '404zen-broken-link-fixer' ); ?></option>
											<option value="daily" <?php selected( $settings['scan_frequency'], 'daily' ); ?>><?php esc_html_e( 'Daily', '404zen-broken-link-fixer' ); ?></option>
											<option value="weekly" <?php selected( $settings['scan_frequency'], 'weekly' ); ?>><?php esc_html_e( 'Weekly', '404zen-broken-link-fixer' ); ?></option>
										</select>
										<p class="description"><?php esc_html_e( 'Hourly suits large, frequently updated sites.', '404zen-broken-link-fixer' ); ?></p>
									</td>
								</tr>
								<tr>
									<th scope="row"><label for="lgbf-batch-size"><?php esc_html_e( 'Batch size', '404zen-broken-link-fixer' ); ?></label></th>
									<td>
										<input type="number" id="lgbf-batch-size" min="10" max="200" name="<?php echo esc_attr( LGBF_Settings::OPTION_KEY ); ?>[batch_size]" value="<?php echo esc_attr( $settings['batch_size'] ); ?>" class="small-text" />
										<p class="description"><?php esc_html_e( 'URLs checked per background run (every 5 minutes). Lower this on shared hosting.', '404zen-broken-link-fixer' ); ?></p>
									</td>
								</tr>
								<tr>
									<th scope="row"><?php esc_html_e( 'What to check', '404zen-broken-link-fixer' ); ?></th>
									<td>
										<fieldset>
											<label><input type="checkbox" name="<?php echo esc_attr( LGBF_Settings::OPTION_KEY ); ?>[check_internal]" value="1" <?php checked( $settings['check_internal'] ); ?> /> <?php esc_html_e( 'Internal links', '404zen-broken-link-fixer' ); ?></label><br />
											<label><input type="checkbox" name="<?php echo esc_attr( LGBF_Settings::OPTION_KEY ); ?>[check_external]" value="1" <?php checked( $settings['check_external'] ); ?> /> <?php esc_html_e( 'External links', '404zen-broken-link-fixer' ); ?></label><br />
											<label><input type="checkbox" name="<?php echo esc_attr( LGBF_Settings::OPTION_KEY ); ?>[check_images]" value="1" <?php checked( $settings['check_images'] ); ?> /> <?php esc_html_e( 'Images', '404zen-broken-link-fixer' ); ?></label>
										</fieldset>
									</td>
								</tr>
								<tr>
									<th scope="row"><?php esc_html_e( 'Exclude post types', '404zen-broken-link-fixer' ); ?></th>
									<td>
										<fieldset>
											<?php foreach ( $post_types as $post_type ) : ?>
												<label>
													<input type="checkbox" name="<?php echo esc_attr( LGBF_Settings::OPTION_KEY ); ?>[exclude_post_types][]" value="<?php echo esc_attr( $post_type->name ); ?>" <?php checked( in_array( $post_type->name, (array) $settings['exclude_post_types'], true ) ); ?> />
													<?php echo esc_html( $post_type->labels->name ); ?>
												</label><br />
											<?php endforeach; ?>
										</fieldset>
									</td>
								</tr>
								<tr>
									<th scope="row"><label for="lgbf-exclude-urls"><?php esc_html_e( 'Exclude URLs', '404zen-broken-link-fixer' ); ?></label></th>
									<td>
										<textarea id="lgbf-exclude-urls" name="<?php echo esc_attr( LGBF_Settings::OPTION_KEY ); ?>[exclude_urls]" rows="4" class="large-text code"><?php echo esc_textarea( implode( "\n", (array) $settings['exclude_urls'] ) ); ?></textarea>
										<p class="description"><?php esc_html_e( 'One pattern per line. Any URL containing a pattern is skipped (e.g. example.com or /wp-json/).', '404zen-broken-link-fixer' ); ?></p>
									</td>
								</tr>
							</table>
						</section>

						<section class="zen-card">
							<h2><?php esc_html_e( 'Server protection', '404zen-broken-link-fixer' ); ?></h2>
							<table class="form-table" role="presentation">
								<tr>
									<th scope="row"><label for="lgbf-max-load"><?php esc_html_e( 'Pause when server load exceeds', '404zen-broken-link-fixer' ); ?></label></th>
									<td>
										<input type="number" id="lgbf-max-load" min="0" max="64" name="<?php echo esc_attr( LGBF_Settings::OPTION_KEY ); ?>[max_load]" value="<?php echo esc_attr( $settings['max_load'] ); ?>" class="small-text" />
										<p class="description"><?php esc_html_e( '0 = automatic (number of CPU cores). When the 1-minute load average is above this value, 404Zen skips its run and waits.', '404zen-broken-link-fixer' ); ?></p>
									</td>
								</tr>
								<tr>
									<th scope="row"><label for="lgbf-timeout"><?php esc_html_e( 'Request timeout', '404zen-broken-link-fixer' ); ?></label></th>
									<td>
										<input type="number" id="lgbf-timeout" min="3" max="30" name="<?php echo esc_attr( LGBF_Settings::OPTION_KEY ); ?>[request_timeout]" value="<?php echo esc_attr( $settings['request_timeout'] ); ?>" class="small-text" />
										<span><?php esc_html_e( 'seconds', '404zen-broken-link-fixer' ); ?></span>
									</td>
								</tr>
							</table>
						</section>

						<section class="zen-card">
							<h2><?php esc_html_e( 'Email digest', '404zen-broken-link-fixer' ); ?></h2>
							<table class="form-table" role="presentation">
								<tr>
									<th scope="row"><?php esc_html_e( 'Weekly summary', '404zen-broken-link-fixer' ); ?></th>
									<td>
										<label>
											<input type="checkbox" name="<?php echo esc_attr( LGBF_Settings::OPTION_KEY ); ?>[digest_enabled]" value="1" <?php checked( $settings['digest_enabled'] ); ?> />
											<?php esc_html_e( 'Email me a weekly summary of newly found broken links', '404zen-broken-link-fixer' ); ?>
										</label>
									</td>
								</tr>
								<tr>
									<th scope="row"><label for="lgbf-recipient"><?php esc_html_e( 'Recipient', '404zen-broken-link-fixer' ); ?></label></th>
									<td>
										<input type="email" id="lgbf-recipient" name="<?php echo esc_attr( LGBF_Settings::OPTION_KEY ); ?>[digest_recipient]" value="<?php echo esc_attr( $settings['digest_recipient'] ); ?>" class="regular-text" placeholder="<?php echo esc_attr( get_option( 'admin_email' ) ); ?>" />
										<p class="description"><?php esc_html_e( 'Leave empty to use the site admin email.', '404zen-broken-link-fixer' ); ?></p>
										<label style="display:block;margin-top:12px">
											<input type="checkbox" name="<?php echo esc_attr( LGBF_Settings::OPTION_KEY ); ?>[updates_optin]" value="1" <?php checked( LGBF_Settings::get( 'updates_optin' ) ); ?> />
											<?php esc_html_e( 'Also send me occasional 404Zen product updates', '404zen-broken-link-fixer' ); ?>
										</label>
									</td>
								</tr>
							</table>
						</section>

						<?php submit_button( null, 'zen-btn zen-btn--primary' ); ?>
					</form>
					<p class="zen-footer-ask"><?php esc_html_e( 'Enjoying 404Zen? We\'re a small team and this plugin is free — a ★★★★★ review keeps it that way →', '404zen-broken-link-fixer' ); ?> <a href="https://wordpress.org/support/plugin/404zen-broken-link-fixer/reviews/#new-post" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Review on WordPress.org', '404zen-broken-link-fixer' ); ?></a></p>

				</main>
			</div>
		</div>
		<?php
	}

	/**
	 * Task keys the current user has hidden.
	 *
	 * @return string[]
	 */
	public static function hidden_tasks() {
		$hidden = get_user_meta( get_current_user_id(), 'lgbf_hidden_tasks', true );

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

	/**
	 * Contact page — a human answers.
	 */
	public static function render_contact() {
		if ( ! current_user_can( self::CAPABILITY ) ) { return; }
		?>
		<div class="zen-admin zen-shell lgbf-wrap">
			<?php self::render_topbar( 'contact' ); ?>
			<div class="zen-layout" style="grid-template-columns:1fr;max-width:640px">
				<main class="zen-main">
					<section class="zen-card" style="text-align:center;padding:40px 32px">
						<h2 style="font-size:24px;margin:0 0 6px"><?php esc_html_e( 'A human answers.', '404zen-broken-link-fixer' ); ?></h2>
						<p class="zen-card-sub" style="margin-bottom:20px"><?php esc_html_e( 'No ticket bots, no tiers. We reply within 24 hours — usually much faster.', '404zen-broken-link-fixer' ); ?></p>
						<a class="zen-btn zen-btn--primary" href="mailto:support@zenplugins.org?subject=404Zen">support@zenplugins.org</a>
						<p style="margin:18px 0 0"><a href="<?php echo esc_url( apply_filters( 'lgbf_docs_base', 'https://404zen.com/docs/' ) ); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Or read the docs →', '404zen-broken-link-fixer' ); ?></a></p>
					</section>
				</main>
			</div>
		</div>
		<?php
	}

	/**
	 * Custom Pro pricing page — Freemius handles checkout, we design the page.
	 */
	public static function render_pricing() {
		if ( ! current_user_can( self::CAPABILITY ) ) {
			return;
		}

		$counts   = LGBF_Links_Store::get_counts();
		$last     = (int) get_option( 'lgbf_last_cycle_completed', 0 );
		$grade    = LGBF_Grade::compute( $counts, $last, LGBF_Scanner::frequency_seconds( LGBF_Settings::get( 'scan_frequency' ) ), time() );
		$problems = $counts['broken'] + $counts['timeout'];

		// Launch discount (EARLYBIRD) is auto-applied at checkout; hide it once it
		// expires so the page never advertises a dead code. Extend via the filter.
		$offer_ends   = apply_filters( 'lgbf_offer_ends', '2026-07-17' );
		$offer_active = $offer_ends && current_time( 'timestamp' ) <= strtotime( $offer_ends . ' 23:59:59' );
		$offer_coupon = 'EARLYBIRD';

		$tiers = array(
			array( 'pricing_id' => 72416, 'name' => __( '1 Site', '404zen-broken-link-fixer' ), 'price' => 49, 'lifetime' => 129, 'popular' => false, 'features' => array( __( 'Scheduled scans — hourly to weekly', '404zen-broken-link-fixer' ), __( 'One-click auto-redirects for 404s', '404zen-broken-link-fixer' ), __( 'CSV export', '404zen-broken-link-fixer' ) ) ),
			array( 'pricing_id' => 72422, 'name' => __( '5 Sites', '404zen-broken-link-fixer' ), 'price' => 99, 'lifetime' => 249, 'popular' => true, 'features' => array( __( 'Everything in 1 Site', '404zen-broken-link-fixer' ), __( 'Use on up to 5 sites', '404zen-broken-link-fixer' ), __( 'Priority email support', '404zen-broken-link-fixer' ) ) ),
			array( 'pricing_id' => 72435, 'name' => __( '25 Sites', '404zen-broken-link-fixer' ), 'price' => 199, 'lifetime' => 499, 'popular' => false, 'features' => array( __( 'Everything in 5 Sites', '404zen-broken-link-fixer' ), __( 'Use on up to 25 sites', '404zen-broken-link-fixer' ), __( 'Multisite support', '404zen-broken-link-fixer' ) ) ),
		);
		?>
		<div class="zen-admin zen-shell lgbf-wrap">
			<?php self::render_topbar( 'pricing' ); ?>
			<h1 class="zen-sr-only"><?php esc_html_e( '404Zen Pro pricing', '404zen-broken-link-fixer' ); ?></h1>
			<div class="zen-layout" style="grid-template-columns:1fr;max-width:980px">
				<main class="zen-main">
					<?php if ( 'pending' !== $grade ) : ?>
						<section class="zen-card zen-grade zen-grade--<?php echo esc_attr( LGBF_Grade::tone( $grade ) ); ?>" style="padding:18px 24px">
							<div class="zen-grade-letter" style="width:64px;height:64px;font-size:34px" aria-hidden="true"><?php echo esc_html( $grade ); ?></div>
							<div class="zen-grade-body"><h2 style="margin:0">
								<?php
								if ( $problems > 0 ) {
									/* translators: 1: grade letter, 2: number of broken links. */
									echo esc_html( sprintf( _n( 'Your site: grade %1$s — %2$d broken link is leaking visitors and rankings right now.', 'Your site: grade %1$s — %2$d broken links are leaking visitors and rankings right now.', $problems, '404zen-broken-link-fixer' ), $grade, $problems ) );
								} else {
									/* translators: %s: grade letter. */
									echo esc_html( sprintf( __( 'Your links are clean today — grade %s. Pro keeps them that way, automatically.', '404zen-broken-link-fixer' ), $grade ) );
								}
								?>
							</h2><p style="margin:6px 0 0;color:var(--zen-muted)">
								<?php
								if ( $problems > 0 ) {
									esc_html_e( 'Pro repairs them in one click and auto-redirects every dead URL — so you never lose another visitor.', '404zen-broken-link-fixer' );
								} else {
									esc_html_e( 'Scheduled scans catch new breaks and auto-redirect them before a visitor ever hits a dead end.', '404zen-broken-link-fixer' );
								}
								?>
							</p></div>
						</section>
					<?php endif; ?>

					<p class="zen-trust" style="text-align:center;margin:14px 0 0;color:var(--zen-muted);font-size:14px">
						<?php esc_html_e( 'From the team behind SSL Zen — 1,000,000+ installs, ★ 4.9 average rating.', '404zen-broken-link-fixer' ); ?>
					</p>

					<div class="zen-harm">
						<div class="zen-card"><h3><?php esc_html_e( 'SEO decay signal', '404zen-broken-link-fixer' ); ?></h3><p><?php esc_html_e( 'Every broken link tells Google your site is decaying. The average five-year-old blog carries 100+ dead links.', '404zen-broken-link-fixer' ); ?></p></div>
						<div class="zen-card"><h3><?php esc_html_e( 'Lost visitors', '404zen-broken-link-fixer' ); ?></h3><p><?php esc_html_e( 'A 404 is the fastest way to end a session. Every dead end is a visitor who leaves and rarely comes back.', '404zen-broken-link-fixer' ); ?></p></div>
						<div class="zen-card"><h3><?php esc_html_e( 'Eroded trust', '404zen-broken-link-fixer' ); ?></h3><p><?php esc_html_e( 'Readers forgive a typo. They remember a site full of links that go nowhere.', '404zen-broken-link-fixer' ); ?></p></div>
					</div>

					<?php if ( $offer_active ) : ?>
						<div class="zen-offer"><span>⚡ <?php
							/* translators: %s: offer end date. */
							echo esc_html( sprintf( __( 'Launch offer — 30%% off, applied automatically at checkout. Ends %s.', '404zen-broken-link-fixer' ), date_i18n( get_option( 'date_format' ), strtotime( $offer_ends ) ) ) );
						?></span></div>
					<?php endif; ?>

					<div class="zen-plans">
						<?php foreach ( $tiers as $tier ) : ?>
							<div class="zen-card zen-plan<?php echo $tier['popular'] ? ' zen-plan--popular' : ''; ?>">
								<?php if ( $tier['popular'] ) : ?><span class="zen-pop"><?php esc_html_e( 'Most popular', '404zen-broken-link-fixer' ); ?></span><?php endif; ?>
								<h3><?php echo esc_html( $tier['name'] ); ?></h3>
								<p class="zen-price">$<?php echo (int) $tier['price']; ?><small> <?php esc_html_e( '/ year', '404zen-broken-link-fixer' ); ?></small></p>
								<p class="zen-lifetime"><button type="button" class="lgbf-buy" data-pricing="<?php echo (int) $tier['pricing_id']; ?>" data-cycle="lifetime"><?php echo esc_html( sprintf( /* translators: %d: lifetime price. */ __( 'or $%d lifetime — pay once, protected forever', '404zen-broken-link-fixer' ), $tier['lifetime'] ) ); ?></button></p>
								<ul>
									<?php foreach ( $tier['features'] as $feature ) : ?><li><?php echo esc_html( $feature ); ?></li><?php endforeach; ?>
								</ul>
								<button type="button" class="zen-btn <?php echo $tier['popular'] ? 'zen-btn--primary' : 'zen-btn--ghost'; ?> lgbf-buy" data-pricing="<?php echo (int) $tier['pricing_id']; ?>">
									<?php
									if ( $offer_active && $tier['popular'] ) {
										/* translators: %s: tier name. */
										echo esc_html( sprintf( __( 'Get %s — 30%% off', '404zen-broken-link-fixer' ), $tier['name'] ) );
									} else {
										/* translators: %s: tier name. */
										echo esc_html( sprintf( __( 'Get %s', '404zen-broken-link-fixer' ), $tier['name'] ) );
									}
									?>
								</button>
							</div>
						<?php endforeach; ?>
					</div>
					<p class="zen-moneyback">🛡 <?php esc_html_e( '14-day money-back guarantee — no questions asked. The free version stays free forever.', '404zen-broken-link-fixer' ); ?></p>

					<section class="zen-card">
						<h2><?php esc_html_e( '404Zen vs cloud checkers', '404zen-broken-link-fixer' ); ?></h2>
						<table class="zen-compare zen-compare--big">
							<thead><tr><th></th><th class="zen-lgcol">404Zen</th><th><?php esc_html_e( 'Cloud checkers', '404zen-broken-link-fixer' ); ?></th></tr></thead>
							<tbody>
							<?php
							$rows = array(
								array( __( 'Unlimited scans', '404zen-broken-link-fixer' ), __( 'Metered credits', '404zen-broken-link-fixer' ) ),
								array( __( 'Runs on YOUR server', '404zen-broken-link-fixer' ), __( 'Uploaded to their cloud', '404zen-broken-link-fixer' ) ),
								array( __( 'No account', '404zen-broken-link-fixer' ), __( 'Signup walls', '404zen-broken-link-fixer' ) ),
								array( __( 'No monthly credits', '404zen-broken-link-fixer' ), __( '$10+/month forever', '404zen-broken-link-fixer' ) ),
								array( __( 'One-click fixes', '404zen-broken-link-fixer' ), __( 'Reports only', '404zen-broken-link-fixer' ) ),
								array( __( 'Auto-redirects', '404zen-broken-link-fixer' ), '—' ),
								array( __( 'Lifetime option', '404zen-broken-link-fixer' ), '—' ),
							);
							foreach ( $rows as $r ) {
								echo '<tr><td>' . esc_html( $r[0] ) . '</td><td class="zen-lgcol">✓</td><td class="zen-mut">' . esc_html( $r[1] ) . '</td></tr>';
							}
							?>
							</tbody>
						</table>
					</section>

					<section class="zen-card">
						<h2><?php esc_html_e( 'Questions', '404zen-broken-link-fixer' ); ?></h2>
						<details class="zen-faq"><summary><?php esc_html_e( 'What happens if Pro is not for me?', '404zen-broken-link-fixer' ); ?></summary><p><?php esc_html_e( 'Every purchase has a 14-day money-back guarantee. One email, full refund, no questions asked.', '404zen-broken-link-fixer' ); ?></p></details>
						<details class="zen-faq"><summary><?php esc_html_e( 'What support do I get?', '404zen-broken-link-fixer' ); ?></summary><p><?php esc_html_e( 'Email support from the developers, with priority handling on the 5- and 25-site plans. A real human replies.', '404zen-broken-link-fixer' ); ?></p></details>
						<details class="zen-faq"><summary><?php esc_html_e( 'Does the free version stay free?', '404zen-broken-link-fixer' ); ?></summary><p><?php esc_html_e( 'Yes. Unlimited scanning and one-click fixes are free forever. Pro adds automation on top.', '404zen-broken-link-fixer' ); ?></p></details>
					</section>
				</main>
			</div>
		</div>
		<script src="https://checkout.freemius.com/js/v1/"></script>
		<script>
		(function(){var COUPON=<?php echo $offer_active ? "'" . esc_js( $offer_coupon ) . "'" : 'null'; ?>;var h=null;document.addEventListener('click',function(e){var b=e.target.closest('.lgbf-buy');if(!b)return;if(!h&&window.FS&&FS.Checkout){h=new FS.Checkout({product_id:33434,public_key:'pk_4bc27cf83ffb91e30cf4d76d4fdf9'});}if(h){var o={name:'404Zen',pricing_id:parseInt(b.getAttribute('data-pricing'),10)};if(COUPON){o.coupon=COUPON;}if(b.getAttribute('data-cycle')){o.billing_cycle=b.getAttribute('data-cycle');}h.open(o);}else{window.open('https://checkout.freemius.com/plugin/33434/','_blank');}});})();
		</script>
		<?php
	}

	/**
	 * Upgrade URL (Freemius checkout when configured).
	 *
	 * @return string
	 */
	public static function upgrade_url() {
		return admin_url( 'admin.php?page=lgbf-404zen-upgrade' );
	}
}
