<?php
/**
 * SiteStaffr Admin Dashboard
 *
 * Clean, mobile-responsive dashboard optimized for "5-minute setup" experience.
 *
 * @link       https://github.com/sitestaffr/sitestaffr-plugin
 * @since      1.0.0
 *
 * @package    SiteStaffr
 * @subpackage SiteStaffr/admin/views
 */

// If this file is called directly, abort.
if ( ! defined( 'WPINC' ) ) {
    die;
}

// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound

if ( ! isset( $sitestaffr_admin_view_query_service ) || ! ( $sitestaffr_admin_view_query_service instanceof SiteStaffr_Admin_View_Query_Service ) ) {
    $sitestaffr_admin_view_query_service = new SiteStaffr_Admin_View_Query_Service();
}

// Read-only routing params — sanitized and validated against strict allowlists.
// These are standard WordPress admin page navigation params set by menu links,
// not form submissions, so nonces do not apply. The call detail view (action=view)
// performs its own nonce verification before displaying any data.
$sitestaffr_action = isset( $_GET['action'] ) ? sanitize_key( wp_unslash( $_GET['action'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only routing; value checked against 'view' only.
if ( 'view' === $sitestaffr_action ) {
    include_once SITESTAFFR_PLUGIN_DIR . 'admin/views/admin-call-detail.php';
    return;
}

$sitestaffr_view = isset( $_GET['view'] ) ? sanitize_key( wp_unslash( $_GET['view'] ) ) : ( isset( $sitestaffr_default_view ) ? $sitestaffr_default_view : '' ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only routing; strict allowlist below.
if ( in_array( $sitestaffr_view, array( 'all', 'trash', 'banned' ), true ) ) {
    include_once SITESTAFFR_PLUGIN_DIR . 'admin/views/admin-calls-list.php';
    return;
}

// Get settings and data
$settings = get_option( 'sitestaffr_settings', array() );
$is_setup_complete = SiteStaffr_Admin::is_setup_complete();
$business_phone = isset( $settings['business_phone'] ) ? stripslashes( $settings['business_phone'] ) : '';
$business_name = isset( $settings['business_name'] ) ? stripslashes( $settings['business_name'] ) : '';
$last_test_call = SiteStaffr_Database::get_last_test_call();

// Billing cache (middleware source of truth for admin display).
$dashboard_billing_cache = array();
if ( class_exists( 'SiteStaffr_Billing_State' ) ) {
	// Force refresh on dashboard load to keep minute balance accurate after recent calls.
	SiteStaffr_Billing_State::maybe_refresh_cache( true );
	$dashboard_billing_cache = SiteStaffr_Billing_State::get_cache();
}

$dashboard_status_key = isset( $dashboard_billing_cache['subscription_status'] ) ? sanitize_key( $dashboard_billing_cache['subscription_status'] ) : '';
$dashboard_status_labels = array(
	'trial_active'  => __( 'Trial Active', 'sitestaffr' ),
	'active'        => __( 'Active', 'sitestaffr' ),
	'past_due'      => __( 'Past Due', 'sitestaffr' ),
	'canceled'      => __( 'Canceled', 'sitestaffr' ),
	'trial_expired' => __( 'Trial Expired', 'sitestaffr' ),
	'unpaid'        => __( 'Payment Failed', 'sitestaffr' ),
);
$dashboard_status_label = isset( $dashboard_status_labels[ $dashboard_status_key ] ) ? $dashboard_status_labels[ $dashboard_status_key ] : __( 'Active', 'sitestaffr' );

// Dashboard stats should align to the middleware billing period.
$balance_option = get_option( 'sitestaffr_minute_balance', array() );
$billing_period_start = '';
if ( ! empty( $dashboard_billing_cache['subscription_current_period_start'] ) ) {
	$billing_period_start = sanitize_text_field( $dashboard_billing_cache['subscription_current_period_start'] );
} elseif ( ! empty( $dashboard_billing_cache['trial_started_at'] ) ) {
	$billing_period_start = sanitize_text_field( $dashboard_billing_cache['trial_started_at'] );
} elseif ( ! empty( $dashboard_billing_cache['subscription_current_period_end'] ) && strtotime( $dashboard_billing_cache['subscription_current_period_end'] ) ) {
	$billing_period_start = gmdate( 'Y-m-d H:i:s', strtotime( '-1 month', strtotime( $dashboard_billing_cache['subscription_current_period_end'] ) ) );
} elseif ( isset( $balance_option['last_reset_date'] ) ) {
	$billing_period_start = sanitize_text_field( $balance_option['last_reset_date'] ) . ' 00:00:00';
} else {
	$billing_period_start = current_time( 'Y-m-01 00:00:00' );
}

$billing_period_start_dt = ( strtotime( $billing_period_start ) ) ? gmdate( 'Y-m-d H:i:s', strtotime( $billing_period_start ) ) : current_time( 'Y-m-01 00:00:00' );
$billing_period_end_dt = current_time( 'mysql' );

$dashboard_period_counts = $sitestaffr_admin_view_query_service->get_dashboard_period_counts( $billing_period_start_dt, $billing_period_end_dt );
$total_calls_month       = isset( $dashboard_period_counts['total_calls'] ) ? (int) $dashboard_period_counts['total_calls'] : 0;
$billable_calls_month    = isset( $dashboard_period_counts['billable_calls'] ) ? (int) $dashboard_period_counts['billable_calls'] : 0;
$answered_calls_month    = isset( $dashboard_period_counts['answered_calls'] ) ? (int) $dashboard_period_counts['answered_calls'] : 0;

$spam_filtered_month = max( 0, $total_calls_month - $billable_calls_month );
$new_calls_count = SiteStaffr_Call_Manager::get_new_calls_count();

// Dynamic stat card: After-Hours Calls OR Answer Rate based on business hours
$business_hours = get_option( 'sitestaffr_business_hours', 'mon-fri-9-5' );
$is_24_7 = SiteStaffr_Call_Manager::is_24_7_schedule( $business_hours );

if ( $is_24_7 ) {
	// Show Answer Rate for 24/7 businesses (billing period).
	$answer_rate = ( $total_calls_month > 0 ) ? ( ( $answered_calls_month / $total_calls_month ) * 100 ) : 100;
	$stat_value = number_format_i18n( $answer_rate, 1 ) . '%';
	$stat_label = __( 'Answer Rate', 'sitestaffr' );
	if ( $answer_rate >= 95 ) {
		$stat_modifier_class = 'is-answer-rate-strong';
	} elseif ( $answer_rate >= 80 ) {
		$stat_modifier_class = 'is-answer-rate-medium';
	} else {
		$stat_modifier_class = 'is-answer-rate-weak';
	}
} else {
	// Show After-Hours Calls for non-24/7 businesses (billing period).
	$after_hours_count = 0;
	$period_call_timestamps = $sitestaffr_admin_view_query_service->get_dashboard_period_call_timestamps( $billing_period_start_dt, $billing_period_end_dt );
	foreach ( $period_call_timestamps as $period_call_created_at ) {
		if ( ! SiteStaffr_Call_Manager::is_within_business_hours( $period_call_created_at, $business_hours ) ) {
			$after_hours_count++;
		}
	}
	$stat_value = $after_hours_count;
	$stat_label = __( 'After-Hours Calls', 'sitestaffr' );
	$stat_modifier_class = 'is-after-hours';
}

// Calculate average call duration from billing period (exclude zero durations).
$avg_duration = $sitestaffr_admin_view_query_service->get_dashboard_average_duration_seconds( $billing_period_start_dt, $billing_period_end_dt );
$avg_minutes = floor( $avg_duration / 60 );
$avg_seconds = $avg_duration % 60;
$avg_duration_display = sprintf( '%d:%02d', $avg_minutes, $avg_seconds );

// Get recent calls (last 5)
$recent_calls = SiteStaffr_Call_Manager::get_calls( array(
    'per_page' => 5,
    'page'     => 1,
) );

// Get unread calls for New Calls section
$new_calls = SiteStaffr_Call_Manager::get_calls( array(
    'is_read'  => 0,  // Only unread calls
    'per_page' => 10,  // Show up to 10 new calls
    'page'     => 1,
) );
$has_new_calls = ! empty( $new_calls );

// AI summaries are now stored in database (Phase 1) - no need to generate on-the-fly!
// The $new_calls array already contains ai_summary and ai_followup fields from database
// This is MUCH faster than the previous reflection-based generation approach
//
// If a summary is missing (old calls from before Phase 1), it will show a fallback message
// in the UI. The AI Summary Generator automatically creates summaries for all new calls.

/**
 * Format dashboard recap HTML/text for safe display in New Conversations cards.
 *
 * @param string $text Raw recap text from database.
 * @return string
 */
function sitestaffr_format_dashboard_recap_html( $text ) {
	$recap = trim( stripslashes( (string) $text ) );
	if ( '' === $recap ) {
		return '';
	}

	// If model already returned structured HTML markup, preserve it.
	if ( false !== stripos( $recap, '<ul' ) || false !== stripos( $recap, '<table' ) ) {
		return $recap;
	}

	$normalized = preg_replace( '/<\s*br\s*\/?>/i', "\n", $recap );
	$normalized = preg_replace( '/<\s*\/p\s*>/i', "\n", $normalized );
	$normalized = preg_replace( '/<\s*p[^>]*>/i', '', $normalized );
	$normalized = wp_strip_all_tags( (string) $normalized );

	$lines = preg_split( '/\r\n|\r|\n/', (string) $normalized );
	$intro_lines = array();
	$detail_lines = array();
	$followup_line = '';

	foreach ( (array) $lines as $line ) {
		$line = trim( (string) $line );
		if ( '' === $line ) {
			continue;
		}

		if ( 0 === stripos( $line, 'Suggested follow-up:' ) ) {
			$followup_line = trim( substr( $line, strlen( 'Suggested follow-up:' ) ) );
			continue;
		}

		if ( preg_match( '/^[A-Za-z][A-Za-z\s\/-]{1,40}:\s+.+$/', $line ) ) {
			$detail_lines[] = $line;
			continue;
		}

		$intro_lines[] = $line;
	}

	$html_parts = array();
	if ( ! empty( $intro_lines ) ) {
		$html_parts[] = '<p>' . esc_html( implode( ' ', $intro_lines ) ) . '</p>';
	}
	if ( ! empty( $detail_lines ) ) {
		$list = '<ul>';
		foreach ( $detail_lines as $detail ) {
			$list .= '<li>' . esc_html( $detail ) . '</li>';
		}
		$list .= '</ul>';
		$html_parts[] = $list;
	}
	if ( '' !== $followup_line ) {
		$html_parts[] = '<hr class="sitestaffr-recap-divider" style="border:none;border-top:1px solid #e0e0e0;margin:12px 0;" />';
		$html_parts[] = '<p><strong>' . esc_html__( 'Suggested follow-up:', 'sitestaffr' ) . '</strong> ' . esc_html( $followup_line ) . '</p>';
	}

	if ( empty( $html_parts ) ) {
		return '<p>' . esc_html( $recap ) . '</p>';
	}

	return implode( '', $html_parts );
}
?>

<div class="wrap sitestaffr-dashboard">
    <?php
    $sitestaffr_page_title = __( 'Dashboard', 'sitestaffr' );
    include SITESTAFFR_PLUGIN_DIR . 'admin/partials/sitestaffr-header.php';
    ?>

    <?php
    // Plan status alert banner (canceled / trial_expired / unpaid / past_due)
    $sitestaffr_alert_statuses = array( 'canceled', 'trial_expired', 'unpaid', 'past_due' );
    if ( in_array( $dashboard_status_key, $sitestaffr_alert_statuses, true ) ) :
        $sitestaffr_usage_url = admin_url( 'admin.php?page=sitestaffr-usage#purchase-minutes' );

        if ( 'canceled' === $dashboard_status_key ) :
            $sitestaffr_alert_class  = 'sitestaffr-plan-alert-danger';
            $sitestaffr_alert_title  = __( 'Subscription Canceled', 'sitestaffr' );
            $sitestaffr_alert_body   = __( 'Your subscription has been canceled. Your AI voice agent is no longer active.', 'sitestaffr' );
            $sitestaffr_alert_cta    = __( 'Resubscribe', 'sitestaffr' );
        elseif ( 'trial_expired' === $dashboard_status_key ) :
            $sitestaffr_alert_class  = 'sitestaffr-plan-alert-warning';
            $sitestaffr_alert_title  = __( 'Free Trial Expired', 'sitestaffr' );
            $sitestaffr_alert_body   = __( 'Your free trial has expired. Upgrade to keep your AI voice agent running.', 'sitestaffr' );
            $sitestaffr_alert_cta    = __( 'Upgrade Now', 'sitestaffr' );
        else : // unpaid or past_due
            $sitestaffr_alert_class  = ( 'past_due' === $dashboard_status_key ) ? 'sitestaffr-plan-alert-warning' : 'sitestaffr-plan-alert-danger';
            $sitestaffr_alert_title  = __( 'Payment Failed', 'sitestaffr' );
            $sitestaffr_alert_body   = __( 'Your payment has failed. Please update your payment method to continue service.', 'sitestaffr' );
            $sitestaffr_alert_cta    = __( 'Update Payment', 'sitestaffr' );
        endif;
    ?>
    <div class="sitestaffr-plan-alert-banner <?php echo esc_attr( $sitestaffr_alert_class ); ?>" id="sitestaffr-plan-alert-banner" role="alert">
        <span class="sitestaffr-plan-alert-icon dashicons dashicons-warning" aria-hidden="true"></span>
        <div class="sitestaffr-plan-alert-body">
            <strong><?php echo esc_html( $sitestaffr_alert_title ); ?></strong>
            <?php echo esc_html( $sitestaffr_alert_body ); ?>
            <a href="<?php echo esc_url( $sitestaffr_usage_url ); ?>" class="sitestaffr-plan-alert-cta"><?php echo esc_html( $sitestaffr_alert_cta ); ?></a>
        </div>
        <button type="button" class="sitestaffr-plan-alert-dismiss dashicons dashicons-dismiss" aria-label="<?php esc_attr_e( 'Dismiss', 'sitestaffr' ); ?>"></button>
    </div>
    <?php endif; ?>

    <?php
    // Display admin notices from nonce-verified redirects (e.g. mark-read, delete).
    // Uses wp_verify_nonce on a redirect nonce to satisfy WP.org scanner requirements.
    if ( isset( $_GET['message'], $_GET['_wpnonce'] )
        && wp_verify_nonce( sanitize_key( wp_unslash( $_GET['_wpnonce'] ) ), 'sitestaffr_admin_notice' )
    ) {
        $message = sanitize_key( wp_unslash( $_GET['message'] ) );
        $success_messages = array(
            'marked_read'        => __( 'Conversation marked as read.', 'sitestaffr' ),
            'marked_unread'      => __( 'Conversation marked as unread.', 'sitestaffr' ),
            'deleted'            => __( 'Conversation deleted.', 'sitestaffr' ),
            'bulk_marked_read'   => __( 'Selected conversations marked as read.', 'sitestaffr' ),
            'bulk_marked_unread' => __( 'Selected conversations marked as unread.', 'sitestaffr' ),
            'bulk_deleted'       => __( 'Selected conversations deleted.', 'sitestaffr' ),
        );

        if ( isset( $success_messages[ $message ] ) ) {
            echo '<div class="notice notice-success is-dismissible"><p>' . esc_html( $success_messages[ $message ] ) . '</p></div>';
        }
    }
    ?>

    <!-- Max-width wrapper for consistent layout with AI Knowledge, Calls, Settings pages -->
    <div class="pe-dashboard-content">

    <!-- New Calls Highlight Section with Carousel (v0.10.8 - Moved to Top) -->
    <div class="sitestaffr-widget sitestaffr-new-calls-widget <?php echo esc_attr( $has_new_calls ? 'has-new-calls' : 'no-new-calls' ); ?>" id="sitestaffr-new-calls-section">
        <div class="sitestaffr-widget-header sitestaffr-new-calls-header">
            <h2>
                <span class="dashicons dashicons-bell"></span>
                <?php esc_html_e( 'New Conversations', 'sitestaffr' ); ?>
                <?php if ( $has_new_calls ) : ?>
                <span class="sitestaffr-new-calls-count"><?php echo esc_html( count( $new_calls ) ); ?></span>
                <?php endif; ?>
            </h2>
            <button type="button" class="sitestaffr-toggle-new-calls" aria-expanded="<?php echo esc_attr( $has_new_calls ? 'true' : 'false' ); ?>" aria-controls="sitestaffr-new-calls-content">
                <span class="dashicons dashicons-arrow-up-alt2"></span>
            </button>
        </div>

        <div class="sitestaffr-new-calls-content" id="sitestaffr-new-calls-content" <?php echo esc_attr( ! $has_new_calls ? 'style="display: none;"' : '' ); ?>>
            <?php if ( $has_new_calls ) : ?>
            <div class="sitestaffr-new-calls-carousel-wrapper">
                <!-- Carousel Navigation -->
                <?php if ( count( $new_calls ) > 1 ) : ?>
                <button type="button" class="sitestaffr-carousel-nav sitestaffr-carousel-prev" aria-label="Previous call">
                    <span class="dashicons dashicons-arrow-left-alt2"></span>
                </button>
                <button type="button" class="sitestaffr-carousel-nav sitestaffr-carousel-next" aria-label="Next call">
                    <span class="dashicons dashicons-arrow-right-alt2"></span>
                </button>
                <?php endif; ?>

                <!-- Carousel Track -->
                <div class="sitestaffr-new-calls-carousel">
                    <?php foreach ( $new_calls as $index => $call ) : ?>
                    <?php
                    // Format time ago
                    // Handle both Unix timestamps (new) and MySQL datetime strings (old data)
                    $started_timestamp = is_numeric( $call->started_at ) ? (int) $call->started_at : strtotime( $call->started_at );
                    $time_ago = human_time_diff( $started_timestamp, time() ) . ' ago';

                    // Format duration
                    $duration = '';
                    if ( $call->call_duration > 0 ) {
                        $minutes = floor( $call->call_duration / 60 );
                        $seconds = $call->call_duration % 60;
                        $duration = sprintf( '%d:%02d', $minutes, $seconds );
                    }

                    // Get AI-generated summary
                    $ai_summary = isset( $call->ai_summary ) ? stripslashes( $call->ai_summary ) : '';

                    // Fallback: Strip any introductory phrases that may have made it into the database
                    $intro_patterns = array(
                        '/^(Okay|Sure|Here\'s|Here is),?\s+.*?(summary|call summary|overview).*?:/i',
                        '/^(Okay|Sure),?\s+/i',
                    );
                    foreach ( $intro_patterns as $pattern ) {
                        $ai_summary = preg_replace( $pattern, '', $ai_summary );
                    }
                    $ai_summary = trim( $ai_summary );

                    ?>
                    <div class="sitestaffr-carousel-slide <?php echo esc_attr( $index === 0 ? 'active' : '' ); ?>" data-slide-index="<?php echo esc_attr( $index ); ?>" data-call-id="<?php echo esc_attr( $call->id ); ?>">
                        <div class="sitestaffr-new-call-card">
                            <div class="sitestaffr-new-call-layout">
                                <div class="sitestaffr-new-call-main">
                                    <div class="sitestaffr-ai-summary-text">
                                        <?php
                                        $call_persona = isset( $call->persona ) ? sanitize_key( $call->persona ) : 'default';
                                        if ( 'onboarding' === $call_persona ) : ?>
                                            <span class="sitestaffr-persona-badge sitestaffr-persona-badge--onboarding"><?php esc_html_e( 'Onboarding Lead', 'sitestaffr' ); ?></span>
                                        <?php endif; ?>
                                        <?php if ( ! empty( $ai_summary ) ) : ?>
                                            <?php echo wp_kses_post( sitestaffr_format_dashboard_recap_html( $ai_summary ) ); ?>
                                        <?php else : ?>
                                            <em style="color: #6c757d;"><?php esc_html_e( 'AI recap not yet generated for this conversation. Click "View Full Details" to see the complete transcript.', 'sitestaffr' ); ?></em>
                                        <?php endif; ?>
                                    </div>
                                </div>
                                <aside class="sitestaffr-new-call-side">
                                    <div class="sitestaffr-new-call-side-metadata">
                                        <div class="sitestaffr-new-call-side-row">
                                            <span class="sitestaffr-new-call-side-label"><?php esc_html_e( 'Received', 'sitestaffr' ); ?></span>
                                            <span class="sitestaffr-new-call-side-value">
                                                <?php echo esc_html( $time_ago ); ?>
                                            </span>
                                        </div>
                                        <?php if ( $duration ) : ?>
                                        <div class="sitestaffr-new-call-side-row">
                                            <span class="sitestaffr-new-call-side-label"><?php esc_html_e( 'Duration', 'sitestaffr' ); ?></span>
                                            <span class="sitestaffr-new-call-side-value">
                                                <?php echo esc_html( $duration ); ?>
                                            </span>
                                        </div>
                                        <?php endif; ?>
                                    </div>

                                    <div class="sitestaffr-new-call-actions">
                                        <button type="button"
                                                class="sitestaffr-new-call-mark-read-link"
                                                data-call-id="<?php echo esc_attr( $call->id ); ?>"
                                                title="<?php esc_attr_e( 'Mark as read', 'sitestaffr' ); ?>">
                                            <span class="dashicons dashicons-yes-alt" aria-hidden="true"></span>
                                            <?php esc_html_e( 'Mark as Read', 'sitestaffr' ); ?>
                                        </button>

                                        <a href="<?php echo esc_url( wp_nonce_url( add_query_arg( array( 'page' => 'sitestaffr', 'action' => 'view', 'call_id' => $call->id ), admin_url( 'admin.php' ) ), 'sitestaffr_view_call' ) ); ?>" class="sitestaffr-new-call-view-link">
                                            <?php esc_html_e( 'View Full Details', 'sitestaffr' ); ?> &rarr;
                                        </a>
                                    </div>
                                </aside>
                            </div>
                                </div>
                    </div>
                    <?php endforeach; ?>
                </div>

                <!-- Carousel Indicators -->
                <?php if ( count( $new_calls ) > 1 ) : ?>
                <div class="sitestaffr-carousel-indicators">
                    <?php foreach ( $new_calls as $index => $call ) : ?>
                    <button type="button" class="sitestaffr-carousel-dot <?php echo esc_attr( $index === 0 ? 'active' : '' ); ?>" data-slide-to="<?php echo esc_attr( $index ); ?>" aria-label="Go to call <?php echo esc_attr( $index + 1 ); ?>"></button>
                    <?php endforeach; ?>
                </div>
                <?php endif; ?>
            </div>
            <?php else : ?>
            <div class="sitestaffr-new-calls-empty">
                <span class="dashicons dashicons-yes-alt"></span>
                <p><?php esc_html_e( 'You\'re all caught up!', 'sitestaffr' ); ?></p>
                <span class="sitestaffr-empty-subtitle"><?php esc_html_e( 'No new conversations to review', 'sitestaffr' ); ?></span>
            </div>
            <?php endif; ?>
        </div>
    </div>

    <!-- Combined Phone Number + AI Minute Balance Widget (Task S - Circular Progress Ring v0.10.19) -->
    <?php
    $subscription_option = get_option( 'sitestaffr_subscription', array() );
    $subscription_option = is_array( $subscription_option ) ? $subscription_option : array();

    $dashboard_plan_key = isset( $dashboard_billing_cache['plan_name'] ) ? sanitize_key( $dashboard_billing_cache['plan_name'] ) : '';
    if ( empty( $dashboard_plan_key ) ) {
        if ( ! empty( $subscription_option['plan_name'] ) ) {
            $dashboard_plan_key = sanitize_key( $subscription_option['plan_name'] );
        } elseif ( ! empty( $subscription_option['plan'] ) ) {
            $dashboard_plan_key = sanitize_key( $subscription_option['plan'] );
        }
    }
    if ( empty( $dashboard_plan_key ) ) {
        $dashboard_plan_key = 'starter';
    }

    $dashboard_plan_quotas = array(
        'trial'    => 30,
        'starter'  => 60,
        'business' => 300,
        'pro'      => 700,
    );
    if ( ! isset( $dashboard_plan_quotas[ $dashboard_plan_key ] ) ) {
        $dashboard_plan_key = 'starter';
    }
    $included_quota = isset( $dashboard_plan_quotas[ $dashboard_plan_key ] ) ? (int) $dashboard_plan_quotas[ $dashboard_plan_key ] : 60;

    // Prefer middleware-backed cache for accurate billing stats; fallback to local usage only when missing.
    $included = isset( $dashboard_billing_cache['included_minutes_remaining'] ) ? (int) $dashboard_billing_cache['included_minutes_remaining'] : null;
    $purchased = isset( $dashboard_billing_cache['addon_minutes_remaining'] ) ? (int) $dashboard_billing_cache['addon_minutes_remaining'] : null;
    $has_seconds_precision = isset( $dashboard_billing_cache['included_seconds_remaining'] ) || isset( $dashboard_billing_cache['addon_seconds_remaining'] );
    $included_seconds_remaining = $has_seconds_precision ? (int) ( isset( $dashboard_billing_cache['included_seconds_remaining'] ) ? $dashboard_billing_cache['included_seconds_remaining'] : 0 ) : null;
    $addon_seconds_remaining = $has_seconds_precision ? (int) ( isset( $dashboard_billing_cache['addon_seconds_remaining'] ) ? $dashboard_billing_cache['addon_seconds_remaining'] : 0 ) : null;

    if ( $has_seconds_precision ) {
        // Use second-level values as source of truth for minute display near 0.
        $included = (int) floor( max( 0, $included_seconds_remaining ) / 60 );
        $purchased = (int) floor( max( 0, $addon_seconds_remaining ) / 60 );
    }

    if ( null === $included || null === $purchased ) {
        $usage_manager = SiteStaffr_Usage_Manager::get_instance();
        $balance = $usage_manager->get_minutes_balance();
        $included = ( null === $included ) ? (int) $balance['included'] : $included;
        $purchased = ( null === $purchased ) ? (int) $balance['purchased'] : $purchased;
    }
    if ( null === $included ) {
        $included = $included_quota;
    }
    if ( null === $purchased ) {
        $purchased = 0;
    }
    $total = $included + $purchased;

    // Use second-level precision for progress ring so small usage is reflected accurately.
    if ( null === $included_seconds_remaining ) {
        $included_seconds_remaining = $included * 60;
    }
    if ( null === $addon_seconds_remaining ) {
        $addon_seconds_remaining = $purchased * 60;
    }
    $total_seconds_remaining = max( 0, $included_seconds_remaining + $addon_seconds_remaining );

    // Calculate total quota with second-level precision.
    $included_quota_seconds = $included_quota * 60;
    $total_quota_seconds = $included_quota_seconds + max( 0, $addon_seconds_remaining );
    $total_quota = $included_quota + $purchased; // keep minute-based denominator for UI copy

    // Percentage for progress bar (float, 0-100).
    $percentage = ( $total_quota_seconds > 0 ) ? ( $total_seconds_remaining / $total_quota_seconds ) * 100 : 0;
    $percentage = max( 0, min( 100, $percentage ) );

    // Determine status tier and tooltip message (Task W - v0.10.67: Show percentage in tooltip)
    if ( $percentage >= 25 && $total >= 15 ) {
        $status = 'healthy';
        $ring_color = 'high';
        $tooltip = number_format_i18n( $percentage, 1 ) . '%';
    } elseif ( $percentage >= 5 && $total >= 2 ) {
        $status = 'medium';
        $ring_color = 'medium';
        $tooltip = number_format_i18n( $percentage, 1 ) . '%';
    } else {
        $status = 'critical';
        $ring_color = 'low';
        $tooltip = number_format_i18n( $percentage, 1 ) . '%';
    }

    // Task 1 Revision - Status Icon Logic (v0.10.47)
    // Determine status icon and color based on remaining percentage
    if ( $percentage >= 25 && $total >= 15 ) {
        $status_icon = 'dashicons-yes'; // Green checkmark (NO circle background)
        $status_color = 'rgba(76, 175, 80, 0.4)'; // Match progress circle green EXACTLY
        $status_label = 'Healthy';
        $health_message = __( 'You have plenty of AI minutes remaining. Your AI voice agent will continue answering calls without interruption!', 'sitestaffr' );
    } elseif ( $percentage >= 5 && $total >= 2 ) {
        $status_icon = 'sitestaffr-exclamation'; // Plain exclamation for low state.
        $status_color = '#f59e0b'; // Yellow/amber
        $status_label = 'Low';
        $health_message = __( 'Your AI minutes are getting low. Consider purchasing more to avoid interruption.', 'sitestaffr' );
    } else {
        $status_icon = 'dashicons-warning'; // Red circle exclamation — "danger"
        $status_color = '#ef4444'; // Red
        $status_label = 'Critical';
        $health_message = ( $total <= 0 )
            ? __( 'Your AI minutes are exhausted. Service is currently interrupted until minutes are added or your plan is upgraded.', 'sitestaffr' )
            : __( 'Your AI minutes are critically low. Purchase more minutes now to avoid service interruption.', 'sitestaffr' );
    }

    $balance_title_icon = 'dashicons-analytics';
    $balance_title_text = __( 'AI Minutes Balance', 'sitestaffr' );
    if ( 'critical' === $status ) {
        $balance_title_icon = 'dashicons-warning';
        $balance_title_text = ( $total <= 0 )
            ? __( 'AI Minutes Balance - Exhausted', 'sitestaffr' )
            : __( 'AI Minutes Balance - Critical', 'sitestaffr' );
    } elseif ( 'medium' === $status ) {
        $balance_title_icon = 'dashicons-warning';
        $balance_title_text = __( 'AI Minutes Balance - Low', 'sitestaffr' );
    }

    $dashboard_upgrade_eligible_plans = array( 'trial', 'starter', 'business' );
    $dashboard_show_upgrade_cta = in_array( $status, array( 'medium', 'critical' ), true )
        && in_array( $dashboard_plan_key, $dashboard_upgrade_eligible_plans, true );
    $dashboard_upgrade_cta_url = admin_url( 'admin.php?page=sitestaffr-usage#purchase-minutes' );

    // SVG circle parameters for stroke-dasharray
    $circle_radius = 54;
    $circle_circumference = 2 * M_PI * $circle_radius;
    $stroke_dashoffset = $circle_circumference - ( $percentage / 100 * $circle_circumference );

    // Calculate next reset date from billing cache (consistent with Usage page)
    $next_reset_raw = isset( $dashboard_billing_cache['subscription_current_period_end'] ) ? $dashboard_billing_cache['subscription_current_period_end'] : null;
    if ( 'trial' === $dashboard_plan_key && ! empty( $dashboard_billing_cache['trial_expires_at'] ) ) {
        $next_reset_raw = $dashboard_billing_cache['trial_expires_at'];
    }
    $next_reset_timestamp = ! empty( $next_reset_raw ) ? strtotime( $next_reset_raw ) : false;
    if ( false !== $next_reset_timestamp ) {
        $next_month = wp_date( 'F j, Y', $next_reset_timestamp, wp_timezone() );
    } else {
        // Fallback to legacy subscription option when billing cache unavailable
        $subscription = get_option( 'sitestaffr_subscription', array() );
        $subscription = wp_parse_args(
            $subscription,
            array(
                'next_billing_date' => current_datetime()->modify( '+1 month' )->format( 'Y-m-d' ),
            )
        );
        $next_billing_timestamp = strtotime( $subscription['next_billing_date'] );
        $next_month             = false !== $next_billing_timestamp
            ? wp_date( 'F j, Y', $next_billing_timestamp, wp_timezone() )
            : current_datetime()->modify( '+1 month' )->format( 'F j, Y' );
    }

    // Calculate usage projection using billing period start as lookback window.
    $projection_stat_value = __( 'No data', 'sitestaffr' );

    // Use billing period start as lookback; fall back to 30-day window if unavailable.
    if ( ! empty( $billing_period_start_dt ) ) {
        $projection_lookback_dt = $billing_period_start_dt;
    } else {
        $projection_lookback_dt = gmdate( 'Y-m-d H:i:s', strtotime( '-30 days', current_time( 'timestamp' ) ) );
    }

    $projection_calls = $sitestaffr_admin_view_query_service->get_projection_usage_calls_since( $projection_lookback_dt );

    if ( ! empty( $projection_calls ) ) {
        // Get date of first call in our dataset
        $first_call_date = strtotime( $projection_calls[0]->created_at );
        $now = current_time( 'timestamp' );
        $days_of_history = max( 1, ( $now - $first_call_date ) / DAY_IN_SECONDS );

        // Calculate total minutes used in this period
        $total_minutes_used = 0;
        foreach ( $projection_calls as $call ) {
            $total_minutes_used += max( 1, (int) $call->effective_billable_minutes );
        }

        // Calculate average daily usage
        $avg_daily_usage = $total_minutes_used / $days_of_history;

        // Show projection if there's actual usage; zero balance should show immediate exhaustion.
        if ( $avg_daily_usage > 0 ) {
            if ( $total <= 0 ) {
                $projection_stat_value = '0';
            } else {
                $days_remaining = $total / $avg_daily_usage;

                // Cap at 365 days to avoid absurd projections.
                if ( $days_remaining >= 365 ) {
                    $projection_stat_value = __( '~365+', 'sitestaffr' );
                } elseif ( $days_remaining >= 1 ) {
                    // Show approximate whole days.
                    $projection_stat_value = sprintf( '~%d', (int) round( $days_remaining ) );
                } else {
                    // Less than one day of runway.
                    $projection_stat_value = __( '~<1', 'sitestaffr' );
                }
            }
        }
    }

    // Progressive Low Balance Alert System (Task U - v0.10.27)
    // Calculate alert level based on minute balance percentage
    $alert_level = 'none';
    $alert_message = '';
    $alert_button_text = '';
    $alert_title = '';

    if ( $percentage < 5 || $total < 2 ) {
        $alert_level = 'critical';
        $alert_title = __( 'CRITICAL: OUT OF AI MINUTES SOON!', 'sitestaffr' );
        $alert_message = sprintf(
            // translators: %1$d: remaining minutes, %2$d: total quota, %3$d: percentage remaining.
            __( 'URGENT: Only %1$d/%2$d AI minutes left (%3$d%%)! Service will be interrupted when balance = 0.', 'sitestaffr' ),
            $total, $total_quota, round( $percentage )
        );
        $alert_button_text = __( 'PURCHASE AI MINUTES IMMEDIATELY', 'sitestaffr' );
    } elseif ( $percentage < 15 || $total < 5 ) {
        $alert_level = 'low';
        $alert_title = __( 'LOW BALANCE ALERT', 'sitestaffr' );
        $alert_message = sprintf(
            // translators: %1$d: remaining minutes, %2$d: total quota, %3$d: percentage remaining.
            __( 'Only %1$d/%2$d AI minutes remaining (%3$d%%)! You may miss calls if your balance runs out.', 'sitestaffr' ),
            $total, $total_quota, round( $percentage )
        );
        $alert_button_text = __( 'Purchase More AI Minutes Now', 'sitestaffr' );
    } elseif ( $percentage < 25 || $total < 15 ) {
        $alert_level = 'warning';
        $alert_title = __( 'Approaching Low Balance', 'sitestaffr' );
        $alert_message = sprintf(
            // translators: %1$d: remaining minutes, %2$d: total quota, %3$d: percentage remaining.
            __( 'You have %1$d/%2$d AI minutes remaining (%3$d%%). Consider purchasing more to avoid interruption.', 'sitestaffr' ),
            $total, $total_quota, round( $percentage )
        );
        $alert_button_text = __( 'Purchase AI Minutes', 'sitestaffr' );
    }
    ?>

    <?php // Low balance alert moved to global header partial (sitestaffr-header.php) — v0.14.158 ?>

    <!-- Two-Column Grid: AI Minutes Balance (Left 50%) + Stat Cards (Right 50%) - v0.10.20 Task S Refinement -->
    <div class="sitestaffr-dashboard-balance-stats-grid">

        <!-- LEFT COLUMN: AI Minutes Balance Section (v0.10.20 - Refined Layout) -->
        <div class="sitestaffr-minutes-balance-section sitestaffr-minutes-widget status-<?php echo esc_attr( $status ); ?>">
            <!-- Header Row: Title + Reset Date in Top-Right -->
            <div class="sitestaffr-minutes-header-row">
                <h3 class="sitestaffr-section-title">
                    <span class="dashicons <?php echo esc_attr( $balance_title_icon ); ?>"></span>
                    <?php echo esc_html( $balance_title_text ); ?>
                </h3>
                <div class="sitestaffr-minutes-reset-header">
                    <?php echo esc_html( sprintf( 'Resets: %s', $next_month ) ); ?>
                </div>
            </div>

            <!-- Main Content: Big Circle (Left) + Info Column (Right) -->
            <div class="sitestaffr-minutes-content">
                <!-- Left: Circular Progress Ring (MUCH BIGGER) -->
                <div class="sitestaffr-progress-circle-container">
                    <svg class="sitestaffr-progress-circle" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
                        <!-- Background circle -->
                        <circle class="sitestaffr-progress-bg" cx="60" cy="60" r="<?php echo esc_attr( $circle_radius ); ?>" />
                        <!-- Progress ring -->
                        <circle
                            class="sitestaffr-progress-ring status-<?php echo esc_attr( $ring_color ); ?>"
                            cx="60"
                            cy="60"
                            r="<?php echo esc_attr( $circle_radius ); ?>"
                            stroke-dasharray="<?php echo esc_attr( $circle_circumference ); ?>"
                            stroke-dashoffset="<?php echo esc_attr( $stroke_dashoffset ); ?>"
                        />
                    </svg>
                    <!-- Task 1 - Status Icon (v0.10.46) -->
                    <div class="sitestaffr-progress-status">
                        <?php if ( 'sitestaffr-exclamation' === $status_icon ) : ?>
                            <span class="sitestaffr-progress-status-exclamation" style="color: <?php echo esc_attr( $status_color ); ?>;">!</span>
                        <?php else : ?>
                            <span class="dashicons <?php echo esc_attr( $status_icon ); ?>"
                                  style="color: <?php echo esc_attr( $status_color ); ?>;"></span>
                        <?php endif; ?>
                    </div>

                    <!-- Tooltip (hidden by default, shown on hover) - Task W v0.10.67: Simple percentage -->
                    <div class="sitestaffr-balance-tooltip" style="display: none;">
                        <?php echo esc_html( $tooltip ); ?>
                    </div>
                </div>

                <!-- Right: Info Column (AI Minutes + Purchased + Projection + Health Message + Button) -->
                <div class="sitestaffr-minutes-info">
                    <div class="sitestaffr-minutes-display">
                        <?php
                        // Primary message: "X minutes remaining" (plain language)
                        echo esc_html( sprintf( '%d minutes remaining', $total ) );
                        ?>
                    </div>
                    <div class="sitestaffr-purchased-display">
                        <?php
                        // Secondary message: Breakdown (only show if purchased > 0)
                        if ( $purchased > 0 ) {
                            echo esc_html( sprintf( 'Purchased: %d', $purchased ) );
                        }
                        ?>
                    </div>
                    <?php if ( ! empty( $health_message ) ) : ?>
                    <div class="sitestaffr-health-message">
                        <?php echo esc_html( $health_message ); ?>
                    </div>
                    <?php endif; ?>
                    <?php
                    // Conditional CTA — open shared add-on modal (all add-on entrypoints use modal UX)
                    // HIDE when >=25% AND >=15 min (healthy), SOFT when warning zone, STRONG when critical
                    if ( $percentage < 25 || $total < 15 ) :
                        $purchase_btn_class = ( $percentage < 5 || $total < 2 )
                            ? 'sitestaffr-purchase-button sitestaffr-purchase-strong'
                            : 'sitestaffr-purchase-button sitestaffr-purchase-soft';
                        $purchase_btn_label = ( $percentage < 5 || $total < 2 )
                            ? __( 'Purchase Now', 'sitestaffr' )
                            : __( 'Purchase More AI Minutes', 'sitestaffr' );
                        ?>
                        <div class="sitestaffr-minutes-cta-row">
                            <button type="button" class="<?php echo esc_attr( $purchase_btn_class ); ?>" data-open-buy-modal>
                                <?php echo esc_html( $purchase_btn_label ); ?>
                            </button>
                            <?php if ( $dashboard_show_upgrade_cta ) : ?>
                                <a class="sitestaffr-purchase-button sitestaffr-purchase-secondary" href="<?php echo esc_url( $dashboard_upgrade_cta_url ); ?>">
                                    <?php esc_html_e( 'Upgrade Plan', 'sitestaffr' ); ?>
                                </a>
                            <?php endif; ?>
                        </div>
                    <?php endif; ?>
                </div>
            </div>
        </div>

        <!-- RIGHT COLUMN: Stats Cards Stacked Vertically -->
        <div class="sitestaffr-widget sitestaffr-stats-widget">
            <div class="sitestaffr-stats-grid">
                <div class="sitestaffr-stat-card sitestaffr-stat-calls">
                    <div class="sitestaffr-stat-content">
                        <span class="sitestaffr-stat-label"><?php esc_html_e( 'Conversations', 'sitestaffr' ); ?></span>
                        <span class="sitestaffr-stat-number"><?php echo esc_html( $total_calls_month ); ?></span>
                    </div>
                </div>
                <div class="sitestaffr-stat-card sitestaffr-stat-duration">
                    <div class="sitestaffr-stat-content">
                        <span class="sitestaffr-stat-label"><?php esc_html_e( 'Avg Duration (min:sec)', 'sitestaffr' ); ?></span>
                        <span class="sitestaffr-stat-number"><?php echo esc_html( $avg_duration_display ); ?></span>
                    </div>
                </div>
                <div class="sitestaffr-stat-card sitestaffr-stat-dynamic <?php echo esc_attr( $stat_modifier_class ); ?>">
                    <div class="sitestaffr-stat-content">
                        <span class="sitestaffr-stat-label"><?php echo esc_html( $stat_label ); ?></span>
                        <span class="sitestaffr-stat-number"><?php echo esc_html( $stat_value ); ?></span>
                    </div>
                </div>
                <div class="sitestaffr-stat-card sitestaffr-stat-projection">
                    <div class="sitestaffr-stat-content">
                        <span class="sitestaffr-stat-label"><?php esc_html_e( 'Days to Exhaustion', 'sitestaffr' ); ?></span>
                        <span class="sitestaffr-stat-number"><?php echo esc_html( $projection_stat_value ); ?></span>
                    </div>
                </div>
            </div>
        </div>

    </div><!-- .sitestaffr-dashboard-balance-stats-grid -->

    <!-- Main Dashboard Grid (70/30 Layout) -->
    <div class="sitestaffr-dashboard-grid">

        <!-- Recent Calls (70% Left Column) -->
        <div class="sitestaffr-widget sitestaffr-calls-widget sitestaffr-recent-calls-widget">
            <div class="sitestaffr-widget-header">
                <h3>
                    <span class="dashicons dashicons-list-view"></span>
                    <?php esc_html_e( 'Recent Conversations', 'sitestaffr' ); ?>
                </h3>
                <a href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?page=sitestaffr&view=all' ), 'sitestaffr_view' ) ); ?>" class="sitestaffr-view-all-link">
                    <span class="sitestaffr-view-all-text"><?php esc_html_e( 'View All', 'sitestaffr' ); ?></span>
                    <span class="dashicons dashicons-arrow-right-alt2"></span>
                </a>
            </div>
            <?php if ( ! empty( $recent_calls ) ) : ?>
            <div class="sitestaffr-calls-list">
                <?php foreach ( $recent_calls as $call ) : ?>
                <div class="sitestaffr-call-item <?php echo esc_attr( $call->is_read ? '' : 'sitestaffr-call-unread' ); ?>" data-call-id="<?php echo esc_attr( $call->id ); ?>" data-call-url="<?php echo esc_url( wp_nonce_url( add_query_arg( array( 'page' => 'sitestaffr', 'action' => 'view', 'call_id' => $call->id ), admin_url( 'admin.php' ) ), 'sitestaffr_view_call' ) ); ?>">
                    <div class="sitestaffr-call-avatar-circle">
                        <span class="dashicons dashicons-format-chat"></span>
                    </div>
                    <div class="sitestaffr-call-info">
                        <?php if ( ! $call->is_read ) : ?>
                            <span class="sitestaffr-badge-new"><?php esc_html_e( 'New', 'sitestaffr' ); ?></span>
                        <?php endif; ?>
                        <?php if ( isset( $call->persona ) && 'onboarding' === sanitize_key( $call->persona ) ) : ?>
                            <span class="sitestaffr-persona-badge sitestaffr-persona-badge--onboarding"><?php esc_html_e( 'Onboarding Lead', 'sitestaffr' ); ?></span>
                        <?php endif; ?>
                        <?php if ( ! empty( $call->ai_summary ) ) : ?>
                            <p class="sitestaffr-call-summary-snippet"><?php
								$snippet_raw = stripslashes( $call->ai_summary );
								// For onboarding table recaps, build a clean "Name — Business" snippet.
								if ( false !== stripos( $snippet_raw, '<table' ) ) {
									$snippet_parts = array();
									if ( preg_match_all( '/<td[^>]*style="padding:6px 0;"[^>]*>(.*?)<\/td>/si', $snippet_raw, $td_matches ) ) {
										foreach ( $td_matches[1] as $td_val ) {
											$clean = trim( wp_strip_all_tags( $td_val ) );
											if ( '' !== $clean ) {
												$snippet_parts[] = $clean;
											}
										}
									}
									echo esc_html( implode( ' · ', $snippet_parts ) );
								} else {
									echo esc_html( wp_trim_words( wp_strip_all_tags( $snippet_raw ), 24, '...' ) );
								}
							?></p>
                        <?php else : ?>
                            <p class="sitestaffr-call-summary-snippet sitestaffr-call-summary-empty"><?php esc_html_e( 'No summary available', 'sitestaffr' ); ?></p>
                        <?php endif; ?>
                        <span class="sitestaffr-call-time"><?php echo esc_html( human_time_diff( strtotime( $call->created_at ), current_time( 'timestamp' ) ) ); ?> <?php esc_html_e( 'ago', 'sitestaffr' ); ?></span>
                    </div>

                    <!-- Duration at top-right corner -->
                    <div class="sitestaffr-call-meta">
                        <?php if ( $call->call_duration > 0 ) : ?>
                            <span class="sitestaffr-call-duration"><?php echo esc_html( sprintf( '%d:%02d', floor( $call->call_duration / 60 ), $call->call_duration % 60 ) ); ?></span>
                        <?php endif; ?>
                    </div>
                </div>
                <?php endforeach; ?>
            </div>
            <?php else : ?>
            <div class="sitestaffr-empty-state">
                <span class="dashicons dashicons-format-chat"></span>
                <p><?php esc_html_e( 'No conversations yet. Once conversations come in, they\'ll appear here.', 'sitestaffr' ); ?></p>
                <?php if ( $has_phone_number ) : ?>
                <p class="sitestaffr-empty-hint"><?php esc_html_e( 'Try making a call to see how it works!', 'sitestaffr' ); ?></p>
                <?php endif; ?>
            </div>
            <?php endif; ?>
            <a href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?page=sitestaffr&view=all' ), 'sitestaffr_view' ) ); ?>" class="sitestaffr-view-all-link sitestaffr-view-all-link-mobile">
                <span class="sitestaffr-view-all-text"><?php esc_html_e( 'View All', 'sitestaffr' ); ?></span>
                <span class="dashicons dashicons-arrow-right-alt2"></span>
            </a>
        </div>

        <!-- Quick Actions (30% Right Sidebar) -->
        <div class="sitestaffr-widget sitestaffr-actions-sidebar">
            <div class="sitestaffr-widget-header">
                <h2>
                    <span class="dashicons dashicons-admin-tools"></span>
                    <?php esc_html_e( 'Quick Actions', 'sitestaffr' ); ?>
                </h2>
            </div>
            <div class="sitestaffr-sidebar-actions">
                <a href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?page=sitestaffr&view=all' ), 'sitestaffr_view' ) ); ?>" class="sitestaffr-sidebar-button">
                    <span class="sitestaffr-sidebar-icon">
                        <span class="dashicons dashicons-list-view"></span>
                    </span>
                    <div class="sitestaffr-sidebar-content">
                        <div class="sitestaffr-action-title"><?php esc_html_e( 'View All Conversations', 'sitestaffr' ); ?></div>
                        <div class="sitestaffr-action-desc"><?php esc_html_e( 'Complete conversation history', 'sitestaffr' ); ?></div>
                    </div>
                    <span class="dashicons dashicons-arrow-right-alt2"></span>
                </a>
                <a href="<?php echo esc_url( admin_url( 'admin.php?page=sitestaffr-usage' ) ); ?>" class="sitestaffr-sidebar-button">
                    <span class="sitestaffr-sidebar-icon">
                        <span class="dashicons dashicons-chart-line"></span>
                    </span>
                    <div class="sitestaffr-sidebar-content">
                        <div class="sitestaffr-action-title"><?php esc_html_e( 'View Usage', 'sitestaffr' ); ?></div>
                        <div class="sitestaffr-action-desc"><?php esc_html_e( 'AI minutes balance & billing', 'sitestaffr' ); ?></div>
                    </div>
                    <span class="dashicons dashicons-arrow-right-alt2"></span>
                </a>
                <a href="<?php echo esc_url( admin_url( 'admin.php?page=sitestaffr-settings' ) ); ?>" class="sitestaffr-sidebar-button">
                    <span class="sitestaffr-sidebar-icon">
                        <span class="dashicons dashicons-admin-generic"></span>
                    </span>
                    <div class="sitestaffr-sidebar-content">
                        <div class="sitestaffr-action-title"><?php esc_html_e( 'Settings', 'sitestaffr' ); ?></div>
                        <div class="sitestaffr-action-desc"><?php esc_html_e( 'Configure your account', 'sitestaffr' ); ?></div>
                    </div>
                    <span class="dashicons dashicons-arrow-right-alt2"></span>
                </a>
                <a href="<?php echo esc_url( admin_url( 'admin.php?page=sitestaffr-widget-settings' ) ); ?>" class="sitestaffr-sidebar-button">
                    <span class="sitestaffr-sidebar-icon">
                        <span class="dashicons dashicons-welcome-widgets-menus"></span>
                    </span>
                    <div class="sitestaffr-sidebar-content">
                        <div class="sitestaffr-action-title"><?php esc_html_e( 'Widget Settings', 'sitestaffr' ); ?></div>
                        <div class="sitestaffr-action-desc"><?php esc_html_e( 'Customize widget appearance', 'sitestaffr' ); ?></div>
                    </div>
                    <span class="dashicons dashicons-arrow-right-alt2"></span>
                </a>
                <button type="button" class="sitestaffr-sidebar-button" data-open-buy-modal>
                    <span class="sitestaffr-sidebar-icon">
                        <span class="dashicons dashicons-plus-alt2"></span>
                    </span>
                    <div class="sitestaffr-sidebar-content">
                        <div class="sitestaffr-action-title"><?php esc_html_e( 'Buy More Minutes', 'sitestaffr' ); ?></div>
                        <div class="sitestaffr-action-desc"><?php esc_html_e( '50 min add-on for $10', 'sitestaffr' ); ?></div>
                    </div>
                    <span class="dashicons dashicons-arrow-right-alt2"></span>
                </button>
            </div>
            <div id="sitestaffr-action-status" class="sitestaffr-action-status"></div>
        </div>

    </div><!-- .sitestaffr-dashboard-grid -->

    </div><!-- .pe-dashboard-content -->
</div><!-- .wrap -->

<\!-- Dashboard JS enqueued via class-sitestaffr-admin.php (sitestaffr-dashboard.js) -->
<?php // phpcs:enable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound,WordPress.Security.NonceVerification.Recommended ?>
